Implement natvis 'na' modifier and $T substitution - #1612
Conversation
Add support for the natvis 'na' (no-address) modifier to strip MI's leading address prefix from string values. This requires tracking the format specifier through variable initialization and applying cleanup at value retrieval points. Also implement template parameter substitution ($T1, $T2, etc.) within natvis brace expressions before format specifier extraction.
There was a problem hiding this comment.
Pull request overview
This PR extends MIEngine’s NatVis evaluator to (1) support the na (no-address) modifier by stripping MI’s leading 0x... address prefix from certain evaluated values, and (2) perform $T1, $T2, … template-parameter substitution inside NatVis brace expressions before parsing format specifiers.
Changes:
- Add
$Tnmacro substitution over full{...}brace expressions in Natvis display-string formatting. - Detect and apply
naaddress-prefix stripping during NatVis display-string formatting and during variable evaluation/initialization by tracking an_formatHasNaflag. - Update NatVis string “cleanup” helpers and related comments around address-prefix stripping behavior.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 4 comments.
| File | Description |
|---|---|
| src/MIDebugEngine/Natvis.Impl/Natvis.cs | Adds $Tn substitution in brace expressions and introduces na detection/cleanup in display-string formatting; updates format-specifier helpers and string cleanup docs. |
| src/MIDebugEngine/Engine.Impl/Variables.cs | Tracks na in parsed format specifiers and attempts to strip MI’s address prefix at variable construction/evaluation time. |
|
Can you add a test for your changes? You may also need to adjust a test baseline for |
The test seems to get properly handled via TestDisplayString in NatvisTests to me |
match tests with out param from extractformatspecifier made VariableInformation.StripLeadingAddress internal static to make public and updated natvis.cs accordingly changed _formathasna to inherit properly and call stripleadingaddress more strictly
| string tail = expression.Substring(commaPos + 1).Trim(); | ||
| hasNa = tail.IndexOf("na", StringComparison.Ordinal) >= 0; | ||
|
|
||
| return expression.Substring(commaPos + 1).Trim() |
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 3 out of 3 changed files in this pull request and generated 2 comments.
Suppressed comments (5)
src/MIDebugEngine/Natvis.Impl/Natvis.cs:1521
- There is an extra standalone XML
<summary>block immediately beforeCleanUtf16StringValuewhich results in back-to-back<summary>tags. This will produce malformed/incorrect XML documentation. Either remove the orphaned summary or convert it into a proper doc comment on a real member (or merge it into the existingExtractFormatSpecifierdocs).
/// <summary>
/// Returns true if the NatVis expression's trailing format specifier (the part after the
/// last top-level comma) contains the "na" modifier. This intentionally inspects the
/// raw specifier text and does not normalize/remove modifiers so callers can detect
/// whether the original expression asked for the "na" behavior.
/// </summary>
/// <summary>
/// Cleans up the raw value that GDB/LLDB returns for a <c>const char16_t*</c>
src/MIDebugEngine/Natvis.Impl/Natvis.cs:1526
- The updated doc comment for
CleanUtf16StringValuesays it does NOT remove surrounding quotes or theu/Uprefix, but the method still strips both (it removes theu\"/U\"prefix and the trailing\", then returns the substring). Please update the comment to match the actual behavior, or adjust the implementation if the new behavior is intended.
/// This method strips the leading address prefix that GDB/LLDB emits ("0x... ").
/// It does NOT remove surrounding quotes or the leading character-width prefix (u/U).
src/MIDebugEngine/Natvis.Impl/Natvis.cs:1536
- The updated doc comment for
CleanUtf16StringValuesays it does NOT remove surrounding quotes or theu/Uprefix, but the method still strips both (it removes theu\"/U\"prefix and the trailing\", then returns the substring). Please update the comment to match the actual behavior, or adjust the implementation if the new behavior is intended.
if (value.Length >= 3 && (value.StartsWith("u\"", StringComparison.Ordinal) || value.StartsWith("U\"", StringComparison.Ordinal)))
{
value = value.EndsWith("\"", StringComparison.Ordinal)
src/MIDebugEngine/Natvis.Impl/Natvis.cs:1511
- The
nadetection/removal is substring-based (IndexOf(\"na\")/.Replace(\"na\", \"\")), which can create false positives and/or corrupt specifiers that legitimately containnaas part of another token (e.g., a function/identifier containingna). Consider parsing known Natvis modifiers as actual modifiers (e.g., stripping only recognized modifier sequences at the end of the specifier) rather than removing arbitrarynasubstrings anywhere in the specifier text.
string tail = expression.Substring(commaPos + 1).Trim();
hasNa = tail.IndexOf("na", StringComparison.Ordinal) >= 0;
return expression.Substring(commaPos + 1).Trim()
.Replace("nvo", "").Replace("na", "").Replace("nr", "").Replace("nd", "");
src/MIDebugEngine/Engine.Impl/Variables.cs:106
- The new
StripLeadingAddressbehavior is central to thenamodifier, but there’s no unit coverage shown here for typical MI string shapes (e.g.,0x0123 \"Hello\",0x0123 u\"Hello\", values without an address prefix, and address-only values). Adding focused unit tests forStripLeadingAddress(and at least one integration-style test demonstratingnaaffecting a formatted Natvis expression) would help prevent regressions.
internal static string StripLeadingAddress(string value)
{
if (string.IsNullOrEmpty(value))
{
return value;
}
return s_naPattern.Replace(value, "$1");
}
Add support for the natvis 'na' (no-address) modifier to strip MI's leading address prefix from string values. This requires tracking the format specifier through variable initialization and applying cleanup at value retrieval points.
Also implement template parameter substitution ($T1, $T2, etc.) within natvis brace expressions before format specifier extraction.