• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2016, the R8 project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file.
4 package com.android.tools.r8.naming;
5 
6 import com.android.tools.r8.graph.DexField;
7 import com.android.tools.r8.graph.DexMethod;
8 import com.android.tools.r8.graph.DexType;
9 import com.android.tools.r8.graph.IndexedDexItem;
10 import com.android.tools.r8.naming.MemberNaming.FieldSignature;
11 import com.android.tools.r8.naming.MemberNaming.MethodSignature;
12 import com.android.tools.r8.naming.MemberNaming.Signature;
13 import com.android.tools.r8.utils.DescriptorUtils;
14 import com.google.common.collect.BiMap;
15 import com.google.common.collect.ImmutableBiMap;
16 import com.google.common.collect.ImmutableMap;
17 import java.io.IOException;
18 import java.io.StringWriter;
19 import java.io.Writer;
20 import java.util.Hashtable;
21 import java.util.Map;
22 import java.util.function.Consumer;
23 
24 public class ClassNameMapper {
25 
26   private final ImmutableMap<String, ClassNaming> classNameMappings;
27   private ImmutableBiMap<String, String> nameMapping;
28 
29   private Hashtable<Signature, Signature> signatureMap = new Hashtable<>();
30 
ClassNameMapper(Map<String, ClassNaming> classNameMappings)31   ClassNameMapper(Map<String, ClassNaming> classNameMappings) {
32     this.classNameMappings = ImmutableMap.copyOf(classNameMappings);
33   }
34 
canonicalizeSignature(Signature signature)35   private Signature canonicalizeSignature(Signature signature) {
36     Signature result = signatureMap.get(signature);
37     if (result != null) {
38       return result;
39     }
40     signatureMap.put(signature, signature);
41     return signature;
42   }
43 
getRenamedMethodSignature(DexMethod method)44   public MethodSignature getRenamedMethodSignature(DexMethod method) {
45     DexType[] parameters = method.proto.parameters.values;
46     String[] parameterTypes = new String[parameters.length];
47     for (int i = 0; i < parameters.length; i++) {
48       parameterTypes[i] = deobfuscateType(parameters[i].toDescriptorString());
49     }
50     String returnType = deobfuscateType(method.proto.returnType.toDescriptorString());
51 
52     MethodSignature signature = new MethodSignature(method.name.toString(), returnType,
53         parameterTypes);
54     return (MethodSignature) canonicalizeSignature(signature);
55   }
56 
getRenamedFieldSignature(DexField field)57   public Signature getRenamedFieldSignature(DexField field) {
58     String type = deobfuscateType(field.type.toDescriptorString());
59     return canonicalizeSignature(new FieldSignature(field.name.toString(), type));
60   }
61 
62   /**
63    * Deobfuscate a class name.
64    *
65    * Returns the deobfuscated name if a mapping was found. Otherwise it returns the passed in name.
66    */
deobfuscateClassName(String name)67   public String deobfuscateClassName(String name) {
68     ClassNaming classNaming = classNameMappings.get(name);
69     if (classNaming == null) {
70       return name;
71     }
72     return classNaming.originalName;
73   }
74 
deobfuscateType(String asString)75   private String deobfuscateType(String asString) {
76     return DescriptorUtils.descriptorToJavaType(asString, this);
77   }
78 
getClassNaming(String name)79   public ClassNaming getClassNaming(String name) {
80     return classNameMappings.get(name);
81   }
82 
write(Writer writer, boolean collapseRanges)83   public void write(Writer writer, boolean collapseRanges) throws IOException {
84     for (ClassNaming naming : classNameMappings.values()) {
85       naming.write(writer, collapseRanges);
86     }
87   }
88 
forAllClassNamings(Consumer<ClassNaming> consumer)89   public void forAllClassNamings(Consumer<ClassNaming> consumer) {
90     classNameMappings.values().forEach(consumer);
91   }
92 
93   @Override
toString()94   public String toString() {
95     try {
96       StringWriter writer = new StringWriter();
97       write(writer, false);
98       return writer.toString();
99     } catch (IOException e) {
100       return e.toString();
101     }
102   }
103 
getObfuscatedToOriginalMapping()104   public BiMap<String, String> getObfuscatedToOriginalMapping() {
105     if (nameMapping == null) {
106       ImmutableBiMap.Builder<String, String> builder = ImmutableBiMap.builder();
107       for (String name : classNameMappings.keySet()) {
108         builder.put(name, classNameMappings.get(name).originalName);
109       }
110       nameMapping = builder.build();
111     }
112     return nameMapping;
113   }
114 
115   @Override
equals(Object o)116   public boolean equals(Object o) {
117     return o instanceof ClassNameMapper
118         && classNameMappings.equals(((ClassNameMapper) o).classNameMappings);
119   }
120 
121   @Override
hashCode()122   public int hashCode() {
123     return 31 * classNameMappings.hashCode();
124   }
125 
originalNameOf(IndexedDexItem item)126   public String originalNameOf(IndexedDexItem item) {
127     if (item instanceof DexField) {
128       return lookupName(getRenamedFieldSignature((DexField) item), ((DexField) item).clazz);
129     } else if (item instanceof DexMethod) {
130       return lookupName(getRenamedMethodSignature((DexMethod) item), ((DexMethod) item).holder);
131     } else if (item instanceof DexType) {
132       return DescriptorUtils.descriptorToJavaType(((DexType) item).toDescriptorString(), this);
133     } else {
134       return item.toString();
135     }
136   }
137 
lookupName(Signature signature, DexType clazz)138   private String lookupName(Signature signature, DexType clazz) {
139     String decoded = DescriptorUtils.descriptorToJavaType(clazz.descriptor.toString());
140     ClassNaming classNaming = getClassNaming(decoded);
141     if (classNaming == null) {
142       return decoded + " " + signature.toString();
143     }
144     MemberNaming memberNaming = classNaming.lookup(signature);
145     if (memberNaming == null) {
146       return classNaming.originalName + " " + signature.toString();
147     }
148     return classNaming.originalName + " " + memberNaming.signature.toString();
149   }
150 
originalSignatureOf(DexMethod method)151   public Signature originalSignatureOf(DexMethod method) {
152     String decoded = DescriptorUtils
153         .descriptorToJavaType(method.holder.descriptor.toString());
154     MethodSignature memberSignature = getRenamedMethodSignature(method);
155     ClassNaming classNaming = getClassNaming(decoded);
156     if (classNaming == null) {
157       return memberSignature;
158     }
159     MemberNaming memberNaming = classNaming.lookup(memberSignature);
160     if (memberNaming == null) {
161       return memberSignature;
162     }
163     return memberNaming.signature;
164   }
165 
originalNameOf(DexType clazz)166   public String originalNameOf(DexType clazz) {
167     return deobfuscateType(clazz.descriptor.toString());
168   }
169 }
170