Merge "Use lookupMethodInAllContexts in rewriteMixedItems"
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 2b51720..dae98ad 100644
--- a/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
+++ b/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
@@ -1651,7 +1651,7 @@
rewriteKeysWhileMergingValues(previous.staticFieldWrites, lense::lookupField);
this.fieldsRead = rewriteItems(previous.fieldsRead, lense::lookupField);
this.fieldsWritten = rewriteItems(previous.fieldsWritten, lense::lookupField);
- this.pinnedItems = rewriteMixedItems(previous.pinnedItems, lense);
+ this.pinnedItems = rewriteMixedItemsConservatively(previous.pinnedItems, lense);
this.virtualInvokes = rewriteMethodsConservatively(previous.virtualInvokes, lense);
this.interfaceInvokes = rewriteMethodsConservatively(previous.interfaceInvokes, lense);
this.superInvokes = rewriteMethodsConservatively(previous.superInvokes, lense);
@@ -1665,7 +1665,8 @@
this.assumedValues = previous.assumedValues;
assert assertNotModifiedByLense(previous.alwaysInline, lense);
this.alwaysInline = previous.alwaysInline;
- this.identifierNameStrings = rewriteMixedItems(previous.identifierNameStrings, lense);
+ this.identifierNameStrings =
+ rewriteMixedItemsConservatively(previous.identifierNameStrings, lense);
// Switchmap classes should never be affected by renaming.
assert assertNotModifiedByLense(
previous.switchMaps.keySet().stream().map(this::definitionFor).filter(Objects::nonNull)
@@ -1846,7 +1847,7 @@
return Collections.unmodifiableMap(result);
}
- private static ImmutableSet<DexItem> rewriteMixedItems(
+ private static ImmutableSet<DexItem> rewriteMixedItemsConservatively(
Set<DexItem> original, GraphLense lense) {
ImmutableSet.Builder<DexItem> builder = ImmutableSet.builder();
for (DexItem item : original) {
@@ -1854,7 +1855,12 @@
if (item instanceof DexType) {
builder.add(lense.lookupType((DexType) item));
} else if (item instanceof DexMethod) {
- builder.add(lense.lookupMethod((DexMethod) item));
+ DexMethod method = (DexMethod) item;
+ if (lense.isContextFreeForMethod(method)) {
+ builder.add(lense.lookupMethod(method));
+ } else {
+ builder.addAll(lense.lookupMethodInAllContexts(method));
+ }
} else if (item instanceof DexField) {
builder.add(lense.lookupField((DexField) item));
} else {
diff --git a/src/test/examples/classmerging/RewritePinnedMethodTest.java b/src/test/examples/classmerging/RewritePinnedMethodTest.java
new file mode 100644
index 0000000..3d25805
--- /dev/null
+++ b/src/test/examples/classmerging/RewritePinnedMethodTest.java
@@ -0,0 +1,41 @@
+// Copyright (c) 2018, 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 classmerging;
+
+public class RewritePinnedMethodTest {
+
+ public static void main(String[] args) {
+ C obj = new C();
+ obj.m();
+ }
+
+ // A.m is pinned by a keep rule, to prevent it from being merged into B.
+ public static class A {
+ public void m() {
+ System.out.println("In A.m");
+ }
+ }
+
+ // B is merged into C.
+ public static class B extends A {
+ @Override
+ public void m() {
+ System.out.println("In B.m");
+ super.m();
+ }
+ }
+
+ public static class C extends B {
+ @Override
+ public void m() {
+ System.out.println("In C.m");
+ // This invocation is changed from invoke-super to invoke-direct. It would be valid for this
+ // instruction to be on the form "invoke-super A.m". Therefore, the graph lense contains a
+ // mapping for "A.m" from (context: "C.m", type: SUPER) to C.m$B, where the method C.m$B is
+ // the direct method that gets created for B.m during vertical class merging.
+ super.m();
+ }
+ }
+}
diff --git a/src/test/examples/classmerging/keep-rules.txt b/src/test/examples/classmerging/keep-rules.txt
index 01e35f3..1a20ce3 100644
--- a/src/test/examples/classmerging/keep-rules.txt
+++ b/src/test/examples/classmerging/keep-rules.txt
@@ -13,6 +13,9 @@
-keep public class classmerging.ExceptionTest {
public static void main(...);
}
+-keep public class classmerging.RewritePinnedMethodTest {
+ public static void main(...);
+}
-keep public class classmerging.SimpleInterfaceAccessTest {
public static void main(...);
}
diff --git a/src/test/java/com/android/tools/r8/classmerging/ClassMergingTest.java b/src/test/java/com/android/tools/r8/classmerging/ClassMergingTest.java
index 7016163..58b87c0 100644
--- a/src/test/java/com/android/tools/r8/classmerging/ClassMergingTest.java
+++ b/src/test/java/com/android/tools/r8/classmerging/ClassMergingTest.java
@@ -289,6 +289,30 @@
"-keep public class classmerging.pkg.SimpleInterfaceImplRetriever"));
}
+ @Ignore("b/73958515")
+ @Test
+ public void testRewritePinnedMethod() throws Exception {
+ String main = "classmerging.RewritePinnedMethodTest";
+ Path[] programFiles =
+ new Path[] {
+ CF_DIR.resolve("RewritePinnedMethodTest.class"),
+ CF_DIR.resolve("RewritePinnedMethodTest$A.class"),
+ CF_DIR.resolve("RewritePinnedMethodTest$B.class"),
+ CF_DIR.resolve("RewritePinnedMethodTest$C.class")
+ };
+ Set<String> preservedClassNames =
+ ImmutableSet.of(
+ "classmerging.RewritePinnedMethodTest",
+ "classmerging.RewritePinnedMethodTest$A",
+ "classmerging.RewritePinnedMethodTest$C");
+ runTest(
+ main,
+ programFiles,
+ preservedClassNames,
+ getProguardConfig(
+ EXAMPLE_KEEP, "-keep class classmerging.RewritePinnedMethodTest$A { *; }"));
+ }
+
@Test
public void testTemplateMethodPattern() throws Exception {
String main = "classmerging.TemplateMethodTest";