From a254edfcd27f1bba5eb7eacb11bfcd077bd1af16 Mon Sep 17 00:00:00 2001 From: Akshay Date: Sun, 30 Jan 2022 12:10:21 +0530 Subject: new lint: faster_zipattrswith --- lib/src/lints.rs | 1 + lib/src/lints/faster_zipattrswith.rs | 72 ++++++++++++++++++++++++++++++++++++ 2 files changed, 73 insertions(+) create mode 100644 lib/src/lints/faster_zipattrswith.rs (limited to 'lib') diff --git a/lib/src/lints.rs b/lib/src/lints.rs index 0add458..d31a754 100644 --- a/lib/src/lints.rs +++ b/lib/src/lints.rs @@ -16,4 +16,5 @@ lints! { deprecated_is_null, empty_inherit, faster_groupby, + faster_zipattrswith, } diff --git a/lib/src/lints/faster_zipattrswith.rs b/lib/src/lints/faster_zipattrswith.rs new file mode 100644 index 0000000..139d499 --- /dev/null +++ b/lib/src/lints/faster_zipattrswith.rs @@ -0,0 +1,72 @@ +use crate::{ + make, + session::{SessionInfo, Version}, + Metadata, Report, Rule, Suggestion, +}; + +use if_chain::if_chain; +use macros::lint; +use rnix::{ + types::{Select, TypedNode}, + NodeOrToken, SyntaxElement, SyntaxKind, +}; + +/// ## What it does +/// Checks for `lib.zipAttrsWith`. +/// +/// ## Why is this bad? +/// Nix 2.6 introduces `builtins.zipAttrsWith` which is faster and does +/// not require a lib import. +/// +/// ## Example +/// +/// ```nix +/// lib.zipAttrsWith (name: values: values) [ {a = "x";} {a = "y"; b = "z";} ] +/// # { a = ["x" "y"]; b = ["z"] } +/// ``` +/// +/// Replace `lib.zipAttrsWith` with `builtins.zipAttrsWith`: +/// +/// ```nix +/// builtins.zipAttrsWith (name: values: values) [ {a = "x";} {a = "y"; b = "z";} ] +/// ``` +#[lint( + name = "faster_zipattrswith", + note = "Found lib.zipAttrsWith", + code = 16, + match_with = SyntaxKind::NODE_SELECT +)] +struct FasterZipAttrsWith; + +impl Rule for FasterZipAttrsWith { + fn validate(&self, node: &SyntaxElement, sess: &SessionInfo) -> Option { + let lint_version = "2.6".parse::().unwrap(); + if_chain! { + if sess.version() >= &lint_version; + if let NodeOrToken::Node(node) = node; + if let Some(select_expr) = Select::cast(node.clone()); + if let Some(select_from) = select_expr.set(); + if let Some(zip_attrs_with) = select_expr.index(); + + // a heuristic to lint on nixpkgs.lib.zipAttrsWith + // and lib.zipAttrsWith and its variants + if select_from.text().to_string() != "builtins"; + if zip_attrs_with.text().to_string() == "zipAttrsWith"; + + then { + let at = node.text_range(); + let replacement = { + let builtins = make::ident("builtins"); + make::select(builtins.node(), &zip_attrs_with).node().clone() + }; + let message = format!("Prefer `builtins.zipAttrsWith` over `{}.zipAttrsWith`", select_from); + Some( + self.report() + .suggest(at, message, Suggestion::new(at, replacement)), + ) + } else { + None + } + } + } +} -- cgit v1.2.3