Fix bridge insertion for code with illegal access errors
Change-Id: If47d870a713ab21679311e697f3e448c020ce524
diff --git a/src/main/java/com/android/tools/r8/optimize/MemberRebindingAnalysis.java b/src/main/java/com/android/tools/r8/optimize/MemberRebindingAnalysis.java
index 7fcedfc..42adbc6 100644
--- a/src/main/java/com/android/tools/r8/optimize/MemberRebindingAnalysis.java
+++ b/src/main/java/com/android/tools/r8/optimize/MemberRebindingAnalysis.java
@@ -323,7 +323,10 @@
|| !packageDescriptor.equals(target.getHolderType().getPackageDescriptor())) {
DexClass bridgeHolder =
findHolderForVisibilityBridge(originalClass, target.getHolder(), packageDescriptor);
- assert bridgeHolder != null;
+ if (bridgeHolder == null) {
+ // The original class does not have access to the target so we cannot insert a valid bridge.
+ return target.getReference().withHolder(originalClass, appView.dexItemFactory());
+ }
if (bridgeHolder.isClasspathClass()) {
// Intentionally empty. We do not need to insert a bridge on a classpath class.
} else if (bridgeHolder.isLibraryClass()) {
diff --git a/src/test/java/com/android/tools/r8/memberrebinding/MemberRebindingClasspathSplitTest.java b/src/test/java/com/android/tools/r8/memberrebinding/MemberRebindingClasspathSplitTest.java
index e87a04d..89d12eb 100644
--- a/src/test/java/com/android/tools/r8/memberrebinding/MemberRebindingClasspathSplitTest.java
+++ b/src/test/java/com/android/tools/r8/memberrebinding/MemberRebindingClasspathSplitTest.java
@@ -8,6 +8,8 @@
import com.android.tools.r8.TestCompileResult;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.ThrowableConsumer;
+import com.android.tools.r8.ToolHelper.DexVm.Version;
+import com.android.tools.r8.graph.AccessFlags;
import com.android.tools.r8.memberrebinding.testclasses.MemberRebindingClasspathSplitTestClasses;
import com.google.common.collect.ImmutableList;
import java.util.List;
@@ -24,20 +26,22 @@
private static class TestConfig {
private final String desc;
-
private final ThrowableConsumer<? super TestBuilder<?, ?>> addToClasspath;
private final ThrowableConsumer<? super TestBuilder<?, ?>> addToProgrampath;
private final ThrowableConsumer<? super TestCompileResult<?, ?>> addToRunClasspath;
+ private final boolean expectFailure;
private TestConfig(
String desc,
ThrowableConsumer<? super TestBuilder<?, ?>> addToClasspath,
ThrowableConsumer<? super TestBuilder<?, ?>> addToProgrampath,
- ThrowableConsumer<? super TestCompileResult<?, ?>> addToRunClasspath) {
+ ThrowableConsumer<? super TestCompileResult<?, ?>> addToRunClasspath,
+ boolean expectFailure) {
this.desc = desc;
this.addToClasspath = addToClasspath;
this.addToProgrampath = addToProgrampath;
this.addToRunClasspath = addToRunClasspath;
+ this.expectFailure = expectFailure;
}
@Override
@@ -66,7 +70,8 @@
b.addRunClasspathClasses(
MemberRebindingClasspathSplitTestClasses.getA(),
MemberRebindingClasspathSplitTestClasses.getB());
- }),
+ },
+ false),
new TestConfig(
"Both A and B on classpath, m() bridge removed from B",
b -> {
@@ -83,7 +88,8 @@
transformer(MemberRebindingClasspathSplitTestClasses.getB())
.removeMethodsWithName("m")
.transform());
- }),
+ },
+ false),
new TestConfig(
"A on classpath and B on programpath",
b -> {
@@ -94,7 +100,8 @@
},
b -> {
b.addRunClasspathClasses(MemberRebindingClasspathSplitTestClasses.getA());
- }),
+ },
+ false),
new TestConfig(
"A on classpath and B on programpath, m() bridge removed from B",
b -> {
@@ -108,7 +115,26 @@
},
b -> {
b.addRunClasspathClasses(MemberRebindingClasspathSplitTestClasses.getA());
- })));
+ },
+ false),
+ new TestConfig(
+ "Both A and B on classpath but neither A or B is public",
+ b -> {
+ b.addClasspathClasses(MemberRebindingClasspathSplitTestClasses.getA());
+ b.addClasspathClassFileData(
+ transformer(MemberRebindingClasspathSplitTestClasses.getB())
+ .setAccessFlags(AccessFlags::unsetPublic)
+ .transform());
+ },
+ b -> {},
+ b -> {
+ b.addRunClasspathClasses(MemberRebindingClasspathSplitTestClasses.getA());
+ b.addRunClasspathClassFileData(
+ transformer(MemberRebindingClasspathSplitTestClasses.getB())
+ .setAccessFlags(AccessFlags::unsetPublic)
+ .transform());
+ },
+ true)));
}
@Test
@@ -124,7 +150,12 @@
.compile()
.apply(split.addToRunClasspath)
.run(parameters.getRuntime(), Main.class)
- .assertSuccessWithOutputLines("A", "A");
+ .applyIf(
+ split.expectFailure && parameters.isDexRuntimeVersionOlderThanOrEqual(Version.V4_4_4),
+ rr -> rr.assertFailureWithErrorThatThrows(NoClassDefFoundError.class),
+ split.expectFailure,
+ rr -> rr.assertFailureWithErrorThatThrows(IllegalAccessError.class),
+ rr -> rr.assertSuccessWithOutputLines("A", "A"));
}
public static class C extends MemberRebindingClasspathSplitTestClasses.B {