corrade icon indicating copy to clipboard operation
corrade copied to clipboard

Natvis for Corrade types

Open Squareys opened this issue 5 years ago • 2 comments

For displaying Container types more conveniently when debugging in Visual Studio, I created a very very rudimentary .natvis file:

<?xml version="1.0" encoding="utf-8"?> 
<AutoVisualizer xmlns="http://schemas.microsoft.com/vstudio/debugger/natvis/2010">
  <Type Name="Corrade::Containers::Array&lt;*&gt;">
    <DisplayString>{{ size={_size} }}</DisplayString>
    <Expand>
      <ArrayItems>
        <Size>_size</Size>
        <ValuePointer>_data</ValuePointer>
      </ArrayItems>
    </Expand>
  </Type>
  <Type Name="Corrade::Containers::ArrayView&lt;*&gt;">
    <DisplayString>{{ size={_size} }}</DisplayString>
    <Expand>
      <ArrayItems>
        <Size>_size</Size>
        <ValuePointer>_data</ValuePointer>
      </ArrayItems>
    </Expand>
  </Type>
</AutoVisualizer>

Make sure to add it to your CMake project's sources so that Visual Studio picks it up.

Also, see the Documentation of NatVis.

Squareys avatar Jan 12 '21 13:01 Squareys

More relevant links, in case someone wants to explore further -- ideal would be to make them embedded directly into PDBs when building Corrade itself (and then actually installing those as well):

  • https://reviews.llvm.org/D48703
  • https://gitlab.kitware.com/cmake/cmake/-/issues/16874

mosra avatar Jan 12 '21 21:01 mosra

Here's an updated natvis file for most things in Containers 🍌

Haven't quite figured out how to visualize StridedArrayView with dimensions > 1. The natvis format supports a limited way to write your own algorithms, but I'm not desperate enough to try that.

<?xml version="1.0" encoding="utf-8"?>
<AutoVisualizer xmlns="http://schemas.microsoft.com/vstudio/debugger/natvis/2010">
  <!-- Containers::Array -->
  <Type Name="Corrade::Containers::Array&lt;*&gt;">
    <DisplayString>{{ size={_size} }}</DisplayString>
    <Expand>
      <Item Name="[deleter]" ExcludeView="simple" Condition="_deleter != nullptr">_deleter</Item>
      <Synthetic Name="[deleter]" ExcludeView="simple" Condition="_deleter == nullptr">
        <DisplayString>operator delete[]</DisplayString>
      </Synthetic>
      <ArrayItems>
        <Size>_size</Size>
        <ValuePointer>_data</ValuePointer>
      </ArrayItems>
    </Expand>
  </Type>
  <!-- Containers::ArrayView -->
  <Type Name="Corrade::Containers::ArrayView&lt;*&gt;">
    <DisplayString>{{ size={_size} }}</DisplayString>
    <Expand>
      <ArrayItems>
        <Size>_size</Size>
        <ValuePointer>_data</ValuePointer>
      </ArrayItems>
    </Expand>
  </Type>
  <!-- Containers::BitArray -->
  <Type Name="Corrade::Containers::BitArray">
    <Intrinsic Name="offset" Expression="_sizeOffset &amp; 0x07"/>
    <Intrinsic Name="size" Expression="_sizeOffset &gt;&gt; 3"/>
    <DisplayString>{{ size={size()} }}</DisplayString>
    <Expand>
      <Item Name="[deleter]" ExcludeView="simple" Condition="_deleter != nullptr">_deleter</Item>
      <Synthetic Name="[deleter]" ExcludeView="simple" Condition="_deleter == nullptr">
        <DisplayString>operator delete[]</DisplayString>
      </Synthetic>
      <IndexListItems>
        <Size>size()</Size>
        <ValueNode>(bool)(_data[(offset() + $i)/8] &amp; (1 &lt;&lt; ((offset() + $i)%8)))</ValueNode>
      </IndexListItems>
    </Expand>
  </Type>
  <!-- Containers::[Mutable]BitArrayView -->
  <Type Name="Corrade::Containers::BasicBitArrayView&lt;*&gt;">
    <Intrinsic Name="offset" Expression="_sizeOffset &amp; 0x07"/>
    <Intrinsic Name="size" Expression="_sizeOffset &gt;&gt; 3"/>
    <DisplayString>{{ size={size()} }}</DisplayString>
    <Expand>
      <IndexListItems>
        <Size>size()</Size>
        <ValueNode>(bool)(_data[(offset() + $i)/8] &amp; (1 &lt;&lt; ((offset() + $i)%8)))</ValueNode>
      </IndexListItems>
    </Expand>
  </Type>
  <!-- Containers::Optional -->
  <Type Name="Corrade::Containers::Optional&lt;*&gt;">
    <DisplayString Condition="!_set">NullOpt</DisplayString>
    <DisplayString>{_value}</DisplayString>
    <Expand>
      <ExpandedItem Condition="_set">_value</ExpandedItem>
    </Expand>
  </Type>
  <!-- Containers::Pair -->
  <Type Name="Corrade::Containers::Pair&lt;*&gt;">
    <DisplayString IncludeView="noparens">{_first}, {_second}</DisplayString>
    <DisplayString ExcludeView="noparens">({_first}, {_second})</DisplayString>
    <Expand>
      <Item Name="first">_first</Item>
      <Item Name="second">_second</Item>
    </Expand>
  </Type>
  <!-- Containers::Triple -->
  <Type Name="Corrade::Containers::Triple&lt;*&gt;">
    <DisplayString IncludeView="noparens">{_first}, {_second}, {_third}</DisplayString>
    <DisplayString ExcludeView="noparens">({_first}, {_second}, {_third})</DisplayString>
    <Expand>
      <Item Name="first">_first</Item>
      <Item Name="second">_second</Item>
      <Item Name="third">_third</Item>
    </Expand>
  </Type>
  <!-- Containers::Pointer -->
  <Type Name="Corrade::Containers::Pointer&lt;*&gt;">
    <!-- SmartPointer enables extra visualization for the underlying data -->
    <SmartPointer Usage="Minimal">_pointer</SmartPointer>
    <DisplayString Condition="!_pointer">empty</DisplayString>
    <DisplayString>{*_pointer}</DisplayString>
    <Expand>
      <ExpandedItem Condition="_pointer">_pointer</ExpandedItem>
    </Expand>
  </Type>
  <!-- Containers::Reference -->
  <Type Name="Corrade::Containers::Reference&lt;*&gt;">
    <DisplayString>{_reference,na}</DisplayString>
    <Expand>
      <ExpandedItem>_reference</ExpandedItem>
    </Expand>
  </Type>
  <!-- Containers::StaticArray -->
  <Type Name="Corrade::Containers::StaticArray&lt;*&gt;">
    <DisplayString>{{ size={$T1} }}</DisplayString>
    <Expand>
      <ArrayItems>
        <Size>$T1</Size>
        <ValuePointer>_data</ValuePointer>
      </ArrayItems>
    </Expand>
  </Type>
  <!-- Containers::StaticArrayView -->
  <Type Name="Corrade::Containers::StaticArrayView&lt;*&gt;">
    <DisplayString>{{ size={$T1} }}</DisplayString>
    <Expand>
      <ArrayItems>
        <Size>$T1</Size>
        <ValuePointer>_data</ValuePointer>
      </ArrayItems>
    </Expand>
  </Type>
  <!-- Containers::StridedArrayView1D -->
  <Type Name="Corrade::Containers::StridedArrayView&lt;1,*&gt;">
    <DisplayString>{{ size={_size._data[0]} }}</DisplayString>
    <Expand>
      <Item Name="[stride]" ExcludeView="simple">_stride._data[0]</Item>
      <IndexListItems>
        <Size>_size._data[0]</Size>
        <ValueNode>*($T1 *)((char*)(_data) + $i*_stride._data[0])</ValueNode>
      </IndexListItems>
    </Expand>
  </Type>
  <!-- Containers::String -->
  <Type Name="Corrade::Containers::String">
    <Intrinsic Name="isSmall" Expression="(_small.size &amp; 0x80) != 0"/>
    <Intrinsic Name="data" Expression="isSmall() ? _small.data : _large.data"/>
    <Intrinsic Name="size" Expression="isSmall() ? _small.size &amp; ~0x80 : _large.size"/>
    <!-- String is null-terminated, but can include null-characters before the end, so use explicit size -->
    <!-- Display as UTF-8 -->
    <DisplayString>{data(),[size()]s8}</DisplayString>
    <!-- Note: StringView ("Text Visualizer") supports a range but always cuts off at null-characters -->
    <StringView>data(),[size()]s8</StringView>
    <Expand>
      <Item Name="[size]" ExcludeView="simple">size()</Item>
      <Item Name="[deleter]" ExcludeView="simple" Condition="!isSmall() &amp;&amp; _large.deleter != nullptr">_large.deleter</Item>
      <Synthetic Name="[deleter]" ExcludeView="simple" Condition="!isSmall() &amp;&amp; _large.deleter == nullptr">
        <DisplayString>operator delete[]</DisplayString>
      </Synthetic>
      <ArrayItems>
        <Size>size()</Size>
        <ValuePointer>data()</ValuePointer>
      </ArrayItems>
    </Expand>
  </Type>
  <!-- Containers::[Mutable]StringView -->
  <Type Name="Corrade::Containers::BasicStringView&lt;*&gt;">
    <Intrinsic Name="size" Expression="_sizePlusFlags &amp; ~Implementation::StringViewSizeMask"/>
    <Intrinsic Name="flags" Expression="_sizePlusFlags &amp; Implementation::StringViewSizeMask"/>
    <DisplayString>{_data,[size()]s8}</DisplayString>
    <StringView>_data,[size()]s8</StringView>
    <Expand>
      <Item Name="[size]" ExcludeView="simple">size()</Item>
      <Item Name="[null-terminated]" ExcludeView="simple">(flags() &amp; StringViewFlag::NullTerminated) != 0</Item>
      <Item Name="[global]" ExcludeView="simple">(flags() &amp; StringViewFlag::Global) != 0</Item>
      <ArrayItems>
        <Size>size()</Size>
        <ValuePointer>_data</ValuePointer>
      </ArrayItems>
    </Expand>
  </Type>
</AutoVisualizer>

pezcode avatar Jun 09 '22 16:06 pezcode

As of 759e3abcf86cfa1a039c782e739ec2ffdb84c7b1, this file is maintained in src/debuggers/natvis/. Thank you!

mosra avatar Sep 18 '22 10:09 mosra