KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > edu > umd > cs > findbugs > ba > AnnotationDatabase


1 /*
2  * FindBugs - Find Bugs in Java programs
3  * Copyright (C) 2005, University of Maryland
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2.1 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this library; if not, write to the Free Software
17  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18  */

19
20 package edu.umd.cs.findbugs.ba;
21
22 import java.util.HashMap JavaDoc;
23 import java.util.HashSet JavaDoc;
24 import java.util.Map JavaDoc;
25 import java.util.Set JavaDoc;
26 import java.util.TreeSet JavaDoc;
27
28 import org.apache.bcel.Repository;
29 import org.apache.bcel.classfile.JavaClass;
30 import org.apache.bcel.classfile.Method;
31
32 import edu.umd.cs.findbugs.SystemProperties;
33 import edu.umd.cs.findbugs.annotations.CheckForNull;
34 import edu.umd.cs.findbugs.ba.ch.Subtypes;
35 import edu.umd.cs.findbugs.util.MapCache;
36
37 /**
38  * @author William Pugh
39  */

40 public class AnnotationDatabase<AnnotationEnum extends AnnotationEnumeration<AnnotationEnum>> {
41     static final boolean DEBUG = SystemProperties.getBoolean("annotations.debug");;
42
43     /**
44      *
45      */

46     public static final String JavaDoc FIELD = "Field";
47
48     /**
49      *
50      */

51     public static final String JavaDoc METHOD = "Method";
52
53     /**
54      *
55      */

56     public static final String JavaDoc PARAMETER = "Parameter";
57
58     /**
59      *
60      */

61     public static final String JavaDoc ANY = "Any";
62
63     private static final String JavaDoc DEFAULT_ANNOTATION_ANNOTATION_CLASS = "DefaultAnnotation";
64
65     private Map JavaDoc<Object JavaDoc, AnnotationEnum> directAnnotations = new HashMap JavaDoc<Object JavaDoc, AnnotationEnum>();
66     
67     private Set JavaDoc<Object JavaDoc> syntheticElements = new HashSet JavaDoc<Object JavaDoc>();
68
69     private final Map JavaDoc<String JavaDoc, Map JavaDoc<String JavaDoc, AnnotationEnum>> defaultAnnotation = new HashMap JavaDoc<String JavaDoc, Map JavaDoc<String JavaDoc, AnnotationEnum>>();
70
71     private Subtypes subtypes;
72     public AnnotationDatabase() {
73         defaultAnnotation.put(ANY,
74                 new HashMap JavaDoc<String JavaDoc, AnnotationEnum>());
75         defaultAnnotation.put(PARAMETER,
76                 new HashMap JavaDoc<String JavaDoc, AnnotationEnum>());
77         defaultAnnotation.put(METHOD,
78                 new HashMap JavaDoc<String JavaDoc, AnnotationEnum>());
79         defaultAnnotation.put(FIELD,
80                 new HashMap JavaDoc<String JavaDoc, AnnotationEnum>());
81         subtypes = AnalysisContext.currentAnalysisContext().getSubtypes();
82
83     }
84
85     public void loadAuxiliaryAnnotations() {
86         
87     }
88     private final Set JavaDoc<AnnotationEnum> seen = new HashSet JavaDoc<AnnotationEnum>();
89     public void addSyntheticElement(Object JavaDoc o) {
90         syntheticElements.add(o);
91         if (DEBUG)
92             System.out.println("Synthetic element: " + o);
93     }
94     
95     public void addDirectAnnotation(Object JavaDoc o, AnnotationEnum n) {
96         directAnnotations.put(o, n);
97         seen.add(n);
98     }
99
100     public void addDefaultAnnotation(String JavaDoc target, String JavaDoc c,
101             AnnotationEnum n) {
102         if (!defaultAnnotation.containsKey(target))
103             return;
104         if (DEBUG)
105             System.out.println("Default annotation " + target + " " + c + " " + n);
106         defaultAnnotation.get(target).put(c, n);
107         seen.add(n);
108     }
109
110     public boolean anyAnnotations(AnnotationEnum n) {
111         return seen.contains(n);
112     }
113     
114     // TODO: Parameterize these values?
115
Map JavaDoc<Object JavaDoc, AnnotationEnum> cachedMinimal = new MapCache<Object JavaDoc, AnnotationEnum>(20000);
116     Map JavaDoc<Object JavaDoc, AnnotationEnum> cachedMaximal= new MapCache<Object JavaDoc, AnnotationEnum>(20000);
117     @CheckForNull
118     public AnnotationEnum getResolvedAnnotation(Object JavaDoc o, boolean getMinimal) {
119         Map JavaDoc<Object JavaDoc, AnnotationEnum> cache;
120         if (getMinimal) cache = cachedMinimal;
121         else cache = cachedMaximal;
122         
123         if (cache.containsKey(o)) {
124             return cache.get(o);
125         }
126         AnnotationEnum n = getUncachedResolvedAnnotation(o, getMinimal);
127         if (DEBUG) System.out.println("TTT: " + o + " " + n);
128         cache.put(o,n);
129         return n;
130     }
131     
132     public boolean annotationIsDirect(Object JavaDoc o) {
133         return directAnnotations.containsKey(o);
134     }
135     @CheckForNull
136     public AnnotationEnum getUncachedResolvedAnnotation(final Object JavaDoc o, boolean getMinimal) {
137         
138         AnnotationEnum n = directAnnotations.get(o);
139         if (n != null)
140             return n;
141
142         try {
143             
144             String JavaDoc className;
145             String JavaDoc kind;
146             boolean isParameterToInitMethodofAnonymousInnerClass = false;
147             boolean isSyntheticMethod = false;
148             if (o instanceof XMethod || o instanceof XMethodParameter) {
149                 
150                 XMethod m;
151                 if (o instanceof XMethod) {
152                     m = (XMethod) o;
153                     isSyntheticMethod = syntheticElements.contains(m);
154                     kind = METHOD;
155                     className = m.getClassName();
156                 } else if (o instanceof XMethodParameter) {
157                     m = ((XMethodParameter) o).getMethod();
158                     // Don't
159
isSyntheticMethod = syntheticElements.contains(m);
160                     className = m.getClassName();
161                     kind = PARAMETER;
162                     if (m.getName().equals("<init>")) {
163                         int i = className.lastIndexOf("$");
164                         if (i+1 < className.length()
165                                 && Character.isDigit(className.charAt(i+1)))
166                                 isParameterToInitMethodofAnonymousInnerClass = true;
167                     }
168                 } else
169                     throw new IllegalStateException JavaDoc("impossible");
170
171                 
172
173                 if (!m.isStatic() && !m.getName().equals("<init>")) {
174                     JavaClass c = Repository.lookupClass(className);
175                     // get inherited annotation
176
TreeSet JavaDoc<AnnotationEnum> inheritedAnnotations = new TreeSet JavaDoc<AnnotationEnum>();
177                     if (c.getSuperclassNameIndex() > 0) {
178                         
179                         n = lookInOverriddenMethod(o, c.getSuperclassName(), m, getMinimal);
180                         if (n != null)
181                             inheritedAnnotations.add(n);
182                     }
183                     for(String JavaDoc implementedInterface : c.getInterfaceNames()) {
184                         n = lookInOverriddenMethod(o, implementedInterface, m, getMinimal);
185                         if (n != null)
186                             inheritedAnnotations.add(n);
187                     }
188                     if (DEBUG) System.out.println("# of inherited annotations : " + inheritedAnnotations.size());
189                     if (!inheritedAnnotations.isEmpty()) {
190                         if (inheritedAnnotations.size() == 1)
191                             return inheritedAnnotations.first();
192                         if (!getMinimal)
193                             return inheritedAnnotations.last();
194                         
195                         AnnotationEnum min = inheritedAnnotations.first();
196                         if (min.getIndex() == 0) {
197                             inheritedAnnotations.remove(min);
198                             min = inheritedAnnotations.first();
199                         }
200                         return min;
201                     }
202                     // check to see if method is defined in this class;
203
// if not, on't consider default annotations
204
if (! classDefinesMethod(c, m) ) return null;
205                     if (DEBUG) System.out.println("looking for default annotations: " + c.getClassName() + " defines " + m);
206                 } // if not static
207
} // associated with method
208
else if (o instanceof XField) {
209                 
210                 className = ((XField) o).getClassName();
211                 kind = FIELD;
212             } else if (o instanceof String JavaDoc) {
213                 className = (String JavaDoc) o;
214                 kind = "CLASS";
215             } else throw new IllegalArgumentException JavaDoc("Can't look up annotation for " + o.getClass().getName());
216
217             // <init> method parameters for inner classes don't inherit default annotations
218
// since some of them are synthetic
219
if (isParameterToInitMethodofAnonymousInnerClass) return null;
220             if (isSyntheticMethod) return null;
221             
222             // synthetic elements should not inherit default annotations
223
if (syntheticElements.contains(o)) return null;
224             if (syntheticElements.contains(className)) return null;
225             
226             
227             // look for default annotation
228
n = defaultAnnotation.get(kind).get(className);
229             if (DEBUG)
230                 System.out.println("Default annotation for " + kind + " is " + n);
231             if (n != null)
232                 return n;
233
234             n = defaultAnnotation.get(ANY).get(className);
235             if (DEBUG)
236                 System.out.println("Default annotation for any is " + n);
237             if (n != null)
238                 return n;
239
240
241             int p = className.lastIndexOf('.');
242             className = className.substring(0,p+1) + "package-info";
243             n = defaultAnnotation.get(kind).get(className);
244             if (DEBUG)
245                 System.out.println("Default annotation for " + kind + " is " + n);
246             if (n != null)
247                 return n;
248
249             n = defaultAnnotation.get(ANY).get(className);
250             if (DEBUG)
251                 System.out.println("Default annotation for any is " + n);
252             if (n != null)
253                 return n;
254             
255             
256             
257             return n;
258         } catch (ClassNotFoundException JavaDoc e) {
259             AnalysisContext.reportMissingClass(e);
260             return null;
261         }
262
263     }
264
265     private boolean classDefinesMethod(JavaClass c, XMethod m) {
266         for(Method definedMethod : c.getMethods())
267             if (definedMethod.getName().equals(m.getName())
268                     && definedMethod.getSignature().equals(m.getSignature())
269                     && definedMethod.isStatic() == m.isStatic())
270                 return true;
271         return false;
272     }
273
274     private AnnotationEnum lookInOverriddenMethod(final Object JavaDoc originalQuery,
275             String JavaDoc classToLookIn, XMethod originalMethod, boolean getMinimal) {
276         try {
277         AnnotationEnum n;
278         // Look in supermethod
279
XMethod superMethod = XFactory.createXMethod(classToLookIn, originalMethod.getName(),
280                 originalMethod.getSignature(), originalMethod.isStatic());
281         if (!superMethod.isResolved()) return null;
282         if (DEBUG)
283             System.out.println("Looking for overridden method " + superMethod);
284         
285         Object JavaDoc probe;
286         if (originalQuery instanceof XMethod)
287             probe = superMethod;
288         else if (originalQuery instanceof XMethodParameter)
289             probe = new XMethodParameter(superMethod,
290                     ((XMethodParameter) originalQuery).getParameterNumber());
291         else
292             throw new IllegalStateException JavaDoc("impossible");
293
294         n = getResolvedAnnotation(probe, getMinimal);
295         return n;
296         } catch (RuntimeException JavaDoc e) {
297             e.printStackTrace();
298             throw e;
299         }
300     }
301
302     boolean addClassOnly = false;
303     public boolean setAddClassOnly(boolean newValue) {
304         boolean oldValue = addClassOnly;
305         addClassOnly = newValue;
306         return oldValue;
307     }
308     protected void addDefaultMethodAnnotation(String JavaDoc cName, AnnotationEnum annotation) {
309         subtypes.addNamedClass(cName);
310
311         if (addClassOnly) return;
312         
313             addDefaultAnnotation(AnnotationDatabase.METHOD, cName, annotation);
314
315     
316     }
317
318     protected void addFieldAnnotation(String JavaDoc cName, String JavaDoc mName, String JavaDoc mSig, boolean isStatic, AnnotationEnum annotation) {
319         subtypes.addNamedClass(cName);
320         if (addClassOnly) return;
321         XField m = XFactory.createXField(cName, mName, mSig, isStatic);
322         addDirectAnnotation(m, annotation);
323     }
324
325     protected void addMethodAnnotation(String JavaDoc cName, String JavaDoc mName, String JavaDoc mSig, boolean isStatic, AnnotationEnum annotation) {
326         subtypes.addNamedClass(cName);
327         if (addClassOnly) return;
328         XMethod m = XFactory.createXMethod(cName, mName, mSig, isStatic);
329         addDirectAnnotation(m, annotation);
330     }
331     protected void addMethodParameterAnnotation(String JavaDoc cName, String JavaDoc mName, String JavaDoc mSig, boolean isStatic, int param, AnnotationEnum annotation) {
332         subtypes.addNamedClass(cName);
333         if (addClassOnly) return;
334         XMethod m = XFactory.createXMethod(cName, mName, mSig, isStatic);
335         addDirectAnnotation(new XMethodParameter(m, param), annotation);
336     }
337 }
338
Popular Tags