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