Skip to content

Commit c66c324

Browse files
committed
Avoid duplicates when finding jsdoc (#24086)
* Avoid duplicates when finding jsdoc 1. Add a cheap assert for detecting duplicates. getJSDocTags must find either [1] 0 or 1 comments or [2] the first two comments must not be identical. This does not always find duplicates for nodes with 3 or more comments, but these nodes are exceptionally rare. This assert fired for over 20 of the around 250 tests we have that retrieve JSDoc at all. So I fixed the asserts in [2] and [3]. 2. There were overlapping cases from calls to getSourceOfAssignment and getSpecialPropertyAssignment. getSpecialPropertyAssignment is too restrictive, but was in the correct location (parent vs parent.parent), so I removed the getSourceOfAssignment call and replaced the getSpecialPropertyAssignment calls with a less restrictive check. 3. When a node's parent is a PropertyDeclaration, getJSDocCOmmentsAndTags would check the parent for jsdoc. But when the *node* is a PropertyDeclaration, getJSDocCommentsAndTags would use the jsdoc from the initializer. This second case is useful to make sure that property declarations get all their jsdoc, but results in duplicates for their initializers. I couldn't think of a better fix than tracking the previous node in the recursive lookup of getJSDocCommentsAndTags, which is a little clunky. * Fix lint; remove new context parameter * Update importJsNodeModule3 with fix
1 parent a724a66 commit c66c324

File tree

2 files changed

+10
-11
lines changed

2 files changed

+10
-11
lines changed

src/compiler/utilities.ts

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1848,9 +1848,9 @@ namespace ts {
18481848
(node as ModuleDeclaration).body;
18491849
}
18501850

1851-
export function getJSDocCommentsAndTags(node: Node): ReadonlyArray<JSDoc | JSDocTag> {
1851+
export function getJSDocCommentsAndTags(hostNode: Node): ReadonlyArray<JSDoc | JSDocTag> {
18521852
let result: (JSDoc | JSDocTag)[] | undefined;
1853-
getJSDocCommentsAndTagsWorker(node);
1853+
getJSDocCommentsAndTagsWorker(hostNode);
18541854
return result || emptyArray;
18551855

18561856
function getJSDocCommentsAndTagsWorker(node: Node): void {
@@ -1866,7 +1866,7 @@ namespace ts {
18661866
// */
18671867
// var x = function(name) { return name.length; }
18681868
if (parent.parent &&
1869-
(getSingleVariableOfVariableStatement(parent.parent) === node || getSourceOfAssignment(parent.parent))) {
1869+
(getSingleVariableOfVariableStatement(parent.parent) === node)) {
18701870
getJSDocCommentsAndTagsWorker(parent.parent);
18711871
}
18721872
if (parent.parent && parent.parent.parent &&
@@ -1875,8 +1875,8 @@ namespace ts {
18751875
getSourceOfDefaultedAssignment(parent.parent.parent))) {
18761876
getJSDocCommentsAndTagsWorker(parent.parent.parent);
18771877
}
1878-
if (isBinaryExpression(node) && getSpecialPropertyAssignmentKind(node) !== SpecialPropertyAssignmentKind.None ||
1879-
isBinaryExpression(parent) && getSpecialPropertyAssignmentKind(parent) !== SpecialPropertyAssignmentKind.None ||
1878+
if (isBinaryExpression(node) && node.operatorToken.kind === SyntaxKind.EqualsToken ||
1879+
isBinaryExpression(parent) && parent.operatorToken.kind === SyntaxKind.EqualsToken ||
18801880
node.kind === SyntaxKind.PropertyAccessExpression && node.parent && node.parent.kind === SyntaxKind.ExpressionStatement) {
18811881
getJSDocCommentsAndTagsWorker(parent);
18821882
}
@@ -1886,7 +1886,7 @@ namespace ts {
18861886
result = addRange(result, getJSDocParameterTags(node as ParameterDeclaration));
18871887
}
18881888

1889-
if (isVariableLike(node) && hasInitializer(node) && hasJSDocNodes(node.initializer)) {
1889+
if (isVariableLike(node) && hasInitializer(node) && node.initializer !== hostNode && hasJSDocNodes(node.initializer)) {
18901890
result = addRange(result, node.initializer.jsDoc);
18911891
}
18921892

@@ -4795,7 +4795,9 @@ namespace ts {
47954795
let tags = (node as JSDocContainer).jsDocCache;
47964796
// If cache is 'null', that means we did the work of searching for JSDoc tags and came up with nothing.
47974797
if (tags === undefined) {
4798-
(node as JSDocContainer).jsDocCache = tags = flatMap(getJSDocCommentsAndTags(node), j => isJSDoc(j) ? j.tags : j);
4798+
const comments = getJSDocCommentsAndTags(node);
4799+
Debug.assert(comments.length < 2 || comments[0] !== comments[1]);
4800+
(node as JSDocContainer).jsDocCache = tags = flatMap(comments, j => isJSDoc(j) ? j.tags : j);
47994801
}
48004802
return tags;
48014803
}

tests/cases/fourslash/importJsNodeModule3.ts

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -37,12 +37,9 @@ edit.backspace(2);
3737
edit.insert('z(');
3838
verify.signatureHelp({
3939
text: "z(a: number | boolean, b: string[]): string",
40-
// TODO: GH#24129
41-
parameterDocComment: "The first param\nThe first param",
40+
parameterDocComment: "The first param",
4241
tags: [
4342
{ name: "param", text: "a The first param" },
4443
{ name: "param", text: "b The second param" },
45-
{ name: "param", text: "a The first param" },
46-
{ name: "param", text: "b The second param" },
4744
],
4845
});

0 commit comments

Comments
 (0)