@@ -17,8 +17,10 @@ package collect
17
17
import (
18
18
"context"
19
19
"fmt"
20
+ "maps"
20
21
"os"
21
22
"path/filepath"
23
+ "slices"
22
24
"strings"
23
25
"unicode"
24
26
@@ -306,13 +308,44 @@ func (c *Collector) getSymbolByTokenWithLimit(ctx context.Context, tok Token, de
306
308
return c .getSymbolByLocation (ctx , defs [0 ], depth , tok )
307
309
}
308
310
309
- func (c * Collector ) filterEntitySymbols (syms []* DocumentSymbol ) * DocumentSymbol {
311
+ // Find the symbol (from the symbol list) that matches the location.
312
+ // It is the smallest (most specific) entity symbol that contains the location.
313
+ //
314
+ // Parameters:
315
+ //
316
+ // @syms: the list of symbols to search in
317
+ // @loc: the location to find the symbol for
318
+ //
319
+ // Returns:
320
+ //
321
+ // *DocumentSymbol: the most specific entity symbol that contains the location.
322
+ // If no such symbol is found, it returns nil.
323
+ func (c * Collector ) findMatchingSymbolIn (loc Location , syms []* DocumentSymbol ) * DocumentSymbol {
324
+ var most_specific * DocumentSymbol
310
325
for _ , sym := range syms {
311
- if c .spec .IsEntitySymbol (* sym ) {
312
- return sym
326
+ if ! sym .Location .Include (loc ) || ! c .spec .IsEntitySymbol (* sym ) {
327
+ continue
328
+ }
329
+ // now we have a candidate (containing loc && entity), check if it is the most specific
330
+ if most_specific == nil {
331
+ most_specific = sym
332
+ continue
313
333
}
334
+ if most_specific .Location .Include (sym .Location ) {
335
+ // use sym, which is more specific than most_specific
336
+ most_specific = sym
337
+ continue
338
+ }
339
+ if sym .Location .Include (most_specific .Location ) {
340
+ // remain current choice
341
+ continue
342
+ }
343
+ // Indicates a bad usage, sym contains unstructured symbols.
344
+ log .Error ("getMostSpecificEntitySymbol: cannot decide between symbols %s (at %+v) and %s (at %+v)\n " ,
345
+ most_specific .Name , most_specific .Location ,
346
+ sym .Name , sym .Location )
314
347
}
315
- return nil
348
+ return most_specific
316
349
}
317
350
318
351
// return a language entity symbol
@@ -324,22 +357,19 @@ func (c *Collector) getSymbolByLocation(ctx context.Context, loc Location, depth
324
357
// if sym, ok := c.syms[loc]; ok {
325
358
// return sym, nil
326
359
// }
327
- var ret []* DocumentSymbol
328
- for _ , sym := range c .syms {
329
- if sym .Location .Include (loc ) {
330
- ret = append (ret , sym )
331
- }
332
- }
333
- if len (ret ) > 0 {
334
- return c .filterEntitySymbols (ret ), nil
360
+
361
+ // 1. already loaded
362
+ if sym := c .findMatchingSymbolIn (loc , slices .Collect (maps .Values (c .syms ))); sym != nil {
363
+ return sym , nil
335
364
}
336
365
337
366
if c .LoadExternalSymbol && ! c .internal (loc ) && (c .NeedStdSymbol || ! c .spec .IsStdToken (from )) {
338
- // external symbol, locate and process it
367
+ // 2. load external symbol from its file
339
368
syms , err := c .cli .DocumentSymbols (ctx , loc .URI )
340
369
if err != nil {
341
370
return nil , err
342
371
}
372
+ // load the other external symbols in that file
343
373
for _ , sym := range syms {
344
374
// save symbol first
345
375
if _ , ok := c .syms [sym .Location ]; ! ok {
@@ -350,10 +380,8 @@ func (c *Collector) getSymbolByLocation(ctx context.Context, loc Location, depth
350
380
sym .Text = content
351
381
c .syms [sym .Location ] = sym
352
382
}
353
- if sym .Location .Include (loc ) {
354
- ret = append (ret , sym )
355
- }
356
383
}
384
+ // load more external symbols if depth permits
357
385
if depth >= 0 {
358
386
// process target symbol
359
387
for _ , sym := range syms {
@@ -369,13 +397,10 @@ func (c *Collector) getSymbolByLocation(ctx context.Context, loc Location, depth
369
397
}
370
398
}
371
399
}
372
-
373
- // filter entity symbol
374
- rsym := c .filterEntitySymbols (ret )
400
+ rsym := c .findMatchingSymbolIn (loc , slices .Collect (maps .Values (syms )))
375
401
return rsym , nil
376
-
377
402
} else {
378
- // external symbol, just locate the content
403
+ // external symbol, just locate the content
379
404
var text string
380
405
if c .internal (loc ) {
381
406
// maybe internal symbol not loaded, like `lazy_static!` in Rust
@@ -535,13 +560,16 @@ func (c *Collector) collectImpl(ctx context.Context, sym *DocumentSymbol, depth
535
560
for _ , method := range c .syms {
536
561
// NOTICE: some class method (ex: XXType::new) are SKFunction, but still collect its receiver
537
562
if (method .Kind == SKMethod || method .Kind == SKFunction ) && sym .Location .Include (method .Location ) {
538
- c .funcs [method ] = functionInfo {
539
- Method : & methodInfo {
540
- Receiver : * rd ,
541
- Interface : ind ,
542
- ImplHead : impl ,
543
- },
563
+ if _ , ok := c .funcs [method ]; ! ok {
564
+ c .funcs [method ] = functionInfo {}
565
+ }
566
+ f := c .funcs [method ]
567
+ f .Method = & methodInfo {
568
+ Receiver : * rd ,
569
+ Interface : ind ,
570
+ ImplHead : impl ,
544
571
}
572
+ c .funcs [method ] = f
545
573
}
546
574
}
547
575
}
@@ -601,32 +629,21 @@ func (c *Collector) processSymbol(ctx context.Context, sym *DocumentSymbol, dept
601
629
}
602
630
603
631
func (c * Collector ) updateFunctionInfo (sym * DocumentSymbol , tsyms , ipsyms , opsyms map [int ]dependency , ts , is , os []dependency , rsym * dependency ) {
604
- f , ok := c .funcs [sym ]
605
- if ok {
606
- f .TypeParams = tsyms
607
- f .TypeParamsSorted = ts
608
- f .Inputs = ipsyms
609
- f .InputsSorted = is
610
- f .Outputs = opsyms
611
- f .OutputsSorted = os
612
- if rsym != nil {
613
- if f .Method == nil {
614
- f .Method = & methodInfo {}
615
- }
616
- f .Method .Receiver = * rsym
617
- }
618
- } else {
619
- f = functionInfo {
620
- TypeParams : tsyms ,
621
- Inputs : ipsyms ,
622
- Outputs : opsyms ,
623
- }
624
- if rsym != nil {
625
- if f .Method == nil {
626
- f .Method = & methodInfo {}
627
- }
628
- f .Method .Receiver = * rsym
632
+ if _ , ok := c .funcs [sym ]; ! ok {
633
+ c .funcs [sym ] = functionInfo {}
634
+ }
635
+ f := c .funcs [sym ]
636
+ f .TypeParams = tsyms
637
+ f .TypeParamsSorted = ts
638
+ f .Inputs = ipsyms
639
+ f .InputsSorted = is
640
+ f .Outputs = opsyms
641
+ f .OutputsSorted = os
642
+ if rsym != nil {
643
+ if f .Method == nil {
644
+ f .Method = & methodInfo {}
629
645
}
646
+ f .Method .Receiver = * rsym
630
647
}
631
648
c .funcs [sym ] = f
632
649
}
0 commit comments