From d1d95e0e494c0630591f04e41bb82bb94d45a413 Mon Sep 17 00:00:00 2001 From: Sebastian McKenzie Date: Thu, 28 May 2015 10:04:32 -0400 Subject: [PATCH] check LHS of ForIn/ForOfStatement for constants - closes #1630 --- .../transformers/es6/constants.js | 17 ++++++++++++++--- src/babel/traversal/scope/index.js | 7 +++++++ src/babel/types/alias-keys.json | 4 ++-- .../es6.constants/no-for-in/actual.js | 3 +++ .../es6.constants/no-for-in/options.json | 3 +++ 5 files changed, 29 insertions(+), 5 deletions(-) create mode 100644 test/core/fixtures/transformation/es6.constants/no-for-in/actual.js create mode 100644 test/core/fixtures/transformation/es6.constants/no-for-in/options.json diff --git a/src/babel/transformation/transformers/es6/constants.js b/src/babel/transformation/transformers/es6/constants.js index 54021f8058..5c72905b76 100644 --- a/src/babel/transformation/transformers/es6/constants.js +++ b/src/babel/transformation/transformers/es6/constants.js @@ -1,12 +1,12 @@ import * as messages from "../../../messages"; -export function AssignmentExpression(node, parent, scope, file) { - var ids = this.getBindingIdentifiers(); +function checkPath(path, file) { + var ids = path.getBindingIdentifiers(); for (var name in ids) { var id = ids[name]; - var binding = scope.getBinding(name); + var binding = path.scope.getBinding(name); // no binding exists if (!binding) continue; @@ -23,8 +23,19 @@ export function AssignmentExpression(node, parent, scope, file) { } } +export function AssignmentExpression(node, parent, scope, file) { + checkPath(this, file); +} + export { AssignmentExpression as UpdateExpression }; export function VariableDeclaration(node) { if (node.kind === "const") node.kind = "let"; } + +export function ForXStatement(node, parent, scope, file) { + var left = this.get("left"); + if (left.isIdentifier() || left.isPattern()) { + checkPath(left, file); + } +} diff --git a/src/babel/traversal/scope/index.js b/src/babel/traversal/scope/index.js index 92fc9cc6c1..e96756c6b7 100644 --- a/src/babel/traversal/scope/index.js +++ b/src/babel/traversal/scope/index.js @@ -46,6 +46,13 @@ var programReferenceVisitor = { } }, + ForXStatement(node, parent, scope, state) { + var left = this.get("left"); + if (left.isPattern() || left.isIdentifier()) { + scope.registerConstantViolation(left); + } + }, + Scopable(node, parent, scope, state) { for (var name in scope.bindings) { state.references[name] = true; diff --git a/src/babel/types/alias-keys.json b/src/babel/types/alias-keys.json index 07fc4000e9..bff7f8134f 100644 --- a/src/babel/types/alias-keys.json +++ b/src/babel/types/alias-keys.json @@ -44,8 +44,8 @@ "ClassDeclaration": ["Scopable", "Class", "Statement", "Declaration"], "ClassExpression": ["Scopable", "Class", "Expression"], - "ForOfStatement": ["Scopable", "Statement", "For", "Loop"], - "ForInStatement": ["Scopable", "Statement", "For", "Loop"], + "ForOfStatement": ["Scopable", "Statement", "For", "Loop", "ForXStatement"], + "ForInStatement": ["Scopable", "Statement", "For", "Loop", "ForXStatement"], "ForStatement": ["Scopable", "Statement", "For", "Loop"], "ObjectPattern": ["Pattern"], diff --git a/test/core/fixtures/transformation/es6.constants/no-for-in/actual.js b/test/core/fixtures/transformation/es6.constants/no-for-in/actual.js new file mode 100644 index 0000000000..46c5fbbc10 --- /dev/null +++ b/test/core/fixtures/transformation/es6.constants/no-for-in/actual.js @@ -0,0 +1,3 @@ +const MULTIPLIER = 5; + +for (MULTIPLIER in arr); diff --git a/test/core/fixtures/transformation/es6.constants/no-for-in/options.json b/test/core/fixtures/transformation/es6.constants/no-for-in/options.json new file mode 100644 index 0000000000..3eed8a7760 --- /dev/null +++ b/test/core/fixtures/transformation/es6.constants/no-for-in/options.json @@ -0,0 +1,3 @@ +{ + "throws": "\"MULTIPLIER\" is read-only" +}