1 package org.robolectric.internal.bytecode; 2 3 import com.google.auto.service.AutoService; 4 import javax.annotation.Priority; 5 import org.objectweb.asm.Opcodes; 6 import org.objectweb.asm.Type; 7 import org.objectweb.asm.tree.FieldNode; 8 import org.objectweb.asm.tree.MethodNode; 9 10 /** Decorator which adds Robolectric's shadowing behavior to a class. */ 11 @AutoService(ClassInstrumentor.Decorator.class) 12 @Priority(Integer.MIN_VALUE) 13 public class ShadowDecorator implements ClassInstrumentor.Decorator { 14 private static final String OBJECT_DESC = Type.getDescriptor(Object.class); 15 private static final Type OBJECT_TYPE = Type.getType(Object.class); 16 private static final String GET_ROBO_DATA_SIGNATURE = "()Ljava/lang/Object;"; 17 18 @Override decorate(MutableClass mutableClass)19 public void decorate(MutableClass mutableClass) { 20 mutableClass.addInterface(Type.getInternalName(ShadowedObject.class)); 21 22 mutableClass.addField( 23 0, 24 new FieldNode( 25 Opcodes.ACC_PUBLIC | Opcodes.ACC_SYNTHETIC | Opcodes.ACC_TRANSIENT, 26 ShadowConstants.CLASS_HANDLER_DATA_FIELD_NAME, 27 OBJECT_DESC, 28 OBJECT_DESC, 29 null)); 30 31 addRoboGetDataMethod(mutableClass); 32 } 33 addRoboGetDataMethod(MutableClass mutableClass)34 private void addRoboGetDataMethod(MutableClass mutableClass) { 35 MethodNode initMethodNode = 36 new MethodNode( 37 Opcodes.ACC_PUBLIC | Opcodes.ACC_SYNTHETIC, 38 ShadowConstants.GET_ROBO_DATA_METHOD_NAME, 39 GET_ROBO_DATA_SIGNATURE, 40 null, 41 null); 42 RobolectricGeneratorAdapter generator = new RobolectricGeneratorAdapter(initMethodNode); 43 generator.loadThis(); // this 44 generator.getField( 45 mutableClass.classType, 46 ShadowConstants.CLASS_HANDLER_DATA_FIELD_NAME, 47 OBJECT_TYPE); // contents of __robo_data__ 48 generator.returnValue(); 49 generator.endMethod(); 50 mutableClass.addMethod(initMethodNode); 51 } 52 } 53