Skip to content

Commit 30ee69c

Browse files
committed
fix buildPkg
1 parent 20c10da commit 30ee69c

File tree

2 files changed

+133
-9
lines changed

2 files changed

+133
-9
lines changed

contextcheck.go

+17-9
Original file line numberDiff line numberDiff line change
@@ -11,14 +11,15 @@ import (
1111
"github.com/gostaticanalysis/analysisutil"
1212
"golang.org/x/tools/go/analysis"
1313
"golang.org/x/tools/go/analysis/passes/buildssa"
14+
"golang.org/x/tools/go/packages"
1415
"golang.org/x/tools/go/ssa"
1516
)
1617

1718
func NewAnalyzer() *analysis.Analyzer {
1819
return &analysis.Analyzer{
1920
Name: "contextcheck",
2021
Doc: "check the function whether use a non-inherited context",
21-
Run: NewRun(),
22+
Run: NewRun(nil),
2223
Requires: []*analysis.Analyzer{
2324
buildssa.Analyzer,
2425
},
@@ -41,6 +42,7 @@ const (
4142
var (
4243
checkedMap = make(map[string]bool)
4344
checkedMapLock sync.RWMutex
45+
c *collector
4446
)
4547

4648
type runner struct {
@@ -51,8 +53,11 @@ type runner struct {
5153
skipFile map[*ast.File]bool
5254
}
5355

54-
func NewRun() func(pass *analysis.Pass) (interface{}, error) {
56+
func NewRun(pkgs []*packages.Package) func(pass *analysis.Pass) (interface{}, error) {
57+
c = newCollector(pkgs)
5558
return func(pass *analysis.Pass) (interface{}, error) {
59+
defer c.DecUse(pass)
60+
5661
r := new(runner)
5762
r.run(pass)
5863
return nil, nil
@@ -264,15 +269,14 @@ func (r *runner) collectCtxRef(f *ssa.Function) (refMap map[ssa.Instruction]bool
264269
return
265270
}
266271

267-
func (r *runner) buildPkg(f *ssa.Function) {
272+
func (r *runner) buildPkg(f *ssa.Function) (ff *ssa.Function) {
268273
if f.Blocks != nil {
274+
ff = f
269275
return
270276
}
271277

272-
// only build the pkg which is in the same repo
273-
if r.checkIsSameRepo(f.Pkg.Pkg.Path()) {
274-
f.Pkg.Build()
275-
}
278+
ff = c.GetFunction(f)
279+
return
276280
}
277281

278282
func (r *runner) checkIsSameRepo(s string) bool {
@@ -324,7 +328,9 @@ func (r *runner) checkFuncWithCtx(f *ssa.Function) {
324328

325329
// if ff has no ctx, start deep traversal check
326330
if !r.checkIsEntry(ff, instr.Pos()) {
327-
r.buildPkg(ff)
331+
if ff = r.buildPkg(ff); ff == nil {
332+
continue
333+
}
328334

329335
checkingMap := make(map[string]bool)
330336
checkingMap[key] = true
@@ -386,7 +392,9 @@ func (r *runner) checkFuncWithoutCtx(f *ssa.Function, checkingMap map[string]boo
386392
}
387393
checkingMap[key] = true
388394

389-
r.buildPkg(ff)
395+
if ff = r.buildPkg(ff); ff == nil {
396+
continue
397+
}
390398

391399
valid := r.checkFuncWithoutCtx(ff, checkingMap)
392400
setValue(key, valid)

dep.go

+116
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
package contextcheck
2+
3+
import (
4+
"go/types"
5+
"sync/atomic"
6+
7+
"golang.org/x/tools/go/analysis"
8+
"golang.org/x/tools/go/analysis/passes/buildssa"
9+
"golang.org/x/tools/go/packages"
10+
"golang.org/x/tools/go/ssa"
11+
)
12+
13+
type pkgInfo struct {
14+
pkgPkg *packages.Package // to find references later
15+
ssaPkg *ssa.Package // to find func which has been built
16+
refCnt int32 // reference count
17+
}
18+
19+
type collector struct {
20+
m map[string]*pkgInfo
21+
}
22+
23+
func newCollector(pkgs []*packages.Package) (c *collector) {
24+
c = &collector{
25+
m: make(map[string]*pkgInfo),
26+
}
27+
28+
// self-reference
29+
for _, pkg := range pkgs {
30+
c.m[pkg.PkgPath] = &pkgInfo{
31+
pkgPkg: pkg,
32+
refCnt: 1,
33+
}
34+
}
35+
36+
// import reference
37+
for _, pkg := range pkgs {
38+
for _, imp := range pkg.Imports {
39+
if val, ok := c.m[imp.PkgPath]; ok {
40+
val.refCnt++
41+
}
42+
}
43+
}
44+
45+
return
46+
}
47+
48+
func (c *collector) DecUse(pass *analysis.Pass) {
49+
curPkg, ok := c.m[pass.Pkg.Path()]
50+
if !ok {
51+
return
52+
}
53+
54+
if atomic.AddInt32(&curPkg.refCnt, -1) != 0 {
55+
curPkg.ssaPkg = pass.ResultOf[buildssa.Analyzer].(*buildssa.SSA).Pkg
56+
return
57+
}
58+
59+
var release func(info *pkgInfo)
60+
release = func(info *pkgInfo) {
61+
for _, pkg := range info.pkgPkg.Imports {
62+
if val, ok := c.m[pkg.PkgPath]; ok {
63+
if atomic.AddInt32(&val.refCnt, -1) == 0 {
64+
release(val)
65+
}
66+
}
67+
}
68+
69+
info.pkgPkg = nil
70+
info.ssaPkg = nil
71+
}
72+
release(curPkg)
73+
}
74+
75+
func (c *collector) GetFunction(f *ssa.Function) (ff *ssa.Function) {
76+
info, ok := c.m[f.Pkg.Pkg.Path()]
77+
if !ok {
78+
return
79+
}
80+
81+
// without recv => get by Func
82+
recv := f.Signature.Recv()
83+
if recv == nil {
84+
ff = info.ssaPkg.Func(f.Name())
85+
return
86+
}
87+
88+
// with recv => find in prog according to type
89+
ntp, ptp := getNamedType(recv.Type())
90+
if ntp == nil {
91+
return
92+
}
93+
sel := info.ssaPkg.Prog.MethodSets.MethodSet(ntp).Lookup(ntp.Obj().Pkg(), f.Name())
94+
if sel == nil {
95+
sel = info.ssaPkg.Prog.MethodSets.MethodSet(ptp).Lookup(ntp.Obj().Pkg(), f.Name())
96+
}
97+
if sel == nil {
98+
return
99+
}
100+
ff = info.ssaPkg.Prog.MethodValue(sel)
101+
return
102+
}
103+
104+
func getNamedType(tp types.Type) (ntp *types.Named, ptp *types.Pointer) {
105+
switch t := tp.(type) {
106+
case *types.Named:
107+
ntp = t
108+
ptp = types.NewPointer(tp)
109+
case *types.Pointer:
110+
if n, ok := t.Elem().(*types.Named); ok {
111+
ntp = n
112+
ptp = t
113+
}
114+
}
115+
return
116+
}

0 commit comments

Comments
 (0)