Add policy for not merging classes with different api level
Bug: 188388130
Change-Id: I92115876f581387918f9d4be374a8fb2788c53eb
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/PolicyScheduler.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/PolicyScheduler.java
index 0d3bf0d..4abddc6 100644
--- a/src/main/java/com/android/tools/r8/horizontalclassmerging/PolicyScheduler.java
+++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/PolicyScheduler.java
@@ -21,6 +21,7 @@
import com.android.tools.r8.horizontalclassmerging.policies.NoDeadLocks;
import com.android.tools.r8.horizontalclassmerging.policies.NoDefaultInterfaceMethodCollisions;
import com.android.tools.r8.horizontalclassmerging.policies.NoDefaultInterfaceMethodMerging;
+import com.android.tools.r8.horizontalclassmerging.policies.NoDifferentApiReferenceLevel;
import com.android.tools.r8.horizontalclassmerging.policies.NoDirectRuntimeTypeChecks;
import com.android.tools.r8.horizontalclassmerging.policies.NoEnums;
import com.android.tools.r8.horizontalclassmerging.policies.NoIllegalInlining;
@@ -199,6 +200,7 @@
new SameParentClass(),
new SyntheticItemsPolicy(appView, mode),
new RespectPackageBoundaries(appView),
+ new NoDifferentApiReferenceLevel(appView),
new PreventClassMethodAndDefaultMethodCollisions(appView));
}
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/NoDifferentApiReferenceLevel.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/NoDifferentApiReferenceLevel.java
new file mode 100644
index 0000000..97d8d21
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/NoDifferentApiReferenceLevel.java
@@ -0,0 +1,42 @@
+// Copyright (c) 2020, 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.horizontalclassmerging.policies;
+
+import com.android.tools.r8.androidapi.AndroidApiReferenceLevelCache;
+import com.android.tools.r8.graph.AppView;
+import com.android.tools.r8.graph.DexProgramClass;
+import com.android.tools.r8.horizontalclassmerging.MultiClassSameReferencePolicy;
+import com.android.tools.r8.utils.AndroidApiLevel;
+
+public class NoDifferentApiReferenceLevel extends MultiClassSameReferencePolicy<AndroidApiLevel> {
+
+ private final AndroidApiReferenceLevelCache apiReferenceLevelCache;
+ private final AndroidApiLevel minApi;
+ // TODO(b/188388130): Remove when stabilized.
+ private final boolean enableApiCallerIdentification;
+
+ public NoDifferentApiReferenceLevel(AppView<?> appView) {
+ apiReferenceLevelCache = AndroidApiReferenceLevelCache.create(appView);
+ minApi = appView.options().minApiLevel;
+ enableApiCallerIdentification =
+ appView.options().apiModelingOptions().enableApiCallerIdentification;
+ }
+
+ @Override
+ public boolean shouldSkipPolicy() {
+ return !enableApiCallerIdentification;
+ }
+
+ @Override
+ public String getName() {
+ return "NoDifferentApiReferenceLevel";
+ }
+
+ @Override
+ public AndroidApiLevel getMergeKey(DexProgramClass clazz) {
+ assert enableApiCallerIdentification;
+ return clazz.getApiReferenceLevel(minApi, apiReferenceLevelCache::lookupMax);
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/apimodel/ApiModelClassMergingWithDifferentApiFieldsTest.java b/src/test/java/com/android/tools/r8/apimodel/ApiModelClassMergingWithDifferentApiFieldsTest.java
index 2f4e83c..cb837ac 100644
--- a/src/test/java/com/android/tools/r8/apimodel/ApiModelClassMergingWithDifferentApiFieldsTest.java
+++ b/src/test/java/com/android/tools/r8/apimodel/ApiModelClassMergingWithDifferentApiFieldsTest.java
@@ -41,9 +41,15 @@
.setMinApi(parameters.getApiLevel())
.addKeepMainRule(Main.class)
.enableInliningAnnotations()
- // TODO(b/138781768): Should not be merged
.addHorizontallyMergedClassesInspector(
- inspector -> inspector.assertClassesMerged(A.class, B.class))
+ inspector -> {
+ if (parameters.isDexRuntime()
+ && parameters.getApiLevel().isGreaterThanOrEqualTo(AndroidApiLevel.L_MR1)) {
+ inspector.assertClassesMerged(A.class, B.class);
+ } else {
+ inspector.assertNoClassesMerged();
+ }
+ })
.apply(ApiModelingTestHelper::enableApiCallerIdentification)
.apply(setMockApiLevelForClass(Api.class, AndroidApiLevel.L_MR1))
.compile()
diff --git a/src/test/java/com/android/tools/r8/apimodel/ApiModelClassMergingWithDifferentApiMethodsTest.java b/src/test/java/com/android/tools/r8/apimodel/ApiModelClassMergingWithDifferentApiMethodsTest.java
index f174546..0eeb405 100644
--- a/src/test/java/com/android/tools/r8/apimodel/ApiModelClassMergingWithDifferentApiMethodsTest.java
+++ b/src/test/java/com/android/tools/r8/apimodel/ApiModelClassMergingWithDifferentApiMethodsTest.java
@@ -42,9 +42,15 @@
.setMinApi(parameters.getApiLevel())
.addKeepMainRule(Main.class)
.enableInliningAnnotations()
- // TODO(b/138781768): Should not be merged
.addHorizontallyMergedClassesInspector(
- inspector -> inspector.assertClassesMerged(A.class, B.class))
+ inspector -> {
+ if (parameters.isDexRuntime()
+ && parameters.getApiLevel().isGreaterThanOrEqualTo(AndroidApiLevel.L_MR1)) {
+ inspector.assertClassesMerged(A.class, B.class);
+ } else {
+ inspector.assertNoClassesMerged();
+ }
+ })
.apply(ApiModelingTestHelper::enableApiCallerIdentification)
.apply(setMockApiLevelForMethod(apiMethod, AndroidApiLevel.L_MR1))
.compile()