Merge "Fix testR8LibCompatibility by renaming dependency jar"
diff --git a/src/main/java/com/android/tools/r8/R8.java b/src/main/java/com/android/tools/r8/R8.java
index 737505c..30b57da 100644
--- a/src/main/java/com/android/tools/r8/R8.java
+++ b/src/main/java/com/android/tools/r8/R8.java
@@ -363,12 +363,15 @@
}
if (options.getProguardConfiguration().isAccessModificationAllowed()) {
- appView.setGraphLense(
- ClassAndMemberPublicizer.run(executorService, timing, application, appView, rootSet));
- // We can now remove visibility bridges. Note that we do not need to update the
- // invoke-targets here, as the existing invokes will simply dispatch to the now
- // visible super-method. MemberRebinding, if run, will then dispatch it correctly.
- application = new VisibilityBridgeRemover(appView.appInfo(), application).run();
+ GraphLense publicizedLense =
+ ClassAndMemberPublicizer.run(executorService, timing, application, appView, rootSet);
+ if (publicizedLense != appView.graphLense()) {
+ appView.setGraphLense(publicizedLense);
+ // We can now remove visibility bridges. Note that we do not need to update the
+ // invoke-targets here, as the existing invokes will simply dispatch to the now
+ // visible super-method. MemberRebinding, if run, will then dispatch it correctly.
+ application = new VisibilityBridgeRemover(appView.appInfo(), application).run();
+ }
}
// Build conservative main dex content before first round of tree shaking. This is used
diff --git a/src/main/java/com/android/tools/r8/graph/JarCode.java b/src/main/java/com/android/tools/r8/graph/JarCode.java
index 04e6516..85cde7c 100644
--- a/src/main/java/com/android/tools/r8/graph/JarCode.java
+++ b/src/main/java/com/android/tools/r8/graph/JarCode.java
@@ -282,7 +282,6 @@
ReparseContext context = this.context;
parseCode(context, false);
if (hasJsr(context)) {
- System.out.println("JarCode: JSR encountered; reparse using JSRInlinerAdapter");
parseCode(context, true);
assert !hasJsr(context);
}
diff --git a/src/main/java/com/android/tools/r8/optimize/PublicizerLense.java b/src/main/java/com/android/tools/r8/optimize/PublicizerLense.java
index e51b38d..2db2dce 100644
--- a/src/main/java/com/android/tools/r8/optimize/PublicizerLense.java
+++ b/src/main/java/com/android/tools/r8/optimize/PublicizerLense.java
@@ -11,7 +11,7 @@
import com.android.tools.r8.graph.GraphLense.NestedGraphLense;
import com.android.tools.r8.ir.code.Invoke.Type;
import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Sets;
import java.util.Set;
final class PublicizerLense extends NestedGraphLense {
@@ -63,17 +63,20 @@
}
static class PublicizedLenseBuilder {
- private final ImmutableSet.Builder<DexMethod> methodSetBuilder = ImmutableSet.builder();
+ private final Set<DexMethod> publicizedMethods = Sets.newIdentityHashSet();
private PublicizedLenseBuilder() {
}
public GraphLense build(AppView appView) {
- return new PublicizerLense(appView, methodSetBuilder.build());
+ if (publicizedMethods.isEmpty()) {
+ return appView.graphLense();
+ }
+ return new PublicizerLense(appView, publicizedMethods);
}
public void add(DexMethod publicizedMethod) {
- methodSetBuilder.add(publicizedMethod);
+ publicizedMethods.add(publicizedMethod);
}
}
}
diff --git a/src/main/java/com/android/tools/r8/shaking/Enqueuer.java b/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
index 673314d..adc6979 100644
--- a/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
+++ b/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
@@ -2832,23 +2832,27 @@
}
ClassGraphNode getClassGraphNode(DexType type) {
- return classNodes.computeIfAbsent(type,
- t -> new ClassGraphNode(
- appInfo.definitionFor(type).isLibraryClass(),
- Reference.classFromDescriptor(t.toDescriptorString())));
+ return classNodes.computeIfAbsent(
+ type,
+ t -> {
+ DexClass definition = appInfo.definitionFor(t);
+ return new ClassGraphNode(
+ definition != null && definition.isLibraryClass(),
+ Reference.classFromDescriptor(t.toDescriptorString()));
+ });
}
MethodGraphNode getMethodGraphNode(DexMethod context) {
return methodNodes.computeIfAbsent(
context,
m -> {
- boolean isLibraryNode = appInfo.definitionFor(context.holder).isLibraryClass();
+ DexClass holderDefinition = appInfo.definitionFor(context.holder);
Builder<TypeReference> builder = ImmutableList.builder();
for (DexType param : m.proto.parameters.values) {
builder.add(Reference.typeFromDescriptor(param.toDescriptorString()));
}
return new MethodGraphNode(
- isLibraryNode,
+ holderDefinition != null && holderDefinition.isLibraryClass(),
Reference.method(
Reference.classFromDescriptor(m.holder.toDescriptorString()),
m.name.toString(),
@@ -2862,13 +2866,15 @@
FieldGraphNode getFieldGraphNode(DexField context) {
return fieldNodes.computeIfAbsent(
context,
- f ->
- new FieldGraphNode(
- appInfo.definitionFor(context.getHolder()).isLibraryClass(),
- Reference.field(
- Reference.classFromDescriptor(f.getHolder().toDescriptorString()),
- f.name.toString(),
- Reference.typeFromDescriptor(f.type.toDescriptorString()))));
+ f -> {
+ DexClass holderDefinition = appInfo.definitionFor(context.getHolder());
+ return new FieldGraphNode(
+ holderDefinition != null && holderDefinition.isLibraryClass(),
+ Reference.field(
+ Reference.classFromDescriptor(f.getHolder().toDescriptorString()),
+ f.name.toString(),
+ Reference.typeFromDescriptor(f.type.toDescriptorString())));
+ });
}
KeepRuleGraphNode getKeepRuleGraphNode(ProguardKeepRule rule) {
diff --git a/src/test/java/com/android/tools/r8/shaking/keptgraph/RemovedClassTest.java b/src/test/java/com/android/tools/r8/shaking/keptgraph/RemovedClassTest.java
new file mode 100644
index 0000000..5992eff
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/shaking/keptgraph/RemovedClassTest.java
@@ -0,0 +1,25 @@
+// 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.shaking.keptgraph;
+
+import com.android.tools.r8.NeverInline;
+
+public class RemovedClassTest {
+
+ public static class RemovedInnerClass {}
+
+ public static void main(String[] args) {
+ bar();
+ }
+
+ @NeverInline
+ public static void bar() {
+ System.out.println("called bar");
+ }
+
+ @NeverInline
+ public static void baz() {
+ System.out.println("called baz, created " + new RemovedClassTest().getClass().getSimpleName());
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/shaking/keptgraph/RemovedClassTestRunner.java b/src/test/java/com/android/tools/r8/shaking/keptgraph/RemovedClassTestRunner.java
new file mode 100644
index 0000000..c555b7e
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/shaking/keptgraph/RemovedClassTestRunner.java
@@ -0,0 +1,84 @@
+// 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.shaking.keptgraph;
+
+import static com.android.tools.r8.references.Reference.classFromClass;
+import static com.android.tools.r8.references.Reference.methodFromMethod;
+import static org.junit.Assert.assertEquals;
+
+import com.android.tools.r8.R8TestCompileResult;
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.origin.Origin;
+import com.android.tools.r8.references.MethodReference;
+import com.android.tools.r8.utils.StringUtils;
+import com.android.tools.r8.utils.graphinspector.GraphInspector;
+import com.android.tools.r8.utils.graphinspector.GraphInspector.QueryNode;
+import com.google.common.collect.ImmutableList;
+import java.io.ByteArrayOutputStream;
+import java.io.PrintStream;
+import java.nio.charset.StandardCharsets;
+import java.util.List;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+
+@RunWith(Parameterized.class)
+public class RemovedClassTestRunner extends TestBase {
+
+ private static final Class<?> CLASS = RemovedClassTest.class;
+ private static final Class<?> REMOVED_CLASS = RemovedClassTest.RemovedInnerClass.class;
+ private static final List<Class<?>> CLASSES = ImmutableList.of(CLASS, REMOVED_CLASS);
+
+ private static final String EXPECTED = StringUtils.lines("called bar");
+
+ private final Backend backend;
+
+ @Parameters(name = "{0}")
+ public static Backend[] data() {
+ return Backend.values();
+ }
+
+ public RemovedClassTestRunner(Backend backend) {
+ this.backend = backend;
+ }
+
+ @Test
+ public void testRemovedClass() throws Exception {
+ MethodReference mainMethod = methodFromMethod(CLASS.getDeclaredMethod("main", String[].class));
+ MethodReference barMethod = methodFromMethod(CLASS.getDeclaredMethod("bar"));
+ MethodReference bazMethod = methodFromMethod(CLASS.getDeclaredMethod("baz"));
+
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ R8TestCompileResult compileResult =
+ testForR8(backend)
+ .enableGraphInspector()
+ .enableInliningAnnotations()
+ .addProgramClasses(CLASSES)
+ .addKeepMethodRules(mainMethod)
+ .addKeepRules("-whyareyoukeeping class " + REMOVED_CLASS.getTypeName())
+ .redirectStdOut(new PrintStream(baos))
+ .compile();
+ String expectedOutput = StringUtils.lines("Nothing is keeping " + REMOVED_CLASS.getTypeName());
+ String compileOutput = new String(baos.toByteArray(), StandardCharsets.UTF_8);
+ assertEquals(expectedOutput, compileOutput);
+
+ GraphInspector inspector =
+ compileResult.run(CLASS).assertSuccessWithOutput(EXPECTED).graphInspector();
+
+ // The only root should be the keep main-method rule.
+ assertEquals(1, inspector.getRoots().size());
+ QueryNode root = inspector.rule(Origin.unknown(), 1, 1).assertRoot();
+
+ // Check that the call chain goes from root -> main(unchanged) -> bar(renamed).
+ inspector.method(barMethod).assertRenamed().assertInvokedFrom(mainMethod);
+ inspector.method(mainMethod).assertNotRenamed().assertKeptBy(root);
+
+ // Check baz is removed.
+ inspector.method(bazMethod).assertAbsent();
+
+ // Check that the inner class is removed.
+ inspector.clazz(classFromClass(REMOVED_CLASS)).assertAbsent();
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/shaking/whyareyoukeeping/WhyAreYouKeepingTest.java b/src/test/java/com/android/tools/r8/shaking/whyareyoukeeping/WhyAreYouKeepingTest.java
index 867d346..2a5a6f6 100644
--- a/src/test/java/com/android/tools/r8/shaking/whyareyoukeeping/WhyAreYouKeepingTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/whyareyoukeeping/WhyAreYouKeepingTest.java
@@ -5,6 +5,7 @@
package com.android.tools.r8.shaking.whyareyoukeeping;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
import com.android.tools.r8.CompilationFailedException;
import com.android.tools.r8.NeverInline;
@@ -127,4 +128,35 @@
String output = new String(baos.toByteArray(), StandardCharsets.UTF_8);
assertEquals(expectedPathToBaz, output);
}
+
+ @Test
+ public void testNonExistentClassWhyAreYouKeepingViaProguardConfig() throws Exception {
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ testForR8(backend)
+ .addProgramClasses(A.class)
+ .addKeepMethodRules(Reference.methodFromMethod(A.class.getMethod("foo")))
+ .addKeepRules("-whyareyoukeeping class NonExistentClass")
+ // Redirect the compilers stdout to intercept the '-whyareyoukeeping' output
+ .redirectStdOut(new PrintStream(baos))
+ .compile();
+ String output = new String(baos.toByteArray(), StandardCharsets.UTF_8);
+ // Expected outcome is empty.
+ assertEquals("", output);
+ }
+
+ @Test
+ public void testNonExistentMethodWhyAreYouKeepingViaProguardConfig() throws Exception {
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ String aName = A.class.getTypeName();
+ testForR8(backend)
+ .addProgramClasses(A.class)
+ .addKeepMethodRules(Reference.methodFromMethod(A.class.getMethod("foo")))
+ .addKeepRules("-whyareyoukeeping class " + aName + " { nonExistentMethod(); }")
+ // Redirect the compilers stdout to intercept the '-whyareyoukeeping' output
+ .redirectStdOut(new PrintStream(baos))
+ .compile();
+ String output = new String(baos.toByteArray(), StandardCharsets.UTF_8);
+ // Expected outcome is empty.
+ assertFalse("b/122820741", output.isEmpty());
+ }
}