KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > jdt > internal > corext > dom > ScopeAnalyzer


1 /*******************************************************************************
2  * Copyright (c) 2000, 2007 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  * IBM Corporation - initial API and implementation
10  *******************************************************************************/

11 package org.eclipse.jdt.internal.corext.dom;
12
13 import java.util.ArrayList JavaDoc;
14 import java.util.Collection JavaDoc;
15 import java.util.HashSet JavaDoc;
16 import java.util.List JavaDoc;
17
18 import org.eclipse.jdt.core.dom.AST;
19 import org.eclipse.jdt.core.dom.ASTNode;
20 import org.eclipse.jdt.core.dom.AbstractTypeDeclaration;
21 import org.eclipse.jdt.core.dom.AnonymousClassDeclaration;
22 import org.eclipse.jdt.core.dom.Block;
23 import org.eclipse.jdt.core.dom.BodyDeclaration;
24 import org.eclipse.jdt.core.dom.CatchClause;
25 import org.eclipse.jdt.core.dom.ClassInstanceCreation;
26 import org.eclipse.jdt.core.dom.CompilationUnit;
27 import org.eclipse.jdt.core.dom.Expression;
28 import org.eclipse.jdt.core.dom.FieldAccess;
29 import org.eclipse.jdt.core.dom.ForStatement;
30 import org.eclipse.jdt.core.dom.IBinding;
31 import org.eclipse.jdt.core.dom.IMethodBinding;
32 import org.eclipse.jdt.core.dom.ITypeBinding;
33 import org.eclipse.jdt.core.dom.IVariableBinding;
34 import org.eclipse.jdt.core.dom.ImportDeclaration;
35 import org.eclipse.jdt.core.dom.Initializer;
36 import org.eclipse.jdt.core.dom.MethodDeclaration;
37 import org.eclipse.jdt.core.dom.MethodInvocation;
38 import org.eclipse.jdt.core.dom.Modifier;
39 import org.eclipse.jdt.core.dom.QualifiedName;
40 import org.eclipse.jdt.core.dom.SimpleName;
41 import org.eclipse.jdt.core.dom.Statement;
42 import org.eclipse.jdt.core.dom.SuperMethodInvocation;
43 import org.eclipse.jdt.core.dom.SwitchCase;
44 import org.eclipse.jdt.core.dom.SwitchStatement;
45 import org.eclipse.jdt.core.dom.Type;
46 import org.eclipse.jdt.core.dom.TypeDeclarationStatement;
47 import org.eclipse.jdt.core.dom.TypeParameter;
48 import org.eclipse.jdt.core.dom.VariableDeclaration;
49 import org.eclipse.jdt.core.dom.VariableDeclarationExpression;
50 import org.eclipse.jdt.core.dom.VariableDeclarationStatement;
51
52 import org.eclipse.jdt.internal.ui.text.correction.ASTResolving;
53
54 /**
55  * Evaluates all fields, methods and types available (declared) at a given offset
56  * in a compilation unit (Code assist that returns IBindings)
57  */

58 public class ScopeAnalyzer {
59     
60     private static final IBinding[] NO_BINDING= new IBinding[0];
61
62     /**
63      * Flag to specify that method should be reported.
64      */

65     public static final int METHODS= 1;
66     
67     /**
68      * Flag to specify that variables should be reported.
69      */

70     public static final int VARIABLES= 2;
71     
72     /**
73      * Flag to specify that types should be reported.
74      */

75     public static final int TYPES= 4;
76     
77     /**
78      * Flag to specify that only visible elements should be added.
79      */

80     public static final int CHECK_VISIBILITY= 16;
81     
82     private static interface IBindingRequestor {
83         boolean acceptBinding(IBinding binding);
84     }
85     
86     private static class DefaultBindingRequestor implements IBindingRequestor {
87         
88         private final List JavaDoc fResult;
89         private final HashSet JavaDoc fNamesAdded;
90         private final int fFlags;
91         private final ITypeBinding fParentTypeBinding;
92         
93         public DefaultBindingRequestor(ITypeBinding parentTypeBinding, int flags) {
94             fParentTypeBinding= parentTypeBinding;
95             fFlags= flags;
96             fResult= new ArrayList JavaDoc();
97             fNamesAdded= new HashSet JavaDoc();
98         }
99         
100         public DefaultBindingRequestor() {
101             this(null, 0);
102         }
103
104         /**
105          * {@inheritDoc}
106          */

107         public boolean acceptBinding(IBinding binding) {
108             if (binding == null)
109                 return false;
110             
111             String JavaDoc signature= getSignature(binding);
112             if (signature != null && fNamesAdded.add(signature)) { // avoid duplicated results from inheritance
113
fResult.add(binding);
114             }
115             return false;
116         }
117
118         public List JavaDoc getResult() {
119             if (hasFlag(CHECK_VISIBILITY, fFlags)) {
120                 for (int i= fResult.size() - 1; i >= 0; i--) {
121                     IBinding binding= (IBinding) fResult.get(i);
122                     if (!isVisible(binding, fParentTypeBinding)) {
123                         fResult.remove(i);
124                     }
125                 }
126             }
127             return fResult;
128         }
129         
130     }
131
132     private HashSet JavaDoc fTypesVisited;
133     
134     private CompilationUnit fRoot;
135     
136     public ScopeAnalyzer(CompilationUnit root) {
137         fTypesVisited= new HashSet JavaDoc();
138         fRoot= root;
139     }
140     
141     private void clearLists() {
142         fTypesVisited.clear();
143     }
144     
145     private static String JavaDoc getSignature(IBinding binding) {
146         if (binding != null) {
147             switch (binding.getKind()) {
148                 case IBinding.METHOD:
149                     StringBuffer JavaDoc buf= new StringBuffer JavaDoc();
150                     buf.append('M');
151                     buf.append(binding.getName()).append('(');
152                     ITypeBinding[] parameters= ((IMethodBinding) binding).getParameterTypes();
153                     for (int i= 0; i < parameters.length; i++) {
154                         if (i > 0) {
155                             buf.append(',');
156                         }
157                         ITypeBinding paramType= parameters[i].getErasure();
158                         buf.append(paramType.getQualifiedName());
159                     }
160                     buf.append(')');
161                     return buf.toString();
162                 case IBinding.VARIABLE:
163                     return 'V' + binding.getName();
164                 case IBinding.TYPE:
165                     return 'T' + binding.getName();
166             }
167         }
168         return null;
169     }
170     
171     static final boolean hasFlag(int property, int flags) {
172         return (flags & property) != 0;
173     }
174     
175     /**
176      * Collects all elements available in a type and its hierarchy
177      * @param binding The type binding
178      * @param flags Flags defining the elements to report
179      * @param requestor the requestor to which all results are reported
180      * @return return <code>true</code> if the requestor has reported the binding as found and no further results are required
181      */

182     private boolean addInherited(ITypeBinding binding, int flags, IBindingRequestor requestor) {
183         if (!fTypesVisited.add(binding)) {
184             return false;
185         }
186         if (hasFlag(VARIABLES, flags)) {
187             IVariableBinding[] variableBindings= binding.getDeclaredFields();
188             for (int i= 0; i < variableBindings.length; i++) {
189                 if (requestor.acceptBinding(variableBindings[i]))
190                     return true;
191             }
192         }
193         
194         if (hasFlag(METHODS, flags)) {
195             IMethodBinding[] methodBindings= binding.getDeclaredMethods();
196             for (int i= 0; i < methodBindings.length; i++) {
197                 IMethodBinding curr= methodBindings[i];
198                 if (!curr.isSynthetic() && !curr.isConstructor()) {
199                     if (requestor.acceptBinding(curr))
200                         return true;
201                 }
202             }
203         }
204
205         if (hasFlag(TYPES, flags)) {
206             ITypeBinding[] typeBindings= binding.getDeclaredTypes();
207             for (int i= 0; i < typeBindings.length; i++) {
208                 ITypeBinding curr= typeBindings[i];
209                 if (requestor.acceptBinding(curr))
210                     return true;
211             }
212         }
213         
214         
215         ITypeBinding superClass= binding.getSuperclass();
216         if (superClass != null) {
217             if (addInherited(superClass, flags, requestor)) // recursive
218
return true;
219         } else if (binding.isArray()) {
220             if (addInherited(fRoot.getAST().resolveWellKnownType("java.lang.Object"), flags, requestor)) //$NON-NLS-1$
221
return true;
222         }
223         
224         ITypeBinding[] interfaces= binding.getInterfaces(); // includes looking for methods: abstract, unimplemented methods
225
for (int i= 0; i < interfaces.length; i++) {
226             if (addInherited(interfaces[i], flags, requestor)) // recursive
227
return true;
228         }
229         return false;
230     }
231         
232     
233     /**
234      * Collects all elements available in a type: its hierarchy and its outer scopes.
235      * @param binding The type binding
236      * @param flags Flags defining the elements to report
237      * @param requestor the requestor to which all results are reported
238      * @return return <code>true</code> if the requestor has reported the binding as found and no further results are required
239      */

240     private boolean addTypeDeclarations(ITypeBinding binding, int flags, IBindingRequestor requestor) {
241         if (hasFlag(TYPES, flags) && !binding.isAnonymous()) {
242             if (requestor.acceptBinding(binding))
243                 return true;
244             
245             ITypeBinding[] typeParameters= binding.getTypeParameters();
246             for (int i= 0; i < typeParameters.length; i++) {
247                 if (requestor.acceptBinding(typeParameters[i]))
248                     return true;
249             }
250         }
251         
252         addInherited(binding, flags, requestor); // add inherited
253

254         if (binding.isLocal()) {
255             addOuterDeclarationsForLocalType(binding, flags, requestor);
256         } else {
257             ITypeBinding declaringClass= binding.getDeclaringClass();
258             if (declaringClass != null) {
259                 if (addTypeDeclarations(declaringClass, flags, requestor)) // Recursively add inherited
260
return true;
261             } else if (hasFlag(TYPES, flags)) {
262                 if (fRoot.findDeclaringNode(binding) != null) {
263                     List JavaDoc types= fRoot.types();
264                     for (int i= 0; i < types.size(); i++) {
265                         if (requestor.acceptBinding(((AbstractTypeDeclaration) types.get(i)).resolveBinding()))
266                             return true;
267                     }
268                 }
269             }
270         }
271         return false;
272     }
273     
274     private boolean addOuterDeclarationsForLocalType(ITypeBinding localBinding, int flags, IBindingRequestor requestor) {
275         ASTNode node= fRoot.findDeclaringNode(localBinding);
276         if (node == null) {
277             return false;
278         }
279         
280         if (node instanceof AbstractTypeDeclaration || node instanceof AnonymousClassDeclaration) {
281             if (addLocalDeclarations(node.getParent(), flags, requestor))
282                 return true;
283             
284             ITypeBinding parentTypeBinding= Bindings.getBindingOfParentType(node.getParent());
285             if (parentTypeBinding != null) {
286                 if (addTypeDeclarations(parentTypeBinding, flags, requestor))
287                     return true;
288             }
289             
290         }
291         return false;
292     }
293     
294     private static ITypeBinding getBinding(Expression node) {
295         if (node != null) {
296             return node.resolveTypeBinding();
297         }
298         return null;
299     }
300         
301     private static ITypeBinding getQualifier(SimpleName selector) {
302         ASTNode parent= selector.getParent();
303         switch (parent.getNodeType()) {
304             case ASTNode.METHOD_INVOCATION:
305                 MethodInvocation decl= (MethodInvocation) parent;
306                 if (selector == decl.getName()) {
307                     return getBinding(decl.getExpression());
308                 }
309                 return null;
310             case ASTNode.QUALIFIED_NAME:
311                 QualifiedName qualifiedName= (QualifiedName) parent;
312                 if (selector == qualifiedName.getName()) {
313                     return getBinding(qualifiedName.getQualifier());
314                 }
315                 return null;
316             case ASTNode.FIELD_ACCESS:
317                 FieldAccess fieldAccess= (FieldAccess) parent;
318                 if (selector == fieldAccess.getName()) {
319                     return getBinding(fieldAccess.getExpression());
320                 }
321                 return null;
322             case ASTNode.SUPER_FIELD_ACCESS: {
323                 ITypeBinding curr= Bindings.getBindingOfParentType(parent);
324                 return curr.getSuperclass();
325             }
326             case ASTNode.SUPER_METHOD_INVOCATION: {
327                 SuperMethodInvocation superInv= (SuperMethodInvocation) parent;
328                 if (selector == superInv.getName()) {
329                     ITypeBinding curr= Bindings.getBindingOfParentType(parent);
330                     return curr.getSuperclass();
331                 }
332                 return null;
333             }
334             default:
335                 if (parent instanceof Type) {
336                     // bug 67644: in 'a.new X()', all member types of A are visible as location of X.
337
ASTNode normalizedNode= ASTNodes.getNormalizedNode(parent);
338                     if (normalizedNode.getLocationInParent() == ClassInstanceCreation.TYPE_PROPERTY) {
339                         ClassInstanceCreation creation= (ClassInstanceCreation) normalizedNode.getParent();
340                         return getBinding(creation.getExpression());
341                     }
342                 }
343                 return null;
344         }
345     }
346     
347     public IBinding[] getDeclarationsInScope(SimpleName selector, int flags) {
348         try {
349             // special case for switch on enum
350
if (selector.getLocationInParent() == SwitchCase.EXPRESSION_PROPERTY) {
351                 ITypeBinding binding= ((SwitchStatement) selector.getParent().getParent()).getExpression().resolveTypeBinding();
352                 if (binding != null && binding.isEnum()) {
353                     return getEnumContants(binding);
354                 }
355             }
356             
357             ITypeBinding parentTypeBinding= Bindings.getBindingOfParentType(selector);
358             if (parentTypeBinding != null) {
359                 ITypeBinding binding= getQualifier(selector);
360                 DefaultBindingRequestor requestor= new DefaultBindingRequestor(parentTypeBinding, flags);
361                 if (binding == null) {
362                     addLocalDeclarations(selector, flags, requestor);
363                     addTypeDeclarations(parentTypeBinding, flags, requestor);
364                 } else {
365                     addInherited(binding, flags, requestor);
366                 }
367
368                 List JavaDoc result= requestor.getResult();
369                 return (IBinding[]) result.toArray(new IBinding[result.size()]);
370             }
371             return NO_BINDING;
372         } finally {
373             clearLists();
374         }
375     }
376     
377     private static class SearchRequestor implements IBindingRequestor {
378         
379         private final int fFlags;
380         private final ITypeBinding fParentTypeBinding;
381         private final IBinding fToSearch;
382         private boolean fFound;
383         private boolean fIsVisible;
384         
385         public SearchRequestor(IBinding toSearch, ITypeBinding parentTypeBinding, int flag) {
386             fFlags= flag;
387             fToSearch= toSearch;
388             fParentTypeBinding= parentTypeBinding;
389             fFound= false;
390             fIsVisible= true;
391         }
392         
393         public boolean acceptBinding(IBinding binding) {
394             if (fFound)
395                 return true;
396             
397             if (binding == null)
398                 return false;
399             
400             if (fToSearch.getKind() != binding.getKind()) {
401                 return false;
402             }
403             
404             boolean checkVisibility= hasFlag(CHECK_VISIBILITY, fFlags);
405             if (binding == fToSearch) {
406                 fFound= true;
407             } else {
408                 IBinding bindingDeclaration= Bindings.getDeclaration(binding);
409                 if (bindingDeclaration == fToSearch) {
410                     fFound= true;
411                 } else if (bindingDeclaration.getName().equals(fToSearch.getName())) {
412                     String JavaDoc signature= getSignature(bindingDeclaration);
413                     if (signature != null && signature.equals(getSignature(fToSearch))) {
414                         if (checkVisibility) {
415                             fIsVisible= false;
416                         }
417                         return true; // found element that hides the binding to find
418
}
419                 }
420             }
421
422             if (fFound && checkVisibility) {
423                 fIsVisible= ScopeAnalyzer.isVisible(binding, fParentTypeBinding);
424             }
425             return fFound;
426         }
427         
428         public boolean found() {
429             return fFound;
430         }
431
432         public boolean isVisible() {
433             return fIsVisible;
434         }
435     }
436     
437     public boolean isDeclaredInScope(IBinding declaration, SimpleName selector, int flags) {
438         try {
439             // special case for switch on enum
440
if (selector.getLocationInParent() == SwitchCase.EXPRESSION_PROPERTY) {
441                 ITypeBinding binding= ((SwitchStatement) selector.getParent().getParent()).getExpression().resolveTypeBinding();
442                 if (binding != null && binding.isEnum()) {
443                     return hasEnumContants(declaration, binding.getTypeDeclaration());
444                 }
445             }
446             
447             ITypeBinding parentTypeBinding= Bindings.getBindingOfParentTypeContext(selector);
448             if (parentTypeBinding != null) {
449                 ITypeBinding binding= getQualifier(selector);
450                 SearchRequestor requestor= new SearchRequestor(declaration, parentTypeBinding, flags);
451                 if (binding == null) {
452                     addLocalDeclarations(selector, flags, requestor);
453                     if (requestor.found())
454                         return requestor.isVisible();
455                     addTypeDeclarations(parentTypeBinding, flags, requestor);
456                     if (requestor.found())
457                         return requestor.isVisible();
458                 } else {
459                     addInherited(binding, flags, requestor);
460                     if (requestor.found())
461                         return requestor.isVisible();
462                 }
463             }
464             return false;
465         } finally {
466             clearLists();
467         }
468     }
469     
470     private IVariableBinding[] getEnumContants(ITypeBinding binding) {
471         IVariableBinding[] declaredFields= binding.getDeclaredFields();
472         ArrayList JavaDoc res= new ArrayList JavaDoc(declaredFields.length);
473         for (int i= 0; i < declaredFields.length; i++) {
474             IVariableBinding curr= declaredFields[i];
475             if (curr.isEnumConstant()) {
476                 res.add(curr);
477             }
478         }
479         return (IVariableBinding[]) res.toArray(new IVariableBinding[res.size()]);
480     }
481     
482     private boolean hasEnumContants(IBinding declaration, ITypeBinding binding) {
483         IVariableBinding[] declaredFields= binding.getDeclaredFields();
484         for (int i= 0; i < declaredFields.length; i++) {
485             IVariableBinding curr= declaredFields[i];
486             if (curr == declaration)
487                 return true;
488         }
489         return false;
490     }
491
492     public IBinding[] getDeclarationsInScope(int offset, int flags) {
493         NodeFinder finder= new NodeFinder(offset, 0);
494         fRoot.accept(finder);
495         ASTNode node= finder.getCoveringNode();
496         if (node == null) {
497             return NO_BINDING;
498         }
499
500         if (node instanceof SimpleName) {
501             return getDeclarationsInScope((SimpleName) node, flags);
502         }
503         
504         try {
505             ITypeBinding binding= Bindings.getBindingOfParentType(node);
506             DefaultBindingRequestor requestor= new DefaultBindingRequestor(binding, flags);
507             addLocalDeclarations(node, offset, flags, requestor);
508             if (binding != null) {
509                 addTypeDeclarations(binding, flags, requestor);
510             }
511             List JavaDoc result= requestor.getResult();
512             return (IBinding[]) result.toArray(new IBinding[result.size()]);
513         } finally {
514             clearLists();
515         }
516     }
517     
518     private static ITypeBinding getDeclaringType(IBinding binding) {
519         switch (binding.getKind()) {
520             case IBinding.VARIABLE:
521                 return ((IVariableBinding) binding).getDeclaringClass();
522             case IBinding.METHOD:
523                 return ((IMethodBinding) binding).getDeclaringClass();
524             case IBinding.TYPE:
525                 ITypeBinding typeBinding= (ITypeBinding) binding;
526                 if (typeBinding.getDeclaringClass() != null) {
527                     return typeBinding;
528                 }
529                 return typeBinding;
530         }
531         return null;
532     }
533     
534     /**
535      * Evaluates if the declaration is visible in a certain context.
536      * @param binding The binding of the declaration to examine
537      * @param context The context to test in
538      * @return Returns
539      */

540     public static boolean isVisible(IBinding binding, ITypeBinding context) {
541         if (binding.getKind() == IBinding.VARIABLE && !((IVariableBinding) binding).isField()) {
542             return true; // all local variables found are visible
543
}
544         ITypeBinding declaring= getDeclaringType(binding);
545         if (declaring == null) {
546             return false;
547         }
548     
549         int modifiers= binding.getModifiers();
550         if (Modifier.isPublic(modifiers) || declaring.isInterface()) {
551             return true;
552         } else if (Modifier.isProtected(modifiers) || !Modifier.isPrivate(modifiers)) {
553             if (declaring.getPackage() == context.getPackage()) {
554                 return true;
555             }
556             return isTypeInScope(declaring, context, Modifier.isProtected(modifiers));
557         }
558         // private visibility
559
return isTypeInScope(declaring, context, false);
560     }
561     
562     private static boolean isTypeInScope(ITypeBinding declaring, ITypeBinding context, boolean includeHierarchy) {
563         ITypeBinding curr= context;
564         while (curr != null && curr != declaring) {
565             if (includeHierarchy && Bindings.isSuperType(declaring, curr)) {
566                 return true;
567             }
568             curr= curr.getDeclaringClass();
569         }
570         return curr == declaring;
571     }
572     
573
574     public IBinding[] getDeclarationsAfter(int offset, int flags) {
575         try {
576             NodeFinder finder= new NodeFinder(offset, 0);
577             fRoot.accept(finder);
578             ASTNode node= finder.getCoveringNode();
579             if (node == null) {
580                 return null;
581             }
582             
583             ASTNode declaration= ASTResolving.findParentStatement(node);
584             while (declaration instanceof Statement && declaration.getNodeType() != ASTNode.BLOCK) {
585                 declaration= declaration.getParent();
586             }
587
588             if (declaration instanceof Block) {
589                 DefaultBindingRequestor requestor= new DefaultBindingRequestor();
590                 DeclarationsAfterVisitor visitor= new DeclarationsAfterVisitor(node.getStartPosition(), flags, requestor);
591                 declaration.accept(visitor);
592                 List JavaDoc result= requestor.getResult();
593                 return (IBinding[])result.toArray(new IBinding[result.size()]);
594             }
595             return NO_BINDING;
596         } finally {
597             clearLists();
598         }
599     }
600     
601     
602     private class ScopeAnalyzerVisitor extends HierarchicalASTVisitor {
603         
604         private int fPosition;
605         private int fFlags;
606         private final IBindingRequestor fRequestor;
607         private boolean fBreak;
608         
609         public ScopeAnalyzerVisitor(int position, int flags, IBindingRequestor requestor) {
610             fPosition= position;
611             fFlags= flags;
612             fRequestor= requestor;
613             fBreak= false;
614         }
615         
616         private boolean isInside(ASTNode node) {
617             int start= node.getStartPosition();
618             int end= start + node.getLength();
619                     
620             return start <= fPosition && fPosition < end;
621         }
622         
623         public boolean visit(MethodDeclaration node) {
624             if (isInside(node)) {
625                 Block body= node.getBody();
626                 if (body != null) {
627                     body.accept(this);
628                 }
629                 visitBackwards(node.parameters());
630                 if (node.getAST().apiLevel() >= AST.JLS3) {
631                     visitBackwards(node.typeParameters());
632                 }
633             }
634             return false;
635         }
636         
637         
638         /* (non-Javadoc)
639          * @see org.eclipse.jdt.internal.corext.dom.HierarchicalASTVisitor#visit(org.eclipse.jdt.core.dom.TypeParameter)
640          */

641         public boolean visit(TypeParameter node) {
642             if (hasFlag(TYPES, fFlags) && node.getStartPosition() < fPosition) {
643                 fBreak= fRequestor.acceptBinding(node.getName().resolveBinding());
644             }
645             return !fBreak;
646         }
647                 
648         public boolean visit(SwitchCase node) {
649             // switch on enum allows to use enum constants without qualification
650
if (hasFlag(VARIABLES, fFlags) && !node.isDefault() && isInside(node.getExpression())) {
651                 SwitchStatement switchStatement= (SwitchStatement) node.getParent();
652                 ITypeBinding binding= switchStatement.getExpression().resolveTypeBinding();
653                 if (binding != null && binding.isEnum()) {
654                     IVariableBinding[] declaredFields= binding.getDeclaredFields();
655                     for (int i= 0; i < declaredFields.length; i++) {
656                         IVariableBinding curr= declaredFields[i];
657                         if (curr.isEnumConstant()) {
658                             fBreak= fRequestor.acceptBinding(curr);
659                             if (fBreak)
660                                 return false;
661                         }
662                     }
663                 }
664             }
665             return false;
666         }
667         
668         public boolean visit(Initializer node) {
669             return !fBreak && isInside(node);
670         }
671         
672         public boolean visit(Statement node) {
673             return !fBreak && isInside(node);
674         }
675         
676         public boolean visit(ASTNode node) {
677             return false;
678         }
679         
680         public boolean visit(Block node) {
681             if (isInside(node)) {
682                 visitBackwards(node.statements());
683             }
684             return false;
685         }
686         
687         public boolean visit(VariableDeclaration node) {
688             if (hasFlag(VARIABLES, fFlags) && node.getStartPosition() < fPosition) {
689                 fBreak= fRequestor.acceptBinding(node.resolveBinding());
690             }
691             return !fBreak;
692         }
693         
694         public boolean visit(VariableDeclarationStatement node) {
695             visitBackwards(node.fragments());
696             return false;
697         }
698         
699         public boolean visit(VariableDeclarationExpression node) {
700             visitBackwards(node.fragments());
701             return false;
702         }
703     
704         public boolean visit(CatchClause node) {
705             if (isInside(node)) {
706                 node.getBody().accept(this);
707                 node.getException().accept(this);
708             }
709             return false;
710         }
711         
712         public boolean visit(ForStatement node) {
713             if (isInside(node)) {
714                 node.getBody().accept(this);
715                 visitBackwards(node.initializers());
716             }
717             return false;
718         }
719     
720         public boolean visit(TypeDeclarationStatement node) {
721             if (hasFlag(TYPES, fFlags) && node.getStartPosition() + node.getLength() < fPosition) {
722                 fBreak= fRequestor.acceptBinding(node.resolveBinding());
723                 return false;
724             }
725             return !fBreak && isInside(node);
726         }
727         
728         private void visitBackwards(List JavaDoc list) {
729             if (fBreak)
730                 return;
731             
732             for (int i= list.size() - 1; i >= 0; i--) {
733                 ASTNode curr= (ASTNode) list.get(i);
734                 if (curr.getStartPosition() < fPosition) {
735                     curr.accept(this);
736                 }
737             }
738         }
739     }
740     
741     private class DeclarationsAfterVisitor extends HierarchicalASTVisitor {
742         private final int fPosition;
743         private final int fFlags;
744         private final IBindingRequestor fRequestor;
745         private boolean fBreak;
746         
747         public DeclarationsAfterVisitor(int position, int flags, IBindingRequestor requestor) {
748             fPosition= position;
749             fFlags= flags;
750             fRequestor= requestor;
751             fBreak= false;
752         }
753         
754         public boolean visit(ASTNode node) {
755             return !fBreak;
756         }
757         
758         public boolean visit(VariableDeclaration node) {
759             if (hasFlag(VARIABLES, fFlags) && fPosition < node.getStartPosition()) {
760                 fBreak= fRequestor.acceptBinding(node.resolveBinding());
761             }
762             return false;
763         }
764         
765         public boolean visit(AnonymousClassDeclaration node) {
766             return false;
767         }
768
769         public boolean visit(TypeDeclarationStatement node) {
770             if (hasFlag(TYPES, fFlags) && fPosition < node.getStartPosition()) {
771                 fBreak= fRequestor.acceptBinding(node.resolveBinding());
772             }
773             return false;
774         }
775     }
776     
777     private boolean addLocalDeclarations(ASTNode node, int flags, IBindingRequestor requestor) {
778         return addLocalDeclarations(node, node.getStartPosition(), flags, requestor);
779     }
780     
781     
782     private boolean addLocalDeclarations(ASTNode node, int offset, int flags, IBindingRequestor requestor) {
783         if (hasFlag(VARIABLES, flags) || hasFlag(TYPES, flags)) {
784             BodyDeclaration declaration= ASTResolving.findParentBodyDeclaration(node);
785             if (declaration instanceof MethodDeclaration || declaration instanceof Initializer) {
786                 ScopeAnalyzerVisitor visitor= new ScopeAnalyzerVisitor(offset, flags, requestor);
787                 declaration.accept(visitor);
788                 return visitor.fBreak;
789             }
790         }
791         return false;
792     }
793     
794     public Collection JavaDoc getUsedVariableNames(int offset, int length) {
795         HashSet JavaDoc result= new HashSet JavaDoc();
796         IBinding[] bindingsBefore= getDeclarationsInScope(offset, VARIABLES);
797         for (int i= 0; i < bindingsBefore.length; i++) {
798             result.add(bindingsBefore[i].getName());
799         }
800         IBinding[] bindingsAfter= getDeclarationsAfter(offset + length, VARIABLES);
801         for (int i= 0; i < bindingsAfter.length; i++) {
802             result.add(bindingsAfter[i].getName());
803         }
804         List JavaDoc imports= fRoot.imports();
805         for (int i= 0; i < imports.size(); i++) {
806             ImportDeclaration decl= (ImportDeclaration) imports.get(i);
807             if (decl.isStatic() && !decl.isOnDemand()) {
808                 result.add(ASTNodes.getSimpleNameIdentifier(decl.getName()));
809             }
810         }
811         return result;
812     }
813 }
814
Popular Tags