diff --git a/lib/util/Components.js b/lib/util/Components.js index 1854c8e6a7..6d0b72dfba 100644 --- a/lib/util/Components.js +++ b/lib/util/Components.js @@ -457,15 +457,12 @@ 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; - if (isArrowFunction) { - functionScope = utils.getParentFunctionScope(scope); - } - const methodNode = functionScope && functionScope.block.parent; - const isMethod = methodNode && methodNode.type === 'MethodDefinition'; // Classes methods + const isArrowFunction = astUtil.isArrowFunction(node); + const enclosingScope = isArrowFunction ? utils.getArrowFunctionScope(scope) : scope; + const enclosingScopeParent = enclosingScope && enclosingScope.block.parent; + const isClass = enclosingScope && astUtil.isClass(enclosingScope.block); + 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'; @@ -483,15 +480,14 @@ 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 (astUtil.isFunction(scope.block) || astUtil.isClass(scope.block)) { return scope; } scope = scope.upper; diff --git a/lib/util/ast.js b/lib/util/ast.js index 10fc434625..9af7e0c5ce 100644 --- a/lib/util/ast.js +++ b/lib/util/ast.js @@ -102,11 +102,41 @@ function isFunctionLikeExpression(node) { return node.type === 'FunctionExpression' || node.type === 'ArrowFunctionExpression'; } +/** + * Checks if the node is a function. + * @param {Object} context The node to check + * @return {Boolean} true if it's a function + */ +function isFunction(node) { + return node.type === 'FunctionExpression' || node.type === 'FunctionDeclaration'; +} + +/** + * Checks if the node is an arrow function. + * @param {Object} context The node to check + * @return {Boolean} true if it's an arrow function + */ +function isArrowFunction(node) { + return node.type === 'ArrowFunctionExpression'; +} + +/** + * Checks if the node is a class. + * @param {Object} context The node to check + * @return {Boolean} true if it's a class + */ +function isClass(node) { + return node.type === 'ClassDeclaration' || node.type === 'ClassExpression'; +} + module.exports = { findReturnStatement: findReturnStatement, getPropertyName: getPropertyName, getPropertyNameNode: getPropertyNameNode, getComponentProperties: getComponentProperties, - isNodeFirstInLine: isNodeFirstInLine, - isFunctionLikeExpression: isFunctionLikeExpression + isArrowFunction: isArrowFunction, + isClass: isClass, + isFunction: isFunction, + isFunctionLikeExpression: isFunctionLikeExpression, + isNodeFirstInLine: isNodeFirstInLine }; diff --git a/tests/lib/rules/no-this-in-sfc.js b/tests/lib/rules/no-this-in-sfc.js index 63a849f840..b5d87f0267 100644 --- a/tests/lib/rules/no-this-in-sfc.js +++ b/tests/lib/rules/no-this-in-sfc.js @@ -119,6 +119,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: `