101 lines
2.1 KiB
Go
101 lines
2.1 KiB
Go
package golinters
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"go/ast"
|
|
"go/token"
|
|
|
|
"github.com/golangci/golangci-lint/pkg/lint/linter"
|
|
"github.com/golangci/golangci-lint/pkg/result"
|
|
)
|
|
|
|
type Nakedret struct{}
|
|
|
|
func (Nakedret) Name() string {
|
|
return "nakedret"
|
|
}
|
|
|
|
func (Nakedret) Desc() string {
|
|
return "Finds naked returns in functions greater than a specified function length"
|
|
}
|
|
|
|
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: Nakedret{}.Name(),
|
|
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
|
|
}
|
|
|
|
func (lint Nakedret) Run(ctx context.Context, lintCtx *linter.Context) ([]result.Issue, error) {
|
|
var res []result.Issue
|
|
for _, f := range lintCtx.ASTCache.GetAllValidFiles() {
|
|
v := nakedretVisitor{
|
|
maxLength: lintCtx.Settings().Nakedret.MaxFuncLines,
|
|
f: f.Fset,
|
|
}
|
|
ast.Walk(&v, f.F)
|
|
res = append(res, v.issues...)
|
|
}
|
|
|
|
return res, nil
|
|
}
|