Skip to content

Commit

Permalink
Add tenv linter (#2221)
Browse files Browse the repository at this point in the history
  • Loading branch information
sivchari committed Sep 26, 2021
1 parent c6c55d2 commit 20699a7
Show file tree
Hide file tree
Showing 11 changed files with 267 additions and 0 deletions.
5 changes: 5 additions & 0 deletions .golangci.example.yml
Original file line number Diff line number Diff line change
Expand Up @@ -627,6 +627,11 @@ linters-settings:
name: true
begin: true

tenv:
# The option `all` will run against whole test files (`_test.go`) regardless of method/function signatures.
# By default, only methods that take `*testing.T`, `*testing.B`, and `testing.TB` as arguments are checked.
all: false

unparam:
# Inspect exported functions, default is false. Set to true if no external program/library imports your code.
# XXX: if you enable this setting, unparam will report a lot of false-positives in text editors:
Expand Down
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ require (
github.com/shazow/go-diff v0.0.0-20160112020656-b6b7b6733b8c
github.com/shirou/gopsutil/v3 v3.21.8
github.com/sirupsen/logrus v1.8.1
github.com/sivchari/tenv v1.4.7
github.com/sonatard/noctx v0.0.1
github.com/sourcegraph/go-diff v0.6.1
github.com/spf13/cobra v1.2.1
Expand Down
22 changes: 22 additions & 0 deletions go.sum

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions pkg/config/linters_settings.go
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,7 @@ type LintersSettings struct {
Tagliatelle TagliatelleSettings
Testpackage TestpackageSettings
Thelper ThelperSettings
Tenv TenvSettings
Unparam UnparamSettings
Unused StaticCheckSettings
Varcheck VarCheckSettings
Expand Down Expand Up @@ -463,6 +464,10 @@ type ThelperSettings struct {
} `mapstructure:"tb"`
}

type TenvSettings struct {
All bool `mapstructure:"all"`
}

type UnparamSettings struct {
CheckExported bool `mapstructure:"check-exported"`
Algo string
Expand Down
33 changes: 33 additions & 0 deletions pkg/golinters/tenv.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package golinters

import (
"github.com/sivchari/tenv"
"golang.org/x/tools/go/analysis"

"github.com/golangci/golangci-lint/pkg/config"
"github.com/golangci/golangci-lint/pkg/golinters/goanalysis"
)

func NewTenv(settings *config.TenvSettings) *goanalysis.Linter {
a := tenv.Analyzer

analyzers := []*analysis.Analyzer{
a,
}

var cfg map[string]map[string]interface{}
if settings != nil {
cfg = map[string]map[string]interface{}{
a.Name: {
tenv.A: settings.All,
},
}
}

return goanalysis.NewLinter(
a.Name,
a.Doc,
analyzers,
cfg,
).WithLoadMode(goanalysis.LoadModeSyntax)
}
7 changes: 7 additions & 0 deletions pkg/lint/lintersdb/manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,7 @@ func (m Manager) GetAllSupportedLinterConfigs() []*linter.Config {
var staticcheckCfg *config.StaticCheckSettings
var stylecheckCfg *config.StaticCheckSettings
var tagliatelleCfg *config.TagliatelleSettings
var tenvCfg *config.TenvSettings
var testpackageCfg *config.TestpackageSettings
var thelperCfg *config.ThelperSettings
var unusedCfg *config.StaticCheckSettings
Expand All @@ -140,6 +141,7 @@ func (m Manager) GetAllSupportedLinterConfigs() []*linter.Config {
staticcheckCfg = &m.cfg.LintersSettings.Staticcheck
stylecheckCfg = &m.cfg.LintersSettings.Stylecheck
tagliatelleCfg = &m.cfg.LintersSettings.Tagliatelle
tenvCfg = &m.cfg.LintersSettings.Tenv
testpackageCfg = &m.cfg.LintersSettings.Testpackage
thelperCfg = &m.cfg.LintersSettings.Thelper
unusedCfg = &m.cfg.LintersSettings.Unused
Expand Down Expand Up @@ -522,6 +524,11 @@ func (m Manager) GetAllSupportedLinterConfigs() []*linter.Config {
WithLoadForGoAnalysis().
WithURL("https://github.com/Antonboom/nilnil").
WithSince("v1.43.0"),
linter.NewConfig(golinters.NewTenv(tenvCfg)).
WithSince("v1.43.0").
WithPresets(linter.PresetStyle).
WithLoadForGoAnalysis().
WithURL("https://github.com/sivchari/tenv"),

// nolintlint must be last because it looks at the results of all the previous linters for unused nolint directives
linter.NewConfig(golinters.NewNoLintLint()).
Expand Down
3 changes: 3 additions & 0 deletions test/testdata/configs/tenv_all.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
linters-settings:
tenv:
all: true
48 changes: 48 additions & 0 deletions test/testdata/tenv.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
// args: -Etenv
// config_path: testdata/configs/tenv_all.yml
package testdata

import (
"os"
"testing"
)

var (
e = os.Setenv("a", "b") // never seen
)

func setup() {
os.Setenv("a", "b") // never seen
err := os.Setenv("a", "b") // never seen
_ = err
if err := os.Setenv("a", "b"); err != nil { // never seen
_ = err
}
}

func TestF(t *testing.T) {
os.Setenv("a", "b") // ERROR "os\\.Setenv\\(\\) can be replaced by `t\\.Setenv\\(\\)` in TestF"
err := os.Setenv("a", "b") // ERROR "os\\.Setenv\\(\\) can be replaced by `t\\.Setenv\\(\\)` in TestF"
_ = err
if err := os.Setenv("a", "b"); err != nil { // ERROR "os\\.Setenv\\(\\) can be replaced by `t\\.Setenv\\(\\)` in TestF"
_ = err
}
}

func BenchmarkF(b *testing.B) {
os.Setenv("a", "b") // ERROR "os\\.Setenv\\(\\) can be replaced by `b\\.Setenv\\(\\)` in BenchmarkF"
err := os.Setenv("a", "b") // ERROR "os\\.Setenv\\(\\) can be replaced by `b\\.Setenv\\(\\)` in BenchmarkF"
_ = err
if err := os.Setenv("a", "b"); err != nil { // ERROR "os\\.Setenv\\(\\) can be replaced by `b\\.Setenv\\(\\)` in BenchmarkF"
_ = err
}
}

func testTB(tb testing.TB) {
os.Setenv("a", "b") // ERROR "os\\.Setenv\\(\\) can be replaced by `tb\\.Setenv\\(\\)` in testTB"
err := os.Setenv("a", "b") // ERROR "os\\.Setenv\\(\\) can be replaced by `tb\\.Setenv\\(\\)` in testTB"
_ = err
if err := os.Setenv("a", "b"); err != nil { // ERROR "os\\.Setenv\\(\\) can be replaced by `tb\\.Setenv\\(\\)` in testTB"
_ = err
}
}
48 changes: 48 additions & 0 deletions test/testdata/tenv_all.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
// args: -Etenv
// config_path: testdata/configs/tenv_all.yml
package testdata

import (
"os"
"testing"
)

var (
e = os.Setenv("a", "b") // never seen
)

func setup() {
os.Setenv("a", "b") // never seen
err := os.Setenv("a", "b") // never seen
_ = err
if err := os.Setenv("a", "b"); err != nil { // never seen
_ = err
}
}

func TestF(t *testing.T) {
os.Setenv("a", "b") // ERROR "os\\.Setenv\\(\\) can be replaced by `t\\.Setenv\\(\\)` in TestF"
err := os.Setenv("a", "b") // ERROR "os\\.Setenv\\(\\) can be replaced by `t\\.Setenv\\(\\)` in TestF"
_ = err
if err := os.Setenv("a", "b"); err != nil { // ERROR "os\\.Setenv\\(\\) can be replaced by `t\\.Setenv\\(\\)` in TestF"
_ = err
}
}

func BenchmarkF(b *testing.B) {
os.Setenv("a", "b") // ERROR "os\\.Setenv\\(\\) can be replaced by `b\\.Setenv\\(\\)` in BenchmarkF"
err := os.Setenv("a", "b") // ERROR "os\\.Setenv\\(\\) can be replaced by `b\\.Setenv\\(\\)` in BenchmarkF"
_ = err
if err := os.Setenv("a", "b"); err != nil { // ERROR "os\\.Setenv\\(\\) can be replaced by `b\\.Setenv\\(\\)` in BenchmarkF"
_ = err
}
}

func testTB(tb testing.TB) {
os.Setenv("a", "b") // ERROR "os\\.Setenv\\(\\) can be replaced by `tb\\.Setenv\\(\\)` in testTB"
err := os.Setenv("a", "b") // ERROR "os\\.Setenv\\(\\) can be replaced by `tb\\.Setenv\\(\\)` in testTB"
_ = err
if err := os.Setenv("a", "b"); err != nil { // ERROR "os\\.Setenv\\(\\) can be replaced by `tb\\.Setenv\\(\\)` in testTB"
_ = err
}
}
48 changes: 48 additions & 0 deletions test/testdata/tenv_all_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
// args: -Etenv
// config_path: testdata/configs/tenv_all.yml
package testdata

import (
"os"
"testing"
)

var (
e = os.Setenv("a", "b") // never seen
)

func setup() {
os.Setenv("a", "b") // ERROR "os\\.Setenv\\(\\) can be replaced by `testing\\.Setenv\\(\\)` in setup"
err := os.Setenv("a", "b") // ERROR "os\\.Setenv\\(\\) can be replaced by `testing\\.Setenv\\(\\)` in setup"
_ = err
if err := os.Setenv("a", "b"); err != nil { // ERROR "os\\.Setenv\\(\\) can be replaced by `testing\\.Setenv\\(\\)` in setup"
_ = err
}
}

func TestF(t *testing.T) {
os.Setenv("a", "b") // ERROR "os\\.Setenv\\(\\) can be replaced by `t\\.Setenv\\(\\)` in TestF"
err := os.Setenv("a", "b") // ERROR "os\\.Setenv\\(\\) can be replaced by `t\\.Setenv\\(\\)` in TestF"
_ = err
if err := os.Setenv("a", "b"); err != nil { // ERROR "os\\.Setenv\\(\\) can be replaced by `t\\.Setenv\\(\\)` in TestF"
_ = err
}
}

func BenchmarkF(b *testing.B) {
os.Setenv("a", "b") // ERROR "os\\.Setenv\\(\\) can be replaced by `b\\.Setenv\\(\\)` in BenchmarkF"
err := os.Setenv("a", "b") // ERROR "os\\.Setenv\\(\\) can be replaced by `b\\.Setenv\\(\\)` in BenchmarkF"
_ = err
if err := os.Setenv("a", "b"); err != nil { // ERROR "os\\.Setenv\\(\\) can be replaced by `b\\.Setenv\\(\\)` in BenchmarkF"
_ = err
}
}

func testTB(tb testing.TB) {
os.Setenv("a", "b") // ERROR "os\\.Setenv\\(\\) can be replaced by `tb\\.Setenv\\(\\)` in testTB"
err := os.Setenv("a", "b") // ERROR "os\\.Setenv\\(\\) can be replaced by `tb\\.Setenv\\(\\)` in testTB"
_ = err
if err := os.Setenv("a", "b"); err != nil { // ERROR "os\\.Setenv\\(\\) can be replaced by `tb\\.Setenv\\(\\)` in testTB"
_ = err
}
}
47 changes: 47 additions & 0 deletions test/testdata/tenv_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
// args: -Etenv
package testdata

import (
"os"
"testing"
)

var (
e = os.Setenv("a", "b") // never seen
)

func setup() {
os.Setenv("a", "b") // OK
err := os.Setenv("a", "b") // OK
_ = err
if err := os.Setenv("a", "b"); err != nil { // OK
_ = err
}
}

func TestF(t *testing.T) {
os.Setenv("a", "b") // ERROR "os\\.Setenv\\(\\) can be replaced by `t\\.Setenv\\(\\)` in TestF"
err := os.Setenv("a", "b") // ERROR "os\\.Setenv\\(\\) can be replaced by `t\\.Setenv\\(\\)` in TestF"
_ = err
if err := os.Setenv("a", "b"); err != nil { // ERROR "os\\.Setenv\\(\\) can be replaced by `t\\.Setenv\\(\\)` in TestF"
_ = err
}
}

func BenchmarkF(b *testing.B) {
os.Setenv("a", "b") // ERROR "os\\.Setenv\\(\\) can be replaced by `b\\.Setenv\\(\\)` in BenchmarkF"
err := os.Setenv("a", "b") // ERROR "os\\.Setenv\\(\\) can be replaced by `b\\.Setenv\\(\\)` in BenchmarkF"
_ = err
if err := os.Setenv("a", "b"); err != nil { // ERROR "os\\.Setenv\\(\\) can be replaced by `b\\.Setenv\\(\\)` in BenchmarkF"
_ = err
}
}

func testTB(tb testing.TB) {
os.Setenv("a", "b") // ERROR "os\\.Setenv\\(\\) can be replaced by `tb\\.Setenv\\(\\)` in testTB"
err := os.Setenv("a", "b") // ERROR "os\\.Setenv\\(\\) can be replaced by `tb\\.Setenv\\(\\)` in testTB"
_ = err
if err := os.Setenv("a", "b"); err != nil { // ERROR "os\\.Setenv\\(\\) can be replaced by `tb\\.Setenv\\(\\)` in testTB"
_ = err
}
}

0 comments on commit 20699a7

Please sign in to comment.