aboutsummaryrefslogtreecommitdiff
path: root/lib/src/lints/faster_groupby.rs
diff options
context:
space:
mode:
Diffstat (limited to 'lib/src/lints/faster_groupby.rs')
-rw-r--r--lib/src/lints/faster_groupby.rs72
1 files changed, 72 insertions, 0 deletions
diff --git a/lib/src/lints/faster_groupby.rs b/lib/src/lints/faster_groupby.rs
new file mode 100644
index 0000000..c496125
--- /dev/null
+++ b/lib/src/lints/faster_groupby.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.groupBy`.
16///
17/// ## Why is this bad?
18/// Nix 2.5 introduces `builtins.groupBy` which is faster and does
19/// not require a lib import.
20///
21/// ## Example
22///
23/// ```nix
24/// lib.groupBy (x: if x > 2 then "big" else "small") [ 1 2 3 4 5 6 ];
25/// # { big = [ 3 4 5 6 ]; small = [ 1 2 ]; }
26/// ```
27///
28/// Replace `lib.groupBy` with `builtins.groupBy`:
29///
30/// ```
31/// builtins.groupBy (x: if x > 2 then "big" else "small") [ 1 2 3 4 5 6 ];
32/// ```
33#[lint(
34 name = "faster_groupby",
35 note = "Found lib.groupBy",
36 code = 15,
37 match_with = SyntaxKind::NODE_SELECT
38)]
39struct FasterGroupBy;
40
41impl Rule for FasterGroupBy {
42 fn validate(&self, node: &SyntaxElement, sess: &SessionInfo) -> Option<Report> {
43 let lint_version = "nix (Nix) 2.5".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(group_by_attr) = select_expr.index();
50
51 // a heuristic to lint on nixpkgs.lib.groupBy
52 // and lib.groupBy and its variants
53 if select_from.text().to_string() != "builtins";
54 if group_by_attr.text().to_string() == "groupBy";
55
56 then {
57 let at = node.text_range();
58 let replacement = {
59 let builtins = make::ident("builtins");
60 make::select(builtins.node(), &group_by_attr).node().clone()
61 };
62 let message = format!("Prefer `builtins.groupBy` over `{}.groupBy`", select_from);
63 Some(
64 self.report()
65 .suggest(at, message, Suggestion::new(at, replacement)),
66 )
67 } else {
68 None
69 }
70 }
71 }
72}