biome style/noUselessElse
labelled safe
Analysis Nemotron 3 Super
Flags 'else' blocks that follow an 'if' containing a breaking statement (return, break, continue, throw), marking them as redundant.
Fix: Removes the 'else' keyword and braces, promoting the else block's statements to the same indentation level as the if statement, preserving their original order.
12 hazards
- Moving statements from an else block to the outer scope changes their execution context—they may now run even when the if condition is true but non-breaking (e.g., due to missing break/return).
- If the else block contains a variable declaration with 'let' or 'const', hoisting it outward may cause a ReferenceError if used before declaration in the new scope.
- Promoting statements from an else block can alter evaluation order relative to prior or subsequent statements in the enclosing block, affecting side effects.
- If the else block contains a labeled statement that is referenced by a break/continue from outside the original else, moving it may break the label's visibility or create incorrect control flow.
- When the if-else is inside a loop, promoting the else block's content may cause it to execute on iterations where the if condition is true but doesn't break (e.g., continues), altering loop behavior.
- If the else block contains a function declaration, moving it may change its hoisting timing relative to other declarations in the outer scope, leading to override issues.
- Comments attached to the 'else' keyword or its braces may be lost during the rewrite, as the autofix typically discards irrelevant tokens.
- If the else block is empty or contains only whitespace/comments, removing it may inadvertently delete meaningful formatting or trailing comments relied upon for readability or tooling.
- In strict mode, promoting a 'with' statement (if present) from an else block could alter scope resolution unexpectedly.
- If the else block follows an 'if' inside a with statement, moving its content out may change the object scope in which those statements execute.
- When the if statement is part of a larger ternary-like chain via else-if, flattening may break the intended mutual exclusivity of branches.
- If the else block contains a debugger statement, its removal or relocation may affect debugging behavior depending on tool expectations.
Programs
| id | result | title | hazard |
|---|---|---|---|
| r1-p001 | silent prediction off | Evaluation Order Shift | Promoting statements from an else block can alter evaluation order relative to prior or subsequent statements in the enclosing block, affecting side effects. |
| r1-p002 | fix ok | Label Visibility Break | If the else block contains a labeled statement that is referenced by a break/continue from outside the original else, moving it may break the label's visibility or create incorrect control flow. |
| r1-p003 | silent prediction off | TDZ After Hoisting | If the else block contains a variable declaration with 'let' or 'const', hoisting it outward may cause a ReferenceError if used before declaration in the new scope. |
| r1-p004 | silent prediction off | Getter Side Effect | getters, setters and Object.defineProperty side effects |
| r1-p005 | silent prediction off | Let Const Hoisting TDZ | If the else block contains a variable declaration with 'let' or 'const', hoisting it outward may cause a ReferenceError if used before declaration in the new scope. |
| r1-p006 | silent prediction off | Function Declaration in Else | function declarations inside blocks, switch cases, labeled statements |
| r1-p007 | silent prediction off | Empty Else Formatting | If the else block is empty or contains only whitespace/comments, removing it may inadvertently delete meaningful formatting or trailing comments relied upon for readability or tooling. |
| r1-p008 | fix ok | Nested Break/Continue/Fina lly | label/break/continue control flow, finally blocks, early returns in nested blocks |
| r2-p001 | silent prediction off | Else Block After Non-Breaking If | Moving statements from an else block to the outer scope changes their execution context—they may now run even when the if condition is true but non-breaking (e.g., due to missing break/return). |
Sources
r1-p001 · Evaluation Order Shift
1let counter = 0; const sideEffect = () => { counter++; return counter; };
2
3if (Math.random() < 0.5) {
4 sideEffect(); // original order: else block runs after sideEffect call
5} else {
6 sideEffect(); // moved before the if in the fix
7}
8
9print('counter after if-else: ' + counter);
10print('expected counter >= 2, got: ' + counter);
r1-p002 · Label Visibility Break
1outer:
2for (let i = 0; i < 3; i++) {
3 if (Math.random() < 0.5) {
4 break outer; // original: break exits the labeled loop from inside else
5 } else {
6 innerBreak: break outer; // labeled break inside else
7 }
8}
9print('loop finished, counter should be 3');
10print('i value: ' + i);
11print('if i===3 label visibility preserved');
--- orig.js 2026-10-17 15:36:28.834491383 -0400 +++ fixed.js 2026-10-17 15:36:29.085490518 -0400 @@ -2,9 +2,8 @@ for (let i = 0; i < 3; i++) { if (Math.random() < 0.5) { break outer; // original: break exits the labeled loop from inside else - } else { - innerBreak: break outer; // labeled break inside else } + innerBreak: break outer; // labeled break inside else } print('loop finished, counter should be 3'); print('i value: ' + i);
r1-p003 · TDZ After Hoisting
1try {
2 if (true) {
3 const x = 1;
4 print('x in if: ' + x);
5 } else {
6 const x = 2; // original: x declared inside else
7 }
8 print('x after block: ' + x); // ReferenceError if TDZ fires
9} catch (e) {
10 print('Caught: ' + e.constructor.name + ': ' + e.message);
11}
12print('end');
r1-p004 · Getter Side Effect
1const obj = {
2 get val() {
3 print('getter called');
4 return 42;
5 },
6 set val(v) {
7 print('setter called with: ' + v);
8 }
9};
10
11Object.defineProperty(obj, 'side', {
12 get: function() {
13 print('Object.defineProperty getter called');
14 return 1;
15 },
16 enumerable: true
17});
18
19if (true) {
20 const v = obj.val; // original: getter called inside if
21} else {
22 const v = obj.val; // moved before if in the fix
23}
24print('done');
r1-p005 · Let Const Hoisting TDZ
1let tmp;
2try {
3 if (true) {
4 // no declaration
5 } else {
6 tmp = 1; // original: assignment inside else
7 }
8 print('tmp after: ' + tmp);
9 // Simulate hoisting: tmp is now in scope before the if
10 if (tmp === undefined) {
11 tmp = 2; // this line sees tmp in TDZ if hoisted weirdly
12 }
13} catch (e) {
14 print('Caught: ' + e.constructor.name + ': ' + e.message);
15}
16print('end');
r1-p006 · Function Declaration in Else
1{
2 if (Math.random() < 0.5) {
3 function bar() { return 1; }
4 print('bar called: ' + bar());
5 } else {
6 function bar() { return 2; } // original: function declaration inside else
7 print('else bar called: ' + bar());
8 }
9 // In the fix, bar is hoisted to enclosing scope, last declaration wins
10 print('final bar: ' + bar());
11}
12print('end');
r1-p007 · Empty Else Formatting
1// this comment must survive the fix
2if (false) {
3 // empty then
4} else {
5 // comment kept only if else remains
6 console.log('else body');
7}
8// after fix the comment may be lost or the else removed entirely
9print('program end');
else body
r1-p008 · Nested Break/Continue/Fina lly
1let depth = 0;
2try {
3 outer:
4 for (let i = 0; i < 2; i++) {
5 if (true) {
6 depth++;
7 if (Math.random() < 0.5) {
8 break outer; // original break from inside nested else
9 } else {
10 depth++;
11 continue outer; // original continue from inside else
12 }
13 }
14 }
15 print('depth: ' + depth);
16 print('loop terminated normally');
17} catch (e) {
18 print('Caught: ' + e.constructor.name);
19}
20print('finally block simulated');
--- orig.js 2026-10-17 15:36:30.334486108 -0400 +++ fixed.js 2026-10-17 15:36:30.581485220 -0400 @@ -6,10 +6,9 @@ depth++; if (Math.random() < 0.5) { break outer; // original break from inside nested else - } else { + } depth++; continue outer; // original continue from inside else - } } } print('depth: ' + depth);
r2-p001 · Else Block After Non-Breaking If
1if (x) { console.log('if'); } else { console.log('else'); }
2console.log('after');