Add API to get user-friendly message for missing definition info
This also ensures that the collection returned by getMissingDefinitions() has deterministic order.
Change-Id: I2f8d60ddc19018f7be5c9033fa093691b2ec13cc
diff --git a/src/main/java/com/android/tools/r8/diagnostic/MissingDefinitionInfo.java b/src/main/java/com/android/tools/r8/diagnostic/MissingDefinitionInfo.java
index c2905ce..ec486de 100644
--- a/src/main/java/com/android/tools/r8/diagnostic/MissingDefinitionInfo.java
+++ b/src/main/java/com/android/tools/r8/diagnostic/MissingDefinitionInfo.java
@@ -64,6 +64,9 @@
return null;
}
+ /** User friendly description of the missing definition. */
+ String getDiagnosticMessage();
+
/** The contexts from which this missing definition was referenced. */
Collection<MissingDefinitionContext> getReferencedFromContexts();
}
diff --git a/src/main/java/com/android/tools/r8/diagnostic/internal/MissingDefinitionInfoBase.java b/src/main/java/com/android/tools/r8/diagnostic/internal/MissingDefinitionInfoBase.java
index 0f9e655..b3d2872 100644
--- a/src/main/java/com/android/tools/r8/diagnostic/internal/MissingDefinitionInfoBase.java
+++ b/src/main/java/com/android/tools/r8/diagnostic/internal/MissingDefinitionInfoBase.java
@@ -18,6 +18,13 @@
}
@Override
+ public String getDiagnosticMessage() {
+ StringBuilder builder = new StringBuilder();
+ MissingDefinitionInfoUtils.writeDiagnosticMessage(builder, this);
+ return builder.toString();
+ }
+
+ @Override
public final Collection<MissingDefinitionContext> getReferencedFromContexts() {
return referencedFromContexts;
}
diff --git a/src/main/java/com/android/tools/r8/diagnostic/internal/MissingDefinitionInfoUtils.java b/src/main/java/com/android/tools/r8/diagnostic/internal/MissingDefinitionInfoUtils.java
index b94dbf1..34f2f2c 100644
--- a/src/main/java/com/android/tools/r8/diagnostic/internal/MissingDefinitionInfoUtils.java
+++ b/src/main/java/com/android/tools/r8/diagnostic/internal/MissingDefinitionInfoUtils.java
@@ -4,13 +4,19 @@
package com.android.tools.r8.diagnostic.internal;
+import static com.android.tools.r8.utils.ClassReferenceUtils.getClassReferenceComparator;
+import static com.android.tools.r8.utils.FieldReferenceUtils.getFieldReferenceComparator;
+import static com.android.tools.r8.utils.MethodReferenceUtils.getMethodReferenceComparator;
+
import com.android.tools.r8.diagnostic.MissingClassInfo;
+import com.android.tools.r8.diagnostic.MissingDefinitionContext;
import com.android.tools.r8.diagnostic.MissingDefinitionInfo;
import com.android.tools.r8.diagnostic.MissingFieldInfo;
import com.android.tools.r8.diagnostic.MissingMethodInfo;
import com.android.tools.r8.references.ClassReference;
import com.android.tools.r8.references.FieldReference;
import com.android.tools.r8.references.MethodReference;
+import com.android.tools.r8.utils.Box;
import com.android.tools.r8.utils.ClassReferenceUtils;
import com.android.tools.r8.utils.FieldReferenceUtils;
import com.android.tools.r8.utils.MethodReferenceUtils;
@@ -77,4 +83,65 @@
public static Comparator<MissingDefinitionInfo> getComparator() {
return COMPARATOR;
}
+
+ public static void writeDiagnosticMessage(
+ StringBuilder builder, MissingDefinitionInfo missingDefinitionInfo) {
+ builder.append("Missing class ");
+ MissingDefinitionInfoUtils.accept(
+ missingDefinitionInfo,
+ missingClassInfo -> builder.append(missingClassInfo.getClassReference().getTypeName()),
+ missingFieldInfo ->
+ builder.append(
+ FieldReferenceUtils.toSourceString(missingFieldInfo.getFieldReference())),
+ missingMethodInfo ->
+ builder.append(
+ MethodReferenceUtils.toSourceString(missingMethodInfo.getMethodReference())));
+ writeReferencedFromSuffix(builder, missingDefinitionInfo);
+ }
+
+ private static void writeReferencedFromSuffix(
+ StringBuilder builder, MissingDefinitionInfo missingDefinitionInfo) {
+ Box<ClassReference> classContext = new Box<>();
+ Box<FieldReference> fieldContext = new Box<>();
+ Box<MethodReference> methodContext = new Box<>();
+ for (MissingDefinitionContext missingDefinitionContext :
+ missingDefinitionInfo.getReferencedFromContexts()) {
+ MissingDefinitionContextUtils.accept(
+ missingDefinitionContext,
+ missingDefinitionClassContext ->
+ classContext.setMin(
+ missingDefinitionClassContext.getClassReference(), getClassReferenceComparator()),
+ missingDefinitionFieldContext ->
+ fieldContext.setMin(
+ missingDefinitionFieldContext.getFieldReference(), getFieldReferenceComparator()),
+ missingDefinitionMethodContext ->
+ methodContext.setMin(
+ missingDefinitionMethodContext.getMethodReference(),
+ getMethodReferenceComparator()));
+ }
+ assert classContext.isSet() || fieldContext.isSet() || methodContext.isSet();
+ if (fieldContext.isSet()) {
+ writeReferencedFromSuffix(
+ builder, missingDefinitionInfo, FieldReferenceUtils.toSourceString(fieldContext.get()));
+ } else if (methodContext.isSet()) {
+ writeReferencedFromSuffix(
+ builder, missingDefinitionInfo, MethodReferenceUtils.toSourceString(methodContext.get()));
+ } else {
+ writeReferencedFromSuffix(builder, missingDefinitionInfo, classContext.get().getTypeName());
+ }
+ }
+
+ private static void writeReferencedFromSuffix(
+ StringBuilder builder, MissingDefinitionInfo missingDefinitionInfo, String referencedFrom) {
+ int numberOfOtherContexts = missingDefinitionInfo.getReferencedFromContexts().size() - 1;
+ assert numberOfOtherContexts >= 0;
+ builder.append(" (referenced from: ").append(referencedFrom);
+ if (numberOfOtherContexts >= 1) {
+ builder.append(" and ").append(numberOfOtherContexts).append(" other context");
+ if (numberOfOtherContexts >= 2) {
+ builder.append("s");
+ }
+ }
+ builder.append(")");
+ }
}
diff --git a/src/main/java/com/android/tools/r8/diagnostic/internal/MissingDefinitionsDiagnosticImpl.java b/src/main/java/com/android/tools/r8/diagnostic/internal/MissingDefinitionsDiagnosticImpl.java
index 7be87b6..a180ed2 100644
--- a/src/main/java/com/android/tools/r8/diagnostic/internal/MissingDefinitionsDiagnosticImpl.java
+++ b/src/main/java/com/android/tools/r8/diagnostic/internal/MissingDefinitionsDiagnosticImpl.java
@@ -4,21 +4,10 @@
package com.android.tools.r8.diagnostic.internal;
-import static com.android.tools.r8.utils.ClassReferenceUtils.getClassReferenceComparator;
-import static com.android.tools.r8.utils.FieldReferenceUtils.getFieldReferenceComparator;
-import static com.android.tools.r8.utils.MethodReferenceUtils.getMethodReferenceComparator;
-
-import com.android.tools.r8.diagnostic.MissingDefinitionContext;
import com.android.tools.r8.diagnostic.MissingDefinitionInfo;
import com.android.tools.r8.diagnostic.MissingDefinitionsDiagnostic;
import com.android.tools.r8.origin.Origin;
import com.android.tools.r8.position.Position;
-import com.android.tools.r8.references.ClassReference;
-import com.android.tools.r8.references.FieldReference;
-import com.android.tools.r8.references.MethodReference;
-import com.android.tools.r8.utils.Box;
-import com.android.tools.r8.utils.FieldReferenceUtils;
-import com.android.tools.r8.utils.MethodReferenceUtils;
import com.google.common.collect.ImmutableList;
import java.util.ArrayList;
import java.util.Collection;
@@ -40,12 +29,12 @@
@Override
public Collection<MissingDefinitionInfo> getMissingDefinitions() {
- return missingDefinitions;
+ return getMissingDefinitionsWithDeterministicOrder();
}
private Collection<MissingDefinitionInfo> getMissingDefinitionsWithDeterministicOrder() {
List<MissingDefinitionInfo> missingDefinitionsWithDeterministicOrder =
- new ArrayList<>(getMissingDefinitions());
+ new ArrayList<>(missingDefinitions);
missingDefinitionsWithDeterministicOrder.sort(MissingDefinitionInfoUtils.getComparator());
return missingDefinitionsWithDeterministicOrder;
}
@@ -72,78 +61,17 @@
assert missingDefinitionsIterator.hasNext();
// Write first line.
- writeMissingDefinition(builder.append("Missing class "), missingDefinitionsIterator.next());
+ MissingDefinitionInfoUtils.writeDiagnosticMessage(builder, missingDefinitionsIterator.next());
// Write remaining lines with line separator before.
missingDefinitionsIterator.forEachRemaining(
missingDefinition ->
- writeMissingDefinition(
- builder.append(System.lineSeparator()).append("Missing class "),
- missingDefinition));
+ MissingDefinitionInfoUtils.writeDiagnosticMessage(
+ builder.append(System.lineSeparator()), missingDefinition));
return builder.toString();
}
- private static void writeMissingDefinition(
- StringBuilder builder, MissingDefinitionInfo missingDefinitionInfo) {
- MissingDefinitionInfoUtils.accept(
- missingDefinitionInfo,
- missingClassInfo -> builder.append(missingClassInfo.getClassReference().getTypeName()),
- missingFieldInfo ->
- builder.append(
- FieldReferenceUtils.toSourceString(missingFieldInfo.getFieldReference())),
- missingMethodInfo ->
- builder.append(
- MethodReferenceUtils.toSourceString(missingMethodInfo.getMethodReference())));
- writeReferencedFromSuffix(builder, missingDefinitionInfo);
- }
-
- private static void writeReferencedFromSuffix(
- StringBuilder builder, MissingDefinitionInfo missingDefinitionInfo) {
- Box<ClassReference> classContext = new Box<>();
- Box<FieldReference> fieldContext = new Box<>();
- Box<MethodReference> methodContext = new Box<>();
- for (MissingDefinitionContext missingDefinitionContext :
- missingDefinitionInfo.getReferencedFromContexts()) {
- MissingDefinitionContextUtils.accept(
- missingDefinitionContext,
- missingDefinitionClassContext ->
- classContext.setMin(
- missingDefinitionClassContext.getClassReference(), getClassReferenceComparator()),
- missingDefinitionFieldContext ->
- fieldContext.setMin(
- missingDefinitionFieldContext.getFieldReference(), getFieldReferenceComparator()),
- missingDefinitionMethodContext ->
- methodContext.setMin(
- missingDefinitionMethodContext.getMethodReference(),
- getMethodReferenceComparator()));
- }
- assert classContext.isSet() || fieldContext.isSet() || methodContext.isSet();
- if (fieldContext.isSet()) {
- writeReferencedFromSuffix(
- builder, missingDefinitionInfo, FieldReferenceUtils.toSourceString(fieldContext.get()));
- } else if (methodContext.isSet()) {
- writeReferencedFromSuffix(
- builder, missingDefinitionInfo, MethodReferenceUtils.toSourceString(methodContext.get()));
- } else {
- writeReferencedFromSuffix(builder, missingDefinitionInfo, classContext.get().getTypeName());
- }
- }
-
- private static void writeReferencedFromSuffix(
- StringBuilder builder, MissingDefinitionInfo missingDefinitionInfo, String referencedFrom) {
- int numberOfOtherContexts = missingDefinitionInfo.getReferencedFromContexts().size() - 1;
- assert numberOfOtherContexts >= 0;
- builder.append(" (referenced from: ").append(referencedFrom);
- if (numberOfOtherContexts >= 1) {
- builder.append(", and ").append(numberOfOtherContexts).append(" other context");
- if (numberOfOtherContexts >= 2) {
- builder.append("s");
- }
- }
- builder.append(")");
- }
-
public static class Builder {
private ImmutableList.Builder<MissingDefinitionInfo> missingDefinitionsBuilder =
diff --git a/src/test/java/com/android/tools/r8/missingclasses/MissingClassesTestBase.java b/src/test/java/com/android/tools/r8/missingclasses/MissingClassesTestBase.java
index 8dfba19..3022ea4 100644
--- a/src/test/java/com/android/tools/r8/missingclasses/MissingClassesTestBase.java
+++ b/src/test/java/com/android/tools/r8/missingclasses/MissingClassesTestBase.java
@@ -169,7 +169,7 @@
.append(" (referenced from: ")
.append(referencedFrom);
if (numberOfContexts > 1) {
- builder.append(", and ").append(numberOfContexts - 1).append(" other context");
+ builder.append(" and ").append(numberOfContexts - 1).append(" other context");
if (numberOfContexts > 2) {
builder.append("s");
}