use std::path::PathBuf;
#[derive(Debug, Clone, Default)]
pub struct AnalysisContext {
pub file_path: PathBuf,
pub scope_stack: Vec<Scope>,
pub in_test_context: bool,
pub in_example: bool,
pub in_benchmark: bool,
pub current_function: Option<String>,
pub current_impl: Option<ImplContext>,
pub visibility: Visibility,
pub has_auth_indicators: bool,
}
impl AnalysisContext {
pub fn new(file_path: PathBuf) -> Self {
let path_context = PathContext::analyze(&file_path);
Self {
file_path,
in_test_context: path_context.is_test,
in_example: path_context.is_example,
in_benchmark: path_context.is_benchmark,
..Default::default()
}
}
pub fn push_scope(&mut self, scope: Scope) {
self.scope_stack.push(scope);
}
pub fn pop_scope(&mut self) -> Option<Scope> {
self.scope_stack.pop()
}
pub fn should_skip(&self) -> bool {
self.in_test_context || self.in_example || self.in_benchmark
}
}
#[derive(Debug, Clone, Default)]
pub struct PathContext {
pub components: Vec<String>,
pub is_test: bool,
pub is_example: bool,
pub is_benchmark: bool,
pub is_generated: bool,
}
impl PathContext {
pub fn analyze(path: &std::path::Path) -> Self {
let components: Vec<String> = path
.components()
.filter_map(|c| c.as_os_str().to_str())
.map(String::from)
.collect();
let is_test = components.iter().any(|c| {
c == "tests"
|| c == "test"
|| c.ends_with("_test.rs")
|| c.starts_with("test_")
|| c.ends_with("_test") || c.ends_with("_tests") });
let is_example = components
.iter()
.any(|c| c == "examples" || c == "example");
let is_benchmark = components.iter().any(|c| c == "benches" || c == "bench");
let is_generated = components
.iter()
.any(|c| c == "generated" || c == "target" || c.ends_with(".generated.rs"));
Self {
components,
is_test,
is_example,
is_benchmark,
is_generated,
}
}
}
#[derive(Debug, Clone)]
pub enum Scope {
Module(String),
TestModule,
Function(String),
TestFunction,
Impl(ImplContext),
TraitImpl {
trait_name: String,
for_type: String,
},
Block,
Closure,
MatchArm,
IfBlock,
Loop,
}
#[derive(Debug, Clone)]
pub struct ImplContext {
pub type_name: String,
pub trait_name: Option<String>,
}
#[derive(Debug, Clone, Default, PartialEq, Eq)]
pub enum Visibility {
#[default]
Private,
PubCrate,
PubSuper,
PubIn(String),
Public,
}
impl Visibility {
pub fn from_syn(vis: &syn::Visibility) -> Self {
match vis {
syn::Visibility::Public(_) => Self::Public,
syn::Visibility::Restricted(r) => {
let path = r
.path
.segments
.first()
.map(|s| s.ident.to_string())
.unwrap_or_default();
match path.as_str() {
"crate" => Self::PubCrate,
"super" => Self::PubSuper,
other => Self::PubIn(other.to_string()),
}
}
syn::Visibility::Inherited => Self::Private,
}
}
}