blob: 2fd89341517ed10134e88a2610e94e53c368f17b [file] [log] [blame]
// 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 com.android.tools.r8.DiagnosticsHandler;
import com.android.tools.r8.StringConsumer;
import com.android.tools.r8.graph.DexApplication;
import com.android.tools.r8.graph.DexClass;
import com.android.tools.r8.graph.DexEncodedMethod;
import com.android.tools.r8.graph.DexField;
import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.DexReference;
import com.android.tools.r8.graph.DexType;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.Set;
abstract class ResultFormatter {
private final StringConsumer output;
private final DiagnosticsHandler diagnosticsHandler;
ResultFormatter(StringConsumer output, DiagnosticsHandler diagnosticsHandler) {
this.output = output;
this.diagnosticsHandler = diagnosticsHandler;
}
protected void append(String string) {
output.accept(string, diagnosticsHandler);
}
protected void appendLine(String string) {
output.accept(string + System.lineSeparator(), diagnosticsHandler);
}
protected void printArguments(DexMethod method) {
append("(");
for (int i = 0; i < method.getArity(); i++) {
if (i != 0) {
append(",");
}
append(method.proto.parameters.values[i].toSourceString());
}
append(")");
}
protected abstract void printConstructorName(DexEncodedMethod encodedMethod);
private void printError(String message) {
appendLine("# Error: " + message);
}
protected abstract void printField(DexClass dexClass, DexField field);
protected abstract void printMethod(DexEncodedMethod encodedMethod, String typeName);
protected abstract void printPackageNames(List<String> packageNames);
protected void printNameAndReturn(DexEncodedMethod encodedMethod) {
if (encodedMethod.accessFlags.isConstructor()) {
printConstructorName(encodedMethod);
} else {
DexMethod method = encodedMethod.method;
append(method.proto.returnType.toSourceString());
append(" ");
append(method.name.toSourceString());
}
}
protected abstract void printTypeHeader(DexClass dexClass);
protected abstract void printTypeFooter();
void format(Result result) {
int errors =
print(
result.application,
result.types,
result.keepPackageNames,
result.fields,
result.methods,
result.missingDefinition);
output.finished(diagnosticsHandler);
assert errors == result.missingDefinition.size();
}
private int print(
DexApplication application,
Set<DexType> types,
Set<String> keepPackageNames,
Map<DexType, Set<DexField>> fields,
Map<DexType, Set<DexMethod>> methods,
Set<DexReference> missingDefinition) {
int errors = 0;
List<DexType> sortedTypes = new ArrayList<>(types);
sortedTypes.sort(Comparator.comparing(DexType::toSourceString));
for (DexType type : sortedTypes) {
DexClass dexClass = application.definitionFor(type);
if (missingDefinition.contains(type)) {
assert dexClass == null;
printError("Could not find definition for type " + type.toSourceString());
errors++;
continue;
}
printTypeHeader(dexClass);
List<DexEncodedMethod> methodDefinitions = new ArrayList<>(methods.size());
for (DexMethod method : methods.get(type)) {
DexEncodedMethod encodedMethod = dexClass.lookupMethod(method);
if (missingDefinition.contains(method)) {
assert encodedMethod == null;
printError("Could not find definition for method " + method.toSourceString());
errors++;
continue;
}
methodDefinitions.add(encodedMethod);
}
methodDefinitions.sort(Comparator.comparing(x -> x.method.name.toSourceString()));
for (DexEncodedMethod encodedMethod : methodDefinitions) {
printMethod(encodedMethod, dexClass.type.toSourceString());
}
List<DexField> sortedFields = new ArrayList<>(fields.get(type));
sortedFields.sort(Comparator.comparing(DexField::toSourceString));
for (DexField field : sortedFields) {
if (missingDefinition.contains(field)) {
printError("Could not find definition for field " + field.toSourceString());
errors++;
continue;
}
printField(dexClass, field);
}
printTypeFooter();
}
ArrayList<String> packageNamesToKeep = new ArrayList<>(keepPackageNames);
Collections.sort(packageNamesToKeep);
printPackageNames(packageNamesToKeep);
return errors;
}
}