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());
+    }
 }