@@ -17,8 +17,10 @@ package collect
1717import (
1818 "context"
1919 "fmt"
20+ "maps"
2021 "os"
2122 "path/filepath"
23+ "slices"
2224 "strings"
2325 "unicode"
2426
@@ -306,13 +308,44 @@ func (c *Collector) getSymbolByTokenWithLimit(ctx context.Context, tok Token, de
306308 return c .getSymbolByLocation (ctx , defs [0 ], depth , tok )
307309}
308310
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
310325 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
313333 }
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 )
314347 }
315- return nil
348+ return most_specific
316349}
317350
318351// return a language entity symbol
@@ -324,22 +357,19 @@ func (c *Collector) getSymbolByLocation(ctx context.Context, loc Location, depth
324357 // if sym, ok := c.syms[loc]; ok {
325358 // return sym, nil
326359 // }
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
335364 }
336365
337366 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
339368 syms , err := c .cli .DocumentSymbols (ctx , loc .URI )
340369 if err != nil {
341370 return nil , err
342371 }
372+ // load the other external symbols in that file
343373 for _ , sym := range syms {
344374 // save symbol first
345375 if _ , ok := c .syms [sym .Location ]; ! ok {
@@ -350,10 +380,8 @@ func (c *Collector) getSymbolByLocation(ctx context.Context, loc Location, depth
350380 sym .Text = content
351381 c .syms [sym .Location ] = sym
352382 }
353- if sym .Location .Include (loc ) {
354- ret = append (ret , sym )
355- }
356383 }
384+ // load more external symbols if depth permits
357385 if depth >= 0 {
358386 // process target symbol
359387 for _ , sym := range syms {
@@ -369,13 +397,10 @@ func (c *Collector) getSymbolByLocation(ctx context.Context, loc Location, depth
369397 }
370398 }
371399 }
372-
373- // filter entity symbol
374- rsym := c .filterEntitySymbols (ret )
400+ rsym := c .findMatchingSymbolIn (loc , slices .Collect (maps .Values (syms )))
375401 return rsym , nil
376-
377402 } else {
378- // external symbol, just locate the content
403+ // external symbol, just locate the content
379404 var text string
380405 if c .internal (loc ) {
381406 // maybe internal symbol not loaded, like `lazy_static!` in Rust
@@ -535,13 +560,16 @@ func (c *Collector) collectImpl(ctx context.Context, sym *DocumentSymbol, depth
535560 for _ , method := range c .syms {
536561 // NOTICE: some class method (ex: XXType::new) are SKFunction, but still collect its receiver
537562 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 ,
544571 }
572+ c .funcs [method ] = f
545573 }
546574 }
547575}
@@ -601,32 +629,21 @@ func (c *Collector) processSymbol(ctx context.Context, sym *DocumentSymbol, dept
601629}
602630
603631func (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 {}
629645 }
646+ f .Method .Receiver = * rsym
630647 }
631648 c .funcs [sym ] = f
632649}
0 commit comments