github.com/Johnny2210/revive@v1.0.8-0.20210625134200-febf37ccd0f5/rule/redefines-builtin-id.go (about) 1 package rule 2 3 import ( 4 "fmt" 5 "github.com/mgechev/revive/lint" 6 "go/ast" 7 "go/token" 8 ) 9 10 // RedefinesBuiltinIDRule warns when a builtin identifier is shadowed. 11 type RedefinesBuiltinIDRule struct{} 12 13 // Apply applies the rule to given file. 14 func (r *RedefinesBuiltinIDRule) Apply(file *lint.File, _ lint.Arguments) []lint.Failure { 15 var failures []lint.Failure 16 17 var builtInConstAndVars = map[string]bool{ 18 "true": true, 19 "false": true, 20 "iota": true, 21 "nil": true, 22 } 23 24 var builtFunctions = map[string]bool{ 25 "append": true, 26 "cap": true, 27 "close": true, 28 "complex": true, 29 "copy": true, 30 "delete": true, 31 "imag": true, 32 "len": true, 33 "make": true, 34 "new": true, 35 "panic": true, 36 "print": true, 37 "println": true, 38 "real": true, 39 "recover": true, 40 } 41 42 var builtInTypes = map[string]bool{ 43 "ComplexType": true, 44 "FloatType": true, 45 "IntegerType": true, 46 "Type": true, 47 "Type1": true, 48 "bool": true, 49 "byte": true, 50 "complex128": true, 51 "complex64": true, 52 "error": true, 53 "float32": true, 54 "float64": true, 55 "int": true, 56 "int16": true, 57 "int32": true, 58 "int64": true, 59 "int8": true, 60 "rune": true, 61 "string": true, 62 "uint": true, 63 "uint16": true, 64 "uint32": true, 65 "uint64": true, 66 "uint8": true, 67 "uintptr": true, 68 } 69 70 onFailure := func(failure lint.Failure) { 71 failures = append(failures, failure) 72 } 73 74 astFile := file.AST 75 w := &lintRedefinesBuiltinID{builtInConstAndVars, builtFunctions, builtInTypes, onFailure} 76 ast.Walk(w, astFile) 77 78 return failures 79 } 80 81 // Name returns the rule name. 82 func (r *RedefinesBuiltinIDRule) Name() string { 83 return "redefines-builtin-id" 84 } 85 86 type lintRedefinesBuiltinID struct { 87 constsAndVars map[string]bool 88 funcs map[string]bool 89 types map[string]bool 90 onFailure func(lint.Failure) 91 } 92 93 func (w *lintRedefinesBuiltinID) Visit(node ast.Node) ast.Visitor { 94 switch n := node.(type) { 95 case *ast.GenDecl: 96 if n.Tok != token.TYPE { 97 return nil // skip if not type declaration 98 } 99 typeSpec, ok := n.Specs[0].(*ast.TypeSpec) 100 if !ok { 101 return nil 102 } 103 id := typeSpec.Name.Name 104 if w.types[id] { 105 w.addFailure(n, fmt.Sprintf("redefinition of the built-in type %s", id)) 106 } 107 case *ast.FuncDecl: 108 if n.Recv != nil { 109 return w // skip methods 110 } 111 112 id := n.Name.Name 113 if w.funcs[id] { 114 w.addFailure(n, fmt.Sprintf("redefinition of the built-in function %s", id)) 115 } 116 case *ast.AssignStmt: 117 for _, e := range n.Lhs { 118 id, ok := e.(*ast.Ident) 119 if !ok { 120 continue 121 } 122 123 if w.constsAndVars[id.Name] { 124 var msg string 125 if n.Tok == token.DEFINE { 126 msg = fmt.Sprintf("assignment creates a shadow of built-in identifier %s", id.Name) 127 } else { 128 msg = fmt.Sprintf("assignment modifies built-in identifier %s", id.Name) 129 } 130 w.addFailure(n, msg) 131 } 132 } 133 } 134 135 return w 136 } 137 138 func (w lintRedefinesBuiltinID) addFailure(node ast.Node, msg string) { 139 w.onFailure(lint.Failure{ 140 Confidence: 1, 141 Node: node, 142 Category: "logic", 143 Failure: msg, 144 }) 145 }