github.com/ldez/golangci-lint@v1.10.1/pkg/golinters/nakedret.go (about)

     1  package golinters
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"go/ast"
     7  	"go/token"
     8  
     9  	"github.com/golangci/golangci-lint/pkg/lint/linter"
    10  	"github.com/golangci/golangci-lint/pkg/result"
    11  )
    12  
    13  type Nakedret struct{}
    14  
    15  func (Nakedret) Name() string {
    16  	return "nakedret"
    17  }
    18  
    19  func (Nakedret) Desc() string {
    20  	return "Finds naked returns in functions greater than a specified function length"
    21  }
    22  
    23  type nakedretVisitor struct {
    24  	maxLength int
    25  	f         *token.FileSet
    26  	issues    []result.Issue
    27  }
    28  
    29  func (v *nakedretVisitor) processFuncDecl(funcDecl *ast.FuncDecl) {
    30  	file := v.f.File(funcDecl.Pos())
    31  	functionLineLength := file.Position(funcDecl.End()).Line - file.Position(funcDecl.Pos()).Line
    32  
    33  	// Scan the body for usage of the named returns
    34  	for _, stmt := range funcDecl.Body.List {
    35  		s, ok := stmt.(*ast.ReturnStmt)
    36  		if !ok {
    37  			continue
    38  		}
    39  
    40  		if len(s.Results) != 0 {
    41  			continue
    42  		}
    43  
    44  		file := v.f.File(s.Pos())
    45  		if file == nil || functionLineLength <= v.maxLength {
    46  			continue
    47  		}
    48  		if funcDecl.Name == nil {
    49  			continue
    50  		}
    51  
    52  		v.issues = append(v.issues, result.Issue{
    53  			FromLinter: Nakedret{}.Name(),
    54  			Text: fmt.Sprintf("naked return in func `%s` with %d lines of code",
    55  				funcDecl.Name.Name, functionLineLength),
    56  			Pos: v.f.Position(s.Pos()),
    57  		})
    58  	}
    59  }
    60  
    61  func (v *nakedretVisitor) Visit(node ast.Node) ast.Visitor {
    62  	funcDecl, ok := node.(*ast.FuncDecl)
    63  	if !ok {
    64  		return v
    65  	}
    66  
    67  	var namedReturns []*ast.Ident
    68  
    69  	// We've found a function
    70  	if funcDecl.Type != nil && funcDecl.Type.Results != nil {
    71  		for _, field := range funcDecl.Type.Results.List {
    72  			for _, ident := range field.Names {
    73  				if ident != nil {
    74  					namedReturns = append(namedReturns, ident)
    75  				}
    76  			}
    77  		}
    78  	}
    79  
    80  	if len(namedReturns) == 0 || funcDecl.Body == nil {
    81  		return v
    82  	}
    83  
    84  	v.processFuncDecl(funcDecl)
    85  	return v
    86  }
    87  
    88  func (lint Nakedret) Run(ctx context.Context, lintCtx *linter.Context) ([]result.Issue, error) {
    89  	var res []result.Issue
    90  	for _, f := range lintCtx.ASTCache.GetAllValidFiles() {
    91  		v := nakedretVisitor{
    92  			maxLength: lintCtx.Settings().Nakedret.MaxFuncLines,
    93  			f:         f.Fset,
    94  		}
    95  		ast.Walk(&v, f.F)
    96  		res = append(res, v.issues...)
    97  	}
    98  
    99  	return res, nil
   100  }