github.com/elek/golangci-lint@v1.42.2-0.20211208090441-c05b7fcb3a9a/pkg/golinters/dogsled.go (about) 1 package golinters 2 3 import ( 4 "fmt" 5 "go/ast" 6 "go/token" 7 "sync" 8 9 "golang.org/x/tools/go/analysis" 10 11 "github.com/elek/golangci-lint/pkg/golinters/goanalysis" 12 "github.com/elek/golangci-lint/pkg/lint/linter" 13 "github.com/elek/golangci-lint/pkg/result" 14 ) 15 16 const dogsledLinterName = "dogsled" 17 18 func NewDogsled() *goanalysis.Linter { 19 var mu sync.Mutex 20 var resIssues []goanalysis.Issue 21 22 analyzer := &analysis.Analyzer{ 23 Name: dogsledLinterName, 24 Doc: goanalysis.TheOnlyanalyzerDoc, 25 } 26 return goanalysis.NewLinter( 27 dogsledLinterName, 28 "Checks assignments with too many blank identifiers (e.g. x, _, _, _, := f())", 29 []*analysis.Analyzer{analyzer}, 30 nil, 31 ).WithContextSetter(func(lintCtx *linter.Context) { 32 analyzer.Run = func(pass *analysis.Pass) (interface{}, error) { 33 var pkgIssues []goanalysis.Issue 34 for _, f := range pass.Files { 35 v := returnsVisitor{ 36 maxBlanks: lintCtx.Settings().Dogsled.MaxBlankIdentifiers, 37 f: pass.Fset, 38 } 39 ast.Walk(&v, f) 40 for i := range v.issues { 41 pkgIssues = append(pkgIssues, goanalysis.NewIssue(&v.issues[i], pass)) 42 } 43 } 44 45 mu.Lock() 46 resIssues = append(resIssues, pkgIssues...) 47 mu.Unlock() 48 49 return nil, nil 50 } 51 }).WithIssuesReporter(func(*linter.Context) []goanalysis.Issue { 52 return resIssues 53 }).WithLoadMode(goanalysis.LoadModeSyntax) 54 } 55 56 type returnsVisitor struct { 57 f *token.FileSet 58 maxBlanks int 59 issues []result.Issue 60 } 61 62 func (v *returnsVisitor) Visit(node ast.Node) ast.Visitor { 63 funcDecl, ok := node.(*ast.FuncDecl) 64 if !ok { 65 return v 66 } 67 if funcDecl.Body == nil { 68 return v 69 } 70 71 for _, expr := range funcDecl.Body.List { 72 assgnStmt, ok := expr.(*ast.AssignStmt) 73 if !ok { 74 continue 75 } 76 77 numBlank := 0 78 for _, left := range assgnStmt.Lhs { 79 ident, ok := left.(*ast.Ident) 80 if !ok { 81 continue 82 } 83 if ident.Name == "_" { 84 numBlank++ 85 } 86 } 87 88 if numBlank > v.maxBlanks { 89 v.issues = append(v.issues, result.Issue{ 90 FromLinter: dogsledLinterName, 91 Text: fmt.Sprintf("declaration has %v blank identifiers", numBlank), 92 Pos: v.f.Position(assgnStmt.Pos()), 93 }) 94 } 95 } 96 return v 97 }