feat(linter): bind CatchVariable

This commit is contained in:
Boshen 2023-03-11 14:06:22 +08:00
parent 34c0599db8
commit 995e7c1767
6 changed files with 164 additions and 16 deletions

View file

@ -93,3 +93,30 @@ impl<'a> Binder for FormalParameters<'a> {
}
}
}
impl<'a> Binder for CatchClause<'a> {
fn bind(&self, builder: &mut SemanticBuilder) {
let current_scope_id = builder.scope.current_scope_id;
if let Some(param) = &self.param {
// https://tc39.es/ecma262/#sec-variablestatements-in-catch-blocks
// It is a Syntax Error if any element of the BoundNames of CatchParameter also occurs in the VarDeclaredNames of Block
// unless CatchParameter is CatchParameter : BindingIdentifier
if let BindingPatternKind::BindingIdentifier(ident) = &param.kind {
let includes = SymbolFlags::FunctionScopedVariable | SymbolFlags::CatchVariable;
// Overshadows declarations so redeclarator error is not reported here
let symbol_id = builder.symbols.create(ident.name.clone(), ident.span, includes);
builder.scope.current_scope_mut().variables.insert(ident.name.clone(), symbol_id);
} else {
for ident in param.bound_names() {
builder.declare_symbol(
&ident.name,
ident.span,
current_scope_id,
SymbolFlags::BlockScopedVariable | SymbolFlags::CatchVariable,
SymbolFlags::BlockScopedVariableExcludes,
);
}
}
}
}
}

View file

@ -181,6 +181,9 @@ impl<'a> SemanticBuilder<'a> {
AstKind::FormalParameters(params) => {
params.bind(self);
}
AstKind::CatchClause(clause) => {
clause.bind(self);
}
AstKind::IdentifierReference(ident) => {
self.reference_identifier(ident);
}

View file

@ -38,6 +38,7 @@ bitflags! {
/// A block-scoped variable (let or const)
const BlockScopedVariable = 1 << 1;
const Class = 1 << 5;
const CatchVariable = 1 << 6; // try {} catch(catch_variable) {}
const Variable = Self::FunctionScopedVariable.bits | Self::BlockScopedVariable.bits;
const Value = Self::Variable.bits | Self::Class.bits;

View file

@ -1,7 +1,7 @@
Babel Summary:
AST Parsed : 2056/2069 (99.37%)
Positive Passed: 2056/2069 (99.37%)
Negative Passed: 965/1502 (64.25%)
Negative Passed: 972/1502 (64.71%)
Expect Syntax Error: "annex-b/disabled/1.1-html-comments-close/input.js"
Expect Syntax Error: "annex-b/disabled/3.1-sloppy-labeled-functions-if-body/input.js"
Expect Syntax Error: "annex-b/disabled/3.1-sloppy-labeled-functions-multiple-labels/input.js"
@ -9,10 +9,8 @@ Expect Syntax Error: "annex-b/disabled/3.1-sloppy-labeled-functions/input.js"
Expect Syntax Error: "annex-b/disabled/3.2.4-duplicate-function-in-block/input.js"
Expect Syntax Error: "annex-b/disabled/3.2.5-duplicate-function-in-switch/input.js"
Expect Syntax Error: "annex-b/disabled/3.3-function-in-if-body/input.js"
Expect Syntax Error: "annex-b/disabled/3.4-var-redeclaration-catch-binding/input.js"
Expect Syntax Error: "annex-b/disabled/3.5-for-in-initializer/input.js"
Expect Syntax Error: "annex-b/enabled/3.1-sloppy-labeled-functions-if-body/input.js"
Expect Syntax Error: "annex-b/enabled/3.4-var-redeclaration-catch-binding/input.js"
Expect Syntax Error: "core/categorized/invalid-fn-decl-inside-loop/input.js"
Expect Syntax Error: "core/categorized/invalid-fn-decl-labeled-inside-if/input.js"
Expect Syntax Error: "core/categorized/invalid-fn-decl-labeled-inside-loop/input.js"
@ -26,12 +24,7 @@ Expect Syntax Error: "core/legacy-octal/legacy-octal-after-use-strict-function/i
Expect Syntax Error: "core/legacy-octal/legacy-octal-after-use-strict/input.js"
Expect Syntax Error: "core/opts/allowNewTargetOutsideFunction-false-2/input.js"
Expect Syntax Error: "core/opts/allowNewTargetOutsideFunction-false/input.js"
Expect Syntax Error: "core/scope/dupl-bind-catch-arr-destr/input.js"
Expect Syntax Error: "core/scope/dupl-bind-catch-func/input.js"
Expect Syntax Error: "core/scope/dupl-bind-catch-let/input.js"
Expect Syntax Error: "core/scope/dupl-bind-catch-obj-destr/input.js"
Expect Syntax Error: "core/scope/dupl-bind-catch-var-arr-destr/input.js"
Expect Syntax Error: "core/scope/dupl-bind-catch-var-obj-destr/input.js"
Expect Syntax Error: "core/scope/dupl-bind-class-func/input.js"
Expect Syntax Error: "core/scope/dupl-bind-func-gen/input.js"
Expect Syntax Error: "core/scope/dupl-bind-func-module-sloppy/input.js"
@ -649,6 +642,24 @@ Expect to Parse: "typescript/types/const-type-parameters/input.ts"
2 │ function b<const T extends U>() {}
╰────
× Identifier `"f"` has already been declared
╭─[annex-b/disabled/3.4-var-redeclaration-catch-binding/input.js:1:1]
1 │ try {} catch (e) { var e; }
2 │ try {} catch ({ f }) { var f; }
· ┬ ┬
· │ ╰── It can not be redeclared here
· ╰── `f` has already been declared here
╰────
× Identifier `"f"` has already been declared
╭─[annex-b/enabled/3.4-var-redeclaration-catch-binding/input.js:1:1]
1 │ try {} catch (e) { var e; }
2 │ try {} catch ({ f }) { var f; }
· ┬ ┬
· │ ╰── It can not be redeclared here
· ╰── `f` has already been declared here
╰────
× Expect token
╭─[core/categorized/for-missing-semicolons/input.js:2:1]
2 │ var a = 1
@ -915,6 +926,16 @@ Expect to Parse: "typescript/types/const-type-parameters/input.ts"
· ╰── It can not be redeclared here
╰────
× Identifier `"foo"` has already been declared
╭─[core/scope/dupl-bind-catch-arr-destr/input.js:1:1]
1 │ try {
2 │ } catch ([foo, foo]) {
· ─┬─ ─┬─
· │ ╰── It can not be redeclared here
· ╰── `foo` has already been declared here
3 │ }
╰────
× Identifier `"foo"` has already been declared
╭─[core/scope/dupl-bind-catch-dbl-let/input.js:1:1]
1 │ let foo; try {} catch (foo) {} let foo;
@ -923,6 +944,52 @@ Expect to Parse: "typescript/types/const-type-parameters/input.ts"
· ╰── `foo` has already been declared here
╰────
× Identifier `"foo"` has already been declared
╭─[core/scope/dupl-bind-catch-let/input.js:1:1]
1 │ try {
2 │ } catch (foo) {
· ─┬─
· ╰── `foo` has already been declared here
3 │ let foo;
· ─┬─
· ╰── It can not be redeclared here
4 │ }
╰────
× Identifier `"foo"` has already been declared
╭─[core/scope/dupl-bind-catch-obj-destr/input.js:1:1]
1 │ try {
2 │ } catch ({ a: foo, b: { c: [foo] } }) {
· ─┬─ ─┬─
· │ ╰── It can not be redeclared here
· ╰── `foo` has already been declared here
3 │ }
╰────
× Identifier `"foo"` has already been declared
╭─[core/scope/dupl-bind-catch-var-arr-destr/input.js:1:1]
1 │ try {
2 │ } catch ([foo]) {
· ─┬─
· ╰── `foo` has already been declared here
3 │ var foo;
· ─┬─
· ╰── It can not be redeclared here
4 │ }
╰────
× Identifier `"foo"` has already been declared
╭─[core/scope/dupl-bind-catch-var-obj-destr/input.js:1:1]
1 │ try {
2 │ } catch ({ foo }) {
· ─┬─
· ╰── `foo` has already been declared here
3 │ var foo;
· ─┬─
· ╰── It can not be redeclared here
4 │ }
╰────
× Identifier `"foo"` has already been declared
╭─[core/scope/dupl-bind-class-class/input.js:1:1]
1 │ class foo {};

View file

@ -1,7 +1,7 @@
Test262 Summary:
AST Parsed : 44022/44034 (99.97%)
Positive Passed: 44022/44034 (99.97%)
Negative Passed: 2694/3917 (68.78%)
Negative Passed: 2696/3917 (68.83%)
Expect Syntax Error: "annexB/language/statements/for-in/const-initializer.js"
Expect Syntax Error: "annexB/language/statements/for-in/let-initializer.js"
Expect Syntax Error: "annexB/language/statements/for-in/strict-initializer.js"
@ -1178,9 +1178,7 @@ Expect Syntax Error: "language/statements/try/catch-parameter-boundnames-restric
Expect Syntax Error: "language/statements/try/dstr/ary-ptrn-rest-init-ary.js"
Expect Syntax Error: "language/statements/try/dstr/ary-ptrn-rest-init-id.js"
Expect Syntax Error: "language/statements/try/dstr/ary-ptrn-rest-init-obj.js"
Expect Syntax Error: "language/statements/try/early-catch-duplicates.js"
Expect Syntax Error: "language/statements/try/early-catch-function.js"
Expect Syntax Error: "language/statements/try/early-catch-lex.js"
Expect Syntax Error: "language/statements/try/static-init-await-binding-invalid.js"
Expect Syntax Error: "language/statements/variable/12.2.1-1gs.js"
Expect Syntax Error: "language/statements/variable/12.2.1-4gs.js"
@ -24397,6 +24395,24 @@ Expect to Parse: "language/statements/class/decorator/syntax/valid/decorator-par
33 │
╰────
× Identifier `"x"` has already been declared
╭─[language/statements/try/early-catch-duplicates.js:15:1]
15 │
16 │ try { } catch ([x, x]) {}
· ┬ ┬
· │ ╰── It can not be redeclared here
· ╰── `x` has already been declared here
╰────
× Identifier `"x"` has already been declared
╭─[language/statements/try/early-catch-lex.js:16:1]
16 │
17 │ try { } catch (x) { let x; }
· ┬ ┬
· │ ╰── It can not be redeclared here
· ╰── `x` has already been declared here
╰────
× Unexpected token
╭─[language/statements/try/optional-catch-binding-parens.js:19:1]
19 │

View file

@ -1,7 +1,7 @@
TypeScript Summary:
AST Parsed : 2306/2338 (98.63%)
Positive Passed: 2306/2338 (98.63%)
Negative Passed: 587/2532 (23.18%)
AST Parsed : 2305/2338 (98.59%)
Positive Passed: 2305/2338 (98.59%)
Negative Passed: 589/2532 (23.26%)
Expect Syntax Error: "Symbols/ES5SymbolProperty2.ts"
Expect Syntax Error: "Symbols/ES5SymbolProperty6.ts"
Expect Syntax Error: "additionalChecks/noPropertyAccessFromIndexSignature1.ts"
@ -998,7 +998,6 @@ Expect Syntax Error: "jsdoc/jsdocAugments_errorInExtendsExpression.ts"
Expect Syntax Error: "jsdoc/jsdocAugments_nameMismatch.ts"
Expect Syntax Error: "jsdoc/jsdocAugments_noExtends.ts"
Expect Syntax Error: "jsdoc/jsdocAugments_notAClass.ts"
Expect Syntax Error: "jsdoc/jsdocCatchClauseWithTypeAnnotation.ts"
Expect Syntax Error: "jsdoc/jsdocFunctionType.ts"
Expect Syntax Error: "jsdoc/jsdocFunction_missingReturn.ts"
Expect Syntax Error: "jsdoc/jsdocImplements_class.ts"
@ -1561,7 +1560,6 @@ Expect Syntax Error: "statements/for-ofStatements/ES5For-ofTypeCheck9.ts"
Expect Syntax Error: "statements/forStatements/forStatementsMultipleInvalidDecl.ts"
Expect Syntax Error: "statements/returnStatements/invalidReturnStatements.ts"
Expect Syntax Error: "statements/switchStatements/switchStatements.ts"
Expect Syntax Error: "statements/tryStatements/catchClauseWithTypeAnnotation.ts"
Expect Syntax Error: "types/any/anyAsConstructor.ts"
Expect Syntax Error: "types/any/anyAsGenericFunctionCall.ts"
Expect Syntax Error: "types/any/assignAnyToEveryType.ts"
@ -1947,6 +1945,19 @@ Expect Syntax Error: "types/unknown/unknownControlFlow.ts"
Expect Syntax Error: "types/unknown/unknownType1.ts"
Expect Syntax Error: "types/unknown/unknownType2.ts"
Expect Syntax Error: "types/witness/witness.ts"
Expect to Parse: "async/es6/asyncWithVarShadowing_es6.ts"
× Identifier `"x"` has already been declared
╭─[async/es6/asyncWithVarShadowing_es6.ts:131:1]
131 │ }
132 │ catch ({ x }) {
· ┬
· ╰── `x` has already been declared here
133 │ var x;
· ┬
· ╰── It can not be redeclared here
134 │ }
╰────
Expect to Parse: "classes/propertyMemberDeclarations/autoAccessor4.ts"
× Automatic Semicolon Insertion
@ -6104,6 +6115,19 @@ Expect to Parse: "salsa/privateIdentifierExpando.ts"
4 │ }
╰────
× Identifier `"err"` has already been declared
╭─[jsdoc/jsdocCatchClauseWithTypeAnnotation.ts:39:1]
39 │ try { }
40 │ catch (err) {
· ─┬─
· ╰── `err` has already been declared here
41 │ /** @type {string} */
42 │ let err;
· ─┬─
· ╰── It can not be redeclared here
43 │ }
╰────
× Unexpected token
╭─[jsdoc/jsdocDisallowedInTypescript.ts:3:1]
3 │ // grammar error from checker
@ -8873,6 +8897,16 @@ Expect to Parse: "salsa/privateIdentifierExpando.ts"
4 │
╰────
× Identifier `"x"` has already been declared
╭─[statements/tryStatements/catchClauseWithTypeAnnotation.ts:28:1]
28 │ // minor bug: shows that the `catch` argument is skipped when checking scope
29 │ try { } catch (x) { let x: string; }
· ┬ ┬
· │ ╰── It can not be redeclared here
· ╰── `x` has already been declared here
30 │ try { } catch (x) { var x: string; }
╰────
× Unexpected token
╭─[statements/tryStatements/invalidTryStatements.ts:1:1]
1 │ function fn() {