Lints and suggestions for the Nix programming language
1
fork

Configure Feed

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

new lint: empty_list_concat (#50)

`[] ++ something` should be reduced to just `something`

Simplify the check

Add unit tests

authored by

Stanisław Pitucha and committed by
GitHub
cd187b2b 9cb88dd5

+124 -1
+16
bin/tests/data/empty_list_concat.nix
··· 1 + [ 2 + # no match 3 + ([1 2] ++ [3 4]) 4 + 5 + # unnecessary left 6 + ([] ++ [1 2 3]) 7 + 8 + # unnecessary right 9 + ([1 2 3] ++ []) 10 + 11 + # collapses to a single array 12 + ([] ++ []) 13 + 14 + # multiple empties 15 + ([] ++ [] ++ []) 16 + ]
+2 -1
bin/tests/main.rs
··· 66 66 deprecated_to_path => session_info!("2.4"), 67 67 bool_simplification, 68 68 useless_has_attr, 69 - repeated_keys 69 + repeated_keys, 70 + empty_list_concat 70 71 }
+41
bin/tests/snapshots/main__empty_list_concat.snap
··· 1 + --- 2 + source: bin/tests/main.rs 3 + expression: "&out" 4 + 5 + --- 6 + [W23] Warning: Unnecessary concatenation with empty list 7 + ╭─[data/empty_list_concat.nix:6:4] 8 + 9 + 6 │ ([] ++ [1 2 3]) 10 + · ──────┬────── 11 + · ╰──────── Concatenation with the empty list, [], is a no-op 12 + ───╯ 13 + [W23] Warning: Unnecessary concatenation with empty list 14 + ╭─[data/empty_list_concat.nix:9:4] 15 + 16 + 9 │ ([1 2 3] ++ []) 17 + · ──────┬────── 18 + · ╰──────── Concatenation with the empty list, [], is a no-op 19 + ───╯ 20 + [W23] Warning: Unnecessary concatenation with empty list 21 + ╭─[data/empty_list_concat.nix:12:4] 22 + 23 + 12 │ ([] ++ []) 24 + · ────┬─── 25 + · ╰───── Concatenation with the empty list, [], is a no-op 26 + ────╯ 27 + [W23] Warning: Unnecessary concatenation with empty list 28 + ╭─[data/empty_list_concat.nix:15:4] 29 + 30 + 15 │ ([] ++ [] ++ []) 31 + · ───────┬────── 32 + · ╰──────── Concatenation with the empty list, [], is a no-op 33 + ────╯ 34 + [W23] Warning: Unnecessary concatenation with empty list 35 + ╭─[data/empty_list_concat.nix:15:4] 36 + 37 + 15 │ ([] ++ [] ++ []) 38 + · ────┬─── 39 + · ╰───── Concatenation with the empty list, [], is a no-op 40 + ────╯ 41 +
+1
lib/src/lints.rs
··· 21 21 bool_simplification, 22 22 useless_has_attr, 23 23 repeated_keys, 24 + empty_list_concat 24 25 }
+64
lib/src/lints/empty_list_concat.rs
··· 1 + use crate::{session::SessionInfo, Metadata, Report, Rule, Suggestion}; 2 + 3 + use if_chain::if_chain; 4 + use macros::lint; 5 + use rnix::{ 6 + types::{BinOp, BinOpKind, List, TypedNode}, 7 + NodeOrToken, SyntaxElement, SyntaxKind, SyntaxNode, 8 + }; 9 + 10 + /// ## What it does 11 + /// Checks for concatenations to empty lists 12 + /// 13 + /// ## Why is this bad? 14 + /// Concatenation with the empty list is a no-op. 15 + /// 16 + /// ## Example 17 + /// ```nix 18 + /// [] ++ something 19 + /// ``` 20 + /// 21 + /// Remove the operation: 22 + /// 23 + /// ```nix 24 + /// something 25 + /// ``` 26 + #[lint( 27 + name = "empty_list_concat", 28 + note = "Unnecessary concatenation with empty list", 29 + code = 23, 30 + match_with = SyntaxKind::NODE_BIN_OP 31 + )] 32 + struct EmptyListConcat; 33 + 34 + impl Rule for EmptyListConcat { 35 + 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 + } 53 + } else { 54 + None 55 + } 56 + } 57 + } 58 + } 59 + 60 + fn is_empty_array(node: &SyntaxNode) -> bool { 61 + List::cast(node.clone()) 62 + .map(|list| list.items().count() == 0) 63 + .unwrap_or_default() 64 + }