Fix C/C++ debug hover on intermediate members of a dereferenced expression#14540
Fix C/C++ debug hover on intermediate members of a dereferenced expression#14540tieo wants to merge 5 commits into
Conversation
…enced members VS Code's default debug data-tip keeps a leading `*`/`&` and clips on the right, so hovering an intermediate member of e.g. `*a.b.c` evaluates `*a.b` (a dereference of the struct `a.b`) and shows no value. Register an EvaluatableExpressionProvider that, only for that case, returns the expression without the leading operator. Every other expression returns undefined so the default behavior is unchanged.
|
@microsoft-github-policy-service agree |
|
Addressed the review feedback in the latest commit:
On the Copilot suggestion to gate with What it does now is keep the leading |
5433ec8 to
b080bf6
Compare
|
Thanks — addressed the feedback and rewrote the description, since the old one no longer matched the code. On the "returns On On On tests: moved the computation into a |
Register the EvaluatableExpressionProvider during debugger activation instead of through the language client, so it also works when IntelliSense is disabled, and move it next to the other debugger code. The expression computation lives in a vscode-free module (evaluatableExpression.ts) so it can be unit tested directly. Registering a provider replaces VS Code's built-in data-tip expression detection, so it reproduces that for ordinary tokens and additionally handles access chains the built-in detection gets wrong for C/C++: - A leading */& binds to the whole access chain (the postfix ., ->, [] operators bind tighter), so it is dropped for an interior member of a dot chain, where *a.b would dereference the struct a.b, and kept on the final member and before ->. - Array subscripts and :: are kept in the token, so members after a subscript (a.b[i].c) and scoped names (ns::var) resolve instead of producing a broken fragment.
b080bf6 to
e21453c
Compare
The leading */& is kept before -> / [] and at the end of a chain because those left operands are provably pointers/arrays, so *ptr->m, *a.b[i] and &a[i] evaluate without error; it is dropped only before . where the left operand may be a struct. Documents these keep-leading outcomes as deliberate per review feedback.
|
Thanks for the detailed review. I've addressed the remaining points. Connector-leading fragments. The provider now declines these explicitly: after any leading The CodeQL. The test helper now slices at the marker index instead of using On the optional suggestion to require an identifier start so numeric literals like |
Inside [...] the token spans whitespace and operators (e.g. a[i + j]), so returning the nearest identifier evaluated the wrong expression when the cursor was on an operator or space. Return undefined unless the cursor is on the index identifier itself, and add tests.
Replace the token regex with a manual scanner so nested subscripts (a[b[i]]) stay in one token, fix hovering past the last identifier truncating a trailing subscript, and decline non-token positions inside [...] (operators/whitespace). Keep the leading * only on the final dereferenced segment (including a final subscript element like *a.b[i]); drop it on interior segments and drop a leading & always. Removes the previous regex (and its ReDoS surface).
|
Pushed a follow-up that reworks the token detection after testing against real debug sessions. Summary of what changed and why: Balanced-bracket scanner instead of a regex. The token is now found by a small manual scanner rather than Leading-operator rule, corrected. My earlier comment described
Subscript edge cases. Non-token positions inside Unit tests cover all of the above (interior vs final Separately: while testing I hit a data-tip rendering issue where a |
Problem
While debugging C/C++, hovering an intermediate member of a
*/&-prefixed access chain (e.g.aorbinif (*a.b.c == X)wherea.bis a struct) shows no value, and hovering a member that comes after an array subscript (e.g.cina.b[i].c) shows no value either.Cause
No
EvaluatableExpressionProvideris registered for C/C++, so VS Code's built-in data-tip expression detection is used. It keeps the leading*/&and clips on the right, so hoveringbin*a.b.cevaluates*a.b— a dereference of the non-pointer membera.b— which errors. It also stops at[and], so hoveringcina.b[i].cevaluates a broken fragment after the].Fix
Register an
EvaluatableExpressionProviderfor C/C++. Once a provider is registered, VS Code uses it instead of its built-in detection (it does not fall back to the default when the provider returns nothing), so the provider reproduces the built-in behavior for ordinary tokens and additionally fixes the access-chain cases:*/&applies to the whole access chain (the postfix.,->,[]operators bind tighter). It is dropped for an interior member of a.chain, where*a.bwould dereference the structa.b, and kept on the final member and before->(so*ptr->memberis unchanged).::are kept in the token, so members after a subscript (a.b[i].c) and scoped names (ns::var) resolve. Hovering a subscript bracket evaluates the indexed element; hovering inside[...]evaluates the index on its own.The provider is registered during debugger activation (so it also works when cpptools IntelliSense is disabled), and the expression computation lives in a
vscode-free module (evaluatableExpression.ts) with unit tests.Note: I created the code in this PR with the help of an LLM, and tested it manually in VS Code plus with the added unit tests.