1
1
use oxc_ast:: AstKind ;
2
2
use oxc_diagnostics:: OxcDiagnostic ;
3
3
use oxc_macros:: declare_oxc_lint;
4
- use oxc_semantic:: NodeId ;
5
- use oxc_span:: Span ;
4
+ use oxc_span:: { GetSpan , Span } ;
6
5
7
6
use crate :: { context:: LintContext , rule:: Rule , AstNode } ;
8
7
9
- fn no_async_await_diagnostic ( span : Span ) -> OxcDiagnostic {
10
- OxcDiagnostic :: warn ( "Unexpected async/await " )
11
- . with_help ( "Async/await is not allowed " )
8
+ fn no_async_diagnostic ( span : Span ) -> OxcDiagnostic {
9
+ OxcDiagnostic :: warn ( "async is not allowed " )
10
+ . with_help ( "Remove the `async` keyword " )
12
11
. with_label ( span)
13
12
}
14
13
@@ -37,29 +36,58 @@ impl Rule for NoAsyncAwait {
37
36
match node. kind ( ) {
38
37
AstKind :: Function ( func_decl) => {
39
38
if func_decl. r#async {
40
- report ( node. id ( ) , func_decl. span , ctx) ;
39
+ let parent_kind = ctx. nodes ( ) . parent_kind ( node. id ( ) ) ;
40
+ let async_span = match & func_decl. id {
41
+ // named function like `async function run() {}`
42
+ Some ( id) => Span :: new ( func_decl. span . start , id. span . end ) ,
43
+ // anonymous function like `async function() {}`
44
+ None => match parent_kind {
45
+ // Actually part of a method definition like:
46
+ // ```
47
+ // class Foo {
48
+ // async bar() {}
49
+ // }
50
+ // ```
51
+ Some ( AstKind :: MethodDefinition ( method_def) ) => {
52
+ Span :: new ( method_def. span . start , method_def. key . span ( ) . start )
53
+ }
54
+ // The function is part of an object property like:
55
+ // ```
56
+ // const obj = {
57
+ // async foo() {}
58
+ // };
59
+ // ```
60
+ Some ( AstKind :: ObjectProperty ( obj_prop) ) => {
61
+ Span :: new ( obj_prop. span . start , obj_prop. key . span ( ) . start )
62
+ }
63
+ _ => func_decl. span ,
64
+ } ,
65
+ } ;
66
+ report_on_async_span ( async_span, ctx) ;
41
67
}
42
68
}
43
69
AstKind :: ArrowFunctionExpression ( arrow_expr) => {
44
70
if arrow_expr. r#async {
45
- report ( node. id ( ) , arrow_expr. span , ctx) ;
71
+ let async_span = Span :: new ( arrow_expr. span . start , arrow_expr. params . span . start ) ;
72
+ report_on_async_span ( async_span, ctx) ;
46
73
}
47
74
}
48
75
_ => { }
49
76
}
50
77
}
51
78
}
52
79
53
- fn report ( node_id : NodeId , func_span : Span , ctx : & LintContext < ' _ > ) {
54
- /// "async".len()
55
- const ASYNC_LEN : u32 = 5 ;
80
+ /// "async".len()
81
+ const ASYNC_LEN : u32 = 5 ;
56
82
57
- let parent = ctx. nodes ( ) . parent_kind ( node_id) ;
58
- if let Some ( AstKind :: ObjectProperty ( obj_prop) ) = parent {
59
- ctx. diagnostic ( no_async_await_diagnostic ( Span :: sized ( obj_prop. span . start , ASYNC_LEN ) ) ) ;
60
- } else {
61
- ctx. diagnostic ( no_async_await_diagnostic ( Span :: sized ( func_span. start , ASYNC_LEN ) ) ) ;
62
- }
83
+ #[ allow( clippy:: cast_possible_truncation) ]
84
+ fn report_on_async_span ( async_span : Span , ctx : & LintContext < ' _ > ) {
85
+ // find the `async` keyword within the span and report on it
86
+ let Some ( async_keyword_offset) = ctx. source_range ( async_span) . find ( "async" ) else {
87
+ return ;
88
+ } ;
89
+ let async_keyword_span = Span :: sized ( async_span. start + async_keyword_offset as u32 , ASYNC_LEN ) ;
90
+ ctx. diagnostic ( no_async_diagnostic ( async_keyword_span) ) ;
63
91
}
64
92
65
93
#[ test]
@@ -71,6 +99,9 @@ fn test() {
71
99
"const foo = () => {}" ,
72
100
"function foo () { return bar(); }" ,
73
101
"class Foo { foo() {} }" ,
102
+ "class async { }" ,
103
+ "const async = {};" ,
104
+ "class async { async() { async(); } }" ,
74
105
] ;
75
106
76
107
let fail = vec ! [
@@ -83,7 +114,6 @@ fn test() {
83
114
async test() {}
84
115
};
85
116
" ,
86
- // FIXME: diagnostics on method `foo` have incorrect spans
87
117
"
88
118
class Foo {
89
119
async foo() {}
@@ -94,12 +124,29 @@ fn test() {
94
124
public async foo() {}
95
125
}
96
126
" ,
97
- // this one is fine
98
127
"
99
128
const obj = {
100
129
async foo() {}
101
130
}
102
131
" ,
132
+ "
133
+ class async {
134
+ async async() {
135
+ async();
136
+ }
137
+ }
138
+ " ,
139
+ "
140
+ class async {
141
+ async async() {
142
+ function async() {
143
+ const async = {
144
+ async: async () => {},
145
+ }
146
+ }
147
+ }
148
+ }
149
+ " ,
103
150
] ;
104
151
105
152
Tester :: new ( NoAsyncAwait :: NAME , NoAsyncAwait :: PLUGIN , pass, fail) . test_and_snapshot ( ) ;
0 commit comments