diff --git a/lib/util/Components.js b/lib/util/Components.js index b7e2a99a63..2ea7cc896f 100644 --- a/lib/util/Components.js +++ b/lib/util/Components.js @@ -456,15 +456,16 @@ function componentRule(rule, context) { let scope = context.getScope(); while (scope) { const node = scope.block; - const isClass = node.type === 'ClassExpression'; const isFunction = /Function/.test(node.type); // Functions const isArrowFunction = node.type === 'ArrowFunctionExpression'; - let functionScope = scope; + let enclosingScope = scope; if (isArrowFunction) { - functionScope = utils.getParentFunctionScope(scope); + enclosingScope = utils.getArrowFunctionScope(scope); } - const methodNode = functionScope && functionScope.block.parent; - const isMethod = methodNode && methodNode.type === 'MethodDefinition'; // Classes methods + const enclosingScopeType = enclosingScope && enclosingScope.block.type; + const enclosingScopeParent = enclosingScope && enclosingScope.block.parent; + const isClass = enclosingScopeType === 'ClassDeclaration' || enclosingScopeType === 'ClassExpression'; + const isMethod = enclosingScopeParent && enclosingScopeParent.type === 'MethodDefinition'; // Classes methods const isArgument = node.parent && node.parent.type === 'CallExpression'; // Arguments (callback, etc.) // Attribute Expressions inside JSX Elements () const isJSXExpressionContainer = node.parent && node.parent.type === 'JSXExpressionContainer'; @@ -482,15 +483,16 @@ function componentRule(rule, context) { }, /** - * Get a parent scope created by a FunctionExpression or FunctionDeclaration - * @param {Scope} scope The child scope - * @returns {Scope} A parent function scope + * Get an enclosing scope used to find `this` value by an arrow function + * @param {Scope} scope Current scope + * @returns {Scope} An enclosing scope used by an arrow function */ - getParentFunctionScope(scope) { + getArrowFunctionScope(scope) { scope = scope.upper; while (scope) { const type = scope.block.type; - if (type === 'FunctionExpression' || type === 'FunctionDeclaration') { + if (type === 'FunctionExpression' || type === 'FunctionDeclaration' + || type === 'ClassDeclaration' || type === 'ClassExpression') { return scope; } scope = scope.upper; diff --git a/tests/lib/rules/no-this-in-sfc.js b/tests/lib/rules/no-this-in-sfc.js index 63a849f840..9c241cb8ed 100644 --- a/tests/lib/rules/no-this-in-sfc.js +++ b/tests/lib/rules/no-this-in-sfc.js @@ -16,6 +16,8 @@ const ERROR_MESSAGE = 'Stateless functional components should not use this'; const rule = require('../../../lib/rules/no-this-in-sfc'); const RuleTester = require('eslint').RuleTester; +require('babel-eslint'); + const parserOptions = { ecmaVersion: 2018, sourceType: 'module', @@ -119,6 +121,24 @@ ruleTester.run('no-this-in-sfc', rule, { }; } }` + }, { + code: ` + class Foo { + bar = () => { + this.something(); + return null; + }; + }`, + parser: 'babel-eslint' + }, { + code: ` + class Foo { + bar = () => () => { + this.something(); + return null; + }; + }`, + parser: 'babel-eslint' }], invalid: [{ code: `