KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > jdt > internal > ui > text > correction > ASTResolving


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
12 package org.eclipse.jdt.internal.ui.text.correction;
13
14 import java.util.ArrayList JavaDoc;
15 import java.util.Collection JavaDoc;
16 import java.util.HashSet JavaDoc;
17 import java.util.Iterator JavaDoc;
18 import java.util.List JavaDoc;
19
20 import org.eclipse.core.runtime.IProgressMonitor;
21
22 import org.eclipse.jdt.core.ICompilationUnit;
23 import org.eclipse.jdt.core.JavaModelException;
24 import org.eclipse.jdt.core.dom.AST;
25 import org.eclipse.jdt.core.dom.ASTNode;
26 import org.eclipse.jdt.core.dom.ASTParser;
27 import org.eclipse.jdt.core.dom.AbstractTypeDeclaration;
28 import org.eclipse.jdt.core.dom.Annotation;
29 import org.eclipse.jdt.core.dom.AnonymousClassDeclaration;
30 import org.eclipse.jdt.core.dom.ArrayAccess;
31 import org.eclipse.jdt.core.dom.ArrayCreation;
32 import org.eclipse.jdt.core.dom.ArrayInitializer;
33 import org.eclipse.jdt.core.dom.ArrayType;
34 import org.eclipse.jdt.core.dom.AssertStatement;
35 import org.eclipse.jdt.core.dom.Assignment;
36 import org.eclipse.jdt.core.dom.BodyDeclaration;
37 import org.eclipse.jdt.core.dom.CastExpression;
38 import org.eclipse.jdt.core.dom.ClassInstanceCreation;
39 import org.eclipse.jdt.core.dom.CompilationUnit;
40 import org.eclipse.jdt.core.dom.ConditionalExpression;
41 import org.eclipse.jdt.core.dom.ConstructorInvocation;
42 import org.eclipse.jdt.core.dom.Expression;
43 import org.eclipse.jdt.core.dom.FieldAccess;
44 import org.eclipse.jdt.core.dom.FieldDeclaration;
45 import org.eclipse.jdt.core.dom.IBinding;
46 import org.eclipse.jdt.core.dom.IMethodBinding;
47 import org.eclipse.jdt.core.dom.ITypeBinding;
48 import org.eclipse.jdt.core.dom.IVariableBinding;
49 import org.eclipse.jdt.core.dom.InfixExpression;
50 import org.eclipse.jdt.core.dom.Initializer;
51 import org.eclipse.jdt.core.dom.InstanceofExpression;
52 import org.eclipse.jdt.core.dom.MemberValuePair;
53 import org.eclipse.jdt.core.dom.MethodDeclaration;
54 import org.eclipse.jdt.core.dom.MethodInvocation;
55 import org.eclipse.jdt.core.dom.Modifier;
56 import org.eclipse.jdt.core.dom.Name;
57 import org.eclipse.jdt.core.dom.ParameterizedType;
58 import org.eclipse.jdt.core.dom.PrefixExpression;
59 import org.eclipse.jdt.core.dom.PrimitiveType;
60 import org.eclipse.jdt.core.dom.QualifiedName;
61 import org.eclipse.jdt.core.dom.QualifiedType;
62 import org.eclipse.jdt.core.dom.SimpleName;
63 import org.eclipse.jdt.core.dom.SimpleType;
64 import org.eclipse.jdt.core.dom.SingleVariableDeclaration;
65 import org.eclipse.jdt.core.dom.Statement;
66 import org.eclipse.jdt.core.dom.StructuralPropertyDescriptor;
67 import org.eclipse.jdt.core.dom.SuperConstructorInvocation;
68 import org.eclipse.jdt.core.dom.SuperMethodInvocation;
69 import org.eclipse.jdt.core.dom.SwitchCase;
70 import org.eclipse.jdt.core.dom.SwitchStatement;
71 import org.eclipse.jdt.core.dom.TagElement;
72 import org.eclipse.jdt.core.dom.TryStatement;
73 import org.eclipse.jdt.core.dom.Type;
74 import org.eclipse.jdt.core.dom.TypeDeclaration;
75 import org.eclipse.jdt.core.dom.TypeLiteral;
76 import org.eclipse.jdt.core.dom.TypeParameter;
77 import org.eclipse.jdt.core.dom.VariableDeclaration;
78 import org.eclipse.jdt.core.dom.VariableDeclarationExpression;
79 import org.eclipse.jdt.core.dom.VariableDeclarationFragment;
80 import org.eclipse.jdt.core.dom.VariableDeclarationStatement;
81 import org.eclipse.jdt.core.dom.WildcardType;
82 import org.eclipse.jdt.core.dom.PrimitiveType.Code;
83
84 import org.eclipse.jdt.internal.corext.dom.ASTNodeFactory;
85 import org.eclipse.jdt.internal.corext.dom.ASTNodes;
86 import org.eclipse.jdt.internal.corext.dom.Bindings;
87 import org.eclipse.jdt.internal.corext.dom.GenericVisitor;
88 import org.eclipse.jdt.internal.corext.dom.ScopeAnalyzer;
89 import org.eclipse.jdt.internal.corext.dom.TypeBindingVisitor;
90
91 import org.eclipse.jdt.ui.JavaElementLabels;
92
93 import org.eclipse.jdt.internal.ui.javaeditor.ASTProvider;
94 import org.eclipse.jdt.internal.ui.viewsupport.BindingLabelProvider;
95
96 public class ASTResolving {
97
98     public static ITypeBinding guessBindingForReference(ASTNode node) {
99         return Bindings.normalizeTypeBinding(getPossibleReferenceBinding(node));
100     }
101
102     private static ITypeBinding getPossibleReferenceBinding(ASTNode node) {
103         ASTNode parent= node.getParent();
104         switch (parent.getNodeType()) {
105         case ASTNode.ASSIGNMENT:
106             Assignment assignment= (Assignment) parent;
107             if (node.equals(assignment.getLeftHandSide())) {
108                 // field write access: xx= expression
109
return assignment.getRightHandSide().resolveTypeBinding();
110             }
111             // read access
112
return assignment.getLeftHandSide().resolveTypeBinding();
113         case ASTNode.INFIX_EXPRESSION:
114             InfixExpression infix= (InfixExpression) parent;
115             InfixExpression.Operator op= infix.getOperator();
116             if (op == InfixExpression.Operator.CONDITIONAL_AND || op == InfixExpression.Operator.CONDITIONAL_OR) {
117                 // boolean operation
118
return infix.getAST().resolveWellKnownType("boolean"); //$NON-NLS-1$
119
} else if (op == InfixExpression.Operator.LEFT_SHIFT || op == InfixExpression.Operator.RIGHT_SHIFT_UNSIGNED || op == InfixExpression.Operator.RIGHT_SHIFT_SIGNED) {
120                 // asymmetric operation
121
return infix.getAST().resolveWellKnownType("int"); //$NON-NLS-1$
122
}
123             if (node.equals(infix.getLeftOperand())) {
124                 // xx operation expression
125
ITypeBinding rigthHandBinding= infix.getRightOperand().resolveTypeBinding();
126                 if (rigthHandBinding != null) {
127                     return rigthHandBinding;
128                 }
129             } else {
130                 // expression operation xx
131
ITypeBinding leftHandBinding= infix.getLeftOperand().resolveTypeBinding();
132                 if (leftHandBinding != null) {
133                     return leftHandBinding;
134                 }
135             }
136             if (op != InfixExpression.Operator.EQUALS && op != InfixExpression.Operator.NOT_EQUALS) {
137                 return infix.getAST().resolveWellKnownType("int"); //$NON-NLS-1$
138
}
139             break;
140         case ASTNode.INSTANCEOF_EXPRESSION:
141             InstanceofExpression instanceofExpression= (InstanceofExpression) parent;
142             return instanceofExpression.getRightOperand().resolveBinding();
143         case ASTNode.VARIABLE_DECLARATION_FRAGMENT:
144             VariableDeclarationFragment frag= (VariableDeclarationFragment) parent;
145             if (frag.getInitializer().equals(node)) {
146                 return frag.getName().resolveTypeBinding();
147             }
148             break;
149         case ASTNode.SUPER_METHOD_INVOCATION:
150             SuperMethodInvocation superMethodInvocation= (SuperMethodInvocation) parent;
151             IMethodBinding superMethodBinding= ASTNodes.getMethodBinding(superMethodInvocation.getName());
152             if (superMethodBinding != null) {
153                 return getParameterTypeBinding(node, superMethodInvocation.arguments(), superMethodBinding);
154             }
155             break;
156         case ASTNode.METHOD_INVOCATION:
157             MethodInvocation methodInvocation= (MethodInvocation) parent;
158             IMethodBinding methodBinding= methodInvocation.resolveMethodBinding();
159             if (methodBinding != null) {
160                 return getParameterTypeBinding(node, methodInvocation.arguments(), methodBinding);
161             }
162             break;
163         case ASTNode.SUPER_CONSTRUCTOR_INVOCATION: {
164             SuperConstructorInvocation superInvocation= (SuperConstructorInvocation) parent;
165             IMethodBinding superBinding= superInvocation.resolveConstructorBinding();
166             if (superBinding != null) {
167                 return getParameterTypeBinding(node, superInvocation.arguments(), superBinding);
168             }
169             break;
170         }
171         case ASTNode.CONSTRUCTOR_INVOCATION: {
172             ConstructorInvocation constrInvocation= (ConstructorInvocation) parent;
173             IMethodBinding constrBinding= constrInvocation.resolveConstructorBinding();
174             if (constrBinding != null) {
175                 return getParameterTypeBinding(node, constrInvocation.arguments(), constrBinding);
176             }
177             break;
178         }
179         case ASTNode.CLASS_INSTANCE_CREATION: {
180             ClassInstanceCreation creation= (ClassInstanceCreation) parent;
181             IMethodBinding creationBinding= creation.resolveConstructorBinding();
182             if (creationBinding != null) {
183                 return getParameterTypeBinding(node, creation.arguments(), creationBinding);
184             }
185             break;
186         }
187         case ASTNode.PARENTHESIZED_EXPRESSION:
188             return guessBindingForReference(parent);
189         case ASTNode.ARRAY_ACCESS:
190             if (((ArrayAccess) parent).getIndex().equals(node)) {
191                 return parent.getAST().resolveWellKnownType("int"); //$NON-NLS-1$
192
} else {
193                 return getPossibleReferenceBinding(parent);
194             }
195         case ASTNode.ARRAY_CREATION:
196             if (((ArrayCreation) parent).dimensions().contains(node)) {
197                 return parent.getAST().resolveWellKnownType("int"); //$NON-NLS-1$
198
}
199             break;
200         case ASTNode.ARRAY_INITIALIZER:
201             ASTNode initializerParent= parent.getParent();
202             int dim= 1;
203             while (initializerParent instanceof ArrayInitializer) {
204                 initializerParent= initializerParent.getParent();
205                 dim++;
206             }
207             Type creationType= null;
208             if (initializerParent instanceof ArrayCreation) {
209                 creationType= ((ArrayCreation) initializerParent).getType();
210             } else if (initializerParent instanceof VariableDeclaration) {
211                 VariableDeclaration varDecl= (VariableDeclaration) initializerParent;
212                 creationType= ASTNodes.getType(varDecl);
213                 dim-= varDecl.getExtraDimensions();
214             } else if (initializerParent instanceof MemberValuePair) {
215                 String JavaDoc name= ((MemberValuePair) initializerParent).getName().getIdentifier();
216                 IMethodBinding annotMember= findAnnotationMember((Annotation) initializerParent.getParent(), name);
217                 if (annotMember != null) {
218                     return getReducedDimensionBinding(annotMember.getReturnType(), dim);
219                 }
220             }
221             if (creationType != null) {
222                 while ((creationType instanceof ArrayType) && dim > 0) {
223                     creationType= ((ArrayType) creationType).getComponentType();
224                     dim--;
225                 }
226                 return creationType.resolveBinding();
227             }
228             break;
229         case ASTNode.CONDITIONAL_EXPRESSION:
230             ConditionalExpression expression= (ConditionalExpression) parent;
231             if (node.equals(expression.getExpression())) {
232                 return parent.getAST().resolveWellKnownType("boolean"); //$NON-NLS-1$
233
}
234             if (node.equals(expression.getElseExpression())) {
235                 return expression.getThenExpression().resolveTypeBinding();
236             }
237             return expression.getElseExpression().resolveTypeBinding();
238         case ASTNode.POSTFIX_EXPRESSION:
239             return parent.getAST().resolveWellKnownType("int"); //$NON-NLS-1$
240
case ASTNode.PREFIX_EXPRESSION:
241             if (((PrefixExpression) parent).getOperator() == PrefixExpression.Operator.NOT) {
242                 return parent.getAST().resolveWellKnownType("boolean"); //$NON-NLS-1$
243
}
244             return parent.getAST().resolveWellKnownType("int"); //$NON-NLS-1$
245
case ASTNode.IF_STATEMENT:
246         case ASTNode.WHILE_STATEMENT:
247         case ASTNode.DO_STATEMENT:
248             if (node instanceof Expression) {
249                 return parent.getAST().resolveWellKnownType("boolean"); //$NON-NLS-1$
250
}
251             break;
252         case ASTNode.SWITCH_STATEMENT:
253             if (((SwitchStatement) parent).getExpression().equals(node)) {
254                 return parent.getAST().resolveWellKnownType("int"); //$NON-NLS-1$
255
}
256             break;
257         case ASTNode.RETURN_STATEMENT:
258             MethodDeclaration decl= ASTResolving.findParentMethodDeclaration(parent);
259             if (decl != null && !decl.isConstructor()) {
260                 return decl.getReturnType2().resolveBinding();
261             }
262             break;
263         case ASTNode.CAST_EXPRESSION:
264             return ((CastExpression) parent).getType().resolveBinding();
265         case ASTNode.THROW_STATEMENT:
266         case ASTNode.CATCH_CLAUSE:
267             return parent.getAST().resolveWellKnownType("java.lang.Exception"); //$NON-NLS-1$
268
case ASTNode.FIELD_ACCESS:
269             if (node.equals(((FieldAccess) parent).getName())) {
270                 return getPossibleReferenceBinding(parent);
271             }
272             break;
273         case ASTNode.SUPER_FIELD_ACCESS:
274             return getPossibleReferenceBinding(parent);
275         case ASTNode.QUALIFIED_NAME:
276             if (node.equals(((QualifiedName) parent).getName())) {
277                 return getPossibleReferenceBinding(parent);
278             }
279             break;
280         case ASTNode.SWITCH_CASE:
281             if (node.equals(((SwitchCase) parent).getExpression()) && parent.getParent() instanceof SwitchStatement) {
282                 return ((SwitchStatement) parent.getParent()).getExpression().resolveTypeBinding();
283             }
284             break;
285         case ASTNode.ASSERT_STATEMENT:
286             if (node.getLocationInParent() == AssertStatement.EXPRESSION_PROPERTY) {
287                 return parent.getAST().resolveWellKnownType("boolean"); //$NON-NLS-1$
288
}
289             return parent.getAST().resolveWellKnownType("java.lang.String"); //$NON-NLS-1$
290
case ASTNode.SINGLE_MEMBER_ANNOTATION: {
291             IMethodBinding annotMember= findAnnotationMember((Annotation) parent, "value"); //$NON-NLS-1$
292
if (annotMember != null) {
293                 return annotMember.getReturnType();
294             }
295             break;
296         }
297         case ASTNode.MEMBER_VALUE_PAIR: {
298             String JavaDoc name= ((MemberValuePair) parent).getName().getIdentifier();
299             IMethodBinding annotMember= findAnnotationMember((Annotation) parent.getParent(), name);
300             if (annotMember != null) {
301                 return annotMember.getReturnType();
302             }
303             break;
304         }
305         default:
306             // do nothing
307
}
308
309         return null;
310     }
311     
312     private static IMethodBinding findAnnotationMember(Annotation annotation, String JavaDoc name) {
313         ITypeBinding annotBinding= annotation.resolveTypeBinding();
314         if (annotBinding != null) {
315             return Bindings.findMethodInType(annotBinding, name, (String JavaDoc[]) null);
316         }
317         return null;
318     }
319
320     public static Type guessTypeForReference(AST ast, ASTNode node) {
321         ASTNode parent= node.getParent();
322         while (parent != null) {
323             switch (parent.getNodeType()) {
324                 case ASTNode.VARIABLE_DECLARATION_FRAGMENT:
325                     if (((VariableDeclarationFragment) parent).getInitializer() == node) {
326                         return ASTNodeFactory.newType(ast, (VariableDeclaration) parent);
327                     }
328                     return null;
329                 case ASTNode.SINGLE_VARIABLE_DECLARATION:
330                     if (((VariableDeclarationFragment) parent).getInitializer() == node) {
331                         return ASTNodeFactory.newType(ast, (VariableDeclaration) parent);
332                     }
333                     return null;
334                 case ASTNode.ARRAY_ACCESS:
335                     if (!((ArrayAccess) parent).getIndex().equals(node)) {
336                         Type type= guessTypeForReference(ast, parent);
337                         if (type != null) {
338                             return ast.newArrayType(type);
339                         }
340                     }
341                     return null;
342                 case ASTNode.FIELD_ACCESS:
343                     if (node.equals(((FieldAccess) parent).getName())) {
344                         node= parent;
345                         parent= parent.getParent();
346                     } else {
347                         return null;
348                     }
349                     break;
350                 case ASTNode.SUPER_FIELD_ACCESS:
351                 case ASTNode.PARENTHESIZED_EXPRESSION:
352                     node= parent;
353                     parent= parent.getParent();
354                     break;
355                 case ASTNode.QUALIFIED_NAME:
356                     if (node.equals(((QualifiedName) parent).getName())) {
357                         node= parent;
358                         parent= parent.getParent();
359                     } else {
360                         return null;
361                     }
362                     break;
363                 default:
364                     return null;
365             }
366         }
367         return null;
368     }
369
370     private static ITypeBinding getReducedDimensionBinding(ITypeBinding arrayBinding, int dimsToReduce) {
371         while (dimsToReduce > 0) {
372             arrayBinding= arrayBinding.getComponentType();
373             dimsToReduce--;
374         }
375         return arrayBinding;
376     }
377
378     private static ITypeBinding getParameterTypeBinding(ASTNode node, List JavaDoc args, IMethodBinding binding) {
379         ITypeBinding[] paramTypes= binding.getParameterTypes();
380         int index= args.indexOf(node);
381         if (binding.isVarargs() && index >= paramTypes.length - 1) {
382             return paramTypes[paramTypes.length - 1].getComponentType();
383         }
384         if (index >= 0 && index < paramTypes.length) {
385             return paramTypes[index];
386         }
387         return null;
388     }
389
390     public static ITypeBinding guessBindingForTypeReference(ASTNode node) {
391         StructuralPropertyDescriptor locationInParent= node.getLocationInParent();
392         if (locationInParent == QualifiedName.QUALIFIER_PROPERTY) {
393             return null; // can't guess type for X.A
394
}
395         if (locationInParent == SimpleType.NAME_PROPERTY) {
396             node= node.getParent();
397         }
398         ITypeBinding binding= Bindings.normalizeTypeBinding(getPossibleTypeBinding(node));
399         if (binding != null) {
400             if (binding.isWildcardType()) {
401                 return normalizeWildcardType(binding, true, node.getAST());
402             }
403         }
404         return binding;
405     }
406
407     private static ITypeBinding getPossibleTypeBinding(ASTNode node) {
408         ASTNode parent= node.getParent();
409         switch (parent.getNodeType()) {
410             case ASTNode.ARRAY_TYPE: {
411                 int dim= 1;
412                 while (parent.getParent() instanceof ArrayType) {
413                     parent= parent.getParent();
414                     dim++;
415                 }
416                 ITypeBinding parentBinding= getPossibleTypeBinding(parent);
417                 if (parentBinding != null && parentBinding.getDimensions() == dim) {
418                     return parentBinding.getElementType();
419                 }
420                 return null;
421             }
422             case ASTNode.PARAMETERIZED_TYPE: {
423                 ITypeBinding parentBinding= getPossibleTypeBinding(parent);
424                 if (parentBinding == null || !parentBinding.isParameterizedType()) {
425                     return null;
426                 }
427                 if (node.getLocationInParent() == ParameterizedType.TYPE_PROPERTY) {
428                     return parentBinding;
429                 }
430
431                 ITypeBinding[] typeArguments= parentBinding.getTypeArguments();
432                 List JavaDoc argumentNodes= ((ParameterizedType) parent).typeArguments();
433                 int index= argumentNodes.indexOf(node);
434                 if (index != -1 && typeArguments.length == argumentNodes.size()) {
435                     return typeArguments[index];
436                 }
437                 return null;
438             }
439             case ASTNode.WILDCARD_TYPE: {
440                 ITypeBinding parentBinding= getPossibleTypeBinding(parent);
441                 if (parentBinding == null || !parentBinding.isWildcardType()) {
442                     return null;
443                 }
444                 WildcardType wildcardType= (WildcardType) parent;
445                 if (parentBinding.isUpperbound() == wildcardType.isUpperBound()) {
446                     return parentBinding.getBound();
447                 }
448                 return null;
449             }
450             case ASTNode.QUALIFIED_TYPE: {
451                 ITypeBinding parentBinding= getPossibleTypeBinding(parent);
452                 if (parentBinding == null || !parentBinding.isMember()) {
453                     return null;
454                 }
455                 if (node.getLocationInParent() == QualifiedType.QUALIFIER_PROPERTY) {
456                     return parentBinding.getDeclaringClass();
457                 }
458                 return parentBinding;
459             }
460             case ASTNode.VARIABLE_DECLARATION_STATEMENT:
461                 return guessVariableType(((VariableDeclarationStatement) parent).fragments());
462             case ASTNode.FIELD_DECLARATION:
463                 return guessVariableType(((FieldDeclaration) parent).fragments());
464             case ASTNode.VARIABLE_DECLARATION_EXPRESSION:
465                 return guessVariableType(((VariableDeclarationExpression) parent).fragments());
466             case ASTNode.SINGLE_VARIABLE_DECLARATION:
467                 SingleVariableDeclaration varDecl= (SingleVariableDeclaration) parent;
468                 if (varDecl.getInitializer() != null) {
469                     return Bindings.normalizeTypeBinding(varDecl.getInitializer().resolveTypeBinding());
470                 }
471                 break;
472             case ASTNode.ARRAY_CREATION:
473                 ArrayCreation creation= (ArrayCreation) parent;
474                 if (creation.getInitializer() != null) {
475                     return creation.getInitializer().resolveTypeBinding();
476                 }
477                 return getPossibleReferenceBinding(parent);
478             case ASTNode.TYPE_LITERAL:
479                 return ((TypeLiteral) parent).getType().resolveBinding();
480             case ASTNode.CLASS_INSTANCE_CREATION:
481                 return getPossibleReferenceBinding(parent);
482             case ASTNode.CAST_EXPRESSION:
483                 return getPossibleReferenceBinding(parent);
484             case ASTNode.TAG_ELEMENT:
485                 TagElement tagElement= (TagElement) parent;
486                 if (TagElement.TAG_THROWS.equals(tagElement.getTagName()) || TagElement.TAG_EXCEPTION.equals(tagElement.getTagName())) {
487                     ASTNode methNode= tagElement.getParent().getParent();
488                     if (methNode instanceof MethodDeclaration) {
489                         List JavaDoc thrownExcpetions= ((MethodDeclaration) methNode).thrownExceptions();
490                         if (thrownExcpetions.size() == 1) {
491                             return ((Name) thrownExcpetions.get(0)).resolveTypeBinding();
492                         }
493                     }
494                 }
495                 break;
496         }
497         return null;
498     }
499
500     private static ITypeBinding guessVariableType(List JavaDoc fragments) {
501         for (Iterator JavaDoc iter= fragments.iterator(); iter.hasNext();) {
502             VariableDeclarationFragment frag= (VariableDeclarationFragment) iter.next();
503             if (frag.getInitializer() != null) {
504                 return Bindings.normalizeTypeBinding(frag.getInitializer().resolveTypeBinding());
505             }
506         }
507         return null;
508     }
509
510     /**
511      * Finds all type bindings that contain a method of a given signature
512      * @param searchRoot the ast node to start the search from
513      * @param selector the method name
514      * @param arguments the method arguments
515      * @param context the context in which the method would be called
516      * @return returns all types known in the AST that have a method with a given name
517      */

518     public static ITypeBinding[] getQualifierGuess(ASTNode searchRoot, final String JavaDoc selector, List JavaDoc arguments, final IBinding context) {
519         final int nArgs= arguments.size();
520         final ArrayList JavaDoc result= new ArrayList JavaDoc();
521         
522         // test if selector is a object method
523
ITypeBinding binding= searchRoot.getAST().resolveWellKnownType("java.lang.Object"); //$NON-NLS-1$
524
IMethodBinding[] objectMethods= binding.getDeclaredMethods();
525         for (int i= 0; i < objectMethods.length; i++) {
526             IMethodBinding meth= objectMethods[i];
527             if (meth.getName().equals(selector) && meth.getParameterTypes().length == nArgs) {
528                 return new ITypeBinding[] { binding };
529             }
530         }
531
532         visitAllBindings(searchRoot, new TypeBindingVisitor() {
533             private HashSet JavaDoc fVisitedBindings= new HashSet JavaDoc(100);
534
535             public boolean visit(ITypeBinding node) {
536                 node= Bindings.normalizeTypeBinding(node);
537                 if (node == null) {
538                     return true;
539                 }
540                 
541                 if (!fVisitedBindings.add(node.getKey())) {
542                     return true;
543                 }
544                 if (node.isGenericType()) {
545                     return true; // only look at parameterized types
546
}
547                 if (context != null && !isUseableTypeInContext(node, context, false)) {
548                     return true;
549                 }
550                 
551                 IMethodBinding[] methods= node.getDeclaredMethods();
552                 for (int i= 0; i < methods.length; i++) {
553                     IMethodBinding meth= methods[i];
554                     if (meth.getName().equals(selector) && meth.getParameterTypes().length == nArgs) {
555                         result.add(node);
556                     }
557                 }
558                 return true;
559             }
560         });
561         return (ITypeBinding[]) result.toArray(new ITypeBinding[result.size()]);
562     }
563     
564     public static void visitAllBindings(ASTNode astRoot, TypeBindingVisitor visitor) {
565         try {
566             astRoot.accept(new AllBindingsVisitor(visitor));
567         } catch (AllBindingsVisitor.VisitCancelledException e) {
568         }
569     }
570     
571     private static class AllBindingsVisitor extends GenericVisitor {
572         private final TypeBindingVisitor fVisitor;
573         
574         private static class VisitCancelledException extends RuntimeException JavaDoc {
575             private static final long serialVersionUID= 1L;
576         }
577         public AllBindingsVisitor(TypeBindingVisitor visitor) {
578             super(true);
579             fVisitor= visitor;
580         }
581         public boolean visit(SimpleName node) {
582             ITypeBinding binding= node.resolveTypeBinding();
583             if (binding != null) {
584                 boolean res= fVisitor.visit(binding);
585                 if (res) {
586                     res= Bindings.visitHierarchy(binding, fVisitor);
587                 }
588                 if (!res) {
589                     throw new VisitCancelledException();
590                 }
591             }
592             return false;
593         }
594     }
595
596
597     public static IBinding getParentMethodOrTypeBinding(ASTNode node) {
598         do {
599             if (node instanceof MethodDeclaration) {
600                 return ((MethodDeclaration) node).resolveBinding();
601             } else if (node instanceof AbstractTypeDeclaration) {
602                 return ((AbstractTypeDeclaration) node).resolveBinding();
603             } else if (node instanceof AnonymousClassDeclaration) {
604                 return ((AnonymousClassDeclaration) node).resolveBinding();
605             }
606             node= node.getParent();
607         } while (node != null);
608         
609         return null;
610     }
611     
612     public static BodyDeclaration findParentBodyDeclaration(ASTNode node) {
613         while ((node != null) && (!(node instanceof BodyDeclaration))) {
614             node= node.getParent();
615         }
616         return (BodyDeclaration) node;
617     }
618     
619     public static BodyDeclaration findParentBodyDeclaration(ASTNode node, boolean treatModifiersOutside) {
620         StructuralPropertyDescriptor lastLocation= null;
621         
622         while (node != null) {
623             if (node instanceof BodyDeclaration) {
624                 BodyDeclaration decl= (BodyDeclaration) node;
625                 if (!treatModifiersOutside || lastLocation != decl.getModifiersProperty()) {
626                     return decl;
627                 }
628                 treatModifiersOutside= false;
629             }
630             lastLocation= node.getLocationInParent();
631             node= node.getParent();
632         }
633         return (BodyDeclaration) node;
634     }
635     
636
637     public static CompilationUnit findParentCompilationUnit(ASTNode node) {
638         return (CompilationUnit) findAncestor(node, ASTNode.COMPILATION_UNIT);
639     }
640
641     /**
642      * Finds the parent type of a node.
643      *
644      * @param node the node inside the type to find
645      * @param treatModifiersOutside if set, modifiers are not part of their type, but of the type's parent
646      * @return returns either a AbstractTypeDeclaration or an AnonymousTypeDeclaration
647      */

648     public static ASTNode findParentType(ASTNode node, boolean treatModifiersOutside) {
649         StructuralPropertyDescriptor lastLocation= null;
650
651         while (node != null) {
652             if (node instanceof AbstractTypeDeclaration) {
653                 AbstractTypeDeclaration decl= (AbstractTypeDeclaration) node;
654                 if (!treatModifiersOutside || lastLocation != decl.getModifiersProperty()) {
655                     return decl;
656                 }
657             } else if (node instanceof AnonymousClassDeclaration) {
658                 return node;
659             }
660             lastLocation= node.getLocationInParent();
661             node= node.getParent();
662         }
663         return null;
664     }
665     
666     public static ASTNode findParentType(ASTNode node) {
667         return findParentType(node, false);
668     }
669
670     /**
671      * Returns the method binding of the node's parent method declaration or <code>null</code> if the node
672      * is not inside a method
673      * @param node
674      * @return CompilationUnit
675      */

676     public static MethodDeclaration findParentMethodDeclaration(ASTNode node) {
677         while (node != null) {
678             if (node.getNodeType() == ASTNode.METHOD_DECLARATION) {
679                 return (MethodDeclaration) node;
680             }
681             if (node instanceof AbstractTypeDeclaration || node instanceof AnonymousClassDeclaration) {
682                 return null;
683             }
684             node= node.getParent();
685         }
686         return null;
687     }
688
689     public static ASTNode findAncestor(ASTNode node, int nodeType) {
690         while ((node != null) && (node.getNodeType() != nodeType)) {
691             node= node.getParent();
692         }
693         return node;
694     }
695
696     public static Statement findParentStatement(ASTNode node) {
697         while ((node != null) && (!(node instanceof Statement))) {
698             node= node.getParent();
699             if (node instanceof BodyDeclaration) {
700                 return null;
701             }
702         }
703         return (Statement) node;
704     }
705
706     public static TryStatement findParentTryStatement(ASTNode node) {
707         while ((node != null) && (!(node instanceof TryStatement))) {
708             node= node.getParent();
709             if (node instanceof BodyDeclaration) {
710                 return null;
711             }
712         }
713         return (TryStatement) node;
714     }
715
716     public static boolean isInsideConstructorInvocation(MethodDeclaration methodDeclaration, ASTNode node) {
717         if (methodDeclaration.isConstructor()) {
718             Statement statement= ASTResolving.findParentStatement(node);
719             if (statement instanceof ConstructorInvocation || statement instanceof SuperConstructorInvocation) {
720                 return true; // argument in a this or super call
721
}
722         }
723         return false;
724     }
725     
726     public static boolean isInsideModifiers(ASTNode node) {
727         while (node != null && !(node instanceof BodyDeclaration)) {
728             if (node instanceof Annotation) {
729                 return true;
730             }
731             node= node.getParent();
732         }
733         return false;
734     }
735
736     public static boolean isInStaticContext(ASTNode selectedNode) {
737         BodyDeclaration decl= ASTResolving.findParentBodyDeclaration(selectedNode);
738         if (decl instanceof MethodDeclaration) {
739             if (isInsideConstructorInvocation((MethodDeclaration) decl, selectedNode)) {
740                 return true;
741             }
742             return Modifier.isStatic(decl.getModifiers());
743         } else if (decl instanceof Initializer) {
744             return Modifier.isStatic(((Initializer)decl).getModifiers());
745         } else if (decl instanceof FieldDeclaration) {
746             return Modifier.isStatic(((FieldDeclaration)decl).getModifiers());
747         }
748         return false;
749     }
750
751     public static boolean isWriteAccess(Name selectedNode) {
752         ASTNode curr= selectedNode;
753         ASTNode parent= curr.getParent();
754         while (parent != null) {
755             switch (parent.getNodeType()) {
756                 case ASTNode.QUALIFIED_NAME:
757                     if (((QualifiedName) parent).getQualifier() == curr) {
758                         return false;
759                     }
760                     break;
761                 case ASTNode.FIELD_ACCESS:
762                     if (((FieldAccess) parent).getExpression() == curr) {
763                         return false;
764                     }
765                     break;
766                 case ASTNode.SUPER_FIELD_ACCESS:
767                     break;
768                 case ASTNode.ASSIGNMENT:
769                     return ((Assignment) parent).getLeftHandSide() == curr;
770                 case ASTNode.VARIABLE_DECLARATION_FRAGMENT:
771                 case ASTNode.SINGLE_VARIABLE_DECLARATION:
772                     return ((VariableDeclaration) parent).getName() == curr;
773                 case ASTNode.POSTFIX_EXPRESSION:
774                 case ASTNode.PREFIX_EXPRESSION:
775                     return true;
776                 default:
777                     return false;
778             }
779
780             curr= parent;
781             parent= curr.getParent();
782         }
783         return false;
784     }
785
786     public static int getPossibleTypeKinds(ASTNode node, boolean is50OrHigher) {
787         int kinds= internalGetPossibleTypeKinds(node);
788         if (!is50OrHigher) {
789             kinds &= (SimilarElementsRequestor.INTERFACES | SimilarElementsRequestor.CLASSES);
790         }
791         return kinds;
792     }
793     
794     
795     private static int internalGetPossibleTypeKinds(ASTNode node) {
796         int kind= SimilarElementsRequestor.ALL_TYPES;
797
798         int mask= SimilarElementsRequestor.ALL_TYPES | SimilarElementsRequestor.VOIDTYPE;
799         
800         ASTNode parent= node.getParent();
801         while (parent instanceof QualifiedName) {
802             if (node.getLocationInParent() == QualifiedName.QUALIFIER_PROPERTY) {
803                 return SimilarElementsRequestor.REF_TYPES;
804             }
805             node= parent;
806             parent= parent.getParent();
807             mask= SimilarElementsRequestor.REF_TYPES;
808         }
809         while (parent instanceof Type) {
810             if (parent instanceof QualifiedType) {
811                 if (node.getLocationInParent() == QualifiedType.QUALIFIER_PROPERTY) {
812                     return mask & (SimilarElementsRequestor.REF_TYPES);
813                 }
814                 mask&= SimilarElementsRequestor.REF_TYPES;
815             } else if (parent instanceof ParameterizedType) {
816                 if (node.getLocationInParent() == ParameterizedType.TYPE_ARGUMENTS_PROPERTY) {
817                     return mask & SimilarElementsRequestor.REF_TYPES_AND_VAR;
818                 }
819                 mask&= SimilarElementsRequestor.CLASSES | SimilarElementsRequestor.INTERFACES;
820             } else if (parent instanceof WildcardType) {
821                 if (node.getLocationInParent() == WildcardType.BOUND_PROPERTY) {
822                     return mask & SimilarElementsRequestor.REF_TYPES_AND_VAR;
823                 }
824             }
825             node= parent;
826             parent= parent.getParent();
827         }
828
829         switch (parent.getNodeType()) {
830             case ASTNode.TYPE_DECLARATION:
831                 if (node.getLocationInParent() == TypeDeclaration.SUPER_INTERFACE_TYPES_PROPERTY) {
832                     kind= SimilarElementsRequestor.INTERFACES;
833                 } else if (node.getLocationInParent() == TypeDeclaration.SUPERCLASS_TYPE_PROPERTY) {
834                     kind= SimilarElementsRequestor.CLASSES;
835                 }
836                 break;
837             case ASTNode.ENUM_DECLARATION:
838                 kind= SimilarElementsRequestor.INTERFACES;
839                 break;
840             case ASTNode.METHOD_DECLARATION:
841                 if (node.getLocationInParent() == MethodDeclaration.THROWN_EXCEPTIONS_PROPERTY) {
842                     kind= SimilarElementsRequestor.CLASSES;
843                 } else if (node.getLocationInParent() == MethodDeclaration.RETURN_TYPE2_PROPERTY) {
844                     kind= SimilarElementsRequestor.ALL_TYPES | SimilarElementsRequestor.VOIDTYPE;
845                 }
846                 break;
847             case ASTNode.ANNOTATION_TYPE_MEMBER_DECLARATION:
848                 kind= SimilarElementsRequestor.PRIMITIVETYPES | SimilarElementsRequestor.ANNOTATIONS | SimilarElementsRequestor.ENUMS;
849                 break;
850             case ASTNode.INSTANCEOF_EXPRESSION:
851                 kind= SimilarElementsRequestor.REF_TYPES;
852                 break;
853             case ASTNode.THROW_STATEMENT:
854                 kind= SimilarElementsRequestor.CLASSES;
855                 break;
856             case ASTNode.CLASS_INSTANCE_CREATION:
857                 if (((ClassInstanceCreation) parent).getAnonymousClassDeclaration() == null) {
858                     kind= SimilarElementsRequestor.CLASSES;
859                 } else {
860                     kind= SimilarElementsRequestor.CLASSES | SimilarElementsRequestor.INTERFACES;
861                 }
862                 break;
863             case ASTNode.SINGLE_VARIABLE_DECLARATION:
864                 int superParent= parent.getParent().getNodeType();
865                 if (superParent == ASTNode.CATCH_CLAUSE) {
866                     kind= SimilarElementsRequestor.CLASSES;
867                 }
868                 break;
869             case ASTNode.TAG_ELEMENT:
870                 kind= SimilarElementsRequestor.REF_TYPES;
871                 break;
872             case ASTNode.MARKER_ANNOTATION:
873             case ASTNode.SINGLE_MEMBER_ANNOTATION:
874             case ASTNode.NORMAL_ANNOTATION:
875                 kind= SimilarElementsRequestor.ANNOTATIONS;
876                 break;
877             case ASTNode.TYPE_PARAMETER:
878                 if (((TypeParameter) parent).typeBounds().indexOf(node) > 0) {
879                     kind= SimilarElementsRequestor.INTERFACES;
880                 } else {
881                     kind= SimilarElementsRequestor.REF_TYPES_AND_VAR;
882                 }
883                 break;
884             case ASTNode.TYPE_LITERAL:
885                 kind= SimilarElementsRequestor.REF_TYPES;
886                 break;
887             default:
888         }
889         return kind & mask;
890     }
891
892     public static String JavaDoc getFullName(Name name) {
893         return name.getFullyQualifiedName();
894     }
895
896     public static ICompilationUnit findCompilationUnitForBinding(ICompilationUnit cu, CompilationUnit astRoot, ITypeBinding binding) throws JavaModelException {
897         if (binding == null || !binding.isFromSource() || binding.isTypeVariable() || binding.isWildcardType()) {
898             return null;
899         }
900         ASTNode node= astRoot.findDeclaringNode(binding.getTypeDeclaration());
901         if (node == null) {
902             ICompilationUnit targetCU= Bindings.findCompilationUnit(binding, cu.getJavaProject());
903             if (targetCU != null) {
904                 return targetCU;
905             }
906             return null;
907         } else if (node instanceof AbstractTypeDeclaration || node instanceof AnonymousClassDeclaration) {
908             return cu;
909         }
910         return null;
911     }
912
913
914     private static final Code[] CODE_ORDER= { PrimitiveType.CHAR, PrimitiveType.SHORT, PrimitiveType.INT, PrimitiveType.LONG, PrimitiveType.FLOAT, PrimitiveType.DOUBLE };
915
916     public static ITypeBinding[] getNarrowingTypes(AST ast, ITypeBinding type) {
917         ArrayList JavaDoc res= new ArrayList JavaDoc();
918         res.add(type);
919         if (type.isPrimitive()) {
920             Code code= PrimitiveType.toCode(type.getName());
921             for (int i= 0; i < CODE_ORDER.length && code != CODE_ORDER[i]; i++) {
922                 String JavaDoc typeName= CODE_ORDER[i].toString();
923                 res.add(ast.resolveWellKnownType(typeName));
924             }
925         }
926         return (ITypeBinding[]) res.toArray(new ITypeBinding[res.size()]);
927     }
928     
929     public static ITypeBinding[] getRelaxingTypes(AST ast, ITypeBinding type) {
930         ArrayList JavaDoc res= new ArrayList JavaDoc();
931         res.add(type);
932         if (type.isArray()) {
933             res.add(ast.resolveWellKnownType("java.lang.Object")); //$NON-NLS-1$
934
res.add(ast.resolveWellKnownType("java.io.Serializable")); //$NON-NLS-1$
935
res.add(ast.resolveWellKnownType("java.lang.Cloneable")); //$NON-NLS-1$
936
} else if (type.isPrimitive()) {
937             Code code= PrimitiveType.toCode(type.getName());
938             boolean found= false;
939             for (int i= 0; i < CODE_ORDER.length; i++) {
940                 if (found) {
941                     String JavaDoc typeName= CODE_ORDER[i].toString();
942                     res.add(ast.resolveWellKnownType(typeName));
943                 }
944                 if (code == CODE_ORDER[i]) {
945                     found= true;
946                 }
947             }
948         } else {
949             collectRelaxingTypes(res, type);
950         }
951         return (ITypeBinding[]) res.toArray(new ITypeBinding[res.size()]);
952     }
953
954     private static void collectRelaxingTypes(Collection JavaDoc res, ITypeBinding type) {
955         ITypeBinding[] interfaces= type.getInterfaces();
956         for (int i= 0; i < interfaces.length; i++) {
957             ITypeBinding curr= interfaces[i];
958             if (!res.contains(curr)) {
959                 res.add(curr);
960             }
961             collectRelaxingTypes(res, curr);
962         }
963         ITypeBinding binding= type.getSuperclass();
964         if (binding != null) {
965             if (!res.contains(binding)) {
966                 res.add(binding);
967             }
968             collectRelaxingTypes(res, binding);
969         }
970     }
971     
972     public static String JavaDoc[] getUsedVariableNames(ASTNode node) {
973         CompilationUnit root= (CompilationUnit) node.getRoot();
974         Collection JavaDoc res= (new ScopeAnalyzer(root)).getUsedVariableNames(node.getStartPosition(), node.getLength());
975         return (String JavaDoc[]) res.toArray(new String JavaDoc[res.size()]);
976     }
977
978     private static boolean isVariableDefinedInContext(IBinding binding, ITypeBinding typeVariable) {
979         if (binding.getKind() == IBinding.VARIABLE) {
980             IVariableBinding var= (IVariableBinding) binding;
981             binding= var.getDeclaringMethod();
982             if (binding == null) {
983                 binding= var.getDeclaringClass();
984             }
985         }
986         if (binding instanceof IMethodBinding) {
987             if (binding == typeVariable.getDeclaringMethod()) {
988                 return true;
989             }
990             binding= ((IMethodBinding) binding).getDeclaringClass();
991         }
992
993         while (binding instanceof ITypeBinding) {
994             if (binding == typeVariable.getDeclaringClass()) {
995                 return true;
996             }
997             if (Modifier.isStatic(binding.getModifiers())) {
998                 break;
999             }
1000            binding= ((ITypeBinding) binding).getDeclaringClass();
1001        }
1002        return false;
1003    }
1004
1005    public static boolean isUseableTypeInContext(ITypeBinding[] binding, IBinding context, boolean noWildcards) {
1006        for (int i= 0; i < binding.length; i++) {
1007            if (!isUseableTypeInContext(binding[i], context, noWildcards)) {
1008                return false;
1009            }
1010        }
1011        return true;
1012    }
1013
1014
1015    public static boolean isUseableTypeInContext(ITypeBinding type, IBinding context, boolean noWildcards) {
1016        if (type.isArray()) {
1017            type= type.getElementType();
1018        }
1019        if (type.isAnonymous()) {
1020            return false;
1021        }
1022        if (type.isRawType() || type.isPrimitive()) {
1023            return true;
1024        }
1025        if (type.isTypeVariable()) {
1026            return isVariableDefinedInContext(context, type);
1027        }
1028        if (type.isGenericType()) {
1029            ITypeBinding[] typeParameters= type.getTypeParameters();
1030            for (int i= 0; i < typeParameters.length; i++) {
1031                if (!isUseableTypeInContext(typeParameters[i], context, noWildcards)) {
1032                    return false;
1033                }
1034            }
1035            return true;
1036        }
1037        if (type.isParameterizedType()) {
1038            ITypeBinding[] typeArguments= type.getTypeArguments();
1039            for (int i= 0; i < typeArguments.length; i++) {
1040                if (!isUseableTypeInContext(typeArguments[i], context, noWildcards)) {
1041                    return false;
1042                }
1043            }
1044            return true;
1045        }
1046        if (type.isCapture()) {
1047            type= type.getWildcard();
1048        }
1049        
1050        if (type.isWildcardType()) {
1051            if (noWildcards) {
1052                return false;
1053            }
1054            if (type.getBound() != null) {
1055                return isUseableTypeInContext(type.getBound(), context, noWildcards);
1056            }
1057        }
1058        return true;
1059    }
1060        
1061    /**
1062     * Use this method before creating a type for a wildcard. Either to assign a wildcard to a new type or for a type to be assigned.
1063     *
1064     * @param wildcardType the wildcard type to normalize
1065     * @param isBindingToAssign If true, then a new receiver type is searched (X x= s), else the type of a sender (R r= x)
1066     * @param ast th current AST
1067     * @return Returns the normalized binding or null when only the 'null' binding
1068     */

1069    public static ITypeBinding normalizeWildcardType(ITypeBinding wildcardType, boolean isBindingToAssign, AST ast) {
1070        ITypeBinding bound= wildcardType.getBound();
1071        if (isBindingToAssign) {
1072            if (bound == null || !wildcardType.isUpperbound()) {
1073                return ast.resolveWellKnownType("java.lang.Object"); //$NON-NLS-1$
1074
}
1075        } else {
1076            if (bound == null || wildcardType.isUpperbound()) {
1077                return null;
1078            }
1079        }
1080        return bound;
1081    }
1082
1083    // pretty signatures
1084

1085    public static String JavaDoc getTypeSignature(ITypeBinding type) {
1086        return BindingLabelProvider.getBindingLabel(type, BindingLabelProvider.DEFAULT_TEXTFLAGS);
1087    }
1088
1089    public static String JavaDoc getMethodSignature(IMethodBinding binding, boolean inOtherCU) {
1090        StringBuffer JavaDoc buf= new StringBuffer JavaDoc();
1091        if (inOtherCU && !binding.isConstructor()) {
1092            buf.append(binding.getDeclaringClass().getTypeDeclaration().getName()).append('.'); // simple type name
1093
}
1094        return BindingLabelProvider.getBindingLabel(binding, BindingLabelProvider.DEFAULT_TEXTFLAGS);
1095    }
1096
1097    public static String JavaDoc getMethodSignature(String JavaDoc name, ITypeBinding[] params, boolean isVarArgs) {
1098        StringBuffer JavaDoc buf= new StringBuffer JavaDoc();
1099        buf.append(name).append('(');
1100        for (int i= 0; i < params.length; i++) {
1101            if (i > 0) {
1102                buf.append(JavaElementLabels.COMMA_STRING);
1103            }
1104            if (isVarArgs && i == params.length - 1) {
1105                buf.append(getTypeSignature(params[i].getElementType()));
1106                buf.append("..."); //$NON-NLS-1$
1107
} else {
1108                buf.append(getTypeSignature(params[i]));
1109            }
1110        }
1111        buf.append(')');
1112        return buf.toString();
1113    }
1114
1115    public static CompilationUnit createQuickFixAST(ICompilationUnit compilationUnit, IProgressMonitor monitor) {
1116        ASTParser astParser= ASTParser.newParser(ASTProvider.SHARED_AST_LEVEL);
1117        astParser.setSource(compilationUnit);
1118        astParser.setResolveBindings(true);
1119        astParser.setStatementsRecovery(ASTProvider.SHARED_AST_STATEMENT_RECOVERY);
1120        astParser.setBindingsRecovery(ASTProvider.SHARED_BINDING_RECOVERY);
1121        return (CompilationUnit) astParser.createAST(monitor);
1122    }
1123
1124}
1125
Popular Tags