OSDN Git Service

b7b615538224ae3df330c839bfe8690804416c8f
[stigmata/stigmata.git] / src / main / java / jp / sourceforge / stigmata / birthmarks / cvfv / ConstantValueOfFieldVariableBirthmarkExtractVisitor.java
1 package jp.sourceforge.stigmata.birthmarks.cvfv;
2
3 import java.util.LinkedHashMap;
4 import java.util.Map;
5
6 import jp.sourceforge.stigmata.Birthmark;
7 import jp.sourceforge.stigmata.BirthmarkContext;
8 import jp.sourceforge.stigmata.birthmarks.BirthmarkExtractVisitor;
9
10 import org.objectweb.asm.ClassVisitor;
11 import org.objectweb.asm.FieldVisitor;
12 import org.objectweb.asm.MethodAdapter;
13 import org.objectweb.asm.MethodVisitor;
14 import org.objectweb.asm.Opcodes;
15 import org.objectweb.asm.Type;
16
17 /**
18  * 
19  * 
20  *
21  * @author Haruaki TAMADA
22  */
23 public class ConstantValueOfFieldVariableBirthmarkExtractVisitor extends BirthmarkExtractVisitor{
24     private Map<String, TypeAndValueBirthmarkElement> elements = new LinkedHashMap<String, TypeAndValueBirthmarkElement>();
25     private String className;
26
27     public ConstantValueOfFieldVariableBirthmarkExtractVisitor(ClassVisitor visitor, Birthmark birthmark, BirthmarkContext context){
28         super(visitor, birthmark, context);
29     }
30
31     @Override
32     public void visitEnd(){
33         for(String key: elements.keySet()){
34             addElement(elements.get(key));
35         }
36         super.visitEnd();
37     }
38
39     @Override
40     public void visit(int version, int access, String name, String signature,
41                       String superName, String[] interfaces){
42         this.className = name;
43
44         super.visit(version, access, name, signature, superName, interfaces);
45     }
46
47     @Override
48     public FieldVisitor visitField(int access, String name, String desc,
49                                    String signature, Object value){
50
51         FieldVisitor visitor = super.visitField(access, name, desc, signature, value);
52
53         TypeAndValueBirthmarkElement e = elements.get(name);
54         if(e == null){
55             e = new TypeAndValueBirthmarkElement(desc, value);
56         }
57         else{
58             if(value != null){
59                 e.setValue(value);
60             }
61         }
62         elements.put(name, e);
63
64         return visitor;
65     }
66
67     @Override
68     public MethodVisitor visitMethod(int access, String name, String desc, String signature,
69                                      String[] exceptions){
70         MethodVisitor visitor = super.visitMethod(access, name, desc, signature, exceptions);
71
72         if(name.equals("<init>") || name.equals("<clinit>")){
73             visitor = new MethodAdapter(visitor){
74                 private Object constant = null;
75
76                 @Override
77                 public void visitIntInsn(int opcode, int operand){
78                     if(opcode == Opcodes.BIPUSH || opcode == Opcodes.SIPUSH){
79                         constant = new Integer(operand);
80                     }
81                     super.visitIntInsn(opcode, operand);
82                 }
83
84                 @Override
85                 public void visitMethodInsn(int opcode, String owner, String name, String desc){
86                     Type type = Type.getReturnType(desc);
87                     if(!type.equals(Type.VOID_TYPE)){
88                         constant = null;
89                     }
90                     super.visitMethodInsn(opcode, owner, name, desc);
91                 }
92
93                 @Override
94                 public void visitInsn(int opcode){
95                     if(opcode == Opcodes.ICONST_M1)     constant = new Integer(-1);
96                     else if(opcode == Opcodes.ICONST_0) constant = new Integer(0);
97                     else if(opcode == Opcodes.ICONST_1) constant = new Integer(1);
98                     else if(opcode == Opcodes.ICONST_2) constant = new Integer(2);
99                     else if(opcode == Opcodes.ICONST_3) constant = new Integer(3);
100                     else if(opcode == Opcodes.ICONST_4) constant = new Integer(4);
101                     else if(opcode == Opcodes.ICONST_5) constant = new Integer(5);
102                     else if(opcode == Opcodes.LCONST_0) constant = new Long(0L);
103                     else if(opcode == Opcodes.LCONST_1) constant = new Long(1L);
104                     else if(opcode == Opcodes.DCONST_0) constant = new Double(0D);
105                     else if(opcode == Opcodes.DCONST_1) constant = new Double(1D);
106                     else if(opcode == Opcodes.FCONST_0) constant = new Float(0F);
107                     else if(opcode == Opcodes.FCONST_1) constant = new Float(1F);
108                     else if(opcode == Opcodes.FCONST_2) constant = new Float(2F);
109
110                     super.visitInsn(opcode);
111                 }
112
113                 @Override
114                 public void visitLdcInsn(Object object){
115                     constant = object;
116                     super.visitLdcInsn(object);
117                 }
118
119                 @Override
120                 public void visitFieldInsn(int opcode, String owner, String name, String desc){
121                     if(className.equals(owner) && opcode == Opcodes.PUTFIELD){
122                         TypeAndValueBirthmarkElement e = elements.get(name);
123                         if(e == null){
124                             e = new TypeAndValueBirthmarkElement(desc, constant);
125                         }
126
127                         if(e.getValue() == null && constant != null){
128                             if(!checkCast(desc, constant)){
129                                 constant = null;
130                             }
131                             e.setValue(constant);
132                         }
133                     }
134                     super.visitFieldInsn(opcode, owner, name, desc);
135                 }
136             };
137         }
138
139         return visitor;
140     }
141
142     private boolean checkCast(String desc, Object constant){
143         if(constant instanceof Integer){
144             return desc.equals("Ljava/lang/Integer;") ||
145                 desc.equals("I") || desc.equals("S") || desc.equals("Z") ||
146                 desc.equals("C") || desc.equals("B");
147         }
148         else if(constant instanceof Float){
149             return desc.equals("Ljava/lang/Float;") || desc.equals("F");
150         }
151         else if(constant instanceof Double){
152             return desc.equals("Ljava/lang/Double;") || desc.equals("D");
153         }
154         else if(constant instanceof Long){
155             return desc.equals("Ljava/lang/Long;") || desc.equals("J");
156         }
157         else if(constant instanceof String){
158             return desc.equals("Ljava/lang/String;");
159         }
160         return false;
161     }
162 }