Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Avoid naming collision with default array element variable in autofix for no-for-loop rule #749

Merged
merged 6 commits into from May 27, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
9 changes: 8 additions & 1 deletion rules/no-for-loop.js
Expand Up @@ -2,6 +2,7 @@
const getDocumentationUrl = require('./utils/get-documentation-url');
const isLiteralValue = require('./utils/is-literal-value');
const {flatten} = require('lodash');
const avoidCapture = require('./utils/avoid-capture');

const defaultElementName = 'element';
const isLiteralZero = node => isLiteralValue(node, 0);
Expand Down Expand Up @@ -261,6 +262,11 @@ const getReferencesInChildScopes = (scope, name) => {
];
};

const getChildScopesRecursive = scope => [
scope,
...flatten(scope.childScopes.map(scope => getChildScopesRecursive(scope)))
];

const create = context => {
const sourceCode = context.getSourceCode();
const {scopeManager} = sourceCode;
Expand Down Expand Up @@ -335,7 +341,8 @@ const create = context => {
const shouldGenerateIndex = isIndexVariableUsedElsewhereInTheLoopBody(indexVariable, bodyScope, arrayIdentifierName);

const index = indexIdentifierName;
const element = elementIdentifierName || defaultElementName;
const element = elementIdentifierName ||
avoidCapture(defaultElementName, getChildScopesRecursive(bodyScope), context.parserOptions.ecmaVersion);
const array = arrayIdentifierName;

let declarationElement = element;
Expand Down
167 changes: 167 additions & 0 deletions test/no-for-loop.js
Expand Up @@ -482,6 +482,173 @@ ruleTester.run('no-for-loop', rule, {
const [ a, b ] = element;
console.log(a, b, element);
}
`),

// Avoid naming collision when using default element name.
testCase(outdent`
for (let i = 0; i < arr.length; i += 1) {
console.log(arr[i]);
const element = foo();
console.log(element);
}
`, outdent`
for (const element_ of arr) {
console.log(element_);
const element = foo();
console.log(element);
}
`),

// Avoid naming collision when using default element name (different scope).
testCase(outdent`
function element(element_) {
for (let i = 0; i < arr.length; i += 1) {
console.log(arr[i], element);
}
}
`, outdent`
function element(element_) {
for (const element__ of arr) {
console.log(element__, element);
}
}
`),
testCase(outdent`
let element;
function foo() {
for (let i = 0; i < arr.length; i += 1) {
console.log(arr[i]);
}
}
`, outdent`
let element;
function foo() {
for (const element_ of arr) {
console.log(element_);
}
}
`),
testCase(outdent`
for (let i = 0; i < arr.length; i += 1) {
function element__(element) {
console.log(arr[i], element);
}
}
`, outdent`
for (const element_ of arr) {
function element__(element) {
console.log(element_, element);
}
}
`),
bmish marked this conversation as resolved.
Show resolved Hide resolved
testCase(outdent`
for (let i = 0; i < arr.length; i += 1) {
function element_(element) {
console.log(arr[i], element);
}
}
`, outdent`
for (const element__ of arr) {
function element_(element) {
console.log(element__, element);
}
}
`),
testCase(outdent`
for (let i = 0; i < arr.length; i += 1) {
function element() {
console.log(arr[i], element);
}
}
`, outdent`
for (const element_ of arr) {
function element() {
console.log(element_, element);
}
}
`),
testCase(outdent`
for (let i = 0; i < arr.length; i += 1) {
console.log(arr[i], element);
}
`, outdent`
for (const element_ of arr) {
console.log(element_, element);
}
`),
testCase(outdent`
for (let i = 0; i < element.length; i += 1) {
console.log(element[i]);
}
`, outdent`
for (const element_ of element) {
console.log(element_);
}
`),
testCase(outdent`
for (let i = 0; i < arr.length; i += 1) {
console.log(arr[i]);
function foo(element) {
console.log(element);
}
}
`, outdent`
for (const element_ of arr) {
console.log(element_);
function foo(element) {
console.log(element);
}
}
`),
testCase(outdent`
for (let element = 0; element < arr.length; element += 1) {
console.log(element, arr[element]);
}
`, outdent`
for (const [element, element_] of arr.entries()) {
console.log(element, element_);
}
`),
testCase(outdent`
for (let element = 0; element < arr.length; element += 1) {
console.log(arr[element]);
}
`, outdent`
for (const element_ of arr) {
console.log(element_);
}
`),
testCase(outdent`
for (const element of arr) {
for (let j = 0; j < arr2.length; j += 1) {
console.log(element, arr2[j]);
}
}
`, outdent`
for (const element of arr) {
for (const element_ of arr2) {
console.log(element, element_);
}
}
`),

// Avoid naming collision when using default element name (multiple collisions).
testCase(outdent`
for (let i = 0; i < arr.length; i += 1) {
const element = foo();
console.log(arr[i]);
const element_ = foo();
console.log(element);
console.log(element_);
}
`, outdent`
for (const element__ of arr) {
const element = foo();
console.log(element__);
const element_ = foo();
console.log(element);
console.log(element_);
}
`)
]
});
Expand Down