Example usage for org.eclipse.jdt.internal.compiler.lookup MostSpecificExceptionMethodBinding MostSpecificExceptionMethodBinding

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

Introduction

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

Prototype

public MostSpecificExceptionMethodBinding(MethodBinding originalMethod,
            ReferenceBinding[] mostSpecificExceptions) 

Source Link

Usage

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