From a42fa46a11854d3fd80a45df2b649d0e3466c181 Mon Sep 17 00:00:00 2001 From: YeonJuan Date: Sun, 8 Dec 2024 18:46:48 +0900 Subject: [PATCH] fix(scope-manager): visit params decorator before nest scope --- .../no-unused-vars/no-unused-vars.test.ts | 63 +++++++++++++++++++ .../src/referencer/ClassVisitor.ts | 5 +- .../decorators/parameter-property.ts.shot | 11 ++-- .../tests/fixtures/decorators/parameter.ts | 9 ++- .../fixtures/decorators/parameter.ts.shot | 50 ++++++++++++--- 5 files changed, 124 insertions(+), 14 deletions(-) diff --git a/packages/eslint-plugin/tests/rules/no-unused-vars/no-unused-vars.test.ts b/packages/eslint-plugin/tests/rules/no-unused-vars/no-unused-vars.test.ts index 2b48e7c6706a..3461829abd44 100644 --- a/packages/eslint-plugin/tests/rules/no-unused-vars/no-unused-vars.test.ts +++ b/packages/eslint-plugin/tests/rules/no-unused-vars/no-unused-vars.test.ts @@ -1116,6 +1116,58 @@ export const x = _Foo; }, ], }, + { + code: ` +const command = (): ParameterDecorator => { + return () => {}; +}; + +export class Foo { + bar(@command() command: string) {} +} + `, + errors: [ + { + data: { + action: 'defined', + additional: '', + varName: 'command', + }, + line: 7, + messageId: 'unusedVar', + }, + ], + }, + { + code: ` +declare const deco: () => ParameterDecorator; + +export class Foo { + bar(@deco() deco, @deco() param) {} +} + `, + errors: [ + { + column: 15, + data: { + action: 'defined', + additional: '', + varName: 'deco', + }, + line: 5, + messageId: 'unusedVar', + }, + { + data: { + action: 'defined', + additional: '', + varName: 'param', + }, + line: 5, + messageId: 'unusedVar', + }, + ], + }, ], valid: [ @@ -2274,5 +2326,16 @@ export enum Foo { `, options: [{ reportUsedIgnorePattern: true, varsIgnorePattern: '_' }], }, + ` +const command = (): ParameterDecorator => { + return () => {}; +}; + +export class Foo { + bar(@command() command: string) { + console.log(command); + } +} + `, ], }); diff --git a/packages/scope-manager/src/referencer/ClassVisitor.ts b/packages/scope-manager/src/referencer/ClassVisitor.ts index 1c5d94a8775f..d83781ff0b57 100644 --- a/packages/scope-manager/src/referencer/ClassVisitor.ts +++ b/packages/scope-manager/src/referencer/ClassVisitor.ts @@ -115,6 +115,10 @@ class ClassVisitor extends Visitor { this.#referencer.scopeManager.nestFunctionExpressionNameScope(node); } + node.params.forEach(param => { + param.decorators.forEach(d => this.visit(d)); + }); + // Consider this function is in the MethodDefinition. this.#referencer.scopeManager.nestFunctionScope(node, true); @@ -205,7 +209,6 @@ class ClassVisitor extends Visitor { { processRightHandNodes: true }, ); this.visitFunctionParameterTypeAnnotation(param); - param.decorators.forEach(d => this.visit(d)); } this.visitType(node.returnType); diff --git a/packages/scope-manager/tests/fixtures/decorators/parameter-property.ts.shot b/packages/scope-manager/tests/fixtures/decorators/parameter-property.ts.shot index dd65f9828627..c819741a89d2 100644 --- a/packages/scope-manager/tests/fixtures/decorators/parameter-property.ts.shot +++ b/packages/scope-manager/tests/fixtures/decorators/parameter-property.ts.shot @@ -21,7 +21,7 @@ ScopeManager { isWrite: false, resolved: Variable$2, }, - Reference$3 { + Reference$2 { identifier: Identifier<"decorator">, isRead: true, isTypeReference: false, @@ -92,7 +92,7 @@ ScopeManager { ], name: "b", references: [ - Reference$2 { + Reference$3 { identifier: Identifier<"b">, init: true, isRead: false, @@ -141,7 +141,10 @@ ScopeManager { ClassScope$3 { block: ClassDeclaration$2, isStrict: true, - references: [], + references: [ + Reference$1, + Reference$2, + ], set: Map { "Foo" => Variable$5, }, @@ -155,8 +158,6 @@ ScopeManager { block: FunctionExpression$3, isStrict: true, references: [ - Reference$1, - Reference$2, Reference$3, ], set: Map { diff --git a/packages/scope-manager/tests/fixtures/decorators/parameter.ts b/packages/scope-manager/tests/fixtures/decorators/parameter.ts index a518ad975a0f..1a0223f1d020 100644 --- a/packages/scope-manager/tests/fixtures/decorators/parameter.ts +++ b/packages/scope-manager/tests/fixtures/decorators/parameter.ts @@ -1,4 +1,11 @@ function decorator() {} class A { - foo(@decorator a, @decorator [b], @decorator { c }, @decorator d = 1) {} + foo( + @decorator a, + @decorator [b], + @decorator { c }, + @decorator d = 1, + @decorator decorator, + @d decorator, + ) {} } diff --git a/packages/scope-manager/tests/fixtures/decorators/parameter.ts.shot b/packages/scope-manager/tests/fixtures/decorators/parameter.ts.shot index 491ddab990e3..67c22a93dd4a 100644 --- a/packages/scope-manager/tests/fixtures/decorators/parameter.ts.shot +++ b/packages/scope-manager/tests/fixtures/decorators/parameter.ts.shot @@ -37,6 +37,14 @@ ScopeManager { isWrite: false, resolved: Variable$2, }, + Reference$4 { + identifier: Identifier<"decorator">, + isRead: true, + isTypeReference: false, + isValueReference: true, + isWrite: false, + resolved: Variable$2, + }, Reference$5 { identifier: Identifier<"decorator">, isRead: true, @@ -132,7 +140,7 @@ ScopeManager { ], name: "d", references: [ - Reference$4 { + Reference$7 { identifier: Identifier<"d">, init: true, isRead: false, @@ -146,6 +154,22 @@ ScopeManager { isValueVariable: true, isTypeVariable: false, }, + Variable$11 { + defs: [ + ParameterDefinition$8 { + name: Identifier<"decorator">, + node: FunctionExpression$3, + }, + ParameterDefinition$9 { + name: Identifier<"decorator">, + node: FunctionExpression$3, + }, + ], + name: "decorator", + references: [], + isValueVariable: true, + isTypeVariable: false, + }, ], scopes: [ GlobalScope$1 { @@ -181,7 +205,21 @@ ScopeManager { ClassScope$3 { block: ClassDeclaration$2, isStrict: true, - references: [], + references: [ + Reference$1, + Reference$2, + Reference$3, + Reference$4, + Reference$5, + Reference$6 { + identifier: Identifier<"d">, + isRead: true, + isTypeReference: false, + isValueReference: true, + isWrite: false, + resolved: null, + }, + ], set: Map { "A" => Variable$5, }, @@ -195,11 +233,7 @@ ScopeManager { block: FunctionExpression$3, isStrict: true, references: [ - Reference$1, - Reference$2, - Reference$3, - Reference$4, - Reference$5, + Reference$7, ], set: Map { "arguments" => Variable$6, @@ -207,6 +241,7 @@ ScopeManager { "b" => Variable$8, "c" => Variable$9, "d" => Variable$10, + "decorator" => Variable$11, }, type: "function", upper: ClassScope$3, @@ -216,6 +251,7 @@ ScopeManager { Variable$8, Variable$9, Variable$10, + Variable$11, ], }, ],