| // Copyright (c) 2018, 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.utils.BiMapContainer; |
| import com.google.common.collect.ImmutableBiMap; |
| import com.google.common.collect.ImmutableSet; |
| import com.google.common.collect.Sets; |
| import java.util.Map; |
| |
| /** |
| * Provides a translation between class names based on a source and target proguard map. |
| * |
| * A mapping consists of: |
| * |
| * <ul> |
| * <li> {@link #translation} a bidirectional mapping between obfuscated names on the source |
| * proguard map to the corresponding class in the target proguard map |
| * <li> {@link #newClasses} a set of the unobfuscated names of classes that are in the source but |
| * not the target map |
| * <li> {@link #unusedNames} a set of names in the target map that are not used by the source map |
| * </ul> |
| */ |
| public class ClassRenamingMapper { |
| |
| public static ClassRenamingMapper from(ClassNameMapper originalMap, ClassNameMapper targetMap) { |
| ImmutableBiMap.Builder<String, String> translationBuilder = ImmutableBiMap.builder(); |
| ImmutableSet.Builder<String> newClasses = ImmutableSet.builder(); |
| |
| Map<String, String> sourceOriginalToObfuscated = |
| originalMap.getObfuscatedToOriginalMapping().inverse; |
| |
| BiMapContainer<String, String> targetMapping = targetMap.getObfuscatedToOriginalMapping(); |
| Map<String, String> targetOriginalToObfuscated = targetMapping.inverse; |
| |
| for (String originalName : sourceOriginalToObfuscated.keySet()) { |
| String sourceObfuscatedName = sourceOriginalToObfuscated.get(originalName); |
| String targetObfuscatedName = targetOriginalToObfuscated.get(originalName); |
| if (targetObfuscatedName == null) { |
| newClasses.add(originalName); |
| continue; |
| } |
| translationBuilder.put(sourceObfuscatedName, targetObfuscatedName); |
| } |
| |
| ImmutableBiMap<String, String> translation = translationBuilder.build(); |
| ImmutableSet<String> unusedNames = |
| ImmutableSet.copyOf(Sets.difference(targetMapping.original.keySet(), translation.values())); |
| |
| return new ClassRenamingMapper(translation, newClasses.build(), unusedNames); |
| } |
| |
| /** |
| * Mapping from obfuscated class names in the source map to their counterpart in the target name |
| * map. |
| */ |
| public final ImmutableBiMap<String, String> translation; |
| |
| /** |
| * Set of (unobfuscated) class names that are present in the source map but not in the target map. |
| */ |
| public final ImmutableSet<String> newClasses; |
| |
| /** |
| * Set of (obfuscated) class names that are present in the target map but not in the source map. |
| */ |
| public final ImmutableSet<String> unusedNames; |
| |
| private ClassRenamingMapper(ImmutableBiMap<String, String> translation, |
| ImmutableSet<String> newClasses, ImmutableSet<String> unusedNames) { |
| this.translation = translation; |
| this.newClasses = newClasses; |
| this.unusedNames = unusedNames; |
| } |
| |
| @Override |
| public String toString() { |
| StringBuilder builder = new StringBuilder(); |
| builder.append("Translation:\n\n"); |
| for (String name : translation.keySet()) { |
| String newName = translation.get(name); |
| builder.append(name.equals(newName) ? " " : " --- ") |
| .append(name) |
| .append(" -> ") |
| .append(newName) |
| .append('\n'); |
| } |
| builder.append("\nNew classes:\n\n"); |
| for (String name : newClasses) { |
| builder.append(" ") |
| .append(name) |
| .append('\n'); |
| } |
| builder.append("\nUnused names:\n\n"); |
| for (String unused : unusedNames) { |
| builder.append(" ") |
| .append(unused) |
| .append('\n'); |
| } |
| return builder.toString(); |
| } |
| } |