From dd49280e50cb2f5bd26dc07210551bc1fda120af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Garc=C3=ADa?= <82288753+juank1809@users.noreply.github.com> Date: Fri, 18 Mar 2022 12:48:02 -0500 Subject: [PATCH] fix(scope-manager): incorrect reference for this within a jsx identifier (#4535) --- .../src/referencer/Referencer.ts | 16 +- .../tests/fixtures/jsx/this-jsxidentifier.tsx | 12 ++ .../fixtures/jsx/this-jsxidentifier.tsx.shot | 143 ++++++++++++++++++ 3 files changed, 168 insertions(+), 3 deletions(-) create mode 100644 packages/scope-manager/tests/fixtures/jsx/this-jsxidentifier.tsx create mode 100644 packages/scope-manager/tests/fixtures/jsx/this-jsxidentifier.tsx.shot diff --git a/packages/scope-manager/src/referencer/Referencer.ts b/packages/scope-manager/src/referencer/Referencer.ts index 10273bfb6b3..3190af3a56c 100644 --- a/packages/scope-manager/src/referencer/Referencer.ts +++ b/packages/scope-manager/src/referencer/Referencer.ts @@ -509,17 +509,27 @@ class Referencer extends Visitor { } protected JSXMemberExpression(node: TSESTree.JSXMemberExpression): void { - this.visit(node.object); + if (node.object.type !== AST_NODE_TYPES.JSXIdentifier) { + this.visit(node.object); + } else { + if (node.object.name !== 'this') { + this.visit(node.object); + } + } // we don't ever reference the property as it's always going to be a property on the thing } - protected JSXOpeningElement(node: TSESTree.JSXOpeningElement): void { this.referenceJsxPragma(); if (node.name.type === AST_NODE_TYPES.JSXIdentifier) { - if (node.name.name[0].toUpperCase() === node.name.name[0]) { + if ( + node.name.name[0].toUpperCase() === node.name.name[0] || + node.name.name === 'this' + ) { // lower cased component names are always treated as "intrinsic" names, and are converted to a string, // not a variable by JSX transforms: //
=> React.createElement("div", null) + + // the only case we want to visit a lower-cased component has its name as "this", this.visit(node.name); } } else { diff --git a/packages/scope-manager/tests/fixtures/jsx/this-jsxidentifier.tsx b/packages/scope-manager/tests/fixtures/jsx/this-jsxidentifier.tsx new file mode 100644 index 00000000000..4a3190a5a6d --- /dev/null +++ b/packages/scope-manager/tests/fixtures/jsx/this-jsxidentifier.tsx @@ -0,0 +1,12 @@ +declare const React; + +class Foo { + foo: any; + Div = { + Element: () =>
, + }; + method() { + ; + ()(); + } +} diff --git a/packages/scope-manager/tests/fixtures/jsx/this-jsxidentifier.tsx.shot b/packages/scope-manager/tests/fixtures/jsx/this-jsxidentifier.tsx.shot new file mode 100644 index 00000000000..713e659bb5b --- /dev/null +++ b/packages/scope-manager/tests/fixtures/jsx/this-jsxidentifier.tsx.shot @@ -0,0 +1,143 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`jsx this-jsxidentifier 1`] = ` +ScopeManager { + variables: Array [ + ImplicitGlobalConstTypeVariable, + Variable$2 { + defs: Array [ + VariableDefinition$1 { + name: Identifier<"React">, + node: VariableDeclarator$1, + }, + ], + name: "React", + references: Array [ + Reference$1 { + identifier: Identifier<"React">, + isRead: true, + isTypeReference: false, + isValueReference: true, + isWrite: false, + resolved: Variable$2, + }, + ], + isValueVariable: true, + isTypeVariable: false, + }, + Variable$3 { + defs: Array [ + ClassNameDefinition$2 { + name: Identifier<"Foo">, + node: ClassDeclaration$2, + }, + ], + name: "Foo", + references: Array [], + isValueVariable: true, + isTypeVariable: true, + }, + Variable$4 { + defs: Array [ + ClassNameDefinition$3 { + name: Identifier<"Foo">, + node: ClassDeclaration$2, + }, + ], + name: "Foo", + references: Array [], + isValueVariable: true, + isTypeVariable: true, + }, + Variable$5 { + defs: Array [], + name: "arguments", + references: Array [], + isValueVariable: true, + isTypeVariable: true, + }, + ], + scopes: Array [ + GlobalScope$1 { + block: Program$3, + isStrict: false, + references: Array [ + Reference$1, + ], + set: Map { + "const" => ImplicitGlobalConstTypeVariable, + "React" => Variable$2, + "Foo" => Variable$3, + }, + type: "global", + upper: null, + variables: Array [ + ImplicitGlobalConstTypeVariable, + Variable$2, + Variable$3, + ], + }, + ClassScope$2 { + block: ClassDeclaration$2, + isStrict: true, + references: Array [], + set: Map { + "Foo" => Variable$4, + }, + type: "class", + upper: GlobalScope$1, + variables: Array [ + Variable$4, + ], + }, + ClassFieldInitializerScope$3 { + block: ObjectExpression$4, + isStrict: true, + references: Array [], + set: Map {}, + type: "class-field-initializer", + upper: ClassScope$2, + variables: Array [], + }, + FunctionScope$4 { + block: ArrowFunctionExpression$5, + isStrict: true, + references: Array [], + set: Map {}, + type: "function", + upper: ClassFieldInitializerScope$3, + variables: Array [], + }, + FunctionScope$5 { + block: FunctionExpression$6, + isStrict: true, + references: Array [ + Reference$2 { + identifier: JSXIdentifier$7, + isRead: true, + isTypeReference: false, + isValueReference: true, + isWrite: false, + resolved: null, + }, + Reference$3 { + identifier: JSXIdentifier$8, + isRead: true, + isTypeReference: false, + isValueReference: true, + isWrite: false, + resolved: null, + }, + ], + set: Map { + "arguments" => Variable$5, + }, + type: "function", + upper: ClassScope$2, + variables: Array [ + Variable$5, + ], + }, + ], +} +`;