@@ -72,14 +72,27 @@ export class DeclarationReferenceGenerator {
7272 return new DeclarationReference ( this . _sourceFileToModuleSource ( sourceFile ) ) ;
7373 }
7474
75+ // Do not generate a declaration reference for a type parameter.
7576 if ( symbol . flags & ts . SymbolFlags . TypeParameter ) {
76- return DeclarationReference . parse ( DeclarationReference . escapeComponentString ( symbol . name ) ) ;
77+ return undefined ;
7778 }
7879
7980 const parent : ts . Symbol | undefined = TypeScriptInternals . getSymbolParent ( symbol ) ;
80- const parentRef : DeclarationReference | undefined = parent
81- ? this . _symbolToDeclarationReference ( parent , ts . SymbolFlags . Namespace , /*includeModuleSymbols*/ true )
82- : new DeclarationReference ( GlobalSource . instance ) ;
81+ let parentRef : DeclarationReference | undefined ;
82+ if ( parent ) {
83+ parentRef = this . _symbolToDeclarationReference ( parent , ts . SymbolFlags . Namespace , /*includeModuleSymbols*/ true ) ;
84+ } else {
85+ // this may be a local symbol in a module...
86+ const sourceFile : ts . SourceFile | undefined =
87+ symbol . declarations
88+ && symbol . declarations [ 0 ]
89+ && symbol . declarations [ 0 ] . getSourceFile ( ) ;
90+ if ( ts . isExternalModule ( sourceFile ) ) {
91+ parentRef = new DeclarationReference ( this . _sourceFileToModuleSource ( sourceFile ) ) ;
92+ } else {
93+ parentRef = new DeclarationReference ( GlobalSource . instance ) ;
94+ }
95+ }
8396
8497 if ( parentRef === undefined ) {
8598 return undefined ;
@@ -108,9 +121,13 @@ export class DeclarationReferenceGenerator {
108121 }
109122 }
110123
111- const navigation : Navigation = isTypeMemberOrNonStaticClassMember ( symbol )
112- ? Navigation . Members
113- : Navigation . Exports ;
124+ let navigation : Navigation | 'global' = getNavigationToSymbol ( symbol ) ;
125+ if ( navigation === 'global' ) {
126+ if ( parentRef . source !== GlobalSource . instance ) {
127+ parentRef = new DeclarationReference ( GlobalSource . instance ) ;
128+ }
129+ navigation = Navigation . Exports ;
130+ }
114131
115132 return parentRef
116133 . addNavigationStep ( navigation , localName )
@@ -144,17 +161,64 @@ function isExternalModuleSymbol(symbol: ts.Symbol): boolean {
144161 && ts . isSourceFile ( symbol . valueDeclaration ) ;
145162}
146163
147- function isTypeMemberOrNonStaticClassMember ( symbol : ts . Symbol ) : boolean {
164+ function isSameSymbol ( left : ts . Symbol | undefined , right : ts . Symbol ) : boolean {
165+ return left === right
166+ || ! ! ( left && left . valueDeclaration && right . valueDeclaration && left . valueDeclaration === right . valueDeclaration ) ;
167+ }
168+
169+ function getNavigationToSymbol ( symbol : ts . Symbol ) : Navigation | 'global' {
170+ const parent : ts . Symbol | undefined = TypeScriptInternals . getSymbolParent ( symbol ) ;
171+ // First, try to determine navigation to symbol via its parent.
172+ if ( parent ) {
173+ if ( parent . exports && isSameSymbol ( parent . exports . get ( symbol . escapedName ) , symbol ) ) {
174+ return Navigation . Exports ;
175+ }
176+ if ( parent . members && isSameSymbol ( parent . members . get ( symbol . escapedName ) , symbol ) ) {
177+ return Navigation . Members ;
178+ }
179+ if ( parent . globalExports && isSameSymbol ( parent . globalExports . get ( symbol . escapedName ) , symbol ) ) {
180+ return 'global' ;
181+ }
182+ }
183+
184+ // Next, try determining navigation to symbol by its node
148185 if ( symbol . valueDeclaration ) {
149- if ( ts . isClassLike ( symbol . valueDeclaration . parent ) ) {
150- return ts . isClassElement ( symbol . valueDeclaration )
151- && ! ( ts . getCombinedModifierFlags ( symbol . valueDeclaration ) & ts . ModifierFlags . Static ) ;
186+ const declaration : ts . Declaration = ts . isBindingElement ( symbol . valueDeclaration )
187+ ? ts . walkUpBindingElementsAndPatterns ( symbol . valueDeclaration )
188+ : symbol . valueDeclaration ;
189+ if ( ts . isClassElement ( declaration ) && ts . isClassLike ( declaration . parent ) ) {
190+ // class members are an "export" if they have the static modifier.
191+ return ts . getCombinedModifierFlags ( declaration ) & ts . ModifierFlags . Static
192+ ? Navigation . Exports
193+ : Navigation . Members ;
194+ }
195+ if ( ts . isTypeElement ( declaration ) || ts . isObjectLiteralElement ( declaration ) ) {
196+ // type and object literal element members are just members
197+ return Navigation . Members ;
198+ }
199+ if ( ts . isEnumMember ( declaration ) ) {
200+ // enum members are exports
201+ return Navigation . Exports ;
202+ }
203+ if ( ts . isExportSpecifier ( declaration )
204+ || ts . isExportAssignment ( declaration )
205+ || ts . isExportSpecifier ( declaration )
206+ || ts . isExportDeclaration ( declaration )
207+ || ts . isNamedExports ( declaration )
208+ ) {
209+ return Navigation . Exports ;
210+ }
211+ // declarations are exports if they have an `export` modifier.
212+ if ( ts . getCombinedModifierFlags ( declaration ) & ts . ModifierFlags . Export ) {
213+ return Navigation . Exports ;
152214 }
153- if ( ts . isInterfaceDeclaration ( symbol . valueDeclaration . parent ) ) {
154- return ts . isTypeElement ( symbol . valueDeclaration ) ;
215+ if ( ts . isSourceFile ( declaration . parent ) && ! ts . isExternalModule ( declaration . parent ) ) {
216+ // declarations in a source file are global if the source file is not a module.
217+ return 'global' ;
155218 }
156219 }
157- return false ;
220+ // all other declarations are locals
221+ return Navigation . Locals ;
158222}
159223
160224function getMeaningOfSymbol ( symbol : ts . Symbol , meaning : ts . SymbolFlags ) : Meaning | undefined {
0 commit comments