Fixing a new bug: Considering parameters with Type and Type array, e.g., T and T[].
[jpf-core.git] / src / main / gov / nasa / jpf / jvm / JVMAnnotationParser.java
1 /*
2  * Copyright (C) 2014, United States Government, as represented by the
3  * Administrator of the National Aeronautics and Space Administration.
4  * All rights reserved.
5  *
6  * The Java Pathfinder core (jpf-core) platform is licensed under the
7  * Apache License, Version 2.0 (the "License"); you may not use this file except
8  * in compliance with the License. You may obtain a copy of the License at
9  * 
10  *        http://www.apache.org/licenses/LICENSE-2.0. 
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and 
16  * limitations under the License.
17  */
18 package gov.nasa.jpf.jvm;
19
20 import java.util.LinkedList;
21
22 import gov.nasa.jpf.JPFException;
23 import gov.nasa.jpf.vm.AnnotationInfo;
24 import gov.nasa.jpf.vm.AnnotationParser;
25 import gov.nasa.jpf.vm.ClassParseException;
26 import gov.nasa.jpf.vm.Types;
27
28 /**
29  * parser that reads annotation classfiles and extracts default value entries
30  * 
31  * Java annotations form a different type system. Java annotations are essentially
32  * restricted interfaces (no super-interface, no fields other than static finals
33  * that are inlined by the compiler)
34  * 
35  * Since Java annotations use only a small subset of the Java classfile format
36  * we only have to parse methods and method attributes
37  * 
38  * <2do> class and enum values are not yet supported
39  */
40 public class JVMAnnotationParser extends ClassFileReaderAdapter implements AnnotationParser {
41
42   ClassFile cf;
43   AnnotationInfo ai;
44   
45   String key;
46   Object value;
47   Object[] valElements;
48
49   String annotationName;
50   AnnotationInfo.Entry[] entries;
51   
52   protected LinkedList<AnnotationInfo> annotationStack;
53   protected AnnotationInfo curAi;
54   protected LinkedList<Object[]> valuesStack;
55   
56   public JVMAnnotationParser (ClassFile cf) {
57     this.cf = cf;
58   }
59
60   @Override
61   public void parse (AnnotationInfo ai) throws ClassParseException {
62     this.ai = ai;
63     
64     cf.parse(this);
65   }
66     
67   //--- the overridden ClassFileReader methods
68
69   @Override
70   public void setClass (ClassFile cf, String clsName, String superClsName, int flags, int cpCount) throws ClassParseException {
71     entries = null;
72     annotationName = Types.getClassNameFromTypeName(clsName);
73     
74     ai.setName(annotationName);
75   }
76
77   @Override
78   public void setInterface (ClassFile cf, int ifcIndex, String ifcName) {
79     if (!"java/lang/annotation/Annotation".equals(ifcName)) {
80       throw new JPFException("illegal annotation interface of: " + annotationName + " is " + ifcName);
81     }
82   }
83
84   @Override
85   public void setMethodCount (ClassFile cf, int methodCount) {
86     entries = new AnnotationInfo.Entry[methodCount];
87   }
88
89   @Override
90   public void setMethod (ClassFile cf, int methodIndex, int accessFlags, String name, String descriptor) {
91     key = name;
92     value = null;
93   }
94
95   @Override
96   public void setMethodDone (ClassFile cf, int methodIndex){
97     entries[methodIndex] = new AnnotationInfo.Entry(key, value);
98   }
99   
100   @Override
101   public void setMethodsDone (ClassFile cf){
102     ai.setEntries(entries);
103   }
104   
105   @Override
106   public void setMethodAttribute (ClassFile cf, int methodIndex, int attrIndex, String name, int attrLength) {
107     if (name == ClassFile.ANNOTATIONDEFAULT_ATTR) {
108       cf.parseAnnotationDefaultAttr(this, key);
109     }
110   }
111
112   @Override
113   public void setClassAttribute (ClassFile cf, int attrIndex, String name, int attrLength) {
114     if (name == ClassFile.RUNTIME_VISIBLE_ANNOTATIONS_ATTR) {
115       key = null;
116       cf.parseAnnotationsAttr(this, null);
117     }
118   }
119
120   @Override
121   public void setAnnotation (ClassFile cf, Object tag, int annotationIndex, String annotationType) {
122     if (key == null && annotationType.equals("Ljava/lang/annotation/Inherited;")) {
123       ai.setInherited( true);
124     }
125     if(key != null  && annotationIndex == -1) {
126       if(annotationStack == null) {
127         assert valuesStack == null;
128         annotationStack = new LinkedList<>();
129         valuesStack = new LinkedList<>();
130       }
131       annotationStack.addFirst(curAi);
132       valuesStack.addFirst(valElements);
133       valElements = null;
134       curAi = ai.getClassLoaderInfo().getResolvedAnnotationInfo(Types.getClassNameFromTypeName(annotationType));
135     }
136   }
137   
138   @Override
139   public void setAnnotationFieldValue(ClassFile cf, Object tag, int annotationIndex, int valueIndex, String elementName, int arrayIndex) {
140     assert annotationStack.size() > 0;
141     AnnotationInfo ai = curAi;
142     valElements = valuesStack.pop();
143     curAi = annotationStack.pop();
144     if(arrayIndex >= 0) {
145       valElements[arrayIndex] = ai;
146     } else {
147       if(curAi != null) {
148         curAi.setClonedEntryValue(elementName, ai);
149       } else {
150         value = ai;
151       }
152     }
153   }
154   
155   @Override
156   public void setPrimitiveAnnotationValue (ClassFile cf, Object tag, int annotationIndex, int valueIndex,
157           String elementName, int arrayIndex, Object val) {
158     if (arrayIndex >= 0) {
159       valElements[arrayIndex] = val;
160     } else if(curAi != null) {
161       curAi.setClonedEntryValue(elementName, val);
162     } else {
163       if (key != null){
164         value = val;
165       }
166     }
167   }
168   
169   @Override
170   public void setStringAnnotationValue (ClassFile cf, Object tag, int annotationIndex, int valueIndex,
171           String elementName, int arrayIndex, String val) {
172     if (arrayIndex >= 0) {
173       valElements[arrayIndex] = val;
174     } else if(curAi != null) {
175       curAi.setClonedEntryValue(elementName, val);
176     } else {
177       if (key != null){
178         value = val;
179       }
180     }
181   }
182
183   @Override
184   public void setClassAnnotationValue (ClassFile cf, Object tag, int annotationIndex, int valueIndex,
185           String elementName, int arrayIndex, String typeName) {
186     Object val = AnnotationInfo.getClassValue(typeName);
187     if (arrayIndex >= 0) {
188       valElements[arrayIndex] = val;
189     } else if(curAi != null) {
190       curAi.setClonedEntryValue(elementName, val);
191     } else {
192       if (key != null){
193         value = val;
194       }
195     }
196   }
197
198   @Override
199   public void setEnumAnnotationValue (ClassFile cf, Object tag, int annotationIndex, int valueIndex,
200           String elementName, int arrayIndex, String enumType, String enumValue) {
201     Object val = AnnotationInfo.getEnumValue(enumType, enumValue);
202     if (arrayIndex >= 0) {
203       valElements[arrayIndex] = val;
204     } else if(curAi != null) {
205       curAi.setClonedEntryValue(elementName, val);
206     } else {
207       if (key != null){
208         value = val;
209       }
210     }
211   }
212
213   @Override
214   public void setAnnotationValueElementCount (ClassFile cf, Object tag, int annotationIndex, int valueIndex,
215           String elementName, int elementCount) {
216     valElements = new Object[elementCount];
217   }
218
219   @Override
220   public void setAnnotationValueElementsDone (ClassFile cf, Object tag, int annotationIndex, int valueIndex,
221           String elementName) {
222     if(curAi != null) {
223       curAi.setClonedEntryValue(elementName, valElements);
224     } else if (key != null) {
225       value = valElements;
226     }
227   }
228 }