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 }