| // Copyright (c) 2017, 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.shaking; |
| |
| import com.android.tools.r8.graph.DexEncodedField; |
| import com.android.tools.r8.graph.DexEncodedMethod; |
| import com.android.tools.r8.graph.DexProgramClass; |
| import java.nio.charset.StandardCharsets; |
| |
| class UsagePrinter { |
| private static final String INDENT = " "; |
| |
| static final UsagePrinter DONT_PRINT = new NoOpUsagePrinter(); |
| |
| private final StringBuilder writer; |
| private DexProgramClass enclosingClazz = null; |
| private boolean clazzPrefixPrinted = false; |
| |
| UsagePrinter() { |
| writer = new StringBuilder(); |
| } |
| |
| String toStringContent() { |
| return writer.toString(); |
| } |
| |
| byte[] toByteArray() { |
| return writer.toString().getBytes(StandardCharsets.UTF_8); |
| } |
| |
| void printUnusedClass(DexProgramClass clazz) { |
| writer.append(clazz.toSourceString()); |
| writer.append('\n'); |
| } |
| |
| // Visiting methods and fields of the given clazz. |
| void visiting(DexProgramClass clazz) { |
| assert enclosingClazz == null; |
| enclosingClazz = clazz; |
| } |
| |
| // Visited methods and fields of the top at the clazz stack. |
| void visited() { |
| enclosingClazz = null; |
| clazzPrefixPrinted = false; |
| } |
| |
| private void printClazzPrefixIfNecessary() { |
| assert enclosingClazz != null; |
| if (!clazzPrefixPrinted) { |
| writer.append(enclosingClazz.toSourceString()); |
| writer.append('\n'); |
| clazzPrefixPrinted = true; |
| } |
| } |
| |
| void printUnusedMethod(DexEncodedMethod method) { |
| printClazzPrefixIfNecessary(); |
| writer.append(INDENT); |
| String accessFlags = method.accessFlags.toString(); |
| if (!accessFlags.isEmpty()) { |
| writer.append(accessFlags).append(' '); |
| } |
| writer.append(method.method.proto.returnType.toSourceString()).append(' '); |
| writer.append(method.method.name.toSourceString()); |
| writer.append('('); |
| for (int i = 0; i < method.method.proto.parameters.values.length; i++) { |
| if (i != 0) { |
| writer.append(','); |
| } |
| writer.append(method.method.proto.parameters.values[i].toSourceString()); |
| } |
| writer.append(')'); |
| writer.append('\n'); |
| } |
| |
| void printUnusedField(DexEncodedField field) { |
| printClazzPrefixIfNecessary(); |
| writer.append(INDENT); |
| String accessFlags = field.accessFlags.toString(); |
| if (!accessFlags.isEmpty()) { |
| writer.append(accessFlags).append(' '); |
| } |
| writer.append(field.field.type.toSourceString()).append(" "); |
| writer.append(field.field.name.toSourceString()); |
| writer.append('\n'); |
| } |
| |
| // Empty implementation to silently ignore printing dead code. |
| private static class NoOpUsagePrinter extends UsagePrinter { |
| |
| @Override |
| byte[] toByteArray() { |
| return null; |
| } |
| |
| @Override |
| void printUnusedClass(DexProgramClass clazz) { |
| // Intentionally left empty. |
| } |
| |
| @Override |
| void visiting(DexProgramClass clazz) { |
| // Intentionally left empty. |
| } |
| |
| @Override |
| void visited() { |
| // Intentionally left empty. |
| } |
| |
| @Override |
| void printUnusedMethod(DexEncodedMethod method) { |
| // Intentionally left empty. |
| } |
| |
| @Override |
| void printUnusedField(DexEncodedField field) { |
| // Intentionally left empty. |
| } |
| } |
| } |