blob: 3986e50bbd0908c878b2dc37c7923720649bb998 [file] [log] [blame]
// 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();
}
}