Lints and suggestions for the Nix programming language
1
fork

Configure Feed

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

at main 77 lines 1.8 kB view raw
1use crate::{Metadata, Report, Rule, Suggestion, make}; 2 3use macros::lint; 4use rnix::{ 5 NodeOrToken, SyntaxElement, SyntaxKind, 6 ast::{Attr, AttrpathValue, Expr}, 7}; 8use rowan::ast::AstNode as _; 9 10/// ## What it does 11/// Checks for bindings of the form `a = a`. 12/// 13/// ## Why is this bad? 14/// If the aim is to bring attributes from a larger scope into 15/// the current scope, prefer an inherit statement. 16/// 17/// ## Example 18/// 19/// ```nix 20/// let 21/// a = 2; 22/// in 23/// { a = a; b = 3; } 24/// ``` 25/// 26/// Try `inherit` instead: 27/// 28/// ```nix 29/// let 30/// a = 2; 31/// in 32/// { inherit a; b = 3; } 33/// ``` 34#[lint( 35 name = "manual_inherit", 36 note = "Assignment instead of inherit", 37 code = 3, 38 match_with = SyntaxKind::NODE_ATTRPATH_VALUE 39)] 40struct ManualInherit; 41 42impl Rule for ManualInherit { 43 fn validate(&self, node: &SyntaxElement) -> Option<Report> { 44 let NodeOrToken::Node(node) = node else { 45 return None; 46 }; 47 48 let attrpath_value = AttrpathValue::cast(node.clone())?; 49 let attrpath = attrpath_value.attrpath()?; 50 let mut attrs = attrpath.attrs(); 51 let first_attr = attrs.next()?; 52 53 if attrs.next().is_some() { 54 return None; 55 } 56 57 let Attr::Ident(key) = first_attr else { 58 return None; 59 }; 60 61 let Some(Expr::Ident(value)) = attrpath_value.value() else { 62 return None; 63 }; 64 65 if key.to_string() != value.to_string() { 66 return None; 67 } 68 69 let replacement = make::inherit_stmt(&[key]).syntax().clone(); 70 71 Some(self.report().suggest( 72 node.text_range(), 73 "This assignment is better written with `inherit`", 74 Suggestion::with_replacement(node.text_range(), replacement), 75 )) 76 } 77}