From e8130a90dca048d195603281f72e1af0b4f7ccc6 Mon Sep 17 00:00:00 2001 From: Akshay Date: Sun, 20 Feb 2022 09:37:32 +0530 Subject: new lint: bool_simplification TODO: add more patterns to this --- bin/tests/data/bool_simplification.nix | 7 +++ bin/tests/main.rs | 3 +- bin/tests/snapshots/main__bool_simplification.snap | 13 +++++ lib/src/lints.rs | 1 + lib/src/lints/bool_simplification.rs | 61 ++++++++++++++++++++++ 5 files changed, 84 insertions(+), 1 deletion(-) create mode 100644 bin/tests/data/bool_simplification.nix create mode 100644 bin/tests/snapshots/main__bool_simplification.snap create mode 100644 lib/src/lints/bool_simplification.rs diff --git a/bin/tests/data/bool_simplification.nix b/bin/tests/data/bool_simplification.nix new file mode 100644 index 0000000..64c2c7a --- /dev/null +++ b/bin/tests/data/bool_simplification.nix @@ -0,0 +1,7 @@ +let + _ = !(a == b); + # do not match here + _ = !(a != b); + _ = a != b; +in + null diff --git a/bin/tests/main.rs b/bin/tests/main.rs index bec64d2..3403f65 100644 --- a/bin/tests/main.rs +++ b/bin/tests/main.rs @@ -63,5 +63,6 @@ test_lint! { empty_inherit, faster_groupby => session_info!("2.5"), faster_zipattrswith => session_info!("2.6"), - deprecated_to_path => session_info!("2.4") + deprecated_to_path => session_info!("2.4"), + bool_simplification } diff --git a/bin/tests/snapshots/main__bool_simplification.snap b/bin/tests/snapshots/main__bool_simplification.snap new file mode 100644 index 0000000..9e3c991 --- /dev/null +++ b/bin/tests/snapshots/main__bool_simplification.snap @@ -0,0 +1,13 @@ +--- +source: bin/tests/main.rs +expression: "&out" + +--- +[W18] Warning: This boolean expression can be simplified + ╭─[data/bool_simplification.nix:2:7] + │ + 2 │ _ = !(a == b); + · ────┬──── + · ╰────── Try != instead of !(... == ...) +───╯ + diff --git a/lib/src/lints.rs b/lib/src/lints.rs index 439fd8f..582cabe 100644 --- a/lib/src/lints.rs +++ b/lib/src/lints.rs @@ -18,4 +18,5 @@ lints! { faster_groupby, faster_zipattrswith, deprecated_to_path, + bool_simplification, } diff --git a/lib/src/lints/bool_simplification.rs b/lib/src/lints/bool_simplification.rs new file mode 100644 index 0000000..9ccb1f6 --- /dev/null +++ b/lib/src/lints/bool_simplification.rs @@ -0,0 +1,61 @@ +use crate::{make, session::SessionInfo, Metadata, Report, Rule, Suggestion}; + +use if_chain::if_chain; +use macros::lint; +use rnix::{ + types::{BinOp, BinOpKind, Paren, TypedNode, UnaryOp, UnaryOpKind, Wrapper}, + NodeOrToken, SyntaxElement, SyntaxKind, +}; + +/// ## What it does +/// Checks for boolean expressions that can be simplified. +/// +/// ## Why is this bad? +/// Complex booleans affect readibility. +/// +/// ## Example +/// ```nix +/// if !(x == y) then 0 else 1 +/// ``` +/// +/// Use `!=` instead: +/// +/// ```nix +/// if x != y then 0 else 1 +/// ``` +#[lint( + name = "bool_simplification", + note = "This boolean expression can be simplified", + code = 18, + match_with = SyntaxKind::NODE_UNARY_OP +)] +struct BoolSimplification; + +impl Rule for BoolSimplification { + fn validate(&self, node: &SyntaxElement, _sess: &SessionInfo) -> Option { + if_chain! { + if let NodeOrToken::Node(node) = node; + if let Some(unary_expr) = UnaryOp::cast(node.clone()); + if unary_expr.operator() == UnaryOpKind::Invert; + if let Some(value_expr) = unary_expr.value(); + if let Some(paren_expr) = Paren::cast(value_expr.clone()); + if let Some(inner_expr) = paren_expr.inner(); + if let Some(bin_expr) = BinOp::cast(inner_expr); + if let Some(BinOpKind::Equal) = bin_expr.operator(); + then { + let at = node.text_range(); + let message = "Try `!=` instead of `!(... == ...)`"; + + let lhs = bin_expr.lhs()?; + let rhs = bin_expr.rhs()?; + let replacement = make::binary(&lhs, "!=", &rhs).node().clone(); + Some( + self.report() + .suggest(at, message, Suggestion::new(at, replacement)), + ) + } else { + None + } + } + } +} -- cgit v1.2.3