diff --git a/go.mod b/go.mod index 624afb8e..174e0511 100644 --- a/go.mod +++ b/go.mod @@ -13,6 +13,7 @@ require ( github.com/Djarvur/go-err113 v0.0.0-20210108212216-aea10b59be24 github.com/GaijinEntertainment/go-exhaustruct/v2 v2.3.0 github.com/OpenPeeDeeP/depguard v1.1.1 + github.com/alexkohler/nakedret/v2 v2.0.1 github.com/alexkohler/prealloc v1.0.0 github.com/alingse/asasalint v0.0.11 github.com/ashanbrown/forbidigo v1.5.1 diff --git a/go.sum b/go.sum index 53b81c52..16a1b85d 100644 --- a/go.sum +++ b/go.sum @@ -65,6 +65,8 @@ github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuy github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho= +github.com/alexkohler/nakedret/v2 v2.0.1 h1:DLFVWaHbEntNHBYGhPX+AhCM1gCErTs35IFWPh6Bnn0= +github.com/alexkohler/nakedret/v2 v2.0.1/go.mod h1:2b8Gkk0GsOrqQv/gPWjNLDSKwG8I5moSXG1K4VIBcTQ= github.com/alexkohler/prealloc v1.0.0 h1:Hbq0/3fJPQhNkN0dR95AVrr6R7tou91y0uHG5pOcUuw= github.com/alexkohler/prealloc v1.0.0/go.mod h1:VetnK3dIgFBBKmg0YnD9F9x6Icjd+9cvfHR56wJVlKE= github.com/alingse/asasalint v0.0.11 h1:SFwnQXJ49Kx/1GghOFz1XGqHYKp21Kq1nHad/0WQRnw= diff --git a/pkg/golinters/nakedret.go b/pkg/golinters/nakedret.go index 3be5fd9d..d276ac6a 100644 --- a/pkg/golinters/nakedret.go +++ b/pkg/golinters/nakedret.go @@ -1,134 +1,27 @@ package golinters import ( - "fmt" - "go/ast" - "go/token" - "sync" - + "github.com/alexkohler/nakedret/v2" "golang.org/x/tools/go/analysis" "github.com/golangci/golangci-lint/pkg/config" "github.com/golangci/golangci-lint/pkg/golinters/goanalysis" - "github.com/golangci/golangci-lint/pkg/lint/linter" - "github.com/golangci/golangci-lint/pkg/result" ) const nakedretName = "nakedret" -//nolint:dupl func NewNakedret(settings *config.NakedretSettings) *goanalysis.Linter { - var mu sync.Mutex - var resIssues []goanalysis.Issue - - analyzer := &analysis.Analyzer{ - Name: nakedretName, - Doc: goanalysis.TheOnlyanalyzerDoc, - Run: func(pass *analysis.Pass) (any, error) { - issues := runNakedRet(pass, settings) - - if len(issues) == 0 { - return nil, nil - } - - mu.Lock() - resIssues = append(resIssues, issues...) - mu.Unlock() - - return nil, nil - }, + var maxLines int + if settings != nil { + maxLines = settings.MaxFuncLines } + analyzer := nakedret.NakedReturnAnalyzer(uint(maxLines)) + return goanalysis.NewLinter( nakedretName, "Finds naked returns in functions greater than a specified function length", []*analysis.Analyzer{analyzer}, nil, - ).WithIssuesReporter(func(*linter.Context) []goanalysis.Issue { - return resIssues - }).WithLoadMode(goanalysis.LoadModeSyntax) -} - -func runNakedRet(pass *analysis.Pass, settings *config.NakedretSettings) []goanalysis.Issue { - var issues []goanalysis.Issue - - for _, file := range pass.Files { - v := nakedretVisitor{ - maxLength: settings.MaxFuncLines, - f: pass.Fset, - } - - ast.Walk(&v, file) - - for i := range v.issues { - issues = append(issues, goanalysis.NewIssue(&v.issues[i], pass)) - } - } - - return issues -} - -type nakedretVisitor struct { - maxLength int - f *token.FileSet - issues []result.Issue -} - -func (v *nakedretVisitor) processFuncDecl(funcDecl *ast.FuncDecl) { - file := v.f.File(funcDecl.Pos()) - functionLineLength := file.Position(funcDecl.End()).Line - file.Position(funcDecl.Pos()).Line - - // Scan the body for usage of the named returns - for _, stmt := range funcDecl.Body.List { - s, ok := stmt.(*ast.ReturnStmt) - if !ok { - continue - } - - if len(s.Results) != 0 { - continue - } - - file := v.f.File(s.Pos()) - if file == nil || functionLineLength <= v.maxLength { - continue - } - if funcDecl.Name == nil { - continue - } - - v.issues = append(v.issues, result.Issue{ - FromLinter: nakedretName, - Text: fmt.Sprintf("naked return in func `%s` with %d lines of code", - funcDecl.Name.Name, functionLineLength), - Pos: v.f.Position(s.Pos()), - }) - } -} - -func (v *nakedretVisitor) Visit(node ast.Node) ast.Visitor { - funcDecl, ok := node.(*ast.FuncDecl) - if !ok { - return v - } - - var namedReturns []*ast.Ident - - // We've found a function - if funcDecl.Type != nil && funcDecl.Type.Results != nil { - for _, field := range funcDecl.Type.Results.List { - for _, ident := range field.Names { - if ident != nil { - namedReturns = append(namedReturns, ident) - } - } - } - } - - if len(namedReturns) == 0 || funcDecl.Body == nil { - return v - } - - v.processFuncDecl(funcDecl) - return v + ).WithLoadMode(goanalysis.LoadModeSyntax) } diff --git a/test/testdata/nakedret.go b/test/testdata/nakedret.go index fc9e9043..b1230a95 100644 --- a/test/testdata/nakedret.go +++ b/test/testdata/nakedret.go @@ -1,11 +1,15 @@ //golangcitest:args -Enakedret package testdata +import "fmt" + func NakedretIssue() (a int, b string) { if a > 0 { - return + return // want "naked return in func `NakedretIssue` with 33 lines of code" } + fmt.Println("nakedret") + if b == "" { return 0, "0" } @@ -30,8 +34,8 @@ func NakedretIssue() (a int, b string) { // ... // ... - // len of this function is 31 - return // want "naked return in func `NakedretIssue` with 31 lines of code" + // len of this function is 33 + return // want "naked return in func `NakedretIssue` with 33 lines of code" } func NoNakedretIssue() (a int, b string) {