Raise diagnostic upon access to non-public item in other isolated split
Bug: b/300247439
Change-Id: Ia5a20c341d71ec606be351753bdba2025cf51cd2
diff --git a/src/main/java/com/android/tools/r8/features/ClassToFeatureSplitMap.java b/src/main/java/com/android/tools/r8/features/ClassToFeatureSplitMap.java
index f4ed7cd..6d0b3e6 100644
--- a/src/main/java/com/android/tools/r8/features/ClassToFeatureSplitMap.java
+++ b/src/main/java/com/android/tools/r8/features/ClassToFeatureSplitMap.java
@@ -206,7 +206,7 @@
}
public boolean isInBaseOrSameFeatureAs(
- DexProgramClass clazz,
+ ProgramDefinition clazz,
ProgramDefinition context,
AppView<? extends AppInfoWithClassHierarchy> appView) {
return isInBaseOrSameFeatureAs(
@@ -218,7 +218,7 @@
}
public boolean isInBaseOrSameFeatureAs(
- DexProgramClass clazz,
+ ProgramDefinition clazz,
ProgramDefinition context,
InternalOptions options,
StartupProfile startupProfile,
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 ee3e64f..5708818 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.features.diagnostic.IllegalAccessWithIsolatedFeatureSplitsDiagnostic;
import com.android.tools.r8.graph.AppInfoWithClassHierarchy;
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.DexClass;
@@ -12,6 +13,8 @@
import com.android.tools.r8.graph.FieldResolutionResult;
import com.android.tools.r8.graph.FieldResolutionResult.SingleFieldResolutionResult;
import com.android.tools.r8.graph.MethodResolutionResult;
+import com.android.tools.r8.graph.ProgramDefinition;
+import com.android.tools.r8.graph.ProgramField;
import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.graph.analysis.EnqueuerFieldAccessAnalysis;
import com.android.tools.r8.graph.analysis.EnqueuerInvokeAnalysis;
@@ -24,22 +27,18 @@
public class IsolatedFeatureSplitsChecker
implements EnqueuerFieldAccessAnalysis, EnqueuerInvokeAnalysis, EnqueuerTypeAccessAnalysis {
- @SuppressWarnings("UnusedVariable")
private final AppView<? extends AppInfoWithClassHierarchy> appView;
+ private final ClassToFeatureSplitMap features;
- @SuppressWarnings("UnusedVariable")
- private final Enqueuer enqueuer;
-
- private IsolatedFeatureSplitsChecker(
- AppView<? extends AppInfoWithClassHierarchy> appView, Enqueuer enqueuer) {
+ private IsolatedFeatureSplitsChecker(AppView<? extends AppInfoWithClassHierarchy> appView) {
this.appView = appView;
- this.enqueuer = enqueuer;
+ this.features = appView.appInfo().getClassToFeatureSplitMap();
}
public static void register(
AppView<? extends AppInfoWithClassHierarchy> appView, Enqueuer enqueuer) {
if (enabled(appView, enqueuer)) {
- IsolatedFeatureSplitsChecker checker = new IsolatedFeatureSplitsChecker(appView, enqueuer);
+ IsolatedFeatureSplitsChecker checker = new IsolatedFeatureSplitsChecker(appView);
enqueuer
.registerFieldAccessAnalysis(checker)
.registerInvokeAnalysis(checker)
@@ -55,19 +54,37 @@
&& enqueuer.getMode().isInitialTreeShaking();
}
- @SuppressWarnings("UnusedVariable")
private void traceFieldAccess(FieldResolutionResult resolutionResult, ProgramMethod context) {
- // TODO(b/300247439): Check access.
+ ProgramField resolvedField = resolutionResult.getSingleProgramField();
+ if (resolvedField != null) {
+ checkAccess(resolvedField, context);
+ checkAccess(resolutionResult.getInitialResolutionHolder().asProgramClass(), context);
+ }
}
@SuppressWarnings("UnusedVariable")
private void traceMethodInvoke(MethodResolutionResult resolutionResult, ProgramMethod context) {
- // TODO(b/300247439): Check access.
+ ProgramMethod resolvedMethod = resolutionResult.getResolvedProgramMethod();
+ if (resolvedMethod != null) {
+ checkAccess(resolvedMethod, context);
+ checkAccess(resolutionResult.getInitialResolutionHolder().asProgramClass(), context);
+ }
}
@SuppressWarnings("UnusedVariable")
private void traceTypeAccess(DexClass clazz, ProgramMethod context) {
- // TODO(b/300247439): Check access.
+ if (clazz != null && clazz.isProgramClass()) {
+ checkAccess(clazz.asProgramClass(), context);
+ }
+ }
+
+ private void checkAccess(ProgramDefinition accessedItem, ProgramMethod context) {
+ if (!features.isInBaseOrSameFeatureAs(accessedItem, context, appView)
+ && !accessedItem.getAccessFlags().isPublic()) {
+ appView
+ .reporter()
+ .error(new IllegalAccessWithIsolatedFeatureSplitsDiagnostic(accessedItem, context));
+ }
}
// Field accesses.
diff --git a/src/main/java/com/android/tools/r8/features/diagnostic/IllegalAccessWithIsolatedFeatureSplitsDiagnostic.java b/src/main/java/com/android/tools/r8/features/diagnostic/IllegalAccessWithIsolatedFeatureSplitsDiagnostic.java
new file mode 100644
index 0000000..dd0c738
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/features/diagnostic/IllegalAccessWithIsolatedFeatureSplitsDiagnostic.java
@@ -0,0 +1,45 @@
+// 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.diagnostic;
+
+import com.android.tools.r8.Diagnostic;
+import com.android.tools.r8.graph.DexReference;
+import com.android.tools.r8.graph.ProgramDefinition;
+import com.android.tools.r8.graph.ProgramMethod;
+import com.android.tools.r8.origin.Origin;
+import com.android.tools.r8.position.Position;
+
+public class IllegalAccessWithIsolatedFeatureSplitsDiagnostic implements Diagnostic {
+
+ private final DexReference accessedItem;
+ private final ProgramMethod context;
+
+ public IllegalAccessWithIsolatedFeatureSplitsDiagnostic(
+ ProgramDefinition accessedItem, ProgramMethod context) {
+ this.accessedItem = accessedItem.getReference();
+ this.context = context;
+ }
+
+ @Override
+ public Origin getOrigin() {
+ return context.getOrigin();
+ }
+
+ @Override
+ public Position getPosition() {
+ return Position.UNKNOWN;
+ }
+
+ @Override
+ public String getDiagnosticMessage() {
+ String kind = accessedItem.apply(clazz -> "class", field -> "field", method -> "method");
+ return "Unexpected illegal access to non-public "
+ + kind
+ + " in another feature split (accessed: "
+ + accessedItem.toSourceString()
+ + ", context: "
+ + context.toSourceString()
+ + ").";
+ }
+}