From 4152367f5dee2a70ff49f4aff4040d5d433b8e44 Mon Sep 17 00:00:00 2001 From: Akshay Date: Mon, 13 Sep 2021 22:20:25 +0530 Subject: add demo lint: bool_comparison --- lib/src/lints/bool_comparison.rs | 78 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 78 insertions(+) create mode 100644 lib/src/lints/bool_comparison.rs (limited to 'lib/src/lints') 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 @@ +use crate::{Diagnostic, Lint, Metadata, Rule}; + +use if_chain::if_chain; +use macros::lint; +use rnix::{ + types::{BinOp, BinOpKind, Ident, TokenWrapper, TypedNode}, + NodeOrToken, SyntaxElement, SyntaxKind, SyntaxNode, +}; + +#[lint( + name = "bool_comparison", + note = "Unnecessary comparison with boolean", + match_with = "SyntaxKind::NODE_BIN_OP" +)] +struct BoolComparison; + +impl Rule for BoolComparison { + fn validate(&self, node: &SyntaxElement) -> Option { + if_chain! { + if let NodeOrToken::Node(bin_op_node) = node; + if let Some(bin_expr) = BinOp::cast(bin_op_node.clone()); + if let Some(lhs) = bin_expr.lhs(); + if let Some(rhs) = bin_expr.rhs(); + + if let BinOpKind::Equal | BinOpKind::NotEqual = bin_expr.operator(); + let (non_bool_side, bool_side) = if is_boolean_ident(&lhs) { + (rhs, lhs) + } else if is_boolean_ident(&rhs) { + (lhs, rhs) + } else { + return None + }; + then { + let at = node.text_range(); + let message = format!( + "Comparing `{}` with boolean literal `{}`", + non_bool_side, + bool_side + ); + dbg!(Some(Diagnostic::new(at, message))) + } else { + None + } + } + } +} + +// not entirely accurate, underhanded nix programmers might write `true = false` +fn is_boolean_ident(node: &SyntaxNode) -> bool { + if let Some(ident_expr) = Ident::cast(node.clone()) { + ident_expr.as_str() == "true" || ident_expr.as_str() == "false" + } else { + false + } +} + +// #[cfg(test)] +// mod tests { +// use super::*; +// use rnix::{parser, WalkEvent}; +// +// #[test] +// fn trivial() { +// let src = r#" +// a == true +// "#; +// let parsed = rnix::parse(src).as_result().ok().unwrap(); +// let _ = parsed +// .node() +// .preorder_with_tokens() +// .filter_map(|event| match event { +// WalkEvent::Enter(t) => Some(t), +// _ => None, +// }) +// .map(|node| BoolComparison.validate(&node)) +// .collect::>(); +// } +// } -- cgit v1.2.3