Index: compiler/org/eclipse/jdt/internal/compiler/lookup/Scope.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/Scope.java,v retrieving revision 1.299 diff -u -r1.299 Scope.java --- compiler/org/eclipse/jdt/internal/compiler/lookup/Scope.java 29 Jan 2007 07:37:02 -0000 1.299 +++ compiler/org/eclipse/jdt/internal/compiler/lookup/Scope.java 2 Mar 2007 21:52:21 -0000 @@ -1035,16 +1035,17 @@ // Internal use only - use findMethod() public MethodBinding findMethod(ReferenceBinding receiverType, char[] selector, TypeBinding[] argumentTypes, InvocationSite invocationSite) { ReferenceBinding currentType = receiverType; + boolean receiverTypeIsInterface = receiverType.isInterface(); ObjectVector found = new ObjectVector(3); CompilationUnitScope unitScope = compilationUnitScope(); unitScope.recordTypeReferences(argumentTypes); - if (currentType.isInterface()) { - unitScope.recordTypeReference(currentType); - MethodBinding[] currentMethods = currentType.getMethods(selector); - if (currentMethods.length > 0) - found.addAll(currentMethods); - findMethodInSuperInterfaces(currentType, selector, found); + if (receiverTypeIsInterface) { + unitScope.recordTypeReference(receiverType); + MethodBinding[] receiverMethods = receiverType.getMethods(selector); + if (receiverMethods.length > 0) + found.addAll(receiverMethods); + findMethodInSuperInterfaces(receiverType, selector, found); currentType = getJavaLangObject(); } @@ -1053,17 +1054,16 @@ boolean isCompliant14 = complianceLevel >= ClassFileConstants.JDK1_4; boolean isCompliant15 = complianceLevel >= ClassFileConstants.JDK1_5; ReferenceBinding classHierarchyStart = currentType; - boolean mustBePublic = receiverType.isInterface(); while (currentType != null) { unitScope.recordTypeReference(currentType); MethodBinding[] currentMethods = currentType.getMethods(selector); int currentLength = currentMethods.length; if (currentLength > 0) { - if (isCompliant14 && (mustBePublic || found.size > 0)) { + if (isCompliant14 && (receiverTypeIsInterface || found.size > 0)) { nextMethod: for (int i = 0, l = currentLength; i < l; i++) { // currentLength can be modified inside the loop MethodBinding currentMethod = currentMethods[i]; if (currentMethod == null) continue nextMethod; - if (mustBePublic && !currentMethod.isPublic()) { // only public methods from Object are visible to interface receiverTypes + if (receiverTypeIsInterface && !currentMethod.isPublic()) { // only public methods from Object are visible to interface receiverTypes currentLength--; currentMethods[i] = null; continue nextMethod; @@ -1109,6 +1109,18 @@ currentType = currentType.superclass(); } + boolean addInterfaceMethods = isCompliant14 && !receiverTypeIsInterface && classHierarchyStart.isAbstract() || classHierarchyStart.isTypeVariable(); + if (addInterfaceMethods) { + // add interface methods to found + // cannot be done until all matching methods in class hierarchy have been found + // an interface method cannot prevent a concrete method from being considered as a match + currentType = receiverType; + while (currentType != null) { + findMethodInSuperInterfaces(currentType, selector, found); + currentType = currentType.superclass(); + } + } + // if found several candidates, then eliminate those not matching argument types int foundSize = found.size; MethodBinding[] candidates = null; @@ -1123,9 +1135,6 @@ if (compatibleMethod.isValidBinding()) { if (foundSize == 1 && compatibleMethod.canBeSeenBy(receiverType, invocationSite, this)) { // return the single visible match now - if (isCompliant14 && (receiverType.isAbstract() || receiverType.isTypeVariable())) - return findDefaultAbstractMethod(receiverType, selector, argumentTypes, invocationSite, classHierarchyStart, found, compatibleMethod); - unitScope.recordTypeReferences(compatibleMethod.thrownExceptions); return compatibleMethod; } if (candidatesCount == 0) @@ -1138,15 +1147,22 @@ } } - // no match was found, try to find a close match when the parameter order is wrong or missing some parameters + // no match was found if (candidatesCount == 0) { - // reduces secondary errors since missing interface method error is already reported - MethodBinding interfaceMethod = - findDefaultAbstractMethod(receiverType, selector, argumentTypes, invocationSite, classHierarchyStart, found, null); - if (interfaceMethod != null) return interfaceMethod; + // abstract classes may get a match in interfaces; for non abstract classes + // reduces secondary errors since missing interface method + // error is already reported + if (!addInterfaceMethods) { + MethodBinding interfaceMethod = + findDefaultAbstractMethod(receiverType, selector, argumentTypes, invocationSite, classHierarchyStart, found, null); + if (interfaceMethod != null) return interfaceMethod; + } if (found.size == 0) return null; if (problemMethod != null) return problemMethod; + // still no match; try to find a close match when the parameter + // order is wrong or missing some parameters + // see https://bugs.eclipse.org/bugs/show_bug.cgi?id=69471 // bad guesses are foo(), when argument types have been supplied // and foo(X, Y), when the argument types are (int, float, Y) @@ -1186,27 +1202,35 @@ // 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) { - if (isCompliant14 && (receiverType.isAbstract() || receiverType.isTypeVariable())) - return findDefaultAbstractMethod(receiverType, selector, argumentTypes, invocationSite, classHierarchyStart, found, candidates[0]); - unitScope.recordTypeReferences(candidates[0].thrownExceptions); - return candidates[0]; - } - if (visiblesCount == 0) { - MethodBinding interfaceMethod = - findDefaultAbstractMethod(receiverType, selector, argumentTypes, invocationSite, classHierarchyStart, found, null); - if (interfaceMethod != null) return interfaceMethod; - return new ProblemMethodBinding(candidates[0], candidates[0].selector, candidates[0].parameters, ProblemReasons.NotVisible); + if (receiverTypeIsInterface) { + if (candidatesCount == 1) { + unitScope.recordTypeReferences(candidates[0].thrownExceptions); + return candidates[0]; + } + visiblesCount = candidatesCount; + } else { + 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) { + unitScope.recordTypeReferences(candidates[0].thrownExceptions); + return candidates[0]; + } + if (visiblesCount == 0) { + if (!addInterfaceMethods) { + MethodBinding interfaceMethod = + findDefaultAbstractMethod(receiverType, selector, argumentTypes, invocationSite, classHierarchyStart, found, null); + if (interfaceMethod != null) return interfaceMethod; + } + return new ProblemMethodBinding(candidates[0], candidates[0].selector, candidates[0].parameters, ProblemReasons.NotVisible); + } } if (complianceLevel <= ClassFileConstants.JDK1_3) { @@ -1229,14 +1253,7 @@ } } - MethodBinding mostSpecificMethod = mostSpecificMethodBinding(candidates, visiblesCount, argumentTypes, invocationSite, receiverType); - if (isCompliant15 - && mostSpecificMethod.isValidBinding() - && parameterCompatibilityLevel(mostSpecificMethod, argumentTypes) > COMPATIBLE) { - // see if there is a better match in the interfaces - see AutoBoxingTest 99 - return findDefaultAbstractMethod(receiverType, selector, argumentTypes, invocationSite, classHierarchyStart, found, mostSpecificMethod); - } - return mostSpecificMethod; + return mostSpecificMethodBinding(candidates, visiblesCount, argumentTypes, invocationSite, receiverType); } // Internal use only @@ -1295,8 +1312,20 @@ currentType = interfacesToVisit[i]; compilationUnitScope().recordTypeReference(currentType); MethodBinding[] currentMethods = currentType.getMethods(selector); - if (currentMethods.length > 0) - found.addAll(currentMethods); + if (currentMethods.length > 0) { + int foundSize = found.size; + if (foundSize > 0) { + // its possible to walk the same superinterface from different classes in the hierarchy + next : for (int c = 0, l = currentMethods.length; c < l; c++) { + MethodBinding current = currentMethods[c]; + for (int f = 0; f < foundSize; f++) + if (current == found.elementAt(f)) continue next; + found.add(current); + } + } else { + found.addAll(currentMethods); + } + } if ((itsInterfaces = currentType.superInterfaces()) != null && itsInterfaces != Binding.NO_SUPERINTERFACES) { int itsLength = itsInterfaces.length; if (nextPosition + itsLength >= interfacesToVisit.length)