Skip to main content

darklua_core/rules/
unused_while.rs

1use crate::nodes::{Block, Statement};
2use crate::process::{DefaultVisitor, Evaluator, NodeProcessor, NodeVisitor};
3use crate::rules::{
4    Context, FlawlessRule, RuleConfiguration, RuleConfigurationError, RuleMetadata, RuleProperties,
5};
6
7use super::verify_no_rule_properties;
8
9#[derive(Debug, Clone, Default)]
10struct WhileFilter {
11    evaluator: Evaluator,
12}
13
14impl NodeProcessor for WhileFilter {
15    fn process_block(&mut self, block: &mut Block) {
16        block.filter_statements(|statement| match statement {
17            Statement::While(while_statement) => {
18                let condition = while_statement.get_condition();
19
20                self.evaluator.has_side_effects(condition)
21                    || self
22                        .evaluator
23                        .evaluate(condition)
24                        .is_truthy()
25                        .unwrap_or(true)
26            }
27            _ => true,
28        });
29    }
30}
31
32pub const REMOVE_UNUSED_WHILE_RULE_NAME: &str = "remove_unused_while";
33
34/// A rule that removes while statements with a known false condition.
35#[derive(Debug, Default, PartialEq, Eq)]
36pub struct RemoveUnusedWhile {
37    metadata: RuleMetadata,
38}
39
40impl FlawlessRule for RemoveUnusedWhile {
41    fn flawless_process(&self, block: &mut Block, _: &Context) {
42        let mut processor = WhileFilter::default();
43        DefaultVisitor::visit_block(block, &mut processor);
44    }
45}
46
47impl RuleConfiguration for RemoveUnusedWhile {
48    fn configure(&mut self, properties: RuleProperties) -> Result<(), RuleConfigurationError> {
49        verify_no_rule_properties(&properties)?;
50
51        Ok(())
52    }
53
54    fn get_name(&self) -> &'static str {
55        REMOVE_UNUSED_WHILE_RULE_NAME
56    }
57
58    fn serialize_to_properties(&self) -> RuleProperties {
59        RuleProperties::new()
60    }
61
62    fn set_metadata(&mut self, metadata: RuleMetadata) {
63        self.metadata = metadata;
64    }
65
66    fn metadata(&self) -> &RuleMetadata {
67        &self.metadata
68    }
69}
70
71#[cfg(test)]
72mod test {
73    use super::*;
74    use crate::rules::Rule;
75
76    use insta::assert_json_snapshot;
77
78    fn new_rule() -> RemoveUnusedWhile {
79        RemoveUnusedWhile::default()
80    }
81
82    #[test]
83    fn serialize_default_rule() {
84        let rule: Box<dyn Rule> = Box::new(new_rule());
85
86        assert_json_snapshot!(rule, @r###""remove_unused_while""###);
87    }
88
89    #[test]
90    fn configure_with_extra_field_error() {
91        let result = json5::from_str::<Box<dyn Rule>>(
92            r#"{
93            rule: 'remove_unused_while',
94            prop: "something",
95        }"#,
96        );
97        insta::assert_snapshot!(result.unwrap_err().to_string(), @"unexpected field 'prop' at line 1 column 1");
98    }
99}