Skip to content

Commit f1a46f9

Browse files
authored
Add Noctx (#1179)
Support for linter that enforces using context on each `http.Request` https://github.com/sonatard/noctx
1 parent b784f44 commit f1a46f9

File tree

7 files changed

+168
-7
lines changed

7 files changed

+168
-7
lines changed

.golangci.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,7 @@ linters:
114114
# - goerr113
115115
# - maligned
116116
# - nestif
117+
# - noctx (TODO: enable after next release; current release at time of writing is v1.27)
117118
# - prealloc
118119
# - testpackage
119120
# - wsl

go.mod

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ require (
4040
github.com/securego/gosec/v2 v2.3.0
4141
github.com/shirou/gopsutil v0.0.0-20190901111213-e4ec7b275ada // v2.19.8
4242
github.com/sirupsen/logrus v1.6.0
43+
github.com/sonatard/noctx v0.0.1
4344
github.com/sourcegraph/go-diff v0.5.3
4445
github.com/spf13/cobra v1.0.0
4546
github.com/spf13/pflag v1.0.5

go.sum

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,8 @@ github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoA
159159
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
160160
github.com/gostaticanalysis/analysisutil v0.0.0-20190318220348-4088753ea4d3 h1:JVnpOZS+qxli+rgVl98ILOXVNbW+kb5wcxeGx8ShUIw=
161161
github.com/gostaticanalysis/analysisutil v0.0.0-20190318220348-4088753ea4d3/go.mod h1:eEOZF4jCKGi+aprrirO9e7WKB3beBRtWgqGunKl6pKE=
162+
github.com/gostaticanalysis/analysisutil v0.0.3 h1:iwp+5/UAyzQSFgQ4uR2sni99sJ8Eo9DEacKWM5pekIg=
163+
github.com/gostaticanalysis/analysisutil v0.0.3/go.mod h1:eEOZF4jCKGi+aprrirO9e7WKB3beBRtWgqGunKl6pKE=
162164
github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
163165
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
164166
github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
@@ -329,8 +331,8 @@ github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1
329331
github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s=
330332
github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
331333
github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
332-
github.com/sourcegraph/go-diff v0.5.2 h1:aREwkyV8nKvCkMW0129XBB4+ZmE/zyLkdZU569ylqmQ=
333-
github.com/sourcegraph/go-diff v0.5.2/go.mod h1:v9JDtjCE4HHHCZGId75rg8gkKKa98RVjBcBGsVmMmak=
334+
github.com/sonatard/noctx v0.0.1 h1:VC1Qhl6Oxx9vvWo3UDgrGXYCeKCe3Wbw7qAWL6FrmTY=
335+
github.com/sonatard/noctx v0.0.1/go.mod h1:9D2D/EoULe8Yy2joDHJj7bv3sZoq9AaSb8B4lqBjiZI=
334336
github.com/sourcegraph/go-diff v0.5.3 h1:lhIKJ2nXLZZ+AfbHpYxTn0pXpNTTui0DX7DO3xeb1Zs=
335337
github.com/sourcegraph/go-diff v0.5.3/go.mod h1:v9JDtjCE4HHHCZGId75rg8gkKKa98RVjBcBGsVmMmak=
336338
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
@@ -417,6 +419,7 @@ golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU
417419
golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=
418420
golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
419421
golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY=
422+
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
420423
golang.org/x/mod v0.2.0 h1:KU7oHjnv3XNWfa5COkzUifxZmxp1TyI7ImMXqFxLwvQ=
421424
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
422425
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@@ -507,16 +510,13 @@ golang.org/x/tools v0.0.0-20191108193012-7d206e10da11/go.mod h1:b+2E5dAYhXwXZwtn
507510
golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
508511
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
509512
golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
513+
golang.org/x/tools v0.0.0-20200117220505-0cba7a3a9ee9/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
510514
golang.org/x/tools v0.0.0-20200321224714-0d839f3cf2ed/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8=
511515
golang.org/x/tools v0.0.0-20200324003944-a576cf524670/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8=
512516
golang.org/x/tools v0.0.0-20200331202046-9d5940d49312/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
513517
golang.org/x/tools v0.0.0-20200414032229-332987a829c3/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
514518
golang.org/x/tools v0.0.0-20200422022333-3d57cf2e726e h1:3Dzrrxi54Io7Aoyb0PYLsI47K2TxkRQg+cqUn+m04do=
515519
golang.org/x/tools v0.0.0-20200422022333-3d57cf2e726e/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
516-
golang.org/x/tools v0.0.0-20200502202811-ed308ab3e770 h1:M9Fif0OxNji8w+HvmhVQ8KJtiZOsjU9RgslJGhn95XE=
517-
golang.org/x/tools v0.0.0-20200502202811-ed308ab3e770 h1:M9Fif0OxNji8w+HvmhVQ8KJtiZOsjU9RgslJGhn95XE=
518-
golang.org/x/tools v0.0.0-20200502202811-ed308ab3e770 h1:M9Fif0OxNji8w+HvmhVQ8KJtiZOsjU9RgslJGhn95XE=
519-
golang.org/x/tools v0.0.0-20200502202811-ed308ab3e770/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
520520
golang.org/x/tools v0.0.0-20200519015757-0d0afa43d58a h1:gILuVKC+ZPD6g/tj6zBOdnOH1ZHI0zZ86+KLMogc6/s=
521521
golang.org/x/tools v0.0.0-20200519015757-0d0afa43d58a/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
522522
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7 h1:9zdDQZ7Thm29KFXgAX/+yaf3eVbP7djjWp/dXAppNCc=

pkg/golinters/noctx.go

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
package golinters
2+
3+
import (
4+
"github.com/sonatard/noctx"
5+
"golang.org/x/tools/go/analysis"
6+
7+
"github.com/golangci/golangci-lint/pkg/golinters/goanalysis"
8+
)
9+
10+
func NewNoctx() *goanalysis.Linter {
11+
analyzers := []*analysis.Analyzer{
12+
noctx.Analyzer,
13+
}
14+
15+
return goanalysis.NewLinter(
16+
"noctx",
17+
"noctx finds sending http request without context.Context",
18+
analyzers,
19+
nil,
20+
).WithLoadMode(goanalysis.LoadModeTypesInfo)
21+
}

pkg/lint/lintersdb/manager.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,10 @@ func (m Manager) GetAllSupportedLinterConfigs() []*linter.Config {
104104
WithLoadForGoAnalysis().
105105
WithPresets(linter.PresetPerformance, linter.PresetBugs).
106106
WithURL("https://github.com/timakin/bodyclose"),
107+
linter.NewConfig(golinters.NewNoctx()).
108+
WithLoadForGoAnalysis().
109+
WithPresets(linter.PresetPerformance, linter.PresetBugs).
110+
WithURL("https://github.com/sonatard/noctx"),
107111
linter.NewConfig(golinters.NewErrcheck()).
108112
WithLoadForGoAnalysis().
109113
WithPresets(linter.PresetBugs).

test/linters_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,7 @@ func testOneSource(t *testing.T, sourcePath string) {
110110
"--print-issued-lines=false",
111111
"--print-linter-name=false",
112112
"--out-format=line-number",
113-
"--max-same-issues=10",
113+
"--max-same-issues=100",
114114
}
115115

116116
rc := extractRunContextFromComments(t, sourcePath)

test/testdata/noctx.go

Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
//args: -Enoctx
2+
package testdata
3+
4+
import (
5+
"context"
6+
"net/http"
7+
)
8+
9+
var newRequestPkg = http.NewRequest
10+
11+
func Noctx() {
12+
const url = "http://example.com"
13+
cli := &http.Client{}
14+
15+
ctx := context.Background()
16+
http.Get(url) // ERROR "net/http\.Get must not be called"
17+
_ = http.Get // OK
18+
f := http.Get // OK
19+
f(url) // ERROR "net/http\.Get must not be called"
20+
21+
http.Head(url) // ERROR "net/http\.Head must not be called"
22+
http.Post(url, "", nil) // ERROR "net/http\.Post must not be called"
23+
http.PostForm(url, nil) // ERROR "net/http\.PostForm must not be called"
24+
25+
cli.Get(url) // ERROR "\(\*net/http\.Client\)\.Get must not be called"
26+
_ = cli.Get // OK
27+
m := cli.Get // OK
28+
m(url) // ERROR "\(\*net/http\.Client\)\.Get must not be called"
29+
30+
cli.Head(url) // ERROR "\(\*net/http\.Client\)\.Head must not be called"
31+
cli.Post(url, "", nil) // ERROR "\(\*net/http\.Client\)\.Post must not be called"
32+
cli.PostForm(url, nil) // ERROR "\(\*net/http\.Client\)\.PostForm must not be called"
33+
34+
req, _ := http.NewRequest(http.MethodPost, url, nil) // ERROR "should rewrite http.NewRequestWithContext or add \(\*Request\).WithContext"
35+
cli.Do(req)
36+
37+
req2, _ := http.NewRequestWithContext(ctx, http.MethodPost, url, nil) // OK
38+
cli.Do(req2)
39+
40+
req3, _ := http.NewRequest(http.MethodPost, url, nil) // OK
41+
req3 = req3.WithContext(ctx)
42+
cli.Do(req3)
43+
44+
f2 := func(req *http.Request, ctx context.Context) *http.Request {
45+
return req
46+
}
47+
req4, _ := http.NewRequest(http.MethodPost, url, nil) // ERROR "should rewrite http.NewRequestWithContext or add \(\*Request\).WithContext"
48+
req4 = f2(req4, ctx)
49+
50+
req41, _ := http.NewRequest(http.MethodPost, url, nil) // OK
51+
req41 = req41.WithContext(ctx)
52+
req41 = f2(req41, ctx)
53+
54+
newRequest := http.NewRequest
55+
req5, _ := newRequest(http.MethodPost, url, nil) // ERROR "should rewrite http.NewRequestWithContext or add \(\*Request\).WithContext"
56+
cli.Do(req5)
57+
58+
req51, _ := newRequest(http.MethodPost, url, nil) // OK
59+
req51 = req51.WithContext(ctx)
60+
cli.Do(req51)
61+
62+
req52, _ := newRequestPkg(http.MethodPost, url, nil) // ERROR "should rewrite http.NewRequestWithContext or add \(\*Request\).WithContext"
63+
cli.Do(req52)
64+
65+
type MyRequest = http.Request
66+
f3 := func(req *MyRequest, ctx context.Context) *MyRequest {
67+
return req
68+
}
69+
req6, _ := http.NewRequest(http.MethodPost, url, nil) // ERROR "should rewrite http.NewRequestWithContext or add \(\*Request\).WithContext"
70+
req6 = f3(req6, ctx)
71+
72+
req61, _ := http.NewRequest(http.MethodPost, url, nil) // OK
73+
req61 = req61.WithContext(ctx)
74+
req61 = f3(req61, ctx)
75+
76+
type MyRequest2 http.Request
77+
f4 := func(req *MyRequest2, ctx context.Context) *MyRequest2 {
78+
return req
79+
}
80+
req7, _ := http.NewRequest(http.MethodPost, url, nil) // ERROR "should rewrite http.NewRequestWithContext or add \(\*Request\).WithContext"
81+
req71 := MyRequest2(*req7)
82+
f4(&req71, ctx)
83+
84+
req72, _ := http.NewRequest(http.MethodPost, url, nil) // OK
85+
req72 = req72.WithContext(ctx)
86+
req73 := MyRequest2(*req7)
87+
f4(&req73, ctx)
88+
89+
req8, _ := func() (*http.Request, error) {
90+
return http.NewRequest(http.MethodPost, url, nil) // ERROR "should rewrite http.NewRequestWithContext or add \(\*Request\).WithContext"
91+
}()
92+
cli.Do(req8)
93+
94+
req82, _ := func() (*http.Request, error) {
95+
req82, _ := http.NewRequest(http.MethodPost, url, nil) // OK
96+
req82 = req82.WithContext(ctx)
97+
return req82, nil
98+
}()
99+
cli.Do(req82)
100+
101+
f5 := func(req, req2 *http.Request, ctx context.Context) (*http.Request, *http.Request) {
102+
return req, req2
103+
}
104+
req9, _ := http.NewRequest(http.MethodPost, url, nil) // ERROR "should rewrite http.NewRequestWithContext or add \(\*Request\).WithContext"
105+
req9, _ = f5(req9, req9, ctx)
106+
107+
req91, _ := http.NewRequest(http.MethodPost, url, nil) // OK
108+
req91 = req91.WithContext(ctx)
109+
req9, _ = f5(req91, req91, ctx)
110+
111+
req10, _ := http.NewRequest(http.MethodPost, url, nil) // ERROR "should rewrite http.NewRequestWithContext or add \(\*Request\).WithContext"
112+
req11, _ := http.NewRequest(http.MethodPost, url, nil) // ERROR "should rewrite http.NewRequestWithContext or add \(\*Request\).WithContext"
113+
req10, req11 = f5(req10, req11, ctx)
114+
115+
req101, _ := http.NewRequest(http.MethodPost, url, nil) // ERROR "should rewrite http.NewRequestWithContext or add \(\*Request\).WithContext"
116+
req111, _ := http.NewRequest(http.MethodPost, url, nil) // OK
117+
req111 = req111.WithContext(ctx)
118+
req101, req111 = f5(req101, req111, ctx)
119+
120+
func() (*http.Request, *http.Request) {
121+
req12, _ := http.NewRequest(http.MethodPost, url, nil) // ERROR "should rewrite http.NewRequestWithContext or add \(\*Request\).WithContext"
122+
req13, _ := http.NewRequest(http.MethodPost, url, nil) // ERROR "should rewrite http.NewRequestWithContext or add \(\*Request\).WithContext"
123+
return req12, req13
124+
}()
125+
126+
func() (*http.Request, *http.Request) {
127+
req14, _ := http.NewRequest(http.MethodPost, url, nil) // ERROR "should rewrite http.NewRequestWithContext or add \(\*Request\).WithContext"
128+
req15, _ := http.NewRequest(http.MethodPost, url, nil) // OK
129+
req15 = req15.WithContext(ctx)
130+
131+
return req14, req15
132+
}()
133+
}
134+

0 commit comments

Comments
 (0)