Regression test for retaining illegal access across isolated split
Bug: b/300247439
Change-Id: Ia7b86542d5e818deb3ed373f0da59b86a2269384
diff --git a/src/main/java/com/android/tools/r8/features/IsolatedFeatureSplitsChecker.java b/src/main/java/com/android/tools/r8/features/IsolatedFeatureSplitsChecker.java
index 840b82a..1043723 100644
--- a/src/main/java/com/android/tools/r8/features/IsolatedFeatureSplitsChecker.java
+++ b/src/main/java/com/android/tools/r8/features/IsolatedFeatureSplitsChecker.java
@@ -3,6 +3,7 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.features;
+import com.android.tools.r8.errors.dontwarn.DontWarnConfiguration;
import com.android.tools.r8.features.diagnostic.IllegalAccessWithIsolatedFeatureSplitsDiagnostic;
import com.android.tools.r8.graph.AppInfoWithClassHierarchy;
import com.android.tools.r8.graph.AppView;
@@ -75,12 +76,17 @@
}
private void checkAccess(ProgramDefinition accessedItem, ProgramMethod context) {
- if (!features.isInSameFeature(accessedItem, context, appView)
- && !accessedItem.getAccessFlags().isPublic()) {
- appView
- .reporter()
- .error(new IllegalAccessWithIsolatedFeatureSplitsDiagnostic(accessedItem, context));
+ if (accessedItem.getAccessFlags().isPublic()
+ || features.isInSameFeature(accessedItem, context, appView)) {
+ return;
}
+ DontWarnConfiguration dontWarnConfiguration = appView.getDontWarnConfiguration();
+ if (dontWarnConfiguration.matches(accessedItem) || dontWarnConfiguration.matches(context)) {
+ return;
+ }
+ appView
+ .reporter()
+ .error(new IllegalAccessWithIsolatedFeatureSplitsDiagnostic(accessedItem, context));
}
// Field accesses.
diff --git a/src/test/java/com/android/tools/r8/features/PreserveIllegalAccessAcrossIsolatedSplitBoundaryTest.java b/src/test/java/com/android/tools/r8/features/PreserveIllegalAccessAcrossIsolatedSplitBoundaryTest.java
new file mode 100644
index 0000000..d6edc0b
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/features/PreserveIllegalAccessAcrossIsolatedSplitBoundaryTest.java
@@ -0,0 +1,98 @@
+// Copyright (c) 2023, 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.features;
+
+import static com.android.tools.r8.utils.codeinspector.CodeMatchers.invokesMethod;
+import static com.android.tools.r8.utils.codeinspector.Matchers.isAbsent;
+import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
+import static org.hamcrest.MatcherAssert.assertThat;
+
+import com.android.tools.r8.NeverInline;
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.utils.BooleanUtils;
+import com.android.tools.r8.utils.Box;
+import com.android.tools.r8.utils.codeinspector.ClassSubject;
+import com.android.tools.r8.utils.codeinspector.CodeInspector;
+import com.android.tools.r8.utils.codeinspector.MethodSubject;
+import java.util.List;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
+import org.junit.runners.Parameterized.Parameters;
+
+@RunWith(Parameterized.class)
+public class PreserveIllegalAccessAcrossIsolatedSplitBoundaryTest extends TestBase {
+
+ @Parameter(0)
+ public boolean enableIsolatedSplits;
+
+ @Parameter(1)
+ public TestParameters parameters;
+
+ @Parameters(name = "{1}, isolated splits: {0}")
+ public static List<Object[]> data() {
+ return buildParameters(
+ BooleanUtils.values(), getTestParameters().withDexRuntimesAndAllApiLevels().build());
+ }
+
+ @Test
+ public void test() throws Exception {
+ Box<CodeInspector> baseInspectorBox = new Box<>();
+ testForR8(parameters.getBackend())
+ .addProgramClasses(Base.class)
+ .addKeepClassRules(Base.class)
+ .addFeatureSplit(Feature.class)
+ .addKeepClassAndMembersRules(Feature.class)
+ .applyIf(enableIsolatedSplits, testBuilder -> testBuilder.addDontWarn(Feature.class))
+ .enableIsolatedSplits(enableIsolatedSplits)
+ .enableInliningAnnotations()
+ .setMinApi(parameters)
+ .compile()
+ .inspect(
+ baseInspectorBox::set,
+ featureInspector -> {
+ CodeInspector baseInspector = baseInspectorBox.get();
+ ClassSubject baseClassSubject = baseInspector.clazz(Base.class);
+ assertThat(baseClassSubject, isPresent());
+
+ // TODO(b/300247439): Illegal access error should be preserved.
+ MethodSubject nonPublicMethodSubject =
+ baseClassSubject.uniqueMethodWithOriginalName("nonPublicMethod");
+ assertThat(nonPublicMethodSubject, isAbsent());
+
+ MethodSubject otherMethodSubject =
+ baseClassSubject.uniqueMethodWithOriginalName("otherMethod");
+ assertThat(otherMethodSubject, isPresent());
+
+ ClassSubject featureClassSubject = featureInspector.clazz(Feature.class);
+ assertThat(featureClassSubject, isPresent());
+
+ MethodSubject featureMethodSubject =
+ featureClassSubject.uniqueMethodWithOriginalName("test");
+ assertThat(featureMethodSubject, isPresent());
+ assertThat(featureMethodSubject, invokesMethod(otherMethodSubject));
+ });
+ }
+
+ public static class Base {
+
+ static void nonPublicMethod() {
+ otherMethod();
+ }
+
+ @NeverInline
+ public static void otherMethod() {
+ System.out.println("Hello, world!");
+ }
+ }
+
+ public static class Feature {
+
+ public static void test() {
+ Base.nonPublicMethod();
+ }
+ }
+}