From fc6409142e68335addc65763a1733526130256b0 Mon Sep 17 00:00:00 2001 From: Akshay Date: Sun, 3 Oct 2021 16:57:34 +0530 Subject: new lint: collapsible_let_in --- Cargo.lock | 1 + lib/Cargo.toml | 1 + lib/src/lib.rs | 8 ++--- lib/src/lints.rs | 1 + lib/src/lints/collapsible_let_in.rs | 60 +++++++++++++++++++++++++++++++++++++ lib/src/make.rs | 4 +++ 6 files changed, 71 insertions(+), 4 deletions(-) create mode 100644 lib/src/lints/collapsible_let_in.rs diff --git a/Cargo.lock b/Cargo.lock index bae8674..8b371ea 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -64,6 +64,7 @@ dependencies = [ "lazy_static", "macros", "rnix", + "rowan", ] [[package]] diff --git a/lib/Cargo.toml b/lib/Cargo.toml index e371c5d..e9e9e69 100644 --- a/lib/Cargo.toml +++ b/lib/Cargo.toml @@ -10,3 +10,4 @@ rnix = "0.9.0" if_chain = "1.0" macros = { path = "../macros" } lazy_static = "1.0" +rowan = "0.12.5" diff --git a/lib/src/lib.rs b/lib/src/lib.rs index f0f26dd..4065345 100644 --- a/lib/src/lib.rs +++ b/lib/src/lib.rs @@ -18,7 +18,7 @@ pub struct Report { } impl Report { - /// Construct a report. Do not invoke manually, see `lint` macro + /// Construct a report. Do not invoke `Report::new` manually, see `lint` macro pub fn new(note: &'static str, code: u32) -> Self { Self { note, @@ -27,7 +27,7 @@ impl Report { } } /// Add a diagnostic to this report - pub fn diagnostic(mut self, at: TextRange, message: String) -> Self { + pub fn diagnostic>(mut self, at: TextRange, message: S) -> Self { self.diagnostics.push(Diagnostic::new(at, message)); self } @@ -55,10 +55,10 @@ pub struct Diagnostic { impl Diagnostic { /// Construct a diagnostic. - pub fn new(at: TextRange, message: String) -> Self { + pub fn new>(at: TextRange, message: S) -> Self { Self { at, - message, + message: message.as_ref().into(), suggestion: None, } } diff --git a/lib/src/lints.rs b/lib/src/lints.rs index 98aa404..7da4933 100644 --- a/lib/src/lints.rs +++ b/lib/src/lints.rs @@ -6,4 +6,5 @@ lint_map! { manual_inherit, manual_inherit_from, legacy_let_syntax, + collapsible_let_in, } 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 @@ +use crate::{make, Lint, Metadata, Report, Rule, Suggestion}; + +use if_chain::if_chain; +use macros::lint; +use rowan::Direction; +use rnix::{ + types::{LetIn, TypedNode}, + NodeOrToken, SyntaxElement, SyntaxKind, TextRange +}; + +#[lint( + name = "collapsible let in", + note = "These let-in expressions are collapsible", + code = 6, + match_with = SyntaxKind::NODE_LET_IN +)] +struct CollapsibleLetIn; + +impl Rule for CollapsibleLetIn { + fn validate(&self, node: &SyntaxElement) -> Option { + if_chain! { + if let NodeOrToken::Node(node) = node; + if let Some(let_in_expr) = LetIn::cast(node.clone()); + if let Some(body) = let_in_expr.body(); + + if LetIn::cast(body.clone()).is_some(); + then { + let first_annotation = node.text_range(); + let first_message = "This let-in expression contains a nested let-in expression"; + + let second_annotation = body.text_range(); + let second_message = "This let-in expression is nested"; + + let replacement_at = { + let start = body + .siblings_with_tokens(Direction::Prev) + .find(|elem| elem.kind() == SyntaxKind::TOKEN_IN)? + .text_range() + .start(); + let end = body + .descendants_with_tokens() + .find(|elem| elem.kind() == SyntaxKind::TOKEN_LET)? + .text_range() + .end(); + TextRange::new(start, end) + }; + let replacement = make::empty().node().clone(); + + Some( + Self::report() + .diagnostic(first_annotation, first_message) + .suggest(second_annotation, second_message, Suggestion::new(replacement_at, replacement)) + ) + } else { + None + } + } + } +} + diff --git a/lib/src/make.rs b/lib/src/make.rs index 2a6450c..aec32d5 100644 --- a/lib/src/make.rs +++ b/lib/src/make.rs @@ -75,3 +75,7 @@ pub fn select(set: &SyntaxNode, index: &SyntaxNode) -> types::Select { pub fn ident(text: &str) -> types::Ident { ast_from_text(text) } + +pub fn empty() -> types::Root { + ast_from_text("") +} -- cgit v1.2.3