Skip to content

Commit a9c2e8b

Browse files
committed
add '// @contextcheck(req_has_ctx)'
1 parent d4cc8a2 commit a9c2e8b

File tree

2 files changed

+47
-13
lines changed

2 files changed

+47
-13
lines changed

contextcheck.go

Lines changed: 41 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,10 @@ var (
6868
type resInfo struct {
6969
Valid bool
7070
Funcs []string
71+
72+
// reuse for doc
73+
ReqCtx bool
74+
Skip bool
7175
}
7276

7377
type ctxFact map[string]resInfo
@@ -238,24 +242,45 @@ func (r *runner) checkIsEntry(f *ssa.Function) entryType {
238242
return EntryWithCtx
239243
}
240244

245+
reqctx, skip := r.docFlag(f)
246+
241247
// check is `func handler(w http.ResponseWriter, r *http.Request) {}`
242-
if r.checkIsHttpHandler(f) {
248+
// or use '// @contextcheck(req_has_ctx)'
249+
if r.checkIsHttpHandler(f, reqctx) {
243250
return EntryWithHttpHandler
244251
}
245252

246-
if r.skipByNolint(f) {
253+
if skip {
247254
return EntryNone
248255
}
249256

250257
return EntryNormal
251258
}
252259

260+
func (r *runner) docFlag(f *ssa.Function) (reqctx, skip bool) {
261+
key := "doc:" + f.RelString(nil)
262+
res, ok := r.getValue(key, f)
263+
if ok {
264+
return res.ReqCtx, res.Skip
265+
}
266+
267+
for _, v := range r.getDocFromFunc(f) {
268+
if len(nolintRe.FindString(v.Text)) > 0 && strings.Contains(v.Text, "contextcheck") {
269+
res.Skip = true
270+
} else if strings.HasPrefix(v.Text, "// @contextcheck(req_has_ctx)") {
271+
res.ReqCtx = true
272+
}
273+
}
274+
r.currentFact[key] = res
275+
return res.ReqCtx, res.Skip
276+
}
277+
253278
var nolintRe = regexp.MustCompile(`^//\s?nolint:`)
254279

255-
func (r *runner) skipByNolint(f *ssa.Function) bool {
280+
func (r *runner) getDocFromFunc(f *ssa.Function) []*ast.Comment {
256281
file := analysisutil.File(r.pass, f.Pos())
257282
if file == nil {
258-
return false
283+
return nil
259284
}
260285

261286
// only support FuncDecl comment
@@ -267,15 +292,9 @@ func (r *runner) skipByNolint(f *ssa.Function) bool {
267292
}
268293
}
269294
if fd == nil || fd.Doc == nil || len(fd.Doc.List) == 0 {
270-
return false
271-
}
272-
273-
for _, v := range fd.Doc.List {
274-
if len(nolintRe.FindString(v.Text)) > 0 && strings.Contains(v.Text, "contextcheck") {
275-
return true
276-
}
295+
return nil
277296
}
278-
return false
297+
return fd.Doc.List
279298
}
280299

281300
func (r *runner) checkIsCtx(f *ssa.Function) (in, out bool) {
@@ -307,7 +326,16 @@ func (r *runner) checkIsCtx(f *ssa.Function) (in, out bool) {
307326
return
308327
}
309328

310-
func (r *runner) checkIsHttpHandler(f *ssa.Function) bool {
329+
func (r *runner) checkIsHttpHandler(f *ssa.Function, reqctx bool) bool {
330+
if reqctx {
331+
tuple := f.Signature.Params()
332+
for i := 0; i < tuple.Len(); i++ {
333+
if r.isHttpReqType(tuple.At(i).Type()) {
334+
return true
335+
}
336+
}
337+
}
338+
311339
// must has no result
312340
if f.Signature.Results().Len() > 0 {
313341
return false

testdata/src/a/a.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,11 @@ func f14(w http.ResponseWriter, r *http.Request, err error) {
114114
f8(r.Context(), w, r)
115115
}
116116

117+
// @contextcheck(req_has_ctx)
118+
func f15(w http.ResponseWriter, r *http.Request, err error) {
119+
f8(r.Context(), w, r)
120+
}
121+
117122
func f11() {
118123
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
119124
f8(r.Context(), w, r)
@@ -125,6 +130,7 @@ func f11() {
125130
f10(true, w, r) // want "Function `f10` should pass the context parameter"
126131

127132
f14(w, r, nil)
133+
f15(w, r, nil)
128134
})
129135
}
130136

0 commit comments

Comments
 (0)