Skip to content

Commit 82344b2

Browse files
sivchariSeigeC
authored andcommitted
Add tenv linter (golangci#2221)
1 parent ad25811 commit 82344b2

File tree

11 files changed

+267
-0
lines changed

11 files changed

+267
-0
lines changed

.golangci.example.yml

+5
Original file line numberDiff line numberDiff line change
@@ -632,6 +632,11 @@ linters-settings:
632632
name: true
633633
begin: true
634634

635+
tenv:
636+
# The option `all` will run against whole test files (`_test.go`) regardless of method/function signatures.
637+
# By default, only methods that take `*testing.T`, `*testing.B`, and `testing.TB` as arguments are checked.
638+
all: false
639+
635640
unparam:
636641
# Inspect exported functions, default is false. Set to true if no external program/library imports your code.
637642
# XXX: if you enable this setting, unparam will report a lot of false-positives in text editors:

go.mod

+1
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@ require (
6969
github.com/shazow/go-diff v0.0.0-20160112020656-b6b7b6733b8c
7070
github.com/shirou/gopsutil/v3 v3.21.8
7171
github.com/sirupsen/logrus v1.8.1
72+
github.com/sivchari/tenv v1.4.7
7273
github.com/sonatard/noctx v0.0.1
7374
github.com/sourcegraph/go-diff v0.6.1
7475
github.com/spf13/cobra v1.2.1

go.sum

+22
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pkg/config/linters_settings.go

+5
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,7 @@ type LintersSettings struct {
132132
Tagliatelle TagliatelleSettings
133133
Testpackage TestpackageSettings
134134
Thelper ThelperSettings
135+
Tenv TenvSettings
135136
Unparam UnparamSettings
136137
Unused StaticCheckSettings
137138
Varcheck VarCheckSettings
@@ -463,6 +464,10 @@ type ThelperSettings struct {
463464
} `mapstructure:"tb"`
464465
}
465466

467+
type TenvSettings struct {
468+
All bool `mapstructure:"all"`
469+
}
470+
466471
type UnparamSettings struct {
467472
CheckExported bool `mapstructure:"check-exported"`
468473
Algo string

pkg/golinters/tenv.go

+33
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
package golinters
2+
3+
import (
4+
"github.com/sivchari/tenv"
5+
"golang.org/x/tools/go/analysis"
6+
7+
"github.com/golangci/golangci-lint/pkg/config"
8+
"github.com/golangci/golangci-lint/pkg/golinters/goanalysis"
9+
)
10+
11+
func NewTenv(settings *config.TenvSettings) *goanalysis.Linter {
12+
a := tenv.Analyzer
13+
14+
analyzers := []*analysis.Analyzer{
15+
a,
16+
}
17+
18+
var cfg map[string]map[string]interface{}
19+
if settings != nil {
20+
cfg = map[string]map[string]interface{}{
21+
a.Name: {
22+
tenv.A: settings.All,
23+
},
24+
}
25+
}
26+
27+
return goanalysis.NewLinter(
28+
a.Name,
29+
a.Doc,
30+
analyzers,
31+
cfg,
32+
).WithLoadMode(goanalysis.LoadModeSyntax)
33+
}

pkg/lint/lintersdb/manager.go

+7
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,7 @@ func (m Manager) GetAllSupportedLinterConfigs() []*linter.Config {
116116
var staticcheckCfg *config.StaticCheckSettings
117117
var stylecheckCfg *config.StaticCheckSettings
118118
var tagliatelleCfg *config.TagliatelleSettings
119+
var tenvCfg *config.TenvSettings
119120
var testpackageCfg *config.TestpackageSettings
120121
var thelperCfg *config.ThelperSettings
121122
var unusedCfg *config.StaticCheckSettings
@@ -140,6 +141,7 @@ func (m Manager) GetAllSupportedLinterConfigs() []*linter.Config {
140141
staticcheckCfg = &m.cfg.LintersSettings.Staticcheck
141142
stylecheckCfg = &m.cfg.LintersSettings.Stylecheck
142143
tagliatelleCfg = &m.cfg.LintersSettings.Tagliatelle
144+
tenvCfg = &m.cfg.LintersSettings.Tenv
143145
testpackageCfg = &m.cfg.LintersSettings.Testpackage
144146
thelperCfg = &m.cfg.LintersSettings.Thelper
145147
unusedCfg = &m.cfg.LintersSettings.Unused
@@ -522,6 +524,11 @@ func (m Manager) GetAllSupportedLinterConfigs() []*linter.Config {
522524
WithLoadForGoAnalysis().
523525
WithURL("https://github.com/Antonboom/nilnil").
524526
WithSince("v1.43.0"),
527+
linter.NewConfig(golinters.NewTenv(tenvCfg)).
528+
WithSince("v1.43.0").
529+
WithPresets(linter.PresetStyle).
530+
WithLoadForGoAnalysis().
531+
WithURL("https://github.com/sivchari/tenv"),
525532

526533
linter.NewConfig(golinters.NewCheckBannedFunc()).
527534
WithPresets(linter.PresetStyle),

test/testdata/configs/tenv_all.yml

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
linters-settings:
2+
tenv:
3+
all: true

test/testdata/tenv.go

+48
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
// args: -Etenv
2+
// config_path: testdata/configs/tenv_all.yml
3+
package testdata
4+
5+
import (
6+
"os"
7+
"testing"
8+
)
9+
10+
var (
11+
e = os.Setenv("a", "b") // never seen
12+
)
13+
14+
func setup() {
15+
os.Setenv("a", "b") // never seen
16+
err := os.Setenv("a", "b") // never seen
17+
_ = err
18+
if err := os.Setenv("a", "b"); err != nil { // never seen
19+
_ = err
20+
}
21+
}
22+
23+
func TestF(t *testing.T) {
24+
os.Setenv("a", "b") // ERROR "os\\.Setenv\\(\\) can be replaced by `t\\.Setenv\\(\\)` in TestF"
25+
err := os.Setenv("a", "b") // ERROR "os\\.Setenv\\(\\) can be replaced by `t\\.Setenv\\(\\)` in TestF"
26+
_ = err
27+
if err := os.Setenv("a", "b"); err != nil { // ERROR "os\\.Setenv\\(\\) can be replaced by `t\\.Setenv\\(\\)` in TestF"
28+
_ = err
29+
}
30+
}
31+
32+
func BenchmarkF(b *testing.B) {
33+
os.Setenv("a", "b") // ERROR "os\\.Setenv\\(\\) can be replaced by `b\\.Setenv\\(\\)` in BenchmarkF"
34+
err := os.Setenv("a", "b") // ERROR "os\\.Setenv\\(\\) can be replaced by `b\\.Setenv\\(\\)` in BenchmarkF"
35+
_ = err
36+
if err := os.Setenv("a", "b"); err != nil { // ERROR "os\\.Setenv\\(\\) can be replaced by `b\\.Setenv\\(\\)` in BenchmarkF"
37+
_ = err
38+
}
39+
}
40+
41+
func testTB(tb testing.TB) {
42+
os.Setenv("a", "b") // ERROR "os\\.Setenv\\(\\) can be replaced by `tb\\.Setenv\\(\\)` in testTB"
43+
err := os.Setenv("a", "b") // ERROR "os\\.Setenv\\(\\) can be replaced by `tb\\.Setenv\\(\\)` in testTB"
44+
_ = err
45+
if err := os.Setenv("a", "b"); err != nil { // ERROR "os\\.Setenv\\(\\) can be replaced by `tb\\.Setenv\\(\\)` in testTB"
46+
_ = err
47+
}
48+
}

test/testdata/tenv_all.go

+48
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
// args: -Etenv
2+
// config_path: testdata/configs/tenv_all.yml
3+
package testdata
4+
5+
import (
6+
"os"
7+
"testing"
8+
)
9+
10+
var (
11+
e = os.Setenv("a", "b") // never seen
12+
)
13+
14+
func setup() {
15+
os.Setenv("a", "b") // never seen
16+
err := os.Setenv("a", "b") // never seen
17+
_ = err
18+
if err := os.Setenv("a", "b"); err != nil { // never seen
19+
_ = err
20+
}
21+
}
22+
23+
func TestF(t *testing.T) {
24+
os.Setenv("a", "b") // ERROR "os\\.Setenv\\(\\) can be replaced by `t\\.Setenv\\(\\)` in TestF"
25+
err := os.Setenv("a", "b") // ERROR "os\\.Setenv\\(\\) can be replaced by `t\\.Setenv\\(\\)` in TestF"
26+
_ = err
27+
if err := os.Setenv("a", "b"); err != nil { // ERROR "os\\.Setenv\\(\\) can be replaced by `t\\.Setenv\\(\\)` in TestF"
28+
_ = err
29+
}
30+
}
31+
32+
func BenchmarkF(b *testing.B) {
33+
os.Setenv("a", "b") // ERROR "os\\.Setenv\\(\\) can be replaced by `b\\.Setenv\\(\\)` in BenchmarkF"
34+
err := os.Setenv("a", "b") // ERROR "os\\.Setenv\\(\\) can be replaced by `b\\.Setenv\\(\\)` in BenchmarkF"
35+
_ = err
36+
if err := os.Setenv("a", "b"); err != nil { // ERROR "os\\.Setenv\\(\\) can be replaced by `b\\.Setenv\\(\\)` in BenchmarkF"
37+
_ = err
38+
}
39+
}
40+
41+
func testTB(tb testing.TB) {
42+
os.Setenv("a", "b") // ERROR "os\\.Setenv\\(\\) can be replaced by `tb\\.Setenv\\(\\)` in testTB"
43+
err := os.Setenv("a", "b") // ERROR "os\\.Setenv\\(\\) can be replaced by `tb\\.Setenv\\(\\)` in testTB"
44+
_ = err
45+
if err := os.Setenv("a", "b"); err != nil { // ERROR "os\\.Setenv\\(\\) can be replaced by `tb\\.Setenv\\(\\)` in testTB"
46+
_ = err
47+
}
48+
}

test/testdata/tenv_all_test.go

+48
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
// args: -Etenv
2+
// config_path: testdata/configs/tenv_all.yml
3+
package testdata
4+
5+
import (
6+
"os"
7+
"testing"
8+
)
9+
10+
var (
11+
e = os.Setenv("a", "b") // never seen
12+
)
13+
14+
func setup() {
15+
os.Setenv("a", "b") // ERROR "os\\.Setenv\\(\\) can be replaced by `testing\\.Setenv\\(\\)` in setup"
16+
err := os.Setenv("a", "b") // ERROR "os\\.Setenv\\(\\) can be replaced by `testing\\.Setenv\\(\\)` in setup"
17+
_ = err
18+
if err := os.Setenv("a", "b"); err != nil { // ERROR "os\\.Setenv\\(\\) can be replaced by `testing\\.Setenv\\(\\)` in setup"
19+
_ = err
20+
}
21+
}
22+
23+
func TestF(t *testing.T) {
24+
os.Setenv("a", "b") // ERROR "os\\.Setenv\\(\\) can be replaced by `t\\.Setenv\\(\\)` in TestF"
25+
err := os.Setenv("a", "b") // ERROR "os\\.Setenv\\(\\) can be replaced by `t\\.Setenv\\(\\)` in TestF"
26+
_ = err
27+
if err := os.Setenv("a", "b"); err != nil { // ERROR "os\\.Setenv\\(\\) can be replaced by `t\\.Setenv\\(\\)` in TestF"
28+
_ = err
29+
}
30+
}
31+
32+
func BenchmarkF(b *testing.B) {
33+
os.Setenv("a", "b") // ERROR "os\\.Setenv\\(\\) can be replaced by `b\\.Setenv\\(\\)` in BenchmarkF"
34+
err := os.Setenv("a", "b") // ERROR "os\\.Setenv\\(\\) can be replaced by `b\\.Setenv\\(\\)` in BenchmarkF"
35+
_ = err
36+
if err := os.Setenv("a", "b"); err != nil { // ERROR "os\\.Setenv\\(\\) can be replaced by `b\\.Setenv\\(\\)` in BenchmarkF"
37+
_ = err
38+
}
39+
}
40+
41+
func testTB(tb testing.TB) {
42+
os.Setenv("a", "b") // ERROR "os\\.Setenv\\(\\) can be replaced by `tb\\.Setenv\\(\\)` in testTB"
43+
err := os.Setenv("a", "b") // ERROR "os\\.Setenv\\(\\) can be replaced by `tb\\.Setenv\\(\\)` in testTB"
44+
_ = err
45+
if err := os.Setenv("a", "b"); err != nil { // ERROR "os\\.Setenv\\(\\) can be replaced by `tb\\.Setenv\\(\\)` in testTB"
46+
_ = err
47+
}
48+
}

test/testdata/tenv_test.go

+47
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
// args: -Etenv
2+
package testdata
3+
4+
import (
5+
"os"
6+
"testing"
7+
)
8+
9+
var (
10+
e = os.Setenv("a", "b") // never seen
11+
)
12+
13+
func setup() {
14+
os.Setenv("a", "b") // OK
15+
err := os.Setenv("a", "b") // OK
16+
_ = err
17+
if err := os.Setenv("a", "b"); err != nil { // OK
18+
_ = err
19+
}
20+
}
21+
22+
func TestF(t *testing.T) {
23+
os.Setenv("a", "b") // ERROR "os\\.Setenv\\(\\) can be replaced by `t\\.Setenv\\(\\)` in TestF"
24+
err := os.Setenv("a", "b") // ERROR "os\\.Setenv\\(\\) can be replaced by `t\\.Setenv\\(\\)` in TestF"
25+
_ = err
26+
if err := os.Setenv("a", "b"); err != nil { // ERROR "os\\.Setenv\\(\\) can be replaced by `t\\.Setenv\\(\\)` in TestF"
27+
_ = err
28+
}
29+
}
30+
31+
func BenchmarkF(b *testing.B) {
32+
os.Setenv("a", "b") // ERROR "os\\.Setenv\\(\\) can be replaced by `b\\.Setenv\\(\\)` in BenchmarkF"
33+
err := os.Setenv("a", "b") // ERROR "os\\.Setenv\\(\\) can be replaced by `b\\.Setenv\\(\\)` in BenchmarkF"
34+
_ = err
35+
if err := os.Setenv("a", "b"); err != nil { // ERROR "os\\.Setenv\\(\\) can be replaced by `b\\.Setenv\\(\\)` in BenchmarkF"
36+
_ = err
37+
}
38+
}
39+
40+
func testTB(tb testing.TB) {
41+
os.Setenv("a", "b") // ERROR "os\\.Setenv\\(\\) can be replaced by `tb\\.Setenv\\(\\)` in testTB"
42+
err := os.Setenv("a", "b") // ERROR "os\\.Setenv\\(\\) can be replaced by `tb\\.Setenv\\(\\)` in testTB"
43+
_ = err
44+
if err := os.Setenv("a", "b"); err != nil { // ERROR "os\\.Setenv\\(\\) can be replaced by `tb\\.Setenv\\(\\)` in testTB"
45+
_ = err
46+
}
47+
}

0 commit comments

Comments
 (0)