feat(linter/tree-shaking): support ForStatement (#3078)

This commit is contained in:
Wang Wenzhe 2024-04-24 00:32:47 +08:00 committed by GitHub
parent d109767330
commit 88ded0cef5
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 157 additions and 31 deletions

View file

@ -5,11 +5,11 @@ use oxc_ast::{
Argument, ArrayExpressionElement, ArrowFunctionExpression, AssignmentTarget,
BinaryExpression, BindingIdentifier, BindingPattern, BindingPatternKind, CallExpression,
Class, ClassBody, ClassElement, ComputedMemberExpression, ConditionalExpression,
Declaration, ExportDefaultDeclarationKind, ExportSpecifier, Expression, FormalParameter,
Function, IdentifierReference, MemberExpression, ModuleDeclaration, ModuleExportName,
NewExpression, ParenthesizedExpression, PrivateFieldExpression, Program, PropertyKey,
SimpleAssignmentTarget, Statement, StaticMemberExpression, ThisExpression,
VariableDeclarator,
Declaration, ExportDefaultDeclarationKind, ExportSpecifier, Expression, ForStatementInit,
ForStatementLeft, FormalParameter, Function, IdentifierReference, MemberExpression,
ModuleDeclaration, ModuleExportName, NewExpression, ParenthesizedExpression,
PrivateFieldExpression, Program, PropertyKey, SimpleAssignmentTarget, Statement,
StaticMemberExpression, ThisExpression, VariableDeclarator,
},
AstKind,
};
@ -152,11 +152,53 @@ impl<'a> ListenerMap for Statement<'a> {
Self::DebuggerStatement(stmt) => {
options.ctx.diagnostic(NoSideEffectsDiagnostic::Debugger(stmt.span));
}
Self::ForStatement(stmt) => {
if let Some(init) = &stmt.init {
init.report_effects(options);
}
if let Some(test) = &stmt.test {
test.report_effects(options);
}
if let Some(update) = &stmt.update {
update.report_effects(options);
}
stmt.body.report_effects(options);
}
Self::ForInStatement(stmt) => {
if let ForStatementLeft::AssignmentTarget(assign) = &stmt.left {
assign.report_effects_when_assigned(options);
}
stmt.right.report_effects(options);
stmt.body.report_effects(options);
}
Self::ForOfStatement(stmt) => {
if let ForStatementLeft::AssignmentTarget(assign) = &stmt.left {
assign.report_effects_when_assigned(options);
}
stmt.right.report_effects(options);
stmt.body.report_effects(options);
}
_ => {}
}
}
}
impl<'a> ListenerMap for ForStatementInit<'a> {
fn report_effects(&self, options: &NodeListenerOptions) {
match self {
Self::Expression(expr) => {
expr.report_effects(options);
}
Self::UsingDeclaration(decl) => {
decl.declarations.iter().for_each(|decl| decl.report_effects(options));
}
Self::VariableDeclaration(decl) => {
decl.declarations.iter().for_each(|decl| decl.report_effects(options));
}
}
}
}
impl<'a> ListenerMap for ExportSpecifier<'a> {
fn report_effects(&self, options: &NodeListenerOptions) {
let ctx = options.ctx;

View file

@ -200,14 +200,14 @@ fn test() {
"export const /* tree-shaking no-side-effects-when-called */ x = function(){}",
"export function /* tree-shaking no-side-effects-when-called */ x(){}",
"const x = function(){}; export {/* tree-shaking no-side-effects-when-called */ x}",
// // ExpressionStatement
// "const x = 1",
// // ForInStatement
// "for(const x in ext){x = 1}",
// "let x; for(x in ext){}",
// // ForStatement
// "for(let i = 0; i < 3; i++){i++}",
// "for(;;){}",
// ExpressionStatement
"const x = 1",
// ForInStatement
"for(const x in ext){x = 1}",
"let x; for(x in ext){}",
// ForStatement
"for(let i = 0; i < 3; i++){i++}",
"for(;;){}",
// // FunctionDeclaration
// "function x(a){a(); ext()}",
// // FunctionDeclaration when called
@ -465,24 +465,24 @@ fn test() {
"export const /* tree-shaking no-side-effects-when-called */ x = ext",
"export function /* tree-shaking no-side-effects-when-called */ x(){ext()}",
"const x = ext; export {/* tree-shaking no-side-effects-when-called */ x}",
// // ExpressionStatement
// "ext()",
// // ForInStatement
// "for(ext in {a: 1}){}",
// "for(const x in ext()){}",
// "for(const x in {a: 1}){ext()}",
// "for(const x in {a: 1}) ext()",
// // ForOfStatement
// "for(ext of {a: 1}){}",
// "for(const x of ext()){}",
// "for(const x of {a: 1}){ext()}",
// "for(const x of {a: 1}) ext()",
// // ForStatement
// "for(ext();;){}",
// "for(;ext();){}",
// "for(;true;ext()){}",
// "for(;true;) ext()",
// "for(;true;){ext()}",
// ExpressionStatement
"ext()",
// ForInStatement
"for(ext in {a: 1}){}",
"for(const x in ext()){}",
"for(const x in {a: 1}){ext()}",
"for(const x in {a: 1}) ext()",
// ForOfStatement
"for(ext of {a: 1}){}",
"for(const x of ext()){}",
"for(const x of {a: 1}){ext()}",
"for(const x of {a: 1}) ext()",
// ForStatement
"for(ext();;){}",
"for(;ext();){}",
"for(;true;ext()){}",
"for(;true;) ext()",
"for(;true;){ext()}",
// // FunctionDeclaration when called
// "function x(){ext()}; x()",
// "function x(){ext()}; const y = new x()",

View file

@ -410,6 +410,90 @@ 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:1]
1 │ 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:5]
1 │ for(ext in {a: 1}){}
· ───
╰────
⚠ 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:16]
1 │ for(const x in 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:24]
1 │ for(const x in {a: 1}){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:24]
1 │ for(const x in {a: 1}) 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:5]
1 │ for(ext of {a: 1}){}
· ───
╰────
⚠ 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:16]
1 │ for(const x of 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:24]
1 │ for(const x of {a: 1}){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:24]
1 │ for(const x of {a: 1}) 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:5]
1 │ for(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:6]
1 │ for(;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:11]
1 │ for(;true;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 │ for(;true;) 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 │ for(;true;){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:5]
1 │ if (ext()>0){}