1b5d56e95f27d484ad3098ac18867262e7c8826c1Christian Williams & Phil Goodwinpackage com.xtremelabs.robolectric.bytecode; 26eedf728138e6f79fa898ff3e31bf61c9b1151dChristian Williams & Tyler Schulz 3c1d4b5222a200d82b1ec9ea56dd0270687ee0920Phil Goodwin & Christian Williamsimport android.net.Uri; 46d7cabef7bfbd7f56c3bb2dca3066430b2116985Christian Williamsimport com.xtremelabs.robolectric.internal.DoNotInstrument; 56d7cabef7bfbd7f56c3bb2dca3066430b2116985Christian Williamsimport com.xtremelabs.robolectric.internal.Instrument; 6f567a9e68c435fa0a98191c8ccda08add2f37566Rick Kawala & Ryan Richardimport javassist.*; 76eedf728138e6f79fa898ff3e31bf61c9b1151dChristian Williams & Tyler Schulz 8e7c2aaf28ca0949241e45085ae056c014c3bbe59Tyler Schultzimport java.io.IOException; 96eedf728138e6f79fa898ff3e31bf61c9b1151dChristian Williams & Tyler Schulzimport java.util.ArrayList; 106eedf728138e6f79fa898ff3e31bf61c9b1151dChristian Williams & Tyler Schulzimport java.util.List; 116eedf728138e6f79fa898ff3e31bf61c9b1151dChristian Williams & Tyler Schulz 12e876a8fad71b3098795fc08a08f794795123442bChristian Williams@SuppressWarnings({"UnusedDeclaration"}) 136eedf728138e6f79fa898ff3e31bf61c9b1151dChristian Williams & Tyler Schulzpublic class AndroidTranslator implements Translator { 1497fe1bbb3849dbaac8d7243b4c2bf42a99689f07Christian Williams /** 1597fe1bbb3849dbaac8d7243b4c2bf42a99689f07Christian Williams * IMPORTANT -- increment this number when the bytecode generated for modified classes changes 1697fe1bbb3849dbaac8d7243b4c2bf42a99689f07Christian Williams * so the cache file can be invalidated. 1797fe1bbb3849dbaac8d7243b4c2bf42a99689f07Christian Williams */ 188c52966dbfcf3dfa705f18716a2690c7354d9b84Jon Boekenoogen public static final int CACHE_VERSION = 21; 1997fe1bbb3849dbaac8d7243b4c2bf42a99689f07Christian Williams 20e876a8fad71b3098795fc08a08f794795123442bChristian Williams private static final List<ClassHandler> CLASS_HANDLERS = new ArrayList<ClassHandler>(); 21935342f72e39cbc067cd37c07765ff6dd897db81Christian Williams 226eedf728138e6f79fa898ff3e31bf61c9b1151dChristian Williams & Tyler Schulz private ClassHandler classHandler; 2330291fcbfe19f4959102bacdc65dddb9a3715b74Christian Williams & Phil Goodwin private ClassCache classCache; 2453c5a5a304aa516f8e088f7bfde25db04053239fJan Berkel private final List<String> instrumentingList = new ArrayList<String>(); 25b28424f3605c0d0eff653a1f3538a1ce56083b7bJan Berkel private final List<String> instrumentingExcludeList = new ArrayList<String>(); 266eedf728138e6f79fa898ff3e31bf61c9b1151dChristian Williams & Tyler Schulz 2730291fcbfe19f4959102bacdc65dddb9a3715b74Christian Williams & Phil Goodwin public AndroidTranslator(ClassHandler classHandler, ClassCache classCache) { 286eedf728138e6f79fa898ff3e31bf61c9b1151dChristian Williams & Tyler Schulz this.classHandler = classHandler; 2930291fcbfe19f4959102bacdc65dddb9a3715b74Christian Williams & Phil Goodwin this.classCache = classCache; 3053c5a5a304aa516f8e088f7bfde25db04053239fJan Berkel 31b28424f3605c0d0eff653a1f3538a1ce56083b7bJan Berkel // Initialize lists 32b9116a1018de7bd622d18742d589eca4b5a12983Kathy Lin instrumentingList.add("android."); 33b9116a1018de7bd622d18742d589eca4b5a12983Kathy Lin instrumentingList.add("com.google.android.maps"); 34b9116a1018de7bd622d18742d589eca4b5a12983Kathy Lin instrumentingList.add("org.apache.http.impl.client.DefaultRequestDirector"); 35b28424f3605c0d0eff653a1f3538a1ce56083b7bJan Berkel 36a737ba49c3a94d16cc2e4bf7e5335615892cb67fMichael Portuesi instrumentingExcludeList.add("android.support.v4.app.NotificationCompat"); 379f52aa80f4b088107eba7ab628f904290963cdcfTyler Schultz instrumentingExcludeList.add("android.support.v4.content.LocalBroadcastManager"); 388c52966dbfcf3dfa705f18716a2690c7354d9b84Jon Boekenoogen instrumentingExcludeList.add("android.support.v4.util.LruCache"); 396eedf728138e6f79fa898ff3e31bf61c9b1151dChristian Williams & Tyler Schulz } 4053c5a5a304aa516f8e088f7bfde25db04053239fJan Berkel 41f567a9e68c435fa0a98191c8ccda08add2f37566Rick Kawala & Ryan Richard public AndroidTranslator(ClassHandler classHandler, ClassCache classCache, List<String> customShadowClassNames) { 4253c5a5a304aa516f8e088f7bfde25db04053239fJan Berkel this(classHandler, classCache); 4353c5a5a304aa516f8e088f7bfde25db04053239fJan Berkel if (customShadowClassNames != null && !customShadowClassNames.isEmpty()) { 4453c5a5a304aa516f8e088f7bfde25db04053239fJan Berkel instrumentingList.addAll(customShadowClassNames); 4553c5a5a304aa516f8e088f7bfde25db04053239fJan Berkel } 46b9116a1018de7bd622d18742d589eca4b5a12983Kathy Lin } 47f567a9e68c435fa0a98191c8ccda08add2f37566Rick Kawala & Ryan Richard 48f567a9e68c435fa0a98191c8ccda08add2f37566Rick Kawala & Ryan Richard public void addCustomShadowClass(String customShadowClassName) { 49f567a9e68c435fa0a98191c8ccda08add2f37566Rick Kawala & Ryan Richard if (!instrumentingList.contains(customShadowClassName)) { 50f567a9e68c435fa0a98191c8ccda08add2f37566Rick Kawala & Ryan Richard instrumentingList.add(customShadowClassName); 51f567a9e68c435fa0a98191c8ccda08add2f37566Rick Kawala & Ryan Richard } 52f567a9e68c435fa0a98191c8ccda08add2f37566Rick Kawala & Ryan Richard } 53f567a9e68c435fa0a98191c8ccda08add2f37566Rick Kawala & Ryan Richard 54e876a8fad71b3098795fc08a08f794795123442bChristian Williams public static ClassHandler getClassHandler(int index) { 55e876a8fad71b3098795fc08a08f794795123442bChristian Williams return CLASS_HANDLERS.get(index); 56e876a8fad71b3098795fc08a08f794795123442bChristian Williams } 57e876a8fad71b3098795fc08a08f794795123442bChristian Williams 5897fe1bbb3849dbaac8d7243b4c2bf42a99689f07Christian Williams @Override 596eedf728138e6f79fa898ff3e31bf61c9b1151dChristian Williams & Tyler Schulz public void start(ClassPool classPool) throws NotFoundException, CannotCompileException { 609122a05312e767618ba0545a951df9cab86c8716Christian Williams injectClassHandlerToInstrumentedClasses(classPool); 619122a05312e767618ba0545a951df9cab86c8716Christian Williams } 629122a05312e767618ba0545a951df9cab86c8716Christian Williams 639122a05312e767618ba0545a951df9cab86c8716Christian Williams private void injectClassHandlerToInstrumentedClasses(ClassPool classPool) throws NotFoundException, CannotCompileException { 64e876a8fad71b3098795fc08a08f794795123442bChristian Williams int index; 65e876a8fad71b3098795fc08a08f794795123442bChristian Williams synchronized (CLASS_HANDLERS) { 66e876a8fad71b3098795fc08a08f794795123442bChristian Williams CLASS_HANDLERS.add(classHandler); 67e876a8fad71b3098795fc08a08f794795123442bChristian Williams index = CLASS_HANDLERS.size() - 1; 68e876a8fad71b3098795fc08a08f794795123442bChristian Williams } 69e876a8fad71b3098795fc08a08f794795123442bChristian Williams 70e876a8fad71b3098795fc08a08f794795123442bChristian Williams CtClass robolectricInternalsCtClass = classPool.get(RobolectricInternals.class.getName()); 719122a05312e767618ba0545a951df9cab86c8716Christian Williams robolectricInternalsCtClass.setModifiers(Modifier.PUBLIC); 729122a05312e767618ba0545a951df9cab86c8716Christian Williams 739122a05312e767618ba0545a951df9cab86c8716Christian Williams robolectricInternalsCtClass.getClassInitializer().insertBefore("{\n" + 74e876a8fad71b3098795fc08a08f794795123442bChristian Williams "classHandler = " + AndroidTranslator.class.getName() + ".getClassHandler(" + index + ");\n" + 75e876a8fad71b3098795fc08a08f794795123442bChristian Williams "}"); 766eedf728138e6f79fa898ff3e31bf61c9b1151dChristian Williams & Tyler Schulz } 776eedf728138e6f79fa898ff3e31bf61c9b1151dChristian Williams & Tyler Schulz 7897fe1bbb3849dbaac8d7243b4c2bf42a99689f07Christian Williams @Override 796eedf728138e6f79fa898ff3e31bf61c9b1151dChristian Williams & Tyler Schulz public void onLoad(ClassPool classPool, String className) throws NotFoundException, CannotCompileException { 8030291fcbfe19f4959102bacdc65dddb9a3715b74Christian Williams & Phil Goodwin if (classCache.isWriting()) { 81a329318a8b2661107af6f9b25ffecf892b3c2c72Christian Williams & Ryan Richard throw new IllegalStateException("shouldn't be modifying bytecode after we've started writing cache! class=" + className); 82a329318a8b2661107af6f9b25ffecf892b3c2c72Christian Williams & Ryan Richard } 833fbe415c50867fd95a2d7c7b1e0b7a08871290b8Christian Williams & Phil Goodwin 84c1d4b5222a200d82b1ec9ea56dd0270687ee0920Phil Goodwin & Christian Williams if (classHasFromAndroidEquivalent(className)) { 85c1d4b5222a200d82b1ec9ea56dd0270687ee0920Phil Goodwin & Christian Williams replaceClassWithFromAndroidEquivalent(classPool, className); 86c1d4b5222a200d82b1ec9ea56dd0270687ee0920Phil Goodwin & Christian Williams return; 87c1d4b5222a200d82b1ec9ea56dd0270687ee0920Phil Goodwin & Christian Williams } 88c1d4b5222a200d82b1ec9ea56dd0270687ee0920Phil Goodwin & Christian Williams 893ac42c39c9f4627c52809c9bf6701df7cd651a02Christian Williams & Phil Goodwin CtClass ctClass; 903ac42c39c9f4627c52809c9bf6701df7cd651a02Christian Williams & Phil Goodwin try { 913ac42c39c9f4627c52809c9bf6701df7cd651a02Christian Williams & Phil Goodwin ctClass = classPool.get(className); 923ac42c39c9f4627c52809c9bf6701df7cd651a02Christian Williams & Phil Goodwin } catch (NotFoundException e) { 93120394e8340f49225bda91512b73e0774f01f3b5Phil Goodwin throw new IgnorableClassNotFoundException(e); 943ac42c39c9f4627c52809c9bf6701df7cd651a02Christian Williams & Phil Goodwin } 9553c5a5a304aa516f8e088f7bfde25db04053239fJan Berkel 9653c5a5a304aa516f8e088f7bfde25db04053239fJan Berkel if (shouldInstrument(ctClass)) { 976eedf728138e6f79fa898ff3e31bf61c9b1151dChristian Williams & Tyler Schulz int modifiers = ctClass.getModifiers(); 986eedf728138e6f79fa898ff3e31bf61c9b1151dChristian Williams & Tyler Schulz if (Modifier.isFinal(modifiers)) { 996eedf728138e6f79fa898ff3e31bf61c9b1151dChristian Williams & Tyler Schulz ctClass.setModifiers(modifiers & ~Modifier.FINAL); 1006eedf728138e6f79fa898ff3e31bf61c9b1151dChristian Williams & Tyler Schulz } 1016eedf728138e6f79fa898ff3e31bf61c9b1151dChristian Williams & Tyler Schulz 1026eedf728138e6f79fa898ff3e31bf61c9b1151dChristian Williams & Tyler Schulz classHandler.instrument(ctClass); 1035586ee2425e7c33e2a123ca5b563f092f66374a6Christian Williams 1046eedf728138e6f79fa898ff3e31bf61c9b1151dChristian Williams & Tyler Schulz fixConstructors(ctClass); 1056eedf728138e6f79fa898ff3e31bf61c9b1151dChristian Williams & Tyler Schulz fixMethods(ctClass); 106e7c2aaf28ca0949241e45085ae056c014c3bbe59Tyler Schultz 107e7c2aaf28ca0949241e45085ae056c014c3bbe59Tyler Schultz try { 10830291fcbfe19f4959102bacdc65dddb9a3715b74Christian Williams & Phil Goodwin classCache.addClass(className, ctClass.toBytecode()); 109e7c2aaf28ca0949241e45085ae056c014c3bbe59Tyler Schultz } catch (IOException e) { 110e7c2aaf28ca0949241e45085ae056c014c3bbe59Tyler Schultz throw new RuntimeException(e); 111e7c2aaf28ca0949241e45085ae056c014c3bbe59Tyler Schultz } 1126eedf728138e6f79fa898ff3e31bf61c9b1151dChristian Williams & Tyler Schulz } 1136eedf728138e6f79fa898ff3e31bf61c9b1151dChristian Williams & Tyler Schulz } 1146eedf728138e6f79fa898ff3e31bf61c9b1151dChristian Williams & Tyler Schulz 11553c5a5a304aa516f8e088f7bfde25db04053239fJan Berkel /* package */ boolean shouldInstrument(CtClass ctClass) { 11653c5a5a304aa516f8e088f7bfde25db04053239fJan Berkel if (ctClass.hasAnnotation(Instrument.class)) { 11753c5a5a304aa516f8e088f7bfde25db04053239fJan Berkel return true; 118b28424f3605c0d0eff653a1f3538a1ce56083b7bJan Berkel } else if (ctClass.isInterface() || ctClass.hasAnnotation(DoNotInstrument.class)) { 11953c5a5a304aa516f8e088f7bfde25db04053239fJan Berkel return false; 12053c5a5a304aa516f8e088f7bfde25db04053239fJan Berkel } else { 121b28424f3605c0d0eff653a1f3538a1ce56083b7bJan Berkel for (String klassName : instrumentingExcludeList) { 122b28424f3605c0d0eff653a1f3538a1ce56083b7bJan Berkel if (ctClass.getName().startsWith(klassName)) { 123b28424f3605c0d0eff653a1f3538a1ce56083b7bJan Berkel return false; 124b28424f3605c0d0eff653a1f3538a1ce56083b7bJan Berkel } 125b28424f3605c0d0eff653a1f3538a1ce56083b7bJan Berkel } 12653c5a5a304aa516f8e088f7bfde25db04053239fJan Berkel for (String klassName : instrumentingList) { 12753c5a5a304aa516f8e088f7bfde25db04053239fJan Berkel if (ctClass.getName().startsWith(klassName)) { 12853c5a5a304aa516f8e088f7bfde25db04053239fJan Berkel return true; 12953c5a5a304aa516f8e088f7bfde25db04053239fJan Berkel } 13053c5a5a304aa516f8e088f7bfde25db04053239fJan Berkel } 13153c5a5a304aa516f8e088f7bfde25db04053239fJan Berkel return false; 13253c5a5a304aa516f8e088f7bfde25db04053239fJan Berkel } 13353c5a5a304aa516f8e088f7bfde25db04053239fJan Berkel } 13453c5a5a304aa516f8e088f7bfde25db04053239fJan Berkel 135c1d4b5222a200d82b1ec9ea56dd0270687ee0920Phil Goodwin & Christian Williams private boolean classHasFromAndroidEquivalent(String className) { 136c1d4b5222a200d82b1ec9ea56dd0270687ee0920Phil Goodwin & Christian Williams return className.startsWith(Uri.class.getName()); 137c1d4b5222a200d82b1ec9ea56dd0270687ee0920Phil Goodwin & Christian Williams } 138c1d4b5222a200d82b1ec9ea56dd0270687ee0920Phil Goodwin & Christian Williams 139c1d4b5222a200d82b1ec9ea56dd0270687ee0920Phil Goodwin & Christian Williams private void replaceClassWithFromAndroidEquivalent(ClassPool classPool, String className) throws NotFoundException { 140c1d4b5222a200d82b1ec9ea56dd0270687ee0920Phil Goodwin & Christian Williams FromAndroidClassNameParts classNameParts = new FromAndroidClassNameParts(className); 141c1d4b5222a200d82b1ec9ea56dd0270687ee0920Phil Goodwin & Christian Williams if (classNameParts.isFromAndroid()) return; 142c1d4b5222a200d82b1ec9ea56dd0270687ee0920Phil Goodwin & Christian Williams 143c1d4b5222a200d82b1ec9ea56dd0270687ee0920Phil Goodwin & Christian Williams String from = classNameParts.getNameWithFromAndroid(); 144c1d4b5222a200d82b1ec9ea56dd0270687ee0920Phil Goodwin & Christian Williams CtClass ctClass = classPool.getAndRename(from, className); 145c1d4b5222a200d82b1ec9ea56dd0270687ee0920Phil Goodwin & Christian Williams 146c1d4b5222a200d82b1ec9ea56dd0270687ee0920Phil Goodwin & Christian Williams ClassMap map = new ClassMap() { 147c1d4b5222a200d82b1ec9ea56dd0270687ee0920Phil Goodwin & Christian Williams @Override 148c1d4b5222a200d82b1ec9ea56dd0270687ee0920Phil Goodwin & Christian Williams public Object get(Object jvmClassName) { 149c1d4b5222a200d82b1ec9ea56dd0270687ee0920Phil Goodwin & Christian Williams FromAndroidClassNameParts classNameParts = new FromAndroidClassNameParts(jvmClassName.toString()); 150c1d4b5222a200d82b1ec9ea56dd0270687ee0920Phil Goodwin & Christian Williams if (classNameParts.isFromAndroid()) { 151c1d4b5222a200d82b1ec9ea56dd0270687ee0920Phil Goodwin & Christian Williams return classNameParts.getNameWithoutFromAndroid(); 152c1d4b5222a200d82b1ec9ea56dd0270687ee0920Phil Goodwin & Christian Williams } else { 153c1d4b5222a200d82b1ec9ea56dd0270687ee0920Phil Goodwin & Christian Williams return jvmClassName; 154c1d4b5222a200d82b1ec9ea56dd0270687ee0920Phil Goodwin & Christian Williams } 155c1d4b5222a200d82b1ec9ea56dd0270687ee0920Phil Goodwin & Christian Williams } 156c1d4b5222a200d82b1ec9ea56dd0270687ee0920Phil Goodwin & Christian Williams }; 157c1d4b5222a200d82b1ec9ea56dd0270687ee0920Phil Goodwin & Christian Williams ctClass.replaceClassName(map); 158c1d4b5222a200d82b1ec9ea56dd0270687ee0920Phil Goodwin & Christian Williams } 159c1d4b5222a200d82b1ec9ea56dd0270687ee0920Phil Goodwin & Christian Williams 160c1d4b5222a200d82b1ec9ea56dd0270687ee0920Phil Goodwin & Christian Williams class FromAndroidClassNameParts { 161c1d4b5222a200d82b1ec9ea56dd0270687ee0920Phil Goodwin & Christian Williams private static final String TOKEN = "__FromAndroid"; 162c1d4b5222a200d82b1ec9ea56dd0270687ee0920Phil Goodwin & Christian Williams 163c1d4b5222a200d82b1ec9ea56dd0270687ee0920Phil Goodwin & Christian Williams private String prefix; 164c1d4b5222a200d82b1ec9ea56dd0270687ee0920Phil Goodwin & Christian Williams private String suffix; 165c1d4b5222a200d82b1ec9ea56dd0270687ee0920Phil Goodwin & Christian Williams 166c1d4b5222a200d82b1ec9ea56dd0270687ee0920Phil Goodwin & Christian Williams FromAndroidClassNameParts(String name) { 167c1d4b5222a200d82b1ec9ea56dd0270687ee0920Phil Goodwin & Christian Williams int dollarIndex = name.indexOf("$"); 168c1d4b5222a200d82b1ec9ea56dd0270687ee0920Phil Goodwin & Christian Williams prefix = name; 169c1d4b5222a200d82b1ec9ea56dd0270687ee0920Phil Goodwin & Christian Williams suffix = ""; 170c1d4b5222a200d82b1ec9ea56dd0270687ee0920Phil Goodwin & Christian Williams if (dollarIndex > -1) { 171c1d4b5222a200d82b1ec9ea56dd0270687ee0920Phil Goodwin & Christian Williams prefix = name.substring(0, dollarIndex); 172c1d4b5222a200d82b1ec9ea56dd0270687ee0920Phil Goodwin & Christian Williams suffix = name.substring(dollarIndex); 173c1d4b5222a200d82b1ec9ea56dd0270687ee0920Phil Goodwin & Christian Williams } 174c1d4b5222a200d82b1ec9ea56dd0270687ee0920Phil Goodwin & Christian Williams } 175c1d4b5222a200d82b1ec9ea56dd0270687ee0920Phil Goodwin & Christian Williams 176c1d4b5222a200d82b1ec9ea56dd0270687ee0920Phil Goodwin & Christian Williams public boolean isFromAndroid() { 177c1d4b5222a200d82b1ec9ea56dd0270687ee0920Phil Goodwin & Christian Williams return prefix.endsWith(TOKEN); 178c1d4b5222a200d82b1ec9ea56dd0270687ee0920Phil Goodwin & Christian Williams } 179c1d4b5222a200d82b1ec9ea56dd0270687ee0920Phil Goodwin & Christian Williams 180c1d4b5222a200d82b1ec9ea56dd0270687ee0920Phil Goodwin & Christian Williams public String getNameWithFromAndroid() { 181c1d4b5222a200d82b1ec9ea56dd0270687ee0920Phil Goodwin & Christian Williams return prefix + TOKEN + suffix; 182c1d4b5222a200d82b1ec9ea56dd0270687ee0920Phil Goodwin & Christian Williams } 183c1d4b5222a200d82b1ec9ea56dd0270687ee0920Phil Goodwin & Christian Williams 184c1d4b5222a200d82b1ec9ea56dd0270687ee0920Phil Goodwin & Christian Williams public String getNameWithoutFromAndroid() { 185c1d4b5222a200d82b1ec9ea56dd0270687ee0920Phil Goodwin & Christian Williams return prefix.replace(TOKEN, "") + suffix; 186c1d4b5222a200d82b1ec9ea56dd0270687ee0920Phil Goodwin & Christian Williams } 187c1d4b5222a200d82b1ec9ea56dd0270687ee0920Phil Goodwin & Christian Williams } 188c1d4b5222a200d82b1ec9ea56dd0270687ee0920Phil Goodwin & Christian Williams 1895586ee2425e7c33e2a123ca5b563f092f66374a6Christian Williams private void addBypassShadowField(CtClass ctClass, String fieldName) { 1905586ee2425e7c33e2a123ca5b563f092f66374a6Christian Williams try { 1915586ee2425e7c33e2a123ca5b563f092f66374a6Christian Williams try { 1925586ee2425e7c33e2a123ca5b563f092f66374a6Christian Williams ctClass.getField(fieldName); 1935586ee2425e7c33e2a123ca5b563f092f66374a6Christian Williams } catch (NotFoundException e) { 1945586ee2425e7c33e2a123ca5b563f092f66374a6Christian Williams CtField field = new CtField(CtClass.booleanType, fieldName, ctClass); 1955586ee2425e7c33e2a123ca5b563f092f66374a6Christian Williams field.setModifiers(java.lang.reflect.Modifier.PUBLIC | java.lang.reflect.Modifier.STATIC); 1965586ee2425e7c33e2a123ca5b563f092f66374a6Christian Williams ctClass.addField(field); 1975586ee2425e7c33e2a123ca5b563f092f66374a6Christian Williams } 1985586ee2425e7c33e2a123ca5b563f092f66374a6Christian Williams } catch (CannotCompileException e) { 1995586ee2425e7c33e2a123ca5b563f092f66374a6Christian Williams throw new RuntimeException(e); 2005586ee2425e7c33e2a123ca5b563f092f66374a6Christian Williams } 2015586ee2425e7c33e2a123ca5b563f092f66374a6Christian Williams } 2025586ee2425e7c33e2a123ca5b563f092f66374a6Christian Williams 2036eedf728138e6f79fa898ff3e31bf61c9b1151dChristian Williams & Tyler Schulz private void fixConstructors(CtClass ctClass) throws CannotCompileException, NotFoundException { 204f567a9e68c435fa0a98191c8ccda08add2f37566Rick Kawala & Ryan Richard 205f567a9e68c435fa0a98191c8ccda08add2f37566Rick Kawala & Ryan Richard if (ctClass.isEnum()) { 206f567a9e68c435fa0a98191c8ccda08add2f37566Rick Kawala & Ryan Richard // skip enum constructors because they are not stubs in android.jar 207f567a9e68c435fa0a98191c8ccda08add2f37566Rick Kawala & Ryan Richard return; 208f567a9e68c435fa0a98191c8ccda08add2f37566Rick Kawala & Ryan Richard } 209f567a9e68c435fa0a98191c8ccda08add2f37566Rick Kawala & Ryan Richard 210935342f72e39cbc067cd37c07765ff6dd897db81Christian Williams boolean hasDefault = false; 2116eedf728138e6f79fa898ff3e31bf61c9b1151dChristian Williams & Tyler Schulz 212f567a9e68c435fa0a98191c8ccda08add2f37566Rick Kawala & Ryan Richard for (CtConstructor ctConstructor : ctClass.getDeclaredConstructors()) { 2131bd18692c4958c09a8daa416137a64ef0bb3d96fChristian Williams try { 214935342f72e39cbc067cd37c07765ff6dd897db81Christian Williams fixConstructor(ctClass, hasDefault, ctConstructor); 215935342f72e39cbc067cd37c07765ff6dd897db81Christian Williams 216935342f72e39cbc067cd37c07765ff6dd897db81Christian Williams if (ctConstructor.getParameterTypes().length == 0) { 217935342f72e39cbc067cd37c07765ff6dd897db81Christian Williams hasDefault = true; 218935342f72e39cbc067cd37c07765ff6dd897db81Christian Williams } 2191bd18692c4958c09a8daa416137a64ef0bb3d96fChristian Williams } catch (Exception e) { 2201bd18692c4958c09a8daa416137a64ef0bb3d96fChristian Williams throw new RuntimeException("problem instrumenting " + ctConstructor, e); 2216eedf728138e6f79fa898ff3e31bf61c9b1151dChristian Williams & Tyler Schulz } 2226eedf728138e6f79fa898ff3e31bf61c9b1151dChristian Williams & Tyler Schulz } 2236eedf728138e6f79fa898ff3e31bf61c9b1151dChristian Williams & Tyler Schulz 224935342f72e39cbc067cd37c07765ff6dd897db81Christian Williams if (!hasDefault) { 2250f8821aeb8597334bbe65b809f6dba2dae912a82Christian Williams & Tyler Schultz String methodBody = generateConstructorBody(ctClass, new CtClass[0]); 2265586ee2425e7c33e2a123ca5b563f092f66374a6Christian Williams ctClass.addConstructor(CtNewConstructor.make(new CtClass[0], new CtClass[0], "{\n" + methodBody + "}\n", ctClass)); 2276eedf728138e6f79fa898ff3e31bf61c9b1151dChristian Williams & Tyler Schulz } 2286eedf728138e6f79fa898ff3e31bf61c9b1151dChristian Williams & Tyler Schulz } 2296eedf728138e6f79fa898ff3e31bf61c9b1151dChristian Williams & Tyler Schulz 2301bd18692c4958c09a8daa416137a64ef0bb3d96fChristian Williams private boolean fixConstructor(CtClass ctClass, boolean needsDefault, CtConstructor ctConstructor) throws NotFoundException, CannotCompileException { 2311bd18692c4958c09a8daa416137a64ef0bb3d96fChristian Williams String methodBody = generateConstructorBody(ctClass, ctConstructor.getParameterTypes()); 2325586ee2425e7c33e2a123ca5b563f092f66374a6Christian Williams ctConstructor.setBody("{\n" + methodBody + "}\n"); 2331bd18692c4958c09a8daa416137a64ef0bb3d96fChristian Williams return needsDefault; 2341bd18692c4958c09a8daa416137a64ef0bb3d96fChristian Williams } 2351bd18692c4958c09a8daa416137a64ef0bb3d96fChristian Williams 2360f8821aeb8597334bbe65b809f6dba2dae912a82Christian Williams & Tyler Schultz private String generateConstructorBody(CtClass ctClass, CtClass[] parameterTypes) throws NotFoundException { 2370f8821aeb8597334bbe65b809f6dba2dae912a82Christian Williams & Tyler Schultz return generateMethodBody(ctClass, 2380f8821aeb8597334bbe65b809f6dba2dae912a82Christian Williams & Tyler Schultz new CtMethod(CtClass.voidType, "<init>", parameterTypes, ctClass), 2390f8821aeb8597334bbe65b809f6dba2dae912a82Christian Williams & Tyler Schultz CtClass.voidType, 2400f8821aeb8597334bbe65b809f6dba2dae912a82Christian Williams & Tyler Schultz Type.VOID, 241537f38b99433fee0ee08d7c634763e7381942f58Phil Goodwin false, 2420f8821aeb8597334bbe65b809f6dba2dae912a82Christian Williams & Tyler Schultz false); 2430f8821aeb8597334bbe65b809f6dba2dae912a82Christian Williams & Tyler Schultz } 2440f8821aeb8597334bbe65b809f6dba2dae912a82Christian Williams & Tyler Schultz 2456eedf728138e6f79fa898ff3e31bf61c9b1151dChristian Williams & Tyler Schulz private void fixMethods(CtClass ctClass) throws NotFoundException, CannotCompileException { 2466eedf728138e6f79fa898ff3e31bf61c9b1151dChristian Williams & Tyler Schulz for (CtMethod ctMethod : ctClass.getDeclaredMethods()) { 247537f38b99433fee0ee08d7c634763e7381942f58Phil Goodwin fixMethod(ctClass, ctMethod, true); 2481bd18692c4958c09a8daa416137a64ef0bb3d96fChristian Williams } 2493fbe415c50867fd95a2d7c7b1e0b7a08871290b8Christian Williams & Phil Goodwin CtMethod equalsMethod = ctClass.getMethod("equals", "(Ljava/lang/Object;)Z"); 2503fbe415c50867fd95a2d7c7b1e0b7a08871290b8Christian Williams & Phil Goodwin CtMethod hashCodeMethod = ctClass.getMethod("hashCode", "()I"); 2513fbe415c50867fd95a2d7c7b1e0b7a08871290b8Christian Williams & Phil Goodwin CtMethod toStringMethod = ctClass.getMethod("toString", "()Ljava/lang/String;"); 2523fbe415c50867fd95a2d7c7b1e0b7a08871290b8Christian Williams & Phil Goodwin 253537f38b99433fee0ee08d7c634763e7381942f58Phil Goodwin fixMethod(ctClass, equalsMethod, false); 254537f38b99433fee0ee08d7c634763e7381942f58Phil Goodwin fixMethod(ctClass, hashCodeMethod, false); 255537f38b99433fee0ee08d7c634763e7381942f58Phil Goodwin fixMethod(ctClass, toStringMethod, false); 2561bd18692c4958c09a8daa416137a64ef0bb3d96fChristian Williams } 2571bd18692c4958c09a8daa416137a64ef0bb3d96fChristian Williams 2585586ee2425e7c33e2a123ca5b563f092f66374a6Christian Williams private String describe(CtMethod ctMethod) throws NotFoundException { 2595586ee2425e7c33e2a123ca5b563f092f66374a6Christian Williams return Modifier.toString(ctMethod.getModifiers()) + " " + ctMethod.getReturnType().getSimpleName() + " " + ctMethod.getLongName(); 2605586ee2425e7c33e2a123ca5b563f092f66374a6Christian Williams } 2615586ee2425e7c33e2a123ca5b563f092f66374a6Christian Williams 262537f38b99433fee0ee08d7c634763e7381942f58Phil Goodwin private void fixMethod(CtClass ctClass, CtMethod ctMethod, boolean wasFoundInClass) throws NotFoundException { 2633fbe415c50867fd95a2d7c7b1e0b7a08871290b8Christian Williams & Phil Goodwin String describeBefore = describe(ctMethod); 2643fbe415c50867fd95a2d7c7b1e0b7a08871290b8Christian Williams & Phil Goodwin try { 2653fbe415c50867fd95a2d7c7b1e0b7a08871290b8Christian Williams & Phil Goodwin CtClass declaringClass = ctMethod.getDeclaringClass(); 2663fbe415c50867fd95a2d7c7b1e0b7a08871290b8Christian Williams & Phil Goodwin int originalModifiers = ctMethod.getModifiers(); 2675586ee2425e7c33e2a123ca5b563f092f66374a6Christian Williams 2683fbe415c50867fd95a2d7c7b1e0b7a08871290b8Christian Williams & Phil Goodwin boolean wasNative = Modifier.isNative(originalModifiers); 2693fbe415c50867fd95a2d7c7b1e0b7a08871290b8Christian Williams & Phil Goodwin boolean wasFinal = Modifier.isFinal(originalModifiers); 2703fbe415c50867fd95a2d7c7b1e0b7a08871290b8Christian Williams & Phil Goodwin boolean wasAbstract = Modifier.isAbstract(originalModifiers); 271537f38b99433fee0ee08d7c634763e7381942f58Phil Goodwin boolean wasDeclaredInClass = ctClass == declaringClass; 2725586ee2425e7c33e2a123ca5b563f092f66374a6Christian Williams 2733fbe415c50867fd95a2d7c7b1e0b7a08871290b8Christian Williams & Phil Goodwin if (wasFinal && ctClass.isEnum()) { 2743fbe415c50867fd95a2d7c7b1e0b7a08871290b8Christian Williams & Phil Goodwin return; 2753fbe415c50867fd95a2d7c7b1e0b7a08871290b8Christian Williams & Phil Goodwin } 2766eedf728138e6f79fa898ff3e31bf61c9b1151dChristian Williams & Tyler Schulz 2773fbe415c50867fd95a2d7c7b1e0b7a08871290b8Christian Williams & Phil Goodwin int newModifiers = originalModifiers; 2783fbe415c50867fd95a2d7c7b1e0b7a08871290b8Christian Williams & Phil Goodwin if (wasNative) { 2793fbe415c50867fd95a2d7c7b1e0b7a08871290b8Christian Williams & Phil Goodwin newModifiers = Modifier.clear(newModifiers, Modifier.NATIVE); 2803fbe415c50867fd95a2d7c7b1e0b7a08871290b8Christian Williams & Phil Goodwin } 2813fbe415c50867fd95a2d7c7b1e0b7a08871290b8Christian Williams & Phil Goodwin if (wasFinal) { 2823fbe415c50867fd95a2d7c7b1e0b7a08871290b8Christian Williams & Phil Goodwin newModifiers = Modifier.clear(newModifiers, Modifier.FINAL); 2833fbe415c50867fd95a2d7c7b1e0b7a08871290b8Christian Williams & Phil Goodwin } 284537f38b99433fee0ee08d7c634763e7381942f58Phil Goodwin if (wasFoundInClass) { 2853fbe415c50867fd95a2d7c7b1e0b7a08871290b8Christian Williams & Phil Goodwin ctMethod.setModifiers(newModifiers); 2863fbe415c50867fd95a2d7c7b1e0b7a08871290b8Christian Williams & Phil Goodwin } 2876eedf728138e6f79fa898ff3e31bf61c9b1151dChristian Williams & Tyler Schulz 2883fbe415c50867fd95a2d7c7b1e0b7a08871290b8Christian Williams & Phil Goodwin CtClass returnCtClass = ctMethod.getReturnType(); 2893fbe415c50867fd95a2d7c7b1e0b7a08871290b8Christian Williams & Phil Goodwin Type returnType = Type.find(returnCtClass); 2906eedf728138e6f79fa898ff3e31bf61c9b1151dChristian Williams & Tyler Schulz 2913fbe415c50867fd95a2d7c7b1e0b7a08871290b8Christian Williams & Phil Goodwin String methodName = ctMethod.getName(); 2923fbe415c50867fd95a2d7c7b1e0b7a08871290b8Christian Williams & Phil Goodwin CtClass[] paramTypes = ctMethod.getParameterTypes(); 2936eedf728138e6f79fa898ff3e31bf61c9b1151dChristian Williams & Tyler Schulz 2946eedf728138e6f79fa898ff3e31bf61c9b1151dChristian Williams & Tyler Schulz// if (!isAbstract) { 2956eedf728138e6f79fa898ff3e31bf61c9b1151dChristian Williams & Tyler Schulz// if (methodName.startsWith("set") && paramTypes.length == 1) { 2966eedf728138e6f79fa898ff3e31bf61c9b1151dChristian Williams & Tyler Schulz// String fieldName = "__" + methodName.substring(3); 2976eedf728138e6f79fa898ff3e31bf61c9b1151dChristian Williams & Tyler Schulz// if (declareField(ctClass, fieldName, paramTypes[0])) { 2986eedf728138e6f79fa898ff3e31bf61c9b1151dChristian Williams & Tyler Schulz// methodBody = fieldName + " = $1;\n" + methodBody; 2996eedf728138e6f79fa898ff3e31bf61c9b1151dChristian Williams & Tyler Schulz// } 3006eedf728138e6f79fa898ff3e31bf61c9b1151dChristian Williams & Tyler Schulz// } else if (methodName.startsWith("get") && paramTypes.length == 0) { 3016eedf728138e6f79fa898ff3e31bf61c9b1151dChristian Williams & Tyler Schulz// String fieldName = "__" + methodName.substring(3); 3026eedf728138e6f79fa898ff3e31bf61c9b1151dChristian Williams & Tyler Schulz// if (declareField(ctClass, fieldName, returnType)) { 3036eedf728138e6f79fa898ff3e31bf61c9b1151dChristian Williams & Tyler Schulz// methodBody = "return " + fieldName + ";\n"; 3046eedf728138e6f79fa898ff3e31bf61c9b1151dChristian Williams & Tyler Schulz// } 3056eedf728138e6f79fa898ff3e31bf61c9b1151dChristian Williams & Tyler Schulz// } 3066eedf728138e6f79fa898ff3e31bf61c9b1151dChristian Williams & Tyler Schulz// } 3076eedf728138e6f79fa898ff3e31bf61c9b1151dChristian Williams & Tyler Schulz 3083fbe415c50867fd95a2d7c7b1e0b7a08871290b8Christian Williams & Phil Goodwin boolean isStatic = Modifier.isStatic(originalModifiers); 309537f38b99433fee0ee08d7c634763e7381942f58Phil Goodwin String methodBody = generateMethodBody(ctClass, ctMethod, wasNative, wasAbstract, returnCtClass, returnType, isStatic, !wasFoundInClass); 3103fbe415c50867fd95a2d7c7b1e0b7a08871290b8Christian Williams & Phil Goodwin 311537f38b99433fee0ee08d7c634763e7381942f58Phil Goodwin if (!wasFoundInClass) { 3123fbe415c50867fd95a2d7c7b1e0b7a08871290b8Christian Williams & Phil Goodwin CtMethod newMethod = makeNewMethod(ctClass, ctMethod, returnCtClass, methodName, paramTypes, "{\n" + methodBody + generateCallToSuper(methodName, paramTypes) + "\n}"); 3133fbe415c50867fd95a2d7c7b1e0b7a08871290b8Christian Williams & Phil Goodwin newMethod.setModifiers(newModifiers); 314537f38b99433fee0ee08d7c634763e7381942f58Phil Goodwin if (wasDeclaredInClass) { 315537f38b99433fee0ee08d7c634763e7381942f58Phil Goodwin ctMethod.insertBefore("{\n" + methodBody + "}\n"); 316537f38b99433fee0ee08d7c634763e7381942f58Phil Goodwin } else { 317537f38b99433fee0ee08d7c634763e7381942f58Phil Goodwin ctClass.addMethod(newMethod); 318537f38b99433fee0ee08d7c634763e7381942f58Phil Goodwin } 3193fbe415c50867fd95a2d7c7b1e0b7a08871290b8Christian Williams & Phil Goodwin } else if (wasAbstract || wasNative) { 3203fbe415c50867fd95a2d7c7b1e0b7a08871290b8Christian Williams & Phil Goodwin CtMethod newMethod = makeNewMethod(ctClass, ctMethod, returnCtClass, methodName, paramTypes, "{\n" + methodBody + "\n}"); 3213fbe415c50867fd95a2d7c7b1e0b7a08871290b8Christian Williams & Phil Goodwin ctMethod.setBody(newMethod, null); 3223fbe415c50867fd95a2d7c7b1e0b7a08871290b8Christian Williams & Phil Goodwin } else { 3233fbe415c50867fd95a2d7c7b1e0b7a08871290b8Christian Williams & Phil Goodwin ctMethod.insertBefore("{\n" + methodBody + "}\n"); 3243fbe415c50867fd95a2d7c7b1e0b7a08871290b8Christian Williams & Phil Goodwin } 3253fbe415c50867fd95a2d7c7b1e0b7a08871290b8Christian Williams & Phil Goodwin } catch (Exception e) { 3263fbe415c50867fd95a2d7c7b1e0b7a08871290b8Christian Williams & Phil Goodwin throw new RuntimeException("problem instrumenting " + describeBefore, e); 3273fbe415c50867fd95a2d7c7b1e0b7a08871290b8Christian Williams & Phil Goodwin } 3283fbe415c50867fd95a2d7c7b1e0b7a08871290b8Christian Williams & Phil Goodwin } 3296eedf728138e6f79fa898ff3e31bf61c9b1151dChristian Williams & Tyler Schulz 3303fbe415c50867fd95a2d7c7b1e0b7a08871290b8Christian Williams & Phil Goodwin private CtMethod makeNewMethod(CtClass ctClass, CtMethod ctMethod, CtClass returnCtClass, String methodName, CtClass[] paramTypes, String methodBody) throws CannotCompileException, NotFoundException { 3313fbe415c50867fd95a2d7c7b1e0b7a08871290b8Christian Williams & Phil Goodwin return CtNewMethod.make( 3323fbe415c50867fd95a2d7c7b1e0b7a08871290b8Christian Williams & Phil Goodwin ctMethod.getModifiers(), 3333fbe415c50867fd95a2d7c7b1e0b7a08871290b8Christian Williams & Phil Goodwin returnCtClass, 3343fbe415c50867fd95a2d7c7b1e0b7a08871290b8Christian Williams & Phil Goodwin methodName, 3353fbe415c50867fd95a2d7c7b1e0b7a08871290b8Christian Williams & Phil Goodwin paramTypes, 3363fbe415c50867fd95a2d7c7b1e0b7a08871290b8Christian Williams & Phil Goodwin ctMethod.getExceptionTypes(), 3373fbe415c50867fd95a2d7c7b1e0b7a08871290b8Christian Williams & Phil Goodwin methodBody, 3383fbe415c50867fd95a2d7c7b1e0b7a08871290b8Christian Williams & Phil Goodwin ctClass); 3393fbe415c50867fd95a2d7c7b1e0b7a08871290b8Christian Williams & Phil Goodwin } 3401bd18692c4958c09a8daa416137a64ef0bb3d96fChristian Williams 3413fbe415c50867fd95a2d7c7b1e0b7a08871290b8Christian Williams & Phil Goodwin public String generateCallToSuper(String methodName, CtClass[] paramTypes) { 3423fbe415c50867fd95a2d7c7b1e0b7a08871290b8Christian Williams & Phil Goodwin return "return super." + methodName + "(" + makeParameterReplacementList(paramTypes.length) + ");"; 3433fbe415c50867fd95a2d7c7b1e0b7a08871290b8Christian Williams & Phil Goodwin } 3445586ee2425e7c33e2a123ca5b563f092f66374a6Christian Williams 3453fbe415c50867fd95a2d7c7b1e0b7a08871290b8Christian Williams & Phil Goodwin public String makeParameterReplacementList(int length) { 3463fbe415c50867fd95a2d7c7b1e0b7a08871290b8Christian Williams & Phil Goodwin if (length == 0) { 3473fbe415c50867fd95a2d7c7b1e0b7a08871290b8Christian Williams & Phil Goodwin return ""; 3485586ee2425e7c33e2a123ca5b563f092f66374a6Christian Williams } 3493fbe415c50867fd95a2d7c7b1e0b7a08871290b8Christian Williams & Phil Goodwin 3503fbe415c50867fd95a2d7c7b1e0b7a08871290b8Christian Williams & Phil Goodwin String parameterReplacementList = "$1"; 3513fbe415c50867fd95a2d7c7b1e0b7a08871290b8Christian Williams & Phil Goodwin for (int i = 2; i <= length; ++i) { 3523fbe415c50867fd95a2d7c7b1e0b7a08871290b8Christian Williams & Phil Goodwin parameterReplacementList += ", $" + i; 3535586ee2425e7c33e2a123ca5b563f092f66374a6Christian Williams } 3543fbe415c50867fd95a2d7c7b1e0b7a08871290b8Christian Williams & Phil Goodwin return parameterReplacementList; 3556eedf728138e6f79fa898ff3e31bf61c9b1151dChristian Williams & Tyler Schulz } 3566eedf728138e6f79fa898ff3e31bf61c9b1151dChristian Williams & Tyler Schulz 357537f38b99433fee0ee08d7c634763e7381942f58Phil Goodwin private String generateMethodBody(CtClass ctClass, CtMethod ctMethod, boolean wasNative, boolean wasAbstract, CtClass returnCtClass, Type returnType, boolean aStatic, boolean shouldGenerateCallToSuper) throws NotFoundException { 358935342f72e39cbc067cd37c07765ff6dd897db81Christian Williams String methodBody; 359935342f72e39cbc067cd37c07765ff6dd897db81Christian Williams if (wasAbstract) { 360935342f72e39cbc067cd37c07765ff6dd897db81Christian Williams methodBody = returnType.isVoid() ? "" : "return " + returnType.defaultReturnString() + ";"; 361935342f72e39cbc067cd37c07765ff6dd897db81Christian Williams } else { 362537f38b99433fee0ee08d7c634763e7381942f58Phil Goodwin methodBody = generateMethodBody(ctClass, ctMethod, returnCtClass, returnType, aStatic, shouldGenerateCallToSuper); 363935342f72e39cbc067cd37c07765ff6dd897db81Christian Williams } 364935342f72e39cbc067cd37c07765ff6dd897db81Christian Williams 365935342f72e39cbc067cd37c07765ff6dd897db81Christian Williams if (wasNative) { 366935342f72e39cbc067cd37c07765ff6dd897db81Christian Williams methodBody += returnType.isVoid() ? "" : "return " + returnType.defaultReturnString() + ";"; 367935342f72e39cbc067cd37c07765ff6dd897db81Christian Williams } 368935342f72e39cbc067cd37c07765ff6dd897db81Christian Williams return methodBody; 369935342f72e39cbc067cd37c07765ff6dd897db81Christian Williams } 370935342f72e39cbc067cd37c07765ff6dd897db81Christian Williams 371537f38b99433fee0ee08d7c634763e7381942f58Phil Goodwin public String generateMethodBody(CtClass ctClass, CtMethod ctMethod, CtClass returnCtClass, Type returnType, boolean isStatic, boolean shouldGenerateCallToSuper) throws NotFoundException { 372a3533036a35e366c47bad39ac9edc0b48498538aChristian Williams boolean returnsVoid = returnType.isVoid(); 3735586ee2425e7c33e2a123ca5b563f092f66374a6Christian Williams String className = ctClass.getName(); 374a3533036a35e366c47bad39ac9edc0b48498538aChristian Williams 3756eedf728138e6f79fa898ff3e31bf61c9b1151dChristian Williams & Tyler Schulz String methodBody; 3766eedf728138e6f79fa898ff3e31bf61c9b1151dChristian Williams & Tyler Schulz StringBuilder buf = new StringBuilder(); 3779122a05312e767618ba0545a951df9cab86c8716Christian Williams buf.append("if (!"); 3789122a05312e767618ba0545a951df9cab86c8716Christian Williams buf.append(RobolectricInternals.class.getName()); 3799122a05312e767618ba0545a951df9cab86c8716Christian Williams buf.append(".shouldCallDirectly("); 3809122a05312e767618ba0545a951df9cab86c8716Christian Williams buf.append(isStatic ? className + ".class" : "this"); 3819122a05312e767618ba0545a951df9cab86c8716Christian Williams buf.append(")) {\n"); 3825586ee2425e7c33e2a123ca5b563f092f66374a6Christian Williams 3836eedf728138e6f79fa898ff3e31bf61c9b1151dChristian Williams & Tyler Schulz if (!returnsVoid) { 3846eedf728138e6f79fa898ff3e31bf61c9b1151dChristian Williams & Tyler Schulz buf.append("Object x = "); 3856eedf728138e6f79fa898ff3e31bf61c9b1151dChristian Williams & Tyler Schulz } 386e876a8fad71b3098795fc08a08f794795123442bChristian Williams buf.append(RobolectricInternals.class.getName()); 387e876a8fad71b3098795fc08a08f794795123442bChristian Williams buf.append(".methodInvoked(\n "); 3885586ee2425e7c33e2a123ca5b563f092f66374a6Christian Williams buf.append(className); 38984a72c253aeabd5617951a4378ec06d91bd2bfa1Christian Williams & Tyler Schulz buf.append(".class, \""); 3906eedf728138e6f79fa898ff3e31bf61c9b1151dChristian Williams & Tyler Schulz buf.append(ctMethod.getName()); 3916eedf728138e6f79fa898ff3e31bf61c9b1151dChristian Williams & Tyler Schulz buf.append("\", "); 3929122a05312e767618ba0545a951df9cab86c8716Christian Williams if (!isStatic) { 3936eedf728138e6f79fa898ff3e31bf61c9b1151dChristian Williams & Tyler Schulz buf.append("this"); 3946eedf728138e6f79fa898ff3e31bf61c9b1151dChristian Williams & Tyler Schulz } else { 3956eedf728138e6f79fa898ff3e31bf61c9b1151dChristian Williams & Tyler Schulz buf.append("null"); 3966eedf728138e6f79fa898ff3e31bf61c9b1151dChristian Williams & Tyler Schulz } 3976eedf728138e6f79fa898ff3e31bf61c9b1151dChristian Williams & Tyler Schulz buf.append(", "); 3986eedf728138e6f79fa898ff3e31bf61c9b1151dChristian Williams & Tyler Schulz 3996eedf728138e6f79fa898ff3e31bf61c9b1151dChristian Williams & Tyler Schulz appendParamTypeArray(buf, ctMethod); 4006eedf728138e6f79fa898ff3e31bf61c9b1151dChristian Williams & Tyler Schulz buf.append(", "); 40184a72c253aeabd5617951a4378ec06d91bd2bfa1Christian Williams & Tyler Schulz appendParamArray(buf, ctMethod); 4026eedf728138e6f79fa898ff3e31bf61c9b1151dChristian Williams & Tyler Schulz 4036eedf728138e6f79fa898ff3e31bf61c9b1151dChristian Williams & Tyler Schulz buf.append(")"); 4046eedf728138e6f79fa898ff3e31bf61c9b1151dChristian Williams & Tyler Schulz buf.append(";\n"); 4056eedf728138e6f79fa898ff3e31bf61c9b1151dChristian Williams & Tyler Schulz 4066eedf728138e6f79fa898ff3e31bf61c9b1151dChristian Williams & Tyler Schulz if (!returnsVoid) { 4076eedf728138e6f79fa898ff3e31bf61c9b1151dChristian Williams & Tyler Schulz buf.append("if (x != null) return (("); 4086eedf728138e6f79fa898ff3e31bf61c9b1151dChristian Williams & Tyler Schulz buf.append(returnType.nonPrimitiveClassName(returnCtClass)); 4096eedf728138e6f79fa898ff3e31bf61c9b1151dChristian Williams & Tyler Schulz buf.append(") x)"); 4106eedf728138e6f79fa898ff3e31bf61c9b1151dChristian Williams & Tyler Schulz buf.append(returnType.unboxString()); 4116eedf728138e6f79fa898ff3e31bf61c9b1151dChristian Williams & Tyler Schulz buf.append(";\n"); 412537f38b99433fee0ee08d7c634763e7381942f58Phil Goodwin if (shouldGenerateCallToSuper) { 413cb22b0511708035ce3ecbfff577a74f2e39a76a9Christian Williams & Phil Goodwin buf.append(generateCallToSuper(ctMethod.getName(), ctMethod.getParameterTypes())); 414cb22b0511708035ce3ecbfff577a74f2e39a76a9Christian Williams & Phil Goodwin } else { 415cb22b0511708035ce3ecbfff577a74f2e39a76a9Christian Williams & Phil Goodwin buf.append("return "); 416cb22b0511708035ce3ecbfff577a74f2e39a76a9Christian Williams & Phil Goodwin buf.append(returnType.defaultReturnString()); 417537f38b99433fee0ee08d7c634763e7381942f58Phil Goodwin buf.append(";\n"); 418cb22b0511708035ce3ecbfff577a74f2e39a76a9Christian Williams & Phil Goodwin } 4195586ee2425e7c33e2a123ca5b563f092f66374a6Christian Williams } else { 4205586ee2425e7c33e2a123ca5b563f092f66374a6Christian Williams buf.append("return;\n"); 4216eedf728138e6f79fa898ff3e31bf61c9b1151dChristian Williams & Tyler Schulz } 4226eedf728138e6f79fa898ff3e31bf61c9b1151dChristian Williams & Tyler Schulz 4235586ee2425e7c33e2a123ca5b563f092f66374a6Christian Williams buf.append("}\n"); 4245586ee2425e7c33e2a123ca5b563f092f66374a6Christian Williams 4256eedf728138e6f79fa898ff3e31bf61c9b1151dChristian Williams & Tyler Schulz methodBody = buf.toString(); 4266eedf728138e6f79fa898ff3e31bf61c9b1151dChristian Williams & Tyler Schulz return methodBody; 4276eedf728138e6f79fa898ff3e31bf61c9b1151dChristian Williams & Tyler Schulz } 4286eedf728138e6f79fa898ff3e31bf61c9b1151dChristian Williams & Tyler Schulz 4296eedf728138e6f79fa898ff3e31bf61c9b1151dChristian Williams & Tyler Schulz private void appendParamTypeArray(StringBuilder buf, CtMethod ctMethod) throws NotFoundException { 4306eedf728138e6f79fa898ff3e31bf61c9b1151dChristian Williams & Tyler Schulz CtClass[] parameterTypes = ctMethod.getParameterTypes(); 4316eedf728138e6f79fa898ff3e31bf61c9b1151dChristian Williams & Tyler Schulz if (parameterTypes.length == 0) { 4326eedf728138e6f79fa898ff3e31bf61c9b1151dChristian Williams & Tyler Schulz buf.append("new String[0]"); 4336eedf728138e6f79fa898ff3e31bf61c9b1151dChristian Williams & Tyler Schulz } else { 4346eedf728138e6f79fa898ff3e31bf61c9b1151dChristian Williams & Tyler Schulz buf.append("new String[] {"); 4356eedf728138e6f79fa898ff3e31bf61c9b1151dChristian Williams & Tyler Schulz for (int i = 0; i < parameterTypes.length; i++) { 4366eedf728138e6f79fa898ff3e31bf61c9b1151dChristian Williams & Tyler Schulz if (i > 0) buf.append(", "); 4376eedf728138e6f79fa898ff3e31bf61c9b1151dChristian Williams & Tyler Schulz buf.append("\""); 4386eedf728138e6f79fa898ff3e31bf61c9b1151dChristian Williams & Tyler Schulz CtClass parameterType = parameterTypes[i]; 4396eedf728138e6f79fa898ff3e31bf61c9b1151dChristian Williams & Tyler Schulz buf.append(parameterType.getName()); 4406eedf728138e6f79fa898ff3e31bf61c9b1151dChristian Williams & Tyler Schulz buf.append("\""); 4416eedf728138e6f79fa898ff3e31bf61c9b1151dChristian Williams & Tyler Schulz } 4426eedf728138e6f79fa898ff3e31bf61c9b1151dChristian Williams & Tyler Schulz buf.append("}"); 4436eedf728138e6f79fa898ff3e31bf61c9b1151dChristian Williams & Tyler Schulz } 4446eedf728138e6f79fa898ff3e31bf61c9b1151dChristian Williams & Tyler Schulz } 4456eedf728138e6f79fa898ff3e31bf61c9b1151dChristian Williams & Tyler Schulz 44684a72c253aeabd5617951a4378ec06d91bd2bfa1Christian Williams & Tyler Schulz private void appendParamArray(StringBuilder buf, CtMethod ctMethod) throws NotFoundException { 4476eedf728138e6f79fa898ff3e31bf61c9b1151dChristian Williams & Tyler Schulz int parameterCount = ctMethod.getParameterTypes().length; 4486eedf728138e6f79fa898ff3e31bf61c9b1151dChristian Williams & Tyler Schulz if (parameterCount == 0) { 4496eedf728138e6f79fa898ff3e31bf61c9b1151dChristian Williams & Tyler Schulz buf.append("new Object[0]"); 4506eedf728138e6f79fa898ff3e31bf61c9b1151dChristian Williams & Tyler Schulz } else { 4516eedf728138e6f79fa898ff3e31bf61c9b1151dChristian Williams & Tyler Schulz buf.append("new Object[] {"); 4526eedf728138e6f79fa898ff3e31bf61c9b1151dChristian Williams & Tyler Schulz for (int i = 0; i < parameterCount; i++) { 4536eedf728138e6f79fa898ff3e31bf61c9b1151dChristian Williams & Tyler Schulz if (i > 0) buf.append(", "); 454e876a8fad71b3098795fc08a08f794795123442bChristian Williams buf.append(RobolectricInternals.class.getName()); 4556eedf728138e6f79fa898ff3e31bf61c9b1151dChristian Williams & Tyler Schulz buf.append(".autobox("); 456329db3eb85b10c4d4cbce8fbbc488af3481ea2f4Christian Williams buf.append("$").append(i + 1); 4576eedf728138e6f79fa898ff3e31bf61c9b1151dChristian Williams & Tyler Schulz buf.append(")"); 4586eedf728138e6f79fa898ff3e31bf61c9b1151dChristian Williams & Tyler Schulz } 4596eedf728138e6f79fa898ff3e31bf61c9b1151dChristian Williams & Tyler Schulz buf.append("}"); 4606eedf728138e6f79fa898ff3e31bf61c9b1151dChristian Williams & Tyler Schulz } 4616eedf728138e6f79fa898ff3e31bf61c9b1151dChristian Williams & Tyler Schulz } 4626eedf728138e6f79fa898ff3e31bf61c9b1151dChristian Williams & Tyler Schulz 4636eedf728138e6f79fa898ff3e31bf61c9b1151dChristian Williams & Tyler Schulz private boolean declareField(CtClass ctClass, String fieldName, CtClass fieldType) throws CannotCompileException, NotFoundException { 4646eedf728138e6f79fa898ff3e31bf61c9b1151dChristian Williams & Tyler Schulz CtMethod ctMethod = getMethod(ctClass, "get" + fieldName, ""); 4656eedf728138e6f79fa898ff3e31bf61c9b1151dChristian Williams & Tyler Schulz if (ctMethod == null) { 4666eedf728138e6f79fa898ff3e31bf61c9b1151dChristian Williams & Tyler Schulz return false; 4676eedf728138e6f79fa898ff3e31bf61c9b1151dChristian Williams & Tyler Schulz } 4686eedf728138e6f79fa898ff3e31bf61c9b1151dChristian Williams & Tyler Schulz CtClass getterFieldType = ctMethod.getReturnType(); 4696eedf728138e6f79fa898ff3e31bf61c9b1151dChristian Williams & Tyler Schulz 4706eedf728138e6f79fa898ff3e31bf61c9b1151dChristian Williams & Tyler Schulz if (!getterFieldType.equals(fieldType)) { 4716eedf728138e6f79fa898ff3e31bf61c9b1151dChristian Williams & Tyler Schulz return false; 4726eedf728138e6f79fa898ff3e31bf61c9b1151dChristian Williams & Tyler Schulz } 4736eedf728138e6f79fa898ff3e31bf61c9b1151dChristian Williams & Tyler Schulz 4746eedf728138e6f79fa898ff3e31bf61c9b1151dChristian Williams & Tyler Schulz if (getField(ctClass, fieldName) == null) { 4756eedf728138e6f79fa898ff3e31bf61c9b1151dChristian Williams & Tyler Schulz CtField field = new CtField(fieldType, fieldName, ctClass); 4766eedf728138e6f79fa898ff3e31bf61c9b1151dChristian Williams & Tyler Schulz field.setModifiers(Modifier.PRIVATE); 4776eedf728138e6f79fa898ff3e31bf61c9b1151dChristian Williams & Tyler Schulz ctClass.addField(field); 4786eedf728138e6f79fa898ff3e31bf61c9b1151dChristian Williams & Tyler Schulz } 4796eedf728138e6f79fa898ff3e31bf61c9b1151dChristian Williams & Tyler Schulz 4806eedf728138e6f79fa898ff3e31bf61c9b1151dChristian Williams & Tyler Schulz return true; 4816eedf728138e6f79fa898ff3e31bf61c9b1151dChristian Williams & Tyler Schulz } 4826eedf728138e6f79fa898ff3e31bf61c9b1151dChristian Williams & Tyler Schulz 4836eedf728138e6f79fa898ff3e31bf61c9b1151dChristian Williams & Tyler Schulz private CtField getField(CtClass ctClass, String fieldName) { 4846eedf728138e6f79fa898ff3e31bf61c9b1151dChristian Williams & Tyler Schulz try { 4856eedf728138e6f79fa898ff3e31bf61c9b1151dChristian Williams & Tyler Schulz return ctClass.getField(fieldName); 4866eedf728138e6f79fa898ff3e31bf61c9b1151dChristian Williams & Tyler Schulz } catch (NotFoundException e) { 4876eedf728138e6f79fa898ff3e31bf61c9b1151dChristian Williams & Tyler Schulz return null; 4886eedf728138e6f79fa898ff3e31bf61c9b1151dChristian Williams & Tyler Schulz } 4896eedf728138e6f79fa898ff3e31bf61c9b1151dChristian Williams & Tyler Schulz } 4906eedf728138e6f79fa898ff3e31bf61c9b1151dChristian Williams & Tyler Schulz 4916eedf728138e6f79fa898ff3e31bf61c9b1151dChristian Williams & Tyler Schulz private CtMethod getMethod(CtClass ctClass, String methodName, String desc) { 4926eedf728138e6f79fa898ff3e31bf61c9b1151dChristian Williams & Tyler Schulz try { 4936eedf728138e6f79fa898ff3e31bf61c9b1151dChristian Williams & Tyler Schulz return ctClass.getMethod(methodName, desc); 4946eedf728138e6f79fa898ff3e31bf61c9b1151dChristian Williams & Tyler Schulz } catch (NotFoundException e) { 4956eedf728138e6f79fa898ff3e31bf61c9b1151dChristian Williams & Tyler Schulz return null; 4966eedf728138e6f79fa898ff3e31bf61c9b1151dChristian Williams & Tyler Schulz } 4976eedf728138e6f79fa898ff3e31bf61c9b1151dChristian Williams & Tyler Schulz } 4983ac42c39c9f4627c52809c9bf6701df7cd651a02Christian Williams & Phil Goodwin 4996eedf728138e6f79fa898ff3e31bf61c9b1151dChristian Williams & Tyler Schulz} 500