diff --git a/lib/rules/no-extra-bind.js b/lib/rules/no-extra-bind.js index b8376adfc11..6d6cad13e97 100644 --- a/lib/rules/no-extra-bind.js +++ b/lib/rules/no-extra-bind.js @@ -10,6 +10,12 @@ const astUtils = require("../util/ast-utils"); +//------------------------------------------------------------------------------ +// Helpers +//------------------------------------------------------------------------------ + +const SIDE_EFFECT_FREE_NODE_TYPES = new Set(["Literal", "Identifier", "ThisExpression", "FunctionExpression"]); + //------------------------------------------------------------------------------ // Rule Definition //------------------------------------------------------------------------------ @@ -35,6 +41,18 @@ module.exports = { create(context) { let scopeInfo = null; + /** + * Checks if a node is free of side effects. + * + * This check is stricter than it needs to be, in order to keep the implementation simple. + * + * @param {ASTNode} node A node to check. + * @returns {boolean} True if the node is known to be side-effect free, false otherwise. + */ + function isSideEffectFree(node) { + return SIDE_EFFECT_FREE_NODE_TYPES.has(node.type); + } + /** * Reports a given function node. * @@ -48,6 +66,10 @@ module.exports = { messageId: "unexpected", loc: node.parent.property.loc.start, fix(fixer) { + if (node.parent.parent.arguments.length && !isSideEffectFree(node.parent.parent.arguments[0])) { + return null; + } + const firstTokenToRemove = context.getSourceCode() .getFirstTokenBetween(node.parent.object, node.parent.property, astUtils.isNotClosingParenToken); diff --git a/tests/lib/rules/no-extra-bind.js b/tests/lib/rules/no-extra-bind.js index 4dfec87ac6c..4e5a08f3660 100644 --- a/tests/lib/rules/no-extra-bind.js +++ b/tests/lib/rules/no-extra-bind.js @@ -70,10 +70,32 @@ ruleTester.run("no-extra-bind", rule, { output: "var a = function() { function c(){ this.d } }", errors }, + { + code: "var a = function() { return 1; }.bind(this)", + output: "var a = function() { return 1; }", + errors + }, { code: "var a = function() { (function(){ (function(){ this.d }.bind(c)) }) }.bind(b)", output: "var a = function() { (function(){ (function(){ this.d }.bind(c)) }) }", errors: [{ messageId: "unexpected", type: "CallExpression", column: 71 }] + }, + + // Should not autofix if bind expression args have side effects + { + code: "var a = function() {}.bind(b++)", + output: null, + errors + }, + { + code: "var a = function() {}.bind(b())", + output: null, + errors + }, + { + code: "var a = function() {}.bind(b.c)", + output: null, + errors } ] });