diff --git a/crates/oxc_linter/src/rules/tree_shaking/no_side_effects_in_initialization/listener_map.rs b/crates/oxc_linter/src/rules/tree_shaking/no_side_effects_in_initialization/listener_map.rs index 18079ce5e..8ac7df58b 100644 --- a/crates/oxc_linter/src/rules/tree_shaking/no_side_effects_in_initialization/listener_map.rs +++ b/crates/oxc_linter/src/rules/tree_shaking/no_side_effects_in_initialization/listener_map.rs @@ -3,9 +3,10 @@ use std::cell::RefCell; use oxc_ast::{ ast::{ Argument, ArrayExpressionElement, ArrowFunctionExpression, AssignmentTarget, - CallExpression, ComputedMemberExpression, Expression, FormalParameter, Function, - IdentifierReference, MemberExpression, ModuleDeclaration, ParenthesizedExpression, - PrivateFieldExpression, Program, SimpleAssignmentTarget, Statement, StaticMemberExpression, + BindingPattern, BindingPatternKind, CallExpression, ComputedMemberExpression, Declaration, + Expression, FormalParameter, Function, IdentifierReference, MemberExpression, + ModuleDeclaration, ParenthesizedExpression, PrivateFieldExpression, Program, + SimpleAssignmentTarget, Statement, StaticMemberExpression, VariableDeclarator, }, AstKind, }; @@ -62,6 +63,9 @@ impl<'a> ListenerMap for Statement<'a> { Self::BreakStatement(_) | Self::ContinueStatement(_) | Self::EmptyStatement(_) => { no_effects(); } + Self::Declaration(decl) => { + decl.report_effects(options); + } Self::ModuleDeclaration(decl) => { if matches!( decl.0, @@ -104,6 +108,52 @@ impl<'a> ListenerMap for AstNode<'a> { } } +impl<'a> ListenerMap for Declaration<'a> { + fn report_effects(&self, options: &NodeListenerOptions) { + #[allow(clippy::single_match)] + match self { + Self::VariableDeclaration(decl) => { + decl.declarations.iter().for_each(|decl| decl.report_effects(options)); + } + _ => {} + } + } +} + +impl<'a> ListenerMap for VariableDeclarator<'a> { + fn report_effects(&self, options: &NodeListenerOptions) { + self.id.report_effects(options); + + if let Some(init) = &self.init { + init.report_effects(options); + } + } +} + +impl<'a> ListenerMap for BindingPattern<'a> { + fn report_effects(&self, options: &NodeListenerOptions) { + match &self.kind { + BindingPatternKind::BindingIdentifier(_) => {} + BindingPatternKind::ArrayPattern(array) => { + array.elements.iter().for_each(|el| { + if let Some(el) = el { + el.report_effects(options); + } + }); + } + BindingPatternKind::ObjectPattern(object) => { + object.properties.iter().for_each(|prop| { + prop.value.report_effects(options); + }); + } + BindingPatternKind::AssignmentPattern(assign_p) => { + assign_p.left.report_effects(options); + assign_p.right.report_effects(options); + } + } + } +} + impl<'a> ListenerMap for Expression<'a> { fn report_effects(&self, options: &NodeListenerOptions) { match self { diff --git a/crates/oxc_linter/src/rules/tree_shaking/no_side_effects_in_initialization/mod.rs b/crates/oxc_linter/src/rules/tree_shaking/no_side_effects_in_initialization/mod.rs index d7bb2a3d6..76f42820f 100644 --- a/crates/oxc_linter/src/rules/tree_shaking/no_side_effects_in_initialization/mod.rs +++ b/crates/oxc_linter/src/rules/tree_shaking/no_side_effects_in_initialization/mod.rs @@ -84,12 +84,12 @@ fn test() { let pass = vec![ // ArrayExpression "[]", - // "const x = []", - // "const x = [ext,ext]", - // "const x = [1,,2,]", + "const x = []", + "const x = [ext,ext]", + "const x = [1,,2,]", // // ArrayPattern - // "const [x] = []", - // "const [,x,] = []", + "const [x] = []", + "const [,x,] = []", // // ArrowFunctionExpression // "const x = a=>{a(); ext()}", // // ArrowFunctionExpression when called @@ -354,11 +354,11 @@ fn test() { let fail = vec![ // // ArrayExpression - // "const x = [ext()]", - // "const x = [,,ext(),]", + "const x = [ext()]", + "const x = [,,ext(),]", // // ArrayPattern - // "const [x = ext()] = []", - // "const [,x = ext(),] = []", + "const [x = ext()] = []", + "const [,x = ext(),] = []", // // ArrowFunctionExpression when called // "(()=>{ext()})()", // "(({a = ext()})=>{})()", diff --git a/crates/oxc_linter/src/snapshots/no_side_effects_in_initialization.snap b/crates/oxc_linter/src/snapshots/no_side_effects_in_initialization.snap index fb2789843..82dff9cdb 100644 --- a/crates/oxc_linter/src/snapshots/no_side_effects_in_initialization.snap +++ b/crates/oxc_linter/src/snapshots/no_side_effects_in_initialization.snap @@ -2,6 +2,30 @@ source: crates/oxc_linter/src/tester.rs expression: no_side_effects_in_initialization --- + ⚠ eslint-plugin-tree-shaking(no-side-effects-in-initialization): Cannot determine side-effects of calling global function `ext` + ╭─[no_side_effects_in_initialization.tsx:1:12] + 1 │ const x = [ext()] + · ─── + ╰──── + + ⚠ eslint-plugin-tree-shaking(no-side-effects-in-initialization): Cannot determine side-effects of calling global function `ext` + ╭─[no_side_effects_in_initialization.tsx:1:14] + 1 │ const x = [,,ext(),] + · ─── + ╰──── + + ⚠ eslint-plugin-tree-shaking(no-side-effects-in-initialization): Cannot determine side-effects of calling global function `ext` + ╭─[no_side_effects_in_initialization.tsx:1:12] + 1 │ const [x = ext()] = [] + · ─── + ╰──── + + ⚠ eslint-plugin-tree-shaking(no-side-effects-in-initialization): Cannot determine side-effects of calling global function `ext` + ╭─[no_side_effects_in_initialization.tsx:1:13] + 1 │ const [,x = ext(),] = [] + · ─── + ╰──── + ⚠ eslint-plugin-tree-shaking(no-side-effects-in-initialization): Cannot determine side-effects of assignment to `ext` ╭─[no_side_effects_in_initialization.tsx:1:1] 1 │ ext = 1