Check all derived class-inlining targets have valid access.

Bug: 120061431
Bug: 200057495
Change-Id: Ic83bcb3d90679160bd4f64252d6dc02fc7faea42
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/classinliner/InlineCandidateProcessor.java b/src/main/java/com/android/tools/r8/ir/optimize/classinliner/InlineCandidateProcessor.java
index 65f0d3f..1f4064f 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/classinliner/InlineCandidateProcessor.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/classinliner/InlineCandidateProcessor.java
@@ -316,10 +316,9 @@
             return user; // Not eligible.
           }
 
-          if (AccessControl.isClassAccessible(singleProgramTarget.getHolder(), method, appView)
-              .isPossiblyFalse()) {
-            return user; // Not eligible.
-          }
+          // The target access is checked in isEligibleSingleTarget above.
+          assert AccessControl.isClassAccessible(singleProgramTarget.getHolder(), method, appView)
+              .isTrue();
 
           // Eligible constructor call (for new instance roots only).
           if (user.isInvokeConstructor(dexItemFactory)) {
@@ -1215,6 +1214,10 @@
     if (methodProcessor.isProcessedConcurrently(singleTarget)) {
       return false;
     }
+    if (AccessControl.isMemberAccessible(singleTarget, singleTarget.getHolder(), method, appView)
+        .isPossiblyFalse()) {
+      return false;
+    }
     if (!singleTarget
         .getDefinition()
         .isInliningCandidate(
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/classinliner/nonpublicsubtype/ClassInlineNonPublicSubtypeTest.java b/src/test/java/com/android/tools/r8/ir/optimize/classinliner/nonpublicsubtype/ClassInlineNonPublicSubtypeTest.java
new file mode 100644
index 0000000..4292720
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/ir/optimize/classinliner/nonpublicsubtype/ClassInlineNonPublicSubtypeTest.java
@@ -0,0 +1,75 @@
+// Copyright (c) 2021, 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.ir.optimize.classinliner.nonpublicsubtype;
+
+import com.android.tools.r8.NeverInline;
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.ir.optimize.classinliner.nonpublicsubtype.subpkg.Utils;
+import com.android.tools.r8.utils.StringUtils;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+@RunWith(Parameterized.class)
+public class ClassInlineNonPublicSubtypeTest extends TestBase {
+
+  static final String EXPECTED = StringUtils.lines("Hello world");
+
+  private final TestParameters parameters;
+
+  @Parameterized.Parameters(name = "{0}")
+  public static TestParametersCollection data() {
+    return getTestParameters().withAllRuntimesAndApiLevels().build();
+  }
+
+  public ClassInlineNonPublicSubtypeTest(TestParameters parameters) {
+    this.parameters = parameters;
+  }
+
+  @Test
+  public void testReference() throws Exception {
+    testForRuntime(parameters)
+        .addInnerClasses(getClass())
+        .addProgramClassesAndInnerClasses(Utils.class)
+        .run(parameters.getRuntime(), TestClass.class)
+        .assertSuccessWithOutput(EXPECTED);
+  }
+
+  @Test
+  public void testR8() throws Exception {
+    testForR8(parameters.getBackend())
+        .enableInliningAnnotations()
+        .addInnerClasses(getClass())
+        .addProgramClassesAndInnerClasses(Utils.class)
+        .addKeepMainRule(TestClass.class)
+        .setMinApi(parameters.getApiLevel())
+        .run(parameters.getRuntime(), TestClass.class)
+        .assertSuccessWithOutput(EXPECTED);
+  }
+
+  public interface I {
+    @NeverInline
+    void method();
+  }
+
+  static class Accessor {
+    @NeverInline
+    static void access(I i) {
+      i.method();
+    }
+  }
+
+  static class TestClass {
+
+    static void run() {
+      Accessor.access(Utils.INSTANCE);
+    }
+
+    public static void main(String[] args) {
+      run();
+    }
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/classinliner/nonpublicsubtype/subpkg/Utils.java b/src/test/java/com/android/tools/r8/ir/optimize/classinliner/nonpublicsubtype/subpkg/Utils.java
new file mode 100644
index 0000000..18c9946
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/ir/optimize/classinliner/nonpublicsubtype/subpkg/Utils.java
@@ -0,0 +1,20 @@
+// Copyright (c) 2021, 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.ir.optimize.classinliner.nonpublicsubtype.subpkg;
+
+import com.android.tools.r8.ir.optimize.classinliner.nonpublicsubtype.ClassInlineNonPublicSubtypeTest.I;
+
+public class Utils {
+
+  // Non-public class can't be accessed by the context calling 'method'.
+  // TODO(b/120061431): Class inlining should be able to inline this as the instance itself will be
+  //  eliminated, but until then, it must consistently refuse to inline in case of invalid access.
+  public static final I INSTANCE =
+      new I() {
+        @Override
+        public void method() {
+          System.out.println("Hello world");
+        }
+      };
+}