use super::super::bindings::{
canonical_from_type, extract_let_binding, normalize_alias_expansion, CanonScope,
};
use super::super::local_symbols::{scope_for_local, FileScope};
use super::super::type_infer::resolve::{resolve_type, ResolveContext};
use super::super::type_infer::self_subst::substitute_bare_self;
use super::super::type_infer::{
extract_bindings, extract_for_bindings, infer_type, BindingLookup, CanonicalType, InferContext,
WorkspaceTypeIndex,
};
use super::{
bare, collect_pattern_idents, extract_pat_ident_name, method_unknown, parse_macro_tokens,
CanonicalCallCollector, CollectorBindings, FnContext,
};
use crate::adapters::analyzers::architecture::forbidden_rule::{
file_to_module_segments, resolve_to_crate_absolute_in,
};
use crate::adapters::shared::use_tree::AliasTarget;
use std::collections::{HashMap, HashSet};
use syn::spanned::Spanned;
impl<'a> CanonicalCallCollector<'a> {
pub(super) fn new(ctx: &'a FnContext<'a>) -> Self {
let self_type_canonical = ctx.self_type.as_ref().map(|segs| {
if segs.first().map(|s| s.as_str()) == Some("crate") {
return segs.clone();
}
let mut full = vec!["crate".to_string()];
full.extend(file_to_module_segments(ctx.file.path));
full.extend(ctx.mod_stack.iter().cloned());
full.extend_from_slice(segs);
full
});
Self {
file: ctx.file,
mod_stack: ctx.mod_stack,
self_type_canonical,
signature_params: ctx.signature_params.clone(),
generic_params: ctx.generic_params.clone(),
bindings: vec![HashMap::new()],
non_path_bindings: vec![HashMap::new()],
calls: HashSet::new(),
workspace_index: ctx.workspace_index,
workspace_files: ctx.workspace_files,
reexports: ctx.reexports,
}
}
pub(super) fn seed_signature_bindings(&mut self) {
if let Some(self_canonical) = self.self_type_canonical.clone() {
self.bindings[0].insert("self".to_string(), self_canonical);
}
let params = self.signature_params.clone();
for (name, ty) in ¶ms {
if self.workspace_index.is_some() {
self.seed_param_via_resolver(name, ty);
continue;
}
if let Some(canonical) = canonical_from_type(
ty,
self.file.alias_map,
self.file.local_symbols,
self.file.crate_root_modules,
self.file.path,
) {
self.bindings[0].insert(name.clone(), canonical);
}
}
}
pub(super) fn seed_param_via_resolver(&mut self, name: &str, ty: &syn::Type) {
match self.resolve_param_type(ty) {
CanonicalType::Path(segs) => {
self.bindings[0].insert(name.to_string(), segs);
}
CanonicalType::Opaque => {}
other => {
self.non_path_bindings[0].insert(name.to_string(), other);
}
}
}
pub(super) fn resolve_param_type(&self, ty: &syn::Type) -> CanonicalType {
let rctx = ResolveContext {
file: self.file,
mod_stack: self.mod_stack,
type_aliases: self.workspace_index.map(|w| &w.type_aliases),
transparent_wrappers: self.workspace_index.map(|w| &w.transparent_wrappers),
workspace_files: self.workspace_files,
alias_param_subs: None,
generic_params: Some(&self.generic_params),
reexports: self.reexports,
};
match self.self_type_canonical.as_deref() {
Some(impl_segs) => resolve_type(&substitute_bare_self(ty, impl_segs), &rctx),
None => resolve_type(ty, &rctx),
}
}
pub(super) fn enter_scope(&mut self) {
self.bindings.push(HashMap::new());
self.non_path_bindings.push(HashMap::new());
}
pub(super) fn exit_scope(&mut self) {
self.bindings.pop();
self.non_path_bindings.pop();
}
pub(super) fn current_scope_mut(&mut self) -> &mut HashMap<String, Vec<String>> {
if self.bindings.is_empty() {
self.bindings.push(HashMap::new());
}
let last = self.bindings.len() - 1;
&mut self.bindings[last]
}
pub(super) fn current_non_path_scope_mut(&mut self) -> &mut HashMap<String, CanonicalType> {
if self.non_path_bindings.is_empty() {
self.non_path_bindings.push(HashMap::new());
}
let last = self.non_path_bindings.len() - 1;
&mut self.non_path_bindings[last]
}
pub(super) fn install_path_binding(&mut self, name: String, segs: Vec<String>) {
self.current_non_path_scope_mut().remove(&name);
self.current_scope_mut().insert(name, segs);
}
pub(super) fn install_non_path_binding(&mut self, name: String, ty: CanonicalType) {
self.current_scope_mut().remove(&name);
self.current_non_path_scope_mut().insert(name, ty);
}
pub(super) fn install_closure_param(&mut self, pat: &syn::Pat) {
if let syn::Pat::Type(pt) = pat {
if let Some(name) = extract_pat_ident_name(pt.pat.as_ref()) {
match self.resolve_param_type(&pt.ty) {
CanonicalType::Path(segs) => self.install_path_binding(name, segs),
other => self.install_non_path_binding(name, other),
}
return;
}
}
let mut idents = Vec::new();
collect_pattern_idents(pat, &mut idents);
for name in idents {
self.install_non_path_binding(name, CanonicalType::Opaque);
}
}
}