diff --git a/src/compiler/binder.ts b/src/compiler/binder.ts index eae59db1bc686..bed72b8ca3b08 100644 --- a/src/compiler/binder.ts +++ b/src/compiler/binder.ts @@ -1379,6 +1379,7 @@ namespace ts { } function bindJSDocTypeAlias(node: JSDocTypedefTag | JSDocCallbackTag) { + node.tagName.parent = node; if (node.fullName) { setParentPointers(node, node.fullName); } diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index 21122b5f7ed4c..3e98b6cbdbc86 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -462,52 +462,46 @@ namespace ts { return visitNodes(cbNode, cbNodes, (node).tags); case SyntaxKind.JSDocParameterTag: case SyntaxKind.JSDocPropertyTag: - if ((node as JSDocPropertyLikeTag).isNameFirst) { - return visitNode(cbNode, (node).name) || - visitNode(cbNode, (node).typeExpression); - } - else { - return visitNode(cbNode, (node).typeExpression) || - visitNode(cbNode, (node).name); - } - case SyntaxKind.JSDocReturnTag: - return visitNode(cbNode, (node).typeExpression); - case SyntaxKind.JSDocTypeTag: - return visitNode(cbNode, (node).typeExpression); + return visitNode(cbNode, (node as JSDocTag).tagName) || + ((node as JSDocPropertyLikeTag).isNameFirst + ? visitNode(cbNode, (node).name) || + visitNode(cbNode, (node).typeExpression) + : visitNode(cbNode, (node).typeExpression) || + visitNode(cbNode, (node).name)); case SyntaxKind.JSDocAugmentsTag: - return visitNode(cbNode, (node).class); + return visitNode(cbNode, (node as JSDocTag).tagName) || + visitNode(cbNode, (node).class); case SyntaxKind.JSDocTemplateTag: - return visitNode(cbNode, (node).constraint) || visitNodes(cbNode, cbNodes, (node).typeParameters); + return visitNode(cbNode, (node as JSDocTag).tagName) || + visitNode(cbNode, (node).constraint) || + visitNodes(cbNode, cbNodes, (node).typeParameters); case SyntaxKind.JSDocTypedefTag: - if ((node as JSDocTypedefTag).typeExpression && - (node as JSDocTypedefTag).typeExpression!.kind === SyntaxKind.JSDocTypeExpression) { - return visitNode(cbNode, (node).typeExpression) || - visitNode(cbNode, (node).fullName); - } - else { - return visitNode(cbNode, (node).fullName) || - visitNode(cbNode, (node).typeExpression); - } + return visitNode(cbNode, (node as JSDocTag).tagName) || + ((node as JSDocTypedefTag).typeExpression && + (node as JSDocTypedefTag).typeExpression!.kind === SyntaxKind.JSDocTypeExpression + ? visitNode(cbNode, (node).typeExpression) || + visitNode(cbNode, (node).fullName) + : visitNode(cbNode, (node).fullName) || + visitNode(cbNode, (node).typeExpression)); case SyntaxKind.JSDocCallbackTag: - return visitNode(cbNode, (node as JSDocCallbackTag).fullName) || + return visitNode(cbNode, (node as JSDocTag).tagName) || + visitNode(cbNode, (node as JSDocCallbackTag).fullName) || visitNode(cbNode, (node as JSDocCallbackTag).typeExpression); + case SyntaxKind.JSDocReturnTag: + case SyntaxKind.JSDocTypeTag: case SyntaxKind.JSDocThisTag: - return visitNode(cbNode, (node as JSDocThisTag).typeExpression); case SyntaxKind.JSDocEnumTag: - return visitNode(cbNode, (node as JSDocEnumTag).typeExpression); + return visitNode(cbNode, (node as JSDocTag).tagName) || + visitNode(cbNode, (node as JSDocReturnTag | JSDocTypeTag | JSDocThisTag | JSDocEnumTag).typeExpression); case SyntaxKind.JSDocSignature: - return visitNodes(cbNode, cbNodes, node.decorators) || - visitNodes(cbNode, cbNodes, node.modifiers) || - forEach((node).typeParameters, cbNode) || + return forEach((node).typeParameters, cbNode) || forEach((node).parameters, cbNode) || visitNode(cbNode, (node).type); case SyntaxKind.JSDocTypeLiteral: - if ((node as JSDocTypeLiteral).jsDocPropertyTags) { - for (const tag of (node as JSDocTypeLiteral).jsDocPropertyTags!) { - visitNode(cbNode, tag); - } - } - return; + return forEach((node as JSDocTypeLiteral).jsDocPropertyTags, cbNode); + case SyntaxKind.JSDocTag: + case SyntaxKind.JSDocClassTag: + return visitNode(cbNode, (node as JSDocTag).tagName); case SyntaxKind.PartiallyEmittedExpression: return visitNode(cbNode, (node).expression); } diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index 8813c705eb5f7..768af9509c27b 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -6772,7 +6772,7 @@ namespace ts { // TODO: determine what this does before making it public. /* @internal */ - export function isJSDocTag(node: Node): boolean { + export function isJSDocTag(node: Node): node is JSDocTag { return node.kind >= SyntaxKind.FirstJSDocTagNode && node.kind <= SyntaxKind.LastJSDocTagNode; } diff --git a/src/services/services.ts b/src/services/services.ts index afcdc7b4f1685..2abfe7095ecb4 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -1481,7 +1481,7 @@ namespace ts { function shouldGetType(sourceFile: SourceFile, node: Node, position: number): boolean { switch (node.kind) { case SyntaxKind.Identifier: - return !isLabelName(node); + return !isLabelName(node) && !isTagName(node); case SyntaxKind.PropertyAccessExpression: case SyntaxKind.QualifiedName: // Don't return quickInfo if inside the comment in `a/**/.b` @@ -2159,7 +2159,7 @@ namespace ts { function initializeNameTable(sourceFile: SourceFile): void { const nameTable = sourceFile.nameTable = createUnderscoreEscapedMap(); sourceFile.forEachChild(function walk(node) { - if (isIdentifier(node) && node.escapedText || isStringOrNumericLiteralLike(node) && literalIsName(node)) { + if (isIdentifier(node) && !isTagName(node) && node.escapedText || isStringOrNumericLiteralLike(node) && literalIsName(node)) { const text = getEscapedTextOfIdentifierOrLiteral(node); nameTable.set(text, nameTable.get(text) === undefined ? node.pos : -1); } diff --git a/src/services/utilities.ts b/src/services/utilities.ts index 61f6e6e60872c..d0b6b59e39bb1 100644 --- a/src/services/utilities.ts +++ b/src/services/utilities.ts @@ -246,6 +246,10 @@ namespace ts { return isLabelOfLabeledStatement(node) || isJumpStatementTarget(node); } + export function isTagName(node: Node): boolean { + return isJSDocTag(node.parent) && node.parent.tagName === node; + } + export function isRightSideOfQualifiedName(node: Node) { return node.parent.kind === SyntaxKind.QualifiedName && (node.parent).right === node; }