1
16
17
18
19 package warn
20
21 import (
22 "github.com/bazelbuild/buildtools/build"
23 )
24
25 func dictionaryConcatenationWarning(f *build.File) []*LinterFinding {
26 var findings []*LinterFinding
27
28 var addWarning = func(expr build.Expr) {
29 findings = append(findings,
30 makeLinterFinding(expr, "Dictionary concatenation is deprecated."))
31 }
32
33 types := DetectTypes(f)
34 build.Walk(f, func(expr build.Expr, stack []build.Expr) {
35 switch expr := expr.(type) {
36 case *build.BinaryExpr:
37 if expr.Op != "+" {
38 return
39 }
40 if types[expr.X] == Dict || types[expr.Y] == Dict {
41 addWarning(expr)
42 }
43 case *build.AssignExpr:
44 if expr.Op != "+=" {
45 return
46 }
47 if types[expr.LHS] == Dict || types[expr.RHS] == Dict {
48 addWarning(expr)
49 }
50 }
51 })
52 return findings
53 }
54
55
56
57
58
59
60
61
62 func dictMethodNamedArgWarning(f *build.File) []*LinterFinding {
63 var findings []*LinterFinding
64
65 types := DetectTypes(f)
66 build.Walk(f, func(expr build.Expr, stack []build.Expr) {
67
68 var callexpr *build.CallExpr
69 var ok bool
70 if callexpr, ok = expr.(*build.CallExpr); !ok {
71 return
72 }
73 var dotexpr *build.DotExpr
74 if dotexpr, ok = callexpr.X.(*build.DotExpr); !ok || types[dotexpr.X] != Dict {
75 return
76 }
77
78 if dotexpr.Name != "pop" && dotexpr.Name != "get" && dotexpr.Name != "setdefault" {
79 return
80 }
81
82 for _, expr := range callexpr.List {
83 assignExpr, ok := expr.(*build.AssignExpr)
84 if !ok {
85 continue
86 }
87 if left, ok := assignExpr.LHS.(*build.Ident); !ok || left.Name != "default" {
88 continue
89 }
90 findings = append(findings,
91 makeLinterFinding(expr, "Named argument \"default\" not allowed, use a positional (unnamed) argument"))
92 }
93 })
94 return findings
95 }
96
97 func stringIterationWarning(f *build.File) []*LinterFinding {
98 var findings []*LinterFinding
99
100 addWarning := func(expr build.Expr) {
101 findings = append(findings,
102 makeLinterFinding(expr, "String iteration is deprecated."))
103 }
104
105 types := DetectTypes(f)
106 build.Walk(f, func(expr build.Expr, stack []build.Expr) {
107 switch expr := expr.(type) {
108 case *build.ForStmt:
109 if types[expr.X] == String {
110 addWarning(expr.X)
111 }
112 case *build.ForClause:
113 if types[expr.X] == String {
114 addWarning(expr.X)
115 }
116 case *build.CallExpr:
117 ident, ok := expr.X.(*build.Ident)
118 if !ok {
119 return
120 }
121 switch ident.Name {
122 case "all", "any", "reversed", "max", "min":
123 if len(expr.List) != 1 {
124 return
125 }
126 if types[expr.List[0]] == String {
127 addWarning(expr.List[0])
128 }
129 case "zip":
130 for _, arg := range expr.List {
131 if types[arg] == String {
132 addWarning(arg)
133 }
134 }
135 }
136 }
137 })
138 return findings
139 }
140
141 func integerDivisionWarning(f *build.File) []*LinterFinding {
142 var findings []*LinterFinding
143
144 types := DetectTypes(f)
145 build.WalkPointers(f, func(e *build.Expr, stack []build.Expr) {
146 switch expr := (*e).(type) {
147 case *build.BinaryExpr:
148 if expr.Op != "/" {
149 return
150 }
151 if types[expr.X] != Int || types[expr.Y] != Int {
152 return
153 }
154 newBinary := *expr
155 newBinary.Op = "//"
156 findings = append(findings,
157 makeLinterFinding(expr, `The "/" operator for integer division is deprecated in favor of "//".`,
158 LinterReplacement{e, &newBinary}))
159
160 case *build.AssignExpr:
161 if expr.Op != "/=" {
162 return
163 }
164 if types[expr.LHS] != Int || types[expr.RHS] != Int {
165 return
166 }
167 newAssign := *expr
168 newAssign.Op = "//="
169 findings = append(findings,
170 makeLinterFinding(expr, `The "/=" operator for integer division is deprecated in favor of "//=".`,
171 LinterReplacement{e, &newAssign}))
172 }
173 })
174 return findings
175 }
176
177 func listAppendWarning(f *build.File) []*LinterFinding {
178 var findings []*LinterFinding
179
180 build.WalkPointers(f, func(expr *build.Expr, stack []build.Expr) {
181 as, ok := (*expr).(*build.AssignExpr)
182 if !ok || as.Op != "+=" {
183 return
184 }
185
186 list, ok := as.RHS.(*build.ListExpr)
187 if !ok || len(list.List) != 1 {
188 return
189 }
190
191 _, end := as.Span()
192 findings = append(findings, makeLinterFinding(as, `Prefer using ".append()" to adding a single element list.`,
193 LinterReplacement{expr, &build.CallExpr{
194 Comments: as.Comments,
195 X: &build.DotExpr{
196 X: as.LHS,
197 Name: "append",
198 },
199 List: list.List,
200 End: build.End{Pos: end},
201 }}))
202
203 })
204 return findings
205 }
206
View as plain text