1use mago_span::*;
2
3use crate::ast::*;
4
5#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash, PartialOrd, Ord)]
6pub enum MethodReference<'a> {
7 MethodCall(&'a MethodCall),
8 StaticMethodCall(&'a StaticMethodCall),
9 MethodClosureCreation(&'a MethodClosureCreation),
10 StaticMethodClosureCreation(&'a StaticMethodClosureCreation),
11}
12
13impl MethodReference<'_> {
14 pub fn get_class_or_object(&self) -> &Expression {
15 match self {
16 MethodReference::MethodCall(call) => &call.object,
17 MethodReference::StaticMethodCall(call) => &call.class,
18 MethodReference::MethodClosureCreation(closure) => &closure.object,
19 MethodReference::StaticMethodClosureCreation(closure) => &closure.class,
20 }
21 }
22
23 pub fn get_selector(&self) -> &ClassLikeMemberSelector {
24 match self {
25 MethodReference::MethodCall(call) => &call.method,
26 MethodReference::StaticMethodCall(call) => &call.method,
27 MethodReference::MethodClosureCreation(closure) => &closure.method,
28 MethodReference::StaticMethodClosureCreation(closure) => &closure.method,
29 }
30 }
31}
32
33impl HasSpan for MethodReference<'_> {
34 fn span(&self) -> Span {
35 match self {
36 MethodReference::MethodCall(call) => call.span(),
37 MethodReference::StaticMethodCall(call) => call.span(),
38 MethodReference::MethodClosureCreation(closure) => closure.span(),
39 MethodReference::StaticMethodClosureCreation(closure) => closure.span(),
40 }
41 }
42}
43
44pub fn find_method_references_in_block<'a, F>(block: &'a Block, predicate: &F) -> Vec<MethodReference<'a>>
45where
46 F: Fn(&MethodReference<'a>) -> bool,
47{
48 let mut method_references = vec![];
49 for statement in block.statements.iter() {
50 method_references.extend(find_method_references_in_statement(statement, predicate));
51 }
52
53 method_references
54}
55
56pub fn find_method_references_in_statement<'a, F>(statement: &'a Statement, predicate: &F) -> Vec<MethodReference<'a>>
57where
58 F: Fn(&MethodReference<'a>) -> bool,
59{
60 match statement {
61 Statement::Block(block) => {
62 let mut references = vec![];
63 for statement in block.statements.iter() {
64 references.extend(find_method_references_in_statement(statement, predicate));
65 }
66
67 references
68 }
69 Statement::Try(try_catch) => {
70 let mut references = vec![];
71 for statement in try_catch.block.statements.iter() {
72 references.extend(find_method_references_in_statement(statement, predicate));
73 }
74
75 for catch in try_catch.catch_clauses.iter() {
76 for statement in catch.block.statements.iter() {
77 references.extend(find_method_references_in_statement(statement, predicate));
78 }
79 }
80
81 if let Some(finally) = &try_catch.finally_clause {
82 for statement in finally.block.statements.iter() {
83 references.extend(find_method_references_in_statement(statement, predicate));
84 }
85 }
86
87 references
88 }
89 Statement::Foreach(foreach) => {
90 let mut references = vec![];
91
92 references.extend(find_method_references_in_expression(&foreach.expression, predicate));
93
94 match &foreach.target {
95 ForeachTarget::Value(foreach_value_target) => {
96 references.extend(find_method_references_in_expression(&foreach_value_target.value, predicate));
97 }
98 ForeachTarget::KeyValue(foreach_key_value_target) => {
99 references.extend(find_method_references_in_expression(&foreach_key_value_target.key, predicate));
100 references.extend(find_method_references_in_expression(&foreach_key_value_target.value, predicate));
101 }
102 }
103
104 match &foreach.body {
105 ForeachBody::Statement(statement) => {
106 references.extend(find_method_references_in_statement(statement, predicate));
107 }
108 ForeachBody::ColonDelimited(foreach_colon_delimited_body) => {
109 for statement in foreach_colon_delimited_body.statements.iter() {
110 references.extend(find_method_references_in_statement(statement, predicate));
111 }
112 }
113 }
114
115 references
116 }
117 Statement::For(for_loop) => {
118 let mut references = vec![];
119
120 for init in for_loop.initializations.iter() {
121 references.extend(find_method_references_in_expression(init, predicate));
122 }
123
124 for condition in for_loop.conditions.iter() {
125 references.extend(find_method_references_in_expression(condition, predicate));
126 }
127
128 for increment in for_loop.increments.iter() {
129 references.extend(find_method_references_in_expression(increment, predicate));
130 }
131
132 match &for_loop.body {
133 ForBody::Statement(statement) => {
134 references.extend(find_method_references_in_statement(statement, predicate));
135 }
136 ForBody::ColonDelimited(for_colon_delimited_body) => {
137 for statement in for_colon_delimited_body.statements.iter() {
138 references.extend(find_method_references_in_statement(statement, predicate));
139 }
140 }
141 }
142
143 references
144 }
145 Statement::While(while_loop) => {
146 let mut references = vec![];
147
148 references.extend(find_method_references_in_expression(&while_loop.condition, predicate));
149
150 match &while_loop.body {
151 WhileBody::Statement(statement) => {
152 references.extend(find_method_references_in_statement(statement, predicate));
153 }
154 WhileBody::ColonDelimited(while_colon_delimited_body) => {
155 for statement in while_colon_delimited_body.statements.iter() {
156 references.extend(find_method_references_in_statement(statement, predicate));
157 }
158 }
159 }
160
161 references
162 }
163 Statement::DoWhile(do_while) => {
164 let mut references = vec![];
165
166 references.extend(find_method_references_in_expression(&do_while.condition, predicate));
167 references.extend(find_method_references_in_statement(&do_while.statement, predicate));
168
169 references
170 }
171 Statement::Switch(switch) => {
172 let mut references = find_method_references_in_expression(&switch.expression, predicate);
173
174 for case in switch.body.cases() {
175 match case {
176 SwitchCase::Expression(expression_case) => {
177 references.extend(find_method_references_in_expression(&expression_case.expression, predicate));
178
179 for statement in expression_case.statements.iter() {
180 references.extend(find_method_references_in_statement(statement, predicate));
181 }
182 }
183 SwitchCase::Default(default_case) => {
184 for statement in default_case.statements.iter() {
185 references.extend(find_method_references_in_statement(statement, predicate));
186 }
187 }
188 }
189 }
190
191 references
192 }
193 Statement::If(if_stmt) => {
194 let mut references = vec![];
195
196 references.extend(find_method_references_in_expression(&if_stmt.condition, predicate));
197 match &if_stmt.body {
198 IfBody::Statement(if_stmt_body) => {
199 references.extend(find_method_references_in_statement(&if_stmt_body.statement, predicate));
200 for else_if_clause in if_stmt_body.else_if_clauses.iter() {
201 references.extend(find_method_references_in_expression(&else_if_clause.condition, predicate));
202 references.extend(find_method_references_in_statement(&else_if_clause.statement, predicate));
203 }
204
205 if let Some(else_clause) = &if_stmt_body.else_clause {
206 references.extend(find_method_references_in_statement(&else_clause.statement, predicate));
207 }
208 }
209 IfBody::ColonDelimited(if_colon_delimited_body) => {
210 for statement in if_colon_delimited_body.statements.iter() {
211 references.extend(find_method_references_in_statement(statement, predicate));
212 }
213
214 for else_if_clause in if_colon_delimited_body.else_if_clauses.iter() {
215 references.extend(find_method_references_in_expression(&else_if_clause.condition, predicate));
216 for statement in else_if_clause.statements.iter() {
217 references.extend(find_method_references_in_statement(statement, predicate));
218 }
219 }
220
221 if let Some(else_clause) = &if_colon_delimited_body.else_clause {
222 for statement in else_clause.statements.iter() {
223 references.extend(find_method_references_in_statement(statement, predicate));
224 }
225 }
226 }
227 }
228
229 references
230 }
231 Statement::Return(r#return) => {
232 if let Some(expression) = &r#return.value {
233 find_method_references_in_expression(expression, predicate)
234 } else {
235 vec![]
236 }
237 }
238 Statement::Expression(expression_statement) => {
239 find_method_references_in_expression(&expression_statement.expression, predicate)
240 }
241 Statement::Echo(echo) => {
242 let mut references = vec![];
243 for expression in echo.values.iter() {
244 references.extend(find_method_references_in_expression(expression, predicate));
245 }
246
247 references
248 }
249 _ => {
250 vec![]
251 }
252 }
253}
254
255pub fn find_method_references_in_expression<'a, F>(
256 expression: &'a Expression,
257 predicate: &F,
258) -> Vec<MethodReference<'a>>
259where
260 F: Fn(&MethodReference<'a>) -> bool,
261{
262 match expression {
263 Expression::Binary(binary) => {
264 let mut references = vec![];
265 references.extend(find_method_references_in_expression(binary.lhs.as_ref(), predicate));
266 references.extend(find_method_references_in_expression(binary.rhs.as_ref(), predicate));
267
268 references
269 }
270 Expression::UnaryPrefix(unary_prefix) => {
271 find_method_references_in_expression(unary_prefix.operand.as_ref(), predicate)
272 }
273 Expression::UnaryPostfix(unary_postfix) => {
274 find_method_references_in_expression(unary_postfix.operand.as_ref(), predicate)
275 }
276 Expression::Parenthesized(parenthesized) => {
277 find_method_references_in_expression(parenthesized.expression.as_ref(), predicate)
278 }
279 Expression::Assignment(assignment) => {
280 let mut references = vec![];
281 references.extend(find_method_references_in_expression(assignment.lhs.as_ref(), predicate));
282 references.extend(find_method_references_in_expression(assignment.rhs.as_ref(), predicate));
283
284 references
285 }
286 Expression::Conditional(conditional) => {
287 let mut references = vec![];
288 references.extend(find_method_references_in_expression(conditional.condition.as_ref(), predicate));
289 if let Some(then) = &conditional.then {
290 references.extend(find_method_references_in_expression(then, predicate));
291 }
292 references.extend(find_method_references_in_expression(conditional.r#else.as_ref(), predicate));
293
294 references
295 }
296 Expression::Array(Array { elements, .. })
297 | Expression::LegacyArray(LegacyArray { elements, .. })
298 | Expression::List(List { elements, .. }) => {
299 let mut references = vec![];
300 for element in elements.iter() {
301 match element {
302 ArrayElement::KeyValue(kv) => {
303 references.extend(find_method_references_in_expression(kv.key.as_ref(), predicate));
304 references.extend(find_method_references_in_expression(kv.value.as_ref(), predicate));
305 }
306 ArrayElement::Value(v) => {
307 references.extend(find_method_references_in_expression(v.value.as_ref(), predicate));
308 }
309 ArrayElement::Variadic(v) => {
310 references.extend(find_method_references_in_expression(v.value.as_ref(), predicate));
311 }
312 ArrayElement::Missing(_) => {}
313 }
314 }
315
316 references
317 }
318 Expression::ArrayAccess(array_access) => {
319 let mut references = vec![];
320 references.extend(find_method_references_in_expression(array_access.array.as_ref(), predicate));
321 references.extend(find_method_references_in_expression(array_access.index.as_ref(), predicate));
322
323 references
324 }
325 Expression::ArrayAppend(array_append) => {
326 find_method_references_in_expression(array_append.array.as_ref(), predicate)
327 }
328 Expression::AnonymousClass(anonymous_class) => {
329 if let Some(argument_list) = &anonymous_class.argument_list {
330 find_references_in_argument_list(argument_list, predicate)
331 } else {
332 vec![]
333 }
334 }
335 Expression::Match(r#match) => {
336 let mut references = vec![];
337 references.extend(find_method_references_in_expression(&r#match.expression, predicate));
338
339 for arm in r#match.arms.iter() {
340 match arm {
341 MatchArm::Expression(match_expression_arm) => {
342 for condition in match_expression_arm.conditions.iter() {
343 references.extend(find_method_references_in_expression(condition, predicate));
344 }
345
346 references
347 .extend(find_method_references_in_expression(&match_expression_arm.expression, predicate));
348 }
349 MatchArm::Default(match_default_arm) => {
350 references
351 .extend(find_method_references_in_expression(&match_default_arm.expression, predicate));
352 }
353 }
354 }
355
356 references
357 }
358 Expression::Yield(r#yield) => match r#yield {
359 Yield::Value(yield_value) => match &yield_value.value {
360 Some(value) => find_method_references_in_expression(value, predicate),
361 None => vec![],
362 },
363 Yield::Pair(yield_pair) => {
364 let mut references = vec![];
365 references.extend(find_method_references_in_expression(&yield_pair.key, predicate));
366 references.extend(find_method_references_in_expression(&yield_pair.value, predicate));
367
368 references
369 }
370 Yield::From(yield_from) => find_method_references_in_expression(&yield_from.iterator, predicate),
371 },
372 Expression::Throw(throw) => find_method_references_in_expression(&throw.exception, predicate),
373 Expression::Clone(clone) => find_method_references_in_expression(&clone.object, predicate),
374 Expression::Call(call) => match call {
375 Call::Function(function_call) => {
376 let mut references = vec![];
377
378 references.extend(find_method_references_in_expression(&function_call.function, predicate));
379 references.extend(find_references_in_argument_list(&function_call.argument_list, predicate));
380 references
381 }
382 Call::Method(method_call) => {
383 let reference = MethodReference::MethodCall(method_call);
384 let mut references = if predicate(&reference) { vec![reference] } else { vec![] };
385
386 references.extend(find_method_references_in_expression(&method_call.object, predicate));
387 references.extend(find_references_in_argument_list(&method_call.argument_list, predicate));
388 references
389 }
390 Call::NullSafeMethod(null_safe_method_call) => {
391 let mut references = vec![];
392
393 references.extend(find_method_references_in_expression(&null_safe_method_call.object, predicate));
394 references.extend(find_references_in_argument_list(&null_safe_method_call.argument_list, predicate));
395 references
396 }
397 Call::StaticMethod(static_method_call) => {
398 let reference = MethodReference::StaticMethodCall(static_method_call);
399 let mut references = if predicate(&reference) { vec![reference] } else { vec![] };
400
401 references.extend(find_method_references_in_expression(&static_method_call.class, predicate));
402 references.extend(find_references_in_argument_list(&static_method_call.argument_list, predicate));
403 references
404 }
405 },
406 Expression::ClosureCreation(closure_creation) => match closure_creation {
407 ClosureCreation::Method(method_closure_creation) => {
408 let reference = MethodReference::MethodClosureCreation(method_closure_creation);
409 let mut references = if predicate(&reference) { vec![reference] } else { vec![] };
410
411 references.extend(find_method_references_in_expression(&method_closure_creation.object, predicate));
412 references
413 }
414 ClosureCreation::StaticMethod(static_method_closure_creation) => {
415 let reference = MethodReference::StaticMethodClosureCreation(static_method_closure_creation);
416 let mut references = if predicate(&reference) { vec![reference] } else { vec![] };
417
418 references
419 .extend(find_method_references_in_expression(&static_method_closure_creation.class, predicate));
420 references
421 }
422 ClosureCreation::Function(_) => vec![],
423 },
424 Expression::Instantiation(instantiation) => {
425 if let Some(argument_list) = &instantiation.argument_list {
426 find_references_in_argument_list(argument_list, predicate)
427 } else {
428 vec![]
429 }
430 }
431 _ => {
432 vec![]
433 }
434 }
435}
436
437fn find_references_in_argument_list<'a, F>(argument_list: &'a ArgumentList, predicate: &F) -> Vec<MethodReference<'a>>
438where
439 F: Fn(&MethodReference<'a>) -> bool,
440{
441 let mut references = vec![];
442 for argument in argument_list.arguments.iter() {
443 match argument {
444 Argument::Positional(positional_argument) => {
445 references.extend(find_method_references_in_expression(&positional_argument.value, predicate));
446 }
447 Argument::Named(named_argument) => {
448 references.extend(find_method_references_in_expression(&named_argument.value, predicate));
449 }
450 }
451 }
452
453 references
454}