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