oxc_ecmascript/side_effects/
statements.rs1use oxc_ast::ast::*;
2
3use crate::constant_evaluation::{DetermineValueType, ValueType};
4
5use super::{MayHaveSideEffects, PropertyReadSideEffects, context::MayHaveSideEffectsContext};
6
7impl<'a> MayHaveSideEffects<'a> for Statement<'a> {
8 fn may_have_side_effects(&self, ctx: &impl MayHaveSideEffectsContext<'a>) -> bool {
9 match self {
10 Statement::BlockStatement(block) => block.may_have_side_effects(ctx),
11 Statement::DoWhileStatement(do_while) => do_while.may_have_side_effects(ctx),
12 Statement::ExpressionStatement(expr) => expr.expression.may_have_side_effects(ctx),
13 Statement::IfStatement(if_stmt) => if_stmt.may_have_side_effects(ctx),
14 Statement::LabeledStatement(labeled) => labeled.body.may_have_side_effects(ctx),
15 Statement::ReturnStatement(return_stmt) => {
16 return_stmt.argument.may_have_side_effects(ctx)
17 }
18 Statement::SwitchStatement(switch) => switch.may_have_side_effects(ctx),
19 Statement::TryStatement(try_stmt) => try_stmt.may_have_side_effects(ctx),
20 Statement::WhileStatement(while_stmt) => while_stmt.may_have_side_effects(ctx),
21 Statement::BreakStatement(_)
22 | Statement::ContinueStatement(_)
23 | Statement::EmptyStatement(_) => false,
24 match_declaration!(Statement) => self.to_declaration().may_have_side_effects(ctx),
25 Statement::ForInStatement(_)
26 | Statement::ForOfStatement(_)
27 | Statement::ForStatement(_)
28 | Statement::ThrowStatement(_)
29 | Statement::WithStatement(_)
30 | Statement::DebuggerStatement(_) => true,
31 #[expect(clippy::match_same_arms)]
32 match_module_declaration!(Statement) => true,
33 }
34 }
35}
36
37impl<'a> MayHaveSideEffects<'a> for BlockStatement<'a> {
38 fn may_have_side_effects(&self, ctx: &impl MayHaveSideEffectsContext<'a>) -> bool {
39 self.body.iter().any(|stmt| stmt.may_have_side_effects(ctx))
40 }
41}
42
43impl<'a> MayHaveSideEffects<'a> for DoWhileStatement<'a> {
44 fn may_have_side_effects(&self, ctx: &impl MayHaveSideEffectsContext<'a>) -> bool {
45 self.test.may_have_side_effects(ctx) || self.body.may_have_side_effects(ctx)
46 }
47}
48
49impl<'a> MayHaveSideEffects<'a> for IfStatement<'a> {
50 fn may_have_side_effects(&self, ctx: &impl MayHaveSideEffectsContext<'a>) -> bool {
51 self.test.may_have_side_effects(ctx)
52 || self.consequent.may_have_side_effects(ctx)
53 || self.alternate.may_have_side_effects(ctx)
54 }
55}
56
57impl<'a> MayHaveSideEffects<'a> for SwitchStatement<'a> {
58 fn may_have_side_effects(&self, ctx: &impl MayHaveSideEffectsContext<'a>) -> bool {
59 self.discriminant.may_have_side_effects(ctx)
60 || self.cases.iter().any(|case| {
61 case.test.may_have_side_effects(ctx)
62 || case.consequent.iter().any(|stmt| stmt.may_have_side_effects(ctx))
63 })
64 }
65}
66
67impl<'a> MayHaveSideEffects<'a> for TryStatement<'a> {
68 fn may_have_side_effects(&self, ctx: &impl MayHaveSideEffectsContext<'a>) -> bool {
69 self.block.may_have_side_effects(ctx)
70 || self.handler.as_ref().is_some_and(|catch_clause| {
71 catch_clause
72 .param
73 .as_ref()
74 .is_some_and(|param| param.pattern.may_have_side_effects(ctx))
75 || catch_clause.body.may_have_side_effects(ctx)
76 })
77 || self.finalizer.as_ref().is_some_and(|finalizer| finalizer.may_have_side_effects(ctx))
78 }
79}
80
81impl<'a> MayHaveSideEffects<'a> for WhileStatement<'a> {
82 fn may_have_side_effects(&self, ctx: &impl MayHaveSideEffectsContext<'a>) -> bool {
83 self.test.may_have_side_effects(ctx) || self.body.may_have_side_effects(ctx)
84 }
85}
86
87impl<'a> MayHaveSideEffects<'a> for Declaration<'a> {
88 fn may_have_side_effects(&self, ctx: &impl MayHaveSideEffectsContext<'a>) -> bool {
89 match self {
90 Declaration::VariableDeclaration(var_decl) => var_decl.may_have_side_effects(ctx),
91 Declaration::FunctionDeclaration(_) => false,
92 Declaration::ClassDeclaration(class_decl) => class_decl.may_have_side_effects(ctx),
93 Declaration::TSEnumDeclaration(_)
94 | Declaration::TSImportEqualsDeclaration(_)
95 | Declaration::TSModuleDeclaration(_)
96 | Declaration::TSInterfaceDeclaration(_)
97 | Declaration::TSTypeAliasDeclaration(_) => unreachable!(),
98 }
99 }
100}
101
102impl<'a> MayHaveSideEffects<'a> for VariableDeclaration<'a> {
103 fn may_have_side_effects(&self, ctx: &impl MayHaveSideEffectsContext<'a>) -> bool {
104 if self.kind == VariableDeclarationKind::AwaitUsing {
105 return true;
106 }
107 if self.kind == VariableDeclarationKind::Using {
108 return self.declarations.iter().any(|decl| {
109 decl.init.as_ref().is_none_or(|init| {
110 !matches!(init.value_type(ctx), ValueType::Undefined | ValueType::Null)
111 || init.may_have_side_effects(ctx)
112 })
113 });
114 }
115 self.declarations
116 .iter()
117 .any(|decl| decl.id.may_have_side_effects(ctx) || decl.init.may_have_side_effects(ctx))
118 }
119}
120
121impl<'a> MayHaveSideEffects<'a> for BindingPattern<'a> {
122 fn may_have_side_effects(&self, ctx: &impl MayHaveSideEffectsContext<'a>) -> bool {
123 match &self.kind {
124 BindingPatternKind::ArrayPattern(array_pattern) => {
125 ctx.property_read_side_effects() != PropertyReadSideEffects::None
126 || array_pattern.elements.iter().any(|el| el.may_have_side_effects(ctx))
127 }
128 BindingPatternKind::ObjectPattern(object_pattern) => {
129 ctx.property_read_side_effects() != PropertyReadSideEffects::None
130 || object_pattern.properties.iter().any(|prop| {
131 prop.key.may_have_side_effects(ctx) || prop.value.may_have_side_effects(ctx)
132 })
133 }
134 BindingPatternKind::AssignmentPattern(assignment_pattern) => {
135 assignment_pattern.left.may_have_side_effects(ctx)
136 || assignment_pattern.right.may_have_side_effects(ctx)
137 }
138 BindingPatternKind::BindingIdentifier(_) => false,
139 }
140 }
141}