Search in sources :

Example 1 with ExtendedClassesIterable

use of org.eclipse.n4js.ts.types.util.ExtendedClassesIterable in project n4js by eclipse.

the class MemberRedefinitionUtils method findThisContextForConstructor.

/**
 * Returns the context type to be used as this binding (see
 * {@link N4JSTypeSystem#createRuleEnvironmentForContext(TypeRef, TypeRef, Resource) here} and
 * {@link RuleEnvironmentExtensions#addThisType(RuleEnvironment, TypeRef)} here) for checking constructor
 * compatibility.
 *
 * For example, given the following code
 *
 * <pre>
 * class C1 {
 *     constructor(@Spec spec: ~i~this) {}
 * }
 *
 * class C2 extends C1 {
 *     public field2;
 * }
 *
 * &#64;CovariantConstructor
 * class C3 extends C2 {
 *     public field3;
 * }
 *
 * class C4 extends C3 {
 *     // XPECT noerrors -->
 *     constructor(@Spec spec: ~i~this) { super(spec); }
 * }
 * </pre>
 *
 * When checking constructor compatibility in C4, we have to use class C3 as the 'this' context on right-hand side,
 * not class C1, because the addition of fields <code>field2</code> and <code>field3</code> does not break the
 * contract of the &#64;CovariantConstructor annotation. Therefore, we cannot simply use the containing type of the
 * right-hand side constructor as 'this' context. In the above example, we would call this method with C4 as
 * <code>baseContext</code> and C1's constructor as <code>ctor</code> and it would return C3 as the 'this' context
 * to use.
 */
public static final Type findThisContextForConstructor(Type baseContext, TMethod ctor) {
    final Type ctorContainer = ctor.getContainingType();
    if (!(baseContext instanceof TClass) || !(ctorContainer instanceof TClass)) {
        return ctorContainer;
    }
    final TClass ctorContainerCasted = (TClass) ctorContainer;
    final TClass baseContextCasted = (TClass) baseContext;
    if (N4JSLanguageUtils.hasCovariantConstructor(ctorContainerCasted)) {
        return ctorContainerCasted;
    }
    final List<TClass> superClassesUpToCtorContainer = new ArrayList<>();
    for (TClass superClass : new ExtendedClassesIterable(baseContextCasted)) {
        if (superClass != ctorContainerCasted) {
            superClassesUpToCtorContainer.add(superClass);
        } else {
            break;
        }
    }
    for (int i = superClassesUpToCtorContainer.size() - 1; i >= 0; i--) {
        final TClass superClass = superClassesUpToCtorContainer.get(i);
        if (N4JSLanguageUtils.hasCovariantConstructor(superClass)) {
            return superClass;
        }
    }
    return baseContext;
}
Also used : MemberType(org.eclipse.n4js.ts.types.MemberType) Type(org.eclipse.n4js.ts.types.Type) ArrayList(java.util.ArrayList) TClass(org.eclipse.n4js.ts.types.TClass) ExtendedClassesIterable(org.eclipse.n4js.ts.types.util.ExtendedClassesIterable)

Aggregations

ArrayList (java.util.ArrayList)1 MemberType (org.eclipse.n4js.ts.types.MemberType)1 TClass (org.eclipse.n4js.ts.types.TClass)1 Type (org.eclipse.n4js.ts.types.Type)1 ExtendedClassesIterable (org.eclipse.n4js.ts.types.util.ExtendedClassesIterable)1