Docjar: A Java Source and Docuemnt Enginecom.*    java.*    javax.*    org.*    all    new    plug-in

Quick Search    Search Deep

Source code: com/port80/eclipse/jdt/graph/MethodReferenceASTVisitor.java


1   package com.port80.eclipse.jdt.graph;
2   
3   import java.util.HashMap;
4   import java.util.HashSet;
5   import java.util.Iterator;
6   import java.util.List;
7   import java.util.Map;
8   import java.util.Set;
9   import java.util.Stack;
10  
11  import org.eclipse.jdt.core.dom.ASTNode;
12  import org.eclipse.jdt.core.dom.ASTVisitor;
13  import org.eclipse.jdt.core.dom.ArrayType;
14  import org.eclipse.jdt.core.dom.ClassInstanceCreation;
15  import org.eclipse.jdt.core.dom.Expression;
16  import org.eclipse.jdt.core.dom.FieldAccess;
17  import org.eclipse.jdt.core.dom.IBinding;
18  import org.eclipse.jdt.core.dom.IMethodBinding;
19  import org.eclipse.jdt.core.dom.ITypeBinding;
20  import org.eclipse.jdt.core.dom.MethodDeclaration;
21  import org.eclipse.jdt.core.dom.MethodInvocation;
22  import org.eclipse.jdt.core.dom.Name;
23  import org.eclipse.jdt.core.dom.PackageDeclaration;
24  import org.eclipse.jdt.core.dom.QualifiedName;
25  import org.eclipse.jdt.core.dom.SimpleName;
26  import org.eclipse.jdt.core.dom.SimpleType;
27  import org.eclipse.jdt.core.dom.SuperConstructorInvocation;
28  import org.eclipse.jdt.core.dom.SuperMethodInvocation;
29  import org.eclipse.jdt.core.dom.ThisExpression;
30  import org.eclipse.jdt.core.dom.TypeDeclaration;
31  
32  import com.port80.util.Msg;
33  
34  /**
35   * Find method referenced in a given CompilationUnit.
36   * 
37   * @author chrisl
38   */
39  public class MethodReferenceASTVisitor extends ASTVisitor {
40  
41    ////////////////////////////////////////////////////////////////////////
42  
43    private static final String NAME = "MethodReferenceASTVisitor";
44    private static final boolean DEBUG = true;
45    private static final boolean TERSE = false;
46  
47    public static class Result {
48      /** 
49       * Declared types. FullyQualifiedName->ITypeBinding mapping.
50       */
51      public Set fDeclares;
52      /**
53       * Methods declared in this unit.
54       */
55      public Set fMethods;
56      /** 
57       * Super classes.  Fully qualified typename -> ITypeBinding.
58       */
59      public Map fSuperClasses;
60      /** 
61       * FullQualifiedName->ITypeBinding mapping.
62       */
63      public Map fSuperInterfaces;
64      /** 
65       * Referenced types. Source TypeWrapper ->Set(Dest. TypeWrapper )mapping.
66       */
67      public Map fReferences;
68      /** 
69       * Caller(TypeWrapper/MethodWrapper)->Set(callee(MethodWrapper)) mapping.
70       */
71      public Map fCalls;
72  
73      /** Stack of TypeWrapper for type being declared.*/
74      private Stack fTypeStack;
75      /** Stack of MethodWrapper for method being declared.*/
76      private Stack fMethodStack;
77  
78      public Result() {
79        fReferences = new HashMap();
80        fSuperClasses = new HashMap();
81        fSuperInterfaces = new HashMap();
82        fDeclares = new HashSet();
83        fMethods = new HashSet();
84        fCalls = new HashMap();
85        fTypeStack = new Stack();
86        fMethodStack = new Stack();
87      }
88      public Set getDeclares() {
89        return fDeclares;
90      }
91      public Map getSuperClasses() {
92        return fSuperClasses;
93      }
94      public Map getReferences() {
95        return fReferences;
96      }
97      public Map getSuperInterfaces() {
98        return fSuperInterfaces;
99      }
100     public Set getMethods() {
101       return fMethods;
102     }
103     public Map getCalls() {
104       return fCalls;
105     }
106     public void declareTypeStart(ITypeBinding type) {
107       if (type == null) {
108         Msg.err(NAME + ".declareTypeStart(): type==null");
109         return;
110       }
111       TypeWrapper wrapper = new TypeWrapper(type);
112       fTypeStack.push(wrapper);
113     }
114     public void declareTypeEnd(ITypeBinding type) {
115       if (type != null)
116         fTypeStack.pop();
117     }
118     public void declareMethodStart(IMethodBinding method) {
119       if (method == null) {
120         Msg.err(NAME + ".declareMethodStart(): method==null");
121         return;
122       }
123       MethodWrapper wrapper = new MethodWrapper(method);
124       fMethodStack.push(wrapper);
125       fMethods.add(wrapper);
126       if (DEBUG)
127         Msg.println(NAME + ".declareMethod(): " + wrapper.getNotSoSimpleSignature());
128     }
129     public void declareMethodEnd(IMethodBinding method) {
130       if (method != null)
131         fMethodStack.pop();
132     }
133     public TypeWrapper getCurrentType() {
134       if (fTypeStack.isEmpty())
135         return null;
136       return (TypeWrapper) fTypeStack.peek();
137     }
138     public MethodWrapper getCurrentMethod() {
139       if (fMethodStack.isEmpty())
140         return null;
141       return (MethodWrapper) fMethodStack.peek();
142     }
143     public void addCall(IMethodBinding method) {
144       MethodWrapper callee = new MethodWrapper(method);
145       MethodWrapper caller = null;
146       if (!fMethodStack.isEmpty())
147         caller = (MethodWrapper) fMethodStack.peek();
148       if (caller != null) {
149         Set callees = (Set) fCalls.get(caller);
150         if (callees == null) {
151           callees = new HashSet();
152           fCalls.put(caller, callees);
153         }
154         callees.add(callee);
155         if (DEBUG)
156           Msg.println(
157             NAME
158               + ".Result.addCall(): method:\n\tcaller="
159               + caller.getNotSoSimpleSignature()
160               + "\n\tcallee="
161               + callee.getNotSoSimpleSignature());
162       } else {
163         TypeWrapper type = (TypeWrapper) fTypeStack.peek();
164         Set callees = (Set) fCalls.get(type);
165         if (callees == null) {
166           callees = new HashSet();
167           fCalls.put(type, callees);
168         }
169         callees.add(callee);
170         if (DEBUG)
171           Msg.println(
172             NAME
173               + ".Result.addCall(): type:\n\ttype="
174               + type.getFullName()
175               + "\n\tcallee="
176               + callee.getNotSoSimpleSignature());
177       }
178     }
179     public void addReference(ITypeBinding type) {
180       TypeWrapper referencee = new TypeWrapper(type);
181       TypeWrapper referer = getCurrentType();
182       if (referer == null) {
183         Msg.err("No caller");
184         return;
185       }
186       Set referencees = (Set) fReferences.get(referer);
187       if (referencees == null) {
188         referencees = new HashSet();
189         fReferences.put(referer, referencees);
190       }
191       referencees.add(referencee);
192       if (DEBUG)
193         Msg.println(
194           NAME
195             + ".Result.addReference(): referer\n\treferer="
196             + referer.getFullName()
197             + "\n\treferencee="
198             + referencee.getFullName());
199     }
200   }
201 
202   private Result fResult;
203 
204   ////////////////////////////////////////////////////////////////////////
205 
206   /**
207    * @return Type references in a (String fullTypeName) -> (ITypeBinding type) hash.
208    */
209   public static MethodReferenceASTVisitor startAt(ASTNode root) {
210     MethodReferenceASTVisitor visitor = new MethodReferenceASTVisitor();
211     root.accept(visitor);
212     return visitor;
213   }
214 
215   public Result getResult() {
216     return fResult;
217   }
218 
219   public MethodReferenceASTVisitor() {
220     fResult = new Result();
221   }
222 
223   private ITypeBinding addDeclaredType(Name node) {
224     ITypeBinding type = resolveType(node);
225     if (type == null) {
226       Msg.err(NAME + ".addDeclaredType(): type==null: node=" + node);
227     } else {
228       fResult.fDeclares.add(new TypeWrapper(type));
229     }
230     return type;
231   }
232 
233   private IMethodBinding addCall(Name node) {
234     IMethodBinding binding = resolveMethod(node);
235     if (binding != null)
236       fResult.addCall(binding);
237     else
238       Msg.err(NAME + ".addCall(): binding==null: node=" + node);
239     return binding;
240   }
241 
242   private ITypeBinding resolveType(Name node) {
243     while (node != null) {
244       IBinding binding = node.resolveBinding();
245       if (DEBUG)
246         Msg.println(NAME + ".resolveType(): " + node);
247       if (binding != null && binding.getKind() == IBinding.TYPE) {
248         return (ITypeBinding) binding;
249       }
250       if (node.isQualifiedName())
251         node = ((QualifiedName) node).getQualifier();
252     }
253     return null;
254   }
255 
256   /**
257    * If a nested type is referenced, only the nested type is counted.
258    * Its enclosing type is not counted.
259    */
260   private ITypeBinding typeRefFound(Name node) {
261     if (DEBUG)
262       System.err.println(NAME + ".typeRefFound(): " + node);
263     while (node != null) {
264       IBinding binding = node.resolveBinding();
265       if (binding != null && binding.getKind() == IBinding.TYPE) {
266         fResult.addReference((ITypeBinding) binding);
267         return (ITypeBinding) binding;
268       }
269       if (node.isQualifiedName())
270         node = ((QualifiedName) node).getQualifier();
271       else
272         break;
273     }
274     return null;
275   }
276 
277   private void possibleTypeRefFound(Name node) {
278     if (DEBUG)
279       System.err.println(NAME + ".possibleTypeRefFound(): " + node);
280     while (node != null) {
281       IBinding binding = node.resolveBinding();
282       if (binding != null && binding.getKind() == IBinding.TYPE) {
283         fResult.addReference((ITypeBinding) binding);
284         break;
285       }
286       if (node.isQualifiedName())
287         node = ((QualifiedName) node).getQualifier();
288       else
289         break;
290     }
291   }
292 
293   ////////////////////////////////////////////////////////////////////////
294 
295   private IMethodBinding resolveMethod(Name node) {
296     if (node == null)
297       return null;
298     // A more general call to resolve binding.
299     // getAST().getBindingResolver().resolveConstructor(node);
300     IBinding binding = node.resolveBinding();
301     if (DEBUG) {
302       System.err.println(NAME + ".resolveMethod(): node=" + node);
303     }
304     if (binding != null && binding.getKind() == IBinding.METHOD) {
305       return (IMethodBinding) binding;
306     } else {
307       Msg.err(NAME + ".resolveMethod(): can't resolve method: node=" + node + ", binding=" + binding);
308     }
309     return null;
310   }
311 
312   ////////////////////////////////////////////////////////////////////////
313 
314   private void visitChildren(List elements) {
315     int nElements = elements.size();
316     for (int i = 0; i < nElements; i++) {
317       ((ASTNode) elements.get(i)).accept(this);
318     }
319   }
320 
321   ////////////////////////////////////////////////////////////////////////
322 
323   /*
324    * @see ASTVisitor#visit(ArrayType)
325    */
326   public boolean visit(ArrayType node) {
327     node.getElementType().accept(this);
328     return false;
329   }
330 
331   /*
332    * @see ASTVisitor#visit(SimpleType)
333    */
334   public boolean visit(SimpleType node) {
335     typeRefFound(node.getName());
336     return false;
337   }
338 
339   /*
340    * @see ASTVisitor#visit(QualifiedName)
341    */
342   public boolean visit(QualifiedName node) {
343     possibleTypeRefFound(node); // possible ref
344     return false;
345   }
346 
347   /*
348    * @see ASTVisitor#visit(PackageDeclaration)
349    */
350   public boolean visit(PackageDeclaration node) {
351     return false;
352   }
353 
354   /*
355    * @see ASTVisitor#visit(ThisExpression)
356    */
357   public boolean visit(ThisExpression node) {
358     typeRefFound(node.getQualifier());
359     return false;
360   }
361 
362   private void evalQualifyingExpression(Expression expr) {
363     if (expr != null) {
364       if (expr instanceof Name) {
365         possibleTypeRefFound((Name) expr);
366       } else {
367         expr.accept(this);
368       }
369     }
370   }
371 
372   /*
373    * @see ASTVisitor#visit(ClassInstanceCreation)
374    */
375   public boolean visit(ClassInstanceCreation node) {
376     typeRefFound(node.getName());
377     evalQualifyingExpression(node.getExpression());
378     //
379     IMethodBinding method = node.resolveConstructorBinding();
380     if (method == null) {
381       Msg.err(NAME + ".visit(ClassInstanceCreation): method==null: node=" + node);
382     } else {
383       fResult.addCall(method);
384     }
385     //
386     if (node.getAnonymousClassDeclaration() != null) {
387       node.getAnonymousClassDeclaration().accept(this);
388     }
389     visitChildren(node.arguments());
390     return false;
391   }
392 
393   /*
394    * @see ASTVisitor#endVisit(MethodInvocation)
395    */
396   public boolean visit(MethodInvocation node) {
397     if (DEBUG)
398       System.err.println(NAME + ".visit(MethodInvocation): node=" + node);
399     evalQualifyingExpression(node.getExpression());
400     addCall(node.getName());
401     visitChildren(node.arguments());
402     return false;
403   }
404 
405   /*
406    * @see ASTVisitor#visit(SuperConstructorInvocation)
407    */
408   public boolean visit(SuperConstructorInvocation node) {
409     evalQualifyingExpression(node.getExpression());
410     //
411     IMethodBinding method = node.resolveConstructorBinding();
412     if (method == null) {
413       Msg.err(NAME + ".visit(SuperConstructorInvocation): method==null: node=" + node);
414     } else {
415       fResult.addCall(method);
416     }
417     //
418     visitChildren(node.arguments());
419     return false;
420   }
421 
422   public boolean visit(SuperMethodInvocation node) {
423     addCall(node.getName());
424     //
425     visitChildren(node.arguments());
426     return false;
427   }
428   /*
429    * @see ASTVisitor#visit(FieldAccess)
430    */
431   public boolean visit(FieldAccess node) {
432     evalQualifyingExpression(node.getExpression());
433     return false;
434   }
435 
436   /*
437    * @see ASTVisitor#visit(SimpleName)
438    */
439   public boolean visit(SimpleName node) {
440     // if the call gets here, it can only be a variable reference
441     return false;
442   }
443 
444   /*
445    * @see ASTVisitor#visit(TypeDeclaration)
446    */
447   public boolean visit(TypeDeclaration node) {
448     ITypeBinding type = addDeclaredType(node.getName());
449     fResult.declareTypeStart(type);
450     visitChildren(node.bodyDeclarations());
451     fResult.declareTypeEnd(type);
452     return false;
453   }
454 
455   /*
456    * @see ASTVisitor#visit(MethodDeclaration)
457    */
458   public boolean visit(MethodDeclaration node) {
459     if (!node.isConstructor()) {
460       node.getReturnType().accept(this);
461     }
462     visitChildren(node.parameters());
463     Iterator iter = node.thrownExceptions().iterator();
464     while (iter.hasNext()) {
465       typeRefFound((Name) iter.next());
466     }
467     IMethodBinding method = resolveMethod(node.getName());
468     if (method == null) {
469       Msg.err(NAME + ".visit(MethodDeclaration(): method==null: node=" + node);
470     } else {
471       fResult.declareMethodStart(method);
472     }
473     if (node.getBody() != null) {
474       node.getBody().accept(this);
475     }
476     fResult.declareMethodEnd(method);
477     return false;
478   }
479 
480   /*
481    * @see ASTVisitor#preVisit(ASTNode)
482    */
483   public void preVisit(ASTNode node) {
484     if ((node.getFlags() & ASTNode.MALFORMED) != 0) {
485       throw new ASTError(node);
486     }
487   }
488 
489   ////////////////////////////////////////////////////////////////////////
490 
491 }