use std::collections::HashMap;
use crate::analyzer::{FunctionSignature, SignatureRegistry};
#[derive(Debug, Clone)]
pub struct ResolvedSignature {
pub sig: FunctionSignature,
pub qualified_key: String,
pub resolution_method: ResolutionMethod,
pub has_collision: bool,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ResolutionMethod {
ExactQualified,
ReceiverQualified,
ModuleAlias,
ProgressiveQualified,
ArgCountValidated,
}
pub fn resolve_call_signature(
registry: &SignatureRegistry,
func_name: &str,
receiver_type: Option<&str>,
arg_count: usize,
module_aliases: &HashMap<String, String>,
) -> Option<ResolvedSignature> {
if let Some(sig) = registry.get_signature(func_name) {
if validate_arg_count(sig, arg_count) {
return Some(ResolvedSignature {
sig: sig.clone(),
qualified_key: func_name.to_string(),
resolution_method: ResolutionMethod::ExactQualified,
has_collision: registry.has_collision(func_name),
});
}
if func_name.contains("::") && !registry.has_collision(func_name) {
return None;
}
}
let method_part = func_name.rsplit("::").next().unwrap_or(func_name);
if let Some(recv) = receiver_type {
if let Some(resolved) = try_receiver_qualified(registry, method_part, recv, arg_count) {
return Some(resolved);
}
}
if let Some(pos) = func_name.rfind("::") {
let qualifier = &func_name[..pos];
let base_qualifier = qualifier.split('<').next().unwrap_or(qualifier);
if base_qualifier != qualifier {
let base_key = format!("{}::{}", base_qualifier, method_part);
if let Some(sig) = registry.get_signature(&base_key) {
if validate_arg_count(sig, arg_count) {
let has_collision = registry.has_collision(&base_key);
return Some(ResolvedSignature {
sig: sig.clone(),
qualified_key: base_key,
resolution_method: ResolutionMethod::ExactQualified,
has_collision,
});
}
}
}
if let Some(original_module) = module_aliases.get(qualifier) {
let resolved_name = format!("{}::{}", original_module, method_part);
if let Some(sig) = registry.get_signature(&resolved_name) {
if validate_arg_count(sig, arg_count) {
let has_collision = registry.has_collision(&resolved_name);
return Some(ResolvedSignature {
sig: sig.clone(),
qualified_key: resolved_name,
resolution_method: ResolutionMethod::ModuleAlias,
has_collision,
});
}
}
}
let parts: Vec<&str> = func_name.split("::").collect();
if parts.len() > 2 {
for start in (1..parts.len().saturating_sub(1)).rev() {
let candidate = parts[start..].join("::");
if let Some(sig) = registry.get_signature(&candidate) {
if validate_arg_count(sig, arg_count) {
let has_collision = registry.has_collision(&candidate);
return Some(ResolvedSignature {
sig: sig.clone(),
qualified_key: candidate,
resolution_method: ResolutionMethod::ProgressiveQualified,
has_collision,
});
}
}
}
}
}
if func_name.contains("::") && registry.has_collision(func_name) {
let suffix = format!("::{}", func_name);
for (key, sig) in registry.all_signatures() {
if key.ends_with(&suffix) && key != func_name && validate_arg_count(sig, arg_count) {
return Some(ResolvedSignature {
sig: sig.clone(),
qualified_key: key.clone(),
resolution_method: ResolutionMethod::ProgressiveQualified,
has_collision: true,
});
}
}
}
if func_name.contains("::") {
if let Some(sig) = registry.find_signature_by_name_and_arg_count(method_part, arg_count) {
let qualified_key = registry
.signatures
.iter()
.find(|(_, v)| std::ptr::eq(*v, sig))
.map(|(k, _)| k.clone())
.unwrap_or_else(|| method_part.to_string());
return Some(ResolvedSignature {
sig: sig.clone(),
qualified_key,
resolution_method: ResolutionMethod::ArgCountValidated,
has_collision: registry.has_collision(method_part),
});
}
}
if !func_name.contains("::") {
let suffix = format!("::{}", func_name);
for (key, sig) in registry.all_signatures() {
if key.ends_with(&suffix)
&& !sig.has_self_receiver
&& validate_arg_count(sig, arg_count)
{
return Some(ResolvedSignature {
sig: sig.clone(),
qualified_key: key.clone(),
resolution_method: ResolutionMethod::ArgCountValidated,
has_collision: true,
});
}
}
}
None
}
fn try_receiver_qualified(
registry: &SignatureRegistry,
method: &str,
receiver_type: &str,
arg_count: usize,
) -> Option<ResolvedSignature> {
let base = receiver_type.split('<').next().unwrap_or(receiver_type);
let qualified = format!("{}::{}", base, method);
if let Some(sig) = registry.get_signature(&qualified) {
if validate_arg_count(sig, arg_count) {
let has_collision = registry.has_collision(&qualified);
return Some(ResolvedSignature {
sig: sig.clone(),
qualified_key: qualified,
resolution_method: ResolutionMethod::ReceiverQualified,
has_collision,
});
}
}
if base != receiver_type {
let full_qualified = format!("{}::{}", receiver_type, method);
if let Some(sig) = registry.get_signature(&full_qualified) {
if validate_arg_count(sig, arg_count) {
let has_collision = registry.has_collision(&full_qualified);
return Some(ResolvedSignature {
sig: sig.clone(),
qualified_key: full_qualified,
resolution_method: ResolutionMethod::ReceiverQualified,
has_collision,
});
}
}
}
None
}
fn validate_arg_count(sig: &FunctionSignature, call_arg_count: usize) -> bool {
let expected = if sig.has_self_receiver {
sig.param_ownership.len().saturating_sub(1)
} else {
sig.param_ownership.len()
};
expected == call_arg_count
}
#[cfg(test)]
mod tests {
use super::*;
use crate::analyzer::OwnershipMode;
use crate::parser::Type;
fn make_sig(name: &str, param_count: usize, has_self: bool) -> FunctionSignature {
FunctionSignature {
name: name.to_string(),
param_types: vec![Type::Custom("i32".into()); param_count],
param_ownership: vec![OwnershipMode::Owned; param_count + if has_self { 1 } else { 0 }],
return_type: None,
return_ownership: OwnershipMode::Owned,
has_self_receiver: has_self,
is_extern: false,
}
}
fn make_sig_with_types(name: &str, types: Vec<Type>, has_self: bool) -> FunctionSignature {
let ownership_len = types.len() + if has_self { 1 } else { 0 };
FunctionSignature {
name: name.to_string(),
param_types: types,
param_ownership: vec![OwnershipMode::Owned; ownership_len],
return_type: None,
return_ownership: OwnershipMode::Owned,
has_self_receiver: has_self,
is_extern: false,
}
}
fn empty_aliases() -> HashMap<String, String> {
HashMap::new()
}
#[test]
fn exact_qualified_match() {
let mut reg = SignatureRegistry::new();
reg.add_function("Vec::push".into(), make_sig("push", 1, true));
let result = resolve_call_signature(®, "Vec::push", None, 1, &empty_aliases());
assert!(result.is_some());
let r = result.unwrap();
assert_eq!(r.resolution_method, ResolutionMethod::ExactQualified);
assert_eq!(r.qualified_key, "Vec::push");
}
#[test]
fn receiver_qualified_match() {
let mut reg = SignatureRegistry::new();
reg.add_function("Emitter::new".into(), make_sig("new", 2, false));
let result = resolve_call_signature(®, "new", Some("Emitter"), 2, &empty_aliases());
assert!(result.is_some());
let r = result.unwrap();
assert_eq!(r.resolution_method, ResolutionMethod::ReceiverQualified);
}
#[test]
fn bare_name_never_matches_wrong_type() {
let mut reg = SignatureRegistry::new();
reg.add_function(
"Vec3::new".into(),
make_sig_with_types(
"new",
vec![
Type::Custom("f32".into()),
Type::Custom("f32".into()),
Type::Custom("f32".into()),
],
false,
),
);
reg.add_function(
"Emitter::new".into(),
make_sig_with_types(
"new",
vec![Type::Custom("Vec3".into()), Type::Custom("i32".into())],
false,
),
);
let result = resolve_call_signature(®, "Emitter::new", None, 2, &empty_aliases());
assert!(result.is_some());
let r = result.unwrap();
assert_eq!(r.qualified_key, "Emitter::new");
assert!(!r
.sig
.param_types
.iter()
.any(|t| matches!(t, Type::Custom(n) if n == "f32")));
}
#[test]
fn module_alias_resolution() {
let mut reg = SignatureRegistry::new();
reg.add_function(
"gpu_safe::load_shader".into(),
make_sig("load_shader", 1, false),
);
let mut aliases = HashMap::new();
aliases.insert("gpu".into(), "gpu_safe".into());
let result = resolve_call_signature(®, "gpu::load_shader", None, 1, &aliases);
assert!(result.is_some());
let r = result.unwrap();
assert_eq!(r.resolution_method, ResolutionMethod::ModuleAlias);
}
#[test]
fn arg_count_mismatch_rejects() {
let mut reg = SignatureRegistry::new();
reg.add_function("Foo::new".into(), make_sig("new", 3, false));
let result = resolve_call_signature(®, "Foo::new", None, 2, &empty_aliases());
assert!(result.is_none());
}
#[test]
fn collision_detected() {
let mut reg = SignatureRegistry::new();
reg.add_function(
"Emitter::new".into(),
make_sig_with_types(
"new",
vec![Type::Custom("Vec3".into()), Type::Custom("i32".into())],
false,
),
);
reg.add_function(
"Emitter::new".into(),
make_sig_with_types(
"new",
vec![Type::Custom("f32".into()), Type::Custom("f32".into())],
false,
),
);
let result = resolve_call_signature(®, "Emitter::new", None, 2, &empty_aliases());
assert!(result.is_some());
assert!(result.unwrap().has_collision);
}
#[test]
fn progressive_qualified_match() {
let mut reg = SignatureRegistry::new();
reg.add_function(
"rendering::Camera::update".into(),
make_sig("update", 1, true),
);
let result = resolve_call_signature(
®,
"scene::rendering::Camera::update",
None,
1,
&empty_aliases(),
);
assert!(result.is_some());
let r = result.unwrap();
assert_eq!(r.resolution_method, ResolutionMethod::ProgressiveQualified);
}
}