@@ -19,14 +19,55 @@ namespace ts.FindAllReferences {
19
19
export interface NodeEntry {
20
20
readonly kind : NodeEntryKind ;
21
21
readonly node : Node ;
22
+ readonly declaration ?: Node ;
22
23
}
23
24
export interface SpanEntry {
24
25
readonly kind : EntryKind . Span ;
25
26
readonly fileName : string ;
26
27
readonly textSpan : TextSpan ;
27
28
}
28
29
export function nodeEntry ( node : Node , kind : NodeEntryKind = EntryKind . Node ) : NodeEntry {
29
- return { kind, node : ( node as NamedDeclaration ) . name || node } ;
30
+ const declaration = getDeclarationForDefinitionSpan (
31
+ isDeclaration ( node ) ?
32
+ node :
33
+ node . parent && isDeclaration ( node . parent ) && node . parent . name === node ?
34
+ node . parent :
35
+ undefined
36
+ ) ;
37
+ return { kind, node : ( node as NamedDeclaration ) . name || node , declaration } ;
38
+ }
39
+
40
+ export function getDeclarationForDefinitionSpan ( node : NamedDeclaration | undefined ) : Node | undefined {
41
+ if ( ! node ) return undefined ;
42
+ switch ( node . kind ) {
43
+ case SyntaxKind . VariableDeclaration :
44
+ return ! isVariableDeclarationList ( node . parent ) || node . parent . declarations . length !== 1 ?
45
+ node :
46
+ isVariableStatement ( node . parent . parent ) ?
47
+ node . parent . parent :
48
+ node . parent ;
49
+
50
+ case SyntaxKind . BindingElement :
51
+ return getDeclarationForDefinitionSpan ( node . parent . parent as NamedDeclaration ) ;
52
+
53
+ case SyntaxKind . ImportSpecifier :
54
+ return node . parent . parent . parent ;
55
+
56
+ case SyntaxKind . ExportSpecifier :
57
+ case SyntaxKind . NamespaceImport :
58
+ return node . parent . parent ;
59
+
60
+ case SyntaxKind . ImportClause :
61
+ return node . parent ;
62
+
63
+ // Not really interesting definition
64
+ // Should we show whole object literal instead?
65
+ case SyntaxKind . ShorthandPropertyAssignment :
66
+ return undefined ;
67
+
68
+ default :
69
+ return node ;
70
+ }
30
71
}
31
72
32
73
export interface Options {
@@ -123,7 +164,16 @@ namespace ts.FindAllReferences {
123
164
const { symbol } = def ;
124
165
const { displayParts, kind } = getDefinitionKindAndDisplayParts ( symbol , checker , originalNode ) ;
125
166
const name = displayParts . map ( p => p . text ) . join ( "" ) ;
126
- return { node : symbol . declarations ? getNameOfDeclaration ( first ( symbol . declarations ) ) || first ( symbol . declarations ) : originalNode , name, kind, displayParts } ;
167
+ const declaration = symbol . declarations ? first ( symbol . declarations ) : undefined ;
168
+ return {
169
+ node : declaration ?
170
+ getNameOfDeclaration ( declaration ) || declaration :
171
+ originalNode ,
172
+ name,
173
+ kind,
174
+ displayParts,
175
+ declaration : getDeclarationForDefinitionSpan ( declaration )
176
+ } ;
127
177
}
128
178
case DefinitionKind . Label : {
129
179
const { node } = def ;
@@ -150,9 +200,21 @@ namespace ts.FindAllReferences {
150
200
}
151
201
} ) ( ) ;
152
202
153
- const { node, name, kind, displayParts } = info ;
203
+ const { node, name, kind, displayParts, declaration } = info ;
154
204
const sourceFile = node . getSourceFile ( ) ;
155
- return { containerKind : ScriptElementKind . unknown , containerName : "" , fileName : sourceFile . fileName , kind, name, textSpan : getTextSpan ( isComputedPropertyName ( node ) ? node . expression : node , sourceFile ) , displayParts } ;
205
+ const result : ReferencedSymbolDefinitionInfo = {
206
+ containerKind : ScriptElementKind . unknown ,
207
+ containerName : "" ,
208
+ fileName : sourceFile . fileName ,
209
+ kind,
210
+ name,
211
+ textSpan : getTextSpan ( isComputedPropertyName ( node ) ? node . expression : node , sourceFile ) ,
212
+ displayParts
213
+ } ;
214
+ if ( declaration ) {
215
+ result . definitionSpan = getTextSpan ( declaration , sourceFile ) ;
216
+ }
217
+ return result ;
156
218
}
157
219
158
220
function getDefinitionKindAndDisplayParts ( symbol : Symbol , checker : TypeChecker , node : Node ) : { displayParts : SymbolDisplayPart [ ] , kind : ScriptElementKind } {
@@ -168,14 +230,13 @@ namespace ts.FindAllReferences {
168
230
}
169
231
170
232
export function toReferenceEntry ( entry : Entry ) : ReferenceEntry {
171
- const { textSpan , fileName } = entryToDocumentSpan ( entry ) ;
233
+ const documentSpan = entryToDocumentSpan ( entry ) ;
172
234
if ( entry . kind === EntryKind . Span ) {
173
- return { textSpan , fileName , isWriteAccess : false , isDefinition : false } ;
235
+ return { ... documentSpan , isWriteAccess : false , isDefinition : false } ;
174
236
}
175
237
const { kind, node } = entry ;
176
238
return {
177
- textSpan,
178
- fileName,
239
+ ...documentSpan ,
179
240
isWriteAccess : isWriteAccessForReference ( node ) ,
180
241
isDefinition : node . kind === SyntaxKind . DefaultKeyword
181
242
|| ! ! getDeclarationFromName ( node )
@@ -190,7 +251,11 @@ namespace ts.FindAllReferences {
190
251
}
191
252
else {
192
253
const sourceFile = entry . node . getSourceFile ( ) ;
193
- return { textSpan : getTextSpan ( entry . node , sourceFile ) , fileName : sourceFile . fileName } ;
254
+ const result : DocumentSpan = { textSpan : getTextSpan ( entry . node , sourceFile ) , fileName : sourceFile . fileName } ;
255
+ if ( entry . declaration ) {
256
+ result . definitionSpan = getTextSpan ( entry . declaration , sourceFile ) ;
257
+ }
258
+ return result ;
194
259
}
195
260
}
196
261
@@ -223,14 +288,16 @@ namespace ts.FindAllReferences {
223
288
}
224
289
225
290
function toImplementationLocation ( entry : Entry , checker : TypeChecker ) : ImplementationLocation {
291
+ const documentSpan = entryToDocumentSpan ( entry ) ;
226
292
if ( entry . kind !== EntryKind . Span ) {
227
293
const { node } = entry ;
228
- const sourceFile = node . getSourceFile ( ) ;
229
- return { textSpan : getTextSpan ( node , sourceFile ) , fileName : sourceFile . fileName , ...implementationKindDisplayParts ( node , checker ) } ;
294
+ return {
295
+ ...documentSpan ,
296
+ ...implementationKindDisplayParts ( node , checker )
297
+ } ;
230
298
}
231
299
else {
232
- const { textSpan, fileName } = entry ;
233
- return { textSpan, fileName, kind : ScriptElementKind . unknown , displayParts : [ ] } ;
300
+ return { ...documentSpan , kind : ScriptElementKind . unknown , displayParts : [ ] } ;
234
301
}
235
302
}
236
303
@@ -257,20 +324,27 @@ namespace ts.FindAllReferences {
257
324
}
258
325
259
326
export function toHighlightSpan ( entry : Entry ) : { fileName : string , span : HighlightSpan } {
327
+ const documentSpan = entryToDocumentSpan ( entry ) ;
260
328
if ( entry . kind === EntryKind . Span ) {
261
- const { fileName, textSpan } = entry ;
262
- return { fileName, span : { textSpan, kind : HighlightSpanKind . reference } } ;
329
+ return {
330
+ fileName : documentSpan . fileName ,
331
+ span : {
332
+ textSpan : documentSpan . textSpan ,
333
+ kind : HighlightSpanKind . reference
334
+ }
335
+ } ;
263
336
}
264
337
265
- const { node, kind } = entry ;
266
- const sourceFile = node . getSourceFile ( ) ;
267
- const writeAccess = isWriteAccessForReference ( node ) ;
338
+ const writeAccess = isWriteAccessForReference ( entry . node ) ;
268
339
const span : HighlightSpan = {
269
- textSpan : getTextSpan ( node , sourceFile ) ,
340
+ textSpan : documentSpan . textSpan ,
270
341
kind : writeAccess ? HighlightSpanKind . writtenReference : HighlightSpanKind . reference ,
271
- isInString : kind === EntryKind . StringLiteral ? true : undefined ,
342
+ isInString : entry . kind === EntryKind . StringLiteral ? true : undefined ,
272
343
} ;
273
- return { fileName : sourceFile . fileName , span } ;
344
+ if ( documentSpan . definitionSpan ) {
345
+ span . definitionSpan = documentSpan . definitionSpan ;
346
+ }
347
+ return { fileName : documentSpan . fileName , span } ;
274
348
}
275
349
276
350
function getTextSpan ( node : Node , sourceFile : SourceFile ) : TextSpan {
0 commit comments