Skip to content

Commit 1ea1254

Browse files
authored
Merge pull request microsoft#19355 from Microsoft/sandersn/fix-getParameterSymbolFromJSDoc
fix getParameterSymbolFromJSDoc
2 parents 8a22767 + 8cc2af5 commit 1ea1254

5 files changed

+167
-32
lines changed

src/compiler/utilities.ts

Lines changed: 43 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1538,6 +1538,34 @@ namespace ts {
15381538
return getJSDocCommentsAndTags(node);
15391539
}
15401540

1541+
export function getSourceOfAssignment(node: Node): Node {
1542+
return isExpressionStatement(node) &&
1543+
node.expression && isBinaryExpression(node.expression) &&
1544+
node.expression.operatorToken.kind === SyntaxKind.EqualsToken &&
1545+
node.expression.right;
1546+
}
1547+
1548+
export function getSingleInitializerOfVariableStatement(node: Node, child?: Node): Node {
1549+
return isVariableStatement(node) &&
1550+
node.declarationList.declarations.length > 0 &&
1551+
(!child || node.declarationList.declarations[0].initializer === child) &&
1552+
node.declarationList.declarations[0].initializer;
1553+
}
1554+
1555+
export function getSingleVariableOfVariableStatement(node: Node, child?: Node): Node {
1556+
return isVariableStatement(node) &&
1557+
node.declarationList.declarations.length > 0 &&
1558+
(!child || node.declarationList.declarations[0] === child) &&
1559+
node.declarationList.declarations[0];
1560+
}
1561+
1562+
export function getNestedModuleDeclaration(node: Node): Node {
1563+
return node.kind === SyntaxKind.ModuleDeclaration &&
1564+
(node as ModuleDeclaration).body &&
1565+
(node as ModuleDeclaration).body.kind === SyntaxKind.ModuleDeclaration &&
1566+
(node as ModuleDeclaration).body;
1567+
}
1568+
15411569
export function getJSDocCommentsAndTags(node: Node): (JSDoc | JSDocTag)[] {
15421570
let result: (JSDoc | JSDocTag)[] | undefined;
15431571
getJSDocCommentsAndTagsWorker(node);
@@ -1551,35 +1579,15 @@ namespace ts {
15511579
// * @returns {number}
15521580
// */
15531581
// var x = function(name) { return name.length; }
1554-
const isInitializerOfVariableDeclarationInStatement =
1555-
isVariableLike(parent) &&
1556-
parent.initializer === node &&
1557-
parent.parent.parent.kind === SyntaxKind.VariableStatement;
1558-
const isVariableOfVariableDeclarationStatement = isVariableLike(node) &&
1559-
parent.parent.kind === SyntaxKind.VariableStatement;
1560-
const variableStatementNode =
1561-
isInitializerOfVariableDeclarationInStatement ? parent.parent.parent :
1562-
isVariableOfVariableDeclarationStatement ? parent.parent :
1563-
undefined;
1564-
if (variableStatementNode) {
1565-
getJSDocCommentsAndTagsWorker(variableStatementNode);
1582+
if (parent && (parent.kind === SyntaxKind.PropertyAssignment || getNestedModuleDeclaration(parent))) {
1583+
getJSDocCommentsAndTagsWorker(parent);
15661584
}
1567-
1568-
// Also recognize when the node is the RHS of an assignment expression
1569-
const isSourceOfAssignmentExpressionStatement =
1570-
parent && parent.parent &&
1571-
parent.kind === SyntaxKind.BinaryExpression &&
1572-
(parent as BinaryExpression).operatorToken.kind === SyntaxKind.EqualsToken &&
1573-
parent.parent.kind === SyntaxKind.ExpressionStatement;
1574-
if (isSourceOfAssignmentExpressionStatement) {
1585+
if (parent && parent.parent &&
1586+
(getSingleVariableOfVariableStatement(parent.parent, node) || getSourceOfAssignment(parent.parent))) {
15751587
getJSDocCommentsAndTagsWorker(parent.parent);
15761588
}
1577-
1578-
const isModuleDeclaration = node.kind === SyntaxKind.ModuleDeclaration &&
1579-
parent && parent.kind === SyntaxKind.ModuleDeclaration;
1580-
const isPropertyAssignmentExpression = parent && parent.kind === SyntaxKind.PropertyAssignment;
1581-
if (isModuleDeclaration || isPropertyAssignmentExpression) {
1582-
getJSDocCommentsAndTagsWorker(parent);
1589+
if (parent && parent.parent && parent.parent.parent && getSingleInitializerOfVariableStatement(parent.parent.parent, node)) {
1590+
getJSDocCommentsAndTagsWorker(parent.parent.parent);
15831591
}
15841592

15851593
// Pull parameter comments from declaring function as well
@@ -1606,13 +1614,16 @@ namespace ts {
16061614
return undefined;
16071615
}
16081616
const name = node.name.escapedText;
1609-
const func = getJSDocHost(node);
1610-
if (!isFunctionLike(func)) {
1611-
return undefined;
1617+
const host = getJSDocHost(node);
1618+
const decl = getSourceOfAssignment(host) ||
1619+
getSingleInitializerOfVariableStatement(host) ||
1620+
getSingleVariableOfVariableStatement(host) ||
1621+
getNestedModuleDeclaration(host) ||
1622+
host;
1623+
if (decl && isFunctionLike(decl)) {
1624+
const parameter = find(decl.parameters, p => p.name.kind === SyntaxKind.Identifier && p.name.escapedText === name);
1625+
return parameter && parameter.symbol;
16121626
}
1613-
const parameter = find(func.parameters, p =>
1614-
p.name.kind === SyntaxKind.Identifier && p.name.escapedText === name);
1615-
return parameter && parameter.symbol;
16161627
}
16171628

16181629
export function getJSDocHost(node: JSDocTag): HasJSDoc {
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
//// [0.js]
2+
// @ts-check
3+
/**
4+
* @param {number=} n
5+
* @param {string} [s]
6+
*/
7+
var x = function foo(n, s) {}
8+
var y;
9+
/**
10+
* @param {boolean!} b
11+
*/
12+
y = function bar(b) {}
13+
14+
/**
15+
* @param {string} s
16+
*/
17+
var one = function (s) { }, two = function (untyped) { };
18+
19+
20+
//// [0.js]
21+
// @ts-check
22+
/**
23+
* @param {number=} n
24+
* @param {string} [s]
25+
*/
26+
var x = function foo(n, s) { };
27+
var y;
28+
/**
29+
* @param {boolean!} b
30+
*/
31+
y = function bar(b) { };
32+
/**
33+
* @param {string} s
34+
*/
35+
var one = function (s) { }, two = function (untyped) { };
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
=== tests/cases/conformance/jsdoc/0.js ===
2+
// @ts-check
3+
/**
4+
* @param {number=} n
5+
* @param {string} [s]
6+
*/
7+
var x = function foo(n, s) {}
8+
>x : Symbol(x, Decl(0.js, 5, 3))
9+
>foo : Symbol(foo, Decl(0.js, 5, 7))
10+
>n : Symbol(n, Decl(0.js, 5, 21))
11+
>s : Symbol(s, Decl(0.js, 5, 23))
12+
13+
var y;
14+
>y : Symbol(y, Decl(0.js, 6, 3))
15+
16+
/**
17+
* @param {boolean!} b
18+
*/
19+
y = function bar(b) {}
20+
>y : Symbol(y, Decl(0.js, 6, 3))
21+
>bar : Symbol(bar, Decl(0.js, 10, 3))
22+
>b : Symbol(b, Decl(0.js, 10, 17))
23+
24+
/**
25+
* @param {string} s
26+
*/
27+
var one = function (s) { }, two = function (untyped) { };
28+
>one : Symbol(one, Decl(0.js, 15, 3))
29+
>s : Symbol(s, Decl(0.js, 15, 20))
30+
>two : Symbol(two, Decl(0.js, 15, 27))
31+
>untyped : Symbol(untyped, Decl(0.js, 15, 44))
32+
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
=== tests/cases/conformance/jsdoc/0.js ===
2+
// @ts-check
3+
/**
4+
* @param {number=} n
5+
* @param {string} [s]
6+
*/
7+
var x = function foo(n, s) {}
8+
>x : (n?: number, s?: string) => void
9+
>function foo(n, s) {} : (n?: number, s?: string) => void
10+
>foo : (n?: number, s?: string) => void
11+
>n : number
12+
>s : string
13+
14+
var y;
15+
>y : any
16+
17+
/**
18+
* @param {boolean!} b
19+
*/
20+
y = function bar(b) {}
21+
>y = function bar(b) {} : (b: boolean) => void
22+
>y : any
23+
>function bar(b) {} : (b: boolean) => void
24+
>bar : (b: boolean) => void
25+
>b : boolean
26+
27+
/**
28+
* @param {string} s
29+
*/
30+
var one = function (s) { }, two = function (untyped) { };
31+
>one : (s: string) => void
32+
>function (s) { } : (s: string) => void
33+
>s : string
34+
>two : (untyped: any) => void
35+
>function (untyped) { } : (untyped: any) => void
36+
>untyped : any
37+
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
// @allowJS: true
2+
// @suppressOutputPathCheck: true
3+
4+
// @filename: 0.js
5+
// @ts-check
6+
/**
7+
* @param {number=} n
8+
* @param {string} [s]
9+
*/
10+
var x = function foo(n, s) {}
11+
var y;
12+
/**
13+
* @param {boolean!} b
14+
*/
15+
y = function bar(b) {}
16+
17+
/**
18+
* @param {string} s
19+
*/
20+
var one = function (s) { }, two = function (untyped) { };

0 commit comments

Comments
 (0)