-
-
Notifications
You must be signed in to change notification settings - Fork 1.2k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(es/lints): Add
no-await-in-loop
rule (#4936)
- Loading branch information
1 parent
6fdf84d
commit b041f29
Showing
6 changed files
with
270 additions
and
0 deletions.
There are no files selected for viewing
9 changes: 9 additions & 0 deletions
9
crates/swc/tests/errors/lints/no-await-in-loop/default/.swcrc
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
{ | ||
"jsc": { | ||
"lints": { | ||
"no-await-in-loop": [ | ||
"error" | ||
] | ||
} | ||
} | ||
} |
29 changes: 29 additions & 0 deletions
29
crates/swc/tests/errors/lints/no-await-in-loop/default/input.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
async function foo() { while (baz) { await bar; } } | ||
async function foo() { while (await foo()) { } } | ||
async function foo() { while (baz) { for await (x of xs); } } | ||
async function foo() { for (var bar of baz) { await bar; } } | ||
async function foo() { for (var bar of baz) await bar; } | ||
async function foo() { for (var bar in baz) { await bar; } } | ||
async function foo() { for (var i; i < n; i++) { await bar; } } | ||
async function foo() { for (var i; await foo(i); i++) { } } | ||
async function foo() { for (var i; i < n; i = await bar) { } } | ||
async function foo() { do { await bar; } while (baz); } | ||
async function foo() { do { } while (await bar); } | ||
async function foo() { while (true) { if (bar) { foo(await bar); } } } | ||
async function foo() { while (xyz || 5 > await x) { } } | ||
async function foo() { for await (var x of xs) { while (1) await f(x) } } | ||
|
||
// valid | ||
async function foo() { await bar; } | ||
async function foo() { for (var bar in await baz) { } } | ||
async function foo() { for (var bar of await baz) { } } | ||
async function foo() { for await (var bar of await baz) { } } | ||
async function foo() { while (true) { async function foo() { await bar; } } } | ||
async function foo() { for (var i = await bar; i < n; i++) { } } | ||
async function foo() { do { } while (bar); } | ||
async function foo() { while (true) { var y = async function () { await bar; } } } | ||
async function foo() { while (true) { var y = async () => await foo; } } | ||
async function foo() { while (true) { var y = async () => { await foo; } } } | ||
async function foo() { while (true) { class Foo { async foo() { await bar; } } } } | ||
async function foo() { while (true) { class Foo { async foo() { await bar; } } } } | ||
async function foo() { for await (var x of xs) { await f(x) } } |
84 changes: 84 additions & 0 deletions
84
crates/swc/tests/errors/lints/no-await-in-loop/default/output.swc-stderr
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,84 @@ | ||
|
||
x Unexpected `await` inside a loop | ||
,---- | ||
1 | async function foo() { while (baz) { await bar; } } | ||
: ^^^^^^^^^ | ||
`---- | ||
|
||
x Unexpected `await` inside a loop | ||
,---- | ||
2 | async function foo() { while (await foo()) { } } | ||
: ^^^^^^^^^^^ | ||
`---- | ||
|
||
x Unexpected `await` inside a loop | ||
,---- | ||
3 | async function foo() { while (baz) { for await (x of xs); } } | ||
: ^^^^^^^^^^^^^^^^^^^^ | ||
`---- | ||
|
||
x Unexpected `await` inside a loop | ||
,---- | ||
4 | async function foo() { for (var bar of baz) { await bar; } } | ||
: ^^^^^^^^^ | ||
`---- | ||
|
||
x Unexpected `await` inside a loop | ||
,---- | ||
5 | async function foo() { for (var bar of baz) await bar; } | ||
: ^^^^^^^^^ | ||
`---- | ||
|
||
x Unexpected `await` inside a loop | ||
,---- | ||
6 | async function foo() { for (var bar in baz) { await bar; } } | ||
: ^^^^^^^^^ | ||
`---- | ||
|
||
x Unexpected `await` inside a loop | ||
,---- | ||
7 | async function foo() { for (var i; i < n; i++) { await bar; } } | ||
: ^^^^^^^^^ | ||
`---- | ||
|
||
x Unexpected `await` inside a loop | ||
,---- | ||
8 | async function foo() { for (var i; await foo(i); i++) { } } | ||
: ^^^^^^^^^^^^ | ||
`---- | ||
|
||
x Unexpected `await` inside a loop | ||
,---- | ||
9 | async function foo() { for (var i; i < n; i = await bar) { } } | ||
: ^^^^^^^^^ | ||
`---- | ||
|
||
x Unexpected `await` inside a loop | ||
,---- | ||
10 | async function foo() { do { await bar; } while (baz); } | ||
: ^^^^^^^^^ | ||
`---- | ||
|
||
x Unexpected `await` inside a loop | ||
,---- | ||
11 | async function foo() { do { } while (await bar); } | ||
: ^^^^^^^^^ | ||
`---- | ||
|
||
x Unexpected `await` inside a loop | ||
,---- | ||
12 | async function foo() { while (true) { if (bar) { foo(await bar); } } } | ||
: ^^^^^^^^^ | ||
`---- | ||
|
||
x Unexpected `await` inside a loop | ||
,---- | ||
13 | async function foo() { while (xyz || 5 > await x) { } } | ||
: ^^^^^^^ | ||
`---- | ||
|
||
x Unexpected `await` inside a loop | ||
,---- | ||
14 | async function foo() { for await (var x of xs) { while (1) await f(x) } } | ||
: ^^^^^^^^^^ | ||
`---- |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,139 @@ | ||
use swc_common::{errors::HANDLER, Span}; | ||
use swc_ecma_ast::*; | ||
use swc_ecma_visit::{Visit, VisitWith}; | ||
|
||
use crate::{ | ||
config::{LintRuleReaction, RuleConfig}, | ||
rule::{visitor_rule, Rule}, | ||
}; | ||
|
||
const MESSAGE: &str = "Unexpected `await` inside a loop"; | ||
|
||
pub fn no_await_in_loop(config: &RuleConfig<()>) -> Option<Box<dyn Rule>> { | ||
let rule_reaction = config.get_rule_reaction(); | ||
|
||
match rule_reaction { | ||
LintRuleReaction::Off => None, | ||
_ => Some(visitor_rule(NoAwaitInLoop::new(rule_reaction))), | ||
} | ||
} | ||
|
||
#[derive(Debug, Default)] | ||
struct NoAwaitInLoop { | ||
expected_reaction: LintRuleReaction, | ||
await_restricted: bool, | ||
} | ||
|
||
impl NoAwaitInLoop { | ||
fn new(expected_reaction: LintRuleReaction) -> Self { | ||
Self { | ||
expected_reaction, | ||
await_restricted: false, | ||
} | ||
} | ||
|
||
fn emit_report(&self, span: Span) { | ||
HANDLER.with(|handler| match self.expected_reaction { | ||
LintRuleReaction::Error => { | ||
handler.struct_span_err(span, MESSAGE).emit(); | ||
} | ||
LintRuleReaction::Warning => { | ||
handler.struct_span_warn(span, MESSAGE).emit(); | ||
} | ||
_ => {} | ||
}); | ||
} | ||
} | ||
|
||
impl Visit for NoAwaitInLoop { | ||
fn visit_for_stmt(&mut self, for_stmt: &ForStmt) { | ||
let prev_await_restriction = self.await_restricted; | ||
|
||
for_stmt.init.visit_children_with(self); | ||
|
||
self.await_restricted = true; | ||
|
||
for_stmt.test.visit_children_with(self); | ||
for_stmt.update.visit_children_with(self); | ||
for_stmt.body.visit_children_with(self); | ||
|
||
self.await_restricted = prev_await_restriction; | ||
} | ||
|
||
fn visit_do_while_stmt(&mut self, do_while_stmt: &DoWhileStmt) { | ||
let prev_await_restriction = self.await_restricted; | ||
|
||
self.await_restricted = true; | ||
|
||
do_while_stmt.body.visit_children_with(self); | ||
do_while_stmt.test.visit_children_with(self); | ||
|
||
self.await_restricted = prev_await_restriction; | ||
} | ||
|
||
fn visit_for_in_stmt(&mut self, for_in_stmt: &ForInStmt) { | ||
let prev_await_restriction = self.await_restricted; | ||
|
||
for_in_stmt.left.visit_children_with(self); | ||
for_in_stmt.right.visit_children_with(self); | ||
|
||
self.await_restricted = true; | ||
|
||
for_in_stmt.body.visit_children_with(self); | ||
|
||
self.await_restricted = prev_await_restriction; | ||
} | ||
|
||
fn visit_for_of_stmt(&mut self, for_of_stmt: &ForOfStmt) { | ||
let prev_await_restriction = self.await_restricted; | ||
|
||
if self.await_restricted { | ||
self.emit_report(for_of_stmt.span); | ||
} | ||
|
||
for_of_stmt.left.visit_children_with(self); | ||
for_of_stmt.right.visit_children_with(self); | ||
|
||
self.await_restricted = for_of_stmt.await_token.is_none(); | ||
|
||
for_of_stmt.body.visit_children_with(self); | ||
|
||
self.await_restricted = prev_await_restriction; | ||
} | ||
|
||
fn visit_while_stmt(&mut self, while_stmt: &WhileStmt) { | ||
let prev_await_restriction = self.await_restricted; | ||
self.await_restricted = true; | ||
|
||
while_stmt.test.visit_children_with(self); | ||
while_stmt.body.visit_children_with(self); | ||
|
||
self.await_restricted = prev_await_restriction; | ||
} | ||
|
||
fn visit_await_expr(&mut self, await_expr: &AwaitExpr) { | ||
if self.await_restricted { | ||
self.emit_report(await_expr.span); | ||
} | ||
|
||
await_expr.visit_children_with(self); | ||
} | ||
|
||
fn visit_function(&mut self, function: &Function) { | ||
let prev_await_restriction = self.await_restricted; | ||
self.await_restricted = false; | ||
|
||
function.visit_children_with(self); | ||
|
||
self.await_restricted = prev_await_restriction; | ||
} | ||
|
||
fn visit_arrow_expr(&mut self, arrow_expr: &ArrowExpr) { | ||
let prev_await_restriction = self.await_restricted; | ||
self.await_restricted = false; | ||
|
||
arrow_expr.visit_children_with(self); | ||
|
||
self.await_restricted = prev_await_restriction; | ||
} | ||
} |
b041f29
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Benchmark
es/full/minify/libraries/antd
1801856233
ns/iter (± 67535184
)1507053340
ns/iter (± 43955912
)1.20
es/full/minify/libraries/d3
449663924
ns/iter (± 3775355
)399078971
ns/iter (± 3284809
)1.13
es/full/minify/libraries/echarts
2319792247
ns/iter (± 44284565
)1788066709
ns/iter (± 11368754
)1.30
es/full/minify/libraries/jquery
98193511
ns/iter (± 2413158
)90628154
ns/iter (± 291175
)1.08
es/full/minify/libraries/lodash
135908126
ns/iter (± 1407229
)123771935
ns/iter (± 513729
)1.10
es/full/minify/libraries/moment
57053307
ns/iter (± 1174923
)52801410
ns/iter (± 127484
)1.08
es/full/minify/libraries/react
18215146
ns/iter (± 358057
)17667206
ns/iter (± 30452
)1.03
es/full/minify/libraries/terser
504202583
ns/iter (± 8284465
)459387347
ns/iter (± 1490363
)1.10
es/full/minify/libraries/three
624186581
ns/iter (± 23548179
)493314004
ns/iter (± 8598656
)1.27
es/full/minify/libraries/typescript
4262301967
ns/iter (± 25221516
)3412375968
ns/iter (± 9232633
)1.25
es/full/minify/libraries/victory
762201324
ns/iter (± 15040280
)662193216
ns/iter (± 6429348
)1.15
es/full/minify/libraries/vue
148445357
ns/iter (± 1762410
)135832803
ns/iter (± 521122
)1.09
es/full/codegen/es3
36204
ns/iter (± 1580
)34865
ns/iter (± 142
)1.04
es/full/codegen/es5
35508
ns/iter (± 1234
)34833
ns/iter (± 171
)1.02
es/full/codegen/es2015
34715
ns/iter (± 1428
)34901
ns/iter (± 153
)0.99
es/full/codegen/es2016
34082
ns/iter (± 1371
)34896
ns/iter (± 140
)0.98
es/full/codegen/es2017
34651
ns/iter (± 1586
)34907
ns/iter (± 136
)0.99
es/full/codegen/es2018
35408
ns/iter (± 1679
)34889
ns/iter (± 158
)1.01
es/full/codegen/es2019
34974
ns/iter (± 1303
)34879
ns/iter (± 107
)1.00
es/full/codegen/es2020
34432
ns/iter (± 1374
)34878
ns/iter (± 122
)0.99
es/full/all/es3
208220769
ns/iter (± 3963579
)189442398
ns/iter (± 810410
)1.10
es/full/all/es5
197687643
ns/iter (± 4165791
)178540437
ns/iter (± 914244
)1.11
es/full/all/es2015
158034904
ns/iter (± 3878207
)136962330
ns/iter (± 355443
)1.15
es/full/all/es2016
156554170
ns/iter (± 3243915
)136298934
ns/iter (± 369705
)1.15
es/full/all/es2017
153853669
ns/iter (± 3870914
)135503463
ns/iter (± 688799
)1.14
es/full/all/es2018
152434401
ns/iter (± 4092637
)133083999
ns/iter (± 12047467
)1.15
es/full/all/es2019
151666129
ns/iter (± 3539084
)132415002
ns/iter (± 402311
)1.15
es/full/all/es2020
146675726
ns/iter (± 3248459
)126632982
ns/iter (± 649418
)1.16
es/full/parser
607017
ns/iter (± 55977
)578363
ns/iter (± 45194
)1.05
es/full/base/fixer
29157
ns/iter (± 1279
)25670
ns/iter (± 240
)1.14
es/full/base/resolver_and_hygiene
143821
ns/iter (± 7008
)140095
ns/iter (± 1991
)1.03
serialization of ast node
185
ns/iter (± 6
)182
ns/iter (± 23
)1.02
serialization of serde
192
ns/iter (± 7
)184
ns/iter (± 0
)1.04
This comment was automatically generated by workflow using github-action-benchmark.