Update tracereferences to keep failed resolutions
Bug: 199142461
Change-Id: Ib81c1cd56b9fef7f37756a8d9a79c7f9df6255c1
diff --git a/src/main/java/com/android/tools/r8/graph/DexClass.java b/src/main/java/com/android/tools/r8/graph/DexClass.java
index 55bec5b..8db4392 100644
--- a/src/main/java/com/android/tools/r8/graph/DexClass.java
+++ b/src/main/java/com/android/tools/r8/graph/DexClass.java
@@ -620,7 +620,8 @@
return signaturePolymorphicMethod;
}
- private boolean isSignaturePolymorphicMethod(DexEncodedMethod method, DexItemFactory factory) {
+ public static boolean isSignaturePolymorphicMethod(
+ DexEncodedMethod method, DexItemFactory factory) {
assert method.getHolderType() == factory.methodHandleType
|| method.getHolderType() == factory.varHandleType;
return method.accessFlags.isVarargs()
diff --git a/src/main/java/com/android/tools/r8/tracereferences/TraceReferencesCommandParser.java b/src/main/java/com/android/tools/r8/tracereferences/TraceReferencesCommandParser.java
index c3c8e30..331ccec 100644
--- a/src/main/java/com/android/tools/r8/tracereferences/TraceReferencesCommandParser.java
+++ b/src/main/java/com/android/tools/r8/tracereferences/TraceReferencesCommandParser.java
@@ -48,7 +48,6 @@
" # outside of library are treated as a missing",
" # references.",
" --output <file> # Output result in <outfile>. If not passed the",
- " # result will go to standard out.",
" # result will go to standard out."),
BaseCompilerCommandParser.MAP_DIAGNOSTICS_USAGE_MESSAGE,
Arrays.asList(
diff --git a/src/main/java/com/android/tools/r8/tracereferences/Tracer.java b/src/main/java/com/android/tools/r8/tracereferences/Tracer.java
index ee3c33d..0a1ec66 100644
--- a/src/main/java/com/android/tools/r8/tracereferences/Tracer.java
+++ b/src/main/java/com/android/tools/r8/tracereferences/Tracer.java
@@ -200,7 +200,7 @@
// - The holder type is registered from visiting the extends/implements clause of the sub
// class.
- TracedMethodImpl tracedMethod = new TracedMethodImpl(method, referencedFrom);
+ TracedMethodImpl tracedMethod = new TracedMethodImpl(method.getDefinition(), referencedFrom);
if (isTargetType(method.getHolderType())) {
consumer.acceptMethod(tracedMethod, diagnostics);
if (method.getAccessFlags().isVisibilityDependingOnPackage()) {
@@ -323,9 +323,8 @@
MethodLookupResult lookupResult = graphLens.lookupInvokeStatic(method, context);
assert lookupResult.getType().isStatic();
DexMethod rewrittenMethod = lookupResult.getReference();
- DexClassAndMethod resolvedMethod =
- appInfo.unsafeResolveMethodDueToDexFormat(rewrittenMethod).getResolutionPair();
- handleRewrittenMethodReference(rewrittenMethod, resolvedMethod);
+ handleRewrittenMethodResolution(
+ rewrittenMethod, appInfo.unsafeResolveMethodDueToDexFormat(rewrittenMethod));
}
@Override
@@ -333,8 +332,16 @@
MethodLookupResult lookupResult = graphLens.lookupInvokeSuper(method, context);
assert lookupResult.getType().isSuper();
DexMethod rewrittenMethod = lookupResult.getReference();
- DexClassAndMethod superTarget = appInfo.lookupSuperTarget(rewrittenMethod, context);
- handleRewrittenMethodReference(rewrittenMethod, superTarget);
+ MethodResolutionResult resolutionResult =
+ appInfo.unsafeResolveMethodDueToDexFormat(rewrittenMethod);
+ if (resolutionResult.isFailedResolution()
+ && resolutionResult.asFailedResolution().hasMethodsCausingError()) {
+ handleRewrittenMethodResolution(rewrittenMethod, resolutionResult);
+ return;
+ }
+ handleRewrittenMethodReference(
+ rewrittenMethod,
+ resolutionResult.lookupInvokeSuperTarget(context.getHolder(), appInfo));
}
@Override
@@ -352,18 +359,39 @@
return;
}
assert lookupResult.getType().isInterface() || lookupResult.getType().isVirtual();
- MethodResolutionResult resolutionResult =
+ handleRewrittenMethodResolution(
+ method,
lookupResult.getType().isInterface()
? appInfo.resolveMethodOnInterface(method)
- : appInfo.resolveMethodOnClass(method);
- DexClassAndMethod resolvedMethod =
- resolutionResult.isVirtualTarget() ? resolutionResult.getResolutionPair() : null;
- handleRewrittenMethodReference(method, resolvedMethod);
+ : appInfo.resolveMethodOnClass(method));
+ }
+
+ private void handleRewrittenMethodResolution(
+ DexMethod method, MethodResolutionResult resolutionResult) {
+ if (resolutionResult.isFailedResolution()
+ && resolutionResult.asFailedResolution().hasMethodsCausingError()) {
+ resolutionResult
+ .asFailedResolution()
+ .forEachFailureDependency(
+ methodCausingFailure -> {
+ handleRewrittenMethodReference(method, methodCausingFailure);
+ });
+ return;
+ }
+ handleRewrittenMethodReference(method, resolutionResult.getResolutionPair());
}
private void handleRewrittenMethodReference(
DexMethod method, DexClassAndMethod resolvedMethod) {
- assert resolvedMethod == null || resolvedMethod.getReference().match(method);
+ handleRewrittenMethodReference(
+ method, resolvedMethod == null ? null : resolvedMethod.getDefinition());
+ }
+
+ private void handleRewrittenMethodReference(
+ DexMethod method, DexEncodedMethod resolvedMethod) {
+ assert resolvedMethod == null
+ || resolvedMethod.getReference().match(method)
+ || DexClass.isSignaturePolymorphicMethod(resolvedMethod, factory);
addType(method.getHolderType(), referencedFrom);
addTypes(method.getParameters(), referencedFrom);
addType(method.getReturnType(), referencedFrom);
diff --git a/src/main/java/com/android/tools/r8/tracereferences/internal/TracedMethodImpl.java b/src/main/java/com/android/tools/r8/tracereferences/internal/TracedMethodImpl.java
index 1ea760a..ea39cb6 100644
--- a/src/main/java/com/android/tools/r8/tracereferences/internal/TracedMethodImpl.java
+++ b/src/main/java/com/android/tools/r8/tracereferences/internal/TracedMethodImpl.java
@@ -5,7 +5,7 @@
package com.android.tools.r8.tracereferences.internal;
import com.android.tools.r8.diagnostic.DefinitionContext;
-import com.android.tools.r8.graph.DexClassAndMethod;
+import com.android.tools.r8.graph.DexEncodedMethod;
import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.references.MethodReference;
import com.android.tools.r8.tracereferences.TraceReferencesConsumer.MethodAccessFlags;
@@ -17,9 +17,9 @@
this(method.asMethodReference(), referencedFrom, null);
}
- public TracedMethodImpl(DexClassAndMethod method, DefinitionContext referencedFrom) {
+ public TracedMethodImpl(DexEncodedMethod method, DefinitionContext referencedFrom) {
this(
- method.getMethodReference(),
+ method.getReference().asMethodReference(),
referencedFrom,
new MethodAccessFlagsImpl(method.getAccessFlags()));
}
diff --git a/src/test/java/com/android/tools/r8/tracereferences/TraceReferencesFailedResolutionInSourceTest.java b/src/test/java/com/android/tools/r8/tracereferences/TraceReferencesFailedResolutionInSourceTest.java
new file mode 100644
index 0000000..d753147
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/tracereferences/TraceReferencesFailedResolutionInSourceTest.java
@@ -0,0 +1,101 @@
+// 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.tracereferences;
+
+import static org.junit.Assert.assertTrue;
+
+import com.android.tools.r8.DiagnosticsHandler;
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.ToolHelper;
+import com.android.tools.r8.references.MethodReference;
+import com.android.tools.r8.utils.ZipUtils.ZipBuilder;
+import java.nio.file.Path;
+import java.util.HashSet;
+import java.util.Set;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+
+@RunWith(Parameterized.class)
+public class TraceReferencesFailedResolutionInSourceTest extends TestBase {
+
+ private final TestParameters parameters;
+
+ @Parameters(name = "{0}")
+ public static TestParametersCollection data() {
+ return getTestParameters().withNoneRuntime().build();
+ }
+
+ public TraceReferencesFailedResolutionInSourceTest(TestParameters parameters) {
+ this.parameters = parameters;
+ }
+
+ static class SeenReferencesConsumer implements TraceReferencesConsumer {
+
+ private Set<MethodReference> seenMethods = new HashSet<>();
+
+ @Override
+ public void acceptType(TracedClass tracedClass, DiagnosticsHandler handler) {}
+
+ @Override
+ public void acceptField(TracedField tracedField, DiagnosticsHandler handler) {}
+
+ @Override
+ public void acceptMethod(TracedMethod tracedMethod, DiagnosticsHandler handler) {
+ seenMethods.add(tracedMethod.getReference());
+ }
+ }
+
+ @Test
+ public void testInvalidResolution() throws Exception {
+ Path dir = temp.newFolder().toPath();
+ Path targetJar =
+ ZipBuilder.builder(dir.resolve("target.jar"))
+ .addFilesRelative(
+ ToolHelper.getClassPathForTests(), ToolHelper.getClassFileForTestClass(I.class))
+ .build();
+ Path sourceJar =
+ ZipBuilder.builder(dir.resolve("source.jar"))
+ .addFilesRelative(
+ ToolHelper.getClassPathForTests(),
+ ToolHelper.getClassFileForTestClass(A.class),
+ ToolHelper.getClassFileForTestClass(B.class),
+ ToolHelper.getClassFileForTestClass(Main.class))
+ .build();
+ SeenReferencesConsumer consumer = new SeenReferencesConsumer();
+ TraceReferences.run(
+ TraceReferencesCommand.builder()
+ .addLibraryFiles(ToolHelper.getMostRecentAndroidJar())
+ .addSourceFiles(sourceJar)
+ .addTargetFiles(targetJar)
+ .setConsumer(consumer)
+ .build());
+ assertTrue(consumer.seenMethods.isEmpty());
+ }
+
+ public interface I {
+ default void f() {
+ System.out.println("I::f");
+ }
+ }
+
+ public static class A {
+ private static void f() {
+ System.out.println("A::f");
+ }
+ }
+
+ public static class B extends A implements I {}
+
+ public static class Main {
+
+ public static void main(String[] args) {
+ new B().f();
+ }
+ }
+}