Lints and suggestions for the Nix programming language
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

chore: rm if_chain dependency

Closes #100, closes #101

Co-authored-by: aviac <aviac@mailbox.org>

+438 -480
+1 -8
Cargo.lock
··· 1 1 # This file is automatically @generated by Cargo. 2 2 # It is not intended for manual editing. 3 - version = 3 3 + version = 4 4 4 5 5 [[package]] 6 6 name = "aho-corasick" ··· 235 235 ] 236 236 237 237 [[package]] 238 - name = "if_chain" 239 - version = "1.0.2" 240 - source = "registry+https://github.com/rust-lang/crates.io-index" 241 - checksum = "cb56e1aa765b4b4f3aadfab769793b7087bb03a4ea4920644a6d238e2df5b9ed" 242 - 243 - [[package]] 244 238 name = "ignore" 245 239 version = "0.4.18" 246 240 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 299 293 name = "lib" 300 294 version = "0.0.0" 301 295 dependencies = [ 302 - "if_chain", 303 296 "lazy_static", 304 297 "macros", 305 298 "rnix",
-1
Cargo.toml
··· 10 10 [workspace.dependencies] 11 11 ariadne = "0.1.3" 12 12 clap = "3.0.0-beta.4" 13 - if_chain = "1.0" 14 13 ignore = "0.4.18" 15 14 indexmap = "1.6.2" 16 15 insta = "1.8.0"
-1
lib/Cargo.toml
··· 7 7 # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 8 8 9 9 [dependencies] 10 - if_chain.workspace = true 11 10 lazy_static.workspace = true 12 11 macros.workspace = true 13 12 rnix.workspace = true
+43 -46
lib/src/lints/bool_comparison.rs
··· 1 1 use crate::{Metadata, Report, Rule, Suggestion, make, session::SessionInfo}; 2 2 3 - use if_chain::if_chain; 4 3 use macros::lint; 5 4 use rnix::{ 6 5 NodeOrToken, SyntaxElement, SyntaxKind, SyntaxNode, ··· 36 35 37 36 impl Rule for BoolComparison { 38 37 fn validate(&self, node: &SyntaxElement, _sess: &SessionInfo) -> Option<Report> { 39 - if_chain! { 40 - if let NodeOrToken::Node(node) = node; 41 - if let Some(bin_expr) = BinOp::cast(node.clone()); 42 - if let Some(lhs) = bin_expr.lhs(); 43 - if let Some(rhs) = bin_expr.rhs(); 44 - if let Some(op) = bin_expr.operator(); 45 - 46 - if let BinOpKind::Equal | BinOpKind::NotEqual = op; 38 + if let NodeOrToken::Node(node) = node 39 + && let Some(bin_expr) = BinOp::cast(node.clone()) 40 + && let Some(lhs) = bin_expr.lhs() 41 + && let Some(rhs) = bin_expr.rhs() 42 + && let Some(op) = bin_expr.operator() 43 + && let BinOpKind::Equal | BinOpKind::NotEqual = op 44 + { 47 45 let (non_bool_side, bool_side) = if boolean_ident(&lhs).is_some() { 48 46 (rhs, lhs) 49 47 } else if boolean_ident(&rhs).is_some() { 50 48 (lhs, rhs) 51 49 } else { 52 - return None 50 + return None; 53 51 }; 54 - then { 55 - let at = node.text_range(); 56 - let replacement = { 57 - match (boolean_ident(&bool_side).unwrap(), op == BinOpKind::Equal) { 58 - (NixBoolean::True, true) | (NixBoolean::False, false) => { 59 - // `a == true`, `a != false` replace with just `a` 60 - non_bool_side.clone() 61 - }, 62 - (NixBoolean::True, false) | (NixBoolean::False, true) => { 63 - // `a != true`, `a == false` replace with `!a` 64 - match non_bool_side.kind() { 65 - SyntaxKind::NODE_APPLY 66 - | SyntaxKind::NODE_PAREN 67 - | SyntaxKind::NODE_IDENT => { 68 - // do not parenthsize the replacement 52 + let at = node.text_range(); 53 + let replacement = { 54 + match (boolean_ident(&bool_side).unwrap(), op == BinOpKind::Equal) { 55 + (NixBoolean::True, true) | (NixBoolean::False, false) => { 56 + // `a == true`, `a != false` replace with just `a` 57 + non_bool_side.clone() 58 + } 59 + (NixBoolean::True, false) | (NixBoolean::False, true) => { 60 + // `a != true`, `a == false` replace with `!a` 61 + match non_bool_side.kind() { 62 + SyntaxKind::NODE_APPLY 63 + | SyntaxKind::NODE_PAREN 64 + | SyntaxKind::NODE_IDENT => { 65 + // do not parenthsize the replacement 66 + make::unary_not(&non_bool_side).node().clone() 67 + } 68 + SyntaxKind::NODE_BIN_OP => { 69 + let inner = BinOp::cast(non_bool_side.clone()).unwrap(); 70 + // `!a ? b`, no paren required 71 + if inner.operator()? == BinOpKind::IsSet { 69 72 make::unary_not(&non_bool_side).node().clone() 70 - }, 71 - SyntaxKind::NODE_BIN_OP => { 72 - let inner = BinOp::cast(non_bool_side.clone()).unwrap(); 73 - // `!a ? b`, no paren required 74 - if inner.operator()? == BinOpKind::IsSet { 75 - make::unary_not(&non_bool_side).node().clone() 76 - } else { 77 - let parens = make::parenthesize(&non_bool_side); 78 - make::unary_not(parens.node()).node().clone() 79 - } 80 - }, 81 - _ => { 73 + } else { 82 74 let parens = make::parenthesize(&non_bool_side); 83 75 make::unary_not(parens.node()).node().clone() 84 76 } 85 77 } 86 - }, 78 + _ => { 79 + let parens = make::parenthesize(&non_bool_side); 80 + make::unary_not(parens.node()).node().clone() 81 + } 82 + } 87 83 } 88 - }; 89 - let message = format!( 90 - "Comparing `{non_bool_side}` with boolean literal `{bool_side}`" 91 - ); 92 - Some(self.report().suggest(at, message, Suggestion::new(at, replacement))) 93 - } else { 94 - None 95 - } 84 + } 85 + }; 86 + let message = format!("Comparing `{non_bool_side}` with boolean literal `{bool_side}`"); 87 + Some( 88 + self.report() 89 + .suggest(at, message, Suggestion::new(at, replacement)), 90 + ) 91 + } else { 92 + None 96 93 } 97 94 } 98 95 }
+20 -23
lib/src/lints/bool_simplification.rs
··· 1 1 use crate::{Metadata, Report, Rule, Suggestion, make, session::SessionInfo}; 2 2 3 - use if_chain::if_chain; 4 3 use macros::lint; 5 4 use rnix::{ 6 5 NodeOrToken, SyntaxElement, SyntaxKind, ··· 33 32 34 33 impl Rule for BoolSimplification { 35 34 fn validate(&self, node: &SyntaxElement, _sess: &SessionInfo) -> Option<Report> { 36 - if_chain! { 37 - if let NodeOrToken::Node(node) = node; 38 - if let Some(unary_expr) = UnaryOp::cast(node.clone()); 39 - if unary_expr.operator() == UnaryOpKind::Invert; 40 - if let Some(value_expr) = unary_expr.value(); 41 - if let Some(paren_expr) = Paren::cast(value_expr); 42 - if let Some(inner_expr) = paren_expr.inner(); 43 - if let Some(bin_expr) = BinOp::cast(inner_expr); 44 - if let Some(BinOpKind::Equal) = bin_expr.operator(); 45 - then { 46 - let at = node.text_range(); 47 - let message = "Try `!=` instead of `!(... == ...)`"; 35 + if let NodeOrToken::Node(node) = node 36 + && let Some(unary_expr) = UnaryOp::cast(node.clone()) 37 + && unary_expr.operator() == UnaryOpKind::Invert 38 + && let Some(value_expr) = unary_expr.value() 39 + && let Some(paren_expr) = Paren::cast(value_expr) 40 + && let Some(inner_expr) = paren_expr.inner() 41 + && let Some(bin_expr) = BinOp::cast(inner_expr) 42 + && let Some(BinOpKind::Equal) = bin_expr.operator() 43 + { 44 + let at = node.text_range(); 45 + let message = "Try `!=` instead of `!(... == ...)`"; 48 46 49 - let lhs = bin_expr.lhs()?; 50 - let rhs = bin_expr.rhs()?; 51 - let replacement = make::binary(&lhs, "!=", &rhs).node().clone(); 52 - Some( 53 - self.report() 54 - .suggest(at, message, Suggestion::new(at, replacement)), 55 - ) 56 - } else { 57 - None 58 - } 47 + let lhs = bin_expr.lhs()?; 48 + let rhs = bin_expr.rhs()?; 49 + let replacement = make::binary(&lhs, "!=", &rhs).node().clone(); 50 + Some( 51 + self.report() 52 + .suggest(at, message, Suggestion::new(at, replacement)), 53 + ) 54 + } else { 55 + None 59 56 } 60 57 } 61 58 }
+34 -34
lib/src/lints/collapsible_let_in.rs
··· 1 1 use crate::{Metadata, Report, Rule, Suggestion, make, session::SessionInfo}; 2 2 3 - use if_chain::if_chain; 4 3 use macros::lint; 5 4 use rnix::{ 6 5 NodeOrToken, SyntaxElement, SyntaxKind, TextRange, ··· 46 45 47 46 impl Rule for CollapsibleLetIn { 48 47 fn validate(&self, node: &SyntaxElement, _sess: &SessionInfo) -> Option<Report> { 49 - if_chain! { 50 - if let NodeOrToken::Node(node) = node; 51 - if let Some(let_in_expr) = LetIn::cast(node.clone()); 52 - if let Some(body) = let_in_expr.body(); 48 + if let NodeOrToken::Node(node) = node 49 + && let Some(let_in_expr) = LetIn::cast(node.clone()) 50 + && let Some(body) = let_in_expr.body() 51 + && LetIn::cast(body.clone()).is_some() 52 + { 53 + let first_annotation = node.text_range(); 54 + let first_message = "This `let in` expression contains a nested `let in` expression"; 53 55 54 - if LetIn::cast(body.clone()).is_some(); 55 - then { 56 - let first_annotation = node.text_range(); 57 - let first_message = "This `let in` expression contains a nested `let in` expression"; 56 + let second_annotation = body.text_range(); 57 + let second_message = "This `let in` expression is nested"; 58 58 59 - let second_annotation = body.text_range(); 60 - let second_message = "This `let in` expression is nested"; 59 + let replacement_at = { 60 + let start = body 61 + .siblings_with_tokens(Direction::Prev) 62 + .find(|elem| elem.kind() == SyntaxKind::TOKEN_IN)? 63 + .text_range() 64 + .start(); 65 + let end = body 66 + .descendants_with_tokens() 67 + .find(|elem| elem.kind() == SyntaxKind::TOKEN_LET)? 68 + .text_range() 69 + .end(); 70 + TextRange::new(start, end) 71 + }; 72 + let replacement = make::empty().node().clone(); 61 73 62 - let replacement_at = { 63 - let start = body 64 - .siblings_with_tokens(Direction::Prev) 65 - .find(|elem| elem.kind() == SyntaxKind::TOKEN_IN)? 66 - .text_range() 67 - .start(); 68 - let end = body 69 - .descendants_with_tokens() 70 - .find(|elem| elem.kind() == SyntaxKind::TOKEN_LET)? 71 - .text_range() 72 - .end(); 73 - TextRange::new(start, end) 74 - }; 75 - let replacement = make::empty().node().clone(); 76 - 77 - Some( 78 - self.report() 79 - .diagnostic(first_annotation, first_message) 80 - .suggest(second_annotation, second_message, Suggestion::new(replacement_at, replacement)) 81 - ) 82 - } else { 83 - None 84 - } 74 + Some( 75 + self.report() 76 + .diagnostic(first_annotation, first_message) 77 + .suggest( 78 + second_annotation, 79 + second_message, 80 + Suggestion::new(replacement_at, replacement), 81 + ), 82 + ) 83 + } else { 84 + None 85 85 } 86 86 } 87 87 }
+12 -13
lib/src/lints/deprecated_to_path.rs
··· 1 1 use crate::{Metadata, Report, Rule, session::SessionInfo}; 2 2 3 - use if_chain::if_chain; 4 3 use macros::lint; 5 4 use rnix::{ 6 5 NodeOrToken, SyntaxElement, SyntaxKind, ··· 42 41 43 42 impl Rule for DeprecatedIsNull { 44 43 fn validate(&self, node: &SyntaxElement, _sess: &SessionInfo) -> Option<Report> { 45 - if_chain! { 46 - if let NodeOrToken::Node(node) = node; 47 - if let Some(apply) = Apply::cast(node.clone()); 48 - let lambda_path = apply.lambda()?.to_string(); 49 - if ALLOWED_PATHS.contains(&lambda_path.as_str()); 50 - then { 51 - let at = node.text_range(); 52 - let message = format!("`{lambda_path}` is deprecated, see `:doc builtins.toPath` within the REPL for more"); 53 - Some(self.report().diagnostic(at, message)) 54 - } else { 55 - None 56 - } 44 + if let NodeOrToken::Node(node) = node 45 + && let Some(apply) = Apply::cast(node.clone()) 46 + && let lambda_path = apply.lambda()?.to_string() 47 + && ALLOWED_PATHS.contains(&lambda_path.as_str()) 48 + { 49 + let at = node.text_range(); 50 + let message = format!( 51 + "`{lambda_path}` is deprecated, see `:doc builtins.toPath` within the REPL for more" 52 + ); 53 + Some(self.report().diagnostic(at, message)) 54 + } else { 55 + None 57 56 } 58 57 } 59 58 }
+15 -19
lib/src/lints/empty_inherit.rs
··· 1 1 use crate::{Metadata, Report, Rule, Suggestion, make, session::SessionInfo, utils}; 2 2 3 - use if_chain::if_chain; 4 3 use macros::lint; 5 4 use rnix::{ 6 5 NodeOrToken, SyntaxElement, SyntaxKind, ··· 30 29 31 30 impl Rule for EmptyInherit { 32 31 fn validate(&self, node: &SyntaxElement, _sess: &SessionInfo) -> Option<Report> { 33 - if_chain! { 34 - if let NodeOrToken::Node(node) = node; 35 - if let Some(inherit_stmt) = Inherit::cast(node.clone()); 36 - if inherit_stmt.from().is_none(); 37 - if inherit_stmt.idents().count() == 0; 38 - then { 39 - let at = node.text_range(); 40 - let replacement = make::empty().node().clone(); 41 - let replacement_at = utils::with_preceeding_whitespace(node); 42 - let message = "Remove this empty `inherit` statement"; 43 - Some( 44 - self 45 - .report() 46 - .suggest(at, message, Suggestion::new(replacement_at, replacement)) 47 - ) 48 - } else { 49 - None 50 - } 32 + if let NodeOrToken::Node(node) = node 33 + && let Some(inherit_stmt) = Inherit::cast(node.clone()) 34 + && inherit_stmt.from().is_none() 35 + && inherit_stmt.idents().count() == 0 36 + { 37 + let at = node.text_range(); 38 + let replacement = make::empty().node().clone(); 39 + let replacement_at = utils::with_preceeding_whitespace(node); 40 + let message = "Remove this empty `inherit` statement"; 41 + Some( 42 + self.report() 43 + .suggest(at, message, Suggestion::new(replacement_at, replacement)), 44 + ) 45 + } else { 46 + None 51 47 } 52 48 } 53 49 }
+19 -23
lib/src/lints/empty_let_in.rs
··· 1 1 use crate::{Metadata, Report, Rule, Suggestion, session::SessionInfo}; 2 2 3 - use if_chain::if_chain; 4 3 use macros::lint; 5 4 use rnix::{ 6 5 NodeOrToken, SyntaxElement, SyntaxKind, ··· 35 34 36 35 impl Rule for EmptyLetIn { 37 36 fn validate(&self, node: &SyntaxElement, _sess: &SessionInfo) -> Option<Report> { 38 - if_chain! { 39 - if let NodeOrToken::Node(node) = node; 40 - if let Some(let_in_expr) = LetIn::cast(node.clone()); 41 - let entries = let_in_expr.entries(); 42 - let inherits = let_in_expr.inherits(); 43 - 44 - if entries.count() == 0; 45 - if inherits.count() == 0; 46 - 47 - if let Some(body) = let_in_expr.body(); 48 - 37 + if let NodeOrToken::Node(node) = node 38 + && let Some(let_in_expr) = LetIn::cast(node.clone()) 39 + && let entries = let_in_expr.entries() 40 + && let inherits = let_in_expr.inherits() 41 + && entries.count() == 0 42 + && inherits.count() == 0 43 + && let Some(body) = let_in_expr.body() 44 + { 49 45 // ensure that the let-in-expr does not have comments 50 46 let has_comments = node 51 47 .children_with_tokens() 52 48 .any(|el| el.kind() == SyntaxKind::TOKEN_COMMENT); 53 - then { 54 - let at = node.text_range(); 55 - let replacement = body; 56 - let message = "This let-in expression has no entries"; 57 - Some(if has_comments { 58 - self.report().diagnostic(at, message) 59 - } else { 60 - self.report().suggest(at, message, Suggestion::new(at, replacement)) 61 - }) 49 + 50 + let at = node.text_range(); 51 + let replacement = body; 52 + let message = "This let-in expression has no entries"; 53 + Some(if has_comments { 54 + self.report().diagnostic(at, message) 62 55 } else { 63 - None 64 - } 56 + self.report() 57 + .suggest(at, message, Suggestion::new(at, replacement)) 58 + }) 59 + } else { 60 + None 65 61 } 66 62 } 67 63 }
+15 -18
lib/src/lints/empty_list_concat.rs
··· 1 1 use crate::{Metadata, Report, Rule, Suggestion, session::SessionInfo}; 2 2 3 - use if_chain::if_chain; 4 3 use macros::lint; 5 4 use rnix::{ 6 5 NodeOrToken, SyntaxElement, SyntaxKind, SyntaxNode, ··· 33 32 34 33 impl Rule for EmptyListConcat { 35 34 fn validate(&self, node: &SyntaxElement, _sess: &SessionInfo) -> Option<Report> { 36 - if_chain! { 37 - if let NodeOrToken::Node(node) = node; 38 - if let Some(bin_expr) = BinOp::cast(node.clone()); 39 - if let Some(lhs) = bin_expr.lhs(); 40 - if let Some(rhs) = bin_expr.rhs(); 41 - if let Some(op) = bin_expr.operator(); 42 - if let BinOpKind::Concat = op; 43 - then { 44 - let at = node.text_range(); 45 - let message = "Concatenation with the empty list, `[]`, is a no-op"; 46 - if is_empty_array(&lhs) { 47 - Some(self.report().suggest(at, message, Suggestion::new(at, rhs))) 48 - } else if is_empty_array(&rhs) { 49 - Some(self.report().suggest(at, message, Suggestion::new(at, lhs))) 50 - } else { 51 - None 52 - } 35 + if let NodeOrToken::Node(node) = node 36 + && let Some(bin_expr) = BinOp::cast(node.clone()) 37 + && let Some(lhs) = bin_expr.lhs() 38 + && let Some(rhs) = bin_expr.rhs() 39 + && let Some(op) = bin_expr.operator() 40 + && let BinOpKind::Concat = op 41 + { 42 + let at = node.text_range(); 43 + let message = "Concatenation with the empty list, `[]`, is a no-op"; 44 + if is_empty_array(&lhs) { 45 + Some(self.report().suggest(at, message, Suggestion::new(at, rhs))) 46 + } else if is_empty_array(&rhs) { 47 + Some(self.report().suggest(at, message, Suggestion::new(at, lhs))) 53 48 } else { 54 49 None 55 50 } 51 + } else { 52 + None 56 53 } 57 54 } 58 55 }
+25 -31
lib/src/lints/empty_pattern.rs
··· 1 1 use crate::{Metadata, Report, Rule, Suggestion, make, session::SessionInfo}; 2 2 3 - use if_chain::if_chain; 4 3 use macros::lint; 5 4 use rnix::{ 6 5 NodeOrToken, SyntaxElement, SyntaxKind, SyntaxNode, ··· 42 41 43 42 impl Rule for EmptyPattern { 44 43 fn validate(&self, node: &SyntaxElement, _sess: &SessionInfo) -> Option<Report> { 45 - if_chain! { 46 - if let NodeOrToken::Node(node) = node; 47 - if let Some(lambda_expr) = Lambda::cast(node.clone()); 48 - if let Some(arg) = lambda_expr.arg(); 49 - if let Some(body) = lambda_expr.body(); 50 - 51 - if let Some(pattern) = Pattern::cast(arg); 52 - 44 + if let NodeOrToken::Node(node) = node 45 + && let Some(lambda_expr) = Lambda::cast(node.clone()) 46 + && let Some(arg) = lambda_expr.arg() 47 + && let Some(body) = lambda_expr.body() 48 + && let Some(pattern) = Pattern::cast(arg) 53 49 // no patterns within `{ }` 54 - if pattern.entries().count() == 0; 50 + && pattern.entries().count() == 0 55 51 // pattern is not bound 56 - if pattern.at().is_none(); 57 - 52 + && pattern.at().is_none() 58 53 // not a nixos module 59 - if !is_module(&body); 60 - 61 - then { 62 - let at = pattern.node().text_range(); 63 - let message = "This pattern is empty, use `_` instead"; 64 - let replacement = make::ident("_").node().clone(); 65 - Some(self.report().suggest(at, message, Suggestion::new(at, replacement))) 66 - } else { 67 - None 68 - } 54 + && !is_module(&body) 55 + { 56 + let at = pattern.node().text_range(); 57 + let message = "This pattern is empty, use `_` instead"; 58 + let replacement = make::ident("_").node().clone(); 59 + Some( 60 + self.report() 61 + .suggest(at, message, Suggestion::new(at, replacement)), 62 + ) 63 + } else { 64 + None 69 65 } 70 66 } 71 67 } 72 68 73 69 fn is_module(body: &SyntaxNode) -> bool { 74 - if_chain! { 75 - if let Some(attr_set) = AttrSet::cast(body.clone()); 76 - if attr_set 70 + if let Some(attr_set) = AttrSet::cast(body.clone()) 71 + && attr_set 77 72 .entries() 78 73 .filter_map(|e| e.key()) 79 - .any(|k| k.node().to_string() == "imports"); 80 - then { 81 - true 82 - } else { 83 - false 84 - } 74 + .any(|k| k.node().to_string() == "imports") 75 + { 76 + true 77 + } else { 78 + false 85 79 } 86 80 }
+24 -34
lib/src/lints/eta_reduction.rs
··· 1 1 use crate::{Metadata, Report, Rule, Suggestion, session::SessionInfo}; 2 2 3 - use if_chain::if_chain; 4 3 use macros::lint; 5 4 use rnix::{ 6 5 NodeOrToken, SyntaxElement, SyntaxKind, SyntaxNode, ··· 43 42 44 43 impl Rule for EtaReduction { 45 44 fn validate(&self, node: &SyntaxElement, _sess: &SessionInfo) -> Option<Report> { 46 - if_chain! { 47 - if let NodeOrToken::Node(node) = node; 48 - if let Some(lambda_expr) = Lambda::cast(node.clone()); 49 - 50 - if let Some(arg_node) = lambda_expr.arg(); 51 - if let Some(arg) = Ident::cast(arg_node); 52 - 53 - if let Some(body_node) = lambda_expr.body(); 54 - if let Some(body) = Apply::cast(body_node); 55 - 56 - if let Some(value_node) = body.value(); 57 - if let Some(value) = Ident::cast(value_node); 58 - 59 - if arg.as_str() == value.as_str(); 60 - 61 - if let Some(lambda_node) = body.lambda(); 62 - if !mentions_ident(&arg, &lambda_node); 63 - // lambda body should be no more than a single Ident to 64 - // retain code readability 65 - if let Some(_) = Ident::cast(lambda_node); 66 - 67 - then { 68 - let at = node.text_range(); 69 - let replacement = body.lambda()?; 70 - let message = 71 - format!( 72 - "Found eta-reduction: `{}`", 73 - replacement.text() 74 - ); 75 - Some(self.report().suggest(at, message, Suggestion::new(at, replacement))) 76 - } else { 77 - None 78 - } 45 + if let NodeOrToken::Node(node) = node 46 + && let Some(lambda_expr) = Lambda::cast(node.clone()) 47 + && let Some(arg_node) = lambda_expr.arg() 48 + && let Some(arg) = Ident::cast(arg_node) 49 + && let Some(body_node) = lambda_expr.body() 50 + && let Some(body) = Apply::cast(body_node) 51 + && let Some(value_node) = body.value() 52 + && let Some(value) = Ident::cast(value_node) 53 + && arg.as_str() == value.as_str() 54 + && let Some(lambda_node) = body.lambda() 55 + && !mentions_ident(&arg, &lambda_node) 56 + // lambda body should be no more than a single Ident to 57 + // retain code readability 58 + && let Some(_) = Ident::cast(lambda_node) 59 + { 60 + let at = node.text_range(); 61 + let replacement = body.lambda()?; 62 + let message = format!("Found eta-reduction: `{}`", replacement.text()); 63 + Some( 64 + self.report() 65 + .suggest(at, message, Suggestion::new(at, replacement)), 66 + ) 67 + } else { 68 + None 79 69 } 80 70 } 81 71 }
+19 -21
lib/src/lints/legacy_let_syntax.rs
··· 1 1 use crate::{Metadata, Report, Rule, Suggestion, make, session::SessionInfo}; 2 2 3 - use if_chain::if_chain; 4 3 use macros::lint; 5 4 use rnix::{ 6 5 NodeOrToken, SyntaxElement, SyntaxKind, ··· 45 44 46 45 impl Rule for ManualInherit { 47 46 fn validate(&self, node: &SyntaxElement, _sess: &SessionInfo) -> Option<Report> { 48 - if_chain! { 49 - if let NodeOrToken::Node(node) = node; 50 - if let Some(legacy_let) = LegacyLet::cast(node.clone()); 51 - 52 - if legacy_let 47 + if let NodeOrToken::Node(node) = node 48 + && let Some(legacy_let) = LegacyLet::cast(node.clone()) 49 + && legacy_let 53 50 .entries() 54 - .any(|kv| matches!(kv.key(), Some(k) if key_is_ident(&k, "body"))); 51 + .any(|kv| matches!(kv.key(), Some(k) if key_is_ident(&k, "body"))) 52 + { 53 + let inherits = legacy_let.inherits(); 54 + let entries = legacy_let.entries(); 55 + let attrset = make::attrset(inherits, entries, true); 56 + let parenthesized = make::parenthesize(attrset.node()); 57 + let selected = make::select(parenthesized.node(), make::ident("body").node()); 55 58 56 - then { 57 - let inherits = legacy_let.inherits(); 58 - let entries = legacy_let.entries(); 59 - let attrset = make::attrset(inherits, entries, true); 60 - let parenthesized = make::parenthesize(attrset.node()); 61 - let selected = make::select(parenthesized.node(), make::ident("body").node()); 59 + let at = node.text_range(); 60 + let message = "Prefer `rec` over undocumented `let` syntax"; 61 + let replacement = selected.node().clone(); 62 62 63 - let at = node.text_range(); 64 - let message = "Prefer `rec` over undocumented `let` syntax"; 65 - let replacement = selected.node().clone(); 66 - 67 - Some(self.report().suggest(at, message, Suggestion::new(at, replacement))) 68 - } else { 69 - None 70 - } 63 + Some( 64 + self.report() 65 + .suggest(at, message, Suggestion::new(at, replacement)), 66 + ) 67 + } else { 68 + None 71 69 } 72 70 } 73 71 }
+19 -20
lib/src/lints/manual_inherit.rs
··· 1 1 use crate::{Metadata, Report, Rule, Suggestion, make, session::SessionInfo}; 2 2 3 - use if_chain::if_chain; 4 3 use macros::lint; 5 4 use rnix::{ 6 5 NodeOrToken, SyntaxElement, SyntaxKind, ··· 41 40 42 41 impl Rule for ManualInherit { 43 42 fn validate(&self, node: &SyntaxElement, _sess: &SessionInfo) -> Option<Report> { 44 - if_chain! { 45 - if let NodeOrToken::Node(node) = node; 46 - if let Some(key_value_stmt) = KeyValue::cast(node.clone()); 47 - if let mut key_path = key_value_stmt.key()?.path(); 48 - if let Some(key_node) = key_path.next(); 43 + if let NodeOrToken::Node(node) = node 44 + && let Some(key_value_stmt) = KeyValue::cast(node.clone()) 45 + && let mut key_path = key_value_stmt.key()?.path() 46 + && let Some(key_node) = key_path.next() 49 47 // ensure that path has exactly one component 50 - if key_path.next().is_none(); 51 - if let Some(key) = Ident::cast(key_node); 48 + && key_path.next().is_none() 49 + && let Some(key) = Ident::cast(key_node) 52 50 53 - if let Some(value_node) = key_value_stmt.value(); 54 - if let Some(value) = Ident::cast(value_node); 55 - 56 - if key.as_str() == value.as_str(); 51 + && let Some(value_node) = key_value_stmt.value() 52 + && let Some(value) = Ident::cast(value_node) 57 53 58 - then { 59 - let at = node.text_range(); 60 - let replacement = make::inherit_stmt(&[key]).node().clone(); 61 - let message = "This assignment is better written with `inherit`"; 62 - Some(self.report().suggest(at, message, Suggestion::new(at, replacement))) 63 - } else { 64 - None 65 - } 54 + && key.as_str() == value.as_str() 55 + { 56 + let at = node.text_range(); 57 + let replacement = make::inherit_stmt(&[key]).node().clone(); 58 + let message = "This assignment is better written with `inherit`"; 59 + Some( 60 + self.report() 61 + .suggest(at, message, Suggestion::new(at, replacement)), 62 + ) 63 + } else { 64 + None 66 65 } 67 66 } 68 67 }
+24 -27
lib/src/lints/manual_inherit_from.rs
··· 1 1 use crate::{Metadata, Report, Rule, Suggestion, make, session::SessionInfo}; 2 2 3 - use if_chain::if_chain; 4 3 use macros::lint; 5 4 use rnix::{ 6 5 NodeOrToken, SyntaxElement, SyntaxKind, ··· 41 40 42 41 impl Rule for ManualInherit { 43 42 fn validate(&self, node: &SyntaxElement, _sess: &SessionInfo) -> Option<Report> { 44 - if_chain! { 45 - if let NodeOrToken::Node(node) = node; 46 - if let Some(key_value_stmt) = KeyValue::cast(node.clone()); 47 - if let mut key_path = key_value_stmt.key()?.path(); 48 - if let Some(key_node) = key_path.next(); 43 + if let NodeOrToken::Node(node) = node 44 + && let Some(key_value_stmt) = KeyValue::cast(node.clone()) 45 + && let mut key_path = key_value_stmt.key()?.path() 46 + && let Some(key_node) = key_path.next() 49 47 // ensure that path has exactly one component 50 - if key_path.next().is_none(); 51 - if let Some(key) = Ident::cast(key_node); 52 - 53 - if let Some(value_node) = key_value_stmt.value(); 54 - if let Some(value) = Select::cast(value_node); 55 - if let Some(index_node) = value.index(); 56 - if let Some(index) = Ident::cast(index_node); 57 - 58 - if key.as_str() == index.as_str(); 59 - 60 - then { 61 - let at = node.text_range(); 62 - let replacement = { 63 - let set = value.set()?; 64 - make::inherit_from_stmt(&set, &[key]).node().clone() 65 - }; 66 - let message = "This assignment is better written with `inherit`"; 67 - Some(self.report().suggest(at, message, Suggestion::new(at, replacement))) 68 - } else { 69 - None 70 - } 48 + && key_path.next().is_none() 49 + && let Some(key) = Ident::cast(key_node) 50 + && let Some(value_node) = key_value_stmt.value() 51 + && let Some(value) = Select::cast(value_node) 52 + && let Some(index_node) = value.index() 53 + && let Some(index) = Ident::cast(index_node) 54 + && key.as_str() == index.as_str() 55 + { 56 + let at = node.text_range(); 57 + let replacement = { 58 + let set = value.set()?; 59 + make::inherit_from_stmt(&set, &[key]).node().clone() 60 + }; 61 + let message = "This assignment is better written with `inherit`"; 62 + Some( 63 + self.report() 64 + .suggest(at, message, Suggestion::new(at, replacement)), 65 + ) 66 + } else { 67 + None 71 68 } 72 69 } 73 70 }
+18 -17
lib/src/lints/redundant_pattern_bind.rs
··· 1 1 use crate::{Metadata, Report, Rule, Suggestion, session::SessionInfo}; 2 2 3 - use if_chain::if_chain; 4 3 use macros::lint; 5 4 use rnix::{ 6 5 NodeOrToken, SyntaxElement, SyntaxKind, ··· 36 35 37 36 impl Rule for RedundantPatternBind { 38 37 fn validate(&self, node: &SyntaxElement, _sess: &SessionInfo) -> Option<Report> { 39 - if_chain! { 40 - if let NodeOrToken::Node(node) = node; 41 - if let Some(pattern) = Pattern::cast(node.clone()); 38 + if let NodeOrToken::Node(node) = node 39 + && let Some(pattern) = Pattern::cast(node.clone()) 42 40 // no patterns within `{ }` 43 - if pattern.entries().count() == 0; 44 - 41 + && pattern.entries().count() == 0 45 42 // pattern is just ellipsis 46 - if pattern.ellipsis(); 47 - 43 + && pattern.ellipsis() 48 44 // pattern is bound 49 - if let Some(ident) = pattern.at(); 50 - then { 51 - let at = node.text_range(); 52 - let message = format!("This pattern bind is redundant, use `{}` instead", ident.as_str()); 53 - let replacement = ident.node().clone(); 54 - Some(self.report().suggest(at, message, Suggestion::new(at, replacement))) 55 - } else { 56 - None 57 - } 45 + && let Some(ident) = pattern.at() 46 + { 47 + let at = node.text_range(); 48 + let message = format!( 49 + "This pattern bind is redundant, use `{}` instead", 50 + ident.as_str() 51 + ); 52 + let replacement = ident.node().clone(); 53 + Some( 54 + self.report() 55 + .suggest(at, message, Suggestion::new(at, replacement)), 56 + ) 57 + } else { 58 + None 58 59 } 59 60 } 60 61 }
+46 -42
lib/src/lints/repeated_keys.rs
··· 2 2 3 3 use crate::{Metadata, Report, Rule, session::SessionInfo}; 4 4 5 - use if_chain::if_chain; 6 5 use macros::lint; 7 6 use rnix::{ 8 7 NodeOrToken, SyntaxElement, SyntaxKind, ··· 46 45 47 46 impl Rule for RepeatedKeys { 48 47 fn validate(&self, node: &SyntaxElement, _sess: &SessionInfo) -> Option<Report> { 49 - if_chain! { 50 - if let NodeOrToken::Node(node) = node; 51 - if let Some(key_value) = KeyValue::cast(node.clone()); 52 - if let Some(key) = key_value.key(); 53 - if let mut components = key.path(); 54 - if let Some(first_component) = components.next(); 55 - if let Some(first_component_ident) = Ident::cast(first_component); 48 + if let NodeOrToken::Node(node) = node 49 + && let Some(key_value) = KeyValue::cast(node.clone()) 50 + && let Some(key) = key_value.key() 51 + && let mut components = key.path() 52 + && let Some(first_component) = components.next() 53 + && let Some(first_component_ident) = Ident::cast(first_component) 56 54 // ensure that there are >1 components 57 - if components.next().is_some(); 58 - 59 - if let Some(parent_node) = node.parent(); 60 - if let Some(parent_attr_set) = AttrSet::cast(parent_node); 61 - 62 - if !parent_attr_set.recursive(); 63 - let occurrences = parent_attr_set.entries().filter_map(|kv_scrutinee| { 55 + && components.next().is_some() 56 + && let Some(parent_node) = node.parent() 57 + && let Some(parent_attr_set) = AttrSet::cast(parent_node) 58 + && !parent_attr_set.recursive() 59 + && let occurrences = parent_attr_set.entries().filter_map(|kv_scrutinee| { 64 60 let scrutinee_key = kv_scrutinee.key()?; 65 61 let mut kv_scrutinee_components = scrutinee_key.path(); 66 62 let kv_scrutinee_first_component = kv_scrutinee_components.next()?; ··· 76 72 } else { 77 73 None 78 74 } 79 - }).collect::<Vec<_>>(); 80 - 81 - if occurrences.first()?.0 == key.node().text_range(); 82 - if occurrences.len() >= 3; 83 - 84 - then { 85 - let mut iter = occurrences.into_iter(); 75 + }).collect::<Vec<_>>() 76 + && occurrences.first()?.0 == key.node().text_range() 77 + && occurrences.len() >= 3 78 + { 79 + let mut iter = occurrences.into_iter(); 86 80 87 - let (first_annotation, first_subkey) = iter.next().unwrap(); 88 - let first_message = format!("The key `{}` is first assigned here ...", first_component_ident.as_str()); 81 + let (first_annotation, first_subkey) = iter.next().unwrap(); 82 + let first_message = format!( 83 + "The key `{}` is first assigned here ...", 84 + first_component_ident.as_str() 85 + ); 89 86 90 - let (second_annotation, second_subkey) = iter.next().unwrap(); 91 - let second_message = "... repeated here ..."; 87 + let (second_annotation, second_subkey) = iter.next().unwrap(); 88 + let second_message = "... repeated here ..."; 92 89 93 - let (third_annotation, third_subkey) = iter.next().unwrap(); 94 - let third_message = { 95 - let remaining_occurrences = iter.count(); 96 - let mut message = match remaining_occurrences { 97 - 0 => "... and here.".to_string(), 98 - 1 => "... and here (`1` occurrence omitted).".to_string(), 99 - n => format!("... and here (`{n}` occurrences omitted)."), 100 - }; 101 - write!(message, " Try `{} = {{ {}=...; {}=...; {}=...; }}` instead.", first_component_ident.as_str(), first_subkey, second_subkey, third_subkey).unwrap(); 102 - message 90 + let (third_annotation, third_subkey) = iter.next().unwrap(); 91 + let third_message = { 92 + let remaining_occurrences = iter.count(); 93 + let mut message = match remaining_occurrences { 94 + 0 => "... and here.".to_string(), 95 + 1 => "... and here (`1` occurrence omitted).".to_string(), 96 + n => format!("... and here (`{n}` occurrences omitted)."), 103 97 }; 98 + write!( 99 + message, 100 + " Try `{} = {{ {}=...; {}=...; {}=...; }}` instead.", 101 + first_component_ident.as_str(), 102 + first_subkey, 103 + second_subkey, 104 + third_subkey 105 + ) 106 + .unwrap(); 107 + message 108 + }; 104 109 105 - Some( 106 - self.report() 110 + Some( 111 + self.report() 107 112 .diagnostic(first_annotation, first_message) 108 113 .diagnostic(second_annotation, second_message) 109 114 .diagnostic(third_annotation, third_message), 110 - ) 111 - } else { 112 - None 113 - } 115 + ) 116 + } else { 117 + None 114 118 } 115 119 } 116 120 }
+12 -12
lib/src/lints/unquoted_splice.rs
··· 1 1 use crate::{Metadata, Report, Rule, Suggestion, make, session::SessionInfo}; 2 2 3 - use if_chain::if_chain; 4 3 use macros::lint; 5 4 use rnix::{ 6 5 NodeOrToken, SyntaxElement, SyntaxKind, ··· 41 40 42 41 impl Rule for UnquotedSplice { 43 42 fn validate(&self, node: &SyntaxElement, _sess: &SessionInfo) -> Option<Report> { 44 - if_chain! { 45 - if let NodeOrToken::Node(node) = node; 46 - if Dynamic::cast(node.clone()).is_some(); 47 - then { 48 - let at = node.text_range(); 49 - let replacement = make::quote(node).node().clone(); 50 - let message = "Consider quoting this splice expression"; 51 - Some(self.report().suggest(at, message, Suggestion::new(at, replacement))) 52 - } else { 53 - None 54 - } 43 + if let NodeOrToken::Node(node) = node 44 + && Dynamic::cast(node.clone()).is_some() 45 + { 46 + let at = node.text_range(); 47 + let replacement = make::quote(node).node().clone(); 48 + let message = "Consider quoting this splice expression"; 49 + Some( 50 + self.report() 51 + .suggest(at, message, Suggestion::new(at, replacement)), 52 + ) 53 + } else { 54 + None 55 55 } 56 56 } 57 57 }
+11 -12
lib/src/lints/unquoted_uri.rs
··· 1 1 use crate::{Metadata, Report, Rule, Suggestion, make, session::SessionInfo}; 2 2 3 - use if_chain::if_chain; 4 3 use macros::lint; 5 4 use rnix::{NodeOrToken, SyntaxElement, SyntaxKind, types::TypedNode}; 6 5 ··· 47 46 48 47 impl Rule for UnquotedUri { 49 48 fn validate(&self, node: &SyntaxElement, _sess: &SessionInfo) -> Option<Report> { 50 - if_chain! { 51 - if let NodeOrToken::Token(token) = node; 52 - then { 53 - let parent_node = token.parent(); 54 - let at = token.text_range(); 55 - let replacement = make::quote(&parent_node).node().clone(); 56 - let message = "Consider quoting this URI expression"; 57 - Some(self.report().suggest(at, message, Suggestion::new(at, replacement))) 58 - } else { 59 - None 60 - } 49 + if let NodeOrToken::Token(token) = node { 50 + let parent_node = token.parent(); 51 + let at = token.text_range(); 52 + let replacement = make::quote(&parent_node).node().clone(); 53 + let message = "Consider quoting this URI expression"; 54 + Some( 55 + self.report() 56 + .suggest(at, message, Suggestion::new(at, replacement)), 57 + ) 58 + } else { 59 + None 61 60 } 62 61 } 63 62 }
+34 -37
lib/src/lints/useless_has_attr.rs
··· 1 1 use crate::{Metadata, Report, Rule, Suggestion, make, session::SessionInfo}; 2 2 3 - use if_chain::if_chain; 4 3 use macros::lint; 5 4 use rnix::{ 6 5 NodeOrToken, SyntaxElement, SyntaxKind, ··· 34 33 35 34 impl Rule for UselessHasAttr { 36 35 fn validate(&self, node: &SyntaxElement, _sess: &SessionInfo) -> Option<Report> { 37 - if_chain! { 38 - if let NodeOrToken::Node(node) = node; 39 - if let Some(if_else_expr) = IfElse::cast(node.clone()); 40 - if let Some(condition_expr) = if_else_expr.condition(); 41 - if let Some(default_expr) = if_else_expr.else_body(); 42 - if let Some(cond_bin_expr) = BinOp::cast(condition_expr); 43 - if let Some(BinOpKind::IsSet) = cond_bin_expr.operator(); 36 + if let NodeOrToken::Node(node) = node 37 + && let Some(if_else_expr) = IfElse::cast(node.clone()) 38 + && let Some(condition_expr) = if_else_expr.condition() 39 + && let Some(default_expr) = if_else_expr.else_body() 40 + && let Some(cond_bin_expr) = BinOp::cast(condition_expr) 41 + && let Some(BinOpKind::IsSet) = cond_bin_expr.operator() 44 42 45 43 // set ? attr_path 46 44 // ^^^--------------- lhs 47 45 // ^^^^^^^^^^--- rhs 48 - if let Some(set) = cond_bin_expr.lhs(); 49 - if let Some(attr_path) = cond_bin_expr.rhs(); 46 + && let Some(set) = cond_bin_expr.lhs() 47 + && let Some(attr_path) = cond_bin_expr.rhs() 50 48 51 49 // check if body of the `if` expression is of the form `set.attr_path` 52 - if let Some(body_expr) = if_else_expr.body(); 53 - if let Some(body_select_expr) = Select::cast(body_expr); 54 - let expected_body = make::select(&set, &attr_path); 50 + && let Some(body_expr) = if_else_expr.body() 51 + && let Some(body_select_expr) = Select::cast(body_expr) 52 + &&let expected_body = make::select(&set, &attr_path) 55 53 56 54 // text comparison will do for now 57 - if body_select_expr.node().text() == expected_body.node().text(); 58 - then { 59 - let at = node.text_range(); 60 - // `or` is tightly binding, we need to parenthesize non-literal exprs 61 - let default_with_parens = match default_expr.kind() { 62 - SyntaxKind::NODE_LIST 63 - | SyntaxKind::NODE_PAREN 64 - | SyntaxKind::NODE_STRING 65 - | SyntaxKind::NODE_ATTR_SET 66 - | SyntaxKind::NODE_IDENT 67 - | SyntaxKind::NODE_SELECT => default_expr, 68 - _ => make::parenthesize(&default_expr).node().clone(), 69 - }; 70 - let replacement = make::or_default(&set, &attr_path, &default_with_parens).node().clone(); 71 - let message = format!( 72 - "Consider using `{replacement}` instead of this `if` expression" 73 - ); 74 - Some( 75 - self.report() 76 - .suggest(at, message, Suggestion::new(at, replacement)), 77 - ) 78 - } else { 79 - None 80 - } 55 + && body_select_expr.node().text() == expected_body.node().text() 56 + { 57 + let at = node.text_range(); 58 + // `or` is tightly binding, we need to parenthesize non-literal exprs 59 + let default_with_parens = match default_expr.kind() { 60 + SyntaxKind::NODE_LIST 61 + | SyntaxKind::NODE_PAREN 62 + | SyntaxKind::NODE_STRING 63 + | SyntaxKind::NODE_ATTR_SET 64 + | SyntaxKind::NODE_IDENT 65 + | SyntaxKind::NODE_SELECT => default_expr, 66 + _ => make::parenthesize(&default_expr).node().clone(), 67 + }; 68 + let replacement = make::or_default(&set, &attr_path, &default_with_parens) 69 + .node() 70 + .clone(); 71 + let message = format!("Consider using `{replacement}` instead of this `if` expression"); 72 + Some( 73 + self.report() 74 + .suggest(at, message, Suggestion::new(at, replacement)), 75 + ) 76 + } else { 77 + None 81 78 } 82 79 } 83 80 }
+47 -41
lib/src/lints/useless_parens.rs
··· 1 1 use crate::{Diagnostic, Metadata, Report, Rule, Suggestion, session::SessionInfo}; 2 2 3 - use if_chain::if_chain; 4 3 use macros::lint; 5 4 use rnix::{ 6 5 NodeOrToken, SyntaxElement, SyntaxKind, ··· 46 45 47 46 impl Rule for UselessParens { 48 47 fn validate(&self, node: &SyntaxElement, _sess: &SessionInfo) -> Option<Report> { 49 - if_chain! { 50 - if let NodeOrToken::Node(node) = node; 51 - if let Some(parsed_type_node) = ParsedType::cast(node.clone()); 52 - 53 - if let Some(diagnostic) = do_thing(parsed_type_node); 54 - then { 55 - let mut report = self.report(); 56 - report.diagnostics.push(diagnostic); 57 - Some(report) 58 - } else { 59 - None 60 - } 48 + if let NodeOrToken::Node(node) = node 49 + && let Some(parsed_type_node) = ParsedType::cast(node.clone()) 50 + && let Some(diagnostic) = do_thing(parsed_type_node) 51 + { 52 + let mut report = self.report(); 53 + report.diagnostics.push(diagnostic); 54 + Some(report) 55 + } else { 56 + None 61 57 } 62 58 } 63 59 } 64 60 65 61 fn do_thing(parsed_type_node: ParsedType) -> Option<Diagnostic> { 66 62 match parsed_type_node { 67 - ParsedType::KeyValue(kv) => if_chain! { 68 - if let Some(value_node) = kv.value(); 69 - let value_range = value_node.text_range(); 70 - if let Some(value_in_parens) = Paren::cast(value_node); 71 - if let Some(inner) = value_in_parens.inner(); 72 - then { 63 + ParsedType::KeyValue(kv) => { 64 + if let Some(value_node) = kv.value() 65 + && let value_range = value_node.text_range() 66 + && let Some(value_in_parens) = Paren::cast(value_node) 67 + && let Some(inner) = value_in_parens.inner() 68 + { 73 69 let at = value_range; 74 70 let message = "Useless parentheses around value in binding"; 75 71 let replacement = inner; 76 - Some(Diagnostic::suggest(at, message, Suggestion::new(at, replacement))) 72 + Some(Diagnostic::suggest( 73 + at, 74 + message, 75 + Suggestion::new(at, replacement), 76 + )) 77 77 } else { 78 78 None 79 79 } 80 - }, 81 - ParsedType::LetIn(let_in) => if_chain! { 82 - if let Some(body_node) = let_in.body(); 83 - let body_range = body_node.text_range(); 84 - if let Some(body_as_parens) = Paren::cast(body_node); 85 - if let Some(inner) = body_as_parens.inner(); 86 - then { 80 + } 81 + ParsedType::LetIn(let_in) => { 82 + if let Some(body_node) = let_in.body() 83 + && let body_range = body_node.text_range() 84 + && let Some(body_as_parens) = Paren::cast(body_node) 85 + && let Some(inner) = body_as_parens.inner() 86 + { 87 87 let at = body_range; 88 88 let message = "Useless parentheses around body of `let` expression"; 89 89 let replacement = inner; 90 - Some(Diagnostic::suggest(at, message, Suggestion::new(at, replacement))) 90 + Some(Diagnostic::suggest( 91 + at, 92 + message, 93 + Suggestion::new(at, replacement), 94 + )) 91 95 } else { 92 96 None 93 97 } 94 - }, 95 - ParsedType::Paren(paren_expr) => if_chain! { 98 + } 99 + ParsedType::Paren(paren_expr) => { 96 100 let paren_expr_range = paren_expr.node().text_range(); 97 - if let Some(father_node) = paren_expr.node().parent(); 98 - 101 + if let Some(father_node) = paren_expr.node().parent() 99 102 // ensure that we don't lint inside let-in statements 100 103 // we already lint such cases in previous match stmt 101 - if KeyValue::cast(father_node.clone()).is_none(); 104 + && KeyValue::cast(father_node.clone()).is_none() 102 105 103 106 // ensure that we don't lint inside let-bodies 104 107 // if this primitive is a let-body, we have already linted it 105 - if LetIn::cast(father_node).is_none(); 108 + && LetIn::cast(father_node).is_none() 106 109 107 - if let Some(inner_node) = paren_expr.inner(); 108 - if let Some(parsed_inner) = ParsedType::cast(inner_node); 109 - if matches!( 110 + && let Some(inner_node) = paren_expr.inner() 111 + && let Some(parsed_inner) = ParsedType::cast(inner_node) 112 + && matches!( 110 113 parsed_inner, 111 114 ParsedType::List(_) 112 115 | ParsedType::Paren(_) ··· 114 117 | ParsedType::AttrSet(_) 115 118 | ParsedType::Select(_) 116 119 | ParsedType::Ident(_) 117 - ); 118 - then { 120 + ) { 119 121 let at = paren_expr_range; 120 122 let message = "Useless parentheses around primitive expression"; 121 123 let replacement = parsed_inner.node().clone(); 122 - Some(Diagnostic::suggest(at, message, Suggestion::new(at, replacement))) 124 + Some(Diagnostic::suggest( 125 + at, 126 + message, 127 + Suggestion::new(at, replacement), 128 + )) 123 129 } else { 124 130 None 125 131 } 126 - }, 132 + } 127 133 _ => None, 128 134 } 129 135 }