[compiler] fix source location for return statements (#35660)

Fixes missing source locations for ReturnStatement nodes in generated
ast. Simple change using existing pattern, only required changes to the
codegen step, no other pipeline changes.

**Most file changes are new lines in generated code.** [First
commit](d15e90ebe0)
has the relevant changes, second commit has the noisy snap updates.

I added an exception to the validator to not report an error when a
return statement will be optimized to an implicit return by codegen, as
there's no separate return statement to instrument anyways in the final
ast. An edge case when it comes to preserving source locations for
instrumentation that is likely not as common for most babel transforms
since they are not doing optimizations.
This commit is contained in:
Nathan
2026-01-30 11:37:19 -05:00
committed by GitHub
parent da64117876
commit 64b4605cb8
229 changed files with 250 additions and 41 deletions

View File

@@ -1160,9 +1160,9 @@ function codegenTerminal(
const value = codegenPlaceToExpression(cx, terminal.value);
if (value.type === 'Identifier' && value.name === 'undefined') {
// Use implicit undefined
return t.returnStatement();
return createReturnStatement(terminal.loc);
}
return t.returnStatement(value);
return createReturnStatement(terminal.loc, value);
}
case 'switch': {
return createSwitchStatement(
@@ -1545,6 +1545,7 @@ const createThrowStatement = withLoc(t.throwStatement);
const createTryStatement = withLoc(t.tryStatement);
const createBreakStatement = withLoc(t.breakStatement);
const createContinueStatement = withLoc(t.continueStatement);
const createReturnStatement = withLoc(t.returnStatement);
function createVariableDeclarator(
id: t.LVal,

View File

@@ -149,6 +149,23 @@ export function validateSourceLocations(
return;
}
/*
* Skip return statements inside arrow functions that will be simplified to expression body.
* The compiler transforms `() => { return expr }` to `() => expr` in CodegenReactiveFunction
*/
if (t.isReturnStatement(node) && node.argument != null) {
const parentBody = path.parentPath;
const parentFunc = parentBody?.parentPath;
if (
parentBody?.isBlockStatement() &&
parentFunc?.isArrowFunctionExpression() &&
parentBody.node.body.length === 1 &&
parentBody.node.directives.length === 0
) {
return;
}
}
// Collect the location if it exists
if (node.loc) {
const key = locationKey(node.loc);

View File

@@ -46,6 +46,7 @@ function foo(cond) {
} else {
a = $[1];
}
return a;
}

View File

@@ -145,6 +145,7 @@ function useFoo(t0) {
if (t1 !== Symbol.for("react.early_return_sentinel")) {
return t1;
}
return s;
}

View File

@@ -61,6 +61,7 @@ function useFoo(t0) {
} else {
items = $[2];
}
return items;
}

View File

@@ -47,6 +47,7 @@ function Foo() {
} else {
thing = $[0];
}
return thing;
} catch {}
}

View File

@@ -33,6 +33,7 @@ function Component(props) {
} else {
x = $[1];
}
return x;
}

View File

@@ -23,6 +23,7 @@ export const FIXTURE_ENTRYPOINT = {
```javascript
function useFoo() {
const update = _temp;
return update;
}
function _temp() {

View File

@@ -36,6 +36,7 @@ function useBar(props) {
z = t0;
}
}
return z;
}

View File

@@ -53,6 +53,7 @@ function Component(props) {
default:
}
const outerHandlers = handlers;
return outerHandlers;
}

View File

@@ -98,6 +98,7 @@ function useFoo(t0) {
}
result = t1;
}
return result;
}

View File

@@ -40,6 +40,7 @@ function component(a) {
} else {
x = $[1];
}
return x;
}

View File

@@ -48,6 +48,7 @@ function component(a) {
} else {
x = $[1];
}
return x;
}

View File

@@ -37,6 +37,7 @@ function component(a) {
} else {
z = $[1];
}
return z;
}

View File

@@ -36,6 +36,7 @@ function component(a) {
t0 = $[1];
}
const x = t0;
return x;
}

View File

@@ -35,6 +35,7 @@ function component(a, b) {
t0 = $[1];
}
const z = t0;
return z;
}

View File

@@ -36,6 +36,7 @@ function component(a) {
t0 = $[1];
}
const x = t0;
return x;
}

View File

@@ -48,6 +48,7 @@ function bar(a, b) {
} else {
y = $[2];
}
return y;
}

View File

@@ -41,6 +41,7 @@ function bar(a) {
} else {
y = $[1];
}
return y;
}

View File

@@ -72,6 +72,7 @@ function Component(t0) {
t2 = $[6];
}
y = t2;
return y;
}

View File

@@ -48,6 +48,7 @@ function useHook(a, b) {
t1 = $[4];
}
const x = t1;
return x;
}

View File

@@ -32,6 +32,7 @@ function Foo(props) {
t0 = $[1];
}
const onFoo = t0;
return onFoo;
}

View File

@@ -50,6 +50,7 @@ function useHook(t0) {
const z_0 = { b };
mutate(z_0);
return z;
}

View File

@@ -48,6 +48,7 @@ function component(a) {
t1 = $[3];
}
x = t1;
return x;
}

View File

@@ -44,6 +44,7 @@ function component(a) {
t1 = $[3];
}
const x = t1;
return x;
}

View File

@@ -33,6 +33,7 @@ function component(a) {
t0 = $[1];
}
const z = t0;
return z;
}

View File

@@ -48,6 +48,7 @@ function component(a) {
t1 = $[3];
}
const x = t1;
return x;
}

View File

@@ -44,6 +44,7 @@ function component(a) {
t1 = $[3];
}
const x = t1;
return x;
}

View File

@@ -38,6 +38,7 @@ function component(a) {
t0 = $[1];
}
const x = t0;
return x;
}

View File

@@ -40,6 +40,7 @@ function component(a) {
t0 = $[1];
}
const x = t0;
return x;
}

View File

@@ -41,6 +41,7 @@ function Component(props) {
}
}
}
return x;
}

View File

@@ -32,6 +32,7 @@ function foo(a, b, c) {
}
}
}
return c;
}

View File

@@ -39,6 +39,7 @@ function Component(props) {
setX(2);
foo();
}
return x;
}

View File

@@ -37,6 +37,7 @@ function Component() {
const obj = { method() {} };
identity(obj);
return 4;
}

View File

@@ -30,6 +30,7 @@ function Component() {
const fn = _temp;
invoke(fn);
return 3;
}
function _temp() {

View File

@@ -26,6 +26,7 @@ function foo() {
for (const x = 100; false; 100) {
y = y + 1;
}
return y;
}

View File

@@ -30,6 +30,7 @@ export const FIXTURE_ENTRYPOINT = {
function foo(a, b, c) {
if (a) {
}
return b;
}

View File

@@ -27,6 +27,7 @@ function foo() {
while (false) {
y = y + 1;
}
return y;
}

View File

@@ -34,6 +34,7 @@ export const FIXTURE_ENTRYPOINT = {
```javascript
function foo() {
console.log("foo");
return -6;
}

View File

@@ -28,6 +28,7 @@ function foo(props) {
while (y < props.max) {
y++;
}
return y;
}

View File

@@ -37,6 +37,7 @@ function Component(p) {
} else {
x = $[0];
}
return x;
}

View File

@@ -56,6 +56,7 @@ function foo(a, b) {
} else {
y = $[4];
}
return y;
}

View File

@@ -50,6 +50,7 @@ function foo(x, y, z) {
if (y) {
items.push(x);
}
return items2;
}

View File

@@ -41,6 +41,7 @@ function Component(props) {
} else {
x = props.fallback;
}
return x;
}

View File

@@ -46,6 +46,7 @@ function Component() {
} else {
ret = $[0];
}
return ret;
}

View File

@@ -28,6 +28,7 @@ function Component(props) {
} else {
x = $[0];
}
return x;
}

View File

@@ -75,6 +75,7 @@ function Component(props) {
if (props.d) {
return null;
}
return x;
}

View File

@@ -38,6 +38,7 @@ function Component(props) {
x = $[1];
}
const x_0 = x;
return x_0;
}

View File

@@ -52,7 +52,7 @@ function Component({prop1, prop2}) {
## Error
```
Found 25 errors:
Found 22 errors:
Todo: Important source location missing in generated code
@@ -302,19 +302,6 @@ error.todo-missing-source-locations.ts:32:14
Todo: Important source location missing in generated code
Source location for ReturnStatement is missing in the generated output. This can cause coverage instrumentation to fail to track this code properly, resulting in inaccurate coverage reports..
error.todo-missing-source-locations.ts:33:4
31 |
32 | const foo = useCallback(() => {
> 33 | return a + b;
| ^^^^^^^^^^^^^
34 | }, [a, b]);
35 |
36 | function bar() {
Todo: Important source location missing in generated code
Source location for Identifier is missing in the generated output. This can cause coverage instrumentation to fail to track this code properly, resulting in inaccurate coverage reports..
error.todo-missing-source-locations.ts:34:6
@@ -341,19 +328,6 @@ error.todo-missing-source-locations.ts:34:9
Todo: Important source location missing in generated code
Source location for ReturnStatement is missing in the generated output. This can cause coverage instrumentation to fail to track this code properly, resulting in inaccurate coverage reports..
error.todo-missing-source-locations.ts:37:4
35 |
36 | function bar() {
> 37 | return (c + d) * 2;
| ^^^^^^^^^^^^^^^^^^^
38 | }
39 |
40 | console.log('Hello, world!');
Todo: Important source location missing in generated code
Source location for ExpressionStatement is missing in the generated output. This can cause coverage instrumentation to fail to track this code properly, resulting in inaccurate coverage reports..
error.todo-missing-source-locations.ts:40:2
@@ -377,18 +351,6 @@ error.todo-missing-source-locations.ts:40:10
41 |
42 | return [y, foo, bar];
43 | }
Todo: Important source location missing in generated code
Source location for ReturnStatement is missing in the generated output. This can cause coverage instrumentation to fail to track this code properly, resulting in inaccurate coverage reports..
error.todo-missing-source-locations.ts:42:2
40 | console.log('Hello, world!');
41 |
> 42 | return [y, foo, bar];
| ^^^^^^^^^^^^^^^^^^^^^
43 | }
44 |
```

View File

@@ -61,6 +61,7 @@ function foo(a, b, c) {
} else {
x = $[3];
}
return x;
}

View File

@@ -52,6 +52,7 @@ function Component(props) {
t2 = $[5];
}
const c = t2;
return (a && b) || c;
}

View File

@@ -32,6 +32,7 @@ function Component(props) {
} else {
y = props.c;
}
return y;
}

View File

@@ -52,6 +52,7 @@ function foo(a, b, c) {
if (x.length) {
return x;
}
return null;
}

View File

@@ -29,6 +29,7 @@ function Component(props) {
x = x + i;
i = i + 1;
}
return x;
}

View File

@@ -32,6 +32,7 @@ function Component(props) {
break;
}
}
return x;
}

View File

@@ -23,6 +23,7 @@ function Component(props) {
for (const x in props.value) {
return x;
}
return null;
}

View File

@@ -45,6 +45,7 @@ function Component(props) {
x = object[y];
}
return x;
}

View File

@@ -54,6 +54,7 @@ function Component(props) {
x = object[y];
}
return x;
}

View File

@@ -23,6 +23,7 @@ function Component(props) {
let x;
for (const y in props.value) {
}
return x;
}

View File

@@ -36,6 +36,7 @@ function foo(props) {
x = x * 2;
y = y + x;
}
return y;
}

View File

@@ -37,6 +37,7 @@ function Component(props) {
} else {
items = $[1];
}
return items;
}

View File

@@ -35,6 +35,7 @@ function Component() {
for (const item of [1, 2]) {
break;
}
return x;
}

View File

@@ -47,6 +47,7 @@ function Component(props) {
} else {
items = $[0];
}
return items;
}

View File

@@ -41,6 +41,7 @@ function Component() {
} else {
x = $[0];
}
return x;
}

View File

@@ -43,6 +43,7 @@ function Component() {
} else {
ret = $[0];
}
return ret;
}

View File

@@ -36,6 +36,7 @@ function Component() {
} else {
x = $[0];
}
return x;
}

View File

@@ -51,6 +51,7 @@ function Router(t0) {
} else {
array = $[2];
}
return array;
}

View File

@@ -51,6 +51,7 @@ function Router(t0) {
} else {
array = $[2];
}
return array;
}

View File

@@ -38,6 +38,7 @@ function Component(props) {
} else {
items = $[0];
}
return items;
}

View File

@@ -36,6 +36,7 @@ function Component() {
} else {
x = $[0];
}
return x;
}

View File

@@ -44,6 +44,7 @@ function useFoo(t0) {
for (const el of s1.values()) {
s2.add(el);
}
return [s1, s2];
}

View File

@@ -60,6 +60,7 @@ function useFoo(t0) {
);
const dispatcher = useHook();
return button;
}

View File

@@ -42,6 +42,7 @@ function component(a) {
} else {
t = $[1];
}
return t;
}

View File

@@ -44,6 +44,7 @@ function hoisting(cond) {
} else {
items = $[1];
}
return items;
}
function _temp() {

View File

@@ -44,6 +44,7 @@ function hoisting(cond) {
} else {
items = $[1];
}
return items;
}
function _temp() {

View File

@@ -44,6 +44,7 @@ function foo(a, b, c) {
} else {
x = $[3];
}
return x;
}

View File

@@ -29,6 +29,7 @@ import { getNumber } from "shared-runtime";
function Component(props) {
const x = getNumber();
return x;
}

View File

@@ -412,6 +412,7 @@ function ConditionalJsx(t0) {
}
content = t3;
}
return content;
}

View File

@@ -35,6 +35,7 @@ function foo(a, b, c) {
x = c;
}
return x;
}

View File

@@ -47,6 +47,7 @@ function foo(a, b, c, d) {
} else {
y = $[4];
}
return y;
}

View File

@@ -58,6 +58,7 @@ function Component(t0) {
t2 = (i, id) => {
const T0 = _temp;
const jsx = <T0 i={i} key={id} x={x} />;
return jsx;
};
$[3] = x;

View File

@@ -50,6 +50,7 @@ function useHook(end) {
} else {
log = $[1];
}
return log;
}

View File

@@ -41,6 +41,7 @@ function Component(props) {
}
x = t0;
}
return x;
}

View File

@@ -49,6 +49,7 @@ function Component(props) {
} else {
y = $[1];
}
return y;
}

View File

@@ -57,6 +57,7 @@ function Component(props) {
t2 = $[4];
}
useEffect(t1, t2);
return y;
}

View File

@@ -44,6 +44,7 @@ function b() {
if (import.meta.url) {
a = 1;
}
return a;
}
@@ -52,6 +53,7 @@ function c() {
if (import.meta.foo) {
a = 1;
}
return a;
}
@@ -60,6 +62,7 @@ function d() {
if (import.meta) {
a = 1;
}
return a;
}

Some files were not shown because too many files have changed in this diff Show More