diff --git a/src/MIDebugEngine/Natvis.Impl/Natvis.cs b/src/MIDebugEngine/Natvis.Impl/Natvis.cs index 63f32693c..9927883c9 100755 --- a/src/MIDebugEngine/Natvis.Impl/Natvis.cs +++ b/src/MIDebugEngine/Natvis.Impl/Natvis.cs @@ -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"); + } + dimensions = new uint[rank]; + 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) @@ -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) @@ -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(); + } + } } diff --git a/test/CppTests/Tests/NatvisTests.cs b/test/CppTests/Tests/NatvisTests.cs index 918e4cadb..37bc46b8f 100644 --- a/test/CppTests/Tests/NatvisTests.cs +++ b/test/CppTests/Tests/NatvisTests.cs @@ -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] @@ -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(); diff --git a/test/CppTests/debuggees/natvis/src/SimpleMatrix.h b/test/CppTests/debuggees/natvis/src/SimpleMatrix.h new file mode 100644 index 000000000..e315e749b --- /dev/null +++ b/test/CppTests/debuggees/natvis/src/SimpleMatrix.h @@ -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; + } +}; \ No newline at end of file diff --git a/test/CppTests/debuggees/natvis/src/main.cpp b/test/CppTests/debuggees/natvis/src/main.cpp index 9feefd6bd..8cc695507 100644 --- a/test/CppTests/debuggees/natvis/src/main.cpp +++ b/test/CppTests/debuggees/natvis/src/main.cpp @@ -3,6 +3,7 @@ #include "SimpleVector.h" #include "SimpleArray.h" #include "SimpleClass.h" +#include "SimpleMatrix.h" class SimpleDisplayObject { @@ -45,5 +46,7 @@ int main(int argc, char** argv) SimpleClass* simpleClass = nullptr; simpleClass = new SimpleClass(); + SimpleMatrix matrix(5, 8, false); + return 0; } \ No newline at end of file diff --git a/test/CppTests/debuggees/natvis/src/visualizer_files/Simple.natvis b/test/CppTests/debuggees/natvis/src/visualizer_files/Simple.natvis index 4a2fb05da..0c3df50fb 100644 --- a/test/CppTests/debuggees/natvis/src/visualizer_files/Simple.natvis +++ b/test/CppTests/debuggees/natvis/src/visualizer_files/Simple.natvis @@ -57,4 +57,16 @@ + + + SimpleMatrix + + + Forward + 2 + ($i == 1) ? 2 : m_size2/2 + m_pData + + + \ No newline at end of file