| // 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.naming; |
| |
| import static com.android.tools.r8.graph.lens.GraphLens.getIdentityLens; |
| import static com.android.tools.r8.utils.DescriptorUtils.descriptorToJavaType; |
| |
| import com.android.tools.r8.graph.AppInfoWithClassHierarchy; |
| import com.android.tools.r8.graph.AppView; |
| import com.android.tools.r8.graph.DexClass; |
| import com.android.tools.r8.graph.DexEncodedField; |
| import com.android.tools.r8.graph.DexReference; |
| import com.android.tools.r8.graph.DexString; |
| import com.android.tools.r8.graph.DexType; |
| import com.android.tools.r8.graph.DexValue.DexItemBasedValueString; |
| import com.android.tools.r8.graph.DexValue.DexValueString; |
| import com.android.tools.r8.graph.ProgramField; |
| import com.android.tools.r8.naming.dexitembasedstring.NameComputationInfo; |
| import com.android.tools.r8.shaking.ProguardClassFilter; |
| import com.android.tools.r8.utils.DescriptorUtils; |
| import com.android.tools.r8.utils.ThreadUtils; |
| import java.util.concurrent.ExecutionException; |
| import java.util.concurrent.ExecutorService; |
| |
| /** Replaces all instances of DexItemBasedValueString by DexValueString. */ |
| public class IdentifierMinifier { |
| |
| private final AppView<? extends AppInfoWithClassHierarchy> appView; |
| private final ProguardClassFilter adaptClassStrings; |
| |
| public IdentifierMinifier(AppView<? extends AppInfoWithClassHierarchy> appView) { |
| this.appView = appView; |
| this.adaptClassStrings = appView.options().getProguardConfiguration().getAdaptClassStrings(); |
| } |
| |
| public void run(ExecutorService executorService) throws ExecutionException { |
| adaptClassStringsInStaticFields(executorService); |
| replaceDexItemBasedConstStringInStaticFields(executorService); |
| } |
| |
| private void adaptClassStringsInStaticFields(ExecutorService executorService) |
| throws ExecutionException { |
| if (adaptClassStrings.isEmpty()) { |
| return; |
| } |
| ThreadUtils.processItems( |
| appView.appInfo().classes(), |
| clazz -> { |
| if (adaptClassStrings.matches(clazz.getType())) { |
| for (DexEncodedField field : clazz.staticFields()) { |
| adaptClassStringsInStaticField(field); |
| } |
| } |
| }, |
| appView.options().getThreadingModule(), |
| executorService); |
| } |
| |
| private void adaptClassStringsInStaticField(DexEncodedField field) { |
| assert field.isStatic(); |
| DexValueString staticValue = field.getStaticValue().asDexValueString(); |
| if (staticValue != null) { |
| field.setStaticValue( |
| new DexValueString(getRenamedStringLiteral(appView, staticValue.getValue()))); |
| } |
| } |
| |
| public static DexString getRenamedStringLiteral( |
| AppView<? extends AppInfoWithClassHierarchy> appView, DexString originalLiteral) { |
| String descriptor = |
| DescriptorUtils.javaTypeToDescriptorIfValidJavaType(originalLiteral.toString()); |
| if (descriptor == null) { |
| return originalLiteral; |
| } |
| DexType type = appView.dexItemFactory().createType(descriptor); |
| DexType originalType = appView.graphLens().getOriginalType(type, getIdentityLens()); |
| if (originalType.isNotIdenticalTo(type)) { |
| // The type has changed to something clashing with the string. |
| return originalLiteral; |
| } |
| DexType rewrittenType = appView.graphLens().lookupType(type, getIdentityLens()); |
| DexClass clazz = appView.appInfo().definitionForWithoutExistenceAssert(rewrittenType); |
| if (clazz == null || clazz.isNotProgramClass()) { |
| return originalLiteral; |
| } |
| DexString rewrittenString = appView.getNamingLens().lookupClassDescriptor(rewrittenType); |
| return rewrittenString == null |
| ? originalLiteral |
| : appView.dexItemFactory().createString(descriptorToJavaType(rewrittenString.toString())); |
| } |
| |
| private void replaceDexItemBasedConstStringInStaticFields(ExecutorService executorService) |
| throws ExecutionException { |
| ThreadUtils.processItems( |
| appView.appInfo().classes(), |
| clazz -> |
| clazz.forEachProgramStaticFieldMatching( |
| IdentifierMinifier::hasExplicitStaticDexItemBasedValueString, |
| this::replaceDexItemBasedConstStringInStaticField), |
| appView.options().getThreadingModule(), |
| executorService); |
| } |
| |
| private void replaceDexItemBasedConstStringInStaticField(ProgramField field) { |
| DexItemBasedValueString staticValue = |
| field.getDefinition().getStaticValue().asDexItemBasedValueString(); |
| DexString replacement = |
| staticValue.getNameComputationInfo().computeNameFor(staticValue.getValue(), appView); |
| field.getDefinition().setStaticValue(new DexValueString(replacement)); |
| } |
| |
| public void rewriteDexItemBasedConstStringInStaticFields(ExecutorService executorService) |
| throws ExecutionException { |
| ThreadUtils.processItems( |
| appView.appInfo().classes(), |
| clazz -> |
| clazz.forEachProgramStaticFieldMatching( |
| IdentifierMinifier::hasExplicitStaticDexItemBasedValueString, |
| this::rewriteDexItemBasedConstStringInStaticFields), |
| appView.options().getThreadingModule(), |
| executorService); |
| } |
| |
| private void rewriteDexItemBasedConstStringInStaticFields(ProgramField field) { |
| DexItemBasedValueString staticValue = |
| field.getDefinition().getStaticValue().asDexItemBasedValueString(); |
| DexReference rewrittenReference = |
| appView.graphLens().getRenamedReference(staticValue.getValue(), appView.codeLens()); |
| NameComputationInfo<?> rewrittenNameComputationInfo = |
| staticValue |
| .getNameComputationInfo() |
| .rewrittenWithLens(appView.graphLens(), appView.codeLens()); |
| field |
| .getDefinition() |
| .setStaticValue( |
| new DexItemBasedValueString(rewrittenReference, rewrittenNameComputationInfo)); |
| } |
| |
| private static boolean hasExplicitStaticDexItemBasedValueString(DexEncodedField field) { |
| return field.hasExplicitStaticValue() && field.getStaticValue().isDexItemBasedValueString(); |
| } |
| } |