fixhunt

biome complexity/noUselessLoneBlockStatements

labelled safe
Runs / 2026-10-17T20-06-50-863Z-e9k5-biome-complexity_noUselessLoneBlockStatementsbiome 2.5.152026-10-17 20:06 UTC8 programs × 2 round(s)16 programs, 2 fired, 2 fixed, 1 findings, 5 rejectedmodel cost $0.03

Analysis Nemotron 3 Super

Flags empty block statements (`{}`) as they serve no purpose unless containing declarations that introduce bindings.

Fix: Removes the empty block statement entirely, preserving surrounding syntax and whitespace except for the braces and their immediate interior.

11 hazards
  • Rewriting `{}` inside a `with` statement changes the object used for property lookup, altering identifier resolution.
  • Removing a block in a comma expression like `( {}, x )` drops the left-hand side, changing the expression's value from `x` to potentially causing a syntax error if the comma was relied upon for sequencing.
  • Deleting a block that follows a label (e.g., `label: {};`) removes the labeled statement, breaking `break label;` or `continue label;` references elsewhere.
  • If the empty block contains a trailing comment (e.g., `{ /* note */ }`), the autofix may discard the comment, losing developer intent.
  • In non-strict mode, a function declaration inside a block is not allowed, but if present due to browser leniency, removing the block could expose it to outer scope, changing hoisting behavior.
  • When the block is the sole member of a `do-while` loop body (e.g., `do {} while (false);`), removing it creates an empty loop body, which is syntactically valid but may affect performance expectations or tooling that counts loop iterations.
  • In a sequence like `if (a) {}; else if (b) {};`, removing the first empty block could merge the `else if` with the prior `if`, changing the binding of the `else` clause if formatting relies on the block to delimit the then-branch.
  • If the empty block is part of a larger expression relying on its presence for automatic semicolon insertion (ASI), such as `return\n{};`, its removal could cause ASI to insert a semicolon after `return`, returning `undefined` instead of the intended value.
  • In a `switch` statement, a case label followed by an empty block (e.g., `case 1: {}; break;`) when rewritten removes the block but leaves the label, which is harmless only if no fall-through is intended; however, if the block was meant to prevent fall-through via explicit emptiness, its removal does not change behavior but may mislead readers about intent.
  • When the block appears immediately after a `yield` expression (e.g., `yield {};`), removing it does not change the yielded value but may affect generator debugging or stack traces that expect a block boundary.
  • In template literals, a tagged template like `tag`{}`` with an empty block afterward (invalid syntax) would not occur, but if malformed code had `{}` adjacent due to a macro, removal could alter parsing; however, this is speculative and not a direct hazard of the rule.

Findings

programoraclelabeljudgestatussummary
r2-p008fix-changes-behaviorlabelled safereal · highrelatedThe fix removes a standalone block `{}` inside a try block that contains a `let x = 1` declaration. According to the documentation, a block is not redundant wh…

Programs

idresulttitlehazard
r1-p001silent prediction offDo-while loop with empty blockWhen the block is the sole member of a `do-while` loop body, removing it creates an empty loop body.
r1-p002silent prediction offEmpty block with trailing commentIf the empty block contains a trailing comment, the autofix may discard the comment, losing developer intent.
r1-p003silentException during rewrite evaluationExceptions thrown inside the code the fix removes or rewrites
r1-p004fix okASI hazard after return newlineIf the empty block is part of a larger expression relying on its presence for automatic semicolon insertion (ASI), such as `return\n{};`, its removal could cause ASI to insert a semicolon after `retur
r1-p005silent prediction offNumeric/string coercion with objectnumeric/string coercion: + vs template literal, objects with toString/valueOf, Symbol, BigInt
r1-p006invalidLabeled empty blockDeleting a block that follows a label (e.g., `label: {};`) removes the labeled statement, breaking `break label;` or `continue label;` references elsewhere.
r1-p007silentTemplate literal adjacency (speculative)In template literals, a tagged template like `tag`{}`` with an empty block afterward (invalid syntax) would not occur, but if malformed code had `{}` adjacent due to a macro, removal could alter parsi
r1-p008silent prediction offAsync/await and generator interactionasync/await ordering, generators and yield position
r2-p001silent prediction offNumeric/String Coercion Hazardnumeric/string coercion: + vs template literal, objects with toString/valueOf, Symbol, BigInt
r2-p002silent prediction offDo-While Sole Member HazardWhen the block is the sole member of a `do-while` loop body (e.g., `do {} while (false);`), removing it creates an empty loop body, which is syntactically valid but may affect performance expectations
r2-p003silent prediction offSwitch Case Fallthrough Misleading HazardIn a `switch` statement, a case label followed by an empty block (e.g., `case 1: {}; break;`) when rewritten removes the block but leaves the label, which is harmless only if no fall-through is intend
r2-p004invalidElse-If Binding Ambiguity HazardIn a sequence like `if (a) {}; else if (b) {};`, removing the first empty block could merge the `else if` with the prior `if`, changing the binding of the `else` clause if formatting relies on the blo
r2-p005invalidWith Statement Object Lookup HazardRewriting `{}` inside a `with` statement changes the object used for property lookup, altering identifier resolution.
r2-p006invalidFunction Declarations in Blocks Hazardfunction declarations inside blocks, switch cases, labeled statements
r2-p007invalidName Collisions Across Scopes Hazardname collisions across scopes after a move (shadowing)
r2-p008fix-changes-behaviorASI Semicolon-Less HazardASI and semicolon-less code, leading ( or [ on the next line

Sources

r1-p001 · Do-while loop with empty block
1let i = 0;
2do {}
3while (i++ < 2);
4console.log('iterations:', i - 1);
iterations: 2
r1-p002 · Empty block with trailing comment
1{ /* keep me */ }
2console.log('comment preserved?');
comment preserved?
r1-p003 · Exception during rewrite evaluation
1try {
2 ({}).toString();
3} catch (e) {
4 console.log(e.name, e.message);
5}
r1-p004 · ASI hazard after return newline
1function f() {
2 return
3{};
4}
5console.log(f());
--- orig.js	2026-10-17 16:07:00.318124510 -0400
+++ fixed.js	2026-10-17 16:07:00.588112088 -0400
@@ -1,5 +1,4 @@
 function f() {
-  return
-{};
+  return;
 }
 console.log(f());
undefined
r1-p005 · Numeric/string coercion with object
1const o = { valueOf: () => 42, toString: () => 'obj' };
2console.log(+{}, +o);
3console.log(`${{}}`, `${o}`);
NaN 42
[object Object] obj
r1-p006 · Labeled empty block (generated program does not parse: /home/sun/dev/diaghunt/runs/2026-10-17T20-06-5)
1outer: {}
2if (true) break outer;
3console.log('labeled block executed');
r1-p007 · Template literal adjacency (speculative)
1console.log(`hello`);
hello
r1-p008 · Async/await and generator interaction
1async function* gen() {
2 yield {}
3 yield 1;
4}
5gen().next().then(r => console.log(r.value));
{}
r2-p001 · Numeric/String Coercion Hazard
1const o = { valueOf: () => '5', toString: () => 'o' };
2console.log(+{} + String(o));
3// Expected: NaNo // After fix: '+String(o)' -> concatenation
NaNo
r2-p002 · Do-While Sole Member Hazard
1let n = 0;
2do { n++; } while (n < 3);
3console.log('Iterations:', n);
4// Before: 3 // After fix: infinite loop? No -- removed block makes body empty, but condition still runs. Actually: do ; while(...) is valid but does nothing -> n stays 0
Iterations: 3
r2-p003 · Switch Case Fallthrough Misleading Hazard
1let x = 1;
2switch (x) {
3 case 1: {}; // block meant to isolate
4 console.log('one');
5 break;
6 case 2:
7 console.log('two');
8}
9// Prints 'one' both before and after fix, but after fix looks like fallthrough
one
r2-p004 · Else-If Binding Ambiguity Hazard (generated program does not parse: /home/sun/dev/diaghunt/runs/2026-10-17T20-06-5)
1let a = false, b = true;
2if (a) {};
3else if (b) console.log('b true');
4else console.log('neither');
5// Before: else if binds to first if -> prints 'b true'
6// After fix: if (a); else if (b) ... -> same due to semicolon, but without block, visual grouping lost
r2-p005 · With Statement Object Lookup Hazard (generated program does not parse: /home/sun/dev/diaghunt/runs/2026-10-17T20-06-5)
1with ({ x: 10 }) {
2 {};
3 console.log(x);
4}
5// With block: x resolved to 10
6// After fix: with ({x:10}) ; console.log(x); -> still 10? Yes, because with object unchanged.
7// But: if block had var x=20, it would leak. Here no decl -> safe. So revise:
8// Let's make block declare a var that shadows
9with ({ x: 10 }) {
10 { var x = 20; }
11 console.log(x);
12}
13// Before: logs 20 (block-scoped? No, var is function-scoped, but with doesn't create scope)
14// Actually: var inside with block is still function-scoped -> x=20 in outer scope
15// After fix: var x=20; runs -> same. Not good.
16// Use let:
17with ({ x: 10 }) {
18 { let x = 20; }
19 console.log(x);
20}
21// Before: logs 10 (let in block)
22// After fix: let x=20; is outside with -> throws ReferenceError? No, x not in with scope -> ReferenceError
23// So:
r2-p006 · Function Declarations in Blocks Hazard (generated program does not parse: /home/sun/dev/diaghunt/runs/2026-10-17T20-06-5)
1if (true) {
2 {};
3 function f() { return 1; }
4 console.log(f());
5}
6// Before: f defined in block scope (ES2015+), but actually hoisted to function scope in non-strict
7// In strict mode? Not used. Assume sloppy: f is function-scoped -> ok
8// After fix: same
9// Problem: if block removed, and we have duplicate?
10// Make two:
11if (true) { {}; function f(){return 1;} }
12if (true) { {}; function f(){return 2;} }
13console.log(f());
14// Before: second f wins -> 2
15// After fix: still 2
16// But if blocks removed, still same.
17// Instead: rely on block scoping via let? No.
18// Use: in switch
19let y = 1;
20switch(y) {
21 case 1: {}; function f(){ return 1; } break;
22 case 2: function f(){ return 2; } break;
23}
24console.log(f());
25// Case B: function declarations in case are not allowed lexically, but in sloppy mode they are hoisted to enclosing function
26// So both f's are in same scope -> second wins -> 2
27// After fix: same
28// Not changing.
29// Hazard: if the block was the only thing making the case boundary clear, removing it might cause fallthrough? But we have break.
30// Let's do labeled statement:
31L: { {}; function f(){ return 1; } }
32console.log(f());
33// Before: f in L's block scope? No, function decl not blocked -> function-scoped
34// After fix: same
35// Not working. Accept that in practice, this hazard is low, but we output something.
r2-p007 · Name Collisions Across Scopes Hazard (generated program does not parse: /home/sun/dev/diaghunt/runs/2026-10-17T20-06-5)
1let x = 1;
2if (true) { {}; let x = 2; }
3console.log(x);
4// Before: logs 1 (outer x)
5// After fix: let x=2; is still inside if block -> same
6// Not changed.
7// Need: after fix, the let moves out? No.
8// How about: the block removal causes a var to be hoisted?
9var x = 1;
10if (true) { {}; var x = 2; }
11console.log(x);
12// Before: logs 2 (var hoisted to if block? No, to function scope)
13// After fix: same
14// Instead: make the empty block contain a declaration that, after removal, conflicts with outer
15let x = 1;
16{}
17let x = 2; // SyntaxError: redeclaration
18// But rule doesn't fire on {} alone? It does.
19// So:
20let x = 1;
21{};
22let x = 2; // Error
23// After fix: becomes two consecutive lets -> still error
24// Same.
25// Make it so that before, the inner x is in block, after fix it's not?
26// Impossible: removing {} doesn't change scope of later let.
27// Unless the block was a with or something.
28// Give up and use:
29function f() {
30 let x = 1;
31 if (true) { {}; let x = 2; }
32 return x;
33}
34console.log(f());
35// Always 1
36// Not helpful.
37// Alternative: the block was preventing a fallback via {} in object destructuring? No.
38// We'll output a program where the trace is same, but note in comment.
r2-p008 · ASI Semicolon-Less Hazard
1let x = 1
2{}
3[1,2,3].forEach(v => console.log(v))
4// Before: {} is parsed as empty block, then [1...] is array literal -> prints 1,2,3
5// After fix: remove {} -> now: let x = 1
6// [1,2,3].forEach(...) -> ASI: tries to parse as 1[1,2,3] -> TypeError
7try {
8 let x = 1
9{}
10[1,2,3].forEach(v => console.log(v))
11} catch(e) {
12 console.log('Error:', e.name + ': ' + e.message)
13}
--- orig.js	2026-10-17 16:07:12.347577815 -0400
+++ fixed.js	2026-10-17 16:07:12.655564001 -0400
@@ -6,7 +6,6 @@
 // [1,2,3].forEach(...) -> ASI: tries to parse as 1[1,2,3] -> TypeError
 try {
   let x = 1
-{}
 [1,2,3].forEach(v => console.log(v))
 } catch(e) {
   console.log('Error:', e.name + ': ' + e.message)
1
2
3
1
2
3