mirror of
https://github.com/oxc-project/oxc.git
synced 2026-11-04 10:29:58 +00:00
fix(linter/eslint/no-unused-vars): count conditional calls in sequences as uses (#27755)
Calls such as `(x ? a(y) : 0, y)` and `(x && a(y), y)` consume `a` even though their results are discarded. Track that consumption through surrounding expressions, resetting at function boundaries so discarded self-referencing closures remain unused, matching ESLint. Addresses report 1 (`eslint/no-unused-vars`) in #27746.
This commit is contained in:
1 parent
7f22fa0d8c
commit
2c671979b5
2 files changed
+61
-7
No files matched your search
@@ -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() {
|
||||
<button onClick={() => (onDismiss?.(), remove())}>x</button>
|
||||
);
|
||||
};",
|
||||
"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![
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user