new lint: faster_zipattrswith

This commit is contained in:
Akshay 2022-01-30 12:10:21 +05:30
parent effe06e2f1
commit a254edfcd2
5 changed files with 109 additions and 2 deletions

View File

@ -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; }
];
}

View File

@ -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")
}

View File

@ -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
───╯

View File

@ -16,4 +16,5 @@ lints! {
deprecated_is_null,
empty_inherit,
faster_groupby,
faster_zipattrswith,
}

View File

@ -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<Report> {
let lint_version = "2.6".parse::<Version>().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
}
}
}
}