mirror of
https://github.com/oxc-project/oxc.git
synced 2026-11-04 10:29:58 +00:00
fix(linter/eslint/require-await): count await using as an await (#27080)
## Root cause
`AwaitFinder`
(`crates/oxc_linter/src/rules/eslint/require_await.rs:220-239`) only
sets `found` for `await` expressions and `for await`. An `await using`
declaration also awaits (the resource's disposal when the scope exits),
so an async function whose only await is `await using x = ...` or `for
(await using x of xs)` is reported.
The rule's dangerous fix then removes `async`, which leaves `await
using` outside an async function. With oxlint 1.85.0:
```js
// input
export async function f() {
await using x = getResource();
}
// after --fix-dangerously
export function f() {
await using x = getResource();
}
```
The fixed file no longer parses (`` `await` is only allowed within async
functions and at the top levels of modules ``). In a debug build the
same fix trips the fixer's syntax check
(`crates/oxc_linter/src/fixer/mod.rs:422`).
ESLint counts these declarations since eslint/eslint#19828
([`lib/rules/require-await.js#L180-L182`](https://github.com/eslint/eslint/blob/6fb3685bcbe9a6f72fd7dfb9129686b6fb96b0bd/lib/rules/require-await.js#L180-L182)):
```js
if (node.kind === "await using") {
scopeInfo.hasAwait = true;
}
```
## Notes
AI-assisted: I used Claude Code while investigating; I reviewed, ran and
verified every change myself.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Cameron <cameron.clark@hey.com>
This commit is contained in:
2 files changed
+32
-2
No files matched your search
@@ -2,10 +2,13 @@ use oxc_ast::{
|
||||
AstKind,
|
||||
ast::{
|
||||
ArrowFunctionExpression, AwaitExpression, ForOfStatement, Function, FunctionBody,
|
||||
FunctionType, MethodDefinition, ObjectProperty, PropertyKey,
|
||||
FunctionType, MethodDefinition, ObjectProperty, PropertyKey, VariableDeclaration,
|
||||
},
|
||||
};
|
||||
use oxc_ast_visit::{VisitJs, walk_js::walk_for_of_statement};
|
||||
use oxc_ast_visit::{
|
||||
VisitJs,
|
||||
walk_js::{walk_for_of_statement, walk_variable_declaration},
|
||||
};
|
||||
use oxc_diagnostics::OxcDiagnostic;
|
||||
use oxc_macros::declare_oxc_lint;
|
||||
use oxc_semantic::ScopeFlags;
|
||||
@@ -233,6 +236,14 @@ impl<'a> VisitJs<'a> for AwaitFinder {
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_variable_declaration(&mut self, decl: &VariableDeclaration<'a>) {
|
||||
if decl.kind.is_await() {
|
||||
self.found = true;
|
||||
} else {
|
||||
walk_variable_declaration(self, decl);
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_arrow_function_expression(&mut self, _expr: &ArrowFunctionExpression<'a>) {}
|
||||
|
||||
fn visit_function(&mut self, _func: &Function<'a>, _flags: ScopeFlags) {}
|
||||
@@ -287,6 +298,9 @@ fn test() {
|
||||
}
|
||||
};
|
||||
",
|
||||
"async function foo() { await using x = getResource() }",
|
||||
"async function foo() { { await using x = getResource() } }",
|
||||
"async function foo() { for (await using x of xs) {} }",
|
||||
];
|
||||
|
||||
let fail = vec![
|
||||
@@ -300,6 +314,8 @@ fn test() {
|
||||
"(class { async ''() { doSomething() } })",
|
||||
"async function foo() { async () => { await doSomething() } }",
|
||||
"async function foo() { await (async () => { doSomething() }) }",
|
||||
"async function foo() { using x = getResource() }",
|
||||
"async function foo() { async () => { await using x = getResource() } }",
|
||||
];
|
||||
|
||||
let fix = vec![
|
||||
|
||||
@@ -71,3 +71,17 @@ source: crates/oxc_linter/src/tester.rs
|
||||
· ─────────────────────────────
|
||||
╰────
|
||||
help: Consider removing the `async` keyword.
|
||||
|
||||
⚠ eslint(require-await): Async function has no `await` expression.
|
||||
╭─[require_await.mts:1:16]
|
||||
1 │ async function foo() { using x = getResource() }
|
||||
· ───
|
||||
╰────
|
||||
help: Consider removing the `async` keyword.
|
||||
|
||||
⚠ eslint(require-await): Async function has no `await` expression.
|
||||
╭─[require_await.mts:1:16]
|
||||
1 │ async function foo() { async () => { await using x = getResource() } }
|
||||
· ───
|
||||
╰────
|
||||
help: Consider removing the `async` keyword.
|
||||
Reference in new issue
Block a user