Fixes default method resolution (#159)
[jpf-core.git] / src / main / gov / nasa / jpf / vm / InfoObject.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
19 package gov.nasa.jpf.vm;
20
21 import gov.nasa.jpf.util.ObjectList;
22 import java.util.ArrayList;
23 import java.util.Collections;
24 import java.util.List;
25
26
27 /**
28  * common root for ClassInfo, MethodInfo, FieldInfo (and maybe more to follow)
29  * 
30  * so far, it's used to factorize the annotation support, but we can also
31  * move the attributes up here
32  * 
33  * Note this is used for both declaration- and type- annotations since there is
34  * a cross-over (type annotations of classes/interfaces are visible through the
35  * reflection API that is otherwise just reserved for declaration annotations)
36  * 
37  * 2do - there are 3 annotation positions that are valid for both type and declaration
38  * annotations: class/interface, field and formal method parameters. Of these,
39  * only class/interface type annotations can be queried at runtime, i.e. are
40  * treated similarly to declaration annotations. It is not clear if this is a
41  * Java 8 implementation artifact or intentional
42  * 
43  * Other than annotating classes/interfaces, type and declaration annotations
44  * are kept separate and only the latter ones can be queried from Java, hence
45  * we provide a query API that is only accessible from instructions,
46  * native peers and listeners. Type annotations are used
47  */
48 public abstract class InfoObject implements Cloneable {
49
50   static AnnotationInfo[] NO_ANNOTATIONS = new AnnotationInfo[0];
51   static AbstractTypeAnnotationInfo[] NO_TYPE_ANNOTATIONS = new AbstractTypeAnnotationInfo[0];
52   
53   // the number of annotations per class/method/field is usually
54   // small enough so that simple arrays are more efficient than HashMaps
55   protected AnnotationInfo[] annotations = NO_ANNOTATIONS;
56
57   protected AbstractTypeAnnotationInfo[] typeAnnotations = NO_TYPE_ANNOTATIONS;
58   
59   /** 
60    * user defined attribute objects.
61    * Note - this is NOT automatically state restored upon backtracking,
62    * subclasses have to do this on their own if required
63    */
64   protected Object attr;
65   
66   
67   public void setAnnotations (AnnotationInfo[] annotations){
68     this.annotations = annotations;
69   }
70   
71   public void addAnnotations (AnnotationInfo[] annotations){
72     if (annotations == null){
73       this.annotations = annotations;
74     } else {
75       AnnotationInfo[] newAi = new AnnotationInfo[this.annotations.length + annotations.length];
76       System.arraycopy(this.annotations,0,newAi, 0, this.annotations.length);
77       System.arraycopy(annotations, 0, newAi, this.annotations.length, annotations.length);
78       this.annotations = newAi;
79     }
80   }
81   
82   public void addAnnotation (AnnotationInfo newAnnotation){
83     AnnotationInfo[] ai = annotations;
84     if (ai == null){
85       ai = new AnnotationInfo[1];
86       ai[0] = newAnnotation;
87
88     } else {
89       int len = annotations.length;
90       ai = new AnnotationInfo[len+1];
91       System.arraycopy(annotations, 0, ai, 0, len);
92       ai[len] = newAnnotation;
93     }
94
95     annotations = ai;
96   }
97
98   // to be overridden by ClassInfo because of superclass inhertited annotations
99   public boolean hasAnnotations(){
100     return (annotations != NO_ANNOTATIONS);
101   }
102   
103   // to be overridden by ClassInfo because of superclass inhertited annotations
104   public AnnotationInfo[] getAnnotations() {
105     return annotations;
106   }
107       
108   // to be overridden by ClassInfo because of superclass inhertited annotations
109   public AnnotationInfo getAnnotation (String name){    
110     AnnotationInfo[] ai = annotations;
111     if (ai != NO_ANNOTATIONS){
112       for (int i=0; i<ai.length; i++){
113         if (ai[i].getName().equals(name)){
114           return ai[i];
115         }
116       }
117     }
118     return null;
119   }
120   
121   public boolean hasAnnotation (String name){
122     return getAnnotation(name) != null;    
123   }
124   
125   public AnnotationInfo[] getDeclaredAnnotations(){
126     return annotations;
127   }
128
129   //--- type annotations
130   
131   public void setTypeAnnotations (AbstractTypeAnnotationInfo[] typeAnnotations){
132     this.typeAnnotations = typeAnnotations;
133   }
134
135   public void addTypeAnnotations (AbstractTypeAnnotationInfo[] tas){
136     if (typeAnnotations == NO_TYPE_ANNOTATIONS){
137       typeAnnotations = tas;
138       
139     } else {
140       int oldLen = typeAnnotations.length;
141       AbstractTypeAnnotationInfo[] newTA = new AbstractTypeAnnotationInfo[oldLen + tas.length];
142       System.arraycopy(typeAnnotations, 0, newTA, 0, oldLen);
143       System.arraycopy(tas, 0, newTA, oldLen, tas.length);
144       typeAnnotations = newTA;
145     }
146   }
147   
148   public void addTypeAnnotation (AbstractTypeAnnotationInfo newAnnotation){
149     AbstractTypeAnnotationInfo[] ai = typeAnnotations;
150     if (ai == null){
151       ai = new AbstractTypeAnnotationInfo[1];
152       ai[0] = newAnnotation;
153
154     } else {
155       int len = annotations.length;
156       ai = new AbstractTypeAnnotationInfo[len+1];
157       System.arraycopy(annotations, 0, ai, 0, len);
158       ai[len] = newAnnotation;
159     }
160
161     typeAnnotations = ai;
162   }
163
164   
165   public AbstractTypeAnnotationInfo[] getTypeAnnotations() {
166     return typeAnnotations;
167   }
168   
169   public boolean hasTypeAnnotations(){
170     return (typeAnnotations != NO_TYPE_ANNOTATIONS);    
171   }
172   
173   public boolean hasTypeAnnotation (String name){
174     return getTypeAnnotation(name) != null;    
175   }
176   
177   public AbstractTypeAnnotationInfo getTypeAnnotation (String annoClsName){    
178     AbstractTypeAnnotationInfo[] ai = typeAnnotations;
179     if (ai != NO_TYPE_ANNOTATIONS){
180       for (int i=0; i<ai.length; i++){
181         if (ai[i].getName().equals(annoClsName)){
182           return ai[i];
183         }
184       }
185     }
186     return null;
187   }
188
189   public <T extends AbstractTypeAnnotationInfo> List<T> getTargetTypeAnnotations (Class<T> targetType){
190     List<T> list = null;
191     
192     AbstractTypeAnnotationInfo[] ais = typeAnnotations;
193     if (ais != NO_TYPE_ANNOTATIONS){
194       for (AbstractTypeAnnotationInfo ai : ais){
195         if (targetType.isAssignableFrom(ai.getClass())){
196           if (list == null){
197             list = new ArrayList();
198           }
199           list.add((T)ai);
200         }
201       }
202     }
203     
204     if (list != null){
205       return list;
206     } else {
207       return Collections.emptyList();
208     }
209   }
210   
211   //--- the generic attribute API
212
213   public boolean hasAttr () {
214     return (attr != null);
215   }
216
217   public boolean hasAttr (Class<?> attrType){
218     return ObjectList.containsType(attr, attrType);
219   }
220
221   public boolean hasAttrValue (Object a){
222     return ObjectList.contains(attr, a);
223   }
224   
225   /**
226    * this returns all of them - use either if you know there will be only
227    * one attribute at a time, or check/process result with ObjectList
228    */
229   public Object getAttr(){
230     return attr;
231   }
232
233   /**
234    * this replaces all of them - use only if you know 
235    *  - there will be only one attribute at a time
236    *  - you obtained the value you set by a previous getXAttr()
237    *  - you constructed a multi value list with ObjectList.createList()
238    */
239   public void setAttr (Object a){
240     attr = a;    
241   }
242
243   public void addAttr (Object a){
244     attr = ObjectList.add(attr, a);
245   }
246
247   public void removeAttr (Object a){
248     attr = ObjectList.remove(attr, a);
249   }
250
251   public void replaceAttr (Object oldAttr, Object newAttr){
252     attr = ObjectList.replace(attr, oldAttr, newAttr);
253   }
254
255   /**
256    * this only returns the first attr of this type, there can be more
257    * if you don't use client private types or the provided type is too general
258    */
259   public <T> T getAttr (Class<T> attrType) {
260     return ObjectList.getFirst(attr, attrType);
261   }
262
263   public <T> T getNextAttr (Class<T> attrType, Object prev) {
264     return ObjectList.getNext(attr, attrType, prev);
265   }
266
267   public ObjectList.Iterator attrIterator(){
268     return ObjectList.iterator(attr);
269   }
270   
271   public <T> ObjectList.TypedIterator<T> attrIterator(Class<T> attrType){
272     return ObjectList.typedIterator(attr, attrType);
273   }
274 }