selene_lib/ast_util/
side_effects.rs1use full_moon::ast;
4
5pub trait HasSideEffects {
6 fn has_side_effects(&self) -> bool;
7}
8
9impl HasSideEffects for ast::Expression {
10 fn has_side_effects(&self) -> bool {
11 #[cfg_attr(
12 feature = "force_exhaustive_checks",
13 deny(non_exhaustive_omitted_patterns)
14 )]
15 match self {
16 ast::Expression::BinaryOperator { lhs, rhs, .. } => {
17 lhs.has_side_effects() || rhs.has_side_effects()
18 }
19 ast::Expression::Parentheses { expression, .. }
20 | ast::Expression::UnaryOperator { expression, .. } => expression.has_side_effects(),
21 ast::Expression::Function(_)
22 | ast::Expression::Number(_)
23 | ast::Expression::String(_)
24 | ast::Expression::Symbol(_) => false,
25 ast::Expression::FunctionCall(_) => true,
26 ast::Expression::TableConstructor(table_constructor) => table_constructor
27 .fields()
28 .into_iter()
29 .any(|field| match field {
30 ast::Field::ExpressionKey { key, value, .. } => {
31 key.has_side_effects() || value.has_side_effects()
32 }
33
34 ast::Field::NameKey { value, .. } => value.has_side_effects(),
35
36 ast::Field::NoKey(expression) => expression.has_side_effects(),
37
38 _ => true,
39 }),
40 ast::Expression::Var(var) => var.has_side_effects(),
41
42 #[cfg(feature = "roblox")]
43 ast::Expression::IfExpression(if_expression) => {
44 if if_expression.if_expression().has_side_effects()
45 || if_expression.condition().has_side_effects()
46 || if_expression.else_expression().has_side_effects()
47 {
48 return true;
49 }
50
51 if let Some(else_if_expressions) = if_expression.else_if_expressions() {
52 for else_if_expression in else_if_expressions {
53 if else_if_expression.condition().has_side_effects()
54 || else_if_expression.expression().has_side_effects()
55 {
56 return true;
57 }
58 }
59 }
60
61 false
62 }
63
64 #[cfg(feature = "roblox")]
65 ast::Expression::InterpolatedString(interpolated_string) => {
66 for expression in interpolated_string.expressions() {
67 if expression.has_side_effects() {
68 return true;
69 }
70 }
71
72 false
73 }
74
75 #[cfg(feature = "roblox")]
76 ast::Expression::TypeAssertion { expression, .. } => expression.has_side_effects(),
77
78 _ => true,
79 }
80 }
81}
82
83impl HasSideEffects for ast::Prefix {
84 fn has_side_effects(&self) -> bool {
85 #[cfg_attr(
86 feature = "force_exhaustive_checks",
87 deny(non_exhaustive_omitted_patterns)
88 )]
89 match self {
90 ast::Prefix::Expression(expression) => expression.has_side_effects(),
91 ast::Prefix::Name(_) => false,
92 _ => true,
93 }
94 }
95}
96
97impl HasSideEffects for ast::Suffix {
98 fn has_side_effects(&self) -> bool {
99 #[cfg_attr(
100 feature = "force_exhaustive_checks",
101 deny(non_exhaustive_omitted_patterns)
102 )]
103 match self {
104 ast::Suffix::Call(_) => true,
105 ast::Suffix::Index(_) => false,
106 _ => true,
107 }
108 }
109}
110
111impl HasSideEffects for ast::Var {
112 fn has_side_effects(&self) -> bool {
113 #[cfg_attr(
114 feature = "force_exhaustive_checks",
115 deny(non_exhaustive_omitted_patterns)
116 )]
117 match self {
118 ast::Var::Expression(var_expr) => var_expr.has_side_effects(),
119 ast::Var::Name(_) => false,
120 _ => true,
121 }
122 }
123}
124
125impl HasSideEffects for ast::VarExpression {
126 fn has_side_effects(&self) -> bool {
127 self.prefix().has_side_effects() || self.suffixes().any(HasSideEffects::has_side_effects)
128 }
129}