new lint: manual_inherit

This commit is contained in:
Akshay 2021-10-02 13:39:11 +05:30
parent 088559eedd
commit c00900120d
5 changed files with 59 additions and 4 deletions

1
.gitignore vendored
View File

@ -1,3 +1,4 @@
/target
.envrc
.direnv
result

View File

@ -3,4 +3,5 @@ use crate::lint_map;
lint_map! {
bool_comparison,
empty_let_in,
manual_inherit,
}

View File

@ -3,8 +3,7 @@ use crate::{Lint, Metadata, Report, Rule, Suggestion};
use if_chain::if_chain;
use macros::lint;
use rnix::{
types::{LetIn, TypedNode,
EntryHolder},
types::{LetIn, TypedNode, EntryHolder},
NodeOrToken, SyntaxElement, SyntaxKind,
};

View File

@ -0,0 +1,43 @@
use crate::{make, Lint, Metadata, Report, Rule, Suggestion};
use if_chain::if_chain;
use macros::lint;
use rnix::{
types::{KeyValue, Ident, TypedNode, TokenWrapper},
NodeOrToken, SyntaxElement, SyntaxKind,
};
#[lint(
name = "manual inherit",
note = "Assignment instead of `inherit` keyword",
code = 3,
match_with = SyntaxKind::NODE_KEY_VALUE
)]
struct ManualInherit;
impl Rule for ManualInherit {
fn validate(&self, node: &SyntaxElement) -> Option<Report> {
if_chain! {
if let NodeOrToken::Node(key_value_node) = node;
if let Some(key_value_stmt) = KeyValue::cast(key_value_node.clone());
if let Some(key_path) = key_value_stmt.key();
if let Some(key_node) = key_path.path().next();
if let Some(key) = Ident::cast(key_node);
if let Some(value_node) = key_value_stmt.value();
if let Some(value) = Ident::cast(value_node);
if key.as_str() == value.as_str();
then {
let at = node.text_range();
let replacement = make::inherit_stmt(&[key]).node().clone();
let message = format!("The assignment `{}` is better written with `inherit`", node);
Some(Self::report().suggest(at, message, Suggestion::new(at, replacement)))
} else {
None
}
}
}
}

View File

@ -1,11 +1,13 @@
use rnix::{SyntaxNode, types::{TypedNode, self}};
use std::iter::IntoIterator;
use rnix::{SyntaxNode, types::{TypedNode, self, TokenWrapper}};
fn ast_from_text<N: TypedNode>(text: &str) -> N {
let parse = rnix::parse(text);
let node = match parse.node().descendants().find_map(N::cast) {
Some(it) => it,
None => {
panic!("Failed to make ast node `{}` from text {}", std::any::type_name::<N>(), text)
panic!("Failed to make ast node `{}` from text `{}`", std::any::type_name::<N>(), text)
}
};
node
@ -18,3 +20,12 @@ pub fn parenthesize(node: &SyntaxNode) -> types::Paren {
pub fn unary_not(node: &SyntaxNode) -> types::UnaryOp {
ast_from_text(&format!("!{}", node))
}
pub fn inherit_stmt<'a>(nodes: impl IntoIterator<Item = &'a types::Ident>) -> types::Inherit {
let inherited_idents = nodes
.into_iter()
.map(|i| i.as_str().to_owned())
.collect::<Vec<_>>()
.join(" ");
ast_from_text(&format!("{{ inherit {}; }}", inherited_idents))
}