--- /dev/null
+/*******************************************************************************
+ * Copyright (c) 2000, 2004 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Common Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.jdt.internal.compiler.lookup;
+
+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.impl.ReferenceContext;
+import org.eclipse.jdt.internal.compiler.problem.AbortCompilation;
+import org.eclipse.jdt.internal.compiler.problem.ProblemReporter;
+import org.eclipse.jdt.internal.compiler.util.HashtableOfObject;
+import org.eclipse.jdt.internal.compiler.util.ObjectVector;
+
+public abstract class Scope
+ implements BaseTypes, BindingIds, 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 int kind;
+ public Scope parent;
+
+ protected Scope(int kind, Scope parent) {
+ this.kind = kind;
+ this.parent = parent;
+ }
+
+ /* Answer an int describing the relationship between the given types.
+ *
+ * NotRelated
+ * EqualOrMoreSpecific : left is compatible with right
+ * MoreGeneric : right is compatible with left
+ */
+ public static int compareTypes(TypeBinding left, TypeBinding right) {
+ if (left.isCompatibleWith(right))
+ return EqualOrMoreSpecific;
+ if (right.isCompatibleWith(left))
+ return MoreGeneric;
+ return NotRelated;
+ }
+
+ // Internal use only
+ protected final boolean areParametersAssignable(TypeBinding[] parameters, TypeBinding[] arguments) {
+ if (parameters == arguments)
+ return true;
+
+ int length = parameters.length;
+ if (length != arguments.length)
+ return false;
+
+ for (int i = 0; i < length; i++)
+ if (parameters[i] != arguments[i])
+ if (!arguments[i].isCompatibleWith(parameters[i]))
+ return false;
+ return true;
+ }
+
+ public final ClassScope classScope() {
+ Scope scope = this;
+ do {
+ if (scope instanceof ClassScope)
+ return (ClassScope) scope;
+ scope = scope.parent;
+ } while (scope != null);
+ return null;
+ }
+
+ /* Answer an int describing the relationship between the given type and unchecked exceptions.
+ *
+ * NotRelated
+ * EqualOrMoreSpecific : type is known for sure to be an unchecked exception type
+ * MoreGeneric : type is a supertype of an actual unchecked exception type
+ */
+ public int compareUncheckedException(ReferenceBinding type) {
+ int comparison = compareTypes(type, getJavaLangRuntimeException());
+ if (comparison != 0) return comparison;
+ return compareTypes(type, getJavaLangError());
+ }
+
+ public final CompilationUnitScope compilationUnitScope() {
+ Scope lastScope = null;
+ Scope scope = this;
+ do {
+ lastScope = scope;
+ scope = scope.parent;
+ } while (scope != null);
+ return (CompilationUnitScope) lastScope;
+ }
+
+ public ArrayBinding createArray(TypeBinding type, int dimension) {
+ if (!type.isValidBinding())
+ return new ArrayBinding(type, dimension);
+ return environment().createArrayType(type, dimension);
+ }
+
+ public final ClassScope enclosingClassScope() {
+ Scope scope = this;
+ while ((scope = scope.parent) != null) {
+ 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;
+ }
+ return null; // may answer null if no method around
+ }
+
+ /* Answer the receiver's enclosing source type.
+ */
+ public final SourceTypeBinding enclosingSourceType() {
+ Scope scope = this;
+ do {
+ if (scope instanceof ClassScope)
+ return ((ClassScope) scope).referenceContext.binding;
+ scope = scope.parent;
+ } while (scope != null);
+ return null;
+ }
+ public final LookupEnvironment environment() {
+ Scope scope, unitScope = this;
+ while ((scope = unitScope.parent) != null)
+ unitScope = scope;
+ return ((CompilationUnitScope) unitScope).environment;
+ }
+
+ 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,
+ char[] selector,
+ TypeBinding[] argumentTypes,
+ InvocationSite invocationSite,
+ ReferenceBinding classHierarchyStart,
+ MethodBinding matchingMethod,
+ ObjectVector found) {
+
+ int startFoundSize = found.size;
+ ReferenceBinding currentType = classHierarchyStart;
+ while (currentType != null) {
+ matchingMethod = findMethodInSuperInterfaces(currentType, selector, found, matchingMethod);
+ currentType = currentType.superclass();
+ }
+ int foundSize = found.size;
+ if (foundSize == startFoundSize) {
+ if (matchingMethod != null) compilationUnitScope().recordTypeReferences(matchingMethod.thrownExceptions);
+ return matchingMethod; // maybe null
+ }
+ MethodBinding[] candidates = new MethodBinding[foundSize - startFoundSize];
+ int candidatesCount = 0;
+ // 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;
+ }
+ if (candidatesCount == 1) {
+ compilationUnitScope().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
+ int argLength = argumentTypes.length;
+ nextMethod : for (int i = 0; i < foundSize; i++) {
+ MethodBinding methodBinding = (MethodBinding) found.elementAt(i);
+ TypeBinding[] params = methodBinding.parameters;
+ int paramLength = params.length;
+ nextArg: for (int a = 0; a < argLength; a++) {
+ TypeBinding arg = argumentTypes[a];
+ for (int p = 0; p < paramLength; p++)
+ if (params[p] == arg)
+ continue nextArg;
+ continue nextMethod;
+ }
+ return methodBinding;
+ }
+ 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);
+ }
+
+ // Internal use only
+ public ReferenceBinding findDirectMemberType(char[] typeName, ReferenceBinding enclosingType) {
+ if ((enclosingType.tagBits & HasNoMemberTypes) != 0)
+ return null; // know it has no member types (nor inherited member types)
+
+ SourceTypeBinding enclosingSourceType = enclosingSourceType();
+ compilationUnitScope().recordReference(enclosingType.compoundName, typeName);
+ ReferenceBinding memberType = enclosingType.getMemberType(typeName);
+ if (memberType != null) {
+ compilationUnitScope().recordTypeReference(memberType); // to record supertypes
+ if (enclosingSourceType == null
+ ? memberType.canBeSeenBy(getCurrentPackage())
+ : memberType.canBeSeenBy(enclosingType, enclosingSourceType))
+ return memberType;
+ return new ProblemReferenceBinding(typeName, memberType, NotVisible);
+ }
+ return null;
+ }
+
+ // Internal use only
+ public MethodBinding findExactMethod(
+ ReferenceBinding receiverType,
+ char[] selector,
+ TypeBinding[] argumentTypes,
+ InvocationSite invocationSite) {
+
+ faultInReceiverType(receiverType);
+ compilationUnitScope().recordTypeReference(receiverType);
+ compilationUnitScope().recordTypeReferences(argumentTypes);
+ MethodBinding exactMethod = receiverType.getExactMethod(selector, argumentTypes);
+ if (exactMethod != null) {
+ compilationUnitScope().recordTypeReferences(exactMethod.thrownExceptions);
+ if (receiverType.isInterface() || exactMethod.canBeSeenBy(receiverType, invocationSite, this))
+ return exactMethod;
+ }
+ return null;
+ }
+
+ // Internal use only
+ /* Answer the field binding that corresponds to fieldName.
+ Start the lookup at the receiverType.
+ InvocationSite implements
+ isSuperAccess(); this is used to determine if the discovered field is visible.
+ Only fields defined by the receiverType or its supertypes are answered;
+ a field of an enclosing type will not be found using this API.
+
+ If no visible field is discovered, null is answered.
+ */
+ public FieldBinding findField(TypeBinding receiverType, char[] fieldName, InvocationSite invocationSite, boolean needResolve) {
+ if (receiverType.isBaseType()) return null;
+ if (receiverType.isArrayType()) {
+ TypeBinding leafType = receiverType.leafComponentType();
+ 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;
+ return new ProblemFieldBinding(field /* closest match*/, field.declaringClass, fieldName, NotVisible);
+ }
+ // collect all superinterfaces of receiverType until the field is found in a supertype
+ ReferenceBinding[][] interfacesToVisit = null;
+ int lastPosition = -1;
+ FieldBinding visibleField = null;
+ boolean keepLooking = true;
+ boolean notVisible = false;
+ // we could hold onto the not visible field for extra error reporting
+ while (keepLooking) {
+ ReferenceBinding[] itsInterfaces = currentType.superInterfaces();
+ if (itsInterfaces != NoSuperInterfaces) {
+ if (interfacesToVisit == null)
+ interfacesToVisit = new ReferenceBinding[5][];
+ if (++lastPosition == interfacesToVisit.length)
+ System.arraycopy(
+ interfacesToVisit,
+ 0,
+ interfacesToVisit = new ReferenceBinding[lastPosition * 2][],
+ 0,
+ lastPosition);
+ interfacesToVisit[lastPosition] = itsInterfaces;
+ }
+ if ((currentType = currentType.superclass()) == null)
+ break;
+
+ if ((field = currentType.getField(fieldName, needResolve)) != null) {
+ keepLooking = false;
+ if (field.canBeSeenBy(receiverType, invocationSite, this)) {
+ if (visibleField == null)
+ visibleField = field;
+ else
+ return new ProblemFieldBinding(visibleField /* closest match*/, visibleField.declaringClass, fieldName, Ambiguous);
+ } else {
+ notVisible = true;
+ }
+ }
+ }
+
+ // walk all visible interfaces to find ambiguous references
+ if (interfacesToVisit != null) {
+ ProblemFieldBinding ambiguous = null;
+ done : for (int i = 0; i <= lastPosition; i++) {
+ ReferenceBinding[] interfaces = interfacesToVisit[i];
+ for (int j = 0, length = interfaces.length; j < length; j++) {
+ ReferenceBinding anInterface = interfaces[j];
+ if ((anInterface.tagBits & InterfaceVisited) == 0) {
+ // if interface as not already been visited
+ anInterface.tagBits |= InterfaceVisited;
+ if ((field = anInterface.getField(fieldName, true /*resolve*/)) != null) {
+ if (visibleField == null) {
+ visibleField = field;
+ } else {
+ ambiguous = new ProblemFieldBinding(visibleField /* closest match*/, visibleField.declaringClass, fieldName, Ambiguous);
+ break done;
+ }
+ } else {
+ ReferenceBinding[] itsInterfaces = anInterface.superInterfaces();
+ if (itsInterfaces != NoSuperInterfaces) {
+ if (++lastPosition == interfacesToVisit.length)
+ System.arraycopy(
+ interfacesToVisit,
+ 0,
+ interfacesToVisit = new ReferenceBinding[lastPosition * 2][],
+ 0,
+ lastPosition);
+ interfacesToVisit[lastPosition] = itsInterfaces;
+ }
+ }
+ }
+ }
+ }
+
+ // bit reinitialization
+ for (int i = 0; i <= lastPosition; i++) {
+ ReferenceBinding[] interfaces = interfacesToVisit[i];
+ for (int j = 0, length = interfaces.length; j < length; j++)
+ interfaces[j].tagBits &= ~InterfaceVisited;
+ }
+ if (ambiguous != null)
+ return ambiguous;
+ }
+
+ if (visibleField != null)
+ return visibleField;
+ if (notVisible)
+ return new ProblemFieldBinding(currentType, fieldName, NotVisible);
+ return null;
+ }
+
+ // Internal use only
+ public ReferenceBinding findMemberType(char[] typeName, ReferenceBinding enclosingType) {
+ if ((enclosingType.tagBits & HasNoMemberTypes) != 0)
+ return null; // know it has no member types (nor inherited member types)
+
+ SourceTypeBinding enclosingSourceType = enclosingSourceType();
+ PackageBinding currentPackage = getCurrentPackage();
+ compilationUnitScope().recordReference(enclosingType.compoundName, typeName);
+ ReferenceBinding memberType = enclosingType.getMemberType(typeName);
+ if (memberType != null) {
+ compilationUnitScope().recordTypeReference(memberType); // to record supertypes
+ if (enclosingSourceType == null
+ ? memberType.canBeSeenBy(currentPackage)
+ : memberType.canBeSeenBy(enclosingType, enclosingSourceType))
+ return memberType;
+ return new ProblemReferenceBinding(typeName, memberType, NotVisible);
+ }
+
+ // collect all superinterfaces of receiverType until the memberType is found in a supertype
+ ReferenceBinding currentType = enclosingType;
+ ReferenceBinding[][] interfacesToVisit = null;
+ int lastPosition = -1;
+ ReferenceBinding visibleMemberType = null;
+ boolean keepLooking = true;
+ ReferenceBinding notVisible = null;
+ // we could hold onto the not visible field for extra error reporting
+ while (keepLooking) {
+ ReferenceBinding[] itsInterfaces = currentType.superInterfaces();
+ if (itsInterfaces != NoSuperInterfaces) {
+ if (interfacesToVisit == null)
+ interfacesToVisit = new ReferenceBinding[5][];
+ if (++lastPosition == interfacesToVisit.length)
+ System.arraycopy(
+ interfacesToVisit,
+ 0,
+ interfacesToVisit = new ReferenceBinding[lastPosition * 2][],
+ 0,
+ lastPosition);
+ interfacesToVisit[lastPosition] = itsInterfaces;
+ }
+ if ((currentType = currentType.superclass()) == null)
+ break;
+
+ compilationUnitScope().recordReference(currentType.compoundName, typeName);
+ if ((memberType = currentType.getMemberType(typeName)) != null) {
+ compilationUnitScope().recordTypeReference(memberType); // to record supertypes
+ keepLooking = false;
+ if (enclosingSourceType == null
+ ? memberType.canBeSeenBy(currentPackage)
+ : memberType.canBeSeenBy(enclosingType, enclosingSourceType)) {
+ if (visibleMemberType == null)
+ visibleMemberType = memberType;
+ else
+ return new ProblemReferenceBinding(typeName, Ambiguous);
+ } else {
+ notVisible = memberType;
+ }
+ }
+ }
+ // walk all visible interfaces to find ambiguous references
+ if (interfacesToVisit != null) {
+ ProblemReferenceBinding ambiguous = null;
+ done : for (int i = 0; i <= lastPosition; i++) {
+ ReferenceBinding[] interfaces = interfacesToVisit[i];
+ for (int j = 0, length = interfaces.length; j < length; j++) {
+ ReferenceBinding anInterface = interfaces[j];
+ if ((anInterface.tagBits & InterfaceVisited) == 0) {
+ // if interface as not already been visited
+ anInterface.tagBits |= InterfaceVisited;
+ compilationUnitScope().recordReference(anInterface.compoundName, typeName);
+ if ((memberType = anInterface.getMemberType(typeName)) != null) {
+ compilationUnitScope().recordTypeReference(memberType); // to record supertypes
+ if (visibleMemberType == null) {
+ visibleMemberType = memberType;
+ } else {
+ ambiguous = new ProblemReferenceBinding(typeName, Ambiguous);
+ break done;
+ }
+ } else {
+ ReferenceBinding[] itsInterfaces = anInterface.superInterfaces();
+ if (itsInterfaces != NoSuperInterfaces) {
+ if (++lastPosition == interfacesToVisit.length)
+ System.arraycopy(
+ interfacesToVisit,
+ 0,
+ interfacesToVisit = new ReferenceBinding[lastPosition * 2][],
+ 0,
+ lastPosition);
+ interfacesToVisit[lastPosition] = itsInterfaces;
+ }
+ }
+ }
+ }
+ }
+
+ // bit reinitialization
+ for (int i = 0; i <= lastPosition; i++) {
+ ReferenceBinding[] interfaces = interfacesToVisit[i];
+ for (int j = 0, length = interfaces.length; j < length; j++)
+ interfaces[j].tagBits &= ~InterfaceVisited;
+ }
+ if (ambiguous != null)
+ return ambiguous;
+ }
+ if (visibleMemberType != null)
+ return visibleMemberType;
+ if (notVisible != null)
+ return new ProblemReferenceBinding(typeName, notVisible, NotVisible);
+ return null;
+ }
+
+ // Internal use only
+ public MethodBinding findMethod(
+ ReferenceBinding receiverType,
+ char[] selector,
+ TypeBinding[] argumentTypes,
+ InvocationSite invocationSite) {
+
+ ReferenceBinding currentType = receiverType;
+ MethodBinding matchingMethod = null;
+ ObjectVector found = new ObjectVector(); //TODO should rewrite to remove #matchingMethod since found is allocated anyway
+
+ faultInReceiverType(receiverType);
+ compilationUnitScope().recordTypeReference(receiverType);
+ compilationUnitScope().recordTypeReferences(argumentTypes);
+
+ if (currentType.isInterface()) {
+ MethodBinding[] currentMethods = currentType.getMethods(selector);
+ int currentLength = currentMethods.length;
+ if (currentLength == 1) {
+ matchingMethod = currentMethods[0];
+ } else if (currentLength > 1) {
+ found.addAll(currentMethods);
+ }
+ matchingMethod = findMethodInSuperInterfaces(currentType, selector, found, matchingMethod);
+ currentType = getJavaLangObject();
+ }
+
+ boolean isCompliant14 = compilationUnitScope().environment.options.complianceLevel >= ClassFileConstants.JDK1_4;
+ // superclass lookup
+ ReferenceBinding classHierarchyStart = currentType;
+ while (currentType != null) {
+ 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++){
+ MethodBinding currentMethod = currentMethods[i];
+ // 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)){
+ 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)){
+ currentLength--;
+ currentMethods[i] = null;
+ continue nextMethod;
+ }
+ }
+ }
+ }
+ }
+
+ if (currentLength == 1 && matchingMethod == null && found.size == 0) {
+ matchingMethod = currentMethods[0];
+ } else if (currentLength > 0) {
+ if (matchingMethod != null) {
+ found.add(matchingMethod);
+ matchingMethod = null;
+ }
+ // append currentMethods, filtering out null entries
+ int maxMethod = currentMethods.length;
+ if (maxMethod == currentLength) { // no method was eliminated for 1.4 compliance (see above)
+ found.addAll(currentMethods);
+ } else {
+ for (int i = 0, max = currentMethods.length; i < max; i++) {
+ MethodBinding currentMethod = currentMethods[i];
+ if (currentMethod != null) found.add(currentMethod);
+ }
+ }
+ }
+ currentType = currentType.superclass();
+ }
+
+ // if found several candidates, then eliminate those not matching argument types
+ int foundSize = found.size;
+ MethodBinding[] candidates = null;
+ int candidatesCount = 0;
+ boolean checkedMatchingMethod = false; // is matchingMethod meeting argument expectation ?
+ 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;
+ }
+ candidatesCount++;
+ }
+ }
+ }
+ // 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 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);
+ if (interfaceMethod != null) return interfaceMethod;
+ compilationUnitScope().recordTypeReferences(matchingMethod.thrownExceptions);
+ return matchingMethod;
+ }
+ }
+ return findDefaultAbstractMethod(receiverType, selector, argumentTypes, invocationSite, classHierarchyStart, matchingMethod, found);
+ }
+
+ // no match was found, try to find a close match when the parameter order is wrong or missing some parameters
+ if (candidatesCount == 0) {
+ MethodBinding interfaceMethod =
+ findDefaultAbstractMethod(receiverType, selector, argumentTypes, invocationSite, classHierarchyStart, matchingMethod, found);
+ if (interfaceMethod != null) return interfaceMethod;
+
+ int argLength = argumentTypes.length;
+ foundSize = found.size;
+ nextMethod : for (int i = 0; i < foundSize; i++) {
+ MethodBinding methodBinding = (MethodBinding) found.elementAt(i);
+ TypeBinding[] params = methodBinding.parameters;
+ int paramLength = params.length;
+ nextArg: for (int a = 0; a < argLength; a++) {
+ TypeBinding arg = argumentTypes[a];
+ for (int p = 0; p < paramLength; p++)
+ if (params[p] == arg)
+ continue nextArg;
+ continue nextMethod;
+ }
+ return methodBinding;
+ }
+ return (MethodBinding) found.elementAt(0); // no good match so just use the first one found
+ }
+
+ // tiebreak using visibility check
+ int visiblesCount = 0;
+ for (int i = 0; i < candidatesCount; i++) {
+ MethodBinding methodBinding = candidates[i];
+ if (methodBinding.canBeSeenBy(receiverType, invocationSite, this)) {
+ if (visiblesCount != i) {
+ candidates[i] = null;
+ candidates[visiblesCount] = methodBinding;
+ }
+ visiblesCount++;
+ }
+ }
+ if (visiblesCount == 1) {
+ compilationUnitScope().recordTypeReferences(candidates[0].thrownExceptions);
+ return candidates[0];
+ }
+ if (visiblesCount == 0) {
+ MethodBinding interfaceMethod =
+ findDefaultAbstractMethod(receiverType, selector, argumentTypes, invocationSite, classHierarchyStart, matchingMethod, found);
+ if (interfaceMethod != null) return interfaceMethod;
+ return new ProblemMethodBinding(candidates[0], candidates[0].selector, candidates[0].parameters, NotVisible);
+ }
+ if (isCompliant14)
+ return mostSpecificMethodBinding(candidates, visiblesCount);
+ return candidates[0].declaringClass.isClass()
+ ? mostSpecificClassMethodBinding(candidates, visiblesCount)
+ : mostSpecificInterfaceMethodBinding(candidates, visiblesCount);
+ }
+
+ // Internal use only
+ public MethodBinding findMethodForArray(
+ ArrayBinding receiverType,
+ char[] selector,
+ TypeBinding[] argumentTypes,
+ InvocationSite invocationSite) {
+
+ TypeBinding leafType = receiverType.leafComponentType();
+ if (leafType instanceof ReferenceBinding) {
+ if (!((ReferenceBinding) leafType).canBeSeenBy(this))
+ return new ProblemMethodBinding(selector, TypeConstants.NoParameters, (ReferenceBinding)leafType, ReceiverTypeNotVisible);
+ }
+
+ ReferenceBinding object = getJavaLangObject();
+ MethodBinding methodBinding = object.getExactMethod(selector, argumentTypes);
+ if (methodBinding != null) {
+ // handle the method clone() specially... cannot be protected or throw exceptions
+ if (argumentTypes == NoParameters && CharOperation.equals(selector, CLONE))
+ return new 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 (methodBinding.canBeSeenBy(receiverType, invocationSite, this))
+ return methodBinding;
+ }
+ // answers closest approximation, may not check argumentTypes or visibility
+ methodBinding = findMethod(object, selector, argumentTypes, invocationSite);
+ if (methodBinding == null)
+ return new ProblemMethodBinding(selector, argumentTypes, NotFound);
+ if (methodBinding.isValidBinding()) {
+ if (!areParametersAssignable(methodBinding.parameters, argumentTypes))
+ return new ProblemMethodBinding(
+ methodBinding,
+ selector,
+ argumentTypes,
+ NotFound);
+ if (!methodBinding.canBeSeenBy(receiverType, invocationSite, this))
+ return new ProblemMethodBinding(
+ methodBinding,
+ selector,
+ methodBinding.parameters,
+ NotVisible);
+ }
+ return methodBinding;
+ }
+
+ public MethodBinding findMethodInSuperInterfaces(
+ ReferenceBinding currentType,
+ char[] selector,
+ ObjectVector found,
+ MethodBinding matchingMethod) {
+
+ ReferenceBinding[] itsInterfaces = currentType.superInterfaces();
+ if (itsInterfaces != NoSuperInterfaces) {
+ ReferenceBinding[][] interfacesToVisit = new ReferenceBinding[5][];
+ int lastPosition = -1;
+ if (++lastPosition == interfacesToVisit.length)
+ System.arraycopy(
+ interfacesToVisit, 0,
+ interfacesToVisit = new ReferenceBinding[lastPosition * 2][], 0,
+ lastPosition);
+ interfacesToVisit[lastPosition] = itsInterfaces;
+
+ for (int i = 0; i <= lastPosition; i++) {
+ ReferenceBinding[] interfaces = interfacesToVisit[i];
+ for (int j = 0, length = interfaces.length; j < length; j++) {
+ currentType = interfaces[j];
+ if ((currentType.tagBits & InterfaceVisited) == 0) {
+ // if interface as not already been visited
+ currentType.tagBits |= InterfaceVisited;
+
+ MethodBinding[] currentMethods = currentType.getMethods(selector);
+ int currentLength = currentMethods.length;
+ if (currentLength == 1 && matchingMethod == null && found.size == 0) {
+ matchingMethod = currentMethods[0];
+ } else if (currentLength > 0) {
+ if (matchingMethod != null) {
+ found.add(matchingMethod);
+ matchingMethod = null;
+ }
+ found.addAll(currentMethods);
+ }
+ itsInterfaces = currentType.superInterfaces();
+ if (itsInterfaces != NoSuperInterfaces) {
+ if (++lastPosition == interfacesToVisit.length)
+ System.arraycopy(
+ interfacesToVisit, 0,
+ interfacesToVisit = new ReferenceBinding[lastPosition * 2][], 0,
+ lastPosition);
+ interfacesToVisit[lastPosition] = itsInterfaces;
+ }
+ }
+ }
+ }
+
+ // bit reinitialization
+ for (int i = 0; i <= lastPosition; i++) {
+ ReferenceBinding[] interfaces = interfacesToVisit[i];
+ for (int j = 0, length = interfaces.length; j < length; j++)
+ interfaces[j].tagBits &= ~InterfaceVisited;
+ }
+ }
+ return matchingMethod;
+ }
+
+ // Internal use only
+ public ReferenceBinding findType(
+ char[] typeName,
+ PackageBinding declarationPackage,
+ PackageBinding invocationPackage) {
+
+ compilationUnitScope().recordReference(declarationPackage.compoundName, typeName);
+ ReferenceBinding typeBinding = declarationPackage.getType(typeName);
+ if (typeBinding == null)
+ return null;
+
+ if (typeBinding.isValidBinding()) {
+ if (declarationPackage != invocationPackage && !typeBinding.canBeSeenBy(invocationPackage))
+ return new ProblemReferenceBinding(typeName, typeBinding, NotVisible);
+ }
+ return typeBinding;
+ }
+
+ public LocalVariableBinding findVariable(char[] variable) {
+
+ return null;
+ }
+
+ public TypeBinding getBaseType(char[] name) {
+ // list should be optimized (with most often used first)
+ int length = name.length;
+ if (length > 2 && length < 8) {
+ switch (name[0]) {
+ case 'i' :
+ if (length == 3 && name[1] == 'n' && name[2] == 't')
+ return IntBinding;
+ break;
+ case 'v' :
+ if (length == 4 && name[1] == 'o' && name[2] == 'i' && name[3] == 'd')
+ return VoidBinding;
+ break;
+ case 'b' :
+ if (length == 7
+ && name[1] == 'o'
+ && name[2] == 'o'
+ && name[3] == 'l'
+ && name[4] == 'e'
+ && name[5] == 'a'
+ && name[6] == 'n')
+ return BooleanBinding;
+ if (length == 4 && name[1] == 'y' && name[2] == 't' && name[3] == 'e')
+ return ByteBinding;
+ break;
+ case 'c' :
+ if (length == 4 && name[1] == 'h' && name[2] == 'a' && name[3] == 'r')
+ return CharBinding;
+ break;
+ case 'd' :
+ if (length == 6
+ && name[1] == 'o'
+ && name[2] == 'u'
+ && name[3] == 'b'
+ && name[4] == 'l'
+ && name[5] == 'e')
+ return DoubleBinding;
+ break;
+ case 'f' :
+ if (length == 5
+ && name[1] == 'l'
+ && name[2] == 'o'
+ && name[3] == 'a'
+ && name[4] == 't')
+ return FloatBinding;
+ break;
+ case 'l' :
+ if (length == 4 && name[1] == 'o' && name[2] == 'n' && name[3] == 'g')
+ return LongBinding;
+ break;
+ case 's' :
+ if (length == 5
+ && name[1] == 'h'
+ && name[2] == 'o'
+ && name[3] == 'r'
+ && name[4] == 't')
+ return ShortBinding;
+ }
+ }
+ return null;
+ }
+
+ /* 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.
+ *
+ * For example, getBinding("foo", VARIABLE, site) will answer
+ * the binding for the field or local named "foo" (or an error binding if none exists).
+ * If a type named "foo" exists, it will not be detected (and an error binding will be answered)
+ *
+ * The VARIABLE mask has precedence over the TYPE mask.
+ *
+ * If the VARIABLE mask is not set, neither fields nor locals will be looked for.
+ *
+ * InvocationSite implements:
+ * isSuperAccess(); this is used to determine if the discovered field is visible.
+ *
+ * Limitations: cannot request FIELD independently of LOCAL, or vice versa
+ */
+ public Binding getBinding(char[] name, int mask, InvocationSite invocationSite, boolean needResolve) {
+
+ try {
+ Binding binding = null;
+ FieldBinding problemField = null;
+ if ((mask & 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;
+ // inside Constructor call or inside static context
+ Scope scope = this;
+ int depth = 0;
+ int foundDepth = 0;
+ ReferenceBinding foundActualReceiverType = null;
+ done : while (true) { // done when a COMPILATION_UNIT_SCOPE is found
+ switch (scope.kind) {
+ case METHOD_SCOPE :
+ MethodScope methodScope = (MethodScope) scope;
+ insideStaticContext |= methodScope.isStatic;
+ insideConstructorCall |= methodScope.isConstructorCall;
+ // Fall through... could duplicate the code below to save a cast - questionable optimization
+ case BLOCK_SCOPE :
+ LocalVariableBinding variableBinding = scope.findVariable(name);
+ // looks in this scope only
+ if (variableBinding != null) {
+ if (foundField != null && foundField.isValidBinding())
+ return new ProblemFieldBinding(
+ foundField, // closest match
+ foundField.declaringClass,
+ name,
+ InheritedNameHidesEnclosingName);
+ if (depth > 0)
+ invocationSite.setDepth(depth);
+ return variableBinding;
+ }
+ break;
+ case CLASS_SCOPE :
+ ClassScope classScope = (ClassScope) scope;
+ SourceTypeBinding enclosingType = classScope.referenceContext.binding;
+ 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);
+ if (fieldBinding != null) { // skip it if we did not find anything
+ if (fieldBinding.problemId() == Ambiguous) {
+ if (foundField == null || foundField.problemId() == NotVisible)
+ // supercedes any potential InheritedNameHidesEnclosingName problem
+ return fieldBinding;
+ // make the user qualify the field, likely wants the first inherited field (javac generates an ambiguous error instead)
+ return new ProblemFieldBinding(
+ foundField, // closest match
+ foundField.declaringClass,
+ name,
+ InheritedNameHidesEnclosingName);
+ }
+
+ ProblemFieldBinding insideProblem = null;
+ if (fieldBinding.isValidBinding()) {
+ if (!fieldBinding.isStatic()) {
+ if (insideConstructorCall) {
+ insideProblem =
+ new ProblemFieldBinding(
+ fieldBinding, // closest match
+ fieldBinding.declaringClass,
+ name,
+ NonStaticReferenceInConstructorInvocation);
+ } else if (insideStaticContext) {
+ insideProblem =
+ new ProblemFieldBinding(
+ fieldBinding, // closest match
+ fieldBinding.declaringClass,
+ name,
+ NonStaticReferenceInStaticContext);
+ }
+ }
+ 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) {
+ if (depth > 0){
+ invocationSite.setDepth(depth);
+ invocationSite.setActualReceiverType(enclosingType);
+ }
+ // return the fieldBinding if it is not declared in a superclass of the scope's binding (that is, inherited)
+ return insideProblem == null ? fieldBinding : insideProblem;
+ }
+ if (foundField.isValidBinding())
+ // if a valid field was found, complain when another is found in an 'immediate' enclosing type (that is, not inherited)
+ if (foundField.declaringClass != fieldBinding.declaringClass)
+ // ie. have we found the same field - do not trust field identity yet
+ return new ProblemFieldBinding(
+ foundField, // closest match
+ foundField.declaringClass,
+ name,
+ InheritedNameHidesEnclosingName);
+ }
+ }
+
+ 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;
+ foundInsideProblem = insideProblem;
+ foundField = fieldBinding;
+ }
+ }
+ depth++;
+ insideStaticContext |= enclosingType.isStatic();
+ // 1EX5I8Z - accessing outer fields within a constructor call is permitted
+ // in order to do so, we change the flag as we exit from the type, not the method
+ // itself, because the class scope is used to retrieve the fields.
+ MethodScope enclosingMethodScope = scope.methodScope();
+ insideConstructorCall =
+ enclosingMethodScope == null ? false : enclosingMethodScope.isConstructorCall;
+ break;
+ case COMPILATION_UNIT_SCOPE :
+ break done;
+ }
+ scope = scope.parent;
+ }
+
+ if (foundInsideProblem != null)
+ return foundInsideProblem;
+ if (foundField != null) {
+ if (foundField.isValidBinding()){
+ if (foundDepth > 0){
+ invocationSite.setDepth(foundDepth);
+ invocationSite.setActualReceiverType(foundActualReceiverType);
+ }
+ return foundField;
+ }
+ problemField = foundField;
+ }
+ }
+
+ // We did not find a local or instance variable.
+ if ((mask & TYPE) != 0) {
+ if ((binding = getBaseType(name)) != null)
+ return binding;
+ binding = getTypeOrPackage(name, (mask & PACKAGE) == 0 ? TYPE : TYPE | PACKAGE);
+ if (binding.isValidBinding() || mask == TYPE)
+ return binding;
+ // answer the problem type binding if we are only looking for a type
+ } else if ((mask & 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);
+ MethodBinding methodBinding = receiverType.getExactConstructor(argumentTypes);
+ if (methodBinding != null && methodBinding.canBeSeenBy(invocationSite, this))
+ return methodBinding;
+ MethodBinding[] methods = receiverType.getMethods(ConstructorDeclaration.ConstantPoolName);
+ if (methods == NoMethods)
+ return new ProblemMethodBinding(
+ ConstructorDeclaration.ConstantPoolName,
+ 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);
+ // need a more descriptive error... cannot convert from X to Y
+
+ MethodBinding[] visible = new MethodBinding[compatibleIndex];
+ int visibleIndex = 0;
+ for (int i = 0; i < compatibleIndex; i++) {
+ MethodBinding method = compatible[i];
+ if (method.canBeSeenBy(invocationSite, this))
+ visible[visibleIndex++] = method;
+ }
+ if (visibleIndex == 1) return visible[0];
+ if (visibleIndex == 0)
+ return new ProblemMethodBinding(
+ compatible[0],
+ ConstructorDeclaration.ConstantPoolName,
+ compatible[0].parameters,
+ NotVisible);
+ return mostSpecificClassMethodBinding(visible, visibleIndex);
+ } catch (AbortCompilation e) {
+ e.updateContext(invocationSite, referenceCompilationUnit().compilationResult);
+ throw e;
+ }
+ }
+
+ public final PackageBinding getCurrentPackage() {
+ Scope scope, unitScope = this;
+ while ((scope = unitScope.parent) != null)
+ unitScope = scope;
+ return ((CompilationUnitScope) unitScope).fPackage;
+ }
+
+ /**
+ * Returns the modifiers of the innermost enclosing declaration.
+ * @return modifiers
+ */
+ public int getDeclarationModifiers(){
+ switch(this.kind){
+ case Scope.BLOCK_SCOPE :
+ case Scope.METHOD_SCOPE :
+ MethodScope methodScope = methodScope();
+ if (!methodScope.isInsideInitializer()){
+ // check method modifiers to see if deprecated
+ MethodBinding context = ((AbstractMethodDeclaration)methodScope.referenceContext).binding;
+ if (context != null) {
+ return context.modifiers;
+ }
+ } else {
+ SourceTypeBinding type = ((BlockScope)this).referenceType().binding;
+
+ // inside field declaration ? check field modifier to see if deprecated
+ if (methodScope.initializedField != null) {
+ return methodScope.initializedField.modifiers;
+ }
+ if (type != null) {
+ return type.modifiers;
+ }
+ }
+ break;
+ case Scope.CLASS_SCOPE :
+ ReferenceBinding context = ((ClassScope)this).referenceType().binding;
+ if (context != null) {
+ return context.modifiers;
+ }
+ break;
+ }
+ return -1;
+ }
+
+ public FieldBinding getField(TypeBinding receiverType, char[] fieldName, InvocationSite invocationSite) {
+ try {
+ FieldBinding field = findField(receiverType, fieldName, invocationSite, true /*resolve*/);
+ if (field != null) return field;
+
+ return new ProblemFieldBinding(
+ receiverType instanceof ReferenceBinding ? (ReferenceBinding) receiverType : null,
+ fieldName,
+ NotFound);
+ } catch (AbortCompilation e) {
+ e.updateContext(invocationSite, referenceCompilationUnit().compilationResult);
+ throw e;
+ }
+ }
+
+ /* API
+ *
+ * Answer the method binding that corresponds to selector, argumentTypes.
+ * Start the lookup at the enclosing type of the receiver.
+ * InvocationSite implements
+ * isSuperAccess(); this is used to determine if the discovered method is visible.
+ * setDepth(int); this is used to record the depth of the discovered method
+ * relative to the enclosing type of the receiver. (If the method is defined
+ * in the enclosing type of the receiver, the depth is 0; in the next enclosing
+ * type, the depth is 1; and so on
+ *
+ * If no visible method is discovered, an error binding is answered.
+ */
+ public MethodBinding getImplicitMethod(
+ char[] selector,
+ TypeBinding[] argumentTypes,
+ InvocationSite invocationSite) {
+
+ boolean insideStaticContext = false;
+ boolean insideConstructorCall = false;
+ MethodBinding foundMethod = null;
+ ProblemMethodBinding foundFuzzyProblem = null;
+ // the weird method lookup case (matches method name in scope, then arg types, then visibility)
+ ProblemMethodBinding foundInsideProblem = null;
+ // inside Constructor call or inside static context
+ Scope scope = this;
+ int depth = 0;
+ done : while (true) { // done when a COMPILATION_UNIT_SCOPE is found
+ switch (scope.kind) {
+ case METHOD_SCOPE :
+ MethodScope methodScope = (MethodScope) scope;
+ insideStaticContext |= methodScope.isStatic;
+ insideConstructorCall |= methodScope.isConstructorCall;
+ break;
+ case CLASS_SCOPE :
+ ClassScope classScope = (ClassScope) scope;
+ SourceTypeBinding receiverType = classScope.referenceContext.binding;
+ boolean isExactMatch = true;
+ // retrieve an exact visible match (if possible)
+ 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);
+ 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);
+ }
+ if (methodBinding != null) { // skip it if we did not find anything
+ if (methodBinding.problemId() == Ambiguous) {
+ if (foundMethod == null || foundMethod.problemId() == NotVisible) {
+ // supercedes any potential InheritedNameHidesEnclosingName problem
+ return methodBinding;
+ }
+ // make the user qualify the method, likely wants the first inherited method (javac generates an ambiguous error instead)
+ return new ProblemMethodBinding(
+ methodBinding, // closest match
+ selector,
+ argumentTypes,
+ InheritedNameHidesEnclosingName);
+ }
+ ProblemMethodBinding fuzzyProblem = null;
+ ProblemMethodBinding insideProblem = null;
+ if (methodBinding.isValidBinding()) {
+ if (!isExactMatch) {
+ if (!areParametersAssignable(methodBinding.parameters, argumentTypes)) {
+ 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);
+ }
+ }
+ if (fuzzyProblem == null && !methodBinding.isStatic()) {
+ if (insideConstructorCall) {
+ insideProblem =
+ new ProblemMethodBinding(
+ methodBinding, // closest match
+ methodBinding.selector,
+ methodBinding.parameters,
+ NonStaticReferenceInConstructorInvocation);
+ } else if (insideStaticContext) {
+ insideProblem =
+ new ProblemMethodBinding(
+ methodBinding, // closest match
+ methodBinding.selector,
+ methodBinding.parameters,
+ NonStaticReferenceInStaticContext);
+ }
+ }
+
+ if (receiverType == methodBinding.declaringClass
+ || (receiverType.getMethods(selector)) != NoMethods
+ || ((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) {
+ if (depth > 0){
+ invocationSite.setDepth(depth);
+ invocationSite.setActualReceiverType(receiverType);
+ }
+ // return the methodBinding if it is not declared in a superclass of the scope's binding (that is, inherited)
+ if (fuzzyProblem != null)
+ return fuzzyProblem;
+ if (insideProblem != null)
+ return insideProblem;
+ return methodBinding;
+ }
+ // if a method was found, complain when another is found in an 'immediate' enclosing type (that is, not inherited)
+ // NOTE: Unlike fields, a non visible method hides a visible method
+ if (foundMethod.declaringClass != methodBinding.declaringClass)
+ // ie. have we found the same method - do not trust field identity yet
+ return new ProblemMethodBinding(
+ methodBinding, // closest match
+ methodBinding.selector,
+ methodBinding.parameters,
+ InheritedNameHidesEnclosingName);
+ }
+ }
+
+ 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){
+ invocationSite.setDepth(depth);
+ invocationSite.setActualReceiverType(receiverType);
+ }
+ foundFuzzyProblem = fuzzyProblem;
+ foundInsideProblem = insideProblem;
+ if (fuzzyProblem == null)
+ foundMethod = methodBinding; // only keep it if no error was found
+ }
+ }
+ depth++;
+ insideStaticContext |= receiverType.isStatic();
+ // 1EX5I8Z - accessing outer fields within a constructor call is permitted
+ // in order to do so, we change the flag as we exit from the type, not the method
+ // itself, because the class scope is used to retrieve the fields.
+ MethodScope enclosingMethodScope = scope.methodScope();
+ insideConstructorCall =
+ enclosingMethodScope == null ? false : enclosingMethodScope.isConstructorCall;
+ break;
+ case COMPILATION_UNIT_SCOPE :
+ break done;
+ }
+ scope = scope.parent;
+ }
+
+ if (foundFuzzyProblem != null)
+ return foundFuzzyProblem;
+ if (foundInsideProblem != null)
+ return foundInsideProblem;
+ if (foundMethod != null)
+ return foundMethod;
+ return new ProblemMethodBinding(selector, argumentTypes, NotFound);
+ }
+
+ public final ReferenceBinding getJavaIoSerializable() {
+ compilationUnitScope().recordQualifiedReference(JAVA_IO_SERIALIZABLE);
+ ReferenceBinding type = environment().getType(JAVA_IO_SERIALIZABLE);
+ if (type != null) return type;
+
+ problemReporter().isClassPathCorrect(JAVA_IO_SERIALIZABLE, 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);
+ if (type != null) return type;
+ problemReporter().isClassPathCorrect(JAVA_LANG_ASSERTIONERROR, referenceCompilationUnit());
+ return null; // will not get here since the above error aborts the compilation
+ }
+
+ public final ReferenceBinding getJavaLangClass() {
+ compilationUnitScope().recordQualifiedReference(JAVA_LANG_CLASS);
+ ReferenceBinding type = environment().getType(JAVA_LANG_CLASS);
+ if (type != null) return type;
+
+ problemReporter().isClassPathCorrect(JAVA_LANG_CLASS, referenceCompilationUnit());
+ return null; // will not get here since the above error aborts the compilation
+ }
+
+ public final ReferenceBinding getJavaLangCloneable() {
+ compilationUnitScope().recordQualifiedReference(JAVA_LANG_CLONEABLE);
+ ReferenceBinding type = environment().getType(JAVA_LANG_CLONEABLE);
+ if (type != null) return type;
+
+ problemReporter().isClassPathCorrect(JAVA_LANG_CLONEABLE, 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);
+ if (type != null) return type;
+
+ problemReporter().isClassPathCorrect(JAVA_LANG_ERROR, 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);
+ if (type != null) return type;
+
+ problemReporter().isClassPathCorrect(JAVA_LANG_OBJECT, referenceCompilationUnit());
+ return null; // will not get here since the above error aborts the compilation
+ }
+
+ public final ReferenceBinding getJavaLangRuntimeException() {
+ compilationUnitScope().recordQualifiedReference(JAVA_LANG_RUNTIMEEXCEPTION);
+ ReferenceBinding type = environment().getType(JAVA_LANG_RUNTIMEEXCEPTION);
+ if (type != null) return type;
+
+ problemReporter().isClassPathCorrect(JAVA_LANG_RUNTIMEEXCEPTION, referenceCompilationUnit());
+ return null; // will not get here since the above error aborts the compilation
+ }
+
+ public final ReferenceBinding getJavaLangString() {
+ compilationUnitScope().recordQualifiedReference(JAVA_LANG_STRING);
+ ReferenceBinding type = environment().getType(JAVA_LANG_STRING);
+ if (type != null) return type;
+
+ problemReporter().isClassPathCorrect(JAVA_LANG_STRING, referenceCompilationUnit());
+ return null; // will not get here since the above error aborts the compilation
+ }
+
+ public final ReferenceBinding getJavaLangThrowable() {
+ compilationUnitScope().recordQualifiedReference(JAVA_LANG_THROWABLE);
+ ReferenceBinding type = environment().getType(JAVA_LANG_THROWABLE);
+ if (type != null) return type;
+
+ problemReporter().isClassPathCorrect(JAVA_LANG_THROWABLE, referenceCompilationUnit());
+ return null; // will not get here since the above error aborts the compilation
+ }
+
+ /* Answer the type binding corresponding to the typeName argument, relative to the enclosingType.
+ */
+ public final ReferenceBinding getMemberType(char[] typeName, ReferenceBinding enclosingType) {
+ ReferenceBinding memberType = findMemberType(typeName, enclosingType);
+ if (memberType != null) return memberType;
+ return new ProblemReferenceBinding(typeName, NotFound);
+ }
+
+ 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);
+
+ ReferenceBinding currentType = (ReferenceBinding) receiverType;
+ if (!currentType.canBeSeenBy(this))
+ return new ProblemMethodBinding(selector, argumentTypes, ReceiverTypeNotVisible);
+
+ // retrieve an exact visible match (if possible)
+ MethodBinding methodBinding = findExactMethod(currentType, selector, argumentTypes, invocationSite);
+ if (methodBinding != null) return methodBinding;
+
+ // 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);
+ if (!methodBinding.canBeSeenBy(currentType, invocationSite, this))
+ return new ProblemMethodBinding(
+ methodBinding,
+ selector,
+ methodBinding.parameters,
+ NotVisible);
+ }
+ return methodBinding;
+
+ } catch (AbortCompilation e) {
+ e.updateContext(invocationSite, referenceCompilationUnit().compilationResult);
+ throw e;
+ }
+ }
+
+ /* Answer the type binding that corresponds the given name, starting the lookup in the receiver.
+ * The name provided is a simple source name (e.g., "Object" , "Point", ...)
+ */
+ // The return type of this method could be ReferenceBinding if we did not answer base types.
+ // NOTE: We could support looking for Base Types last in the search, however any code using
+ // this feature would be extraordinarily slow. Therefore we don't do this
+ public final TypeBinding getType(char[] name) {
+ // Would like to remove this test and require senders to specially handle base types
+ TypeBinding binding = getBaseType(name);
+ if (binding != null) return binding;
+ return (ReferenceBinding) getTypeOrPackage(name, TYPE);
+ }
+
+ /* Answer the type binding corresponding to the compoundName.
+ *
+ * NOTE: If a problem binding is returned, senders should extract the compound name
+ * from the binding & not assume the problem applies to the entire compoundName.
+ */
+ public final TypeBinding getType(char[][] compoundName) {
+ int typeNameLength = compoundName.length;
+ if (typeNameLength == 1) {
+ // Would like to remove this test and require senders to specially handle base types
+ TypeBinding binding = getBaseType(compoundName[0]);
+ if (binding != null) return binding;
+ }
+
+ compilationUnitScope().recordQualifiedReference(compoundName);
+ Binding binding =
+ getTypeOrPackage(compoundName[0], typeNameLength == 1 ? TYPE : TYPE | PACKAGE);
+ if (binding == null)
+ return new ProblemReferenceBinding(compoundName[0], NotFound);
+ if (!binding.isValidBinding())
+ return (ReferenceBinding) binding;
+
+ int currentIndex = 1;
+ boolean checkVisibility = false;
+ if (binding instanceof PackageBinding) {
+ PackageBinding packageBinding = (PackageBinding) binding;
+ while (currentIndex < typeNameLength) {
+ binding = packageBinding.getTypeOrPackage(compoundName[currentIndex++]); // does not check visibility
+ if (binding == null)
+ return new ProblemReferenceBinding(
+ CharOperation.subarray(compoundName, 0, currentIndex),
+ NotFound);
+ if (!binding.isValidBinding())
+ return new ProblemReferenceBinding(
+ CharOperation.subarray(compoundName, 0, currentIndex),
+ binding.problemId());
+ if (!(binding instanceof PackageBinding))
+ break;
+ packageBinding = (PackageBinding) binding;
+ }
+ if (binding instanceof PackageBinding)
+ return new ProblemReferenceBinding(
+ CharOperation.subarray(compoundName, 0, currentIndex),
+ NotFound);
+ checkVisibility = true;
+ }
+
+ // binding is now a ReferenceBinding
+ ReferenceBinding typeBinding = (ReferenceBinding) binding;
+ compilationUnitScope().recordTypeReference(typeBinding); // to record supertypes
+ if (checkVisibility) // handles the fall through case
+ if (!typeBinding.canBeSeenBy(this))
+ return new ProblemReferenceBinding(
+ CharOperation.subarray(compoundName, 0, currentIndex),
+ typeBinding,
+ NotVisible);
+
+ while (currentIndex < typeNameLength) {
+ typeBinding = getMemberType(compoundName[currentIndex++], typeBinding);
+ if (!typeBinding.isValidBinding()) {
+ if (typeBinding instanceof ProblemReferenceBinding) {
+ ProblemReferenceBinding problemBinding = (ProblemReferenceBinding) typeBinding;
+ return new ProblemReferenceBinding(
+ CharOperation.subarray(compoundName, 0, currentIndex),
+ problemBinding.original,
+ typeBinding.problemId());
+ }
+ return new ProblemReferenceBinding(
+ CharOperation.subarray(compoundName, 0, currentIndex),
+ typeBinding.problemId());
+ }
+ }
+ return typeBinding;
+ }
+
+ /* Internal use only
+ */
+ final Binding getTypeOrPackage(char[] name, int mask) {
+ Scope scope = this;
+ ReferenceBinding foundType = null;
+ if ((mask & TYPE) == 0) {
+ Scope next = scope;
+ while ((next = scope.parent) != null)
+ scope = next;
+ } else {
+ done : while (true) { // done when a COMPILATION_UNIT_SCOPE is found
+ switch (scope.kind) {
+ case METHOD_SCOPE :
+ case BLOCK_SCOPE :
+ ReferenceBinding localType = ((BlockScope) scope).findLocalType(name); // looks in this scope only
+ if (localType != null) {
+ if (foundType != null && foundType != localType)
+ return new ProblemReferenceBinding(name, InheritedNameHidesEnclosingName);
+ return localType;
+ }
+ break;
+ case CLASS_SCOPE :
+ SourceTypeBinding sourceType = ((ClassScope) scope).referenceContext.binding;
+ // 6.5.5.1 - simple name favors member type 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) {
+ if (foundType == null || foundType.problemId() == NotVisible)
+ // supercedes any potential InheritedNameHidesEnclosingName problem
+ return memberType;
+ // make the user qualify the type, likely wants the first inherited type
+ return new ProblemReferenceBinding(name, InheritedNameHidesEnclosingName);
+ }
+ if (memberType.isValidBinding()) {
+ if (sourceType == memberType.enclosingType()
+ || environment().options.complianceLevel >= ClassFileConstants.JDK1_4) {
+ // found a valid type in the 'immediate' scope (ie. not inherited)
+ // 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 (foundType == null || (foundType.problemId() == NotVisible && memberType.problemId() != NotVisible))
+ // only remember the memberType if its the first one found or the previous one was not visible & memberType is...
+ foundType = memberType;
+ }
+ if (CharOperation.equals(sourceType.sourceName, name)) {
+ if (foundType != null && foundType != sourceType && foundType.problemId() != NotVisible)
+ return new ProblemReferenceBinding(name, InheritedNameHidesEnclosingName);
+ return sourceType;
+ }
+ break;
+ case COMPILATION_UNIT_SCOPE :
+ break done;
+ }
+ scope = scope.parent;
+ }
+ if (foundType != null && foundType.problemId() != NotVisible)
+ return foundType;
+ }
+
+ // at this point the scope is a compilation unit scope
+ CompilationUnitScope unitScope = (CompilationUnitScope) scope;
+ PackageBinding currentPackage = unitScope.fPackage;
+ // ask for the imports + name
+ if ((mask & TYPE) != 0) {
+ // check single type imports.
+
+ ImportBinding[] imports = unitScope.imports;
+ if (imports != null) {
+ HashtableOfObject typeImports = unitScope.resolvedSingeTypeImports;
+ if (typeImports != null) {
+ ImportBinding typeImport = (ImportBinding) typeImports.get(name);
+ if (typeImport != null) {
+ ImportReference importReference = typeImport.reference;
+ if (importReference != null) importReference.used = true;
+ return typeImport.resolvedImport; // already know its visible
+ }
+ } else {
+ // walk all the imports since resolvedSingeTypeImports is not yet initialized
+ for (int i = 0, length = imports.length; i < length; i++) {
+ ImportBinding typeImport = imports[i];
+ if (!typeImport.onDemand) {
+ if (CharOperation.equals(typeImport.compoundName[typeImport.compoundName.length - 1], name)) {
+ if (unitScope.resolveSingleTypeImport(typeImport) != null) {
+ ImportReference importReference = typeImport.reference;
+ if (importReference != null) importReference.used = true;
+ return typeImport.resolvedImport; // already know its visible
+ }
+ }
+ }
+ }
+ }
+ }
+ // check if the name is in the current package, skip it if its a sub-package
+ unitScope.recordReference(currentPackage.compoundName, name);
+ Binding binding = currentPackage.getTypeOrPackage(name);
+ if (binding instanceof ReferenceBinding) return binding; // type is always visible to its own package
+
+ // check on demand imports
+ if (imports != null) {
+ boolean foundInImport = false;
+ ReferenceBinding type = null;
+ for (int i = 0, length = imports.length; i < length; i++) {
+ ImportBinding someImport = imports[i];
+ if (someImport.onDemand) {
+ Binding resolvedImport = someImport.resolvedImport;
+ ReferenceBinding temp = resolvedImport instanceof PackageBinding
+ ? findType(name, (PackageBinding) resolvedImport, currentPackage)
+ : findDirectMemberType(name, (ReferenceBinding) resolvedImport);
+ if (temp != null) {
+ if (temp.isValidBinding()) {
+ ImportReference importReference = someImport.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);
+ type = temp;
+ foundInImport = true;
+ } else if (foundType == null) {
+ foundType = temp;
+ }
+ }
+ }
+ }
+ if (type != null) return type;
+ }
+ }
+
+ unitScope.recordSimpleReference(name);
+ if ((mask & PACKAGE) != 0) {
+ PackageBinding packageBinding = unitScope.environment.getTopLevelPackage(name);
+ if (packageBinding != null) return packageBinding;
+ }
+
+ // Answer error binding -- could not find name
+ if (foundType != null) return foundType; // problem type from above
+ return new ProblemReferenceBinding(name, NotFound);
+ }
+
+ // Added for code assist... NOT Public API
+ public final Binding getTypeOrPackage(char[][] compoundName) {
+ int nameLength = compoundName.length;
+ if (nameLength == 1) {
+ TypeBinding binding = getBaseType(compoundName[0]);
+ if (binding != null) return binding;
+ }
+ Binding binding = getTypeOrPackage(compoundName[0], TYPE | PACKAGE);
+ if (!binding.isValidBinding()) return binding;
+
+ int currentIndex = 1;
+ boolean checkVisibility = false;
+ if (binding instanceof PackageBinding) {
+ PackageBinding packageBinding = (PackageBinding) binding;
+
+ while (currentIndex < nameLength) {
+ binding = packageBinding.getTypeOrPackage(compoundName[currentIndex++]);
+ if (binding == null)
+ return new ProblemReferenceBinding(
+ CharOperation.subarray(compoundName, 0, currentIndex),
+ NotFound);
+ if (!binding.isValidBinding())
+ return new ProblemReferenceBinding(
+ CharOperation.subarray(compoundName, 0, currentIndex),
+ binding.problemId());
+ if (!(binding instanceof PackageBinding))
+ break;
+ packageBinding = (PackageBinding) binding;
+ }
+ if (binding instanceof PackageBinding) return binding;
+ checkVisibility = true;
+ }
+ // binding is now a ReferenceBinding
+ ReferenceBinding typeBinding = (ReferenceBinding) binding;
+ if (checkVisibility) // handles the fall through case
+ if (!typeBinding.canBeSeenBy(this))
+ return new ProblemReferenceBinding(
+ CharOperation.subarray(compoundName, 0, currentIndex),
+ typeBinding,
+ NotVisible);
+
+ while (currentIndex < nameLength) {
+ typeBinding = getMemberType(compoundName[currentIndex++], typeBinding);
+ // checks visibility
+ if (!typeBinding.isValidBinding())
+ return new ProblemReferenceBinding(
+ CharOperation.subarray(compoundName, 0, currentIndex),
+ typeBinding.problemId());
+ }
+ return typeBinding;
+ }
+
+ /* 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.
+ */
+ public final boolean isDefinedInField(FieldBinding field) {
+ Scope scope = this;
+ do {
+ if (scope instanceof MethodScope) {
+ MethodScope methodScope = (MethodScope) scope;
+ if (methodScope.initializedField == field) return true;
+ }
+ scope = scope.parent;
+ } while (scope != null);
+ return false;
+ }
+
+ /* Answer true if the scope is nested inside a given method declaration
+ */
+ public final boolean isDefinedInMethod(MethodBinding method) {
+ Scope scope = this;
+ do {
+ if (scope instanceof MethodScope) {
+ ReferenceContext refContext = ((MethodScope) scope).referenceContext;
+ if (refContext instanceof AbstractMethodDeclaration
+ && ((AbstractMethodDeclaration)refContext).binding == method) {
+ return true;
+ }
+ }
+ scope = scope.parent;
+ } while (scope != null);
+ return false;
+ }
+
+ /* Answer whether the type is defined in the same compilation unit as the receiver
+ */
+ public final boolean isDefinedInSameUnit(ReferenceBinding type) {
+ // find the outer most enclosing type
+ ReferenceBinding enclosingType = type;
+ while ((type = enclosingType.enclosingType()) != null)
+ enclosingType = type;
+
+ // find the compilation unit scope
+ Scope scope, unitScope = this;
+ while ((scope = unitScope.parent) != null)
+ unitScope = scope;
+
+ // test that the enclosingType is not part of the compilation unit
+ SourceTypeBinding[] topLevelTypes =
+ ((CompilationUnitScope) unitScope).topLevelTypes;
+ for (int i = topLevelTypes.length; --i >= 0;)
+ if (topLevelTypes[i] == enclosingType)
+ return true;
+ return false;
+ }
+
+ /* Answer true if the scope is nested inside a given type declaration
+ */
+ public final boolean isDefinedInType(ReferenceBinding type) {
+ Scope scope = this;
+ do {
+ if (scope instanceof ClassScope)
+ if (((ClassScope) scope).referenceContext.binding == type){
+ return true;
+ }
+ scope = scope.parent;
+ } while (scope != null);
+ return false;
+ }
+
+ public boolean isInsideDeprecatedCode(){
+ switch(this.kind){
+ case Scope.BLOCK_SCOPE :
+ case Scope.METHOD_SCOPE :
+ MethodScope methodScope = methodScope();
+ if (!methodScope.isInsideInitializer()){
+ // check method modifiers to see if deprecated
+ MethodBinding context = ((AbstractMethodDeclaration)methodScope.referenceContext).binding;
+ 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()) {
+ return true;
+ }
+ if (type != null && type.isViewedAsDeprecated()) {
+ return true;
+ }
+ }
+ break;
+ case Scope.CLASS_SCOPE :
+ ReferenceBinding context = ((ClassScope)this).referenceType().binding;
+ if (context != null && context.isViewedAsDeprecated()) {
+ return true;
+ }
+ break;
+ }
+ return false;
+ }
+
+ public final MethodScope methodScope() {
+ Scope scope = this;
+ do {
+ if (scope instanceof MethodScope)
+ return (MethodScope) scope;
+ scope = scope.parent;
+ } while (scope != null);
+ return null;
+ }
+
+ // Internal use only
+ /* All methods in visible are acceptable matches for the method in question...
+ * The methods defined by the receiver type appear before those defined by its
+ * superclass and so on. We want to find the one which matches best.
+ *
+ * Since the receiver type is a class, we know each method's declaring class is
+ * either the receiver type or one of its superclasses. It is an error if the best match
+ * is defined by a superclass, when a lesser match is defined by the receiver type
+ * or a closer superclass.
+ */
+ protected final MethodBinding mostSpecificClassMethodBinding(MethodBinding[] visible, int visibleSize) {
+
+ MethodBinding method = null;
+ MethodBinding previous = null;
+
+ nextVisible : for (int i = 0; i < visibleSize; i++) {
+ method = visible[i];
+
+ if (previous != null && method.declaringClass != previous.declaringClass)
+ break; // cannot answer a method farther up the hierarchy than the first method found
+ 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))
+ continue nextVisible;
+ }
+ compilationUnitScope().recordTypeReferences(method.thrownExceptions);
+ return method;
+ }
+ return new ProblemMethodBinding(visible[0].selector, visible[0].parameters, Ambiguous);
+ }
+
+ // Internal use only
+ /* All methods in visible are acceptable matches for the method in question...
+ * Since the receiver type is an interface, we ignore the possibility that 2 inherited
+ * but unrelated superinterfaces may define the same method in acceptable but
+ * not identical ways... we just take the best match that we find since any class which
+ * implements the receiver interface MUST implement all signatures for the method...
+ * in which case the best match is correct.
+ *
+ * NOTE: This is different than javac... in the following example, the message send of
+ * bar(X) in class Y is supposed to be ambiguous. But any class which implements the
+ * interface I MUST implement both signatures for bar. If this class was the receiver of
+ * the message send instead of the interface I, then no problem would be reported.
+ *
+ interface I1 {
+ void bar(J j);
+ }
+ interface I2 {
+ // void bar(J j);
+ void bar(Object o);
+ }
+ interface I extends I1, I2 {}
+ interface J {}
+
+ class X implements J {}
+
+ class Y extends X {
+ public void foo(I i, X x) { i.bar(x); }
+ }
+ */
+ protected final MethodBinding mostSpecificInterfaceMethodBinding(MethodBinding[] visible, int visibleSize) {
+ MethodBinding method = null;
+ nextVisible : for (int i = 0; i < visibleSize; i++) {
+ method = visible[i];
+ for (int j = 0; j < visibleSize; j++) {
+ if (i == j) continue;
+ MethodBinding next = visible[j];
+ if (!areParametersAssignable(next.parameters, method.parameters))
+ continue nextVisible;
+ }
+ compilationUnitScope().recordTypeReferences(method.thrownExceptions);
+ return method;
+ }
+ return new ProblemMethodBinding(visible[0].selector, visible[0].parameters, Ambiguous);
+ }
+
+
+ // Internal use only
+ /* All methods in visible are acceptable matches for the method in question...
+ * Since 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;
+ }
+ compilationUnitScope().recordTypeReferences(method.thrownExceptions);
+ return method;
+ }
+ return new ProblemMethodBinding(visible[0].selector, visible[0].parameters, Ambiguous);
+ }
+
+ public final ClassScope outerMostClassScope() {
+ ClassScope lastClassScope = null;
+ Scope scope = this;
+ do {
+ if (scope instanceof ClassScope)
+ lastClassScope = (ClassScope) scope;
+ scope = scope.parent;
+ } while (scope != null);
+ return lastClassScope; // may answer null if no class around
+ }
+
+ public final MethodScope outerMostMethodScope() {
+ MethodScope lastMethodScope = null;
+ Scope scope = this;
+ do {
+ if (scope instanceof MethodScope)
+ lastMethodScope = (MethodScope) scope;
+ scope = scope.parent;
+ } while (scope != null);
+ return lastMethodScope; // may answer null if no method around
+ }
+
+ public abstract ProblemReporter problemReporter();
+
+ public final CompilationUnitDeclaration referenceCompilationUnit() {
+ Scope scope, unitScope = this;
+ while ((scope = unitScope.parent) != null)
+ unitScope = scope;
+ return ((CompilationUnitScope) unitScope).referenceContext;
+ }
+ // start position in this scope - for ordering scopes vs. variables
+ int startIndex() {
+ return 0;
+ }
+
+ /**
+ * Returns the immediately enclosing switchCase statement (carried by closest blockScope),
+ */
+ public CaseStatement switchCase() {
+ Scope scope = this;
+ do {
+ if (scope instanceof BlockScope)
+ return ((BlockScope) scope).switchCase;
+ scope = scope.parent;
+ } while (scope != null);
+ return null;
+ }
+}