use crate::executor::registry::ConvertError;
use crate::executor::spec::MutationTargetSymbol;
use ryo_analysis::AnalysisContext;
use ryo_symbol::SymbolId;
pub trait ResolveTargetSymbol {
fn resolve_target_symbol(
&self,
target: &MutationTargetSymbol,
ctx: &AnalysisContext,
) -> Result<SymbolId, ConvertError> {
match target {
MutationTargetSymbol::ById(id) => {
if ctx.registry.resolve(*id).is_none() {
return Err(ConvertError::TargetNotFound(format!(
"SymbolId {:?} not found in registry",
id
)));
}
Ok(*id)
}
MutationTargetSymbol::ByPath(path) => {
ctx.registry
.iter()
.find(|(_, p)| *p == &**path)
.map(|(id, _)| id)
.ok_or_else(|| {
ConvertError::TargetNotFound(format!("Symbol not found by path: {}", path))
})
}
MutationTargetSymbol::ByKindAndName(kind, name) => {
let normalized_name = normalize_generic_name(name);
let matches: Vec<_> = ctx
.registry
.iter()
.filter(|(_, path)| normalize_generic_name(path.name()) == normalized_name)
.collect();
match matches.len() {
0 => Err(ConvertError::TargetNotFound(format!(
"Symbol not found: kind={:?}, name={}",
kind, name
))),
1 => Ok(matches[0].0),
_ => Err(ConvertError::TargetNotFound(format!(
"Multiple symbols found: kind={:?}, name={} (found {} matches)",
kind,
name,
matches.len()
))),
}
}
MutationTargetSymbol::ByAffectedId {
parent_id,
kind,
name,
} => {
let parent_path = ctx.registry.resolve(*parent_id).ok_or_else(|| {
ConvertError::TargetNotFound(format!(
"Parent SymbolId {:?} not found",
parent_id
))
})?;
if let Some(child_name) = name {
parent_path
.child(child_name)
.map_err(|e| {
ConvertError::TargetNotFound(format!("Invalid child path: {}", e))
})
.and_then(|child_path| {
ctx.registry
.iter()
.find(|(_, p)| p == &&child_path)
.map(|(id, _)| id)
.ok_or_else(|| {
ConvertError::TargetNotFound(format!(
"Child symbol not found: parent={:?}, kind={:?}, name={}",
parent_id, kind, child_name
))
})
})
} else {
Err(ConvertError::TargetNotFound(format!(
"Anonymous child symbols not yet supported: parent={:?}, kind={:?}",
parent_id, kind
)))
}
}
}
}
}
fn normalize_generic_name(name: &str) -> String {
name.replace(" < ", "<")
.replace(" > ", ">")
.replace("< ", "<")
.replace(" >", ">")
.replace(", ", ",")
.replace(" ,", ",")
}
pub mod derive;
pub mod field;
pub mod rename;
pub mod visibility;
pub mod add_item;
pub mod enum_;
pub mod method;
pub mod module;
pub mod remove;
pub mod duplicate;
pub mod idiom;
pub mod match_arm;
pub mod move_;
pub mod plugin;
pub mod stmt;
pub mod struct_literal_field;
pub mod trait_;
pub use add_item::AddItemConverter;
pub use derive::DeriveConverter;
pub use duplicate::DuplicateConverter;
pub use enum_::EnumConverter;
pub use field::FieldConverter;
pub use idiom::IdiomConverter;
pub use match_arm::MatchArmConverter;
pub use method::MethodConverter;
pub use module::ModuleConverter;
pub use move_::MoveConverter;
pub use plugin::PluginConverter;
pub use remove::RemoveConverter;
pub use rename::RenameConverter;
pub use stmt::StmtConverter;
pub use struct_literal_field::StructLiteralFieldConverter;
pub use trait_::TraitConverter;
pub use visibility::VisibilityConverter;