Search in sources :

Example 1 with TemplateTypeMapReplacer

use of com.google.javascript.rhino.jstype.TemplateTypeMapReplacer in project closure-compiler by google.

the class TypeCheck method checkDeclaredPropertyInheritance.

/**
 * Given a constructor type and a property name, check that the property has
 * the JSDoc annotation @override iff the property is declared on a
 * superclass. Several checks regarding inheritance correctness are also
 * performed.
 */
private void checkDeclaredPropertyInheritance(NodeTraversal t, Node n, FunctionType ctorType, String propertyName, JSDocInfo info, JSType propertyType) {
    // already.
    if (hasUnknownOrEmptySupertype(ctorType)) {
        return;
    }
    FunctionType superClass = ctorType.getSuperClassConstructor();
    boolean superClassHasProperty = superClass != null && superClass.getInstanceType().hasProperty(propertyName);
    boolean superClassHasDeclaredProperty = superClass != null && superClass.getInstanceType().isPropertyTypeDeclared(propertyName);
    // For interface
    boolean superInterfaceHasProperty = false;
    boolean superInterfaceHasDeclaredProperty = false;
    if (ctorType.isInterface()) {
        for (ObjectType interfaceType : ctorType.getExtendedInterfaces()) {
            superInterfaceHasProperty = superInterfaceHasProperty || interfaceType.hasProperty(propertyName);
            superInterfaceHasDeclaredProperty = superInterfaceHasDeclaredProperty || interfaceType.isPropertyTypeDeclared(propertyName);
        }
    }
    boolean declaredOverride = info != null && info.isOverride();
    boolean foundInterfaceProperty = false;
    if (ctorType.isConstructor()) {
        for (JSType implementedInterface : ctorType.getAllImplementedInterfaces()) {
            if (implementedInterface.isUnknownType() || implementedInterface.isEmptyType()) {
                continue;
            }
            FunctionType interfaceType = implementedInterface.toObjectType().getConstructor();
            checkNotNull(interfaceType);
            boolean interfaceHasProperty = interfaceType.getPrototype().hasProperty(propertyName);
            foundInterfaceProperty = foundInterfaceProperty || interfaceHasProperty;
            if (!declaredOverride && interfaceHasProperty && !"__proto__".equals(propertyName)) {
                // @override not present, but the property does override an interface property
                compiler.report(t.makeError(n, HIDDEN_INTERFACE_PROPERTY, propertyName, interfaceType.getTopMostDefiningType(propertyName).toString()));
            }
        }
    }
    if (!declaredOverride && !superClassHasProperty && !superInterfaceHasProperty) {
        // nothing to do here, it's just a plain new property
        return;
    }
    ObjectType topInstanceType = superClassHasDeclaredProperty ? superClass.getTopMostDefiningType(propertyName) : null;
    boolean declaredLocally = ctorType.isConstructor() && (ctorType.getPrototype().hasOwnProperty(propertyName) || ctorType.getInstanceType().hasOwnProperty(propertyName));
    if (!declaredOverride && superClassHasDeclaredProperty && declaredLocally && !"__proto__".equals(propertyName)) {
        // @override not present, but the property does override a superclass
        // property
        compiler.report(t.makeError(n, HIDDEN_SUPERCLASS_PROPERTY, propertyName, topInstanceType.toString()));
    }
    // @override is present and we have to check that it is ok
    if (superClassHasDeclaredProperty) {
        // there is a superclass implementation
        JSType superClassPropType = superClass.getInstanceType().getPropertyType(propertyName);
        TemplateTypeMap ctorTypeMap = ctorType.getTypeOfThis().getTemplateTypeMap();
        if (!ctorTypeMap.isEmpty()) {
            superClassPropType = superClassPropType.visit(new TemplateTypeMapReplacer(typeRegistry, ctorTypeMap));
        }
        if (!propertyType.isSubtype(superClassPropType, this.subtypingMode)) {
            compiler.report(t.makeError(n, HIDDEN_SUPERCLASS_PROPERTY_MISMATCH, propertyName, topInstanceType.toString(), superClassPropType.toString(), propertyType.toString()));
        }
    } else if (superInterfaceHasDeclaredProperty) {
        // there is an super interface property
        for (ObjectType interfaceType : ctorType.getExtendedInterfaces()) {
            if (interfaceType.hasProperty(propertyName)) {
                JSType superPropertyType = interfaceType.getPropertyType(propertyName);
                if (!propertyType.isSubtype(superPropertyType, this.subtypingMode)) {
                    topInstanceType = interfaceType.getConstructor().getTopMostDefiningType(propertyName);
                    compiler.report(t.makeError(n, HIDDEN_SUPERCLASS_PROPERTY_MISMATCH, propertyName, topInstanceType.toString(), superPropertyType.toString(), propertyType.toString()));
                }
            }
        }
    } else if (!foundInterfaceProperty && !superClassHasProperty && !superInterfaceHasProperty) {
        // there is no superclass nor interface implementation
        compiler.report(t.makeError(n, UNKNOWN_OVERRIDE, propertyName, ctorType.getInstanceType().toString()));
    }
}
Also used : ObjectType(com.google.javascript.rhino.jstype.ObjectType) TemplateTypeMap(com.google.javascript.rhino.jstype.TemplateTypeMap) JSType(com.google.javascript.rhino.jstype.JSType) TemplateTypeMapReplacer(com.google.javascript.rhino.jstype.TemplateTypeMapReplacer) FunctionType(com.google.javascript.rhino.jstype.FunctionType)

Example 2 with TemplateTypeMapReplacer

use of com.google.javascript.rhino.jstype.TemplateTypeMapReplacer in project closure-compiler by google.

the class TypeValidator method expectInterfaceProperty.

/**
 * Expect that the property in an interface that this type implements is
 * implemented and correctly typed.
 */
private void expectInterfaceProperty(NodeTraversal t, Node n, ObjectType instance, ObjectType implementedInterface, String prop) {
    StaticTypedSlot<JSType> propSlot = instance.getSlot(prop);
    if (propSlot == null) {
        // Not implemented
        String sourceName = n.getSourceFileName();
        sourceName = nullToEmpty(sourceName);
        TypeMismatch.registerMismatch(this.mismatches, this.implicitInterfaceUses, instance, implementedInterface, report(JSError.make(n, INTERFACE_METHOD_NOT_IMPLEMENTED, prop, implementedInterface.toString(), instance.toString())));
    } else {
        Node propNode = propSlot.getDeclaration() == null ? null : propSlot.getDeclaration().getNode();
        // Fall back on the constructor node if we can't find a node for the
        // property.
        propNode = propNode == null ? n : propNode;
        JSType found = propSlot.getType();
        found = found.restrictByNotNullOrUndefined();
        JSType required = implementedInterface.getImplicitPrototype().getPropertyType(prop);
        TemplateTypeMap typeMap = implementedInterface.getTemplateTypeMap();
        if (!typeMap.isEmpty()) {
            TemplateTypeMapReplacer replacer = new TemplateTypeMapReplacer(typeRegistry, typeMap);
            required = required.visit(replacer);
        }
        required = required.restrictByNotNullOrUndefined();
        if (!found.isSubtype(required, this.subtypingMode)) {
            // Implemented, but not correctly typed
            FunctionType constructor = implementedInterface.toObjectType().getConstructor();
            JSError err = t.makeError(propNode, HIDDEN_INTERFACE_PROPERTY_MISMATCH, prop, instance.toString(), constructor.getTopMostDefiningType(prop).toString(), required.toString(), found.toString());
            TypeMismatch.registerMismatch(this.mismatches, this.implicitInterfaceUses, found, required, err);
            report(err);
        }
    }
}
Also used : TemplateTypeMap(com.google.javascript.rhino.jstype.TemplateTypeMap) JSType(com.google.javascript.rhino.jstype.JSType) TemplateTypeMapReplacer(com.google.javascript.rhino.jstype.TemplateTypeMapReplacer) Node(com.google.javascript.rhino.Node) FunctionType(com.google.javascript.rhino.jstype.FunctionType)

Aggregations

FunctionType (com.google.javascript.rhino.jstype.FunctionType)2 JSType (com.google.javascript.rhino.jstype.JSType)2 TemplateTypeMap (com.google.javascript.rhino.jstype.TemplateTypeMap)2 TemplateTypeMapReplacer (com.google.javascript.rhino.jstype.TemplateTypeMapReplacer)2 Node (com.google.javascript.rhino.Node)1 ObjectType (com.google.javascript.rhino.jstype.ObjectType)1