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 --- lib/src/lints.rs | 1 + lib/src/lints/bool_simplification.rs | 61 ++++++++++++++++++++++++++++++++++++ 2 files changed, 62 insertions(+) create mode 100644 lib/src/lints/bool_simplification.rs (limited to 'lib') 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