From 00be0ce1fd3da367a8afceabe7cef337aead3137 Mon Sep 17 00:00:00 2001 From: Klaus Meinhardt Date: Mon, 5 Nov 2018 20:26:44 +0000 Subject: [PATCH 1/5] forEachChild: handle JSDocTags and all their children --- src/compiler/parser.ts | 69 +++++++++++++++++++++--------------------- 1 file changed, 34 insertions(+), 35 deletions(-) diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index 77bf0351242f0..43fae6bc4d474 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -462,52 +462,51 @@ 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).atToken) || 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).atToken) || + 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).atToken) || + 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).atToken) || + 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).atToken) || + 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).atToken) || + 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).atToken) || visitNode(cbNode, (node as JSDocTag).tagName); case SyntaxKind.PartiallyEmittedExpression: return visitNode(cbNode, (node).expression); } From cb1d66b274c7ef40642701800adc53838f27effe Mon Sep 17 00:00:00 2001 From: Klaus Meinhardt Date: Mon, 5 Nov 2018 20:26:57 +0000 Subject: [PATCH 2/5] fix codefix for unused identifier --- src/services/codefixes/fixUnusedIdentifier.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/services/codefixes/fixUnusedIdentifier.ts b/src/services/codefixes/fixUnusedIdentifier.ts index 2905f0b131b25..e13b60532dd51 100644 --- a/src/services/codefixes/fixUnusedIdentifier.ts +++ b/src/services/codefixes/fixUnusedIdentifier.ts @@ -22,8 +22,8 @@ namespace ts.codefix { const sourceFiles = program.getSourceFiles(); const token = getTokenAtPosition(sourceFile, context.span.start); - if (isJSDocTemplateTag(token)) { - return [createDeleteFix(textChanges.ChangeTracker.with(context, t => t.delete(sourceFile, token)), Diagnostics.Remove_template_tag)]; + if (token.kind === ts.SyntaxKind.AtToken && isJSDocTemplateTag(token.parent)) { + return [createDeleteFix(textChanges.ChangeTracker.with(context, t => t.delete(sourceFile, token.parent)), Diagnostics.Remove_template_tag)]; } if (token.kind === SyntaxKind.LessThanToken) { const changes = textChanges.ChangeTracker.with(context, t => deleteTypeParameters(t, sourceFile, token)); @@ -84,8 +84,8 @@ namespace ts.codefix { if (importDecl) { changes.delete(sourceFile, importDecl); } - else if (isJSDocTemplateTag(token)) { - changes.delete(sourceFile, token); + else if (token.kind === ts.SyntaxKind.AtToken && isJSDocTemplateTag(token.parent)) { + changes.delete(sourceFile, token.parent); } else if (token.kind === SyntaxKind.LessThanToken) { deleteTypeParameters(changes, sourceFile, token); From 5fb2b3df601184ff5bd4a03a64d212c4162a8dcd Mon Sep 17 00:00:00 2001 From: Klaus Meinhardt Date: Mon, 5 Nov 2018 20:27:13 +0000 Subject: [PATCH 3/5] fix lint --- src/services/codefixes/fixUnusedIdentifier.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/services/codefixes/fixUnusedIdentifier.ts b/src/services/codefixes/fixUnusedIdentifier.ts index e13b60532dd51..c1b5cd14a573e 100644 --- a/src/services/codefixes/fixUnusedIdentifier.ts +++ b/src/services/codefixes/fixUnusedIdentifier.ts @@ -22,7 +22,7 @@ namespace ts.codefix { const sourceFiles = program.getSourceFiles(); const token = getTokenAtPosition(sourceFile, context.span.start); - if (token.kind === ts.SyntaxKind.AtToken && isJSDocTemplateTag(token.parent)) { + if (token.kind === SyntaxKind.AtToken && isJSDocTemplateTag(token.parent)) { return [createDeleteFix(textChanges.ChangeTracker.with(context, t => t.delete(sourceFile, token.parent)), Diagnostics.Remove_template_tag)]; } if (token.kind === SyntaxKind.LessThanToken) { @@ -84,7 +84,7 @@ namespace ts.codefix { if (importDecl) { changes.delete(sourceFile, importDecl); } - else if (token.kind === ts.SyntaxKind.AtToken && isJSDocTemplateTag(token.parent)) { + else if (token.kind === SyntaxKind.AtToken && isJSDocTemplateTag(token.parent)) { changes.delete(sourceFile, token.parent); } else if (token.kind === SyntaxKind.LessThanToken) { From ea558ede869deb5ef5ec4ca7b406153a3f809aea Mon Sep 17 00:00:00 2001 From: Klaus Meinhardt Date: Tue, 6 Nov 2018 18:13:49 +0000 Subject: [PATCH 4/5] fix build --- src/compiler/parser.ts | 19 +++++++------------ src/services/codefixes/fixUnusedIdentifier.ts | 4 ++-- 2 files changed, 9 insertions(+), 14 deletions(-) diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index b74768f02f01d..3e98b6cbdbc86 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -462,24 +462,21 @@ namespace ts { return visitNodes(cbNode, cbNodes, (node).tags); case SyntaxKind.JSDocParameterTag: case SyntaxKind.JSDocPropertyTag: - return visitNode(cbNode, (node as JSDocTag).atToken) || visitNode(cbNode, (node as JSDocTag).tagName) || + 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 as JSDocTag).atToken) || - visitNode(cbNode, (node as JSDocTag).tagName) || + return visitNode(cbNode, (node as JSDocTag).tagName) || visitNode(cbNode, (node).class); case SyntaxKind.JSDocTemplateTag: - return visitNode(cbNode, (node as JSDocTag).atToken) || - visitNode(cbNode, (node as JSDocTag).tagName) || + return visitNode(cbNode, (node as JSDocTag).tagName) || visitNode(cbNode, (node).constraint) || visitNodes(cbNode, cbNodes, (node).typeParameters); case SyntaxKind.JSDocTypedefTag: - return visitNode(cbNode, (node as JSDocTag).atToken) || - visitNode(cbNode, (node as JSDocTag).tagName) || + return visitNode(cbNode, (node as JSDocTag).tagName) || ((node as JSDocTypedefTag).typeExpression && (node as JSDocTypedefTag).typeExpression!.kind === SyntaxKind.JSDocTypeExpression ? visitNode(cbNode, (node).typeExpression) || @@ -487,16 +484,14 @@ namespace ts { : visitNode(cbNode, (node).fullName) || visitNode(cbNode, (node).typeExpression)); case SyntaxKind.JSDocCallbackTag: - return visitNode(cbNode, (node as JSDocTag).atToken) || - visitNode(cbNode, (node as JSDocTag).tagName) || + 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: case SyntaxKind.JSDocEnumTag: - return visitNode(cbNode, (node as JSDocTag).atToken) || - visitNode(cbNode, (node as JSDocTag).tagName) || + return visitNode(cbNode, (node as JSDocTag).tagName) || visitNode(cbNode, (node as JSDocReturnTag | JSDocTypeTag | JSDocThisTag | JSDocEnumTag).typeExpression); case SyntaxKind.JSDocSignature: return forEach((node).typeParameters, cbNode) || @@ -506,7 +501,7 @@ namespace ts { return forEach((node as JSDocTypeLiteral).jsDocPropertyTags, cbNode); case SyntaxKind.JSDocTag: case SyntaxKind.JSDocClassTag: - return visitNode(cbNode, (node as JSDocTag).atToken) || visitNode(cbNode, (node as JSDocTag).tagName); + return visitNode(cbNode, (node as JSDocTag).tagName); case SyntaxKind.PartiallyEmittedExpression: return visitNode(cbNode, (node).expression); } diff --git a/src/services/codefixes/fixUnusedIdentifier.ts b/src/services/codefixes/fixUnusedIdentifier.ts index c1b5cd14a573e..8997368a6b432 100644 --- a/src/services/codefixes/fixUnusedIdentifier.ts +++ b/src/services/codefixes/fixUnusedIdentifier.ts @@ -22,8 +22,8 @@ namespace ts.codefix { const sourceFiles = program.getSourceFiles(); const token = getTokenAtPosition(sourceFile, context.span.start); - if (token.kind === SyntaxKind.AtToken && isJSDocTemplateTag(token.parent)) { - return [createDeleteFix(textChanges.ChangeTracker.with(context, t => t.delete(sourceFile, token.parent)), Diagnostics.Remove_template_tag)]; + if (isJSDocTemplateTag(token)) { + return [createDeleteFix(textChanges.ChangeTracker.with(context, t => t.delete(sourceFile, token)), Diagnostics.Remove_template_tag)]; } if (token.kind === SyntaxKind.LessThanToken) { const changes = textChanges.ChangeTracker.with(context, t => deleteTypeParameters(t, sourceFile, token)); From c2cdce3cd675c87e5806dc67c9bb6e8261b0c04d Mon Sep 17 00:00:00 2001 From: Andy Hanson Date: Tue, 6 Nov 2018 17:15:52 -0800 Subject: [PATCH 5/5] Fix test failures --- src/compiler/binder.ts | 1 + src/compiler/utilities.ts | 2 +- src/services/codefixes/fixUnusedIdentifier.ts | 4 ++-- src/services/services.ts | 4 ++-- src/services/utilities.ts | 4 ++++ 5 files changed, 10 insertions(+), 5 deletions(-) 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/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/codefixes/fixUnusedIdentifier.ts b/src/services/codefixes/fixUnusedIdentifier.ts index 8997368a6b432..2905f0b131b25 100644 --- a/src/services/codefixes/fixUnusedIdentifier.ts +++ b/src/services/codefixes/fixUnusedIdentifier.ts @@ -84,8 +84,8 @@ namespace ts.codefix { if (importDecl) { changes.delete(sourceFile, importDecl); } - else if (token.kind === SyntaxKind.AtToken && isJSDocTemplateTag(token.parent)) { - changes.delete(sourceFile, token.parent); + else if (isJSDocTemplateTag(token)) { + changes.delete(sourceFile, token); } else if (token.kind === SyntaxKind.LessThanToken) { deleteTypeParameters(changes, sourceFile, token); 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; }