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
use crate::rule_prelude::*;
use ast::*;
use SyntaxKind::*;
declare_lint! {
#[derive(Default)]
NoConstantCondition,
errors,
"no-constant-condition"
}
#[typetag::serde]
impl CstRule for NoConstantCondition {
fn check_node(&self, node: &SyntaxNode, ctx: &mut RuleCtx) -> Option<()> {
let mut notes = vec![];
let cond = match node.kind() {
IF_STMT | DO_WHILE_STMT | WHILE_STMT => {
if let Some(cond) = node.children().find_map(|node| node.try_to::<Condition>()) {
if !util::is_const(cond.condition()?, true, &mut notes) {
return None;
}
cond.condition().unwrap()
} else {
return None;
}
}
COND_EXPR => {
let cond = node.to::<CondExpr>().test()?;
if !util::is_const(cond.clone(), true, &mut notes) {
return None;
}
cond
}
FOR_STMT => {
let cond = node.to::<ForStmt>().test()?.expr()?;
if !util::is_const(cond.clone(), true, &mut notes) {
return None;
}
cond
}
_ => return None,
};
let mut err = ctx.err(self.name(), "Unexpected constant condition");
if let Some(condition_value) = util::simple_bool_coerce(cond.clone()) {
err = util::simple_const_condition_context(node.clone(), condition_value, err);
} else {
err = err.primary(cond.syntax(), "this condition always yields one result")
}
ctx.add_err(err);
None
}
}
rule_tests! {
NoConstantCondition::default(),
err: {
"if(6) {}",
"if(6 - 7 || 3 ? 7 && 2 : NaN + NaN || 2) {}",
"if (true) {}",
"if (NaN) {} else {}",
"6 + 2 ? false : NaN",
"false ? false : false ? false : false",
"while (true) {}",
"do { /* */ } while (NaN ? NaN : true)",
"do { } while (NaN ? Infinity : true)"
},
ok: {
"if (foo) {}",
"if (false > foo) {} else {}",
"if (foo ? NaN : Infinity) {}",
"do {} while (foo + 6)",
"for(var i = 5; foo; i++) {}"
}
}