Mercurial > hg > icedrobot > daneel
changeset 119:8c0170381072
Adapted parser interface for annotations.
* dex/AnnotationsDirectory.java: Implemented annotation parameter visiting.
* dex/Code.java (acceptInsns): Switched to new method description getter.
* dex/DexAnnotationVisitor.java: Defined rest of the interface.
* dex/EncodedValue.java (parse): Implemented for type, field and method refs.
* dex/MethodId.java (getMethodDesc): Added new method description getter.
author | Michael Starzinger <michi@complang.tuwien.ac.at> |
---|---|
date | Mon, 04 Apr 2011 23:21:45 +0200 |
parents | 56844aab0e5c |
children | 08de240ca6d8 |
files | src/main/java/org/icedrobot/daneel/dex/AnnotationsDirectory.java src/main/java/org/icedrobot/daneel/dex/Code.java src/main/java/org/icedrobot/daneel/dex/DexAnnotationVisitor.java src/main/java/org/icedrobot/daneel/dex/EncodedValue.java src/main/java/org/icedrobot/daneel/dex/MethodId.java |
diffstat | 5 files changed, 149 insertions(+), 13 deletions(-) [+] |
line wrap: on
line diff
--- a/src/main/java/org/icedrobot/daneel/dex/AnnotationsDirectory.java Mon Apr 04 23:11:15 2011 +0200 +++ b/src/main/java/org/icedrobot/daneel/dex/AnnotationsDirectory.java Mon Apr 04 23:21:45 2011 +0200 @@ -42,6 +42,7 @@ import java.util.Map; import org.icedrobot.daneel.dex.EncodedValue.AnnotationValue; +import org.icedrobot.daneel.dex.EncodedValue.AnnotationVisitable; /** * A parser class capable of parsing {@code annotations_directory_item} @@ -193,11 +194,43 @@ Annotation annotation) { if (visitor == null) return; - // XXX Visit the annotation! + Map<String, Object> params = annotation.annotationValue.elements; + for (Map.Entry<String, Object> entry : params.entrySet()) { + String name = entry.getKey(); + Object value = entry.getValue(); + acceptAnnotationParam(visitor, name, value); + } visitor.visitEnd(); } /** + * Allows the given visitor to visit the given annotation parameter. + * + * @param visitor The given DEX annotation visitor. + * @param name The annotation parameter name. + * @param value The annotation parameter value. + */ + private static void acceptAnnotationParam(DexAnnotationVisitor visitor, + String name, Object value) { + if (value instanceof AnnotationVisitable) { + AnnotationVisitable visitable = (AnnotationVisitable) value; + visitable.accept(visitor, name); + return; + } + if (value instanceof Object[]) { + Object[] array = (Object[]) value; + DexAnnotationVisitor v = visitor.visitArray(name, array.length); + if (v == null) + return; + for (Object element : array) + acceptAnnotationParam(v, null, element); + v.visitEnd(); + return; + } + visitor.visitPrimitive(name, value); + } + + /** * Helper method decoding an {@code annotation_set_item} array. * * @param buffer The byte buffer to read from.
--- a/src/main/java/org/icedrobot/daneel/dex/Code.java Mon Apr 04 23:11:15 2011 +0200 +++ b/src/main/java/org/icedrobot/daneel/dex/Code.java Mon Apr 04 23:21:45 2011 +0200 @@ -47,7 +47,6 @@ import org.icedrobot.daneel.dex.DebugInfo.LineNumber; import org.icedrobot.daneel.dex.DebugInfo.LocalVariable; import org.icedrobot.daneel.util.BufferUtil; -import org.icedrobot.daneel.util.TypeUtil; /** * A parser class capable of parsing {@code code_item} structures as part of DEX @@ -588,10 +587,8 @@ // Format 35c B|A|op CCCC G|F|E|D // Syntax: op {vD, vE, vF, vG, vA}, meth@CCCC method = dex.getMethodId(u2); - string = TypeUtil.convertProtoToDesc(method.getProtoId() - .getReturnType(), method.getProtoId().getParameters()); v.visitInstrMethod(op, n1, n2, u3, method.getClassName(), - method.getName(), string); + method.getName(), method.getMethodDesc()); break; case INVOKE_VIRTUAL_RANGE: @@ -602,10 +599,8 @@ // Format 3rc AA|op BBBB CCCC // Syntax: op {vCCCC .. vNNNN}, meth@BBBB method = dex.getMethodId(u2); - string = TypeUtil.convertProtoToDesc(method.getProtoId() - .getReturnType(), method.getProtoId().getParameters()); v.visitInstrMethod(op, b1, u3, 0, method.getClassName(), - method.getName(), string); + method.getName(), method.getMethodDesc()); break; case CMPL_FLOAT:
--- a/src/main/java/org/icedrobot/daneel/dex/DexAnnotationVisitor.java Mon Apr 04 23:11:15 2011 +0200 +++ b/src/main/java/org/icedrobot/daneel/dex/DexAnnotationVisitor.java Mon Apr 04 23:21:45 2011 +0200 @@ -42,7 +42,75 @@ */ public interface DexAnnotationVisitor { - // XXX Define further methods! + /** + * Visits a primitive annotation parameter. The primitive value is passed as + * a boxed value. The {@code null} reference is passed as {@code null} + * value. + * + * @param name The annotation parameter name. + * @param value The boxed primitive value or a {@code null} reference. + */ + void visitPrimitive(String name, Object value); + + /** + * Visits a type-reference (i.e. class or interface) annotation parameter. + * The type is passed as a type descriptor. + * + * @param name The annotation parameter name. + * @param typeDesc The type's type descriptor. + */ + void visitType(String name, String typeDesc); + + /** + * Visits a field-reference annotation parameter. The field is passed as a + * combination of the field owner, name and type. + * + * @param name The annotation parameter name. + * @param fieldOwner The field's owner as a type descriptor. + * @param fieldName The field's name. + * @param fieldDesc The field's type descriptor. + */ + void visitField(String name, String fieldOwner, String fieldName, + String fieldDesc); + + /** + * Visits a method-reference annotation parameter. The field is passed as a + * combination of the method owner, name and type. + * + * @param name The annotation parameter name. + * @param methodOwner The method's owner as a type descriptor. + * @param methodName The method's name. + * @param methodDesc The method's method descriptor. + */ + void visitMethod(String name, String methodOwner, String methodName, + String methodDesc); + + /** + * Visits a sub-annotation annotation parameter. In case this visitor is + * interested in further details about the annotation parameter it should + * return a new visitor object, otherwise it should return {@code null}. + * + * @param name The annotation parameter name. + * @param type The sub-annotation's type as a type descriptor. + * @return A visitor object for the parameter or {@code null} if this + * visitor is not interested in details about the parameter. + */ + DexAnnotationVisitor visitAnnotation(String name, String type); + + /** + * Visits an array annotation parameter. In case this visitor is interested + * in further details about the annotation parameter it should return a new + * visitor object, otherwise it should return {@code null}. + * <p> + * This nifty little trick to reduce interface complexity by reusing + * annotation visitors for arrays was kindly borrowed from ASM's interface. + * + * @param name The annotation parameter name. + * @param size The size of the array to be visited. + * @return A visitor object for the parameter or {@code null} if this + * visitor is not interested in details about the parameter. + */ + DexAnnotationVisitor visitArray(String name, int size); /** * Visits the end of the annotation.
--- a/src/main/java/org/icedrobot/daneel/dex/EncodedValue.java Mon Apr 04 23:11:15 2011 +0200 +++ b/src/main/java/org/icedrobot/daneel/dex/EncodedValue.java Mon Apr 04 23:21:45 2011 +0200 @@ -107,12 +107,30 @@ return dex.getString((int) readU64(buffer, arg)); case VALUE_TYPE: assertValueArg(arg, 3); - // XXX What kind of boxing should we use? - return "type@" + readU64(buffer, arg); + final String t = dex.getTypeDescriptor((int) readU64(buffer, arg)); + return new AnnotationVisitable() { + public void accept(DexAnnotationVisitor visitor, String name) { + visitor.visitType(name, t); + } + }; + case VALUE_FIELD: + assertValueArg(arg, 3); + final FieldId f = dex.getFieldId((int) readU64(buffer, arg)); + return new AnnotationVisitable() { + public void accept(DexAnnotationVisitor visitor, String name) { + visitor.visitField(name, f.getClassName(), f.getName(), f + .getTypeDescriptor()); + } + }; case VALUE_METHOD: assertValueArg(arg, 3); - // XXX What kind of boxing should we use? - return "method@" + readU64(buffer, arg); + final MethodId m = dex.getMethodId((int) readU64(buffer, arg)); + return new AnnotationVisitable() { + public void accept(DexAnnotationVisitor visitor, String name) { + visitor.visitMethod(name, m.getClassName(), m.getName(), m + .getMethodDesc()); + } + }; case VALUE_ARRAY: assertValueArg(arg, 0); return parseArray(buffer, dex); @@ -222,6 +240,15 @@ } /** + * An internal interface to allow boxing of certain encoded values + * representing reflective references. Allows those boxed types to be + * visited by an annotation visitor. + */ + static interface AnnotationVisitable { + public void accept(DexAnnotationVisitor visitor, String name); + }; + + /** * An internal representation of an annotation as encoded in the {@code * encoded_annotation} structure. */
--- a/src/main/java/org/icedrobot/daneel/dex/MethodId.java Mon Apr 04 23:11:15 2011 +0200 +++ b/src/main/java/org/icedrobot/daneel/dex/MethodId.java Mon Apr 04 23:21:45 2011 +0200 @@ -39,6 +39,8 @@ import java.nio.ByteBuffer; +import org.icedrobot.daneel.util.TypeUtil; + /** * A parser class capable of parsing {@code method_id_item} structures as part * of DEX files. Keep package-private to hide internal API. @@ -85,4 +87,15 @@ public String getName() { return name; } + + /** + * Returns the method descriptor for this method. That descriptor is + * computed from various parts of the prototype identifier. + * + * @return The method descriptor. + */ + public String getMethodDesc() { + return TypeUtil.convertProtoToDesc(protoId.getReturnType(), protoId + .getParameters()); + } }