Ensure rebound target has same or lower api level as static target
Bug: b/234613774
Change-Id: Icae862637d3a886b1f66967c012116ddd4cb0fd8
diff --git a/src/main/java/com/android/tools/r8/optimize/MemberRebindingAnalysis.java b/src/main/java/com/android/tools/r8/optimize/MemberRebindingAnalysis.java
index b7e591b..c7395e9 100644
--- a/src/main/java/com/android/tools/r8/optimize/MemberRebindingAnalysis.java
+++ b/src/main/java/com/android/tools/r8/optimize/MemberRebindingAnalysis.java
@@ -103,7 +103,8 @@
currentResolutionResult.withInitialResolutionHolder(
currentResolutionResult.getResolvedHolder()),
contexts,
- invokeType)) {
+ invokeType,
+ original)) {
eligibleLibraryMethod = currentResolvedMethod.asLibraryMethod();
}
if (appView.appInfo().isAssumeMethod(currentResolvedMethod)) {
@@ -140,7 +141,8 @@
DexClassAndMethod resolvedMethod,
SingleResolutionResult resolutionResult,
ProgramMethodSet contexts,
- Type invokeType) {
+ Type invokeType,
+ DexMethod original) {
// TODO(b/194422791): It could potentially be that `original.holder` is not a subtype of
// `original.holder` on all API levels, in which case it is not OK to rebind to the resolved
// method.
@@ -149,7 +151,7 @@
&& !isInvokeSuperToInterfaceMethod(resolvedMethod, invokeType)
&& !isInvokeSuperToAbstractMethod(resolvedMethod, invokeType)
&& isApiSafeForMemberRebinding(
- resolvedMethod.asLibraryMethod(), androidApiLevelCompute, options);
+ resolvedMethod.asLibraryMethod(), original, androidApiLevelCompute, options);
}
private boolean isAccessibleInAllContexts(
diff --git a/src/main/java/com/android/tools/r8/utils/AndroidApiLevelUtils.java b/src/main/java/com/android/tools/r8/utils/AndroidApiLevelUtils.java
index 8eb6b51..374459a 100644
--- a/src/main/java/com/android/tools/r8/utils/AndroidApiLevelUtils.java
+++ b/src/main/java/com/android/tools/r8/utils/AndroidApiLevelUtils.java
@@ -8,6 +8,7 @@
import com.android.tools.r8.androidapi.ComputedApiLevel;
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.DexEncodedMethod;
+import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.DexProgramClass;
import com.android.tools.r8.graph.LibraryMethod;
import com.android.tools.r8.graph.ProgramMethod;
@@ -78,6 +79,7 @@
public static boolean isApiSafeForMemberRebinding(
LibraryMethod method,
+ DexMethod original,
AndroidApiLevelCompute androidApiLevelCompute,
InternalOptions options) {
ComputedApiLevel apiLevel =
@@ -87,6 +89,17 @@
return false;
}
assert options.apiModelingOptions().enableApiCallerIdentification;
- return apiLevel.asKnownApiLevel().getApiLevel().isLessThanOrEqualTo(options.getMinApiLevel());
+ ComputedApiLevel apiLevelOfOriginal =
+ androidApiLevelCompute.computeApiLevelForLibraryReference(
+ original, ComputedApiLevel.unknown());
+ if (apiLevelOfOriginal.isUnknownApiLevel()) {
+ return false;
+ }
+ return apiLevelOfOriginal
+ .asKnownApiLevel()
+ .max(apiLevel)
+ .asKnownApiLevel()
+ .getApiLevel()
+ .isLessThanOrEqualTo(options.getMinApiLevel());
}
}
diff --git a/src/test/java/com/android/tools/r8/memberrebinding/LibraryMemberRebindingSuperTypeWithApiMethodTest.java b/src/test/java/com/android/tools/r8/memberrebinding/LibraryMemberRebindingSuperTypeWithApiMethodTest.java
index 04a051a..c474de2 100644
--- a/src/test/java/com/android/tools/r8/memberrebinding/LibraryMemberRebindingSuperTypeWithApiMethodTest.java
+++ b/src/test/java/com/android/tools/r8/memberrebinding/LibraryMemberRebindingSuperTypeWithApiMethodTest.java
@@ -55,8 +55,7 @@
.run(parameters.getRuntime(), Main.class)
.applyIf(
parameters.getDexRuntimeVersion().isOlderThan(Version.V8_1_0),
- // TODO(b/234613774): We should not introduce ICCE.
- result -> result.assertFailureWithErrorThatThrows(IncompatibleClassChangeError.class),
+ result -> result.assertFailureWithErrorThatThrows(NoSuchMethodError.class),
result -> result.assertFailureWithErrorThatThrows(DestroyFailedException.class));
}