diff --git a/docs/uniast-en.md b/docs/uniast-en.md index a5fa4149..f618712a 100644 --- a/docs/uniast-en.md +++ b/docs/uniast-en.md @@ -432,7 +432,7 @@ Represents a dependency relationship, containing the dependent node Id, dependen - Extra: Additional information for storing language-specific details or extra metadata - - IsInvoked: For function/method dependencies, whether it is invoked or just referenced (not executed). + - IsInvoked: For function/method dependencies, or for GlobalVars dependencies whose target is a func-typed global variable, whether it is invoked or just referenced (not executed). For example, given `var Foo = func() {...}`, if another function body contains `Foo()`, the corresponding dependency in that function's `GlobalVars` is marked `IsInvoked: true`; a plain reference such as `_ = Foo` is not marked. ##### Type diff --git a/docs/uniast-zh.md b/docs/uniast-zh.md index 294783d5..f7e9dfdd 100644 --- a/docs/uniast-zh.md +++ b/docs/uniast-zh.md @@ -432,7 +432,7 @@ Universal Abstract-Syntax-Tree 是 ABCoder 建立的一种 LLM 亲和、语言 - Extra: 额外信息,用于存储一些语言特定的信息,或者是一些额外的元数据 - - IsInvoked: 对于函数 / 方法调用类依赖,用于说明该函数是被调用(invoke),还是仅获取其引用而不执行。 + - IsInvoked: 对于函数 / 方法调用类依赖,或函数型全局变量(GlobalVars)类依赖,用于说明该函数 / 全局变量是被调用(invoke),还是仅获取其引用而不执行。例如 `var Foo = func() {...}` 时,若另一函数体内出现 `Foo()`,则其在该函数 `GlobalVars` 中的依赖会被标记 `IsInvoked: true`;若仅出现 `_ = Foo` 等纯引用,则不会被标记。 ##### Type diff --git a/lang/golang/parser/file.go b/lang/golang/parser/file.go index 4631e4ac..0627535c 100644 --- a/lang/golang/parser/file.go +++ b/lang/golang/parser/file.go @@ -584,6 +584,11 @@ set_func: f.MethodCalls[i].SetExtra(ExtraKey_IsInvoked, true) } } + for i, dep := range f.GlobalVars { + if collects.directCalls[dep.FileLine] { + f.GlobalVars[i].SetExtra(ExtraKey_IsInvoked, true) + } + } } if len(collects.anonymousFunctions) > 0 { f.SetExtra(ExtraKey_AnonymousFunctions, collects.anonymousFunctions) diff --git a/lang/golang/parser/pkg_test.go b/lang/golang/parser/pkg_test.go index 81807dc3..2bf9bda0 100644 --- a/lang/golang/parser/pkg_test.go +++ b/lang/golang/parser/pkg_test.go @@ -114,6 +114,50 @@ func Test_goParser_ParseDirs(t *testing.T) { } } +func Test_goParser_GlobalFuncVar_IsInvoked(t *testing.T) { + p := newGoParser("a.b/c", testutils.FirstTest("go"), Options{LoadByPackages: true}) + pkgPath := "a.b/c/pkg" + if err := p.parsePackage(pkgPath); err != nil { + t.Fatalf("parsePackage failed: %v", err) + } + var6 := NewIdentity("a.b/c", pkgPath, "Var6") + + // Case_Invoke_GlobalFuncVar() directly calls Var6() -> IsInvoked must be true. + invokeFn := p.repo.GetFunction(NewIdentity("a.b/c", pkgPath, "Case_Invoke_GlobalFuncVar")) + if invokeFn == nil { + t.Fatalf("function Case_Invoke_GlobalFuncVar not found") + } + dep := findDep(invokeFn.GlobalVars, var6) + if dep == nil { + t.Fatalf("Var6 not found in GlobalVars of Case_Invoke_GlobalFuncVar") + } + if v, _ := dep.GetExtra(ExtraKey_IsInvoked).(bool); !v { + t.Fatalf("expected Var6 to be marked IsInvoked=true in Case_Invoke_GlobalFuncVar, got Extra=%+v", dep.Extra) + } + + // Case_Func_Global() only references Var6 (no call) -> IsInvoked must be unset. + refFn := p.repo.GetFunction(NewIdentity("a.b/c", pkgPath, "Case_Func_Global")) + if refFn == nil { + t.Fatalf("function Case_Func_Global not found") + } + dep = findDep(refFn.GlobalVars, var6) + if dep == nil { + t.Fatalf("Var6 not found in GlobalVars of Case_Func_Global") + } + if v, _ := dep.GetExtra(ExtraKey_IsInvoked).(bool); v { + t.Fatalf("expected Var6 to NOT be marked IsInvoked in Case_Func_Global") + } +} + +func findDep(deps []Dependency, id Identity) *Dependency { + for i := range deps { + if deps[i].Identity == id { + return &deps[i] + } + } + return nil +} + func TestGoAst(t *testing.T) { src := ` package parse diff --git a/testdata/go/0_golang/pkg/util.go b/testdata/go/0_golang/pkg/util.go index 7cc960b2..4a25f51d 100644 --- a/testdata/go/0_golang/pkg/util.go +++ b/testdata/go/0_golang/pkg/util.go @@ -125,6 +125,13 @@ func Case_Func_Global() { _ = entity.V1 } +// Case_Invoke_GlobalFuncVar directly invokes a global var that holds a func value. +// Used to verify that the GlobalVars dependency for Var6 is marked IsInvoked=true, +// while a pure reference (e.g. in Case_Func_Global) is not. +func Case_Invoke_GlobalFuncVar() { + Var6() +} + // Type is Result type type Type int