totally new file layout
[org.ibex.tool.git] / repo / org.ibex.tool / src / org / eclipse / jdt / internal / compiler / lookup / Scope.java
diff --git a/repo/org.ibex.tool/src/org/eclipse/jdt/internal/compiler/lookup/Scope.java b/repo/org.ibex.tool/src/org/eclipse/jdt/internal/compiler/lookup/Scope.java
new file mode 100644 (file)
index 0000000..bfbb0b5
--- /dev/null
@@ -0,0 +1,2000 @@
+/*******************************************************************************
+ * 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;
+       }
+}