Update the message for the MissingDefinitionsDiagnostic
Bug: 169127026
Bug: 169546956
Change-Id: Id251613a961edc4f8a21d77b1aac571d4f2dbfc1
diff --git a/src/main/java/com/android/tools/r8/tracereferences/MissingDefinitionsDiagnostic.java b/src/main/java/com/android/tools/r8/tracereferences/MissingDefinitionsDiagnostic.java
index db31dac..8fd9edb 100644
--- a/src/main/java/com/android/tools/r8/tracereferences/MissingDefinitionsDiagnostic.java
+++ b/src/main/java/com/android/tools/r8/tracereferences/MissingDefinitionsDiagnostic.java
@@ -10,6 +10,7 @@
import com.android.tools.r8.tracereferences.Tracer.TracedClassImpl;
import com.android.tools.r8.tracereferences.Tracer.TracedFieldImpl;
import com.android.tools.r8.tracereferences.Tracer.TracedMethodImpl;
+import com.android.tools.r8.tracereferences.Tracer.TracedReferenceBase;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
@@ -40,18 +41,27 @@
return Position.UNKNOWN;
}
+ private <T extends TracedReferenceBase<?, ?>> void appendSorted(
+ StringBuilder builder, Set<T> missing) {
+ missing.stream()
+ .map(element -> element.getReference())
+ .map(Object::toString)
+ .sorted()
+ .forEach(item -> builder.append(" ").append(item).append(System.lineSeparator()));
+ }
+
@Override
public String getDiagnosticMessage() {
StringBuilder builder = new StringBuilder("Tracereferences found ");
List<String> components = new ArrayList<>();
if (missingClasses.size() > 0) {
- components.add("" + missingClasses.size() + " classes");
+ components.add("" + missingClasses.size() + " classe(s)");
}
if (missingFields.size() > 0) {
- components.add("" + missingClasses.size() + " fields");
+ components.add("" + missingFields.size() + " field(s)");
}
if (missingMethods.size() > 0) {
- components.add("" + missingClasses.size() + " methods");
+ components.add("" + missingMethods.size() + " method(s)");
}
assert components.size() > 0;
for (int i = 0; i < components.size(); i++) {
@@ -63,27 +73,12 @@
builder.append(" without definition");
builder.append(System.lineSeparator());
builder.append(System.lineSeparator());
- builder.append("Classes without definition:");
- missingClasses.forEach(
- clazz ->
- builder
- .append(" ")
- .append(clazz.getReference().toString())
- .append(System.lineSeparator()));
- builder.append("Fields without definition");
- missingFields.forEach(
- field ->
- builder
- .append(" ")
- .append(field.getReference().toString())
- .append(System.lineSeparator()));
- builder.append("Methods without definition");
- missingMethods.forEach(
- method ->
- builder
- .append(" ")
- .append(method.getReference().toString())
- .append(System.lineSeparator()));
+ builder.append("Classe(s) without definition:" + System.lineSeparator());
+ appendSorted(builder, missingClasses);
+ builder.append("Field(s) without definition:" + System.lineSeparator());
+ appendSorted(builder, missingFields);
+ builder.append("Method(s) without definition:" + System.lineSeparator());
+ appendSorted(builder, missingMethods);
return builder.toString();
}
}
diff --git a/src/test/java/com/android/tools/r8/tracereferences/TraceReferencesDiagnosticTest.java b/src/test/java/com/android/tools/r8/tracereferences/TraceReferencesDiagnosticTest.java
new file mode 100644
index 0000000..b21d409
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/tracereferences/TraceReferencesDiagnosticTest.java
@@ -0,0 +1,220 @@
+// 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.tracereferences;
+
+import static org.junit.Assert.fail;
+
+import com.android.tools.r8.CompilationFailedException;
+import com.android.tools.r8.DiagnosticsChecker;
+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.utils.AndroidApiLevel;
+import com.android.tools.r8.utils.DescriptorUtils;
+import com.android.tools.r8.utils.StringUtils;
+import com.android.tools.r8.utils.ZipUtils.ZipBuilder;
+import com.google.common.collect.ImmutableList;
+import java.nio.file.Path;
+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 TraceReferencesDiagnosticTest extends TestBase {
+ @Parameters(name = "{0}")
+ public static TestParametersCollection data() {
+ return getTestParameters().withNoneRuntime().build();
+ }
+
+ public TraceReferencesDiagnosticTest(TestParameters parameters) {}
+
+ @Test
+ public void traceReferencesDiagnosticClassesFieldsAndMethods() throws Throwable {
+ Path dir = temp.newFolder().toPath();
+ Path targetJar =
+ ZipBuilder.builder(dir.resolve("target.jar"))
+ .addBytes(
+ DescriptorUtils.getPathFromJavaType(Target.class),
+ transformer(Target.class)
+ .removeFields(
+ (access, name, descriptor, signature, value) ->
+ name.equals("missingField1"))
+ .removeFields(
+ (access, name, descriptor, signature, value) ->
+ name.equals("missingField2"))
+ .removeMethods(
+ (access, name, descriptor, signature, exceptions) ->
+ name.equals("missingMethod"))
+ .transform())
+ .build();
+ Path sourceJar =
+ ZipBuilder.builder(dir.resolve("source.jar"))
+ .addFilesRelative(
+ ToolHelper.getClassPathForTests(),
+ ToolHelper.getClassFileForTestClass(Source.class))
+ .build();
+
+ String prefix = " Lcom/android/tools/r8/tracereferences/TraceReferencesDiagnosticTest$";
+ try {
+ DiagnosticsChecker.checkErrorsContains(
+ ImmutableList.of(
+ "Tracereferences found 3 classe(s), 2 field(s) and 4 method(s) without definition",
+ StringUtils.lines(
+ "Classe(s) without definition:",
+ prefix + "Target1;",
+ prefix + "Target2;",
+ prefix + "Target3;"),
+ StringUtils.lines(
+ "Field(s) without definition:",
+ prefix + "Target;missingField1:I",
+ prefix + "Target;missingField2:I"),
+ StringUtils.lines(
+ "Method(s) without definition:",
+ prefix + "Target1;<init>()V",
+ prefix + "Target2;<init>()V",
+ prefix + "Target3;<init>()V",
+ prefix + "Target;missingMethod()V")),
+ handler ->
+ TraceReferences.run(
+ TraceReferencesCommand.builder(handler)
+ .addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.P))
+ .addSourceFiles(sourceJar)
+ .addTargetFiles(targetJar)
+ .setConsumer(TraceReferencesConsumer.emptyConsumer())
+ .build()));
+ fail("Unexpected success");
+ } catch (CompilationFailedException e) {
+ // Expected.
+ }
+ }
+
+ @Test
+ public void traceReferencesDiagnosticFieldsAndMethods() throws Throwable {
+ Path dir = temp.newFolder().toPath();
+ Path targetJar =
+ ZipBuilder.builder(dir.resolve("target.jar"))
+ .addFilesRelative(
+ ToolHelper.getClassPathForTests(),
+ ToolHelper.getClassFileForTestClass(Target1.class),
+ ToolHelper.getClassFileForTestClass(Target2.class),
+ ToolHelper.getClassFileForTestClass(Target3.class))
+ .addBytes(
+ DescriptorUtils.getPathFromJavaType(Target.class),
+ transformer(Target.class)
+ .removeFields(
+ (access, name, descriptor, signature, value) ->
+ name.equals("missingField1"))
+ .removeFields(
+ (access, name, descriptor, signature, value) ->
+ name.equals("missingField2"))
+ .removeMethods(
+ (access, name, descriptor, signature, exceptions) ->
+ name.equals("missingMethod"))
+ .transform())
+ .build();
+ Path sourceJar =
+ ZipBuilder.builder(dir.resolve("source.jar"))
+ .addFilesRelative(
+ ToolHelper.getClassPathForTests(),
+ ToolHelper.getClassFileForTestClass(Source.class))
+ .build();
+
+ String prefix = " Lcom/android/tools/r8/tracereferences/TraceReferencesDiagnosticTest$";
+ try {
+ DiagnosticsChecker.checkErrorsContains(
+ ImmutableList.of(
+ "Tracereferences found 2 field(s) and 1 method(s) without definition",
+ StringUtils.lines(
+ "Field(s) without definition:",
+ prefix + "Target;missingField1:I",
+ prefix + "Target;missingField2:I"),
+ StringUtils.lines(
+ "Method(s) without definition:", prefix + "Target;missingMethod()V")),
+ handler ->
+ TraceReferences.run(
+ TraceReferencesCommand.builder(handler)
+ .addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.P))
+ .addSourceFiles(sourceJar)
+ .addTargetFiles(targetJar)
+ .setConsumer(TraceReferencesConsumer.emptyConsumer())
+ .build()));
+ fail("Unexpected success");
+ } catch (CompilationFailedException e) {
+ // Expected.
+ }
+ }
+
+ @Test
+ public void traceReferencesDiagnosticMethods() throws Throwable {
+ Path dir = temp.newFolder().toPath();
+ Path targetJar =
+ ZipBuilder.builder(dir.resolve("target.jar"))
+ .addFilesRelative(
+ ToolHelper.getClassPathForTests(),
+ ToolHelper.getClassFileForTestClass(Target1.class),
+ ToolHelper.getClassFileForTestClass(Target2.class),
+ ToolHelper.getClassFileForTestClass(Target3.class))
+ .addBytes(
+ DescriptorUtils.getPathFromJavaType(Target.class),
+ transformer(Target.class)
+ .removeMethods(
+ (access, name, descriptor, signature, exceptions) ->
+ name.equals("missingMethod"))
+ .transform())
+ .build();
+ Path sourceJar =
+ ZipBuilder.builder(dir.resolve("source.jar"))
+ .addFilesRelative(
+ ToolHelper.getClassPathForTests(),
+ ToolHelper.getClassFileForTestClass(Source.class))
+ .build();
+
+ String prefix = " Lcom/android/tools/r8/tracereferences/TraceReferencesDiagnosticTest$";
+ try {
+ DiagnosticsChecker.checkErrorsContains(
+ ImmutableList.of(
+ "Tracereferences found 1 method(s) without definition",
+ StringUtils.lines(
+ "Method(s) without definition:", prefix + "Target;missingMethod()V")),
+ handler ->
+ TraceReferences.run(
+ TraceReferencesCommand.builder(handler)
+ .addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.P))
+ .addSourceFiles(sourceJar)
+ .addTargetFiles(targetJar)
+ .setConsumer(TraceReferencesConsumer.emptyConsumer())
+ .build()));
+ fail("Unexpected success");
+ } catch (CompilationFailedException e) {
+ // Expected.
+ }
+ }
+
+ static class Target1 {}
+
+ static class Target2 {}
+
+ static class Target3 {}
+
+ static class Target {
+ public static int missingField1;
+ public static int missingField2;
+
+ public static void missingMethod() {}
+ }
+
+ static class Source {
+ public static void source() {
+ new Target1();
+ new Target2();
+ new Target3();
+
+ Target.missingField1 = 1;
+ Target.missingField2 = 2;
+ Target.missingMethod();
+ }
+ }
+}