Example usage for org.eclipse.jdt.internal.compiler.lookup MethodBinding isValidBinding

List of usage examples for org.eclipse.jdt.internal.compiler.lookup MethodBinding isValidBinding

Introduction

In this page you can find the example usage for org.eclipse.jdt.internal.compiler.lookup MethodBinding isValidBinding.

Prototype

public final boolean isValidBinding() 

Source Link

Usage

From source file:com.codenvy.ide.ext.java.server.internal.core.search.matching.MethodLocator.java

License:Open Source License

protected int matchMethod(MethodBinding method, boolean skipImpossibleArg) {
    if (!matchesName(this.pattern.selector, method.selector))
        return IMPOSSIBLE_MATCH;

    int level = ACCURATE_MATCH;
    // look at return type only if declaring type is not specified
    if (this.pattern.declaringSimpleName == null) {
        // TODO (frederic) use this call to refine accuracy on return type
        // int newLevel = resolveLevelForType(this.pattern.returnSimpleName, this.pattern.returnQualification, this.pattern.returnTypeArguments, 0, method.returnType);
        int newLevel = resolveLevelForType(this.pattern.returnSimpleName, this.pattern.returnQualification,
                method.returnType);//from   w  w w  .j a va  2s  . c om
        if (level > newLevel) {
            if (newLevel == IMPOSSIBLE_MATCH)
                return IMPOSSIBLE_MATCH;
            level = newLevel; // can only be downgraded
        }
    }

    // parameter types
    int parameterCount = this.pattern.parameterSimpleNames == null ? -1
            : this.pattern.parameterSimpleNames.length;
    if (parameterCount > -1) {
        // global verification
        if (method.parameters == null)
            return INACCURATE_MATCH;
        if (parameterCount != method.parameters.length)
            return IMPOSSIBLE_MATCH;
        if (!method.isValidBinding()
                && ((ProblemMethodBinding) method).problemId() == ProblemReasons.Ambiguous) {
            // return inaccurate match for ambiguous call (bug 80890)
            return INACCURATE_MATCH;
        }
        boolean foundTypeVariable = false;
        // verify each parameter
        for (int i = 0; i < parameterCount; i++) {
            TypeBinding argType = method.parameters[i];
            int newLevel = IMPOSSIBLE_MATCH;
            if (argType.isMemberType()) {
                // only compare source name for member type (bug 41018)
                newLevel = CharOperation.match(this.pattern.parameterSimpleNames[i], argType.sourceName(),
                        this.isCaseSensitive) ? ACCURATE_MATCH : IMPOSSIBLE_MATCH;
            } else {
                // TODO (frederic) use this call to refine accuracy on parameter types
                //             newLevel = resolveLevelForType(this.pattern.parameterSimpleNames[i], this.pattern.parameterQualifications[i], this.pattern.parametersTypeArguments[i], 0, argType);
                newLevel = resolveLevelForType(this.pattern.parameterSimpleNames[i],
                        this.pattern.parameterQualifications[i], argType);
            }
            if (level > newLevel) {
                if (newLevel == IMPOSSIBLE_MATCH) {
                    if (skipImpossibleArg) {
                        // Do not consider match as impossible while finding declarations and source level >= 1.5
                        // (see  bugs https://bugs.eclipse.org/bugs/show_bug.cgi?id=79990, 96761, 96763)
                        newLevel = level;
                    } else if (argType.isTypeVariable()) {
                        newLevel = level;
                        foundTypeVariable = true;
                    } else {
                        return IMPOSSIBLE_MATCH;
                    }
                }
                level = newLevel; // can only be downgraded
            }
        }
        if (foundTypeVariable) {
            if (!method.isStatic() && !method.isPrivate()) {
                // https://bugs.eclipse.org/bugs/show_bug.cgi?id=123836, No point in textually comparing type variables, captures etc with concrete types.
                MethodBinding focusMethodBinding = this.matchLocator.getMethodBinding(this.pattern);
                if (focusMethodBinding != null) {
                    if (matchOverriddenMethod(focusMethodBinding.declaringClass, focusMethodBinding, method)) {
                        return ACCURATE_MATCH;
                    }
                }
            }
            return IMPOSSIBLE_MATCH;
        }
    }

    return level;
}

From source file:org.eclipse.che.jdt.internal.core.search.indexing.SourceIndexer.java

License:Open Source License

public void indexResolvedDocument() {
    try {/*from   ww  w  .j a va2 s.  co  m*/
        if (DEBUG)
            System.out.println(new String(this.cud.compilationResult.fileName) + ':');
        for (int i = 0, length = this.cud.functionalExpressionsCount; i < length; i++) {
            FunctionalExpression expression = this.cud.functionalExpressions[i];
            if (expression instanceof LambdaExpression) {
                LambdaExpression lambdaExpression = (LambdaExpression) expression;
                if (lambdaExpression.binding != null && lambdaExpression.binding.isValidBinding()) {
                    final char[] superinterface = lambdaExpression.resolvedType.sourceName();
                    if (DEBUG) {
                        System.out.println('\t' + new String(superinterface) + '.'
                                + new String(lambdaExpression.descriptor.selector) + "-> {}"); //$NON-NLS-1$
                    }
                    SourceIndexer.this.addIndexEntry(IIndexConstants.METHOD_DECL,
                            MethodPattern.createIndexKey(lambdaExpression.descriptor.selector,
                                    lambdaExpression.descriptor.parameters.length));

                    addClassDeclaration(0, // most entries are blank, that is fine, since lambda type/method cannot be searched.
                            CharOperation.NO_CHAR, // package name
                            ONE_ZERO, ONE_ZERO_CHAR, // enclosing types.
                            CharOperation.NO_CHAR, // super class
                            new char[][] { superinterface }, CharOperation.NO_CHAR_CHAR, true); // not primary.

                } else {
                    if (DEBUG)
                        System.out.println("\tnull/bad binding in lambda"); //$NON-NLS-1$
                }
            } else {
                ReferenceExpression referenceExpression = (ReferenceExpression) expression;
                if (referenceExpression.isArrayConstructorReference())
                    continue;
                MethodBinding binding = referenceExpression.getMethodBinding();
                if (binding != null && binding.isValidBinding()) {
                    if (DEBUG) {
                        System.out
                                .println('\t' + new String(referenceExpression.resolvedType.sourceName()) + "::" //$NON-NLS-1$
                                        + new String(referenceExpression.descriptor.selector) + " == "
                                        + new String(binding.declaringClass.sourceName()) + '.' + //$NON-NLS-1$
                                        new String(binding.selector));
                    }
                    if (referenceExpression.isMethodReference())
                        SourceIndexer.this.addMethodReference(binding.selector, binding.parameters.length);
                    else
                        SourceIndexer.this.addConstructorReference(binding.declaringClass.sourceName(),
                                binding.parameters.length);
                } else {
                    if (DEBUG)
                        System.out.println("\tnull/bad binding in reference expression"); //$NON-NLS-1$
                }
            }
        }
    } catch (Exception e) {
        if (JobManager.VERBOSE) {
            e.printStackTrace();
        }
    }
}

From source file:org.eclipse.che.jdt.internal.core.search.matching.MethodLocator.java

License:Open Source License

protected int resolveLevel(ReferenceExpression referenceExpression) {
    MethodBinding method = referenceExpression.getMethodBinding();
    if (method == null || !method.isValidBinding())
        return INACCURATE_MATCH;

    int methodLevel = matchMethod(method, false);
    if (methodLevel == IMPOSSIBLE_MATCH) {
        if (method != method.original())
            methodLevel = matchMethod(method.original(), false);
        if (methodLevel == IMPOSSIBLE_MATCH)
            return IMPOSSIBLE_MATCH;
        method = method.original();/*  w ww.  jav  a  2s .  com*/
    }

    // receiver type
    if (this.pattern.declaringSimpleName == null && this.pattern.declaringQualification == null)
        return methodLevel; // since any declaring class will do
    int declaringLevel = resolveLevelForType(this.pattern.declaringSimpleName,
            this.pattern.declaringQualification, method.declaringClass);
    return (methodLevel & MATCH_LEVEL_MASK) > (declaringLevel & MATCH_LEVEL_MASK) ? declaringLevel
            : methodLevel; // return the weaker match
}

From source file:org.eclipse.jdt.internal.compiler.lookup.Scope.java

License:Open Source License

/**
 * Internal use only//from ww w .j a  v a  2 s .c om
 * Given a method, returns null if arguments cannot be converted to parameters.
 * Will answer a substituted method in case the method was generic and type inference got triggered;
 * in case the method was originally compatible, then simply answer it back.
 */
protected final MethodBinding computeCompatibleMethod(MethodBinding method, TypeBinding[] arguments,
        InvocationSite invocationSite) {
    TypeBinding[] genericTypeArguments = invocationSite.genericTypeArguments();
    TypeBinding[] parameters = method.parameters;
    TypeVariableBinding[] typeVariables = method.typeVariables;
    if (parameters == arguments && (method.returnType.tagBits & TagBits.HasTypeVariable) == 0
            && genericTypeArguments == null && typeVariables == Binding.NO_TYPE_VARIABLES)
        return method;

    int argLength = arguments.length;
    int paramLength = parameters.length;
    boolean isVarArgs = method.isVarargs();
    if (argLength != paramLength)
        if (!isVarArgs || argLength < paramLength - 1)
            return null; // incompatible

    // https://bugs.eclipse.org/bugs/show_bug.cgi?id=330435, inference should kick in only at source 1.5+
    if (typeVariables != Binding.NO_TYPE_VARIABLES
            && compilerOptions().sourceLevel >= ClassFileConstants.JDK1_5) { // generic method
        TypeBinding[] newArgs = null;
        for (int i = 0; i < argLength; i++) {
            TypeBinding param = i < paramLength ? parameters[i] : parameters[paramLength - 1];
            if (arguments[i].isBaseType() != param.isBaseType()) {
                if (newArgs == null) {
                    newArgs = new TypeBinding[argLength];
                    System.arraycopy(arguments, 0, newArgs, 0, argLength);
                }
                newArgs[i] = environment().computeBoxingType(arguments[i]);
            }
        }
        if (newArgs != null)
            arguments = newArgs;
        method = ParameterizedGenericMethodBinding.computeCompatibleMethod(method, arguments, this,
                invocationSite);
        if (method == null)
            return null; // incompatible
        if (!method.isValidBinding())
            return method; // bound check issue is taking precedence
    } else if (genericTypeArguments != null && compilerOptions().complianceLevel < ClassFileConstants.JDK1_7) {
        if (method instanceof ParameterizedGenericMethodBinding) {
            if (!((ParameterizedGenericMethodBinding) method).wasInferred)
                // attempt to invoke generic method of raw type with type hints <String>foo()
                return new ProblemMethodBinding(method, method.selector, genericTypeArguments,
                        ProblemReasons.TypeArgumentsForRawGenericMethod);
        } else if (!method.isOverriding() || !isOverriddenMethodGeneric(method)) {
            return new ProblemMethodBinding(method, method.selector, genericTypeArguments,
                    ProblemReasons.TypeParameterArityMismatch);
        }
    }

    if (parameterCompatibilityLevel(method, arguments) > NOT_COMPATIBLE) {
        if ((method.tagBits & TagBits.AnnotationPolymorphicSignature) != 0) {
            // generate polymorphic method
            return this.environment().createPolymorphicMethod(method, arguments);
        }
        return method;
    }
    // if method is generic and type arguments have been supplied, only then answer a problem 
    // of ParameterizedMethodTypeMismatch, else a non-generic method was invoked using type arguments
    // in which case this problem category will be bogus
    if (genericTypeArguments != null && typeVariables != Binding.NO_TYPE_VARIABLES)
        return new ProblemMethodBinding(method, method.selector, arguments,
                ProblemReasons.ParameterizedMethodTypeMismatch);
    return null; // incompatible
}

From source file:org.eclipse.jdt.internal.compiler.lookup.Scope.java

License:Open Source License

protected MethodBinding findDefaultAbstractMethod(ReferenceBinding receiverType, char[] selector,
        TypeBinding[] argumentTypes, InvocationSite invocationSite, ReferenceBinding classHierarchyStart,
        ObjectVector found, MethodBinding concreteMatch) {

    int startFoundSize = found.size;
    ReferenceBinding currentType = classHierarchyStart;
    while (currentType != null) {
        findMethodInSuperInterfaces(currentType, selector, found, invocationSite);
        currentType = currentType.superclass();
    }//from ww  w.  j  a  v a  2 s.  co m
    MethodBinding[] candidates = null;
    int candidatesCount = 0;
    MethodBinding problemMethod = null;
    int foundSize = found.size;
    if (foundSize > startFoundSize) {
        // argument type compatibility check
        for (int i = startFoundSize; i < foundSize; i++) {
            MethodBinding methodBinding = (MethodBinding) found.elementAt(i);
            MethodBinding compatibleMethod = computeCompatibleMethod(methodBinding, argumentTypes,
                    invocationSite);
            if (compatibleMethod != null) {
                if (compatibleMethod.isValidBinding()) {
                    if (concreteMatch != null && environment().methodVerifier()
                            .areMethodsCompatible(concreteMatch, compatibleMethod))
                        continue; // can skip this method since concreteMatch overrides it
                    if (candidatesCount == 0) {
                        candidates = new MethodBinding[foundSize - startFoundSize + 1];
                        if (concreteMatch != null)
                            candidates[candidatesCount++] = concreteMatch;
                    }
                    candidates[candidatesCount++] = compatibleMethod;
                } else if (problemMethod == null) {
                    problemMethod = compatibleMethod;
                }
            }
        }
    }

    if (candidatesCount < 2) {
        if (concreteMatch == null) {
            if (candidatesCount == 0)
                return problemMethod; // can be null
            concreteMatch = candidates[0];
        }
        compilationUnitScope().recordTypeReferences(concreteMatch.thrownExceptions);
        return concreteMatch;
    }
    // no need to check for visibility - interface methods are public
    if (compilerOptions().complianceLevel >= ClassFileConstants.JDK1_4)
        return mostSpecificMethodBinding(candidates, candidatesCount, argumentTypes, invocationSite,
                receiverType);
    return mostSpecificInterfaceMethodBinding(candidates, candidatesCount, invocationSite);
}

From source file:org.eclipse.jdt.internal.compiler.lookup.Scope.java

License:Open Source License

public MethodBinding findMethod(ReferenceBinding receiverType, char[] selector, TypeBinding[] argumentTypes,
        InvocationSite invocationSite, boolean inStaticContext) {
    ReferenceBinding currentType = receiverType;
    boolean receiverTypeIsInterface = receiverType.isInterface();
    ObjectVector found = new ObjectVector(3);
    CompilationUnitScope unitScope = compilationUnitScope();
    unitScope.recordTypeReferences(argumentTypes);

    if (receiverTypeIsInterface) {
        unitScope.recordTypeReference(receiverType);
        MethodBinding[] receiverMethods = receiverType.getMethods(selector, argumentTypes.length);
        if (receiverMethods.length > 0)
            found.addAll(receiverMethods);
        findMethodInSuperInterfaces(receiverType, selector, found, invocationSite);
        currentType = getJavaLangObject();
    }//from  w  w  w  . j av  a2 s .  c  om

    // superclass lookup
    long complianceLevel = compilerOptions().complianceLevel;
    boolean isCompliant14 = complianceLevel >= ClassFileConstants.JDK1_4;
    boolean isCompliant15 = complianceLevel >= ClassFileConstants.JDK1_5;
    ReferenceBinding classHierarchyStart = currentType;
    MethodVerifier verifier = environment().methodVerifier();
    while (currentType != null) {
        unitScope.recordTypeReference(currentType);
        currentType = (ReferenceBinding) currentType.capture(this,
                invocationSite == null ? 0 : invocationSite.sourceEnd());
        MethodBinding[] currentMethods = currentType.getMethods(selector, argumentTypes.length);
        int currentLength = currentMethods.length;
        if (currentLength > 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 (receiverTypeIsInterface && !currentMethod.isPublic()) { // only public methods from Object are visible to interface receiverTypes
                        currentLength--;
                        currentMethods[i] = null;
                        continue nextMethod;
                    }

                    // if 1.4 compliant, must filter out redundant protected methods from superclasses
                    // protected method need to be checked only - default access is already dealt with in #canBeSeen implementation
                    // when checking that p.C -> q.B -> p.A cannot see default access members from A through B.
                    // if ((currentMethod.modifiers & AccProtected) == 0) continue nextMethod;
                    // BUT we can also ignore any overridden method since we already know the better match (fixes 80028)
                    for (int j = 0, max = found.size; j < max; j++) {
                        MethodBinding matchingMethod = (MethodBinding) found.elementAt(j);
                        MethodBinding matchingOriginal = matchingMethod.original();
                        MethodBinding currentOriginal = matchingOriginal
                                .findOriginalInheritedMethod(currentMethod);
                        if (currentOriginal != null
                                && verifier.isParameterSubsignature(matchingOriginal, currentOriginal)) {
                            if (isCompliant15) {
                                if (matchingMethod.isBridge() && !currentMethod.isBridge())
                                    continue nextMethod; // keep inherited methods to find concrete method over a bridge method
                            }
                            currentLength--;
                            currentMethods[i] = null;
                            continue nextMethod;
                        }
                    }
                }
            }

            if (currentLength > 0) {
                // append currentMethods, filtering out null entries
                if (currentMethods.length == currentLength) {
                    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;
    MethodBinding problemMethod = null;
    boolean searchForDefaultAbstractMethod = isCompliant14 && !receiverTypeIsInterface
            && (receiverType.isAbstract() || receiverType.isTypeVariable());
    if (foundSize > 0) {
        // argument type compatibility check
        for (int i = 0; i < foundSize; i++) {
            MethodBinding methodBinding = (MethodBinding) found.elementAt(i);
            MethodBinding compatibleMethod = computeCompatibleMethod(methodBinding, argumentTypes,
                    invocationSite);
            if (compatibleMethod != null) {
                if (compatibleMethod.isValidBinding()) {
                    if (foundSize == 1 && compatibleMethod.canBeSeenBy(receiverType, invocationSite, this)) {
                        // return the single visible match now
                        if (searchForDefaultAbstractMethod)
                            return findDefaultAbstractMethod(receiverType, selector, argumentTypes,
                                    invocationSite, classHierarchyStart, found, compatibleMethod);
                        unitScope.recordTypeReferences(compatibleMethod.thrownExceptions);
                        return compatibleMethod;
                    }
                    if (candidatesCount == 0)
                        candidates = new MethodBinding[foundSize];
                    candidates[candidatesCount++] = compatibleMethod;
                } else if (problemMethod == null) {
                    problemMethod = compatibleMethod;
                }
            }
        }
    }

    // no match was found
    if (candidatesCount == 0) {
        if (problemMethod != null) {
            switch (problemMethod.problemId()) {
            case ProblemReasons.TypeArgumentsForRawGenericMethod:
            case ProblemReasons.TypeParameterArityMismatch:
                return problemMethod;
            }
        }
        // abstract classes may get a match in interfaces; for non abstract
        // classes, 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;
        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)
        // so answer the method with the most argType matches and least parameter type mismatches
        int bestArgMatches = -1;
        MethodBinding bestGuess = (MethodBinding) found.elementAt(0); // if no good match so just use the first one found
        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;
            int argMatches = 0;
            next: for (int a = 0; a < argLength; a++) {
                TypeBinding arg = argumentTypes[a];
                for (int p = a == 0 ? 0 : a - 1; p < paramLength && p < a + 1; p++) { // look one slot before & after to see if the type matches
                    if (params[p] == arg) {
                        argMatches++;
                        continue next;
                    }
                }
            }
            if (argMatches < bestArgMatches)
                continue nextMethod;
            if (argMatches == bestArgMatches) {
                int diff1 = paramLength < argLength ? 2 * (argLength - paramLength) : paramLength - argLength;
                int bestLength = bestGuess.parameters.length;
                int diff2 = bestLength < argLength ? 2 * (argLength - bestLength) : bestLength - argLength;
                if (diff1 >= diff2)
                    continue nextMethod;
            }
            bestArgMatches = argMatches;
            bestGuess = methodBinding;
        }
        return new ProblemMethodBinding(bestGuess, bestGuess.selector, argumentTypes, ProblemReasons.NotFound);
    }

    // tiebreak using visibility check
    int visiblesCount = 0;
    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++;
            }
        }
        switch (visiblesCount) {
        case 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);
        case 1:
            if (searchForDefaultAbstractMethod)
                return findDefaultAbstractMethod(receiverType, selector, argumentTypes, invocationSite,
                        classHierarchyStart, found, candidates[0]);
            unitScope.recordTypeReferences(candidates[0].thrownExceptions);
            return candidates[0];
        default:
            break;
        }
    }

    if (complianceLevel <= ClassFileConstants.JDK1_3) {
        ReferenceBinding declaringClass = candidates[0].declaringClass;
        return !declaringClass.isInterface()
                ? mostSpecificClassMethodBinding(candidates, visiblesCount, invocationSite)
                : mostSpecificInterfaceMethodBinding(candidates, visiblesCount, invocationSite);
    }

    // check for duplicate parameterized methods
    if (compilerOptions().sourceLevel >= ClassFileConstants.JDK1_5) {
        for (int i = 0; i < visiblesCount; i++) {
            MethodBinding candidate = candidates[i];
            if (candidate instanceof ParameterizedGenericMethodBinding)
                candidate = ((ParameterizedGenericMethodBinding) candidate).originalMethod;
            if (candidate.hasSubstitutedParameters()) {
                for (int j = i + 1; j < visiblesCount; j++) {
                    MethodBinding otherCandidate = candidates[j];
                    if (otherCandidate.hasSubstitutedParameters()) {
                        if (otherCandidate == candidate
                                || (candidate.declaringClass == otherCandidate.declaringClass
                                        && candidate.areParametersEqual(otherCandidate))) {
                            return new ProblemMethodBinding(candidates[i], candidates[i].selector,
                                    candidates[i].parameters, ProblemReasons.Ambiguous);
                        }
                    }
                }
            }
        }
    }
    if (inStaticContext) {
        MethodBinding[] staticCandidates = new MethodBinding[visiblesCount];
        int staticCount = 0;
        for (int i = 0; i < visiblesCount; i++)
            if (candidates[i].isStatic())
                staticCandidates[staticCount++] = candidates[i];
        if (staticCount == 1)
            return staticCandidates[0];
        if (staticCount > 1)
            return mostSpecificMethodBinding(staticCandidates, staticCount, argumentTypes, invocationSite,
                    receiverType);
    }

    MethodBinding mostSpecificMethod = mostSpecificMethodBinding(candidates, visiblesCount, argumentTypes,
            invocationSite, receiverType);
    if (searchForDefaultAbstractMethod) { // search interfaces for a better match
        if (mostSpecificMethod.isValidBinding())
            // see if there is a better match in the interfaces - see AutoBoxingTest 99, LookupTest#81
            return findDefaultAbstractMethod(receiverType, selector, argumentTypes, invocationSite,
                    classHierarchyStart, found, mostSpecificMethod);
        // see if there is a match in the interfaces - see LookupTest#84
        MethodBinding interfaceMethod = findDefaultAbstractMethod(receiverType, selector, argumentTypes,
                invocationSite, classHierarchyStart, found, null);
        if (interfaceMethod != null
                && interfaceMethod.isValidBinding() /* else return the same error as before */)
            return interfaceMethod;
    }
    return mostSpecificMethod;
}

From source file:org.eclipse.jdt.internal.compiler.lookup.Scope.java

License:Open Source License

public MethodBinding getConstructor(ReferenceBinding receiverType, TypeBinding[] argumentTypes,
        InvocationSite invocationSite) {
    CompilationUnitScope unitScope = compilationUnitScope();
    LookupEnvironment env = unitScope.environment;
    try {//from  www  .  ja  v a2  s  . c o m
        env.missingClassFileLocation = invocationSite;
        unitScope.recordTypeReference(receiverType);
        unitScope.recordTypeReferences(argumentTypes);
        MethodBinding methodBinding = receiverType.getExactConstructor(argumentTypes);
        if (methodBinding != null && methodBinding.canBeSeenBy(invocationSite, this)) {
            // targeting a non generic constructor with type arguments ?
            if (invocationSite.genericTypeArguments() != null)
                methodBinding = computeCompatibleMethod(methodBinding, argumentTypes, invocationSite);
            return methodBinding;
        }
        MethodBinding[] methods = receiverType.getMethods(TypeConstants.INIT, argumentTypes.length);
        if (methods == Binding.NO_METHODS)
            return new ProblemMethodBinding(TypeConstants.INIT, argumentTypes, ProblemReasons.NotFound);

        MethodBinding[] compatible = new MethodBinding[methods.length];
        int compatibleIndex = 0;
        MethodBinding problemMethod = null;
        for (int i = 0, length = methods.length; i < length; i++) {
            MethodBinding compatibleMethod = computeCompatibleMethod(methods[i], argumentTypes, invocationSite);
            if (compatibleMethod != null) {
                if (compatibleMethod.isValidBinding())
                    compatible[compatibleIndex++] = compatibleMethod;
                else if (problemMethod == null)
                    problemMethod = compatibleMethod;
            }
        }
        if (compatibleIndex == 0) {
            if (problemMethod == null)
                return new ProblemMethodBinding(methods[0], TypeConstants.INIT, argumentTypes,
                        ProblemReasons.NotFound);
            return problemMethod;
        }
        // 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], TypeConstants.INIT, compatible[0].parameters,
                    ProblemReasons.NotVisible);
        // all of visible are from the same declaringClass, even before 1.4 we can call this method instead of mostSpecificClassMethodBinding
        return mostSpecificMethodBinding(visible, visibleIndex, argumentTypes, invocationSite, receiverType);
    } catch (AbortCompilation e) {
        e.updateContext(invocationSite, referenceCompilationUnit().compilationResult);
        throw e;
    } finally {
        env.missingClassFileLocation = null;
    }
}

From source file:org.eclipse.jdt.internal.compiler.lookup.Scope.java

License:Open Source License

public MethodBinding getImplicitMethod(char[] selector, TypeBinding[] argumentTypes,
        InvocationSite invocationSite) {

    boolean insideStaticContext = false;
    boolean insideConstructorCall = false;
    boolean insideTypeAnnotation = false;
    MethodBinding foundMethod = null;//from w  ww .  jav a2s.c om
    MethodBinding foundProblem = null;
    boolean foundProblemVisible = false;
    Scope scope = this;
    int depth = 0;
    // in 1.4 mode (inherited visible shadows enclosing)
    CompilerOptions options;
    boolean inheritedHasPrecedence = (options = compilerOptions()).complianceLevel >= ClassFileConstants.JDK1_4;

    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;
            insideTypeAnnotation = methodScope.insideTypeAnnotation;
            break;
        case CLASS_SCOPE:
            ClassScope classScope = (ClassScope) scope;
            ReferenceBinding receiverType = classScope.enclosingReceiverType();
            if (!insideTypeAnnotation) {
                // retrieve an exact visible match (if possible)
                // compilationUnitScope().recordTypeReference(receiverType);   not needed since receiver is the source type
                MethodBinding methodBinding = classScope.findExactMethod(receiverType, selector, argumentTypes,
                        invocationSite);
                if (methodBinding == null)
                    methodBinding = classScope.findMethod(receiverType, selector, argumentTypes,
                            invocationSite);
                if (methodBinding != null) { // skip it if we did not find anything
                    if (foundMethod == null) {
                        if (methodBinding.isValidBinding()) {
                            if (!methodBinding.isStatic() && (insideConstructorCall || insideStaticContext)) {
                                if (foundProblem != null
                                        && foundProblem.problemId() != ProblemReasons.NotVisible)
                                    return foundProblem; // takes precedence
                                return new ProblemMethodBinding(methodBinding, // closest match
                                        methodBinding.selector, methodBinding.parameters,
                                        insideConstructorCall
                                                ? ProblemReasons.NonStaticReferenceInConstructorInvocation
                                                : ProblemReasons.NonStaticReferenceInStaticContext);
                            }
                            if (inheritedHasPrecedence || receiverType == methodBinding.declaringClass
                                    || (receiverType.getMethods(selector)) != Binding.NO_METHODS) {
                                // found a valid method in the 'immediate' scope (i.e. not inherited)
                                // OR in 1.4 mode (inherited visible shadows enclosing)
                                // OR the receiverType implemented a method with the correct name
                                // return the methodBinding if it is not declared in a superclass of the scope's binding (that is, inherited)
                                if (foundProblemVisible) {
                                    return foundProblem;
                                }
                                if (depth > 0) {
                                    invocationSite.setDepth(depth);
                                    invocationSite.setActualReceiverType(receiverType);
                                }
                                // special treatment for Object.getClass() in 1.5 mode (substitute parameterized return type)
                                if (argumentTypes == Binding.NO_PARAMETERS
                                        && CharOperation.equals(selector, TypeConstants.GETCLASS)
                                        && methodBinding.returnType.isParameterizedType()/*1.5*/) {
                                    return environment().createGetClassMethod(receiverType, methodBinding,
                                            this);
                                }
                                return methodBinding;
                            }

                            if (foundProblem == null || foundProblem.problemId() == ProblemReasons.NotVisible) {
                                if (foundProblem != null)
                                    foundProblem = null;
                                // only remember the methodBinding if its the first one found
                                // remember that private methods are visible if defined directly by an enclosing class
                                if (depth > 0) {
                                    invocationSite.setDepth(depth);
                                    invocationSite.setActualReceiverType(receiverType);
                                }
                                foundMethod = methodBinding;
                            }
                        } else { // methodBinding is a problem method
                            if (methodBinding.problemId() != ProblemReasons.NotVisible
                                    && methodBinding.problemId() != ProblemReasons.NotFound)
                                return methodBinding; // return the error now
                            if (foundProblem == null) {
                                foundProblem = methodBinding; // hold onto the first not visible/found error and keep the second not found if first is not visible
                            }
                            if (!foundProblemVisible && methodBinding.problemId() == ProblemReasons.NotFound) {
                                MethodBinding closestMatch = ((ProblemMethodBinding) methodBinding).closestMatch;
                                if (closestMatch != null
                                        && closestMatch.canBeSeenBy(receiverType, invocationSite, this)) {
                                    foundProblem = methodBinding; // hold onto the first not visible/found error and keep the second not found if first is not visible
                                    foundProblemVisible = true;
                                }
                            }
                        }
                    } else { // found a valid method so check to see if this is a hiding case
                        if (methodBinding.problemId() == ProblemReasons.Ambiguous
                                || (foundMethod.declaringClass != methodBinding.declaringClass
                                        && (receiverType == methodBinding.declaringClass
                                                || receiverType.getMethods(selector) != Binding.NO_METHODS)))
                            // ambiguous case -> must qualify the method (javac generates an ambiguous error instead)
                            // otherwise 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
                            return new ProblemMethodBinding(methodBinding, // closest match
                                    selector, argumentTypes, ProblemReasons.InheritedNameHidesEnclosingName);
                    }
                }
            }
            insideTypeAnnotation = false;
            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 (insideStaticContext && options.sourceLevel >= ClassFileConstants.JDK1_5) {
        if (foundProblem != null) {
            if (foundProblem.declaringClass != null
                    && foundProblem.declaringClass.id == TypeIds.T_JavaLangObject)
                return foundProblem; // static imports lose to methods from Object
            if (foundProblem.problemId() == ProblemReasons.NotFound && foundProblemVisible) {
                return foundProblem; // visible method selectors take precedence
            }
        }

        // at this point the scope is a compilation unit scope & need to check for imported static methods
        CompilationUnitScope unitScope = (CompilationUnitScope) scope;
        unitScope.faultInImports(); // field constants can cause static imports to be accessed before they're resolved
        ImportBinding[] imports = unitScope.imports;
        if (imports != null) {
            ObjectVector visible = null;
            boolean skipOnDemand = false; // set to true when matched static import of method name so stop looking for on demand methods
            for (int i = 0, length = imports.length; i < length; i++) {
                ImportBinding importBinding = imports[i];
                if (importBinding.isStatic()) {
                    Binding resolvedImport = importBinding.resolvedImport;
                    MethodBinding possible = null;
                    if (importBinding.onDemand) {
                        if (!skipOnDemand && resolvedImport instanceof ReferenceBinding)
                            // answers closest approximation, may not check argumentTypes or visibility
                            possible = findMethod((ReferenceBinding) resolvedImport, selector, argumentTypes,
                                    invocationSite, true);
                    } else {
                        if (resolvedImport instanceof MethodBinding) {
                            MethodBinding staticMethod = (MethodBinding) resolvedImport;
                            if (CharOperation.equals(staticMethod.selector, selector))
                                // answers closest approximation, may not check argumentTypes or visibility
                                possible = findMethod(staticMethod.declaringClass, selector, argumentTypes,
                                        invocationSite, true);
                        } else if (resolvedImport instanceof FieldBinding) {
                            // check to see if there are also methods with the same name
                            FieldBinding staticField = (FieldBinding) resolvedImport;
                            if (CharOperation.equals(staticField.name, selector)) {
                                // must find the importRef's type again since the field can be from an inherited type
                                char[][] importName = importBinding.reference.tokens;
                                TypeBinding referencedType = getType(importName, importName.length - 1);
                                if (referencedType != null)
                                    // answers closest approximation, may not check argumentTypes or visibility
                                    possible = findMethod((ReferenceBinding) referencedType, selector,
                                            argumentTypes, invocationSite, true);
                            }
                        }
                    }
                    if (possible != null && possible != foundProblem) {
                        if (!possible.isValidBinding()) {
                            if (foundProblem == null)
                                foundProblem = possible; // answer as error case match
                        } else if (possible.isStatic()) {
                            MethodBinding compatibleMethod = computeCompatibleMethod(possible, argumentTypes,
                                    invocationSite);
                            if (compatibleMethod != null) {
                                if (compatibleMethod.isValidBinding()) {
                                    if (compatibleMethod.canBeSeenBy(unitScope.fPackage)) {
                                        if (visible == null || !visible.contains(compatibleMethod)) {
                                            ImportReference importReference = importBinding.reference;
                                            if (importReference != null) {
                                                importReference.bits |= ASTNode.Used;
                                            }
                                            if (!skipOnDemand && !importBinding.onDemand) {
                                                visible = null; // forget previous matches from on demand imports
                                                skipOnDemand = true;
                                            }
                                            if (visible == null)
                                                visible = new ObjectVector(3);
                                            visible.add(compatibleMethod);
                                        }
                                    } else if (foundProblem == null) {
                                        foundProblem = new ProblemMethodBinding(compatibleMethod, selector,
                                                compatibleMethod.parameters, ProblemReasons.NotVisible);
                                    }
                                } else if (foundProblem == null) {
                                    foundProblem = compatibleMethod;
                                }
                            } else if (foundProblem == null) {
                                foundProblem = new ProblemMethodBinding(possible, selector, argumentTypes,
                                        ProblemReasons.NotFound);
                            }
                        }
                    }
                }
            }
            if (visible != null) {
                MethodBinding[] temp = new MethodBinding[visible.size];
                visible.copyInto(temp);
                foundMethod = mostSpecificMethodBinding(temp, temp.length, argumentTypes, invocationSite, null);
            }
        }
    }

    if (foundMethod != null) {
        invocationSite.setActualReceiverType(foundMethod.declaringClass);
        return foundMethod;
    }
    if (foundProblem != null)
        return foundProblem;

    return new ProblemMethodBinding(selector, argumentTypes, ProblemReasons.NotFound);
}

From source file:org.eclipse.jdt.internal.compiler.lookup.Scope.java

License:Open Source License

public MethodBinding getMethod(TypeBinding receiverType, char[] selector, TypeBinding[] argumentTypes,
        InvocationSite invocationSite) {
    CompilationUnitScope unitScope = compilationUnitScope();
    LookupEnvironment env = unitScope.environment;
    try {//ww  w  .  j a v a  2 s.  co m
        env.missingClassFileLocation = invocationSite;
        switch (receiverType.kind()) {
        case Binding.BASE_TYPE:
            return new ProblemMethodBinding(selector, argumentTypes, ProblemReasons.NotFound);
        case Binding.ARRAY_TYPE:
            unitScope.recordTypeReference(receiverType);
            return findMethodForArray((ArrayBinding) receiverType, selector, argumentTypes, invocationSite);
        }
        unitScope.recordTypeReference(receiverType);

        ReferenceBinding currentType = (ReferenceBinding) receiverType;
        if (!currentType.canBeSeenBy(this))
            return new ProblemMethodBinding(selector, argumentTypes, ProblemReasons.ReceiverTypeNotVisible);

        // retrieve an exact visible match (if possible)
        MethodBinding methodBinding = findExactMethod(currentType, selector, argumentTypes, invocationSite);
        if (methodBinding != null)
            return methodBinding;

        methodBinding = findMethod(currentType, selector, argumentTypes, invocationSite);
        // GROOVY start: give it one more chance as the ast transform may have introduced it
        // is this the right approach?  Requires ast transforms running before this is done
        if (methodBinding == null) {
            methodBinding = oneLastLook(currentType, selector, argumentTypes, invocationSite);
        }
        // GROOVY end
        if (methodBinding == null)
            return new ProblemMethodBinding(selector, argumentTypes, ProblemReasons.NotFound);
        if (!methodBinding.isValidBinding())
            return methodBinding;

        // special treatment for Object.getClass() in 1.5 mode (substitute parameterized return type)
        if (argumentTypes == Binding.NO_PARAMETERS && CharOperation.equals(selector, TypeConstants.GETCLASS)
                && methodBinding.returnType.isParameterizedType()/*1.5*/) {
            return environment().createGetClassMethod(receiverType, methodBinding, this);
        }
        return methodBinding;
    } catch (AbortCompilation e) {
        e.updateContext(invocationSite, referenceCompilationUnit().compilationResult);
        throw e;
    } finally {
        env.missingClassFileLocation = null;
    }
}

From source file:org.eclipse.jdt.internal.compiler.lookup.Scope.java

License:Open Source License

protected final MethodBinding mostSpecificMethodBinding(MethodBinding[] visible, int visibleSize,
        TypeBinding[] argumentTypes, final InvocationSite invocationSite, ReferenceBinding receiverType) {
    int[] compatibilityLevels = new int[visibleSize];
    for (int i = 0; i < visibleSize; i++)
        compatibilityLevels[i] = parameterCompatibilityLevel(visible[i], argumentTypes);

    InvocationSite tieBreakInvocationSite = new InvocationSite() {
        public TypeBinding[] genericTypeArguments() {
            return null;
        } // ignore genericTypeArgs

        public boolean isSuperAccess() {
            return invocationSite.isSuperAccess();
        }//from w w  w  .j av a2  s .c o m

        public boolean isTypeAccess() {
            return invocationSite.isTypeAccess();
        }

        public void setActualReceiverType(ReferenceBinding actualReceiverType) {
            /* ignore */}

        public void setDepth(int depth) {
            /* ignore */}

        public void setFieldIndex(int depth) {
            /* ignore */}

        public int sourceStart() {
            return invocationSite.sourceStart();
        }

        public int sourceEnd() {
            return invocationSite.sourceStart();
        }

        public TypeBinding expectedType() {
            return invocationSite.expectedType();
        }
    };
    MethodBinding[] moreSpecific = new MethodBinding[visibleSize];
    int count = 0;
    for (int level = 0, max = VARARGS_COMPATIBLE; level <= max; level++) {
        nextVisible: for (int i = 0; i < visibleSize; i++) {
            if (compatibilityLevels[i] != level)
                continue nextVisible;
            max = level; // do not examine further categories, will either return mostSpecific or report ambiguous case
            MethodBinding current = visible[i];
            MethodBinding original = current.original();
            MethodBinding tiebreakMethod = current.tiebreakMethod();
            for (int j = 0; j < visibleSize; j++) {
                if (i == j || compatibilityLevels[j] != level)
                    continue;
                MethodBinding next = visible[j];
                if (original == next.original()) {
                    // parameterized superclasses & interfaces may be walked twice from different paths so skip next from now on
                    compatibilityLevels[j] = -1;
                    continue;
                }

                MethodBinding methodToTest = next;
                if (next instanceof ParameterizedGenericMethodBinding) {
                    ParameterizedGenericMethodBinding pNext = (ParameterizedGenericMethodBinding) next;
                    if (pNext.isRaw && !pNext.isStatic()) {
                        // hold onto the raw substituted method
                    } else {
                        methodToTest = pNext.originalMethod;
                    }
                }
                MethodBinding acceptable = computeCompatibleMethod(methodToTest, tiebreakMethod.parameters,
                        tieBreakInvocationSite);
                /* There are 4 choices to consider with current & next :
                 foo(B) & foo(A) where B extends A
                 1. the 2 methods are equal (both accept each others parameters) -> want to continue
                 2. current has more specific parameters than next (so acceptable is a valid method) -> want to continue
                 3. current has less specific parameters than next (so acceptable is null) -> go on to next
                 4. current and next are not compatible with each other (so acceptable is null) -> go on to next
                 */
                if (acceptable == null || !acceptable.isValidBinding())
                    continue nextVisible;
                if (!isAcceptableMethod(tiebreakMethod, acceptable))
                    continue nextVisible;
                // pick a concrete method over a bridge method when parameters are equal since the return type of the concrete method is more specific
                if (current.isBridge() && !next.isBridge())
                    if (tiebreakMethod.areParametersEqual(acceptable))
                        continue nextVisible; // skip current so acceptable wins over this bridge method
            }
            moreSpecific[i] = current;
            count++;
        }
    }
    if (count == 1) {
        for (int i = 0; i < visibleSize; i++) {
            if (moreSpecific[i] != null) {
                compilationUnitScope().recordTypeReferences(visible[i].thrownExceptions);
                return visible[i];
            }
        }
    } else if (count == 0) {
        return new ProblemMethodBinding(visible[0], visible[0].selector, visible[0].parameters,
                ProblemReasons.Ambiguous);
    }

    // found several methods that are mutually acceptable -> must be equal
    // so now with the first acceptable method, find the 'correct' inherited method for each other acceptable method AND
    // see if they are equal after substitution of type variables (do the type variables have to be equal to be considered an override???)
    if (receiverType != null)
        receiverType = receiverType instanceof CaptureBinding ? receiverType
                : (ReferenceBinding) receiverType.erasure();
    nextSpecific: for (int i = 0; i < visibleSize; i++) {
        MethodBinding current = moreSpecific[i];
        if (current != null) {
            ReferenceBinding[] mostSpecificExceptions = null;
            MethodBinding original = current.original();
            boolean shouldIntersectExceptions = original.declaringClass.isAbstract()
                    && original.thrownExceptions != Binding.NO_EXCEPTIONS; // only needed when selecting from interface methods
            for (int j = 0; j < visibleSize; j++) {
                MethodBinding next = moreSpecific[j];
                if (next == null || i == j)
                    continue;
                MethodBinding original2 = next.original();
                if (original.declaringClass == original2.declaringClass)
                    break nextSpecific; // duplicates thru substitution

                if (!original.isAbstract()) {
                    if (original2.isAbstract())
                        continue; // only compare current against other concrete methods

                    original2 = original.findOriginalInheritedMethod(original2);
                    if (original2 == null)
                        continue nextSpecific; // current's declaringClass is not a subtype of next's declaringClass
                    if (current.hasSubstitutedParameters()
                            || original.typeVariables != Binding.NO_TYPE_VARIABLES) {
                        if (!environment().methodVerifier().isParameterSubsignature(original, original2))
                            continue nextSpecific; // current does not override next
                    }
                } else if (receiverType != null) { // should not be null if original isAbstract, but be safe
                    TypeBinding superType = receiverType
                            .findSuperTypeOriginatingFrom(original.declaringClass.erasure());
                    if (original.declaringClass == superType || !(superType instanceof ReferenceBinding)) {
                        // keep original
                    } else {
                        // must find inherited method with the same substituted variables
                        MethodBinding[] superMethods = ((ReferenceBinding) superType)
                                .getMethods(original.selector, argumentTypes.length);
                        for (int m = 0, l = superMethods.length; m < l; m++) {
                            if (superMethods[m].original() == original) {
                                original = superMethods[m];
                                break;
                            }
                        }
                    }
                    superType = receiverType.findSuperTypeOriginatingFrom(original2.declaringClass.erasure());
                    if (original2.declaringClass == superType || !(superType instanceof ReferenceBinding)) {
                        // keep original2
                    } else {
                        // must find inherited method with the same substituted variables
                        MethodBinding[] superMethods = ((ReferenceBinding) superType)
                                .getMethods(original2.selector, argumentTypes.length);
                        for (int m = 0, l = superMethods.length; m < l; m++) {
                            if (superMethods[m].original() == original2) {
                                original2 = superMethods[m];
                                break;
                            }
                        }
                    }
                    if (original.typeVariables != Binding.NO_TYPE_VARIABLES)
                        original2 = original.computeSubstitutedMethod(original2, environment());
                    if (original2 == null || !original.areParameterErasuresEqual(original2))
                        continue nextSpecific; // current does not override next
                    if (original.returnType != original2.returnType) {
                        if (next.original().typeVariables != Binding.NO_TYPE_VARIABLES) {
                            if (original.returnType.erasure()
                                    .findSuperTypeOriginatingFrom(original2.returnType.erasure()) == null)
                                continue nextSpecific;
                        } else if (!current.returnType.isCompatibleWith(next.returnType)) {
                            continue nextSpecific;
                        }
                        // continue with original 15.12.2.5
                    }
                    if (shouldIntersectExceptions && original2.declaringClass.isInterface()) {
                        if (current.thrownExceptions != next.thrownExceptions) {
                            if (next.thrownExceptions == Binding.NO_EXCEPTIONS) {
                                mostSpecificExceptions = Binding.NO_EXCEPTIONS;
                            } else {
                                if (mostSpecificExceptions == null) {
                                    mostSpecificExceptions = current.thrownExceptions;
                                }
                                int mostSpecificLength = mostSpecificExceptions.length;
                                int nextLength = next.thrownExceptions.length;
                                SimpleSet temp = new SimpleSet(mostSpecificLength);
                                boolean changed = false;
                                nextException: for (int t = 0; t < mostSpecificLength; t++) {
                                    ReferenceBinding exception = mostSpecificExceptions[t];
                                    for (int s = 0; s < nextLength; s++) {
                                        ReferenceBinding nextException = next.thrownExceptions[s];
                                        if (exception.isCompatibleWith(nextException)) {
                                            temp.add(exception);
                                            continue nextException;
                                        } else if (nextException.isCompatibleWith(exception)) {
                                            temp.add(nextException);
                                            changed = true;
                                            continue nextException;
                                        } else {
                                            changed = true;
                                        }
                                    }
                                }
                                if (changed) {
                                    mostSpecificExceptions = temp.elementSize == 0 ? Binding.NO_EXCEPTIONS
                                            : new ReferenceBinding[temp.elementSize];
                                    temp.asArray(mostSpecificExceptions);
                                }
                            }
                        }
                    }
                }
            }
            if (mostSpecificExceptions != null && mostSpecificExceptions != current.thrownExceptions) {
                return new MostSpecificExceptionMethodBinding(current, mostSpecificExceptions);
            }
            return current;
        }
    }

    // if all moreSpecific methods are equal then see if duplicates exist because of substitution
    return new ProblemMethodBinding(visible[0], visible[0].selector, visible[0].parameters,
            ProblemReasons.Ambiguous);
}