aboutsummaryrefslogtreecommitdiff
path: root/lib/src/lints/bool_comparison.rs
diff options
context:
space:
mode:
Diffstat (limited to 'lib/src/lints/bool_comparison.rs')
-rw-r--r--lib/src/lints/bool_comparison.rs78
1 files changed, 78 insertions, 0 deletions
diff --git a/lib/src/lints/bool_comparison.rs b/lib/src/lints/bool_comparison.rs
new file mode 100644
index 0000000..4476b31
--- /dev/null
+++ b/lib/src/lints/bool_comparison.rs
@@ -0,0 +1,78 @@
1use crate::{Diagnostic, Lint, Metadata, Rule};
2
3use if_chain::if_chain;
4use macros::lint;
5use rnix::{
6 types::{BinOp, BinOpKind, Ident, TokenWrapper, TypedNode},
7 NodeOrToken, SyntaxElement, SyntaxKind, SyntaxNode,
8};
9
10#[lint(
11 name = "bool_comparison",
12 note = "Unnecessary comparison with boolean",
13 match_with = "SyntaxKind::NODE_BIN_OP"
14)]
15struct BoolComparison;
16
17impl Rule for BoolComparison {
18 fn validate(&self, node: &SyntaxElement) -> Option<Diagnostic> {
19 if_chain! {
20 if let NodeOrToken::Node(bin_op_node) = node;
21 if let Some(bin_expr) = BinOp::cast(bin_op_node.clone());
22 if let Some(lhs) = bin_expr.lhs();
23 if let Some(rhs) = bin_expr.rhs();
24
25 if let BinOpKind::Equal | BinOpKind::NotEqual = bin_expr.operator();
26 let (non_bool_side, bool_side) = if is_boolean_ident(&lhs) {
27 (rhs, lhs)
28 } else if is_boolean_ident(&rhs) {
29 (lhs, rhs)
30 } else {
31 return None
32 };
33 then {
34 let at = node.text_range();
35 let message = format!(
36 "Comparing `{}` with boolean literal `{}`",
37 non_bool_side,
38 bool_side
39 );
40 dbg!(Some(Diagnostic::new(at, message)))
41 } else {
42 None
43 }
44 }
45 }
46}
47
48// not entirely accurate, underhanded nix programmers might write `true = false`
49fn is_boolean_ident(node: &SyntaxNode) -> bool {
50 if let Some(ident_expr) = Ident::cast(node.clone()) {
51 ident_expr.as_str() == "true" || ident_expr.as_str() == "false"
52 } else {
53 false
54 }
55}
56
57// #[cfg(test)]
58// mod tests {
59// use super::*;
60// use rnix::{parser, WalkEvent};
61//
62// #[test]
63// fn trivial() {
64// let src = r#"
65// a == true
66// "#;
67// let parsed = rnix::parse(src).as_result().ok().unwrap();
68// let _ = parsed
69// .node()
70// .preorder_with_tokens()
71// .filter_map(|event| match event {
72// WalkEvent::Enter(t) => Some(t),
73// _ => None,
74// })
75// .map(|node| BoolComparison.validate(&node))
76// .collect::<Vec<_>>();
77// }
78// }