Skip to content

Commit 339a56f

Browse files
authored
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 77168e5 commit 339a56f

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
@@ -1842,9 +1842,9 @@ namespace ts {
18421842
(node as ModuleDeclaration).body;
18431843
}
18441844

1845-
export function getJSDocCommentsAndTags(node: Node): ReadonlyArray<JSDoc | JSDocTag> {
1845+
export function getJSDocCommentsAndTags(hostNode: Node): ReadonlyArray<JSDoc | JSDocTag> {
18461846
let result: (JSDoc | JSDocTag)[] | undefined;
1847-
getJSDocCommentsAndTagsWorker(node);
1847+
getJSDocCommentsAndTagsWorker(hostNode);
18481848
return result || emptyArray;
18491849

18501850
function getJSDocCommentsAndTagsWorker(node: Node): void {
@@ -1860,7 +1860,7 @@ namespace ts {
18601860
// */
18611861
// var x = function(name) { return name.length; }
18621862
if (parent.parent &&
1863-
(getSingleVariableOfVariableStatement(parent.parent) === node || getSourceOfAssignment(parent.parent))) {
1863+
(getSingleVariableOfVariableStatement(parent.parent) === node)) {
18641864
getJSDocCommentsAndTagsWorker(parent.parent);
18651865
}
18661866
if (parent.parent && parent.parent.parent &&
@@ -1869,8 +1869,8 @@ namespace ts {
18691869
getSourceOfDefaultedAssignment(parent.parent.parent))) {
18701870
getJSDocCommentsAndTagsWorker(parent.parent.parent);
18711871
}
1872-
if (isBinaryExpression(node) && getSpecialPropertyAssignmentKind(node) !== SpecialPropertyAssignmentKind.None ||
1873-
isBinaryExpression(parent) && getSpecialPropertyAssignmentKind(parent) !== SpecialPropertyAssignmentKind.None ||
1872+
if (isBinaryExpression(node) && node.operatorToken.kind === SyntaxKind.EqualsToken ||
1873+
isBinaryExpression(parent) && parent.operatorToken.kind === SyntaxKind.EqualsToken ||
18741874
node.kind === SyntaxKind.PropertyAccessExpression && node.parent && node.parent.kind === SyntaxKind.ExpressionStatement) {
18751875
getJSDocCommentsAndTagsWorker(parent);
18761876
}
@@ -1880,7 +1880,7 @@ namespace ts {
18801880
result = addRange(result, getJSDocParameterTags(node as ParameterDeclaration));
18811881
}
18821882

1883-
if (isVariableLike(node) && hasInitializer(node) && hasJSDocNodes(node.initializer)) {
1883+
if (isVariableLike(node) && hasInitializer(node) && node.initializer !== hostNode && hasJSDocNodes(node.initializer)) {
18841884
result = addRange(result, node.initializer.jsDoc);
18851885
}
18861886

@@ -4771,7 +4771,9 @@ namespace ts {
47714771
let tags = (node as JSDocContainer).jsDocCache;
47724772
// If cache is 'null', that means we did the work of searching for JSDoc tags and came up with nothing.
47734773
if (tags === undefined) {
4774-
(node as JSDocContainer).jsDocCache = tags = flatMap(getJSDocCommentsAndTags(node), j => isJSDoc(j) ? j.tags : j);
4774+
const comments = getJSDocCommentsAndTags(node);
4775+
Debug.assert(comments.length < 2 || comments[0] !== comments[1]);
4776+
(node as JSDocContainer).jsDocCache = tags = flatMap(comments, j => isJSDoc(j) ? j.tags : j);
47754777
}
47764778
return tags;
47774779
}

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)