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