ryo_executor/executor/registry/converters/
method.rs1use crate::engine::ASTRegApply;
4use crate::executor::registry::converters::ResolveTargetSymbol;
5use crate::executor::registry::{ConvertError, MutationConverter};
6use crate::executor::spec::{MutationSpec, SelfParam};
7use ryo_analysis::AnalysisContext;
8use ryo_mutations::{AddMethodMutation, RemoveMethodMutation};
9
10#[derive(Debug, Clone, Default)]
12pub struct MethodConverter;
13
14impl MethodConverter {
15 pub fn new() -> Self {
16 Self
17 }
18}
19
20impl ResolveTargetSymbol for MethodConverter {}
22
23impl MutationConverter for MethodConverter {
24 fn spec_kinds(&self) -> &'static [&'static str] {
25 &["AddMethod", "RemoveMethod"]
26 }
27
28 fn convert_v2(
29 &self,
30 spec: &MutationSpec,
31 ctx: &AnalysisContext,
32 ) -> Result<Vec<Box<dyn ASTRegApply>>, ConvertError> {
33 match spec {
34 MutationSpec::AddMethod {
35 target: target_symbol,
36 method_name,
37 params,
38 return_type,
39 body,
40 is_pub,
41 self_param,
42 } => {
43 use ryo_symbol::SymbolKind;
44
45 let type_id = self.resolve_target_symbol(target_symbol, ctx)?;
48
49 let kind = ctx.registry.kind(type_id);
51 if !matches!(kind, Some(SymbolKind::Struct | SymbolKind::Enum)) {
52 return Err(ConvertError::TargetNotFound(format!(
53 "Expected struct or enum, got {:?}",
54 kind
55 )));
56 }
57
58 let mut mutation = AddMethodMutation::new(type_id, method_name);
60
61 mutation = match self_param {
63 Some(SelfParam::Ref) => mutation.with_self(),
64 Some(SelfParam::Mut) => mutation.with_mut_self(),
65 Some(SelfParam::Owned) => mutation.with_owned_self(),
66 None => mutation,
67 };
68
69 if !params.is_empty() {
71 mutation = mutation.with_params(params.clone());
72 }
73
74 if let Some(ret) = return_type {
76 mutation = mutation.with_return_type(ret);
77 }
78
79 mutation = mutation.with_body(body);
81
82 if *is_pub {
84 mutation = mutation.public();
85 }
86
87 Ok(vec![Box::new(mutation)])
88 }
89 MutationSpec::RemoveMethod {
90 target: target_symbol,
91 method_name,
92 } => {
93 use ryo_symbol::SymbolKind;
94
95 let type_id = self.resolve_target_symbol(target_symbol, ctx)?;
97
98 let kind = ctx.registry.kind(type_id);
100 if !matches!(kind, Some(SymbolKind::Struct | SymbolKind::Enum)) {
101 return Err(ConvertError::TargetNotFound(format!(
102 "Expected struct or enum, got {:?}",
103 kind
104 )));
105 }
106
107 let type_path = ctx.registry.resolve(type_id).ok_or_else(|| {
109 ConvertError::TargetNotFound(format!("Type {} not found", type_id))
110 })?;
111
112 let method_path = type_path.child(method_name).map_err(|_| {
114 ConvertError::TargetNotFound(format!("Invalid method name: {}", method_name))
115 })?;
116
117 let method_id = ctx.registry.lookup(&method_path).ok_or_else(|| {
119 ConvertError::TargetNotFound(format!(
120 "Method '{}' not found on type",
121 method_name
122 ))
123 })?;
124
125 let mutation = RemoveMethodMutation::new(method_id);
126 Ok(vec![Box::new(mutation)])
127 }
128 _ => Err(ConvertError::TypeMismatch {
129 expected: "AddMethod or RemoveMethod",
130 actual: spec.kind_name().to_string(),
131 }),
132 }
133 }
134}
135
136#[cfg(test)]
137mod tests {
138 use super::*;
139
140 #[test]
141 fn test_method_converter_spec_kinds() {
142 let converter = MethodConverter::new();
143 assert_eq!(converter.spec_kinds(), &["AddMethod", "RemoveMethod"]);
144 }
145
146 #[test]
147 fn test_method_converter_can_handle() {
148 let converter = MethodConverter::new();
149
150 let spec = MutationSpec::AddMethod {
151 target: crate::executor::spec::MutationTargetSymbol::ByKindAndName(
152 crate::executor::ItemKind::Impl,
153 "Config".to_string(),
154 ),
155 method_name: "new".into(),
156 params: vec![],
157 return_type: Some("Self".into()),
158 body: "Self { }".into(),
159 is_pub: true,
160 self_param: None,
161 };
162 assert!(converter.can_handle(&spec));
163 }
164}