use syn::Item;
use syn::parse_file;
use syn::spanned::Spanned;
use crate::finding::registry_item::RegistryItem;
use crate::finding::registry_policy::RegistryPolicy;
use crate::source_file::SourceFile;
pub struct RegistryParser;
impl RegistryParser {
pub fn strays(file: &SourceFile, policy: RegistryPolicy) -> Option<Vec<RegistryItem>> {
let syntax = parse_file(&file.contents()).ok()?;
Some(
syntax
.items
.iter()
.filter(|item| !policy.is_declaration(item))
.map(|item| Self::stray(file, item))
.collect(),
)
}
fn stray(file: &SourceFile, item: &Item) -> RegistryItem {
let line = item.span().start().line;
RegistryItem::new(line, &Self::label(file, item, line))
}
fn label(file: &SourceFile, item: &Item, line: usize) -> String {
match item {
Item::Const(inner) => format!("the constant `{}`", inner.ident),
Item::Enum(inner) => format!("the enum `{}`", inner.ident),
Item::Fn(inner) => format!("the function `{}`", inner.sig.ident),
Item::Impl(_) => format!("the impl block `{}`", Self::source_line(file, line)),
Item::Mod(inner) => format!("the inline module `{}`", inner.ident),
Item::Static(inner) => format!("the static `{}`", inner.ident),
Item::Struct(inner) => format!("the struct `{}`", inner.ident),
Item::Trait(inner) => format!("the trait `{}`", inner.ident),
Item::Type(inner) => format!("the type alias `{}`", inner.ident),
Item::Use(_) => format!("the import `{}`", Self::source_line(file, line)),
_ => format!("`{}`", Self::source_line(file, line)),
}
}
fn source_line(file: &SourceFile, line: usize) -> String {
file.lines()
.get(line.saturating_sub(1))
.map_or_else(String::new, |text| text.trim().to_string())
}
}