fixhunt

biome style/noUselessElse

labelled safe
Runs / 2026-10-17T19-42-12-619Z-e4vp-biome-style_noUselessElsebiome 2.5.152026-10-17 19:42 UTC8 programs × 2 round(s)16 programs, 14 fired, 14 fixed, 3 findings, 2 rejectedmodel cost $0.06

Analysis Nemotron 3 Super

Flags else blocks that follow an if block containing a breaking statement (return, break, continue, throw), as they are unreachable and redundant.

Fix: Removes the else block and places its statements directly after the if block, preserving their original order and indentation relative to the function or block scope.

10 hazards
  • Moving a break statement out of a switch case alters fall-through behavior, potentially executing unintended cases.
  • Relocating a continue statement may cause it to target an outer loop instead of the innermost one, changing iteration behavior.
  • Hoisting a function declaration from within the else block could make it available earlier than intended, causing premature invocation.
  • Moving a variable declaration with let/const from the else block risks referencing it before initialization if used prior to the if block.
  • Extracting a labeled statement from the else block may break label targeting if the label is referenced elsewhere via break/continue.
  • Relocating a throw statement could change the stack trace by altering the point of origin, affecting error handling logic.
  • Moving a return statement from within a try block may skip execution of a finally block that was meant to run regardless.
  • Duplicating a side-effecting expression (e.g., a function call) from the else block into multiple paths due to code duplication during refactoring is not applicable here, but the fix assumes single occurrence—however, if the else block contains multiple statements, their relative order is preserved but their execution context changes.
  • If the else block contains a debugger statement, moving it may alter developer tooling behavior if the surrounding scope has different blackboxing settings.
  • Comments attached to the else brace or internal to the else block may be lost or misplaced during the rewrite, degrading code readability.

Findings

programoraclelabeljudgestatussummary
r1-p007fix-changes-behaviorlabelled safereal · highduplicateThe fix hoists the function declaration out of the else block, changing it from a block-scoped declaration (ES2015+) that only exists when the else runs to a f…
r1-p008fix-changes-behaviorlabelled safereal · highduplicateThe fix hoists a function declaration out of an else block into a switch case clause, where function declarations are not allowed in strict mode and have imple…
r2-p001fix-breaks-syntaxlabelled safereal · highduplicateThe fix hoists the `let x = 2` declaration out of the `else` block into the same scope where `let x = 1` already exists, causing a duplicate declaration Syntax…

Programs

idresulttitlehazard
r1-p001fix okContinue targeting wrong loopRelocating a continue statement may cause it to target an outer loop instead of the innermost one, changing iteration behavior.
r1-p002fix okClass field timingclass fields, static blocks, private names, super calls
r1-p003fix okLabel and finally interactionlabel/break/continue control flow, finally blocks, early returns in nested blocks
r1-p004invalidLabeled statement extractionExtracting a labeled statement from the else block may break label targeting if the label is referenced elsewhere via break/continue.
r1-p005fix okComment displacementComments attached to the else brace or internal to the else block may be lost or misplaced during the rewrite, degrading code readability.
r1-p006fix okSide effect duplicationorder of evaluation when expressions are merged, duplicated or deleted (side effects run twice or never)
r1-p007fix-changes-behaviorPremature function hoistHoisting a function declaration from within the else block could make it available earlier than intended, causing premature invocation.
r1-p008fix-changes-behaviorBlock-scoped function in switchfunction declarations inside blocks, switch cases, labeled statements
r2-p001fix-breaks-syntaxShadowing after removal of else blockname collisions across scopes after a move (shadowing)
r2-p002fix okLabel targeting broken by else block extractionExtracting a labeled statement from the else block may break label targeting if the label is referenced elsewhere via break/continue.
r2-p003fix okFunction declaration hoisted from else blockHoisting a function declaration from within the else block could make it available earlier than intended, causing premature invocation.
r2-p004fix okComment displaced when else block removedcomments attached to the removed or moved code
r2-p005fix okDebugger statement moved alters tooling behaviorIf the else block contains a debugger statement, moving it may alter developer tooling behavior if the surrounding scope has different blackboxing settings.
r2-p006fix okFunction declaration in else block of switch casefunction declarations inside blocks, switch cases, labeled statements
r2-p007fix okOrder preservation but context change in else blockDuplicating a side-effecting expression [...] their relative order is preserved but their execution context changes.
r2-p008invalidNullish vs falsy in else block after movenull/undefined distinction, optional chaining short-circuit, nullish vs falsy

Sources

r1-p001 · Continue targeting wrong loop
1function main() {
2 let out = '';
3 L1: for (let i = 0; i < 2; i++) {
4 for (let j = 0; j < 2; j++) {
5 if (j === 0) { continue L1; }
6 else { out += i + ',' + j + '|'; }
7 }
8 }
9 console.log(out);
10}
11main();
--- orig.js	2026-10-17 15:42:21.261561278 -0400
+++ fixed.js	2026-10-17 15:42:21.532555670 -0400
@@ -3,7 +3,7 @@
   L1: for (let i = 0; i < 2; i++) {
     for (let j = 0; j < 2; j++) {
       if (j === 0) { continue L1; }
-      else { out += i + ',' + j + '|'; }
+      out += i + ',' + j + '|'; 
     }
   }
   console.log(out);
r1-p002 · Class field timing
1class C {
2 static x = 1;
3 #p;
4 constructor() {
5 this.#p = 0;
6 if (false) { return; }
7 else { this.#p = 2; }
8 }
9 get p() { return this.#p; }
10}
11const c = new C();
12console.log(c.p);
--- orig.js	2026-10-17 15:42:21.701552173 -0400
+++ fixed.js	2026-10-17 15:42:21.967546668 -0400
@@ -4,7 +4,7 @@
   constructor() {
     this.#p = 0;
     if (false) { return; }
-    else { this.#p = 2; }
+    this.#p = 2; 
   }
   get p() { return this.#p; }
 }
2
r1-p003 · Label and finally interaction
1function main() {
2 let out = '';
3 L: for (let i = 0; i < 2; i++) {
4 try {
5 if (i === 0) { break L; }
6 else { out += i; }
7 } finally { out += 'f'; }
8 }
9 console.log(out);
10}
11main();
--- orig.js	2026-10-17 15:42:22.127543355 -0400
+++ fixed.js	2026-10-17 15:42:22.396537782 -0400
@@ -3,7 +3,7 @@
   L: for (let i = 0; i < 2; i++) {
     try {
       if (i === 0) { break L; }
-      else { out += i; }
+      out += i; 
     } finally { out += 'f'; }
   }
   console.log(out);
f
r1-p004 · Labeled statement extraction (generated program does not parse: /home/sun/dev/diaghunt/runs/2026-10-17T19-42-1)
1function main() {
2 let out = '';
3 L: for (let i = 0; i < 2; i++) {
4 if (i === 0) { continue; }
5 else { L: out += i; break L; }
6 }
7 console.log(out);
8}
9main();
r1-p005 · Comment displacement
1function main() {
2 let x = 0;
3 if (false) { return; }
4 /* keep-me */
5 else { x = 1; /* inner */ }
6 console.log(x);
7}
8main();
--- orig.js	2026-10-17 15:42:22.618533183 -0400
+++ fixed.js	2026-10-17 15:42:22.899527362 -0400
@@ -2,7 +2,7 @@
   let x = 0;
   if (false) { return; }
   /* keep-me */
-  else { x = 1; /* inner */ }
+  x = 1; /* inner */ 
   console.log(x);
 }
 main();
1
r1-p006 · Side effect duplication
1function main() {
2 let a = 0, b = 0;
3 if (false) { return; }
4 else { a++; b += a; }
5 console.log(a, b);
6}
7main();
--- orig.js	2026-10-17 15:42:23.061524004 -0400
+++ fixed.js	2026-10-17 15:42:23.339518239 -0400
@@ -1,7 +1,7 @@
 function main() {
   let a = 0, b = 0;
   if (false) { return; }
-  else { a++; b += a; }
+  a++; b += a; 
   console.log(a, b);
 }
 main();
1 1
r1-p007 · Premature function hoist
1function main() {
2 if (false) { return; }
3 else { function f() { return 1; } }
4 try { console.log(f()); } catch (e) { console.log(e.name); }
5}
6main();
--- orig.js	2026-10-17 15:42:23.507514755 -0400
+++ fixed.js	2026-10-17 15:42:23.777509156 -0400
@@ -1,6 +1,6 @@
 function main() {
   if (false) { return; }
-  else { function f() { return 1; } }
+  function f() { return 1; } 
   try { console.log(f()); } catch (e) { console.log(e.name); }
 }
 main();
ReferenceError
r1-p008 · Block-scoped function in switch
1function main() {
2 switch (0) {
3 case 0:
4 if (false) { return; }
5 else { function g() { return 2; } }
6 console.log(typeof g);
7 break;
8 }
9}
10main();
--- orig.js	2026-10-17 15:42:23.938505817 -0400
+++ fixed.js	2026-10-17 15:42:24.206500254 -0400
@@ -2,7 +2,7 @@
   switch (0) {
     case 0:
       if (false) { return; }
-      else { function g() { return 2; } }
+      function g() { return 2; } 
       console.log(typeof g);
       break;
   }
undefined
r2-p001 · Shadowing after removal of else block
1function f() {
2 let x = 1;
3 if (true) { return x; }
4 else {
5 let x = 2;
6 console.log(x);
7 }
8}
9f();
--- orig.js	2026-10-17 15:42:28.435412284 -0400
+++ fixed.js	2026-10-17 15:42:28.696406842 -0400
@@ -1,9 +1,8 @@
 function f() {
   let x = 1;
   if (true) { return x; }
-  else {
+  
     let x = 2;
     console.log(x);
-  }
 }
 f();
r2-p002 · Label targeting broken by else block extraction
1outer: for (let i = 0; i < 2; i++) {
2 if (i === 0) { continue outer; }
3 else {
4 console.log('reached');
5 break outer;
6 }
7}
--- orig.js	2026-10-17 15:42:28.746405799 -0400
+++ fixed.js	2026-10-17 15:42:29.010400295 -0400
@@ -1,7 +1,6 @@
 outer: for (let i = 0; i < 2; i++) {
   if (i === 0) { continue outer; }
-  else {
+  
     console.log('reached');
     break outer;
-  }
 }
reached
r2-p003 · Function declaration hoisted from else block
1function f() {
2 if (false) {
3 return g();
4 } else {
5 function g() { return 'early'; }
6 return g();
7 }
8}
9console.log(f());
--- orig.js	2026-10-17 15:42:29.177396809 -0400
+++ fixed.js	2026-10-17 15:42:29.432391487 -0400
@@ -1,9 +1,8 @@
 function f() {
   if (false) {
     return g();
-  } else {
+  }
     function g() { return 'early'; }
     return g();
-  }
 }
 console.log(f());
early
r2-p004 · Comment displaced when else block removed
1function f() {
2 if (true) { return 1; }
3 // This comment should stay
4 else {
5 // This comment may be lost
6 console.log(2);
7 }
8}
9f();
--- orig.js	2026-10-17 15:42:29.599388001 -0400
+++ fixed.js	2026-10-17 15:42:29.839382992 -0400
@@ -1,9 +1,8 @@
 function f() {
   if (true) { return 1; }
   // This comment should stay
-  else {
+  
     // This comment may be lost
     console.log(2);
-  }
 }
 f();
r2-p005 · Debugger statement moved alters tooling behavior
1function f() {
2 if (true) { return; }
3 else {
4 debugger;
5 console.log('unreachable');
6 }
7}
8f();
--- orig.js	2026-10-17 15:42:29.990379840 -0400
+++ fixed.js	2026-10-17 15:42:30.237374680 -0400
@@ -1,8 +1,7 @@
 function f() {
   if (true) { return; }
-  else {
+  
     debugger;
     console.log('unreachable');
-  }
 }
 f();
r2-p006 · Function declaration in else block of switch case
1function f() {
2 switch (0) {
3 case 0:
4 if (true) { break; }
5 else {
6 function g() { return 1; }
7 return g();
8 }
9 }
10}
11console.log(f());
--- orig.js	2026-10-17 15:42:30.382371650 -0400
+++ fixed.js	2026-10-17 15:42:30.664365758 -0400
@@ -2,10 +2,9 @@
   switch (0) {
     case 0:
       if (true) { break; }
-      else {
+      
         function g() { return 1; }
         return g();
-      }
   }
 }
 console.log(f());
undefined
r2-p007 · Order preservation but context change in else block
1let log = [];
2function f() {
3 if (true) { return; }
4 else {
5 log.push(1);
6 log.push(2);
7 }
8}
9f();
10console.log(log);
--- orig.js	2026-10-17 15:42:30.830362290 -0400
+++ fixed.js	2026-10-17 15:42:31.095356751 -0400
@@ -1,10 +1,9 @@
 let log = [];
 function f() {
   if (true) { return; }
-  else {
+  
     log.push(1);
     log.push(2);
-  }
 }
 f();
 console.log(log);
[]
r2-p008 · Nullish vs falsy in else block after move (generated program does not parse: /home/sun/dev/diaghunt/runs/2026-10-17T19-42-1)
1let obj = { foo: undefined };
2if (obj?.foo ?? false) {
3 return;
4} else {
5 console.log(obj?.foo ?? 'default');
6}