blob: 1bc0d6f8f1dbac70f6ade231dcb1438c67685b5e [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2000, 2003 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Common Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/cpl-v10.html
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.jdt.internal.ui.text.correction;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import org.eclipse.jdt.core.ICompilationUnit;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.jdt.core.dom.*;
import org.eclipse.jdt.core.dom.PrimitiveType.Code;
import org.eclipse.jdt.internal.corext.dom.ASTNodes;
import org.eclipse.jdt.internal.corext.dom.Bindings;
import org.eclipse.jdt.internal.corext.util.JavaModelUtil;
public class ASTResolving {
public static ITypeBinding guessBindingForReference(ASTNode node) {
return Bindings.normalizeTypeBinding(getPossibleReferenceBinding(node));
}
private static ITypeBinding getPossibleReferenceBinding(ASTNode node) {
ASTNode parent= node.getParent();
switch (parent.getNodeType()) {
case ASTNode.ASSIGNMENT:
Assignment assignment= (Assignment) parent;
if (node.equals(assignment.getLeftHandSide())) {
// field write access: xx= expression
return assignment.getRightHandSide().resolveTypeBinding();
}
// read access
return assignment.getLeftHandSide().resolveTypeBinding();
case ASTNode.INFIX_EXPRESSION:
InfixExpression infix= (InfixExpression) parent;
InfixExpression.Operator op= infix.getOperator();
if (op == InfixExpression.Operator.CONDITIONAL_AND || op == InfixExpression.Operator.CONDITIONAL_OR) {
// boolean operation
return infix.getAST().resolveWellKnownType("boolean"); //$NON-NLS-1$
} else if (op == InfixExpression.Operator.LEFT_SHIFT || op == InfixExpression.Operator.RIGHT_SHIFT_UNSIGNED || op == InfixExpression.Operator.RIGHT_SHIFT_SIGNED) {
// assymetric operation
return infix.getAST().resolveWellKnownType("int"); //$NON-NLS-1$
}
if (node.equals(infix.getLeftOperand())) {
// xx op expression
ITypeBinding rigthHandBinding= infix.getRightOperand().resolveTypeBinding();
if (rigthHandBinding != null) {
return rigthHandBinding;
}
} else {
// expression op xx
ITypeBinding leftHandBinding= infix.getLeftOperand().resolveTypeBinding();
if (leftHandBinding != null) {
return leftHandBinding;
}
}
if (op != InfixExpression.Operator.EQUALS && op != InfixExpression.Operator.NOT_EQUALS) {
return infix.getAST().resolveWellKnownType("int"); //$NON-NLS-1$
}
break;
case ASTNode.INSTANCEOF_EXPRESSION:
InstanceofExpression instanceofExpression= (InstanceofExpression) parent;
return instanceofExpression.getRightOperand().resolveBinding();
case ASTNode.VARIABLE_DECLARATION_FRAGMENT:
VariableDeclarationFragment frag= (VariableDeclarationFragment) parent;
if (frag.getInitializer().equals(node)) {
return frag.getName().resolveTypeBinding();
}
break;
case ASTNode.SUPER_METHOD_INVOCATION:
SuperMethodInvocation superMethodInvocation= (SuperMethodInvocation) parent;
IMethodBinding superMethodBinding= ASTNodes.getMethodBinding(superMethodInvocation.getName());
if (superMethodBinding != null) {
return getParameterTypeBinding(node, superMethodInvocation.arguments(), superMethodBinding);
}
break;
case ASTNode.METHOD_INVOCATION:
MethodInvocation methodInvocation= (MethodInvocation) parent;
IMethodBinding methodBinding= methodInvocation.resolveMethodBinding();
if (methodBinding != null) {
return getParameterTypeBinding(node, methodInvocation.arguments(), methodBinding);
}
break;
case ASTNode.SUPER_CONSTRUCTOR_INVOCATION:
SuperConstructorInvocation superInvocation= (SuperConstructorInvocation) parent;
IMethodBinding superBinding= superInvocation.resolveConstructorBinding();
if (superBinding != null) {
return getParameterTypeBinding(node, superInvocation.arguments(), superBinding);
}
break;
case ASTNode.CONSTRUCTOR_INVOCATION:
ConstructorInvocation constrInvocation= (ConstructorInvocation) parent;
IMethodBinding constrBinding= constrInvocation.resolveConstructorBinding();
if (constrBinding != null) {
return getParameterTypeBinding(node, constrInvocation.arguments(), constrBinding);
}
break;
case ASTNode.CLASS_INSTANCE_CREATION:
ClassInstanceCreation creation= (ClassInstanceCreation) parent;
IMethodBinding creationBinding= creation.resolveConstructorBinding();
if (creationBinding != null) {
return getParameterTypeBinding(node, creation.arguments(), creationBinding);
}
break;
case ASTNode.PARENTHESIZED_EXPRESSION:
return guessBindingForReference(parent);
case ASTNode.ARRAY_ACCESS:
if (((ArrayAccess) parent).getIndex().equals(node)) {
return parent.getAST().resolveWellKnownType("int"); //$NON-NLS-1$
} else {
return getPossibleReferenceBinding(parent);
}
case ASTNode.ARRAY_CREATION:
if (((ArrayCreation) parent).dimensions().contains(node)) {
return parent.getAST().resolveWellKnownType("int"); //$NON-NLS-1$
}
break;
case ASTNode.ARRAY_INITIALIZER:
ASTNode initializerParent= parent.getParent();
if (initializerParent instanceof ArrayCreation) {
return ((ArrayCreation) initializerParent).getType().getElementType().resolveBinding();
}
break;
case ASTNode.CONDITIONAL_EXPRESSION:
ConditionalExpression expression= (ConditionalExpression) parent;
if (node.equals(expression.getExpression())) {
return parent.getAST().resolveWellKnownType("boolean"); //$NON-NLS-1$
}
if (node.equals(expression.getElseExpression())) {
return expression.getThenExpression().resolveTypeBinding();
}
return expression.getElseExpression().resolveTypeBinding();
case ASTNode.POSTFIX_EXPRESSION:
return parent.getAST().resolveWellKnownType("int"); //$NON-NLS-1$
case ASTNode.PREFIX_EXPRESSION:
if (((PrefixExpression) parent).getOperator() == PrefixExpression.Operator.NOT) {
return parent.getAST().resolveWellKnownType("boolean"); //$NON-NLS-1$
}
return parent.getAST().resolveWellKnownType("int"); //$NON-NLS-1$
case ASTNode.IF_STATEMENT:
case ASTNode.WHILE_STATEMENT:
case ASTNode.DO_STATEMENT:
if (node instanceof Expression) {
return parent.getAST().resolveWellKnownType("boolean"); //$NON-NLS-1$
}
break;
case ASTNode.SWITCH_STATEMENT:
if (((SwitchStatement) parent).getExpression().equals(node)) {
return parent.getAST().resolveWellKnownType("int"); //$NON-NLS-1$
}
break;
case ASTNode.RETURN_STATEMENT:
MethodDeclaration decl= findParentMethodDeclaration(parent);
if (decl != null) {
return decl.getReturnType().resolveBinding();
}
break;
case ASTNode.CAST_EXPRESSION:
return ((CastExpression) parent).getType().resolveBinding();
case ASTNode.THROW_STATEMENT:
case ASTNode.CATCH_CLAUSE:
return parent.getAST().resolveWellKnownType("java.lang.Exception"); //$NON-NLS-1$
case ASTNode.FIELD_ACCESS:
if (node.equals(((FieldAccess) parent).getName())) {
return getPossibleReferenceBinding(parent);
}
break;
case ASTNode.SUPER_FIELD_ACCESS:
return getPossibleReferenceBinding(parent);
case ASTNode.QUALIFIED_NAME:
if (node.equals(((QualifiedName) parent).getName())) {
return getPossibleReferenceBinding(parent);
}
break;
default:
// do nothing
}
return null;
}
public static Type guessTypeForReference(AST ast, ASTNode node) {
ASTNode parent= node.getParent();
while (parent != null) {
switch (parent.getNodeType()) {
case ASTNode.VARIABLE_DECLARATION_FRAGMENT:
if (((VariableDeclarationFragment) parent).getInitializer() == node) {
return ASTNodes.getType(ast, (VariableDeclaration) parent);
}
return null;
case ASTNode.SINGLE_VARIABLE_DECLARATION:
if (((VariableDeclarationFragment) parent).getInitializer() == node) {
return ASTNodes.getType(ast, (VariableDeclaration) parent);
}
return null;
case ASTNode.ARRAY_ACCESS:
if (!((ArrayAccess) parent).getIndex().equals(node)) {
Type type= guessTypeForReference(ast, parent);
if (type != null) {
return ast.newArrayType(type);
}
}
return null;
case ASTNode.FIELD_ACCESS:
if (node.equals(((FieldAccess) parent).getName())) {
node= parent;
parent= parent.getParent();
} else {
return null;
}
break;
case ASTNode.SUPER_FIELD_ACCESS:
case ASTNode.PARENTHESIZED_EXPRESSION:
node= parent;
parent= parent.getParent();
break;
case ASTNode.QUALIFIED_NAME:
if (node.equals(((QualifiedName) parent).getName())) {
node= parent;
parent= parent.getParent();
} else {
return null;
}
break;
default:
return null;
}
}
return null;
}
private static ITypeBinding getParameterTypeBinding(ASTNode node, List args, IMethodBinding binding) {
ITypeBinding[] paramTypes= binding.getParameterTypes();
int index= args.indexOf(node);
if (index >= 0 && index < paramTypes.length) {
return paramTypes[index];
}
return null;
}
public static ITypeBinding guessBindingForTypeReference(ASTNode node) {
return Bindings.normalizeTypeBinding(getPossibleTypeBinding(node));
}
private static ITypeBinding getPossibleTypeBinding(ASTNode node) {
ASTNode parent= node.getParent();
while (parent instanceof Type) {
parent= parent.getParent();
}
switch (parent.getNodeType()) {
case ASTNode.VARIABLE_DECLARATION_STATEMENT:
return guessVariableType(((VariableDeclarationStatement) parent).fragments());
case ASTNode.FIELD_DECLARATION:
return guessVariableType(((FieldDeclaration) parent).fragments());
case ASTNode.VARIABLE_DECLARATION_EXPRESSION:
return guessVariableType(((VariableDeclarationExpression) parent).fragments());
case ASTNode.SINGLE_VARIABLE_DECLARATION:
SingleVariableDeclaration varDecl= (SingleVariableDeclaration) parent;
if (varDecl.getInitializer() != null) {
return varDecl.getInitializer().resolveTypeBinding();
}
break;
case ASTNode.ARRAY_CREATION:
ArrayCreation creation= (ArrayCreation) parent;
if (creation.getInitializer() != null) {
return creation.getInitializer().resolveTypeBinding();
}
return getPossibleReferenceBinding(parent);
case ASTNode.TYPE_LITERAL:
case ASTNode.CLASS_INSTANCE_CREATION:
return getPossibleReferenceBinding(parent);
}
return null;
}
private static ITypeBinding guessVariableType(List fragments) {
for (Iterator iter= fragments.iterator(); iter.hasNext();) {
VariableDeclarationFragment frag= (VariableDeclarationFragment) iter.next();
if (frag.getInitializer() != null) {
return frag.getInitializer().resolveTypeBinding();
}
}
return null;
}
public static MethodDeclaration findParentMethodDeclaration(ASTNode node) {
while ((node != null) && (node.getNodeType() != ASTNode.METHOD_DECLARATION)) {
node= node.getParent();
}
return (MethodDeclaration) node;
}
public static BodyDeclaration findParentBodyDeclaration(ASTNode node) {
while ((node != null) && (!(node instanceof BodyDeclaration))) {
node= node.getParent();
}
return (BodyDeclaration) node;
}
public static CompilationUnit findParentCompilationUnit(ASTNode node) {
return (CompilationUnit) findAncestor(node, ASTNode.COMPILATION_UNIT);
}
/**
* Returns either a TypeDeclaration or an AnonymousTypeDeclaration
* @param node
* @return CompilationUnit
*/
public static ASTNode findParentType(ASTNode node) {
while ((node != null) && (node.getNodeType() != ASTNode.TYPE_DECLARATION) && (node.getNodeType() != ASTNode.ANONYMOUS_CLASS_DECLARATION)) {
node= node.getParent();
}
return node;
}
public static ASTNode findAncestor(ASTNode node, int nodeType) {
while ((node != null) && (node.getNodeType() != nodeType)) {
node= node.getParent();
}
return node;
}
public static Statement findParentStatement(ASTNode node) {
while ((node != null) && (!(node instanceof Statement))) {
node= node.getParent();
if (node instanceof BodyDeclaration) {
return null;
}
}
return (Statement) node;
}
public static TryStatement findParentTryStatement(ASTNode node) {
while ((node != null) && (!(node instanceof TryStatement))) {
node= node.getParent();
if (node instanceof BodyDeclaration) {
return null;
}
}
return (TryStatement) node;
}
public static boolean isInStaticContext(ASTNode selectedNode) {
BodyDeclaration decl= ASTResolving.findParentBodyDeclaration(selectedNode);
if (decl instanceof MethodDeclaration) {
MethodDeclaration methodDecl= (MethodDeclaration) decl;
if (methodDecl.isConstructor()) {
Statement statement= findParentStatement(selectedNode);
if (statement instanceof ConstructorInvocation || statement instanceof SuperConstructorInvocation) {
return true; // argument in a this or super call
}
}
return Modifier.isStatic(methodDecl.getModifiers());
} else if (decl instanceof Initializer) {
return Modifier.isStatic(((Initializer)decl).getModifiers());
} else if (decl instanceof FieldDeclaration) {
return Modifier.isStatic(((FieldDeclaration)decl).getModifiers());
}
return false;
}
public static boolean isWriteAccess(Name selectedNode) {
ASTNode curr= selectedNode;
ASTNode parent= curr.getParent();
while (parent != null) {
switch (parent.getNodeType()) {
case ASTNode.QUALIFIED_NAME:
if (((QualifiedName) parent).getQualifier() == curr) {
return false;
}
break;
case ASTNode.FIELD_ACCESS:
if (((FieldAccess) parent).getExpression() == curr) {
return false;
}
break;
case ASTNode.SUPER_FIELD_ACCESS:
break;
case ASTNode.ASSIGNMENT:
return ((Assignment) parent).getLeftHandSide() == curr;
case ASTNode.VARIABLE_DECLARATION_FRAGMENT:
case ASTNode.SINGLE_VARIABLE_DECLARATION:
return ((VariableDeclaration) parent).getName() == curr;
case ASTNode.POSTFIX_EXPRESSION:
case ASTNode.PREFIX_EXPRESSION:
return true;
default:
return false;
}
curr= parent;
parent= curr.getParent();
}
return false;
}
public static Type getTypeFromTypeBinding(AST ast, ITypeBinding binding) {
if (binding.isArray()) {
int dim= binding.getDimensions();
return ast.newArrayType(getTypeFromTypeBinding(ast, binding.getElementType()), dim);
} else if (binding.isPrimitive()) {
String name= binding.getName();
return ast.newPrimitiveType(PrimitiveType.toCode(name));
} else if (!binding.isNullType() && !binding.isAnonymous()) {
return ast.newSimpleType(ast.newSimpleName(binding.getName()));
}
return null;
}
private static TypeDeclaration findTypeDeclaration(List decls, String name) {
for (Iterator iter= decls.iterator(); iter.hasNext();) {
ASTNode elem= (ASTNode) iter.next();
if (elem instanceof TypeDeclaration) {
TypeDeclaration decl= (TypeDeclaration) elem;
if (name.equals(decl.getName().getIdentifier())) {
return decl;
}
}
}
return null;
}
public static TypeDeclaration findTypeDeclaration(CompilationUnit root, ITypeBinding binding) {
ArrayList names= new ArrayList(5);
while (binding != null) {
names.add(binding.getName());
binding= binding.getDeclaringClass();
}
List types= root.types();
for (int i= names.size() - 1; i >= 0; i--) {
String name= (String) names.get(i);
TypeDeclaration decl= findTypeDeclaration(types, name);
if (decl == null || i == 0) {
return decl;
}
types= decl.bodyDeclarations();
}
return null;
}
public static String getFullName(Name name) {
return ASTNodes.asString(name);
}
public static String getQualifier(Name name) {
if (name.isQualifiedName()) {
return getFullName(((QualifiedName) name).getQualifier());
}
return ""; //$NON-NLS-1$
}
public static String getSimpleName(Name name) {
if (name.isQualifiedName()) {
return ((QualifiedName) name).getName().getIdentifier();
} else {
return ((SimpleName) name).getIdentifier();
}
}
public static ICompilationUnit findCompilationUnitForBinding(ICompilationUnit cu, CompilationUnit astRoot, ITypeBinding binding) throws JavaModelException {
if (binding != null && binding.isFromSource() && astRoot.findDeclaringNode(binding) == null) {
ICompilationUnit targetCU= Bindings.findCompilationUnit(binding, cu.getJavaProject());
if (targetCU != null) {
return JavaModelUtil.toWorkingCopy(targetCU);
}
return null;
}
return cu;
}
private static final Code[] CODE_ORDER= { PrimitiveType.CHAR, PrimitiveType.SHORT, PrimitiveType.INT, PrimitiveType.LONG, PrimitiveType.FLOAT, PrimitiveType.DOUBLE };
public static ITypeBinding[] getRelaxingTypes(AST ast, ITypeBinding type) {
HashSet res= new HashSet();
res.add(type);
if (type.isArray()) {
res.add(ast.resolveWellKnownType("java.lang.Object")); //$NON-NLS-1$
res.add(ast.resolveWellKnownType("java.io.Serializable")); //$NON-NLS-1$
res.add(ast.resolveWellKnownType("java.lang.Cloneable")); //$NON-NLS-1$
} else if (type.isPrimitive()) {
Code code= PrimitiveType.toCode(type.getName());
boolean found= false;
for (int i= 0; i < CODE_ORDER.length; i++) {
if (found) {
String typeName= CODE_ORDER[i].toString();
res.add(ast.resolveWellKnownType(typeName));
}
if (code == CODE_ORDER[i]) {
found= true;
}
}
} else {
collectRelaxingTypes(res, type);
}
return (ITypeBinding[]) res.toArray(new ITypeBinding[res.size()]);
}
private static void collectRelaxingTypes(Set res, ITypeBinding type) {
ITypeBinding[] interfaces= type.getInterfaces();
for (int i= 0; i < interfaces.length; i++) {
ITypeBinding curr= interfaces[i];
res.add(curr);
collectRelaxingTypes(res, curr);
}
ITypeBinding binding= type.getSuperclass();
if (binding != null) {
res.add(binding);
collectRelaxingTypes(res, binding);
}
}
}