mirror of
https://github.com/danbulant/oxc
synced 2026-05-19 12:19:15 +00:00
fix(linter): fix diagnostic spans for oxc/no-async-await (#8721)
Fixes broken diagnostic spans for async functions that did not correctly report on the `async` keyword. I changed the diagnostic reporting to look for the `async` keyword itself within a given span which is a little slower but worth it for accuracy I think. I also updated the diagnostic to be async-specific as we don't report on await yet.
This commit is contained in:
parent
d318238cd2
commit
77ef61a68e
2 changed files with 112 additions and 38 deletions
|
|
@ -1,14 +1,13 @@
|
|||
use oxc_ast::AstKind;
|
||||
use oxc_diagnostics::OxcDiagnostic;
|
||||
use oxc_macros::declare_oxc_lint;
|
||||
use oxc_semantic::NodeId;
|
||||
use oxc_span::Span;
|
||||
use oxc_span::{GetSpan, Span};
|
||||
|
||||
use crate::{context::LintContext, rule::Rule, AstNode};
|
||||
|
||||
fn no_async_await_diagnostic(span: Span) -> OxcDiagnostic {
|
||||
OxcDiagnostic::warn("Unexpected async/await")
|
||||
.with_help("Async/await is not allowed")
|
||||
fn no_async_diagnostic(span: Span) -> OxcDiagnostic {
|
||||
OxcDiagnostic::warn("async is not allowed")
|
||||
.with_help("Remove the `async` keyword")
|
||||
.with_label(span)
|
||||
}
|
||||
|
||||
|
|
@ -37,12 +36,40 @@ impl Rule for NoAsyncAwait {
|
|||
match node.kind() {
|
||||
AstKind::Function(func_decl) => {
|
||||
if func_decl.r#async {
|
||||
report(node.id(), func_decl.span, ctx);
|
||||
let parent_kind = ctx.nodes().parent_kind(node.id());
|
||||
let async_span = match &func_decl.id {
|
||||
// named function like `async function run() {}`
|
||||
Some(id) => Span::new(func_decl.span.start, id.span.end),
|
||||
// anonymous function like `async function() {}`
|
||||
None => match parent_kind {
|
||||
// Actually part of a method definition like:
|
||||
// ```
|
||||
// class Foo {
|
||||
// async bar() {}
|
||||
// }
|
||||
// ```
|
||||
Some(AstKind::MethodDefinition(method_def)) => {
|
||||
Span::new(method_def.span.start, method_def.key.span().start)
|
||||
}
|
||||
// The function is part of an object property like:
|
||||
// ```
|
||||
// const obj = {
|
||||
// async foo() {}
|
||||
// };
|
||||
// ```
|
||||
Some(AstKind::ObjectProperty(obj_prop)) => {
|
||||
Span::new(obj_prop.span.start, obj_prop.key.span().start)
|
||||
}
|
||||
_ => func_decl.span,
|
||||
},
|
||||
};
|
||||
report_on_async_span(async_span, ctx);
|
||||
}
|
||||
}
|
||||
AstKind::ArrowFunctionExpression(arrow_expr) => {
|
||||
if arrow_expr.r#async {
|
||||
report(node.id(), arrow_expr.span, ctx);
|
||||
let async_span = Span::new(arrow_expr.span.start, arrow_expr.params.span.start);
|
||||
report_on_async_span(async_span, ctx);
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
|
|
@ -50,16 +77,17 @@ impl Rule for NoAsyncAwait {
|
|||
}
|
||||
}
|
||||
|
||||
fn report(node_id: NodeId, func_span: Span, ctx: &LintContext<'_>) {
|
||||
/// "async".len()
|
||||
const ASYNC_LEN: u32 = 5;
|
||||
/// "async".len()
|
||||
const ASYNC_LEN: u32 = 5;
|
||||
|
||||
let parent = ctx.nodes().parent_kind(node_id);
|
||||
if let Some(AstKind::ObjectProperty(obj_prop)) = parent {
|
||||
ctx.diagnostic(no_async_await_diagnostic(Span::sized(obj_prop.span.start, ASYNC_LEN)));
|
||||
} else {
|
||||
ctx.diagnostic(no_async_await_diagnostic(Span::sized(func_span.start, ASYNC_LEN)));
|
||||
}
|
||||
#[allow(clippy::cast_possible_truncation)]
|
||||
fn report_on_async_span(async_span: Span, ctx: &LintContext<'_>) {
|
||||
// find the `async` keyword within the span and report on it
|
||||
let Some(async_keyword_offset) = ctx.source_range(async_span).find("async") else {
|
||||
return;
|
||||
};
|
||||
let async_keyword_span = Span::sized(async_span.start + async_keyword_offset as u32, ASYNC_LEN);
|
||||
ctx.diagnostic(no_async_diagnostic(async_keyword_span));
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
@ -71,6 +99,9 @@ fn test() {
|
|||
"const foo = () => {}",
|
||||
"function foo () { return bar(); }",
|
||||
"class Foo { foo() {} }",
|
||||
"class async { }",
|
||||
"const async = {};",
|
||||
"class async { async() { async(); } }",
|
||||
];
|
||||
|
||||
let fail = vec![
|
||||
|
|
@ -83,7 +114,6 @@ fn test() {
|
|||
async test() {}
|
||||
};
|
||||
",
|
||||
// FIXME: diagnostics on method `foo` have incorrect spans
|
||||
"
|
||||
class Foo {
|
||||
async foo() {}
|
||||
|
|
@ -94,12 +124,29 @@ fn test() {
|
|||
public async foo() {}
|
||||
}
|
||||
",
|
||||
// this one is fine
|
||||
"
|
||||
const obj = {
|
||||
async foo() {}
|
||||
}
|
||||
",
|
||||
"
|
||||
class async {
|
||||
async async() {
|
||||
async();
|
||||
}
|
||||
}
|
||||
",
|
||||
"
|
||||
class async {
|
||||
async async() {
|
||||
function async() {
|
||||
const async = {
|
||||
async: async () => {},
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
",
|
||||
];
|
||||
|
||||
Tester::new(NoAsyncAwait::NAME, NoAsyncAwait::PLUGIN, pass, fail).test_and_snapshot();
|
||||
|
|
|
|||
|
|
@ -1,66 +1,93 @@
|
|||
---
|
||||
source: crates/oxc_linter/src/tester.rs
|
||||
---
|
||||
⚠ oxc(no-async-await): Unexpected async/await
|
||||
⚠ oxc(no-async-await): async is not allowed
|
||||
╭─[no_async_await.tsx:1:1]
|
||||
1 │ async function foo() {}
|
||||
· ─────
|
||||
╰────
|
||||
help: Async/await is not allowed
|
||||
help: Remove the `async` keyword
|
||||
|
||||
⚠ oxc(no-async-await): Unexpected async/await
|
||||
⚠ oxc(no-async-await): async is not allowed
|
||||
╭─[no_async_await.tsx:1:13]
|
||||
1 │ const foo = async () => {}
|
||||
· ─────
|
||||
╰────
|
||||
help: Async/await is not allowed
|
||||
help: Remove the `async` keyword
|
||||
|
||||
⚠ oxc(no-async-await): Unexpected async/await
|
||||
⚠ oxc(no-async-await): async is not allowed
|
||||
╭─[no_async_await.tsx:1:1]
|
||||
1 │ async () => {}
|
||||
· ─────
|
||||
╰────
|
||||
help: Async/await is not allowed
|
||||
help: Remove the `async` keyword
|
||||
|
||||
⚠ oxc(no-async-await): Unexpected async/await
|
||||
⚠ oxc(no-async-await): async is not allowed
|
||||
╭─[no_async_await.tsx:1:14]
|
||||
1 │ const test = async () => {};
|
||||
· ─────
|
||||
╰────
|
||||
help: Async/await is not allowed
|
||||
help: Remove the `async` keyword
|
||||
|
||||
⚠ oxc(no-async-await): Unexpected async/await
|
||||
⚠ oxc(no-async-await): async is not allowed
|
||||
╭─[no_async_await.tsx:3:17]
|
||||
2 │ const test = {
|
||||
3 │ async test() {}
|
||||
· ─────
|
||||
4 │ };
|
||||
╰────
|
||||
help: Async/await is not allowed
|
||||
help: Remove the `async` keyword
|
||||
|
||||
⚠ oxc(no-async-await): Unexpected async/await
|
||||
╭─[no_async_await.tsx:3:22]
|
||||
⚠ oxc(no-async-await): async is not allowed
|
||||
╭─[no_async_await.tsx:3:13]
|
||||
2 │ class Foo {
|
||||
3 │ async foo() {}
|
||||
· ─────
|
||||
· ─────
|
||||
4 │ }
|
||||
╰────
|
||||
help: Async/await is not allowed
|
||||
help: Remove the `async` keyword
|
||||
|
||||
⚠ oxc(no-async-await): Unexpected async/await
|
||||
╭─[no_async_await.tsx:3:29]
|
||||
⚠ oxc(no-async-await): async is not allowed
|
||||
╭─[no_async_await.tsx:3:20]
|
||||
2 │ class Foo {
|
||||
3 │ public async foo() {}
|
||||
· ─────
|
||||
· ─────
|
||||
4 │ }
|
||||
╰────
|
||||
help: Async/await is not allowed
|
||||
help: Remove the `async` keyword
|
||||
|
||||
⚠ oxc(no-async-await): Unexpected async/await
|
||||
⚠ oxc(no-async-await): async is not allowed
|
||||
╭─[no_async_await.tsx:3:13]
|
||||
2 │ const obj = {
|
||||
3 │ async foo() {}
|
||||
· ─────
|
||||
4 │ }
|
||||
╰────
|
||||
help: Async/await is not allowed
|
||||
help: Remove the `async` keyword
|
||||
|
||||
⚠ oxc(no-async-await): async is not allowed
|
||||
╭─[no_async_await.tsx:3:13]
|
||||
2 │ class async {
|
||||
3 │ async async() {
|
||||
· ─────
|
||||
4 │ async();
|
||||
╰────
|
||||
help: Remove the `async` keyword
|
||||
|
||||
⚠ oxc(no-async-await): async is not allowed
|
||||
╭─[no_async_await.tsx:3:13]
|
||||
2 │ class async {
|
||||
3 │ async async() {
|
||||
· ─────
|
||||
4 │ function async() {
|
||||
╰────
|
||||
help: Remove the `async` keyword
|
||||
|
||||
⚠ oxc(no-async-await): async is not allowed
|
||||
╭─[no_async_await.tsx:6:32]
|
||||
5 │ const async = {
|
||||
6 │ async: async () => {},
|
||||
· ─────
|
||||
7 │ }
|
||||
╰────
|
||||
help: Remove the `async` keyword
|
||||
|
|
|
|||
Loading…
Reference in a new issue