*******************************************************************************/
package org.eclipse.jdt.internal.compiler.lookup;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
import org.eclipse.jdt.core.compiler.CharOperation;
import org.eclipse.jdt.internal.compiler.ast.*;
import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
import org.eclipse.jdt.internal.compiler.util.ObjectVector;
public abstract class Scope
- implements BaseTypes, BindingIds, CompilerModifiers, ProblemReasons, TagBits, TypeConstants, TypeIds {
+ implements BaseTypes, CompilerModifiers, ProblemReasons, TagBits, TypeConstants, TypeIds {
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;
+ public final static int METHOD_SCOPE = 2;
- public int kind;
- public Scope parent;
-
- protected Scope(int kind, Scope parent) {
- this.kind = kind;
- this.parent = parent;
- }
+ public final static int NOT_COMPATIBLE = -1;
+ public final static int COMPATIBLE = 0;
+ public final static int AUTOBOX_COMPATIBLE = 1;
+ public final static int VARARGS_COMPATIBLE = 2;
- /* Answer an int describing the relationship between the given types.
+ /* Answer an int describing the relationship between the given types.
*
* NotRelated
* EqualOrMoreSpecific : left is compatible with right
return NotRelated;
}
- // Internal use only
- protected final boolean areParametersAssignable(TypeBinding[] parameters, TypeBinding[] arguments) {
- if (parameters == arguments)
- return true;
+ /**
+ * Returns an array of types, where original types got substituted given a substitution.
+ * Only allocate an array if anything is different.
+ */
+ public static ReferenceBinding[] substitute(Substitution substitution, ReferenceBinding[] originalTypes) {
+ ReferenceBinding[] substitutedTypes = originalTypes;
+ for (int i = 0, length = originalTypes.length; i < length; i++) {
+ ReferenceBinding originalType = originalTypes[i];
+ ReferenceBinding substitutedParameter = (ReferenceBinding)substitution.substitute(originalType);
+ if (substitutedParameter != originalType) {
+ if (substitutedTypes == originalTypes) {
+ System.arraycopy(originalTypes, 0, substitutedTypes = new ReferenceBinding[length], 0, i);
+ }
+ substitutedTypes[i] = substitutedParameter;
+ } else if (substitutedTypes != originalTypes) {
+ substitutedTypes[i] = originalType;
+ }
+ }
+ return substitutedTypes;
+ }
+
+ /**
+ * Returns an array of types, where original types got substituted given a substitution.
+ * Only allocate an array if anything is different.
+ */
+ public static TypeBinding[] substitute(Substitution substitution, TypeBinding[] originalTypes) {
+ TypeBinding[] substitutedTypes = originalTypes;
+ for (int i = 0, length = originalTypes.length; i < length; i++) {
+ TypeBinding originalType = originalTypes[i];
+ TypeBinding substitutedParameter = substitution.substitute(originalType);
+ if (substitutedParameter != originalType) {
+ if (substitutedTypes == originalTypes) {
+ System.arraycopy(originalTypes, 0, substitutedTypes = new TypeBinding[length], 0, i);
+ }
+ substitutedTypes[i] = substitutedParameter;
+ } else if (substitutedTypes != originalTypes) {
+ substitutedTypes[i] = originalType;
+ }
+ }
+ return substitutedTypes;
+ }
- int length = parameters.length;
- if (length != arguments.length)
- return false;
+ public int kind;
+ public Scope parent;
+
+ protected Scope(int kind, Scope parent) {
+ this.kind = kind;
+ this.parent = parent;
+ }
- for (int i = 0; i < length; i++)
- if (parameters[i] != arguments[i])
- if (!arguments[i].isCompatibleWith(parameters[i]))
- return false;
- return true;
+ /*
+ * Boxing primitive
+ */
+ public int boxing(int id) {
+ switch (id) {
+ case T_int :
+ return T_JavaLangInteger;
+ case T_byte :
+ return T_JavaLangByte;
+ case T_short :
+ return T_JavaLangShort;
+ case T_char :
+ return T_JavaLangCharacter;
+ case T_long :
+ return T_JavaLangLong;
+ case T_float :
+ return T_JavaLangFloat;
+ case T_double :
+ return T_JavaLangDouble;
+ case T_boolean :
+ return T_JavaLangBoolean;
+ case T_void :
+ return T_JavaLangVoid;
+ }
+ return id;
}
-
+ /*
+ * Boxing primitive
+ */
+ public TypeBinding boxing(TypeBinding type) {
+ TypeBinding boxedType;
+ switch (type.id) {
+ case T_int :
+ boxedType = environment().getType(JAVA_LANG_INTEGER);
+ if (boxedType != null) return boxedType;
+ return new ProblemReferenceBinding( JAVA_LANG_INTEGER, NotFound);
+ case T_byte :
+ boxedType = environment().getType(JAVA_LANG_BYTE);
+ if (boxedType != null) return boxedType;
+ return new ProblemReferenceBinding( JAVA_LANG_BYTE, NotFound);
+ case T_short :
+ boxedType = environment().getType(JAVA_LANG_SHORT);
+ if (boxedType != null) return boxedType;
+ return new ProblemReferenceBinding( JAVA_LANG_SHORT, NotFound);
+ case T_char :
+ boxedType = environment().getType(JAVA_LANG_CHARACTER);
+ if (boxedType != null) return boxedType;
+ return new ProblemReferenceBinding( JAVA_LANG_CHARACTER, NotFound);
+ case T_long :
+ boxedType = environment().getType(JAVA_LANG_LONG);
+ if (boxedType != null) return boxedType;
+ return new ProblemReferenceBinding( JAVA_LANG_LONG, NotFound);
+ case T_float :
+ boxedType = environment().getType(JAVA_LANG_FLOAT);
+ if (boxedType != null) return boxedType;
+ return new ProblemReferenceBinding( JAVA_LANG_FLOAT, NotFound);
+ case T_double :
+ boxedType = environment().getType(JAVA_LANG_DOUBLE);
+ if (boxedType != null) return boxedType;
+ return new ProblemReferenceBinding( JAVA_LANG_DOUBLE, NotFound);
+ case T_boolean :
+ boxedType = environment().getType(JAVA_LANG_BOOLEAN);
+ if (boxedType != null) return boxedType;
+ return new ProblemReferenceBinding( JAVA_LANG_BOOLEAN, NotFound);
+ case T_void :
+ boxedType = environment().getType(JAVA_LANG_VOID);
+ if (boxedType != null) return boxedType;
+ return new ProblemReferenceBinding( JAVA_LANG_VOID, NotFound);
+ }
+ return type;
+ }
+
public final ClassScope classScope() {
Scope scope = this;
do {
return (CompilationUnitScope) lastScope;
}
- public ArrayBinding createArray(TypeBinding type, int dimension) {
- if (!type.isValidBinding())
- return new ArrayBinding(type, dimension);
- return environment().createArrayType(type, dimension);
+ /**
+ * Internal use only
+ * Given a method, returns null if arguments cannot be converted to parameters.
+ * Will answer a subsituted method in case the method was generic and type inference got triggered;
+ * in case the method was originally compatible, then simply answer it back.
+ */
+ protected final MethodBinding computeCompatibleMethod(MethodBinding method, TypeBinding[] arguments, InvocationSite invocationSite) {
+
+ TypeBinding[] genericTypeArguments = invocationSite.genericTypeArguments();
+ TypeBinding[] parameters = method.parameters;
+ TypeVariableBinding[] typeVariables = method.typeVariables;
+ if (parameters == arguments
+ && (method.returnType.tagBits & HasTypeVariable) == 0
+ && genericTypeArguments == null
+ && typeVariables == NoTypeVariables)
+ return method;
+
+ int argLength = arguments.length;
+ int paramLength = parameters.length;
+ boolean isVarArgs = method.isVarargs();
+ if (argLength != paramLength)
+ if (!isVarArgs || argLength < paramLength - 1)
+ return null; // incompatible
+
+ if (typeVariables != NoTypeVariables) { // generic method
+ method = ParameterizedGenericMethodBinding.computeCompatibleMethod(method, arguments, this, invocationSite);
+ if (method == null) return null; // incompatible
+ if (!method.isValidBinding()) return method; // bound check issue is taking precedence
+ parameters = method.parameters; // reacquire them after type inference has performed
+ } else if (genericTypeArguments != null) {
+ if (method instanceof ParameterizedGenericMethodBinding) {
+ if (!((ParameterizedGenericMethodBinding) method).wasInferred) {
+ // attempt to invoke generic method of raw type with type hints <String>foo()
+ return new ProblemMethodBinding(method, method.selector, genericTypeArguments, TypeArgumentsForRawGenericMethod);
+ }
+ } else {
+ return new ProblemMethodBinding(method, method.selector, genericTypeArguments, TypeParameterArityMismatch);
+ }
+ }
+
+ if (parameterCompatibilityLevel(method, arguments) > NOT_COMPATIBLE)
+ return method;
+ if (genericTypeArguments != null)
+ return new ProblemMethodBinding(method, method.selector, arguments, ParameterizedMethodTypeMismatch);
+ return null; // incompatible
+ }
+
+ protected boolean connectTypeVariables(TypeParameter[] typeParameters) {
+ boolean noProblems = true;
+ if (typeParameters == null || environment().options.sourceLevel < ClassFileConstants.JDK1_5) return true;
+
+ nextVariable : for (int i = 0, paramLength = typeParameters.length; i < paramLength; i++) {
+ TypeParameter typeParameter = typeParameters[i];
+ TypeVariableBinding typeVariable = typeParameter.binding;
+ if (typeVariable == null) return false;
+
+ typeVariable.superclass = getJavaLangObject();
+ typeVariable.superInterfaces = NoSuperInterfaces;
+ // set firstBound to the binding of the first explicit bound in parameter declaration
+ typeVariable.firstBound = null; // first bound used to compute erasure
+
+ TypeReference typeRef = typeParameter.type;
+ if (typeRef == null)
+ continue nextVariable;
+ ReferenceBinding superType = this.kind == METHOD_SCOPE
+ ? (ReferenceBinding) typeRef.resolveType((BlockScope)this, false/*no bound check*/)
+ : (ReferenceBinding) typeRef.resolveType((ClassScope)this);
+ if (superType == null) {
+ typeVariable.tagBits |= HierarchyHasProblems;
+ noProblems = false;
+ continue nextVariable;
+ }
+ if (superType.isTypeVariable()) {
+ TypeVariableBinding varSuperType = (TypeVariableBinding) superType;
+ if (varSuperType.rank >= typeVariable.rank && varSuperType.declaringElement == typeVariable.declaringElement) {
+ problemReporter().forwardTypeVariableReference(typeParameter, varSuperType);
+ typeVariable.tagBits |= HierarchyHasProblems;
+ noProblems = false;
+ continue nextVariable;
+ }
+ }
+ if (superType.isFinal())
+ problemReporter().finalVariableBound(typeVariable, typeRef);
+ typeRef.resolvedType = superType; // hold onto the problem type
+ if (superType.isClass()) {
+ typeVariable.superclass = superType;
+ } else {
+ typeVariable.superInterfaces = new ReferenceBinding[] {superType};
+ typeVariable.modifiers |= AccInterface;
+ }
+ typeVariable.firstBound = superType; // first bound used to compute erasure
+
+ TypeReference[] boundRefs = typeParameter.bounds;
+ if (boundRefs != null) {
+ for (int j = 0, k = boundRefs.length; j < k; j++) {
+ typeRef = boundRefs[j];
+ superType = this.kind == METHOD_SCOPE
+ ? (ReferenceBinding) typeRef.resolveType((BlockScope)this, false)
+ : (ReferenceBinding) typeRef.resolveType((ClassScope)this);
+ if (superType == null) {
+ typeVariable.tagBits |= HierarchyHasProblems;
+ noProblems = false;
+ continue nextVariable;
+ }
+ typeRef.resolvedType = superType; // hold onto the problem type
+ if (superType.isClass()) {
+ problemReporter().boundsMustBeAnInterface(typeRef, superType);
+ typeVariable.tagBits |= HierarchyHasProblems;
+ noProblems = false;
+ continue nextVariable;
+ }
+ if (superType.isParameterizedType()) {
+ ReferenceBinding match = typeVariable.superclass.findSuperTypeErasingTo((ReferenceBinding) superType.erasure());
+ boolean isCollision = match != null && match != superType;
+ for (int index = typeVariable.superInterfaces.length; !isCollision && --index >= 0;) {
+ ReferenceBinding temp = typeVariable.superInterfaces[index];
+ isCollision = superType != temp && superType.erasure() == temp.erasure();
+ }
+ if (isCollision) {
+ problemReporter().boundHasConflictingArguments(typeRef, superType);
+ typeVariable.tagBits |= HierarchyHasProblems;
+ noProblems = false;
+ continue nextVariable;
+ }
+ }
+ int size = typeVariable.superInterfaces.length;
+ System.arraycopy(typeVariable.superInterfaces, 0, typeVariable.superInterfaces = new ReferenceBinding[size + 1], 0, size);
+ typeVariable.superInterfaces[size] = superType;
+ }
+ }
+ }
+ return noProblems;
+ }
+
+ public TypeBinding convertToRawType(TypeBinding type) {
+ int dimension = type.dimensions();
+ TypeBinding originalType = type.leafComponentType();
+ if (originalType instanceof ReferenceBinding) {
+ ReferenceBinding convertedType = (ReferenceBinding) originalType;
+ ReferenceBinding originalEnclosing = originalType.enclosingType();
+ ReferenceBinding convertedEnclosing = originalEnclosing;
+ if (originalEnclosing != null && convertedType.isStatic() && originalEnclosing.isGenericType()) {
+ convertedEnclosing = (ReferenceBinding) convertToRawType(originalEnclosing);
+ }
+ if (originalType.isGenericType()) {
+ convertedType = environment().createRawType(convertedType, convertedEnclosing);
+ } else if (originalEnclosing != convertedEnclosing) {
+ convertedType = createParameterizedType(convertedType, null, convertedEnclosing);
+ }
+ if (originalType != convertedType) {
+ return dimension > 0 ? (TypeBinding)createArrayType(convertedType, dimension) : convertedType;
+ }
+ }
+ return type;
+ }
+// TypeBinding leafType = type.leafComponentType();
+// int dimension = type.dimensions();
+// ReferenceBinding originalEnclosing = leafType.enclosingType();
+// ReferenceBinding convertedEnclosing = originalEnclosing;
+// if (originalEnclosing != null && ((ReferenceBinding)leafType).isStatic()) {
+// convertedEnclosing = (ReferenceBinding) convertToRawType(originalEnclosing);
+// }
+// if (leafType.isGenericType()) {
+// type = environment().createRawType((ReferenceBinding) leafType, convertedEnclosing);
+// if (dimension > 0)
+// type = createArrayType(type, dimension);
+// } else if (originalEnclosing != convertedEnclosing) {
+// type = createParameterizedType((ReferenceBinding)leafType, null, convertedEnclosing);
+// if (dimension > 0)
+// type = createArrayType(type, dimension);
+// }
+// return type;
+
+ public ArrayBinding createArrayType(TypeBinding type, int dimension) {
+ if (type.isValidBinding())
+ return environment().createArrayType(type, dimension);
+ // do not cache obvious invalid types
+ return new ArrayBinding(type, dimension, environment());
+ }
+
+ public ParameterizedTypeBinding createParameterizedType(ReferenceBinding genericType, TypeBinding[] arguments, ReferenceBinding enclosingType) {
+ valid: {
+ if (!genericType.isValidBinding()) break valid;
+ for (int i = 0, max = arguments == null ? 0 : arguments.length; i < max; i++)
+ if (!arguments[i].isValidBinding()) break valid;
+ return environment().createParameterizedType(genericType, arguments, enclosingType);
+ }
+ return new ParameterizedTypeBinding(genericType, arguments, enclosingType, environment());
+ }
+
+ public TypeVariableBinding[] createTypeVariables(TypeParameter[] typeParameters, Binding declaringElement) {
+
+ PackageBinding unitPackage = compilationUnitScope().fPackage;
+
+ // do not construct type variables if source < 1.5
+ if (typeParameters == null || environment().options.sourceLevel < ClassFileConstants.JDK1_5)
+ return NoTypeVariables;
+ TypeVariableBinding[] typeVariableBindings = NoTypeVariables;
+
+ int length = typeParameters.length;
+ typeVariableBindings = new TypeVariableBinding[length];
+ HashtableOfObject knownTypeParameterNames = new HashtableOfObject(length);
+ int count = 0;
+ nextParameter : for (int i = 0; i < length; i++) {
+ TypeParameter typeParameter = typeParameters[i];
+ TypeVariableBinding parameterBinding = new TypeVariableBinding(typeParameter.name, declaringElement, i);
+ parameterBinding.fPackage = unitPackage;
+ typeParameter.binding = parameterBinding;
+
+ if (knownTypeParameterNames.containsKey(typeParameter.name)) {
+ TypeVariableBinding previousBinding = (TypeVariableBinding) knownTypeParameterNames.get(typeParameter.name);
+ if (previousBinding != null) {
+ for (int j = 0; j < i; j++) {
+ TypeParameter previousParameter = typeParameters[j];
+ if (previousParameter.binding == previousBinding) {
+ problemReporter().duplicateTypeParameterInType(previousParameter);
+ previousParameter.binding = null;
+ break;
+ }
+ }
+ }
+ knownTypeParameterNames.put(typeParameter.name, null); // ensure that the duplicate parameter is found & removed
+ problemReporter().duplicateTypeParameterInType(typeParameter);
+ typeParameter.binding = null;
+ } else {
+ knownTypeParameterNames.put(typeParameter.name, parameterBinding);
+ // remember that we have seen a field with this name
+ if (parameterBinding != null)
+ typeVariableBindings[count++] = parameterBinding;
+ }
+// TODO should offer warnings to inform about hiding declaring, enclosing or member types
+// ReferenceBinding type = sourceType;
+// // check that the member does not conflict with an enclosing type
+// do {
+// if (CharOperation.equals(type.sourceName, memberContext.name)) {
+// problemReporter().hidingEnclosingType(memberContext);
+// continue nextParameter;
+// }
+// type = type.enclosingType();
+// } while (type != null);
+// // check that the member type does not conflict with another sibling member type
+// for (int j = 0; j < i; j++) {
+// if (CharOperation.equals(referenceContext.memberTypes[j].name, memberContext.name)) {
+// problemReporter().duplicateNestedType(memberContext);
+// continue nextParameter;
+// }
+// }
+ }
+ if (count != length) {
+ System.arraycopy(typeVariableBindings, 0, typeVariableBindings = new TypeVariableBinding[count], 0, count);
+ }
+ return typeVariableBindings;
}
public final ClassScope enclosingClassScope() {
Scope scope = this;
while ((scope = scope.parent) != null) {
- if (scope instanceof ClassScope) return (ClassScope)scope;
+ if (scope instanceof ClassScope) return (ClassScope) scope;
}
return null; // may answer null if no type around
}
public final MethodScope enclosingMethodScope() {
Scope scope = this;
while ((scope = scope.parent) != null) {
- if (scope instanceof MethodScope) return (MethodScope)scope;
+ if (scope instanceof MethodScope) return (MethodScope) scope;
}
return null; // may answer null if no method around
}
return ((CompilationUnitScope) unitScope).environment;
}
- protected void faultInReceiverType(TypeBinding type) {
- if (type.isArrayType())
- type = ((ArrayBinding) type).leafComponentType;
-
- // check on Begin bit, so as to be resilient with potential illformed binaries containing cycles (67769)
- if (type instanceof BinaryTypeBinding && (type.tagBits & BeginHierarchyCheck) == 0) {
- type.tagBits |= BeginHierarchyCheck;
- // fault in the hierarchy of the type now so we can detect missing types instead of in storeDependencyInfo
- BinaryTypeBinding binaryType = (BinaryTypeBinding) type;
- ReferenceBinding enclosingType = binaryType.enclosingType();
- if (enclosingType != null)
- faultInReceiverType(enclosingType);
- ReferenceBinding superclass = binaryType.superclass();
- if (superclass != null)
- faultInReceiverType(superclass);
- ReferenceBinding[] interfaces = binaryType.superInterfaces();
- for (int i = 0, l = interfaces.length; i < l; i++)
- faultInReceiverType(interfaces[i]);
- type.tagBits |= EndHierarchyCheck;
- }
- }
-
// abstract method lookup lookup (since maybe missing default abstract methods)
public MethodBinding findDefaultAbstractMethod(
ReferenceBinding receiverType,
matchingMethod = findMethodInSuperInterfaces(currentType, selector, found, matchingMethod);
currentType = currentType.superclass();
}
+ CompilationUnitScope unitScope = compilationUnitScope();
int foundSize = found.size;
if (foundSize == startFoundSize) {
- if (matchingMethod != null) compilationUnitScope().recordTypeReferences(matchingMethod.thrownExceptions);
+ if (matchingMethod != null)
+ unitScope.recordTypeReferences(matchingMethod.thrownExceptions);
return matchingMethod; // maybe null
}
MethodBinding[] candidates = new MethodBinding[foundSize - startFoundSize];
int candidatesCount = 0;
+ MethodBinding problemMethod = null;
// argument type compatibility check
for (int i = startFoundSize; i < foundSize; i++) {
MethodBinding methodBinding = (MethodBinding) found.elementAt(i);
- if (areParametersAssignable(methodBinding.parameters, argumentTypes))
- candidates[candidatesCount++] = methodBinding;
+ MethodBinding compatibleMethod = computeCompatibleMethod(methodBinding, argumentTypes, invocationSite);
+ if (compatibleMethod != null) {
+ if (compatibleMethod.isValidBinding())
+ candidates[candidatesCount++] = compatibleMethod;
+ else if (problemMethod == null)
+ problemMethod = compatibleMethod;
+ }
}
+
if (candidatesCount == 1) {
- compilationUnitScope().recordTypeReferences(candidates[0].thrownExceptions);
+ unitScope.recordTypeReferences(candidates[0].thrownExceptions);
return candidates[0];
}
if (candidatesCount == 0) { // try to find a close match when the parameter order is wrong or missing some parameters
+ if (problemMethod != null) return problemMethod;
int argLength = argumentTypes.length;
nextMethod : for (int i = 0; i < foundSize; i++) {
MethodBinding methodBinding = (MethodBinding) found.elementAt(i);
return (MethodBinding) found.elementAt(0); // no good match so just use the first one found
}
// no need to check for visibility - interface methods are public
- return mostSpecificInterfaceMethodBinding(candidates, candidatesCount);
+ boolean isCompliant14 = unitScope.environment.options.complianceLevel >= ClassFileConstants.JDK1_4;
+ if (isCompliant14)
+ return mostSpecificMethodBinding(candidates, candidatesCount, argumentTypes, invocationSite);
+ return mostSpecificInterfaceMethodBinding(candidates, candidatesCount, invocationSite);
}
// Internal use only
return null; // know it has no member types (nor inherited member types)
SourceTypeBinding enclosingSourceType = enclosingSourceType();
- compilationUnitScope().recordReference(enclosingType.compoundName, typeName);
+ CompilationUnitScope unitScope = compilationUnitScope();
+ unitScope.recordReference(enclosingType, typeName);
ReferenceBinding memberType = enclosingType.getMemberType(typeName);
if (memberType != null) {
- compilationUnitScope().recordTypeReference(memberType); // to record supertypes
+ unitScope.recordTypeReference(memberType);
if (enclosingSourceType == null
- ? memberType.canBeSeenBy(getCurrentPackage())
- : memberType.canBeSeenBy(enclosingType, enclosingSourceType))
- return memberType;
+ ? memberType.canBeSeenBy(getCurrentPackage())
+ : memberType.canBeSeenBy(enclosingType, enclosingSourceType))
+ return memberType;
return new ProblemReferenceBinding(typeName, memberType, NotVisible);
}
return null;
TypeBinding[] argumentTypes,
InvocationSite invocationSite) {
- faultInReceiverType(receiverType);
- compilationUnitScope().recordTypeReference(receiverType);
- compilationUnitScope().recordTypeReferences(argumentTypes);
- MethodBinding exactMethod = receiverType.getExactMethod(selector, argumentTypes);
+ CompilationUnitScope unitScope = compilationUnitScope();
+ unitScope.recordTypeReferences(argumentTypes);
+ MethodBinding exactMethod = receiverType.getExactMethod(selector, argumentTypes, unitScope);
if (exactMethod != null) {
- compilationUnitScope().recordTypeReferences(exactMethod.thrownExceptions);
- if (receiverType.isInterface() || exactMethod.canBeSeenBy(receiverType, invocationSite, this))
+ unitScope.recordTypeReferences(exactMethod.thrownExceptions);
+ // special treatment for Object.getClass() in 1.5 mode (substitute parameterized return type)
+ if (receiverType.isInterface() || exactMethod.canBeSeenBy(receiverType, invocationSite, this)) {
+ if (receiverType.id != T_JavaLangObject
+ && argumentTypes == NoParameters
+ && CharOperation.equals(selector, GETCLASS)
+ && exactMethod.returnType.isParameterizedType()/*1.5*/) {
+ return ParameterizedMethodBinding.instantiateGetClass(receiverType, exactMethod, this);
+ }
+ // targeting a generic method could find an exact match with variable return type
+ if (exactMethod.typeVariables != NoTypeVariables || invocationSite.genericTypeArguments() != null)
+ exactMethod = computeCompatibleMethod(exactMethod, argumentTypes, invocationSite);
return exactMethod;
+ }
}
return null;
}
*/
public FieldBinding findField(TypeBinding receiverType, char[] fieldName, InvocationSite invocationSite, boolean needResolve) {
if (receiverType.isBaseType()) return null;
+
+ CompilationUnitScope unitScope = compilationUnitScope();
+ unitScope.recordTypeReference(receiverType);
if (receiverType.isArrayType()) {
TypeBinding leafType = receiverType.leafComponentType();
- if (leafType instanceof ReferenceBinding) {
+ if (leafType instanceof ReferenceBinding)
if (!((ReferenceBinding) leafType).canBeSeenBy(this))
return new ProblemFieldBinding((ReferenceBinding)leafType, fieldName, ReceiverTypeNotVisible);
- }
if (CharOperation.equals(fieldName, LENGTH))
return ArrayBinding.ArrayLength;
return null;
}
- faultInReceiverType(receiverType);
- compilationUnitScope().recordTypeReference(receiverType);
-
ReferenceBinding currentType = (ReferenceBinding) receiverType;
if (!currentType.canBeSeenBy(this))
return new ProblemFieldBinding(currentType, fieldName, ReceiverTypeNotVisible);
FieldBinding field = currentType.getField(fieldName, true /*resolve*/);
if (field != null) {
- if (field.canBeSeenBy(currentType, invocationSite, this))
- return field;
+ if (invocationSite == null
+ ? field.canBeSeenBy(getCurrentPackage())
+ : field.canBeSeenBy(currentType, invocationSite, this))
+ return field;
return new ProblemFieldBinding(field /* closest match*/, field.declaringClass, fieldName, NotVisible);
}
// collect all superinterfaces of receiverType until the field is found in a supertype
// we could hold onto the not visible field for extra error reporting
while (keepLooking) {
ReferenceBinding[] itsInterfaces = currentType.superInterfaces();
+ if (itsInterfaces == null) { // needed for statically imported types which don't know their hierarchy yet
+ ((SourceTypeBinding) currentType).scope.connectTypeHierarchy();
+ 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);
+ System.arraycopy(interfacesToVisit, 0, interfacesToVisit = new ReferenceBinding[lastPosition * 2][], 0, lastPosition);
interfacesToVisit[lastPosition] = itsInterfaces;
}
if ((currentType = currentType.superclass()) == null)
break;
+ unitScope.recordTypeReference(currentType);
if ((field = currentType.getField(fieldName, needResolve)) != null) {
keepLooking = false;
if (field.canBeSeenBy(receiverType, invocationSite, this)) {
if ((anInterface.tagBits & InterfaceVisited) == 0) {
// if interface as not already been visited
anInterface.tagBits |= InterfaceVisited;
+ unitScope.recordTypeReference(anInterface);
if ((field = anInterface.getField(fieldName, true /*resolve*/)) != null) {
if (visibleField == null) {
visibleField = field;
ReferenceBinding[] itsInterfaces = anInterface.superInterfaces();
if (itsInterfaces != NoSuperInterfaces) {
if (++lastPosition == interfacesToVisit.length)
- System.arraycopy(
- interfacesToVisit,
- 0,
- interfacesToVisit = new ReferenceBinding[lastPosition * 2][],
- 0,
- lastPosition);
+ System.arraycopy(interfacesToVisit, 0, interfacesToVisit = new ReferenceBinding[lastPosition * 2][], 0, lastPosition);
interfacesToVisit[lastPosition] = itsInterfaces;
}
}
SourceTypeBinding enclosingSourceType = enclosingSourceType();
PackageBinding currentPackage = getCurrentPackage();
- compilationUnitScope().recordReference(enclosingType.compoundName, typeName);
+ CompilationUnitScope unitScope = compilationUnitScope();
+ unitScope.recordReference(enclosingType, typeName);
ReferenceBinding memberType = enclosingType.getMemberType(typeName);
if (memberType != null) {
- compilationUnitScope().recordTypeReference(memberType); // to record supertypes
+ unitScope.recordTypeReference(memberType);
if (enclosingSourceType == null
- ? memberType.canBeSeenBy(currentPackage)
- : memberType.canBeSeenBy(enclosingType, enclosingSourceType))
- return memberType;
+ ? memberType.canBeSeenBy(currentPackage)
+ : memberType.canBeSeenBy(enclosingType, enclosingSourceType))
+ return memberType;
return new ProblemReferenceBinding(typeName, memberType, NotVisible);
}
// we could hold onto the not visible field for extra error reporting
while (keepLooking) {
ReferenceBinding[] itsInterfaces = currentType.superInterfaces();
+ if (itsInterfaces == null) { // needed for statically imported types which don't know their hierarchy yet
+ ((SourceTypeBinding) currentType).scope.connectTypeHierarchy();
+ 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);
+ System.arraycopy(interfacesToVisit, 0, interfacesToVisit = new ReferenceBinding[lastPosition * 2][], 0, lastPosition);
interfacesToVisit[lastPosition] = itsInterfaces;
}
if ((currentType = currentType.superclass()) == null)
break;
- compilationUnitScope().recordReference(currentType.compoundName, typeName);
+ unitScope.recordReference(currentType, typeName);
if ((memberType = currentType.getMemberType(typeName)) != null) {
- compilationUnitScope().recordTypeReference(memberType); // to record supertypes
+ unitScope.recordTypeReference(memberType);
keepLooking = false;
if (enclosingSourceType == null
? memberType.canBeSeenBy(currentPackage)
if ((anInterface.tagBits & InterfaceVisited) == 0) {
// if interface as not already been visited
anInterface.tagBits |= InterfaceVisited;
- compilationUnitScope().recordReference(anInterface.compoundName, typeName);
+ unitScope.recordReference(anInterface, typeName);
if ((memberType = anInterface.getMemberType(typeName)) != null) {
- compilationUnitScope().recordTypeReference(memberType); // to record supertypes
+ unitScope.recordTypeReference(memberType);
if (visibleMemberType == null) {
visibleMemberType = memberType;
} else {
ReferenceBinding[] itsInterfaces = anInterface.superInterfaces();
if (itsInterfaces != NoSuperInterfaces) {
if (++lastPosition == interfacesToVisit.length)
- System.arraycopy(
- interfacesToVisit,
- 0,
- interfacesToVisit = new ReferenceBinding[lastPosition * 2][],
- 0,
- lastPosition);
+ System.arraycopy(interfacesToVisit, 0, interfacesToVisit = new ReferenceBinding[lastPosition * 2][], 0, lastPosition);
interfacesToVisit[lastPosition] = itsInterfaces;
}
}
ReferenceBinding currentType = receiverType;
MethodBinding matchingMethod = null;
- ObjectVector found = new ObjectVector(); //TODO should rewrite to remove #matchingMethod since found is allocated anyway
+ ObjectVector found = new ObjectVector(); //TODO (kent) should rewrite to remove #matchingMethod since found is allocated anyway
- faultInReceiverType(receiverType);
- compilationUnitScope().recordTypeReference(receiverType);
- compilationUnitScope().recordTypeReferences(argumentTypes);
+ CompilationUnitScope unitScope = compilationUnitScope();
+ unitScope.recordTypeReferences(argumentTypes);
if (currentType.isInterface()) {
+ unitScope.recordTypeReference(currentType);
MethodBinding[] currentMethods = currentType.getMethods(selector);
int currentLength = currentMethods.length;
if (currentLength == 1) {
currentType = getJavaLangObject();
}
- boolean isCompliant14 = compilationUnitScope().environment.options.complianceLevel >= ClassFileConstants.JDK1_4;
+ boolean isCompliant14 = unitScope.environment.options.complianceLevel >= ClassFileConstants.JDK1_4;
// superclass lookup
ReferenceBinding classHierarchyStart = currentType;
while (currentType != null) {
+ unitScope.recordTypeReference(currentType);
MethodBinding[] currentMethods = currentType.getMethods(selector);
int currentLength = currentMethods.length;
-
- /*
- * if 1.4 compliant, must filter out redundant protected methods from superclasses
- */
- if (isCompliant14){
- nextMethod: for (int i = 0; i < currentLength; i++){
+
+ if (isCompliant14 && matchingMethod != null || found.size > 0) {
+ nextMethod: for (int i = 0; i < currentLength; i++) {
MethodBinding currentMethod = currentMethods[i];
+ // if 1.4 compliant, must filter out redundant protected methods from superclasses
// protected method need to be checked only - default access is already dealt with in #canBeSeen implementation
// when checking that p.C -> q.B -> p.A cannot see default access members from A through B.
- if ((currentMethod.modifiers & AccProtected) == 0) continue nextMethod;
- if (matchingMethod != null){
- if (currentMethod.areParametersEqual(matchingMethod)){
+ // if ((currentMethod.modifiers & AccProtected) == 0) continue nextMethod;
+ // BUT we can also ignore any overridden method since we already know the better match (fixes 80028)
+ if (matchingMethod != null) {
+ if (currentMethod.areParametersEqual(matchingMethod)) {
currentLength--;
currentMethods[i] = null; // discard this match
continue nextMethod;
}
} else {
for (int j = 0, max = found.size; j < max; j++) {
- if (((MethodBinding)found.elementAt(j)).areParametersEqual(currentMethod)){
+ if (((MethodBinding) found.elementAt(j)).areParametersEqual(currentMethod)) {
currentLength--;
currentMethods[i] = null;
continue nextMethod;
}
}
}
-
+
if (currentLength == 1 && matchingMethod == null && found.size == 0) {
matchingMethod = currentMethods[0];
} else if (currentLength > 0) {
MethodBinding[] candidates = null;
int candidatesCount = 0;
boolean checkedMatchingMethod = false; // is matchingMethod meeting argument expectation ?
+ MethodBinding problemMethod = null;
if (foundSize > 0) {
// argument type compatibility check
for (int i = 0; i < foundSize; i++) {
MethodBinding methodBinding = (MethodBinding) found.elementAt(i);
- if (areParametersAssignable(methodBinding.parameters, argumentTypes)) {
- switch (candidatesCount) {
- case 0:
- matchingMethod = methodBinding; // if only one match, reuse matchingMethod
- checkedMatchingMethod = true; // matchingMethod is known to exist and match params here
- break;
- case 1:
- candidates = new MethodBinding[foundSize]; // only lazily created if more than one match
- candidates[0] = matchingMethod; // copy back
- matchingMethod = null;
- // fall through
- default:
- candidates[candidatesCount] = methodBinding;
+ MethodBinding compatibleMethod = computeCompatibleMethod(methodBinding, argumentTypes, invocationSite);
+ if (compatibleMethod != null) {
+ if (compatibleMethod.isValidBinding()) {
+ switch (candidatesCount) {
+ case 0:
+ matchingMethod = compatibleMethod; // if only one match, reuse matchingMethod
+ checkedMatchingMethod = true; // matchingMethod is known to exist and match params here
+ break;
+ case 1:
+ candidates = new MethodBinding[foundSize]; // only lazily created if more than one match
+ candidates[0] = matchingMethod; // copy back
+ matchingMethod = null;
+ // fall through
+ default:
+ candidates[candidatesCount] = compatibleMethod;
+ }
+ candidatesCount++;
+ } else if (problemMethod == null) {
+ problemMethod = compatibleMethod;
}
- candidatesCount++;
}
}
}
+ if (candidatesCount > 0)
+ problemMethod = null; // forget the problem method if candidates were found
+
// if only one matching method left (either from start or due to elimination of rivals), then match is in matchingMethod
if (matchingMethod != null) {
- if (checkedMatchingMethod || areParametersAssignable(matchingMethod.parameters, argumentTypes)) {
+ if (!checkedMatchingMethod) {
+ MethodBinding compatibleMethod = computeCompatibleMethod(matchingMethod, argumentTypes, invocationSite);
+ if (compatibleMethod != null) {
+ if (compatibleMethod.isValidBinding()) {
+ matchingMethod = compatibleMethod;
+ checkedMatchingMethod = true;
+ } else {
+ problemMethod = compatibleMethod;
+ }
+ }
+ }
+ if (checkedMatchingMethod) {
// (if no default abstract) must explicitly look for one instead, which could be a better match
if (!matchingMethod.canBeSeenBy(receiverType, invocationSite, this)) {
// ignore matching method (to be consistent with multiple matches, none visible (matching method is then null)
- MethodBinding interfaceMethod = findDefaultAbstractMethod(receiverType, selector, argumentTypes, invocationSite, classHierarchyStart, null, found);
+ MethodBinding interfaceMethod =
+ findDefaultAbstractMethod(receiverType, selector, argumentTypes, invocationSite, classHierarchyStart, null, found);
if (interfaceMethod != null) return interfaceMethod;
- compilationUnitScope().recordTypeReferences(matchingMethod.thrownExceptions);
+ unitScope.recordTypeReferences(matchingMethod.thrownExceptions);
return matchingMethod;
}
}
- return findDefaultAbstractMethod(receiverType, selector, argumentTypes, invocationSite, classHierarchyStart, matchingMethod, found);
+ matchingMethod =
+ findDefaultAbstractMethod(receiverType, selector, argumentTypes, invocationSite, classHierarchyStart, matchingMethod, found);
+ if (matchingMethod != null) return matchingMethod;
+ return problemMethod;
}
// no match was found, try to find a close match when the parameter order is wrong or missing some parameters
MethodBinding interfaceMethod =
findDefaultAbstractMethod(receiverType, selector, argumentTypes, invocationSite, classHierarchyStart, matchingMethod, found);
if (interfaceMethod != null) return interfaceMethod;
+ if (problemMethod != null) return problemMethod;
int argLength = argumentTypes.length;
foundSize = found.size;
}
return methodBinding;
}
+ if (found.size == 0) return null;
return (MethodBinding) found.elementAt(0); // no good match so just use the first one found
}
+ // check for duplicate parameterized methods
+ if (unitScope.environment.options.sourceLevel >= ClassFileConstants.JDK1_5) {
+ for (int i = 0; i < candidatesCount; i++) {
+ MethodBinding current = candidates[i];
+ if (current instanceof ParameterizedGenericMethodBinding)
+ current = ((ParameterizedGenericMethodBinding) current).originalMethod;
+ if (current instanceof ParameterizedMethodBinding)
+ for (int j = i + 1; j < candidatesCount; j++)
+ if (current.declaringClass == candidates[j].declaringClass && current.areParametersEqual(candidates[j]))
+ return new ProblemMethodBinding(candidates[i].selector, candidates[i].parameters, Ambiguous);
+ }
+ }
+
// tiebreak using visibility check
int visiblesCount = 0;
for (int i = 0; i < candidatesCount; i++) {
}
}
if (visiblesCount == 1) {
- compilationUnitScope().recordTypeReferences(candidates[0].thrownExceptions);
+ unitScope.recordTypeReferences(candidates[0].thrownExceptions);
return candidates[0];
}
if (visiblesCount == 0) {
return new ProblemMethodBinding(candidates[0], candidates[0].selector, candidates[0].parameters, NotVisible);
}
if (isCompliant14)
- return mostSpecificMethodBinding(candidates, visiblesCount);
+ return mostSpecificMethodBinding(candidates, visiblesCount, argumentTypes, invocationSite);
return candidates[0].declaringClass.isClass()
- ? mostSpecificClassMethodBinding(candidates, visiblesCount)
- : mostSpecificInterfaceMethodBinding(candidates, visiblesCount);
+ ? mostSpecificClassMethodBinding(candidates, visiblesCount, invocationSite)
+ : mostSpecificInterfaceMethodBinding(candidates, visiblesCount, invocationSite);
}
// Internal use only
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 UpdatedMethodBinding(
- environment().options.targetJDK >= ClassFileConstants.JDK1_4 ? (TypeBinding)receiverType : (TypeBinding)object, // remember its array type for codegen purpose on target>=1.4.0
- (methodBinding.modifiers ^ AccProtected) | AccPublic,
- CLONE,
- methodBinding.returnType,
- argumentTypes,
- null,
- object);
+ if (argumentTypes == NoParameters) {
+ switch (selector[0]) {
+ case 'c':
+ if (CharOperation.equals(selector, CLONE)) {
+ return new UpdatedMethodBinding(
+ environment().options.targetJDK >= ClassFileConstants.JDK1_4 ? (TypeBinding)receiverType : (TypeBinding)object, // remember its array type for codegen purpose on target>=1.4.0
+ (methodBinding.modifiers & ~AccProtected) | AccPublic,
+ CLONE,
+ methodBinding.returnType,
+ argumentTypes,
+ null,
+ object);
+ }
+ break;
+ case 'g':
+ if (CharOperation.equals(selector, GETCLASS) && methodBinding.returnType.isParameterizedType()/*1.5*/) {
+ return ParameterizedMethodBinding.instantiateGetClass(receiverType, methodBinding, this);
+ }
+ break;
+ }
+ }
if (methodBinding.canBeSeenBy(receiverType, invocationSite, this))
return methodBinding;
}
if (methodBinding == null)
return new ProblemMethodBinding(selector, argumentTypes, NotFound);
if (methodBinding.isValidBinding()) {
- if (!areParametersAssignable(methodBinding.parameters, argumentTypes))
- return new ProblemMethodBinding(
- methodBinding,
- selector,
- argumentTypes,
- NotFound);
+ MethodBinding compatibleMethod = computeCompatibleMethod(methodBinding, argumentTypes, invocationSite);
+ if (compatibleMethod == null)
+ return new ProblemMethodBinding(methodBinding, selector, argumentTypes, NotFound);
+ if (!compatibleMethod.isValidBinding())
+ return compatibleMethod;
+
+ methodBinding = compatibleMethod;
if (!methodBinding.canBeSeenBy(receiverType, invocationSite, this))
- return new ProblemMethodBinding(
- methodBinding,
- selector,
- methodBinding.parameters,
- NotVisible);
+ return new ProblemMethodBinding(methodBinding, selector, methodBinding.parameters, NotVisible);
}
return methodBinding;
}
// if interface as not already been visited
currentType.tagBits |= InterfaceVisited;
+ compilationUnitScope().recordTypeReference(currentType);
MethodBinding[] currentMethods = currentType.getMethods(selector);
int currentLength = currentMethods.length;
if (currentLength == 1 && matchingMethod == null && found.size == 0) {
return null;
}
- public TypeBinding getBaseType(char[] name) {
+ public static TypeBinding getBaseType(char[] name) {
// list should be optimized (with most often used first)
int length = name.length;
if (length > 2 && length < 8) {
}
/* API
- *
+ *
* Answer the binding that corresponds to the argument name.
* flag is a mask of the following values VARIABLE (= FIELD or LOCAL), TYPE, PACKAGE.
* Only bindings corresponding to the mask can be answered.
try {
Binding binding = null;
FieldBinding problemField = null;
- if ((mask & VARIABLE) != 0) {
+ if ((mask & Binding.VARIABLE) != 0) {
boolean insideStaticContext = false;
boolean insideConstructorCall = false;
-
+
FieldBinding foundField = null;
// can be a problem field which is answered if a valid field is not found
ProblemFieldBinding foundInsideProblem = null;
case CLASS_SCOPE :
ClassScope classScope = (ClassScope) scope;
SourceTypeBinding enclosingType = classScope.referenceContext.binding;
- FieldBinding fieldBinding =
- classScope.findField(enclosingType, name, invocationSite, needResolve);
+ FieldBinding fieldBinding = classScope.findField(enclosingType, name, invocationSite, needResolve);
// Use next line instead if willing to enable protected access accross inner types
// FieldBinding fieldBinding = findField(enclosingType, name, invocationSite);
+
+// SourceTypeBinding initialType = this.enclosingSourceType();
+// if ((fieldBinding == null || !fieldBinding.isValidBinding()) && enclosingType.hasMemberTypes()) { // check member enums
+// ReferenceBinding[] memberTypes = enclosingType.memberTypes();
+// for (int i = 0, length = memberTypes.length; i < length; i++) {
+// ReferenceBinding memberType = memberTypes[i];
+// if (memberType != initialType && memberType.isEnum()) { // do not find one's field through its enclosing members
+// FieldBinding enumField = ((SourceTypeBinding)memberType).scope.findField(memberType, name, invocationSite, needResolve);
+// if (enumField != null && (enumField.modifiers & AccEnum) != 0) {
+// // grant access to enum constants of enclosing members
+// // TODO (kent) need to revisit to see whether should walk sibling enums and issue an ambiguous match
+// return enumField;
+// }
+// }
+// }
+// }
if (fieldBinding != null) { // skip it if we did not find anything
if (fieldBinding.problemId() == Ambiguous) {
if (foundField == null || foundField.problemId() == NotVisible)
name,
InheritedNameHidesEnclosingName);
}
-
+
ProblemFieldBinding insideProblem = null;
if (fieldBinding.isValidBinding()) {
if (!fieldBinding.isStatic()) {
NonStaticReferenceInStaticContext);
}
}
- if (enclosingType == fieldBinding.declaringClass
- || environment().options.complianceLevel >= ClassFileConstants.JDK1_4){
+ if (enclosingType == fieldBinding.declaringClass || environment().options.complianceLevel >= ClassFileConstants.JDK1_4) {
// found a valid field in the 'immediate' scope (ie. not inherited)
// OR in 1.4 mode (inherited shadows enclosing)
if (foundField == null) {
InheritedNameHidesEnclosingName);
}
}
-
- if (foundField == null
- || (foundField.problemId() == NotVisible
- && fieldBinding.problemId() != NotVisible)) {
+
+ if (foundField == null || (foundField.problemId() == NotVisible && fieldBinding.problemId() != NotVisible)) {
// only remember the fieldBinding if its the first one found or the previous one was not visible & fieldBinding is...
foundDepth = depth;
foundActualReceiverType = enclosingType;
}
scope = scope.parent;
}
-
+
if (foundInsideProblem != null)
return foundInsideProblem;
if (foundField != null) {
- if (foundField.isValidBinding()){
- if (foundDepth > 0){
+ if (foundField.isValidBinding()) {
+ if (foundDepth > 0) {
invocationSite.setDepth(foundDepth);
invocationSite.setActualReceiverType(foundActualReceiverType);
}
}
problemField = foundField;
}
+
+ if (environment().options.complianceLevel >= ClassFileConstants.JDK1_5) {
+ // at this point the scope is a compilation unit scope & need to check for imported static fields
+ CompilationUnitScope unitScope = (CompilationUnitScope) scope;
+ ImportBinding[] imports = unitScope.imports;
+ if (imports != null) {
+ // check single static imports
+ for (int i = 0, length = imports.length; i < length; i++) {
+ ImportBinding importBinding = imports[i];
+ if (importBinding.isStatic() && !importBinding.onDemand) {
+ if (CharOperation.equals(importBinding.compoundName[importBinding.compoundName.length - 1], name)) {
+ if (unitScope.resolveSingleImport(importBinding) != null && importBinding.resolvedImport instanceof FieldBinding) {
+ ImportReference importReference = importBinding.reference;
+ if (importReference != null) importReference.used = true;
+ return importBinding.resolvedImport; // already know its visible
+ }
+ }
+ }
+ }
+ // check on demand imports
+ boolean foundInImport = false;
+ for (int i = 0, length = imports.length; i < length; i++) {
+ ImportBinding importBinding = imports[i];
+ if (importBinding.isStatic() && importBinding.onDemand) {
+ Binding resolvedImport = importBinding.resolvedImport;
+ if (resolvedImport instanceof ReferenceBinding) {
+ FieldBinding temp = findField((ReferenceBinding) resolvedImport, name, invocationSite, needResolve);
+ if (temp != null) {
+ if (!temp.isValidBinding()) {
+ problemField = temp;
+ } else if (temp.isStatic()) {
+ ImportReference importReference = importBinding.reference;
+ if (importReference != null) importReference.used = true;
+ if (foundInImport)
+ // Answer error binding -- import on demand conflict; name found in two import on demand packages.
+ return new ProblemReferenceBinding(name, Ambiguous);
+ foundField = temp;
+ foundInImport = true;
+ }
+ }
+ }
+ }
+ }
+ if (foundField != null) return foundField;
+ }
+ }
}
-
+
// We did not find a local or instance variable.
- if ((mask & TYPE) != 0) {
+ if ((mask & Binding.TYPE) != 0) {
if ((binding = getBaseType(name)) != null)
return binding;
- binding = getTypeOrPackage(name, (mask & PACKAGE) == 0 ? TYPE : TYPE | PACKAGE);
- if (binding.isValidBinding() || mask == TYPE)
+ binding = getTypeOrPackage(name, (mask & Binding.PACKAGE) == 0 ? Binding.TYPE : Binding.TYPE | Binding.PACKAGE);
+ if (binding.isValidBinding() || mask == Binding.TYPE)
return binding;
// answer the problem type binding if we are only looking for a type
- } else if ((mask & PACKAGE) != 0) {
+ } else if ((mask & Binding.PACKAGE) != 0) {
compilationUnitScope().recordSimpleReference(name);
if ((binding = environment().getTopLevelPackage(name)) != null)
return binding;
}
if (problemField != null) return problemField;
return new ProblemBinding(name, enclosingSourceType(), NotFound);
-
} catch (AbortCompilation e) {
e.updateContext(invocationSite, referenceCompilationUnit().compilationResult);
throw e;
public MethodBinding getConstructor(ReferenceBinding receiverType, TypeBinding[] argumentTypes, InvocationSite invocationSite) {
try {
- faultInReceiverType(receiverType);
- compilationUnitScope().recordTypeReference(receiverType);
- compilationUnitScope().recordTypeReferences(argumentTypes);
+ CompilationUnitScope unitScope = compilationUnitScope();
+ unitScope.recordTypeReference(receiverType);
+ unitScope.recordTypeReferences(argumentTypes);
MethodBinding methodBinding = receiverType.getExactConstructor(argumentTypes);
- if (methodBinding != null && methodBinding.canBeSeenBy(invocationSite, this))
+ if (methodBinding != null && methodBinding.canBeSeenBy(invocationSite, this)) {
+ // targeting a non generic constructor with type arguments ?
+ if (invocationSite.genericTypeArguments() != null)
+ methodBinding = computeCompatibleMethod(methodBinding, argumentTypes, invocationSite);
return methodBinding;
- MethodBinding[] methods = receiverType.getMethods(ConstructorDeclaration.ConstantPoolName);
+ }
+ MethodBinding[] methods = receiverType.getMethods(TypeConstants.INIT);
if (methods == NoMethods)
return new ProblemMethodBinding(
- ConstructorDeclaration.ConstantPoolName,
+ TypeConstants.INIT,
argumentTypes,
NotFound);
-
+
MethodBinding[] compatible = new MethodBinding[methods.length];
int compatibleIndex = 0;
- for (int i = 0, length = methods.length; i < length; i++)
- if (areParametersAssignable(methods[i].parameters, argumentTypes))
- compatible[compatibleIndex++] = methods[i];
- if (compatibleIndex == 0)
- return new ProblemMethodBinding(
- ConstructorDeclaration.ConstantPoolName,
- argumentTypes,
- NotFound);
+ MethodBinding problemMethod = null;
+ for (int i = 0, length = methods.length; i < length; i++) {
+ MethodBinding compatibleMethod = computeCompatibleMethod(methods[i], argumentTypes, invocationSite);
+ if (compatibleMethod != null) {
+ if (compatibleMethod.isValidBinding())
+ compatible[compatibleIndex++] = compatibleMethod;
+ else if (problemMethod == null)
+ problemMethod = compatibleMethod;
+ }
+ }
+ if (compatibleIndex == 0) {
+ if (problemMethod == null)
+ return new ProblemMethodBinding(TypeConstants.INIT, argumentTypes, NotFound);
+ return problemMethod;
+ }
// need a more descriptive error... cannot convert from X to Y
MethodBinding[] visible = new MethodBinding[compatibleIndex];
if (visibleIndex == 0)
return new ProblemMethodBinding(
compatible[0],
- ConstructorDeclaration.ConstantPoolName,
+ TypeConstants.INIT,
compatible[0].parameters,
NotVisible);
- return mostSpecificClassMethodBinding(visible, visibleIndex);
+ // all of visible are from the same declaringClass, even before 1.4 we can call this method instead of mostSpecificClassMethodBinding
+ return mostSpecificMethodBinding(visible, visibleIndex, argumentTypes, invocationSite);
} catch (AbortCompilation e) {
e.updateContext(invocationSite, referenceCompilationUnit().compilationResult);
throw e;
if (!methodScope.isInsideInitializer()){
// check method modifiers to see if deprecated
MethodBinding context = ((AbstractMethodDeclaration)methodScope.referenceContext).binding;
- if (context != null) {
+ if (context != null)
return context.modifiers;
- }
} else {
- SourceTypeBinding type = ((BlockScope)this).referenceType().binding;
+ SourceTypeBinding type = ((BlockScope) this).referenceType().binding;
// inside field declaration ? check field modifier to see if deprecated
- if (methodScope.initializedField != null) {
+ if (methodScope.initializedField != null)
return methodScope.initializedField.modifiers;
- }
- if (type != null) {
+ if (type != null)
return type.modifiers;
- }
}
break;
case Scope.CLASS_SCOPE :
ReferenceBinding context = ((ClassScope)this).referenceType().binding;
- if (context != null) {
+ if (context != null)
return context.modifiers;
- }
break;
}
return -1;
} catch (AbortCompilation e) {
e.updateContext(invocationSite, referenceCompilationUnit().compilationResult);
throw e;
- }
+ }
}
/* API
*
* If no visible method is discovered, an error binding is answered.
*/
- public MethodBinding getImplicitMethod(
- char[] selector,
- TypeBinding[] argumentTypes,
- InvocationSite invocationSite) {
+ public MethodBinding getImplicitMethod(char[] selector, TypeBinding[] argumentTypes, InvocationSite invocationSite) {
boolean insideStaticContext = false;
boolean insideConstructorCall = false;
MethodBinding foundMethod = null;
- ProblemMethodBinding foundFuzzyProblem = null;
+ MethodBinding foundFuzzyProblem = null;
// the weird method lookup case (matches method name in scope, then arg types, then visibility)
- ProblemMethodBinding foundInsideProblem = null;
+ MethodBinding foundInsideProblem = null;
// inside Constructor call or inside static context
Scope scope = this;
int depth = 0;
SourceTypeBinding receiverType = classScope.referenceContext.binding;
boolean isExactMatch = true;
// retrieve an exact visible match (if possible)
+ // compilationUnitScope().recordTypeReference(receiverType); not needed since receiver is the source type
MethodBinding methodBinding =
(foundMethod == null)
- ? classScope.findExactMethod(
- receiverType,
- selector,
- argumentTypes,
- invocationSite)
- : classScope.findExactMethod(
- receiverType,
- foundMethod.selector,
- foundMethod.parameters,
- invocationSite);
- // ? findExactMethod(receiverType, selector, argumentTypes, invocationSite)
- // : findExactMethod(receiverType, foundMethod.selector, foundMethod.parameters, invocationSite);
+ ? classScope.findExactMethod(receiverType, selector, argumentTypes, invocationSite)
+ : classScope.findExactMethod(receiverType, foundMethod.selector, foundMethod.parameters, invocationSite);
if (methodBinding == null) {
// answers closest approximation, may not check argumentTypes or visibility
isExactMatch = false;
- methodBinding =
- classScope.findMethod(receiverType, selector, argumentTypes, invocationSite);
- // methodBinding = findMethod(receiverType, selector, argumentTypes, invocationSite);
+ methodBinding = classScope.findMethod(receiverType, selector, argumentTypes, invocationSite);
+ // methodBinding = findMethod(receiverType, selector, argumentTypes, invocationSite);
}
if (methodBinding != null) { // skip it if we did not find anything
if (methodBinding.problemId() == Ambiguous) {
argumentTypes,
InheritedNameHidesEnclosingName);
}
- ProblemMethodBinding fuzzyProblem = null;
- ProblemMethodBinding insideProblem = null;
+ MethodBinding fuzzyProblem = null;
+ MethodBinding insideProblem = null;
if (methodBinding.isValidBinding()) {
if (!isExactMatch) {
- if (!areParametersAssignable(methodBinding.parameters, argumentTypes)) {
- if (foundMethod == null || foundMethod.problemId() == NotVisible){
+ MethodBinding compatibleMethod = computeCompatibleMethod(methodBinding, argumentTypes, invocationSite);
+ if (compatibleMethod == null) {
+ if (foundMethod == null || foundMethod.problemId() == NotVisible)
// inherited mismatch is reported directly, not looking at enclosing matches
return new ProblemMethodBinding(methodBinding, selector, argumentTypes, NotFound);
- }
// make the user qualify the method, likely wants the first inherited method (javac generates an ambiguous error instead)
- fuzzyProblem = new ProblemMethodBinding(selector, methodBinding.parameters, InheritedNameHidesEnclosingName);
-
- } else if (!methodBinding.canBeSeenBy(receiverType, invocationSite, classScope)) {
- // using <classScope> instead of <this> for visibility check does grant all access to innerclass
- fuzzyProblem =
- new ProblemMethodBinding(
- methodBinding,
- selector,
- methodBinding.parameters,
- NotVisible);
+ fuzzyProblem = new ProblemMethodBinding(methodBinding, selector, methodBinding.parameters, InheritedNameHidesEnclosingName);
+ } else if (!compatibleMethod.isValidBinding()) {
+ fuzzyProblem = compatibleMethod;
+ } else {
+ methodBinding = compatibleMethod;
+ if (!methodBinding.canBeSeenBy(receiverType, invocationSite, classScope)) {
+ // using <classScope> instead of <this> for visibility check does grant all access to innerclass
+ fuzzyProblem = new ProblemMethodBinding(methodBinding, selector, methodBinding.parameters, NotVisible);
+ }
}
}
if (fuzzyProblem == null && !methodBinding.isStatic()) {
NonStaticReferenceInStaticContext);
}
}
-
+
if (receiverType == methodBinding.declaringClass
|| (receiverType.getMethods(selector)) != NoMethods
- || ((fuzzyProblem == null || fuzzyProblem.problemId() != NotVisible) && environment().options.complianceLevel >= ClassFileConstants.JDK1_4)){
+ || ((fuzzyProblem == null || fuzzyProblem.problemId() != NotVisible) && environment().options.complianceLevel >= ClassFileConstants.JDK1_4)) {
// found a valid method in the 'immediate' scope (ie. not inherited)
// OR the receiverType implemented a method with the correct name
// OR in 1.4 mode (inherited visible shadows enclosing)
}
}
- if (foundMethod == null
- || (foundMethod.problemId() == NotVisible
- && methodBinding.problemId() != NotVisible)) {
+ if (foundMethod == null || (foundMethod.problemId() == NotVisible && methodBinding.problemId() != NotVisible)) {
// only remember the methodBinding if its the first one found or the previous one was not visible & methodBinding is...
// remember that private methods are visible if defined directly by an enclosing class
- if (depth > 0){
+ if (depth > 0) {
invocationSite.setDepth(depth);
invocationSite.setActualReceiverType(receiverType);
}
return foundInsideProblem;
if (foundMethod != null)
return foundMethod;
+
+ if (insideStaticContext && environment().options.complianceLevel >= ClassFileConstants.JDK1_5) {
+ // at this point the scope is a compilation unit scope & need to check for imported static methods
+ CompilationUnitScope unitScope = (CompilationUnitScope) scope;
+ ImportBinding[] imports = unitScope.imports;
+ if (imports != null) {
+ // check on demand imports
+ boolean foundInImport = false;
+ for (int i = 0, length = imports.length; i < length; i++) {
+ ImportBinding importBinding = imports[i];
+ if (importBinding.isStatic() && importBinding.onDemand) {
+ Binding resolvedImport = importBinding.resolvedImport;
+ if (resolvedImport instanceof ReferenceBinding) {
+ // answers closest approximation, may not check argumentTypes or visibility
+ MethodBinding temp = findMethod((ReferenceBinding) resolvedImport, selector, argumentTypes, invocationSite);
+ if (temp != null) {
+ if (!temp.isValidBinding()) {
+ if (foundMethod == null)
+ foundMethod = temp;
+ } else if (temp.isStatic()) {
+ MethodBinding compatibleMethod = computeCompatibleMethod(temp, argumentTypes, invocationSite);
+ if (compatibleMethod != null) {
+ if (compatibleMethod.isValidBinding()) {
+ if (compatibleMethod.canBeSeenBy(unitScope.fPackage)) {
+ ImportReference importReference = importBinding.reference;
+ if (importReference != null) importReference.used = true;
+ if (foundInImport)
+ // Answer error binding -- import on demand conflict; name found in two import on demand types.
+ return new ProblemMethodBinding(compatibleMethod, selector, compatibleMethod.parameters, Ambiguous);
+ foundMethod = compatibleMethod;
+ foundInImport = true;
+ } else if (foundMethod == null) {
+ foundMethod = new ProblemMethodBinding(compatibleMethod, selector, compatibleMethod.parameters, NotVisible);
+ }
+ }
+ } else if (foundMethod == null) {
+ foundMethod = new ProblemMethodBinding(temp, selector, argumentTypes, NotFound);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ if (foundMethod != null)
+ return foundMethod;
+ }
return new ProblemMethodBinding(selector, argumentTypes, NotFound);
}
problemReporter().isClassPathCorrect(JAVA_IO_SERIALIZABLE, referenceCompilationUnit());
return null; // will not get here since the above error aborts the compilation
}
-
+
+ public final ReferenceBinding getJavaLangAnnotationAnnotation() {
+ compilationUnitScope().recordQualifiedReference(JAVA_LANG_ANNOTATION_ANNOTATION);
+ ReferenceBinding type = environment().getType(JAVA_LANG_ANNOTATION_ANNOTATION);
+ if (type != null) return type;
+
+ problemReporter().isClassPathCorrect(JAVA_LANG_ANNOTATION_ANNOTATION, referenceCompilationUnit());
+ return null; // will not get here since the above error aborts the compilation
+ }
+
public final ReferenceBinding getJavaLangAssertionError() {
compilationUnitScope().recordQualifiedReference(JAVA_LANG_ASSERTIONERROR);
ReferenceBinding type = environment().getType(JAVA_LANG_ASSERTIONERROR);
problemReporter().isClassPathCorrect(JAVA_LANG_CLONEABLE, referenceCompilationUnit());
return null; // will not get here since the above error aborts the compilation
}
-
+ public final ReferenceBinding getJavaLangEnum() {
+ compilationUnitScope().recordQualifiedReference(JAVA_LANG_ENUM);
+ ReferenceBinding type = environment().getType(JAVA_LANG_ENUM);
+ if (type != null) return type;
+
+ problemReporter().isClassPathCorrect(JAVA_LANG_ENUM, referenceCompilationUnit());
+ return null; // will not get here since the above error aborts the compilation
+ }
public final ReferenceBinding getJavaLangError() {
compilationUnitScope().recordQualifiedReference(JAVA_LANG_ERROR);
ReferenceBinding type = environment().getType(JAVA_LANG_ERROR);
problemReporter().isClassPathCorrect(JAVA_LANG_ERROR, referenceCompilationUnit());
return null; // will not get here since the above error aborts the compilation
}
-
+ public final ReferenceBinding getJavaLangIterable() {
+ compilationUnitScope().recordQualifiedReference(JAVA_LANG_ITERABLE);
+ ReferenceBinding type = environment().getType(JAVA_LANG_ITERABLE);
+ if (type != null) return type;
+
+ problemReporter().isClassPathCorrect(JAVA_LANG_ITERABLE, referenceCompilationUnit());
+ return null; // will not get here since the above error aborts the compilation
+ }
public final ReferenceBinding getJavaLangObject() {
compilationUnitScope().recordQualifiedReference(JAVA_LANG_OBJECT);
ReferenceBinding type = environment().getType(JAVA_LANG_OBJECT);
problemReporter().isClassPathCorrect(JAVA_LANG_THROWABLE, referenceCompilationUnit());
return null; // will not get here since the above error aborts the compilation
}
+ public final ReferenceBinding getJavaUtilIterator() {
+ compilationUnitScope().recordQualifiedReference(JAVA_UTIL_ITERATOR);
+ ReferenceBinding type = environment().getType(JAVA_UTIL_ITERATOR);
+ if (type != null) return type;
+
+ problemReporter().isClassPathCorrect(JAVA_UTIL_ITERATOR, 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 MethodBinding getMethod(TypeBinding receiverType, char[] selector, TypeBinding[] argumentTypes, InvocationSite invocationSite) {
try {
- if (receiverType.isArrayType())
- return findMethodForArray((ArrayBinding) receiverType, selector, argumentTypes, invocationSite);
if (receiverType.isBaseType())
return new ProblemMethodBinding(selector, argumentTypes, NotFound);
-
+
+ compilationUnitScope().recordTypeReference(receiverType);
+ if (receiverType.isArrayType())
+ return findMethodForArray((ArrayBinding) receiverType, selector, argumentTypes, invocationSite);
+
ReferenceBinding currentType = (ReferenceBinding) receiverType;
if (!currentType.canBeSeenBy(this))
return new ProblemMethodBinding(selector, argumentTypes, ReceiverTypeNotVisible);
MethodBinding methodBinding = findExactMethod(currentType, selector, argumentTypes, invocationSite);
if (methodBinding != null) return methodBinding;
+ // TODO (kent) performance - we are accumulating super methods which are *hidden* during the walk (see testcase from bug 69141)
// answers closest approximation, may not check argumentTypes or visibility
methodBinding = findMethod(currentType, 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);
+ MethodBinding compatibleMethod = computeCompatibleMethod(methodBinding, argumentTypes, invocationSite);
+ if (compatibleMethod == null)
+ return new ProblemMethodBinding(methodBinding, selector, argumentTypes, NotFound);
+ if (!compatibleMethod.isValidBinding())
+ return compatibleMethod;
+
+ methodBinding = compatibleMethod;
if (!methodBinding.canBeSeenBy(currentType, invocationSite, this))
- return new ProblemMethodBinding(
- methodBinding,
- selector,
- methodBinding.parameters,
- NotVisible);
+ return new ProblemMethodBinding( methodBinding, selector, methodBinding.parameters, NotVisible);
}
return methodBinding;
-
} catch (AbortCompilation e) {
e.updateContext(invocationSite, referenceCompilationUnit().compilationResult);
throw e;
}
}
+ /* Answer the package from the compoundName or null if it begins with a type.
+ * Intended to be used while resolving a qualified type name.
+ *
+ * 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 Binding getPackage(char[][] compoundName) {
+ compilationUnitScope().recordQualifiedReference(compoundName);
+ Binding binding = getTypeOrPackage(compoundName[0], Binding.TYPE | Binding.PACKAGE);
+ if (binding == null)
+ return new ProblemReferenceBinding(compoundName[0], NotFound);
+ if (!binding.isValidBinding())
+ return (ReferenceBinding) binding;
+
+ if (!(binding instanceof PackageBinding)) return null; // compoundName does not start with a package
+
+ int currentIndex = 1;
+ PackageBinding packageBinding = (PackageBinding) binding;
+ while (currentIndex < compoundName.length) {
+ 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))
+ return packageBinding;
+ packageBinding = (PackageBinding) binding;
+ }
+ return new ProblemReferenceBinding(compoundName, NotFound);
+ }
+
/* 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", ...)
*/
// 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);
+ return (ReferenceBinding) getTypeOrPackage(name, Binding.TYPE);
+ }
+
+ /* Answer the type binding that corresponds to the given name, starting the lookup in the receiver
+ * or the packageBinding if provided.
+ * The name provided is a simple source name (e.g., "Object" , "Point", ...)
+ */
+ public final TypeBinding getType(char[] name, PackageBinding packageBinding) {
+ if (packageBinding == null)
+ return getType(name);
+
+ Binding binding = packageBinding.getTypeOrPackage(name);
+ if (binding == null)
+ return new ProblemReferenceBinding(
+ CharOperation.arrayConcat(packageBinding.compoundName, name),
+ NotFound);
+ if (!binding.isValidBinding())
+ return new ProblemReferenceBinding(
+ CharOperation.arrayConcat(packageBinding.compoundName, name),
+ binding.problemId());
+
+ ReferenceBinding typeBinding = (ReferenceBinding) binding;
+ if (!typeBinding.canBeSeenBy(this))
+ return new ProblemReferenceBinding(
+ CharOperation.arrayConcat(packageBinding.compoundName, name),
+ typeBinding,
+ NotVisible);
+ return typeBinding;
}
/* 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;
+ public final TypeBinding getType(char[][] compoundName, int typeNameLength) {
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;
}
- compilationUnitScope().recordQualifiedReference(compoundName);
+ CompilationUnitScope unitScope = compilationUnitScope();
+ unitScope.recordQualifiedReference(compoundName);
Binding binding =
- getTypeOrPackage(compoundName[0], typeNameLength == 1 ? TYPE : TYPE | PACKAGE);
+ getTypeOrPackage(compoundName[0], typeNameLength == 1 ? Binding.TYPE : Binding.TYPE | Binding.PACKAGE);
if (binding == null)
return new ProblemReferenceBinding(compoundName[0], NotFound);
if (!binding.isValidBinding())
// binding is now a ReferenceBinding
ReferenceBinding typeBinding = (ReferenceBinding) binding;
- compilationUnitScope().recordTypeReference(typeBinding); // to record supertypes
+ unitScope.recordTypeReference(typeBinding);
if (checkVisibility) // handles the fall through case
if (!typeBinding.canBeSeenBy(this))
return new ProblemReferenceBinding(
final Binding getTypeOrPackage(char[] name, int mask) {
Scope scope = this;
ReferenceBinding foundType = null;
- if ((mask & TYPE) == 0) {
+ boolean insideStaticContext = false;
+ if ((mask & Binding.TYPE) == 0) {
Scope next = scope;
while ((next = scope.parent) != null)
scope = next;
done : while (true) { // done when a COMPILATION_UNIT_SCOPE is found
switch (scope.kind) {
case METHOD_SCOPE :
+ MethodScope methodScope = (MethodScope) scope;
+ AbstractMethodDeclaration methodDecl = methodScope.referenceMethod();
+ if (methodDecl != null && methodDecl.binding != null) {
+ TypeVariableBinding typeVariable = methodDecl.binding.getTypeVariable(name);
+ if (typeVariable != null) return typeVariable;
+ }
+ insideStaticContext |= methodScope.isStatic;
case BLOCK_SCOPE :
ReferenceBinding localType = ((BlockScope) scope).findLocalType(name); // looks in this scope only
if (localType != null) {
break;
case CLASS_SCOPE :
SourceTypeBinding sourceType = ((ClassScope) scope).referenceContext.binding;
- // 6.5.5.1 - simple name favors member type over top-level type in same unit
+ if (sourceType.isHierarchyBeingConnected()) {
+ // type variables take precedence over the source type, ex. class X <X> extends X == class X <Y> extends Y
+ TypeVariableBinding typeVariable = sourceType.getTypeVariable(name);
+ if (typeVariable != null)
+ return typeVariable;
+ if (CharOperation.equals(name, sourceType.sourceName))
+ return sourceType;
+ break;
+ }
+ // type variables take precedence over member types
+ TypeVariableBinding typeVariable = sourceType.getTypeVariable(name);
+ if (typeVariable != null) {
+ if (insideStaticContext) // do not consider this type modifiers: access is legite within same type
+ return new ProblemReferenceBinding(name, NonStaticReferenceInStaticContext);
+ return typeVariable;
+ }
+ insideStaticContext |= (sourceType.modifiers & AccStatic) != 0; // not isStatic()
+ // 6.5.5.1 - member types have precedence over top-level type in same unit
ReferenceBinding memberType = findMemberType(name, sourceType);
if (memberType != null) { // skip it if we did not find anything
if (memberType.problemId() == Ambiguous) {
// OR in 1.4 mode (inherited shadows enclosing)
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 a valid type was found, complain when another is found in an 'immediate' enclosing type (ie. not inherited)
+ if (foundType.isValidBinding() && foundType != memberType)
+ return new ProblemReferenceBinding(name, InheritedNameHidesEnclosingName);
}
}
if (foundType == null || (foundType.problemId() == NotVisible && memberType.problemId() != NotVisible))
CompilationUnitScope unitScope = (CompilationUnitScope) scope;
PackageBinding currentPackage = unitScope.fPackage;
// ask for the imports + name
- if ((mask & TYPE) != 0) {
+ if ((mask & Binding.TYPE) != 0) {
// check single type imports.
ImportBinding[] imports = unitScope.imports;
ImportBinding typeImport = imports[i];
if (!typeImport.onDemand) {
if (CharOperation.equals(typeImport.compoundName[typeImport.compoundName.length - 1], name)) {
- if (unitScope.resolveSingleTypeImport(typeImport) != null) {
+ if (unitScope.resolveSingleImport(typeImport) != null) {
ImportReference importReference = typeImport.reference;
- if (importReference != null) importReference.used = true;
+ if (importReference != null)
+ importReference.used = true;
return typeImport.resolvedImport; // already know its visible
}
}
Binding resolvedImport = someImport.resolvedImport;
ReferenceBinding temp = resolvedImport instanceof PackageBinding
? findType(name, (PackageBinding) resolvedImport, currentPackage)
- : findDirectMemberType(name, (ReferenceBinding) resolvedImport);
+ : (someImport.isStatic()
+ ? findMemberType(name, (ReferenceBinding) resolvedImport) // static imports are allowed to see inherited member types
+ : findDirectMemberType(name, (ReferenceBinding) resolvedImport));
if (temp != null) {
if (temp.isValidBinding()) {
ImportReference importReference = someImport.reference;
}
unitScope.recordSimpleReference(name);
- if ((mask & PACKAGE) != 0) {
+ if ((mask & Binding.PACKAGE) != 0) {
PackageBinding packageBinding = unitScope.environment.getTopLevelPackage(name);
if (packageBinding != null) return packageBinding;
}
}
// Added for code assist... NOT Public API
+ // DO NOT USE to resolve import references since this method assumes 'A.B' is relative to a single type import of 'p1.A'
+ // when it may actually mean the type B in the package A
+ // use CompilationUnitScope.getImport(char[][]) instead
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);
+ Binding binding = getTypeOrPackage(compoundName[0], Binding.TYPE | Binding.PACKAGE);
if (!binding.isValidBinding()) return binding;
int currentIndex = 1;
checkVisibility = true;
}
// binding is now a ReferenceBinding
+ ReferenceBinding qualifiedType = null;
+
ReferenceBinding typeBinding = (ReferenceBinding) binding;
+ if (typeBinding.isGenericType()) {
+ qualifiedType = this.environment().createRawType(typeBinding, qualifiedType);
+ } else {
+ qualifiedType = (qualifiedType != null && (qualifiedType.isRawType() || qualifiedType.isParameterizedType()))
+ ? this.createParameterizedType(typeBinding, null, qualifiedType)
+ : typeBinding;
+ }
+
if (checkVisibility) // handles the fall through case
if (!typeBinding.canBeSeenBy(this))
return new ProblemReferenceBinding(
while (currentIndex < nameLength) {
typeBinding = getMemberType(compoundName[currentIndex++], typeBinding);
+
+ if (typeBinding.isGenericType()) {
+ qualifiedType = this.environment().createRawType(typeBinding, qualifiedType);
+ } else {
+ qualifiedType = (qualifiedType != null && (qualifiedType.isRawType() || qualifiedType.isParameterizedType()))
+ ? this.createParameterizedType(typeBinding, null, qualifiedType)
+ : typeBinding;
+ }
+
// checks visibility
- if (!typeBinding.isValidBinding())
+ if (!qualifiedType.isValidBinding())
return new ProblemReferenceBinding(
CharOperation.subarray(compoundName, 0, currentIndex),
- typeBinding.problemId());
+ qualifiedType.problemId());
}
- return typeBinding;
+ return qualifiedType;
+ }
+
+ // 5.1.10
+ public TypeBinding[] greaterLowerBound(TypeBinding[] types) {
+ if (types == null) return null;
+ int length = types.length;
+ TypeBinding[] result = types;
+ int removed = 0;
+ for (int i = 0; i < length; i++) {
+ TypeBinding iType = result[i];
+ for (int j = 0; j < length; j++) {
+ if (i == j) continue;
+ TypeBinding jType = result[j];
+ if (jType == null) continue;
+ if (iType.isCompatibleWith(jType)) { // if Vi <: Vj, Vj is removed
+ if (result == types) { // defensive copy
+ System.arraycopy(result, 0, result = new TypeBinding[length], 0, length);
+ }
+ result[j] = null;
+ removed ++;
+ }
+ }
+ }
+ if (removed == 0) return result;
+ TypeBinding[] trimmedResult = new TypeBinding[length - removed];
+ for (int i = 0, index = 0; i < length; i++) {
+ TypeBinding iType = result[i];
+ if (iType != null) {
+ trimmedResult[index++] = iType;
+ }
+ }
+ return trimmedResult;
+ }
+
+ public boolean isBoxingCompatibleWith(TypeBinding left, TypeBinding right) {
+ return left.isBaseType() != right.isBaseType() && environment().isBoxingCompatibleWith(left, right);
}
/* Answer true if the scope is nested inside a given field declaration.
- * Note: it works as long as the scope.fieldDeclarationIndex is reflecting the field being traversed
- * e.g. during name resolution.
+ * Note: it works as long as the scope.fieldDeclarationIndex is reflecting the field being traversed
+ * e.g. during name resolution.
*/
public final boolean isDefinedInField(FieldBinding field) {
Scope scope = this;
do {
if (scope instanceof MethodScope) {
ReferenceContext refContext = ((MethodScope) scope).referenceContext;
- if (refContext instanceof AbstractMethodDeclaration
- && ((AbstractMethodDeclaration)refContext).binding == method) {
- return true;
- }
+ if (refContext instanceof AbstractMethodDeclaration)
+ if (((AbstractMethodDeclaration) refContext).binding == method)
+ return true;
}
scope = scope.parent;
} while (scope != null);
unitScope = scope;
// test that the enclosingType is not part of the compilation unit
- SourceTypeBinding[] topLevelTypes =
- ((CompilationUnitScope) unitScope).topLevelTypes;
+ SourceTypeBinding[] topLevelTypes = ((CompilationUnitScope) unitScope).topLevelTypes;
for (int i = topLevelTypes.length; --i >= 0;)
if (topLevelTypes[i] == enclosingType)
return true;
Scope scope = this;
do {
if (scope instanceof ClassScope)
- if (((ClassScope) scope).referenceContext.binding == type){
+ if (((ClassScope) scope).referenceContext.binding == type)
return true;
- }
scope = scope.parent;
} while (scope != null);
return false;
if (!methodScope.isInsideInitializer()){
// check method modifiers to see if deprecated
MethodBinding context = ((AbstractMethodDeclaration)methodScope.referenceContext).binding;
- if (context != null && context.isViewedAsDeprecated()) {
+ if (context != null && context.isViewedAsDeprecated())
return true;
- }
} else {
SourceTypeBinding type = ((BlockScope)this).referenceType().binding;
// inside field declaration ? check field modifier to see if deprecated
- if (methodScope.initializedField != null && methodScope.initializedField.isViewedAsDeprecated()) {
+ if (methodScope.initializedField != null && methodScope.initializedField.isViewedAsDeprecated())
return true;
- }
- if (type != null && type.isViewedAsDeprecated()) {
+ if (type != null && type.isViewedAsDeprecated())
return true;
- }
}
break;
case Scope.CLASS_SCOPE :
ReferenceBinding context = ((ClassScope)this).referenceType().binding;
- if (context != null && context.isViewedAsDeprecated()) {
+ if (context != null && context.isViewedAsDeprecated())
return true;
- }
break;
}
return false;
}
+ private TypeBinding leastContainingInvocation(TypeBinding mec, List invocations) {
+ int length = invocations.size();
+ if (length == 0) return mec;
+ if (length == 1) return (TypeBinding) invocations.get(0);
+ int argLength = mec.typeVariables().length;
+ if (argLength == 0) return mec; // should be caught by no invocation check
+
+ // infer proper parameterized type from invocations
+ TypeBinding[] bestArguments = new TypeBinding[argLength];
+ for (int i = 0; i < length; i++) {
+ TypeBinding invocation = (TypeBinding)invocations.get(i);
+ TypeVariableBinding[] invocationVariables = invocation.typeVariables();
+ if (invocation.isGenericType()) {
+ for (int j = 0; j < argLength; j++) {
+ TypeBinding bestArgument = leastContainingTypeArgument(bestArguments[j], invocationVariables[j], (ReferenceBinding) mec, j);
+ if (bestArgument == null) return null;
+ bestArguments[j] = bestArgument;
+ }
+ } else if (invocation.isParameterizedType()) {
+ ParameterizedTypeBinding parameterizedType = (ParameterizedTypeBinding)invocation;
+ for (int j = 0; j < argLength; j++) {
+ TypeBinding bestArgument = leastContainingTypeArgument(bestArguments[j], parameterizedType.arguments[j], (ReferenceBinding) mec, j);
+ if (bestArgument == null) return null;
+ bestArguments[j] = bestArgument;
+ }
+ } else if (invocation.isRawType()) {
+ return invocation; // raw type is taking precedence
+ }
+ }
+ return createParameterizedType((ReferenceBinding) mec.erasure(), bestArguments, null);
+ }
+
+ // JLS 15.12.2
+ private TypeBinding leastContainingTypeArgument(TypeBinding u, TypeBinding v, ReferenceBinding genericType, int rank) {
+ if (u == null) return v;
+ if (u == v) return u;
+ if (v.isWildcard()) {
+ WildcardBinding wildV = (WildcardBinding) v;
+ if (u.isWildcard()) {
+ WildcardBinding wildU = (WildcardBinding) u;
+ switch (wildU.kind) {
+ // ? extends U
+ case Wildcard.EXTENDS :
+ switch(wildV.kind) {
+ // ? extends U, ? extends V
+ case Wildcard.EXTENDS :
+ TypeBinding lub = lowerUpperBound(new TypeBinding[]{wildU.bound,wildV.bound});
+ if (lub == null) return null;
+ return environment().createWildcard(genericType, rank, lub, Wildcard.EXTENDS);
+ // ? extends U, ? SUPER V
+ case Wildcard.SUPER :
+ if (wildU.bound == wildV.bound) return wildU.bound;
+ return environment().createWildcard(genericType, rank, null, Wildcard.UNBOUND);
+ }
+ break;
+ // ? super U
+ case Wildcard.SUPER :
+ // ? super U, ? super V
+ if (wildU.kind == Wildcard.SUPER) {
+ TypeBinding[] glb = greaterLowerBound(new TypeBinding[]{wildU.bound,wildV.bound});
+ if (glb == null) return null;
+ return environment().createWildcard(genericType, rank, glb[0], Wildcard.SUPER); // TODO (philippe) need to capture entire bounds
+ }
+ }
+ } else {
+ switch (wildV.kind) {
+ // U, ? extends V
+ case Wildcard.EXTENDS :
+ TypeBinding lub = lowerUpperBound(new TypeBinding[]{u,wildV.bound});
+ if (lub == null) return null;
+ return environment().createWildcard(genericType, rank, lub, Wildcard.EXTENDS);
+ // U, ? super V
+ case Wildcard.SUPER :
+ TypeBinding[] glb = greaterLowerBound(new TypeBinding[]{u,wildV.bound});
+ if (glb == null) return null;
+ return environment().createWildcard(genericType, rank, glb[0], Wildcard.SUPER); // TODO (philippe) need to capture entire bounds
+ case Wildcard.UNBOUND :
+ }
+ }
+ } else if (u.isWildcard()) {
+ WildcardBinding wildU = (WildcardBinding) u;
+ switch (wildU.kind) {
+ // U, ? extends V
+ case Wildcard.EXTENDS :
+ TypeBinding lub = lowerUpperBound(new TypeBinding[]{wildU.bound, v});
+ if (lub == null) return null;
+ return environment().createWildcard(genericType, rank, lub, Wildcard.EXTENDS);
+ // U, ? super V
+ case Wildcard.SUPER :
+ TypeBinding[] glb = greaterLowerBound(new TypeBinding[]{wildU.bound, v});
+ if (glb == null) return null;
+ return environment().createWildcard(genericType, rank, glb[0], Wildcard.SUPER); // TODO (philippe) need to capture entire bounds
+ case Wildcard.UNBOUND :
+ }
+ }
+ TypeBinding lub = lowerUpperBound(new TypeBinding[]{u,v});
+ if (lub == null) return null;
+ return environment().createWildcard(genericType, rank, lub, Wildcard.EXTENDS);
+ }
+
+ // 15.12.2
+ public TypeBinding lowerUpperBound(TypeBinding[] types) {
+
+ if (types.length == 1) {
+ TypeBinding type = types[0];
+ return type == null ? VoidBinding : type;
+ }
+ ArrayList invocations = new ArrayList(1);
+ TypeBinding mec = minimalErasedCandidate(types, invocations);
+ return leastContainingInvocation(mec, invocations);
+ }
public final MethodScope methodScope() {
Scope scope = this;
return null;
}
+ /**
+ * Returns the most specific type compatible with all given types.
+ * (i.e. most specific common super type)
+ * If no types is given, will return VoidBinding. If not compatible
+ * reference type is found, returns null.
+ */
+ private TypeBinding minimalErasedCandidate(TypeBinding[] types, List invocations) {
+ Map allInvocations = new HashMap(2);
+ int length = types.length;
+ int indexOfFirst = -1, actualLength = 0;
+ for (int i = 0; i < length; i++) {
+ TypeBinding type = types[i];
+ if (type == null) continue;
+ if (type.isBaseType()) return null;
+ if (indexOfFirst < 0) indexOfFirst = i;
+ actualLength ++;
+ }
+ switch (actualLength) {
+ case 0: return VoidBinding;
+ case 1: return types[indexOfFirst];
+ }
+
+ // record all supertypes of type
+ // intersect with all supertypes of otherType
+ TypeBinding firstType = types[indexOfFirst];
+ TypeBinding[] superTypes;
+ int superLength;
+ if (firstType.isBaseType()) {
+ return null;
+ } else if (firstType.isArrayType()) {
+ superLength = 4;
+ if (firstType.erasure() != firstType) {
+ ArrayList someInvocations = new ArrayList(1);
+ someInvocations.add(firstType);
+ allInvocations.put(firstType.erasure(), someInvocations);
+ }
+ superTypes = new TypeBinding[] {
+ firstType.erasure(),
+ getJavaIoSerializable(),
+ getJavaLangCloneable(),
+ getJavaLangObject(),
+ };
+ } else {
+ ArrayList typesToVisit = new ArrayList(5);
+ if (firstType.erasure() != firstType) {
+ ArrayList someInvocations = new ArrayList(1);
+ someInvocations.add(firstType);
+ allInvocations.put(firstType.erasure(), someInvocations);
+ }
+ typesToVisit.add(firstType.erasure());
+ ReferenceBinding currentType = (ReferenceBinding)firstType;
+ for (int i = 0, max = 1; i < max; i++) {
+ currentType = (ReferenceBinding) typesToVisit.get(i);
+ TypeBinding itsSuperclass = currentType.superclass();
+ if (itsSuperclass != null) {
+ TypeBinding itsSuperclassErasure = itsSuperclass.erasure();
+ if (!typesToVisit.contains(itsSuperclassErasure)) {
+ if (itsSuperclassErasure != itsSuperclass) {
+ ArrayList someInvocations = new ArrayList(1);
+ someInvocations.add(itsSuperclass);
+ allInvocations.put(itsSuperclassErasure, someInvocations);
+ }
+ typesToVisit.add(itsSuperclassErasure);
+ max++;
+ }
+ }
+ ReferenceBinding[] itsInterfaces = currentType.superInterfaces();
+ for (int j = 0, count = itsInterfaces.length; j < count; j++) {
+ TypeBinding itsInterface = itsInterfaces[j];
+ TypeBinding itsInterfaceErasure = itsInterface.erasure();
+ if (!typesToVisit.contains(itsInterfaceErasure)) {
+ if (itsInterfaceErasure != itsInterface) {
+ ArrayList someInvocations = new ArrayList(1);
+ someInvocations.add(itsInterface);
+ allInvocations.put(itsInterfaceErasure, someInvocations);
+ }
+ typesToVisit.add(itsInterfaceErasure);
+ max++;
+ }
+ }
+ }
+ superLength = typesToVisit.size();
+ superTypes = new TypeBinding[superLength];
+ typesToVisit.toArray(superTypes);
+ }
+ int remaining = superLength;
+ nextOtherType: for (int i = indexOfFirst+1; i < length; i++) {
+ TypeBinding otherType = types[i];
+ if (otherType == null)
+ continue nextOtherType;
+ else if (otherType.isArrayType()) {
+ nextSuperType: for (int j = 0; j < superLength; j++) {
+ TypeBinding superType = superTypes[j];
+ if (superType == null || superType == otherType) continue nextSuperType;
+ switch (superType.id) {
+ case T_JavaIoSerializable :
+ case T_JavaLangCloneable :
+ case T_JavaLangObject :
+ continue nextSuperType;
+ }
+ superTypes[j] = null;
+ if (--remaining == 0) return null;
+
+ }
+ continue nextOtherType;
+ }
+ ReferenceBinding otherRefType = (ReferenceBinding) otherType;
+ nextSuperType: for (int j = 0; j < superLength; j++) {
+ TypeBinding superType = superTypes[j];
+ if (superType == null) continue nextSuperType;
+ if (otherRefType.erasure().isCompatibleWith(superType)) {
+ TypeBinding match = otherRefType.findSuperTypeErasingTo((ReferenceBinding)superType);
+ if (match != null && match.erasure() != match) { // match can be null: interface.findSuperTypeErasingTo(Object)
+ ArrayList someInvocations = (ArrayList) allInvocations.get(superType);
+ if (someInvocations == null) someInvocations = new ArrayList(1);
+ someInvocations.add(match);
+ allInvocations.put(superType, someInvocations);
+ }
+ break nextSuperType;
+ } else {
+ superTypes[j] = null;
+ if (--remaining == 0) return null;
+ }
+ }
+ }
+ // per construction, first non-null supertype is most specific common supertype
+ for (int i = 0; i < superLength; i++) {
+ TypeBinding superType = superTypes[i];
+ if (superType != null) {
+ List matchingInvocations = (List)allInvocations.get(superType);
+ if (matchingInvocations != null) invocations.addAll(matchingInvocations);
+ return superType;
+ }
+ }
+ 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
* 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;
+ protected final MethodBinding mostSpecificClassMethodBinding(MethodBinding[] visible, int visibleSize, InvocationSite invocationSite) {
+ MethodBinding problemMethod = null;
MethodBinding previous = null;
-
nextVisible : for (int i = 0; i < visibleSize; i++) {
- method = visible[i];
-
+ MethodBinding method = visible[i];
if (previous != null && method.declaringClass != previous.declaringClass)
break; // cannot answer a method farther up the hierarchy than the first method found
- if (!method.isStatic()) previous = method; // no ambiguity for static methods
+
+ if (!method.isStatic()) previous = method; // no ambiguity for static methods
for (int j = 0; j < visibleSize; j++) {
if (i == j) continue;
- MethodBinding next = visible[j];
- if (!areParametersAssignable(next.parameters, method.parameters))
+ if (!visible[j].areParametersCompatibleWith(method.parameters))
continue nextVisible;
}
compilationUnitScope().recordTypeReferences(method.thrownExceptions);
return method;
}
- return new ProblemMethodBinding(visible[0].selector, visible[0].parameters, Ambiguous);
+ if (problemMethod == null)
+ return new ProblemMethodBinding(visible[0].selector, visible[0].parameters, Ambiguous);
+ return problemMethod;
}
-
+
// 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
public void foo(I i, X x) { i.bar(x); }
}
*/
- protected final MethodBinding mostSpecificInterfaceMethodBinding(MethodBinding[] visible, int visibleSize) {
- MethodBinding method = null;
+ protected final MethodBinding mostSpecificInterfaceMethodBinding(MethodBinding[] visible, int visibleSize, InvocationSite invocationSite) {
+ MethodBinding problemMethod = null;
nextVisible : for (int i = 0; i < visibleSize; i++) {
- method = visible[i];
+ MethodBinding method = visible[i];
for (int j = 0; j < visibleSize; j++) {
if (i == j) continue;
- MethodBinding next = visible[j];
- if (!areParametersAssignable(next.parameters, method.parameters))
+ if (!visible[j].areParametersCompatibleWith(method.parameters))
continue nextVisible;
}
compilationUnitScope().recordTypeReferences(method.thrownExceptions);
return method;
}
- return new ProblemMethodBinding(visible[0].selector, visible[0].parameters, Ambiguous);
+ if (problemMethod == null)
+ return new ProblemMethodBinding(visible[0].selector, visible[0].parameters, Ambiguous);
+ return problemMethod;
}
-
- // Internal use only
- /* All methods in visible are acceptable matches for the method in question...
- * Since 1.4, the inherited ambiguous case has been removed from mostSpecificClassMethodBinding
- */
- protected final MethodBinding mostSpecificMethodBinding(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;
+ protected final MethodBinding mostSpecificMethodBinding(MethodBinding[] visible, int visibleSize, TypeBinding[] argumentTypes, InvocationSite invocationSite) {
+ int[] compatibilityLevels = new int[visibleSize];
+ for (int i = 0; i < visibleSize; i++)
+ compatibilityLevels[i] = parameterCompatibilityLevel(visible[i], argumentTypes);
+
+ for (int level = 0; level <= 2; level++) {
+ nextVisible : for (int i = 0; i < visibleSize; i++) {
+ if (compatibilityLevels[i] != level) continue nextVisible; // skip this method for now
+ MethodBinding method = visible[i];
+ for (int j = 0; j < visibleSize; j++) {
+ if (i == j || compatibilityLevels[j] != level) continue;
+ // tiebreak generic methods using variant where type params are substituted by their erasures
+ if (!visible[j].tiebreakMethod().areParametersCompatibleWith(method.tiebreakMethod().parameters)) {
+ if (method.isVarargs() && visible[j].isVarargs()) {
+ int paramLength = method.parameters.length;
+ if (paramLength == visible[j].parameters.length && paramLength == argumentTypes.length + 1) {
+ TypeBinding elementsType = ((ArrayBinding) visible[j].parameters[paramLength - 1]).elementsType();
+ if (method.parameters[paramLength - 1].isCompatibleWith(elementsType))
+ continue; // special case to choose between 2 varargs methods when the last arg is missing
+ }
+ }
+ continue nextVisible;
+ }
+ }
+ compilationUnitScope().recordTypeReferences(method.thrownExceptions);
+ return method;
}
- compilationUnitScope().recordTypeReferences(method.thrownExceptions);
- return method;
}
return new ProblemMethodBinding(visible[0].selector, visible[0].parameters, Ambiguous);
- }
+ }
public final ClassScope outerMostClassScope() {
ClassScope lastClassScope = null;
return lastMethodScope; // may answer null if no method around
}
+ protected int parameterCompatibilityLevel(MethodBinding method, TypeBinding[] arguments) {
+ TypeBinding[] parameters = method.parameters;
+ int paramLength = parameters.length;
+ int argLength = arguments.length;
+ int lastIndex = argLength;
+ int level = COMPATIBLE; // no autoboxing or varargs support needed
+ if (method.isVarargs()) {
+ lastIndex = paramLength - 1;
+ if (paramLength == argLength) { // accept X or X[] but not X[][]
+ TypeBinding param = parameters[lastIndex]; // is an ArrayBinding by definition
+ TypeBinding arg = arguments[lastIndex];
+ if (param != arg && !arg.isCompatibleWith(param)) {
+ if (isBoxingCompatibleWith(arg, param)) {
+ level = AUTOBOX_COMPATIBLE; // autoboxing support needed
+ } else {
+ // expect X[], called with X
+ param = ((ArrayBinding) param).elementsType();
+ if (!arg.isCompatibleWith(param) && !isBoxingCompatibleWith(arg, param))
+ return NOT_COMPATIBLE;
+ level = VARARGS_COMPATIBLE; // varargs support needed
+ }
+ }
+ } else {
+ if (paramLength < argLength) { // all remainig argument types must be compatible with the elementsType of varArgType
+ TypeBinding param = ((ArrayBinding) parameters[lastIndex]).elementsType();
+ for (int i = lastIndex; i < argLength; i++) {
+ TypeBinding arg = arguments[i];
+ if (param != arg && !arg.isCompatibleWith(param) && !isBoxingCompatibleWith(arg, param))
+ return NOT_COMPATIBLE;
+ }
+ } else if (lastIndex != argLength) { // can call foo(int i, X ... x) with foo(1) but NOT foo();
+ return NOT_COMPATIBLE;
+ }
+ level = VARARGS_COMPATIBLE; // varargs support needed
+ }
+ // now compare standard arguments from 0 to lastIndex
+ }
+ for (int i = 0; i < lastIndex; i++) {
+ TypeBinding param = parameters[i];
+ TypeBinding arg = arguments[i];
+ if (arg != param && !arg.isCompatibleWith(param)) {
+ if (!isBoxingCompatibleWith(arg, param))
+ return NOT_COMPATIBLE;
+ level = AUTOBOX_COMPATIBLE; // autoboxing support needed
+ }
+ }
+ return level;
+ }
+
public abstract ProblemReporter problemReporter();
public final CompilationUnitDeclaration referenceCompilationUnit() {
} while (scope != null);
return null;
}
+ /*
+ * Unboxing primitive
+ */
+ public int unboxing(int id) {
+ switch (id) {
+ case T_JavaLangInteger :
+ return T_int;
+ case T_JavaLangByte :
+ return T_byte;
+ case T_JavaLangShort :
+ return T_short;
+ case T_JavaLangCharacter :
+ return T_char;
+ case T_JavaLangLong :
+ return T_long;
+ case T_JavaLangFloat :
+ return T_float;
+ case T_JavaLangDouble :
+ return T_double;
+ case T_JavaLangBoolean :
+ return T_boolean;
+ case T_JavaLangVoid :
+ return T_void;
+ }
+ return id;
+ }
+ /*
+ * Unboxing primitive
+ */
+ public TypeBinding unboxing(TypeBinding type) {
+ switch (type.id) {
+ case T_JavaLangInteger :
+ return IntBinding;
+ case T_JavaLangByte :
+ return ByteBinding;
+ case T_JavaLangShort :
+ return ShortBinding;
+ case T_JavaLangCharacter :
+ return CharBinding;
+ case T_JavaLangLong :
+ return LongBinding;
+ case T_JavaLangFloat :
+ return FloatBinding;
+ case T_JavaLangDouble :
+ return DoubleBinding;
+ case T_JavaLangBoolean :
+ return BooleanBinding;
+ case T_JavaLangVoid :
+ return VoidBinding;
+ }
+ return type;
+ }
}