From 3ae94795a121e97661edbe6c631927df3dd2be84 Mon Sep 17 00:00:00 2001 From: Wang Wenzhe Date: Tue, 12 Mar 2024 11:04:38 +0800 Subject: [PATCH] feat(linter): report side effect for array element in node_side_effects rule (#2683) --- .../no_side_effects_in_initialization.rs | 68 ++++++++++++++++++- 1 file changed, 66 insertions(+), 2 deletions(-) diff --git a/crates/oxc_linter/src/rules/tree_shaking/no_side_effects_in_initialization.rs b/crates/oxc_linter/src/rules/tree_shaking/no_side_effects_in_initialization.rs index 26e950ae4..40fdcded7 100644 --- a/crates/oxc_linter/src/rules/tree_shaking/no_side_effects_in_initialization.rs +++ b/crates/oxc_linter/src/rules/tree_shaking/no_side_effects_in_initialization.rs @@ -1,3 +1,7 @@ +use oxc_ast::{ + ast::{ArrayExpressionElement, Expression, Program, Statement}, + AstKind, +}; use oxc_diagnostics::{ miette::{self, Diagnostic}, thiserror::Error, @@ -5,7 +9,7 @@ use oxc_diagnostics::{ use oxc_macros::declare_oxc_lint; use oxc_span::Span; -use crate::{context::LintContext, rule::Rule, AstNode}; +use crate::{context::LintContext, rule::Rule}; #[derive(Debug, Error, Diagnostic)] #[error( @@ -40,7 +44,67 @@ declare_oxc_lint!( ); impl Rule for NoSideEffectsInInitialization { - fn run<'a>(&self, _node: &AstNode<'a>, _ctx: &LintContext<'a>) {} + fn run_once(&self, ctx: &LintContext) { + let Some(root) = ctx.nodes().iter().next() else { return }; + let AstKind::Program(program) = root.kind() else { return }; + + program.report_effects(ctx); + } +} + +// TODO: add more type +#[allow(dead_code)] +enum Value { + Boolean(bool), + Number(f64), +} + +trait ListenerMap { + fn report_effects(&self, _ctx: &LintContext) {} + fn report_effects_when_assigned(&self, _ctx: &LintContext) {} + fn report_effects_when_called(&self, _ctx: &LintContext) {} + fn report_effects_when_mutated(&self, _ctx: &LintContext) {} + fn get_value_and_report_effects(&self, _ctx: &LintContext) -> Option { + None + } +} + +impl<'a> ListenerMap for Program<'a> { + fn report_effects(&self, ctx: &LintContext) { + self.body.iter().for_each(|stmt| stmt.report_effects(ctx)); + } +} + +impl<'a> ListenerMap for Statement<'a> { + fn report_effects(&self, ctx: &LintContext) { + if let Self::ExpressionStatement(expr_stmt) = self { + expr_stmt.expression.report_effects(ctx); + } + } +} + +impl<'a> ListenerMap for Expression<'a> { + fn report_effects(&self, ctx: &LintContext) { + #[allow(clippy::single_match)] + match self { + Self::ArrayExpression(array_expr) => { + array_expr.elements.iter().for_each(|el| el.report_effects(ctx)); + } + _ => {} + } + } +} + +impl<'a> ListenerMap for ArrayExpressionElement<'a> { + fn report_effects(&self, ctx: &LintContext) { + match self { + Self::Expression(expr) => expr.report_effects(ctx), + Self::SpreadElement(spreed) => { + spreed.argument.report_effects(ctx); + } + Self::Elision(_) => {} + } + } } #[ignore]