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

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

Introduction

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

Prototype

public final boolean isBridge() 

Source Link

Usage

From source file:com.redhat.ceylon.eclipse.core.model.mirror.UnknownClassMirror.java

License:Open Source License

@Override
public List<MethodMirror> getDirectMethods() {
    if (methods == null) {
        doWithBindings(new ActionOnClassBinding() {
            @Override//  ww w  .  j  a va2  s  . co m
            public void doWithBinding(IType classModel, ReferenceBinding klass) {
                MethodBinding[] directMethods;
                directMethods = klass.methods();
                methods = new ArrayList<MethodMirror>(directMethods.length);
                for (MethodBinding method : directMethods) {
                    if (!method.isBridge() && !method.isSynthetic() && !method.isPrivate())
                        methods.add(new JDTMethod(JDTClass.this, method));
                }
            }
        });
    }
    return methods;
}

From source file:com.redhat.ceylon.eclipse.core.model.mirror.JDTMethod.java

License:Open Source License

private boolean isOverloadingInType(ReferenceBinding superClass, MethodBinding method) {
    MethodVerifier methodVerifier = superClass.getPackage().environment.methodVerifier();
    for (MethodBinding inheritedMethod : superClass.methods()) {
        if (inheritedMethod.isPrivate() || inheritedMethod.isStatic() || inheritedMethod.isConstructor()
                || inheritedMethod.isBridge() || inheritedMethod.isSynthetic()
                || !Arrays.equals(inheritedMethod.constantPoolName(), method.selector))
            continue;

        // skip ignored methods
        if (ignoreMethodInAncestorSearch(inheritedMethod)) {
            continue;
        }//from   w w w .  jav a 2 s .  co  m

        // if it does not override it and has the same name, it's overloading
        if (!methodVerifier.doesMethodOverride(method, inheritedMethod)) {
            return true;
        }
    }
    return false;
}

From source file:lombok.eclipse.agent.PatchDelegate.java

License:Open Source License

private static void addAllMethodBindings0(List<BindingTuple> list, TypeBinding binding, Set<String> banList,
        char[] fieldName, ASTNode responsible) throws DelegateRecursion {
    if (binding instanceof SourceTypeBinding)
        ((SourceTypeBinding) binding).scope.environment().globalOptions.storeAnnotations = true;
    if (binding == null)
        return;//from w  w w .  ja  v a 2  s.co  m

    TypeBinding inner;

    if (binding instanceof ParameterizedTypeBinding) {
        inner = ((ParameterizedTypeBinding) binding).genericType();
    } else {
        inner = binding;
    }

    if (inner instanceof SourceTypeBinding) {
        ClassScope cs = ((SourceTypeBinding) inner).scope;
        if (cs != null) {
            try {
                Reflection.classScopeBuildFieldsAndMethodsMethod.invoke(cs);
            } catch (Exception e) {
                // See 'Reflection' class for why we ignore this exception.
            }
        }
    }

    if (binding instanceof ReferenceBinding) {
        ReferenceBinding rb = (ReferenceBinding) binding;
        MethodBinding[] availableMethods = rb.availableMethods();
        FieldBinding[] availableFields = rb.availableFields();
        failIfContainsAnnotation(binding, availableMethods);
        failIfContainsAnnotation(binding, availableFields);

        MethodBinding[] parameterizedSigs = availableMethods;
        MethodBinding[] baseSigs = parameterizedSigs;
        if (binding instanceof ParameterizedTypeBinding) {
            baseSigs = ((ParameterizedTypeBinding) binding).genericType().availableMethods();
            if (baseSigs.length != parameterizedSigs.length) {
                // The last known state of eclipse source says this can't happen, so we rely on it,
                // but if this invariant is broken, better to go with 'arg0' naming instead of crashing.
                baseSigs = parameterizedSigs;
            }
        }
        for (int i = 0; i < parameterizedSigs.length; i++) {
            MethodBinding mb = parameterizedSigs[i];
            String sig = printSig(mb);
            if (mb.isStatic())
                continue;
            if (mb.isBridge())
                continue;
            if (mb.isConstructor())
                continue;
            if (mb.isDefaultAbstract())
                continue;
            if (!mb.isPublic())
                continue;
            if (mb.isSynthetic())
                continue;
            if (!banList.add(sig))
                continue; // If add returns false, it was already in there.
            BindingTuple pair = new BindingTuple(mb, baseSigs[i], fieldName, responsible);
            list.add(pair);
        }
        addAllMethodBindings0(list, rb.superclass(), banList, fieldName, responsible);
        ReferenceBinding[] interfaces = rb.superInterfaces();
        if (interfaces != null) {
            for (ReferenceBinding iface : interfaces)
                addAllMethodBindings0(list, iface, banList, fieldName, responsible);
        }
    }
}

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

License:Open Source License

public MethodBinding findExactMethod(ReferenceBinding receiverType, char[] selector,
        TypeBinding[] argumentTypes, InvocationSite invocationSite) {
    CompilationUnitScope unitScope = compilationUnitScope();
    unitScope.recordTypeReferences(argumentTypes);
    MethodBinding exactMethod = receiverType.getExactMethod(selector, argumentTypes, unitScope);
    if (exactMethod != null && exactMethod.typeVariables == Binding.NO_TYPE_VARIABLES
            && !exactMethod.isBridge()) {
        // in >= 1.5 mode, ensure the exactMatch did not match raw types
        if (compilerOptions().sourceLevel >= ClassFileConstants.JDK1_5)
            for (int i = argumentTypes.length; --i >= 0;)
                if (isPossibleSubtypeOfRawType(argumentTypes[i]))
                    return null;
        // must find both methods for this case: <S extends A> void foo() {}  and  <N extends B> N foo() { return null; }
        // or find an inherited method when the exact match is to a bridge method
        unitScope.recordTypeReferences(exactMethod.thrownExceptions);
        if (exactMethod.isAbstract() && exactMethod.thrownExceptions != Binding.NO_EXCEPTIONS)
            return null; // may need to merge exceptions with interface method
        // special treatment for Object.getClass() in 1.5 mode (substitute parameterized return type)
        if (receiverType.isInterface() || exactMethod.canBeSeenBy(receiverType, invocationSite, this)) {
            if (argumentTypes == Binding.NO_PARAMETERS && CharOperation.equals(selector, TypeConstants.GETCLASS)
                    && exactMethod.returnType.isParameterizedType()/*1.5*/) {
                return environment().createGetClassMethod(receiverType, exactMethod, this);
            }//from   w  ww. j  a  va2  s  .com
            // targeting a generic method could find an exact match with variable return type
            if (invocationSite.genericTypeArguments() != null) {
                exactMethod = computeCompatibleMethod(exactMethod, argumentTypes, invocationSite);
            }
            return exactMethod;
        }
    }
    return null;
}

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 a v a 2  s. co m

    // 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

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  a  v a  2s . co 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);
}