Skip to content

Implement natvis 'na' modifier and $T substitution - #1612

Open
SachinM123 wants to merge 4 commits into
microsoft:mainfrom
SachinM123:natvisFormatSpecifierFix
Open

Implement natvis 'na' modifier and $T substitution#1612
SachinM123 wants to merge 4 commits into
microsoft:mainfrom
SachinM123:natvisFormatSpecifierFix

Conversation

@SachinM123

Copy link
Copy Markdown
Collaborator

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.

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.
Comment thread src/MIDebugEngine/Engine.Impl/Variables.cs Outdated
Comment thread src/MIDebugEngine/Engine.Impl/Variables.cs Outdated
Comment thread src/MIDebugEngine/Engine.Impl/Variables.cs Outdated

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 $Tn macro substitution over full {...} brace expressions in Natvis display-string formatting.
  • Detect and apply na address-prefix stripping during NatVis display-string formatting and during variable evaluation/initialization by tracking an _formatHasNa flag.
  • 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.

Comment thread src/MIDebugEngine/Natvis.Impl/Natvis.cs
Comment thread src/MIDebugEngine/Natvis.Impl/Natvis.cs
Comment thread src/MIDebugEngine/Natvis.Impl/Natvis.cs Outdated
Comment thread src/MIDebugEngine/Engine.Impl/Variables.cs
Comment thread src/MIDebugEngine/Engine.Impl/Variables.cs Outdated
Comment thread src/MIDebugEngine/Engine.Impl/Variables.cs
Comment thread src/MIDebugEngine/Engine.Impl/Variables.cs Outdated
Comment thread src/MIDebugEngine/Natvis.Impl/Natvis.cs Outdated
return mt.Value;
});
}
bool hasNa = HasNaModifier(rawExpr);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

bool hasNa = HasNaModifier(rawExpr);

Instead of duplicating the work of ExtractFormatSpecifier, have ExtractFormatSpecifier return this as an out param

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

if (spec == "sub" || spec == "su")
exprValue = CleanUtf16StringValue(exprValue);
else if (spec == "sb")
exprValue = CleanAsciiStringValue(exprValue);

@gregg-miskelly gregg-miskelly Jul 22, 2026

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did you mean to loose this sub/su/sb code?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually, is su needed? Variabel.cs line 477 already handles su correctly.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This problem seems to still be here

value = value.EndsWith("\"", StringComparison.Ordinal)
? value.Substring(2, value.Length - 3)
: value.Substring(2);
}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

,sub is supposed to remove the quotes/prefix

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Though this changes looks like it is correct for ,su

return replacement;
return mt.Value;
});
}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If I am reading the code correctly, this is already at least partially done by ReplaceNamesInExpression, which is called by GetExpressionValue, so I don't think you want to do this over the entire expression.

Can you trace through why ReplaceNamesInExpression isn't doing this already? (lines 1713-1717).

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah it seems like ReplaceNamesInExpression should properly handle the substitution, and it seems like it gets called at the right time, so I have no answer for why it isn't doing it already

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should debug through it and see why it doesn't work. Let me know if you need help.

@gregg-miskelly

Copy link
Copy Markdown
Member

Can you add a test for your changes? You may also need to adjust a test baseline for su since the code was doing the wrong thing there.

@SachinM123

Copy link
Copy Markdown
Collaborator Author

Can you add a test for your changes? You may also need to adjust a test baseline for su since the code was doing the wrong thing there.

The test seems to get properly handled via TestDisplayString in NatvisTests to me

TypeName = results.TryFindString("type");
Value = results.TryFindString("value");
// Only strip the leading MI address prefix ("0x... ") when the natvis format included the 'na' modifier.
Value = StripLeadingAddress(Value, _formatHasNa);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

StripLeadingAddress

nit: Either change to:

if (_formatHasNa)
{
   Value = StripLeadingAddress(Value);
}

Or rename to MaybeStripLeadingAddress

And get rid of the comment and extra trailing whitespace

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

if (hasNa && !string.IsNullOrEmpty(exprValue))
{
exprValue = s_addressPrefix.Replace(exprValue, "");
}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggestion: Make VariableInformation.StripLeadingAddress public so you can use it here

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

/// "nr", "nd" are stripped before returning. Returns null when no specifier is present.
/// </summary>
internal static string ExtractFormatSpecifier(string expression)
internal static string ExtractFormatSpecifier(string expression, out bool hasNa)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ExtractFormatSpecifier

You need to update src/MIDebugEngineUnitTests/NatvisFormatSpecifierTest.cs for this change

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

TypeName = results.TryFindString("type");
Value = results.TryFindString("value");
// Only strip the leading MI address prefix ("0x... ") when the natvis format included the 'na' modifier.
Value = StripLeadingAddress(Value, _formatHasNa);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

_formatHasNa

You are reading this before you assigned to it

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

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 expFS = exp.Substring(lastComma + 1).Trim();
// Detect whether the natvis 'na' modifier is present in the original format specifier.
// We must detect this before we strip modifiers below.
_formatHasNa = expFS.IndexOf("na", StringComparison.Ordinal) >= 0;

@gregg-miskelly gregg-miskelly Jul 28, 2026

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

_formatHasNa

Not that it really matters, but to be the same as the rest of the outputs of this function, you want to just assign to the out param (which in all cases currently is just a ref to _formatHasNa, but you want to keep that consistency for the future)

string tail = expression.Substring(commaPos + 1);
return tail.IndexOf("na", StringComparison.Ordinal) >= 0;
}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This method should be deleted in favor of just using ExtractFormatSpecifier

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants