Implemented class and method annotations

git-svn-id: https://smali.googlecode.com/svn/trunk@166 55b6fa8a-2a1e-11de-a435-ffa8d773f76a
This commit is contained in:
JesusFreke@JesusFreke.com
2009-06-18 06:52:02 +00:00
parent 1080561460
commit fa07a1972e
9 changed files with 223 additions and 17 deletions

View File

@ -0,0 +1,65 @@
/*
* [The "BSD licence"]
* Copyright (c) 2009 Ben Gruver
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package org.jf.baksmali.Adaptors;
import org.jf.dexlib.AnnotationItem;
import org.jf.baksmali.Adaptors.EncodedValue.AnnotationEncodedValueAdaptor;
import org.jf.baksmali.Adaptors.Reference.TypeReference;
import java.util.List;
public class AnnotationAdaptor {
private AnnotationItem annotationItem;
private AnnotationEncodedValueAdaptor encodedAnnotationAdaptor;
public AnnotationAdaptor(AnnotationItem annotationItem) {
this.annotationItem = annotationItem;
this.encodedAnnotationAdaptor = new AnnotationEncodedValueAdaptor(annotationItem.getEncodedAnnotation());
}
public String getVisibility() {
switch (annotationItem.getVisibility()) {
case 0:
return "build";
case 1:
return "runtime";
case 2:
return "system";
}
return null;
}
public TypeReference getAnnotationType() {
return encodedAnnotationAdaptor.getAnnotationType();
}
public List<AnnotationEncodedValueAdaptor.AnnotationElementAdaptor> getElements() {
return encodedAnnotationAdaptor.getElements();
}
}

View File

@ -28,23 +28,37 @@
package org.jf.baksmali.Adaptors; package org.jf.baksmali.Adaptors;
import org.jf.dexlib.ClassDataItem;
import org.jf.dexlib.ClassDefItem;
import org.jf.dexlib.EncodedArrayItem;
import org.jf.dexlib.EncodedValue.EncodedValue; import org.jf.dexlib.EncodedValue.EncodedValue;
import org.jf.dexlib.TypeIdItem; import org.jf.dexlib.*;
import org.jf.dexlib.util.AccessFlags; import org.jf.dexlib.util.AccessFlags;
import java.util.ArrayList; import java.util.*;
import java.util.List;
public class ClassDefinition { public class ClassDefinition {
private ClassDefItem classDefItem; private ClassDefItem classDefItem;
private ClassDataItem classDataItem; private ClassDataItem classDataItem;
private HashMap<Integer, AnnotationSetItem> methodAnnotations = new HashMap<Integer, AnnotationSetItem>();
public ClassDefinition(ClassDefItem classDefItem) { public ClassDefinition(ClassDefItem classDefItem) {
this.classDefItem = classDefItem; this.classDefItem = classDefItem;
this.classDataItem = classDefItem.getClassData(); this.classDataItem = classDefItem.getClassData();
buildAnnotationMaps();
}
private void buildAnnotationMaps() {
AnnotationDirectoryItem annotationDirectory = classDefItem.getAnnotationDirectory();
if (annotationDirectory == null) {
return;
}
List<AnnotationDirectoryItem.MethodAnnotation> methodAnnotationList = annotationDirectory.getMethodAnnotations();
if (methodAnnotations != null) {
for (AnnotationDirectoryItem.MethodAnnotation methodAnnotation: methodAnnotationList) {
methodAnnotations.put(methodAnnotation.getMethod().getIndex(), methodAnnotation.getAnnotationSet());
}
}
} }
private List<String> accessFlags = null; private List<String> accessFlags = null;
@ -142,7 +156,8 @@ public class ClassDefinition {
if (classDataItem != null) { if (classDataItem != null) {
for (ClassDataItem.EncodedMethod method: classDataItem.getDirectMethods()) { for (ClassDataItem.EncodedMethod method: classDataItem.getDirectMethods()) {
directMethods.add(new MethodDefinition(method)); AnnotationSetItem annotationSet = methodAnnotations.get(method.getMethod().getIndex());
directMethods.add(new MethodDefinition(method, annotationSet));
} }
} }
} }
@ -156,10 +171,30 @@ public class ClassDefinition {
if (classDataItem != null) { if (classDataItem != null) {
for (ClassDataItem.EncodedMethod method: classDataItem.getVirtualMethods()) { for (ClassDataItem.EncodedMethod method: classDataItem.getVirtualMethods()) {
virtualMethods.add(new MethodDefinition(method)); AnnotationSetItem annotationSet = methodAnnotations.get(method.getMethod().getIndex());
virtualMethods.add(new MethodDefinition(method, annotationSet));
} }
} }
} }
return virtualMethods; return virtualMethods;
} }
public List<AnnotationAdaptor> getAnnotations() {
AnnotationDirectoryItem annotationDirectory = classDefItem.getAnnotationDirectory();
if (annotationDirectory == null) {
return null;
}
AnnotationSetItem annotationSet = annotationDirectory.getClassAnnotations();
if (annotationSet == null) {
return null;
}
List<AnnotationAdaptor> annotationAdaptors = new ArrayList<AnnotationAdaptor>();
for (AnnotationItem annotationItem: annotationSet.getAnnotationItems()) {
annotationAdaptors.add(new AnnotationAdaptor(annotationItem));
}
return annotationAdaptors;
}
} }

View File

@ -29,9 +29,7 @@
package org.jf.baksmali.Adaptors; package org.jf.baksmali.Adaptors;
import org.jf.baksmali.Adaptors.Format.*; import org.jf.baksmali.Adaptors.Format.*;
import org.jf.dexlib.ClassDataItem; import org.jf.dexlib.*;
import org.jf.dexlib.CodeItem;
import org.jf.dexlib.MethodIdItem;
import org.jf.dexlib.code.Format.*; import org.jf.dexlib.code.Format.*;
import org.jf.dexlib.code.Instruction; import org.jf.dexlib.code.Instruction;
import org.jf.dexlib.code.InstructionField; import org.jf.dexlib.code.InstructionField;
@ -44,11 +42,13 @@ public class MethodDefinition {
private ClassDataItem.EncodedMethod encodedMethod; private ClassDataItem.EncodedMethod encodedMethod;
private MethodIdItem methodIdItem; private MethodIdItem methodIdItem;
private CodeItem codeItem; private CodeItem codeItem;
private AnnotationSetItem annotationSet;
public MethodDefinition(ClassDataItem.EncodedMethod encodedMethod) { public MethodDefinition(ClassDataItem.EncodedMethod encodedMethod, AnnotationSetItem annotationSet) {
this.encodedMethod = encodedMethod; this.encodedMethod = encodedMethod;
this.methodIdItem = encodedMethod.getMethod(); this.methodIdItem = encodedMethod.getMethod();
this.codeItem = encodedMethod.getCodeItem(); this.codeItem = encodedMethod.getCodeItem();
this.annotationSet = annotationSet;
} }
private String methodName = null; private String methodName = null;
@ -99,6 +99,19 @@ public class MethodDefinition {
return registerCount; return registerCount;
} }
public List<AnnotationAdaptor> getAnnotations() {
if (annotationSet == null) {
return null;
}
List<AnnotationAdaptor> annotationAdaptors = new ArrayList<AnnotationAdaptor>();
for (AnnotationItem annotationItem: annotationSet.getAnnotationItems()) {
annotationAdaptors.add(new AnnotationAdaptor(annotationItem));
}
return annotationAdaptors;
}
private List<MethodItem> methodItems = null; private List<MethodItem> methodItems = null;
public List<MethodItem> getMethodItems() { public List<MethodItem> getMethodItems() {

View File

@ -9,6 +9,13 @@ smaliFile(classDef) ::=
# interfaces # interfaces
<classDef.Interfaces: implement(it); separator="\n"> <classDef.Interfaces: implement(it); separator="\n">
<endif>
<if(classDef.Annotations)>
# annotations
<classDef.Annotations: annotation(it); separator="\n\n">
<endif> <endif>
<if(classDef.StaticFields)> <if(classDef.StaticFields)>
@ -49,6 +56,19 @@ implement(interface) ::=
>> >>
annotation(annotationAdaptor) ::=
<<
.annotation <annotationAdaptor.Visibility> <Reference(annotationAdaptor.AnnotationType)>
<if(annotationAdaptor.Elements)>
<annotationAdaptor.Elements: AnnotationElement(it); separator="\n">
<endif>
<if(annotationAdaptor.Elements)>
<endif>
.end annotation
>>
field(fieldDef) ::= field(fieldDef) ::=
@ -60,12 +80,19 @@ field(fieldDef) ::=
method(methodDef) ::= method(methodDef) ::=
<< <<
.method <methodDef.AccessFlags; separator=" "> <methodDef.MethodName><methodDef.Prototype> .method <methodDef.AccessFlags; separator=" "> <methodDef.MethodName><methodDef.Prototype>
<if(methodDef.hasCode)> <if(methodDef.hasCode)>
.registers <methodDef.RegisterCount> .registers <methodDef.RegisterCount>
<if(methodDef.Annotations)>
<methodDef.Annotations: annotation(it); separator="\n\n">
<endif>
<methodDef.MethodItems: MethodItem(it); separator="\n"> <methodDef.MethodItems: MethodItem(it); separator="\n">
<endif>
.end method .end method
<elseif(methodDef.Annotations)>
<methodDef.Annotations: annotation(it); separator="\n\n">
.end method
<endif>
>> >>
MethodItem(MethodItem) ::= MethodItem(MethodItem) ::=
@ -291,7 +318,7 @@ EnumEncodedValue(EncodedValue) ::=
AnnotationEncodedValue(EncodedValue) ::= AnnotationEncodedValue(EncodedValue) ::=
<< <<
.subannotation EncodedValue.Type .subannotation <Reference(EncodedValue.AnnotationType)>
<EncodedValue.Elements: AnnotationElement(it); separator="\n"> <EncodedValue.Elements: AnnotationElement(it); separator="\n">
.end subannotation .end subannotation
>> >>

View File

@ -5,6 +5,19 @@
.implements Lsome/other/interface; .implements Lsome/other/interface;
.annotation build Lsome/annotation;
value1 = "test"
value2 = .subannotation Lsome/annotation;
value1 = "test2"
value2 = Lsome/enum;
.end subannotation
.end annotation
.annotation system Lsome/annotation;
.end annotation
.field public static aStaticFieldWithoutAnInitializer:I .field public static aStaticFieldWithoutAnInitializer:I
.field public static longStaticField:J = 0x300000000L .field public static longStaticField:J = 0x300000000L
@ -63,6 +76,12 @@
.method public testMethod(ILjava/lang/String;)Ljava/lang/String; .method public testMethod(ILjava/lang/String;)Ljava/lang/String;
.registers 3 .registers 3
.annotation runtime Lorg/junit/Test;
.end annotation
.annotation system Lyet/another/annotation;
somevalue = 1234
anothervalue = 3.14159
.end annotation
const-string v0, "testing\n123" const-string v0, "testing\n123"
@ -96,3 +115,13 @@
.end method .end method
.method public abstract testMethod2()V
.annotation runtime Lsome/annotation;
subannotation = .subannotation Lsome/other/annotation;
value = "value"
.end subannotation
.end annotation
.annotation runtime Lorg/junit/Test;
.end annotation
.end method

View File

@ -119,6 +119,14 @@ public class AnnotationDirectoryItem extends OffsettedItem<AnnotationDirectoryIt
return "annotation_directory_item @0x" + Integer.toHexString(getOffset()); return "annotation_directory_item @0x" + Integer.toHexString(getOffset());
} }
public AnnotationSetItem getClassAnnotations() {
return classAnnotationsReferenceField.getReference();
}
public List<MethodAnnotation> getMethodAnnotations() {
return methodAnnotationList;
}
public static class FieldAnnotation extends CompositeField<FieldAnnotation> public static class FieldAnnotation extends CompositeField<FieldAnnotation>
implements Comparable<FieldAnnotation> { implements Comparable<FieldAnnotation> {
private final IndexedItemReference<FieldIdItem> fieldReferenceField; private final IndexedItemReference<FieldIdItem> fieldReferenceField;
@ -170,6 +178,14 @@ public class AnnotationDirectoryItem extends OffsettedItem<AnnotationDirectoryIt
public int compareTo(MethodAnnotation o) { public int compareTo(MethodAnnotation o) {
return ((Integer)method.getReference().getIndex()).compareTo(o.method.getReference().getIndex()); return ((Integer)method.getReference().getIndex()).compareTo(o.method.getReference().getIndex());
} }
public MethodIdItem getMethod() {
return method.getReference();
}
public AnnotationSetItem getAnnotationSet() {
return annotationSet.getReference();
}
} }
public static class ParameterAnnotation extends CompositeField<ParameterAnnotation> public static class ParameterAnnotation extends CompositeField<ParameterAnnotation>

View File

@ -60,4 +60,12 @@ public class AnnotationItem extends OffsettedItem<AnnotationItem> {
public String getConciseIdentity() { public String getConciseIdentity() {
return "annotation_item @0x" + Integer.toHexString(getOffset()); return "annotation_item @0x" + Integer.toHexString(getOffset());
} }
public byte getVisibility() {
return (byte)visibilityField.getCachedValue();
}
public AnnotationEncodedValueSubField getEncodedAnnotation() {
return annotationField;
}
} }

View File

@ -74,4 +74,13 @@ public class AnnotationSetItem extends OffsettedItem<AnnotationSetItem> {
public String getConciseIdentity() { public String getConciseIdentity() {
return "annotation_set_item @0x" + Integer.toHexString(getOffset()); return "annotation_set_item @0x" + Integer.toHexString(getOffset());
} }
public List<AnnotationItem> getAnnotationItems() {
List<AnnotationItem> annotationItems = new ArrayList<AnnotationItem>();
for (OffsettedItemReference<AnnotationItem> annotationItemReference: annotationReferences) {
annotationItems.add(annotationItemReference.getReference());
}
return annotationItems;
}
} }

View File

@ -129,6 +129,10 @@ public class ClassDefItem extends IndexedItem<ClassDefItem> {
return classDataReferenceField.getReference(); return classDataReferenceField.getReference();
} }
public AnnotationDirectoryItem getAnnotationDirectory() {
return classAnnotationsReferenceField.getReference();
}
public String getConciseIdentity() { public String getConciseIdentity() {
return "class_def_item: " + getClassName(); return "class_def_item: " + getClassName();
} }