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 --- bin/tests/data/faster_zipattrswith.nix | 13 ++++ bin/tests/main.rs | 5 +- bin/tests/snapshots/main__faster_zipattrswith.snap | 20 ++++++ lib/src/lints.rs | 1 + lib/src/lints/faster_zipattrswith.rs | 72 ++++++++++++++++++++++ 5 files changed, 109 insertions(+), 2 deletions(-) create mode 100644 bin/tests/data/faster_zipattrswith.nix create mode 100644 bin/tests/snapshots/main__faster_zipattrswith.snap create mode 100644 lib/src/lints/faster_zipattrswith.rs diff --git a/bin/tests/data/faster_zipattrswith.nix b/bin/tests/data/faster_zipattrswith.nix new file mode 100644 index 0000000..2612995 --- /dev/null +++ b/bin/tests/data/faster_zipattrswith.nix @@ -0,0 +1,13 @@ +{ + # trivial case + _ = lib.zipAttrsWith (name: values: values) [{ a = 1; } { a = 2; b = 3; }]; + + # offer lint heuristically on this too + _ = nixpkgs.lib.zipAttrsWith (name: values: values) [{ a = 1; } { a = 2; b = 3; }]; + + # do not lint on `builtins` + _ = builtins.zipAttrsWith (name: values: values) [ + { a = 1; } + { a = 2; b = 3; } + ]; +} diff --git a/bin/tests/main.rs b/bin/tests/main.rs index 89d58e7..2c4b521 100644 --- a/bin/tests/main.rs +++ b/bin/tests/main.rs @@ -19,7 +19,7 @@ mod util { test_lint!($($tail)*); }; ($tname:ident) => { - test_lint!($tname => session_info!("2.5")); + test_lint!($tname => session_info!("2.6")); }; ($tname:ident => $sess:expr) => { #[test] @@ -61,5 +61,6 @@ test_lint! { unquoted_uri, deprecated_is_null, empty_inherit, - faster_groupby => session_info!("2.5") + faster_groupby => session_info!("2.5"), + faster_zipattrswith => session_info!("2.6") } diff --git a/bin/tests/snapshots/main__faster_zipattrswith.snap b/bin/tests/snapshots/main__faster_zipattrswith.snap new file mode 100644 index 0000000..6b21322 --- /dev/null +++ b/bin/tests/snapshots/main__faster_zipattrswith.snap @@ -0,0 +1,20 @@ +--- +source: bin/tests/main.rs +expression: "&out" + +--- +[W16] Warning: Found lib.zipAttrsWith + ╭─[data/faster_zipattrswith.nix:3:7] + │ + 3 │ _ = lib.zipAttrsWith (name: values: values) [{ a = 1; } { a = 2; b = 3; }]; + · ────────┬─────── + · ╰───────── Prefer builtins.zipAttrsWith over lib.zipAttrsWith +───╯ +[W16] Warning: Found lib.zipAttrsWith + ╭─[data/faster_zipattrswith.nix:6:7] + │ + 6 │ _ = nixpkgs.lib.zipAttrsWith (name: values: values) [{ a = 1; } { a = 2; b = 3; }]; + · ────────────┬─────────── + · ╰───────────── Prefer builtins.zipAttrsWith over nixpkgs.lib.zipAttrsWith +───╯ + 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