1 package org.robolectric.internal.bytecode; 2 3 import static org.objectweb.asm.Type.ARRAY; 4 import static org.objectweb.asm.Type.OBJECT; 5 6 import java.util.HashMap; 7 import java.util.Map; 8 import org.objectweb.asm.Type; 9 10 class TypeMapper { 11 private final Map<String, String> classesToRemap; 12 TypeMapper(Map<String, String> classNameToClassNameMap)13 public TypeMapper(Map<String, String> classNameToClassNameMap) { 14 classesToRemap = convertToSlashes(classNameToClassNameMap); 15 } 16 convertToSlashes(Map<String, String> map)17 private static Map<String, String> convertToSlashes(Map<String, String> map) { 18 HashMap<String, String> newMap = new HashMap<>(); 19 for (Map.Entry<String, String> entry : map.entrySet()) { 20 String key = internalize(entry.getKey()); 21 String value = internalize(entry.getValue()); 22 newMap.put(key, value); 23 newMap.put("L" + key + ";", "L" + value + ";"); // also the param reference form 24 } 25 return newMap; 26 } 27 internalize(String className)28 private static String internalize(String className) { 29 return className.replace('.', '/'); 30 } 31 32 // remap android/Foo to android/Bar mappedTypeName(String internalName)33 String mappedTypeName(String internalName) { 34 String remappedInternalName = classesToRemap.get(internalName); 35 if (remappedInternalName != null) { 36 return remappedInternalName; 37 } else { 38 return internalName; 39 } 40 } 41 mappedType(Type type)42 Type mappedType(Type type) { 43 String internalName = type.getInternalName(); 44 String remappedInternalName = classesToRemap.get(internalName); 45 if (remappedInternalName != null) { 46 return Type.getObjectType(remappedInternalName); 47 } else { 48 return type; 49 } 50 } 51 remapParams(String desc)52 String remapParams(String desc) { 53 StringBuilder buf = new StringBuilder(); 54 buf.append("("); 55 for (Type type : Type.getArgumentTypes(desc)) { 56 buf.append(remapParamType(type)); 57 } 58 buf.append(")"); 59 buf.append(remapParamType(Type.getReturnType(desc))); 60 return buf.toString(); 61 } 62 63 // remap Landroid/Foo; to Landroid/Bar; remapParamType(String desc)64 String remapParamType(String desc) { 65 return remapParamType(Type.getType(desc)); 66 } 67 remapParamType(Type type)68 private String remapParamType(Type type) { 69 String remappedName; 70 String internalName; 71 72 switch (type.getSort()) { 73 case ARRAY: 74 internalName = type.getInternalName(); 75 int count = 0; 76 while (internalName.charAt(count) == '[') count++; 77 78 remappedName = remapParamType(internalName.substring(count)); 79 if (remappedName != null) { 80 return Type.getObjectType(internalName.substring(0, count) + remappedName).getDescriptor(); 81 } 82 break; 83 84 case OBJECT: 85 type = mappedType(type); 86 break; 87 88 default: 89 break; 90 } 91 return type.getDescriptor(); 92 } 93 } 94