2018-06-30 15:41:47 +03:00

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
}