mod bindings;
mod builder;
mod entries;
mod format;
mod patterns;
mod pure;
mod scope;
#[cfg(test)]
mod tests;
mod units;
mod usedonce;
use tree_sitter::Node;
use crate::abc::{AbcOffense, offense_at};
pub use builder::build;
pub use pure::never_used_offenses;
pub use scope::RustFile;
pub use usedonce::used_once_offenses;
fn skip_subtree(kind: &str) -> bool {
if matches!(
kind,
"type_arguments"
| "type_parameters"
| "where_clause"
| "trait_bounds"
| "attribute_item"
| "scoped_type_identifier"
| "metavariable"
| "line_comment"
| "scoped_identifier"
) {
return true;
}
kind.ends_with("_type") && kind != "type_cast_expression"
}
fn visit_units(fm: &RustFile, n: Node, f: &mut impl FnMut(Node, &str)) {
let is_fn = n.kind() == "function_item";
if is_fn && let Some(name_node) = n.child_by_field_name("name") {
f(n, fm.text(name_node));
}
let mut cursor = n.walk();
for child in n.children(&mut cursor) {
visit_units(fm, child, f);
}
}
fn score_unit(fm: &RustFile, unit: Node, name: &str) -> AbcOffense {
let calc = units::Calc::over(fm);
if let Some(body) = unit.child_by_field_name("body") {
let (a, b, c) = calc.score(body);
return offense_at(unit, name, a, b, c);
}
offense_at(unit, name, 0, 0, 0)
}
pub fn all_scores(fm: &RustFile) -> Vec<AbcOffense> {
let mut offenses = Vec::new();
visit_units(fm, fm.tree.root_node(), &mut |unit, name| {
if unit.child_by_field_name("body").is_some() {
offenses.push(score_unit(fm, unit, name));
}
});
offenses.sort_by_key(|o| (o.line, o.column));
offenses
}