blob: f8e2e4ed781158e4bfe1d3329ded7f755eab23cb [file] [log] [blame]
// Copyright (c) 2019, 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 com.android.tools.r8.errors.Unimplemented;
import com.android.tools.r8.graph.DexApplication;
import com.android.tools.r8.graph.DexCallSite;
import com.android.tools.r8.graph.DexField;
import com.android.tools.r8.graph.DexItem;
import com.android.tools.r8.graph.DexItemFactory;
import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.DexString;
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.graph.InnerClassAttribute;
import com.android.tools.r8.utils.DescriptorUtils;
import com.android.tools.r8.utils.InternalOptions;
import com.google.common.base.Strings;
import com.google.common.collect.ImmutableMap;
import java.util.Collections;
import java.util.IdentityHashMap;
import java.util.Map;
import java.util.TreeMap;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;
// Naming lens for rewriting type prefixes.
public class PrefixRewritingNamingLens extends NamingLens {
Map<DexType, DexString> classRenaming = new IdentityHashMap<>();
public static NamingLens createPrefixRewritingNamingLens(
DexApplication app, Map<String, String> additionalRewritePrefix) {
if (app.options.rewritePrefix.isEmpty() && additionalRewritePrefix.isEmpty()) {
return NamingLens.getIdentityLens();
}
return new PrefixRewritingNamingLens(app, additionalRewritePrefix);
}
public PrefixRewritingNamingLens(
DexApplication app, Map<String, String> additionalRewritePrefix) {
// Create a map of descriptor prefix remappings.
Map<String, String> descriptorPrefixRewriting = new TreeMap<>(Collections.reverseOrder());
BiConsumer<String, String> lambda =
(from, to) ->
descriptorPrefixRewriting.put(
"L" + DescriptorUtils.getBinaryNameFromJavaType(from),
"L" + DescriptorUtils.getBinaryNameFromJavaType(to));
app.options.rewritePrefix.forEach(lambda);
additionalRewritePrefix.forEach(lambda);
// Run over all types and remap types with matching prefixes.
// TODO(134732760): Use a more efficient data structure (prefix tree/trie).
DexItemFactory itemFactory = app.options.itemFactory;
itemFactory.forAllTypes(
type -> {
String descriptor = type.descriptor.toString();
int count = 0;
while (descriptor.charAt(count) == '[') {
count++;
}
descriptor = descriptor.substring(count);
for (String s : descriptorPrefixRewriting.keySet()) {
if (descriptor.startsWith(s)) {
String prefix = Strings.repeat("[", count);
classRenaming.put(
type,
itemFactory.createString(
prefix
+ descriptorPrefixRewriting.get(s)
+ descriptor.substring(s.length())));
return;
}
}
});
}
@Override
public DexString lookupDescriptor(DexType type) {
return classRenaming.getOrDefault(type, type.descriptor);
}
@Override
public DexString lookupInnerName(InnerClassAttribute attribute, InternalOptions options) {
return attribute.getInnerName();
}
@Override
public DexString lookupName(DexMethod method) {
return method.name;
}
@Override
public DexString lookupMethodName(DexCallSite callSite) {
return callSite.methodName;
}
@Override
public DexString lookupName(DexField field) {
return field.name;
}
@Override
public String lookupPackageName(String packageName) {
throw new Unimplemented();
}
@Override
public void forAllRenamedTypes(Consumer<DexType> consumer) {
throw new Unimplemented();
}
@Override
public <T extends DexItem> Map<String, T> getRenamedItems(
Class<T> clazz, Predicate<T> predicate, Function<T, String> namer) {
if (clazz == DexType.class) {
return classRenaming.keySet().stream()
.filter(item -> predicate.test(clazz.cast(item)))
.map(clazz::cast)
.collect(ImmutableMap.toImmutableMap(namer, i -> i));
}
return ImmutableMap.of();
}
@Override
public boolean checkTargetCanBeTranslated(DexMethod item) {
return true;
}
}