rowan: 0.12 -> 0.15

This commit is contained in:
Astro 2023-04-15 00:39:26 +02:00
parent ea55361244
commit 8e2e6af26e
11 changed files with 172 additions and 182 deletions

49
Cargo.lock generated
View File

@ -72,15 +72,6 @@ version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
[[package]]
name = "cbitset"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "29b6ad25ae296159fb0da12b970b2fe179b234584d7cd294c891e2bbb284466b"
dependencies = [
"num-traits",
]
[[package]]
name = "cc"
version = "1.0.79"
@ -123,9 +114,9 @@ checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7"
[[package]]
name = "countme"
version = "2.0.4"
version = "3.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "328b822bdcba4d4e402be8d9adb6eebf269f969f8eadef977a553ff3c4fbcb58"
checksum = "7704b5fdd17b18ae31c4c1da5a2e0305a2bf17b5249300a9ee9ed7b72114c636"
[[package]]
name = "deadnix"
@ -163,9 +154,9 @@ dependencies = [
[[package]]
name = "hashbrown"
version = "0.9.1"
version = "0.12.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d7afe4a420e3fe79967a00898cc1f4db7c8a49a9333a29f8a4bd76a253d5cd04"
checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888"
[[package]]
name = "hermit-abi"
@ -216,38 +207,27 @@ checksum = "d59d8c75012853d2e872fb56bc8a2e53718e2cafe1a4c823143141c6d90c322f"
[[package]]
name = "memoffset"
version = "0.6.5"
version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5aa361d4faea93603064a027415f07bd8e1d5c88c9fbf68bf56a285428fd79ce"
dependencies = [
"autocfg",
]
[[package]]
name = "num-traits"
version = "0.2.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd"
checksum = "d61c719bcfbcf5d62b3a09efa6088de8c54bc0bfcd3ea7ae39fcc186108b8de1"
dependencies = [
"autocfg",
]
[[package]]
name = "rnix"
version = "0.10.2"
version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8024a523e8836f1a5d051203dc00d833357fee94e351b51348dfaeca5364daa9"
checksum = "bb35cedbeb70e0ccabef2a31bcff0aebd114f19566086300b8f42c725fc2cb5f"
dependencies = [
"cbitset",
"rowan",
"smol_str",
]
[[package]]
name = "rowan"
version = "0.12.6"
version = "0.15.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a1b36e449f3702f3b0c821411db1cbdf30fb451726a9456dce5dabcd44420043"
checksum = "64449cfef9483a475ed56ae30e2da5ee96448789fb2aa240a04beb6a055078bf"
dependencies = [
"countme",
"hashbrown",
@ -308,15 +288,6 @@ dependencies = [
"serde",
]
[[package]]
name = "smol_str"
version = "0.1.24"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fad6c857cbab2627dcf01ec85a623ca4e7dcb5691cbaa3d7fb7653671f0d09c9"
dependencies = [
"serde",
]
[[package]]
name = "strsim"
version = "0.10.0"

View File

@ -10,8 +10,8 @@ repository = "https://github.com/astro/deadnix.git"
documentation = "https://docs.rs/deadnix"
[dependencies]
rowan = "0.12" # dependency version of rnix-0.10.1
rnix = "0.10"
rowan = "0.15" # dependency version of rnix-0.11.0
rnix = "0.11"
clap = "4"
walkdir = "2"
ariadne = "0.1"

View File

@ -1,5 +1,5 @@
use rnix::{
types::{Ident, TokenWrapper},
ast::Ident,
NixLanguage,
};
use rowan::api::SyntaxNode;
@ -14,7 +14,8 @@ pub struct Binding {
impl PartialEq for Binding {
fn eq(&self, other: &Self) -> bool {
self.decl_node == other.decl_node && self.name.as_str() == other.name.as_str()
self.decl_node == other.decl_node &&
self.name.syntax().text() == other.name.syntax().text()
}
}
impl Eq for Binding {}

View File

@ -1,9 +1,8 @@
use crate::{binding::Binding, scope::Scope, usage};
use rnix::{
types::{TokenWrapper, TypedNode},
NixLanguage,
};
use rowan::api::SyntaxNode;
use rowan::{api::SyntaxNode, ast::AstNode};
use std::{
collections::{HashMap, HashSet},
fmt,
@ -17,7 +16,7 @@ pub struct DeadCode {
impl fmt::Display for DeadCode {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
write!(fmt, "Unused {}: {}", self.scope, self.binding.name.as_str())
write!(fmt, "Unused {}: {}", self.scope, self.binding.name)
}
}
@ -41,7 +40,7 @@ impl Settings {
}
let mut results = results.into_values().collect::<Vec<_>>();
results.sort_unstable_by_key(|result| result.binding.name.node().text_range().start());
results.sort_unstable_by_key(|result| result.binding.name.syntax().text_range().start());
results
}
@ -65,7 +64,7 @@ impl Settings {
// find if used anywhere
usage::find(&binding.name, &body)
})
|| self.no_underscore && binding.name.as_str().starts_with('_')
|| self.no_underscore && binding.name.syntax().text().char_at(0.into()) == Some('_')
|| self.no_lambda_pattern_names
&& scope.is_lambda_pattern_name(&binding.name))
{

View File

@ -1,10 +1,9 @@
#![cfg(test)]
use crate::dead_code::{DeadCode, Settings};
use rnix::types::TokenWrapper;
fn run(content: &str) -> Vec<DeadCode> {
let ast = rnix::parse(content);
let ast = rnix::Root::parse(content);
assert_eq!(0, ast.errors().len());
Settings {
@ -12,7 +11,7 @@ fn run(content: &str) -> Vec<DeadCode> {
no_lambda_pattern_names: false,
no_underscore: false,
}
.find_dead_code(&ast.node())
.find_dead_code(&ast.syntax())
}
#[test]
@ -31,39 +30,39 @@ fn let_in_alive_deep() {
fn let_in_dead() {
let results = run("let dead = 23; in false");
assert_eq!(1, results.len());
assert_eq!(results[0].binding.name.as_str(), "dead");
assert_eq!(results[0].binding.name.to_string(), "dead");
}
#[test]
fn let_in_dead_multi() {
let results = run("let dead1 = 23; dead2 = 5; dead3 = 42; in false");
assert_eq!(3, results.len());
assert_eq!(results[0].binding.name.as_str(), "dead1");
assert_eq!(results[1].binding.name.as_str(), "dead2");
assert_eq!(results[2].binding.name.as_str(), "dead3");
assert_eq!(results[0].binding.name.to_string(), "dead1");
assert_eq!(results[1].binding.name.to_string(), "dead2");
assert_eq!(results[2].binding.name.to_string(), "dead3");
}
#[test]
fn let_in_dead_multi_recursive() {
let results = run("let dead1 = dead2; dead2 = dead3; dead3 = 42; in false");
assert_eq!(3, results.len());
assert_eq!(results[0].binding.name.as_str(), "dead1");
assert_eq!(results[1].binding.name.as_str(), "dead2");
assert_eq!(results[2].binding.name.as_str(), "dead3");
assert_eq!(results[0].binding.name.to_string(), "dead1");
assert_eq!(results[1].binding.name.to_string(), "dead2");
assert_eq!(results[2].binding.name.to_string(), "dead3");
}
#[test]
fn let_in_dead_recursive() {
let results = run("let dead = dead; in false");
assert_eq!(1, results.len());
assert_eq!(results[0].binding.name.as_str(), "dead");
assert_eq!(results[0].binding.name.to_string(), "dead");
}
#[test]
fn let_in_shadowed() {
let results = run("let dead = true; in let dead = false; in dead");
assert_eq!(1, results.len());
assert_eq!(results[0].binding.name.as_str(), "dead");
assert_eq!(results[0].binding.name.to_string(), "dead");
}
#[test]
@ -76,16 +75,16 @@ fn let_in_inherit_alive() {
fn let_in_inherit_dead() {
let results = run("let inherit (alive) dead; in alive");
assert_eq!(1, results.len());
assert_eq!(results[0].binding.name.as_str(), "dead");
assert_eq!(results[0].binding.name.to_string(), "dead");
}
#[test]
fn let_in_inherit_dead_multi() {
let results = run("let inherit (grave) dead1 dead2 dead3; in false");
assert_eq!(3, results.len());
assert_eq!(results[0].binding.name.as_str(), "dead1");
assert_eq!(results[1].binding.name.as_str(), "dead2");
assert_eq!(results[2].binding.name.as_str(), "dead3");
assert_eq!(results[0].binding.name.to_string(), "dead1");
assert_eq!(results[1].binding.name.to_string(), "dead2");
assert_eq!(results[2].binding.name.to_string(), "dead3");
}
#[test]
@ -93,16 +92,16 @@ fn let_in_inherit_dead_recursive_multi() {
let results =
run("let inherit (grave) dead1; inherit (dead1) dead2; inherit (dead2) dead3; in false");
assert_eq!(3, results.len());
assert_eq!(results[0].binding.name.as_str(), "dead1");
assert_eq!(results[1].binding.name.as_str(), "dead2");
assert_eq!(results[2].binding.name.as_str(), "dead3");
assert_eq!(results[0].binding.name.to_string(), "dead1");
assert_eq!(results[1].binding.name.to_string(), "dead2");
assert_eq!(results[2].binding.name.to_string(), "dead3");
}
#[test]
fn let_in_inherit_shadowed() {
let results = run("let inherit (dead) dead; in let inherit (alive) dead; in dead");
assert_eq!(1, results.len());
assert_eq!(results[0].binding.name.as_str(), "dead");
assert_eq!(results[0].binding.name.to_string(), "dead");
}
#[test]
@ -121,14 +120,14 @@ fn lambda_arg_underscore() {
fn lambda_arg_dead() {
let results = run("dead: false");
assert_eq!(1, results.len());
assert_eq!(results[0].binding.name.as_str(), "dead");
assert_eq!(results[0].binding.name.to_string(), "dead");
}
#[test]
fn lambda_arg_shadowed() {
let results = run("dead: dead: dead");
assert_eq!(1, results.len());
assert_eq!(results[0].binding.name.as_str(), "dead");
assert_eq!(results[0].binding.name.to_string(), "dead");
}
#[test]
@ -147,14 +146,14 @@ fn lambda_at_pattern_alive() {
fn lambda_at_dead() {
let results = run("dead@{ ... }: false");
assert_eq!(1, results.len());
assert_eq!(results[0].binding.name.as_str(), "dead");
assert_eq!(results[0].binding.name.to_string(), "dead");
}
#[test]
fn lambda_at_shadowed() {
let results = run("dead@{ ... }: dead@{ ... }: dead");
assert_eq!(1, results.len());
assert_eq!(results[0].binding.name.as_str(), "dead");
assert_eq!(results[0].binding.name.to_string(), "dead");
}
#[test]
@ -167,43 +166,43 @@ fn lambda_pattern_alive() {
fn lambda_pattern_dead_ellipsis_alias() {
let results = run("alive@{ dead, ... }: alive");
assert_eq!(1, results.len());
assert_eq!(results[0].binding.name.as_str(), "dead");
assert_eq!(results[0].binding.name.to_string(), "dead");
}
#[test]
fn lambda_pattern_dead_simple() {
let results = run("{ dead }: false");
assert_eq!(1, results.len());
assert_eq!(results[0].binding.name.as_str(), "dead");
assert_eq!(results[0].binding.name.to_string(), "dead");
}
#[test]
fn lambda_pattern_alias() {
let results = run("{ dead }@args: args");
assert_eq!(1, results.len());
assert_eq!(results[0].binding.name.as_str(), "dead");
assert_eq!(results[0].binding.name.to_string(), "dead");
}
#[test]
fn lambda_pattern_shadowed() {
let results = run("{ dead, ... }: { dead, ... }: dead");
assert_eq!(1, results.len());
assert_eq!(results[0].binding.name.as_str(), "dead");
assert_eq!(results[0].binding.name.to_string(), "dead");
}
#[test]
fn looped() {
let results = run("let dead1 = dead2; dead2 = {}; in false");
assert_eq!(2, results.len());
assert_eq!(results[0].binding.name.as_str(), "dead1");
assert_eq!(results[1].binding.name.as_str(), "dead2");
assert_eq!(results[0].binding.name.to_string(), "dead1");
assert_eq!(results[1].binding.name.to_string(), "dead2");
}
#[test]
fn rec_attrset_shadowed() {
let results = run("let dead = false; in rec { dead = true; alive = dead; }");
assert_eq!(1, results.len());
assert_eq!(results[0].binding.name.as_str(), "dead");
assert_eq!(results[0].binding.name.to_string(), "dead");
}
#[test]

View File

@ -1,9 +1,9 @@
use crate::{dead_code::DeadCode, scope::Scope};
use rnix::{
types::{EntryHolder, Inherit, LetIn, TokenWrapper, TypedNode},
ast::{Inherit, LetIn, HasEntry},
NixLanguage, SyntaxKind,
};
use rowan::api::SyntaxNode;
use rowan::{api::SyntaxNode, ast::AstNode};
#[derive(Debug)]
struct Edit {
@ -44,9 +44,9 @@ pub fn edit_dead_code(original: &str, dead: impl Iterator<Item = DeadCode>) -> (
let edited = apply_edits(original, edits.iter());
// remove empty `let in`
let ast = rnix::parse(&edited);
let ast = rnix::Root::parse(&edited);
let mut let_in_edits = Vec::new();
remove_empty_scopes(&ast.node(), &mut let_in_edits);
remove_empty_scopes(&ast.syntax(), &mut let_in_edits);
if let_in_edits.is_empty() {
(edited, has_changes)
} else {
@ -63,11 +63,11 @@ fn dead_to_edit(dead_code: DeadCode) -> Option<Edit> {
match dead_code.scope {
Scope::LambdaPattern(pattern, _) => {
if pattern
.at()
.map_or(false, |at| *at.node() == dead_code.binding.decl_node)
.pat_bind()
.map_or(false, |at| at.ident().expect("at.ident").syntax() == &dead_code.binding.decl_node)
{
if let Some(pattern_bind_node) = pattern
.node()
.syntax()
.children()
.find(|child| child.kind() == SyntaxKind::NODE_PAT_BIND)
{
@ -85,7 +85,7 @@ fn dead_to_edit(dead_code: DeadCode) -> Option<Edit> {
replace_node = pattern_bind_node;
}
} else {
let mut tokens = pattern.node().children_with_tokens().skip_while(|node| {
let mut tokens = pattern.syntax().children_with_tokens().skip_while(|node| {
node.as_node()
.map_or(true, |node| *node != dead_code.binding.decl_node)
});
@ -105,28 +105,28 @@ fn dead_to_edit(dead_code: DeadCode) -> Option<Edit> {
}
Scope::LambdaArg(name, _) => {
replacement = Some(format!("_{}", name.as_str()));
replacement = Some(format!("_{}", name));
}
Scope::LetIn(let_in) => {
if let_in
.entries()
.any(|entry| *entry.node() == dead_code.binding.decl_node)
.attrpath_values()
.any(|entry| *entry.syntax() == dead_code.binding.decl_node)
{
replacement = Some(String::new());
} else if let Some(ident) = let_in
.inherits()
.flat_map(|inherit| {
inherit
.idents()
.filter(|ident| *ident.node() == dead_code.binding.decl_node)
.attrs()
.filter(|attr| attr.syntax() == &dead_code.binding.decl_node)
})
.next()
{
let range = ident.node().text_range();
let range = ident.syntax().text_range();
start = usize::from(range.start());
end = usize::from(range.end());
replace_node = ident.node().clone();
replace_node = ident.syntax().clone();
replacement = Some(String::new());
}
}
@ -157,11 +157,11 @@ fn remove_empty_scopes(node: &SyntaxNode<NixLanguage>, edits: &mut Vec<Edit>) {
let let_in = LetIn::cast(node.clone()).expect("LetIn::cast");
if let_in
.inherits()
.all(|inherit| inherit.idents().next().is_none())
&& let_in.entries().next().is_none()
.all(|inherit| inherit.attrs().next().is_none())
&& let_in.attrpath_values().next().is_none()
{
let start = usize::from(node.text_range().start());
let end = usize::from(let_in.body().expect("let_in.body").text_range().start());
let end = usize::from(let_in.body().expect("let_in.body").syntax().text_range().start());
edits.push(Edit {
start,
end,
@ -173,7 +173,7 @@ fn remove_empty_scopes(node: &SyntaxNode<NixLanguage>, edits: &mut Vec<Edit>) {
// remove empty `inherit;` and `inherit (...);` constructs
SyntaxKind::NODE_INHERIT => {
let inherit = Inherit::cast(node.clone()).expect("Inherit::cast");
if inherit.idents().next().is_none() {
if inherit.attrs().next().is_none() {
let mut start = usize::from(node.text_range().start());
// remove whitespace before node
if let Some(prev) = node.prev_sibling_or_token() {

View File

@ -3,7 +3,7 @@
use crate::dead_code::Settings;
fn run(content: &str) -> (String, bool) {
let ast = rnix::parse(content);
let ast = rnix::Root::parse(content);
assert_eq!(0, ast.errors().len());
let results = Settings {
@ -11,7 +11,7 @@ fn run(content: &str) -> (String, bool) {
no_lambda_pattern_names: false,
no_underscore: false,
}
.find_dead_code(&ast.node());
.find_dead_code(&ast.syntax());
crate::edit::edit_dead_code(content, results.into_iter())
}

View File

@ -213,7 +213,7 @@ fn main() {
}
};
let ast = rnix::parse(&content);
let ast = rnix::Root::parse(&content);
let errors = ast.errors();
if !errors.is_empty() {
@ -240,7 +240,7 @@ fn main() {
continue;
}
let results = settings.find_dead_code(&ast.node());
let results = settings.find_dead_code(&ast.syntax());
report_count += results.len();
if !quiet && !results.is_empty() {
match output_format {

View File

@ -1,6 +1,7 @@
use crate::dead_code::DeadCode;
use ariadne::{sources, Config, Label, Report, ReportKind};
use rnix::{types::TypedNode, TextSize};
use rnix::TextSize;
use rowan::ast::AstNode;
use std::env;
#[cfg(feature = "json-out")]
@ -10,7 +11,7 @@ use serde_json::json;
pub fn print(file: String, content: &str, results: &[DeadCode]) {
let no_color = env::var("NO_COLOR").is_ok();
let first_result_range = results[0].binding.name.node().text_range();
let first_result_range = results[0].binding.name.syntax().text_range();
let mut builder = Report::build(
ReportKind::Warning,
file.clone(),
@ -28,7 +29,7 @@ pub fn print(file: String, content: &str, results: &[DeadCode]) {
for result in results {
order -= 1;
let range = result.binding.name.node().text_range();
let range = result.binding.name.syntax().text_range();
let start_byte = usize::from(range.start());
while content_bytes < start_byte {
content_bytes += char_bytes.next().unwrap();
@ -71,7 +72,7 @@ pub fn print_json(file: &str, content: &str, results: &[DeadCode]) {
let json = json!({
"file": file,
"results": results.iter().map(|result| {
let range = result.binding.name.node().text_range();
let range = result.binding.name.syntax().text_range();
let start = usize::from(range.start());
let mut line_number = 0;
let mut line_offset = 0;

View File

@ -1,10 +1,10 @@
use crate::{binding::Binding, usage};
use ariadne::Color;
use rnix::{
types::{AttrSet, EntryHolder, Ident, Lambda, LetIn, Pattern, TokenWrapper, TypedNode},
ast::{AttrSet, Ident, Lambda, LetIn, Pattern, Param, HasEntry, Attr},
NixLanguage, SyntaxKind,
};
use rowan::api::SyntaxNode;
use rowan::{api::SyntaxNode, ast::AstNode};
use std::fmt;
/// AST subtree that declares variables
@ -33,18 +33,16 @@ impl Scope {
match node.kind() {
SyntaxKind::NODE_LAMBDA => {
let lambda = Lambda::cast(node.clone()).expect("Lambda::cast");
let arg = lambda.arg().expect("lambda.arg()");
let body = lambda.body().expect("lambda.body()");
match arg.kind() {
SyntaxKind::NODE_IDENT => {
let name = Ident::cast(arg).expect("Ident::cast");
Some(Scope::LambdaArg(name, body))
let param = lambda.param().expect("lambda.param()");
let body = lambda.body().expect("lambda.body()").syntax().clone();
match param {
Param::IdentParam(ident_param) => {
let name = ident_param.ident().expect("IdentParam.ident()");
Some(Scope::LambdaArg(name, body.clone()))
}
SyntaxKind::NODE_PATTERN => {
let pattern = Pattern::cast(arg).expect("Pattern::cast");
Param::Pattern(pattern) => {
Some(Scope::LambdaPattern(pattern, body))
}
_ => panic!("Unhandled arg kind: {:?}", arg.kind()),
}
}
@ -55,7 +53,7 @@ impl Scope {
SyntaxKind::NODE_ATTR_SET => {
let attr_set = AttrSet::cast(node.clone()).expect("AttrSet::cast");
if attr_set.recursive() {
if attr_set.rec_token().is_some() {
Some(Scope::RecAttrSet(attr_set))
} else {
None
@ -73,8 +71,8 @@ impl Scope {
pub fn is_lambda_pattern_name(&self, name: &Ident) -> bool {
if let Scope::LambdaPattern(pattern, _) = self {
pattern
.entries()
.any(|entry| entry.name().expect("entry.name").as_str() == name.as_str())
.pat_entries()
.any(|entry| entry.ident().expect("entry.ident").syntax().text() == name.syntax().text())
} else {
false
}
@ -85,25 +83,23 @@ impl Scope {
match self {
Scope::LambdaPattern(pattern, _) => Box::new(
pattern
.at()
.map(|name| {
let binding_node = name.node().clone();
Binding::new(name, binding_node.clone(), binding_node, true)
})
.pat_bind()
.and_then(|name| name.ident())
.map(|name| Binding::new(name.clone(), name.syntax().clone(), name.syntax().clone(), true))
.into_iter()
.chain(pattern.entries().map(move |entry| {
let name = entry.name().expect("entry.name");
Binding::new(name, entry.node().clone(), entry.node().clone(), true)
.chain(pattern.pat_entries().map(move |entry| {
let name = entry.ident().expect("entry.ident");
Binding::new(name, entry.syntax().clone(), entry.syntax().clone(), true)
})),
),
Scope::LambdaArg(name, _) => {
let mortal = !name.as_str().starts_with('_');
let mortal = name.syntax().text().char_at(0.into()) != Some('_');
Box::new(
Some(Binding::new(
name.clone(),
name.node().clone(),
name.node().clone(),
name.syntax().clone(),
name.syntax().clone(),
mortal,
))
.into_iter(),
@ -115,24 +111,34 @@ impl Scope {
.inherits()
.flat_map(|inherit| {
let body_node = if let Some(from) = inherit.from() {
from.node().clone()
from.syntax().clone()
} else {
inherit.node().clone()
inherit.syntax().clone()
};
inherit.idents().map(move |name| {
let name_node = name.node().clone();
Binding::new(name, body_node.clone(), name_node, true)
inherit.attrs().filter_map(move |attr|
match attr {
Attr::Ident(ident) => Some(ident),
_ => None,
}
).map(move |ident| {
Binding::new(
ident.clone(),
body_node.clone(),
ident.syntax().clone(),
true
)
})
})
.chain(let_in.entries().map(|entry| {
let key = entry
.key()
.expect("entry.key")
.path()
.next()
.expect("key.path.next");
let name = Ident::cast(key).expect("Ident::cast");
Binding::new(name, entry.node().clone(), entry.node().clone(), true)
.chain(let_in.attrpath_values().filter_map(|entry| {
let attrpath = entry.attrpath()
.expect("entry.attrpath");
match attrpath.attrs().next() {
Some(Attr::Ident(name)) =>
Some(
Binding::new(name, entry.syntax().clone(), entry.syntax().clone(), true)
),
_ => None,
}
})),
),
@ -140,29 +146,29 @@ impl Scope {
attr_set
.inherits()
.flat_map(|inherit| {
let binding_node = inherit.node().clone();
inherit.idents().map(move |name| {
let name_node = name.node().clone();
Binding::new(name, binding_node.clone(), name_node, false)
inherit.attrs().filter_map(move |attr| {
match attr {
Attr::Ident(ref name) =>
Some(
Binding::new(name.clone(), inherit.syntax().clone(), attr.syntax().clone(), false)
),
_ =>
None,
}
})
})
.chain(attr_set.entries().filter_map(|entry| {
.chain(attr_set.attrpath_values().filter_map(|entry| {
let key = entry
.key()
.expect("entry.key")
.path()
.next()
.expect("key.path.next");
if key.kind() == SyntaxKind::NODE_IDENT {
let name = Ident::cast(key).expect("Ident::cast");
Some(Binding::new(
name,
entry.node().clone(),
entry.node().clone(),
false,
))
} else {
None
.attrpath()
.expect("entry.attrpath")
.attrs()
.next();
match key {
Some(Attr::Ident(name)) =>
Some(
Binding::new(name, entry.syntax().clone(), entry.syntax().clone(), false)
),
_ => None,
}
})),
),
@ -176,8 +182,8 @@ impl Scope {
match self {
Scope::LambdaPattern(pattern, body) => Box::new(
pattern
.entries()
.map(|entry| entry.node().clone())
.pat_entries()
.map(|entry| entry.syntax().clone())
.chain(Some(body.clone()).into_iter()),
),
@ -186,16 +192,20 @@ impl Scope {
Scope::LetIn(let_in) => Box::new(
let_in
.inherits()
.filter_map(|inherit| inherit.from().map(|from| from.node().clone()))
.chain(let_in.entries().map(|entry| entry.node().clone()))
.chain(let_in.body()),
),
.filter_map(|inherit| inherit.from().map(|from| from.syntax().clone()))
.chain(
let_in.attrpath_values().map(|entry| entry.syntax().clone())
)
.chain(
let_in.body().map(|body| body.syntax().clone())
),
) },
Scope::RecAttrSet(attr_set) => Box::new(
attr_set
.inherits()
.map(|inherit| inherit.node().clone())
.chain(attr_set.entries().map(|entry| entry.node().clone())),
.map(|inherit| inherit.syntax().clone())
.chain(attr_set.attrpath_values().map(|entry| entry.syntax().clone())),
),
}
}
@ -211,15 +221,15 @@ impl Scope {
Scope::LetIn(let_in) => let_in.inherits().any(|inherit| {
inherit.from().map_or_else(
|| usage::find(name, inherit.node()),
|from| usage::find(name, from.node()),
|| usage::find(name, inherit.syntax()),
|from| usage::find(name, from.syntax()),
)
}),
Scope::RecAttrSet(attr_set) => attr_set.inherits().any(|inherit| {
inherit.from().map_or_else(
|| usage::find(name, inherit.node()),
|from| usage::find(name, from.node()),
|| usage::find(name, inherit.syntax()),
|from| usage::find(name, from.syntax()),
)
}),
}

View File

@ -1,9 +1,9 @@
use crate::scope::Scope;
use rnix::{
types::{Ident, TokenWrapper, TypedNode},
ast::Ident,
NixLanguage, SyntaxKind,
};
use rowan::api::SyntaxNode;
use rowan::{api::SyntaxNode, ast::AstNode};
/// find out if `name` is used in `node`
pub fn find(name: &Ident, node: &SyntaxNode<NixLanguage>) -> bool {
@ -13,7 +13,7 @@ pub fn find(name: &Ident, node: &SyntaxNode<NixLanguage>) -> bool {
}
for binding in scope.bindings() {
if binding.name.as_str() == name.as_str() {
if binding.name.syntax().text() == name.syntax().text() {
// shadowed by a a new child scope that redefines the
// variable with the same name
return false;
@ -21,8 +21,17 @@ pub fn find(name: &Ident, node: &SyntaxNode<NixLanguage>) -> bool {
}
}
if node.kind() == SyntaxKind::NODE_IDENT {
Ident::cast(node.clone()).expect("Ident::cast").as_str() == name.as_str()
let ident = if node.kind() == SyntaxKind::NODE_IDENT {
if let Some(ident) = Ident::cast(node.clone()) {
Some(ident)
} else {
None
}
} else {
None
};
if let Some(ident) = &ident {
ident.syntax().text() == name.syntax().text()
} else {
node.children().any(|node| find(name, &node))
}