From bc274e037d3a409c3558ab4ef14ff73283bc474a Mon Sep 17 00:00:00 2001 From: Toru Nagashima Date: Mon, 27 May 2019 11:28:45 +0900 Subject: [PATCH] fix rule behavior - Makes the member accesses of parameters danger. - Makes closure handling relax. --- lib/rules/require-atomic-updates.js | 29 +++++++++++++++++++---------- 1 file changed, 19 insertions(+), 10 deletions(-) diff --git a/lib/rules/require-atomic-updates.js b/lib/rules/require-atomic-updates.js index 86783b84439..92e27d5641e 100644 --- a/lib/rules/require-atomic-updates.js +++ b/lib/rules/require-atomic-updates.js @@ -55,18 +55,25 @@ function getWriteExpr(reference) { /** * Checks if an expression is a variable that can only be observed within the given function. - * @param {escope.Variable} variable The variable to check - * @returns {boolean} `true` if the variable is local to the given function, and is never referenced in a closure. + * @param {Scope} functionScope The function scope of the current function. + * @param {Variable|null} variable The variable to check + * @param {boolean} isMemberAccess If `true` then this is a member access. + * @returns {boolean} `true` if the variable is local to the given function. */ -function isLocalVariableWithoutEscape(variable) { +function isLocalVariable(functionScope, variable, isMemberAccess) { if (!variable) { return false; // A global variable which was not defined. } - const functionScope = variable.scope.variableScope; + // If the reference is a property access and the variable is a parameter, it handles the variable is not local. + if (isMemberAccess && variable.defs.some(d => d.type === "Parameter")) { + return false; + } - return variable.references.every(reference => - reference.from.variableScope === functionScope); + return variable.defs.every(def => ( + def.node.range[0] >= functionScope.block.range[0] && + def.node.range[1] <= functionScope.block.range[1] + )); } class SegmentInfo { @@ -184,7 +191,8 @@ module.exports = { stack = { upper: stack, codePath, - referenceMap: shouldVerify ? createReferenceMap(scope) : null + referenceMap: shouldVerify ? createReferenceMap(scope) : null, + scope }; }, onCodePathEnd() { @@ -198,7 +206,7 @@ module.exports = { // Handle references to prepare verification. Identifier(node) { - const { codePath, referenceMap } = stack; + const { codePath, referenceMap, scope } = stack; const reference = referenceMap && referenceMap.get(node); // Ignore if this is not a valid variable reference. @@ -208,6 +216,7 @@ module.exports = { const name = reference.identifier.name; const variable = reference.resolved; const writeExpr = getWriteExpr(reference); + const isMemberAccess = reference.identifier.parent.type === "MemberExpression"; // Add a fresh read variable. if (reference.isRead() && !(writeExpr && writeExpr.parent.operator === "=")) { @@ -216,11 +225,11 @@ module.exports = { /* * Register the variable to verify after ESLint traversed the `writeExpr` node - * if this reference is an assignment to a variable which is referred from other clausure. + * if this reference is an assignment to a local variable. */ if (writeExpr && writeExpr.parent.right === writeExpr && // ← exclude variable declarations. - !isLocalVariableWithoutEscape(variable) + !isLocalVariable(scope, variable, isMemberAccess) ) { let refs = assignmentReferences.get(writeExpr);