Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions src/MIDebugEngine/Natvis.Impl/Natvis.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1440,6 +1440,13 @@ private string GetExpressionValue(string expression, IVariableInformation variab
string processedExpr = ReplaceNamesInExpression(expression, variable, scopedNames);
IVariableInformation expressionVariable = new VariableInformation(processedExpr, variable, _process.Engine, null);
expressionVariable.SyncEval();

// Avoid recursive natvis formatting when expression is 'this'
if (expression.Trim() == "this")
{
return expressionVariable.Value;
}

return FormatDisplayString(expressionVariable).value;
}

Expand Down
45 changes: 43 additions & 2 deletions test/CppTests/Tests/NatvisTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,8 @@ public NatvisTests(ITestOutputHelper outputHelper) : base(outputHelper)
private const string NatvisSourceName = "main.cpp";

// These line numbers will need to change if src/natvis/main.cpp changes
private const int SimpleClassAssignmentLine = 64;
private const int ReturnSourceLine = 76;
private const int SimpleClassAssignmentLine = 65;
private const int ReturnSourceLine = 80;

[Theory]
[RequiresTestSettings]
Expand Down Expand Up @@ -397,6 +397,47 @@ public void TestThisConditional(ITestSettings settings)
}
}

[Theory]
[DependsOnTest(nameof(CompileNatvisDebuggee))]
[RequiresTestSettings]
public void TestThisInDisplayString(ITestSettings settings)
{
this.TestPurpose("This test checks that {this} in a DisplayString value does not produce extra braces.");
this.WriteSettings(settings);

IDebuggee debuggee = Debuggee.Open(this, settings.CompilerSettings, NatvisName, DebuggeeMonikers.Natvis.Default);

using (IDebuggerRunner runner = CreateDebugAdapterRunner(settings))
{
this.Comment("Configure launch");
string visFile = Path.Join(debuggee.SourceRoot, "visualizer_files", "Simple.natvis");

LaunchCommand launch = new LaunchCommand(settings.DebuggerSettings, debuggee.OutputPath, visFile, false);
runner.RunCommand(launch);

this.Comment("Set Breakpoint");
SourceBreakpoints writerBreakpoints = debuggee.Breakpoints(NatvisSourceName, ReturnSourceLine);
runner.SetBreakpoints(writerBreakpoints);

runner.Expects.StoppedEvent(StoppedReason.Breakpoint).AfterConfigurationDone();

using (IThreadInspector threadInspector = runner.GetThreadInspector())
{
IFrameInspector currentFrame = threadInspector.Stack.First();

this.Comment("Verifying {this} in DisplayString does not recurse");
var dpPtr = currentFrame.GetVariable("dpPtr");

// Natvis: <DisplayString>{{ {this}={*this} }}</DisplayString>
// Expected: "{ 0x<hex_address>=42 }" — {this} is the raw address, {*this} is the dereferenced value
Assert.Matches(@"^\{ 0x[0-9a-fA-F]+=42 \}$", dpPtr.Value);
}

runner.Expects.ExitedEvent(exitCode: 0).TerminatedEvent().AfterContinue();
runner.DisconnectAndVerify();
}
}

[Theory]
[DependsOnTest(nameof(CompileNatvisDebuggee))]
[RequiresTestSettings]
Expand Down
5 changes: 5 additions & 0 deletions test/CppTests/debuggees/natvis/src/DataPoint.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
struct DataPoint
{
int value;
DataPoint(int v) : value(v) {}
};
4 changes: 4 additions & 0 deletions test/CppTests/debuggees/natvis/src/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#include "SimpleClass.h"
#include "SimpleMatrix.h"
#include "SimpleTemplated.h"
#include "DataPoint.h"

class SimpleDisplayObject
{
Expand Down Expand Up @@ -73,5 +74,8 @@ int main(int argc, char** argv)
HideRawViewObject hideRawObj;
ShowRawViewObject showRawObj;

DataPoint dp(42);
DataPoint *dpPtr = &dp;

return 0;
}
Original file line number Diff line number Diff line change
Expand Up @@ -113,4 +113,12 @@
</Expand>
</Type>

<Type Name="DataPoint">
<DisplayString>{value}</DisplayString>
</Type>

<Type Name="DataPoint *">
<DisplayString>{{ {this}={*this} }}</DisplayString>
</Type>

</AutoVisualizer>
Loading