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.catch_clauses.iter().any(|catch| block_has_yield(&catch.block)) {
93 return true;
94 }
95
96 for catch in r#try.catch_clauses.iter() {
97 if block_has_yield(&catch.block) {
98 return true;
99 }
100 }
101
102 if let Some(finally) = &r#try.finally_clause
103 && block_has_yield(&finally.block)
104 {
105 return true;
106 }
107
108 false
109 }
110 Statement::Foreach(foreach) => match &foreach.body {
111 ForeachBody::Statement(statement) => statement_has_yield(statement),
112 ForeachBody::ColonDelimited(foreach_colon_delimited_body) => {
113 foreach_colon_delimited_body.statements.iter().any(statement_has_yield)
114 }
115 },
116 Statement::For(r#for) => match &r#for.body {
117 ForBody::Statement(statement) => statement_has_yield(statement),
118 ForBody::ColonDelimited(foreach_colon_delimited_body) => {
119 foreach_colon_delimited_body.statements.iter().any(statement_has_yield)
120 }
121 },
122 Statement::While(r#while) => match &r#while.body {
123 WhileBody::Statement(statement) => statement_has_yield(statement),
124 WhileBody::ColonDelimited(foreach_colon_delimited_body) => {
125 foreach_colon_delimited_body.statements.iter().any(statement_has_yield)
126 }
127 },
128 Statement::DoWhile(do_while) => statement_has_yield(&do_while.statement),
129 Statement::Switch(switch) => {
130 let cases = match &switch.body {
131 SwitchBody::BraceDelimited(switch_brace_delimited_body) => &switch_brace_delimited_body.cases,
132 SwitchBody::ColonDelimited(switch_colon_delimited_body) => &switch_colon_delimited_body.cases,
133 };
134
135 for case in cases.iter() {
136 match &case {
137 SwitchCase::Expression(switch_expression_case) => {
138 for statement in switch_expression_case.statements.iter() {
139 if statement_has_yield(statement) {
140 return true;
141 }
142 }
143 }
144 SwitchCase::Default(switch_default_case) => {
145 for statement in switch_default_case.statements.iter() {
146 if statement_has_yield(statement) {
147 return true;
148 }
149 }
150 }
151 }
152 }
153
154 false
155 }
156 Statement::If(r#if) => match &r#if.body {
157 IfBody::Statement(if_statement_body) => {
158 if statement_has_yield(&if_statement_body.statement) {
159 return true;
160 }
161
162 for else_if in if_statement_body.else_if_clauses.iter() {
163 if statement_has_yield(&else_if.statement) {
164 return true;
165 }
166 }
167
168 if let Some(else_clause) = &if_statement_body.else_clause
169 && statement_has_yield(&else_clause.statement)
170 {
171 return true;
172 }
173
174 false
175 }
176 IfBody::ColonDelimited(if_colon_delimited_body) => {
177 if if_colon_delimited_body.statements.iter().any(statement_has_yield) {
178 return true;
179 }
180
181 for else_if in if_colon_delimited_body.else_if_clauses.iter() {
182 if else_if.statements.iter().any(statement_has_yield) {
183 return true;
184 }
185 }
186
187 if let Some(else_clause) = &if_colon_delimited_body.else_clause
188 && else_clause.statements.iter().any(statement_has_yield)
189 {
190 return true;
191 }
192
193 false
194 }
195 },
196 Statement::Expression(expression) => expression_has_yield(&expression.expression),
197 _ => false,
198 }
199}
200
201#[inline]
202pub fn expression_has_yield(expression: &Expression) -> bool {
203 match &expression {
204 Expression::Parenthesized(parenthesized) => expression_has_yield(&parenthesized.expression),
205 Expression::Literal(_) => false,
206 Expression::CompositeString(_) => false,
207 Expression::Binary(operation) => expression_has_yield(&operation.lhs) || expression_has_yield(&operation.rhs),
208 Expression::UnaryPrefix(operation) => expression_has_yield(&operation.operand),
209 Expression::UnaryPostfix(operation) => expression_has_yield(&operation.operand),
210 Expression::Assignment(assignment_operation) => {
211 expression_has_yield(&assignment_operation.lhs) || expression_has_yield(&assignment_operation.rhs)
212 }
213 Expression::Conditional(conditional) => {
214 expression_has_yield(&conditional.condition)
215 || conditional.then.as_ref().map(|e| expression_has_yield(e.as_ref())).unwrap_or(false)
216 || expression_has_yield(&conditional.r#else)
217 }
218 Expression::Array(array) => array.elements.iter().any(|element| match element {
219 ArrayElement::KeyValue(key_value_array_element) => {
220 expression_has_yield(&key_value_array_element.key)
221 || expression_has_yield(&key_value_array_element.value)
222 }
223 ArrayElement::Value(value_array_element) => expression_has_yield(&value_array_element.value),
224 ArrayElement::Variadic(variadic_array_element) => expression_has_yield(&variadic_array_element.value),
225 _ => false,
226 }),
227 Expression::LegacyArray(legacy_array) => legacy_array.elements.iter().any(|element| match element {
228 ArrayElement::KeyValue(key_value_array_element) => {
229 expression_has_yield(&key_value_array_element.key)
230 || expression_has_yield(&key_value_array_element.value)
231 }
232 ArrayElement::Value(value_array_element) => expression_has_yield(&value_array_element.value),
233 ArrayElement::Variadic(variadic_array_element) => expression_has_yield(&variadic_array_element.value),
234 _ => false,
235 }),
236 Expression::List(list) => list.elements.iter().any(|element| match element {
237 ArrayElement::KeyValue(key_value_array_element) => {
238 expression_has_yield(&key_value_array_element.key)
239 || expression_has_yield(&key_value_array_element.value)
240 }
241 ArrayElement::Value(value_array_element) => expression_has_yield(&value_array_element.value),
242 ArrayElement::Variadic(variadic_array_element) => expression_has_yield(&variadic_array_element.value),
243 _ => false,
244 }),
245 Expression::ArrayAccess(array_access) => {
246 expression_has_yield(&array_access.array) || expression_has_yield(&array_access.index)
247 }
248 Expression::ArrayAppend(array_append) => expression_has_yield(&array_append.array),
249 Expression::Match(r#match) => {
250 expression_has_yield(&r#match.expression)
251 || r#match.arms.iter().any(|arm| match arm {
252 MatchArm::Expression(match_expression_arm) => {
253 match_expression_arm.conditions.iter().any(expression_has_yield)
254 || expression_has_yield(&match_expression_arm.expression)
255 }
256 MatchArm::Default(match_default_arm) => expression_has_yield(&match_default_arm.expression),
257 })
258 }
259 Expression::Construct(construct) => match construct {
260 Construct::Isset(isset_construct) => isset_construct.values.iter().any(expression_has_yield),
261 Construct::Empty(empty_construct) => expression_has_yield(&empty_construct.value),
262 Construct::Eval(eval_construct) => expression_has_yield(&eval_construct.value),
263 Construct::Include(include_construct) => expression_has_yield(&include_construct.value),
264 Construct::IncludeOnce(include_once_construct) => expression_has_yield(&include_once_construct.value),
265 Construct::Require(require_construct) => expression_has_yield(&require_construct.value),
266 Construct::RequireOnce(require_once_construct) => expression_has_yield(&require_once_construct.value),
267 Construct::Print(print_construct) => expression_has_yield(&print_construct.value),
268 Construct::Exit(exit_construct) => exit_construct
269 .arguments
270 .as_ref()
271 .map(|arguments| {
272 arguments.arguments.iter().any(|argument| match argument {
273 Argument::Positional(positional_argument) => expression_has_yield(&positional_argument.value),
274 Argument::Named(named_argument) => expression_has_yield(&named_argument.value),
275 })
276 })
277 .unwrap_or(false),
278 Construct::Die(die_construct) => die_construct
279 .arguments
280 .as_ref()
281 .map(|arguments| {
282 arguments.arguments.iter().any(|argument| match argument {
283 Argument::Positional(positional_argument) => expression_has_yield(&positional_argument.value),
284 Argument::Named(named_argument) => expression_has_yield(&named_argument.value),
285 })
286 })
287 .unwrap_or(false),
288 },
289 Expression::Throw(throw) => expression_has_yield(&throw.exception),
290 Expression::Clone(clone) => expression_has_yield(&clone.object),
291 Expression::Call(call) => match call {
292 Call::Function(function_call) => {
293 expression_has_yield(&function_call.function)
294 || function_call.argument_list.arguments.iter().any(|argument| match argument {
295 Argument::Positional(positional_argument) => expression_has_yield(&positional_argument.value),
296 Argument::Named(named_argument) => expression_has_yield(&named_argument.value),
297 })
298 }
299 Call::Method(method_call) => {
300 expression_has_yield(&method_call.object)
301 || matches!(&method_call.method, ClassLikeMemberSelector::Expression(selector) if expression_has_yield(&selector.expression))
302 || method_call.argument_list.arguments.iter().any(|argument| match argument {
303 Argument::Positional(positional_argument) => expression_has_yield(&positional_argument.value),
304 Argument::Named(named_argument) => expression_has_yield(&named_argument.value),
305 })
306 }
307 Call::NullSafeMethod(null_safe_method_call) => {
308 expression_has_yield(&null_safe_method_call.object)
309 || matches!(&null_safe_method_call.method, ClassLikeMemberSelector::Expression(selector) if expression_has_yield(&selector.expression))
310 || null_safe_method_call.argument_list.arguments.iter().any(|argument| match argument {
311 Argument::Positional(positional_argument) => expression_has_yield(&positional_argument.value),
312 Argument::Named(named_argument) => expression_has_yield(&named_argument.value),
313 })
314 }
315 Call::StaticMethod(static_method_call) => {
316 expression_has_yield(&static_method_call.class)
317 || matches!(&static_method_call.method, ClassLikeMemberSelector::Expression(selector) if expression_has_yield(&selector.expression))
318 || static_method_call.argument_list.arguments.iter().any(|argument| match argument {
319 Argument::Positional(positional_argument) => expression_has_yield(&positional_argument.value),
320 Argument::Named(named_argument) => expression_has_yield(&named_argument.value),
321 })
322 }
323 },
324 Expression::Access(access) => match access {
325 Access::Property(property_access) => {
326 expression_has_yield(&property_access.object)
327 || matches!(&property_access.property, ClassLikeMemberSelector::Expression(selector) if expression_has_yield(&selector.expression))
328 }
329 Access::NullSafeProperty(null_safe_property_access) => {
330 expression_has_yield(&null_safe_property_access.object)
331 || matches!(&null_safe_property_access.property, ClassLikeMemberSelector::Expression(selector) if expression_has_yield(&selector.expression))
332 }
333 Access::StaticProperty(static_property_access) => expression_has_yield(&static_property_access.class),
334 Access::ClassConstant(class_constant_access) => {
335 expression_has_yield(&class_constant_access.class)
336 || matches!(&class_constant_access.constant, ClassLikeConstantSelector::Expression(selector) if expression_has_yield(&selector.expression))
337 }
338 },
339 Expression::ClosureCreation(closure_creation) => match closure_creation {
340 ClosureCreation::Function(function_closure_creation) => {
341 expression_has_yield(&function_closure_creation.function)
342 }
343 ClosureCreation::Method(method_closure_creation) => {
344 expression_has_yield(&method_closure_creation.object)
345 || matches!(&method_closure_creation.method, ClassLikeMemberSelector::Expression(selector) if expression_has_yield(&selector.expression))
346 }
347 ClosureCreation::StaticMethod(static_method_closure_creation) => {
348 expression_has_yield(&static_method_closure_creation.class)
349 || matches!(&static_method_closure_creation.method, ClassLikeMemberSelector::Expression(selector) if expression_has_yield(&selector.expression))
350 }
351 },
352 Expression::Instantiation(instantiation) => {
353 expression_has_yield(&instantiation.class)
354 || instantiation
355 .argument_list
356 .as_ref()
357 .map(|arguments| {
358 arguments.arguments.iter().any(|argument| match argument {
359 Argument::Positional(positional_argument) => {
360 expression_has_yield(&positional_argument.value)
361 }
362 Argument::Named(named_argument) => expression_has_yield(&named_argument.value),
363 })
364 })
365 .unwrap_or(false)
366 }
367 Expression::Yield(_) => true,
368 _ => false,
369 }
370}