Skip to content

Commit ef7f434

Browse files
committed
feat: add Extra field to store additional AST node metadata
Collect direct calls and anonymous functions in Go parser and store them in the Extra field of Function, Dependency, Type, and Var.
1 parent 375e069 commit ef7f434

2 files changed

Lines changed: 75 additions & 3 deletions

File tree

lang/golang/parser/file.go

Lines changed: 66 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,9 @@ func (p *GoParser) parseVar(ctx *fileContext, vspec *ast.ValueSpec, isConst bool
121121

122122
// collect func value dependencies, in case of var a = func() {...}
123123
if val != nil && !isConst {
124-
collects := collectInfos{}
124+
collects := collectInfos{
125+
directCalls: map[FileLine]bool{},
126+
}
125127
ast.Inspect(*val, func(n ast.Node) bool {
126128
return p.parseASTNode(ctx, n, &collects)
127129
})
@@ -137,6 +139,20 @@ func (p *GoParser) parseVar(ctx *fileContext, vspec *ast.ValueSpec, isConst bool
137139
for _, dep := range collects.tys {
138140
v.Dependencies = InsertDependency(v.Dependencies, dep)
139141
}
142+
if len(collects.directCalls) > 0 {
143+
for i, dep := range v.Dependencies {
144+
if collects.directCalls[dep.FileLine] {
145+
if v.Dependencies[i].Extra == nil {
146+
v.Dependencies[i].Extra = map[string]any{}
147+
}
148+
v.Dependencies[i].Extra["FunctionIsCall"] = true
149+
}
150+
}
151+
}
152+
if len(collects.anonymousFunctions) > 0 {
153+
v.Extra = map[string]any{}
154+
v.Extra["AnonymousFunctions"] = collects.anonymousFunctions
155+
}
140156
}
141157

142158
if vspec.Type != nil {
@@ -392,12 +408,19 @@ func (p *GoParser) parseSelector(ctx *fileContext, expr *ast.SelectorExpr, infos
392408
type collectInfos struct {
393409
functionCalls, methodCalls []Dependency
394410
tys, globalVars []Dependency
411+
412+
directCalls map[FileLine]bool
413+
anonymousFunctions []FileLine // record anonymous function
395414
}
396415

397416
func (p *GoParser) parseASTNode(ctx *fileContext, node ast.Node, collect *collectInfos) bool {
398417
switch expr := node.(type) {
399418
case *ast.SelectorExpr:
400419
return p.parseSelector(ctx, expr, collect)
420+
case *ast.CallExpr:
421+
p.parseCall(ctx, expr, collect)
422+
case *ast.FuncLit:
423+
collect.anonymousFunctions = append(collect.anonymousFunctions, ctx.FileLine(expr))
401424
case *ast.Ident:
402425
callName := expr.Name
403426
// println("[parseFunc] ast.Ident:", callName)
@@ -462,6 +485,22 @@ func (p *GoParser) parseASTNode(ctx *fileContext, node ast.Node, collect *collec
462485
return true
463486
}
464487

488+
// parseCall collect direct call info
489+
func (p *GoParser) parseCall(ctx *fileContext, expr *ast.CallExpr, collect *collectInfos) {
490+
var ident *ast.Ident
491+
492+
switch idt := expr.Fun.(type) {
493+
case *ast.Ident:
494+
ident = idt
495+
case *ast.SelectorExpr:
496+
ident = idt.Sel
497+
}
498+
499+
if ident != nil {
500+
collect.directCalls[ctx.FileLine(ident)] = true
501+
}
502+
}
503+
465504
// parseFunc parses all function declaration in one file
466505
func (p *GoParser) parseFunc(ctx *fileContext, funcDecl *ast.FuncDecl) (*Function, bool) {
467506
// method receiver
@@ -511,7 +550,9 @@ func (p *GoParser) parseFunc(ctx *fileContext, funcDecl *ast.FuncDecl) (*Functio
511550
// collect content
512551
content := string(ctx.GetRawContent(funcDecl))
513552

514-
collects := collectInfos{}
553+
collects := collectInfos{
554+
directCalls: map[FileLine]bool{},
555+
}
515556
if funcDecl.Body == nil {
516557
goto set_func
517558
}
@@ -521,7 +562,6 @@ func (p *GoParser) parseFunc(ctx *fileContext, funcDecl *ast.FuncDecl) (*Functio
521562
})
522563

523564
set_func:
524-
525565
if fname == "init" && p.repo.GetFunction(NewIdentity(ctx.module.Name, ctx.pkgPath, fname)) != nil {
526566
// according to https://go.dev/ref/spec#Program_initialization_and_execution,
527567
// duplicated init() is allowed and never be referenced, thus add a subfix
@@ -544,6 +584,29 @@ set_func:
544584
f.Types = InsertDependency(f.Types, t)
545585
}
546586
f.Signature = string(sig)
587+
588+
if len(collects.directCalls) > 0 {
589+
for i, dep := range f.FunctionCalls {
590+
if collects.directCalls[dep.FileLine] {
591+
if f.FunctionCalls[i].Extra == nil {
592+
f.FunctionCalls[i].Extra = map[string]any{}
593+
}
594+
f.FunctionCalls[i].Extra["FunctionIsCall"] = true
595+
}
596+
}
597+
for i, dep := range f.MethodCalls {
598+
if collects.directCalls[dep.FileLine] {
599+
if f.MethodCalls[i].Extra == nil {
600+
f.MethodCalls[i].Extra = map[string]any{}
601+
}
602+
f.MethodCalls[i].Extra["FunctionIsCall"] = true
603+
}
604+
}
605+
}
606+
if len(collects.anonymousFunctions) > 0 {
607+
f.Extra = map[string]any{}
608+
f.Extra["AnonymousFunctions"] = collects.anonymousFunctions
609+
}
547610
return f, false
548611
}
549612

lang/uniast/ast.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -510,11 +510,14 @@ type Function struct {
510510

511511
// func llm compress result
512512
CompressData *string `json:"compress_data,omitempty"`
513+
514+
Extra map[string]any `json:",omitempty"`
513515
}
514516

515517
type Dependency struct {
516518
Identity
517519
FileLine `json:",omitempty"`
520+
Extra map[string]any `json:",omitempty"`
518521
}
519522

520523
func (d Dependency) Id() Identity {
@@ -607,6 +610,9 @@ type Type struct {
607610
// FieldFunctions map[string]string
608611

609612
CompressData *string `json:"compress_data,omitempty"` // struct llm compress result
613+
614+
// extra data
615+
Extra map[string]any `json:",omitempty"`
610616
}
611617

612618
type Var struct {
@@ -623,4 +629,7 @@ type Var struct {
623629
Groups []Identity `json:",omitempty"`
624630

625631
CompressData *string `json:"compress_data,omitempty"`
632+
633+
// extra data
634+
Extra map[string]any `json:",omitempty"`
626635
}

0 commit comments

Comments
 (0)