@@ -669,6 +669,12 @@ namespace ts {
669
669
case SyntaxKind . CallExpression :
670
670
bindCallExpressionFlow ( < CallExpression > node ) ;
671
671
break ;
672
+ case SyntaxKind . JSDocComment :
673
+ bindJSDocComment ( < JSDoc > node ) ;
674
+ break ;
675
+ case SyntaxKind . JSDocTypedefTag :
676
+ bindJSDocTypedefTag ( < JSDocTypedefTag > node ) ;
677
+ break ;
672
678
default :
673
679
bindEachChild ( node ) ;
674
680
break ;
@@ -1298,6 +1304,26 @@ namespace ts {
1298
1304
}
1299
1305
}
1300
1306
1307
+ function bindJSDocComment ( node : JSDoc ) {
1308
+ forEachChild ( node , n => {
1309
+ if ( n . kind !== SyntaxKind . JSDocTypedefTag ) {
1310
+ bind ( n ) ;
1311
+ }
1312
+ } ) ;
1313
+ }
1314
+
1315
+ function bindJSDocTypedefTag ( node : JSDocTypedefTag ) {
1316
+ forEachChild ( node , n => {
1317
+ // if the node has a fullName "A.B.C", that means symbol "C" was already bond
1318
+ // when we visit "fullName"; so when we visit the name "C" as the next child of
1319
+ // the jsDocTypedefTag, we should skip binding it.
1320
+ if ( n === node . name && node . fullName . kind !== SyntaxKind . Identifier ) {
1321
+ return ;
1322
+ }
1323
+ bind ( n ) ;
1324
+ } ) ;
1325
+ }
1326
+
1301
1327
function bindCallExpressionFlow ( node : CallExpression ) {
1302
1328
// If the target of the call expression is a function expression or arrow function we have
1303
1329
// an immediately invoked function expression (IIFE). Initialize the flowNode property to
@@ -1827,6 +1853,18 @@ namespace ts {
1827
1853
}
1828
1854
node . parent = parent ;
1829
1855
const saveInStrictMode = inStrictMode ;
1856
+
1857
+ // Even though in the AST the jsdoc @typedef node belongs to the current node,
1858
+ // its symbol might be in the same scope with the current node's symbol. Consider:
1859
+ //
1860
+ // /** @typedef {string | number } MyType */
1861
+ // function foo();
1862
+ //
1863
+ // Here the current node is "foo", which is a container, but the scope of "MyType" should
1864
+ // not be inside "foo". Therefore we always bind @typedef before bind the parent node,
1865
+ // and skip binding this tag later when binding all the other jsdoc tags.
1866
+ bindJSDocTypedefTagIfAny ( node ) ;
1867
+
1830
1868
// First we bind declaration nodes to a symbol if possible. We'll both create a symbol
1831
1869
// and then potentially add the symbol to an appropriate symbol table. Possible
1832
1870
// destination symbol tables are:
@@ -1861,6 +1899,27 @@ namespace ts {
1861
1899
inStrictMode = saveInStrictMode ;
1862
1900
}
1863
1901
1902
+ function bindJSDocTypedefTagIfAny ( node : Node ) {
1903
+ if ( ! node . jsDoc ) {
1904
+ return ;
1905
+ }
1906
+
1907
+ for ( const jsDoc of node . jsDoc ) {
1908
+ if ( ! jsDoc . tags ) {
1909
+ continue ;
1910
+ }
1911
+
1912
+ for ( const tag of jsDoc . tags ) {
1913
+ if ( tag . kind === SyntaxKind . JSDocTypedefTag ) {
1914
+ const savedParent = parent ;
1915
+ parent = jsDoc ;
1916
+ bind ( tag ) ;
1917
+ parent = savedParent ;
1918
+ }
1919
+ }
1920
+ }
1921
+ }
1922
+
1864
1923
function updateStrictModeStatementList ( statements : NodeArray < Statement > ) {
1865
1924
if ( ! inStrictMode ) {
1866
1925
for ( const statement of statements ) {
0 commit comments