Undo-block review fixes: exception-safe depth, corrected docs, real test teeth
Fixes ctor exception safety, a ValidatePtr2 guard, false SDK-citation and enforcement claims, the span-depth invariant, and vacuous fx_reclaim tests.
This commit is contained in:
@@ -11,13 +11,19 @@ nests over it.
|
||||
|
||||
## Invariants
|
||||
|
||||
- **`Undo_BeginBlock2` is not callable outside this directory, and that is enforced
|
||||
by the compiler, not by review.** Only `undo_block.cpp` and `shell/view`'s
|
||||
`fx_reclaim.cpp` (which owns the span's own begin/end) define
|
||||
`REAPERAPI_WANT_Undo_BeginBlock2` / `..._Undo_EndBlock2`. Every other TU compiles
|
||||
under `REAPERAPI_MINIMAL` with no header in its include graph pulling the SDK in
|
||||
unguarded, so a raw `Undo_BeginBlock2` there is an undeclared identifier. Adding
|
||||
the WANT define back to a third TU is the one way to defeat this — do not.
|
||||
- **`Undo_BeginBlock2` is not callable outside this directory in every TU but one, and
|
||||
that is enforced by the compiler, not by review.** Only `undo_block.cpp` and
|
||||
`shell/view`'s `fx_reclaim.cpp` (which owns the span's own begin/end) define
|
||||
`REAPERAPI_WANT_Undo_BeginBlock2` / `..._Undo_EndBlock2`; every other TU compiles
|
||||
under `REAPERAPI_MINIMAL`, so a raw `Undo_BeginBlock2` there is an undeclared
|
||||
identifier. **`app/main.cpp` is the one exception** — as the sole
|
||||
`REAPERAPI_IMPLEMENT` TU it never sets `REAPERAPI_MINIMAL` (it must allocate storage
|
||||
for whatever ANY TU wants), so the whole API, `Undo_*` included, compiles clean
|
||||
there too. That TU stays out of the undo business by discipline
|
||||
(`src/app/CLAUDE.md`: pointers + entry + dispatch only), not because the compiler
|
||||
stops it — do not add business logic there that would make this matter. Adding the
|
||||
WANT define back to a third TU is a second, easier way to defeat the enforcement
|
||||
that DOES exist — do not.
|
||||
- **Ending the reclaim span is part of opening, and ONLY the outermost block does
|
||||
it.** At depth 0 the span is the only block that can be open, so ending it mints
|
||||
the pending mode switch's point whole before this block exists. At depth > 0 an
|
||||
@@ -26,6 +32,12 @@ nests over it.
|
||||
is the same criterion `applyMode`'s reapply is gated on; it lives in the
|
||||
constructor so no call site has to make the judgment. Full reasoning for the rule
|
||||
itself: `src/shell/view/CLAUDE.md`.
|
||||
- **The constructor's body is one `try`.** `fxReclaimEndUndoSpan` copies a
|
||||
`std::string` and can throw; a throwing constructor runs no destructor, so an
|
||||
uncompensated depth increment would stick forever — `undoBlockOpen()` reads true
|
||||
for the rest of the session, `fxReclaimTick` refuses every tick, and no later
|
||||
`UndoBlock` is ever outermost. Any throw between the increment and the end of the
|
||||
constructor rolls the depth back before propagating.
|
||||
- **Closing is a destructor.** No throw between the open and the label decision can
|
||||
leave a block open in the user's project, which is why several call sites can
|
||||
allocate freely between the two.
|
||||
@@ -46,6 +58,15 @@ nests over it.
|
||||
|
||||
## Gotchas
|
||||
|
||||
- **`Undo_EndBlock2` is guarded by `ValidatePtr2` only when `project_` is a real,
|
||||
non-null pointer.** `nullptr` means "the active project" — the same convention
|
||||
`Undo_BeginBlock2` was handed — and `ValidatePtr2` does not accept `nullptr` as a
|
||||
valid object of any type, so guarding it unconditionally would silently stop every
|
||||
`UndoBlock undo(nullptr)` site (most of them) from ever closing. A real pointer, by
|
||||
contrast, can go stale between open and close (several call sites allocate freely
|
||||
in between), so only that case is validated — the same asymmetry `fx_reclaim.cpp`'s
|
||||
`closeSpan` already has, for the same reason: its span always holds a real pinned
|
||||
pointer, never `nullptr` for "active".
|
||||
- The depth counter deliberately does NOT count the reclaim span. The span is the
|
||||
thing this stands off, not a peer.
|
||||
- The counter drops AFTER `Undo_EndBlock2`, not before: the close that reaches depth
|
||||
|
||||
Reference in New Issue
Block a user