Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Update: Support generator yields in no constant condition (#8762)
* Update: support generators in no constant condition (Fixes #8566)

* handle yield in init of forloops

* Revert "Update: support generators in no constant condition (Fixes #8566)"

This reverts commit 7bcd3cc.

* fix errors

* remove parser options since included in ruletester

* handle more init checks in forloop

* update test cases

* remove unused fxn
  • Loading branch information
VictorHom authored and btmills committed Jul 21, 2017
1 parent 96df8c9 commit 3bebcfd
Show file tree
Hide file tree
Showing 2 changed files with 118 additions and 10 deletions.
68 changes: 62 additions & 6 deletions lib/rules/no-constant-condition.js
Expand Up @@ -33,7 +33,10 @@ module.exports = {

create(context) {
const options = context.options[0] || {},
checkLoops = options.checkLoops !== false;
checkLoops = options.checkLoops !== false,
loopSetStack = [];

let loopsInCurrentScope = new Set();

//--------------------------------------------------------------------------
// Helpers
Expand Down Expand Up @@ -114,18 +117,64 @@ module.exports = {
return false;
}

/**
* Tracks when the given node contains a constant condition.
* @param {ASTNode} node The AST node to check.
* @returns {void}
* @private
*/
function trackConstantConditionLoop(node) {
if (node.test && isConstant(node.test, true)) {
loopsInCurrentScope.add(node);
}
}

/**
* Reports when the set contains the given constant condition node
* @param {ASTNode} node The AST node to check.
* @returns {void}
* @private
*/
function checkConstantConditionLoopInSet(node) {
if (loopsInCurrentScope.has(node)) {
loopsInCurrentScope.delete(node);
context.report({ node, message: "Unexpected constant condition." });
}
}

/**
* Reports when the given node contains a constant condition.
* @param {ASTNode} node The AST node to check.
* @returns {void}
* @private
*/
function checkConstantCondition(node) {
function reportIfConstant(node) {
if (node.test && isConstant(node.test, true)) {
context.report({ node, message: "Unexpected constant condition." });
}
}

/**
* Stores current set of constant loops in loopSetStack temporarily
* and uses a new set to track constant loops
* @returns {void}
* @private
*/
function enterFunction() {
loopSetStack.push(loopsInCurrentScope);
loopsInCurrentScope = new Set();
}

/**
* Reports when the set still contains stored constant conditions
* @param {ASTNode} node The AST node to check.
* @returns {void}
* @private
*/
function exitFunction() {
loopsInCurrentScope = loopSetStack.pop();
}

/**
* Checks node when checkLoops option is enabled
* @param {ASTNode} node The AST node to check.
Expand All @@ -134,7 +183,7 @@ module.exports = {
*/
function checkLoop(node) {
if (checkLoops) {
checkConstantCondition(node);
trackConstantConditionLoop(node);
}
}

Expand All @@ -143,11 +192,18 @@ module.exports = {
//--------------------------------------------------------------------------

return {
ConditionalExpression: checkConstantCondition,
IfStatement: checkConstantCondition,
ConditionalExpression: reportIfConstant,
IfStatement: reportIfConstant,
WhileStatement: checkLoop,
"WhileStatement:exit": checkConstantConditionLoopInSet,
DoWhileStatement: checkLoop,
ForStatement: checkLoop
"DoWhileStatement:exit": checkConstantConditionLoopInSet,
ForStatement: checkLoop,
"ForStatement > .test": node => checkLoop(node.parent),
"ForStatement:exit": checkConstantConditionLoopInSet,
FunctionDeclaration: enterFunction,
"FunctionDeclaration:exit": exitFunction,
YieldExpression: () => loopsInCurrentScope.clear()
};

}
Expand Down
60 changes: 56 additions & 4 deletions tests/lib/rules/no-constant-condition.js
Expand Up @@ -16,7 +16,7 @@ const rule = require("../../../lib/rules/no-constant-condition"),
// Tests
//------------------------------------------------------------------------------

const ruleTester = new RuleTester();
const ruleTester = new RuleTester({ parserOptions: { ecmaVersion: 6 } });

ruleTester.run("no-constant-condition", rule, {
valid: [
Expand Down Expand Up @@ -58,7 +58,17 @@ ruleTester.run("no-constant-condition", rule, {
// { checkLoops: false }
{ code: "while(true);", options: [{ checkLoops: false }] },
{ code: "for(;true;);", options: [{ checkLoops: false }] },
{ code: "do{}while(true)", options: [{ checkLoops: false }] }
{ code: "do{}while(true)", options: [{ checkLoops: false }] },

{ code: "function* foo(){while(true){yield 'foo';}}" },
{ code: "function* foo(){for(;true;){yield 'foo';}}" },
{ code: "function* foo(){do{yield 'foo';}while(true)}" },
{ code: "function* foo(){while (true) { while(true) {yield;}}}" },
{ code: "function* foo() {for (; yield; ) {}}" },
{ code: "function* foo() {for (; ; yield) {}}" },
{ code: "function* foo() {while (true) {function* foo() {yield;}yield;}}" },
{ code: "function* foo() { for (let x = yield; x < 10; x++) {yield;}yield;}" },
{ code: "function* foo() { for (let x = yield; ; x++) { yield; }}" }
],
invalid: [
{ code: "for(;true;);", errors: [{ message: "Unexpected constant condition.", type: "ForStatement" }] },
Expand All @@ -78,7 +88,8 @@ ruleTester.run("no-constant-condition", rule, {
{ code: "while(~!0);", errors: [{ message: "Unexpected constant condition.", type: "WhileStatement" }] },
{ code: "while(x = 1);", errors: [{ message: "Unexpected constant condition.", type: "WhileStatement" }] },
{ code: "while(function(){});", errors: [{ message: "Unexpected constant condition.", type: "WhileStatement" }] },
{ code: "while(() => {});", parserOptions: { ecmaVersion: 6 }, errors: [{ message: "Unexpected constant condition.", type: "WhileStatement" }] },
{ code: "while(true);", errors: [{ message: "Unexpected constant condition.", type: "WhileStatement" }] },
{ code: "while(() => {});", errors: [{ message: "Unexpected constant condition.", type: "WhileStatement" }] },

// #5228 , typeof conditions
{ code: "if(typeof x){}", errors: [{ message: "Unexpected constant condition.", type: "IfStatement" }] },
Expand All @@ -103,6 +114,47 @@ ruleTester.run("no-constant-condition", rule, {
{ code: "if(abc==='str' || true){}", errors: [{ message: "Unexpected constant condition.", type: "IfStatement" }] },
{ code: "if(abc==='str' || true || def ==='str'){}", errors: [{ message: "Unexpected constant condition.", type: "IfStatement" }] },
{ code: "if(false || true){}", errors: [{ message: "Unexpected constant condition.", type: "IfStatement" }] },
{ code: "if(typeof abc==='str' || true){}", errors: [{ message: "Unexpected constant condition.", type: "IfStatement" }] }
{ code: "if(typeof abc==='str' || true){}", errors: [{ message: "Unexpected constant condition.", type: "IfStatement" }] },

{
code: "function* foo(){while(true){} yield 'foo';}",
errors: [{ message: "Unexpected constant condition.", type: "WhileStatement" }]
},
{
code: "function* foo(){while(true){if (true) {yield 'foo';}}}",
errors: [{ message: "Unexpected constant condition.", type: "IfStatement" }]
},
{
code: "function* foo(){while(true){yield 'foo';} while(true) {}}",
errors: [{ message: "Unexpected constant condition.", type: "WhileStatement" }]
},
{
code: "var a = function* foo(){while(true){} yield 'foo';}",
errors: [{ message: "Unexpected constant condition.", type: "WhileStatement" }]
},
{
code: "while (true) { function* foo() {yield;}}",
errors: [{ message: "Unexpected constant condition.", type: "WhileStatement" }]
},
{
code: "function* foo(){if (true) {yield 'foo';}}",
errors: [{ message: "Unexpected constant condition.", type: "IfStatement" }]
},
{
code: "function* foo() {for (let foo = yield; true;) {}}",
errors: [{ message: "Unexpected constant condition.", type: "ForStatement" }]
},
{
code: "function* foo() {for (foo = yield; true;) {}}",
errors: [{ message: "Unexpected constant condition.", type: "ForStatement" }]
},
{
code: "function foo() {while (true) {function* bar() {while (true) {yield;}}}}",
errors: [{ message: "Unexpected constant condition.", type: "WhileStatement" }]
},
{
code: "function* foo() { for (let foo = 1 + 2 + 3 + (yield); true; baz) {}}",
errors: [{ message: "Unexpected constant condition.", type: "ForStatement" }]
}
]
});

0 comments on commit 3bebcfd

Please sign in to comment.