From 712de1c63d9db97c81af68cd0dc4372c53d2e57a Mon Sep 17 00:00:00 2001 From: Dmitry Vyukov Date: Tue, 15 Sep 2020 18:05:35 +0200 Subject: vendor/github.com/golangci/golangci-lint: update to v1.31 --- vendor/github.com/sonatard/noctx/.gitignore | 1 + vendor/github.com/sonatard/noctx/.golangci.yml | 20 +++ vendor/github.com/sonatard/noctx/LICENSE | 21 +++ vendor/github.com/sonatard/noctx/Makefile | 16 ++ vendor/github.com/sonatard/noctx/README.md | 95 +++++++++++ vendor/github.com/sonatard/noctx/go.mod | 8 + vendor/github.com/sonatard/noctx/go.sum | 16 ++ vendor/github.com/sonatard/noctx/ngfunc/main.go | 57 +++++++ vendor/github.com/sonatard/noctx/ngfunc/report.go | 29 ++++ vendor/github.com/sonatard/noctx/ngfunc/types.go | 65 ++++++++ vendor/github.com/sonatard/noctx/noctx.go | 31 ++++ .../sonatard/noctx/reqwithoutctx/main.go | 14 ++ .../sonatard/noctx/reqwithoutctx/report.go | 26 +++ .../github.com/sonatard/noctx/reqwithoutctx/ssa.go | 180 +++++++++++++++++++++ 14 files changed, 579 insertions(+) create mode 100644 vendor/github.com/sonatard/noctx/.gitignore create mode 100644 vendor/github.com/sonatard/noctx/.golangci.yml create mode 100644 vendor/github.com/sonatard/noctx/LICENSE create mode 100644 vendor/github.com/sonatard/noctx/Makefile create mode 100644 vendor/github.com/sonatard/noctx/README.md create mode 100644 vendor/github.com/sonatard/noctx/go.mod create mode 100644 vendor/github.com/sonatard/noctx/go.sum create mode 100644 vendor/github.com/sonatard/noctx/ngfunc/main.go create mode 100644 vendor/github.com/sonatard/noctx/ngfunc/report.go create mode 100644 vendor/github.com/sonatard/noctx/ngfunc/types.go create mode 100644 vendor/github.com/sonatard/noctx/noctx.go create mode 100644 vendor/github.com/sonatard/noctx/reqwithoutctx/main.go create mode 100644 vendor/github.com/sonatard/noctx/reqwithoutctx/report.go create mode 100644 vendor/github.com/sonatard/noctx/reqwithoutctx/ssa.go (limited to 'vendor/github.com/sonatard') diff --git a/vendor/github.com/sonatard/noctx/.gitignore b/vendor/github.com/sonatard/noctx/.gitignore new file mode 100644 index 000000000..2d830686d --- /dev/null +++ b/vendor/github.com/sonatard/noctx/.gitignore @@ -0,0 +1 @@ +coverage.out diff --git a/vendor/github.com/sonatard/noctx/.golangci.yml b/vendor/github.com/sonatard/noctx/.golangci.yml new file mode 100644 index 000000000..1580acde2 --- /dev/null +++ b/vendor/github.com/sonatard/noctx/.golangci.yml @@ -0,0 +1,20 @@ +run: + +linters-settings: + govet: + enable-all: true + +linters: + enable-all: true + disable: + - gochecknoglobals + - gomnd + - gocognit + - nestif + +issues: + exclude-rules: + - path: reqwithoutctx/ssa.go + text: "Consider preallocating `exts`" + linters: + - prealloc diff --git a/vendor/github.com/sonatard/noctx/LICENSE b/vendor/github.com/sonatard/noctx/LICENSE new file mode 100644 index 000000000..a00d5727f --- /dev/null +++ b/vendor/github.com/sonatard/noctx/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2020 sonatard + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/vendor/github.com/sonatard/noctx/Makefile b/vendor/github.com/sonatard/noctx/Makefile new file mode 100644 index 000000000..1a27f6b59 --- /dev/null +++ b/vendor/github.com/sonatard/noctx/Makefile @@ -0,0 +1,16 @@ +.PHONY: all imports test lint + +all: imports test lint + +imports: + goimports -w ./ + +test: + go test -race ./... + +test_coverage: + go test -race -coverprofile=coverage.out -covermode=atomic ./... + +lint: + golangci-lint run ./... + diff --git a/vendor/github.com/sonatard/noctx/README.md b/vendor/github.com/sonatard/noctx/README.md new file mode 100644 index 000000000..bfe9782c6 --- /dev/null +++ b/vendor/github.com/sonatard/noctx/README.md @@ -0,0 +1,95 @@ +# noctx + +![](https://github.com/sonatard/noctx/workflows/.github/workflows/ci.yml/badge.svg) + +`noctx` finds sending http request without context.Context. + +You should use `noctx` if sending http request in your library. +Passing `context.Context` enables library user to cancel http request, getting trace information and so on. + +## Install + +```sh +$ go get -u github.com/sonatard/noctx/cmd/noctx +``` + +## Usage + +```sh +$ go vet -vettool=`which noctx` main.go +./main.go:6:11: net/http.Get must not be called +``` + +## Detection rules +- Executing following functions + - `net/http.Get` + - `net/http.Head` + - `net/http.Post` + - `net/http.PostForm` + - `(*net/http.Client).Get` + - `(*net/http.Client).Head` + - `(*net/http.Client).Post` + - `(*net/http.Client).PostForm` +- `http.Request` returned by `http.NewRequest` function and passes it to other function. + +## How to fix +- Send http request using `(*http.Client).Do(*http.Request)` method. +- In Go 1.13 and later, use `http.NewRequestWithContext` function instead of using `http.NewRequest` function. +- In Go 1.12 and earlier, call `(http.Request).WithContext(ctx)` after `http.NewRequest`. + +`(http.Request).WithContext(ctx)` has a disadvantage of performance because it returns a copy of `http.Request`. Use `http.NewRequestWithContext` function if you only support Go1.13 or later. + +## Sample Code + +```go +package main + +import ( + "context" + "net/http" +) + +func main() { + const url = "http://example.com" + http.Get(url) // want `net/http\.Get must not be called` + http.Head(url) // want `net/http\.Head must not be called` + http.Post(url, "", nil) // want `net/http\.Post must not be called` + http.PostForm(url, nil) // want `net/http\.PostForm must not be called` + + cli := &http.Client{} + cli.Get(url) // want `\(\*net/http\.Client\)\.Get must not be called` + cli.Head(url) // want `\(\*net/http\.Client\)\.Head must not be called` + cli.Post(url, "", nil) // want `\(\*net/http\.Client\)\.Post must not be called` + cli.PostForm(url, nil) // want `\(\*net/http\.Client\)\.PostForm must not be called` + + req, _ := http.NewRequest(http.MethodPost, url, nil) // want `should rewrite http.NewRequestWithContext or add \(\*Request\).WithContext` + cli.Do(req) + + ctx := context.Background() + req2, _ := http.NewRequestWithContext(ctx, http.MethodPost, url, nil) // OK + cli.Do(req2) + + req3, _ := http.NewRequest(http.MethodPost, url, nil) // OK + req3 = req3.WithContext(ctx) + cli.Do(req3) + + f2 := func(req *http.Request, ctx context.Context) *http.Request { + return req + } + req4, _ := http.NewRequest(http.MethodPost, url, nil) // want `should rewrite http.NewRequestWithContext or add \(\*Request\).WithContext` + req4 = f2(req4, ctx) + cli.Do(req4) + + req5, _ := func() (*http.Request, error) { + return http.NewRequest(http.MethodPost, url, nil) // want `should rewrite http.NewRequestWithContext or add \(\*Request\).WithContext` + }() + cli.Do(req5) + +} +``` + +## Reference +- [net/http - NewRequest](https://golang.org/pkg/net/http/#NewRequest) +- [net/http - NewRequestWithContext](https://golang.org/pkg/net/http/#NewRequestWithContext) +- [net/http - Request.WithContext](https://golang.org/pkg/net/http/#Request.WithContext) + diff --git a/vendor/github.com/sonatard/noctx/go.mod b/vendor/github.com/sonatard/noctx/go.mod new file mode 100644 index 000000000..47b7901a0 --- /dev/null +++ b/vendor/github.com/sonatard/noctx/go.mod @@ -0,0 +1,8 @@ +module github.com/sonatard/noctx + +go 1.13 + +require ( + github.com/gostaticanalysis/analysisutil v0.0.3 + golang.org/x/tools v0.0.0-20200117220505-0cba7a3a9ee9 +) diff --git a/vendor/github.com/sonatard/noctx/go.sum b/vendor/github.com/sonatard/noctx/go.sum new file mode 100644 index 000000000..f8e5b0759 --- /dev/null +++ b/vendor/github.com/sonatard/noctx/go.sum @@ -0,0 +1,16 @@ +github.com/gostaticanalysis/analysisutil v0.0.3 h1:iwp+5/UAyzQSFgQ4uR2sni99sJ8Eo9DEacKWM5pekIg= +github.com/gostaticanalysis/analysisutil v0.0.3/go.mod h1:eEOZF4jCKGi+aprrirO9e7WKB3beBRtWgqGunKl6pKE= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/tools v0.0.0-20190311215038-5c2858a9cfe5/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20200117220505-0cba7a3a9ee9 h1:KOkk4e2xd5OeCDJGwacvr75ICCbCsShrHiqPEdsA9hg= +golang.org/x/tools v0.0.0-20200117220505-0cba7a3a9ee9/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= diff --git a/vendor/github.com/sonatard/noctx/ngfunc/main.go b/vendor/github.com/sonatard/noctx/ngfunc/main.go new file mode 100644 index 000000000..cfeb0f001 --- /dev/null +++ b/vendor/github.com/sonatard/noctx/ngfunc/main.go @@ -0,0 +1,57 @@ +package ngfunc + +import ( + "go/types" + + "github.com/gostaticanalysis/analysisutil" + "golang.org/x/tools/go/analysis" + "golang.org/x/tools/go/analysis/passes/buildssa" +) + +func Run(pass *analysis.Pass) (interface{}, error) { + ngFuncNames := []string{ + "net/http.Get", + "net/http.Head", + "net/http.Post", + "net/http.PostForm", + "(*net/http.Client).Get", + "(*net/http.Client).Head", + "(*net/http.Client).Post", + "(*net/http.Client).PostForm", + } + + ngFuncs := typeFuncs(pass, ngFuncNames) + if len(ngFuncs) == 0 { + return nil, nil + } + + reportFuncs := ngCalledFuncs(pass, ngFuncs) + report(pass, reportFuncs) + + return nil, nil +} + +func ngCalledFuncs(pass *analysis.Pass, ngFuncs []*types.Func) []*Report { + var reports []*Report + + srcFuncs := pass.ResultOf[buildssa.Analyzer].(*buildssa.SSA).SrcFuncs + for _, sf := range srcFuncs { + for _, b := range sf.Blocks { + for _, instr := range b.Instrs { + for _, ngFunc := range ngFuncs { + if analysisutil.Called(instr, nil, ngFunc) { + ngCalledFunc := &Report{ + Instruction: instr, + function: ngFunc, + } + reports = append(reports, ngCalledFunc) + + break + } + } + } + } + } + + return reports +} diff --git a/vendor/github.com/sonatard/noctx/ngfunc/report.go b/vendor/github.com/sonatard/noctx/ngfunc/report.go new file mode 100644 index 000000000..e50051798 --- /dev/null +++ b/vendor/github.com/sonatard/noctx/ngfunc/report.go @@ -0,0 +1,29 @@ +package ngfunc + +import ( + "fmt" + "go/token" + "go/types" + + "golang.org/x/tools/go/analysis" + "golang.org/x/tools/go/ssa" +) + +type Report struct { + Instruction ssa.Instruction + function *types.Func +} + +func (n *Report) Pos() token.Pos { + return n.Instruction.Pos() +} + +func (n *Report) Message() string { + return fmt.Sprintf("%s must not be called", n.function.FullName()) +} + +func report(pass *analysis.Pass, reports []*Report) { + for _, report := range reports { + pass.Reportf(report.Pos(), report.Message()) + } +} diff --git a/vendor/github.com/sonatard/noctx/ngfunc/types.go b/vendor/github.com/sonatard/noctx/ngfunc/types.go new file mode 100644 index 000000000..f1877386c --- /dev/null +++ b/vendor/github.com/sonatard/noctx/ngfunc/types.go @@ -0,0 +1,65 @@ +package ngfunc + +import ( + "fmt" + "go/types" + "strings" + + "github.com/gostaticanalysis/analysisutil" + "golang.org/x/tools/go/analysis" +) + +var errNotFound = fmt.Errorf("function not found") + +func typeFuncs(pass *analysis.Pass, funcs []string) []*types.Func { + fs := make([]*types.Func, 0, len(funcs)) + + for _, fn := range funcs { + f, err := typeFunc(pass, fn) + if err != nil { + continue + } + + fs = append(fs, f) + } + + return fs +} + +func typeFunc(pass *analysis.Pass, funcName string) (*types.Func, error) { + ss := strings.Split(strings.TrimSpace(funcName), ".") + + switch len(ss) { + case 2: + // package function: pkgname.Func + f, ok := analysisutil.ObjectOf(pass, ss[0], ss[1]).(*types.Func) + if !ok || f == nil { + return nil, errNotFound + } + + return f, nil + case 3: + // method: (*pkgname.Type).Method + pkgname := strings.TrimLeft(ss[0], "(") + typename := strings.TrimRight(ss[1], ")") + + if pkgname != "" && pkgname[0] == '*' { + pkgname = pkgname[1:] + typename = "*" + typename + } + + typ := analysisutil.TypeOf(pass, pkgname, typename) + if typ == nil { + return nil, errNotFound + } + + m := analysisutil.MethodOf(typ, ss[2]) + if m == nil { + return nil, errNotFound + } + + return m, nil + } + + return nil, errNotFound +} diff --git a/vendor/github.com/sonatard/noctx/noctx.go b/vendor/github.com/sonatard/noctx/noctx.go new file mode 100644 index 000000000..478ad8855 --- /dev/null +++ b/vendor/github.com/sonatard/noctx/noctx.go @@ -0,0 +1,31 @@ +package noctx + +import ( + "github.com/sonatard/noctx/ngfunc" + "github.com/sonatard/noctx/reqwithoutctx" + "golang.org/x/tools/go/analysis" + "golang.org/x/tools/go/analysis/passes/buildssa" +) + +var Analyzer = &analysis.Analyzer{ + Name: "noctx", + Doc: Doc, + Run: run, + Requires: []*analysis.Analyzer{ + buildssa.Analyzer, + }, +} + +const Doc = "noctx finds sending http request without context.Context" + +func run(pass *analysis.Pass) (interface{}, error) { + if _, err := ngfunc.Run(pass); err != nil { + return nil, err + } + + if _, err := reqwithoutctx.Run(pass); err != nil { + return nil, err + } + + return nil, nil +} diff --git a/vendor/github.com/sonatard/noctx/reqwithoutctx/main.go b/vendor/github.com/sonatard/noctx/reqwithoutctx/main.go new file mode 100644 index 000000000..b09e1de1b --- /dev/null +++ b/vendor/github.com/sonatard/noctx/reqwithoutctx/main.go @@ -0,0 +1,14 @@ +package reqwithoutctx + +import ( + "golang.org/x/tools/go/analysis" +) + +func Run(pass *analysis.Pass) (interface{}, error) { + analyzer := NewAnalyzer(pass) + reports := analyzer.Exec() + + report(pass, reports) + + return nil, nil +} diff --git a/vendor/github.com/sonatard/noctx/reqwithoutctx/report.go b/vendor/github.com/sonatard/noctx/reqwithoutctx/report.go new file mode 100644 index 000000000..1c94e3148 --- /dev/null +++ b/vendor/github.com/sonatard/noctx/reqwithoutctx/report.go @@ -0,0 +1,26 @@ +package reqwithoutctx + +import ( + "go/token" + + "golang.org/x/tools/go/analysis" + "golang.org/x/tools/go/ssa" +) + +type Report struct { + Instruction ssa.Instruction +} + +func (n *Report) Pos() token.Pos { + return n.Instruction.Pos() +} + +func (n *Report) Message() string { + return "should rewrite http.NewRequestWithContext or add (*Request).WithContext" +} + +func report(pass *analysis.Pass, reports []*Report) { + for _, report := range reports { + pass.Reportf(report.Pos(), report.Message()) + } +} diff --git a/vendor/github.com/sonatard/noctx/reqwithoutctx/ssa.go b/vendor/github.com/sonatard/noctx/reqwithoutctx/ssa.go new file mode 100644 index 000000000..35751269e --- /dev/null +++ b/vendor/github.com/sonatard/noctx/reqwithoutctx/ssa.go @@ -0,0 +1,180 @@ +package reqwithoutctx + +import ( + "go/types" + + "github.com/gostaticanalysis/analysisutil" + + "golang.org/x/tools/go/analysis" + "golang.org/x/tools/go/analysis/passes/buildssa" + "golang.org/x/tools/go/ssa" +) + +type Analyzer struct { + Funcs []*ssa.Function + newRequestType types.Type + requestType types.Type +} + +func NewAnalyzer(pass *analysis.Pass) *Analyzer { + newRequestType := analysisutil.TypeOf(pass, "net/http", "NewRequest") + requestType := analysisutil.TypeOf(pass, "net/http", "*Request") + + srcFuncs := pass.ResultOf[buildssa.Analyzer].(*buildssa.SSA).SrcFuncs + + return &Analyzer{ + Funcs: srcFuncs, + newRequestType: newRequestType, + requestType: requestType, + } +} + +func (a *Analyzer) Exec() []*Report { + if a.newRequestType == nil || a.requestType == nil { + return []*Report{} + } + + usedReqs := a.usedReqs() + newReqs := a.requestsByNewRequest() + + return a.report(usedReqs, newReqs) +} + +func (a *Analyzer) report(usedReqs map[string]*ssa.Extract, newReqs map[*ssa.Call]*ssa.Extract) []*Report { + var reports []*Report + + for _, fReq := range usedReqs { + for newRequest, req := range newReqs { + if fReq == req { + reports = append(reports, &Report{Instruction: newRequest}) + } + } + } + + return reports +} + +func (a *Analyzer) usedReqs() map[string]*ssa.Extract { + reqExts := make(map[string]*ssa.Extract) + + for _, f := range a.Funcs { + for _, b := range f.Blocks { + for _, instr := range b.Instrs { + switch i := instr.(type) { + case *ssa.Call: + exts := a.usedReqByCall(i) + for _, ext := range exts { + key := i.String() + ext.String() + reqExts[key] = ext + } + case *ssa.UnOp: + ext := a.usedReqByUnOp(i) + if ext != nil { + key := i.String() + ext.String() + reqExts[key] = ext + } + case *ssa.Return: + exts := a.usedReqByReturn(i) + for _, ext := range exts { + key := i.String() + ext.String() + reqExts[key] = ext + } + } + } + } + } + + return reqExts +} + +func (a *Analyzer) usedReqByCall(call *ssa.Call) []*ssa.Extract { + var exts []*ssa.Extract + + // skip net/http.Request method call + if call.Common().Signature().Recv() != nil && types.Identical(call.Value().Type(), a.requestType) { + return exts + } + + args := call.Common().Args + if len(args) == 0 { + return exts + } + + for _, arg := range args { + ext, ok := arg.(*ssa.Extract) + if !ok { + continue + } + + if !types.Identical(ext.Type(), a.requestType) { + continue + } + + exts = append(exts, ext) + } + + return exts +} + +func (a *Analyzer) usedReqByUnOp(op *ssa.UnOp) *ssa.Extract { + if ext, ok := op.X.(*ssa.Extract); ok && types.Identical(ext.Type(), a.requestType) { + return ext + } + + return nil +} + +func (a *Analyzer) usedReqByReturn(ret *ssa.Return) []*ssa.Extract { + rets := ret.Results + exts := make([]*ssa.Extract, 0, len(rets)) + + for _, ret := range rets { + ext, ok := ret.(*ssa.Extract) + if !ok { + continue + } + + if types.Identical(ext.Type(), a.requestType) { + exts = append(exts, ext) + } + } + + return exts +} + +func (a *Analyzer) requestsByNewRequest() map[*ssa.Call]*ssa.Extract { + reqs := make(map[*ssa.Call]*ssa.Extract) + + for _, f := range a.Funcs { + for _, b := range f.Blocks { + for _, instr := range b.Instrs { + ext, ok := instr.(*ssa.Extract) + if !ok { + continue + } + + if !types.Identical(ext.Type(), a.requestType) { + continue + } + + operands := ext.Operands([]*ssa.Value{}) + if len(operands) != 1 { + continue + } + + operand := *operands[0] + + f, ok := operand.(*ssa.Call) + if !ok { + continue + } + + if types.Identical(f.Call.Value.Type(), a.newRequestType) { + reqs[f] = ext + } + } + } + } + + return reqs +} -- cgit mrf-deployment