KickJava   Java API By Example, From Geeks To Geeks.

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


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.ArrayList JavaDoc;
23 import java.util.Collections JavaDoc;
24 import java.util.HashMap JavaDoc;
25 import java.util.HashSet JavaDoc;
26 import java.util.Map JavaDoc;
27 import java.util.Set JavaDoc;
28
29 import org.apache.bcel.Constants;
30 import org.apache.bcel.Repository;
31 import org.apache.bcel.classfile.Field;
32 import org.apache.bcel.classfile.JavaClass;
33 import org.apache.bcel.classfile.Method;
34 import org.apache.bcel.generic.ConstantPoolGen;
35 import org.apache.bcel.generic.FieldInstruction;
36 import org.apache.bcel.generic.InvokeInstruction;
37 import org.apache.bcel.generic.MethodGen;
38
39 import edu.umd.cs.findbugs.FieldAnnotation;
40 import edu.umd.cs.findbugs.MethodAnnotation;
41 import edu.umd.cs.findbugs.SystemProperties;
42 import edu.umd.cs.findbugs.annotations.CheckReturnValue;
43 import edu.umd.cs.findbugs.annotations.NonNull;
44 import edu.umd.cs.findbugs.visitclass.DismantleBytecode;
45 import edu.umd.cs.findbugs.visitclass.PreorderVisitor;
46
47 /**
48  * Factory methods for creating XMethod objects.
49  *
50  * @author David Hovemeyer
51  */

52 public class XFactory {
53     
54     public XFactory() {};
55
56     private Map JavaDoc<XMethod,XMethod> methods = new HashMap JavaDoc<XMethod,XMethod>();
57
58     private Set JavaDoc<ClassMember> deprecated = new HashSet JavaDoc<ClassMember>();
59     private Set JavaDoc<? extends ClassMember> deprecatedView = Collections.unmodifiableSet(deprecated);
60     private Map JavaDoc<XField,XField> fields = new HashMap JavaDoc<XField,XField>();
61
62     private Set JavaDoc<XMethod> methodsView = Collections
63             .unmodifiableSet(methods.keySet());
64
65     private Set JavaDoc<XField> fieldsView = Collections
66             .unmodifiableSet(fields.keySet());
67
68     private Set JavaDoc<XMethod> calledMethods = new HashSet JavaDoc<XMethod>();
69     private boolean calledMethodsIsInterned = false;
70
71     public void addCalledMethod(XMethod m) {
72         if (calledMethods.add(m) && !m.isResolved())
73             calledMethodsIsInterned = false;
74     }
75     
76     public boolean isCalled(XMethod m) {
77         if (!calledMethodsIsInterned) {
78             Set JavaDoc<XMethod> tmp = new HashSet JavaDoc<XMethod>();
79             for(XMethod m2 : calledMethods)
80                 tmp.add(intern(m2));
81             calledMethodsIsInterned = true;
82         }
83         return calledMethods.contains(m);
84     }
85     
86     public boolean isInterned(XMethod m) {
87         return methods.containsKey(m);
88     }
89
90     public @CheckReturnValue @NonNull XMethod intern(XMethod m) {
91         XMethod m2 = methods.get(m);
92         if (m2 != null) return m2;
93     
94         methods.put(m,m);
95         return m;
96     }
97
98     public @CheckReturnValue @NonNull XField intern(XField f) {
99         XField f2 = fields.get(f);
100         if (f2 != null) return f2;
101
102         fields.put(f,f);
103         return f;
104     }
105     public Set JavaDoc<XMethod> getMethods() {
106         return methodsView;
107     }
108
109     public Set JavaDoc<XField> getFields() {
110         return fieldsView;
111     }
112
113     /**
114      * Create an XMethod object from a BCEL Method.
115      *
116      * @param className the class to which the Method belongs
117      * @param method the Method
118      * @return an XMethod representing the Method
119      */

120     public static XMethod createXMethod(String JavaDoc className, Method method) {
121         XFactory xFactory = AnalysisContext.currentXFactory();
122         String JavaDoc methodName = method.getName();
123         String JavaDoc methodSig = method.getSignature();
124         int accessFlags = method.getAccessFlags();
125         boolean isStatic = method.isStatic();
126         XMethod m;
127         if (isStatic)
128             m = new StaticMethod(className, methodName, methodSig, accessFlags);
129         else
130             m = new InstanceMethod(className, methodName, methodSig, accessFlags);
131         
132         XMethod m2 = xFactory.intern(m);
133         // MUSTFIX: Check this
134
// assert m2.getAccessFlags() == m.getAccessFlags();
135
((AbstractMethod) m2).markAsResolved();
136         return m2;
137     }
138
139     /**
140      * Create an XMethod object from a BCEL Method.
141      *
142      * @param javaClass the class to which the Method belongs
143      * @param method the Method
144      * @return an XMethod representing the Method
145      */

146     public static XMethod createXMethod(JavaClass javaClass , Method method) {
147         return createXMethod(javaClass.getClassName(), method);
148     }
149     /**
150      * @param className
151      * @param methodName
152      * @param methodSig
153      * @param isStatic
154      * @return the created XMethod
155      */

156     public static XMethod createXMethod(String JavaDoc className, String JavaDoc methodName, String JavaDoc methodSig, boolean isStatic) {
157         XMethod m;
158         if (isStatic)
159             m = new StaticMethod(className, methodName, methodSig, Constants.ACC_STATIC);
160         else
161             m = new InstanceMethod(className, methodName, methodSig, 0);
162         XFactory xFactory = AnalysisContext.currentXFactory();
163         m = xFactory.intern(m);
164         m = xFactory.resolve(m);
165         return m;
166     }
167
168     public static XMethod createXMethod(MethodAnnotation ma) {
169         return createXMethod(ma.getClassName(), ma.getMethodName(), ma.getMethodSignature(), ma.isStatic());
170     }
171
172     static class RecursionDepth {
173        private static final int MAX_DEPTH = 50;
174      private int depth = 0;
175      ArrayList JavaDoc<Object JavaDoc> list = new ArrayList JavaDoc<Object JavaDoc>();
176      public String JavaDoc toString() {
177          return list.toString();
178      }
179      public void dump() {
180          System.out.println("Recursive calls" );
181          for(Object JavaDoc o : list)
182              System.out.println(" resolve " + o);
183      }
184      public boolean enter(Object JavaDoc value) {
185          if (depth > MAX_DEPTH)
186              return false;
187          if (DEBUG_CIRCULARITY) list.add(value);
188          depth++;
189          return true;
190      }
191      public void exit() {
192         depth--;
193         if (DEBUG_CIRCULARITY) list.remove(list.size()-1);
194         assert depth >= 0;
195      }
196     }
197     static ThreadLocal JavaDoc<RecursionDepth> recursionDepth = new ThreadLocal JavaDoc<RecursionDepth>() {
198         @Override JavaDoc
199         public RecursionDepth initialValue() {
200             return new RecursionDepth();
201         }
202     };
203     /**
204      * Create an XField object
205      *
206      * @param className
207      * @param fieldName
208      * @param fieldSignature
209      * @param isStatic
210      * @return the created XField
211      */

212     public static XField createXField(String JavaDoc className, String JavaDoc fieldName, String JavaDoc fieldSignature, boolean isStatic) {
213         XFactory xFactory =AnalysisContext.currentXFactory();
214         XField f;
215         
216         if (isStatic) {
217             int accessFlags = 0;
218             if (fieldName.toUpperCase().equals(fieldName))
219                 accessFlags = Constants.ACC_FINAL;
220             f = new StaticField(className, fieldName, fieldSignature, accessFlags);
221         }
222         else {
223             int accessFlags = 0;
224             if (fieldName.startsWith("this$")) accessFlags = Constants.ACC_FINAL;
225             f = new InstanceField(className, fieldName, fieldSignature, accessFlags);
226         }
227         f = xFactory.intern(f);
228         f = xFactory.resolve(f);
229         return f;
230     }
231     
232     public static boolean DEBUG_CIRCULARITY = SystemProperties.getBoolean("circularity.debug");
233     /**
234      * @param f
235      * @return
236      */

237     private @NonNull XField resolve(XField f) {
238         if (f.isResolved()) return f;
239         if (f.isStatic()) return f;
240         if (f.getName().startsWith("this$")) return f;
241         try {
242             if (!recursionDepth.get().enter(f)) {
243                 fail("recursive cycle trying to resolve " + f, null, null);
244                 return f;
245             }
246
247             XField f2 = f;
248             String JavaDoc classname = f.getClassName();
249             try {
250                 JavaClass superClass = Repository.lookupClass(classname).getSuperClass();
251                 if (superClass == null) return f;
252                 
253                 if (classname.equals(superClass.getClassName())) return f;
254                 f2 = createXField(superClass.getClassName(), f.getName(), f.getSignature(), f.isStatic());
255                 f2 = intern(f2);
256                 if (f2.isResolved()) {
257                     fields.put(f, f2);
258                     return f2;
259                 }
260                
261
262             } catch (ClassNotFoundException JavaDoc e) {
263                 AnalysisContext.reportMissingClass(e);
264             }
265             return f;
266         } finally {
267             recursionDepth.get().exit();
268         }
269     }
270
271     private static void fail(String JavaDoc s, JavaClass jClass, JavaClass superClass) {
272          AnalysisContext.logError(s);
273         if (DEBUG_CIRCULARITY) {
274             System.out.println(s);
275             recursionDepth.get().dump();
276             
277         }
278         if (jClass != null)
279             System.out.println(jClass);
280         if (superClass != null)
281             System.out.println(superClass);
282         System.exit(1);
283     }
284     /**
285      * If a method is not marked as resolved, look in superclasses to see if the method can be found there.
286      * Return whatever method is found.
287      * @param m
288      * @return
289      */

290     private @NonNull XMethod resolve(XMethod m) {
291         if (m.isResolved()) return m;
292         // if (m.isStatic()) return m;
293
try {
294             if (!recursionDepth.get().enter(m)) {
295                 fail("recursive cycle trying to resolve " + m, null, null);
296                 return m;
297             }
298
299             String JavaDoc className = m.getClassName();
300
301             String JavaDoc methodName = m.getName();
302             if (className.charAt(0)=='[' || methodName.equals("<init>") || methodName.equals("<clinit>") || methodName.startsWith("access$")) {
303                 ((AbstractMethod)m).markAsResolved();
304                 return m;
305             }
306             try {
307                 JavaClass javaClass = Repository.lookupClass(className);
308                 if (!javaClass.getClassName().equals(className)) {
309                     fail("Looked up " + className + ", got a class named " + javaClass.getClassName(), javaClass, null);
310                     return m;
311                 }
312                 JavaClass superClass = javaClass.getSuperClass();
313                 if (superClass == null) return m;
314                 String JavaDoc superClassName = superClass.getClassName();
315                 if (!javaClass.getSuperclassName().equals(superClassName))
316                     fail("requested superclass of " + className + ", expecting to get " + javaClass.getSuperclassName()
317                             + ", instead got " + superClassName, javaClass, superClass);
318                 if (superClass.getSuperclassName().equals(className)
319                         || className.equals(superClassName)) {
320                     fail("superclass of " + className + " is " + superClassName, javaClass, superClass);
321                     return m;
322                 }
323                 XMethod m2 = createXMethod(superClassName, methodName, m.getSignature(), m.isStatic());
324                 if (m2.isResolved()) {
325                     methods.put(m, m2);
326                     return m2;
327                 }
328             } catch (ClassNotFoundException JavaDoc e) {
329                 AnalysisContext.reportMissingClass(e);
330             }
331             // ((AbstractMethod)m).markAsResolved();
332
return m;
333         } finally {
334             recursionDepth.get().exit();
335         }
336
337     }
338
339     public static XField createXField(FieldInstruction fieldInstruction, ConstantPoolGen cpg) {
340         String JavaDoc className = fieldInstruction.getClassName(cpg);
341         String JavaDoc fieldName = fieldInstruction.getName(cpg);
342         String JavaDoc fieldSig = fieldInstruction.getSignature(cpg);
343
344         int opcode = fieldInstruction.getOpcode();
345         return createXField(className, fieldName, fieldSig, opcode == Constants.GETSTATIC
346                 || opcode == Constants.PUTSTATIC );
347     }
348     public static XField createReferencedXField(DismantleBytecode visitor) {
349         return createXField(visitor.getDottedClassConstantOperand(),
350                 visitor.getNameConstantOperand(),
351                 visitor.getSigConstantOperand(),
352                  visitor.getRefFieldIsStatic());
353     }
354     public static XMethod createReferencedXMethod(DismantleBytecode visitor) {
355         return createXMethod(visitor.getDottedClassConstantOperand(),
356                 visitor.getNameConstantOperand(),
357                 visitor.getSigConstantOperand(),
358                  visitor.getOpcode() == Constants.INVOKESTATIC);
359     }
360
361     public static XField createXField(FieldAnnotation f) {
362         return createXField(f.getClassName(), f.getFieldName(), f.getFieldSignature(), f.isStatic());
363     }
364     
365     public static XField createXField(JavaClass javaClass, Field field) {
366         return createXField(javaClass.getClassName(), field);
367     }
368     /**
369      * Create an XField object from a BCEL Field.
370      *
371      * @param className the name of the Java class containing the field
372      * @param field the Field within the JavaClass
373      * @return the created XField
374      */

375     public static XField createXField(String JavaDoc className, Field field) {
376         String JavaDoc fieldName = field.getName();
377         String JavaDoc fieldSig = field.getSignature();
378         int accessFlags = field.getAccessFlags();
379         XFactory xFactory = AnalysisContext.currentXFactory();
380         XField f;
381         if (field.isStatic())
382             f = new StaticField(className, fieldName, fieldSig, accessFlags);
383         else
384             f = new InstanceField(className, fieldName, fieldSig, accessFlags);
385         XField f2 = xFactory.intern(f);
386         // MUSTFIX: investigate
387
// assert f.getAccessFlags() == f2.getAccessFlags();
388
((AbstractField) f2).markAsResolved();
389         return f2;
390     }
391     /**
392      * Create an XMethod object from an InvokeInstruction.
393      *
394      * @param invokeInstruction the InvokeInstruction
395      * @param cpg ConstantPoolGen from the class containing the instruction
396      * @return XMethod representing the method called by the InvokeInstruction
397      */

398     public static XMethod createXMethod(InvokeInstruction invokeInstruction, ConstantPoolGen cpg) {
399         String JavaDoc className = invokeInstruction.getClassName(cpg);
400         String JavaDoc methodName = invokeInstruction.getName(cpg);
401         String JavaDoc methodSig = invokeInstruction.getSignature(cpg);
402
403         return createXMethod(className, methodName, methodSig, invokeInstruction.getOpcode() == Constants.INVOKESTATIC);
404     }
405     
406     /**
407      * Create an XMethod object from the method currently being visited by
408      * the given PreorderVisitor.
409      *
410      * @param visitor the PreorderVisitor
411      * @return the XMethod representing the method currently being visited
412      */

413     public static XMethod createXMethod(PreorderVisitor visitor) {
414         JavaClass javaClass = visitor.getThisClass();
415         Method method = visitor.getMethod();
416         XMethod m = createXMethod(javaClass, method);
417         return m;
418     }
419     
420     /**
421      * Create an XField object from the field currently being visited by
422      * the given PreorderVisitor.
423      *
424      * @param visitor the PreorderVisitor
425      * @return the XField representing the method currently being visited
426      */

427     public static XField createXField(PreorderVisitor visitor) {
428         JavaClass javaClass = visitor.getThisClass();
429         Field field = visitor.getField();
430         XField f = createXField(javaClass, field);
431         return f;
432     }
433     
434     public static XMethod createXMethod(MethodGen methodGen) {
435         return createXMethod(methodGen.getClassName(), methodGen.getMethod());
436         
437     }
438
439     /**
440      * @param m
441      */

442     public void deprecate(ClassMember m) {
443         deprecated.add(m);
444         
445     }
446     public Set JavaDoc<? extends ClassMember> getDeprecated() {
447         return deprecatedView;
448     }
449
450 }
451
Popular Tags