Skip to content
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

User Story 1556891: [MIEngine Natvis] Support multi-dimensional arrays #1346

Merged
merged 13 commits into from
Sep 9, 2022
85 changes: 82 additions & 3 deletions src/MIDebugEngine/Natvis.Impl/Natvis.cs
Original file line number Diff line number Diff line change
Expand Up @@ -577,9 +577,39 @@ private IVariableInformation[] ExpandVisualized(IVariableInformation variable)
{
continue;
}

uint totalSize = 0;
string val = GetExpressionValue(item.Size, variable, visualizer.ScopedNames);
totalSize = MICore.Debugger.ParseUint(val, throwOnError: true);
int rank = 0;
uint[] dimensions = null;

if (!string.IsNullOrEmpty(item.Rank))
{
totalSize = 1;
if (!int.TryParse(item.Rank, NumberStyles.None, CultureInfo.InvariantCulture, out rank))
{
string expressionValue = GetExpressionValue(item.Rank, variable, visualizer.ScopedNames);
rank = Int32.Parse(expressionValue, CultureInfo.InvariantCulture);
}
if (rank <= 0)
{
throw new Exception("Invalid rank value");
gregg-miskelly marked this conversation as resolved.
Show resolved Hide resolved
}
dimensions = new uint[rank];
gc46 marked this conversation as resolved.
Show resolved Hide resolved
for (int idx = 0; idx < rank; idx++)
{
// replace $i with Item.Rank here before passing it into GetExpressionValue
string substitute = item.Size.Replace("$i", idx.ToString(CultureInfo.InvariantCulture));
string val = GetExpressionValue(substitute, variable, visualizer.ScopedNames);
uint tmp = MICore.Debugger.ParseUint(val, throwOnError: true);
dimensions[idx] = tmp;
totalSize *= tmp;
}
}
else
{
string val = GetExpressionValue(item.Size, variable, visualizer.ScopedNames);
totalSize = MICore.Debugger.ParseUint(val, throwOnError: true);
}

uint startIndex = 0;
if (variable is PaginatedVisualizerWrapper pvwVariable)
Expand Down Expand Up @@ -624,10 +654,17 @@ private IVariableInformation[] ExpandVisualized(IVariableInformation variable)
if (arrayExpr.CountChildren != 0)
{
uint offset = startIndex + requestedSize;
bool isForward = item.Direction != ArrayDirectionType.Backward;

for (uint index = 0; index < requestedSize; ++index)
{
children.Add(new SimpleWrapper("[" + (startIndex + index).ToString(CultureInfo.InvariantCulture) + "]", _process.Engine, arrayExpr.Children[index]));
string displayName = (startIndex + index).ToString(CultureInfo.InvariantCulture);
if (rank > 1)
{
displayName = GetDisplayNameFromArrayIndex(index, rank, dimensions, isForward);
}

children.Add(new SimpleWrapper("[" + displayName + "]", _process.Engine, arrayExpr.Children[index]));
}

if (totalSize > offset)
Expand Down Expand Up @@ -1286,5 +1323,47 @@ private string GetExpressionValue(string expression, IVariableInformation variab
expressionVariable.SyncEval();
return FormatDisplayString(expressionVariable).value;
}

private string GetDisplayNameFromArrayIndex(uint arrayIndex, int rank, uint[] dimensions, bool isForward)
{
StringBuilder displayName = new StringBuilder();
uint index = arrayIndex;

int i = rank - 1;
int inc = -1;
int endLoop = -1;

if (!isForward)
{
i = 0;
inc = 1;
endLoop = rank;
}

uint[] indices = new uint[rank];

while (i != endLoop)
{
uint dimensionSize = dimensions[i];
uint divResult = index / dimensionSize;
uint modResult = index % dimensionSize;

indices[i] = modResult;
index = divResult;

i += inc;
}

string format = _process.Engine.CurrentRadix() == 16 ? "0x{0:X}" : "{0:D}";
displayName.AppendFormat(CultureInfo.InvariantCulture, format, indices[0]);
for (i = 1; i < rank; i++)
{
displayName.Append(',');
displayName.AppendFormat(CultureInfo.InvariantCulture, format, indices[i]);
}

return displayName.ToString();
}

}
}
6 changes: 5 additions & 1 deletion test/CppTests/Tests/NatvisTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ public NatvisTests(ITestOutputHelper outputHelper) : base(outputHelper)

private const string NatvisName = "natvis";
private const string NatvisSourceName = "main.cpp";
private const int ReturnSourceLine = 48;
private const int ReturnSourceLine = 51;

[Theory]
[RequiresTestSettings]
Expand Down Expand Up @@ -175,6 +175,10 @@ public void TestArrayItems(ITestSettings settings)
// Index element for ArrayItems
Assert.Equal("20", ll.GetVariable("[5]").Value);
Assert.Equal("51", ll.GetVariable("[More...]").GetVariable("[51]").Value);

// Multi-dimensional array
var matrix = currentFrame.GetVariable("matrix");
Assert.Equal("3", matrix.GetVariable("[1,1]").Value);
}

runner.Expects.ExitedEvent(exitCode: 0).TerminatedEvent().AfterContinue();
Expand Down
27 changes: 27 additions & 0 deletions test/CppTests/debuggees/natvis/src/SimpleMatrix.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
class SimpleMatrix
{
public:
int m_size1;
int m_size2;
bool m_fUseSize1;
int* m_pData;

SimpleMatrix(int size1, int size2, bool fUseSize1)
{
m_size1 = size1;
m_size2 = size2;
m_fUseSize1 = fUseSize1;

m_pData = new int[GetSize()];

for (int i = 0; i < GetSize(); i++)
{
m_pData[i] = i;
}
}

int GetSize()
{
return m_fUseSize1 ? m_size1 : m_size2;
}
};
3 changes: 3 additions & 0 deletions test/CppTests/debuggees/natvis/src/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
#include "SimpleVector.h"
#include "SimpleArray.h"
#include "SimpleClass.h"
#include "SimpleMatrix.h"

class SimpleDisplayObject
{
Expand Down Expand Up @@ -45,5 +46,7 @@ int main(int argc, char** argv)
SimpleClass* simpleClass = nullptr;
simpleClass = new SimpleClass();

SimpleMatrix matrix(5, 8, false);

return 0;
}
12 changes: 12 additions & 0 deletions test/CppTests/debuggees/natvis/src/visualizer_files/Simple.natvis
Original file line number Diff line number Diff line change
Expand Up @@ -57,4 +57,16 @@
</TreeItems>
</Expand>
</Type>

<Type Name="SimpleMatrix">
<DisplayString>SimpleMatrix</DisplayString>
<Expand>
<ArrayItems>
<Direction>Forward</Direction>
<Rank>2</Rank>
<Size>($i == 1) ? 2 : m_size2/2</Size>
<ValuePointer>m_pData</ValuePointer>
</ArrayItems>
</Expand>
</Type>
</AutoVisualizer>