use syn::Item;
use syn::parse_file;
use syn::spanned::Spanned;
use crate::finding::model::registry_item::RegistryItem;
use crate::finding::model::registry_policy::RegistryPolicy;
use crate::finding::parsing::item_naming::ItemNaming;
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 {
let Some(kind) = Self::kind(item) else {
return format!("`{}`", ItemNaming::source_line(file, line));
};
let subject =
ItemNaming::identifier(item).unwrap_or_else(|| ItemNaming::source_line(file, line));
format!("the {kind} `{subject}`")
}
fn kind(item: &Item) -> Option<&'static str> {
match item {
Item::Const(_) => Some("constant"),
Item::Enum(_) => Some("enum"),
Item::Fn(_) => Some("function"),
Item::Impl(_) => Some("impl block"),
Item::Mod(_) => Some("inline module"),
Item::Static(_) => Some("static"),
Item::Struct(_) => Some("struct"),
Item::Trait(_) => Some("trait"),
Item::Type(_) => Some("type alias"),
Item::Use(_) => Some("import"),
_ => None,
}
}
}