use of com.google.javascript.rhino.JSTypeExpression in project closure-compiler by google.
the class ClosureRewriteClass method mergeJsDocFor.
private JSDocInfo mergeJsDocFor(ClassDefinition cls, Node associatedNode) {
// avoid null checks
JSDocInfo classInfo = (cls.classInfo != null) ? cls.classInfo : new JSDocInfoBuilder(true).build(true);
JSDocInfo ctorInfo = (cls.constructor.info != null) ? cls.constructor.info : new JSDocInfoBuilder(true).build(true);
Node superNode = cls.superClass;
// Start with a clone of the constructor info if there is one.
JSDocInfoBuilder mergedInfo = cls.constructor.info != null ? JSDocInfoBuilder.copyFrom(ctorInfo) : new JSDocInfoBuilder(true);
// merge block description
String blockDescription = Joiner.on("\n").skipNulls().join(classInfo.getBlockDescription(), ctorInfo.getBlockDescription());
if (!blockDescription.isEmpty()) {
mergedInfo.recordBlockDescription(blockDescription);
}
// merge suppressions
Set<String> suppressions = new HashSet<>();
suppressions.addAll(classInfo.getSuppressions());
suppressions.addAll(ctorInfo.getSuppressions());
if (!suppressions.isEmpty()) {
mergedInfo.recordSuppressions(suppressions);
}
// Use class deprecation if set.
if (classInfo.isDeprecated()) {
mergedInfo.recordDeprecated();
}
String deprecationReason = null;
if (classInfo.getDeprecationReason() != null) {
deprecationReason = classInfo.getDeprecationReason();
mergedInfo.recordDeprecationReason(deprecationReason);
}
// Use class visibility if specifically set
Visibility visibility = classInfo.getVisibility();
if (visibility != null && visibility != JSDocInfo.Visibility.INHERITED) {
mergedInfo.recordVisibility(classInfo.getVisibility());
}
if (classInfo.isAbstract()) {
mergedInfo.recordAbstract();
}
if (classInfo.isConstant()) {
mergedInfo.recordConstancy();
}
if (classInfo.isExport()) {
mergedInfo.recordExport();
}
// If @ngInject is on the ctor, it's already been copied above.
if (classInfo.isNgInject()) {
compiler.report(JSError.make(associatedNode, GOOG_CLASS_NG_INJECT_ON_CLASS));
mergedInfo.recordNgInject(true);
}
if (classInfo.makesUnrestricted() || ctorInfo.makesUnrestricted()) {
mergedInfo.recordUnrestricted();
} else if (classInfo.makesDicts() || ctorInfo.makesDicts()) {
mergedInfo.recordDict();
} else {
// @struct by default
mergedInfo.recordStruct();
}
// @constructor is implied, @interface must be explicit
boolean isInterface = classInfo.isInterface() || ctorInfo.isInterface();
if (isInterface) {
if (classInfo.usesImplicitMatch() || ctorInfo.usesImplicitMatch()) {
mergedInfo.recordImplicitMatch();
} else {
mergedInfo.recordInterface();
}
List<JSTypeExpression> extendedInterfaces = null;
if (classInfo.getExtendedInterfacesCount() > 0) {
extendedInterfaces = classInfo.getExtendedInterfaces();
} else if (ctorInfo.getExtendedInterfacesCount() == 0 && superNode != null) {
extendedInterfaces = ImmutableList.of(new JSTypeExpression(new Node(Token.BANG, IR.string(superNode.getQualifiedName())), VIRTUAL_FILE));
}
if (extendedInterfaces != null) {
for (JSTypeExpression extend : extendedInterfaces) {
mergedInfo.recordExtendedInterface(extend);
}
}
} else {
// @constructor by default
mergedInfo.recordConstructor();
if (classInfo.getBaseType() != null) {
mergedInfo.recordBaseType(classInfo.getBaseType());
} else if (superNode != null) {
// a "super" implies @extends, build a default.
JSTypeExpression baseType = new JSTypeExpression(new Node(Token.BANG, IR.string(superNode.getQualifiedName())), VIRTUAL_FILE);
mergedInfo.recordBaseType(baseType);
}
// @implements from the class if they exist
List<JSTypeExpression> interfaces = classInfo.getImplementedInterfaces();
for (JSTypeExpression implemented : interfaces) {
mergedInfo.recordImplementedInterface(implemented);
}
}
// merge @template types if they exist
List<String> templateNames = new ArrayList<>();
templateNames.addAll(classInfo.getTemplateTypeNames());
templateNames.addAll(ctorInfo.getTemplateTypeNames());
for (String typeName : templateNames) {
mergedInfo.recordTemplateTypeName(typeName);
}
return mergedInfo.build();
}
use of com.google.javascript.rhino.JSTypeExpression in project closure-compiler by google.
the class Es6RewriteClass method visitNonMethodMember.
/**
* Visits class members other than simple methods: Getters, setters, and computed properties.
*/
private void visitNonMethodMember(Node member, ClassDeclarationMetadata metadata) {
if (member.isComputedProp() && member.isStaticMember()) {
cannotConvertYet(member, "Static computed property");
return;
}
if (member.isComputedProp() && !member.getFirstChild().isQualifiedName()) {
cannotConvert(member.getFirstChild(), "Computed property with non-qualified-name key");
return;
}
JSTypeExpression typeExpr = getTypeFromGetterOrSetter(member);
addToDefinePropertiesObject(metadata, member);
Map<String, JSDocInfo> membersToDeclare;
String memberName;
if (member.isComputedProp()) {
checkState(!member.isStaticMember());
membersToDeclare = metadata.prototypeComputedPropsToDeclare;
memberName = member.getFirstChild().getQualifiedName();
} else {
membersToDeclare = member.isStaticMember() ? metadata.classMembersToDeclare : metadata.prototypeMembersToDeclare;
memberName = member.getString();
}
JSDocInfo existingJSDoc = membersToDeclare.get(memberName);
JSTypeExpression existingType = existingJSDoc == null ? null : existingJSDoc.getType();
if (existingType != null && typeExpr != null && !existingType.equals(typeExpr)) {
compiler.report(JSError.make(member, CONFLICTING_GETTER_SETTER_TYPE, memberName));
} else {
JSDocInfoBuilder jsDoc = new JSDocInfoBuilder(false);
if (member.getJSDocInfo() != null && member.getJSDocInfo().isExport()) {
jsDoc.recordExport();
jsDoc.recordVisibility(Visibility.PUBLIC);
}
if (member.getJSDocInfo() != null && member.getJSDocInfo().isOverride()) {
jsDoc.recordOverride();
} else if (typeExpr == null) {
typeExpr = new JSTypeExpression(new Node(Token.QMARK), member.getSourceFileName());
}
if (typeExpr != null) {
jsDoc.recordType(typeExpr.copy());
}
if (member.isStaticMember() && !member.isComputedProp()) {
jsDoc.recordNoCollapse();
}
membersToDeclare.put(memberName, jsDoc.build());
}
}
use of com.google.javascript.rhino.JSTypeExpression in project closure-compiler by google.
the class FunctionTypeBuilder method inferInheritance.
/**
* Infer the role of the function (whether it's a constructor or interface)
* and what it inherits from in JSDocInfo.
*/
FunctionTypeBuilder inferInheritance(@Nullable JSDocInfo info) {
if (info != null) {
isConstructor = info.isConstructor();
isInterface = info.isInterface();
isAbstract = info.isAbstract();
makesStructs = info.makesStructs();
makesDicts = info.makesDicts();
if (makesStructs && !(isConstructor || isInterface)) {
reportWarning(CONSTRUCTOR_REQUIRED, "@struct", formatFnName());
} else if (makesDicts && !isConstructor) {
reportWarning(CONSTRUCTOR_REQUIRED, "@dict", formatFnName());
}
// TODO(b/74253232): maybeGetNativeTypesOfBuiltin should also handle cases where a local type
// declaration shadows a templatized native type.
ImmutableList<TemplateType> nativeClassTemplateTypeNames = typeRegistry.maybeGetTemplateTypesOfBuiltin(fnName);
ImmutableList<String> infoTemplateTypeNames = info.getTemplateTypeNames();
// Preconditions check. It currently fails for "var symbol" in the externs.
if (nativeClassTemplateTypeNames != null && infoTemplateTypeNames.size() == nativeClassTemplateTypeNames.size()) {
classTemplateTypeNames = nativeClassTemplateTypeNames;
typeRegistry.setTemplateTypeNames(classTemplateTypeNames);
} else {
// Otherwise, create new template type for
// the template values of the constructor/interface
// Class template types, which can be used in the scope of a constructor
// definition.
ImmutableList<String> typeParameters = info.getTemplateTypeNames();
if (!typeParameters.isEmpty() && (isConstructor || isInterface)) {
ImmutableList.Builder<TemplateType> builder = ImmutableList.builder();
for (String typeParameter : typeParameters) {
builder.add(typeRegistry.createTemplateType(typeParameter));
}
classTemplateTypeNames = builder.build();
typeRegistry.setTemplateTypeNames(classTemplateTypeNames);
}
}
// base type
if (info.hasBaseType()) {
if (isConstructor) {
JSType maybeBaseType = info.getBaseType().evaluate(scope, typeRegistry);
if (maybeBaseType != null && maybeBaseType.setValidator(new ExtendedTypeValidator())) {
baseType = (ObjectType) maybeBaseType;
}
} else {
reportWarning(EXTENDS_WITHOUT_TYPEDEF, formatFnName());
}
}
// Implemented interfaces (for constructors only).
if (info.getImplementedInterfaceCount() > 0) {
if (isConstructor) {
implementedInterfaces = new ArrayList<>();
Set<JSType> baseInterfaces = new HashSet<>();
for (JSTypeExpression t : info.getImplementedInterfaces()) {
JSType maybeInterType = t.evaluate(scope, typeRegistry);
if (maybeInterType != null && maybeInterType.setValidator(new ImplementedTypeValidator())) {
// Disallow implementing the same base (not templatized) interface
// type more than once.
JSType baseInterface = maybeInterType;
if (baseInterface.toMaybeTemplatizedType() != null) {
baseInterface = baseInterface.toMaybeTemplatizedType().getReferencedType();
}
if (!baseInterfaces.add(baseInterface)) {
reportWarning(SAME_INTERFACE_MULTIPLE_IMPLEMENTS, baseInterface.toString());
}
implementedInterfaces.add((ObjectType) maybeInterType);
}
}
} else if (isInterface) {
reportWarning(TypeCheck.CONFLICTING_IMPLEMENTED_TYPE, formatFnName());
} else {
reportWarning(CONSTRUCTOR_REQUIRED, "@implements", formatFnName());
}
}
// We've already emitted a warning if this is not an interface.
if (isInterface) {
extendedInterfaces = new ArrayList<>();
for (JSTypeExpression t : info.getExtendedInterfaces()) {
JSType maybeInterfaceType = t.evaluate(scope, typeRegistry);
if (maybeInterfaceType != null && maybeInterfaceType.setValidator(new ExtendedTypeValidator())) {
extendedInterfaces.add((ObjectType) maybeInterfaceType);
}
}
}
}
return this;
}
use of com.google.javascript.rhino.JSTypeExpression in project closure-compiler by google.
the class PolymerClassRewriter method rewritePolymerClassDeclaration.
/**
* Rewrites a class which extends Polymer.Element to a set of declarations and assignments which
* can be understood by the compiler.
*
* @param clazz The class node
* @param cls The extracted {@link PolymerClassDefinition} for the Polymer element created by this
* call.
*/
void rewritePolymerClassDeclaration(Node clazz, final PolymerClassDefinition cls, boolean isInGlobalScope) {
if (cls.descriptor != null) {
addTypesToFunctions(cls.descriptor, cls.target.getQualifiedName(), cls.defType);
}
PolymerPassStaticUtils.switchDollarSignPropsToBrackets(NodeUtil.getClassMembers(clazz), compiler);
for (MemberDefinition prop : cls.props) {
if (prop.value.isObjectLit()) {
PolymerPassStaticUtils.switchDollarSignPropsToBrackets(prop.value, compiler);
}
}
// For simplicity add everything into a block, before adding it to the AST.
Node block = IR.block();
appendPropertiesToBlock(cls, block, cls.target.getQualifiedName() + ".prototype.");
ImmutableList<MemberDefinition> readOnlyProps = parseReadOnlyProperties(cls, block);
ImmutableList<MemberDefinition> attributeReflectedProps = parseAttributeReflectedProperties(cls);
addInterfaceExterns(cls, readOnlyProps, attributeReflectedProps);
// If an external interface is required, mark the class as implementing it
if (!readOnlyProps.isEmpty() || !attributeReflectedProps.isEmpty()) {
JSDocInfoBuilder classInfo = JSDocInfoBuilder.maybeCopyFrom(clazz.getJSDocInfo());
String interfaceName = getInterfaceName(cls);
JSTypeExpression interfaceType = new JSTypeExpression(new Node(Token.BANG, IR.string(interfaceName)), VIRTUAL_FILE);
classInfo.recordImplementedInterface(interfaceType);
clazz.setJSDocInfo(classInfo.build());
}
if (block.hasChildren()) {
removePropertyDocs(cls.descriptor, cls.defType);
Node stmt = NodeUtil.getEnclosingStatement(clazz);
stmt.getParent().addChildrenAfter(block.removeChildren(), stmt);
compiler.reportChangeToEnclosingScope(stmt);
}
addReturnTypeIfMissing(cls, "is", new JSTypeExpression(IR.string("string"), VIRTUAL_FILE));
Node type = new Node(Token.BANG);
Node array = IR.string("Array");
type.addChildToBack(array);
Node arrayTemplateType = new Node(Token.BLOCK, IR.string("string"));
array.addChildToBack(arrayTemplateType);
addReturnTypeIfMissing(cls, "observers", new JSTypeExpression(type, VIRTUAL_FILE));
addReturnTypeIfMissing(cls, "properties", new JSTypeExpression(IR.string(POLYMER_ELEMENT_PROP_CONFIG), VIRTUAL_FILE));
// with the class members.
if (propertyRenamingEnabled && cls.descriptor != null) {
addObjectReflectionCall(cls, cls.descriptor);
}
}
use of com.google.javascript.rhino.JSTypeExpression in project closure-compiler by google.
the class PolymerClassRewriter method addInterfaceExterns.
/**
* Adds an interface for the given ClassDefinition to externs. This allows generated setter
* functions for read-only properties to avoid renaming altogether.
*
* @see https://www.polymer-project.org/0.8/docs/devguide/properties.html#read-only
*/
private void addInterfaceExterns(final PolymerClassDefinition cls, List<MemberDefinition> readOnlyProps, List<MemberDefinition> attributeReflectedProps) {
Node block = IR.block();
String interfaceName = getInterfaceName(cls);
Node fnNode = NodeUtil.emptyFunction();
compiler.reportChangeToChangeScope(fnNode);
Node varNode = IR.var(NodeUtil.newQName(compiler, interfaceName), fnNode);
JSDocInfoBuilder info = new JSDocInfoBuilder(true);
info.recordInterface();
varNode.setJSDocInfo(info.build());
block.addChildToBack(varNode);
if (polymerVersion == 1) {
// For Polymer 1, all declared properties are non-renameable
appendPropertiesToBlock(cls, block, interfaceName + ".prototype.");
} else {
List<MemberDefinition> interfaceProperties = new ArrayList<>();
interfaceProperties.addAll(readOnlyProps);
if (attributeReflectedProps != null) {
interfaceProperties.addAll(attributeReflectedProps);
}
// For Polymer 2, only read-only properties and reflectToAttribute properties are
// non-renameable. Other properties follow the ALL_UNQUOTED renaming rules.
PolymerClassDefinition tmpDef = new PolymerClassDefinition(cls.defType, cls.definition, cls.target, cls.descriptor, null, null, null, interfaceProperties, null, null);
// disallow renaming of readonly properties
appendPropertiesToBlock(tmpDef, block, interfaceName + ".prototype.");
}
for (MemberDefinition prop : readOnlyProps) {
// Add all _set* functions to avoid renaming.
String propName = prop.name.getString();
String setterName = "_set" + propName.substring(0, 1).toUpperCase() + propName.substring(1);
Node setterExprNode = IR.exprResult(NodeUtil.newQName(compiler, interfaceName + ".prototype." + setterName));
JSDocInfoBuilder setterInfo = new JSDocInfoBuilder(true);
JSTypeExpression propType = PolymerPassStaticUtils.getTypeFromProperty(prop, compiler);
setterInfo.recordParameter(propName, propType);
setterExprNode.getFirstChild().setJSDocInfo(setterInfo.build());
block.addChildToBack(setterExprNode);
}
block.useSourceInfoIfMissingFromForTree(polymerElementExterns);
Node scopeRoot = polymerElementExterns;
if (!scopeRoot.isScript()) {
scopeRoot = scopeRoot.getParent();
}
Node stmts = block.removeChildren();
scopeRoot.addChildrenToBack(stmts);
compiler.reportChangeToEnclosingScope(stmts);
}
Aggregations