blob: c0dce0c46b92344f5d46771d596de7761da1fe46 [file] [log] [blame]
package org.eclipse.jdt.internal.compiler.lookup;
/*
* (c) Copyright IBM Corp. 2000, 2001.
* All Rights Reserved.
*/
import org.eclipse.jdt.internal.compiler.ast.*;
import org.eclipse.jdt.internal.compiler.codegen.*;
import org.eclipse.jdt.internal.compiler.problem.*;
import org.eclipse.jdt.internal.compiler.util.*;
public abstract class Scope
implements
BaseTypes,
BindingIds,
CompilerModifiers,
ProblemReasons,
TagBits,
TypeConstants,
TypeIds {
public Scope parent;
public int kind;
public final static int BLOCK_SCOPE = 1;
public final static int METHOD_SCOPE = 2;
public final static int CLASS_SCOPE = 3;
public final static int COMPILATION_UNIT_SCOPE = 4;
protected Scope(int kind, Scope parent) {
this.kind = kind;
this.parent = parent;
}
public abstract ProblemReporter problemReporter();
// Internal use only
protected final boolean areParametersAssignable(
TypeBinding[] parameters,
TypeBinding[] arguments) {
if (parameters == arguments)
return true;
int length = parameters.length;
if (length != arguments.length)
return false;
for (int i = 0; i < length; i++)
if (parameters[i] != arguments[i])
if (!arguments[i].isCompatibleWith(parameters[i]))
return false;
return true;
}
/* Answer true if the left type can be assigned to right
*/
public boolean areTypesCompatible(TypeBinding left, TypeBinding right) {
return left.isCompatibleWith(right);
}
/* Answer an int describing the relationship between the given types.
*
* NotRelated
* EqualOrMoreSpecific : left is compatible with right
* MoreGeneric : right is compatible with left
*/
public int compareTypes(TypeBinding left, TypeBinding right) {
if (areTypesCompatible(left, right))
return EqualOrMoreSpecific;
if (areTypesCompatible(right, left))
return MoreGeneric;
return NotRelated;
}
/* Answer an int describing the relationship between the given type and unchecked exceptions.
*
* NotRelated
* EqualOrMoreSpecific : type is known for sure to be an unchecked exception type
* MoreGeneric : type is a supertype of an actual unchecked exception type
*/
public int compareUncheckedException(ReferenceBinding type) {
int comparison = compareTypes(type, getJavaLangRuntimeException());
if (comparison != 0)
return comparison;
else
return compareTypes(type, getJavaLangError());
}
public final CompilationUnitScope compilationUnitScope() {
Scope lastScope = null;
Scope scope = this;
do {
lastScope = scope;
scope = scope.parent;
} while (scope != null);
return (CompilationUnitScope) lastScope;
}
public ArrayBinding createArray(TypeBinding type, int dimension) {
if (type.isValidBinding())
return environment().createArrayType(type, dimension);
else
return new ArrayBinding(type, dimension);
}
/* Answer the receiver's enclosing source type.
*/
public final SourceTypeBinding enclosingSourceType() {
Scope scope = this;
do {
if (scope instanceof ClassScope)
return ((ClassScope) scope).referenceContext.binding;
scope = scope.parent;
} while (scope != null);
return null;
}
public final LookupEnvironment environment() {
Scope scope, unitScope = this;
while ((scope = unitScope.parent) != null)
unitScope = scope;
return ((CompilationUnitScope) unitScope).environment;
}
// Internal use only
public ReferenceBinding findDirectMemberType(
char[] typeName,
ReferenceBinding enclosingType) {
if ((enclosingType.tagBits & HasNoMemberTypes) != 0)
return null; // know it has no member types (nor inherited member types)
SourceTypeBinding enclosingSourceType = enclosingSourceType();
compilationUnitScope().addTypeReference(enclosingType);
ReferenceBinding memberType = enclosingType.getMemberType(typeName);
if (memberType != null) {
compilationUnitScope().addTypeReference(memberType);
if (enclosingSourceType == null
? memberType.canBeSeenBy(getCurrentPackage())
: memberType.canBeSeenBy(enclosingType, enclosingSourceType))
return memberType;
else
return new ProblemReferenceBinding(typeName, NotVisible);
}
return null;
}
// Internal use only
public MethodBinding findExactMethod(
ReferenceBinding receiverType,
char[] selector,
TypeBinding[] argumentTypes,
InvocationSite invocationSite) {
compilationUnitScope().addTypeReference(receiverType);
compilationUnitScope().addTypeReferences(argumentTypes);
MethodBinding exactMethod =
receiverType.getExactMethod(selector, argumentTypes);
if (exactMethod != null) {
compilationUnitScope().addTypeReferences(exactMethod.thrownExceptions);
if (receiverType.isInterface()
|| exactMethod.canBeSeenBy(receiverType, invocationSite, this))
return exactMethod;
}
return null;
}
// Internal use only
/* Answer the field binding that corresponds to fieldName.
Start the lookup at the receiverType.
InvocationSite implements
isSuperAccess(); this is used to determine if the discovered field is visible.
Only fields defined by the receiverType or its supertypes are answered;
a field of an enclosing type will not be found using this API.
If no visible field is discovered, null is answered.
*/
public FieldBinding findField(
TypeBinding receiverType,
char[] fieldName,
InvocationSite invocationSite) {
if (receiverType.isBaseType())
return null;
if (receiverType.isArrayType()) {
if (CharOperation.equals(fieldName, LENGTH))
return ArrayBinding.LengthField;
return null;
}
ReferenceBinding currentType = (ReferenceBinding) receiverType;
if (!currentType.canBeSeenBy(this))
return new ProblemFieldBinding(currentType, fieldName, NotVisible);
// *** Need a new problem id - TypeNotVisible?
compilationUnitScope().addTypeReference(currentType);
FieldBinding field = currentType.getField(fieldName);
if (field != null) {
if (field.canBeSeenBy(currentType, invocationSite, this))
return field;
else
return new ProblemFieldBinding(field.declaringClass, fieldName, NotVisible);
}
// collect all superinterfaces of receiverType until the field is found in a supertype
ReferenceBinding[][] interfacesToVisit = null;
int lastPosition = -1;
FieldBinding visibleField = null;
boolean keepLooking = true;
boolean notVisible = false;
// we could hold onto the not visible field for extra error reporting
while (keepLooking) {
ReferenceBinding[] itsInterfaces = currentType.superInterfaces();
if (itsInterfaces != NoSuperInterfaces) {
if (interfacesToVisit == null)
interfacesToVisit = new ReferenceBinding[5][];
if (++lastPosition == interfacesToVisit.length)
System.arraycopy(
interfacesToVisit,
0,
interfacesToVisit = new ReferenceBinding[lastPosition * 2][],
0,
lastPosition);
interfacesToVisit[lastPosition] = itsInterfaces;
}
if ((currentType = currentType.superclass()) == null)
break;
if ((field = currentType.getField(fieldName)) != null) {
keepLooking = false;
if (field.canBeSeenBy(receiverType, invocationSite, this)) {
if (visibleField == null)
visibleField = field;
else
return new ProblemFieldBinding(visibleField.declaringClass, fieldName, Ambiguous);
} else {
notVisible = true;
}
}
}
// walk all visible interfaces to find ambiguous references
if (interfacesToVisit != null) {
ProblemFieldBinding ambiguous = null;
done : for (int i = 0; i <= lastPosition; i++) {
ReferenceBinding[] interfaces = interfacesToVisit[i];
for (int j = 0, length = interfaces.length; j < length; j++) {
ReferenceBinding anInterface = interfaces[j];
if ((anInterface.tagBits & InterfaceVisited) == 0) {
// if interface as not already been visited
anInterface.tagBits |= InterfaceVisited;
if ((field = anInterface.getField(fieldName)) != null) {
if (visibleField == null) {
visibleField = field;
} else {
ambiguous = new ProblemFieldBinding(visibleField.declaringClass, fieldName, Ambiguous);
break done;
}
} else {
ReferenceBinding[] itsInterfaces = anInterface.superInterfaces();
if (itsInterfaces != NoSuperInterfaces) {
if (++lastPosition == interfacesToVisit.length)
System.arraycopy(
interfacesToVisit,
0,
interfacesToVisit = new ReferenceBinding[lastPosition * 2][],
0,
lastPosition);
interfacesToVisit[lastPosition] = itsInterfaces;
}
}
}
}
}
// bit reinitialization
for (int i = 0; i <= lastPosition; i++) {
ReferenceBinding[] interfaces = interfacesToVisit[i];
for (int j = 0, length = interfaces.length; j < length; j++)
interfaces[j].tagBits &= ~InterfaceVisited;
}
if (ambiguous != null)
return ambiguous;
}
if (visibleField != null)
return visibleField;
if (notVisible)
return new ProblemFieldBinding(currentType, fieldName, NotVisible);
return null;
}
// Internal use only
public ReferenceBinding findMemberType(
char[] typeName,
ReferenceBinding enclosingType) {
if ((enclosingType.tagBits & HasNoMemberTypes) != 0)
return null; // know it has no member types (nor inherited member types)
SourceTypeBinding enclosingSourceType = enclosingSourceType();
PackageBinding currentPackage = getCurrentPackage();
compilationUnitScope().addTypeReference(enclosingType);
ReferenceBinding memberType = enclosingType.getMemberType(typeName);
if (memberType != null) {
compilationUnitScope().addTypeReference(memberType);
if (enclosingSourceType == null
? memberType.canBeSeenBy(currentPackage)
: memberType.canBeSeenBy(enclosingType, enclosingSourceType))
return memberType;
else
return new ProblemReferenceBinding(typeName, NotVisible);
}
// collect all superinterfaces of receiverType until the memberType is found in a supertype
ReferenceBinding currentType = enclosingType;
ReferenceBinding[][] interfacesToVisit = null;
int lastPosition = -1;
ReferenceBinding visibleMemberType = null;
boolean keepLooking = true;
boolean notVisible = false;
// we could hold onto the not visible field for extra error reporting
while (keepLooking) {
ReferenceBinding[] itsInterfaces = currentType.superInterfaces();
if (itsInterfaces != NoSuperInterfaces) {
if (interfacesToVisit == null)
interfacesToVisit = new ReferenceBinding[5][];
if (++lastPosition == interfacesToVisit.length)
System.arraycopy(
interfacesToVisit,
0,
interfacesToVisit = new ReferenceBinding[lastPosition * 2][],
0,
lastPosition);
interfacesToVisit[lastPosition] = itsInterfaces;
}
if ((currentType = currentType.superclass()) == null)
break;
compilationUnitScope().addTypeReference(currentType);
if ((memberType = currentType.getMemberType(typeName)) != null) {
compilationUnitScope().addTypeReference(memberType);
keepLooking = false;
if (enclosingSourceType == null
? memberType.canBeSeenBy(currentPackage)
: memberType.canBeSeenBy(enclosingType, enclosingSourceType)) {
if (visibleMemberType == null)
visibleMemberType = memberType;
else
return new ProblemReferenceBinding(typeName, Ambiguous);
} else {
notVisible = true;
}
}
}
// walk all visible interfaces to find ambiguous references
if (interfacesToVisit != null) {
ProblemReferenceBinding ambiguous = null;
done : for (int i = 0; i <= lastPosition; i++) {
ReferenceBinding[] interfaces = interfacesToVisit[i];
for (int j = 0, length = interfaces.length; j < length; j++) {
ReferenceBinding anInterface = interfaces[j];
if ((anInterface.tagBits & InterfaceVisited) == 0) {
// if interface as not already been visited
anInterface.tagBits |= InterfaceVisited;
compilationUnitScope().addTypeReference(anInterface);
if ((memberType = anInterface.getMemberType(typeName)) != null) {
compilationUnitScope().addTypeReference(memberType);
if (visibleMemberType == null) {
visibleMemberType = memberType;
} else {
ambiguous = new ProblemReferenceBinding(typeName, Ambiguous);
break done;
}
} else {
ReferenceBinding[] itsInterfaces = anInterface.superInterfaces();
if (itsInterfaces != NoSuperInterfaces) {
if (++lastPosition == interfacesToVisit.length)
System.arraycopy(
interfacesToVisit,
0,
interfacesToVisit = new ReferenceBinding[lastPosition * 2][],
0,
lastPosition);
interfacesToVisit[lastPosition] = itsInterfaces;
}
}
}
}
}
// bit reinitialization
for (int i = 0; i <= lastPosition; i++) {
ReferenceBinding[] interfaces = interfacesToVisit[i];
for (int j = 0, length = interfaces.length; j < length; j++)
interfaces[j].tagBits &= ~InterfaceVisited;
}
if (ambiguous != null)
return ambiguous;
}
if (visibleMemberType != null)
return visibleMemberType;
if (notVisible)
return new ProblemReferenceBinding(typeName, NotVisible);
return null;
}
// Internal use only
public MethodBinding findMethod(
ReferenceBinding receiverType,
char[] selector,
TypeBinding[] argumentTypes,
InvocationSite invocationSite) {
ReferenceBinding currentType = receiverType;
MethodBinding matchingMethod = null;
ObjectVector found = null;
compilationUnitScope().addTypeReference(currentType);
compilationUnitScope().addTypeReferences(argumentTypes);
if (currentType.isInterface()) {
MethodBinding[] currentMethods = currentType.getMethods(selector);
int currentLength = currentMethods.length;
if (currentLength == 1) {
matchingMethod = currentMethods[0];
} else if (currentLength > 1) {
found = new ObjectVector();
for (int f = 0; f < currentLength; f++)
found.add(currentMethods[f]);
}
ReferenceBinding[] itsInterfaces = currentType.superInterfaces();
if (itsInterfaces != NoSuperInterfaces) {
ReferenceBinding[][] interfacesToVisit = new ReferenceBinding[5][];
int lastPosition = -1;
if (++lastPosition == interfacesToVisit.length)
System.arraycopy(
interfacesToVisit,
0,
interfacesToVisit = new ReferenceBinding[lastPosition * 2][],
0,
lastPosition);
interfacesToVisit[lastPosition] = itsInterfaces;
for (int i = 0; i <= lastPosition; i++) {
ReferenceBinding[] interfaces = interfacesToVisit[i];
for (int j = 0, length = interfaces.length; j < length; j++) {
currentType = interfaces[j];
if ((currentType.tagBits & InterfaceVisited) == 0) {
// if interface as not already been visited
currentType.tagBits |= InterfaceVisited;
currentMethods = currentType.getMethods(selector);
if ((currentLength = currentMethods.length) == 1
&& matchingMethod == null
&& found == null) {
matchingMethod = currentMethods[0];
} else if (currentLength > 0) {
if (found == null) {
found = new ObjectVector();
if (matchingMethod != null)
found.add(matchingMethod);
}
for (int f = 0; f < currentLength; f++)
found.add(currentMethods[f]);
}
itsInterfaces = currentType.superInterfaces();
if (itsInterfaces != NoSuperInterfaces) {
if (++lastPosition == interfacesToVisit.length)
System.arraycopy(
interfacesToVisit,
0,
interfacesToVisit = new ReferenceBinding[lastPosition * 2][],
0,
lastPosition);
interfacesToVisit[lastPosition] = itsInterfaces;
}
}
}
}
// bit reinitialization
for (int i = 0; i <= lastPosition; i++) {
ReferenceBinding[] interfaces = interfacesToVisit[i];
for (int j = 0, length = interfaces.length; j < length; j++)
interfaces[j].tagBits &= ~InterfaceVisited;
}
}
currentType =
(matchingMethod == null && found == null) ? getJavaLangObject() : null;
}
while (currentType != null) {
MethodBinding[] currentMethods = currentType.getMethods(selector);
int currentLength = currentMethods.length;
if (currentLength == 1 && matchingMethod == null && found == null) {
matchingMethod = currentMethods[0];
} else if (currentLength > 0) {
if (found == null) {
found = new ObjectVector();
if (matchingMethod != null)
found.add(matchingMethod);
}
for (int f = 0; f < currentLength; f++)
found.add(currentMethods[f]);
}
currentType = currentType.superclass();
}
if (found == null)
return matchingMethod;
// may be null - have not checked arg types or visibility
int foundSize = found.size;
MethodBinding[] compatible = new MethodBinding[foundSize];
int compatibleIndex = 0;
for (int i = 0; i < foundSize; i++) {
MethodBinding methodBinding = (MethodBinding) found.elementAt(i);
if (areParametersAssignable(methodBinding.parameters, argumentTypes))
compatible[compatibleIndex++] = methodBinding;
}
if (compatibleIndex == 1)
return compatible[0]; // have not checked visibility
if (compatibleIndex == 0)
return (MethodBinding) found.elementAt(0);
// no good match so just use the first one found
MethodBinding[] visible = new MethodBinding[compatibleIndex];
int visibleIndex = 0;
for (int i = 0; i < compatibleIndex; i++) {
MethodBinding methodBinding = compatible[i];
if (methodBinding.canBeSeenBy(receiverType, invocationSite, this))
visible[visibleIndex++] = methodBinding;
}
if (visibleIndex == 1) {
compilationUnitScope().addTypeReferences(visible[0].thrownExceptions);
return visible[0];
}
if (visibleIndex == 0)
return new ProblemMethodBinding(
compatible[0].selector,
argumentTypes,
compatible[0].declaringClass,
NotVisible);
if (visible[0].declaringClass.isClass())
return mostSpecificClassMethodBinding(visible, visibleIndex);
else
return mostSpecificInterfaceMethodBinding(visible, visibleIndex);
}
// Internal use only
public MethodBinding findMethodForArray(
ArrayBinding receiverType,
char[] selector,
TypeBinding[] argumentTypes,
InvocationSite invocationSite) {
ReferenceBinding object = getJavaLangObject();
MethodBinding methodBinding = object.getExactMethod(selector, argumentTypes);
if (methodBinding != null) {
// handle the method clone() specially... cannot be protected or throw exceptions
if (argumentTypes == NoParameters && CharOperation.equals(selector, CLONE))
return new MethodBinding(
(methodBinding.modifiers ^ AccProtected) | AccPublic,
CLONE,
methodBinding.returnType,
argumentTypes,
null,
object);
if (methodBinding.canBeSeenBy(receiverType, invocationSite, this))
return methodBinding;
}
// answers closest approximation, may not check argumentTypes or visibility
methodBinding = findMethod(object, selector, argumentTypes, invocationSite);
if (methodBinding == null)
return new ProblemMethodBinding(selector, argumentTypes, NotFound);
if (methodBinding.isValidBinding()) {
if (!areParametersAssignable(methodBinding.parameters, argumentTypes))
return new ProblemMethodBinding(
methodBinding,
selector,
argumentTypes,
NotFound);
if (!methodBinding.canBeSeenBy(receiverType, invocationSite, this))
return new ProblemMethodBinding(
selector,
argumentTypes,
methodBinding.declaringClass,
NotVisible);
}
return methodBinding;
}
// Internal use only
public ReferenceBinding findType(
char[] typeName,
PackageBinding declarationPackage,
PackageBinding invocationPackage) {
compilationUnitScope().addNamespaceReference(declarationPackage);
ReferenceBinding typeBinding = declarationPackage.getType(typeName);
if (typeBinding == null)
return null;
if (typeBinding.isValidBinding()) {
compilationUnitScope().addTypeReference(typeBinding);
if (declarationPackage != invocationPackage
&& !typeBinding.canBeSeenBy(invocationPackage))
return new ProblemReferenceBinding(typeName, NotVisible);
}
return typeBinding;
}
public TypeBinding getBaseType(char[] name) {
// list should be optimized (with most often used first)
int length = name.length;
if (length > 2 && length < 8) {
switch (name[0]) {
case 'i' :
if (length == 3 && name[1] == 'n' && name[2] == 't')
return IntBinding;
break;
case 'v' :
if (length == 4 && name[1] == 'o' && name[2] == 'i' && name[3] == 'd')
return VoidBinding;
break;
case 'b' :
if (length == 7
&& name[1] == 'o'
&& name[2] == 'o'
&& name[3] == 'l'
&& name[4] == 'e'
&& name[5] == 'a'
&& name[6] == 'n')
return BooleanBinding;
if (length == 4 && name[1] == 'y' && name[2] == 't' && name[3] == 'e')
return ByteBinding;
break;
case 'c' :
if (length == 4 && name[1] == 'h' && name[2] == 'a' && name[3] == 'r')
return CharBinding;
break;
case 'd' :
if (length == 6
&& name[1] == 'o'
&& name[2] == 'u'
&& name[3] == 'b'
&& name[4] == 'l'
&& name[5] == 'e')
return DoubleBinding;
break;
case 'f' :
if (length == 5
&& name[1] == 'l'
&& name[2] == 'o'
&& name[3] == 'a'
&& name[4] == 't')
return FloatBinding;
break;
case 'l' :
if (length == 4 && name[1] == 'o' && name[2] == 'n' && name[3] == 'g')
return LongBinding;
break;
case 's' :
if (length == 5
&& name[1] == 'h'
&& name[2] == 'o'
&& name[3] == 'r'
&& name[4] == 't')
return ShortBinding;
}
}
return null;
}
public final PackageBinding getCurrentPackage() {
Scope scope, unitScope = this;
while ((scope = unitScope.parent) != null)
unitScope = scope;
return ((CompilationUnitScope) unitScope).fPackage;
}
public final ReferenceBinding getJavaIoSerializable() {
ReferenceBinding type = environment().getType(JAVA_IO_SERIALIZABLE);
if (type != null)
return type;
compilationUnitScope().addNamespaceReference(
new ProblemPackageBinding(JAVA_IO, NotFound));
// record extra reference to pkg
problemReporter().isClassPathCorrect(
JAVA_IO_SERIALIZABLE,
referenceCompilationUnit());
return null; // will not get here since the above error aborts the compilation
}
public final ReferenceBinding getJavaLangClass() {
ReferenceBinding type = environment().getType(JAVA_LANG_CLASS);
if (type != null)
return type;
compilationUnitScope().addNamespaceReference(
new ProblemPackageBinding(JAVA_LANG, NotFound));
// record extra reference to pkg
problemReporter().isClassPathCorrect(
JAVA_LANG_CLASS,
referenceCompilationUnit());
return null; // will not get here since the above error aborts the compilation
}
public final ReferenceBinding getJavaLangCloneable() {
ReferenceBinding type = environment().getType(JAVA_LANG_CLONEABLE);
if (type != null)
return type;
compilationUnitScope().addNamespaceReference(
new ProblemPackageBinding(JAVA_LANG, NotFound));
// record extra reference to pkg
problemReporter().isClassPathCorrect(
JAVA_LANG_CLONEABLE,
referenceCompilationUnit());
return null; // will not get here since the above error aborts the compilation
}
public final ReferenceBinding getJavaLangError() {
ReferenceBinding type = environment().getType(JAVA_LANG_ERROR);
if (type != null)
return type;
compilationUnitScope().addNamespaceReference(
new ProblemPackageBinding(JAVA_LANG, NotFound));
// record extra reference to pkg
problemReporter().isClassPathCorrect(
JAVA_LANG_ERROR,
referenceCompilationUnit());
return null; // will not get here since the above error aborts the compilation
}
public final ReferenceBinding getJavaLangAssertionError() {
ReferenceBinding type = environment().getType(JAVA_LANG_ASSERTIONERROR);
if (type != null)
return type;
compilationUnitScope().addNamespaceReference(
new ProblemPackageBinding(JAVA_LANG, NotFound));
// record extra reference to pkg
problemReporter().isClassPathCorrect(
JAVA_LANG_ASSERTIONERROR,
referenceCompilationUnit());
return null; // will not get here since the above error aborts the compilation
}
public final ReferenceBinding getJavaLangObject() {
ReferenceBinding type = environment().getType(JAVA_LANG_OBJECT);
if (type != null)
return type;
compilationUnitScope().addNamespaceReference(
new ProblemPackageBinding(JAVA_LANG, NotFound));
// record extra reference to pkg
problemReporter().isClassPathCorrect(
JAVA_LANG_OBJECT,
referenceCompilationUnit());
return null; // will not get here since the above error aborts the compilation
}
public final ReferenceBinding getJavaLangRuntimeException() {
ReferenceBinding type = environment().getType(JAVA_LANG_RUNTIMEEXCEPTION);
if (type != null)
return type;
compilationUnitScope().addNamespaceReference(
new ProblemPackageBinding(JAVA_LANG, NotFound));
// record extra reference to pkg
problemReporter().isClassPathCorrect(
JAVA_LANG_RUNTIMEEXCEPTION,
referenceCompilationUnit());
return null; // will not get here since the above error aborts the compilation
}
public final ReferenceBinding getJavaLangString() {
ReferenceBinding type = environment().getType(JAVA_LANG_STRING);
if (type != null)
return type;
compilationUnitScope().addNamespaceReference(
new ProblemPackageBinding(JAVA_LANG, NotFound));
problemReporter().isClassPathCorrect(
JAVA_LANG_STRING,
referenceCompilationUnit());
return null; // will not get here since the above error aborts the compilation
}
public final ReferenceBinding getJavaLangThrowable() {
ReferenceBinding type = environment().getType(JAVA_LANG_THROWABLE);
if (type != null)
return type;
compilationUnitScope().addNamespaceReference(
new ProblemPackageBinding(JAVA_LANG, NotFound));
problemReporter().isClassPathCorrect(
JAVA_LANG_THROWABLE,
referenceCompilationUnit());
return null; // will not get here since the above error aborts the compilation
}
/* Answer the type binding corresponding to the typeName argument, relative to the enclosingType.
*/
public final ReferenceBinding getMemberType(
char[] typeName,
ReferenceBinding enclosingType) {
ReferenceBinding memberType = findMemberType(typeName, enclosingType);
if (memberType == null)
return new ProblemReferenceBinding(typeName, NotFound);
else
return memberType;
}
/* Answer the type binding corresponding to the compoundName.
*
* NOTE: If a problem binding is returned, senders should extract the compound name
* from the binding & not assume the problem applies to the entire compoundName.
*/
public final TypeBinding getType(char[][] compoundName) {
int typeNameLength = compoundName.length;
if (typeNameLength == 1) {
// Would like to remove this test and require senders to specially handle base types
TypeBinding binding = getBaseType(compoundName[0]);
if (binding != null)
return binding;
}
Binding binding =
getTypeOrPackage(compoundName[0], typeNameLength == 1 ? TYPE : TYPE | PACKAGE);
if (binding == null)
return new ProblemReferenceBinding(compoundName[0], NotFound);
if (!binding.isValidBinding()) {
compilationUnitScope().addNamespaceReference(
new ProblemPackageBinding(compoundName[0], NotFound));
// record extra reference to pkg
return (ReferenceBinding) binding;
}
int currentIndex = 1;
boolean checkVisibility = false;
if (binding instanceof PackageBinding) {
PackageBinding packageBinding = (PackageBinding) binding;
compilationUnitScope().addNamespaceReference(packageBinding);
while (currentIndex < typeNameLength) {
binding = packageBinding.getTypeOrPackage(compoundName[currentIndex++]);
// does not check visibility
if (binding == null)
return new ProblemReferenceBinding(
CharOperation.subarray(compoundName, 0, currentIndex),
NotFound);
if (!binding.isValidBinding())
return new ProblemReferenceBinding(
CharOperation.subarray(compoundName, 0, currentIndex),
binding.problemId());
if (!(binding instanceof PackageBinding))
break;
packageBinding = (PackageBinding) binding;
compilationUnitScope().addNamespaceReference(packageBinding);
}
if (binding instanceof PackageBinding)
return new ProblemReferenceBinding(
CharOperation.subarray(compoundName, 0, currentIndex),
NotFound);
checkVisibility = true;
}
// binding is now a ReferenceBinding
ReferenceBinding typeBinding = (ReferenceBinding) binding;
compilationUnitScope().addTypeReference(typeBinding);
if (checkVisibility) // handles the fall through case
if (!typeBinding.canBeSeenBy(this))
return new ProblemReferenceBinding(
CharOperation.subarray(compoundName, 0, currentIndex),
NotVisible);
while (currentIndex < typeNameLength) {
typeBinding = getMemberType(compoundName[currentIndex++], typeBinding);
if (!typeBinding.isValidBinding())
return new ProblemReferenceBinding(
CharOperation.subarray(compoundName, 0, currentIndex),
typeBinding.problemId());
}
return typeBinding;
}
/* Answer the type binding that corresponds the given name, starting the lookup in the receiver.
* The name provided is a simple source name (e.g., "Object" , "Point", ...)
*/
// The return type of this method could be ReferenceBinding if we did not answer base types.
// NOTE: We could support looking for Base Types last in the search, however any code using
// this feature would be extraordinarily slow. Therefore we don't do this
public final TypeBinding getType(char[] name) {
// Would like to remove this test and require senders to specially handle base types
TypeBinding binding = getBaseType(name);
if (binding != null)
return binding;
return (ReferenceBinding) getTypeOrPackage(name, TYPE);
}
// Added for code assist... NOT Public API
public final Binding getTypeOrPackage(char[][] compoundName) {
int nameLength = compoundName.length;
if (nameLength == 1) {
TypeBinding binding = getBaseType(compoundName[0]);
if (binding != null)
return binding;
}
Binding binding = getTypeOrPackage(compoundName[0], TYPE | PACKAGE);
if (!binding.isValidBinding())
return binding;
int currentIndex = 1;
boolean checkVisibility = false;
if (binding instanceof PackageBinding) {
PackageBinding packageBinding = (PackageBinding) binding;
while (currentIndex < nameLength) {
binding = packageBinding.getTypeOrPackage(compoundName[currentIndex++]);
if (binding == null)
return new ProblemReferenceBinding(
CharOperation.subarray(compoundName, 0, currentIndex),
NotFound);
if (!binding.isValidBinding())
return new ProblemReferenceBinding(
CharOperation.subarray(compoundName, 0, currentIndex),
binding.problemId());
if (!(binding instanceof PackageBinding))
break;
packageBinding = (PackageBinding) binding;
}
if (binding instanceof PackageBinding)
return binding;
checkVisibility = true;
}
// binding is now a ReferenceBinding
ReferenceBinding typeBinding = (ReferenceBinding) binding;
if (checkVisibility) // handles the fall through case
if (!typeBinding.canBeSeenBy(this))
return new ProblemReferenceBinding(
CharOperation.subarray(compoundName, 0, currentIndex),
NotVisible);
while (currentIndex < nameLength) {
typeBinding = getMemberType(compoundName[currentIndex++], typeBinding);
// checks visibility
if (!typeBinding.isValidBinding())
return new ProblemReferenceBinding(
CharOperation.subarray(compoundName, 0, currentIndex),
typeBinding.problemId());
}
return typeBinding;
}
/* Internal use only
*/
final Binding getTypeOrPackage(char[] name, int mask) {
Scope scope = this;
if ((mask & TYPE) == 0) {
Scope next = scope;
while ((next = scope.parent) != null)
scope = next;
} else {
ReferenceBinding foundType = null;
done : while (true) { // done when a COMPILATION_UNIT_SCOPE is found
switch (scope.kind) {
case METHOD_SCOPE :
case BLOCK_SCOPE :
ReferenceBinding localType = ((BlockScope) scope).findLocalType(name);
// looks in this scope only
if (localType != null) {
if (foundType != null && foundType != localType)
return new ProblemReferenceBinding(name, InheritedNameHidesEnclosingName);
return localType;
}
break;
case CLASS_SCOPE :
SourceTypeBinding sourceType = ((ClassScope) scope).referenceContext.binding;
if (CharOperation.equals(sourceType.sourceName, name)) {
if (foundType != null && foundType != sourceType)
return new ProblemReferenceBinding(name, InheritedNameHidesEnclosingName);
return sourceType;
}
ReferenceBinding memberType = findMemberType(name, sourceType);
if (memberType != null) { // skip it if we did not find anything
if (memberType.problemId() == Ambiguous) {
if (foundType == null || foundType.problemId() == NotVisible)
// supercedes any potential InheritedNameHidesEnclosingName problem
return memberType;
else
// make the user qualify the type, likely wants the first inherited type
return new ProblemReferenceBinding(name, InheritedNameHidesEnclosingName);
}
if (memberType.isValidBinding()) {
if (sourceType == memberType.enclosingType()) {
// found a valid type in the 'immediate' scope (ie. not inherited)
if (foundType == null)
return memberType;
if (foundType.isValidBinding())
// if a valid type was found, complain when another is found in an 'immediate' enclosing type (ie. not inherited)
if (foundType != memberType)
return new ProblemReferenceBinding(name, InheritedNameHidesEnclosingName);
}
}
if (foundType == null
|| (foundType.problemId() == NotVisible && memberType.problemId() != NotVisible))
// only remember the memberType if its the first one found or the previous one was not visible & memberType is...
foundType = memberType;
}
break;
case COMPILATION_UNIT_SCOPE :
break done;
}
scope = scope.parent;
}
if (foundType != null)
return foundType;
}
// at this point the scope is a compilation unit scope
CompilationUnitScope unitScope = (CompilationUnitScope) scope;
// ask for the imports + name
if ((mask & TYPE) != 0) {
// check single type imports.
ImportBinding[] imports = unitScope.imports;
// copy the list, since single type imports are removed if they cannot be resolved
for (int i = 0, length = imports.length; i < length; i++) {
ImportBinding typeImport = imports[i];
if (!typeImport.onDemand)
if (CharOperation
.equals(typeImport.compoundName[typeImport.compoundName.length - 1], name))
if (unitScope.resolveSingleTypeImport(typeImport) != null)
return typeImport.resolvedImport; // already know its visible
}
// check if the name is in the current package (answer the problem binding unless its not found in which case continue to look)
ReferenceBinding type = findType(name, unitScope.fPackage, unitScope.fPackage);
// is always visible
if (type != null)
return type;
// check on demand imports
boolean foundInImport = false;
for (int i = 0, length = unitScope.imports.length; i < length; i++) {
if (unitScope.imports[i].onDemand) {
Binding resolvedImport = unitScope.imports[i].resolvedImport;
ReferenceBinding temp =
(resolvedImport instanceof PackageBinding)
? findType(name, (PackageBinding) resolvedImport, unitScope.fPackage)
: findDirectMemberType(name, (ReferenceBinding) resolvedImport);
if (temp != null && temp.isValidBinding()) {
if (foundInImport)
// Answer error binding -- import on demand conflict; name found in two import on demand packages.
return new ProblemReferenceBinding(name, Ambiguous);
type = temp;
foundInImport = true;
}
}
}
if (type != null)
return type;
}
// see if the name is a package
if ((mask & PACKAGE) != 0) {
PackageBinding packageBinding = unitScope.environment.getTopLevelPackage(name);
if (packageBinding != null)
return packageBinding;
}
// Answer error binding -- could not find name
compilationUnitScope().addNamespaceReference(
new ProblemPackageBinding(name, NotFound));
return new ProblemReferenceBinding(name, NotFound);
}
/* Answer whether the type is defined in the same compilation unit as the receiver
*/
public final boolean isDefinedInSameUnit(ReferenceBinding type) {
// find the outer most enclosing type
ReferenceBinding enclosingType = type;
while ((type = enclosingType.enclosingType()) != null)
enclosingType = type;
// find the compilation unit scope
Scope scope, unitScope = this;
while ((scope = unitScope.parent) != null)
unitScope = scope;
// test that the enclosingType is not part of the compilation unit
SourceTypeBinding[] topLevelTypes =
((CompilationUnitScope) unitScope).topLevelTypes;
for (int i = topLevelTypes.length; --i >= 0;)
if (topLevelTypes[i] == enclosingType)
return true;
return false;
}
public final boolean isJavaIoSerializable(TypeBinding tb) {
//a first -none optimized version-...:-)....
//please modify as needed
return tb == getJavaIoSerializable();
}
public final boolean isJavaLangCloneable(TypeBinding tb) {
//a first -none optimized version-...:-)....
//please modify as needed
return tb == getJavaLangCloneable();
}
public final boolean isJavaLangObject(TypeBinding type) {
return type.id == T_JavaLangObject;
}
public final MethodScope methodScope() {
Scope scope = this;
do {
if (scope instanceof MethodScope)
return (MethodScope) scope;
scope = scope.parent;
} while (scope != null);
return null;
}
// Internal use only
/* All methods in visible are acceptable matches for the method in question...
* The methods defined by the receiver type appear before those defined by its
* superclass and so on. We want to find the one which matches best.
*
* Since the receiver type is a class, we know each method's declaring class is
* either the receiver type or one of its superclasses. It is an error if the best match
* is defined by a superclass, when a lesser match is defined by the receiver type
* or a closer superclass.
*/
protected final MethodBinding mostSpecificClassMethodBinding(
MethodBinding[] visible,
int visibleSize) {
MethodBinding method = null;
MethodBinding previous = null;
nextVisible : for (int i = 0; i < visibleSize; i++) {
method = visible[i];
if (previous != null && method.declaringClass != previous.declaringClass)
break;
// cannot answer a method farther up the hierarchy than the first method found
previous = method;
for (int j = 0; j < visibleSize; j++) {
if (i == j)
continue;
MethodBinding next = visible[j];
if (!areParametersAssignable(next.parameters, method.parameters))
continue nextVisible;
}
compilationUnitScope().addTypeReferences(method.thrownExceptions);
return method;
}
return new ProblemMethodBinding(
visible[0].selector,
visible[0].parameters,
Ambiguous);
}
// Internal use only
/* All methods in visible are acceptable matches for the method in question...
* Since the receiver type is an interface, we ignore the possibility that 2 inherited
* but unrelated superinterfaces may define the same method in acceptable but
* not identical ways... we just take the best match that we find since any class which
* implements the receiver interface MUST implement all signatures for the method...
* in which case the best match is correct.
*
* NOTE: This is different than javac... in the following example, the message send of
* bar(X) in class Y is supposed to be ambiguous. But any class which implements the
* interface I MUST implement both signatures for bar. If this class was the receiver of
* the message send instead of the interface I, then no problem would be reported.
*
interface I1 {
void bar(J j);
}
interface I2 {
// void bar(J j);
void bar(Object o);
}
interface I extends I1, I2 {}
interface J {}
class X implements J {}
class Y extends X {
public void foo(I i, X x) { i.bar(x); }
}
*/
protected final MethodBinding mostSpecificInterfaceMethodBinding(
MethodBinding[] visible,
int visibleSize) {
MethodBinding method = null;
nextVisible : for (int i = 0; i < visibleSize; i++) {
method = visible[i];
for (int j = 0; j < visibleSize; j++) {
if (i == j)
continue;
MethodBinding next = visible[j];
if (!areParametersAssignable(next.parameters, method.parameters))
continue nextVisible;
}
compilationUnitScope().addTypeReferences(method.thrownExceptions);
return method;
}
return new ProblemMethodBinding(
visible[0].selector,
visible[0].parameters,
Ambiguous);
}
public final ClassScope outerMostClassScope() {
ClassScope lastClassScope = null;
Scope scope = this;
do {
if (scope instanceof ClassScope)
lastClassScope = (ClassScope) scope;
scope = scope.parent;
} while (scope != null);
return lastClassScope; // may answer null if no class around
}
public final MethodScope outerMostMethodScope() {
MethodScope lastMethodScope = null;
Scope scope = this;
do {
if (scope instanceof MethodScope)
lastMethodScope = (MethodScope) scope;
scope = scope.parent;
} while (scope != null);
return lastMethodScope; // may answer null if no method around
}
public final CompilationUnitDeclaration referenceCompilationUnit() {
Scope scope, unitScope = this;
while ((scope = unitScope.parent) != null)
unitScope = scope;
return ((CompilationUnitScope) unitScope).referenceContext;
}
// start position in this scope - for ordering scopes vs. variables
int startIndex() {
return 0;
}
}