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()));
}
}
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);
}
}
}
Aggregations