From 5044bf32f922253a881a70a8f05eced6f5770527 Mon Sep 17 00:00:00 2001 From: austaras Date: Sat, 5 Nov 2022 23:21:02 +0800 Subject: [PATCH] fix(es/lints): Disallow assign to class --- .../errors/lints/const-assign/3/input.js | 1 + .../lints/const-assign/3/output.swc-stderr | 7 ++ ...mentToParenthesizedIdentifiers.1.normal.js | 99 +++---------------- ...ntToParenthesizedIdentifiers.2.minified.js | 38 +++---- .../tsc-references/assignments.1.normal.js | 38 ++----- .../tsc-references/assignments.2.minified.js | 13 ++- .../invalidUndefinedAssignments.1.normal.js | 35 ++----- .../invalidUndefinedAssignments.2.minified.js | 14 ++- .../validNullAssignments.1.normal.js | 43 +++----- .../validNullAssignments.2.minified.js | 15 ++- .../swc_ecma_lints/src/rules/const_assign.rs | 38 +++++-- 11 files changed, 124 insertions(+), 217 deletions(-) create mode 100644 crates/swc/tests/errors/lints/const-assign/3/input.js create mode 100644 crates/swc/tests/errors/lints/const-assign/3/output.swc-stderr diff --git a/crates/swc/tests/errors/lints/const-assign/3/input.js b/crates/swc/tests/errors/lints/const-assign/3/input.js new file mode 100644 index 000000000000..869749c7948f --- /dev/null +++ b/crates/swc/tests/errors/lints/const-assign/3/input.js @@ -0,0 +1 @@ +class X { static y = X = 0 } \ No newline at end of file diff --git a/crates/swc/tests/errors/lints/const-assign/3/output.swc-stderr b/crates/swc/tests/errors/lints/const-assign/3/output.swc-stderr new file mode 100644 index 000000000000..a0c19b856209 --- /dev/null +++ b/crates/swc/tests/errors/lints/const-assign/3/output.swc-stderr @@ -0,0 +1,7 @@ + + x cannot reassign to a class + ,---- + 1 | class X { static y = X = 0 } + : | ^ + : `-- class name + `---- diff --git a/crates/swc/tests/tsc-references/assignmentToParenthesizedIdentifiers.1.normal.js b/crates/swc/tests/tsc-references/assignmentToParenthesizedIdentifiers.1.normal.js index fb7d4baba9bc..c2e64fe145ea 100644 --- a/crates/swc/tests/tsc-references/assignmentToParenthesizedIdentifiers.1.normal.js +++ b/crates/swc/tests/tsc-references/assignmentToParenthesizedIdentifiers.1.normal.js @@ -1,88 +1,13 @@ //// [assignmentToParenthesizedIdentifiers.ts] -import _class_call_check from "@swc/helpers/src/_class_call_check.mjs"; -var x; -x = 3; // OK -x = 3; // OK -x = ""; // Error -x = ""; // Error -var M; -(function(M) { - var y; - M.y = y; -})(M || (M = {})); -M.y = 3; // OK -M.y = 3; // OK -M.y = 3; // OK -M.y = ""; // Error -M.y = ""; // Error -M.y = ""; // Error -M = { - y: 3 -}; // Error -M = { - y: 3 -}; // Error -var M2; -(function(M2) { - var M3; - (function(M3) { - var x; - M3.x = x; - })(M3 = M2.M3 || (M2.M3 = {})); - M3 = { - x: 3 - }; // Error -})(M2 || (M2 = {})); -M2.M3 = { - x: 3 -}; // OK -M2.M3 = { - x: 3 -}; // OK -M2.M3 = { - x: 3 -}; // OK -M2.M3 = { - x: "" -}; // Error -M2.M3 = { - x: "" -}; // Error -M2.M3 = { - x: "" -}; // Error -function fn() {} -fn = function() { - return 3; -}; // Bug 823548: Should be error (fn is not a reference) -fn = function() { - return 3; -}; // Should be error -function fn2(x, y) { - x = 3; - x = 3; // OK - x = ""; // Error - x = ""; // Error - y.t = 3; // OK - y.t = 3; // OK - y.t = ""; // Error - y.t = ""; // Error - y["t"] = 3; // OK - y["t"] = 3; // OK - y["t"] = 3; // OK - y["t"] = ""; // Error - y["t"] = ""; // Error - y["t"] = ""; // Error -} -var E; -(function(E) { - E[E["A"] = 0] = "A"; -})(E || (E = {})); -E = undefined; // Error -E = undefined; // Error -var C = function C() { - "use strict"; - _class_call_check(this, C); -}; -C = undefined; // Error -C = undefined; // Error +//! +//! x cannot reassign to a class +//! ,-[65:1] +//! 65 | class C { +//! : | +//! : `-- class name +//! 66 | +//! 67 | } +//! 68 | +//! 69 | C = undefined; // Error +//! : ^ +//! `---- diff --git a/crates/swc/tests/tsc-references/assignmentToParenthesizedIdentifiers.2.minified.js b/crates/swc/tests/tsc-references/assignmentToParenthesizedIdentifiers.2.minified.js index d87078323262..c2e64fe145ea 100644 --- a/crates/swc/tests/tsc-references/assignmentToParenthesizedIdentifiers.2.minified.js +++ b/crates/swc/tests/tsc-references/assignmentToParenthesizedIdentifiers.2.minified.js @@ -1,27 +1,13 @@ //// [assignmentToParenthesizedIdentifiers.ts] -var M, M2, E; -!function(M) { - var y; - M.y = y; -}(M || (M = {})), M.y = 3, M.y = 3, M.y = 3, M.y = "", M.y = "", M.y = "", M = { - y: 3 -}, M = { - y: 3 -}, function(M2) { - var x; - (M2.M3 || (M2.M3 = {})).x = x; -}(M2 || (M2 = {})), M2.M3 = { - x: 3 -}, M2.M3 = { - x: 3 -}, M2.M3 = { - x: 3 -}, M2.M3 = { - x: "" -}, M2.M3 = { - x: "" -}, M2.M3 = { - x: "" -}, function(E) { - E[E.A = 0] = "A"; -}(E || (E = {})), E = void 0, E = void 0; +//! +//! x cannot reassign to a class +//! ,-[65:1] +//! 65 | class C { +//! : | +//! : `-- class name +//! 66 | +//! 67 | } +//! 68 | +//! 69 | C = undefined; // Error +//! : ^ +//! `---- diff --git a/crates/swc/tests/tsc-references/assignments.1.normal.js b/crates/swc/tests/tsc-references/assignments.1.normal.js index 741db84407ea..312285c896b5 100644 --- a/crates/swc/tests/tsc-references/assignments.1.normal.js +++ b/crates/swc/tests/tsc-references/assignments.1.normal.js @@ -1,30 +1,10 @@ //// [assignments.ts] -// In this file: -// Assign to a module -// Assign to a class -// Assign to an enum -// Assign to a function -// Assign to a variable -// Assign to a parameter -// Assign to an interface -import _class_call_check from "@swc/helpers/src/_class_call_check.mjs"; -M = null; // Error -var C = function C() { - "use strict"; - _class_call_check(this, C); -}; -C = null; // Error -var E; -(function(E) { - E[E["A"] = 0] = "A"; -})(E || (E = {})); -E = null; // Error -E.A = null; // OK per spec, Error per implementation (509581) -function fn() {} -fn = null; // Should be error -var v; -v = null; // OK -function fn2(p) { - p = null; // OK -} -I = null; // Error +//! +//! x cannot reassign to a class +//! ,-[13:1] +//! 13 | class C { } +//! : | +//! : `-- class name +//! 14 | C = null; // Error +//! : ^ +//! `---- diff --git a/crates/swc/tests/tsc-references/assignments.2.minified.js b/crates/swc/tests/tsc-references/assignments.2.minified.js index 75f1ceb0f0ad..312285c896b5 100644 --- a/crates/swc/tests/tsc-references/assignments.2.minified.js +++ b/crates/swc/tests/tsc-references/assignments.2.minified.js @@ -1,5 +1,10 @@ //// [assignments.ts] -var E; -M = null, function(E) { - E[E.A = 0] = "A"; -}(E || (E = {})), (E = null).A = null, I = null; +//! +//! x cannot reassign to a class +//! ,-[13:1] +//! 13 | class C { } +//! : | +//! : `-- class name +//! 14 | C = null; // Error +//! : ^ +//! `---- diff --git a/crates/swc/tests/tsc-references/invalidUndefinedAssignments.1.normal.js b/crates/swc/tests/tsc-references/invalidUndefinedAssignments.1.normal.js index f26b5449cb92..3c358f371f41 100644 --- a/crates/swc/tests/tsc-references/invalidUndefinedAssignments.1.normal.js +++ b/crates/swc/tests/tsc-references/invalidUndefinedAssignments.1.normal.js @@ -1,26 +1,11 @@ //// [invalidUndefinedAssignments.ts] -import _class_call_check from "@swc/helpers/src/_class_call_check.mjs"; -var x; -var E; -(function(E) { - E[E["A"] = 0] = "A"; -})(E || (E = {})); -E = x; -E.A = x; -var C = function C() { - "use strict"; - _class_call_check(this, C); -}; -var f; -C = x; -var g; -g = x; -I = x; -var M; -(function(M) { - var x = M.x = 1; -})(M || (M = {})); -M = x; -function i(a) {} -// BUG 767030 -i = x; +//! +//! x cannot reassign to a class +//! ,-[7:1] +//! 7 | class C { foo: string } +//! : | +//! : `-- class name +//! 8 | var f: C; +//! 9 | C = x; +//! : ^ +//! `---- diff --git a/crates/swc/tests/tsc-references/invalidUndefinedAssignments.2.minified.js b/crates/swc/tests/tsc-references/invalidUndefinedAssignments.2.minified.js index ce97b1983f56..3c358f371f41 100644 --- a/crates/swc/tests/tsc-references/invalidUndefinedAssignments.2.minified.js +++ b/crates/swc/tests/tsc-references/invalidUndefinedAssignments.2.minified.js @@ -1,5 +1,11 @@ //// [invalidUndefinedAssignments.ts] -var x, E, M; -!function(E) { - E[E.A = 0] = "A"; -}(E || (E = {})), (E = x).A = x, I = x, (M || (M = {})).x = 1, M = x; +//! +//! x cannot reassign to a class +//! ,-[7:1] +//! 7 | class C { foo: string } +//! : | +//! : `-- class name +//! 8 | var f: C; +//! 9 | C = x; +//! : ^ +//! `---- diff --git a/crates/swc/tests/tsc-references/validNullAssignments.1.normal.js b/crates/swc/tests/tsc-references/validNullAssignments.1.normal.js index d863c45fc879..7a83c03fb572 100644 --- a/crates/swc/tests/tsc-references/validNullAssignments.1.normal.js +++ b/crates/swc/tests/tsc-references/validNullAssignments.1.normal.js @@ -1,33 +1,12 @@ //// [validNullAssignments.ts] -import _class_call_check from "@swc/helpers/src/_class_call_check.mjs"; -var a = null; -var b = null; -var c = null; -var d = null; -var e = null; -e = null; // ok -var E; -(function(E) { - E[E["A"] = 0] = "A"; -})(E || (E = {})); -E.A = null; // error -var C = function C() { - "use strict"; - _class_call_check(this, C); -}; -var f; -f = null; // ok -C = null; // error -var g; -g = null; // ok -I = null; // error -var M; -(function(M) { - var x = M.x = 1; -})(M || (M = {})); -M = null; // error -var h = null; -function i(a) { - a = null; -} -i = null; // error +//! +//! x cannot reassign to a class +//! ,-[12:1] +//! 12 | class C { foo: string } +//! : | +//! : `-- class name +//! 13 | var f: C; +//! 14 | f = null; // ok +//! 15 | C = null; // error +//! : ^ +//! `---- diff --git a/crates/swc/tests/tsc-references/validNullAssignments.2.minified.js b/crates/swc/tests/tsc-references/validNullAssignments.2.minified.js index ec4e4d75e3a7..7a83c03fb572 100644 --- a/crates/swc/tests/tsc-references/validNullAssignments.2.minified.js +++ b/crates/swc/tests/tsc-references/validNullAssignments.2.minified.js @@ -1,5 +1,12 @@ //// [validNullAssignments.ts] -var E, M; -!function(E) { - E[E.A = 0] = "A"; -}(E || (E = {})), E.A = null, I = null, (M || (M = {})).x = 1, M = null; +//! +//! x cannot reassign to a class +//! ,-[12:1] +//! 12 | class C { foo: string } +//! : | +//! : `-- class name +//! 13 | var f: C; +//! 14 | f = null; // ok +//! 15 | C = null; // error +//! : ^ +//! `---- diff --git a/crates/swc_ecma_lints/src/rules/const_assign.rs b/crates/swc_ecma_lints/src/rules/const_assign.rs index 22a36fea900c..96a87b77202d 100644 --- a/crates/swc_ecma_lints/src/rules/const_assign.rs +++ b/crates/swc_ecma_lints/src/rules/const_assign.rs @@ -11,7 +11,8 @@ pub fn const_assign() -> Box { #[derive(Debug, Default)] struct ConstAssign { const_vars: AHashMap, - import_binding: AHashMap, + import_bindings: AHashMap, + classes: AHashMap, is_pat_decl: bool, } @@ -40,7 +41,7 @@ impl ConstAssign { }); } - if let Some(&binding_span) = self.import_binding.get(&id.to_id()) { + if let Some(&binding_span) = self.import_bindings.get(&id.to_id()) { HANDLER.with(|handler| { handler .struct_span_err(id.span, "cannot reassign to an imported binding") @@ -48,6 +49,15 @@ impl ConstAssign { .emit(); }); } + + if let Some(&binding_span) = self.classes.get(&id.to_id()) { + HANDLER.with(|handler| { + handler + .struct_span_err(id.span, "cannot reassign to a class") + .span_label(binding_span, "class name") + .emit(); + }); + } } } @@ -63,7 +73,8 @@ impl Visit for ConstAssign { fn visit_module(&mut self, program: &Module) { program.visit_children_with(&mut Collector { const_vars: &mut self.const_vars, - import_binding: &mut self.import_binding, + import_bindings: &mut self.import_bindings, + classes: &mut self.classes, var_decl_kind: None, }); @@ -101,7 +112,8 @@ impl Visit for ConstAssign { const_vars: &mut self.const_vars, // I don't believe that import stmt exists in Script // But it's ok. Let's pass it in. - import_binding: &mut self.import_binding, + import_bindings: &mut self.import_bindings, + classes: &mut self.classes, var_decl_kind: None, }); @@ -120,7 +132,8 @@ impl Visit for ConstAssign { struct Collector<'a> { const_vars: &'a mut AHashMap, - import_binding: &'a mut AHashMap, + import_bindings: &'a mut AHashMap, + classes: &'a mut AHashMap, var_decl_kind: Option, } @@ -133,7 +146,7 @@ impl Visit for Collector<'_> { ImportSpecifier::Named(ImportNamedSpecifier { local, .. }) | ImportSpecifier::Default(ImportDefaultSpecifier { local, .. }) | ImportSpecifier::Namespace(ImportStarAsSpecifier { local, .. }) => { - self.import_binding.insert(local.to_id(), local.span); + self.import_bindings.insert(local.to_id(), local.span); } } } @@ -173,4 +186,17 @@ impl Visit for Collector<'_> { self.var_decl_kind = old_var_decl_kind; } + + fn visit_class_decl(&mut self, class: &ClassDecl) { + *self.classes.entry(class.ident.to_id()).or_default() = class.ident.span; + + class.visit_children_with(self); + } + + fn visit_class_expr(&mut self, class: &ClassExpr) { + if let Some(ident) = &class.ident { + *self.classes.entry(ident.to_id()).or_default() = ident.span; + } + class.visit_children_with(self); + } }