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 ea2eb03d733..eaf59a48571 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 @@ -1,6 +1,6 @@ import rule from '../../../src/rules/no-unused-vars'; import { collectUnusedVariables } from '../../../src/util'; -import { noFormat, RuleTester } from '../../RuleTester'; +import { getFixturesRootDir, noFormat, RuleTester } from '../../RuleTester'; const ruleTester = new RuleTester({ parserOptions: { @@ -11,6 +11,11 @@ const ruleTester = new RuleTester({ parser: '@typescript-eslint/parser', }); +const withMetaParserOptions = { + tsconfigRootDir: getFixturesRootDir(), + project: './tsconfig-withmeta.json', +}; + // this is used to ensure that the caching the utility does does not impact the results done by no-unused-vars ruleTester.defineRule('collect-unused-vars', context => { collectUnusedVariables(context); @@ -978,6 +983,19 @@ declare module 'next-auth' { } } `, + // https://github.com/typescript-eslint/typescript-eslint/issues/2972 + { + code: ` +import { TestGeneric, Test } from 'fake-module'; + +declare function deco(..._param: any): any; +export class TestClass { + @deco + public test(): TestGeneric {} +} + `, + parserOptions: withMetaParserOptions, + }, ], invalid: [ diff --git a/packages/scope-manager/src/referencer/ClassVisitor.ts b/packages/scope-manager/src/referencer/ClassVisitor.ts index 9f9315fa411..fff57583191 100644 --- a/packages/scope-manager/src/referencer/ClassVisitor.ts +++ b/packages/scope-manager/src/referencer/ClassVisitor.ts @@ -295,9 +295,14 @@ class ClassVisitor extends Visitor { } if (withDecorators) { - return this.#referencer - .currentScope() - .referenceDualValueType(identifier); + this.#referencer.currentScope().referenceDualValueType(identifier); + + if (node.typeAnnotation.typeParameters) { + this.visitType(node.typeAnnotation.typeParameters); + } + + // everything is handled now + return; } } this.visitType(node); diff --git a/packages/scope-manager/tests/fixtures/class/emit-metadata/method-return-generic.ts b/packages/scope-manager/tests/fixtures/class/emit-metadata/method-return-generic.ts new file mode 100644 index 00000000000..ea8c1a53790 --- /dev/null +++ b/packages/scope-manager/tests/fixtures/class/emit-metadata/method-return-generic.ts @@ -0,0 +1,9 @@ +//// @emitDecoratorMetadata = true + +import { TestGeneric, Test } from 'fake-module'; + +declare function deco(..._param: any): any; +export class TestClass { + @deco + public test(): TestGeneric {} +} diff --git a/packages/scope-manager/tests/fixtures/class/emit-metadata/method-return-generic.ts.shot b/packages/scope-manager/tests/fixtures/class/emit-metadata/method-return-generic.ts.shot new file mode 100644 index 00000000000..64e13471b5e --- /dev/null +++ b/packages/scope-manager/tests/fixtures/class/emit-metadata/method-return-generic.ts.shot @@ -0,0 +1,191 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`class emit-metadata method-return-generic 1`] = ` +ScopeManager { + variables: Array [ + ImplicitGlobalConstTypeVariable, + Variable$2 { + defs: Array [ + ImportBindingDefinition$1 { + name: Identifier<"TestGeneric">, + node: ImportSpecifier$1, + }, + ], + name: "TestGeneric", + references: Array [ + Reference$1 { + identifier: Identifier<"TestGeneric">, + isRead: true, + isTypeReference: true, + isValueReference: true, + isWrite: false, + resolved: Variable$2, + }, + ], + isValueVariable: true, + isTypeVariable: true, + }, + Variable$3 { + defs: Array [ + ImportBindingDefinition$2 { + name: Identifier<"Test">, + node: ImportSpecifier$2, + }, + ], + name: "Test", + references: Array [ + Reference$2 { + identifier: Identifier<"Test">, + isRead: true, + isTypeReference: true, + isValueReference: false, + isWrite: false, + resolved: Variable$3, + }, + ], + isValueVariable: true, + isTypeVariable: true, + }, + Variable$4 { + defs: Array [ + FunctionNameDefinition$3 { + name: Identifier<"deco">, + node: TSDeclareFunction$3, + }, + ], + name: "deco", + references: Array [ + Reference$3 { + identifier: Identifier<"deco">, + isRead: true, + isTypeReference: false, + isValueReference: true, + isWrite: false, + resolved: Variable$4, + }, + ], + isValueVariable: true, + isTypeVariable: false, + }, + Variable$5 { + defs: Array [], + name: "arguments", + references: Array [], + isValueVariable: true, + isTypeVariable: true, + }, + Variable$6 { + defs: Array [ + ParameterDefinition$4 { + name: Identifier<"_param">, + node: TSDeclareFunction$3, + }, + ], + name: "_param", + references: Array [], + isValueVariable: true, + isTypeVariable: false, + }, + Variable$7 { + defs: Array [ + ClassNameDefinition$5 { + name: Identifier<"TestClass">, + node: ClassDeclaration$4, + }, + ], + name: "TestClass", + references: Array [], + isValueVariable: true, + isTypeVariable: true, + }, + Variable$8 { + defs: Array [ + ClassNameDefinition$6 { + name: Identifier<"TestClass">, + node: ClassDeclaration$4, + }, + ], + name: "TestClass", + references: Array [], + isValueVariable: true, + isTypeVariable: true, + }, + Variable$9 { + defs: Array [], + name: "arguments", + references: Array [], + isValueVariable: true, + isTypeVariable: true, + }, + ], + scopes: Array [ + GlobalScope$1 { + block: Program$5, + isStrict: false, + references: Array [], + set: Map { + "const" => ImplicitGlobalConstTypeVariable, + "TestGeneric" => Variable$2, + "Test" => Variable$3, + "deco" => Variable$4, + "TestClass" => Variable$7, + }, + type: "global", + upper: null, + variables: Array [ + ImplicitGlobalConstTypeVariable, + Variable$2, + Variable$3, + Variable$4, + Variable$7, + ], + }, + FunctionScope$2 { + block: TSDeclareFunction$3, + isStrict: false, + references: Array [], + set: Map { + "arguments" => Variable$5, + "_param" => Variable$6, + }, + type: "function", + upper: GlobalScope$1, + variables: Array [ + Variable$5, + Variable$6, + ], + }, + ClassScope$3 { + block: ClassDeclaration$4, + isStrict: true, + references: Array [ + Reference$3, + ], + set: Map { + "TestClass" => Variable$8, + }, + type: "class", + upper: GlobalScope$1, + variables: Array [ + Variable$8, + ], + }, + FunctionScope$4 { + block: FunctionExpression$6, + isStrict: true, + references: Array [ + Reference$1, + Reference$2, + ], + set: Map { + "arguments" => Variable$9, + }, + type: "function", + upper: ClassScope$3, + variables: Array [ + Variable$9, + ], + }, + ], +} +`;