blob: d5052c1119783aeebdd8cff82abd890f95c00c6c [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.AnonymousLocalTypeDeclaration;
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.CompilationUnitDeclaration;
import org.eclipse.jdt.internal.compiler.ast.CompoundAssignment;
import org.eclipse.jdt.internal.compiler.ast.ExplicitConstructorCall;
import org.eclipse.jdt.internal.compiler.ast.FalseLiteral;
import org.eclipse.jdt.internal.compiler.ast.FieldReference;
import org.eclipse.jdt.internal.compiler.ast.ImportReference;
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.QualifiedSuperReference;
import org.eclipse.jdt.internal.compiler.ast.QualifiedTypeReference;
import org.eclipse.jdt.internal.compiler.ast.SingleNameReference;
import org.eclipse.jdt.internal.compiler.ast.SingleTypeReference;
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.ArrayBinding;
import org.eclipse.jdt.internal.compiler.lookup.Binding;
import org.eclipse.jdt.internal.compiler.lookup.BindingIds;
import org.eclipse.jdt.internal.compiler.lookup.CompilationUnitScope;
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;
import org.eclipse.jdt.internal.compiler.lookup.Scope;
import org.eclipse.jdt.internal.compiler.util.CharOperation;
/**
* Internal class for resolving bindings using old ASTs.
*/
class DefaultBindingResolver extends BindingResolver {
private static final char[][] JAVA_LANG_STRINGBUFFER = new char[][] {"java".toCharArray(), "lang".toCharArray(), "StringBuffer".toCharArray()}; //$NON-NLS-3$//$NON-NLS-2$//$NON-NLS-1$
private static final char[][] JAVA_LANG_EXCEPTION = new char[][] {"java".toCharArray(), "lang".toCharArray(), "Exception".toCharArray()};//$NON-NLS-3$//$NON-NLS-2$//$NON-NLS-1$
/**
* 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;
/**
* Compilation unit scope
*/
private CompilationUnitScope scope;
/**
* Check if the binding resolver has to ensure the modification cound
* didn't change
*/
private boolean checkModificationCount;
/**
* Constructor for DefaultBindingResolver.
*/
DefaultBindingResolver() {
checkModificationCount = false;
this.newAstToOldAst = new HashMap();
this.compilerBindingsToASTBindings = new HashMap();
this.bindingsToAstNodes = new HashMap();
this.astNodesToBindings = new HashMap();
}
/**
* Constructor for DefaultBindingResolver.
*/
DefaultBindingResolver(CompilationUnitScope scope) {
this();
this.scope = scope;
}
/*
* Method declared on BindingResolver.
*/
IBinding resolveName(Name name) {
if (this.checkModificationCount && this.modificationCount != name.getAST().modificationCount()) {
return null;
}
ASTNode parent = name.getParent();
if (parent instanceof MethodDeclaration && name.equals(((MethodDeclaration) parent).getName())) {
return this.resolveMethod((MethodDeclaration)parent);
}
if (parent instanceof TypeDeclaration && name.equals(((TypeDeclaration) parent).getName())) {
return this.resolveType((TypeDeclaration)parent);
}
if ((parent instanceof MethodInvocation && name.equals(((MethodInvocation) parent).getName()))
|| (parent instanceof SuperMethodInvocation && name.equals(((SuperMethodInvocation) parent).getName()))) {
return this.internalResolveNameForMethodInvocation(name);
}
if ((parent instanceof FieldAccess && name.equals(((FieldAccess) parent).getName()))
|| (parent instanceof SuperFieldAccess && name.equals(((SuperFieldAccess) parent).getName()))) {
return this.internalResolveNameForFieldAccess(name);
}
if (parent instanceof PackageDeclaration && name.equals(((PackageDeclaration) parent).getName())) {
return this.internalResolveNameForPackageDeclaration(name);
}
if (parent instanceof SimpleType && name.equals(((SimpleType) parent).getName())) {
return this.internalResolveNameForSimpleType(name);
}
if (parent instanceof ThisExpression) {
return this.internalResolveNameForThisExpression(name);
}
if (name instanceof QualifiedName) {
return this.internalResolveNameForQualifiedName(name);
}
if (name instanceof SimpleName) {
return this.internalResolveNameForSimpleName(name);
}
return super.resolveName(name);
}
private IBinding internalResolveNameForPackageDeclaration(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) {
if (this.checkModificationCount && this.modificationCount != type.getAST().modificationCount()) {
return null;
}
// retrieve the old ast node
int index = 0;
ASTNode parentType = type.getParent();
Type arrayType = null;
AstNode node = (AstNode) this.newAstToOldAst.get(type);
if (node == null) {
if (parentType instanceof ArrayCreation) {
node = (AstNode) this.newAstToOldAst.get(parentType);
} else {
// we try to retrieve the type as an element type of an array type
while ((parentType instanceof Type) && ((Type) parentType).isArrayType()) {
arrayType = (Type) parentType;
parentType = parentType.getParent();
index++;
}
if (index != 0) {
node = (AstNode) this.newAstToOldAst.get(arrayType);
}
}
}
if (node != null) {
if (node instanceof TypeReference) {
TypeReference typeReference = (TypeReference) node;
ITypeBinding typeBinding = this.getTypeBinding(typeReference.binding);
if (index != 0) {
if (typeBinding.isArray()) {
ArrayBinding arrayBinding = (ArrayBinding)typeReference.binding;
if (index == arrayBinding.dimensions) {
return this.getTypeBinding(arrayBinding.leafComponentType);
} else {
for (int i = 0; i < index; i++) {
arrayBinding = (ArrayBinding) arrayBinding.elementsType(this.scope);
}
return this.getTypeBinding(arrayBinding);
}
} else {
return null;
}
} else {
return typeBinding;
}
} else if (node instanceof SingleNameReference) {
SingleNameReference singleNameReference = (SingleNameReference) node;
if (singleNameReference.isTypeReference()) {
ITypeBinding typeBinding = this.getTypeBinding((ReferenceBinding)singleNameReference.binding);
if (index != 0) {
if (typeBinding.isArray()) {
ArrayBinding arrayBinding = (ArrayBinding)singleNameReference.binding;
if (index == arrayBinding.dimensions) {
return this.getTypeBinding(arrayBinding.leafComponentType);
} else {
for (int i = 0; i < index; i++) {
arrayBinding = (ArrayBinding) arrayBinding.elementsType(this.scope);
}
return this.getTypeBinding(arrayBinding);
}
} else {
return null;
}
} else {
return typeBinding;
}
} else {
// it should be a type reference
return null;
}
} else if (node instanceof QualifiedNameReference) {
QualifiedNameReference qualifiedNameReference = (QualifiedNameReference) node;
if (qualifiedNameReference.isTypeReference()) {
ITypeBinding typeBinding = this.getTypeBinding((ReferenceBinding)qualifiedNameReference.binding);
if (index != 0) {
if (typeBinding.isArray()) {
ArrayBinding arrayBinding = (ArrayBinding)qualifiedNameReference.binding;
if (index == arrayBinding.dimensions) {
return this.getTypeBinding(arrayBinding.leafComponentType);
} else {
for (int i = 0; i < index; i++) {
arrayBinding = (ArrayBinding) arrayBinding.elementsType(this.scope);
}
}
return this.getTypeBinding(arrayBinding);
} else {
return null;
}
} else {
return typeBinding;
}
} else {
// it should be a type reference
return null;
}
} else if (node instanceof ArrayAllocationExpression) {
ArrayAllocationExpression arrayAllocationExpression = (ArrayAllocationExpression) node;
ArrayBinding arrayBinding = arrayAllocationExpression.arrayTb;
if (index != 0) {
return this.getTypeBinding(this.scope.createArray(arrayBinding.leafComponentType, arrayBinding.dimensions - index));
}
return this.getTypeBinding(arrayBinding);
}
}
return null;
}
/*
* Method declared on BindingResolver.
*/
ITypeBinding resolveWellKnownType(String name) {
if (("boolean".equals(name))//$NON-NLS-1$
|| ("char".equals(name))//$NON-NLS-1$
|| ("byte".equals(name))//$NON-NLS-1$
|| ("short".equals(name))//$NON-NLS-1$
|| ("int".equals(name))//$NON-NLS-1$
|| ("long".equals(name))//$NON-NLS-1$
|| ("float".equals(name))//$NON-NLS-1$
|| ("double".equals(name))//$NON-NLS-1$
|| ("void".equals(name))) {//$NON-NLS-1$
return this.getTypeBinding(this.scope.getBaseType(name.toCharArray()));
} else if ("java.lang.Object".equals(name)) {//$NON-NLS-1$
return this.getTypeBinding(this.scope.getJavaLangObject());
} else if ("java.lang.String".equals(name)) {//$NON-NLS-1$
return this.getTypeBinding(this.scope.getJavaLangString());
} else if ("java.lang.StringBuffer".equals(name)) {//$NON-NLS-1$
return this.getTypeBinding(this.scope.getType(JAVA_LANG_STRINGBUFFER));
} else if ("java.lang.Throwable".equals(name)) {//$NON-NLS-1$
return this.getTypeBinding(this.scope.getJavaLangThrowable());
} else if ("java.lang.Exception".equals(name)) {//$NON-NLS-1$
return this.getTypeBinding(this.scope.getType(JAVA_LANG_EXCEPTION));
} else if ("java.lang.RuntimeException".equals(name)) {//$NON-NLS-1$
return this.getTypeBinding(this.scope.getJavaLangRuntimeException());
} else if ("java.lang.Error".equals(name)) {//$NON-NLS-1$
return this.getTypeBinding(this.scope.getJavaLangError());
} else if ("java.lang.Class".equals(name)) {//$NON-NLS-1$
return this.getTypeBinding(this.scope.getJavaLangClass());
} else {
return super.resolveWellKnownType(name);
}
}
/*
* Method declared on BindingResolver.
*/
ITypeBinding resolveType(TypeDeclaration type) {
if (this.checkModificationCount && this.modificationCount != type.getAST().modificationCount()) {
return null;
}
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) {
if (this.checkModificationCount && this.modificationCount != method.getAST().modificationCount()) {
return null;
}
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) {
if (this.checkModificationCount && this.modificationCount != variable.getAST().modificationCount()) {
return null;
}
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;
IVariableBinding variableBinding = this.getVariableBinding(fieldDeclaration.binding);
this.bindingsToAstNodes.put(variableBinding, variable);
return variableBinding;
}
IVariableBinding variableBinding = this.getVariableBinding(((LocalDeclaration) abstractVariableDeclaration).binding);
this.bindingsToAstNodes.put(variableBinding, variable);
return variableBinding;
}
/*
* Method declared on BindingResolver.
*/
IVariableBinding resolveVariable(FieldDeclaration variable) {
if (this.checkModificationCount && this.modificationCount != variable.getAST().modificationCount()) {
return null;
}
org.eclipse.jdt.internal.compiler.ast.FieldDeclaration fieldDeclaration = (org.eclipse.jdt.internal.compiler.ast.FieldDeclaration) this.newAstToOldAst.get(variable);
IVariableBinding variableBinding = this.getVariableBinding(fieldDeclaration.binding);
this.bindingsToAstNodes.put(variableBinding, variable);
return variableBinding;
}
/*
* Method declared on BindingResolver.
*/
ITypeBinding resolveExpressionType(Expression expression) {
if (this.checkModificationCount && this.modificationCount != expression.getAST().modificationCount()) {
return null;
}
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;
IMethodBinding methodBinding = this.getMethodBinding(allocationExpression.binding);
if (methodBinding == null) {
return null;
} else {
return methodBinding.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 StringLiteral) {
org.eclipse.jdt.internal.compiler.ast.StringLiteral stringLiteral = (org.eclipse.jdt.internal.compiler.ast.StringLiteral) this.newAstToOldAst.get(expression);
BlockScope blockScope = this.retrieveEnclosingScope(expression);
if (blockScope == null) {
return this.getTypeBinding(this.scope.getJavaLangString());
} else {
return this.getTypeBinding(stringLiteral.literalType(blockScope));
}
} else if (expression instanceof TypeLiteral) {
return this.getTypeBinding(this.scope.getJavaLangClass());
} 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 InstanceofExpression) {
org.eclipse.jdt.internal.compiler.ast.InstanceOfExpression instanceOfExpression = (org.eclipse.jdt.internal.compiler.ast.InstanceOfExpression) this.newAstToOldAst.get(expression);
return this.getTypeBinding(instanceOfExpression.typeBinding);
} else if (expression instanceof FieldAccess) {
FieldReference fieldReference = (FieldReference) this.newAstToOldAst.get(expression);
IVariableBinding variableBinding = this.getVariableBinding(fieldReference.binding);
if (variableBinding == null) {
return null;
} else {
return variableBinding.getType();
}
} else if (expression instanceof SuperFieldAccess) {
FieldReference fieldReference = (FieldReference) this.newAstToOldAst.get(expression);
IVariableBinding variableBinding = this.getVariableBinding(fieldReference.binding);
if (variableBinding == null) {
return null;
} else {
return variableBinding.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);
BlockScope blockScope = this.retrieveEnclosingScope(expression);
if (blockScope == null) {
return null;
}
return this.getTypeBinding(thisReference.resolveType(blockScope));
} else if (expression instanceof MethodInvocation) {
MessageSend messageSend = (MessageSend) this.newAstToOldAst.get(expression);
IMethodBinding methodBinding = this.getMethodBinding(messageSend.binding);
if (methodBinding == null) {
return null;
} else {
return methodBinding.getReturnType();
}
} else if (expression instanceof ParenthesizedExpression) {
ParenthesizedExpression parenthesizedExpression = (ParenthesizedExpression) expression;
return this.resolveExpressionType(parenthesizedExpression.getExpression());
} else if (expression instanceof ConditionalExpression) {
org.eclipse.jdt.internal.compiler.ast.ConditionalExpression conditionalExpression = (org.eclipse.jdt.internal.compiler.ast.ConditionalExpression) this.newAstToOldAst.get(expression);
return this.getTypeBinding(conditionalExpression.typeBinding);
}
return super.resolveExpressionType(expression);
}
/*
* @see BindingResolver#resolveImport(ImportDeclaration)
*/
IBinding resolveImport(ImportDeclaration importDeclaration) {
if (this.checkModificationCount && this.modificationCount != importDeclaration.getAST().modificationCount()) {
return null;
}
AstNode node = (AstNode) this.newAstToOldAst.get(importDeclaration);
if (node instanceof ImportReference) {
ImportReference importReference = (ImportReference) node;
if (importReference.onDemand) {
Binding binding = this.scope.getTypeOrPackage(CharOperation.subarray(importReference.tokens, 0, importReference.tokens.length));
if ((binding != null) && (binding.isValidBinding())) {
IPackageBinding packageBinding = this.getPackageBinding((org.eclipse.jdt.internal.compiler.lookup.PackageBinding) binding);
this.bindingsToAstNodes.put(packageBinding, importDeclaration);
return packageBinding;
}
} else {
Binding binding = this.scope.getTypeOrPackage(importReference.tokens);
if (binding != null && binding.isValidBinding()) {
ITypeBinding typeBinding = this.getTypeBinding((org.eclipse.jdt.internal.compiler.lookup.TypeBinding) binding);
this.bindingsToAstNodes.put(typeBinding, importDeclaration);
return typeBinding;
}
}
}
return super.resolveImport(importDeclaration);
}
/*
* @see BindingResolver#resolvePackage(PackageDeclaration)
*/
IPackageBinding resolvePackage(PackageDeclaration pkg) {
if (this.checkModificationCount && this.modificationCount != pkg.getAST().modificationCount()) {
return null;
}
AstNode node = (AstNode) this.newAstToOldAst.get(pkg);
if (node instanceof ImportReference) {
ImportReference importReference = (ImportReference) node;
Binding binding = this.scope.getTypeOrPackage(CharOperation.subarray(importReference.tokens, 0, importReference.tokens.length));
if ((binding != null) && (binding.isValidBinding())) {
IPackageBinding packageBinding = this.getPackageBinding((org.eclipse.jdt.internal.compiler.lookup.PackageBinding) binding);
this.bindingsToAstNodes.put(packageBinding, pkg);
return packageBinding;
}
}
return super.resolvePackage(pkg);
}
/*
* Method declared on BindingResolver.
*/
public ASTNode findDeclaringNode(IBinding binding) {
if (binding == null) {
return null;
}
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 != null
&&!(currentNode instanceof MethodDeclaration)
&& !(currentNode instanceof Initializer)
&& !(currentNode instanceof FieldDeclaration)) {
currentNode = currentNode.getParent();
}
if (currentNode == null) {
return null;
}
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;
}
} else if (currentNode instanceof FieldDeclaration) {
FieldDeclaration fieldDeclaration = (FieldDeclaration) 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 ((fieldDeclaration.getModifiers() & Modifier.STATIC) != 0) {
return typeDecl.staticInitializerScope;
} else {
return typeDecl.initializerScope;
}
}
AbstractMethodDeclaration abstractMethodDeclaration = (AbstractMethodDeclaration) this.newAstToOldAst.get(currentNode);
return abstractMethodDeclaration.scope;
}
private IBinding internalResolveNameForQualifiedName(Name name) {
QualifiedName qualifiedName = (QualifiedName) name;
ASTNode parent = qualifiedName.getParent();
int index = 0;
while (parent instanceof QualifiedName) {
qualifiedName = (QualifiedName) parent;
parent = parent.getParent();
index++;
}
return returnBindingForQualifiedNamePart(qualifiedName, index);
}
private IBinding returnBindingForQualifiedNamePart(ASTNode parent, int index) {
// now we can retrieve the compiler's node
AstNode node = (AstNode) this.newAstToOldAst.get(parent);
if (node instanceof QualifiedNameReference) {
QualifiedNameReference qualifiedNameReference = (QualifiedNameReference) node;
if (qualifiedNameReference.isTypeReference()) {
return this.getTypeBinding((ReferenceBinding)qualifiedNameReference.binding);
} else {
int qualifiedNameLength = qualifiedNameReference.tokens.length;
int indexInQualifiedName = qualifiedNameLength - index; // one-based
int indexOfFirstFieldBinding = qualifiedNameReference.indexOfFirstFieldBinding; // one-based
int otherBindingLength = qualifiedNameLength - indexOfFirstFieldBinding;
if (indexInQualifiedName < indexOfFirstFieldBinding) {
// a extra lookup is required
BlockScope internalScope = retrieveEnclosingScope(parent);
Binding binding = null;
if (internalScope == null) {
binding = this.scope.getTypeOrPackage(CharOperation.subarray(qualifiedNameReference.tokens, 0, indexInQualifiedName));
} else {
binding = internalScope.getTypeOrPackage(CharOperation.subarray(qualifiedNameReference.tokens, 0, indexInQualifiedName));
}
if (binding != null && binding.isValidBinding()) {
if (binding instanceof org.eclipse.jdt.internal.compiler.lookup.PackageBinding) {
return this.getPackageBinding((org.eclipse.jdt.internal.compiler.lookup.PackageBinding)binding);
} else {
// it is a type
return this.getTypeBinding((org.eclipse.jdt.internal.compiler.lookup.TypeBinding)binding);
}
}
return null;
} else {
if (indexInQualifiedName == indexOfFirstFieldBinding) {
Binding binding = qualifiedNameReference.binding;
if (binding != null && binding.isValidBinding()) {
return this.getVariableBinding((org.eclipse.jdt.internal.compiler.lookup.VariableBinding) binding);
} else {
return null;
}
} else {
/* This is the case for a name which is part of a qualified name that
* cannot be resolved. See PR 13063.
*/
if (qualifiedNameReference.otherBindings == null) {
return null;
} else {
return this.getVariableBinding(qualifiedNameReference.otherBindings[otherBindingLength - index - 1]);
}
}
}
}
} else if (node instanceof QualifiedTypeReference) {
QualifiedTypeReference qualifiedTypeReference = (QualifiedTypeReference) node;
if (index == 0) {
return this.getTypeBinding((ReferenceBinding)qualifiedTypeReference.binding);
} else {
int qualifiedTypeLength = qualifiedTypeReference.tokens.length;
int indexInQualifiedName = qualifiedTypeLength - index; // one-based
BlockScope internalScope = retrieveEnclosingScope(parent);
Binding binding = null;
if (internalScope == null) {
binding = this.scope.getTypeOrPackage(CharOperation.subarray(qualifiedTypeReference.tokens, 0, indexInQualifiedName));
} else {
binding = internalScope.getTypeOrPackage(CharOperation.subarray(qualifiedTypeReference.tokens, 0, indexInQualifiedName));
}
if (binding != null && binding.isValidBinding()) {
if (binding instanceof org.eclipse.jdt.internal.compiler.lookup.PackageBinding) {
return this.getPackageBinding((org.eclipse.jdt.internal.compiler.lookup.PackageBinding)binding);
} else {
// it is a type
return this.getTypeBinding((org.eclipse.jdt.internal.compiler.lookup.TypeBinding)binding);
}
}
}
}
return null;
}
private IBinding internalResolveNameForSimpleName(Name name) {
AstNode node = (AstNode) this.newAstToOldAst.get(name);
if (node == null) {
ASTNode parent = name.getParent();
if (parent instanceof QualifiedName) {
// retrieve the qualified name and remember at which position is the simple name
QualifiedName qualifiedName = (QualifiedName) parent;
int index = -1;
if (qualifiedName.getQualifier() == name) {
index++;
}
while (parent instanceof QualifiedName) {
qualifiedName = (QualifiedName) parent;
parent = parent.getParent();
index++;
}
return returnBindingForQualifiedNamePart(qualifiedName, index);
}
}
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
Binding binding = singleNameReference.binding;
if (binding != null && binding.isValidBinding()) {
return this.getVariableBinding((org.eclipse.jdt.internal.compiler.lookup.VariableBinding) binding);
} else {
return null;
}
}
} else if (node instanceof QualifiedSuperReference) {
QualifiedSuperReference qualifiedSuperReference = (QualifiedSuperReference) node;
return this.getTypeBinding(qualifiedSuperReference.qualification.binding);
} else if (node instanceof LocalDeclaration) {
return this.getVariableBinding(((LocalDeclaration)node).binding);
} else if (node instanceof FieldReference) {
return getVariableBinding(((FieldReference) node).binding);
} else if (node instanceof SingleTypeReference) {
SingleTypeReference singleTypeReference = (SingleTypeReference) node;
return this.getTypeBinding(singleTypeReference.binding);
} else if (node instanceof org.eclipse.jdt.internal.compiler.ast.FieldDeclaration) {
org.eclipse.jdt.internal.compiler.ast.FieldDeclaration fieldDeclaration = (org.eclipse.jdt.internal.compiler.ast.FieldDeclaration) node;
IVariableBinding variableBinding = this.getVariableBinding(fieldDeclaration.binding);
return variableBinding;
}
return null;
}
private IBinding internalResolveNameForMethodInvocation(Name name) {
ASTNode parent = name.getParent();
if (parent instanceof MethodInvocation) {
MethodInvocation methodInvocation = (MethodInvocation) parent;
if (name == methodInvocation.getExpression()) {
if (name.isQualifiedName()) {
return this.internalResolveNameForQualifiedName(name);
} else {
return this.internalResolveNameForSimpleName(name);
}
} else {
AstNode node = (AstNode) this.newAstToOldAst.get(name);
if (node instanceof MessageSend) {
MessageSend messageSend = (MessageSend) node;
return getMethodBinding(messageSend.binding);
} else if (name.isQualifiedName()) {
return this.internalResolveNameForQualifiedName(name);
} else {
return this.internalResolveNameForSimpleName(name);
}
}
} else {
SuperMethodInvocation superMethodInvocation = (SuperMethodInvocation) parent;
if (name == superMethodInvocation.getQualifier()) {
if (name.isQualifiedName()) {
return this.internalResolveNameForQualifiedName(name);
} else {
return this.internalResolveNameForSimpleName(name);
}
} else {
AstNode node = (AstNode) this.newAstToOldAst.get(name);
if (node instanceof MessageSend) {
MessageSend messageSend = (MessageSend) node;
return getMethodBinding(messageSend.binding);
} else if (name.isQualifiedName()) {
return this.internalResolveNameForQualifiedName(name);
} else {
return this.internalResolveNameForSimpleName(name);
}
}
}
}
private IBinding internalResolveNameForFieldAccess(Name name) {
if (name.isQualifiedName()) {
return this.internalResolveNameForQualifiedName(name);
} else {
return this.internalResolveNameForSimpleName(name);
}
}
private IBinding internalResolveNameForSimpleType(Name name) {
AstNode node = (AstNode) this.newAstToOldAst.get(name);
if (node instanceof TypeReference) {
return this.getTypeBinding(((TypeReference) node).binding);
} else if (node instanceof NameReference) {
NameReference nameReference = (NameReference) node;
if (nameReference.isTypeReference()) {
return this.getTypeBinding((org.eclipse.jdt.internal.compiler.lookup.TypeBinding) nameReference.binding);
}
}
return null;
}
private IBinding internalResolveNameForThisExpression(Name name) {
AstNode node = (AstNode) this.newAstToOldAst.get(name);
if (node instanceof TypeReference) {
return this.getTypeBinding(((TypeReference) node).binding);
}
return null;
}
/*
* @see BindingResolver#resolveConstructor(ClassInstanceCreation)
*/
IMethodBinding resolveConstructor(ClassInstanceCreation expression) {
if (this.checkModificationCount && this.modificationCount != expression.getAST().modificationCount()) {
return null;
}
AstNode node = (AstNode) this.newAstToOldAst.get(expression);
if (node instanceof AnonymousLocalTypeDeclaration) {
AnonymousLocalTypeDeclaration anonymousLocalTypeDeclaration = (AnonymousLocalTypeDeclaration) node;
return this.getMethodBinding(anonymousLocalTypeDeclaration.allocation.binding);
} else if (node instanceof AllocationExpression) {
return this.getMethodBinding(((AllocationExpression)node).binding);
}
return null;
}
/*
* @see BindingResolver#resolveConstructor(ConstructorInvocation)
*/
IMethodBinding resolveConstructor(ConstructorInvocation expression) {
if (this.checkModificationCount && this.modificationCount != expression.getAST().modificationCount()) {
return null;
}
AstNode node = (AstNode) this.newAstToOldAst.get(expression);
if (node instanceof ExplicitConstructorCall) {
ExplicitConstructorCall explicitConstructorCall = (ExplicitConstructorCall) node;
return this.getMethodBinding(explicitConstructorCall.binding);
}
return null;
}
/*
* @see BindingResolver#resolveConstructor(SuperConstructorInvocation)
*/
IMethodBinding resolveConstructor(SuperConstructorInvocation expression) {
if (this.checkModificationCount && this.modificationCount != expression.getAST().modificationCount()) {
return null;
}
AstNode node = (AstNode) this.newAstToOldAst.get(expression);
if (node instanceof ExplicitConstructorCall) {
ExplicitConstructorCall explicitConstructorCall = (ExplicitConstructorCall) node;
return this.getMethodBinding(explicitConstructorCall.binding);
}
return null;
}
/*
* @see BindingResolver#resolveType(AnonymousClassDeclaration)
*/
ITypeBinding resolveType(AnonymousClassDeclaration type) {
if (this.checkModificationCount && this.modificationCount != type.getAST().modificationCount()) {
return null;
}
org.eclipse.jdt.internal.compiler.ast.AnonymousLocalTypeDeclaration anonymousLocalTypeDeclaration = (org.eclipse.jdt.internal.compiler.ast.AnonymousLocalTypeDeclaration) this.newAstToOldAst.get(type);
if (anonymousLocalTypeDeclaration != null) {
ITypeBinding typeBinding = this.getTypeBinding(anonymousLocalTypeDeclaration.binding);
this.bindingsToAstNodes.put(typeBinding, type);
return typeBinding;
}
return super.resolveType(type);
}
/**
* Store the number of modifications done using the ast. This is used to validate
* resolveBinding methods. If the number changed, all resolve bindings methods
* simply return null.
*/
protected void storeModificationCount(long modificationCount) {
super.storeModificationCount(modificationCount);
this.checkModificationCount = true;
}
}