@ttsc/lint 0.7.1 → 0.7.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +62 -24
- package/lib/index.js.map +1 -1
- package/package.json +3 -3
- package/plugin/ast_helpers.go +158 -158
- package/plugin/compile.go +303 -303
- package/plugin/config.go +322 -322
- package/plugin/engine.go +152 -153
- package/plugin/host.go +128 -128
- package/plugin/main.go +21 -21
- package/plugin/rules_arrays.go +51 -51
- package/plugin/rules_console.go +22 -23
- package/plugin/rules_debugger.go +4 -4
- package/plugin/rules_dupes.go +134 -134
- package/plugin/rules_empty.go +68 -68
- package/plugin/rules_eval.go +28 -28
- package/plugin/rules_finally.go +91 -91
- package/plugin/rules_gap.go +188 -188
- package/plugin/rules_logic.go +268 -268
- package/plugin/rules_loops.go +89 -89
- package/plugin/rules_misc.go +43 -43
- package/plugin/rules_problems.go +396 -396
- package/plugin/rules_protos.go +17 -17
- package/plugin/rules_self.go +56 -56
- package/plugin/rules_strings.go +65 -65
- package/plugin/rules_suggestions.go +863 -863
- package/plugin/rules_throw.go +16 -16
- package/plugin/rules_ts.go +161 -161
- package/plugin/rules_ts_extra.go +467 -467
- package/plugin/rules_var.go +86 -86
- package/src/index.ts +1 -4
package/plugin/rules_logic.go
CHANGED
|
@@ -9,73 +9,73 @@ type noExtraBooleanCast struct{}
|
|
|
9
9
|
|
|
10
10
|
func (noExtraBooleanCast) Name() string { return "no-extra-boolean-cast" }
|
|
11
11
|
func (noExtraBooleanCast) Visits() []shimast.Kind {
|
|
12
|
-
|
|
12
|
+
return []shimast.Kind{shimast.KindCallExpression, shimast.KindPrefixUnaryExpression}
|
|
13
13
|
}
|
|
14
14
|
func (noExtraBooleanCast) Check(ctx *Context, node *shimast.Node) {
|
|
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
|
-
|
|
15
|
+
switch node.Kind {
|
|
16
|
+
case shimast.KindCallExpression:
|
|
17
|
+
call := node.AsCallExpression()
|
|
18
|
+
if call == nil {
|
|
19
|
+
return
|
|
20
|
+
}
|
|
21
|
+
if identifierText(call.Expression) != "Boolean" {
|
|
22
|
+
return
|
|
23
|
+
}
|
|
24
|
+
if isInBooleanContext(node) {
|
|
25
|
+
ctx.Report(node, "Redundant Boolean call.")
|
|
26
|
+
}
|
|
27
|
+
case shimast.KindPrefixUnaryExpression:
|
|
28
|
+
outer := node.AsPrefixUnaryExpression()
|
|
29
|
+
if outer == nil || outer.Operator != shimast.KindExclamationToken {
|
|
30
|
+
return
|
|
31
|
+
}
|
|
32
|
+
operand := outer.Operand
|
|
33
|
+
if operand == nil || operand.Kind != shimast.KindPrefixUnaryExpression {
|
|
34
|
+
return
|
|
35
|
+
}
|
|
36
|
+
inner := operand.AsPrefixUnaryExpression()
|
|
37
|
+
if inner == nil || inner.Operator != shimast.KindExclamationToken {
|
|
38
|
+
return
|
|
39
|
+
}
|
|
40
|
+
if isInBooleanContext(node) {
|
|
41
|
+
ctx.Report(node, "Redundant double negation.")
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
44
|
}
|
|
45
45
|
|
|
46
46
|
// isInBooleanContext walks up the parent chain to determine whether the
|
|
47
47
|
// expression's value is consumed as a boolean (test of an if/while/for/
|
|
48
48
|
// ternary, or operand of `!`).
|
|
49
49
|
func isInBooleanContext(node *shimast.Node) bool {
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
50
|
+
parent := node.Parent
|
|
51
|
+
for parent != nil && parent.Kind == shimast.KindParenthesizedExpression {
|
|
52
|
+
parent = parent.Parent
|
|
53
|
+
}
|
|
54
|
+
if parent == nil {
|
|
55
|
+
return false
|
|
56
|
+
}
|
|
57
|
+
switch parent.Kind {
|
|
58
|
+
case shimast.KindIfStatement:
|
|
59
|
+
return parent.AsIfStatement().Expression == skipParents(node)
|
|
60
|
+
case shimast.KindWhileStatement:
|
|
61
|
+
return parent.AsWhileStatement().Expression == skipParents(node)
|
|
62
|
+
case shimast.KindDoStatement:
|
|
63
|
+
return parent.AsDoStatement().Expression == skipParents(node)
|
|
64
|
+
case shimast.KindForStatement:
|
|
65
|
+
return parent.AsForStatement().Condition == skipParents(node)
|
|
66
|
+
case shimast.KindConditionalExpression:
|
|
67
|
+
return parent.AsConditionalExpression().Condition == skipParents(node)
|
|
68
|
+
case shimast.KindPrefixUnaryExpression:
|
|
69
|
+
return parent.AsPrefixUnaryExpression().Operator == shimast.KindExclamationToken
|
|
70
|
+
}
|
|
71
|
+
return false
|
|
72
72
|
}
|
|
73
73
|
|
|
74
74
|
func skipParents(node *shimast.Node) *shimast.Node {
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
75
|
+
for node != nil && node.Parent != nil && node.Parent.Kind == shimast.KindParenthesizedExpression {
|
|
76
|
+
node = node.Parent
|
|
77
|
+
}
|
|
78
|
+
return node
|
|
79
79
|
}
|
|
80
80
|
|
|
81
81
|
// no-unsafe-negation: `!a in b` and `!a instanceof b` — the parser
|
|
@@ -86,23 +86,23 @@ type noUnsafeNegation struct{}
|
|
|
86
86
|
func (noUnsafeNegation) Name() string { return "no-unsafe-negation" }
|
|
87
87
|
func (noUnsafeNegation) Visits() []shimast.Kind { return []shimast.Kind{shimast.KindBinaryExpression} }
|
|
88
88
|
func (noUnsafeNegation) Check(ctx *Context, node *shimast.Node) {
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
89
|
+
expr := node.AsBinaryExpression()
|
|
90
|
+
if expr == nil || expr.OperatorToken == nil {
|
|
91
|
+
return
|
|
92
|
+
}
|
|
93
|
+
switch expr.OperatorToken.Kind {
|
|
94
|
+
case shimast.KindInKeyword, shimast.KindInstanceOfKeyword:
|
|
95
|
+
default:
|
|
96
|
+
return
|
|
97
|
+
}
|
|
98
|
+
if expr.Left == nil || expr.Left.Kind != shimast.KindPrefixUnaryExpression {
|
|
99
|
+
return
|
|
100
|
+
}
|
|
101
|
+
prefix := expr.Left.AsPrefixUnaryExpression()
|
|
102
|
+
if prefix == nil || prefix.Operator != shimast.KindExclamationToken {
|
|
103
|
+
return
|
|
104
|
+
}
|
|
105
|
+
ctx.Report(node, "Unexpected negating the left operand of a relational operator.")
|
|
106
106
|
}
|
|
107
107
|
|
|
108
108
|
// eqeqeq: enforce `===` / `!==`. Default mode matches ESLint's `always`
|
|
@@ -113,16 +113,16 @@ type eqeqeq struct{}
|
|
|
113
113
|
func (eqeqeq) Name() string { return "eqeqeq" }
|
|
114
114
|
func (eqeqeq) Visits() []shimast.Kind { return []shimast.Kind{shimast.KindBinaryExpression} }
|
|
115
115
|
func (eqeqeq) Check(ctx *Context, node *shimast.Node) {
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
116
|
+
expr := node.AsBinaryExpression()
|
|
117
|
+
if expr == nil || expr.OperatorToken == nil {
|
|
118
|
+
return
|
|
119
|
+
}
|
|
120
|
+
switch expr.OperatorToken.Kind {
|
|
121
|
+
case shimast.KindEqualsEqualsToken:
|
|
122
|
+
ctx.ReportRange(expr.OperatorToken.Pos(), expr.OperatorToken.End(), "Expected '===' and instead saw '=='.")
|
|
123
|
+
case shimast.KindExclamationEqualsToken:
|
|
124
|
+
ctx.ReportRange(expr.OperatorToken.Pos(), expr.OperatorToken.End(), "Expected '!==' and instead saw '!='.")
|
|
125
|
+
}
|
|
126
126
|
}
|
|
127
127
|
|
|
128
128
|
// use-isnan: `x === NaN` is always false. Use `Number.isNaN(x)`.
|
|
@@ -132,16 +132,16 @@ type useIsnan struct{}
|
|
|
132
132
|
func (useIsnan) Name() string { return "use-isnan" }
|
|
133
133
|
func (useIsnan) Visits() []shimast.Kind { return []shimast.Kind{shimast.KindBinaryExpression} }
|
|
134
134
|
func (useIsnan) Check(ctx *Context, node *shimast.Node) {
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
135
|
+
expr := node.AsBinaryExpression()
|
|
136
|
+
if expr == nil || expr.OperatorToken == nil {
|
|
137
|
+
return
|
|
138
|
+
}
|
|
139
|
+
if !isComparisonOperator(expr.OperatorToken.Kind) {
|
|
140
|
+
return
|
|
141
|
+
}
|
|
142
|
+
if identifierText(expr.Left) == "NaN" || identifierText(expr.Right) == "NaN" {
|
|
143
|
+
ctx.Report(node, "Use the isNaN function to compare with NaN.")
|
|
144
|
+
}
|
|
145
145
|
}
|
|
146
146
|
|
|
147
147
|
// valid-typeof: typeof expressions can only be compared to known type
|
|
@@ -152,41 +152,41 @@ type validTypeof struct{}
|
|
|
152
152
|
func (validTypeof) Name() string { return "valid-typeof" }
|
|
153
153
|
func (validTypeof) Visits() []shimast.Kind { return []shimast.Kind{shimast.KindBinaryExpression} }
|
|
154
154
|
func (validTypeof) Check(ctx *Context, node *shimast.Node) {
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
155
|
+
expr := node.AsBinaryExpression()
|
|
156
|
+
if expr == nil || expr.OperatorToken == nil {
|
|
157
|
+
return
|
|
158
|
+
}
|
|
159
|
+
if !isComparisonOperator(expr.OperatorToken.Kind) {
|
|
160
|
+
return
|
|
161
|
+
}
|
|
162
|
+
left := stripParens(expr.Left)
|
|
163
|
+
right := stripParens(expr.Right)
|
|
164
|
+
var literal *shimast.Node
|
|
165
|
+
if left != nil && left.Kind == shimast.KindTypeOfExpression {
|
|
166
|
+
literal = right
|
|
167
|
+
} else if right != nil && right.Kind == shimast.KindTypeOfExpression {
|
|
168
|
+
literal = left
|
|
169
|
+
} else {
|
|
170
|
+
return
|
|
171
|
+
}
|
|
172
|
+
if literal == nil {
|
|
173
|
+
return
|
|
174
|
+
}
|
|
175
|
+
value := stringLiteralText(literal)
|
|
176
|
+
if value == "" {
|
|
177
|
+
return
|
|
178
|
+
}
|
|
179
|
+
if !isValidTypeofString(value) {
|
|
180
|
+
ctx.Report(literal, "Invalid typeof comparison value.")
|
|
181
|
+
}
|
|
182
182
|
}
|
|
183
183
|
|
|
184
184
|
func isValidTypeofString(value string) bool {
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
185
|
+
switch value {
|
|
186
|
+
case "undefined", "object", "boolean", "number", "string", "function", "symbol", "bigint":
|
|
187
|
+
return true
|
|
188
|
+
}
|
|
189
|
+
return false
|
|
190
190
|
}
|
|
191
191
|
|
|
192
192
|
// no-compare-neg-zero: `x === -0`. Comparison ignores the sign — use
|
|
@@ -197,27 +197,27 @@ type noCompareNegZero struct{}
|
|
|
197
197
|
func (noCompareNegZero) Name() string { return "no-compare-neg-zero" }
|
|
198
198
|
func (noCompareNegZero) Visits() []shimast.Kind { return []shimast.Kind{shimast.KindBinaryExpression} }
|
|
199
199
|
func (noCompareNegZero) Check(ctx *Context, node *shimast.Node) {
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
200
|
+
expr := node.AsBinaryExpression()
|
|
201
|
+
if expr == nil || expr.OperatorToken == nil {
|
|
202
|
+
return
|
|
203
|
+
}
|
|
204
|
+
if !isComparisonOperator(expr.OperatorToken.Kind) {
|
|
205
|
+
return
|
|
206
|
+
}
|
|
207
|
+
if isNegZero(expr.Left) || isNegZero(expr.Right) {
|
|
208
|
+
ctx.Report(node, "Do not use the '-0' literal in comparisons.")
|
|
209
|
+
}
|
|
210
210
|
}
|
|
211
211
|
|
|
212
212
|
func isNegZero(node *shimast.Node) bool {
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
213
|
+
if node == nil || node.Kind != shimast.KindPrefixUnaryExpression {
|
|
214
|
+
return false
|
|
215
|
+
}
|
|
216
|
+
prefix := node.AsPrefixUnaryExpression()
|
|
217
|
+
if prefix == nil || prefix.Operator != shimast.KindMinusToken || prefix.Operand == nil {
|
|
218
|
+
return false
|
|
219
|
+
}
|
|
220
|
+
return numericLiteralText(prefix.Operand) == "0"
|
|
221
221
|
}
|
|
222
222
|
|
|
223
223
|
// no-cond-assign: `if (a = b)` is almost always a typo for `if (a == b)`.
|
|
@@ -228,72 +228,72 @@ type noCondAssign struct{}
|
|
|
228
228
|
|
|
229
229
|
func (noCondAssign) Name() string { return "no-cond-assign" }
|
|
230
230
|
func (noCondAssign) Visits() []shimast.Kind {
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
231
|
+
return []shimast.Kind{
|
|
232
|
+
shimast.KindIfStatement,
|
|
233
|
+
shimast.KindWhileStatement,
|
|
234
|
+
shimast.KindDoStatement,
|
|
235
|
+
shimast.KindForStatement,
|
|
236
|
+
shimast.KindConditionalExpression,
|
|
237
|
+
}
|
|
238
238
|
}
|
|
239
239
|
func (noCondAssign) Check(ctx *Context, node *shimast.Node) {
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
240
|
+
var test *shimast.Node
|
|
241
|
+
switch node.Kind {
|
|
242
|
+
case shimast.KindIfStatement:
|
|
243
|
+
test = node.AsIfStatement().Expression
|
|
244
|
+
case shimast.KindWhileStatement:
|
|
245
|
+
test = node.AsWhileStatement().Expression
|
|
246
|
+
case shimast.KindDoStatement:
|
|
247
|
+
test = node.AsDoStatement().Expression
|
|
248
|
+
case shimast.KindForStatement:
|
|
249
|
+
test = node.AsForStatement().Condition
|
|
250
|
+
case shimast.KindConditionalExpression:
|
|
251
|
+
test = node.AsConditionalExpression().Condition
|
|
252
|
+
}
|
|
253
|
+
if test == nil {
|
|
254
|
+
return
|
|
255
|
+
}
|
|
256
|
+
// `except-parens`: an explicitly parenthesized assignment is OK.
|
|
257
|
+
if test.Kind == shimast.KindParenthesizedExpression {
|
|
258
|
+
return
|
|
259
|
+
}
|
|
260
|
+
if isAssignmentExpression(test) {
|
|
261
|
+
ctx.Report(test, "Expected a conditional expression and instead saw an assignment.")
|
|
262
|
+
}
|
|
263
263
|
}
|
|
264
264
|
|
|
265
265
|
func isAssignmentExpression(node *shimast.Node) bool {
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
266
|
+
if node == nil || node.Kind != shimast.KindBinaryExpression {
|
|
267
|
+
return false
|
|
268
|
+
}
|
|
269
|
+
expr := node.AsBinaryExpression()
|
|
270
|
+
if expr == nil || expr.OperatorToken == nil {
|
|
271
|
+
return false
|
|
272
|
+
}
|
|
273
|
+
return isAssignmentOperator(expr.OperatorToken.Kind)
|
|
274
274
|
}
|
|
275
275
|
|
|
276
276
|
func isAssignmentOperator(kind shimast.Kind) bool {
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
277
|
+
switch kind {
|
|
278
|
+
case shimast.KindEqualsToken,
|
|
279
|
+
shimast.KindPlusEqualsToken,
|
|
280
|
+
shimast.KindMinusEqualsToken,
|
|
281
|
+
shimast.KindAsteriskEqualsToken,
|
|
282
|
+
shimast.KindAsteriskAsteriskEqualsToken,
|
|
283
|
+
shimast.KindSlashEqualsToken,
|
|
284
|
+
shimast.KindPercentEqualsToken,
|
|
285
|
+
shimast.KindLessThanLessThanEqualsToken,
|
|
286
|
+
shimast.KindGreaterThanGreaterThanEqualsToken,
|
|
287
|
+
shimast.KindGreaterThanGreaterThanGreaterThanEqualsToken,
|
|
288
|
+
shimast.KindAmpersandEqualsToken,
|
|
289
|
+
shimast.KindBarEqualsToken,
|
|
290
|
+
shimast.KindCaretEqualsToken,
|
|
291
|
+
shimast.KindAmpersandAmpersandEqualsToken,
|
|
292
|
+
shimast.KindBarBarEqualsToken,
|
|
293
|
+
shimast.KindQuestionQuestionEqualsToken:
|
|
294
|
+
return true
|
|
295
|
+
}
|
|
296
|
+
return false
|
|
297
297
|
}
|
|
298
298
|
|
|
299
299
|
// no-constant-condition: `if (true)`, `while (1)`, `if (literal)`. Often
|
|
@@ -303,79 +303,79 @@ type noConstantCondition struct{}
|
|
|
303
303
|
|
|
304
304
|
func (noConstantCondition) Name() string { return "no-constant-condition" }
|
|
305
305
|
func (noConstantCondition) Visits() []shimast.Kind {
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
306
|
+
return []shimast.Kind{
|
|
307
|
+
shimast.KindIfStatement,
|
|
308
|
+
shimast.KindWhileStatement,
|
|
309
|
+
shimast.KindDoStatement,
|
|
310
|
+
shimast.KindForStatement,
|
|
311
|
+
shimast.KindConditionalExpression,
|
|
312
|
+
}
|
|
313
313
|
}
|
|
314
314
|
func (noConstantCondition) Check(ctx *Context, node *shimast.Node) {
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
315
|
+
var test *shimast.Node
|
|
316
|
+
switch node.Kind {
|
|
317
|
+
case shimast.KindIfStatement:
|
|
318
|
+
test = node.AsIfStatement().Expression
|
|
319
|
+
case shimast.KindWhileStatement:
|
|
320
|
+
test = node.AsWhileStatement().Expression
|
|
321
|
+
case shimast.KindDoStatement:
|
|
322
|
+
test = node.AsDoStatement().Expression
|
|
323
|
+
case shimast.KindForStatement:
|
|
324
|
+
test = node.AsForStatement().Condition
|
|
325
|
+
case shimast.KindConditionalExpression:
|
|
326
|
+
test = node.AsConditionalExpression().Condition
|
|
327
|
+
}
|
|
328
|
+
test = stripParens(test)
|
|
329
|
+
if test == nil {
|
|
330
|
+
return // covers `for (;;)` — omitted condition is idiomatic.
|
|
331
|
+
}
|
|
332
|
+
// Allow `while (true)` since it's a common deliberate idiom.
|
|
333
|
+
if node.Kind == shimast.KindWhileStatement {
|
|
334
|
+
if v, ok := isLiteralBoolean(test); ok && v {
|
|
335
|
+
return
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
if isConstantTruthyOrFalsy(test) {
|
|
339
|
+
ctx.Report(test, "Unexpected constant condition.")
|
|
340
|
+
}
|
|
341
341
|
}
|
|
342
342
|
|
|
343
343
|
func isConstantTruthyOrFalsy(node *shimast.Node) bool {
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
344
|
+
if node == nil {
|
|
345
|
+
return false
|
|
346
|
+
}
|
|
347
|
+
switch node.Kind {
|
|
348
|
+
case
|
|
349
|
+
shimast.KindNumericLiteral,
|
|
350
|
+
shimast.KindBigIntLiteral,
|
|
351
|
+
shimast.KindStringLiteral,
|
|
352
|
+
shimast.KindNoSubstitutionTemplateLiteral,
|
|
353
|
+
shimast.KindRegularExpressionLiteral,
|
|
354
|
+
shimast.KindTrueKeyword,
|
|
355
|
+
shimast.KindFalseKeyword,
|
|
356
|
+
shimast.KindNullKeyword,
|
|
357
|
+
shimast.KindArrayLiteralExpression,
|
|
358
|
+
shimast.KindObjectLiteralExpression,
|
|
359
|
+
shimast.KindArrowFunction,
|
|
360
|
+
shimast.KindFunctionExpression:
|
|
361
|
+
return true
|
|
362
|
+
case shimast.KindPrefixUnaryExpression:
|
|
363
|
+
prefix := node.AsPrefixUnaryExpression()
|
|
364
|
+
if prefix == nil {
|
|
365
|
+
return false
|
|
366
|
+
}
|
|
367
|
+
return isConstantTruthyOrFalsy(prefix.Operand)
|
|
368
|
+
}
|
|
369
|
+
return false
|
|
370
370
|
}
|
|
371
371
|
|
|
372
372
|
func init() {
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
373
|
+
Register(noExtraBooleanCast{})
|
|
374
|
+
Register(noUnsafeNegation{})
|
|
375
|
+
Register(eqeqeq{})
|
|
376
|
+
Register(useIsnan{})
|
|
377
|
+
Register(validTypeof{})
|
|
378
|
+
Register(noCompareNegZero{})
|
|
379
|
+
Register(noCondAssign{})
|
|
380
|
+
Register(noConstantCondition{})
|
|
381
381
|
}
|