github.com/azazeal/revive@v1.0.9/rule/modifies-param.go (about) 1 package rule 2 3 import ( 4 "fmt" 5 "go/ast" 6 7 "github.com/azazeal/revive/lint" 8 ) 9 10 // ModifiesParamRule lints given else constructs. 11 type ModifiesParamRule struct{} 12 13 // Apply applies the rule to given file. 14 func (r *ModifiesParamRule) Apply(file *lint.File, _ lint.Arguments) []lint.Failure { 15 var failures []lint.Failure 16 17 onFailure := func(failure lint.Failure) { 18 failures = append(failures, failure) 19 } 20 21 w := lintModifiesParamRule{onFailure: onFailure} 22 ast.Walk(w, file.AST) 23 return failures 24 } 25 26 // Name returns the rule name. 27 func (r *ModifiesParamRule) Name() string { 28 return "modifies-parameter" 29 } 30 31 type lintModifiesParamRule struct { 32 params map[string]bool 33 onFailure func(lint.Failure) 34 } 35 36 func retrieveParamNames(pl []*ast.Field) map[string]bool { 37 result := make(map[string]bool, len(pl)) 38 for _, p := range pl { 39 for _, n := range p.Names { 40 if n.Name == "_" { 41 continue 42 } 43 44 result[n.Name] = true 45 } 46 } 47 return result 48 } 49 50 func (w lintModifiesParamRule) Visit(node ast.Node) ast.Visitor { 51 switch v := node.(type) { 52 case *ast.FuncDecl: 53 w.params = retrieveParamNames(v.Type.Params.List) 54 case *ast.IncDecStmt: 55 if id, ok := v.X.(*ast.Ident); ok { 56 checkParam(id, &w) 57 } 58 case *ast.AssignStmt: 59 lhs := v.Lhs 60 for _, e := range lhs { 61 id, ok := e.(*ast.Ident) 62 if ok { 63 checkParam(id, &w) 64 } 65 } 66 } 67 68 return w 69 } 70 71 func checkParam(id *ast.Ident, w *lintModifiesParamRule) { 72 if w.params[id.Name] { 73 w.onFailure(lint.Failure{ 74 Confidence: 0.5, // confidence is low because of shadow variables 75 Node: id, 76 Category: "bad practice", 77 Failure: fmt.Sprintf("parameter '%s' seems to be modified", id), 78 }) 79 } 80 }