1use crate::ast::*;
2use crate::utils::control_flow::ControlFlow;
3
4pub mod assignment;
5pub mod condition;
6pub mod control_flow;
7pub mod definition;
8pub mod reference;
9
10#[inline]
11pub fn find_returns_in_block(block: &Block) -> Vec<&Return> {
12 let mut returns = vec![];
13 for control_flow in control_flow::find_control_flows_in_block(block) {
14 if let ControlFlow::Return(r#return) = control_flow {
15 returns.push(r#return);
16 }
17 }
18
19 returns
20}
21
22#[inline]
23pub fn find_returns_in_statement(statement: &Statement) -> Vec<&Return> {
24 let mut returns = vec![];
25 for control_flow in control_flow::find_control_flows_in_statement(statement) {
26 if let ControlFlow::Return(r#return) = control_flow {
27 returns.push(r#return);
28 }
29 }
30
31 returns
32}
33
34#[inline]
35pub fn block_has_throws(block: &Block) -> bool {
36 for control_flow in control_flow::find_control_flows_in_block(block) {
37 if let ControlFlow::Throw(_) = control_flow {
38 return true;
39 }
40 }
41
42 false
43}
44
45#[inline]
46pub fn statement_has_throws(statement: &Statement) -> bool {
47 for control_flow in control_flow::find_control_flows_in_statement(statement) {
48 if let ControlFlow::Throw(_) = control_flow {
49 return true;
50 }
51 }
52
53 false
54}
55
56#[inline]
57pub fn expression_has_throws(expression: &Expression) -> bool {
58 for control_flow in control_flow::find_control_flows_in_expression(expression) {
59 if let ControlFlow::Throw(_) = control_flow {
60 return true;
61 }
62 }
63
64 false
65}
66
67#[inline]
68pub fn block_has_yield(block: &Block) -> bool {
69 for statement in block.statements.iter() {
70 if statement_has_yield(statement) {
71 return true;
72 }
73 }
74
75 false
76}
77
78#[inline]
79pub fn statement_has_yield(statement: &Statement) -> bool {
80 match statement {
81 Statement::Namespace(namespace) => {
82 for statement in namespace.statements().iter() {
83 if statement_has_yield(statement) {
84 return true;
85 }
86 }
87
88 false
89 }
90 Statement::Block(block) => block_has_yield(block),
91 Statement::Try(r#try) => {
92 if r#try.block.statements.iter().any(statement_has_yield)
93 || r#try.catch_clauses.iter().any(|catch| block_has_yield(&catch.block))
94 {
95 return true;
96 }
97
98 for catch in r#try.catch_clauses.iter() {
99 if block_has_yield(&catch.block) {
100 return true;
101 }
102 }
103
104 if let Some(finally) = &r#try.finally_clause
105 && block_has_yield(&finally.block)
106 {
107 return true;
108 }
109
110 false
111 }
112 Statement::Foreach(foreach) => match &foreach.body {
113 ForeachBody::Statement(statement) => statement_has_yield(statement),
114 ForeachBody::ColonDelimited(foreach_colon_delimited_body) => {
115 foreach_colon_delimited_body.statements.iter().any(statement_has_yield)
116 }
117 },
118 Statement::For(r#for) => match &r#for.body {
119 ForBody::Statement(statement) => statement_has_yield(statement),
120 ForBody::ColonDelimited(foreach_colon_delimited_body) => {
121 foreach_colon_delimited_body.statements.iter().any(statement_has_yield)
122 }
123 },
124 Statement::While(r#while) => match &r#while.body {
125 WhileBody::Statement(statement) => statement_has_yield(statement),
126 WhileBody::ColonDelimited(foreach_colon_delimited_body) => {
127 foreach_colon_delimited_body.statements.iter().any(statement_has_yield)
128 }
129 },
130 Statement::DoWhile(do_while) => statement_has_yield(&do_while.statement),
131 Statement::Switch(switch) => {
132 let cases = match &switch.body {
133 SwitchBody::BraceDelimited(switch_brace_delimited_body) => &switch_brace_delimited_body.cases,
134 SwitchBody::ColonDelimited(switch_colon_delimited_body) => &switch_colon_delimited_body.cases,
135 };
136
137 for case in cases.iter() {
138 match &case {
139 SwitchCase::Expression(switch_expression_case) => {
140 for statement in switch_expression_case.statements.iter() {
141 if statement_has_yield(statement) {
142 return true;
143 }
144 }
145 }
146 SwitchCase::Default(switch_default_case) => {
147 for statement in switch_default_case.statements.iter() {
148 if statement_has_yield(statement) {
149 return true;
150 }
151 }
152 }
153 }
154 }
155
156 false
157 }
158 Statement::If(r#if) => match &r#if.body {
159 IfBody::Statement(if_statement_body) => {
160 if statement_has_yield(&if_statement_body.statement) {
161 return true;
162 }
163
164 for else_if in if_statement_body.else_if_clauses.iter() {
165 if statement_has_yield(&else_if.statement) {
166 return true;
167 }
168 }
169
170 if let Some(else_clause) = &if_statement_body.else_clause
171 && statement_has_yield(&else_clause.statement)
172 {
173 return true;
174 }
175
176 false
177 }
178 IfBody::ColonDelimited(if_colon_delimited_body) => {
179 if if_colon_delimited_body.statements.iter().any(statement_has_yield) {
180 return true;
181 }
182
183 for else_if in if_colon_delimited_body.else_if_clauses.iter() {
184 if else_if.statements.iter().any(statement_has_yield) {
185 return true;
186 }
187 }
188
189 if let Some(else_clause) = &if_colon_delimited_body.else_clause
190 && else_clause.statements.iter().any(statement_has_yield)
191 {
192 return true;
193 }
194
195 false
196 }
197 },
198 Statement::Expression(expression) => expression_has_yield(&expression.expression),
199 _ => false,
200 }
201}
202
203#[inline]
204pub fn expression_has_yield(expression: &Expression) -> bool {
205 match &expression {
206 Expression::Parenthesized(parenthesized) => expression_has_yield(&parenthesized.expression),
207 Expression::Literal(_) => false,
208 Expression::CompositeString(_) => false,
209 Expression::Binary(operation) => expression_has_yield(&operation.lhs) || expression_has_yield(&operation.rhs),
210 Expression::UnaryPrefix(operation) => expression_has_yield(&operation.operand),
211 Expression::UnaryPostfix(operation) => expression_has_yield(&operation.operand),
212 Expression::Assignment(assignment_operation) => {
213 expression_has_yield(&assignment_operation.lhs) || expression_has_yield(&assignment_operation.rhs)
214 }
215 Expression::Conditional(conditional) => {
216 expression_has_yield(&conditional.condition)
217 || conditional.then.as_ref().map(|e| expression_has_yield(e.as_ref())).unwrap_or(false)
218 || expression_has_yield(&conditional.r#else)
219 }
220 Expression::Array(array) => array.elements.iter().any(|element| match element {
221 ArrayElement::KeyValue(key_value_array_element) => {
222 expression_has_yield(&key_value_array_element.key)
223 || expression_has_yield(&key_value_array_element.value)
224 }
225 ArrayElement::Value(value_array_element) => expression_has_yield(&value_array_element.value),
226 ArrayElement::Variadic(variadic_array_element) => expression_has_yield(&variadic_array_element.value),
227 _ => false,
228 }),
229 Expression::LegacyArray(legacy_array) => legacy_array.elements.iter().any(|element| match element {
230 ArrayElement::KeyValue(key_value_array_element) => {
231 expression_has_yield(&key_value_array_element.key)
232 || expression_has_yield(&key_value_array_element.value)
233 }
234 ArrayElement::Value(value_array_element) => expression_has_yield(&value_array_element.value),
235 ArrayElement::Variadic(variadic_array_element) => expression_has_yield(&variadic_array_element.value),
236 _ => false,
237 }),
238 Expression::List(list) => list.elements.iter().any(|element| match element {
239 ArrayElement::KeyValue(key_value_array_element) => {
240 expression_has_yield(&key_value_array_element.key)
241 || expression_has_yield(&key_value_array_element.value)
242 }
243 ArrayElement::Value(value_array_element) => expression_has_yield(&value_array_element.value),
244 ArrayElement::Variadic(variadic_array_element) => expression_has_yield(&variadic_array_element.value),
245 _ => false,
246 }),
247 Expression::ArrayAccess(array_access) => {
248 expression_has_yield(&array_access.array) || expression_has_yield(&array_access.index)
249 }
250 Expression::ArrayAppend(array_append) => expression_has_yield(&array_append.array),
251 Expression::Match(r#match) => {
252 expression_has_yield(&r#match.expression)
253 || r#match.arms.iter().any(|arm| match arm {
254 MatchArm::Expression(match_expression_arm) => {
255 match_expression_arm.conditions.iter().any(expression_has_yield)
256 || expression_has_yield(&match_expression_arm.expression)
257 }
258 MatchArm::Default(match_default_arm) => expression_has_yield(&match_default_arm.expression),
259 })
260 }
261 Expression::Construct(construct) => match construct {
262 Construct::Isset(isset_construct) => isset_construct.values.iter().any(expression_has_yield),
263 Construct::Empty(empty_construct) => expression_has_yield(&empty_construct.value),
264 Construct::Eval(eval_construct) => expression_has_yield(&eval_construct.value),
265 Construct::Include(include_construct) => expression_has_yield(&include_construct.value),
266 Construct::IncludeOnce(include_once_construct) => expression_has_yield(&include_once_construct.value),
267 Construct::Require(require_construct) => expression_has_yield(&require_construct.value),
268 Construct::RequireOnce(require_once_construct) => expression_has_yield(&require_once_construct.value),
269 Construct::Print(print_construct) => expression_has_yield(&print_construct.value),
270 Construct::Exit(exit_construct) => exit_construct
271 .arguments
272 .as_ref()
273 .map(|arguments| {
274 arguments.arguments.iter().any(|argument| match argument {
275 Argument::Positional(positional_argument) => expression_has_yield(&positional_argument.value),
276 Argument::Named(named_argument) => expression_has_yield(&named_argument.value),
277 })
278 })
279 .unwrap_or(false),
280 Construct::Die(die_construct) => die_construct
281 .arguments
282 .as_ref()
283 .map(|arguments| {
284 arguments.arguments.iter().any(|argument| match argument {
285 Argument::Positional(positional_argument) => expression_has_yield(&positional_argument.value),
286 Argument::Named(named_argument) => expression_has_yield(&named_argument.value),
287 })
288 })
289 .unwrap_or(false),
290 },
291 Expression::Throw(throw) => expression_has_yield(&throw.exception),
292 Expression::Clone(clone) => expression_has_yield(&clone.object),
293 Expression::Call(call) => match call {
294 Call::Function(function_call) => {
295 expression_has_yield(&function_call.function)
296 || function_call.argument_list.arguments.iter().any(|argument| match argument {
297 Argument::Positional(positional_argument) => expression_has_yield(&positional_argument.value),
298 Argument::Named(named_argument) => expression_has_yield(&named_argument.value),
299 })
300 }
301 Call::Method(method_call) => {
302 expression_has_yield(&method_call.object)
303 || matches!(&method_call.method, ClassLikeMemberSelector::Expression(selector) if expression_has_yield(&selector.expression))
304 || method_call.argument_list.arguments.iter().any(|argument| match argument {
305 Argument::Positional(positional_argument) => expression_has_yield(&positional_argument.value),
306 Argument::Named(named_argument) => expression_has_yield(&named_argument.value),
307 })
308 }
309 Call::NullSafeMethod(null_safe_method_call) => {
310 expression_has_yield(&null_safe_method_call.object)
311 || matches!(&null_safe_method_call.method, ClassLikeMemberSelector::Expression(selector) if expression_has_yield(&selector.expression))
312 || null_safe_method_call.argument_list.arguments.iter().any(|argument| match argument {
313 Argument::Positional(positional_argument) => expression_has_yield(&positional_argument.value),
314 Argument::Named(named_argument) => expression_has_yield(&named_argument.value),
315 })
316 }
317 Call::StaticMethod(static_method_call) => {
318 expression_has_yield(&static_method_call.class)
319 || matches!(&static_method_call.method, ClassLikeMemberSelector::Expression(selector) if expression_has_yield(&selector.expression))
320 || static_method_call.argument_list.arguments.iter().any(|argument| match argument {
321 Argument::Positional(positional_argument) => expression_has_yield(&positional_argument.value),
322 Argument::Named(named_argument) => expression_has_yield(&named_argument.value),
323 })
324 }
325 },
326 Expression::Access(access) => match access {
327 Access::Property(property_access) => {
328 expression_has_yield(&property_access.object)
329 || matches!(&property_access.property, ClassLikeMemberSelector::Expression(selector) if expression_has_yield(&selector.expression))
330 }
331 Access::NullSafeProperty(null_safe_property_access) => {
332 expression_has_yield(&null_safe_property_access.object)
333 || matches!(&null_safe_property_access.property, ClassLikeMemberSelector::Expression(selector) if expression_has_yield(&selector.expression))
334 }
335 Access::StaticProperty(static_property_access) => expression_has_yield(&static_property_access.class),
336 Access::ClassConstant(class_constant_access) => {
337 expression_has_yield(&class_constant_access.class)
338 || matches!(&class_constant_access.constant, ClassLikeConstantSelector::Expression(selector) if expression_has_yield(&selector.expression))
339 }
340 },
341 Expression::ClosureCreation(closure_creation) => match closure_creation {
342 ClosureCreation::Function(function_closure_creation) => {
343 expression_has_yield(&function_closure_creation.function)
344 }
345 ClosureCreation::Method(method_closure_creation) => {
346 expression_has_yield(&method_closure_creation.object)
347 || matches!(&method_closure_creation.method, ClassLikeMemberSelector::Expression(selector) if expression_has_yield(&selector.expression))
348 }
349 ClosureCreation::StaticMethod(static_method_closure_creation) => {
350 expression_has_yield(&static_method_closure_creation.class)
351 || matches!(&static_method_closure_creation.method, ClassLikeMemberSelector::Expression(selector) if expression_has_yield(&selector.expression))
352 }
353 },
354 Expression::Instantiation(instantiation) => {
355 expression_has_yield(&instantiation.class)
356 || instantiation
357 .argument_list
358 .as_ref()
359 .map(|arguments| {
360 arguments.arguments.iter().any(|argument| match argument {
361 Argument::Positional(positional_argument) => {
362 expression_has_yield(&positional_argument.value)
363 }
364 Argument::Named(named_argument) => expression_has_yield(&named_argument.value),
365 })
366 })
367 .unwrap_or(false)
368 }
369 Expression::Yield(_) => true,
370 _ => false,
371 }
372}