dillon1000/react

Commit

[DevTools] Fix printOperationsArray decode of applied activity slice change (#36935)

`printOperationsArray` in `react-devtools-shared` walks an operations
array under
the invariant that each `switch` case leaves `i` pointing at the next
opcode (loop
header at `packages/react-devtools-shared/src/utils.js`).

The `TREE_OPERATION_APPLIED_ACTIVITY_SLICE_CHANGE` case broke that
invariant:

```js
case TREE_OPERATION_APPLIED_ACTIVITY_SLICE_CHANGE: {
  i++;                                        // skip opcode -> i now at the value slot
  const activitySliceIDChange = operations[i + 1]; // reads the slot AFTER the value; i not advanced
  ...
}
```

The operation is exactly two slots, `[opcode, activitySliceID]` (see the
writer in
`packages/react-devtools-shared/src/backend/fiber/renderer.js`, which
pushes the
opcode then the id). So the case did two things wrong:

1. It logged the wrong number: `operations[i + 1]` reads the slot
*after* the
value (the next operation's opcode, or `undefined` at the end of the
array).
2. It left `i` pointing at the value slot, so the outer `while (i <
operations.length)` loop re-read the activity-slice id as an opcode. For
any
non-zero slice id that falls through to `default: throw
Error("Unsupported
   Bridge operation ...")`, aborting the whole dump.

The two canonical decoders of this same operation both use the correct
pattern
(skip the opcode, then read *and* advance past the value):

- `devtools/store.js`: `i++; nextActivitySliceID = operations[i++];`
- `devtools/views/Profiler/CommitTreeBuilder.js`: `i++; const
activitySliceIDChange = operations[i++];`

This change makes `printOperationsArray` match them by reading
`operations[i++]`.

This is a debug-only diagnostic path: the only caller is the
`__DEBUG__`-guarded
dump in `backend/legacy/renderer.js`, so it is not a production crash.
The bug was
introduced in #34908.

## How did you test this change?

Added a regression test for `printOperationsArray` in
`packages/react-devtools-shared/src/__tests__/utils-test.js`. The
fixture chains
two activity-slice operations, `[rendererID, rootID, stringTableSize=0,
opcode, 42,
opcode, 0]`; the trailing operation is what forces the reader to advance
past the
first value slot rather than re-read it. It asserts the call does not
throw, logs
once, and that the message contains both `Applied activity slice change
to 42` and
`Reset applied activity slice`.

Ran the DevTools Jest project (built first, as that project requires a
build):

- With the fix: 51/51 pass, including the new test.
- Reverting only the one-line fix back to `operations[i + 1]` and
rebuilding: the
new test fails with `Unsupported Bridge operation "42"` (exactly the
predicted
  failure), 50 pass / 1 fail. Restored the fix and it is green again.

`yarn prettier-check` and `yarn linc` are clean on the changed files.
Browse files
Changed paths2 files
First-parent comparison
M packages/react-devtools-shared/src/__tests__/utils-test.js ModifiedM packages/react-devtools-shared/src/utils.js Modified
Patch

Files changed

Rendering syntax-highlighted changes…