Skip to content

Commit

Permalink
fix(scope-manager): fix incorrect handling of class decorators and cl…
Browse files Browse the repository at this point in the history
…ass method default params (#2943)

Fixes #2941
Fixes #2942

This was a regression introduced by #2751
  • Loading branch information
bradzacher committed Jan 19, 2021
1 parent 60c5dcd commit e1eac83
Show file tree
Hide file tree
Showing 7 changed files with 375 additions and 1 deletion.
11 changes: 11 additions & 0 deletions packages/eslint-plugin/tests/eslint-rules/no-undef.test.ts
Expand Up @@ -224,6 +224,17 @@ function Foo() {}
`
const x = 1 as const;
`,
// https://github.com/typescript-eslint/typescript-eslint/issues/2942
`
declare function deco(...param: any): (...param: any) => any;
@deco({
components: {
val: true,
},
})
class Foo {}
`,
],
invalid: [
{
Expand Down
14 changes: 14 additions & 0 deletions packages/eslint-plugin/tests/rules/no-use-before-define.test.ts
Expand Up @@ -428,6 +428,20 @@ export class CidrIpPatternDirective implements Validator {}
},
],
},
// https://github.com/typescript-eslint/typescript-eslint/issues/2941
`
class A {
constructor(printName) {
this.printName = printName;
}
openPort(printerName = this.printerName) {
this.tscOcx.ActiveXopenport(printerName);
return this;
}
}
`,
],
invalid: [
{
Expand Down
17 changes: 16 additions & 1 deletion packages/scope-manager/src/referencer/ClassVisitor.ts
Expand Up @@ -33,6 +33,15 @@ class ClassVisitor extends Visitor {
classVisitor.visitClass(node);
}

visit(node: TSESTree.Node | null | undefined): void {
// make sure we only handle the nodes we are designed to handle
if (node && node.type in this) {
super.visit(node);
} else {
this.#referencer.visit(node);
}
}

///////////////////
// Visit helpers //
///////////////////
Expand All @@ -46,7 +55,7 @@ class ClassVisitor extends Visitor {
.defineIdentifier(node.id, new ClassNameDefinition(node.id, node));
}

node.decorators?.forEach(d => this.visit(d));
node.decorators?.forEach(d => this.#referencer.visit(d));

this.#referencer.scopeManager.nestClassScope(node);

Expand Down Expand Up @@ -298,6 +307,12 @@ class ClassVisitor extends Visitor {
// Visit selectors //
/////////////////////

protected ClassBody(node: TSESTree.ClassBody): void {
// this is here on purpose so that this visitor explicitly declares visitors
// for all nodes it cares about (see the instance visit method above)
this.visitChildren(node);
}

protected ClassProperty(node: TSESTree.ClassProperty): void {
this.visitClassProperty(node);
}
Expand Down
@@ -0,0 +1,13 @@
// https://github.com/typescript-eslint/typescript-eslint/issues/2941

class A {
constructor(printName) {
this.printName = printName;
}

openPort(printerName = this.printerName) {
this.tscOcx.ActiveXopenport(printerName);

return this;
}
}
@@ -0,0 +1,164 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`class declaration method-param-default 1`] = `
ScopeManager {
variables: Array [
ImplicitGlobalConstTypeVariable,
Variable$2 {
defs: Array [
ClassNameDefinition$1 {
name: Identifier<"A">,
node: ClassDeclaration$1,
},
],
name: "A",
references: Array [],
isValueVariable: true,
isTypeVariable: true,
},
Variable$3 {
defs: Array [
ClassNameDefinition$2 {
name: Identifier<"A">,
node: ClassDeclaration$1,
},
],
name: "A",
references: Array [],
isValueVariable: true,
isTypeVariable: true,
},
Variable$4 {
defs: Array [],
name: "arguments",
references: Array [],
isValueVariable: true,
isTypeVariable: true,
},
Variable$5 {
defs: Array [
ParameterDefinition$3 {
name: Identifier<"printName">,
node: FunctionExpression$2,
},
],
name: "printName",
references: Array [
Reference$1 {
identifier: Identifier<"printName">,
isRead: true,
isTypeReference: false,
isValueReference: true,
isWrite: false,
resolved: Variable$5,
},
],
isValueVariable: true,
isTypeVariable: false,
},
Variable$6 {
defs: Array [],
name: "arguments",
references: Array [],
isValueVariable: true,
isTypeVariable: true,
},
Variable$7 {
defs: Array [
ParameterDefinition$4 {
name: Identifier<"printerName">,
node: FunctionExpression$3,
},
],
name: "printerName",
references: Array [
Reference$2 {
identifier: Identifier<"printerName">,
init: true,
isRead: false,
isTypeReference: false,
isValueReference: true,
isWrite: true,
resolved: Variable$7,
writeExpr: MemberExpression$4,
},
Reference$3 {
identifier: Identifier<"printerName">,
isRead: true,
isTypeReference: false,
isValueReference: true,
isWrite: false,
resolved: Variable$7,
},
],
isValueVariable: true,
isTypeVariable: false,
},
],
scopes: Array [
GlobalScope$1 {
block: Program$5,
isStrict: false,
references: Array [],
set: Map {
"const" => ImplicitGlobalConstTypeVariable,
"A" => Variable$2,
},
type: "global",
upper: null,
variables: Array [
ImplicitGlobalConstTypeVariable,
Variable$2,
],
},
ClassScope$2 {
block: ClassDeclaration$1,
isStrict: true,
references: Array [],
set: Map {
"A" => Variable$3,
},
type: "class",
upper: GlobalScope$1,
variables: Array [
Variable$3,
],
},
FunctionScope$3 {
block: FunctionExpression$2,
isStrict: true,
references: Array [
Reference$1,
],
set: Map {
"arguments" => Variable$4,
"printName" => Variable$5,
},
type: "function",
upper: ClassScope$2,
variables: Array [
Variable$4,
Variable$5,
],
},
FunctionScope$4 {
block: FunctionExpression$3,
isStrict: true,
references: Array [
Reference$2,
Reference$3,
],
set: Map {
"arguments" => Variable$6,
"printerName" => Variable$7,
},
type: "function",
upper: ClassScope$2,
variables: Array [
Variable$6,
Variable$7,
],
},
],
}
`;
@@ -0,0 +1,10 @@
// https://github.com/typescript-eslint/typescript-eslint/issues/2942

declare function deco(...param: any): (...param: any) => any;

@deco({
components: {
val: true,
},
})
class Foo {}

0 comments on commit e1eac83

Please sign in to comment.