diff options
author | Akshay <[email protected]> | 2021-10-03 12:27:34 +0100 |
---|---|---|
committer | Akshay <[email protected]> | 2021-10-03 12:28:38 +0100 |
commit | fc6409142e68335addc65763a1733526130256b0 (patch) | |
tree | e39163c7705268645b4afcb042d1bc59faec80b9 /lib/src/lints | |
parent | c5c4b55c2b3a3fb824c3fd64e33bb30f1b011b71 (diff) |
new lint: collapsible_let_in
Diffstat (limited to 'lib/src/lints')
-rw-r--r-- | lib/src/lints/collapsible_let_in.rs | 60 |
1 files changed, 60 insertions, 0 deletions
diff --git a/lib/src/lints/collapsible_let_in.rs b/lib/src/lints/collapsible_let_in.rs new file mode 100644 index 0000000..c2cdf9b --- /dev/null +++ b/lib/src/lints/collapsible_let_in.rs | |||
@@ -0,0 +1,60 @@ | |||
1 | use crate::{make, Lint, Metadata, Report, Rule, Suggestion}; | ||
2 | |||
3 | use if_chain::if_chain; | ||
4 | use macros::lint; | ||
5 | use rowan::Direction; | ||
6 | use rnix::{ | ||
7 | types::{LetIn, TypedNode}, | ||
8 | NodeOrToken, SyntaxElement, SyntaxKind, TextRange | ||
9 | }; | ||
10 | |||
11 | #[lint( | ||
12 | name = "collapsible let in", | ||
13 | note = "These let-in expressions are collapsible", | ||
14 | code = 6, | ||
15 | match_with = SyntaxKind::NODE_LET_IN | ||
16 | )] | ||
17 | struct CollapsibleLetIn; | ||
18 | |||
19 | impl Rule for CollapsibleLetIn { | ||
20 | fn validate(&self, node: &SyntaxElement) -> Option<Report> { | ||
21 | if_chain! { | ||
22 | if let NodeOrToken::Node(node) = node; | ||
23 | if let Some(let_in_expr) = LetIn::cast(node.clone()); | ||
24 | if let Some(body) = let_in_expr.body(); | ||
25 | |||
26 | if LetIn::cast(body.clone()).is_some(); | ||
27 | then { | ||
28 | let first_annotation = node.text_range(); | ||
29 | let first_message = "This let-in expression contains a nested let-in expression"; | ||
30 | |||
31 | let second_annotation = body.text_range(); | ||
32 | let second_message = "This let-in expression is nested"; | ||
33 | |||
34 | let replacement_at = { | ||
35 | let start = body | ||
36 | .siblings_with_tokens(Direction::Prev) | ||
37 | .find(|elem| elem.kind() == SyntaxKind::TOKEN_IN)? | ||
38 | .text_range() | ||
39 | .start(); | ||
40 | let end = body | ||
41 | .descendants_with_tokens() | ||
42 | .find(|elem| elem.kind() == SyntaxKind::TOKEN_LET)? | ||
43 | .text_range() | ||
44 | .end(); | ||
45 | TextRange::new(start, end) | ||
46 | }; | ||
47 | let replacement = make::empty().node().clone(); | ||
48 | |||
49 | Some( | ||
50 | Self::report() | ||
51 | .diagnostic(first_annotation, first_message) | ||
52 | .suggest(second_annotation, second_message, Suggestion::new(replacement_at, replacement)) | ||
53 | ) | ||
54 | } else { | ||
55 | None | ||
56 | } | ||
57 | } | ||
58 | } | ||
59 | } | ||
60 | |||