Skip to content

Commit d4c14b3

Browse files
authored
fix: cgo file length calculate wrong (#138)
1 parent 964a648 commit d4c14b3

File tree

3 files changed

+80
-21
lines changed

3 files changed

+80
-21
lines changed

lang/golang/parser/ctx.go

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,15 @@ func (p *GoParser) referCodes(ctx *fileContext, id *Identity, depth int) (err er
8686
if pkg == nil {
8787
return fmt.Errorf("cannot find package %s", id.PkgPath)
8888
}
89-
for _, fpath := range pkg.GoFiles {
89+
90+
var files []string
91+
if len(p.cgoPkgs) > 0 {
92+
files = pkg.CompiledGoFiles
93+
} else {
94+
files = pkg.GoFiles
95+
}
96+
97+
for _, fpath := range files {
9098
bs := p.getFileBytes(fpath)
9199
file, err := parser.ParseFile(pkg.Fset, fpath, bs, parser.ParseComments)
92100
if err != nil {

lang/golang/parser/parser.go

Lines changed: 33 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ type GoParser struct {
4747
types map[types.Type]Identity
4848
files map[string][]byte
4949
exclues []*regexp.Regexp
50+
cgoPkgs map[string]bool // CGO packages
5051
}
5152

5253
type moduleInfo struct {
@@ -98,6 +99,7 @@ func newGoParser(name string, homePageDir string, opts Options) *GoParser {
9899
func (p *GoParser) collectGoMods(startDir string) error {
99100
hasGoWork := false
100101
deps := map[string]string{}
102+
var cgoPkgs map[string]bool
101103
err := filepath.Walk(startDir, func(path string, info fs.FileInfo, err error) error {
102104
if err != nil || !strings.HasSuffix(path, "go.mod") {
103105
return nil
@@ -115,10 +117,18 @@ func (p *GoParser) collectGoMods(startDir string) error {
115117
p.repo.Modules[name] = newModule(name, rel)
116118
p.modules = append(p.modules, newModuleInfo(name, rel, name))
117119

118-
deps, hasGoWork, err = getDeps(filepath.Dir(path), hasGoWork)
120+
deps, hasGoWork, cgoPkgs, err = getDeps(filepath.Dir(path), hasGoWork)
119121
if err != nil {
120122
return err
121123
}
124+
if p.cgoPkgs == nil {
125+
p.cgoPkgs = make(map[string]bool)
126+
}
127+
for pkgPath := range cgoPkgs {
128+
if strings.HasPrefix(pkgPath, name) {
129+
p.cgoPkgs[pkgPath] = true
130+
}
131+
}
122132
for k, v := range deps {
123133
p.repo.Modules[name].Dependencies[k] = v
124134
p.modules = append(p.modules, newModuleInfo(k, "", v))
@@ -148,18 +158,29 @@ type dep struct {
148158
Dir string `json:"Dir"`
149159
GoMod string `json:"GoMod"`
150160
} `json:"Module"`
161+
CgoFiles []string `json:"CgoFiles"`
151162
}
152163

153-
func getDeps(dir string, goWork bool) (a map[string]string, hasGoWork bool, err error) {
164+
func getDeps(dir string, goWork bool) (a map[string]string, hasGoWork bool, cgoPkgs map[string]bool, err error) {
165+
cgoPkgs = make(map[string]bool)
154166
// run go mod tidy first to ensure all dependencies are resolved
155167
cmd := exec.Command("go", "mod", "tidy", "-e")
156168
cmd.Dir = dir
169+
cmd.Env = append(os.Environ(), "GONOSUMDB=*")
157170
output, err := cmd.CombinedOutput()
158171
if err != nil {
159-
return nil, hasGoWork, fmt.Errorf("failed to execute 'go mod tidy', err: %v, output: %s", err, string(output))
172+
fmt.Fprintf(os.Stderr, "failed to execute 'go mod tidy', err: %v, output: %s, remove go.sum file reexecute\n", err, string(output))
173+
os.Remove(filepath.Join(dir, "go.sum"))
174+
cmd = exec.Command("go", "mod", "tidy", "-e")
175+
cmd.Dir = dir
176+
cmd.Env = append(os.Environ(), "GOSUMDB=off")
177+
output, err = cmd.CombinedOutput()
178+
if err != nil {
179+
return nil, hasGoWork, cgoPkgs, fmt.Errorf("failed to execute 'go mod tidy', err: %v, output: %s", err, string(output))
180+
}
160181
}
161182
if hasNoDeps(filepath.Join(dir, "go.mod")) {
162-
return map[string]string{}, hasGoWork, nil
183+
return map[string]string{}, hasGoWork, cgoPkgs, nil
163184
}
164185
// -mod=mod to use go mod when go mod is inconsistent with go vendor
165186
// if go.work exist, it's no need to set -mod=mod
@@ -170,14 +191,15 @@ func getDeps(dir string, goWork bool) (a map[string]string, hasGoWork bool, err
170191
cmd = exec.Command("go", "list", "-e", "-json", "-mod=mod", "all")
171192
}
172193
cmd.Dir = dir
194+
cmd.Env = append(os.Environ(), "GOSUMDB=off")
173195
output, err = cmd.CombinedOutput()
174196
if err != nil {
175-
return nil, hasGoWork, fmt.Errorf("failed to execute 'go list -json all', err: %v, output: %s, cmd string: %s, dir: %s", err, string(output), cmd.String(), dir)
197+
return nil, hasGoWork, cgoPkgs, fmt.Errorf("failed to execute 'go list -json all', err: %v, output: %s, cmd string: %s, dir: %s", err, string(output), cmd.String(), dir)
176198
}
177199
// ignore content until first open
178200
index := strings.Index(string(output), "{")
179201
if index == -1 {
180-
return nil, hasGoWork, fmt.Errorf("failed to find '{' in output, output: %s", string(output))
202+
return nil, hasGoWork, cgoPkgs, fmt.Errorf("failed to find '{' in output, output: %s", string(output))
181203
}
182204
if index > 0 {
183205
log.Info("go list skip prefix, output: %s", string(output[:index]))
@@ -191,13 +213,16 @@ func getDeps(dir string, goWork bool) (a map[string]string, hasGoWork bool, err
191213
if err.Error() == "EOF" {
192214
break
193215
}
194-
return nil, hasGoWork, fmt.Errorf("failed to decode json: %v, output: %s", err, string(output))
216+
return nil, hasGoWork, cgoPkgs, fmt.Errorf("failed to decode json: %v, output: %s", err, string(output))
195217
}
196218
module := mod.Module
197219
// golang internal package, ignore it.
198220
if module.Path == "" {
199221
continue
200222
}
223+
if len(mod.CgoFiles) > 0 {
224+
cgoPkgs[module.Path] = true
225+
}
201226
if module.Replace != nil {
202227
deps[module.Path] = module.Replace.Path + "@" + module.Replace.Version
203228
} else {
@@ -214,8 +239,7 @@ func getDeps(dir string, goWork bool) (a map[string]string, hasGoWork bool, err
214239
}
215240
}
216241
}
217-
218-
return deps, hasGoWork, nil
242+
return deps, hasGoWork, cgoPkgs, nil
219243
}
220244

221245
// ParseRepo parse the entiry repo from homePageDir recursively until end

lang/golang/parser/pkg.go

Lines changed: 38 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -172,24 +172,44 @@ func (p *GoParser) loadPackages(mod *Module, dir string, pkgPath PkgPath) (err e
172172
fmt.Fprintf(os.Stderr, "[loadPackages] mod: %s, dir: %s, pkgPath: %s\n", mod.Name, dir, pkgPath)
173173
fset := token.NewFileSet()
174174
loadCount++
175-
// slow-path: load packages in the dir, including sub pakcages
176-
opts := packages.NeedFiles | packages.NeedSyntax | packages.NeedTypes | packages.NeedTypesInfo | packages.NeedImports
175+
176+
baseOpts := packages.NeedFiles | packages.NeedSyntax | packages.NeedTypes | packages.NeedTypesInfo | packages.NeedImports
177+
if p.opts.ReferCodeDepth != 0 {
178+
baseOpts |= packages.NeedDeps
179+
}
180+
if p.opts.NeedTest {
181+
baseOpts |= packages.NeedForTest
182+
}
183+
177184
cfg := &packages.Config{
178-
Mode: opts,
185+
Mode: baseOpts,
179186
Fset: fset,
180187
Dir: dir,
181188
}
182-
if p.opts.ReferCodeDepth != 0 {
183-
opts |= packages.NeedDeps
184-
}
189+
185190
if p.opts.NeedTest {
186-
opts |= packages.NeedForTest
187191
cfg.Tests = true
188192
}
193+
189194
pkgs, err := packages.Load(cfg, pkgPath)
190195
if err != nil {
191196
return fmt.Errorf("load path '%s' failed: %v", dir, err)
192197
}
198+
199+
hasCGO := false
200+
if len(p.cgoPkgs) > 0 {
201+
hasCGO = true
202+
}
203+
fmt.Fprintf(os.Stderr, "[loadPackages] mod: %s, dir: %s, pkgPath: %s, hasCGO: %v\n", mod.Name, dir, pkgPath, hasCGO)
204+
if hasCGO {
205+
baseOpts |= packages.NeedCompiledGoFiles
206+
cfg.Mode = baseOpts
207+
pkgs, err = packages.Load(cfg, pkgPath)
208+
if err != nil {
209+
return fmt.Errorf("load path '%s' with CGO failed: %v", dir, err)
210+
}
211+
}
212+
193213
for _, pkg := range pkgs {
194214
if mm := p.repo.Modules[mod.Name]; mm != nil && (*mm).Packages[pkg.ID] != nil {
195215
continue
@@ -198,11 +218,18 @@ func (p *GoParser) loadPackages(mod *Module, dir string, pkgPath PkgPath) (err e
198218
continue
199219
}
200220
for idx, file := range pkg.Syntax {
201-
if idx >= len(pkg.GoFiles) {
202-
fmt.Fprintf(os.Stderr, "skip file %s by loader\n", file.Name)
203-
continue
221+
var filePath string
222+
if hasCGO {
223+
// Cgo file path is tmp file path, like: /Users/bytedance/Library/Caches/go-build/61/6150fdadd44b9dca151737e261abf95697ba13b799e8dbdd464c0c27b443792a-d.
224+
// We should get it through CompiledGoFiles
225+
if idx >= len(pkg.CompiledGoFiles) {
226+
fmt.Fprintf(os.Stderr, "skip file %s by loader\n", file.Name)
227+
continue
228+
}
229+
filePath = pkg.CompiledGoFiles[idx]
230+
} else {
231+
filePath = fset.Position(file.Pos()).Filename
204232
}
205-
filePath := pkg.GoFiles[idx]
206233
var skip bool
207234
for _, exclude := range p.exclues {
208235
if exclude.MatchString(filePath) {

0 commit comments

Comments
 (0)