@@ -227,7 +227,7 @@ namespace ts {
227227 symbol . flags |= symbolFlags ;
228228
229229 node . symbol = symbol ;
230- symbol . declarations = append ( symbol . declarations , node ) ;
230+ symbol . declarations = appendIfUnique ( symbol . declarations , node ) ;
231231
232232 if ( symbolFlags & ( SymbolFlags . Class | SymbolFlags . Enum | SymbolFlags . Module | SymbolFlags . Variable ) && ! symbol . exports ) {
233233 symbol . exports = createSymbolTable ( ) ;
@@ -737,6 +737,9 @@ namespace ts {
737737 case SyntaxKind . JSDocEnumTag :
738738 bindJSDocTypeAlias ( node as JSDocTypedefTag | JSDocCallbackTag | JSDocEnumTag ) ;
739739 break ;
740+ case SyntaxKind . JSDocClassTag :
741+ bindJSDocClassTag ( node as JSDocClassTag ) ;
742+ break ;
740743 // In source files and blocks, bind functions first to match hoisting that occurs at runtime
741744 case SyntaxKind . SourceFile : {
742745 bindEachFunctionsFirst ( ( node as SourceFile ) . statements ) ;
@@ -1446,6 +1449,14 @@ namespace ts {
14461449 }
14471450 }
14481451
1452+ function bindJSDocClassTag ( node : JSDocClassTag ) {
1453+ bindEachChild ( node ) ;
1454+ const host = getHostSignatureFromJSDoc ( node ) ;
1455+ if ( host && host . kind !== SyntaxKind . MethodDeclaration ) {
1456+ addDeclarationToSymbol ( host . symbol , host , SymbolFlags . Class ) ;
1457+ }
1458+ }
1459+
14491460 function bindCallExpressionFlow ( node : CallExpression ) {
14501461 // If the target of the call expression is a function expression or arrow function we have
14511462 // an immediately invoked function expression (IIFE). Initialize the flowNode property to
@@ -1813,7 +1824,8 @@ namespace ts {
18131824 // typedef anchored to an A.B.C assignment - we need to bind into B's namespace under name C
18141825 const isTopLevel = isTopLevelNamespaceAssignment ( declName . parent ) ;
18151826 if ( isTopLevel ) {
1816- bindPotentiallyMissingNamespaces ( file . symbol , declName . parent , isTopLevel , ! ! findAncestor ( declName , d => isPropertyAccessExpression ( d ) && d . name . escapedText === "prototype" ) ) ;
1827+ bindPotentiallyMissingNamespaces ( file . symbol , declName . parent , isTopLevel ,
1828+ ! ! findAncestor ( declName , d => isPropertyAccessExpression ( d ) && d . name . escapedText === "prototype" ) , /*containerIsClass*/ false ) ;
18171829 const oldContainer = container ;
18181830 container = isPropertyAccessExpression ( declName . parent . expression ) ? declName . parent . expression . name : declName . parent . expression ;
18191831 declareModuleMember ( typeAlias , SymbolFlags . TypeAlias , SymbolFlags . TypeAliasExcludes ) ;
@@ -2510,6 +2522,7 @@ namespace ts {
25102522 constructorSymbol . members = constructorSymbol . members || createSymbolTable ( ) ;
25112523 // It's acceptable for multiple 'this' assignments of the same identifier to occur
25122524 declareSymbol ( constructorSymbol . members , constructorSymbol , node , SymbolFlags . Property , SymbolFlags . PropertyExcludes & ~ SymbolFlags . Property ) ;
2525+ addDeclarationToSymbol ( constructorSymbol , constructorSymbol . valueDeclaration , SymbolFlags . Class ) ;
25132526 }
25142527 break ;
25152528
@@ -2558,7 +2571,7 @@ namespace ts {
25582571 node . left . parent = node ;
25592572 node . right . parent = node ;
25602573 const lhs = node . left as PropertyAccessEntityNameExpression ;
2561- bindPropertyAssignment ( lhs . expression , lhs , /*isPrototypeProperty*/ false ) ;
2574+ bindPropertyAssignment ( lhs . expression , lhs , /*isPrototypeProperty*/ false , /*containerIsClass*/ true ) ;
25622575 }
25632576
25642577 function bindObjectDefinePrototypeProperty ( node : BindableObjectDefinePropertyCall ) {
@@ -2581,13 +2594,13 @@ namespace ts {
25812594 constructorFunction . parent = classPrototype ;
25822595 classPrototype . parent = lhs ;
25832596
2584- bindPropertyAssignment ( constructorFunction , lhs , /*isPrototypeProperty*/ true ) ;
2597+ bindPropertyAssignment ( constructorFunction , lhs , /*isPrototypeProperty*/ true , /*containerIsClass*/ true ) ;
25852598 }
25862599
25872600 function bindObjectDefinePropertyAssignment ( node : BindableObjectDefinePropertyCall ) {
25882601 let namespaceSymbol = lookupSymbolForPropertyAccess ( node . arguments [ 0 ] ) ;
25892602 const isToplevel = node . parent . parent . kind === SyntaxKind . SourceFile ;
2590- namespaceSymbol = bindPotentiallyMissingNamespaces ( namespaceSymbol , node . arguments [ 0 ] , isToplevel , /*isPrototypeProperty*/ false ) ;
2603+ namespaceSymbol = bindPotentiallyMissingNamespaces ( namespaceSymbol , node . arguments [ 0 ] , isToplevel , /*isPrototypeProperty*/ false , /*containerIsClass*/ false ) ;
25912604 bindPotentiallyNewExpandoMemberToNamespace ( node , namespaceSymbol , /*isPrototypeProperty*/ false ) ;
25922605 }
25932606
@@ -2618,10 +2631,10 @@ namespace ts {
26182631 */
26192632 function bindStaticPropertyAssignment ( node : PropertyAccessEntityNameExpression ) {
26202633 node . expression . parent = node ;
2621- bindPropertyAssignment ( node . expression , node , /*isPrototypeProperty*/ false ) ;
2634+ bindPropertyAssignment ( node . expression , node , /*isPrototypeProperty*/ false , /*containerIsClass*/ false ) ;
26222635 }
26232636
2624- function bindPotentiallyMissingNamespaces ( namespaceSymbol : Symbol | undefined , entityName : EntityNameExpression , isToplevel : boolean , isPrototypeProperty : boolean ) {
2637+ function bindPotentiallyMissingNamespaces ( namespaceSymbol : Symbol | undefined , entityName : EntityNameExpression , isToplevel : boolean , isPrototypeProperty : boolean , containerIsClass : boolean ) {
26252638 if ( isToplevel && ! isPrototypeProperty ) {
26262639 // make symbols or add declarations for intermediate containers
26272640 const flags = SymbolFlags . Module | SymbolFlags . Assignment ;
@@ -2638,6 +2651,9 @@ namespace ts {
26382651 }
26392652 } ) ;
26402653 }
2654+ if ( containerIsClass && namespaceSymbol ) {
2655+ addDeclarationToSymbol ( namespaceSymbol , namespaceSymbol . valueDeclaration , SymbolFlags . Class ) ;
2656+ }
26412657 return namespaceSymbol ;
26422658 }
26432659
@@ -2663,10 +2679,10 @@ namespace ts {
26632679 : propertyAccess . parent . parent . kind === SyntaxKind . SourceFile ;
26642680 }
26652681
2666- function bindPropertyAssignment ( name : EntityNameExpression , propertyAccess : PropertyAccessEntityNameExpression , isPrototypeProperty : boolean ) {
2682+ function bindPropertyAssignment ( name : EntityNameExpression , propertyAccess : PropertyAccessEntityNameExpression , isPrototypeProperty : boolean , containerIsClass : boolean ) {
26672683 let namespaceSymbol = lookupSymbolForPropertyAccess ( name ) ;
26682684 const isToplevel = isTopLevelNamespaceAssignment ( propertyAccess ) ;
2669- namespaceSymbol = bindPotentiallyMissingNamespaces ( namespaceSymbol , propertyAccess . expression , isToplevel , isPrototypeProperty ) ;
2685+ namespaceSymbol = bindPotentiallyMissingNamespaces ( namespaceSymbol , propertyAccess . expression , isToplevel , isPrototypeProperty , containerIsClass ) ;
26702686 bindPotentiallyNewExpandoMemberToNamespace ( propertyAccess , namespaceSymbol , isPrototypeProperty ) ;
26712687 }
26722688
0 commit comments