From 46cc49eadbdc3f18fd11b3d82b7672611b90c18a Mon Sep 17 00:00:00 2001 From: REAndroid Date: Sat, 7 Dec 2024 15:27:35 +0100 Subject: [PATCH] [DEX] Simplify KeyList usages and rework RenameTypes --- .../dex/dalvik/DalvikInnerClass.java | 5 +- .../dex/dalvik/DalvikMemberClass.java | 6 +- .../reandroid/dex/dalvik/DalvikSignature.java | 4 +- .../reandroid/dex/data/AnnotationItem.java | 12 +- .../com/reandroid/dex/data/AnnotationSet.java | 6 +- .../dex/data/AnnotationsDirectory.java | 2 +- src/main/java/com/reandroid/dex/data/Def.java | 2 +- .../com/reandroid/dex/data/EncodedArray.java | 5 +- .../dex/data/IntegerDataItemList.java | 3 +- .../reandroid/dex/data/MethodParameter.java | 2 +- .../dex/data/StaticFieldDefArray.java | 2 +- .../java/com/reandroid/dex/id/CallSiteId.java | 6 +- .../java/com/reandroid/dex/id/ClassId.java | 6 +- .../reandroid/dex/key/AnnotationItemKey.java | 82 ++----- .../reandroid/dex/key/AnnotationSetKey.java | 105 +++----- .../java/com/reandroid/dex/key/ArrayKey.java | 77 +++--- .../com/reandroid/dex/key/ArrayValueKey.java | 57 +++-- .../com/reandroid/dex/key/CallSiteKey.java | 18 +- .../reandroid/dex/key/DalvikSignatureKey.java | 20 +- .../java/com/reandroid/dex/key/KeyList.java | 169 ++++++++++--- .../java/com/reandroid/dex/key/KeyPair.java | 18 +- .../dex/key/ParameterisedProtoKey.java | 29 +-- .../dex/key/ParameterisedTypeKey.java | 9 +- .../java/com/reandroid/dex/key/ProtoKey.java | 4 +- .../dex/key/SignatureStringsBuilder.java | 2 +- .../java/com/reandroid/dex/key/TypeKey.java | 37 +-- .../com/reandroid/dex/key/TypeListKey.java | 60 +---- .../com/reandroid/dex/model/DexClass.java | 15 +- .../dex/model/DexClassRepository.java | 7 - .../com/reandroid/dex/refactor/Rename.java | 89 +++++-- .../reandroid/dex/refactor/RenameTypes.java | 224 ++++++------------ .../dex/smali/model/SmaliAnnotationSet.java | 2 +- .../reandroid/dex/smali/model/SmaliDef.java | 2 +- .../dex/smali/model/SmaliInterfaceSet.java | 2 +- .../dex/smali/model/SmaliMethodParameter.java | 2 +- .../dex/smali/model/SmaliValueArray.java | 2 +- .../java/com/reandroid/utils/CompareUtil.java | 20 +- 37 files changed, 528 insertions(+), 585 deletions(-) diff --git a/src/main/java/com/reandroid/dex/dalvik/DalvikInnerClass.java b/src/main/java/com/reandroid/dex/dalvik/DalvikInnerClass.java index d0195ab11..30304a067 100644 --- a/src/main/java/com/reandroid/dex/dalvik/DalvikInnerClass.java +++ b/src/main/java/com/reandroid/dex/dalvik/DalvikInnerClass.java @@ -39,12 +39,15 @@ public void setAccessFlags(int flags) { writeValue(Key.DALVIK_accessFlags, PrimitiveKey.of(flags)); } public String getName() { - Key key = getKey().getValue(Key.DALVIK_name); + Key key = readValue(Key.DALVIK_name); if (key instanceof StringKey) { return ((StringKey) key).getString(); } return null; } + public boolean hasName() { + return readValue(Key.DALVIK_name) instanceof StringKey; + } public void setName(String name) { Key key = name == null? NullValueKey.INSTANCE : StringKey.create(name); writeValue(Key.DALVIK_name, key); diff --git a/src/main/java/com/reandroid/dex/dalvik/DalvikMemberClass.java b/src/main/java/com/reandroid/dex/dalvik/DalvikMemberClass.java index c0f42d239..b7d63e71e 100644 --- a/src/main/java/com/reandroid/dex/dalvik/DalvikMemberClass.java +++ b/src/main/java/com/reandroid/dex/dalvik/DalvikMemberClass.java @@ -89,13 +89,13 @@ public void addSimpleName(TypeKey enclosing, String simpleName) { public ArrayValueKey getArray() { ArrayValueKey arrayValueKey = (ArrayValueKey) readValue(Key.DALVIK_value); if (arrayValueKey == null) { - arrayValueKey = ArrayValueKey.EMPTY; + arrayValueKey = ArrayValueKey.empty(); } return arrayValueKey; } public void setArray(ArrayValueKey array) { if (array == null) { - array = ArrayValueKey.EMPTY; + array = ArrayValueKey.empty(); } writeValue(Key.DALVIK_value, array); } @@ -116,7 +116,7 @@ public static DalvikMemberClass getOrCreate(AnnotatedProgram annotatedProgram) { annotatedProgram.addAnnotation(AnnotationItemKey.create( AnnotationVisibility.SYSTEM, TypeKey.DALVIK_MemberClass, - AnnotationElementKey.create(Key.DALVIK_value, ArrayValueKey.EMPTY) + AnnotationElementKey.create(Key.DALVIK_value, ArrayValueKey.empty()) ) ); } diff --git a/src/main/java/com/reandroid/dex/dalvik/DalvikSignature.java b/src/main/java/com/reandroid/dex/dalvik/DalvikSignature.java index 3cb7a25a5..92182a20f 100644 --- a/src/main/java/com/reandroid/dex/dalvik/DalvikSignature.java +++ b/src/main/java/com/reandroid/dex/dalvik/DalvikSignature.java @@ -35,7 +35,7 @@ public Iterator values() { public ArrayValueKey getArrayKey() { ArrayValueKey key = (ArrayValueKey) getKey().getValue(Key.DALVIK_value); if (key == null) { - key = ArrayValueKey.EMPTY; + key = ArrayValueKey.empty(); } return key; } @@ -76,7 +76,7 @@ public static DalvikSignature getOrCreate(AnnotatedProgram annotatedProgram) { annotatedProgram.addAnnotation(AnnotationItemKey.create( AnnotationVisibility.SYSTEM, TypeKey.DALVIK_Signature, - AnnotationElementKey.create(Key.DALVIK_value, ArrayValueKey.EMPTY) + AnnotationElementKey.create(Key.DALVIK_value, ArrayValueKey.empty()) ) ); } diff --git a/src/main/java/com/reandroid/dex/data/AnnotationItem.java b/src/main/java/com/reandroid/dex/data/AnnotationItem.java index 0e6dd0e65..f9a010ea4 100644 --- a/src/main/java/com/reandroid/dex/data/AnnotationItem.java +++ b/src/main/java/com/reandroid/dex/data/AnnotationItem.java @@ -227,9 +227,11 @@ public void setType(TypeKey typeKey){ typeId.setKey(typeKey); } - public void replaceKeys(Key search, Key replace){ - for(AnnotationElement element : this){ - element.replaceKeys(search, replace); + public void replaceKeys(Key search, Key replace) { + AnnotationItemKey itemKey = getKey(); + AnnotationItemKey update = itemKey.replaceKey(search, replace); + if (itemKey != update) { + setKey(update); } } public Iterator usedIds(){ @@ -373,9 +375,9 @@ private AnnotationItemKey getItemKey() { public AnnotationSetKey getAnnotation() { AnnotationItemKey key = getItemKey(); if (key != null) { - return AnnotationSetKey.create(new AnnotationItemKey[]{key}); + return AnnotationSetKey.of(key); } - return AnnotationSetKey.EMPTY; + return AnnotationSetKey.empty(); } @Override public void setAnnotation(AnnotationSetKey annotationSet) { diff --git a/src/main/java/com/reandroid/dex/data/AnnotationSet.java b/src/main/java/com/reandroid/dex/data/AnnotationSet.java index ff6fd8a2e..db429906a 100644 --- a/src/main/java/com/reandroid/dex/data/AnnotationSet.java +++ b/src/main/java/com/reandroid/dex/data/AnnotationSet.java @@ -64,7 +64,7 @@ public boolean isBlank() { public AnnotationSetKey getKey() { AnnotationItemKey[] elements = new AnnotationItemKey[size()]; getItemKeys(elements); - return checkKey(AnnotationSetKey.create(elements)); + return checkKey(AnnotationSetKey.of(elements)); } @Override public void setKey(Key key) { @@ -166,10 +166,10 @@ public void replaceKeys(Key search, Key replace){ } } @Override - public void refreshFull(){ + public void refreshFull() { sort(); } - public boolean sort(){ + public boolean sort() { return super.sort(CollectionUtil.getComparator()); } diff --git a/src/main/java/com/reandroid/dex/data/AnnotationsDirectory.java b/src/main/java/com/reandroid/dex/data/AnnotationsDirectory.java index 7d5e3b8a5..57faec884 100644 --- a/src/main/java/com/reandroid/dex/data/AnnotationsDirectory.java +++ b/src/main/java/com/reandroid/dex/data/AnnotationsDirectory.java @@ -90,7 +90,7 @@ public AnnotationSet getOrCreateClassAnnotations(){ public AnnotationSetKey getClassAnnotation() { AnnotationSetKey key = (AnnotationSetKey) header.classAnnotation.getKey(); if (key == null) { - key = AnnotationSetKey.EMPTY; + key = AnnotationSetKey.empty(); } return key; } diff --git a/src/main/java/com/reandroid/dex/data/Def.java b/src/main/java/com/reandroid/dex/data/Def.java index c265db7cb..f988e4fa8 100644 --- a/src/main/java/com/reandroid/dex/data/Def.java +++ b/src/main/java/com/reandroid/dex/data/Def.java @@ -69,7 +69,7 @@ public void setAnnotation(AnnotationSetKey annotationSet) { } @Override public void clearAnnotations() { - writeAnnotation(AnnotationSetKey.EMPTY); + writeAnnotation(AnnotationSetKey.empty()); } private boolean hasAnnotationSetBlocks() { return getAnnotationItemBlocks().hasNext(); diff --git a/src/main/java/com/reandroid/dex/data/EncodedArray.java b/src/main/java/com/reandroid/dex/data/EncodedArray.java index e6cc1f26b..e00df9517 100644 --- a/src/main/java/com/reandroid/dex/data/EncodedArray.java +++ b/src/main/java/com/reandroid/dex/data/EncodedArray.java @@ -20,6 +20,7 @@ import com.reandroid.arsc.io.BlockReader; import com.reandroid.dex.base.Ule128Item; import com.reandroid.dex.id.IdItem; +import com.reandroid.dex.key.ArrayKey; import com.reandroid.dex.key.ArrayValueKey; import com.reandroid.dex.key.Key; import com.reandroid.dex.key.KeyReference; @@ -57,11 +58,11 @@ public ArrayValueKey getKey() { for (int i = 0; i < size; i++) { keys[i] = get(i).getKey(); } - return checkKey(ArrayValueKey.create(keys)); + return checkKey(ArrayValueKey.of(keys)); } @Override public void setKey(Key key) { - ArrayValueKey arrayKey = (ArrayValueKey) key; + ArrayKey arrayKey = (ArrayKey) key; clear(); int size = arrayKey.size(); for (int i = 0; i < size; i++) { diff --git a/src/main/java/com/reandroid/dex/data/IntegerDataItemList.java b/src/main/java/com/reandroid/dex/data/IntegerDataItemList.java index 900437498..a120c313c 100644 --- a/src/main/java/com/reandroid/dex/data/IntegerDataItemList.java +++ b/src/main/java/com/reandroid/dex/data/IntegerDataItemList.java @@ -140,7 +140,7 @@ public boolean removeIf(Predicate filter) { return referenceList.removeIf(reference -> filter.test(reference.getItem())); } void removeNulls() { - removeIf(item -> item == null); + referenceList.removeIf(reference -> reference.getItem() == null); } @Override public Iterator iterator() { @@ -157,6 +157,7 @@ public boolean isEmpty() { return !iterator().hasNext(); } public boolean sort(Comparator comparator) { + removeNulls(); return referenceList.sort((ref1, ref2) -> comparator.compare(ref1.getItem(), ref2.getItem())); } diff --git a/src/main/java/com/reandroid/dex/data/MethodParameter.java b/src/main/java/com/reandroid/dex/data/MethodParameter.java index ec45e1c59..53f8136bf 100644 --- a/src/main/java/com/reandroid/dex/data/MethodParameter.java +++ b/src/main/java/com/reandroid/dex/data/MethodParameter.java @@ -55,7 +55,7 @@ public void setAnnotation(AnnotationSetKey annotationSet) { } @Override public void clearAnnotations() { - writeAnnotation(AnnotationSetKey.EMPTY); + writeAnnotation(AnnotationSetKey.empty()); } public void onRemoved() { diff --git a/src/main/java/com/reandroid/dex/data/StaticFieldDefArray.java b/src/main/java/com/reandroid/dex/data/StaticFieldDefArray.java index 6cd98b41a..206482c75 100644 --- a/src/main/java/com/reandroid/dex/data/StaticFieldDefArray.java +++ b/src/main/java/com/reandroid/dex/data/StaticFieldDefArray.java @@ -145,7 +145,7 @@ private ArrayValueKey buildCachedKey() { elements[i] = key; fieldDef.cachedStaticValue(null); } - return ArrayValueKey.create(elements); + return ArrayValueKey.of(elements); } private int lastCachedKeyIndex() { int result = -1; diff --git a/src/main/java/com/reandroid/dex/id/CallSiteId.java b/src/main/java/com/reandroid/dex/id/CallSiteId.java index 7164c8e3e..7bab76f30 100644 --- a/src/main/java/com/reandroid/dex/id/CallSiteId.java +++ b/src/main/java/com/reandroid/dex/id/CallSiteId.java @@ -97,13 +97,13 @@ public void setProto(ProtoKey protoKey){ setKey(getKey().changeProto(protoKey)); } } - public ArrayKey getArguments() { + public ArrayValueKey getArguments() { int size = getArgumentsSize(); Key[] results = new Key[size]; for (int i = 0; i < size; i++) { results[i] = getArgument(i); } - return ArrayKey.create(results); + return ArrayValueKey.of(results); } public Iterator> getArgumentValues() { EncodedArray encodedArray = getEncodedArray(); @@ -138,7 +138,7 @@ public int getArgumentsSize() { } return 0; } - public void setArguments(ArrayValueKey key) { + public void setArguments(ArrayKey key) { if (!key.equals(getArguments())) { setKey(getKey().changeArguments(key)); } diff --git a/src/main/java/com/reandroid/dex/id/ClassId.java b/src/main/java/com/reandroid/dex/id/ClassId.java index f59128a94..b62d2b115 100644 --- a/src/main/java/com/reandroid/dex/id/ClassId.java +++ b/src/main/java/com/reandroid/dex/id/ClassId.java @@ -101,7 +101,7 @@ public AnnotationSetKey getAnnotation() { if (directory != null) { return directory.getClassAnnotation(); } - return AnnotationSetKey.EMPTY; + return AnnotationSetKey.empty(); } @Override public void setAnnotation(AnnotationSetKey annotationSet) { @@ -110,7 +110,7 @@ public void setAnnotation(AnnotationSetKey annotationSet) { } @Override public void clearAnnotations() { - writeAnnotation(AnnotationSetKey.EMPTY); + writeAnnotation(AnnotationSetKey.empty()); } @Override public boolean hasAnnotations() { @@ -189,7 +189,7 @@ public Iterator getInstanceKeys(){ public TypeListKey getInterfacesKey() { TypeListKey typeListKey = interfaces.getKey(); if (typeListKey == null) { - typeListKey = TypeListKey.EMPTY; + typeListKey = TypeListKey.empty(); } return typeListKey; } diff --git a/src/main/java/com/reandroid/dex/key/AnnotationItemKey.java b/src/main/java/com/reandroid/dex/key/AnnotationItemKey.java index 608d7f73e..a1aed3a0a 100644 --- a/src/main/java/com/reandroid/dex/key/AnnotationItemKey.java +++ b/src/main/java/com/reandroid/dex/key/AnnotationItemKey.java @@ -24,18 +24,17 @@ import com.reandroid.utils.collection.*; import java.io.IOException; +import java.util.Comparator; import java.util.Iterator; import java.util.function.Predicate; public class AnnotationItemKey extends KeyList implements Key, Iterable { - private static final AnnotationElementKey[] EMPTY_ARRAY = new AnnotationElementKey[0]; - private final AnnotationVisibility visibility; private final TypeKey type; - private AnnotationItemKey(AnnotationVisibility visibility, TypeKey type, AnnotationElementKey[] elements) { - super(elements); + private AnnotationItemKey(AnnotationVisibility visibility, TypeKey type, Key[] elements) { + super(elements, true); this.visibility = visibility; this.type = type; } @@ -53,7 +52,7 @@ public AnnotationItemKey changeType(TypeKey typeKey) { if (typeKey.equals(getType())) { return this; } - return create(getVisibility(), typeKey, getElements()); + return createKey(getVisibility(), typeKey, getElements()); } public AnnotationItemKey remove(String name) { return removeIf(elementKey -> ObjectsUtil.equals(elementKey.getName(), name)); @@ -87,7 +86,7 @@ public AnnotationItemKey changeVisibility(AnnotationVisibility visibility) { if (ObjectsUtil.equals(getVisibility(), visibility)) { return this; } - return create(visibility, getType(), getElements()); + return createKey(visibility, getType(), getElements()); } public AnnotationElementKey get(String name) { int size = size(); @@ -152,39 +151,18 @@ public AnnotationItemKey set(int i, AnnotationElementKey item) { public AnnotationItemKey sorted() { return (AnnotationItemKey) super.sorted(); } - @Override - AnnotationItemKey newInstance(AnnotationElementKey[] elements) { - return create(getVisibility(), getType(), elements); + public AnnotationItemKey clearDuplicates() { + return (AnnotationItemKey) super.clearDuplicates(); } @Override - AnnotationElementKey[] newArray(int length) { - if (length == 0) { - return EMPTY_ARRAY; - } - return new AnnotationElementKey[length]; + public AnnotationItemKey clearDuplicates(Comparator comparator) { + return (AnnotationItemKey) super.clearDuplicates(comparator); } + @Override - AnnotationElementKey[] initializeSortedElements(AnnotationElementKey[] elements) { - if (elements == null || elements.length < 2) { - return null; - } - boolean needsSort = false; - int length = elements.length; - AnnotationElementKey previous = elements[0]; - for (int i = 1; i < length; i ++) { - AnnotationElementKey next = elements[i]; - if (CompareUtil.compare(previous, next) > 0) { - needsSort = true; - break; - } - } - if (!needsSort) { - return null; - } - elements = elements.clone(); - ArraySort.sort(elements, CompareUtil.getComparableComparator()); - return elements; + AnnotationItemKey newInstance(Key[] elements) { + return createKey(getVisibility(), getType(), elements); } public SmaliDirective getSmaliDirective() { @@ -265,11 +243,13 @@ public int hashCode() { } public static AnnotationItemKey create(AnnotationVisibility visibility, TypeKey typeKey, AnnotationElementKey ... elements) { + return createKey(visibility, typeKey, elements); + } + public static AnnotationItemKey createKey(AnnotationVisibility visibility, TypeKey typeKey, Key[] elements) { if (typeKey == null) { return null; } - elements = removeNulls(elements); - return new AnnotationItemKey(visibility, typeKey, elements); + return new AnnotationItemKey(visibility, typeKey, removeNulls(elements)); } public static AnnotationItemKey read(SmaliReader reader) throws IOException { @@ -280,34 +260,4 @@ public static AnnotationItemKey parse(String text) { //FIXME throw new RuntimeException("AnnotationItemKey.parse not implemented"); } - - private static AnnotationElementKey[] removeNulls(AnnotationElementKey[] elements) { - if (elements == null || elements.length == 0) { - return EMPTY_ARRAY; - } - int length = elements.length; - int size = 0; - for (int i = 0; i < length; i ++) { - AnnotationElementKey key = elements[i]; - if (key != null) { - size ++; - } - } - if (size == length) { - return elements; - } - if (size == 0) { - return EMPTY_ARRAY; - } - AnnotationElementKey[] results = new AnnotationElementKey[size]; - int j = 0; - for (int i = 0; i < length; i ++) { - AnnotationElementKey key = elements[i]; - if (key != null) { - results[j] = key; - j ++; - } - } - return results; - } } diff --git a/src/main/java/com/reandroid/dex/key/AnnotationSetKey.java b/src/main/java/com/reandroid/dex/key/AnnotationSetKey.java index decf7962b..71ef6e798 100644 --- a/src/main/java/com/reandroid/dex/key/AnnotationSetKey.java +++ b/src/main/java/com/reandroid/dex/key/AnnotationSetKey.java @@ -17,29 +17,21 @@ import com.reandroid.dex.common.AnnotationVisibility; import com.reandroid.dex.smali.SmaliWriter; -import com.reandroid.utils.CompareUtil; import com.reandroid.utils.ObjectsUtil; import com.reandroid.utils.collection.ArrayCollection; -import com.reandroid.utils.collection.ArraySort; import com.reandroid.utils.collection.ComputeIterator; import java.io.IOException; +import java.util.Comparator; import java.util.Iterator; import java.util.function.Predicate; -public class AnnotationSetKey extends KeyList implements Key { +public class AnnotationSetKey extends KeyList { - private static final AnnotationItemKey[] EMPTY_ARRAY; - public static final AnnotationSetKey EMPTY; + private static final AnnotationSetKey EMPTY = new AnnotationSetKey(EMPTY_ARRAY); - static { - AnnotationItemKey[] emptyArray = new AnnotationItemKey[0]; - EMPTY_ARRAY = emptyArray; - EMPTY = new AnnotationSetKey(emptyArray); - } - - private AnnotationSetKey(AnnotationItemKey[] elements) { - super(elements); + private AnnotationSetKey(Key[] elements) { + super(elements, true); } public Iterator getTypes() { @@ -188,39 +180,18 @@ public AnnotationSetKey set(int i, AnnotationItemKey item) { public AnnotationSetKey sorted() { return (AnnotationSetKey) super.sorted(); } - @Override - AnnotationSetKey newInstance(AnnotationItemKey[] elements) { - return create(elements); + public AnnotationSetKey clearDuplicates() { + return (AnnotationSetKey) super.clearDuplicates(); } @Override - AnnotationItemKey[] newArray(int length) { - if (length == 0) { - return EMPTY_ARRAY; - } - return new AnnotationItemKey[length]; + public AnnotationSetKey clearDuplicates(Comparator comparator) { + return (AnnotationSetKey) super.clearDuplicates(comparator); } + @Override - AnnotationItemKey[] initializeSortedElements(AnnotationItemKey[] elements) { - if (elements == null || elements.length < 2) { - return null; - } - boolean needsSort = false; - int length = elements.length; - AnnotationItemKey previous = elements[0]; - for (int i = 1; i < length; i ++) { - AnnotationItemKey next = elements[i]; - if (CompareUtil.compare(previous, next) > 0) { - needsSort = true; - break; - } - } - if (!needsSort) { - return null; - } - elements = elements.clone(); - ArraySort.sort(elements, CompareUtil.getComparableComparator()); - return elements; + AnnotationSetKey newInstance(Key[] elements) { + return createKey(elements); } @Override @@ -262,13 +233,19 @@ public int hashCode() { return getHashCode(); } - public static AnnotationSetKey create(AnnotationItemKey[] elements) { + public static AnnotationSetKey empty() { + return EMPTY; + } + public static AnnotationSetKey of(AnnotationItemKey ... elements) { + return createKey(elements); + } + private static AnnotationSetKey createKey(Key[] elements) { if (elements == null || elements.length == 0) { - return EMPTY; + return empty(); } elements = removeNulls(elements); if (elements.length == 0) { - return EMPTY; + return empty(); } return new AnnotationSetKey(elements); } @@ -282,9 +259,9 @@ public static AnnotationSetKey create(Iterator iterator) { elements.add(key); } if (elements == null) { - return create((AnnotationItemKey[]) null); + return empty(); } - return create(elements.toArrayFill(new AnnotationItemKey[elements.size()])); + return createKey(elements.toArrayFill(new Key[elements.size()])); } public static AnnotationSetKey combined(Iterator iterator) { ArrayCollection elements = null; @@ -292,43 +269,17 @@ public static AnnotationSetKey combined(Iterator iterator) { AnnotationSetKey key = iterator.next(); if (!key.isEmpty()) { if (elements == null) { + if (!iterator.hasNext()) { + return key; + } elements = new ArrayCollection<>(); } elements.addAll(key.iterator()); } } if (elements == null) { - return create((AnnotationItemKey[]) null); - } - return create(elements.toArrayFill(new AnnotationItemKey[elements.size()])); - } - private static AnnotationItemKey[] removeNulls(AnnotationItemKey[] elements) { - if (elements == null || elements.length == 0) { - return EMPTY_ARRAY; - } - int length = elements.length; - int size = 0; - for (int i = 0; i < length; i ++) { - AnnotationItemKey key = elements[i]; - if (key != null) { - size ++; - } - } - if (size == length) { - return elements; - } - if (size == 0) { - return EMPTY_ARRAY; - } - AnnotationItemKey[] results = new AnnotationItemKey[size]; - int j = 0; - for (int i = 0; i < length; i ++) { - AnnotationItemKey key = elements[i]; - if (key != null) { - results[j] = key; - j ++; - } + return empty(); } - return results; + return createKey(elements.toArrayFill(new Key[elements.size()])); } } diff --git a/src/main/java/com/reandroid/dex/key/ArrayKey.java b/src/main/java/com/reandroid/dex/key/ArrayKey.java index 77b9d2c85..096d9108e 100644 --- a/src/main/java/com/reandroid/dex/key/ArrayKey.java +++ b/src/main/java/com/reandroid/dex/key/ArrayKey.java @@ -28,57 +28,50 @@ import java.util.Comparator; import java.util.function.Predicate; -public class ArrayKey extends KeyList { +public class ArrayKey extends KeyList { - public static final ArrayKey EMPTY; - static final Key[] EMPTY_ARRAY; + private static final ArrayKey EMPTY = new ArrayKey<>(EMPTY_ARRAY); - static { - Key[] emptyArray = new Key[0]; - EMPTY_ARRAY = emptyArray; - EMPTY = new ArrayKey(emptyArray); - } - - ArrayKey(Key[] elements) { + protected ArrayKey(Key[] elements) { super(elements); } - @Override - public ArrayKey add(Key item) { - return (ArrayKey) super.add(item); + public ArrayKey add(T item) { + return (ArrayKey) super.add(item); } @Override - public ArrayKey remove(Key itemKey) { - return (ArrayKey) super.remove(itemKey); + public ArrayKey remove(T itemKey) { + return (ArrayKey) super.remove(itemKey); } @Override - public ArrayKey remove(int index) { - return (ArrayKey) super.remove(index); + public ArrayKey remove(int index) { + return (ArrayKey) super.remove(index); } @Override - public ArrayKey removeIf(Predicate predicate) { - return (ArrayKey) super.removeIf(predicate); + public ArrayKey removeIf(Predicate predicate) { + return (ArrayKey) super.removeIf(predicate); } @Override - public ArrayKey set(int i, Key item) { - return (ArrayKey) super.set(i, item); + public ArrayKey set(int i, T item) { + return (ArrayKey) super.set(i, item); } @Override - public ArrayKey sort(Comparator comparator) { - return (ArrayKey) super.sort(comparator); + public ArrayKey sort(Comparator comparator) { + return (ArrayKey) super.sort(comparator); } - @Override - ArrayKey newInstance(Key[] elements) { - return create(elements); + public ArrayKey clearDuplicates() { + return (ArrayKey) super.clearDuplicates(); } @Override - Key[] newArray(int length) { - if (length == 0) { - return EMPTY_ARRAY; - } - return new Key[length]; + public ArrayKey clearDuplicates(Comparator comparator) { + return (ArrayKey) super.clearDuplicates(comparator); + } + + @Override + ArrayKey newInstance(Key[] elements) { + return create(elements); } @Override @@ -121,8 +114,8 @@ public String toString(String separator) { } @Override - public ArrayKey replaceKey(Key search, Key replace) { - return (ArrayKey) super.replaceKey(search, replace); + public ArrayKey replaceKey(Key search, Key replace) { + return (ArrayKey) super.replaceKey(search, replace); } @Override @@ -133,7 +126,7 @@ public int compareTo(Object obj) { if (!(obj instanceof ArrayKey)) { return StringsUtil.compareToString(this, obj); } - return compareElements((ArrayKey) obj); + return compareElements((ArrayKey) obj); } @Override @@ -149,16 +142,20 @@ public boolean equals(Object obj) { if (!(obj instanceof ArrayKey)) { return false; } - return equalsElements((ArrayKey) obj); + return equalsElements((ArrayKey) obj); } - public static ArrayKey create(Key ... elements) { + @SuppressWarnings("unchecked") + public static ArrayKey empty() { + return (ArrayKey) EMPTY; + } + public static ArrayKey create(Key ... elements) { if (elements == null || elements.length == 0) { - return EMPTY; + return empty(); } - return new ArrayKey(elements); + return new ArrayKey<>(elements); } - public static ArrayKey read(SmaliReader reader, char end) throws IOException { + public static ArrayKey read(SmaliReader reader, char end) throws IOException { return create(readElements(reader, end)); } public static Key[] readElements(SmaliReader reader, char end) throws IOException { @@ -240,7 +237,7 @@ private static Key readNext(SmaliReader reader) throws IOException { throw new SmaliParseException("Unexpected value ", reader); } - public static ArrayKey parse(String text) { + public static ArrayKey parse(String text) { //FIXME throw new RuntimeException("ArrayKey.parse not implemented"); } diff --git a/src/main/java/com/reandroid/dex/key/ArrayValueKey.java b/src/main/java/com/reandroid/dex/key/ArrayValueKey.java index 69aaed066..d69689b89 100644 --- a/src/main/java/com/reandroid/dex/key/ArrayValueKey.java +++ b/src/main/java/com/reandroid/dex/key/ArrayValueKey.java @@ -25,9 +25,9 @@ import java.util.Iterator; import java.util.function.Predicate; -public class ArrayValueKey extends ArrayKey { +public class ArrayValueKey extends ArrayKey { - public static final ArrayValueKey EMPTY; + private static final ArrayValueKey EMPTY; static { EMPTY = new ArrayValueKey(EMPTY_ARRAY); @@ -131,17 +131,23 @@ public ArrayValueKey set(int i, Key item) { public ArrayValueKey sort(Comparator comparator) { return (ArrayValueKey) super.sort(comparator); } + @Override + public ArrayValueKey clearDuplicates() { + return (ArrayValueKey) super.clearDuplicates(); + } + @Override + public ArrayValueKey clearDuplicates(Comparator comparator) { + return (ArrayValueKey) super.clearDuplicates(comparator); + } @Override - ArrayValueKey newInstance(Key[] elements) { - return create(elements); + public ArrayValueKey replaceKey(Key search, Key replace) { + return (ArrayValueKey) super.replaceKey(search, replace); } + @Override - Key[] newArray(int length) { - if (length == 0) { - return EMPTY_ARRAY; - } - return new Key[length]; + ArrayValueKey newInstance(Key[] elements) { + return of(elements); } @Override @@ -170,25 +176,28 @@ public String toString() { } - public static ArrayValueKey create(Key ... elements) { + public static ArrayValueKey empty() { + return EMPTY; + } + public static ArrayValueKey of(Key ... elements) { if (elements == null || elements.length == 0) { - return EMPTY; + return empty(); } return new ArrayValueKey(elements); } - public static ArrayValueKey create(ArrayKey arrayKey) { + public static ArrayValueKey create(ArrayKey arrayKey) { if (arrayKey instanceof ArrayValueKey) { return (ArrayValueKey) arrayKey; } if (arrayKey.isEmpty()) { - return EMPTY; + return empty(); } - return create(arrayKey.getElements()); + return of(arrayKey.getElements()); } public static ArrayValueKey read(SmaliReader reader) throws IOException { SmaliParseException.expect(reader, '{'); - return create(readElements(reader, '}')); + return of(readElements(reader, '}')); } public static ArrayValueKey parse(String text) { @@ -197,30 +206,30 @@ public static ArrayValueKey parse(String text) { } public static ArrayValueKey of(String[] values) { - return create(ArrayKeyHelper.toStringKeys(values)); + return of(ArrayKeyHelper.toStringKeys(values)); } public static ArrayValueKey of(byte[] values) { - return create(ArrayKeyHelper.toPrimitiveKeys(values)); + return of(ArrayKeyHelper.toPrimitiveKeys(values)); } public static ArrayValueKey of(short[] values) { - return create(ArrayKeyHelper.toPrimitiveKeys(values)); + return of(ArrayKeyHelper.toPrimitiveKeys(values)); } public static ArrayValueKey of(int[] values) { - return create(ArrayKeyHelper.toPrimitiveKeys(values)); + return of(ArrayKeyHelper.toPrimitiveKeys(values)); } public static ArrayValueKey of(long[] values) { - return create(ArrayKeyHelper.toPrimitiveKeys(values)); + return of(ArrayKeyHelper.toPrimitiveKeys(values)); } public static ArrayValueKey of(float[] values) { - return create(ArrayKeyHelper.toPrimitiveKeys(values)); + return of(ArrayKeyHelper.toPrimitiveKeys(values)); } public static ArrayValueKey of(double[] values) { - return create(ArrayKeyHelper.toPrimitiveKeys(values)); + return of(ArrayKeyHelper.toPrimitiveKeys(values)); } public static ArrayValueKey of(char[] values) { - return create(ArrayKeyHelper.toPrimitiveKeys(values)); + return of(ArrayKeyHelper.toPrimitiveKeys(values)); } public static ArrayValueKey of(boolean[] values) { - return create(ArrayKeyHelper.toPrimitiveKeys(values)); + return of(ArrayKeyHelper.toPrimitiveKeys(values)); } } diff --git a/src/main/java/com/reandroid/dex/key/CallSiteKey.java b/src/main/java/com/reandroid/dex/key/CallSiteKey.java index 651b0fefe..cb5bfd5d1 100644 --- a/src/main/java/com/reandroid/dex/key/CallSiteKey.java +++ b/src/main/java/com/reandroid/dex/key/CallSiteKey.java @@ -30,9 +30,9 @@ public class CallSiteKey implements Key { private final MethodHandleKey methodHandle; private final StringKey name; private final ProtoKey proto; - private final ArrayKey arguments; + private final ArrayKey arguments; - public CallSiteKey(MethodHandleKey methodHandle, StringKey name, ProtoKey proto, ArrayKey arguments) { + public CallSiteKey(MethodHandleKey methodHandle, StringKey name, ProtoKey proto, ArrayKey arguments) { this.methodHandle = methodHandle; this.name = name; this.proto = proto; @@ -48,11 +48,11 @@ public StringKey getName() { public ProtoKey getProto() { return proto; } - public ArrayKey getArguments() { + public ArrayKey getArguments() { return arguments; } - public ArrayKey toArrayKey() { - ArrayKey arguments = getArguments(); + public ArrayKey toArrayKey() { + ArrayKey arguments = getArguments(); int argumentsLength = arguments.size(); Key[] elements = new Key[3 + arguments.size()]; elements[0] = getMethodHandle(); @@ -81,7 +81,7 @@ public CallSiteKey changeProto(ProtoKey proto) { } return new CallSiteKey(getMethodHandle(), getName(), proto, getArguments()); } - public CallSiteKey changeArguments(ArrayValueKey arguments) { + public CallSiteKey changeArguments(ArrayKey arguments) { if (arguments.equals(getArguments())) { return this; } @@ -94,7 +94,7 @@ public void append(SmaliWriter writer) throws IOException { getName().append(writer); writer.append(", "); getProto().append(writer); - ArrayKey arguments = getArguments(); + ArrayKey arguments = getArguments(); int size = arguments.size(); for (int i = 0; i < size; i++) { if (i != 0) { @@ -156,7 +156,7 @@ public String toString() { builder.append(getName()); builder.append(", "); builder.append(getProto()); - ArrayKey arguments = getArguments(); + ArrayKey arguments = getArguments(); if (!arguments.isEmpty()) { builder.append(", "); builder.append(arguments.toString(", ")); @@ -182,7 +182,7 @@ public static CallSiteKey read(SmaliReader reader) throws IOException { ProtoKey protoKey = ProtoKey.read(reader); reader.skipWhitespacesOrComment(); SmaliParseException.expect(reader, ','); - ArrayKey arguments = ArrayKey.read(reader, ')'); + ArrayKey arguments = ArrayKey.read(reader, ')'); reader.skipWhitespacesOrComment(); SmaliParseException.expect(reader, '@'); MethodHandleKey methodHandleKey = MethodHandleKey.read(MethodHandleType.INVOKE_STATIC, reader); diff --git a/src/main/java/com/reandroid/dex/key/DalvikSignatureKey.java b/src/main/java/com/reandroid/dex/key/DalvikSignatureKey.java index 2bc71b72a..25195daa4 100644 --- a/src/main/java/com/reandroid/dex/key/DalvikSignatureKey.java +++ b/src/main/java/com/reandroid/dex/key/DalvikSignatureKey.java @@ -28,26 +28,26 @@ public class DalvikSignatureKey implements Key { - private final ArrayKey elements; + private final ArrayKey elements; - private DalvikSignatureKey(ArrayKey elements) { + private DalvikSignatureKey(ArrayKey elements) { this.elements = elements; } public Iterator iterator() { - return ObjectsUtil.cast(getElements().iterator()); + return getElements().iterator(); } public int size() { return getElements().size(); } public ParameterisedTypeKey get(int i) { - return (ParameterisedTypeKey) getElements().get(i); + return getElements().get(i); } - private ArrayKey getElements() { + private ArrayKey getElements() { return elements; } - private DalvikSignatureKey changeElements(ArrayKey elements) { + private DalvikSignatureKey changeElements(ArrayKey elements) { if (getElements().equals(elements)) { return this; } @@ -65,10 +65,10 @@ public Iterator iterator(ParameterisedTypeKey element) { public ArrayValueKey toStringValues() { SignatureStringsBuilder builder = new SignatureStringsBuilder(); - ArrayKey elements = getElements(); + ArrayKey elements = getElements(); int size = elements.size(); for (int i = 0; i < size; i++) { - ParameterisedTypeKey key = (ParameterisedTypeKey) elements.get(i); + ParameterisedTypeKey key = elements.get(i); key.buildSignature(builder); } builder.flush(); @@ -80,7 +80,7 @@ public DalvikSignatureKey replaceKey(Key search, Key replace) { if (search.equals(this)) { return (DalvikSignatureKey) replace; } - ArrayKey arrayKey = getElements(); + ArrayKey arrayKey = getElements(); arrayKey = arrayKey.replaceKey(search, replace); return changeElements(arrayKey); } @@ -127,7 +127,7 @@ public int hashCode() { @Override public String toString() { StringBuilder builder = new StringBuilder(); - ArrayKey elements = getElements(); + ArrayKey elements = getElements(); int size = elements.size(); for (int i = 0; i < size; i ++) { ((ParameterisedTypeKey) elements.get(i)).appendString(builder); diff --git a/src/main/java/com/reandroid/dex/key/KeyList.java b/src/main/java/com/reandroid/dex/key/KeyList.java index 0fabd9e45..075b809d2 100644 --- a/src/main/java/com/reandroid/dex/key/KeyList.java +++ b/src/main/java/com/reandroid/dex/key/KeyList.java @@ -27,17 +27,23 @@ public abstract class KeyList implements Key, Iterable { - private final T[] elements; - private final T[] sortedElements; + static final Key[] EMPTY_ARRAY = new Key[0]; + + private final Key[] elements; + private final Key[] sortedElements; private int mHash; - public KeyList(T[] elements) { + public KeyList(Key[] elements, boolean sorted) { this.elements = elements; - this.sortedElements = initializeSortedElements(elements); + this.sortedElements = sorted ? sortElements(elements) : null; + } + public KeyList(Key[] elements) { + this(elements, false); } + @SuppressWarnings("unchecked") public T get(int i) { - return elements[i]; + return (T) elements[i]; } public int size() { return elements.length; @@ -57,7 +63,7 @@ public Iterator iterator(Class instance) { } public int indexOf(Object key) { - T[] elements = this.elements; + Key[] elements = this.elements; int length = elements.length; for (int i = 0; i < length; i++) { if (ObjectsUtil.equals(elements[i], key)) { @@ -67,7 +73,7 @@ public int indexOf(Object key) { return -1; } public boolean contains(Object item) { - T[] elements = this.elements; + Key[] elements = this.elements; int length = elements.length; for (int i = 0; i < length; i++) { if (ObjectsUtil.equals(elements[i], item)) { @@ -80,14 +86,14 @@ public KeyList set(int i, T item) { if (ObjectsUtil.equals(item, get(i))) { return this; } - T[] elements = this.elements.clone(); + Key[] elements = this.elements.clone(); elements[i] = item; return newInstance(elements); } public KeyList add(T item) { - T[] elements = this.elements; + Key[] elements = this.elements; int length = elements.length; - T[] result = newArray(length + 1); + Key[] result = newArray(length + 1); for (int i = 0; i < length; i++) { result[i] = elements[i]; } @@ -101,7 +107,7 @@ public KeyList remove(int index) { if (index < 0) { return this; } - T[] elements = this.elements; + Key[] elements = this.elements; int length = elements.length; if (index >= length) { return this; @@ -109,7 +115,7 @@ public KeyList remove(int index) { if (length == 1) { return newInstance(newArray(0)); } - T[] result = newArray(length - 1); + Key[] result = newArray(length - 1); int j = 0; for (int i = 0; i < length; i++) { if (i != index) { @@ -119,16 +125,17 @@ public KeyList remove(int index) { } return newInstance(result); } + @SuppressWarnings("unchecked") public KeyList removeIf(Predicate predicate) { - T[] elements = this.elements; + Key[] elements = this.elements; int length = elements.length; if (length == 0) { return this; } - T[] filtered = null; + Key[] filtered = null; int j = 0; for (int i = 0; i < length; i++) { - T item = elements[i]; + T item = (T) elements[i]; if (predicate.test(item)) { if (filtered == null) { filtered = elements.clone(); @@ -142,7 +149,7 @@ public KeyList removeIf(Predicate predicate) { if (filtered == null) { return this; } - T[] result = newArray(j); + Key[] result = newArray(j); length = result.length; for (int i = 0; i < length; i++) { result[i] = filtered[i]; @@ -150,39 +157,73 @@ public KeyList removeIf(Predicate predicate) { return newInstance(result); } + @SuppressWarnings("unchecked") public T getDuplicate() { - T[] elements = getSortedElements(); + Key[] elements = getSortedElements(); int length = elements.length; if (length < 2) { return null; } - T last = elements[0]; + Key last = elements[0]; for (int i = 1; i < length; i++) { - T element = elements[i]; + Key element = elements[i]; if (ObjectsUtil.equals(last, element)) { - return element; + return (T) element; } last = element; } return null; } + public KeyList clearDuplicates() { + return clearDuplicates(CompareUtil.getComparableComparator()); + } + public KeyList clearDuplicates(Comparator comparator) { + Key[] elements = getSortedElements(); + if (elements.length < 2) { + return this; + } + elements = sortElements(elements, comparator); + if (elements == null) { + elements = getSortedElements(); + } + Comparator c = ObjectsUtil.cast(comparator); + int length = elements.length; + Key previous = elements[0]; + Key[] results = null; + for (int i = 1; i < length; i++) { + Key element = elements[i]; + if (c.compare(previous, element) == 0) { + if (results == null) { + results = elements.clone(); + } + results[i] = null; + } + previous = element; + } + if (results == null) { + return this; + } + results = removeNulls(results); + return newInstance(results); + } public KeyList sorted() { - T[] elements = this.sortedElements; + Key[] elements = this.sortedElements; if (elements == null) { return this; } return newInstance(elements); } + @SuppressWarnings("unchecked") public KeyList sort(Comparator comparator) { - T[] elements = this.elements; + Key[] elements = this.elements; int length = elements.length; if (length < 2) { return this; } boolean sortRequired = false; - T previous = elements[0]; + T previous = (T) elements[0]; for (int i = 1; i < length; i++) { - T item = elements[i]; + T item = (T) elements[i]; if (comparator.compare(previous, item) > 0) { sortRequired = true; break; @@ -196,22 +237,24 @@ public KeyList sort(Comparator comparator) { ArraySort.sort(elements, comparator); return newInstance(elements); } - private T[] getSortedElements() { - T[] elements = this.sortedElements; + private Key[] getSortedElements() { + Key[] elements = this.sortedElements; if (elements == null) { elements = this.elements; } return elements; } - T[] initializeSortedElements(T[] elements) { - return null; - } - T[] getElements() { + Key[] getElements() { return elements; } - abstract KeyList newInstance(T[] elements); - abstract T[] newArray(int length); + abstract KeyList newInstance(Key[] elements); + private Key[] newArray(int length) { + if (length == 0) { + return EMPTY_ARRAY; + } + return new Key[length]; + } @SuppressWarnings("unchecked") @Override @@ -254,10 +297,10 @@ public void append(SmaliWriter writer) throws IOException { } - int compareElements(KeyList keyList) { + int compareElements(KeyList keyList) { return CompareUtil.compare(getSortedElements(), keyList.getSortedElements()); } - boolean equalsElements(KeyList keyList) { + boolean equalsElements(KeyList keyList) { return ObjectsUtil.equalsArray(this.getSortedElements(), keyList.getSortedElements()); } int getHashCode() { @@ -293,4 +336,62 @@ public static boolean equalsIgnoreEmpty(KeyList key1, KeyLis } return key1.equalsElements(key2); } + + private static T[] sortElements(T[] elements) { + return sortElements(elements, CompareUtil.getComparableComparator()); + } + + private static T[] sortElements(T[] elements, Comparator comparator) { + if (elements == null || elements.length < 2) { + return null; + } + boolean needsSort = false; + int length = elements.length; + Key previous = elements[0]; + Comparator c = ObjectsUtil.cast(comparator); + for (int i = 1; i < length; i ++) { + Key next = elements[i]; + if (c.compare(previous, next) > 0) { + needsSort = true; + break; + } + previous = next; + } + if (!needsSort) { + return null; + } + elements = elements.clone(); + ArraySort.sort(elements, c); + return elements; + } + + static Key[] removeNulls(Key[] elements) { + if (elements == null || elements.length == 0) { + return EMPTY_ARRAY; + } + int length = elements.length; + int size = 0; + for (int i = 0; i < length; i ++) { + Key key = elements[i]; + if (key != null) { + size ++; + } + } + if (size == length) { + return elements; + } + if (size == 0) { + return EMPTY_ARRAY; + } + Key[] results = new Key[size]; + int j = 0; + for (int i = 0; i < length; i ++) { + Key key = elements[i]; + if (key != null) { + results[j] = key; + j ++; + } + } + return results; + } } diff --git a/src/main/java/com/reandroid/dex/key/KeyPair.java b/src/main/java/com/reandroid/dex/key/KeyPair.java index 05baeb358..5c79240a5 100644 --- a/src/main/java/com/reandroid/dex/key/KeyPair.java +++ b/src/main/java/com/reandroid/dex/key/KeyPair.java @@ -16,13 +16,13 @@ package com.reandroid.dex.key; import com.reandroid.utils.CompareUtil; +import com.reandroid.utils.ObjectsUtil; import com.reandroid.utils.collection.ArrayCollection; import com.reandroid.utils.collection.ComputeIterator; import java.util.Collection; import java.util.Iterator; import java.util.List; -import java.util.Objects; public class KeyPair implements Comparable>{ @@ -90,6 +90,14 @@ public int compareTo(KeyPair pair) { } return i; } + + public boolean equalsBoth(KeyPair keyPair) { + if (this == keyPair) { + return true; + } + return ObjectsUtil.equals(getFirst(), keyPair.getFirst()) && + ObjectsUtil.equals(getSecond(), keyPair.getSecond()); + } @Override public boolean equals(Object obj) { if (this == obj) { @@ -99,16 +107,12 @@ public boolean equals(Object obj) { return false; } KeyPair keyPair = (KeyPair) obj; - return Objects.equals(getFirst(), keyPair.getFirst()); + return ObjectsUtil.equals(getFirst(), keyPair.getFirst()); } @Override public int hashCode() { - T1 first = getFirst(); - if(first != null){ - return first.hashCode(); - } - return 0; + return ObjectsUtil.hash(getFirst()); } @Override public String toString() { diff --git a/src/main/java/com/reandroid/dex/key/ParameterisedProtoKey.java b/src/main/java/com/reandroid/dex/key/ParameterisedProtoKey.java index 2955a2c5b..7a6a54048 100644 --- a/src/main/java/com/reandroid/dex/key/ParameterisedProtoKey.java +++ b/src/main/java/com/reandroid/dex/key/ParameterisedProtoKey.java @@ -25,22 +25,17 @@ import java.io.IOException; import java.util.Iterator; -public class ParameterisedProtoKey extends KeyList { +public class ParameterisedProtoKey extends ArrayKey { - private static final ParameterisedTypeKey[] EMPTY_ARRAY; - public static final ParameterisedProtoKey EMPTY; + public static final ParameterisedProtoKey EMPTY = new ParameterisedProtoKey( + false, null, EMPTY_ARRAY); - static { - ParameterisedTypeKey[] emptyArray = new ParameterisedTypeKey[0]; - EMPTY_ARRAY = emptyArray; - EMPTY = new ParameterisedProtoKey(false,null, emptyArray); - } private final boolean method; private final ParameterisedTypeKey returnType; private ParameterisedProtoKey(boolean method, ParameterisedTypeKey returnType, - ParameterisedTypeKey[] elements) { + Key[] elements) { super(elements); this.method = method; this.returnType = returnType; @@ -175,7 +170,7 @@ public String toString() { } @Override - ParameterisedProtoKey newInstance(ParameterisedTypeKey[] elements) { + ParameterisedProtoKey newInstance(Key[] elements) { boolean method = isMethod(); ParameterisedTypeKey returnType = getReturnType(); if (elements.length == 0) { @@ -187,15 +182,7 @@ ParameterisedProtoKey newInstance(ParameterisedTypeKey[] elements) { return new ParameterisedProtoKey(method, returnType, elements); } - @Override - ParameterisedTypeKey[] newArray(int length) { - if (length == 0) { - return EMPTY_ARRAY; - } - return new ParameterisedTypeKey[length]; - } - - public static ParameterisedProtoKey create(boolean method, ParameterisedTypeKey returnType, ParameterisedTypeKey[] elements) { + public static ParameterisedProtoKey create(boolean method, ParameterisedTypeKey returnType, Key[] elements) { if (elements == null || elements.length == 0) { if (returnType == null) { return EMPTY; @@ -226,9 +213,9 @@ public static ParameterisedProtoKey read(SmaliReader reader) throws IOException } else { returnType = null; } - ParameterisedTypeKey[] elements; + Key[] elements; if (results != null) { - elements = results.toArrayFill(new ParameterisedTypeKey[results.size()]); + elements = results.toArrayFill(new Key[results.size()]); } else { elements = null; } diff --git a/src/main/java/com/reandroid/dex/key/ParameterisedTypeKey.java b/src/main/java/com/reandroid/dex/key/ParameterisedTypeKey.java index ea582d0db..a693a2803 100644 --- a/src/main/java/com/reandroid/dex/key/ParameterisedTypeKey.java +++ b/src/main/java/com/reandroid/dex/key/ParameterisedTypeKey.java @@ -22,6 +22,7 @@ import com.reandroid.utils.ObjectsUtil; import com.reandroid.utils.StringsUtil; import com.reandroid.utils.collection.CombiningIterator; +import com.reandroid.utils.collection.IterableIterator; import com.reandroid.utils.collection.SingleIterator; import java.io.IOException; @@ -135,9 +136,15 @@ private ParameterisedTypeKey changeInnerKey(TypeKey innerKey) { } public Iterator getTypes() { - return CombiningIterator.singleTwo(getInnerClassKey(), + Iterator iterator = CombiningIterator.singleTwo(getInnerClassKey(), getProtoKey().getTypes(), SingleIterator.of(getNameTypeKey())); + return new IterableIterator(iterator) { + @Override + public Iterator iterator(TypeKey element) { + return element.mentionedKeys(); + } + }; } void buildSignature(SignatureStringsBuilder builder) { diff --git a/src/main/java/com/reandroid/dex/key/ProtoKey.java b/src/main/java/com/reandroid/dex/key/ProtoKey.java index 227b2ea28..d767d892e 100644 --- a/src/main/java/com/reandroid/dex/key/ProtoKey.java +++ b/src/main/java/com/reandroid/dex/key/ProtoKey.java @@ -206,12 +206,12 @@ public static ProtoKey create(TypeListKey typeListKey, TypeKey returnType){ return null; } if (typeListKey == null) { - typeListKey = TypeListKey.EMPTY; + typeListKey = TypeListKey.empty(); } return new ProtoKey(typeListKey, returnType); } public static ProtoKey emptyParameters(TypeKey returnType) { - return create(TypeListKey.EMPTY, returnType); + return create(TypeListKey.empty(), returnType); } public static ProtoKey parse(String text) { diff --git a/src/main/java/com/reandroid/dex/key/SignatureStringsBuilder.java b/src/main/java/com/reandroid/dex/key/SignatureStringsBuilder.java index e2f660e0b..755e04809 100644 --- a/src/main/java/com/reandroid/dex/key/SignatureStringsBuilder.java +++ b/src/main/java/com/reandroid/dex/key/SignatureStringsBuilder.java @@ -30,7 +30,7 @@ public SignatureStringsBuilder() { public ArrayValueKey build() { ArrayCollection results = this.results; - return ArrayValueKey.create(results.toArrayFill(new Key[results.size()])); + return ArrayValueKey.of(results.toArrayFill(new Key[results.size()])); } public void append(char c) { this.stringBuilder.append(c); diff --git a/src/main/java/com/reandroid/dex/key/TypeKey.java b/src/main/java/com/reandroid/dex/key/TypeKey.java index 6df8cedaf..3a7823b14 100644 --- a/src/main/java/com/reandroid/dex/key/TypeKey.java +++ b/src/main/java/com/reandroid/dex/key/TypeKey.java @@ -116,9 +116,7 @@ public String getArrayType(int dimension){ public int getArrayDimension(){ return DexUtils.countArrayPrefix(getTypeName()); } - public boolean isTypeSignature(){ - return DexUtils.isTypeSignature(getTypeName()); - } + public boolean isTypeArray(){ String name = getTypeName(); return name.length() > 1 && name.charAt(0) == '['; @@ -143,11 +141,16 @@ public String getSimpleName() { } return simpleName; } - public String getSimpleInnerName(){ - return DexUtils.getSimpleInnerName(getTypeName()); + public String getSimpleInnerName() { + String simple = getSimpleName(); + int i = simple.lastIndexOf('$'); + if (i > 0 && i < simple.length() - 1) { + return simple.substring(i + 1); + } + return null; } - public boolean isInnerName(){ - return !getSimpleName().equals(getSimpleInnerName()); + public boolean isInnerName() { + return getSimpleInnerName() != null; } public String getPackageName() { return DexUtils.getPackageName(getTypeName()); @@ -241,7 +244,12 @@ public Iterator iteratePackageNames(){ String name = packageName; @Override public boolean hasNext() { - return name.charAt(name.length() - 1) == '/'; + String name = this.name; + int i = name.length(); + if (i == 0) { + return false; + } + return name.charAt(i - 1) == '/'; } @Override public String next() { @@ -280,7 +288,10 @@ public int compareInnerFirst(TypeKey other) { return CompareUtil.compare(name1, name2); } public boolean equalsPackage(TypeKey typeKey) { - if(typeKey == null) { + if (typeKey == this) { + return true; + } + if (typeKey == null) { return false; } String name1 = StringsUtil.trimStart(getTypeName(), '['); @@ -288,7 +299,7 @@ public boolean equalsPackage(TypeKey typeKey) { if(name1.charAt(0) != 'L' || name2.charAt(0) != 'L') { return false; } - if(typeKey == this || name1.equals(name2)) { + if (name1.equals(name2)) { return true; } int start = StringsUtil.diffStart(name1, name2); @@ -314,7 +325,7 @@ public boolean equals(Object obj) { if (this == obj) { return true; } - if(!(obj instanceof TypeKey)) { + if (!(obj instanceof TypeKey)) { return false; } TypeKey key = (TypeKey) obj; @@ -560,10 +571,6 @@ public boolean isTypeArray() { public boolean isInnerName() { return false; } - @Override - public boolean isTypeSignature() { - return false; - } } public static final TypeKey TYPE_B = new PrimitiveTypeKey("B", "byte"); diff --git a/src/main/java/com/reandroid/dex/key/TypeListKey.java b/src/main/java/com/reandroid/dex/key/TypeListKey.java index 24ea6decf..67fbe95c9 100644 --- a/src/main/java/com/reandroid/dex/key/TypeListKey.java +++ b/src/main/java/com/reandroid/dex/key/TypeListKey.java @@ -25,16 +25,9 @@ public class TypeListKey extends KeyList { - public static final TypeListKey EMPTY; - private static final TypeKey[] EMPTY_ARRAY; + private static final TypeListKey EMPTY = new TypeListKey(EMPTY_ARRAY); - static { - TypeKey[] emptyArray = new TypeKey[0]; - EMPTY_ARRAY = emptyArray; - EMPTY = new TypeListKey(emptyArray); - } - - private TypeListKey(TypeKey[] keys) { + private TypeListKey(Key[] keys) { super(keys); } @@ -52,16 +45,9 @@ public TypeListKey remove(int index) { } @Override - TypeListKey newInstance(TypeKey[] elements) { + TypeListKey newInstance(Key[] elements) { return TypeListKey.create(elements); } - @Override - TypeKey[] newArray(int length) { - if (length == 0) { - return EMPTY_ARRAY; - } - return new TypeKey[length]; - } @Override public TypeListKey add(TypeKey typeKey) { @@ -117,10 +103,13 @@ public String toString() { return '(' + StringsUtil.join(iterator(), null) + ')'; } - public static TypeListKey create(TypeKey ... keys) { + public static TypeListKey empty() { + return EMPTY; + } + public static TypeListKey create(Key ... keys) { keys = removeNulls(keys); if (keys == EMPTY_ARRAY) { - return EMPTY; + return empty(); } return new TypeListKey(keys); } @@ -140,7 +129,7 @@ public static TypeListKey readParameters(SmaliReader reader) throws IOException } SmaliParseException.expect(reader, ')'); if (keys == null) { - return EMPTY; + return empty(); } return create(keys.toArrayFill(new TypeKey[keys.size()])); } @@ -150,7 +139,7 @@ public static TypeListKey parseParameters(String parameters) { } public static TypeListKey parseParameters(String text, int start, int end) { if (end == start) { - return EMPTY; + return empty(); } if (start > end) { return null; @@ -166,33 +155,4 @@ public static TypeListKey parseParameters(String text, int start, int end) { } return create(results.toArrayFill(new TypeKey[results.size()])); } - private static TypeKey[] removeNulls(TypeKey[] elements) { - if (elements == null || elements.length == 0) { - return EMPTY_ARRAY; - } - int length = elements.length; - int size = 0; - for (int i = 0; i < length; i ++) { - TypeKey key = elements[i]; - if (key != null) { - size ++; - } - } - if (size == length) { - return elements; - } - if (size == 0) { - return EMPTY_ARRAY; - } - TypeKey[] results = new TypeKey[size]; - int j = 0; - for (int i = 0; i < length; i ++) { - TypeKey key = elements[i]; - if (key != null) { - results[j] = key; - j ++; - } - } - return results; - } } diff --git a/src/main/java/com/reandroid/dex/model/DexClass.java b/src/main/java/com/reandroid/dex/model/DexClass.java index 740d877f5..f3d98d06a 100644 --- a/src/main/java/com/reandroid/dex/model/DexClass.java +++ b/src/main/java/com/reandroid/dex/model/DexClass.java @@ -436,7 +436,7 @@ public void removeInterface(TypeKey typeKey) { getId().setInterfaces(typeListKey); } public void clearInterfaces() { - getId().setInterfaces(TypeListKey.EMPTY); + getId().setInterfaces(TypeListKey.empty()); } public void clearDebug(){ Iterator iterator = getDeclaredMethods(); @@ -446,14 +446,11 @@ public void clearDebug(){ } public void fixDalvikInnerClassName() { DalvikInnerClass dalvikInnerClass = DalvikInnerClass.of(this); - if (dalvikInnerClass == null || dalvikInnerClass.getName() == null) { - return; - } - TypeKey typeKey = getKey(); - if (!typeKey.isInnerName()) { - dalvikInnerClass.setName(null); - } else { - dalvikInnerClass.setName(typeKey.getSimpleInnerName()); + if (dalvikInnerClass != null && dalvikInnerClass.hasName()) { + String inner = getKey().getSimpleInnerName(); + if (inner != null) { + dalvikInnerClass.setName(inner); + } } } public Set fixAccessibility(){ diff --git a/src/main/java/com/reandroid/dex/model/DexClassRepository.java b/src/main/java/com/reandroid/dex/model/DexClassRepository.java index d1d2e7c06..dfd0194db 100644 --- a/src/main/java/com/reandroid/dex/model/DexClassRepository.java +++ b/src/main/java/com/reandroid/dex/model/DexClassRepository.java @@ -76,13 +76,6 @@ default int shrink() { } return result; } - /** - * Use getDexClass(TypeKey) - * */ - @Deprecated - default DexClass getDexClass(String name) { - return getDexClass(TypeKey.create(name)); - } default DexClass getDexClass(TypeKey typeKey) { return searchClass(modules(), typeKey); diff --git a/src/main/java/com/reandroid/dex/refactor/Rename.java b/src/main/java/com/reandroid/dex/refactor/Rename.java index 6ce7c2437..48546b27e 100644 --- a/src/main/java/com/reandroid/dex/refactor/Rename.java +++ b/src/main/java/com/reandroid/dex/refactor/Rename.java @@ -19,6 +19,7 @@ import com.reandroid.dex.key.KeyPair; import com.reandroid.dex.model.DexClassRepository; import com.reandroid.utils.CompareUtil; +import com.reandroid.utils.ObjectsUtil; import com.reandroid.utils.StringsUtil; import com.reandroid.utils.collection.ArrayCollection; @@ -26,13 +27,13 @@ public abstract class Rename { - private final Set> keyPairSet; - private final Set> flippedSet; + private final Map, KeyPair> keyPairMap; + private final Map, KeyPair> flippedKeyMap; private final Set> badKeys; - public Rename(){ - this.keyPairSet = new HashSet<>(); - this.flippedSet = new HashSet<>(); + public Rename() { + this.keyPairMap = new HashMap<>(); + this.flippedKeyMap = new HashMap<>(); this.badKeys = new HashSet<>(); } @@ -51,37 +52,81 @@ public void addAll(Iterator> iterator){ } } private void addToSet(KeyPair keyPair) { - if(keyPair != null && keyPair.isValid() && !this.badKeys.contains(keyPair)){ - KeyPair flip = keyPair.flip(); - if (flippedSet.contains(flip) || keyPairSet.contains(flip) - || keyPairSet.contains(keyPair) || flippedSet.contains(keyPair)) { - badKeys.add(keyPair); - badKeys.add(flip); - keyPairSet.remove(keyPair); - keyPairSet.remove(flip); + if (keyPair == null || !keyPair.isValid()) { + return; + } + boolean bad = false; + if (badKeys.contains(keyPair)) { + bad = true; + } + KeyPair flip = keyPair.flip(); + if (badKeys.contains(flip)) { + if (bad) { return; } - this.keyPairSet.add(keyPair); - flippedSet.add(flip); + bad = true; + } + if (!bad) { + KeyPair exist = keyPairMap.get(keyPair); + if (exist == null) { + exist = flippedKeyMap.get(flip); + if (exist != null) { + bad = true; + } + } else { + if (keyPair.equalsBoth(exist)) { + return; + } + bad = true; + } + } + if (bad) { + addBadKey(keyPair, flip); + } else { + keyPairMap.put(keyPair, keyPair); + flippedKeyMap.put(flip, keyPair); + } + } + private void addBadKey(KeyPair keyPair, KeyPair flip) { + badKeys.add(keyPair); + badKeys.add(flip); + KeyPair p1 = keyPairMap.remove(keyPair); + if (p1 == null) { + p1 = keyPairMap.remove(flip); + } + KeyPair p2 = flippedKeyMap.remove(flip); + if (p2 == null) { + p2 = flippedKeyMap.remove(keyPair); + } + if (p1 != null && !p1.equalsBoth(keyPair)) { + addBadKey(p1, p1.flip()); } + if (p2 != null && !p2.equalsBoth(keyPair)) { + addBadKey(p2, p2.flip()); + } + } + public int size() { + return keyPairMap.size(); } - public int size(){ - return keyPairSet.size(); + public List> toList() { + return toList(CompareUtil.getComparableComparator()); } - public List> sortedList(){ - List> results = new ArrayCollection<>(keyPairSet); - results.sort(CompareUtil.getComparableComparator()); + public List> toList(Comparator> comparator) { + List> results = new ArrayCollection<>(getKeyPairSet()); + if (comparator != null) { + results.sort(comparator); + } return results; } public abstract int apply(DexClassRepository classRepository); public Set> getKeyPairSet() { - return keyPairSet; + return ObjectsUtil.cast(keyPairMap.keySet()); } @Override public String toString() { - return StringsUtil.join(sortedList(), '\n'); + return StringsUtil.join(toList(), '\n'); } } diff --git a/src/main/java/com/reandroid/dex/refactor/RenameTypes.java b/src/main/java/com/reandroid/dex/refactor/RenameTypes.java index 9fe53e66c..bec59bb2a 100644 --- a/src/main/java/com/reandroid/dex/refactor/RenameTypes.java +++ b/src/main/java/com/reandroid/dex/refactor/RenameTypes.java @@ -15,35 +15,38 @@ */ package com.reandroid.dex.refactor; -import com.reandroid.dex.base.UsageMarker; -import com.reandroid.dex.common.DexUtils; +import com.reandroid.dex.dalvik.DalvikSignature; import com.reandroid.dex.id.StringId; +import com.reandroid.dex.key.DalvikSignatureKey; import com.reandroid.dex.key.KeyPair; import com.reandroid.dex.key.TypeKey; import com.reandroid.dex.key.TypeKeyReference; import com.reandroid.dex.model.DexClass; import com.reandroid.dex.model.DexClassRepository; import com.reandroid.dex.sections.SectionType; +import com.reandroid.utils.CompareUtil; import com.reandroid.utils.ObjectsUtil; +import com.reandroid.utils.collection.CollectionUtil; +import com.reandroid.utils.collection.ComputeIterator; import java.util.*; public class RenameTypes extends Rename{ private int arrayDepth; - private boolean renameSignatures; private boolean renameSource; - private boolean noRenameSourceForNoPackageClass; + private boolean skipSourceRenameRootPackageClass; private boolean fixAccessibility; + private boolean fixInnerSimpleName; private Set renamedStrings; - public RenameTypes(){ + public RenameTypes() { super(); this.arrayDepth = DEFAULT_ARRAY_DEPTH; - this.renameSignatures = true; this.renameSource = true; - this.noRenameSourceForNoPackageClass = true; + this.skipSourceRenameRootPackageClass = true; this.fixAccessibility = true; + this.fixInnerSimpleName = true; this.renamedStrings = new HashSet<>(); } @@ -52,12 +55,13 @@ public int apply(DexClassRepository classRepository) { Map map = buildRenameMap(); this.renamedStrings = new HashSet<>(map.size()); renameStringIds(classRepository, map); + renameAnnotationSignatures(classRepository, map); renameExternalTypeKeyReferences(classRepository, map); int size = renamedStrings.size(); if(size != 0) { classRepository.clearPoolMap(); } - fixAccessibility(classRepository); + applyFix(classRepository); renamedStrings.clear(); renamedStrings = null; return size; @@ -66,15 +70,43 @@ private void renameStringIds(DexClassRepository classRepository, Map iterator = classRepository.getClonedItems(SectionType.STRING_ID); while (iterator.hasNext()){ StringId stringId = iterator.next(); - stringId.addUsageType(UsageMarker.USAGE_DEFINITION); String text = map.get(stringId.getString()); - if(text != null){ + if (text != null) { setString(stringId, text); - }else { - renameSignatures(map, stringId); } } } + private void renameAnnotationSignatures(DexClassRepository classRepository, Map map) { + Set renamedStrings = this.renamedStrings; + + Iterator iterator = ComputeIterator.of( + classRepository.getItems(SectionType.ANNOTATION_ITEM), + annotationItem -> DalvikSignature.of(annotationItem.asAnnotated())); + + while (iterator.hasNext()) { + DalvikSignature dalvikSignature = iterator.next(); + DalvikSignatureKey signatureKey = dalvikSignature.getSignature(); + if (signatureKey == null) { + // unlikely + continue; + } + DalvikSignatureKey update = signatureKey; + Iterator types = CollectionUtil.copyOfUniqueOf(signatureKey.getTypes()); + while (types.hasNext()) { + TypeKey search = types.next(); + String replace = map.get(search.getTypeName()); + if (replace == null) { + continue; + } + update = update.replaceKey(search, TypeKey.create(replace)); + renamedStrings.add(replace); + } + if (signatureKey != update) { + dalvikSignature.setSignature(update); + } + } + } + private void renameExternalTypeKeyReferences(DexClassRepository classRepository, Map map) { List referenceList = classRepository.getExternalTypeKeyReferenceList(); for(TypeKeyReference reference : referenceList) { @@ -96,42 +128,30 @@ private void renameExternalTypeKeyReference(TypeKeyReference reference, Map renamedSet = this.renamedStrings; - if(!this.fixAccessibility || renamedSet == null || renamedSet.isEmpty()) { + if (renamedSet == null || renamedSet.isEmpty()) { + return; + } + + boolean fixAccessibility = this.fixAccessibility; + boolean fixInnerSimpleName = this.fixInnerSimpleName; + + if (!fixAccessibility && !fixInnerSimpleName) { return; } + Iterator iterator = classRepository.getDexClasses( typeKey -> renamedSet.contains(typeKey.getTypeName())); + while (iterator.hasNext()) { - iterator.next().fixAccessibility(); - } - } - private void renameSignatures(Map map, StringId stringId){ - if(!stringId.containsUsage(UsageMarker.USAGE_SIGNATURE_TYPE)){ - return; - } - String text = stringId.getString(); - if(text.indexOf('L') < 0){ - return; - } - String[] signatures = DexUtils.splitSignatures(text); - int length = signatures.length; - boolean found = false; - for(int i = 0; i < length; i++){ - String type = signatures[i]; - String replace = map.get(type); - if(replace != null){ - signatures[i] = replace; - found = true; + DexClass dexClass = iterator.next(); + if (fixAccessibility) { + dexClass.fixAccessibility(); } - } - if(found){ - StringBuilder builder = new StringBuilder(); - for(int i = 0; i < length; i++){ - builder.append(signatures[i]); + if (fixInnerSimpleName) { + dexClass.fixDalvikInnerClassName(); } - setString(stringId, builder.toString()); } } private void setString(StringId stringId, String value) { @@ -145,113 +165,37 @@ public void setArrayDepth(int arrayDepth) { } this.arrayDepth = arrayDepth; } - public void setRenameSignatures(boolean renameSignatures) { - this.renameSignatures = renameSignatures; - } public void setRenameSource(boolean renameSource) { this.renameSource = renameSource; } - public void setNoRenameSourceForNoPackageClass(boolean noRenameSourceForNoPackageClass) { - this.noRenameSourceForNoPackageClass = noRenameSourceForNoPackageClass; + public void setSkipSourceRenameRootPackageClass(boolean skipSourceRenameRootPackageClass) { + this.skipSourceRenameRootPackageClass = skipSourceRenameRootPackageClass; } public void setFixAccessibility(boolean fixAccessibility) { this.fixAccessibility = fixAccessibility; } + public void setFixInnerSimpleName(boolean fixInnerSimpleName) { + this.fixInnerSimpleName = fixInnerSimpleName; + } private Map buildRenameMap() { - List> list = sortedList(); - boolean renameSignatures = this.renameSignatures; + List> list = toList(); boolean renameSource = this.renameSource; - boolean noRenameSourceForNoPackageClass = this.noRenameSourceForNoPackageClass; + boolean skipSourceFileForRootPackageClass = this.skipSourceRenameRootPackageClass; int estimatedSize = 1; - if(renameSignatures){ - estimatedSize = estimatedSize + 2; - } - if(renameSource){ + if(renameSource) { estimatedSize = estimatedSize + 1; } if(arrayDepth > 0){ estimatedSize = estimatedSize + arrayDepth + 1; } - estimatedSize = list.size() * estimatedSize; - - Map map = new HashMap<>(estimatedSize); - int size = list.size(); - int arrayDepth = this.arrayDepth + 1; - - for(int i = 0; i < size; i++){ - - KeyPair keyPair = list.get(i); - TypeKey first = keyPair.getFirst(); - TypeKey second = keyPair.getSecond(); - String name1 = first.getTypeName(); - String name2 = second.getTypeName(); - map.put(name1, name2); - - if(renameSignatures){ - name1 = first.getTypeName(); - name2 = second.getTypeName(); - - name1 = name1.replace(';', '<'); - name2 = name2.replace(';', '<'); - - map.put(name1, name2); - - name1 = first.getTypeName(); - name2 = second.getTypeName(); - - name1 = name1.substring(0, name1.length() - 1); - name2 = name2.substring(0, name2.length() - 1); - - map.put(name1, name2); - } - - for(int j = 1; j < arrayDepth; j++){ - name1 = first.getArrayType(j); - name2 = second.getArrayType(j); - map.put(name1, name2); - if(renameSignatures && j == 1){ - name1 = name1.replace(';', '<'); - name2 = name2.replace(';', '<'); - map.put(name1, name2); - } - } - if(renameSource){ - name1 = first.getTypeName(); - if(!noRenameSourceForNoPackageClass || name1.indexOf('/') > 0){ - name1 = first.getSourceName(); - name2 = second.getSourceName(); - map.put(name1, name2); - } - } - } - return map; - } - - private Map buildSignatureRenameMap() { - List> list = sortedList(); - boolean renameSignatures = this.renameSignatures; - boolean renameSource = this.renameSource; - boolean noRenameSourceForNoPackageClass = this.noRenameSourceForNoPackageClass; - - int estimatedSize = 1; - if(renameSignatures){ - estimatedSize = estimatedSize + 2; - } - if(renameSource){ - estimatedSize = estimatedSize + 1; - } - if(arrayDepth > 0){ - estimatedSize = estimatedSize + arrayDepth + 1; - } - estimatedSize = list.size() * estimatedSize; + estimatedSize = size * estimatedSize; Map map = new HashMap<>(estimatedSize); - int size = list.size(); int arrayDepth = this.arrayDepth + 1; for(int i = 0; i < size; i++){ @@ -264,37 +208,14 @@ private Map buildSignatureRenameMap() { String name2 = second.getTypeName(); map.put(name1, name2); - if(renameSignatures){ - name1 = first.getTypeName(); - name2 = second.getTypeName(); - - name1 = name1.replace(';', '<'); - name2 = name2.replace(';', '<'); - - map.put(name1, name2); - - name1 = first.getTypeName(); - name2 = second.getTypeName(); - - name1 = name1.substring(0, name1.length() - 1); - name2 = name2.substring(0, name2.length() - 1); - - map.put(name1, name2); - } - for(int j = 1; j < arrayDepth; j++){ name1 = first.getArrayType(j); name2 = second.getArrayType(j); map.put(name1, name2); - if(renameSignatures && j == 1){ - name1 = name1.replace(';', '<'); - name2 = name2.replace(';', '<'); - map.put(name1, name2); - } } if(renameSource){ name1 = first.getTypeName(); - if(!noRenameSourceForNoPackageClass || name1.indexOf('/') > 0){ + if(!skipSourceFileForRootPackageClass || name1.indexOf('/') > 0){ name1 = first.getSourceName(); name2 = second.getSourceName(); map.put(name1, name2); @@ -304,5 +225,10 @@ private Map buildSignatureRenameMap() { return map; } + @Override + public List> toList() { + return super.toList(CompareUtil.getInverseComparator()); + } + public static final int DEFAULT_ARRAY_DEPTH = ObjectsUtil.of(3); } diff --git a/src/main/java/com/reandroid/dex/smali/model/SmaliAnnotationSet.java b/src/main/java/com/reandroid/dex/smali/model/SmaliAnnotationSet.java index 40c859c44..eafb21ec3 100644 --- a/src/main/java/com/reandroid/dex/smali/model/SmaliAnnotationSet.java +++ b/src/main/java/com/reandroid/dex/smali/model/SmaliAnnotationSet.java @@ -37,7 +37,7 @@ public AnnotationSetKey getKey() { for (int i = 0; i < size; i++) { elements[i] = get(i).getKey(); } - return AnnotationSetKey.create(elements); + return AnnotationSetKey.of(elements); } public void setKey(Key key) { clear(); diff --git a/src/main/java/com/reandroid/dex/smali/model/SmaliDef.java b/src/main/java/com/reandroid/dex/smali/model/SmaliDef.java index 576b3d4f8..900866b4d 100644 --- a/src/main/java/com/reandroid/dex/smali/model/SmaliDef.java +++ b/src/main/java/com/reandroid/dex/smali/model/SmaliDef.java @@ -58,7 +58,7 @@ public AnnotationSetKey getAnnotation() { if (annotationSet != null) { return annotationSet.getKey(); } - return AnnotationSetKey.EMPTY; + return AnnotationSetKey.empty(); } @Override public void setAnnotation(AnnotationSetKey annotation) { diff --git a/src/main/java/com/reandroid/dex/smali/model/SmaliInterfaceSet.java b/src/main/java/com/reandroid/dex/smali/model/SmaliInterfaceSet.java index 427b6b262..17154c026 100644 --- a/src/main/java/com/reandroid/dex/smali/model/SmaliInterfaceSet.java +++ b/src/main/java/com/reandroid/dex/smali/model/SmaliInterfaceSet.java @@ -34,7 +34,7 @@ public SmaliInterfaceSet(){ public TypeListKey getKey(){ int size = size(); if(size == 0){ - return TypeListKey.EMPTY; + return TypeListKey.empty(); } TypeKey[] keys = new TypeKey[size]; for (int i = 0; i < size; i++) { diff --git a/src/main/java/com/reandroid/dex/smali/model/SmaliMethodParameter.java b/src/main/java/com/reandroid/dex/smali/model/SmaliMethodParameter.java index 5058b86be..0c8670f04 100644 --- a/src/main/java/com/reandroid/dex/smali/model/SmaliMethodParameter.java +++ b/src/main/java/com/reandroid/dex/smali/model/SmaliMethodParameter.java @@ -94,7 +94,7 @@ public AnnotationSetKey getAnnotation() { if (annotationSet != null) { return annotationSet.getKey(); } - return AnnotationSetKey.EMPTY; + return AnnotationSetKey.empty(); } @Override public void setAnnotation(AnnotationSetKey annotation) { diff --git a/src/main/java/com/reandroid/dex/smali/model/SmaliValueArray.java b/src/main/java/com/reandroid/dex/smali/model/SmaliValueArray.java index 5a61f3be1..06cbf158c 100644 --- a/src/main/java/com/reandroid/dex/smali/model/SmaliValueArray.java +++ b/src/main/java/com/reandroid/dex/smali/model/SmaliValueArray.java @@ -42,7 +42,7 @@ public ArrayValueKey getKey() { for (int i = 0; i < size; i++) { elements[i] = get(i).getKey(); } - return ArrayValueKey.create(elements); + return ArrayValueKey.of(elements); } @Override public void setKey(Key key) { diff --git a/src/main/java/com/reandroid/utils/CompareUtil.java b/src/main/java/com/reandroid/utils/CompareUtil.java index 5a2f11a45..95811d4f8 100644 --- a/src/main/java/com/reandroid/utils/CompareUtil.java +++ b/src/main/java/com/reandroid/utils/CompareUtil.java @@ -15,8 +15,6 @@ */ package com.reandroid.utils; -import com.reandroid.utils.collection.ArraySort; - import java.util.Comparator; import java.util.function.Function; @@ -25,13 +23,6 @@ public class CompareUtil { public static> Comparator computeComparator(Function function) { return (t1, t2) -> compare(function.apply(t1), function.apply(t2)); } - @Deprecated - public static> void sort(T[] items) { - if(items == null || items.length < 2){ - return; - } - ArraySort.sort(items, getComparableComparator()); - } public static> int compare(T[] items1, T[] items2) { if(items1 == items2){ return 0; @@ -117,6 +108,10 @@ public static Comparator getComparatorUnchecked(){ return (Comparator) COMPARATOR; } + @SuppressWarnings("unchecked") + public static > Comparator getInverseComparator(){ + return (Comparator) INVERSE_COMPARATOR; + } @SuppressWarnings("unchecked") public static > Comparator getComparableComparator(){ return (Comparator) COMPARATOR; @@ -136,4 +131,11 @@ public int compare(Comparable comparable1, Comparable comparable2) { return CompareUtil.compare(comparable1, comparable2); } }; + @SuppressWarnings("unchecked") + private static final Comparator> INVERSE_COMPARATOR = new Comparator>() { + @Override + public int compare(Comparable comparable1, Comparable comparable2) { + return CompareUtil.compare(comparable2, comparable1); + } + }; }