@@ -311,3 +311,117 @@ func (p *Processor) findSelfObject(self *ast.Self) *ast.DesugaredObject {
311311 }
312312 return nil
313313}
314+
315+ // findUsagesVisitor creates a visitor function that finds all usages of a given symbol
316+ func (p * Processor ) findUsagesVisitor (symbolID ast.Identifier , symbol string , ranges * []ObjectRange ) func (node ast.Node ) {
317+ return func (node ast.Node ) {
318+ switch node := node .(type ) {
319+ case * ast.Var :
320+ // For variables, check if the ID matches
321+ if node .Id == symbolID {
322+ * ranges = append (* ranges , ObjectRange {
323+ Filename : node .LocRange .FileName ,
324+ SelectionRange : node .LocRange ,
325+ FullRange : node .LocRange ,
326+ })
327+ }
328+ case * ast.Index :
329+ // For field access, check if the index matches
330+ if litStr , ok := node .Index .(* ast.LiteralString ); ok {
331+ if litStr .Value == symbol {
332+ * ranges = append (* ranges , ObjectRange {
333+ Filename : node .LocRange .FileName ,
334+ SelectionRange : node .LocRange ,
335+ FullRange : node .LocRange ,
336+ })
337+ }
338+ }
339+ case * ast.Apply :
340+ if litStr , ok := node .Target .(* ast.LiteralString ); ok {
341+ if litStr .Value == symbol {
342+ * ranges = append (* ranges , ObjectRange {
343+ Filename : node .LocRange .FileName ,
344+ SelectionRange : node .LocRange ,
345+ FullRange : node .LocRange ,
346+ })
347+ }
348+ }
349+ }
350+
351+ // Visit all children
352+ switch node := node .(type ) {
353+ case * ast.Apply :
354+ p .findUsagesVisitor (symbolID , symbol , ranges )(node .Target )
355+ for _ , arg := range node .Arguments .Positional {
356+ p .findUsagesVisitor (symbolID , symbol , ranges )(arg .Expr )
357+ }
358+ for _ , arg := range node .Arguments .Named {
359+ p .findUsagesVisitor (symbolID , symbol , ranges )(arg .Arg )
360+ }
361+ case * ast.Array :
362+ for _ , element := range node .Elements {
363+ p .findUsagesVisitor (symbolID , symbol , ranges )(element .Expr )
364+ }
365+ case * ast.Binary :
366+ p .findUsagesVisitor (symbolID , symbol , ranges )(node .Left )
367+ p .findUsagesVisitor (symbolID , symbol , ranges )(node .Right )
368+ case * ast.Conditional :
369+ p .findUsagesVisitor (symbolID , symbol , ranges )(node .Cond )
370+ p .findUsagesVisitor (symbolID , symbol , ranges )(node .BranchTrue )
371+ p .findUsagesVisitor (symbolID , symbol , ranges )(node .BranchFalse )
372+ case * ast.DesugaredObject :
373+ for _ , field := range node .Fields {
374+ p .findUsagesVisitor (symbolID , symbol , ranges )(field .Name )
375+ p .findUsagesVisitor (symbolID , symbol , ranges )(field .Body )
376+ }
377+ case * ast.Error :
378+ p .findUsagesVisitor (symbolID , symbol , ranges )(node .Expr )
379+ case * ast.Function :
380+ for _ , param := range node .Parameters {
381+ if param .DefaultArg != nil {
382+ p .findUsagesVisitor (symbolID , symbol , ranges )(param .DefaultArg )
383+ }
384+ }
385+ p .findUsagesVisitor (symbolID , symbol , ranges )(node .Body )
386+ case * ast.Index :
387+ p .findUsagesVisitor (symbolID , symbol , ranges )(node .Target )
388+ p .findUsagesVisitor (symbolID , symbol , ranges )(node .Index )
389+ case * ast.Local :
390+ for _ , bind := range node .Binds {
391+ p .findUsagesVisitor (symbolID , symbol , ranges )(bind .Body )
392+ }
393+ p .findUsagesVisitor (symbolID , symbol , ranges )(node .Body )
394+ case * ast.Object :
395+ for _ , field := range node .Fields {
396+ p .findUsagesVisitor (symbolID , symbol , ranges )(field .Expr1 )
397+ p .findUsagesVisitor (symbolID , symbol , ranges )(field .Expr2 )
398+ }
399+ case * ast.SuperIndex :
400+ p .findUsagesVisitor (symbolID , symbol , ranges )(node .Index )
401+ case * ast.Unary :
402+ p .findUsagesVisitor (symbolID , symbol , ranges )(node .Expr )
403+ default :
404+ // No children to visit
405+ }
406+ }
407+ }
408+
409+ // FindUsages finds all usages of a symbol in the given files
410+ func (p * Processor ) FindUsages (files []string , symbol string ) ([]ObjectRange , error ) {
411+ var ranges []ObjectRange
412+ symbolID := ast .Identifier (symbol )
413+
414+ // Create a visitor to find all usages
415+ visitor := p .findUsagesVisitor (symbolID , symbol , & ranges )
416+
417+ // Process each file
418+ for _ , file := range files {
419+ rootNode , _ , err := p .vm .ImportAST ("" , file )
420+ if err != nil {
421+ return nil , fmt .Errorf ("failed to import AST for file %s: %w" , file , err )
422+ }
423+ visitor (rootNode )
424+ }
425+
426+ return ranges , nil
427+ }
0 commit comments