0

I want to create a natvis for QObject. There are dynamic properties concepts, which stored in form

  QList<QByteArray> propertyNames;
  QVector<QVariant> propertyValues;

and I want to group them and visualize as a map(key-value items).

My natvis is pretty simple (for illustration purposes, I replaced all complex logic of getting data from QList and QVector with _GetNameAsVoidPtr and _GetValueAsVoidPtr):

<Type Name="QObject">
  ...
  <Synthetic Name="dynamic_properties">
    <DisplayString>{{ size = {propertyNames.d-&gt;end - propertyNames.d-&gt;begin} }}</DisplayString>
    <Expand>
      <CustomListItems>
        <Variable Name="index" InitialValue="0" />
        <Variable Name="size" InitialValue="propertyNames.d-&gt;end - propertyNames.d-&gt;begin" />
        <Loop>
          <Break Condition="index >= size" />
          <Item Name="[{index}] {*reinterpret_cast&lt;const QByteArray*&gt;(_GetNameAsVoidPtr(index))}">
            {*reinterpret_cast&lt;const QVariant*&gt;(_GetValueAsVoidPtr(index))}
          </Item>
          <Exec>++index</Exec>
        </Loop>
      </CustomListItems>
    </Expand>
  </Synthetic>
  ...
</Type>

I get the following error:

Natvis: QObject.natvis(217,21): Error: constant "QByteArray" is not a type name
    Error while evaluating '*reinterpret_cast<const QByteArray*>(_GetNameAsVoidPtr(index))' in the context of type 'Qt5Cored.dll!QObject'.
Natvis: QObject.natvis(217,21): Error: constant "QVariant" is not a type name
    Error while evaluating '*reinterpret_cast<const QVariant*>(_GetValueAsVoidPtr(index))' in the context of type 'Qt5Widgetsd.dll!QObject'.

I tried to replace reinterpret_cast&lt;const QByteArray*&gt; with reinterpret_cast&lt;const Qt5Cored.dll::QByteArray*&gt;, removed const and other things - nothing worked. Then I printed these values in VS-Watch window and get the following picture: TypesEnums

And here I realised, that Qt has classes: class QByteArray and class QVariant, also, it has enum QMetaType::Type with values QByteArray and QVariant. In most places, natvis use types as-is(as you type them in xml), but for some reason, inside CustomListItems section, it adds the module name in the front of all types.

So, instead of QByteArray and QVariant, it treat them as ModuleName.dll!QByteArray and ModuleName.dll!QVariant. The same for QString, for instance. And as you can see on screenshot from Watch window, Visual studio interpet classes with explicit ModuleName.dll prefix as enum-values(not classes).

It there any way to to specify explicitly that QVariant is a class, not an enum?

I tried to add double colons(::QVariant) or "class" keyword(class QVariant) - does not work :(

I have some ideas how to workaround that issue(if some of them work - i will reply), but first of all, I am curios is there proper way, to tell compiler that it is a class-name?

2 Answers 2

0

If you install Qt Visual Studio Tools add-in, it will automatically install qt5.natvis and qt6.natvis. You can also download qt5.natvis and qt6.natvis, and add them to your project.

As for the error. When your natvis is loaded, QByteArray and QTVariant typs are unknown. You can't use them in expressions.

Sign up to request clarification or add additional context in comments.

2 Comments

I use qt5.natvis, and it's overlight, so I decided to create my own, at least for QObject, QWidget, QLayout(I'm working on it now). I am 100% sure that "QByteArray", "QVariant" and other types already known at the moment of natvis reload. If you statement were true, the error had to be something like Error: identifier "QByteArray" is undefined. In my case, the error says constant "QByteArray" is not a type name. I even provided a screenshot from VS, where you can see, that it knows QVariant class, but it thinks that Qt5Core.dll!QVariant - is QMetaType::Type::QVariant enum value.
"When your natvis is loaded, QByteArray and QTVariant typs are unknown." - This isn't correct. Type lookups are done via queries to the PDB. If you dump the UDT table you'll find that those types are present. The debugger is not a C++ compiler frontend and the rules for expression evaluation are distinctly different.
0

As a workaround, I used QVector::operator[] for extracting values. Fortunately, this function not optimized and has no side-effects(I am afraid it will not work in Release mode, will test it later).

Tried to do the same for names with QList::operator[] and QList::at(), but get errors:

Natvis: QObject.natvis(222,131): Error: no operator "[]" matches these operands

Error while evaluating 'this->extraData->propertyNames[index]' in the context of type 'Qt5Widgetsd.dll!QObjectPrivate'. Natvis: QObject.natvis(222,131): Error: Function QList::at has no address, possibly due to compiler optimizations.

Error while evaluating 'this->extraData->propertyNames.at(index)' in the context of type 'Qt5Widgetsd.dll!QObjectPrivate'.

So, I decided to copy-paste logic from QByteArray qt5.natvis and convert it to const char*:

<Type Name="QObjectPrivate" Inheritable="true">
  ...
  <Synthetic Name="dynamic_properties">
    <DisplayString Condition="this-&gt;extraData == nullptr">{{ size = 0 }}</DisplayString>
    <DisplayString>{{ size = {this-&gt;extraData-&gt;propertyNames.d-&gt;end - this-&gt;extraData-&gt;propertyNames.d-&gt;begin} }}</DisplayString>
    <Expand>
      <CustomListItems MaxItemsPerView="25">
        <Variable Name="index" InitialValue="0" />
        <Variable Name="size"
                  InitialValue="this-&gt;extraData-&gt;propertyNames.d-&gt;end - this-&gt;extraData-&gt;propertyNames.d-&gt;begin" />
        <Variable Name="p_property_name_byte_array"
                  InitialValue="reinterpret_cast&lt;const char* const*&gt;(this-&gt;extraData-&gt;propertyNames.d-&gt;array)
                                + this-&gt;extraData-&gt;propertyNames.d-&gt;begin" />
        <Loop>
          <Break Condition="index >= size" />
          <Item Name="[{index}] {*p_property_name_byte_array +
                      reinterpret_cast&lt;const QTypedArrayData&lt;char&gt;*&gt;(*p_property_name_byte_array)-&gt;offset,sb}">
            this-&gt;extraData-&gt;propertyValues[index]
          </Item>
          <Exec>++index</Exec>
          <Exec>++p_property_name_byte_array</Exec>
        </Loop>
      </CustomListItems>
    </Expand>
  </Synthetic>
  ...
</Type>

It looks as I expected:

dynamic_properties_visualization

But my question is still relevant. Is there a way to convince visual_studio/natvis that QVariant is a typename, not a QMetaType::Type::QVariant.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.