aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAkshay <[email protected]>2022-01-30 06:40:21 +0000
committerAkshay <[email protected]>2022-01-30 06:40:21 +0000
commita254edfcd27f1bba5eb7eacb11bfcd077bd1af16 (patch)
tree6cf3eb3df65952b49f6539607741eca2e65ba149
parenteffe06e2f16f5b6faab258ff2b031dd5f14d59ec (diff)
new lint: faster_zipattrswith
-rw-r--r--bin/tests/data/faster_zipattrswith.nix13
-rw-r--r--bin/tests/main.rs5
-rw-r--r--bin/tests/snapshots/main__faster_zipattrswith.snap20
-rw-r--r--lib/src/lints.rs1
-rw-r--r--lib/src/lints/faster_zipattrswith.rs72
5 files changed, 109 insertions, 2 deletions
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 @@
1{
2 # trivial case
3 _ = lib.zipAttrsWith (name: values: values) [{ a = 1; } { a = 2; b = 3; }];
4
5 # offer lint heuristically on this too
6 _ = nixpkgs.lib.zipAttrsWith (name: values: values) [{ a = 1; } { a = 2; b = 3; }];
7
8 # do not lint on `builtins`
9 _ = builtins.zipAttrsWith (name: values: values) [
10 { a = 1; }
11 { a = 2; b = 3; }
12 ];
13}
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 {
19 test_lint!($($tail)*); 19 test_lint!($($tail)*);
20 }; 20 };
21 ($tname:ident) => { 21 ($tname:ident) => {
22 test_lint!($tname => session_info!("2.5")); 22 test_lint!($tname => session_info!("2.6"));
23 }; 23 };
24 ($tname:ident => $sess:expr) => { 24 ($tname:ident => $sess:expr) => {
25 #[test] 25 #[test]
@@ -61,5 +61,6 @@ test_lint! {
61 unquoted_uri, 61 unquoted_uri,
62 deprecated_is_null, 62 deprecated_is_null,
63 empty_inherit, 63 empty_inherit,
64 faster_groupby => session_info!("2.5") 64 faster_groupby => session_info!("2.5"),
65 faster_zipattrswith => session_info!("2.6")
65} 66}
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 @@
1---
2source: bin/tests/main.rs
3expression: "&out"
4
5---
6[W16] Warning: Found lib.zipAttrsWith
7 ╭─[data/faster_zipattrswith.nix:3:7]
8
9 3 │ _ = lib.zipAttrsWith (name: values: values) [{ a = 1; } { a = 2; b = 3; }];
10 · ────────┬───────
11 · ╰───────── Prefer builtins.zipAttrsWith over lib.zipAttrsWith
12───╯
13[W16] Warning: Found lib.zipAttrsWith
14 ╭─[data/faster_zipattrswith.nix:6:7]
15
16 6 │ _ = nixpkgs.lib.zipAttrsWith (name: values: values) [{ a = 1; } { a = 2; b = 3; }];
17 · ────────────┬───────────
18 · ╰───────────── Prefer builtins.zipAttrsWith over nixpkgs.lib.zipAttrsWith
19───╯
20
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! {
16 deprecated_is_null, 16 deprecated_is_null,
17 empty_inherit, 17 empty_inherit,
18 faster_groupby, 18 faster_groupby,
19 faster_zipattrswith,
19} 20}
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 @@
1use crate::{
2 make,
3 session::{SessionInfo, Version},
4 Metadata, Report, Rule, Suggestion,
5};
6
7use if_chain::if_chain;
8use macros::lint;
9use rnix::{
10 types::{Select, TypedNode},
11 NodeOrToken, SyntaxElement, SyntaxKind,
12};
13
14/// ## What it does
15/// Checks for `lib.zipAttrsWith`.
16///
17/// ## Why is this bad?
18/// Nix 2.6 introduces `builtins.zipAttrsWith` which is faster and does
19/// not require a lib import.
20///
21/// ## Example
22///
23/// ```nix
24/// lib.zipAttrsWith (name: values: values) [ {a = "x";} {a = "y"; b = "z";} ]
25/// # { a = ["x" "y"]; b = ["z"] }
26/// ```
27///
28/// Replace `lib.zipAttrsWith` with `builtins.zipAttrsWith`:
29///
30/// ```nix
31/// builtins.zipAttrsWith (name: values: values) [ {a = "x";} {a = "y"; b = "z";} ]
32/// ```
33#[lint(
34 name = "faster_zipattrswith",
35 note = "Found lib.zipAttrsWith",
36 code = 16,
37 match_with = SyntaxKind::NODE_SELECT
38)]
39struct FasterZipAttrsWith;
40
41impl Rule for FasterZipAttrsWith {
42 fn validate(&self, node: &SyntaxElement, sess: &SessionInfo) -> Option<Report> {
43 let lint_version = "2.6".parse::<Version>().unwrap();
44 if_chain! {
45 if sess.version() >= &lint_version;
46 if let NodeOrToken::Node(node) = node;
47 if let Some(select_expr) = Select::cast(node.clone());
48 if let Some(select_from) = select_expr.set();
49 if let Some(zip_attrs_with) = select_expr.index();
50
51 // a heuristic to lint on nixpkgs.lib.zipAttrsWith
52 // and lib.zipAttrsWith and its variants
53 if select_from.text().to_string() != "builtins";
54 if zip_attrs_with.text().to_string() == "zipAttrsWith";
55
56 then {
57 let at = node.text_range();
58 let replacement = {
59 let builtins = make::ident("builtins");
60 make::select(builtins.node(), &zip_attrs_with).node().clone()
61 };
62 let message = format!("Prefer `builtins.zipAttrsWith` over `{}.zipAttrsWith`", select_from);
63 Some(
64 self.report()
65 .suggest(at, message, Suggestion::new(at, replacement)),
66 )
67 } else {
68 None
69 }
70 }
71 }
72}