KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > jdt > internal > corext > callhierarchy > CalleeAnalyzerVisitor


1 /*******************************************************************************
2  * Copyright (c) 2000, 2006 IBM Corporation and others.
3  * All rights reserved. This program and the accompanying materials
4  * are made available under the terms of the Eclipse Public License v1.0
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/epl-v10.html
7  *
8  * Contributors:
9  * Jesper Kamstrup Linnet (eclipse@kamstrup-linnet.dk) - initial API and implementation
10  * (report 36180: Callers/Callees view)
11  *******************************************************************************/

12 package org.eclipse.jdt.internal.corext.callhierarchy;
13
14 import java.util.Collection JavaDoc;
15 import java.util.Map JavaDoc;
16
17 import org.eclipse.core.runtime.IProgressMonitor;
18 import org.eclipse.core.runtime.OperationCanceledException;
19
20 import org.eclipse.jdt.core.IMember;
21 import org.eclipse.jdt.core.IMethod;
22 import org.eclipse.jdt.core.ISourceRange;
23 import org.eclipse.jdt.core.IType;
24 import org.eclipse.jdt.core.JavaModelException;
25 import org.eclipse.jdt.core.dom.ASTNode;
26 import org.eclipse.jdt.core.dom.ASTVisitor;
27 import org.eclipse.jdt.core.dom.AnonymousClassDeclaration;
28 import org.eclipse.jdt.core.dom.ClassInstanceCreation;
29 import org.eclipse.jdt.core.dom.CompilationUnit;
30 import org.eclipse.jdt.core.dom.ConstructorInvocation;
31 import org.eclipse.jdt.core.dom.IMethodBinding;
32 import org.eclipse.jdt.core.dom.ITypeBinding;
33 import org.eclipse.jdt.core.dom.MethodDeclaration;
34 import org.eclipse.jdt.core.dom.MethodInvocation;
35 import org.eclipse.jdt.core.dom.SuperConstructorInvocation;
36 import org.eclipse.jdt.core.dom.SuperMethodInvocation;
37 import org.eclipse.jdt.core.search.IJavaSearchScope;
38
39 import org.eclipse.jdt.internal.corext.dom.Bindings;
40 import org.eclipse.jdt.internal.corext.util.JavaModelUtil;
41
42 import org.eclipse.jdt.internal.ui.JavaPlugin;
43
44 class CalleeAnalyzerVisitor extends ASTVisitor {
45     private CallSearchResultCollector fSearchResults;
46     private IMethod fMethod;
47     private CompilationUnit fCompilationUnit;
48     private IProgressMonitor fProgressMonitor;
49     private int fMethodEndPosition;
50     private int fMethodStartPosition;
51
52     CalleeAnalyzerVisitor(IMethod method, CompilationUnit compilationUnit, IProgressMonitor progressMonitor) {
53         fSearchResults = new CallSearchResultCollector();
54         this.fMethod = method;
55         this.fCompilationUnit= compilationUnit;
56         this.fProgressMonitor = progressMonitor;
57
58         try {
59             ISourceRange sourceRange = method.getSourceRange();
60             this.fMethodStartPosition = sourceRange.getOffset();
61             this.fMethodEndPosition = fMethodStartPosition + sourceRange.getLength();
62         } catch (JavaModelException jme) {
63             JavaPlugin.log(jme);
64         }
65     }
66
67     /**
68      * Method getCallees.
69      *
70      * @return CallerElement
71      */

72     public Map JavaDoc getCallees() {
73         return fSearchResults.getCallers();
74     }
75
76     /* (non-Javadoc)
77      * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.ClassInstanceCreation)
78      */

79     public boolean visit(ClassInstanceCreation node) {
80         progressMonitorWorked(1);
81         if (!isFurtherTraversalNecessary(node)) {
82             return false;
83         }
84
85         if (isNodeWithinMethod(node)) {
86             addMethodCall(node.resolveConstructorBinding(), node);
87         }
88
89         return true;
90     }
91
92     /**
93      * Find all constructor invocations (<code>this(...)</code>) from the called method.
94      * Since we only traverse into the AST on the wanted method declaration, this method
95      * should not hit on more constructor invocations than those in the wanted method.
96      *
97      * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.ConstructorInvocation)
98      */

99     public boolean visit(ConstructorInvocation node) {
100         progressMonitorWorked(1);
101         if (!isFurtherTraversalNecessary(node)) {
102             return false;
103         }
104
105         if (isNodeWithinMethod(node)) {
106             addMethodCall(node.resolveConstructorBinding(), node);
107         }
108
109         return true;
110     }
111
112     /**
113      * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.MethodDeclaration)
114      */

115     public boolean visit(MethodDeclaration node) {
116         progressMonitorWorked(1);
117         return isFurtherTraversalNecessary(node);
118     }
119
120     /**
121      * Find all method invocations from the called method. Since we only traverse into
122      * the AST on the wanted method declaration, this method should not hit on more
123      * method invocations than those in the wanted method.
124      *
125      * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.MethodInvocation)
126      */

127     public boolean visit(MethodInvocation node) {
128         progressMonitorWorked(1);
129         if (!isFurtherTraversalNecessary(node)) {
130             return false;
131         }
132
133         if (isNodeWithinMethod(node)) {
134             addMethodCall(node.resolveMethodBinding(), node);
135         }
136
137         return true;
138     }
139
140     /**
141      * Find invocations of the supertype's constructor from the called method
142      * (=constructor). Since we only traverse into the AST on the wanted method
143      * declaration, this method should not hit on more method invocations than those in
144      * the wanted method.
145      *
146      * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.SuperConstructorInvocation)
147      */

148     public boolean visit(SuperConstructorInvocation node) {
149         progressMonitorWorked(1);
150         if (!isFurtherTraversalNecessary(node)) {
151             return false;
152         }
153
154         if (isNodeWithinMethod(node)) {
155             addMethodCall(node.resolveConstructorBinding(), node);
156         }
157         
158         return true;
159     }
160
161     /**
162      * Find all method invocations from the called method. Since we only traverse into
163      * the AST on the wanted method declaration, this method should not hit on more
164      * method invocations than those in the wanted method.
165      *
166      * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.MethodInvocation)
167      */

168     public boolean visit(SuperMethodInvocation node) {
169         progressMonitorWorked(1);
170         if (!isFurtherTraversalNecessary(node)) {
171             return false;
172         }
173
174         if (isNodeWithinMethod(node)) {
175             addMethodCall(node.resolveMethodBinding(), node);
176         }
177         
178         return true;
179     }
180     
181     /**
182      * When an anonymous class declaration is reached, the traversal should not go further since it's not
183      * supposed to consider calls inside the anonymous inner class as calls from the outer method.
184      *
185      * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.AnonymousClassDeclaration)
186      */

187     public boolean visit(AnonymousClassDeclaration node) {
188         return isNodeEnclosingMethod(node);
189     }
190
191
192     /**
193      * Adds the specified method binding to the search results.
194      *
195      * @param calledMethodBinding
196      * @param node
197      */

198     protected void addMethodCall(IMethodBinding calledMethodBinding, ASTNode node) {
199         try {
200             if (calledMethodBinding != null) {
201                 fProgressMonitor.worked(1);
202
203                 ITypeBinding calledTypeBinding = calledMethodBinding.getDeclaringClass();
204                 IType calledType = null;
205
206                 if (!calledTypeBinding.isAnonymous()) {
207                     calledType = (IType) calledTypeBinding.getJavaElement();
208                 } else {
209                     if (!"java.lang.Object".equals(calledTypeBinding.getSuperclass().getQualifiedName())) { //$NON-NLS-1$
210
calledType= (IType) calledTypeBinding.getSuperclass().getJavaElement();
211                     } else {
212                         calledType = (IType) calledTypeBinding.getInterfaces()[0].getJavaElement();
213                     }
214                 }
215
216                 IMethod calledMethod = findIncludingSupertypes(calledMethodBinding,
217                         calledType, fProgressMonitor);
218
219                 IMember referencedMember= null;
220                 if (calledMethod == null) {
221                     if (calledMethodBinding.isConstructor() && calledMethodBinding.getParameterTypes().length == 0) {
222                         referencedMember= calledType;
223                     }
224                 } else {
225                     if (calledType.isInterface()) {
226                         calledMethod = findImplementingMethods(calledMethod);
227                     }
228
229                     if (!isIgnoredBySearchScope(calledMethod)) {
230                         referencedMember= calledMethod;
231                     }
232                 }
233                 final int position= node.getStartPosition();
234                 final int number= fCompilationUnit.getLineNumber(position);
235                 fSearchResults.addMember(fMethod, referencedMember, position, position + node.getLength(), number < 1 ? 1 : number);
236             }
237         } catch (JavaModelException jme) {
238             JavaPlugin.log(jme);
239         }
240     }
241     
242     private static IMethod findIncludingSupertypes(IMethodBinding method, IType type, IProgressMonitor pm) throws JavaModelException {
243         IMethod inThisType= Bindings.findMethod(method, type);
244         if (inThisType != null)
245             return inThisType;
246         IType[] superTypes= JavaModelUtil.getAllSuperTypes(type, pm);
247         for (int i= 0; i < superTypes.length; i++) {
248             IMethod m= Bindings.findMethod(method, superTypes[i]);
249             if (m != null)
250                 return m;
251         }
252         return null;
253     }
254
255     private boolean isIgnoredBySearchScope(IMethod enclosingElement) {
256         if (enclosingElement != null) {
257             return !getSearchScope().encloses(enclosingElement);
258         } else {
259             return false;
260         }
261     }
262
263     private IJavaSearchScope getSearchScope() {
264         return CallHierarchy.getDefault().getSearchScope();
265     }
266
267     private boolean isNodeWithinMethod(ASTNode node) {
268         int nodeStartPosition = node.getStartPosition();
269         int nodeEndPosition = nodeStartPosition + node.getLength();
270
271         if (nodeStartPosition < fMethodStartPosition) {
272             return false;
273         }
274
275         if (nodeEndPosition > fMethodEndPosition) {
276             return false;
277         }
278
279         return true;
280     }
281
282     private boolean isNodeEnclosingMethod(ASTNode node) {
283         int nodeStartPosition = node.getStartPosition();
284         int nodeEndPosition = nodeStartPosition + node.getLength();
285
286         if (nodeStartPosition < fMethodStartPosition && nodeEndPosition > fMethodEndPosition) {
287             // Is the method completely enclosed by the node?
288
return true;
289         }
290         return false;
291     }
292     
293     private boolean isFurtherTraversalNecessary(ASTNode node) {
294         return isNodeWithinMethod(node) || isNodeEnclosingMethod(node);
295     }
296
297     private IMethod findImplementingMethods(IMethod calledMethod) {
298         Collection JavaDoc implementingMethods = CallHierarchy.getDefault()
299                                                         .getImplementingMethods(calledMethod);
300
301         if ((implementingMethods.size() == 0) || (implementingMethods.size() > 1)) {
302             return calledMethod;
303         } else {
304             return (IMethod) implementingMethods.iterator().next();
305         }
306     }
307     
308     private void progressMonitorWorked(int work) {
309         if (fProgressMonitor != null) {
310             fProgressMonitor.worked(work);
311             if (fProgressMonitor.isCanceled()) {
312                 throw new OperationCanceledException();
313             }
314         }
315     }
316 }
317
Popular Tags