Better JSDoc generic errors and faster isInJSDoc

This commit is contained in:
Nathan Shively-Sanders 2017-07-14 11:07:20 -07:00
parent f1145c35ca
commit 40ae42221e
4 changed files with 14 additions and 8 deletions

View File

@ -18454,8 +18454,9 @@ namespace ts {
function checkTypeReferenceNode(node: TypeReferenceNode | ExpressionWithTypeArguments) {
checkGrammarTypeArguments(node, node.typeArguments);
if (node.kind === SyntaxKind.TypeReference && node.typeName.jsdocDot && !isInJavaScriptFile(node) && !findAncestor(node, n => n.kind === SyntaxKind.JSDocTypeExpression)) {
grammarErrorOnNode(node, Diagnostics.JSDoc_types_can_only_be_used_inside_documentation_comments);
if (node.kind === SyntaxKind.TypeReference && node.typeName.jsdocDotPos !== undefined && !isInJavaScriptFile(node) && !isInJSDoc(node)) {
grammarErrorAtPos(getSourceFileOfNode(node), node.typeName.jsdocDotPos, 1, Diagnostics.JSDoc_types_can_only_be_used_inside_documentation_comments);
}
const type = getTypeFromTypeReference(node);
if (type !== unknownType) {
@ -22046,7 +22047,7 @@ namespace ts {
case SyntaxKind.JSDocNullableType:
case SyntaxKind.JSDocAllType:
case SyntaxKind.JSDocUnknownType:
if (!isInJavaScriptFile(node) && !findAncestor(node, n => n.kind === SyntaxKind.JSDocTypeExpression)) {
if (!isInJavaScriptFile(node) && !isInJSDoc(node)) {
grammarErrorOnNode(node, Diagnostics.JSDoc_types_can_only_be_used_inside_documentation_comments);
}
return;

View File

@ -1925,10 +1925,11 @@ namespace ts {
// The allowReservedWords parameter controls whether reserved words are permitted after the first dot
function parseEntityName(allowReservedWords: boolean, diagnosticMessage?: DiagnosticMessage): EntityName {
let entity: EntityName = allowReservedWords ? parseIdentifierName() : parseIdentifier(diagnosticMessage);
let dotPos = scanner.getStartPos();
while (parseOptional(SyntaxKind.DotToken)) {
if (token() === SyntaxKind.LessThanToken) {
// the entity is part of a JSDoc-style generic, so record this for later in case it's an error
entity.jsdocDot = true;
// the entity is part of a JSDoc-style generic, so record the trailing dot for later error reporting
entity.jsdocDotPos = dotPos;
break;
}
const node: QualifiedName = <QualifiedName>createNode(SyntaxKind.QualifiedName, entity.pos);

View File

@ -576,7 +576,7 @@ namespace ts {
/*@internal*/ autoGenerateId?: number; // Ensures unique generated identifiers get unique names, but clones get the same name.
isInJSDocNamespace?: boolean; // if the node is a member in a JSDoc namespace
/*@internal*/ typeArguments?: NodeArray<TypeNode>; // Only defined on synthesized nodes. Though not syntactically valid, used in emitting diagnostics.
/*@internal*/ jsdocDot?: boolean; // Identifier occurs in JSDoc-style generic: Id.<T>
/*@internal*/ jsdocDotPos?: number; // Identifier occurs in JSDoc-style generic: Id.<T>
}
// Transient identifier node (marked by id === -1)
@ -596,7 +596,7 @@ namespace ts {
kind: SyntaxKind.QualifiedName;
left: EntityName;
right: Identifier;
/*@internal*/ jsdocDot?: boolean; // Identifier occurs in JSDoc-style generic: Id1.Id2.<T>
/*@internal*/ jsdocDotPos?: number; // QualifiedName occurs in JSDoc-style generic: Id1.Id2.<T>
}
export type EntityName = Identifier | QualifiedName;

View File

@ -1292,6 +1292,10 @@ namespace ts {
return node && !!(node.flags & NodeFlags.JavaScriptFile);
}
export function isInJSDoc(node: Node): boolean {
return node && !!(node.flags & NodeFlags.JSDoc);
}
/**
* Returns true if the node is a CallExpression to the identifier 'require' with
* exactly one argument (of the form 'require("name")').
@ -3299,7 +3303,7 @@ namespace ts {
}
export function isJSDocTypeReference(node: TypeReferenceType): node is TypeReferenceNode {
return node.kind === SyntaxKind.TypeReference && !!findAncestor(node, n => n.kind === SyntaxKind.JSDocTypeExpression);
return node.flags & NodeFlags.JSDoc && node.kind === SyntaxKind.TypeReference;
}
/**