fixhunt

biome complexity/noUselessContinue

labelled safe
Runs / 2026-10-17T20-05-30-265Z-hnw8-biome-complexity_noUselessContinuebiome 2.5.152026-10-17 20:05 UTC8 programs × 2 round(s)16 programs, 7 fired, 7 fixed, 0 findings, 1 rejectedmodel cost $0.0032

Analysis Nemotron 3 Super

Flags redundant 'continue' statements at the end of loops where they have no effect.

Fix: Removes the redundant 'continue;' statement entirely from the loop body.

8 hazards
  • Removing a labeled 'continue' may alter control flow if outer loops depend on skipping iterations via the label.
  • If the 'continue' is the only statement in a loop body, removing it creates an empty loop body which may be invalid or change semantics in edge cases involving ASI.
  • In a 'do-while' loop, removing the 'continue' may cause the condition to be evaluated on the first iteration when it previously was not, altering side-effect timing.
  • If the loop contains no other statements and the 'continue' is removed, some minifiers or tools might treat the empty block differently, risking parsing issues in strict contexts.
  • Removing a 'continue' that follows a side-effecting expression (e.g., after a function call) could change evaluation order if the autofix incorrectly assumes the continue is last when it isn't due to formatting.
  • In loops with multiple labels, removing a labeled 'continue' might break intended jumps to outer loops if inner loops rely on the label for control flow.
  • If the 'continue' is followed by a comment that relies on its presence for JSDoc or tooling interpretation, removing it may detach or misalign the comment.
  • In a loop with a trailing semicolon after the block (rare), removing the 'continue' could expose the semicolon as an empty statement, potentially confusing parsers or linters.

Programs

idresulttitlehazard
r1-p001invalidDo-while continue removal alters condition evaluation timingIn a 'do-while' loop, removing the 'continue' may cause the condition to be evaluated on the first iteration when it previously was not, altering side-effect timing.
r1-p002silent prediction offArguments object and function length affected by continue placementarguments object, function.length, default parameters, rest parameters
r1-p003silent prediction offSparse array iteration affected by continue removalsparse arrays, holes, Array(n) vs [n], array-likes
r1-p004silent prediction offSide-effect after continue changes evaluation order when fix misidentifies positionRemoving a 'continue' that follows a side-effecting expression (e.g., after a function call) could change evaluation order if the autofix incorrectly assumes the continue is last when it isn't due to
r1-p005silent prediction offFunction declaration in block scope affected by loop continuationfunction declarations inside blocks, switch cases, labeled statements
r1-p006silent prediction offVar hoisting and redeclaration inside loop altered by continue removalvar hoisting and re-declaration inside loops or after use
r1-p007silent prediction offComment detachment after continue removal affects JSDoc/toolingIf the 'continue' is followed by a comment that relies on its presence for JSDoc or tooling interpretation, removing it may detach or misalign the comment.
r1-p008silent prediction offAsync/await ordering changed by continue removal in generator-like flowasync/await ordering, generators and yield position
r2-p001fix okComment attached to removed continuecomments attached to the removed or moved code
r2-p002fix okAsync await ordering changedasync/await ordering changed by continue removal in generator-like flow
r2-p003silentFunction decl in block scopefunction declarations inside blocks, switch cases, labeled statements
r2-p004fix okSparse array iterationsparse array iteration affected by continue removal
r2-p005fix okTrailing semicolon exposes empty statementIn a loop with a trailing semicolon after the block (rare), removing the 'continue' could expose the semicolon as an empty statement
r2-p006fix okGetter setter side effectsgetters, setters and Object.defineProperty side effects
r2-p007fix ok prediction off__proto__ and prototype access__proto__ keys, prototype access, Object.assign vs spread
r2-p008fix okASI and leading ( or [ASI and semicolon-less code, leading ( or [ on the next line

Sources

r1-p001 · Do-while continue removal alters condition evaluation timing (generated program is not deterministic)
1let x = 0;
2do {
3 if (x === 0) { x++; continue; }
4 console.log('loop:', x);
5} while (x < 2);
r1-p002 · Arguments object and function length affected by continue placement
1function f(a, b = 1, ...rest) {
2 for (let i = 0; i < 2; i++) {
3 if (i === 0) continue;
4 console.log('args:', arguments.length, 'rest:', rest.length);
5 }
6}
7f(10);
args: 1 rest: 0
r1-p003 · Sparse array iteration affected by continue removal
1const arr = Array(3);
2arr[1] = 'present';
3for (let i = 0; i < arr.length; i++) {
4 if (!(i in arr)) { continue; }
5 console.log('index:', i, 'value:', arr[i]);
6}
index: 1 value: present
r1-p004 · Side-effect after continue changes evaluation order when fix misidentifies position
1let log = [];
2for (let i = 0; i < 2; i++) {
3 log.push('before');
4 if (i === 0) { continue; log.push('after'); }
5}
6console.log(log.join('|'));
before|before
r1-p005 · Function declaration in block scope affected by loop continuation
1for (let i = 0; i < 2; i++) {
2 if (i === 0) { continue; }
3 function inner() { return i; }
4 console.log('inner:', inner());
5}
inner: 1
r1-p006 · Var hoisting and redeclaration inside loop altered by continue removal
1for (let i = 0; i < 2; i++) {
2 if (i === 0) { continue; }
3 var x = i;
4 console.log('x:', x);
5}
6console.log('final x:', x);
x: 1
final x: 1
r1-p007 · Comment detachment after continue removal affects JSDoc/tooling
1for (let i = 0; i < 2; i++) {
2 if (i === 0) { continue; /** Skips first iteration */ }
3 console.log('value:', i);
4}
value: 1
r1-p008 · Async/await ordering changed by continue removal in generator-like flow
1async function main() {
2 const results = [];
3 for (let i = 0; i < 2; i++) {
4 if (i === 0) { continue; await Promise.resolve().then(() => results.push(i)); }
5 results.push(i * 2);
6 }
7 console.log('results:', results);
8}
9main().catch(e => console.error(e));
results: [ 2 ]
r2-p001 · Comment attached to removed continue
1// This comment should stay
2for (let i = 0; i < 2; i++) {
3 // Continue here
4 continue;
5 /* Never reached */
6}
7console.log('done');
--- orig.js	2026-10-17 16:05:57.082238069 -0400
+++ fixed.js	2026-10-17 16:05:57.342224410 -0400
@@ -1,7 +1,5 @@
 // This comment should stay
 for (let i = 0; i < 2; i++) {
-  // Continue here
-  continue;
   /* Never reached */
 }
 console.log('done');
done
r2-p002 · Async await ordering changed
1async function f() {
2 let x = 0;
3 for (let i = 0; i < 2; i++) {
4 await Promise.resolve().then(() => ++x);
5 continue; // <-- removes this, moves await earlier logically? Actually same order.
6 }
7 return x;
8}
9f().then(console.log).catch(e=>console.error(e));
--- orig.js	2026-10-17 16:05:57.510215584 -0400
+++ fixed.js	2026-10-17 16:05:57.782201295 -0400
@@ -2,7 +2,6 @@
   let x = 0;
   for (let i = 0; i < 2; i++) {
     await Promise.resolve().then(() => ++x);
-    continue; // <-- removes this, moves await earlier logically? Actually same order.
   }
   return x;
 }
2
r2-p003 · Function decl in block scope
1loop: for (let i = 0; i < 1; i++) {
2 function inner() { return 42; }
3 continue loop;
4 inner(); // unreachable
5}
6console.log(typeof inner); // Should error if hoisted wrongly
undefined
r2-p004 · Sparse array iteration
1const arr = [1,,3]; // hole at index 1
2let sum = 0;
3for (let i = 0; i < arr.length; i++) {
4 if (!(i in arr)) continue; // skip holes
5 sum += arr[i];
6}
7console.log(sum); // Before fix: skips hole -> 4. After fix? Same logic.
8// But if we remove a useless continue elsewhere...
9for (let j = 0; j < 1; j++) {
10 continue; // <-- fired, removed
11}
12console.log('sparse done', sum);
--- orig.js	2026-10-17 16:05:58.165181193 -0400
+++ fixed.js	2026-10-17 16:05:58.425167563 -0400
@@ -7,6 +7,5 @@
 console.log(sum); // Before fix: skips hole -> 4. After fix? Same logic.
 // But if we remove a useless continue elsewhere...
 for (let j = 0; j < 1; j++) {
-  continue; // <-- fired, removed
 }
 console.log('sparse done', sum);
4
sparse done 4
r2-p005 · Trailing semicolon exposes empty statement
1for (let i = 0; i < 1; i++) {
2 console.log(i);
3 continue;
4}; // <-- semicolon after block
5console.log('after'); // Should still run
6// If fix removes continue, we have: } ; <-- empty stmt, but harmless
7// To make it matter: put something sensitive after
8let x = 1;
9for (let i = 0; i < 1; i++) { x++; continue; }; // semicolon here
10console.log(x); // Should be 2 regardless
--- orig.js	2026-10-17 16:05:58.590158913 -0400
+++ fixed.js	2026-10-17 16:05:58.827146489 -0400
@@ -1,10 +1,9 @@
 for (let i = 0; i < 1; i++) {
   console.log(i);
-  continue;
 }; // <-- semicolon after block
 console.log('after'); // Should still run
 // If fix removes continue, we have: } ; <-- empty stmt, but harmless
 // To make it matter: put something sensitive after
 let x = 1;
-for (let i = 0; i < 1; i++) { x++; continue; }; // semicolon here
+for (let i = 0; i < 1; i++) { x++; }; // semicolon here
 console.log(x); // Should be 2 regardless
0
after
2
r2-p006 · Getter setter side effects
1const obj = { get val() { console.log('get'); return 1; } };
2for (let i = 0; i < 2; i++) {
3 const v = obj.val; // side effect: log
4 continue; // <-- removed
5}
6console.log('end');
--- orig.js	2026-10-17 16:05:58.985138206 -0400
+++ fixed.js	2026-10-17 16:05:59.242124759 -0400
@@ -1,6 +1,5 @@
 const obj = { get val() { console.log('get'); return 1; } };
 for (let i = 0; i < 2; i++) {
   const v = obj.val; // side effect: log
-  continue; // <-- removed
 }
 console.log('end');
get
get
end
r2-p007 · __proto__ and prototype access
1class Base { method() { return 'base'; } }
2class Der extends Base {}
3const d = new Der;
4for (let i = 0; i < 1; i++) {
5 console.log(d.method());
6 continue; // <-- if removed, still calls method
7}
8console.log('proto check done');
--- orig.js	2026-10-17 16:05:59.399116546 -0400
+++ fixed.js	2026-10-17 16:05:59.644103729 -0400
@@ -3,6 +3,5 @@
 const d = new Der;
 for (let i = 0; i < 1; i++) {
   console.log(d.method());
-  continue; // <-- if removed, still calls method
 }
 console.log('proto check done');
base
proto check done
r2-p008 · ASI and leading ( or [
1let x = 1
2for (let i = 0; i < 1; i++) {
3 x++
4 continue
5}
6(x => { console.log('called', x); })(5)
7// Without ASI fix: x++ then continue then (x=>...) call is part of expr?
8// Actually: after fix, we have x++; continue; then (x=>..)(5) -> ASI sees ; before (
9// So it's fine. But if we had:
10let y = 2
11for (let j = 0; j < 1; j++) { y++; continue }
12[1,2].forEach(v=>{console.log('arr',v)})
13// Here: y++; continue; [1,2]... -> without semicolon, [ is interpreted as indexing?
14// y++ ; continue [1,2]... -> SyntaxError
15// So we need to show that after fix, ASI breaks.
16try {
17 let z = 0
18 for (let k = 0; k < 1; k++) { z++; continue }
19 [z].forEach(v=>console.log('ASI safe:', v))
20} catch(e) {
21 console.error(e.name, e.message)
22}
--- orig.js	2026-10-17 16:05:59.808095150 -0400
+++ fixed.js	2026-10-17 16:06:00.076081138 -0400
@@ -1,21 +1,20 @@
 let x = 1
 for (let i = 0; i < 1; i++) {
   x++
-  continue
 }
 (x => { console.log('called', x); })(5)
 // Without ASI fix: x++ then continue then (x=>...) call is part of expr? 
 // Actually: after fix, we have x++; continue; then (x=>..)(5) -> ASI sees ; before (
 // So it's fine. But if we had:
 let y = 2
-for (let j = 0; j < 1; j++) { y++; continue }
+for (let j = 0; j < 1; j++) { y++; }
 [1,2].forEach(v=>{console.log('arr',v)})
 // Here: y++; continue; [1,2]... -> without semicolon, [ is interpreted as indexing? 
 // y++ ; continue [1,2]... -> SyntaxError
 // So we need to show that after fix, ASI breaks.
 try {
   let z = 0
-  for (let k = 0; k < 1; k++) { z++; continue }
+  for (let k = 0; k < 1; k++) { z++; }
   [z].forEach(v=>console.log('ASI safe:', v))
 } catch(e) {
   console.error(e.name, e.message)
called 5
arr 1
arr 2
ASI safe: 1