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
This commit is contained in:
Nathan Shively-Sanders 2018-05-15 15:12:29 -07:00 committed by GitHub
parent 77168e5d50
commit 339a56fbf0
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 10 additions and 11 deletions

View file

@ -1842,9 +1842,9 @@ namespace ts {
(node as ModuleDeclaration).body;
}
export function getJSDocCommentsAndTags(node: Node): ReadonlyArray<JSDoc | JSDocTag> {
export function getJSDocCommentsAndTags(hostNode: Node): ReadonlyArray<JSDoc | JSDocTag> {
let result: (JSDoc | JSDocTag)[] | undefined;
getJSDocCommentsAndTagsWorker(node);
getJSDocCommentsAndTagsWorker(hostNode);
return result || emptyArray;
function getJSDocCommentsAndTagsWorker(node: Node): void {
@ -1860,7 +1860,7 @@ namespace ts {
// */
// var x = function(name) { return name.length; }
if (parent.parent &&
(getSingleVariableOfVariableStatement(parent.parent) === node || getSourceOfAssignment(parent.parent))) {
(getSingleVariableOfVariableStatement(parent.parent) === node)) {
getJSDocCommentsAndTagsWorker(parent.parent);
}
if (parent.parent && parent.parent.parent &&
@ -1869,8 +1869,8 @@ namespace ts {
getSourceOfDefaultedAssignment(parent.parent.parent))) {
getJSDocCommentsAndTagsWorker(parent.parent.parent);
}
if (isBinaryExpression(node) && getSpecialPropertyAssignmentKind(node) !== SpecialPropertyAssignmentKind.None ||
isBinaryExpression(parent) && getSpecialPropertyAssignmentKind(parent) !== SpecialPropertyAssignmentKind.None ||
if (isBinaryExpression(node) && node.operatorToken.kind === SyntaxKind.EqualsToken ||
isBinaryExpression(parent) && parent.operatorToken.kind === SyntaxKind.EqualsToken ||
node.kind === SyntaxKind.PropertyAccessExpression && node.parent && node.parent.kind === SyntaxKind.ExpressionStatement) {
getJSDocCommentsAndTagsWorker(parent);
}
@ -1880,7 +1880,7 @@ namespace ts {
result = addRange(result, getJSDocParameterTags(node as ParameterDeclaration));
}
if (isVariableLike(node) && hasInitializer(node) && hasJSDocNodes(node.initializer)) {
if (isVariableLike(node) && hasInitializer(node) && node.initializer !== hostNode && hasJSDocNodes(node.initializer)) {
result = addRange(result, node.initializer.jsDoc);
}
@ -4771,7 +4771,9 @@ namespace ts {
let tags = (node as JSDocContainer).jsDocCache;
// If cache is 'null', that means we did the work of searching for JSDoc tags and came up with nothing.
if (tags === undefined) {
(node as JSDocContainer).jsDocCache = tags = flatMap(getJSDocCommentsAndTags(node), j => isJSDoc(j) ? j.tags : j);
const comments = getJSDocCommentsAndTags(node);
Debug.assert(comments.length < 2 || comments[0] !== comments[1]);
(node as JSDocContainer).jsDocCache = tags = flatMap(comments, j => isJSDoc(j) ? j.tags : j);
}
return tags;
}

View file

@ -37,12 +37,9 @@ edit.backspace(2);
edit.insert('z(');
verify.signatureHelp({
text: "z(a: number | boolean, b: string[]): string",
// TODO: GH#24129
parameterDocComment: "The first param\nThe first param",
parameterDocComment: "The first param",
tags: [
{ name: "param", text: "a The first param" },
{ name: "param", text: "b The second param" },
{ name: "param", text: "a The first param" },
{ name: "param", text: "b The second param" },
],
});