pub mod boilerplate;
pub(crate) mod call_targets;
pub mod dead_code;
pub mod fragments;
pub mod functions;
pub mod match_patterns;
pub mod wildcards;
pub use boilerplate::BoilerplateFind;
pub use dead_code::{DeadCodeKind, DeadCodeWarning};
pub use fragments::FragmentGroup;
pub use functions::{DuplicateGroup, DuplicateKind};
use crate::adapters::shared::declared_function::DeclaredFunction;
use crate::adapters::shared::file_visitor::visit_all_files;
use crate::adapters::shared::normalize::NormalizedToken;
pub struct FunctionHashEntry {
pub name: String,
pub qualified_name: String,
pub file: String,
pub line: usize,
pub hash: u64,
pub token_count: usize,
pub tokens: Vec<NormalizedToken>,
}
pub(crate) fn collect_function_hashes(
parsed: &[(String, String, syn::File)],
config: &crate::config::sections::DuplicatesConfig,
) -> Vec<FunctionHashEntry> {
let mut collector = functions::FunctionCollector::new(config);
visit_all_files(parsed, &mut collector);
collector.entries
}
pub(crate) fn collect_declared_functions(
parsed: &[(String, String, syn::File)],
) -> Vec<DeclaredFunction> {
let mut collector = dead_code::DeclaredFnCollector::new();
visit_all_files(parsed, &mut collector);
collector.functions
}
pub(crate) use crate::adapters::shared::cfg_test::{has_cfg_test, has_test_attr};
fn has_allow_dead_code(attrs: &[syn::Attribute]) -> bool {
attrs
.iter()
.filter(|a| a.path().is_ident("allow"))
.any(allow_contains_dead_code)
}
fn allow_contains_dead_code(attr: &syn::Attribute) -> bool {
attr.parse_args_with(syn::punctuated::Punctuated::<syn::Path, syn::Token![,]>::parse_terminated)
.is_ok_and(|paths| paths.iter().any(|p| p.is_ident("dead_code")))
}
fn qualify_name(parent: &Option<String>, name: &str) -> String {
parent
.as_ref()
.map_or_else(|| name.to_string(), |p| [p.as_str(), "::", name].concat())
}
#[cfg(test)]
mod tests;