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