From 7be313c69e967dc81063d61f84d0736462503384 Mon Sep 17 00:00:00 2001 From: kkHAIKE Date: Sat, 3 Sep 2022 17:01:20 +0800 Subject: [PATCH] add nolint skip support --- README.md | 17 +++++++++++++++++ contextcheck.go | 33 +++++++++++++++++++++++++++++++++ testdata/src/a/a.go | 7 +++++++ 3 files changed, 57 insertions(+) diff --git a/README.md b/README.md index c6bb989..3466dd9 100644 --- a/README.md +++ b/README.md @@ -94,6 +94,23 @@ func NoInheritCancel(_ context.Context) (context.Context,context.CancelFunc) { } ``` +You can add `// nolint: contextcheck` in function decl doc comment, to skip this linter in some false-positive case. + +```go +// nolint: contextcheck +func call1() { + doSomeThing(context.Background()) // add nolint will no issuss for that +} + +func call2(ctx context.Context) { + call1() +} + +func call3() { + call2(context.Background()) +} +``` + ## Installation You can get `contextcheck` by `go get` command. diff --git a/contextcheck.go b/contextcheck.go index a560e0d..2f9271e 100644 --- a/contextcheck.go +++ b/contextcheck.go @@ -3,6 +3,7 @@ package contextcheck import ( "go/ast" "go/types" + "regexp" "strconv" "strings" "sync" @@ -239,9 +240,41 @@ func (r *runner) checkIsEntry(f *ssa.Function) entryType { return EntryWithHttpHandler } + if r.skipByNolint(f) { + return EntryNone + } + return EntryNormal } +var nolintRe = regexp.MustCompile(`^//\s?nolint:`) + +func (r *runner) skipByNolint(f *ssa.Function) bool { + file := analysisutil.File(r.pass, f.Pos()) + if file == nil { + return false + } + + // only support FuncDecl comment + var fd *ast.FuncDecl + for _, v := range file.Decls { + if tmp, ok := v.(*ast.FuncDecl); ok && tmp.Name.Pos() == f.Pos() { + fd = tmp + break + } + } + if fd == nil || fd.Doc == nil || len(fd.Doc.List) == 0 { + return false + } + + for _, v := range fd.Doc.List { + if len(nolintRe.FindString(v.Text)) > 0 && strings.Contains(v.Text, "contextcheck") { + return true + } + } + return false +} + func (r *runner) checkIsCtx(f *ssa.Function) (in, out bool) { // check params tuple := f.Signature.Params() diff --git a/testdata/src/a/a.go b/testdata/src/a/a.go index 6c4b985..874cd52 100644 --- a/testdata/src/a/a.go +++ b/testdata/src/a/a.go @@ -109,6 +109,11 @@ func f10(in bool, w http.ResponseWriter, r *http.Request) { f8(context.Background(), w, r) } +// nolint: contextcheck +func f14(w http.ResponseWriter, r *http.Request, err error) { + f8(r.Context(), w, r) +} + func f11() { http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { f8(r.Context(), w, r) @@ -118,6 +123,8 @@ func f11() { // f10 should be like `func f10(ctx context.Context, in bool, w http.ResponseWriter, r *http.Request)` f10(true, w, r) // want "Function `f10` should pass the context parameter" + + f14(w, r, nil) }) }