selene_lib/ast_util/
side_effects.rs

1// Unimplemented methods will report having side effects for safety reasons.
2
3use 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}