Skip to content

Commit 2304cd8

Browse files
authoredFeb 27, 2025··
fix(es/lints): Capture errors and emit from the original thread (#10119)
**Description:** This is to avoid potential regressions due to implementation details of `swc_common::errors::Emitter`.
1 parent 62b2526 commit 2304cd8

File tree

10 files changed

+191
-152
lines changed

10 files changed

+191
-152
lines changed
 

‎.changeset/plenty-worms-yawn.md

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
swc_core: patch
3+
swc_ecma_lints: patch
4+
---
5+
6+
fix(es/lints): Capture errors and emit from the original thread

‎.changset/foo.md

Whitespace-only changes.

‎crates/swc/tests/errors/lints/constructor-super/default/output.swc-stderr

+61-61
Original file line numberDiff line numberDiff line change
@@ -1,64 +1,3 @@
1-
x the name `A30` is defined multiple times
2-
,-[29:1]
3-
26 | class A27 { constructor() { for (let i = 0; i < a.length; i++) { super(); } super(); } }
4-
27 | class A28 extends B { constructor() { return; super(); } }
5-
28 | class A29 extends B { constructor() { try { super(); } catch (e) { } } }
6-
29 | class A30 extends B { constructor() { try { } catch (e) { super(); } } }
7-
: ^|^
8-
: `-- previous definition of `A30` here
9-
30 | class A31 extends B { constructor() { try { } catch (e) { super(); } super(); } }
10-
31 | class A30 extends B { constructor() { try { super(); } catch (e) { } finally { super() } } }
11-
: ^|^
12-
: `-- `A30` redefined here
13-
32 |
14-
33 |
15-
34 | // valid
16-
`----
17-
x the name `A9` is defined multiple times
18-
,-[9:1]
19-
6 | class A6 extends (B && 5) { constructor() { super(); } }
20-
7 | class A7 extends (B &&= 5) { constructor() { super(); } }
21-
8 | class A8 extends (B += C) { constructor() { super(); } }
22-
9 | class A9 extends (B -= C) { constructor() { super(); } }
23-
: ^|
24-
: `-- previous definition of `A9` here
25-
10 | class A10 extends (B **= C) { constructor() { super(); } }
26-
11 | class A11 extends (B |= C) { constructor() { super(); } }
27-
12 | class A12 extends (B &= C) { constructor() { super(); } }
28-
13 | class A13 extends B { constructor() { } }
29-
14 | class A14 extends B { constructor() { for (var a of b) super.foo(); } }
30-
15 | class A15 extends B { constructor() { class C extends D { constructor() { super(); } } } }
31-
16 | class A16 extends B { constructor() { var c = class extends D { constructor() { super(); } } } }
32-
17 | class A17 extends B { constructor() { var c = () => super(); } }
33-
18 | class A18 extends B { constructor() { class C extends D { constructor() { super(); } } } }
34-
19 | class A19 extends B { constructor() { var C = class extends D { constructor() { super(); } } } }
35-
20 | class A20 extends B { constructor() { super(); class C extends D { constructor() { } } } }
36-
21 | class A21 extends B { constructor() { super(); var C = class extends D { constructor() { } } } }
37-
22 | class A23 extends B { constructor() { if (a) super(); } }
38-
23 | class A24 extends B { constructor() { x ? super() : null; } }
39-
24 | class A25 extends B { constructor() { switch (x) { case 'a': super(); } } }
40-
25 | class A26 { constructor() { for (let i = 0; i < a.length; i++) { super(); } } }
41-
26 | class A27 { constructor() { for (let i = 0; i < a.length; i++) { super(); } super(); } }
42-
27 | class A28 extends B { constructor() { return; super(); } }
43-
28 | class A29 extends B { constructor() { try { super(); } catch (e) { } } }
44-
29 | class A30 extends B { constructor() { try { } catch (e) { super(); } } }
45-
30 | class A31 extends B { constructor() { try { } catch (e) { super(); } super(); } }
46-
31 | class A30 extends B { constructor() { try { super(); } catch (e) { } finally { super() } } }
47-
32 |
48-
33 |
49-
34 | // valid
50-
35 | class V1 extends (B, C) { constructor() { super(); } }
51-
36 | class V2 extends (class B { }) { constructor() { super(); } }
52-
37 | class V3 { constructor() { class B extends C { constructor() { super(); } } } }
53-
38 | class V4 extends Object { constructor() { super(); for (let i = 0; i < 0; i++); } }
54-
39 | class V5 { }
55-
40 | class V6 { constructor() { } }
56-
41 | class V7 extends null { }
57-
42 | class V8 { constructor() { } }
58-
43 | class A9 extends B { constructor() { try { } finally { super(); } } }
59-
: ^|
60-
: `-- `A9` redefined here
61-
`----
621
x Unexpected 'super()' because 'super' is not a constructor
632
,-[1:1]
643
1 | class A1 extends null { constructor() { super(); } }
@@ -381,6 +320,22 @@
381320
31 | class A30 extends B { constructor() { try { super(); } catch (e) { } finally { super() } } }
382321
32 |
383322
`----
323+
x the name `A30` is defined multiple times
324+
,-[29:1]
325+
26 | class A27 { constructor() { for (let i = 0; i < a.length; i++) { super(); } super(); } }
326+
27 | class A28 extends B { constructor() { return; super(); } }
327+
28 | class A29 extends B { constructor() { try { super(); } catch (e) { } } }
328+
29 | class A30 extends B { constructor() { try { } catch (e) { super(); } } }
329+
: ^|^
330+
: `-- previous definition of `A30` here
331+
30 | class A31 extends B { constructor() { try { } catch (e) { super(); } super(); } }
332+
31 | class A30 extends B { constructor() { try { super(); } catch (e) { } finally { super() } } }
333+
: ^|^
334+
: `-- `A30` redefined here
335+
32 |
336+
33 |
337+
34 | // valid
338+
`----
384339
x Unexpected duplicate 'super()'
385340
,-[31:1]
386341
28 | class A29 extends B { constructor() { try { super(); } catch (e) { } } }
@@ -392,3 +347,48 @@
392347
33 |
393348
34 | // valid
394349
`----
350+
x the name `A9` is defined multiple times
351+
,-[9:1]
352+
6 | class A6 extends (B && 5) { constructor() { super(); } }
353+
7 | class A7 extends (B &&= 5) { constructor() { super(); } }
354+
8 | class A8 extends (B += C) { constructor() { super(); } }
355+
9 | class A9 extends (B -= C) { constructor() { super(); } }
356+
: ^|
357+
: `-- previous definition of `A9` here
358+
10 | class A10 extends (B **= C) { constructor() { super(); } }
359+
11 | class A11 extends (B |= C) { constructor() { super(); } }
360+
12 | class A12 extends (B &= C) { constructor() { super(); } }
361+
13 | class A13 extends B { constructor() { } }
362+
14 | class A14 extends B { constructor() { for (var a of b) super.foo(); } }
363+
15 | class A15 extends B { constructor() { class C extends D { constructor() { super(); } } } }
364+
16 | class A16 extends B { constructor() { var c = class extends D { constructor() { super(); } } } }
365+
17 | class A17 extends B { constructor() { var c = () => super(); } }
366+
18 | class A18 extends B { constructor() { class C extends D { constructor() { super(); } } } }
367+
19 | class A19 extends B { constructor() { var C = class extends D { constructor() { super(); } } } }
368+
20 | class A20 extends B { constructor() { super(); class C extends D { constructor() { } } } }
369+
21 | class A21 extends B { constructor() { super(); var C = class extends D { constructor() { } } } }
370+
22 | class A23 extends B { constructor() { if (a) super(); } }
371+
23 | class A24 extends B { constructor() { x ? super() : null; } }
372+
24 | class A25 extends B { constructor() { switch (x) { case 'a': super(); } } }
373+
25 | class A26 { constructor() { for (let i = 0; i < a.length; i++) { super(); } } }
374+
26 | class A27 { constructor() { for (let i = 0; i < a.length; i++) { super(); } super(); } }
375+
27 | class A28 extends B { constructor() { return; super(); } }
376+
28 | class A29 extends B { constructor() { try { super(); } catch (e) { } } }
377+
29 | class A30 extends B { constructor() { try { } catch (e) { super(); } } }
378+
30 | class A31 extends B { constructor() { try { } catch (e) { super(); } super(); } }
379+
31 | class A30 extends B { constructor() { try { super(); } catch (e) { } finally { super() } } }
380+
32 |
381+
33 |
382+
34 | // valid
383+
35 | class V1 extends (B, C) { constructor() { super(); } }
384+
36 | class V2 extends (class B { }) { constructor() { super(); } }
385+
37 | class V3 { constructor() { class B extends C { constructor() { super(); } } } }
386+
38 | class V4 extends Object { constructor() { super(); for (let i = 0; i < 0; i++); } }
387+
39 | class V5 { }
388+
40 | class V6 { constructor() { } }
389+
41 | class V7 extends null { }
390+
42 | class V8 { constructor() { } }
391+
43 | class A9 extends B { constructor() { try { } finally { super(); } } }
392+
: ^|
393+
: `-- `A9` redefined here
394+
`----

‎crates/swc/tests/errors/lints/no-loop-func/default/output.swc-stderr

+34-34
Original file line numberDiff line numberDiff line change
@@ -1,37 +1,3 @@
1-
x the name `a` is defined multiple times
2-
,-[36:1]
3-
33 | }
4-
34 |
5-
35 | // Not ok
6-
36 | let a; for (let i in {}) { (function() { a; }); a = 1; }
7-
: |
8-
: `-- previous definition of `a` here
9-
37 |
10-
38 | // interview example =)
11-
39 | for (var i = 0; i < 10; i++) {
12-
40 | setTimeout(() => {
13-
41 | console.log(i);
14-
42 | })
15-
43 | }
16-
44 |
17-
45 | // it's ok
18-
46 | while (cond) {
19-
47 | let x = 10;
20-
48 |
21-
49 | function ee() {
22-
50 | alert(x);
23-
51 | }
24-
52 | }
25-
53 |
26-
54 | // not ok
27-
55 | while (true) {
28-
56 | var a = 0;
29-
: |
30-
: `-- `a` redefined here
31-
57 |
32-
58 | while (true) {
33-
59 | setTimeout(() => {
34-
`----
351
x Function declared in a loop contains unsafe references to variable i
362
,-[9:1]
373
6 |
@@ -77,6 +43,40 @@
7743
44 |
7844
45 | // it's ok
7945
`----
46+
x the name `a` is defined multiple times
47+
,-[36:1]
48+
33 | }
49+
34 |
50+
35 | // Not ok
51+
36 | let a; for (let i in {}) { (function() { a; }); a = 1; }
52+
: |
53+
: `-- previous definition of `a` here
54+
37 |
55+
38 | // interview example =)
56+
39 | for (var i = 0; i < 10; i++) {
57+
40 | setTimeout(() => {
58+
41 | console.log(i);
59+
42 | })
60+
43 | }
61+
44 |
62+
45 | // it's ok
63+
46 | while (cond) {
64+
47 | let x = 10;
65+
48 |
66+
49 | function ee() {
67+
50 | alert(x);
68+
51 | }
69+
52 | }
70+
53 |
71+
54 | // not ok
72+
55 | while (true) {
73+
56 | var a = 0;
74+
: |
75+
: `-- `a` redefined here
76+
57 |
77+
58 | while (true) {
78+
59 | setTimeout(() => {
79+
`----
8080
x Function declared in a loop contains unsafe references to variable a
8181
,-[59:1]
8282
56 | var a = 0;

‎crates/swc/tests/errors/lints/no-prototype-builtins/default/output.swc-stderr

+2-2
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,7 @@
140140
27 | (foo?.anotherProp, foo?.hasOwnProperty)('bar');
141141
28 |
142142
29 | (foo.hasOwnProperty('ok'), foo?.hasOwnProperty)('bar');
143-
: ^^^^^^^^^^^^^^
143+
: ^^^^^^^^^^^^^^
144144
30 |
145145
31 | foo['hasOwnProperty']('bar');
146146
`----
@@ -150,7 +150,7 @@
150150
27 | (foo?.anotherProp, foo?.hasOwnProperty)('bar');
151151
28 |
152152
29 | (foo.hasOwnProperty('ok'), foo?.hasOwnProperty)('bar');
153-
: ^^^^^^^^^^^^^^
153+
: ^^^^^^^^^^^^^^
154154
30 |
155155
31 | foo['hasOwnProperty']('bar');
156156
`----
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,4 @@
11
//// [multipleDefaultExports03.ts]
2-
//! x the name `C` is defined multiple times
3-
//! ,-[2:1]
4-
//! 1 |
5-
//! 2 | export default class C {
6-
//! : |
7-
//! : `-- previous definition of `C` here
8-
//! 3 | }
9-
//! 4 |
10-
//! 5 | export default class C {
11-
//! : |
12-
//! : `-- `C` redefined here
13-
//! 6 | }
14-
//! `----
152
//! x the name `default` is exported multiple times
163
//! ,-[2:1]
174
//! 1 |
@@ -25,3 +12,16 @@
2512
//! `----
2613
//!
2714
//! Advice: > Exported identifiers must be unique
15+
//! x the name `C` is defined multiple times
16+
//! ,-[2:1]
17+
//! 1 |
18+
//! 2 | export default class C {
19+
//! : |
20+
//! : `-- previous definition of `C` here
21+
//! 3 | }
22+
//! 4 |
23+
//! 5 | export default class C {
24+
//! : |
25+
//! : `-- `C` redefined here
26+
//! 6 | }
27+
//! `----
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,4 @@
11
//// [multipleDefaultExports03.ts]
2-
//! x the name `C` is defined multiple times
3-
//! ,-[2:1]
4-
//! 1 |
5-
//! 2 | export default class C {
6-
//! : |
7-
//! : `-- previous definition of `C` here
8-
//! 3 | }
9-
//! 4 |
10-
//! 5 | export default class C {
11-
//! : |
12-
//! : `-- `C` redefined here
13-
//! 6 | }
14-
//! `----
152
//! x the name `default` is exported multiple times
163
//! ,-[2:1]
174
//! 1 |
@@ -25,3 +12,16 @@
2512
//! `----
2613
//!
2714
//! Advice: > Exported identifiers must be unique
15+
//! x the name `C` is defined multiple times
16+
//! ,-[2:1]
17+
//! 1 |
18+
//! 2 | export default class C {
19+
//! : |
20+
//! : `-- previous definition of `C` here
21+
//! 3 | }
22+
//! 4 |
23+
//! 5 | export default class C {
24+
//! : |
25+
//! : `-- `C` redefined here
26+
//! 6 | }
27+
//! `----
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,4 @@
11
//// [multipleDefaultExports04.ts]
2-
//! x the name `f` is defined multiple times
3-
//! ,-[2:1]
4-
//! 1 |
5-
//! 2 | export default function f() {
6-
//! : |
7-
//! : `-- previous definition of `f` here
8-
//! 3 | }
9-
//! 4 |
10-
//! 5 | export default function f() {
11-
//! : |
12-
//! : `-- `f` redefined here
13-
//! 6 | }
14-
//! `----
152
//! x the name `default` is exported multiple times
163
//! ,-[2:1]
174
//! 1 |
@@ -25,3 +12,16 @@
2512
//! `----
2613
//!
2714
//! Advice: > Exported identifiers must be unique
15+
//! x the name `f` is defined multiple times
16+
//! ,-[2:1]
17+
//! 1 |
18+
//! 2 | export default function f() {
19+
//! : |
20+
//! : `-- previous definition of `f` here
21+
//! 3 | }
22+
//! 4 |
23+
//! 5 | export default function f() {
24+
//! : |
25+
//! : `-- `f` redefined here
26+
//! 6 | }
27+
//! `----
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,4 @@
11
//// [multipleDefaultExports04.ts]
2-
//! x the name `f` is defined multiple times
3-
//! ,-[2:1]
4-
//! 1 |
5-
//! 2 | export default function f() {
6-
//! : |
7-
//! : `-- previous definition of `f` here
8-
//! 3 | }
9-
//! 4 |
10-
//! 5 | export default function f() {
11-
//! : |
12-
//! : `-- `f` redefined here
13-
//! 6 | }
14-
//! `----
152
//! x the name `default` is exported multiple times
163
//! ,-[2:1]
174
//! 1 |
@@ -25,3 +12,16 @@
2512
//! `----
2613
//!
2714
//! Advice: > Exported identifiers must be unique
15+
//! x the name `f` is defined multiple times
16+
//! ,-[2:1]
17+
//! 1 |
18+
//! 2 | export default function f() {
19+
//! : |
20+
//! : `-- previous definition of `f` here
21+
//! 3 | }
22+
//! 4 |
23+
//! 5 | export default function f() {
24+
//! : |
25+
//! : `-- `f` redefined here
26+
//! 6 | }
27+
//! `----

‎crates/swc_ecma_lints/src/rule.rs

+36-3
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,11 @@
1-
use std::fmt::Debug;
1+
use std::{fmt::Debug, mem::take, sync::Arc};
22

33
use auto_impl::auto_impl;
4-
use swc_common::{errors::HANDLER, GLOBALS};
4+
use parking_lot::Mutex;
5+
use swc_common::{
6+
errors::{Diagnostic, DiagnosticBuilder, Emitter, Handler, HANDLER},
7+
GLOBALS,
8+
};
59
use swc_ecma_ast::{Module, Script};
610
use swc_ecma_visit::{Visit, VisitWith};
711
use swc_parallel::join;
@@ -75,7 +79,36 @@ fn lint_rules<N: LintNode<R>, R: Rule>(rules: &mut Vec<R>, program: &N) {
7579
program.lint(rule);
7680
}
7781
} else {
78-
join_lint_rules(rules, program);
82+
let capturing = Capturing::default();
83+
84+
{
85+
HANDLER.set(
86+
&Handler::with_emitter(true, false, Box::new(capturing.clone())),
87+
|| {
88+
join_lint_rules(rules, program);
89+
},
90+
);
91+
92+
let mut errors = take(&mut *capturing.errors.lock());
93+
errors.sort_by_key(|error| error.span.primary_span());
94+
95+
HANDLER.with(|handler| {
96+
for error in errors {
97+
DiagnosticBuilder::new_diagnostic(handler, error).emit();
98+
}
99+
});
100+
}
101+
}
102+
}
103+
104+
#[derive(Default, Clone)]
105+
struct Capturing {
106+
errors: Arc<Mutex<Vec<Diagnostic>>>,
107+
}
108+
109+
impl Emitter for Capturing {
110+
fn emit(&mut self, db: &DiagnosticBuilder<'_>) {
111+
self.errors.lock().push((**db).clone());
79112
}
80113
}
81114

0 commit comments

Comments
 (0)
Please sign in to comment.