biome complexity/useArrowFunction
labelled safe
Analysis Nemotron 3 Super
Flags named or anonymous function expressions without 'this' usage or generator syntax that can be safely rewritten as arrow functions.
Fix: Replaces the function expression with an arrow function having the same parameters and body, preserving async if present, while maintaining identical lexical scope and binding behavior for non-this references.
10 hazards
- Rewriting a function used as a constructor breaks instantiation because arrow functions lack [[Construct]] and throw when called with new.
- If the function expression is referenced before its declaration via a different identifier, hoisting differences may cause ReferenceError where none occurred before.
- When the function is a method in an object literal, the rewrite severs any implicit dependency on the function's name property for recursion or debugging, potentially breaking named function expression patterns.
- If the function expression is wrapped in parentheses and immediately invoked, the arrow function rewrite may alter parsing due to tighter binding of => vs function in edge-case grammar contexts.
- Comments attached to the function keyword or between parameters and body may be lost during the rewrite, as biome's autofix does not preserve arbitrary comment placement.
- In TypeScript, if the function expression has a return type annotation inferred from context, the arrow function may trigger a type mismatch due to differing contextual typing rules.
- If the function expression is part of a sequence expression or comma operator, replacing it with an arrow function could change operator precedence interpretation.
- When the function expression is used as a getter or setter in an object literal, the rewrite fails silently because biome skips such cases, but if misapplied would violate ES accessor semantics.
- If the function expression relies on arguments.callee for self-reference, the arrow function lacks both arguments and arguments.callee, breaking legacy introspection patterns.
- In sloppy mode, if the function expression contains 'use strict' in its body, the arrow function inherits the outer strictness, potentially altering behavior if the outer scope is not strict.
Programs
| id | result | title | hazard |
|---|---|---|---|
| r2-p001 | fix ok | Name collision via shadowing after rewrite | name collisions across scopes after a move (shadowing) |
| r2-p002 | fix ok | Comments on function keyword lost during rewrite | Comments attached to the function keyword or between parameters and body may be lost during the rewrite, as biome's autofix does not preserve arbitrary comment placement. |
| r2-p003 | silent prediction off | Named function expression recursion severed by rewrite | When the function is a method in an object literal, the rewrite severs any implicit dependency on the function's name property for recursion or debugging, potentially breaking named function expressio |
| r2-p004 | fix ok | Comments attached to removed/moved code lost | comments attached to the removed or moved code |
| r2-p005 | silent prediction off | arguments.callee reliance breaks with arrow function | If the function expression relies on arguments.callee for self-reference, the arrow function lacks both arguments and arguments.callee, breaking legacy introspection patterns. |
| r2-p006 | fix ok | Function declaration inside case block interacted badly | function declarations inside blocks, switch cases, labeled statements |
| r2-p007 | silent | Getter/setter skipped by rule but would break if rewritten | When the function expression is used as a getter or setter in an object literal, the rewrite fails silently because biome skips such cases, but if misapplied would violate ES accessor semantics. |
| r2-p008 | fix ok | Null/undefined distinction in optional chaining context | null/undefined distinction, optional chaining short-circuit, nullish vs falsy |
Sources
r2-p001 · Name collision via shadowing after rewrite
1function outer() {
2 let f = 1;
3 const x = function () {
4 console.log('inner:', f);
5 return f++;
6 };
7 for (let i = 0; i < 2; i++) {
8 const f = 10;
9 console.log(x());
10 }
11}
12outer();
--- orig.js 2026-10-17 15:41:13.678902704 -0400 +++ fixed.js 2026-10-17 15:41:13.942897707 -0400 @@ -1,6 +1,6 @@ function outer() { let f = 1; - const x = function () { + const x = () => { console.log('inner:', f); return f++; };
inner: 1 1 inner: 2 2
r2-p002 · Comments on function keyword lost during rewrite
1const log = /* start */function(x/* param */) {/* body */ return x * 2;};
2console.log(log(5));
--- orig.js 2026-10-17 15:41:14.107894581 -0400 +++ fixed.js 2026-10-17 15:41:14.387889274 -0400 @@ -1,2 +1,2 @@ -const log = /* start */function(x/* param */) {/* body */ return x * 2;}; +const log = /* start */(x/* param */) => x * 2; console.log(log(5));
10
r2-p003 · Named function expression recursion severed by rewrite
1const obj = {
2 fact: function fact(n) {
3 return n <= 1 ? 1 : n * fact(n - 1);
4 }
5};
6try {
7 console.log(obj.fact(4));
8} catch (e) {
9 console.log(e.name + ': ' + e.message);
10}
24
r2-p004 · Comments attached to removed/moved code lost
1const data = [1, 2, 3];
2const doubled = data.map(function(/* item */x) {/* double */ return x * 2;});
3console.log(doubled);
--- orig.js 2026-10-17 15:41:14.780881824 -0400 +++ fixed.js 2026-10-17 15:41:15.053876648 -0400 @@ -1,3 +1,3 @@ const data = [1, 2, 3]; -const doubled = data.map(function(/* item */x) {/* double */ return x * 2;}); +const doubled = data.map((/* item */x) => x * 2); console.log(doubled);
[ 2, 4, 6 ]
r2-p005 · arguments.callee reliance breaks with arrow function
1const factorial = function(n) {
2 return n <= 1 ? 1 : n * arguments.callee(n - 1);
3};
4try {
5 console.log(factorial(4));
6} catch (e) {
7 console.log(e.name + ': ' + e.message);
8}
TypeError: 'caller', 'callee', and 'arguments' properties may not be accessed on strict mode functions or the arguments objects for calls to them
r2-p006 · Function declaration inside case block interacted badly
1switch (1) {
2 case 1:
3 let x = function () { return 'case'; };
4 console.log(x());
5 break;
6}
7console.log('done');
--- orig.js 2026-10-17 15:41:15.436869377 -0400 +++ fixed.js 2026-10-17 15:41:15.710864175 -0400 @@ -1,6 +1,6 @@ switch (1) { case 1: - let x = function () { return 'case'; }; + let x = () => 'case'; console.log(x()); break; }
case done
r2-p007 · Getter/setter skipped by rule but would break if rewritten
1const obj = {
2 get value() { return 42; },
3 set value(v) { this._val = v; }
4};
5obj.value = 10;
6console.log(obj.value, obj._val);
42 10
r2-p008 · Null/undefined distinction in optional chaining context
1const getValue = function(obj) {
2 return obj?.prop ?? 'default';
3};
4console.log(getValue({ prop: null }));
5console.log(getValue({}));
6console.log(getValue(undefined));
--- orig.js 2026-10-17 15:41:16.101856749 -0400 +++ fixed.js 2026-10-17 15:41:16.370851634 -0400 @@ -1,6 +1,4 @@ -const getValue = function(obj) { - return obj?.prop ?? 'default'; -}; +const getValue = (obj) => obj?.prop ?? 'default'; console.log(getValue({ prop: null })); console.log(getValue({})); console.log(getValue(undefined));
default default default