Repository: swc-project/swc (rust)

Issue:
[Bug]: `this` inside class computed function throws `TypeError`
### Describe the bug

Hello,

`input.js` is expected to be terminated normally but the output code results in `TypeError`.

This is because `this` on the line 27 of the output code is `undefined`, since it is inside a function:
```js
// output.js
...
   20 var x = function() {
   21     "use strict";
   22     function x() {
   23         _classCallCheck(this, x);
   24     }
   25     _createClass(x, [
   26         {
   27             key: this[0],
   28             value: function value() {}
   29         }
   30     ]);
   31     return x;
   32 }();
```

### Input code

```typescript
class x { [ this [ 0 ] ] ( ) { } }
```


### Config

_No response_

### Playground link

https://play.swc.rs/?version=1.3.14&code=H4sIAAAAAAAAA0vOSSwuVqhQqFaIVijJyCwGUgYKsUCooaAJFKwFQgC%2F%2F8VBIwAAAA%3D%3D&config=H4sIAAAAAAAAA0WMTQrEIAxG75K1286id5hDBCctFv9IUhgR714tlu7C915ehUMsrBUyshCPS0pU%2FMMKZAOKZZcVTNf6tKEXagYUeScdiiyd%2BZSEJjUQXHRbGSWbQmYSeRHG3T9m66GQfucYKmjJdAc%2F0N7G%2FHPynaLySe0Cj9ke9LUAAAA%3D

### Expected behavior

`input.js` is expected to be terminated normally:
```console
$ node input.js # no error

```

### Actual behavior

The output code results in `TypeError`:
```console
$ node output.js
output.js:27
            key: this[0],
                     ^

TypeError: Cannot read properties of undefined (reading '0')
    at output.js:27:22
    at Object.<anonymous> (output.js:32:2)
    at Module._compile (node:internal/modules/cjs/loader:1159:14)
    at Module._extensions..js (node:internal/modules/cjs/loader:1213:10)
    at Module.load (node:internal/modules/cjs/loader:1037:32)
    at Module._load (node:internal/modules/cjs/loader:878:12)
    at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:81:12)
    at node:internal/main/run_main_module:23:47

Node.js v18.11.0
```

### Version

1.3.14 (default SWC playground)

### Additional context

_No response_

Pull request description:
fix(es/compat): `this` in computed class method name
<!-- Note: CI script will automatically rebase your PR so please do not rebase unless required -->

<!-- Thanks for submitting a pull request! Please provide enough information so that others can review your pull request. -->

**Description:**

Some remain problem -- `in_strict` should always be true when in es module, but that would be too many lines of code change
**BREAKING CHANGE:**

<!--
If this PR introduces a breaking change, it must contain a notice for it to be included in the CHANGELOG. Add description or remove entirely if not breaking.

You may need to update `MIGRATION.md` for the breaking changes.
-->

**Related issue (if exists):**
closes #6356 

Patch:
diff --git a/crates/swc_ecma_transforms_compat/src/es2015/classes/mod.rs b/crates/swc_ecma_transforms_compat/src/es2015/classes/mod.rs
index b769fb4512..859ca08507 100644
--- a/crates/swc_ecma_transforms_compat/src/es2015/classes/mod.rs
+++ b/crates/swc_ecma_transforms_compat/src/es2015/classes/mod.rs
@@ -7,9 +7,9 @@ use swc_ecma_transforms_base::{helper, native::is_native, perf::Check};
 use swc_ecma_transforms_classes::super_field::SuperFieldAccessFolder;
 use swc_ecma_transforms_macros::fast_path;
 use swc_ecma_utils::{
-    alias_if_required, default_constructor, is_valid_ident, is_valid_prop_ident, prepend_stmt,
-    private_ident, prop_name_to_expr, quote_expr, quote_ident, quote_str, replace_ident,
-    ExprFactory, IdentExt, IsDirective, ModuleItemLike, StmtLike,
+    alias_if_required, contains_this_expr, default_constructor, is_valid_ident,
+    is_valid_prop_ident, prepend_stmt, private_ident, prop_name_to_expr, quote_expr, quote_ident,
+    quote_str, replace_ident, ExprFactory, IdentExt, IsDirective, ModuleItemLike, StmtLike,
 };
 use swc_ecma_visit::{
     as_folder, noop_visit_mut_type, noop_visit_type, Fold, Visit, VisitMut, VisitMutWith, VisitWith,
@@ -535,7 +535,6 @@ where
         let class_name = class_name.unwrap_or_else(|| quote_ident!("_class"));
         let mut stmts = vec![];
 
-        let mut priv_methods = vec![];
         let mut methods = vec![];
         let mut constructor = None;
         for member in class.body {
@@ -547,7 +546,9 @@ where
                         constructor = Some(c)
                     }
                 }
-                ClassMember::PrivateMethod(m) => priv_methods.push(m),
+                ClassMember::PrivateMethod(_) => unreachable!(
+                    "classes pass: private method\nclass_properties pass should remove this"
+                ),
                 ClassMember::Method(m) => methods.push(m),
 
                 ClassMember::ClassProp(..) => {
@@ -773,7 +774,6 @@ where
         }
 
         // convert class methods
-        // stmts.extend(self.fold_class_methods(class_name.clone(), priv_methods));
         stmts.extend(self.fold_class_methods(&class_name, &super_class_ident, methods));
 
         if stmts.first().map(|v| !v.is_use_strict()).unwrap_or(false) && !self.in_strict {
@@ -1009,11 +1009,13 @@ where
         for mut m in methods {
             let key = HashKey::from(&m.key);
             let key_is_pure = is_pure_prop_name(&m.key);
+            // class is always strict, however computed key is not part of class
+            let key_contain_this = !self.in_strict && contains_this_expr(&m.key);
             let key_prop = Box::new(m.key.clone());
             let computed = matches!(m.key, PropName::Computed(..));
             let prop_name = prop_name_to_expr(m.key);
 
-            let key_prop = if should_extract && !key_is_pure {
+            let key_prop = if should_extract && !key_is_pure || key_contain_this {
                 let ident = private_ident!("_prop");
 
                 self.params.push(ident.clone().into());


Test patch:
diff --git a/crates/swc/tests/tsc-references/computedPropertyNames21_ES5.1.normal.js b/crates/swc/tests/tsc-references/computedPropertyNames21_ES5.1.normal.js
index 9e171cb0f2..5ad07c553b 100644
--- a/crates/swc/tests/tsc-references/computedPropertyNames21_ES5.1.normal.js
+++ b/crates/swc/tests/tsc-references/computedPropertyNames21_ES5.1.normal.js
@@ -1,6 +1,6 @@
 //// [computedPropertyNames21_ES5.ts]
 import _class_call_check from "@swc/helpers/src/_class_call_check.mjs";
-var C = /*#__PURE__*/ function() {
+var C = /*#__PURE__*/ function(_prop) {
     "use strict";
     function C() {
         _class_call_check(this, C);
@@ -9,6 +9,6 @@ var C = /*#__PURE__*/ function() {
     _proto.bar = function bar() {
         return 0;
     };
-    _proto[this.bar()] = function() {};
+    _proto[_prop] = function() {};
     return C;
-}();
+}(this.bar());
diff --git a/crates/swc/tests/tsc-references/computedPropertyNames21_ES5.2.minified.js b/crates/swc/tests/tsc-references/computedPropertyNames21_ES5.2.minified.js
index 74f8475887..247c0a335f 100644
--- a/crates/swc/tests/tsc-references/computedPropertyNames21_ES5.2.minified.js
+++ b/crates/swc/tests/tsc-references/computedPropertyNames21_ES5.2.minified.js
@@ -1,2 +1,3 @@
 //// [computedPropertyNames21_ES5.ts]
 import _class_call_check from "@swc/helpers/src/_class_call_check.mjs";
+this.bar();
diff --git a/crates/swc/tests/tsc-references/computedPropertyNames23_ES5.1.normal.js b/crates/swc/tests/tsc-references/computedPropertyNames23_ES5.1.normal.js
index a4e061a1ec..27c184ad9f 100644
--- a/crates/swc/tests/tsc-references/computedPropertyNames23_ES5.1.normal.js
+++ b/crates/swc/tests/tsc-references/computedPropertyNames23_ES5.1.normal.js
@@ -1,7 +1,7 @@
 //// [computedPropertyNames23_ES5.ts]
 import _class_call_check from "@swc/helpers/src/_class_call_check.mjs";
 import _define_property from "@swc/helpers/src/_define_property.mjs";
-var C = /*#__PURE__*/ function() {
+var C = /*#__PURE__*/ function(_prop) {
     "use strict";
     function C() {
         _class_call_check(this, C);
@@ -10,6 +10,6 @@ var C = /*#__PURE__*/ function() {
     _proto.bar = function bar() {
         return 0;
     };
-    _proto[_define_property({}, this.bar(), 1)[0]] = function() {};
+    _proto[_prop] = function() {};
     return C;
-}();
+}(_define_property({}, this.bar(), 1)[0]);
diff --git a/crates/swc/tests/tsc-references/computedPropertyNames23_ES5.2.minified.js b/crates/swc/tests/tsc-references/computedPropertyNames23_ES5.2.minified.js
index a7cb8ebe50..5aa2acce45 100644
--- a/crates/swc/tests/tsc-references/computedPropertyNames23_ES5.2.minified.js
+++ b/crates/swc/tests/tsc-references/computedPropertyNames23_ES5.2.minified.js
@@ -1,3 +1,4 @@
 //// [computedPropertyNames23_ES5.ts]
 import _class_call_check from "@swc/helpers/src/_class_call_check.mjs";
 import _define_property from "@swc/helpers/src/_define_property.mjs";
+_define_property({}, this.bar(), 1)[0];
diff --git a/crates/swc_ecma_transforms_compat/tests/classes/issue-6356/input.js b/crates/swc_ecma_transforms_compat/tests/classes/issue-6356/input.js
new file mode 100644
index 0000000000..9ccef33fa2
--- /dev/null
+++ b/crates/swc_ecma_transforms_compat/tests/classes/issue-6356/input.js
@@ -0,0 +1,3 @@
+class x {
+    [this[0]]() {}
+}
diff --git a/crates/swc_ecma_transforms_compat/tests/classes/issue-6356/output.js b/crates/swc_ecma_transforms_compat/tests/classes/issue-6356/output.js
new file mode 100644
index 0000000000..aaf67c6c58
--- /dev/null
+++ b/crates/swc_ecma_transforms_compat/tests/classes/issue-6356/output.js
@@ -0,0 +1,13 @@
+let x = /*#__PURE__*/ function(_prop) {
+    "use strict";
+    function x() {
+        _classCallCheck(this, x);
+    }
+    _createClass(x, [
+        {
+            key: _prop,
+            value: function() {}
+        }
+    ]);
+    return x;
+}(this[0]);