github.com/elek/golangci-lint@v1.42.2-0.20211208090441-c05b7fcb3a9a/pkg/golinters/deferloop/main.go (about)

     1  // Copyright (C) 2021 Storj Labs, Inc.
     2  // See LICENSE for copying information.
     3  
     4  // check-deferloop finds defer being used inside a for loop.
     5  package deferloop
     6  
     7  import (
     8  	"github.com/elek/golangci-lint/pkg/golinters/goanalysis"
     9  	"go/ast"
    10  
    11  	"golang.org/x/tools/go/analysis"
    12  	"golang.org/x/tools/go/analysis/passes/inspect"
    13  	"golang.org/x/tools/go/analysis/singlechecker"
    14  	"golang.org/x/tools/go/ast/inspector"
    15  )
    16  
    17  func main() { singlechecker.Main(Analyzer) }
    18  
    19  func NewDeferLoopCheck() *goanalysis.Linter {
    20  	return goanalysis.NewLinter(
    21  		"deferloop",
    22  		"STORJ: check for defers inside a loop",
    23  		[]*analysis.Analyzer{
    24  			Analyzer,
    25  		},
    26  		nil,
    27  	).WithLoadMode(goanalysis.LoadModeWholeProgram)
    28  }
    29  
    30  // Analyzer implements unused task analysis pass.
    31  var Analyzer = &analysis.Analyzer{
    32  	Name:     "deferloop",
    33  	Doc:      `check for defers inside a loop`,
    34  	Requires: []*analysis.Analyzer{inspect.Analyzer},
    35  	Run:      run,
    36  }
    37  
    38  func run(pass *analysis.Pass) (interface{}, error) {
    39  	inspect := pass.ResultOf[inspect.Analyzer].(*inspector.Inspector)
    40  
    41  	inspect.Nodes([]ast.Node{
    42  		(*ast.ForStmt)(nil),
    43  	}, func(n ast.Node, push bool) (proceed bool) {
    44  		if push {
    45  			return true
    46  		}
    47  
    48  		ast.Inspect(n, func(n ast.Node) bool {
    49  			switch n := n.(type) {
    50  			case *ast.DeferStmt:
    51  				pass.Reportf(n.Pos(), "defer inside a loop")
    52  				return false
    53  			case *ast.ExprStmt, *ast.FuncLit:
    54  				return false
    55  			}
    56  			return true
    57  		})
    58  
    59  		return true
    60  	})
    61  	return nil, nil
    62  }