|  | // 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.references.ClassReference; | 
|  | import com.android.tools.r8.references.MethodReference; | 
|  | import com.android.tools.r8.references.PackageReference; | 
|  | import com.android.tools.r8.references.TypeReference; | 
|  | import com.android.tools.r8.tracereferences.TraceReferencesConsumer.TracedClass; | 
|  | import com.android.tools.r8.tracereferences.TraceReferencesConsumer.TracedField; | 
|  | import com.android.tools.r8.tracereferences.TraceReferencesConsumer.TracedMethod; | 
|  | import com.android.tools.r8.tracereferences.internal.TraceReferencesResult; | 
|  | import com.android.tools.r8.utils.ListUtils; | 
|  | import com.android.tools.r8.utils.StringUtils; | 
|  | import com.android.tools.r8.utils.StringUtils.BraceType; | 
|  | import java.util.ArrayList; | 
|  | import java.util.Collections; | 
|  | import java.util.Comparator; | 
|  | import java.util.List; | 
|  | import java.util.Map; | 
|  | import java.util.Set; | 
|  | import java.util.stream.Collectors; | 
|  |  | 
|  | abstract class Formatter { | 
|  |  | 
|  | private final StringBuilder output; | 
|  |  | 
|  | Formatter() { | 
|  | output = new StringBuilder(); | 
|  | } | 
|  |  | 
|  | String get() { | 
|  | return output.toString(); | 
|  | } | 
|  |  | 
|  | protected void append(String string) { | 
|  | output.append(string); | 
|  | } | 
|  |  | 
|  | protected void appendLine(String string) { | 
|  | output.append(StringUtils.lines(string)); | 
|  | } | 
|  |  | 
|  | protected void printArguments(MethodReference method) { | 
|  | StringUtils.append( | 
|  | output, | 
|  | ListUtils.map(method.getFormalTypes(), TypeReference::getTypeName), | 
|  | ",", | 
|  | BraceType.PARENS); | 
|  | } | 
|  |  | 
|  | protected abstract void printConstructorName(MethodReference method); | 
|  |  | 
|  | protected abstract void printField(TracedField field); | 
|  |  | 
|  | protected abstract void printMethod(TracedMethod method); | 
|  |  | 
|  | protected abstract void printPackageNames(List<String> packageNames); | 
|  |  | 
|  | protected void printReturn(MethodReference method) { | 
|  | append(method.getReturnType() != null ? method.getReturnType().getTypeName() : "void"); | 
|  | } | 
|  |  | 
|  | protected void printNameAndReturn(MethodReference method) { | 
|  | if (method.getMethodName().equals("<init>")) { | 
|  | printConstructorName(method); | 
|  | } else { | 
|  | printReturn(method); | 
|  | append(" "); | 
|  | append(method.getMethodName()); | 
|  | } | 
|  | } | 
|  |  | 
|  | protected abstract void printTypeHeader(TracedClass clazz); | 
|  |  | 
|  | protected abstract void printTypeFooter(); | 
|  |  | 
|  | void format(TraceReferencesResult result) { | 
|  | print( | 
|  | result.getTracedClasses(), | 
|  | result.getTracedPackageNames(), | 
|  | result.getTracedFields(), | 
|  | result.getTracedMethods()); | 
|  | } | 
|  |  | 
|  | private void print( | 
|  | Set<TracedClass> types, | 
|  | Set<PackageReference> keepPackageNames, | 
|  | Map<ClassReference, Set<TracedField>> fields, | 
|  | Map<ClassReference, Set<TracedMethod>> methods) { | 
|  | List<TracedClass> sortedTypes = new ArrayList<>(types); | 
|  | sortedTypes.sort(Comparator.comparing(tracedClass -> tracedClass.getReference().getTypeName())); | 
|  | for (TracedClass type : sortedTypes) { | 
|  | Set<TracedMethod> methodsForClass = | 
|  | methods.getOrDefault(type.getReference(), Collections.emptySet()); | 
|  | Set<TracedField> fieldsForClass = | 
|  | fields.getOrDefault(type.getReference(), Collections.emptySet()); | 
|  | if (type.isMissingDefinition()) { | 
|  | continue; | 
|  | } | 
|  | printTypeHeader(type); | 
|  | List<TracedMethod> sortedMethods = new ArrayList<>(methodsForClass.size()); | 
|  | for (TracedMethod method : methodsForClass) { | 
|  | if (method.isMissingDefinition()) { | 
|  | continue; | 
|  | } | 
|  | assert method.getAccessFlags() != null; | 
|  | sortedMethods.add(method); | 
|  | } | 
|  | sortedMethods.sort( | 
|  | Comparator.comparing(tracedMethod -> tracedMethod.getReference().toString())); | 
|  | for (TracedMethod method : sortedMethods) { | 
|  | printMethod(method); | 
|  | } | 
|  | List<TracedField> sortedFields = new ArrayList<>(fieldsForClass); | 
|  | sortedFields.sort(Comparator.comparing(tracedField -> tracedField.getReference().toString())); | 
|  | for (TracedField field : sortedFields) { | 
|  | if (field.isMissingDefinition()) { | 
|  | continue; | 
|  | } | 
|  | printField(field); | 
|  | } | 
|  | printTypeFooter(); | 
|  | } | 
|  | List<String> packageNamesToKeep = | 
|  | keepPackageNames.stream() | 
|  | .map(PackageReference::getPackageName) | 
|  | .sorted() | 
|  | .collect(Collectors.toList()); | 
|  | printPackageNames(packageNamesToKeep); | 
|  | } | 
|  | } |