diff --git a/go.mod b/go.mod index 88b177ffdbc7..a4a5abf31f33 100644 --- a/go.mod +++ b/go.mod @@ -48,6 +48,7 @@ require ( github.com/spf13/cobra v1.0.0 github.com/spf13/pflag v1.0.5 github.com/spf13/viper v1.7.0 + github.com/ssgreg/nlreturn/v2 v2.0.1 github.com/stretchr/testify v1.6.1 github.com/tdakkota/asciicheck v0.0.0-20200416190851-d7f85be797a2 github.com/tetafro/godot v0.4.8 diff --git a/go.sum b/go.sum index 263854770ef5..f4ed1ccb463f 100644 --- a/go.sum +++ b/go.sum @@ -359,6 +359,8 @@ github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE= github.com/spf13/viper v1.7.0 h1:xVKxvI7ouOI5I+U9s2eeiUfMaWBVoXA3AWskkrqK0VM= github.com/spf13/viper v1.7.0/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg= +github.com/ssgreg/nlreturn/v2 v2.0.1 h1:+lm6xFjVuNw/9t/Fh5sIwfNWefiD5bddzc6vwJ1TvRI= +github.com/ssgreg/nlreturn/v2 v2.0.1/go.mod h1:E/iiPB78hV7Szg2YfRgyIrk1AD6JVMTRkkxBiELzh2I= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1 h1:2vfRuCMp5sSVIDSqO8oNnWJq7mPa6KVP3iPIwFBuy8A= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= diff --git a/pkg/golinters/nlreturn.go b/pkg/golinters/nlreturn.go new file mode 100644 index 000000000000..3b661c64c83c --- /dev/null +++ b/pkg/golinters/nlreturn.go @@ -0,0 +1,19 @@ +package golinters + +import ( + "github.com/ssgreg/nlreturn/v2/pkg/nlreturn" + "golang.org/x/tools/go/analysis" + + "github.com/golangci/golangci-lint/pkg/golinters/goanalysis" +) + +func NewNLReturn() *goanalysis.Linter { + return goanalysis.NewLinter( + "nlreturn", + "nlreturn checks for a new line before return and branch statements to increase code clarity", + []*analysis.Analyzer{ + nlreturn.NewAnalyzer(), + }, + nil, + ).WithLoadMode(goanalysis.LoadModeSyntax) +} diff --git a/pkg/lint/lintersdb/manager.go b/pkg/lint/lintersdb/manager.go index 56fb7a10988b..7ffaf9c2e229 100644 --- a/pkg/lint/lintersdb/manager.go +++ b/pkg/lint/lintersdb/manager.go @@ -301,6 +301,10 @@ func (m Manager) GetAllSupportedLinterConfigs() []*linter.Config { WithPresets(linter.PresetBugs). WithLoadForGoAnalysis(). WithURL("https://github.com/ryanrolds/sqlclosecheck"), + linter.NewConfig(golinters.NewNLReturn()). + WithPresets(linter.PresetStyle). + WithLoadForGoAnalysis(). + WithURL("https://github.com/ssgreg/nlreturn"), // nolintlint must be last because it looks at the results of all the previous linters for unused nolint directives linter.NewConfig(golinters.NewNoLintLint()). WithPresets(linter.PresetStyle). diff --git a/test/testdata/nlreturn.go b/test/testdata/nlreturn.go new file mode 100644 index 000000000000..4637a65d11ba --- /dev/null +++ b/test/testdata/nlreturn.go @@ -0,0 +1,161 @@ +//args: -Enlreturn +package testdata + +func cha() { + ch := make(chan interface{}) + ch1 := make(chan interface{}) + ch2 := make(chan interface{}) + + select { + case <-ch: + return + + case <-ch1: + { + a := 1 + _ = a + { + a := 1 + _ = a + return // ERROR "return with no blank line before" + } + + return + } + + return + + case <-ch2: + { + a := 1 + _ = a + return // ERROR "return with no blank line before" + } + return // ERROR "return with no blank line before" + } +} + +func baz() { + switch 0 { + case 0: + a := 1 + _ = a + fallthrough // ERROR "fallthrough with no blank line before" + case 1: + a := 1 + _ = a + break // ERROR "break with no blank line before" + case 2: + break + } +} + +func foo() int { + v := []int{} + for range v { + return 0 + } + + for range v { + for range v { + return 0 + } + return 0 // ERROR "return with no blank line before" + } + + o := []int{ + 0, 1, + } + + return o[0] +} + +func bar() int { + o := 1 + if o == 1 { + if o == 0 { + return 1 + } + return 0 // ERROR "return with no blank line before" + } + + return o +} + +func main() { + return +} + +func bugNoAssignSmthHandling() string { + switch 0 { + case 0: + o := struct { + foo string + }{ + "foo", + } + return o.foo // ERROR "return with no blank line before" + + case 1: + o := struct { + foo string + }{ + "foo", + } + + return o.foo + } + + return "" +} + +func bugNoExprSmthHandling(string) { + switch 0 { + case 0: + bugNoExprSmthHandling( + "", + ) + return // ERROR "return with no blank line before" + + case 1: + bugNoExprSmthHandling( + "", + ) + + return + } +} + +func bugNoDeferSmthHandling(string) { + switch 0 { + case 0: + defer bugNoDeferSmthHandling( + "", + ) + return // ERROR "return with no blank line before" + + case 1: + defer bugNoDeferSmthHandling( + "", + ) + + return + } +} + +func bugNoGoSmthHandling(string) { + switch 0 { + case 0: + go bugNoGoSmthHandling( + "", + ) + return // ERROR "return with no blank line before" + + case 1: + go bugNoGoSmthHandling( + "", + ) + + return + } +}