1 /*******************************************************************************
2 * Copyright (c) 2000, 2011 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
9 * IBM Corporation - initial API and implementation
10 *******************************************************************************/
12 package org.eclipse.jdt.internal.ui.text.correction;
14 import java.util.ArrayList;
15 import java.util.Collection;
16 import java.util.HashSet;
17 import java.util.Iterator;
18 import java.util.List;
20 import org.eclipse.core.runtime.IProgressMonitor;
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.PrimitiveType.Code;
61 import org.eclipse.jdt.core.dom.QualifiedName;
62 import org.eclipse.jdt.core.dom.QualifiedType;
63 import org.eclipse.jdt.core.dom.SimpleName;
64 import org.eclipse.jdt.core.dom.SimpleType;
65 import org.eclipse.jdt.core.dom.SingleVariableDeclaration;
66 import org.eclipse.jdt.core.dom.Statement;
67 import org.eclipse.jdt.core.dom.StructuralPropertyDescriptor;
68 import org.eclipse.jdt.core.dom.SuperConstructorInvocation;
69 import org.eclipse.jdt.core.dom.SuperMethodInvocation;
70 import org.eclipse.jdt.core.dom.SwitchCase;
71 import org.eclipse.jdt.core.dom.SwitchStatement;
72 import org.eclipse.jdt.core.dom.TagElement;
73 import org.eclipse.jdt.core.dom.TryStatement;
74 import org.eclipse.jdt.core.dom.Type;
75 import org.eclipse.jdt.core.dom.TypeDeclaration;
76 import org.eclipse.jdt.core.dom.TypeLiteral;
77 import org.eclipse.jdt.core.dom.TypeParameter;
78 import org.eclipse.jdt.core.dom.VariableDeclaration;
79 import org.eclipse.jdt.core.dom.VariableDeclarationExpression;
80 import org.eclipse.jdt.core.dom.VariableDeclarationFragment;
81 import org.eclipse.jdt.core.dom.VariableDeclarationStatement;
82 import org.eclipse.jdt.core.dom.WildcardType;
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;
91 import org.eclipse.jdt.ui.JavaElementLabels;
93 import org.eclipse.jdt.internal.ui.javaeditor.ASTProvider;
94 import org.eclipse.jdt.internal.ui.viewsupport.BasicElementLabels;
95 import org.eclipse.jdt.internal.ui.viewsupport.BindingLabelProvider;
97 public class ASTResolving {
99 public static ITypeBinding guessBindingForReference(ASTNode node) {
100 return Bindings.normalizeTypeBinding(getPossibleReferenceBinding(node));
103 private static ITypeBinding getPossibleReferenceBinding(ASTNode node) {
104 ASTNode parent= node.getParent();
105 switch (parent.getNodeType()) {
106 case ASTNode.ASSIGNMENT:
107 Assignment assignment= (Assignment) parent;
108 if (node.equals(assignment.getLeftHandSide())) {
109 // field write access: xx= expression
110 return assignment.getRightHandSide().resolveTypeBinding();
113 return assignment.getLeftHandSide().resolveTypeBinding();
114 case ASTNode.INFIX_EXPRESSION:
115 InfixExpression infix= (InfixExpression) parent;
116 InfixExpression.Operator op= infix.getOperator();
117 if (op == InfixExpression.Operator.CONDITIONAL_AND || op == InfixExpression.Operator.CONDITIONAL_OR) {
119 return infix.getAST().resolveWellKnownType("boolean"); //$NON-NLS-1$
120 } else if (op == InfixExpression.Operator.LEFT_SHIFT || op == InfixExpression.Operator.RIGHT_SHIFT_UNSIGNED || op == InfixExpression.Operator.RIGHT_SHIFT_SIGNED) {
121 // asymmetric operation
122 return infix.getAST().resolveWellKnownType("int"); //$NON-NLS-1$
124 if (node.equals(infix.getLeftOperand())) {
125 // xx operation expression
126 ITypeBinding rigthHandBinding= infix.getRightOperand().resolveTypeBinding();
127 if (rigthHandBinding != null) {
128 return rigthHandBinding;
131 // expression operation xx
132 ITypeBinding leftHandBinding= infix.getLeftOperand().resolveTypeBinding();
133 if (leftHandBinding != null) {
134 return leftHandBinding;
137 if (op != InfixExpression.Operator.EQUALS && op != InfixExpression.Operator.NOT_EQUALS) {
138 return infix.getAST().resolveWellKnownType("int"); //$NON-NLS-1$
141 case ASTNode.INSTANCEOF_EXPRESSION:
142 InstanceofExpression instanceofExpression= (InstanceofExpression) parent;
143 return instanceofExpression.getRightOperand().resolveBinding();
144 case ASTNode.VARIABLE_DECLARATION_FRAGMENT:
145 VariableDeclarationFragment frag= (VariableDeclarationFragment) parent;
146 if (frag.getInitializer().equals(node)) {
147 return frag.getName().resolveTypeBinding();
150 case ASTNode.SUPER_METHOD_INVOCATION:
151 SuperMethodInvocation superMethodInvocation= (SuperMethodInvocation) parent;
152 IMethodBinding superMethodBinding= ASTNodes.getMethodBinding(superMethodInvocation.getName());
153 if (superMethodBinding != null) {
154 return getParameterTypeBinding(node, superMethodInvocation.arguments(), superMethodBinding);
157 case ASTNode.METHOD_INVOCATION:
158 MethodInvocation methodInvocation= (MethodInvocation) parent;
159 IMethodBinding methodBinding= methodInvocation.resolveMethodBinding();
160 if (methodBinding != null) {
161 return getParameterTypeBinding(node, methodInvocation.arguments(), methodBinding);
164 case ASTNode.SUPER_CONSTRUCTOR_INVOCATION: {
165 SuperConstructorInvocation superInvocation= (SuperConstructorInvocation) parent;
166 IMethodBinding superBinding= superInvocation.resolveConstructorBinding();
167 if (superBinding != null) {
168 return getParameterTypeBinding(node, superInvocation.arguments(), superBinding);
172 case ASTNode.CONSTRUCTOR_INVOCATION: {
173 ConstructorInvocation constrInvocation= (ConstructorInvocation) parent;
174 IMethodBinding constrBinding= constrInvocation.resolveConstructorBinding();
175 if (constrBinding != null) {
176 return getParameterTypeBinding(node, constrInvocation.arguments(), constrBinding);
180 case ASTNode.CLASS_INSTANCE_CREATION: {
181 ClassInstanceCreation creation= (ClassInstanceCreation) parent;
182 IMethodBinding creationBinding= creation.resolveConstructorBinding();
183 if (creationBinding != null) {
184 return getParameterTypeBinding(node, creation.arguments(), creationBinding);
188 case ASTNode.PARENTHESIZED_EXPRESSION:
189 return guessBindingForReference(parent);
190 case ASTNode.ARRAY_ACCESS:
191 if (((ArrayAccess) parent).getIndex().equals(node)) {
192 return parent.getAST().resolveWellKnownType("int"); //$NON-NLS-1$
194 ITypeBinding parentBinding= getPossibleReferenceBinding(parent);
195 if (parentBinding == null) {
196 parentBinding= parent.getAST().resolveWellKnownType("java.lang.Object"); //$NON-NLS-1$
198 return parentBinding.createArrayType(1);
200 case ASTNode.ARRAY_CREATION:
201 if (((ArrayCreation) parent).dimensions().contains(node)) {
202 return parent.getAST().resolveWellKnownType("int"); //$NON-NLS-1$
205 case ASTNode.ARRAY_INITIALIZER:
206 ASTNode initializerParent= parent.getParent();
208 while (initializerParent instanceof ArrayInitializer) {
209 initializerParent= initializerParent.getParent();
212 Type creationType= null;
213 if (initializerParent instanceof ArrayCreation) {
214 creationType= ((ArrayCreation) initializerParent).getType();
215 } else if (initializerParent instanceof VariableDeclaration) {
216 VariableDeclaration varDecl= (VariableDeclaration) initializerParent;
217 creationType= ASTNodes.getType(varDecl);
218 dim-= varDecl.getExtraDimensions();
219 } else if (initializerParent instanceof MemberValuePair) {
220 String name= ((MemberValuePair) initializerParent).getName().getIdentifier();
221 IMethodBinding annotMember= findAnnotationMember((Annotation) initializerParent.getParent(), name);
222 if (annotMember != null) {
223 return getReducedDimensionBinding(annotMember.getReturnType(), dim);
226 if (creationType != null) {
227 while ((creationType instanceof ArrayType) && dim > 0) {
228 creationType= ((ArrayType) creationType).getComponentType();
231 return creationType.resolveBinding();
234 case ASTNode.CONDITIONAL_EXPRESSION:
235 ConditionalExpression expression= (ConditionalExpression) parent;
236 if (node.equals(expression.getExpression())) {
237 return parent.getAST().resolveWellKnownType("boolean"); //$NON-NLS-1$
239 if (node.equals(expression.getElseExpression())) {
240 return expression.getThenExpression().resolveTypeBinding();
242 return expression.getElseExpression().resolveTypeBinding();
243 case ASTNode.POSTFIX_EXPRESSION:
244 return parent.getAST().resolveWellKnownType("int"); //$NON-NLS-1$
245 case ASTNode.PREFIX_EXPRESSION:
246 if (((PrefixExpression) parent).getOperator() == PrefixExpression.Operator.NOT) {
247 return parent.getAST().resolveWellKnownType("boolean"); //$NON-NLS-1$
249 return parent.getAST().resolveWellKnownType("int"); //$NON-NLS-1$
250 case ASTNode.IF_STATEMENT:
251 case ASTNode.WHILE_STATEMENT:
252 case ASTNode.DO_STATEMENT:
253 if (node instanceof Expression) {
254 return parent.getAST().resolveWellKnownType("boolean"); //$NON-NLS-1$
257 case ASTNode.SWITCH_STATEMENT:
258 if (((SwitchStatement) parent).getExpression().equals(node)) {
259 return parent.getAST().resolveWellKnownType("int"); //$NON-NLS-1$
262 case ASTNode.RETURN_STATEMENT:
263 MethodDeclaration decl= ASTResolving.findParentMethodDeclaration(parent);
264 if (decl != null && !decl.isConstructor()) {
265 return decl.getReturnType2().resolveBinding();
268 case ASTNode.CAST_EXPRESSION:
269 return ((CastExpression) parent).getType().resolveBinding();
270 case ASTNode.THROW_STATEMENT:
271 case ASTNode.CATCH_CLAUSE:
272 return parent.getAST().resolveWellKnownType("java.lang.Exception"); //$NON-NLS-1$
273 case ASTNode.FIELD_ACCESS:
274 if (node.equals(((FieldAccess) parent).getName())) {
275 return getPossibleReferenceBinding(parent);
278 case ASTNode.SUPER_FIELD_ACCESS:
279 return getPossibleReferenceBinding(parent);
280 case ASTNode.QUALIFIED_NAME:
281 if (node.equals(((QualifiedName) parent).getName())) {
282 return getPossibleReferenceBinding(parent);
285 case ASTNode.SWITCH_CASE:
286 if (node.equals(((SwitchCase) parent).getExpression()) && parent.getParent() instanceof SwitchStatement) {
287 return ((SwitchStatement) parent.getParent()).getExpression().resolveTypeBinding();
290 case ASTNode.ASSERT_STATEMENT:
291 if (node.getLocationInParent() == AssertStatement.EXPRESSION_PROPERTY) {
292 return parent.getAST().resolveWellKnownType("boolean"); //$NON-NLS-1$
294 return parent.getAST().resolveWellKnownType("java.lang.String"); //$NON-NLS-1$
295 case ASTNode.SINGLE_MEMBER_ANNOTATION: {
296 IMethodBinding annotMember= findAnnotationMember((Annotation) parent, "value"); //$NON-NLS-1$
297 if (annotMember != null) {
298 return annotMember.getReturnType();
302 case ASTNode.MEMBER_VALUE_PAIR: {
303 String name= ((MemberValuePair) parent).getName().getIdentifier();
304 IMethodBinding annotMember= findAnnotationMember((Annotation) parent.getParent(), name);
305 if (annotMember != null) {
306 return annotMember.getReturnType();
317 private static IMethodBinding findAnnotationMember(Annotation annotation, String name) {
318 ITypeBinding annotBinding= annotation.resolveTypeBinding();
319 if (annotBinding != null) {
320 return Bindings.findMethodInType(annotBinding, name, (String[]) null);
325 public static Type guessTypeForReference(AST ast, ASTNode node) {
326 ASTNode parent= node.getParent();
327 while (parent != null) {
328 switch (parent.getNodeType()) {
329 case ASTNode.VARIABLE_DECLARATION_FRAGMENT:
330 if (((VariableDeclarationFragment) parent).getInitializer() == node) {
331 return ASTNodeFactory.newType(ast, (VariableDeclaration) parent);
334 case ASTNode.SINGLE_VARIABLE_DECLARATION:
335 if (((VariableDeclarationFragment) parent).getInitializer() == node) {
336 return ASTNodeFactory.newType(ast, (VariableDeclaration) parent);
339 case ASTNode.ARRAY_ACCESS:
340 if (!((ArrayAccess) parent).getIndex().equals(node)) {
341 Type type= guessTypeForReference(ast, parent);
343 return ast.newArrayType(type);
347 case ASTNode.FIELD_ACCESS:
348 if (node.equals(((FieldAccess) parent).getName())) {
350 parent= parent.getParent();
355 case ASTNode.SUPER_FIELD_ACCESS:
356 case ASTNode.PARENTHESIZED_EXPRESSION:
358 parent= parent.getParent();
360 case ASTNode.QUALIFIED_NAME:
361 if (node.equals(((QualifiedName) parent).getName())) {
363 parent= parent.getParent();
375 private static ITypeBinding getReducedDimensionBinding(ITypeBinding arrayBinding, int dimsToReduce) {
376 while (dimsToReduce > 0) {
377 arrayBinding= arrayBinding.getComponentType();
383 private static ITypeBinding getParameterTypeBinding(ASTNode node, List<Expression> args, IMethodBinding binding) {
384 ITypeBinding[] paramTypes= binding.getParameterTypes();
385 int index= args.indexOf(node);
386 if (binding.isVarargs() && index >= paramTypes.length - 1) {
387 return paramTypes[paramTypes.length - 1].getComponentType();
389 if (index >= 0 && index < paramTypes.length) {
390 return paramTypes[index];
395 public static ITypeBinding guessBindingForTypeReference(ASTNode node) {
396 StructuralPropertyDescriptor locationInParent= node.getLocationInParent();
397 if (locationInParent == QualifiedName.QUALIFIER_PROPERTY) {
398 return null; // can't guess type for X.A
400 if (locationInParent == SimpleType.NAME_PROPERTY) {
401 node= node.getParent();
403 ITypeBinding binding= Bindings.normalizeTypeBinding(getPossibleTypeBinding(node));
404 if (binding != null) {
405 if (binding.isWildcardType()) {
406 return normalizeWildcardType(binding, true, node.getAST());
412 private static ITypeBinding getPossibleTypeBinding(ASTNode node) {
413 ASTNode parent= node.getParent();
414 switch (parent.getNodeType()) {
415 case ASTNode.ARRAY_TYPE: {
417 while (parent.getParent() instanceof ArrayType) {
418 parent= parent.getParent();
421 ITypeBinding parentBinding= getPossibleTypeBinding(parent);
422 if (parentBinding != null && parentBinding.getDimensions() == dim) {
423 return parentBinding.getElementType();
427 case ASTNode.PARAMETERIZED_TYPE: {
428 ITypeBinding parentBinding= getPossibleTypeBinding(parent);
429 if (parentBinding == null || !parentBinding.isParameterizedType()) {
432 if (node.getLocationInParent() == ParameterizedType.TYPE_PROPERTY) {
433 return parentBinding;
436 ITypeBinding[] typeArguments= parentBinding.getTypeArguments();
437 List<Type> argumentNodes= ((ParameterizedType) parent).typeArguments();
438 int index= argumentNodes.indexOf(node);
439 if (index != -1 && typeArguments.length == argumentNodes.size()) {
440 return typeArguments[index];
444 case ASTNode.WILDCARD_TYPE: {
445 ITypeBinding parentBinding= getPossibleTypeBinding(parent);
446 if (parentBinding == null || !parentBinding.isWildcardType()) {
449 WildcardType wildcardType= (WildcardType) parent;
450 if (parentBinding.isUpperbound() == wildcardType.isUpperBound()) {
451 return parentBinding.getBound();
455 case ASTNode.QUALIFIED_TYPE: {
456 ITypeBinding parentBinding= getPossibleTypeBinding(parent);
457 if (parentBinding == null || !parentBinding.isMember()) {
460 if (node.getLocationInParent() == QualifiedType.QUALIFIER_PROPERTY) {
461 return parentBinding.getDeclaringClass();
463 return parentBinding;
465 case ASTNode.VARIABLE_DECLARATION_STATEMENT:
466 return guessVariableType(((VariableDeclarationStatement) parent).fragments());
467 case ASTNode.FIELD_DECLARATION:
468 return guessVariableType(((FieldDeclaration) parent).fragments());
469 case ASTNode.VARIABLE_DECLARATION_EXPRESSION:
470 return guessVariableType(((VariableDeclarationExpression) parent).fragments());
471 case ASTNode.SINGLE_VARIABLE_DECLARATION:
472 SingleVariableDeclaration varDecl= (SingleVariableDeclaration) parent;
473 if (varDecl.getInitializer() != null) {
474 return Bindings.normalizeTypeBinding(varDecl.getInitializer().resolveTypeBinding());
477 case ASTNode.ARRAY_CREATION:
478 ArrayCreation creation= (ArrayCreation) parent;
479 if (creation.getInitializer() != null) {
480 return creation.getInitializer().resolveTypeBinding();
482 return getPossibleReferenceBinding(parent);
483 case ASTNode.TYPE_LITERAL:
484 return ((TypeLiteral) parent).getType().resolveBinding();
485 case ASTNode.CLASS_INSTANCE_CREATION:
486 return getPossibleReferenceBinding(parent);
487 case ASTNode.CAST_EXPRESSION:
488 return getPossibleReferenceBinding(parent);
489 case ASTNode.TAG_ELEMENT:
490 TagElement tagElement= (TagElement) parent;
491 if (TagElement.TAG_THROWS.equals(tagElement.getTagName()) || TagElement.TAG_EXCEPTION.equals(tagElement.getTagName())) {
492 ASTNode methNode= tagElement.getParent().getParent();
493 if (methNode instanceof MethodDeclaration) {
494 List<Name> thrownExceptions= ((MethodDeclaration) methNode).thrownExceptions();
495 if (thrownExceptions.size() == 1) {
496 return thrownExceptions.get(0).resolveTypeBinding();
505 private static ITypeBinding guessVariableType(List<VariableDeclarationFragment> fragments) {
506 for (Iterator<VariableDeclarationFragment> iter= fragments.iterator(); iter.hasNext();) {
507 VariableDeclarationFragment frag= iter.next();
508 if (frag.getInitializer() != null) {
509 return Bindings.normalizeTypeBinding(frag.getInitializer().resolveTypeBinding());
516 * Finds all type bindings that contain a method of a given signature
517 * @param searchRoot the ast node to start the search from
518 * @param selector the method name
519 * @param arguments the method arguments
520 * @param context the context in which the method would be called
521 * @return returns all types known in the AST that have a method with a given name
523 public static ITypeBinding[] getQualifierGuess(ASTNode searchRoot, final String selector, List<Expression> arguments, final IBinding context) {
524 final int nArgs= arguments.size();
525 final ArrayList<ITypeBinding> result= new ArrayList<ITypeBinding>();
527 // test if selector is a object method
528 ITypeBinding binding= searchRoot.getAST().resolveWellKnownType("java.lang.Object"); //$NON-NLS-1$
529 IMethodBinding[] objectMethods= binding.getDeclaredMethods();
530 for (int i= 0; i < objectMethods.length; i++) {
531 IMethodBinding meth= objectMethods[i];
532 if (meth.getName().equals(selector) && meth.getParameterTypes().length == nArgs) {
533 return new ITypeBinding[] { binding };
537 visitAllBindings(searchRoot, new TypeBindingVisitor() {
538 private HashSet<String> fVisitedBindings= new HashSet<String>(100);
540 public boolean visit(ITypeBinding node) {
541 node= Bindings.normalizeTypeBinding(node);
546 if (!fVisitedBindings.add(node.getKey())) {
549 if (node.isGenericType()) {
550 return true; // only look at parameterized types
552 if (context != null && !isUseableTypeInContext(node, context, false)) {
556 IMethodBinding[] methods= node.getDeclaredMethods();
557 for (int i= 0; i < methods.length; i++) {
558 IMethodBinding meth= methods[i];
559 if (meth.getName().equals(selector) && meth.getParameterTypes().length == nArgs) {
566 return result.toArray(new ITypeBinding[result.size()]);
569 public static void visitAllBindings(ASTNode astRoot, TypeBindingVisitor visitor) {
571 astRoot.accept(new AllBindingsVisitor(visitor));
572 } catch (AllBindingsVisitor.VisitCancelledException e) {
576 private static class AllBindingsVisitor extends GenericVisitor {
577 private final TypeBindingVisitor fVisitor;
579 private static class VisitCancelledException extends RuntimeException {
580 private static final long serialVersionUID= 1L;
582 public AllBindingsVisitor(TypeBindingVisitor visitor) {
587 public boolean visit(SimpleName node) {
588 ITypeBinding binding= node.resolveTypeBinding();
589 if (binding != null) {
590 boolean res= fVisitor.visit(binding);
592 res= Bindings.visitHierarchy(binding, fVisitor);
595 throw new VisitCancelledException();
603 public static IBinding getParentMethodOrTypeBinding(ASTNode node) {
605 if (node instanceof MethodDeclaration) {
606 return ((MethodDeclaration) node).resolveBinding();
607 } else if (node instanceof AbstractTypeDeclaration) {
608 return ((AbstractTypeDeclaration) node).resolveBinding();
609 } else if (node instanceof AnonymousClassDeclaration) {
610 return ((AnonymousClassDeclaration) node).resolveBinding();
612 node= node.getParent();
613 } while (node != null);
618 public static BodyDeclaration findParentBodyDeclaration(ASTNode node) {
619 while ((node != null) && (!(node instanceof BodyDeclaration))) {
620 node= node.getParent();
622 return (BodyDeclaration) node;
625 public static BodyDeclaration findParentBodyDeclaration(ASTNode node, boolean treatModifiersOutside) {
626 StructuralPropertyDescriptor lastLocation= null;
628 while (node != null) {
629 if (node instanceof BodyDeclaration) {
630 BodyDeclaration decl= (BodyDeclaration) node;
631 if (!treatModifiersOutside || lastLocation != decl.getModifiersProperty()) {
634 treatModifiersOutside= false;
636 lastLocation= node.getLocationInParent();
637 node= node.getParent();
639 return (BodyDeclaration) node;
643 public static CompilationUnit findParentCompilationUnit(ASTNode node) {
644 return (CompilationUnit) findAncestor(node, ASTNode.COMPILATION_UNIT);
648 * Finds the parent type of a node.
650 * @param node the node inside the type to find
651 * @param treatModifiersOutside if set, modifiers are not part of their type, but of the type's parent
652 * @return returns either a AbstractTypeDeclaration or an AnonymousTypeDeclaration
654 public static ASTNode findParentType(ASTNode node, boolean treatModifiersOutside) {
655 StructuralPropertyDescriptor lastLocation= null;
657 while (node != null) {
658 if (node instanceof AbstractTypeDeclaration) {
659 AbstractTypeDeclaration decl= (AbstractTypeDeclaration) node;
660 if (!treatModifiersOutside || lastLocation != decl.getModifiersProperty()) {
663 } else if (node instanceof AnonymousClassDeclaration) {
666 lastLocation= node.getLocationInParent();
667 node= node.getParent();
672 public static ASTNode findParentType(ASTNode node) {
673 return findParentType(node, false);
677 * Returns the method binding of the node's parent method declaration or <code>null</code> if
678 * the node is not inside a method.
680 * @param node the ast node
681 * @return the method binding of the node's parent method declaration or <code>null</code> if
684 public static MethodDeclaration findParentMethodDeclaration(ASTNode node) {
685 while (node != null) {
686 if (node.getNodeType() == ASTNode.METHOD_DECLARATION) {
687 return (MethodDeclaration) node;
689 if (node instanceof AbstractTypeDeclaration || node instanceof AnonymousClassDeclaration) {
692 node= node.getParent();
697 public static ASTNode findAncestor(ASTNode node, int nodeType) {
698 while ((node != null) && (node.getNodeType() != nodeType)) {
699 node= node.getParent();
704 public static Statement findParentStatement(ASTNode node) {
705 while ((node != null) && (!(node instanceof Statement))) {
706 node= node.getParent();
707 if (node instanceof BodyDeclaration) {
711 return (Statement) node;
714 public static TryStatement findParentTryStatement(ASTNode node) {
715 while ((node != null) && (!(node instanceof TryStatement))) {
716 node= node.getParent();
717 if (node instanceof BodyDeclaration) {
721 return (TryStatement) node;
724 public static boolean isInsideConstructorInvocation(MethodDeclaration methodDeclaration, ASTNode node) {
725 if (methodDeclaration.isConstructor()) {
726 Statement statement= ASTResolving.findParentStatement(node);
727 if (statement instanceof ConstructorInvocation || statement instanceof SuperConstructorInvocation) {
728 return true; // argument in a this or super call
734 public static boolean isInsideModifiers(ASTNode node) {
735 while (node != null && !(node instanceof BodyDeclaration)) {
736 if (node instanceof Annotation) {
739 node= node.getParent();
744 public static boolean isInStaticContext(ASTNode selectedNode) {
745 BodyDeclaration decl= ASTResolving.findParentBodyDeclaration(selectedNode);
746 if (decl instanceof MethodDeclaration) {
747 if (isInsideConstructorInvocation((MethodDeclaration) decl, selectedNode)) {
750 return Modifier.isStatic(decl.getModifiers());
751 } else if (decl instanceof Initializer) {
752 return Modifier.isStatic(((Initializer)decl).getModifiers());
753 } else if (decl instanceof FieldDeclaration) {
754 return Modifier.isStatic(((FieldDeclaration)decl).getModifiers());
759 public static boolean isWriteAccess(Name selectedNode) {
760 ASTNode curr= selectedNode;
761 ASTNode parent= curr.getParent();
762 while (parent != null) {
763 switch (parent.getNodeType()) {
764 case ASTNode.QUALIFIED_NAME:
765 if (((QualifiedName) parent).getQualifier() == curr) {
769 case ASTNode.FIELD_ACCESS:
770 if (((FieldAccess) parent).getExpression() == curr) {
774 case ASTNode.SUPER_FIELD_ACCESS:
776 case ASTNode.ASSIGNMENT:
777 return ((Assignment) parent).getLeftHandSide() == curr;
778 case ASTNode.VARIABLE_DECLARATION_FRAGMENT:
779 case ASTNode.SINGLE_VARIABLE_DECLARATION:
780 return ((VariableDeclaration) parent).getName() == curr;
781 case ASTNode.POSTFIX_EXPRESSION:
783 case ASTNode.PREFIX_EXPRESSION:
784 PrefixExpression.Operator op= ((PrefixExpression) parent).getOperator();
785 return op == PrefixExpression.Operator.DECREMENT || op == PrefixExpression.Operator.INCREMENT;
791 parent= curr.getParent();
796 public static int getPossibleTypeKinds(ASTNode node, boolean is50OrHigher) {
797 int kinds= internalGetPossibleTypeKinds(node);
799 kinds &= (SimilarElementsRequestor.INTERFACES | SimilarElementsRequestor.CLASSES);
805 private static int internalGetPossibleTypeKinds(ASTNode node) {
806 int kind= SimilarElementsRequestor.ALL_TYPES;
808 int mask= SimilarElementsRequestor.ALL_TYPES | SimilarElementsRequestor.VOIDTYPE;
810 ASTNode parent= node.getParent();
811 while (parent instanceof QualifiedName) {
812 if (node.getLocationInParent() == QualifiedName.QUALIFIER_PROPERTY) {
813 return SimilarElementsRequestor.REF_TYPES;
816 parent= parent.getParent();
817 mask= SimilarElementsRequestor.REF_TYPES;
819 while (parent instanceof Type) {
820 if (parent instanceof QualifiedType) {
821 if (node.getLocationInParent() == QualifiedType.QUALIFIER_PROPERTY) {
822 return mask & (SimilarElementsRequestor.REF_TYPES);
824 mask&= SimilarElementsRequestor.REF_TYPES;
825 } else if (parent instanceof ParameterizedType) {
826 if (node.getLocationInParent() == ParameterizedType.TYPE_ARGUMENTS_PROPERTY) {
827 return mask & SimilarElementsRequestor.REF_TYPES_AND_VAR;
829 mask&= SimilarElementsRequestor.CLASSES | SimilarElementsRequestor.INTERFACES;
830 } else if (parent instanceof WildcardType) {
831 if (node.getLocationInParent() == WildcardType.BOUND_PROPERTY) {
832 return mask & SimilarElementsRequestor.REF_TYPES_AND_VAR;
836 parent= parent.getParent();
839 switch (parent.getNodeType()) {
840 case ASTNode.TYPE_DECLARATION:
841 if (node.getLocationInParent() == TypeDeclaration.SUPER_INTERFACE_TYPES_PROPERTY) {
842 kind= SimilarElementsRequestor.INTERFACES;
843 } else if (node.getLocationInParent() == TypeDeclaration.SUPERCLASS_TYPE_PROPERTY) {
844 kind= SimilarElementsRequestor.CLASSES;
847 case ASTNode.ENUM_DECLARATION:
848 kind= SimilarElementsRequestor.INTERFACES;
850 case ASTNode.METHOD_DECLARATION:
851 if (node.getLocationInParent() == MethodDeclaration.THROWN_EXCEPTIONS_PROPERTY) {
852 kind= SimilarElementsRequestor.CLASSES;
853 } else if (node.getLocationInParent() == MethodDeclaration.RETURN_TYPE2_PROPERTY) {
854 kind= SimilarElementsRequestor.ALL_TYPES | SimilarElementsRequestor.VOIDTYPE;
857 case ASTNode.ANNOTATION_TYPE_MEMBER_DECLARATION:
858 kind= SimilarElementsRequestor.PRIMITIVETYPES | SimilarElementsRequestor.ANNOTATIONS | SimilarElementsRequestor.ENUMS;
860 case ASTNode.INSTANCEOF_EXPRESSION:
861 kind= SimilarElementsRequestor.REF_TYPES;
863 case ASTNode.THROW_STATEMENT:
864 kind= SimilarElementsRequestor.CLASSES;
866 case ASTNode.CLASS_INSTANCE_CREATION:
867 if (((ClassInstanceCreation) parent).getAnonymousClassDeclaration() == null) {
868 kind= SimilarElementsRequestor.CLASSES;
870 kind= SimilarElementsRequestor.CLASSES | SimilarElementsRequestor.INTERFACES;
873 case ASTNode.SINGLE_VARIABLE_DECLARATION:
874 int superParent= parent.getParent().getNodeType();
875 if (superParent == ASTNode.CATCH_CLAUSE) {
876 kind= SimilarElementsRequestor.CLASSES;
879 case ASTNode.TAG_ELEMENT:
880 kind= SimilarElementsRequestor.REF_TYPES;
882 case ASTNode.MARKER_ANNOTATION:
883 case ASTNode.SINGLE_MEMBER_ANNOTATION:
884 case ASTNode.NORMAL_ANNOTATION:
885 kind= SimilarElementsRequestor.ANNOTATIONS;
887 case ASTNode.TYPE_PARAMETER:
888 if (((TypeParameter) parent).typeBounds().indexOf(node) > 0) {
889 kind= SimilarElementsRequestor.INTERFACES;
891 kind= SimilarElementsRequestor.REF_TYPES_AND_VAR;
894 case ASTNode.TYPE_LITERAL:
895 kind= SimilarElementsRequestor.REF_TYPES;
902 public static String getFullName(Name name) {
903 return name.getFullyQualifiedName();
906 public static ICompilationUnit findCompilationUnitForBinding(ICompilationUnit cu, CompilationUnit astRoot, ITypeBinding binding) throws JavaModelException {
907 if (binding == null || !binding.isFromSource() || binding.isTypeVariable() || binding.isWildcardType()) {
910 ASTNode node= astRoot.findDeclaringNode(binding.getTypeDeclaration());
912 ICompilationUnit targetCU= Bindings.findCompilationUnit(binding, cu.getJavaProject());
913 if (targetCU != null) {
917 } else if (node instanceof AbstractTypeDeclaration || node instanceof AnonymousClassDeclaration) {
924 private static final Code[] CODE_ORDER= { PrimitiveType.CHAR, PrimitiveType.SHORT, PrimitiveType.INT, PrimitiveType.LONG, PrimitiveType.FLOAT, PrimitiveType.DOUBLE };
926 public static ITypeBinding[] getNarrowingTypes(AST ast, ITypeBinding type) {
927 ArrayList<ITypeBinding> res= new ArrayList<ITypeBinding>();
929 if (type.isPrimitive()) {
930 Code code= PrimitiveType.toCode(type.getName());
931 for (int i= 0; i < CODE_ORDER.length && code != CODE_ORDER[i]; i++) {
932 String typeName= CODE_ORDER[i].toString();
933 res.add(ast.resolveWellKnownType(typeName));
936 return res.toArray(new ITypeBinding[res.size()]);
939 public static ITypeBinding[] getRelaxingTypes(AST ast, ITypeBinding type) {
940 ArrayList<ITypeBinding> res= new ArrayList<ITypeBinding>();
942 if (type.isArray()) {
943 res.add(ast.resolveWellKnownType("java.lang.Object")); //$NON-NLS-1$
944 // The following two types are not available in some j2me implementations, see https://bugs.eclipse.org/bugs/show_bug.cgi?id=288060 :
945 ITypeBinding serializable= ast.resolveWellKnownType("java.io.Serializable"); //$NON-NLS-1$
946 if (serializable != null)
947 res.add(serializable);
948 ITypeBinding cloneable= ast.resolveWellKnownType("java.lang.Cloneable"); //$NON-NLS-1$
949 if (cloneable != null)
951 } else if (type.isPrimitive()) {
952 Code code= PrimitiveType.toCode(type.getName());
953 boolean found= false;
954 for (int i= 0; i < CODE_ORDER.length; i++) {
956 String typeName= CODE_ORDER[i].toString();
957 res.add(ast.resolveWellKnownType(typeName));
959 if (code == CODE_ORDER[i]) {
964 collectRelaxingTypes(res, type);
966 return res.toArray(new ITypeBinding[res.size()]);
969 private static void collectRelaxingTypes(Collection<ITypeBinding> res, ITypeBinding type) {
970 ITypeBinding[] interfaces= type.getInterfaces();
971 for (int i= 0; i < interfaces.length; i++) {
972 ITypeBinding curr= interfaces[i];
973 if (!res.contains(curr)) {
976 collectRelaxingTypes(res, curr);
978 ITypeBinding binding= type.getSuperclass();
979 if (binding != null) {
980 if (!res.contains(binding)) {
983 collectRelaxingTypes(res, binding);
987 public static String[] getUsedVariableNames(ASTNode node) {
988 CompilationUnit root= (CompilationUnit) node.getRoot();
989 Collection<String> res= (new ScopeAnalyzer(root)).getUsedVariableNames(node.getStartPosition(), node.getLength());
990 return res.toArray(new String[res.size()]);
993 private static boolean isVariableDefinedInContext(IBinding binding, ITypeBinding typeVariable) {
994 if (binding.getKind() == IBinding.VARIABLE) {
995 IVariableBinding var= (IVariableBinding) binding;
996 binding= var.getDeclaringMethod();
997 if (binding == null) {
998 binding= var.getDeclaringClass();
1001 if (binding instanceof IMethodBinding) {
1002 if (binding == typeVariable.getDeclaringMethod()) {
1005 binding= ((IMethodBinding) binding).getDeclaringClass();
1008 while (binding instanceof ITypeBinding) {
1009 if (binding == typeVariable.getDeclaringClass()) {
1012 if (Modifier.isStatic(binding.getModifiers())) {
1015 binding= ((ITypeBinding) binding).getDeclaringClass();
1020 public static boolean isUseableTypeInContext(ITypeBinding[] binding, IBinding context, boolean noWildcards) {
1021 for (int i= 0; i < binding.length; i++) {
1022 if (!isUseableTypeInContext(binding[i], context, noWildcards)) {
1030 public static boolean isUseableTypeInContext(ITypeBinding type, IBinding context, boolean noWildcards) {
1031 if (type.isArray()) {
1032 type= type.getElementType();
1034 if (type.isAnonymous()) {
1037 if (type.isRawType() || type.isPrimitive()) {
1040 if (type.isTypeVariable()) {
1041 return isVariableDefinedInContext(context, type);
1043 if (type.isGenericType()) {
1044 ITypeBinding[] typeParameters= type.getTypeParameters();
1045 for (int i= 0; i < typeParameters.length; i++) {
1046 if (!isUseableTypeInContext(typeParameters[i], context, noWildcards)) {
1052 if (type.isParameterizedType()) {
1053 ITypeBinding[] typeArguments= type.getTypeArguments();
1054 for (int i= 0; i < typeArguments.length; i++) {
1055 if (!isUseableTypeInContext(typeArguments[i], context, noWildcards)) {
1061 if (type.isCapture()) {
1062 type= type.getWildcard();
1065 if (type.isWildcardType()) {
1069 if (type.getBound() != null) {
1070 return isUseableTypeInContext(type.getBound(), context, noWildcards);
1077 * 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.
1079 * @param wildcardType the wildcard type to normalize
1080 * @param isBindingToAssign If true, then a new receiver type is searched (X x= s), else the type of a sender (R r= x)
1081 * @param ast th current AST
1082 * @return Returns the normalized binding or null when only the 'null' binding
1084 public static ITypeBinding normalizeWildcardType(ITypeBinding wildcardType, boolean isBindingToAssign, AST ast) {
1085 ITypeBinding bound= wildcardType.getBound();
1086 if (isBindingToAssign) {
1087 if (bound == null || !wildcardType.isUpperbound()) {
1088 return ast.resolveWellKnownType("java.lang.Object"); //$NON-NLS-1$
1091 if (bound == null || wildcardType.isUpperbound()) {
1098 // pretty signatures
1100 public static String getTypeSignature(ITypeBinding type) {
1101 return BindingLabelProvider.getBindingLabel(type, BindingLabelProvider.DEFAULT_TEXTFLAGS);
1104 public static String getMethodSignature(IMethodBinding binding) {
1105 return BindingLabelProvider.getBindingLabel(binding, BindingLabelProvider.DEFAULT_TEXTFLAGS);
1108 public static String getMethodSignature(String name, ITypeBinding[] params, boolean isVarArgs) {
1109 StringBuffer buf= new StringBuffer();
1110 buf.append(name).append('(');
1111 for (int i= 0; i < params.length; i++) {
1113 buf.append(JavaElementLabels.COMMA_STRING);
1115 if (isVarArgs && i == params.length - 1) {
1116 buf.append(getTypeSignature(params[i].getElementType()));
1117 buf.append("..."); //$NON-NLS-1$
1119 buf.append(getTypeSignature(params[i]));
1123 return BasicElementLabels.getJavaElementName(buf.toString());
1126 public static CompilationUnit createQuickFixAST(ICompilationUnit compilationUnit, IProgressMonitor monitor) {
1127 ASTParser astParser= ASTParser.newParser(ASTProvider.SHARED_AST_LEVEL);
1128 astParser.setSource(compilationUnit);
1129 astParser.setResolveBindings(true);
1130 astParser.setStatementsRecovery(ASTProvider.SHARED_AST_STATEMENT_RECOVERY);
1131 astParser.setBindingsRecovery(ASTProvider.SHARED_BINDING_RECOVERY);
1132 return (CompilationUnit) astParser.createAST(monitor);