aboutsummaryrefslogtreecommitdiff
path: root/lib/src/lints
diff options
context:
space:
mode:
Diffstat (limited to 'lib/src/lints')
-rw-r--r--lib/src/lints/legacy_let_syntax.rs55
1 files changed, 55 insertions, 0 deletions
diff --git a/lib/src/lints/legacy_let_syntax.rs b/lib/src/lints/legacy_let_syntax.rs
new file mode 100644
index 0000000..c5588e2
--- /dev/null
+++ b/lib/src/lints/legacy_let_syntax.rs
@@ -0,0 +1,55 @@
1use crate::{make, Lint, Metadata, Report, Rule, Suggestion};
2
3use if_chain::if_chain;
4use macros::lint;
5use rnix::{
6 types::{EntryHolder, Ident, Key, LegacyLet, TokenWrapper, TypedNode},
7 NodeOrToken, SyntaxElement, SyntaxKind,
8};
9
10#[lint(
11 name = "legacy let syntax",
12 note = "Using undocumented `let` syntax",
13 code = 5,
14 match_with = SyntaxKind::NODE_LEGACY_LET
15)]
16struct ManualInherit;
17
18impl Rule for ManualInherit {
19 fn validate(&self, node: &SyntaxElement) -> Option<Report> {
20 if_chain! {
21 if let NodeOrToken::Node(node) = node;
22 if let Some(legacy_let) = LegacyLet::cast(node.clone());
23
24 if legacy_let
25 .entries()
26 .find(|kv| matches!(kv.key(), Some(k) if key_is_ident(&k, "body")))
27 .is_some();
28
29 then {
30 let inherits = legacy_let.inherits();
31 let entries = legacy_let.entries();
32 let attrset = make::attrset(inherits, entries, true);
33 let parenthesized = make::parenthesize(&attrset.node());
34 let selected = make::select(parenthesized.node(), &make::ident("body").node());
35
36 let at = node.text_range();
37 let message = "Prefer `rec` over undocumented `let` syntax";
38 let replacement = selected.node().clone();
39
40 Some(Self::report().suggest(at, message, Suggestion::new(at, replacement)))
41 } else {
42 None
43 }
44 }
45 }
46}
47
48fn key_is_ident(key_path: &Key, ident: &str) -> bool {
49 if let Some(key_node) = key_path.path().next() {
50 if let Some(key) = Ident::cast(key_node) {
51 return key.as_str() == ident;
52 }
53 }
54 false
55}