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