Skip to content

Commit

Permalink
[DEX] Associate annotations with its method/class definition
Browse files Browse the repository at this point in the history
  • Loading branch information
REAndroid committed Dec 9, 2024
1 parent 5009b6b commit bad5a7b
Show file tree
Hide file tree
Showing 4 changed files with 178 additions and 6 deletions.
25 changes: 25 additions & 0 deletions src/main/java/com/reandroid/dex/key/AnnotationElementKey.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
*/
package com.reandroid.dex.key;

import com.reandroid.dex.smali.SmaliParseException;
import com.reandroid.dex.smali.SmaliReader;
import com.reandroid.dex.smali.SmaliWriter;
import com.reandroid.utils.CompareUtil;
import com.reandroid.utils.ObjectsUtil;
Expand Down Expand Up @@ -61,6 +63,11 @@ public AnnotationElementKey changeValue(Key value) {
return create(getName(), value);
}

public MethodKey toMethod(TypeKey declaring) {
return MethodKey.create(declaring, getNameKey(),
ProtoKey.create(KeyUtil.getReturnTypeForValue(getValue())));
}

@Override
public AnnotationElementKey replaceKey(Key search, Key replace) {
if (this.equals(search)) {
Expand Down Expand Up @@ -150,4 +157,22 @@ public static AnnotationElementKey create(String name, Key value) {
}
return new AnnotationElementKey(name, value);
}

public static AnnotationElementKey read(SmaliReader reader) throws IOException {
reader.skipWhitespacesOrComment();
int i1 = reader.indexOfWhiteSpace();
int i2 = reader.indexOf('=');
int i;
if (i1 >= 0 && i1 < i2) {
i = i1;
} else {
i = i2;
}
int length = i - reader.position();
String name = reader.readString(length);
reader.skipWhitespaces();
SmaliParseException.expect(reader, '=');
Key value = KeyUtil.readValue(reader);
return create(name, value);
}
}
77 changes: 72 additions & 5 deletions src/main/java/com/reandroid/dex/key/AnnotationItemKey.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@

import com.reandroid.dex.common.AnnotationVisibility;
import com.reandroid.dex.smali.SmaliDirective;
import com.reandroid.dex.smali.SmaliParseException;
import com.reandroid.dex.smali.SmaliReader;
import com.reandroid.dex.smali.SmaliWriter;
import com.reandroid.utils.CompareUtil;
Expand Down Expand Up @@ -172,23 +173,51 @@ public SmaliDirective getSmaliDirective() {
return SmaliDirective.SUB_ANNOTATION;
}

public Iterator<MethodKey> getMethods() {
TypeKey typeKey = getType();
return ComputeIterator.of(iterator(), elementKey -> elementKey.toMethod(typeKey));
}
@Override
public AnnotationItemKey replaceKey(Key search, Key replace) {
if (this.equals(search)) {
return (AnnotationItemKey) replace;
}
AnnotationItemKey result = this;
if(search.equals(getType())) {
if (search instanceof MethodKey) {
result = result.replaceMethodKeys((MethodKey) search, (MethodKey) replace);
} else if (search.equals(getType())) {
result = result.changeType((TypeKey) replace);
}
return (AnnotationItemKey) result.replaceElements(search, replace);
}
private AnnotationItemKey replaceMethodKeys(MethodKey search, MethodKey replace) {
AnnotationItemKey result = this;
TypeKey declaring = result.getType();
if (!declaring.equals(search.getDeclaring())) {
return result;
}
TypeKey replaceType = replace.getDeclaring();
if (!declaring.equals(replaceType)) {
result = result.changeType(replaceType);
}
String name = search.getName();
String replaceName = replace.getName();
if (!name.equals(replaceName) && !containsElement(replaceName)) {
AnnotationElementKey element = result.get(name);
if (element != null) {
result = result.set(
indexOf(element), element.changeName(replaceName));
}
}
return result;
}

@Override
public Iterator<? extends Key> mentionedKeys() {
return CombiningIterator.singleOne(
return CombiningIterator.singleTwo(
getType(),
super.mentionedKeys());
super.mentionedKeys(),
getMethods());
}

@Override
Expand Down Expand Up @@ -222,6 +251,13 @@ int computeHash() {
public boolean equalsType(TypeKey typeKey) {
return ObjectsUtil.equals(getType(), typeKey);
}

public boolean equalsMethod(MethodKey methodKey) {
return methodKey != null &&
ObjectsUtil.equals(getType(), methodKey.getDeclaring()) &&
containsElement(methodKey.getName());
}

@Override
public boolean equals(Object obj) {
if (this == obj) {
Expand Down Expand Up @@ -253,8 +289,39 @@ public static AnnotationItemKey createKey(AnnotationVisibility visibility, TypeK
}

public static AnnotationItemKey read(SmaliReader reader) throws IOException {
//FIXME
throw new RuntimeException("AnnotationItemKey.read not implemented");
reader.skipWhitespacesOrComment();
SmaliDirective directive = SmaliDirective.parse(reader);
if (directive != SmaliDirective.ANNOTATION && directive != SmaliDirective.SUB_ANNOTATION) {
throw new SmaliParseException("Expecting annotation directive", reader);
}
AnnotationVisibility visibility = null;
if(directive == SmaliDirective.ANNOTATION) {
visibility = AnnotationVisibility.parse(reader);
if(visibility == null) {
throw new SmaliParseException("Unrecognized annotation visibility", reader);
}
}
reader.skipWhitespacesOrComment();
TypeKey typeKey = TypeKey.read(reader);
reader.skipWhitespacesOrComment();
ArrayCollection<AnnotationElementKey> elementList = null;
while (!directive.isEnd(reader)) {
AnnotationElementKey element = AnnotationElementKey.read(reader);
if (elementList == null) {
elementList = new ArrayCollection<>();
}
elementList.add(element);
reader.skipWhitespacesOrComment();
}
reader.skipWhitespacesOrComment();
SmaliParseException.expect(reader, directive, true);
Key[] elements;
if (elementList != null) {
elements = elementList.toArrayFill(new Key[elementList.size()]);
} else {
elements = null;
}
return createKey(visibility, typeKey, elements);
}
public static AnnotationItemKey parse(String text) {
//FIXME
Expand Down
2 changes: 1 addition & 1 deletion src/main/java/com/reandroid/dex/key/EnumKey.java
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ public void append(SmaliWriter writer) throws IOException {

@Override
public String toString() {
return SmaliDirective.ENUM.getName() + " " + super.toString();
return SmaliDirective.ENUM + " " + super.toString();
}

public static EnumKey create(FieldKey fieldKey) {
Expand Down
80 changes: 80 additions & 0 deletions src/main/java/com/reandroid/dex/key/KeyUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,13 @@
*/
package com.reandroid.dex.key;

import com.reandroid.dex.smali.SmaliDirective;
import com.reandroid.dex.smali.SmaliParseException;
import com.reandroid.dex.smali.SmaliReader;
import com.reandroid.utils.ObjectsUtil;

import java.io.IOException;

public class KeyUtil {

public static final String ANY_NAME = ObjectsUtil.of("*");
Expand All @@ -36,4 +41,79 @@ public static boolean matches(String name1, String name2){
name2.equals(ANY_NAME);
}

public static Key readValue(SmaliReader reader) throws IOException {
reader.skipWhitespacesOrComment();
SmaliDirective directive = SmaliDirective.parse(reader, false);
if (directive != null) {
if (directive == SmaliDirective.SUB_ANNOTATION) {
return AnnotationItemKey.read(reader);
}
if (directive == SmaliDirective.ENUM) {
return EnumKey.read(reader);
}
throw new SmaliParseException("Unexpected directive", reader);
}
char first = reader.getASCII(reader.position());
if (first == '{') {
return ArrayValueKey.read(reader);
}
if (first == '"') {
return StringKey.read(reader);
}
if (first == '(') {
return ProtoKey.read(reader);
}
if (first == 'L' || first == '[') {
TypeKey typeKey = TypeKey.read(reader);
if (reader.skipWhitespacesOrComment() || reader.finished()) {
return typeKey;
}
char c = reader.getASCII(reader.position());
if (c == '}' || c == ',') {
return typeKey;
}
SmaliParseException.expect(reader, '-');
SmaliParseException.expect(reader, '>');
reader.skipWhitespacesOrComment();
int i = reader.indexOfBeforeLineEnd('(');
if (i > 0) {
StringKey name = StringKey.readSimpleName(reader, '(');
ProtoKey protoKey = ProtoKey.read(reader);
return MethodKey.create(typeKey, name, protoKey);
}
throw new SmaliParseException("Expecting method", reader);
}
PrimitiveKey primitiveKey = PrimitiveKey.readSafe(reader);
if (primitiveKey == null) {
throw new SmaliParseException("Unexpected value", reader);
}
return primitiveKey;
}

public static TypeKey getReturnTypeForValue(Key value) {
return getReturnTypeForValue(value, 0);
}
private static TypeKey getReturnTypeForValue(Key value, int arrayDimension) {
if (value instanceof StringKey) {
return TypeKey.STRING.setArrayDimension(arrayDimension);
}
if (value instanceof TypeKey) {
return TypeKey.CLASS.setArrayDimension(arrayDimension);
}
if (value instanceof PrimitiveKey) {
return ((PrimitiveKey) value).valueType().setArrayDimension(arrayDimension);
}
if (value instanceof EnumKey) {
return ((EnumKey) value).getType().setArrayDimension(arrayDimension);
}
if (value instanceof AnnotationItemKey) {
return ((AnnotationItemKey) value).getType().setArrayDimension(arrayDimension);
}
if (value instanceof KeyList<?>) {
KeyList<?> keyList = (KeyList<?>) value;
return getReturnTypeForValue(keyList.get(0), arrayDimension + 1);
}
return null;
}

}

0 comments on commit bad5a7b

Please sign in to comment.