use crate::adapters::analyzers::architecture::call_parity_rule::bindings::strip_wrappers;
use crate::adapters::analyzers::architecture::call_parity_rule::local_symbols::FileScope;
use crate::adapters::analyzers::architecture::call_parity_rule::pub_fns_visibility::peel_to_inner_path;
use crate::adapters::shared::use_tree::{AliasMap, ScopedAliasMap};
use std::collections::{HashMap, HashSet};
fn ty(src: &str) -> syn::Type {
syn::parse_str(src).expect("parse type")
}
fn render(ty: &syn::Type) -> String {
use quote::ToTokens;
ty.to_token_stream().to_string()
}
#[test]
fn strip_wrappers_peels_parens_and_stdlib_owners() {
assert_eq!(render(strip_wrappers(&ty("(Box<Inner>)"))), "Inner");
assert_eq!(render(strip_wrappers(&ty("Plain"))), "Plain");
}
struct Scope {
alias_map: AliasMap,
aliases_per_scope: ScopedAliasMap,
local_symbols: HashSet<String>,
local_decl_scopes: HashMap<String, Vec<Vec<String>>>,
crate_roots: HashSet<String>,
}
impl Scope {
fn new() -> Self {
Self {
alias_map: HashMap::new(),
aliases_per_scope: ScopedAliasMap::new(),
local_symbols: HashSet::new(),
local_decl_scopes: HashMap::new(),
crate_roots: HashSet::new(),
}
}
fn file_scope(&self) -> FileScope<'_> {
FileScope {
path: "src/app/x.rs",
alias_map: &self.alias_map,
aliases_per_scope: &self.aliases_per_scope,
local_symbols: &self.local_symbols,
local_decl_scopes: &self.local_decl_scopes,
crate_root_modules: &self.crate_roots,
workspace_module_paths: None,
}
}
}
fn peel_leaf(src: &str) -> Option<String> {
let scope = Scope::new();
let wraps = HashSet::new();
peel_to_inner_path(&ty(src), &wraps, &scope.file_scope(), &[]).map(|tp| {
tp.path
.segments
.last()
.map(|s| s.ident.to_string())
.unwrap_or_default()
})
}
#[test]
fn peel_to_inner_path_unwraps_references_and_parens() {
assert_eq!(peel_leaf("&Inner").as_deref(), Some("Inner"), "reference");
assert_eq!(peel_leaf("(Inner)").as_deref(), Some("Inner"), "paren");
}
#[test]
fn peel_to_inner_path_peels_stdlib_wrapper_but_not_other_generics() {
assert_eq!(
peel_leaf("Box<Inner>").as_deref(),
Some("Inner"),
"Box peeled"
);
assert_eq!(
peel_leaf("Mutex<Inner>").as_deref(),
Some("Mutex"),
"non-transparent wrapper kept"
);
assert_eq!(
peel_leaf("::Box<Inner>").as_deref(),
Some("Inner"),
"::Box peeled via single-segment fallback"
);
assert_eq!(
peel_leaf("::Mutex<Inner>").as_deref(),
Some("Mutex"),
"::Mutex not peeled (single && is_stdlib_direct)"
);
assert_eq!(
peel_leaf("std::boxed::Box<Inner>").as_deref(),
Some("Inner"),
"explicit-std Box peeled"
);
assert_eq!(
peel_leaf("std::sync::Mutex<Inner>").as_deref(),
Some("Mutex"),
"explicit-std Mutex not peeled (explicit_stdlib && is_stdlib_direct)"
);
}