blob: da84a4dd234f988570bdf7386c996ad11008d5fe [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2002 International Business Machines Corp. and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Common Public License v0.5
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/cpl-v05.html
*
* Contributors:
* IBM Corporation - initial API and implementation
******************************************************************************/
package org.eclipse.jdt.core.dom;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration;
import org.eclipse.jdt.internal.compiler.ast.AbstractVariableDeclaration;
import org.eclipse.jdt.internal.compiler.ast.AllocationExpression;
import org.eclipse.jdt.internal.compiler.ast.ArrayAllocationExpression;
import org.eclipse.jdt.internal.compiler.ast.ArrayReference;
import org.eclipse.jdt.internal.compiler.ast.AstNode;
import org.eclipse.jdt.internal.compiler.ast.BinaryExpression;
import org.eclipse.jdt.internal.compiler.ast.CharLiteral;
import org.eclipse.jdt.internal.compiler.ast.ClassLiteralAccess;
import org.eclipse.jdt.internal.compiler.ast.CompoundAssignment;
import org.eclipse.jdt.internal.compiler.ast.FalseLiteral;
import org.eclipse.jdt.internal.compiler.ast.FieldReference;
import org.eclipse.jdt.internal.compiler.ast.Literal;
import org.eclipse.jdt.internal.compiler.ast.LocalDeclaration;
import org.eclipse.jdt.internal.compiler.ast.MessageSend;
import org.eclipse.jdt.internal.compiler.ast.NameReference;
import org.eclipse.jdt.internal.compiler.ast.OperatorExpression;
import org.eclipse.jdt.internal.compiler.ast.QualifiedNameReference;
import org.eclipse.jdt.internal.compiler.ast.SingleNameReference;
import org.eclipse.jdt.internal.compiler.ast.ThisReference;
import org.eclipse.jdt.internal.compiler.ast.TrueLiteral;
import org.eclipse.jdt.internal.compiler.ast.TypeReference;
import org.eclipse.jdt.internal.compiler.lookup.FieldBinding;
import org.eclipse.jdt.internal.compiler.lookup.LocalVariableBinding;
import org.eclipse.jdt.internal.compiler.lookup.BlockScope;
import org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding;
/**
* Internal class for resolving bindings using old ASTs.
*/
class DefaultBindingResolver extends BindingResolver {
/**
* This map is used to keep the correspondance between new bindings and the
* compiler bindings. This is an identity map. We should only create one object
* for one binding.
*/
Map compilerBindingsToASTBindings;
/**
* This map is used to retrieve an old ast node using the new ast node. This is not an
* identity map.
*/
Map newAstToOldAst;
/**
* This map is used to get an ast node from its binding (new binding)
*/
Map bindingsToAstNodes;
/**
* This map is used to get a binding from its ast node
*/
Map astNodesToBindings;
/**
* Constructor for DefaultBindingResolver.
*/
DefaultBindingResolver() {
this.newAstToOldAst = new HashMap();
this.compilerBindingsToASTBindings = new HashMap();
this.bindingsToAstNodes = new HashMap();
this.astNodesToBindings = new HashMap();
}
/*
* Method declared on BindingResolver.
*/
IBinding resolveName(Name name) {
// retrieve the old ast node
if (name.getParent() instanceof PackageDeclaration) {
return resolveNameForPackageDeclaration(name);
}
if (name.getParent() instanceof ImportDeclaration) {
return null;
}
AstNode node = (AstNode) this.newAstToOldAst.get(name);
if (node instanceof NameReference || node == null) {
return resolveNameForNameReference(name, node);
}
if (node instanceof MessageSend) {
return resolveNameForMessageSend(name, node);
}
return super.resolveName(name);
}
private IBinding resolveNameForMessageSend(Name name, AstNode node) {
MessageSend messageSend = (MessageSend) node;
if (name.isSimpleName()) {
// this can be either the qualifier or the method invocation name
SimpleName simpleName = (SimpleName) name;
if (simpleName.getIdentifier().equals(new String(messageSend.selector))) {
return this.getMethodBinding(messageSend.binding);
} else {
// this is the qualifier
org.eclipse.jdt.internal.compiler.ast.Expression receiver = messageSend.receiver;
if (receiver instanceof SingleNameReference) {
SingleNameReference singleNameReference = (SingleNameReference) receiver;
if (singleNameReference.isTypeReference()) {
return this.getTypeBinding((ReferenceBinding)singleNameReference.binding);
} else {
// this is a variable or a field
return this.getVariableBinding((org.eclipse.jdt.internal.compiler.lookup.VariableBinding)singleNameReference.binding);
}
}
}
} else {
// this is the qualifier
org.eclipse.jdt.internal.compiler.ast.Expression receiver = messageSend.receiver;
if (receiver instanceof QualifiedNameReference) {
QualifiedNameReference qualifiedNameReference = (QualifiedNameReference) receiver;
if (qualifiedNameReference.isTypeReference()) {
return this.getTypeBinding((ReferenceBinding)qualifiedNameReference.binding);
} else {
// this is a variable or a field
return this.getVariableBinding((org.eclipse.jdt.internal.compiler.lookup.VariableBinding) qualifiedNameReference.binding);
}
}
}
return super.resolveName(name);
}
private IBinding resolveNameForMessageSend(Name name, AstNode node, int index) {
MessageSend messageSend = (MessageSend) node;
// this is the qualifier
org.eclipse.jdt.internal.compiler.ast.Expression receiver = messageSend.receiver;
if (receiver instanceof QualifiedNameReference) {
QualifiedNameReference qualifiedNameReference = (QualifiedNameReference) receiver;
if (qualifiedNameReference.isTypeReference()) {
return this.getTypeBinding((ReferenceBinding)qualifiedNameReference.binding);
} else {
// this is a variable or a field
if (index != 0) {
return this.getVariableBinding((org.eclipse.jdt.internal.compiler.lookup.VariableBinding) qualifiedNameReference.binding).getDeclaringClass();
} else {
return this.getVariableBinding((org.eclipse.jdt.internal.compiler.lookup.VariableBinding) qualifiedNameReference.binding);
}
}
}
return super.resolveName(name);
}
private IBinding resolveNameForNameReference(Name name, AstNode node) {
if (node != null) {
if (node instanceof SingleNameReference) {
SingleNameReference singleNameReference = (SingleNameReference) node;
if (singleNameReference.isTypeReference()) {
return this.getTypeBinding((ReferenceBinding)singleNameReference.binding);
} else {
// this is a variable or a field
return this.getVariableBinding((org.eclipse.jdt.internal.compiler.lookup.VariableBinding)singleNameReference.binding);
}
} else if (node instanceof QualifiedNameReference) {
QualifiedNameReference qualifiedNameReference = (QualifiedNameReference) node;
if (qualifiedNameReference.isTypeReference()) {
return this.getTypeBinding((ReferenceBinding)qualifiedNameReference.binding);
} else {
// this is a variable or a field
if (qualifiedNameReference.otherBindings == null) {
return this.getVariableBinding((org.eclipse.jdt.internal.compiler.lookup.VariableBinding) qualifiedNameReference.binding);
} else {
return this.getVariableBinding((org.eclipse.jdt.internal.compiler.lookup.VariableBinding) qualifiedNameReference.otherBindings[qualifiedNameReference.otherBindings.length - 1]);
}
}
}
}
// this might be a inner qualified name or simple name inside a qualified name
int index = 1;
QualifiedName firstQualifier = null;
Name firstName = name;
if (name.isSimpleName()) {
if (name.getParent() instanceof QualifiedName) {
name = (QualifiedName) name.getParent();
firstQualifier = (QualifiedName) name;
} else {
return super.resolveName(name);
}
}
while (name.getParent() instanceof QualifiedName) {
index++;
name = (QualifiedName) name.getParent();
}
// now we can retrieve the enclosing compiler's node corresponding to the inner name
node = (AstNode) this.newAstToOldAst.get(name);
if (node == null) {
return super.resolveName(name);
} else if (node instanceof NameReference) {
QualifiedNameReference qualifiedNameReference = (QualifiedNameReference) node;
if (firstQualifier != null) {
// handle the first simple name in a qualified name a.b.c.d (handles the 'a' case)
Name firstQualifierName = firstQualifier.getQualifier();
if (firstQualifierName.isSimpleName() && firstName == firstQualifierName) {
return this.getVariableBinding((org.eclipse.jdt.internal.compiler.lookup.VariableBinding) qualifiedNameReference.binding);
}
}
if (qualifiedNameReference.isTypeReference()) {
return this.getTypeBinding((ReferenceBinding)qualifiedNameReference.binding);
} else {
// this is a variable or a field
return this.getVariableBinding((org.eclipse.jdt.internal.compiler.lookup.VariableBinding) qualifiedNameReference.otherBindings[qualifiedNameReference.otherBindings.length - index]);
}
} else if (node instanceof MessageSend) {
return this.resolveNameForMessageSend(name, node, index);
}
return super.resolveName(name);
}
private IBinding resolveNameForPackageDeclaration(Name name) {
PackageDeclaration packageDeclaration = (PackageDeclaration) name.getParent();
CompilationUnit unit = (CompilationUnit) packageDeclaration.getParent();
List types = unit.types();
if (types.size() == 0) {
return super.resolveName(name);
}
TypeDeclaration type = (TypeDeclaration) types.get(0);
ITypeBinding typeBinding = type.resolveBinding();
return typeBinding.getPackage();
}
/*
* Method declared on BindingResolver.
*/
ITypeBinding resolveType(Type type) {
// retrieve the old ast node
TypeReference typeReference = (TypeReference) this.newAstToOldAst.get(type);
if (typeReference == null) {
return super.resolveType(type);
}
return this.getTypeBinding(typeReference.binding);
}
/*
* Method declared on BindingResolver.
*/
ITypeBinding resolveWellKnownType(String name) {
return super.resolveWellKnownType(name);
}
/*
* Method declared on BindingResolver.
*/
ITypeBinding resolveType(TypeDeclaration type) {
org.eclipse.jdt.internal.compiler.ast.TypeDeclaration typeDeclaration = (org.eclipse.jdt.internal.compiler.ast.TypeDeclaration) this.newAstToOldAst.get(type);
if (typeDeclaration != null) {
ITypeBinding typeBinding = this.getTypeBinding(typeDeclaration.binding);
this.bindingsToAstNodes.put(typeBinding, type);
return typeBinding;
}
return super.resolveType(type);
}
/*
* Method declared on BindingResolver.
*/
IMethodBinding resolveMethod(MethodDeclaration method) {
AbstractMethodDeclaration methodDeclaration = (AbstractMethodDeclaration) this.newAstToOldAst.get(method);
if (methodDeclaration != null) {
IMethodBinding methodBinding = this.getMethodBinding(methodDeclaration.binding);
this.bindingsToAstNodes.put(methodBinding, method);
return methodBinding;
}
return super.resolveMethod(method);
}
/*
* Method declared on BindingResolver.
*/
IVariableBinding resolveVariable(VariableDeclaration variable) {
AbstractVariableDeclaration abstractVariableDeclaration = (AbstractVariableDeclaration) this.newAstToOldAst.get(variable);
if (abstractVariableDeclaration instanceof org.eclipse.jdt.internal.compiler.ast.FieldDeclaration) {
org.eclipse.jdt.internal.compiler.ast.FieldDeclaration fieldDeclaration = (org.eclipse.jdt.internal.compiler.ast.FieldDeclaration) abstractVariableDeclaration;
return this.getVariableBinding(fieldDeclaration.binding);
}
return this.getVariableBinding(((LocalDeclaration) abstractVariableDeclaration).binding);
}
/*
* Method declared on BindingResolver.
*/
IVariableBinding resolveVariable(FieldDeclaration variable) {
org.eclipse.jdt.internal.compiler.ast.FieldDeclaration fieldDeclaration = (org.eclipse.jdt.internal.compiler.ast.FieldDeclaration) this.newAstToOldAst.get(variable);
return this.getVariableBinding(fieldDeclaration.binding);
}
/*
* Method declared on BindingResolver.
*/
ITypeBinding resolveExpressionType(Expression expression) {
if (expression instanceof ClassInstanceCreation) {
AstNode astNode = (AstNode) this.newAstToOldAst.get(expression);
if (astNode instanceof org.eclipse.jdt.internal.compiler.ast.TypeDeclaration) {
org.eclipse.jdt.internal.compiler.ast.TypeDeclaration typeDeclaration = (org.eclipse.jdt.internal.compiler.ast.TypeDeclaration) astNode;
if (typeDeclaration != null) {
ITypeBinding typeBinding = this.getTypeBinding(typeDeclaration.binding);
this.bindingsToAstNodes.put(typeBinding, expression);
return typeBinding;
}
} else {
// should be an AllocationExpression
AllocationExpression allocationExpression = (AllocationExpression) astNode;
return this.getMethodBinding(allocationExpression.binding).getDeclaringClass();
}
} else if (expression instanceof Name) {
IBinding binding = this.resolveName((Name) expression);
if (binding == null) {
return null;
}
switch(binding.getKind()) {
case IBinding.TYPE :
return (ITypeBinding) binding;
case IBinding.VARIABLE :
return ((IVariableBinding) binding).getType();
}
} else if (expression instanceof ArrayInitializer) {
org.eclipse.jdt.internal.compiler.ast.ArrayInitializer oldAst = (org.eclipse.jdt.internal.compiler.ast.ArrayInitializer) this.newAstToOldAst.get(expression);
if (oldAst == null || oldAst.binding == null) {
return super.resolveExpressionType(expression);
}
return this.getTypeBinding(oldAst.binding);
} else if (expression instanceof ArrayCreation) {
ArrayAllocationExpression arrayAllocationExpression = (ArrayAllocationExpression) this.newAstToOldAst.get(expression);
return this.getTypeBinding(arrayAllocationExpression.arrayTb);
} else if (expression instanceof Assignment) {
Assignment assignment = (Assignment) expression;
return this.resolveExpressionType(assignment.getLeftHandSide());
} else if (expression instanceof PostfixExpression) {
PostfixExpression postFixExpression = (PostfixExpression) expression;
return this.resolveExpressionType(postFixExpression.getOperand());
} else if (expression instanceof PrefixExpression) {
PrefixExpression preFixExpression = (PrefixExpression) expression;
return this.resolveExpressionType(preFixExpression.getOperand());
} else if (expression instanceof CastExpression) {
org.eclipse.jdt.internal.compiler.ast.CastExpression castExpression = (org.eclipse.jdt.internal.compiler.ast.CastExpression) this.newAstToOldAst.get(expression);
return this.getTypeBinding(castExpression.castTb);
} else if (expression instanceof TypeLiteral) {
ClassLiteralAccess classLiteralAccess = (ClassLiteralAccess) this.newAstToOldAst.get(expression);
return this.getTypeBinding(classLiteralAccess.targetType);
} else if (expression instanceof BooleanLiteral) {
BooleanLiteral booleanLiteral = (BooleanLiteral) expression;
if (booleanLiteral.booleanValue()) {
TrueLiteral trueLiteral = (TrueLiteral) this.newAstToOldAst.get(booleanLiteral);
return this.getTypeBinding(trueLiteral.literalType(null));
} else {
FalseLiteral falseLiteral = (FalseLiteral) this.newAstToOldAst.get(booleanLiteral);
return this.getTypeBinding(falseLiteral.literalType(null));
}
} else if (expression instanceof NullLiteral) {
org.eclipse.jdt.internal.compiler.ast.NullLiteral nullLiteral = (org.eclipse.jdt.internal.compiler.ast.NullLiteral) this.newAstToOldAst.get(expression);
return this.getTypeBinding(nullLiteral.literalType(null));
} else if (expression instanceof CharacterLiteral) {
CharLiteral charLiteral = (CharLiteral) this.newAstToOldAst.get(expression);
return this.getTypeBinding(charLiteral.literalType(null));
} else if (expression instanceof NumberLiteral) {
Literal literal = (Literal) this.newAstToOldAst.get(expression);
return this.getTypeBinding(literal.literalType(null));
} else if (expression instanceof InfixExpression) {
OperatorExpression operatorExpression = (OperatorExpression) this.newAstToOldAst.get(expression);
return this.getTypeBinding(operatorExpression.typeBinding);
} else if (expression instanceof FieldAccess) {
FieldReference fieldReference = (FieldReference) this.newAstToOldAst.get(expression);
return this.getVariableBinding(fieldReference.binding).getType();
} else if (expression instanceof SuperFieldAccess) {
FieldReference fieldReference = (FieldReference) this.newAstToOldAst.get(expression);
return this.getVariableBinding(fieldReference.binding).getType();
} else if (expression instanceof ArrayAccess) {
ArrayReference arrayReference = (ArrayReference) this.newAstToOldAst.get(expression);
return this.getTypeBinding(arrayReference.arrayElementBinding);
} else if (expression instanceof ThisExpression) {
ThisReference thisReference = (ThisReference) this.newAstToOldAst.get(expression);
return this.getTypeBinding(thisReference.resolveType(this.retrieveEnclosingScope(expression)));
} else if (expression instanceof MethodInvocation) {
MessageSend messageSend = (MessageSend) this.newAstToOldAst.get(expression);
return this.getMethodBinding(messageSend.binding).getReturnType();
} else if (expression instanceof ParenthesizedExpression) {
ParenthesizedExpression parenthesizedExpression = (ParenthesizedExpression) expression;
return this.resolveExpressionType(parenthesizedExpression.getExpression());
}
return super.resolveExpressionType(expression);
}
/*
* Method declared on BindingResolver.
*/
public ASTNode findDeclaringNode(IBinding binding) {
return (ASTNode) this.bindingsToAstNodes.get(binding);
}
/*
* Method declared on BindingResolver.
*/
void store(ASTNode node, AstNode oldASTNode) {
this.newAstToOldAst.put(node, oldASTNode);
}
/*
* Method declared on BindingResolver.
*/
protected ITypeBinding getTypeBinding(org.eclipse.jdt.internal.compiler.lookup.TypeBinding referenceBinding) {
if (referenceBinding == null || !referenceBinding.isValidBinding()) {
return null;
}
TypeBinding binding = (TypeBinding) this.compilerBindingsToASTBindings.get(referenceBinding);
if (binding != null) {
return binding;
}
binding = new TypeBinding(this, referenceBinding);
this.compilerBindingsToASTBindings.put(referenceBinding, binding);
return binding;
}
/*
* Method declared on BindingResolver.
*/
protected IPackageBinding getPackageBinding(org.eclipse.jdt.internal.compiler.lookup.PackageBinding packageBinding) {
if (packageBinding == null || !packageBinding.isValidBinding()) {
return null;
}
IPackageBinding binding = (IPackageBinding) this.compilerBindingsToASTBindings.get(packageBinding);
if (binding != null) {
return binding;
}
binding = new PackageBinding(this, packageBinding);
this.compilerBindingsToASTBindings.put(packageBinding, binding);
return binding;
}
/*
* Method declared on BindingResolver.
*/
protected IVariableBinding getVariableBinding(org.eclipse.jdt.internal.compiler.lookup.VariableBinding variableBinding) {
if (variableBinding == null || !variableBinding.isValidBinding()) {
return null;
}
IVariableBinding binding = (IVariableBinding) this.compilerBindingsToASTBindings.get(variableBinding);
if (binding != null) {
return binding;
}
binding = new VariableBinding(this, variableBinding);
this.compilerBindingsToASTBindings.put(variableBinding, binding);
return binding;
}
/*
* Method declared on BindingResolver.
*/
protected IMethodBinding getMethodBinding(org.eclipse.jdt.internal.compiler.lookup.MethodBinding methodBinding) {
if (methodBinding == null || !methodBinding.isValidBinding()) {
return null;
}
IMethodBinding binding = (IMethodBinding) this.compilerBindingsToASTBindings.get(methodBinding);
if (binding != null) {
return binding;
}
binding = new MethodBinding(this, methodBinding);
this.compilerBindingsToASTBindings.put(methodBinding, binding);
return binding;
}
private BlockScope retrieveEnclosingScope(ASTNode node) {
ASTNode currentNode = node;
while(!(currentNode instanceof MethodDeclaration) && !(currentNode instanceof Initializer)) {
currentNode = currentNode.getParent();
}
if (currentNode instanceof Initializer) {
Initializer initializer = (Initializer) currentNode;
while(!(currentNode instanceof TypeDeclaration)) {
currentNode = currentNode.getParent();
}
org.eclipse.jdt.internal.compiler.ast.TypeDeclaration typeDecl = (org.eclipse.jdt.internal.compiler.ast.TypeDeclaration) this.newAstToOldAst.get(currentNode);
if ((initializer.getModifiers() & Modifier.STATIC) != 0) {
return typeDecl.staticInitializerScope;
} else {
return typeDecl.initializerScope;
}
}
// this is a MethodDeclaration
AbstractMethodDeclaration abstractMethodDeclaration = (AbstractMethodDeclaration) this.newAstToOldAst.get(currentNode);
return abstractMethodDeclaration.scope;
}
}