Merge "Add test for signature annotation with vertical class merging"
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..3112ae7
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/naming/b124357885/B124357885Test.java
@@ -0,0 +1,97 @@
+// 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.containsString;
+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.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.codeinspector.AnnotationSubject;
+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(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);
+ }
+ // TODO(124357885): This should be the minified name for FooImpl instead of Foo.
+ String fooDescriptor = DescriptorUtils.javaTypeToDescriptor(Foo.class.getTypeName());
+ StringBuilder expected =
+ new StringBuilder()
+ .append("()")
+ .append(fooDescriptor.substring(0, fooDescriptor.length() - 1)) // Remove the ;.
+ .append("<Ljava/lang/String;>")
+ .append(";"); // Add the ; here.
+ assertEquals(expected.toString(), builder.toString());
+ }
+
+ @Test
+ public void test() throws Exception {
+ 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(signature);
+ })
+ .run(Main.class)
+ .assertFailureWithErrorThatMatches(
+ containsString(
+ "java.lang.ClassNotFoundException: "
+ + "Didn't find class \"com.android.tools.r8.naming.b124357885.Foo\""));
+ }
+}
+
+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);
+ }
+}
+
+interface Service {
+ Foo<String> fooList();
+}
+
+interface Foo<T> {}
+
+class FooImpl<T> implements Foo<T> {}
\ No newline at end of file
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 8e24088..87ae2ec 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
@@ -116,4 +116,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/FoundMethodSubject.java b/src/test/java/com/android/tools/r8/utils/codeinspector/FoundMethodSubject.java
index 796532d..6581a47 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
@@ -12,6 +12,7 @@
import com.android.tools.r8.graph.AppInfo;
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;
@@ -283,4 +284,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 8fb4001..1575372 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
@@ -72,4 +72,6 @@
public boolean isMethodSubject() {
return true;
}
+
+ public abstract AnnotationSubject annotation(String name);
}