Version 1.4.49 Cherry-pick: Handle renaming of types in Signature annotations after vertical class merging CL: https://r8-review.googlesource.com/c/r8/+/34472 Cherry-pick: Update test expectation CL: https://r8-review.googlesource.com/c/r8/+/34479 Cherry-pick: Add test for signature annotation with vertical class merging CL: https://r8-review.googlesource.com/c/r8/+/34403 Cherry-pick: Correctly handle '***' in ProguardTypeMatcher CL: https://r8-review.googlesource.com/c/r8/+/34526 Cherry-pick: Add a failing test for use of '***' CL: https://r8-review.googlesource.com/c/r8/+/34524 Cherry-pick: Only interpret pattern as include-all if separators are also included CL: https://r8-review.googlesource.com/c/r8/+/34531 Cherry-pick: Don't use Class.getTypeName in test CL: https://r8-review.googlesource.com/c/r8/+/34538 Bug: 124584385, 124357885 Change-Id: Id052501b8aa98014e54ed129409c11beed5fb7cd
diff --git a/src/main/java/com/android/tools/r8/R8.java b/src/main/java/com/android/tools/r8/R8.java index 37311e8..40c2ffa 100644 --- a/src/main/java/com/android/tools/r8/R8.java +++ b/src/main/java/com/android/tools/r8/R8.java
@@ -624,9 +624,7 @@ NamingLens namingLens; if (options.enableMinification) { timing.begin("Minification"); - namingLens = - new Minifier(appView.appInfo().withLiveness(), rootSet, desugaredCallSites, options) - .run(timing); + namingLens = new Minifier(appView.withLiveness(), rootSet, desugaredCallSites).run(timing); timing.end(); } else { namingLens = NamingLens.getIdentityLens();
diff --git a/src/main/java/com/android/tools/r8/Version.java b/src/main/java/com/android/tools/r8/Version.java index 893fefa..b31bcbd 100644 --- a/src/main/java/com/android/tools/r8/Version.java +++ b/src/main/java/com/android/tools/r8/Version.java
@@ -11,7 +11,7 @@ // This field is accessed from release scripts using simple pattern matching. // Therefore, changing this field could break our release scripts. - public static final String LABEL = "1.4.48"; + public static final String LABEL = "1.4.49"; private Version() { }
diff --git a/src/main/java/com/android/tools/r8/naming/ClassNameMinifier.java b/src/main/java/com/android/tools/r8/naming/ClassNameMinifier.java index bc81538..b59b79b 100644 --- a/src/main/java/com/android/tools/r8/naming/ClassNameMinifier.java +++ b/src/main/java/com/android/tools/r8/naming/ClassNameMinifier.java
@@ -9,6 +9,7 @@ import static com.android.tools.r8.utils.DescriptorUtils.getDescriptorFromClassBinaryName; import static com.android.tools.r8.utils.DescriptorUtils.getPackageBinaryNameFromJavaType; +import com.android.tools.r8.graph.AppView; import com.android.tools.r8.graph.DexAnnotation; import com.android.tools.r8.graph.DexAnnotationSet; import com.android.tools.r8.graph.DexClass; @@ -50,6 +51,7 @@ class ClassNameMinifier { + private final AppView<AppInfoWithLiveness> appView; private final AppInfoWithLiveness appInfo; private final Reporter reporter; private final PackageObfuscationMode packageObfuscationMode; @@ -74,11 +76,10 @@ private final GenericSignatureParser<DexType> genericSignatureParser = new GenericSignatureParser<>(genericSignatureRewriter); - ClassNameMinifier( - AppInfoWithLiveness appInfo, - RootSet rootSet, - InternalOptions options) { - this.appInfo = appInfo; + ClassNameMinifier(AppView<AppInfoWithLiveness> appView, RootSet rootSet) { + this.appView = appView; + this.appInfo = appView.appInfo(); + InternalOptions options = appView.options(); this.reporter = options.reporter; this.packageObfuscationMode = options.getProguardConfiguration().getPackageObfuscationMode(); this.isAccessModificationAllowed = @@ -546,6 +547,7 @@ @Override public DexType parsedTypeName(String name) { DexType type = appInfo.dexItemFactory.createType(getDescriptorFromClassBinaryName(name)); + type = appView.graphLense().lookupType(type); DexString renamedDescriptor = renaming.getOrDefault(type, type.descriptor); renamedSignature.append(getClassBinaryNameFromDescriptor(renamedDescriptor.toString())); return type; @@ -564,6 +566,7 @@ String enclosingRenamedBinaryName = getClassBinaryNameFromDescriptor( renaming.getOrDefault(enclosingType, enclosingType.descriptor).toString()); + type = appView.graphLense().lookupType(type); DexString renamedDescriptor = renaming.get(type); if (renamedDescriptor != null) { // Pick the renamed inner class from the fully renamed binary name.
diff --git a/src/main/java/com/android/tools/r8/naming/FieldNameMinifier.java b/src/main/java/com/android/tools/r8/naming/FieldNameMinifier.java index be339b6..e2127dd 100644 --- a/src/main/java/com/android/tools/r8/naming/FieldNameMinifier.java +++ b/src/main/java/com/android/tools/r8/naming/FieldNameMinifier.java
@@ -3,6 +3,7 @@ // BSD-style license that can be found in the LICENSE file. package com.android.tools.r8.naming; +import com.android.tools.r8.graph.AppView; import com.android.tools.r8.graph.DexClass; import com.android.tools.r8.graph.DexEncodedField; import com.android.tools.r8.graph.DexField; @@ -10,7 +11,6 @@ import com.android.tools.r8.graph.DexType; import com.android.tools.r8.shaking.Enqueuer.AppInfoWithLiveness; import com.android.tools.r8.shaking.RootSetBuilder.RootSet; -import com.android.tools.r8.utils.InternalOptions; import com.android.tools.r8.utils.Timing; import com.google.common.collect.ImmutableMap; import com.google.common.collect.Sets; @@ -19,8 +19,8 @@ class FieldNameMinifier extends MemberNameMinifier<DexField, DexType> { - FieldNameMinifier(AppInfoWithLiveness appInfo, RootSet rootSet, InternalOptions options) { - super(appInfo, rootSet, options); + FieldNameMinifier(AppView<AppInfoWithLiveness> appView, RootSet rootSet) { + super(appView, rootSet); } @Override
diff --git a/src/main/java/com/android/tools/r8/naming/MemberNameMinifier.java b/src/main/java/com/android/tools/r8/naming/MemberNameMinifier.java index 419bfbb..53957e4 100644 --- a/src/main/java/com/android/tools/r8/naming/MemberNameMinifier.java +++ b/src/main/java/com/android/tools/r8/naming/MemberNameMinifier.java
@@ -3,6 +3,7 @@ // BSD-style license that can be found in the LICENSE file. package com.android.tools.r8.naming; +import com.android.tools.r8.graph.AppView; import com.android.tools.r8.graph.CachedHashValueDexItem; import com.android.tools.r8.graph.DexString; import com.android.tools.r8.graph.DexType; @@ -18,6 +19,7 @@ abstract class MemberNameMinifier<MemberType, StateType extends CachedHashValueDexItem> { + protected final AppView<AppInfoWithLiveness> appView; protected final AppInfoWithLiveness appInfo; protected final RootSet rootSet; protected final InternalOptions options; @@ -34,10 +36,11 @@ // which is useful for debugging. private final BiMap<DexType, NamingState<StateType, ?>> states = HashBiMap.create(); - MemberNameMinifier(AppInfoWithLiveness appInfo, RootSet rootSet, InternalOptions options) { - this.appInfo = appInfo; + MemberNameMinifier(AppView<AppInfoWithLiveness> appView, RootSet rootSet) { + this.appView = appView; + this.appInfo = appView.appInfo(); this.rootSet = rootSet; - this.options = options; + this.options = appView.options(); this.dictionary = options.getProguardConfiguration().getObfuscationDictionary(); this.useUniqueMemberNames = options.getProguardConfiguration().isUseUniqueClassMemberNames(); this.overloadAggressively =
diff --git a/src/main/java/com/android/tools/r8/naming/MethodNameMinifier.java b/src/main/java/com/android/tools/r8/naming/MethodNameMinifier.java index 8864271..2cd8712 100644 --- a/src/main/java/com/android/tools/r8/naming/MethodNameMinifier.java +++ b/src/main/java/com/android/tools/r8/naming/MethodNameMinifier.java
@@ -3,6 +3,7 @@ // BSD-style license that can be found in the LICENSE file. package com.android.tools.r8.naming; +import com.android.tools.r8.graph.AppView; import com.android.tools.r8.graph.DexCallSite; import com.android.tools.r8.graph.DexClass; import com.android.tools.r8.graph.DexEncodedMethod; @@ -91,11 +92,8 @@ private final FrontierState frontierState = new FrontierState(); - MethodNameMinifier( - AppInfoWithLiveness appInfo, - RootSet rootSet, - InternalOptions options) { - super(appInfo, rootSet, options); + MethodNameMinifier(AppView<AppInfoWithLiveness> appView, RootSet rootSet) { + super(appView, rootSet); equivalence = overloadAggressively ? MethodSignatureEquivalence.get()
diff --git a/src/main/java/com/android/tools/r8/naming/Minifier.java b/src/main/java/com/android/tools/r8/naming/Minifier.java index 5333125..af18595 100644 --- a/src/main/java/com/android/tools/r8/naming/Minifier.java +++ b/src/main/java/com/android/tools/r8/naming/Minifier.java
@@ -4,6 +4,7 @@ package com.android.tools.r8.naming; import com.android.tools.r8.graph.AppInfo; +import com.android.tools.r8.graph.AppView; import com.android.tools.r8.graph.DexCallSite; import com.android.tools.r8.graph.DexClass; import com.android.tools.r8.graph.DexEncodedMethod; @@ -35,26 +36,27 @@ static final char INNER_CLASS_SEPARATOR = '$'; + private final AppView<AppInfoWithLiveness> appView; private final AppInfoWithLiveness appInfo; private final RootSet rootSet; private final Set<DexCallSite> desugaredCallSites; private final InternalOptions options; public Minifier( - AppInfoWithLiveness appInfo, + AppView<AppInfoWithLiveness> appView, RootSet rootSet, - Set<DexCallSite> desugaredCallSites, - InternalOptions options) { - this.appInfo = appInfo; + Set<DexCallSite> desugaredCallSites) { + this.appView = appView; + this.appInfo = appView.appInfo(); this.rootSet = rootSet; this.desugaredCallSites = desugaredCallSites; - this.options = options; + this.options = appView.options(); } public NamingLens run(Timing timing) { assert options.enableMinification; timing.begin("MinifyClasses"); - ClassNameMinifier classNameMinifier = new ClassNameMinifier(appInfo, rootSet, options); + ClassNameMinifier classNameMinifier = new ClassNameMinifier(appView, rootSet); ClassRenaming classRenaming = classNameMinifier.computeRenaming(timing); timing.end(); @@ -64,16 +66,14 @@ timing.begin("MinifyMethods"); MethodRenaming methodRenaming = - new MethodNameMinifier(appInfo, rootSet, options) - .computeRenaming(desugaredCallSites, timing); + new MethodNameMinifier(appView, rootSet).computeRenaming(desugaredCallSites, timing); timing.end(); assert new MinifiedRenaming(classRenaming, methodRenaming, FieldRenaming.empty(), appInfo) .verifyNoCollisions(appInfo.classes(), appInfo.dexItemFactory); timing.begin("MinifyFields"); - FieldRenaming fieldRenaming = - new FieldNameMinifier(appInfo, rootSet, options).computeRenaming(timing); + FieldRenaming fieldRenaming = new FieldNameMinifier(appView, rootSet).computeRenaming(timing); timing.end(); NamingLens lens = new MinifiedRenaming(classRenaming, methodRenaming, fieldRenaming, appInfo);
diff --git a/src/main/java/com/android/tools/r8/shaking/ProguardTypeMatcher.java b/src/main/java/com/android/tools/r8/shaking/ProguardTypeMatcher.java index dc8925a..996f83f 100644 --- a/src/main/java/com/android/tools/r8/shaking/ProguardTypeMatcher.java +++ b/src/main/java/com/android/tools/r8/shaking/ProguardTypeMatcher.java
@@ -386,24 +386,44 @@ wildcard = wildcards.get(wildcardIndex); assert wildcard.isPattern(); wildcardPattern = wildcard.asPattern(); + boolean includeSeparators = pattern.length() > (i + 1) && pattern.charAt(i + 1) == '*'; - int nextPatternIndex = i + (includeSeparators ? 2 : 1); - // Fast cases for the common case where a pattern ends with '**' or '*'. + boolean includeAll = + includeSeparators && pattern.length() > (i + 2) && pattern.charAt(i + 2) == '*'; + int nextPatternIndex = i + 1; + if (includeAll) { + nextPatternIndex += 2; + } else if (includeSeparators) { + nextPatternIndex += 1; + } + + // Fast cases for the common case where a pattern ends with '*', '**', or '***'. if (nextPatternIndex == pattern.length()) { - wildcardPattern.setCaptured(name.substring(nameIndex, name.length())); + wildcardPattern.setCaptured(name.substring(nameIndex)); + if (includeAll) { + return true; + } if (includeSeparators) { return kind == ClassOrType.CLASS || !isArrayType(name); } boolean hasSeparators = containsSeparatorsStartingAt(name, nameIndex); return !hasSeparators && (kind == ClassOrType.CLASS || !isArrayType(name)); } + // Match the rest of the pattern against the (non-empty) rest of the class name. for (int nextNameIndex = nameIndex; nextNameIndex < name.length(); nextNameIndex++) { wildcardPattern.setCaptured(name.substring(nameIndex, nextNameIndex)); - if (!includeSeparators && name.charAt(nextNameIndex) == '.') { - return matchClassOrTypeNameImpl( - pattern, nextPatternIndex, name, nextNameIndex, wildcards, wildcardIndex + 1, - kind); + if (!includeSeparators) { + if (name.charAt(nextNameIndex) == '.') { + return matchClassOrTypeNameImpl( + pattern, + nextPatternIndex, + name, + nextNameIndex, + wildcards, + wildcardIndex + 1, + kind); + } } if (kind == ClassOrType.TYPE && name.charAt(nextNameIndex) == '[') { return matchClassOrTypeNameImpl( @@ -416,11 +436,12 @@ return true; } } - // Finally, check the case where the '*' or '**' eats all of the class name. - wildcardPattern.setCaptured(name.substring(nameIndex, name.length())); + + // Finally, check the case where the '*', '**', or '***' eats all of the class name. + wildcardPattern.setCaptured(name.substring(nameIndex)); return matchClassOrTypeNameImpl( - pattern, nextPatternIndex, name, name.length(), wildcards, wildcardIndex + 1, - kind); + pattern, nextPatternIndex, name, name.length(), wildcards, wildcardIndex + 1, kind); + case '?': wildcard = wildcards.get(wildcardIndex); assert wildcard.isPattern(); @@ -432,6 +453,7 @@ nameIndex++; wildcardIndex++; break; + case '<': wildcard = wildcards.get(wildcardIndex); assert wildcard.isBackReference(); @@ -446,6 +468,7 @@ wildcardIndex++; i = pattern.indexOf(">", i); break; + default: if (nameIndex == name.length() || patternChar != name.charAt(nameIndex++)) { return false;
diff --git a/src/test/java/com/android/tools/r8/naming/NamingTestBase.java b/src/test/java/com/android/tools/r8/naming/NamingTestBase.java index 7b6052a..4dcb52f 100644 --- a/src/test/java/com/android/tools/r8/naming/NamingTestBase.java +++ b/src/test/java/com/android/tools/r8/naming/NamingTestBase.java
@@ -10,6 +10,7 @@ import com.android.tools.r8.graph.DexItemFactory; import com.android.tools.r8.graph.GraphLense; import com.android.tools.r8.shaking.Enqueuer; +import com.android.tools.r8.shaking.Enqueuer.AppInfoWithLiveness; import com.android.tools.r8.shaking.ProguardConfiguration; import com.android.tools.r8.shaking.RootSetBuilder; import com.android.tools.r8.shaking.RootSetBuilder.RootSet; @@ -74,9 +75,12 @@ new RootSetBuilder(appView, program, configuration.getRules(), options).run(executor); Enqueuer enqueuer = new Enqueuer(appView, options, null, options.forceProguardCompatibility); - AppInfoWithSubtyping appInfo = + AppInfoWithLiveness appInfo = enqueuer.traceApplication(rootSet, configuration.getDontWarnPatterns(), executor, timing); - return new Minifier(appInfo.withLiveness(), rootSet, Collections.emptySet(), options) + return new Minifier( + new AppView<>(appInfo, GraphLense.getIdentityLense(), options), + rootSet, + Collections.emptySet()) .run(timing); }
diff --git a/src/test/java/com/android/tools/r8/naming/b124357885/B124357885Test.java b/src/test/java/com/android/tools/r8/naming/b124357885/B124357885Test.java new file mode 100644 index 0000000..37a0215 --- /dev/null +++ b/src/test/java/com/android/tools/r8/naming/b124357885/B124357885Test.java
@@ -0,0 +1,102 @@ +// Copyright (c) 2019, the R8 project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +package com.android.tools.r8.naming.b124357885; + +import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent; +import static com.android.tools.r8.utils.codeinspector.Matchers.isRenamed; +import static org.hamcrest.CoreMatchers.allOf; +import static org.hamcrest.CoreMatchers.not; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertThat; +import static org.junit.Assert.assertTrue; + +import com.android.tools.r8.R8TestCompileResult; +import com.android.tools.r8.TestBase; +import com.android.tools.r8.graph.DexAnnotationElement; +import com.android.tools.r8.graph.DexValue; +import com.android.tools.r8.graph.DexValue.DexValueArray; +import com.android.tools.r8.graph.DexValue.DexValueString; +import com.android.tools.r8.utils.DescriptorUtils; +import com.android.tools.r8.utils.StringUtils; +import com.android.tools.r8.utils.codeinspector.AnnotationSubject; +import com.android.tools.r8.utils.codeinspector.CodeInspector; +import com.android.tools.r8.utils.codeinspector.MethodSubject; +import java.lang.reflect.Method; +import java.lang.reflect.ParameterizedType; +import org.junit.Test; + +public class B124357885Test extends TestBase { + + private void checkSignatureAnnotation(CodeInspector inspector, AnnotationSubject signature) { + DexAnnotationElement[] elements = signature.getAnnotation().elements; + assertEquals(1, elements.length); + assertEquals("value", elements[0].name.toString()); + assertTrue(elements[0].value instanceof DexValueArray); + DexValueArray array = (DexValueArray) elements[0].value; + StringBuilder builder = new StringBuilder(); + for (DexValue value : array.getValues()) { + assertTrue(value instanceof DexValueString); + builder.append(((DexValueString) value).value); + } + String fooImplFinalDescriptor = + DescriptorUtils.javaTypeToDescriptor(inspector.clazz(FooImpl.class).getFinalName()); + StringBuilder expected = + new StringBuilder() + .append("()") + // Remove the final ; from the descriptor to add the generic type. + .append(fooImplFinalDescriptor.substring(0, fooImplFinalDescriptor.length() - 1)) + .append("<Ljava/lang/String;>") + // Add the ; after the generic type. + .append(";"); + assertEquals(expected.toString(), builder.toString()); + } + + @Test + public void test() throws Exception { + R8TestCompileResult compileResult = testForR8(Backend.DEX) + .addProgramClasses(Main.class, Service.class, Foo.class, FooImpl.class) + .addKeepMainRule(Main.class) + .addKeepRules("-keepattributes Signature,InnerClasses,EnclosingMethod") + .compile() + .inspect(inspector -> { + assertThat(inspector.clazz(Main.class), allOf(isPresent(), not(isRenamed()))); + assertThat(inspector.clazz(Service.class), allOf(isPresent(), isRenamed())); + assertThat(inspector.clazz(Foo.class), not(isPresent())); + assertThat(inspector.clazz(FooImpl.class), allOf(isPresent(), isRenamed())); + // TODO(124477502): Using uniqueMethodWithName("fooList") does not work. + assertEquals(1, inspector.clazz(Service.class).allMethods().size()); + MethodSubject fooList = inspector.clazz(Service.class).allMethods().get(0); + AnnotationSubject signature = fooList.annotation("dalvik.annotation.Signature"); + checkSignatureAnnotation(inspector, signature); + }); + + String fooImplFinalName = compileResult.inspector().clazz(FooImpl.class).getFinalName(); + + compileResult + .run(Main.class) + .assertSuccessWithOutput(StringUtils.lines(fooImplFinalName, fooImplFinalName)); + } +} + +class Main { + public static void main(String... args) throws Exception { + Method method = Service.class.getMethod("fooList"); + ParameterizedType type = (ParameterizedType) method.getGenericReturnType(); + Class<?> rawType = (Class<?>) type.getRawType(); + System.out.println(rawType.getName()); + + // Convince R8 we only use subtypes to get class merging of Foo into FooImpl. + Foo<String> foo = new FooImpl<>(); + System.out.println(foo.getClass().getCanonicalName()); + } +} + +interface Service { + Foo<String> fooList(); +} + +interface Foo<T> {} + +class FooImpl<T> implements Foo<T> {}
diff --git a/src/test/java/com/android/tools/r8/proguard/rules/ProguardMatchAllRuleWithPrefixTest.java b/src/test/java/com/android/tools/r8/proguard/rules/ProguardMatchAllRuleWithPrefixTest.java new file mode 100644 index 0000000..d5f456b --- /dev/null +++ b/src/test/java/com/android/tools/r8/proguard/rules/ProguardMatchAllRuleWithPrefixTest.java
@@ -0,0 +1,59 @@ +// Copyright (c) 2019, the R8 project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +package com.android.tools.r8.proguard.rules; + +import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent; +import static org.junit.Assert.assertThat; + +import com.android.tools.r8.TestBase; +import com.android.tools.r8.utils.codeinspector.ClassSubject; +import com.android.tools.r8.utils.codeinspector.CodeInspector; +import org.junit.Test; + +/** Regression test for b/124584385. */ +public class ProguardMatchAllRuleWithPrefixTest extends TestBase { + + @Test + public void test() throws Exception { + CodeInspector inspector = + testForR8(Backend.DEX) + .addProgramClasses(TestClass.class) + .addKeepRules( + "-keep,allowobfuscation class com.android.tools.r8.*** {", + " com.android.tools.r8.*** methodA();", + " com.android.tools.r8.***Class methodB();", + " com.android.tools.r8.***[] methodC();", + " com.android.tools.r8.***Class[] methodD();", + "}") + .compile() + .inspector(); + + ClassSubject classSubject = inspector.clazz(TestClass.class); + assertThat(classSubject, isPresent()); + assertThat(classSubject.uniqueMethodWithName("methodA"), isPresent()); + assertThat(classSubject.uniqueMethodWithName("methodB"), isPresent()); + assertThat(classSubject.uniqueMethodWithName("methodC"), isPresent()); + assertThat(classSubject.uniqueMethodWithName("methodD"), isPresent()); + } + + static class TestClass { + + TestClass methodA() { + return new TestClass(); + } + + TestClass methodB() { + return new TestClass(); + } + + TestClass[] methodC() { + return new TestClass[0]; + } + + TestClass[] methodD() { + return new TestClass[0]; + } + } +}
diff --git a/src/test/java/com/android/tools/r8/utils/codeinspector/AbsentMethodSubject.java b/src/test/java/com/android/tools/r8/utils/codeinspector/AbsentMethodSubject.java index 5eb2f22..d1249ab 100644 --- a/src/test/java/com/android/tools/r8/utils/codeinspector/AbsentMethodSubject.java +++ b/src/test/java/com/android/tools/r8/utils/codeinspector/AbsentMethodSubject.java
@@ -104,4 +104,9 @@ public boolean hasLocalVariableTable() { throw new Unreachable("Cannot determine if an absent method has a local variable table"); } + + @Override + public AnnotationSubject annotation(String name) { + return new AbsentAnnotationSubject(); + } }
diff --git a/src/test/java/com/android/tools/r8/utils/codeinspector/CodeInspector.java b/src/test/java/com/android/tools/r8/utils/codeinspector/CodeInspector.java index fe98075..43cbf20 100644 --- a/src/test/java/com/android/tools/r8/utils/codeinspector/CodeInspector.java +++ b/src/test/java/com/android/tools/r8/utils/codeinspector/CodeInspector.java
@@ -321,6 +321,14 @@ return obfuscatedTypeName != null ? obfuscatedTypeName : originalTypeName; } + String getOriginalTypeName(String minifiedTypeName) { + String originalTypeName = null; + if (mapping != null) { + originalTypeName = mapType(obfuscatedToOriginalMapping, minifiedTypeName); + } + return originalTypeName != null ? originalTypeName : minifiedTypeName; + } + InstructionSubject createInstructionSubject(Instruction instruction) { DexInstructionSubject dexInst = new DexInstructionSubject(instruction); if (dexInst.isInvoke()) {
diff --git a/src/test/java/com/android/tools/r8/utils/codeinspector/FoundMethodSubject.java b/src/test/java/com/android/tools/r8/utils/codeinspector/FoundMethodSubject.java index 5643091..544c8f8 100644 --- a/src/test/java/com/android/tools/r8/utils/codeinspector/FoundMethodSubject.java +++ b/src/test/java/com/android/tools/r8/utils/codeinspector/FoundMethodSubject.java
@@ -11,6 +11,7 @@ import com.android.tools.r8.errors.Unreachable; import com.android.tools.r8.graph.CfCode; import com.android.tools.r8.graph.Code; +import com.android.tools.r8.graph.DexAnnotation; import com.android.tools.r8.graph.DexCode; import com.android.tools.r8.graph.DexDebugEvent; import com.android.tools.r8.graph.DexDebugInfo; @@ -119,18 +120,14 @@ // X method(X) -> a // // whereas the final signature is for X.a is "a (a)" - String[] OriginalParameters = new String[signature.parameters.length]; - for (int i = 0; i < OriginalParameters.length; i++) { - String obfuscated = signature.parameters[i]; - String original = codeInspector.obfuscatedToOriginalMapping.get(obfuscated); - OriginalParameters[i] = original != null ? original : obfuscated; + String[] originalParameters = new String[signature.parameters.length]; + for (int i = 0; i < originalParameters.length; i++) { + originalParameters[i] = codeInspector.getOriginalTypeName(signature.parameters[i]); } - String obfuscatedReturnType = signature.type; - String originalReturnType = codeInspector.obfuscatedToOriginalMapping.get(obfuscatedReturnType); - String returnType = originalReturnType != null ? originalReturnType : obfuscatedReturnType; + String returnType = codeInspector.getOriginalTypeName(signature.type); MethodSignature lookupSignature = - new MethodSignature(signature.name, returnType, OriginalParameters); + new MethodSignature(signature.name, returnType, originalParameters); MemberNaming memberNaming = clazz.naming.lookup(lookupSignature); return memberNaming != null ? (MethodSignature) memberNaming.getOriginalSignature() : signature; @@ -261,4 +258,13 @@ public String toString() { return dexMethod.toSourceString(); } + + @Override + public AnnotationSubject annotation(String name) { + DexAnnotation annotation = codeInspector.findAnnotation(name, dexMethod.annotations); + return annotation == null + ? new AbsentAnnotationSubject() + : new FoundAnnotationSubject(annotation); + } + }
diff --git a/src/test/java/com/android/tools/r8/utils/codeinspector/MethodSubject.java b/src/test/java/com/android/tools/r8/utils/codeinspector/MethodSubject.java index 9cecb1d..a32097b 100644 --- a/src/test/java/com/android/tools/r8/utils/codeinspector/MethodSubject.java +++ b/src/test/java/com/android/tools/r8/utils/codeinspector/MethodSubject.java
@@ -65,4 +65,6 @@ public boolean isMethodSubject() { return true; } + + public abstract AnnotationSubject annotation(String name); }