diff --git a/crates/oxc_linter/src/rules/eslint/no_unused_vars/tests/oxc.rs b/crates/oxc_linter/src/rules/eslint/no_unused_vars/tests/oxc.rs index 2b5bad289e..ac1ae24d0d 100644 --- a/crates/oxc_linter/src/rules/eslint/no_unused_vars/tests/oxc.rs +++ b/crates/oxc_linter/src/rules/eslint/no_unused_vars/tests/oxc.rs @@ -246,6 +246,24 @@ fn test_vars_self_use_js() { .test(); } +#[test] +fn discarded_instance_initializers() { + let pass = vec![ + "let f = () => 0; (class { static field = f() }, 0);", + "let f = () => 0; (class { [f()] = 0 }, 0);", + "let f = () => 0; (class { static accessor field = f() }, 0);", + "let f = () => 0; (class { accessor [f()] = 0 }, 0);", + ]; + let fail = vec![ + "let C; (C = class { field = new C() }, 0);", + "let C; (C = class { accessor field = new C() }, 0);", + ]; + + Tester::new(NoUnusedVars::NAME, NoUnusedVars::PLUGIN, pass, fail) + .intentionally_allow_no_fix_tests() + .test(); +} + #[test] fn test_vars_discarded_reads() { let pass = vec![ @@ -307,6 +325,18 @@ fn test_vars_discarded_reads() { ); };", + "let a = (v) => v; module.exports = (x, y) => (x ? a(y) : 0, y);", + "let a = (v) => v; module.exports = (x, y) => (x ? 0 : a(y), y);", + "let a = (v) => v; module.exports = (x, y) => (x && a(y), y);", + "let a = (v) => v; module.exports = (x, y) => (x || a(y), y);", + "let a = (v) => v; module.exports = (x, y) => (x ?? a(y), y);", + "module.exports = (x, y, a) => (x ? a(y) : 0, y);", + "module.exports = (x, y, a) => (x && a(y), y);", + "module.exports = (x, y, a) => (x ? new a(y) : 0, y);", + "module.exports = (x, y, a) => (x ? a?.(y) : 0, y);", + "module.exports = (x, y, a) => (x ? (0, a)(y) : 0, y);", + "module.exports = (x, y, a) => (x ? a((y, 0)) : 0, y);", + "module.exports = (x, y, a) => (x ? (a(y), 0) : 0, y);", ]; let fail = vec![ diff --git a/crates/oxc_linter/src/rules/eslint/no_unused_vars/usage.rs b/crates/oxc_linter/src/rules/eslint/no_unused_vars/usage.rs index 92fdec9af9..a31cc05dc6 100644 --- a/crates/oxc_linter/src/rules/eslint/no_unused_vars/usage.rs +++ b/crates/oxc_linter/src/rules/eslint/no_unused_vars/usage.rs @@ -748,11 +748,33 @@ impl<'a> Symbol<'_, 'a> { return false; } + let mut is_call_result = false; for (parent, grandparent) in self.iter_relevant_parent_and_grandparent_kinds(reference.node_id()) { let ref_span = || self.get_ref_span(reference); + if match parent { + AstKind::Function(_) | AstKind::ArrowFunctionExpression(_) => true, + AstKind::PropertyDefinition(property) => { + !property.r#static + && property + .value + .as_ref() + .is_some_and(|value| value.span().contains_inclusive(ref_span())) + } + AstKind::AccessorProperty(property) => { + !property.r#static + && property + .value + .as_ref() + .is_some_and(|value| value.span().contains_inclusive(ref_span())) + } + _ => false, + } { + is_call_result = false; + } + match (parent, grandparent) { // (foo.bar = new Foo(a), f(b)) // `a` should not be considered discarded @@ -764,6 +786,7 @@ impl<'a> Symbol<'_, 'a> { AstKind::CallExpression(_) | AstKind::NewExpression(_), ) => { if id.span == ref_span() { + is_call_result = true; continue; } break; @@ -814,13 +837,14 @@ impl<'a> Symbol<'_, 'a> { return false; } (parent, AstKind::SequenceExpression(seq)) => { - if matches!( - parent, - AstKind::CallExpression(_) - | AstKind::AwaitExpression(_) - | AstKind::YieldExpression(_) - | AstKind::ChainExpression(_) - ) { + if is_call_result + || matches!( + parent, + AstKind::AwaitExpression(_) + | AstKind::YieldExpression(_) + | AstKind::ChainExpression(_) + ) + { continue; }