diff --git a/lang/golang/parser/file.go b/lang/golang/parser/file.go index 1115f6ee..822ee703 100644 --- a/lang/golang/parser/file.go +++ b/lang/golang/parser/file.go @@ -471,10 +471,17 @@ func (p *GoParser) parseStruct(ctx *fileContext, struName string, name *ast.Iden fieldname = fieldDecl.Names[0].Name } if stru, ok := fieldDecl.Type.(*ast.StructType); ok { - // anonymous struct. parse and collect it + // anonymous struct. parse it as, _ := p.parseStruct(ctx, "_"+fieldname, nil, stru) - dep := NewDependency(as.Identity, ctx.FileLine(fieldDecl.Type)) - st.SubStruct = append(st.SubStruct, dep) + // move out substructs of the anonymous struct + for _, dep := range as.SubStruct { + st.SubStruct = InsertDependency(st.SubStruct, dep) + } + for _, dep := range as.InlineStruct { + st.SubStruct = InsertDependency(st.InlineStruct, dep) + } + // remove the anonymous struct from the repo + delete(p.repo.GetPackage(as.ModPath, as.PkgPath).Types, as.Name) } else { p.collectTypes(ctx, fieldDecl.Type, st, inlined) } diff --git a/lang/golang/parser/pkg.go b/lang/golang/parser/pkg.go index ce75aca8..540df8f6 100644 --- a/lang/golang/parser/pkg.go +++ b/lang/golang/parser/pkg.go @@ -93,12 +93,12 @@ func (p *GoParser) associateImplements() { for iface, iid := range p.interfaces { if types.Implements(typ, iface) { tobj := p.getRepo().GetType(tid) - tobj.Implements = append(tobj.Implements, iid) + tobj.Implements = Append(tobj.Implements, iid) } // 另外检查 typ 的指针类型是否实现了 iface if types.Implements(types.NewPointer(typ), iface) { tobj := p.getRepo().GetType(tid) - tobj.Implements = append(tobj.Implements, iid) + tobj.Implements = Append(tobj.Implements, iid) } } } diff --git a/lang/golang/parser/pkg_test.go b/lang/golang/parser/pkg_test.go index 7c9ea858..1763338c 100644 --- a/lang/golang/parser/pkg_test.go +++ b/lang/golang/parser/pkg_test.go @@ -114,8 +114,9 @@ func Test_goParser_ParseDirs(t *testing.T) { if err != nil { t.Fatal(err) } - _ = out - println(string(out)) + if err := os.WriteFile("golang.json", out, 0644); err != nil { + t.Fatal(err) + } }) } } diff --git a/lang/uniast/node.go b/lang/uniast/node.go index 1112b9ea..d6dfc096 100644 --- a/lang/uniast/node.go +++ b/lang/uniast/node.go @@ -90,7 +90,7 @@ func calOffset(ref, dep FileLine) int { func (r *Repository) AddRelation(node *Node, dep Identity, depFl FileLine) { line := calOffset(node.FileLine(), depFl) - node.Dependencies = append(node.Dependencies, Relation{ + node.Dependencies = InsertRelation(node.Dependencies, Relation{ Identity: dep, Kind: DEPENDENCY, Line: line, @@ -104,7 +104,7 @@ func (r *Repository) AddRelation(node *Node, dep Identity, depFl FileLine) { } r.Graph[key] = nd } - nd.References = append(nd.References, Relation{ + nd.References = InsertRelation(nd.References, Relation{ Identity: node.Identity, Kind: REFERENCE, Line: line, @@ -145,6 +145,9 @@ func (r *Repository) BuildGraph() error { for _, dep := range f.Types { r.AddRelation(n, dep.Identity, dep.FileLine) } + if f.Receiver != nil { + r.AddRelation(n, f.Receiver.Type, n.FileLine()) + } for _, dep := range f.GlobalVars { r.AddRelation(n, dep.Identity, dep.FileLine) } diff --git a/lang/uniast/utils.go b/lang/uniast/utils.go index 0870024f..a00957cc 100644 --- a/lang/uniast/utils.go +++ b/lang/uniast/utils.go @@ -21,6 +21,15 @@ import ( "os" ) +func Append[T comparable](ids []T, id T) []T { + for _, i := range ids { + if i == id { + return ids + } + } + return append(ids, id) +} + func InsertDependency(ids []Dependency, id Dependency) []Dependency { for _, i := range ids { if i.Identity == id.Identity { @@ -39,6 +48,15 @@ func InserImport(ids []Import, id Import) []Import { return append(ids, id) } +func InsertRelation(ids []Relation, id Relation) []Relation { + for _, i := range ids { + if i.Identity == id.Identity { + return ids + } + } + return append(ids, id) +} + func LoadRepo(path string) (*Repository, error) { bs, err := os.ReadFile(path) if err != nil { diff --git a/testdata/golang/go.mod b/testdata/golang/go.mod index 1f107d0e..6e52283a 100644 --- a/testdata/golang/go.mod +++ b/testdata/golang/go.mod @@ -2,10 +2,7 @@ module a.b/c go 1.20 -require ( - github.com/bytedance/sonic v1.10.2 - github.com/pkg/errors v0.9.1 -) +require github.com/bytedance/sonic v1.10.2 require ( github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d // indirect diff --git a/testdata/golang/go.sum b/testdata/golang/go.sum index a99e9adf..956451c1 100644 --- a/testdata/golang/go.sum +++ b/testdata/golang/go.sum @@ -14,8 +14,6 @@ github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs github.com/klauspost/cpuid/v2 v2.0.9 h1:lgaqFMSdTdQYdZ04uHyN2d/eKdOMyi2YLSvlQIBFYa4= github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= github.com/knz/go-libedit v1.10.1/go.mod h1:MZTVkCWyz0oBc7JOWP3wNAzd002ZbM/5hgShxwh4x8M= -github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= -github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= diff --git a/testdata/golang/pkg/entity/entity.go b/testdata/golang/pkg/entity/entity.go index 23983492..830ef77c 100644 --- a/testdata/golang/pkg/entity/entity.go +++ b/testdata/golang/pkg/entity/entity.go @@ -1,11 +1,11 @@ // Copyright 2025 CloudWeGo Authors -// +// // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at -// +// // https://www.apache.org/licenses/LICENSE-2.0 -// +// // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -25,6 +25,9 @@ type MyStruct struct { b string c MyStructC MyStructD + Embed struct { + *MyStruct + } } type InterfaceB interface { @@ -32,6 +35,8 @@ type InterfaceB interface { } func (a MyStruct) String() string { + _ = a.Embed.MyStruct + _ = a.MyStructD return "base struct" }