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