diff --git a/go.mod b/go.mod index ecb318aec6d4..13c2edb28c84 100644 --- a/go.mod +++ b/go.mod @@ -54,6 +54,7 @@ require ( github.com/polyfloyd/go-errorlint v0.0.0-20201127212506-19bd8db6546f github.com/ryancurrah/gomodguard v1.2.0 github.com/ryanrolds/sqlclosecheck v0.3.0 + github.com/sanposhiho/wastedassign v0.1.3 github.com/securego/gosec/v2 v2.6.1 github.com/shazow/go-diff v0.0.0-20160112020656-b6b7b6733b8c github.com/shirou/gopsutil/v3 v3.21.1 diff --git a/go.sum b/go.sum index 181e1417edab..42384ba47858 100644 --- a/go.sum +++ b/go.sum @@ -353,6 +353,8 @@ github.com/ryancurrah/gomodguard v1.2.0/go.mod h1:rNqbC4TOIdUDcVMSIpNNAzTbzXAZa6 github.com/ryanrolds/sqlclosecheck v0.3.0 h1:AZx+Bixh8zdUBxUA1NxbxVAS78vTPq4rCb8OUZI9xFw= github.com/ryanrolds/sqlclosecheck v0.3.0/go.mod h1:1gREqxyTGR3lVtpngyFo3hZAgk0KCtEdgEkHwDbigdA= github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= +github.com/sanposhiho/wastedassign v0.1.3 h1:qIMpTh4NGZYRbFJ+DSpLoVn8F4SLciX2afRvXPefC7w= +github.com/sanposhiho/wastedassign v0.1.3/go.mod h1:LGpq5Hsv74QaqM47WtIsRSF/ik9kqk07kchgv66tLVE= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= github.com/securego/gosec/v2 v2.6.1 h1:+KCw+uz16FYfFyJ/A5aU6uP7mnrL+j1TbDnk1yN+8R0= github.com/securego/gosec/v2 v2.6.1/go.mod h1:I76p3NTHBXsGhybUW+cEQ692q2Vp+A0Z6ZLzDIZy+Ao= diff --git a/pkg/golinters/wastedassign.go b/pkg/golinters/wastedassign.go new file mode 100644 index 000000000000..9ce1afdd4810 --- /dev/null +++ b/pkg/golinters/wastedassign.go @@ -0,0 +1,21 @@ +package golinters + +import ( + "github.com/sanposhiho/wastedassign" + "golang.org/x/tools/go/analysis" + + "github.com/golangci/golangci-lint/pkg/golinters/goanalysis" +) + +func NewWastedAssign() *goanalysis.Linter { + analyzers := []*analysis.Analyzer{ + wastedassign.Analyzer, + } + + return goanalysis.NewLinter( + "wastedassign", + "wastedassign finds wasted assignment statements.", + analyzers, + nil, + ).WithLoadMode(goanalysis.LoadModeTypesInfo) +} diff --git a/pkg/lint/lintersdb/manager.go b/pkg/lint/lintersdb/manager.go index 035ab151c626..60fec473ce34 100644 --- a/pkg/lint/lintersdb/manager.go +++ b/pkg/lint/lintersdb/manager.go @@ -374,6 +374,10 @@ func (m Manager) GetAllSupportedLinterConfigs() []*linter.Config { WithPresets(linter.PresetBugs). WithLoadForGoAnalysis(). WithURL("https://github.com/charithe/durationcheck"), + linter.NewConfig(golinters.NewWastedAssign()). + WithPresets(linter.PresetStyle). + WithLoadForGoAnalysis(). + WithURL("https://github.com/sanposhiho/wastedassign"), // nolintlint must be last because it looks at the results of all the previous linters for unused nolint directives linter.NewConfig(golinters.NewNoLintLint()). diff --git a/test/testdata/wastedassign.go b/test/testdata/wastedassign.go new file mode 100644 index 000000000000..923ab7aae0ed --- /dev/null +++ b/test/testdata/wastedassign.go @@ -0,0 +1,107 @@ +//args: -Ewastedassign +package testdata + +import ( + "strings" +) + +func p(x int) int { + return x + 1 +} + +func typeSwitchNoError(val interface{}, times uint) interface{} { + switch hoge := val.(type) { + case int: + return 12 + case string: + return strings.Repeat(hoge, int(times)) + default: + return nil + } +} + +func noUseParamsNoError(params string) int { + a := 12 + println(a) + return a +} + +func manyif(param int) int { + println(param) + useOutOfIf := 1212121 // ERROR "wasted assignment" + ret := 0 + if false { + useOutOfIf = 200 // ERROR "reassigned, but never used afterwards" + return 0 + } else if param == 100 { + useOutOfIf = 100 // ERROR "wasted assignment" + useOutOfIf = 201 + useOutOfIf = p(useOutOfIf) + useOutOfIf += 200 // ERROR "wasted assignment" + } else { + useOutOfIf = 100 + useOutOfIf += 100 + useOutOfIf = p(useOutOfIf) + useOutOfIf += 200 // ERROR "wasted assignment" + } + + if false { + useOutOfIf = 200 // ERROR "reassigned, but never used afterwards" + return 0 + } else if param == 200 { + useOutOfIf = 100 // ERROR "wasted assignment" + useOutOfIf = 201 + useOutOfIf = p(useOutOfIf) + useOutOfIf += 200 + } else { + useOutOfIf = 100 + useOutOfIf += 100 + useOutOfIf = p(useOutOfIf) + useOutOfIf += 200 + } + println(useOutOfIf) + useOutOfIf = 192 + useOutOfIf += 100 + useOutOfIf += 200 // ERROR "reassigned, but never used afterwards" + return ret +} + +func checkLoopTest() int { + hoge := 12 + noUse := 1111 + println(noUse) + + noUse = 1111 // ERROR "reassigned, but never used afterwards" + for { + if hoge == 14 { + break + } + hoge = hoge + 1 + } + return hoge +} + +func infinity() { + var i int + var hoge int + for { + hoge = 5 // ERROR "reassigned, but never used afterwards" + } + + println(i) + println(hoge) + return +} + +func infinity2() { + var i int + var hoge int + for { + hoge = 5 + break + } + + println(i) + println(hoge) + return +}