-
Notifications
You must be signed in to change notification settings - Fork 230
Implement natvis 'na' modifier and $T substitution #1612
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
507e16f
442a1d3
3f38aef
79422c4
42fa4c9
55881f8
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -1283,12 +1283,23 @@ private string FormatValue(string format, IVariableInformation variable, IDictio | |
| if (m.Success) | ||
| { | ||
| string rawExpr = format.Substring(i + 1, m.Length - 2); | ||
| string spec = ExtractFormatSpecifier(rawExpr); | ||
| // Substitute template parameter macros ($T1, $T2, ...) inside the whole brace | ||
| // expression (this covers both the expression and any trailing format specifier) | ||
| if (scopedNames != null) | ||
| { | ||
| rawExpr = Regex.Replace(rawExpr, @"\$T\d+", (Match mt) => | ||
| { | ||
| if (scopedNames.TryGetValue(mt.Value, out string replacement)) | ||
| return replacement; | ||
| return mt.Value; | ||
| }); | ||
| } | ||
| ExtractFormatSpecifier(rawExpr, out bool hasNa); | ||
| string exprValue = GetExpressionValue(rawExpr, variable, scopedNames, intrinsics); | ||
| if (spec == "sub" || spec == "su") | ||
| exprValue = CleanUtf16StringValue(exprValue); | ||
| else if (spec == "sb") | ||
| exprValue = CleanAsciiStringValue(exprValue); | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Did you mean to loose this
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Actually, is
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This problem seems to still be here |
||
| if (hasNa) | ||
| { | ||
| exprValue = VariableInformation.StripLeadingAddress(exprValue); | ||
| } | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Suggestion: Make
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. done |
||
| value.Append(exprValue); | ||
| i += m.Length - 1; | ||
| } | ||
|
|
@@ -1494,30 +1505,40 @@ private static int FindLastTopLevelComma(string expression) | |
| /// <see cref="VariableInformation.ProcessFormatSpecifiers"/>: modifiers "nvo", "na", | ||
| /// "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) | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. done |
||
| { | ||
| hasNa = false; | ||
| int commaPos = FindLastTopLevelComma(expression); | ||
| if (commaPos < 0) return null; | ||
|
|
||
| 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", ""); | ||
| } | ||
|
|
||
| /// <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> | ||
| /// expression (i.e. one evaluated with the <c>,sub</c> / <c>,su</c> format specifier). | ||
| /// GDB and LLDB both prefix the string with the pointer address, e.g. | ||
| /// <c>0x00007fff5fbff6c0 u"Hello"</c> | ||
| /// This method strips the address and the surrounding <c>u"…"</c> quotes so that | ||
| /// the NatVis DisplayString shows just the string content. | ||
| /// 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). | ||
| /// </summary> | ||
| internal static string CleanUtf16StringValue(string value) | ||
| { | ||
| if (string.IsNullOrEmpty(value)) return value; | ||
| // Strip leading "0x<hex> " address prefix emitted by GDB/LLDB. | ||
| value = s_addressPrefix.Replace(value, ""); | ||
| value = VariableInformation.StripLeadingAddress(value); | ||
| // Strip surrounding u"..." or U"..." quotes. | ||
| if (value.Length >= 3 && | ||
| (value.StartsWith("u\"", StringComparison.Ordinal) || value.StartsWith("U\"", StringComparison.Ordinal))) | ||
| if (value.Length >= 3 && (value.StartsWith("u\"", StringComparison.Ordinal) || value.StartsWith("U\"", StringComparison.Ordinal))) | ||
| { | ||
| value = value.EndsWith("\"", StringComparison.Ordinal) | ||
| ? value.Substring(2, value.Length - 3) | ||
|
|
@@ -1531,15 +1552,13 @@ internal static string CleanUtf16StringValue(string value) | |
| /// (i.e. one evaluated with the <c>,sb</c> format specifier). | ||
| /// GDB and LLDB prefix the string with the pointer address, e.g. | ||
| /// <c>0x00007fff5fbff6c0 "Hello"</c> | ||
| /// This method strips the address and the surrounding <c>"…"</c> quotes so that | ||
| /// the NatVis DisplayString shows just the string content (matching VS behaviour, | ||
| /// where <c>{ptr,sb}</c> evaluates to bare text without quotes). | ||
| /// This method strips the leading address prefix that GDB/LLDB emits ("0x... "). | ||
| /// </summary> | ||
| internal static string CleanAsciiStringValue(string value) | ||
| { | ||
| if (string.IsNullOrEmpty(value)) return value; | ||
| // Strip leading "0x<hex> " address prefix emitted by GDB/LLDB. | ||
| value = s_addressPrefix.Replace(value, ""); | ||
| value = VariableInformation.StripLeadingAddress(value); | ||
| // Strip surrounding "..." quotes. | ||
| if (value.Length >= 2 && value.StartsWith("\"", StringComparison.Ordinal)) | ||
| { | ||
|
|
||
There was a problem hiding this comment.
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 byGetExpressionValue, so I don't think you want to do this over the entire expression.Can you trace through why
ReplaceNamesInExpressionisn't doing this already? (lines 1713-1717).There was a problem hiding this comment.
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
There was a problem hiding this comment.
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.