summaryrefslogtreecommitdiff
path: root/src/main/java/cuchaz/enigma/bytecode/ClassRenamer.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/java/cuchaz/enigma/bytecode/ClassRenamer.java')
-rw-r--r--src/main/java/cuchaz/enigma/bytecode/ClassRenamer.java1028
1 files changed, 514 insertions, 514 deletions
diff --git a/src/main/java/cuchaz/enigma/bytecode/ClassRenamer.java b/src/main/java/cuchaz/enigma/bytecode/ClassRenamer.java
index d874633..a52cab6 100644
--- a/src/main/java/cuchaz/enigma/bytecode/ClassRenamer.java
+++ b/src/main/java/cuchaz/enigma/bytecode/ClassRenamer.java
@@ -8,532 +8,532 @@
8 * Contributors: 8 * Contributors:
9 * Jeff Martin - initial API and implementation 9 * Jeff Martin - initial API and implementation
10 ******************************************************************************/ 10 ******************************************************************************/
11package cuchaz.enigma.bytecode;
12 11
13import java.lang.reflect.InvocationTargetException; 12package cuchaz.enigma.bytecode;
14import java.lang.reflect.Method;
15import java.util.Arrays;
16import java.util.HashMap;
17import java.util.List;
18import java.util.Map;
19 13
20import cuchaz.enigma.mapping.ClassEntry; 14import cuchaz.enigma.mapping.ClassEntry;
21import cuchaz.enigma.mapping.ClassNameReplacer; 15import cuchaz.enigma.mapping.ClassNameReplacer;
22import cuchaz.enigma.mapping.Mappings; 16import cuchaz.enigma.mapping.Mappings;
23import cuchaz.enigma.mapping.Translator; 17import cuchaz.enigma.mapping.Translator;
24import javassist.*; 18import javassist.CtBehavior;
19import javassist.CtClass;
20import javassist.CtField;
21import javassist.Modifier;
25import javassist.bytecode.*; 22import javassist.bytecode.*;
26import javassist.bytecode.SignatureAttribute.*; 23import javassist.bytecode.SignatureAttribute.*;
27 24
25import java.lang.reflect.InvocationTargetException;
26import java.lang.reflect.Method;
27import java.util.Arrays;
28import java.util.HashMap;
29import java.util.List;
30import java.util.Map;
31
28public class ClassRenamer { 32public class ClassRenamer {
29 33
30 private enum SignatureType { 34 public static void applyModifier(Object obj, Mappings.EntryModifier modifier) {
31 Class { 35 int mod = -1;
32 @Override 36 if (obj instanceof CtField)
33 public String rename(String signature, ReplacerClassMap map) { 37 mod = ((CtField) obj).getModifiers();
34 return renameClassSignature(signature, map); 38 else if (obj instanceof CtBehavior)
35 } 39 mod = ((CtBehavior) obj).getModifiers();
36 }, 40 else if (obj instanceof CtClass)
37 Field { 41 mod = ((CtClass) obj).getModifiers();
38 @Override 42
39 public String rename(String signature, ReplacerClassMap map) { 43 if (mod != -1) {
40 return renameFieldSignature(signature, map); 44 switch (modifier) {
41 } 45 case PRIVATE:
42 }, 46 mod = Modifier.setPrivate(mod);
43 Method { 47 break;
44 @Override 48 case PROTECTED:
45 public String rename(String signature, ReplacerClassMap map) { 49 mod = Modifier.setProtected(mod);
46 return renameMethodSignature(signature, map); 50 break;
47 } 51 case PUBLIC:
48 }; 52 mod = Modifier.setPublic(mod);
49 53 break;
50 public abstract String rename(String signature, ReplacerClassMap map); 54 default:
51 } 55 break;
52 56 }
53 private static class ReplacerClassMap extends HashMap<String, String> { 57 if (obj instanceof CtField)
54 58 ((CtField) obj).setModifiers(mod);
55 private ClassNameReplacer replacer; 59 else if (obj instanceof CtBehavior)
56 60 ((CtBehavior) obj).setModifiers(mod);
57 public ReplacerClassMap(ClassNameReplacer replacer) { 61 else
58 this.replacer = replacer; 62 ((CtClass) obj).setModifiers(mod);
59 } 63 }
60 64 }
61 @Override 65
62 public String get(Object obj) { 66 public static void renameClasses(CtClass c, final Translator translator) {
63 if (obj instanceof String) { 67 renameClasses(c, className -> {
64 return get((String) obj); 68 ClassEntry entry = translator.translateEntry(new ClassEntry(className));
65 } 69 if (entry != null) {
66 return null; 70 return entry.getName();
67 } 71 }
68 72 return null;
69 public String get(String className) { 73 });
70 return replacer.replace(className); 74 }
71 } 75
72 } 76 public static void moveAllClassesOutOfDefaultPackage(CtClass c, final String newPackageName) {
73 77 renameClasses(c, className -> {
74 public static void applyModifier(Object obj, Mappings.EntryModifier modifier) 78 ClassEntry entry = new ClassEntry(className);
75 { 79 if (entry.isInDefaultPackage()) {
76 int mod = -1; 80 return newPackageName + "/" + entry.getName();
77 if (obj instanceof CtField) 81 }
78 mod = ((CtField) obj).getModifiers(); 82 return null;
79 else if (obj instanceof CtBehavior) 83 });
80 mod = ((CtBehavior) obj).getModifiers(); 84 }
81 else if (obj instanceof CtClass) 85
82 mod = ((CtClass) obj).getModifiers(); 86 public static void moveAllClassesIntoDefaultPackage(CtClass c, final String oldPackageName) {
83 87 renameClasses(c, className -> {
84 if (mod != -1) 88 ClassEntry entry = new ClassEntry(className);
85 { 89 if (entry.getPackageName().equals(oldPackageName)) {
86 switch (modifier) 90 return entry.getSimpleName();
87 { 91 }
88 case PRIVATE: 92 return null;
89 mod = Modifier.setPrivate(mod); 93 });
90 break; 94 }
91 case PROTECTED: 95
92 mod = Modifier.setProtected(mod); 96 @SuppressWarnings("unchecked")
93 break; 97 public static void renameClasses(CtClass c, ClassNameReplacer replacer) {
94 case PUBLIC: 98
95 mod = Modifier.setPublic(mod); 99 // sadly, we can't use CtClass.renameClass() because SignatureAttribute.renameClass() is extremely buggy =(
96 break; 100
97 default: 101 ReplacerClassMap map = new ReplacerClassMap(replacer);
98 break; 102 ClassFile classFile = c.getClassFile();
99 } 103
100 if (obj instanceof CtField) 104 // rename the constant pool (covers ClassInfo, MethodTypeInfo, and NameAndTypeInfo)
101 ((CtField) obj).setModifiers(mod); 105 ConstPool constPool = c.getClassFile().getConstPool();
102 else if (obj instanceof CtBehavior) 106 constPool.renameClass(map);
103 ((CtBehavior) obj).setModifiers(mod); 107
104 else 108 // rename class attributes
105 ((CtClass) obj).setModifiers(mod); 109 renameAttributes(classFile.getAttributes(), map, SignatureType.Class);
106 } 110
107 } 111 // rename methods
108 112 for (MethodInfo methodInfo : (List<MethodInfo>) classFile.getMethods()) {
109 public static void renameClasses(CtClass c, final Translator translator) { 113 methodInfo.setDescriptor(Descriptor.rename(methodInfo.getDescriptor(), map));
110 renameClasses(c, className -> { 114 renameAttributes(methodInfo.getAttributes(), map, SignatureType.Method);
111 ClassEntry entry = translator.translateEntry(new ClassEntry(className)); 115 }
112 if (entry != null) { 116
113 return entry.getName(); 117 // rename fields
114 } 118 for (FieldInfo fieldInfo : (List<FieldInfo>) classFile.getFields()) {
115 return null; 119 fieldInfo.setDescriptor(Descriptor.rename(fieldInfo.getDescriptor(), map));
116 }); 120 renameAttributes(fieldInfo.getAttributes(), map, SignatureType.Field);
117 } 121 }
118 122
119 public static void moveAllClassesOutOfDefaultPackage(CtClass c, final String newPackageName) { 123 // rename the class name itself last
120 renameClasses(c, className -> { 124 // NOTE: don't use the map here, because setName() calls the buggy SignatureAttribute.renameClass()
121 ClassEntry entry = new ClassEntry(className); 125 // we only want to replace exactly this class name
122 if (entry.isInDefaultPackage()) { 126 String newName = renameClassName(c.getName(), map);
123 return newPackageName + "/" + entry.getName(); 127 if (newName != null) {
124 } 128 c.setName(newName);
125 return null; 129 }
126 }); 130
127 } 131 // replace simple names in the InnerClasses attribute too
128 132 InnerClassesAttribute attr = (InnerClassesAttribute) c.getClassFile().getAttribute(InnerClassesAttribute.tag);
129 public static void moveAllClassesIntoDefaultPackage(CtClass c, final String oldPackageName) { 133 if (attr != null) {
130 renameClasses(c, className -> { 134 for (int i = 0; i < attr.tableLength(); i++) {
131 ClassEntry entry = new ClassEntry(className); 135
132 if (entry.getPackageName().equals(oldPackageName)) { 136 String innerName = attr.innerClass(i);
133 return entry.getSimpleName(); 137 // get the inner class full name (which has already been translated)
134 } 138 ClassEntry classEntry = new ClassEntry(Descriptor.toJvmName(innerName));
135 return null; 139
136 }); 140 if (attr.innerNameIndex(i) != 0) {
137 } 141 // update the inner name
138 142 attr.setInnerNameIndex(i, constPool.addUtf8Info(classEntry.getInnermostClassName()));
139 @SuppressWarnings("unchecked") 143 }
140 public static void renameClasses(CtClass c, ClassNameReplacer replacer) {
141
142 // sadly, we can't use CtClass.renameClass() because SignatureAttribute.renameClass() is extremely buggy =(
143
144 ReplacerClassMap map = new ReplacerClassMap(replacer);
145 ClassFile classFile = c.getClassFile();
146
147 // rename the constant pool (covers ClassInfo, MethodTypeInfo, and NameAndTypeInfo)
148 ConstPool constPool = c.getClassFile().getConstPool();
149 constPool.renameClass(map);
150
151 // rename class attributes
152 renameAttributes(classFile.getAttributes(), map, SignatureType.Class);
153
154 // rename methods
155 for (MethodInfo methodInfo : (List<MethodInfo>) classFile.getMethods()) {
156 methodInfo.setDescriptor(Descriptor.rename(methodInfo.getDescriptor(), map));
157 renameAttributes(methodInfo.getAttributes(), map, SignatureType.Method);
158 }
159
160 // rename fields
161 for (FieldInfo fieldInfo : (List<FieldInfo>) classFile.getFields()) {
162 fieldInfo.setDescriptor(Descriptor.rename(fieldInfo.getDescriptor(), map));
163 renameAttributes(fieldInfo.getAttributes(), map, SignatureType.Field);
164 }
165
166 // rename the class name itself last
167 // NOTE: don't use the map here, because setName() calls the buggy SignatureAttribute.renameClass()
168 // we only want to replace exactly this class name
169 String newName = renameClassName(c.getName(), map);
170 if (newName != null) {
171 c.setName(newName);
172 }
173
174 // replace simple names in the InnerClasses attribute too
175 InnerClassesAttribute attr = (InnerClassesAttribute) c.getClassFile().getAttribute(InnerClassesAttribute.tag);
176 if (attr != null) {
177 for (int i = 0; i < attr.tableLength(); i++) {
178
179 String innerName = attr.innerClass(i);
180 // get the inner class full name (which has already been translated)
181 ClassEntry classEntry = new ClassEntry(Descriptor.toJvmName(innerName));
182
183 if (attr.innerNameIndex(i) != 0) {
184 // update the inner name
185 attr.setInnerNameIndex(i, constPool.addUtf8Info(classEntry.getInnermostClassName()));
186 }
187 144
188 /* DEBUG 145 /* DEBUG
189 System.out.println(String.format("\tDEOBF: %s-> ATTR: %s,%s,%s", classEntry, attr.outerClass(i), attr.innerClass(i), attr.innerName(i))); 146 System.out.println(String.format("\tDEOBF: %s-> ATTR: %s,%s,%s", classEntry, attr.outerClass(i), attr.innerClass(i), attr.innerName(i)));
190 */ 147 */
191 } 148 }
192 } 149 }
193 } 150 }
194 151
195 @SuppressWarnings("unchecked") 152 @SuppressWarnings("unchecked")
196 private static void renameAttributes(List<AttributeInfo> attributes, ReplacerClassMap map, SignatureType type) { 153 private static void renameAttributes(List<AttributeInfo> attributes, ReplacerClassMap map, SignatureType type) {
197 try { 154 try {
198 155
199 // make the rename class method accessible 156 // make the rename class method accessible
200 Method renameClassMethod = AttributeInfo.class.getDeclaredMethod("renameClass", Map.class); 157 Method renameClassMethod = AttributeInfo.class.getDeclaredMethod("renameClass", Map.class);
201 renameClassMethod.setAccessible(true); 158 renameClassMethod.setAccessible(true);
202 159
203 for (AttributeInfo attribute : attributes) { 160 for (AttributeInfo attribute : attributes) {
204 if (attribute instanceof SignatureAttribute) { 161 if (attribute instanceof SignatureAttribute) {
205 // this has to be handled specially because SignatureAttribute.renameClass() is buggy as hell 162 // this has to be handled specially because SignatureAttribute.renameClass() is buggy as hell
206 SignatureAttribute signatureAttribute = (SignatureAttribute) attribute; 163 SignatureAttribute signatureAttribute = (SignatureAttribute) attribute;
207 String newSignature = type.rename(signatureAttribute.getSignature(), map); 164 String newSignature = type.rename(signatureAttribute.getSignature(), map);
208 if (newSignature != null) { 165 if (newSignature != null) {
209 signatureAttribute.setSignature(newSignature); 166 signatureAttribute.setSignature(newSignature);
210 } 167 }
211 } else if (attribute instanceof CodeAttribute) { 168 } else if (attribute instanceof CodeAttribute) {
212 // code attributes have signature attributes too (indirectly) 169 // code attributes have signature attributes too (indirectly)
213 CodeAttribute codeAttribute = (CodeAttribute) attribute; 170 CodeAttribute codeAttribute = (CodeAttribute) attribute;
214 renameAttributes(codeAttribute.getAttributes(), map, type); 171 renameAttributes(codeAttribute.getAttributes(), map, type);
215 } else if (attribute instanceof LocalVariableTypeAttribute) { 172 } else if (attribute instanceof LocalVariableTypeAttribute) {
216 // lvt attributes have signature attributes too 173 // lvt attributes have signature attributes too
217 LocalVariableTypeAttribute localVariableAttribute = (LocalVariableTypeAttribute) attribute; 174 LocalVariableTypeAttribute localVariableAttribute = (LocalVariableTypeAttribute) attribute;
218 renameLocalVariableTypeAttribute(localVariableAttribute, map); 175 renameLocalVariableTypeAttribute(localVariableAttribute, map);
219 } else { 176 } else {
220 renameClassMethod.invoke(attribute, map); 177 renameClassMethod.invoke(attribute, map);
221 } 178 }
222 } 179 }
223 180
224 } catch (NoSuchMethodException | IllegalAccessException | IllegalArgumentException | InvocationTargetException ex) { 181 } catch (NoSuchMethodException | IllegalAccessException | IllegalArgumentException | InvocationTargetException ex) {
225 throw new Error("Unable to call javassist methods by reflection!", ex); 182 throw new Error("Unable to call javassist methods by reflection!", ex);
226 } 183 }
227 } 184 }
228 185
229 private static void renameLocalVariableTypeAttribute(LocalVariableTypeAttribute attribute, ReplacerClassMap map) { 186 private static void renameLocalVariableTypeAttribute(LocalVariableTypeAttribute attribute, ReplacerClassMap map) {
230 187
231 // adapted from LocalVariableAttribute.renameClass() 188 // adapted from LocalVariableAttribute.renameClass()
232 ConstPool cp = attribute.getConstPool(); 189 ConstPool cp = attribute.getConstPool();
233 int n = attribute.tableLength(); 190 int n = attribute.tableLength();
234 byte[] info = attribute.get(); 191 byte[] info = attribute.get();
235 for (int i = 0; i < n; ++i) { 192 for (int i = 0; i < n; ++i) {
236 int pos = i * 10 + 2; 193 int pos = i * 10 + 2;
237 int index = ByteArray.readU16bit(info, pos + 6); 194 int index = ByteArray.readU16bit(info, pos + 6);
238 if (index != 0) { 195 if (index != 0) {
239 String signature = cp.getUtf8Info(index); 196 String signature = cp.getUtf8Info(index);
240 String newSignature = renameLocalVariableSignature(signature, map); 197 String newSignature = renameLocalVariableSignature(signature, map);
241 if (newSignature != null) { 198 if (newSignature != null) {
242 ByteArray.write16bit(cp.addUtf8Info(newSignature), info, pos + 6); 199 ByteArray.write16bit(cp.addUtf8Info(newSignature), info, pos + 6);
243 } 200 }
244 } 201 }
245 } 202 }
246 } 203 }
247 204
248 private static String renameLocalVariableSignature(String signature, ReplacerClassMap map) { 205 private static String renameLocalVariableSignature(String signature, ReplacerClassMap map) {
249 206
250 // for some reason, signatures with . in them don't count as field signatures 207 // for some reason, signatures with . in them don't count as field signatures
251 // looks like anonymous classes delimit with . in stead of $ 208 // looks like anonymous classes delimit with . in stead of $
252 // convert the . to $, but keep track of how many we replace 209 // convert the . to $, but keep track of how many we replace
253 // we need to put them back after we translate 210 // we need to put them back after we translate
254 int start = signature.lastIndexOf('$') + 1; 211 int start = signature.lastIndexOf('$') + 1;
255 int numConverted = 0; 212 int numConverted = 0;
256 StringBuilder buf = new StringBuilder(signature); 213 StringBuilder buf = new StringBuilder(signature);
257 for (int i = buf.length() - 1; i >= start; i--) { 214 for (int i = buf.length() - 1; i >= start; i--) {
258 char c = buf.charAt(i); 215 char c = buf.charAt(i);
259 if (c == '.') { 216 if (c == '.') {
260 buf.setCharAt(i, '$'); 217 buf.setCharAt(i, '$');
261 numConverted++; 218 numConverted++;
262 } 219 }
263 } 220 }
264 signature = buf.toString(); 221 signature = buf.toString();
265 222
266 // translate 223 // translate
267 String newSignature = renameFieldSignature(signature, map); 224 String newSignature = renameFieldSignature(signature, map);
268 if (newSignature != null) { 225 if (newSignature != null) {
269 226
270 // put the delimiters back 227 // put the delimiters back
271 buf = new StringBuilder(newSignature); 228 buf = new StringBuilder(newSignature);
272 for (int i = buf.length() - 1; i >= 0 && numConverted > 0; i--) { 229 for (int i = buf.length() - 1; i >= 0 && numConverted > 0; i--) {
273 char c = buf.charAt(i); 230 char c = buf.charAt(i);
274 if (c == '$') { 231 if (c == '$') {
275 buf.setCharAt(i, '.'); 232 buf.setCharAt(i, '.');
276 numConverted--; 233 numConverted--;
277 } 234 }
278 } 235 }
279 assert (numConverted == 0); 236 assert (numConverted == 0);
280 newSignature = buf.toString(); 237 newSignature = buf.toString();
281 238
282 return newSignature; 239 return newSignature;
283 } 240 }
284 241
285 return null; 242 return null;
286 } 243 }
287 244
288 private static String renameClassSignature(String signature, ReplacerClassMap map) { 245 private static String renameClassSignature(String signature, ReplacerClassMap map) {
289 try { 246 try {
290 ClassSignature type = renameType(SignatureAttribute.toClassSignature(signature), map); 247 ClassSignature type = renameType(SignatureAttribute.toClassSignature(signature), map);
291 return type.encode(); 248 return type.encode();
292 } catch (BadBytecode ex) { 249 } catch (BadBytecode ex) {
293 throw new Error("Can't parse field signature: " + signature); 250 throw new Error("Can't parse field signature: " + signature);
294 } 251 }
295 } 252 }
296 253
297 private static String renameFieldSignature(String signature, ReplacerClassMap map) { 254 private static String renameFieldSignature(String signature, ReplacerClassMap map) {
298 try { 255 try {
299 ObjectType type = renameType(SignatureAttribute.toFieldSignature(signature), map); 256 ObjectType type = renameType(SignatureAttribute.toFieldSignature(signature), map);
300 if (type != null) { 257 if (type != null) {
301 return type.encode(); 258 return type.encode();
302 } 259 }
303 return null; 260 return null;
304 } catch (BadBytecode ex) { 261 } catch (BadBytecode ex) {
305 throw new Error("Can't parse class signature: " + signature); 262 throw new Error("Can't parse class signature: " + signature);
306 } 263 }
307 } 264 }
308 265
309 private static String renameMethodSignature(String signature, ReplacerClassMap map) { 266 private static String renameMethodSignature(String signature, ReplacerClassMap map) {
310 try { 267 try {
311 MethodSignature type = renameType(SignatureAttribute.toMethodSignature(signature), map); 268 MethodSignature type = renameType(SignatureAttribute.toMethodSignature(signature), map);
312 return type.encode(); 269 return type.encode();
313 } catch (BadBytecode ex) { 270 } catch (BadBytecode ex) {
314 throw new Error("Can't parse method signature: " + signature); 271 throw new Error("Can't parse method signature: " + signature);
315 } 272 }
316 } 273 }
317 274
318 private static TypeParameter[] renameTypeParameter(TypeParameter[] typeParamTypes, ReplacerClassMap map) 275 private static TypeParameter[] renameTypeParameter(TypeParameter[] typeParamTypes, ReplacerClassMap map) {
319 { 276 if (typeParamTypes != null) {
320 if (typeParamTypes != null) { 277 typeParamTypes = Arrays.copyOf(typeParamTypes, typeParamTypes.length);
321 typeParamTypes = Arrays.copyOf(typeParamTypes, typeParamTypes.length); 278 for (int i = 0; i < typeParamTypes.length; i++) {
322 for (int i = 0; i < typeParamTypes.length; i++) { 279 TypeParameter newParamType = renameType(typeParamTypes[i], map);
323 TypeParameter newParamType = renameType(typeParamTypes[i], map); 280 if (newParamType != null) {
324 if (newParamType != null) { 281 typeParamTypes[i] = newParamType;
325 typeParamTypes[i] = newParamType; 282 }
326 } 283 }
327 } 284 }
328 } 285 return typeParamTypes;
329 return typeParamTypes; 286 }
330 } 287
331 288 private static ClassSignature renameType(ClassSignature type, ReplacerClassMap map) {
332 private static ClassSignature renameType(ClassSignature type, ReplacerClassMap map) { 289
333 290 TypeParameter[] typeParamTypes = renameTypeParameter(type.getParameters(), map);
334 TypeParameter[] typeParamTypes = renameTypeParameter(type.getParameters(), map); 291
335 292 ClassType superclassType = type.getSuperClass();
336 ClassType superclassType = type.getSuperClass(); 293 if (superclassType != ClassType.OBJECT) {
337 if (superclassType != ClassType.OBJECT) { 294 ClassType newSuperclassType = renameType(superclassType, map);
338 ClassType newSuperclassType = renameType(superclassType, map); 295 if (newSuperclassType != null) {
339 if (newSuperclassType != null) { 296 superclassType = newSuperclassType;
340 superclassType = newSuperclassType; 297 }
341 } 298 }
342 } 299
343 300 ClassType[] interfaceTypes = type.getInterfaces();
344 ClassType[] interfaceTypes = type.getInterfaces(); 301 if (interfaceTypes != null) {
345 if (interfaceTypes != null) { 302 interfaceTypes = Arrays.copyOf(interfaceTypes, interfaceTypes.length);
346 interfaceTypes = Arrays.copyOf(interfaceTypes, interfaceTypes.length); 303 for (int i = 0; i < interfaceTypes.length; i++) {
347 for (int i = 0; i < interfaceTypes.length; i++) { 304 ClassType newInterfaceType = renameType(interfaceTypes[i], map);
348 ClassType newInterfaceType = renameType(interfaceTypes[i], map); 305 if (newInterfaceType != null) {
349 if (newInterfaceType != null) { 306 interfaceTypes[i] = newInterfaceType;
350 interfaceTypes[i] = newInterfaceType; 307 }
351 } 308 }
352 } 309 }
353 } 310
354 311 return new ClassSignature(typeParamTypes, superclassType, interfaceTypes);
355 return new ClassSignature(typeParamTypes, superclassType, interfaceTypes); 312 }
356 } 313
357 314 private static MethodSignature renameType(MethodSignature type, ReplacerClassMap map) {
358 private static MethodSignature renameType(MethodSignature type, ReplacerClassMap map) { 315
359 316 TypeParameter[] typeParamTypes = renameTypeParameter(type.getTypeParameters(), map);
360 TypeParameter[] typeParamTypes = renameTypeParameter(type.getTypeParameters(), map); 317
361 318 Type[] paramTypes = type.getParameterTypes();
362 Type[] paramTypes = type.getParameterTypes(); 319 if (paramTypes != null) {
363 if (paramTypes != null) { 320 paramTypes = Arrays.copyOf(paramTypes, paramTypes.length);
364 paramTypes = Arrays.copyOf(paramTypes, paramTypes.length); 321 for (int i = 0; i < paramTypes.length; i++) {
365 for (int i = 0; i < paramTypes.length; i++) { 322 Type newParamType = renameType(paramTypes[i], map);
366 Type newParamType = renameType(paramTypes[i], map); 323 if (newParamType != null) {
367 if (newParamType != null) { 324 paramTypes[i] = newParamType;
368 paramTypes[i] = newParamType; 325 }
369 } 326 }
370 } 327 }
371 } 328
372 329 Type returnType = type.getReturnType();
373 Type returnType = type.getReturnType(); 330 if (returnType != null) {
374 if (returnType != null) { 331 Type newReturnType = renameType(returnType, map);
375 Type newReturnType = renameType(returnType, map); 332 if (newReturnType != null) {
376 if (newReturnType != null) { 333 returnType = newReturnType;
377 returnType = newReturnType; 334 }
378 } 335 }
379 } 336
380 337 ObjectType[] exceptionTypes = type.getExceptionTypes();
381 ObjectType[] exceptionTypes = type.getExceptionTypes(); 338 if (exceptionTypes != null) {
382 if (exceptionTypes != null) { 339 exceptionTypes = Arrays.copyOf(exceptionTypes, exceptionTypes.length);
383 exceptionTypes = Arrays.copyOf(exceptionTypes, exceptionTypes.length); 340 for (int i = 0; i < exceptionTypes.length; i++) {
384 for (int i = 0; i < exceptionTypes.length; i++) { 341 ObjectType newExceptionType = renameType(exceptionTypes[i], map);
385 ObjectType newExceptionType = renameType(exceptionTypes[i], map); 342 if (newExceptionType != null) {
386 if (newExceptionType != null) { 343 exceptionTypes[i] = newExceptionType;
387 exceptionTypes[i] = newExceptionType; 344 }
388 } 345 }
389 } 346 }
390 } 347
391 348 return new MethodSignature(typeParamTypes, paramTypes, returnType, exceptionTypes);
392 return new MethodSignature(typeParamTypes, paramTypes, returnType, exceptionTypes); 349 }
393 } 350
394 351 private static Type renameType(Type type, ReplacerClassMap map) {
395 private static Type renameType(Type type, ReplacerClassMap map) { 352 if (type instanceof ObjectType) {
396 if (type instanceof ObjectType) { 353 return renameType((ObjectType) type, map);
397 return renameType((ObjectType) type, map); 354 } else if (type instanceof BaseType) {
398 } else if (type instanceof BaseType) { 355 return renameType((BaseType) type, map);
399 return renameType((BaseType) type, map); 356 } else {
400 } else { 357 throw new Error("Don't know how to rename type " + type.getClass());
401 throw new Error("Don't know how to rename type " + type.getClass()); 358 }
402 } 359 }
403 } 360
404 361 private static ObjectType renameType(ObjectType type, ReplacerClassMap map) {
405 private static ObjectType renameType(ObjectType type, ReplacerClassMap map) { 362 if (type instanceof ArrayType) {
406 if (type instanceof ArrayType) { 363 return renameType((ArrayType) type, map);
407 return renameType((ArrayType) type, map); 364 } else if (type instanceof ClassType) {
408 } else if (type instanceof ClassType) { 365 return renameType((ClassType) type, map);
409 return renameType((ClassType) type, map); 366 } else if (type instanceof TypeVariable) {
410 } else if (type instanceof TypeVariable) { 367 return renameType((TypeVariable) type, map);
411 return renameType((TypeVariable) type, map); 368 } else {
412 } else { 369 throw new Error("Don't know how to rename type " + type.getClass());
413 throw new Error("Don't know how to rename type " + type.getClass()); 370 }
414 } 371 }
415 } 372
416 373 private static BaseType renameType(BaseType type, ReplacerClassMap map) {
417 private static BaseType renameType(BaseType type, ReplacerClassMap map) { 374 // don't have to rename primitives
418 // don't have to rename primitives 375 return null;
419 return null; 376 }
420 } 377
421 378 private static TypeVariable renameType(TypeVariable type, ReplacerClassMap map) {
422 private static TypeVariable renameType(TypeVariable type, ReplacerClassMap map) { 379 // don't have to rename template args
423 // don't have to rename template args 380 return null;
424 return null; 381 }
425 } 382
426 383 private static ClassType renameType(ClassType type, ReplacerClassMap map) {
427 private static ClassType renameType(ClassType type, ReplacerClassMap map) { 384
428 385 // translate type args
429 // translate type args 386 TypeArgument[] args = type.getTypeArguments();
430 TypeArgument[] args = type.getTypeArguments(); 387 if (args != null) {
431 if (args != null) { 388 args = Arrays.copyOf(args, args.length);
432 args = Arrays.copyOf(args, args.length); 389 for (int i = 0; i < args.length; i++) {
433 for (int i = 0; i < args.length; i++) { 390 TypeArgument newType = renameType(args[i], map);
434 TypeArgument newType = renameType(args[i], map); 391 if (newType != null) {
435 if (newType != null) { 392 args[i] = newType;
436 args[i] = newType; 393 }
437 } 394 }
438 } 395 }
439 } 396
440 397 if (type instanceof NestedClassType) {
441 if (type instanceof NestedClassType) { 398 NestedClassType nestedType = (NestedClassType) type;
442 NestedClassType nestedType = (NestedClassType) type; 399
443 400 // translate the name
444 // translate the name 401 String name = getClassName(type);
445 String name = getClassName(type); 402 String newName = map.get(name);
446 String newName = map.get(name); 403 if (newName != null) {
447 if (newName != null) { 404 name = new ClassEntry(newName).getInnermostClassName();
448 name = new ClassEntry(newName).getInnermostClassName(); 405 }
449 } 406
450 407 // translate the parent class too
451 // translate the parent class too 408 ClassType parent = renameType(nestedType.getDeclaringClass(), map);
452 ClassType parent = renameType(nestedType.getDeclaringClass(), map); 409 if (parent == null) {
453 if (parent == null) { 410 parent = nestedType.getDeclaringClass();
454 parent = nestedType.getDeclaringClass(); 411 }
455 } 412
456 413 return new NestedClassType(parent, name, args);
457 return new NestedClassType(parent, name, args); 414 } else {
458 } else { 415
459 416 // translate the name
460 // translate the name 417 String name = type.getName();
461 String name = type.getName(); 418 String newName = renameClassName(name, map);
462 String newName = renameClassName(name, map); 419 if (newName != null) {
463 if (newName != null) { 420 name = newName;
464 name = newName; 421 }
465 } 422
466 423 return new ClassType(name, args);
467 return new ClassType(name, args); 424 }
468 } 425 }
469 } 426
470 427 private static String getClassName(ClassType type) {
471 private static String getClassName(ClassType type) { 428 if (type instanceof NestedClassType) {
472 if (type instanceof NestedClassType) { 429 NestedClassType nestedType = (NestedClassType) type;
473 NestedClassType nestedType = (NestedClassType) type; 430 return getClassName(nestedType.getDeclaringClass()) + "$" + Descriptor.toJvmName(type.getName().replace('.', '$'));
474 return getClassName(nestedType.getDeclaringClass()) + "$" + Descriptor.toJvmName(type.getName().replace('.', '$')); 431 } else {
475 } else { 432 return Descriptor.toJvmName(type.getName());
476 return Descriptor.toJvmName(type.getName()); 433 }
477 } 434 }
478 } 435
479 436 private static String renameClassName(String name, ReplacerClassMap map) {
480 private static String renameClassName(String name, ReplacerClassMap map) { 437 String newName = map.get(Descriptor.toJvmName(name));
481 String newName = map.get(Descriptor.toJvmName(name)); 438 if (newName != null) {
482 if (newName != null) { 439 return Descriptor.toJavaName(newName);
483 return Descriptor.toJavaName(newName); 440 }
484 } 441 return null;
485 return null; 442 }
486 } 443
487 444 private static TypeArgument renameType(TypeArgument type, ReplacerClassMap map) {
488 private static TypeArgument renameType(TypeArgument type, ReplacerClassMap map) { 445 ObjectType subType = type.getType();
489 ObjectType subType = type.getType(); 446 if (subType != null) {
490 if (subType != null) { 447 ObjectType newSubType = renameType(subType, map);
491 ObjectType newSubType = renameType(subType, map); 448 if (newSubType != null) {
492 if (newSubType != null) { 449 switch (type.getKind()) {
493 switch (type.getKind()) { 450 case ' ':
494 case ' ': 451 return new TypeArgument(newSubType);
495 return new TypeArgument(newSubType); 452 case '+':
496 case '+': 453 return TypeArgument.subclassOf(newSubType);
497 return TypeArgument.subclassOf(newSubType); 454 case '-':
498 case '-': 455 return TypeArgument.superOf(newSubType);
499 return TypeArgument.superOf(newSubType); 456 default:
500 default: 457 throw new Error("Unknown type kind: " + type.getKind());
501 throw new Error("Unknown type kind: " + type.getKind()); 458 }
502 } 459 }
503 } 460 }
504 } 461 return null;
505 return null; 462 }
506 } 463
507 464 private static ArrayType renameType(ArrayType type, ReplacerClassMap map) {
508 private static ArrayType renameType(ArrayType type, ReplacerClassMap map) { 465 Type newSubType = renameType(type.getComponentType(), map);
509 Type newSubType = renameType(type.getComponentType(), map); 466 if (newSubType != null) {
510 if (newSubType != null) { 467 return new ArrayType(type.getDimension(), newSubType);
511 return new ArrayType(type.getDimension(), newSubType); 468 }
512 } 469 return null;
513 return null; 470 }
514 } 471
515 472 private static TypeParameter renameType(TypeParameter type, ReplacerClassMap map) {
516 private static TypeParameter renameType(TypeParameter type, ReplacerClassMap map) { 473
517 474 ObjectType superclassType = type.getClassBound();
518 ObjectType superclassType = type.getClassBound(); 475 if (superclassType != null) {
519 if (superclassType != null) { 476 ObjectType newSuperclassType = renameType(superclassType, map);
520 ObjectType newSuperclassType = renameType(superclassType, map); 477 if (newSuperclassType != null) {
521 if (newSuperclassType != null) { 478 superclassType = newSuperclassType;
522 superclassType = newSuperclassType; 479 }
523 } 480 }
524 } 481
525 482 ObjectType[] interfaceTypes = type.getInterfaceBound();
526 ObjectType[] interfaceTypes = type.getInterfaceBound(); 483 if (interfaceTypes != null) {
527 if (interfaceTypes != null) { 484 interfaceTypes = Arrays.copyOf(interfaceTypes, interfaceTypes.length);
528 interfaceTypes = Arrays.copyOf(interfaceTypes, interfaceTypes.length); 485 for (int i = 0; i < interfaceTypes.length; i++) {
529 for (int i = 0; i < interfaceTypes.length; i++) { 486 ObjectType newInterfaceType = renameType(interfaceTypes[i], map);
530 ObjectType newInterfaceType = renameType(interfaceTypes[i], map); 487 if (newInterfaceType != null) {
531 if (newInterfaceType != null) { 488 interfaceTypes[i] = newInterfaceType;
532 interfaceTypes[i] = newInterfaceType; 489 }
533 } 490 }
534 } 491 }
535 } 492
536 493 return new TypeParameter(type.getName(), superclassType, interfaceTypes);
537 return new TypeParameter(type.getName(), superclassType, interfaceTypes); 494 }
538 } 495
496 private enum SignatureType {
497 Class {
498 @Override
499 public String rename(String signature, ReplacerClassMap map) {
500 return renameClassSignature(signature, map);
501 }
502 },
503 Field {
504 @Override
505 public String rename(String signature, ReplacerClassMap map) {
506 return renameFieldSignature(signature, map);
507 }
508 },
509 Method {
510 @Override
511 public String rename(String signature, ReplacerClassMap map) {
512 return renameMethodSignature(signature, map);
513 }
514 };
515
516 public abstract String rename(String signature, ReplacerClassMap map);
517 }
518
519 private static class ReplacerClassMap extends HashMap<String, String> {
520
521 private ClassNameReplacer replacer;
522
523 public ReplacerClassMap(ClassNameReplacer replacer) {
524 this.replacer = replacer;
525 }
526
527 @Override
528 public String get(Object obj) {
529 if (obj instanceof String) {
530 return get((String) obj);
531 }
532 return null;
533 }
534
535 public String get(String className) {
536 return replacer.replace(className);
537 }
538 }
539} 539}