Repository: swc-project/swc (rust)

Issue:
Duplicate Declared Identifiers are not Detected at Try-Catch Code Block
### Describe the bug

The identifier in exception are repeatedly declared in the catch code block, and this syntax error is not detected by SWC.
Here are some examples about this bug.
poc_1.js
```js
try {
} catch (foo) {  
  let foo;
}
```
poc_2.js
```js
try {
} catch ([foo]) {
  var foo;
}
```
Another situation is that duplicate identifiers in exception of catch can't be recognized by SWC.
Here is the poc
poc_3.js
```js
try {
} catch ({ a: foo, b: { c: [foo] } }) {
}
```

### Input code

```typescript
// poc_01.js
try {
} catch (foo_1) {  
  let foo_1;
}

// poc_2.js
try {
} catch ([foo_2]) {
  var foo_2;
}

// poc_3.js
try {
} catch ({ a: foo_3, b: { c: [foo_3] } }) {
}
```


### Config

```json
{
  "jsc": {
    "parser": {
      "syntax": "ecmascript",
      "jsx": false,
      "dynamicImport": false,
      "privateMethod": false,
      "functionBind": false,
      "exportDefaultFrom": false,
      "exportNamespaceFrom": false,
      "decorators": false,
      "decoratorsBeforeExport": false,
      "topLevelAwait": false,
      "importMeta": false
    },
    "transform": null,
    "target": "es5",
    "loose": false,
    "externalHelpers": false
  }
}
```


### Playground link

https://play.swc.rs/?version=1.2.112&code=H4sIAAAAAAAAA22NQQqDMBRE9x%2F%2BHWZZoZia7NKjSJAYKiJCioaChNxd%2Fe6K2%2BG9N0rhG0P3auppZUrLhsxUEHwKIx5DjF1TIQNMwPxJkOV9IExM6pL1rdueqHbVOQI%2Fv4ir%2F1xz62Z4K7h5orfHf7CQnnEoKNIsO27Ks6C7AAAA&config=H4sIAAAAAAAAA0WMTQrEIAxG75K1286id5hDBCctFv9IUhgR714tlu7C915ehUMsrBUyshCPS0pU%2FMMKZAOKZZcVTNf6tKEXagYUeScdiiyd%2BZSEJjUQXHRbGSWbQmYSeRHG3T9m66GQfucYKmjJdAc%2F0N7G%2FHPynaLySe0Cj9ke9LUAAAA%3D

### Expected behavior

It's a syntax error, I hope swc can find it and report.

### Version

1.2.112

### Additional context

I run swc use cmd as follows
```bash
npx swc --config-file=.swcrc poc.js -o poc.js
```
The environment is ubuntu 20.04 amd64.

Pull request:
feat(es/lints): Mark catch params as binding patterns while checking duplicates
**Description:**

**Related issue (if exists):**

 - Closes #2864

Patch:
diff --git a/crates/swc_ecma_lints/src/rules/duplicate_bindings.rs b/crates/swc_ecma_lints/src/rules/duplicate_bindings.rs
index 265e175cbc..c7cbc7dbd4 100644
--- a/crates/swc_ecma_lints/src/rules/duplicate_bindings.rs
+++ b/crates/swc_ecma_lints/src/rules/duplicate_bindings.rs
@@ -84,23 +84,6 @@ impl DuplicateBindings {
 impl Visit for DuplicateBindings {
     noop_visit_type!();
 
-    fn visit_module(&mut self, m: &Module) {
-        m.visit_with(&mut TypeCollector {
-            type_bindings: &mut self.type_bindings,
-        });
-
-        self.is_module = true;
-        m.visit_children_with(self);
-    }
-
-    fn visit_script(&mut self, s: &Script) {
-        s.visit_with(&mut TypeCollector {
-            type_bindings: &mut self.type_bindings,
-        });
-
-        s.visit_children_with(self);
-    }
-
     fn visit_assign_pat_prop(&mut self, p: &AssignPatProp) {
         p.visit_children_with(self);
 
@@ -109,6 +92,19 @@ impl Visit for DuplicateBindings {
         }
     }
 
+    fn visit_catch_clause(&mut self, c: &CatchClause) {
+        let old_var_decl_kind = self.var_decl_kind.take();
+        let old_is_pat_decl = self.is_pat_decl;
+
+        self.var_decl_kind = Some(VarDeclKind::Var);
+        self.is_pat_decl = true;
+
+        c.visit_children_with(self);
+
+        self.is_pat_decl = old_is_pat_decl;
+        self.var_decl_kind = old_var_decl_kind;
+    }
+
     fn visit_class_decl(&mut self, d: &ClassDecl) {
         self.add(&d.ident, true);
 
@@ -160,6 +156,15 @@ impl Visit for DuplicateBindings {
         }
     }
 
+    fn visit_module(&mut self, m: &Module) {
+        m.visit_with(&mut TypeCollector {
+            type_bindings: &mut self.type_bindings,
+        });
+
+        self.is_module = true;
+        m.visit_children_with(self);
+    }
+
     fn visit_pat(&mut self, p: &Pat) {
         p.visit_children_with(self);
 
@@ -170,6 +175,14 @@ impl Visit for DuplicateBindings {
         }
     }
 
+    fn visit_script(&mut self, s: &Script) {
+        s.visit_with(&mut TypeCollector {
+            type_bindings: &mut self.type_bindings,
+        });
+
+        s.visit_children_with(self);
+    }
+
     fn visit_var_decl(&mut self, d: &VarDecl) {
         let old_var_decl_kind = self.var_decl_kind.take();
         let old_is_pat_decl = self.is_pat_decl;


Test patch:
diff --git a/crates/swc/tests/errors/lints/duplicate-bindings/catch-clause/1/input.js b/crates/swc/tests/errors/lints/duplicate-bindings/catch-clause/1/input.js
new file mode 100644
index 0000000000..44251e5133
--- /dev/null
+++ b/crates/swc/tests/errors/lints/duplicate-bindings/catch-clause/1/input.js
@@ -0,0 +1,4 @@
+try {
+} catch (foo) {
+    let foo;
+}
\ No newline at end of file
diff --git a/crates/swc/tests/errors/lints/duplicate-bindings/catch-clause/1/output.swc-stderr b/crates/swc/tests/errors/lints/duplicate-bindings/catch-clause/1/output.swc-stderr
new file mode 100644
index 0000000000..89efdf56db
--- /dev/null
+++ b/crates/swc/tests/errors/lints/duplicate-bindings/catch-clause/1/output.swc-stderr
@@ -0,0 +1,8 @@
+error: the name `foo` is defined multiple times
+ 
+  |
+2 | } catch (foo) {
+  |          --- previous definition of `foo` here
+3 |     let foo;
+  |         ^^^ `foo` redefined here
+
diff --git a/crates/swc_ecma_lints/tests/fixture.rs b/crates/swc_ecma_lints/tests/fixture.rs
index d76f3e0578..f0c1709e90 100644
--- a/crates/swc_ecma_lints/tests/fixture.rs
+++ b/crates/swc_ecma_lints/tests/fixture.rs
@@ -4,6 +4,7 @@ use swc_common::{input::SourceFileInput, Mark, SyntaxContext};
 use swc_ecma_ast::{EsVersion, Program};
 use swc_ecma_lints::{
     config::LintConfig,
+    rule::Rule,
     rules::{all, LintParams},
 };
 use swc_ecma_parser::{lexer::Lexer, Parser, Syntax};
@@ -53,7 +54,7 @@ fn pass(input: PathBuf) {
 
         let config = LintConfig::default();
 
-        let rules = all(LintParams {
+        let mut rules = all(LintParams {
             program: &program,
             lint_config: &config,
             top_level_ctxt,
@@ -61,11 +62,12 @@ fn pass(input: PathBuf) {
             source_map: cm,
         });
 
-        HANDLER.set(handler, || {
-            if let Program::Module(m) = &program {
-                for mut rule in rules {
-                    rule.lint_module(m);
-                }
+        HANDLER.set(handler, || match &program {
+            Program::Module(m) => {
+                rules.lint_module(m);
+            }
+            Program::Script(s) => {
+                rules.lint_script(s);
             }
         });