Don't rebind within the library
Bug: 135627418
Change-Id: Idb9e245aa18d4ca7bbc30500f02422bd40ea0fb6
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/LensCodeRewriter.java b/src/main/java/com/android/tools/r8/ir/conversion/LensCodeRewriter.java
index a8596b0..f957d81 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/LensCodeRewriter.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/LensCodeRewriter.java
@@ -627,7 +627,10 @@
// Most likely due to a missing class, or invoke is already as specific as it gets.
return target;
}
- if (!canInvokeTargetWithInvokeVirtual(newTarget)
+ DexClass newTargetClass = appView.definitionFor(newTarget.method.holder);
+ if (newTargetClass == null
+ || newTargetClass.isLibraryClass()
+ || !canInvokeTargetWithInvokeVirtual(newTarget)
|| !hasAccessToInvokeTargetFromContext(newTarget, context)) {
// Not safe to invoke `newTarget` with virtual invoke from the current context.
return target;
diff --git a/src/test/java/com/android/tools/r8/memberrebinding/b135627418/B135627418.java b/src/test/java/com/android/tools/r8/memberrebinding/b135627418/B135627418.java
new file mode 100644
index 0000000..5935d18
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/memberrebinding/b135627418/B135627418.java
@@ -0,0 +1,108 @@
+// 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.memberrebinding.b135627418;
+
+import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.junit.Assert.assertTrue;
+
+import com.android.tools.r8.D8TestCompileResult;
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.memberrebinding.b135627418.library.Drawable;
+import com.android.tools.r8.memberrebinding.b135627418.library.DrawableWrapper;
+import com.android.tools.r8.memberrebinding.b135627418.library.InsetDrawable;
+import com.android.tools.r8.utils.codeinspector.ClassSubject;
+import com.android.tools.r8.utils.codeinspector.CodeInspector;
+import com.android.tools.r8.utils.codeinspector.InstructionSubject;
+import com.android.tools.r8.utils.codeinspector.InvokeInstructionSubject;
+import com.google.common.collect.ImmutableMap;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+@RunWith(Parameterized.class)
+public class B135627418 extends TestBase {
+
+ private final TestParameters parameters;
+
+ @Parameterized.Parameters(name = "{0}")
+ public static TestParametersCollection data() {
+ // Only run on dex, as the runtime library used in the test is built as dex.
+ return getTestParameters().withDexRuntimes().build();
+ }
+
+ public B135627418(TestParameters parameters) {
+ this.parameters = parameters;
+ }
+
+ private void noInvokeToDrawableWrapper(CodeInspector inspector) {
+ ClassSubject classSubject = inspector.clazz(TestClass.class);
+ assertThat(classSubject, isPresent());
+ assertTrue(
+ classSubject
+ .uniqueMethodWithName("main")
+ .streamInstructions()
+ .filter(InstructionSubject::isInvokeVirtual)
+ .noneMatch(
+ instruction ->
+ ((InvokeInstructionSubject) instruction)
+ .invokedMethod()
+ .holder
+ .getName()
+ .contains("DrawableWrapper")));
+ }
+
+ @Test
+ public void dontRebindWithinLibrary() throws Exception {
+ String packageName = getClass().getPackage().getName();
+
+ // Build a runtime library without DrawableWrapper, where InsetDrawable inherits directly
+ // from Drawable. Use the prefix rewriting to move the InsetDrawable from package runtime to
+ // package library. This creates a mock of the structure of classes android.drawable.Drawable,
+ // android.drawable.DrawableWrapper and android.drawable.InsetDrawable. The class
+ // android.drawable.DrawableWrapper was introduced in API level 23 between
+ // android.drawable.Drawable and android.drawable.InsetDrawable, so present at compile time,
+ // but not at runtime on pre API level 23 devices.
+ D8TestCompileResult runtimeLibrary =
+ testForD8()
+ .addProgramClasses(
+ Drawable.class,
+ com.android.tools.r8.memberrebinding.b135627418.runtime.InsetDrawable.class)
+ .setMinApi(parameters.getRuntime())
+ .addOptionsModification(
+ options ->
+ options.rewritePrefix =
+ ImmutableMap.of(packageName + ".runtime", packageName + ".library"))
+ .compile();
+
+ testForR8(parameters.getBackend())
+ .addLibraryFiles(runtimeJar(parameters.getBackend()))
+ .addLibraryClasses(Drawable.class, DrawableWrapper.class, InsetDrawable.class)
+ .addProgramClasses(TestClass.class)
+ .addKeepMainRule(TestClass.class)
+ .setMinApi(parameters.getRuntime())
+ .compile()
+ .disassemble()
+ .inspect(this::noInvokeToDrawableWrapper)
+ .addRunClasspathFiles(runtimeLibrary.writeToZip())
+ .run(parameters.getRuntime(), TestClass.class)
+ .assertSuccessWithOutputLines("In InsetDrawable.setAlpha");
+ }
+
+ static class TestClass {
+
+ public static void main(String[] args) {
+ Drawable drawable;
+ if (args.length == 0) {
+ drawable = new InsetDrawable();
+ } else {
+ drawable = new InsetDrawable();
+ }
+ drawable.setAlpha(0);
+ }
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/memberrebinding/b135627418/library/Drawable.java b/src/test/java/com/android/tools/r8/memberrebinding/b135627418/library/Drawable.java
new file mode 100644
index 0000000..c606ff2
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/memberrebinding/b135627418/library/Drawable.java
@@ -0,0 +1,10 @@
+// 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.memberrebinding.b135627418.library;
+
+// android.graphics.drawable.Drawable
+public abstract class Drawable {
+ public abstract void setAlpha(int alpha);
+}
diff --git a/src/test/java/com/android/tools/r8/memberrebinding/b135627418/library/DrawableWrapper.java b/src/test/java/com/android/tools/r8/memberrebinding/b135627418/library/DrawableWrapper.java
new file mode 100644
index 0000000..d11d888
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/memberrebinding/b135627418/library/DrawableWrapper.java
@@ -0,0 +1,12 @@
+// 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.memberrebinding.b135627418.library;
+
+// android.graphics.drawable.DrawableWrapper
+public class DrawableWrapper extends Drawable {
+ public void setAlpha(int alpha) {
+ System.out.println("In DrawableWrapper.setAlpha");
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/memberrebinding/b135627418/library/InsetDrawable.java b/src/test/java/com/android/tools/r8/memberrebinding/b135627418/library/InsetDrawable.java
new file mode 100644
index 0000000..c24de97
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/memberrebinding/b135627418/library/InsetDrawable.java
@@ -0,0 +1,8 @@
+// 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.memberrebinding.b135627418.library;
+
+// android.graphics.drawable.InsetDrawable
+public class InsetDrawable extends DrawableWrapper {}
diff --git a/src/test/java/com/android/tools/r8/memberrebinding/b135627418/runtime/InsetDrawable.java b/src/test/java/com/android/tools/r8/memberrebinding/b135627418/runtime/InsetDrawable.java
new file mode 100644
index 0000000..6cffd08
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/memberrebinding/b135627418/runtime/InsetDrawable.java
@@ -0,0 +1,14 @@
+// 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.memberrebinding.b135627418.runtime;
+
+import com.android.tools.r8.memberrebinding.b135627418.library.Drawable;
+
+// android.graphics.drawable.InsetDrawable
+public class InsetDrawable extends Drawable {
+ public void setAlpha(int alpha) {
+ System.out.println("In InsetDrawable.setAlpha");
+ }
+}