Skip to content

Commit 575841c

Browse files
authored
fix:(uniast) collect parameters when buildgraph (#40)
* fix:(uniast) collect parameters when buildgraph * fix:(go) should match the longest prefix of a PkgPath to find ModPath * license
1 parent c35f8eb commit 575841c

File tree

7 files changed

+146
-41
lines changed

7 files changed

+146
-41
lines changed

lang/golang/parser/ctx.go

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -152,17 +152,11 @@ func (ctx *fileContext) GetMod(impt string) (string, error) {
152152
return ims[0], nil
153153
}
154154
}
155-
// try find self first
156-
if strings.HasPrefix(impt, ctx.module.Name) {
157-
return ctx.module.Name, nil
158-
}
159-
// try find in go.mod
160-
for dep, ver := range ctx.module.Dependencies {
161-
if strings.HasPrefix(impt, dep) {
162-
return ver, nil
163-
}
155+
mod, _ := matchMod(impt, ctx.module.Dependencies)
156+
if mod == "" {
157+
return "", fmt.Errorf("not found mod for %s", impt)
164158
}
165-
return "", fmt.Errorf("not found mod: %s", impt)
159+
return mod, nil
166160
}
167161

168162
func (ctx *fileContext) FileLine(node ast.Node) FileLine {

lang/golang/parser/file.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -422,6 +422,9 @@ func (p *GoParser) parseFunc(ctx *fileContext, funcDecl *ast.FuncDecl) (*Functio
422422
// method receiver
423423
var receiver *Receiver
424424
isMethod := funcDecl.Recv != nil
425+
if strings.HasSuffix(ctx.filePath, "cmds/life_stat/main.go") && funcDecl.Name.Name == "init" {
426+
427+
}
425428
if isMethod {
426429
// TODO: reserve the pointer message?
427430
ti := ctx.GetTypeInfo(funcDecl.Recv.List[0].Type)

lang/golang/parser/pkg.go

Lines changed: 28 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@ import (
2121
"go/types"
2222
"os"
2323
"path/filepath"
24+
"sort"
25+
"strconv"
2426
"strings"
2527

2628
. "github.com/cloudwego/abcoder/lang/uniast"
@@ -33,7 +35,7 @@ func (p *GoParser) parseImports(fset *token.FileSet, file []byte, mod *Module, i
3335
sysImports := make(map[string]string)
3436
ret := &importInfo{}
3537
for _, imp := range impts {
36-
importPath := imp.Path.Value[1 : len(imp.Path.Value)-1] // remove the quotes
38+
importPath, _ := strconv.Unquote(imp.Path.Value) // remove the quotes
3739
importAlias := ""
3840
// Check if user has defined an alias for current import
3941
if imp.Name != nil {
@@ -49,12 +51,14 @@ func (p *GoParser) parseImports(fset *token.FileSet, file []byte, mod *Module, i
4951
// Ignoring golang standard libraries(like net/http)
5052
sysImports[importAlias] = importPath
5153
} else {
52-
// Distinguish between project packages and third party packages
53-
if strings.HasPrefix(importPath, mod.Name) {
54+
match, path := matchMod(importPath, mod.Dependencies)
55+
if match == "" {
56+
if !strings.HasPrefix(importPath, mod.Name) {
57+
return nil, fmt.Errorf("package %s not found mod", importPath)
58+
}
5459
projectImports[importAlias] = importPath
5560
} else {
56-
mod := mod.GetDependency(importPath)
57-
thirdPartyImports[importAlias] = [2]string{mod, importPath}
61+
thirdPartyImports[importAlias] = [2]string{path, importPath}
5862
}
5963
}
6064
}
@@ -64,6 +68,24 @@ func (p *GoParser) parseImports(fset *token.FileSet, file []byte, mod *Module, i
6468
return ret, nil
6569
}
6670

71+
func matchMod(impt string, modules map[string]string) (name string, path string) {
72+
matches := [][2]string{}
73+
for name, path := range modules {
74+
if strings.HasPrefix(impt, name) {
75+
matches = append(matches, [2]string{name, path})
76+
}
77+
}
78+
79+
if len(matches) > 0 {
80+
sort.Slice(matches, func(i, j int) bool {
81+
return len(matches[i][0]) > len(matches[j][0])
82+
})
83+
name = matches[0][0]
84+
path = matches[0][1]
85+
}
86+
return
87+
}
88+
6789
func (p *GoParser) ParseNode(pkgPath string, name string) (Repository, error) {
6890
out := NewRepository(p.repo.Name)
6991
if pkgPath == "" {
@@ -117,19 +139,10 @@ func (p *GoParser) ParsePackage(pkgPath PkgPath) (Repository, error) {
117139
}
118140

119141
func (p *GoParser) parsePackage(pkgPath PkgPath) (err error) {
120-
mod, dir := p.getModuleFromPkg(pkgPath)
142+
mod, _ := p.getModuleFromPkg(pkgPath)
121143
if mod == "" {
122144
return fmt.Errorf("not found module for package %s", pkgPath)
123145
}
124-
if dir == "" {
125-
// NOTICE: external package should set the dir to the one of its referer
126-
for _, m := range p.repo.Modules {
127-
if m.GetDependency(pkgPath) != "" {
128-
dir = filepath.Join(p.homePageDir, m.Dir)
129-
break
130-
}
131-
}
132-
}
133146
// fast-path: check cache first
134147
if p.visited[pkgPath] {
135148
return nil

lang/golang/parser/pkg_test.go

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -191,3 +191,41 @@ func Test_goParser_ParseNode(t *testing.T) {
191191
})
192192
}
193193
}
194+
195+
func Test_matchMod(t *testing.T) {
196+
type args struct {
197+
impt string
198+
modules map[string]string
199+
}
200+
tests := []struct {
201+
name string
202+
args args
203+
wantName string
204+
wantPath string
205+
}{
206+
{
207+
name: "test",
208+
args: args{
209+
impt: "github.com/xx/yy/zz",
210+
modules: map[string]string{
211+
"github.com/xx/yy": "github.com/xx/yy@v1",
212+
"github.com/xx/yy/zz": "github.com/xx/yy/zz@v2",
213+
"github.com/xx/yy/bb": "github.com/xx/yy/bb@v3",
214+
},
215+
},
216+
wantName: "github.com/xx/yy/zz",
217+
wantPath: "github.com/xx/yy/zz@v2",
218+
},
219+
}
220+
for _, tt := range tests {
221+
t.Run(tt.name, func(t *testing.T) {
222+
gotName, gotPath := matchMod(tt.args.impt, tt.args.modules)
223+
if gotName != tt.wantName {
224+
t.Errorf("matchMod() gotName = %v, want %v", gotName, tt.wantName)
225+
}
226+
if gotPath != tt.wantPath {
227+
t.Errorf("matchMod() gotPath = %v, want %v", gotPath, tt.wantPath)
228+
}
229+
})
230+
}
231+
}

lang/uniast/ast.go

Lines changed: 0 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -218,22 +218,6 @@ func NewModule(name string, dir string, language Language) *Module {
218218
return &ret
219219
}
220220

221-
func (p *Module) GetDependency(pkg string) string {
222-
// // search internal library first
223-
// if lib := p.Libraries[mod]; lib != nil {
224-
// return lib
225-
// }
226-
// match the prefix of name for each repo.Dependencies
227-
for k, v := range p.Dependencies {
228-
if strings.HasPrefix(pkg, k) {
229-
return v
230-
}
231-
}
232-
// FIXME: return value's dependency may not explicitly defined in go.mod, thus may not be found
233-
// fmt.Fprintf(os.Stderr, "Error: not found dependency for %v", pkg)
234-
return ""
235-
}
236-
237221
// Package
238222
type Package struct {
239223
IsMain bool

lang/uniast/node.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,12 @@ func (r *Repository) BuildGraph() error {
164164
for _, pkg := range mod.Packages {
165165
for _, f := range pkg.Functions {
166166
n := r.SetNode(f.Identity, FUNC)
167+
for _, dep := range f.Params {
168+
r.AddRelation(n, dep.Identity, dep.FileLine, DEPENDENCY)
169+
}
170+
for _, dep := range f.Results {
171+
r.AddRelation(n, dep.Identity, dep.FileLine, DEPENDENCY)
172+
}
167173
for _, dep := range f.FunctionCalls {
168174
r.AddRelation(n, dep.Identity, dep.FileLine, DEPENDENCY)
169175
}

script/pretty_json.go

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
// Copyright 2025 CloudWeGo Authors
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// https://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
package main
16+
17+
import (
18+
"encoding/json"
19+
"fmt"
20+
"io/ioutil"
21+
"os"
22+
)
23+
24+
// prettyPrintJSON 读取 JSON 文件,格式化后写回原文件
25+
func prettyPrintJSON(filePath string) error {
26+
// 读取文件内容
27+
fileContent, err := ioutil.ReadFile(filePath)
28+
if err != nil {
29+
return fmt.Errorf("读取文件失败: %w", err)
30+
}
31+
32+
var data interface{}
33+
// 解析 JSON 数据
34+
err = json.Unmarshal(fileContent, &data)
35+
if err != nil {
36+
return fmt.Errorf("解析 JSON 数据失败: %w", err)
37+
}
38+
39+
// 格式化 JSON 数据
40+
prettyJSON, err := json.MarshalIndent(data, "", " ")
41+
if err != nil {
42+
return fmt.Errorf("格式化 JSON 数据失败: %w", err)
43+
}
44+
45+
// 将格式化后的 JSON 数据写回原文件
46+
err = ioutil.WriteFile(filePath, prettyJSON, 0644)
47+
if err != nil {
48+
return fmt.Errorf("写入文件失败: %w", err)
49+
}
50+
51+
return nil
52+
}
53+
54+
func main() {
55+
if len(os.Args) != 2 {
56+
fmt.Println("用法: go run pretty_json.go <json_file_path>")
57+
os.Exit(1)
58+
}
59+
60+
filePath := os.Args[1]
61+
err := prettyPrintJSON(filePath)
62+
if err != nil {
63+
fmt.Printf("错误: %v\n", err)
64+
os.Exit(1)
65+
}
66+
fmt.Printf("JSON 文件 %s 已成功格式化。\n", filePath)
67+
}

0 commit comments

Comments
 (0)