forked from qt-creator/qt-creator
Debugger: tl::expected and Utils::Result dumpers
Added dumpers for `tl::expected` and `Utils::Result` utility classes. Added a basic test. Useless `enum` prefix from CDB enum types (e.g. `enum MyEnum`) will be discarded in tests (credits to @hjk). Note that the include path for the newly added test executable is based on `__FILE__` macro value so it might easily break if the sources are reorganized. Also creating a test for `Utils::Result` is practically impossible within current setup as it is not a header only class, so the test binary must actually link against the correct version of Utils library target. Fixes: QTCREATORBUG-31795 Change-Id: I7f9ccb92d0c59333a2dca4ba928ac991f1e5238b Reviewed-by: hjk <hjk@qt.io>
This commit is contained in:
@@ -369,3 +369,15 @@ def qdump__QmakeProjectManager__QmakePriFileNode(d, value):
|
|||||||
|
|
||||||
def qdump__QmakeProjectManager__QmakeProFileNode(d, value):
|
def qdump__QmakeProjectManager__QmakeProFileNode(d, value):
|
||||||
qdump__ProjectExplorer__FolderNode(d, value)
|
qdump__ProjectExplorer__FolderNode(d, value)
|
||||||
|
|
||||||
|
|
||||||
|
def qdump__Utils__Result(d, value):
|
||||||
|
error, _pad, has_err = value.split('{QString}@b')
|
||||||
|
if has_err:
|
||||||
|
d.putExpandable()
|
||||||
|
d.putValue('Error')
|
||||||
|
if d.isExpanded():
|
||||||
|
with Children(d):
|
||||||
|
d.putSubItem('message', error)
|
||||||
|
else:
|
||||||
|
d.putValue('Ok')
|
||||||
|
@@ -4052,7 +4052,7 @@ typename))
|
|||||||
#self.warn('SEARCHING FOR MEMBER: %s IN %s' % (name, value.type.name))
|
#self.warn('SEARCHING FOR MEMBER: %s IN %s' % (name, value.type.name))
|
||||||
members = self.value_members(value, True)
|
members = self.value_members(value, True)
|
||||||
#self.warn('MEMBERS: %s' % ', '.join(str(m.name) for m in members))
|
#self.warn('MEMBERS: %s' % ', '.join(str(m.name) for m in members))
|
||||||
base = None
|
bases = []
|
||||||
for member in members:
|
for member in members:
|
||||||
#self.warn('CHECKING FIELD %s' % member.name)
|
#self.warn('CHECKING FIELD %s' % member.name)
|
||||||
if member.type.code == TypeCode.Typedef:
|
if member.type.code == TypeCode.Typedef:
|
||||||
@@ -4061,9 +4061,9 @@ typename))
|
|||||||
#self.warn('FOUND MEMBER 1: %s IN %s' % (name, value.type.name))
|
#self.warn('FOUND MEMBER 1: %s IN %s' % (name, value.type.name))
|
||||||
return member
|
return member
|
||||||
if member.isBaseClass:
|
if member.isBaseClass:
|
||||||
base = member
|
bases.append(member)
|
||||||
if self.isCdb:
|
if self.isCdb:
|
||||||
if base is not None:
|
for base in bases:
|
||||||
# self.warn("CHECKING BASE CLASS '%s' for '%s'" % (base.type.name, name))
|
# self.warn("CHECKING BASE CLASS '%s' for '%s'" % (base.type.name, name))
|
||||||
res = self.value_member_by_name(base, name)
|
res = self.value_member_by_name(base, name)
|
||||||
if res is not None:
|
if res is not None:
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
# Copyright (C) 2016 The Qt Company Ltd.
|
# Copyright (C) 2016 The Qt Company Ltd.
|
||||||
# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||||
|
|
||||||
from dumper import Children, SubItem
|
from dumper import Children, SubItem, DumperBase
|
||||||
from utils import TypeCode, DisplayFormat
|
from utils import TypeCode, DisplayFormat
|
||||||
import re
|
import re
|
||||||
|
|
||||||
@@ -586,3 +586,35 @@ def qdump__QtcDumperTest_String(d, value):
|
|||||||
second = d.hexdecode(d.putSubItem('second', value['second']).value)
|
second = d.hexdecode(d.putSubItem('second', value['second']).value)
|
||||||
third = d.hexdecode(d.putSubItem('third', value['third']).value)[:-1]
|
third = d.hexdecode(d.putSubItem('third', value['third']).value)[:-1]
|
||||||
d.putValue(first + ', ' + second + ', ' + third)
|
d.putValue(first + ', ' + second + ', ' + third)
|
||||||
|
|
||||||
|
|
||||||
|
def qdump__tl__expected(d: DumperBase, value: DumperBase.Value):
|
||||||
|
# There are issues with correct type handling for enums and pointer in CDB
|
||||||
|
# preventing type cast from working as expected in these cases
|
||||||
|
|
||||||
|
has_value = False
|
||||||
|
val = {}
|
||||||
|
|
||||||
|
try:
|
||||||
|
has_value = value["m_has_val"].integer() != 0
|
||||||
|
val = value["m_val"] if has_value else value["m_unexpect"]["m_val"]
|
||||||
|
except:
|
||||||
|
okType = value.type[0]
|
||||||
|
errType = value.type[1]
|
||||||
|
|
||||||
|
# Result and error (and a initialized flag) are packed into a union storage
|
||||||
|
largerType = max(okType, errType, key=lambda t: t.size())
|
||||||
|
storage, has_value = value.split(f'{{{largerType.name}}}b')
|
||||||
|
val = storage.cast(okType.name) if has_value else storage.cast(errType.name)
|
||||||
|
|
||||||
|
if has_value:
|
||||||
|
if val.type.name != 'void':
|
||||||
|
d.putExpandable()
|
||||||
|
d.putValue('Expected')
|
||||||
|
else:
|
||||||
|
d.putExpandable()
|
||||||
|
d.putValue('Unexpected')
|
||||||
|
|
||||||
|
if d.isExpanded():
|
||||||
|
with Children(d):
|
||||||
|
d.putSubItem('inner', val)
|
||||||
|
@@ -411,6 +411,7 @@ struct Type
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
QString actualType = simplifyType(actualType0);
|
QString actualType = simplifyType(actualType0);
|
||||||
|
actualType.replace(QRegularExpression("\\benum\\b"), "");
|
||||||
actualType.replace(' ', "");
|
actualType.replace(' ', "");
|
||||||
actualType.replace("const", "");
|
actualType.replace("const", "");
|
||||||
QString expectedType;
|
QString expectedType;
|
||||||
@@ -418,6 +419,7 @@ struct Type
|
|||||||
expectedType = type;
|
expectedType = type;
|
||||||
else
|
else
|
||||||
expectedType = aliasName;
|
expectedType = aliasName;
|
||||||
|
expectedType.replace(QRegularExpression("\\benum\\b"), "");
|
||||||
expectedType.replace(' ', "");
|
expectedType.replace(' ', "");
|
||||||
expectedType.replace("const", "");
|
expectedType.replace("const", "");
|
||||||
expectedType.replace('@', context.nameSpace);
|
expectedType.replace('@', context.nameSpace);
|
||||||
@@ -770,14 +772,16 @@ struct XmlProfile {};
|
|||||||
struct NimProfile {};
|
struct NimProfile {};
|
||||||
|
|
||||||
struct BigArrayProfile {};
|
struct BigArrayProfile {};
|
||||||
|
struct InternalProfile
|
||||||
|
{};
|
||||||
|
|
||||||
class Data
|
class Data
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Data() {}
|
Data() {}
|
||||||
|
|
||||||
Data(const QString &includes, const QString &code, const QString &unused)
|
Data(const QString &preamble, const QString &code, const QString &unused)
|
||||||
: includes(includes), code(code), unused(unused)
|
: preamble(preamble), code(code), unused(unused)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
const Data &operator+(const Check &check) const
|
const Data &operator+(const Check &check) const
|
||||||
@@ -824,7 +828,7 @@ public:
|
|||||||
const Data &operator+(const Profile &profile) const
|
const Data &operator+(const Profile &profile) const
|
||||||
{
|
{
|
||||||
profileExtra += QString::fromUtf8(profile.contents);
|
profileExtra += QString::fromUtf8(profile.contents);
|
||||||
includes += QString::fromUtf8(profile.includes);
|
preamble += QString::fromUtf8(profile.includes);
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1059,6 +1063,13 @@ public:
|
|||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const Data &operator+(InternalProfile) const
|
||||||
|
{
|
||||||
|
const auto parentDir = Utils::FilePath::fromUserInput(__FILE__).parentDir().path();
|
||||||
|
profileExtra += "INCLUDEPATH += " + parentDir + "/../../../src/libs/3rdparty\n";
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
const Data &operator+(const ForceC &) const
|
const Data &operator+(const ForceC &) const
|
||||||
{
|
{
|
||||||
language = Language::C;
|
language = Language::C;
|
||||||
@@ -1108,7 +1119,7 @@ public:
|
|||||||
mutable QString dumperOptions;
|
mutable QString dumperOptions;
|
||||||
mutable QString profileExtra;
|
mutable QString profileExtra;
|
||||||
mutable QString cmakelistsExtra;
|
mutable QString cmakelistsExtra;
|
||||||
mutable QString includes;
|
mutable QString preamble;
|
||||||
mutable QString code;
|
mutable QString code;
|
||||||
mutable QString unused;
|
mutable QString unused;
|
||||||
|
|
||||||
@@ -1594,7 +1605,7 @@ void tst_Dumpers::dumper()
|
|||||||
"\n}\n"
|
"\n}\n"
|
||||||
"\n#endif"
|
"\n#endif"
|
||||||
"\n"
|
"\n"
|
||||||
"\n\n" + data.includes +
|
"\n\n" + data.preamble +
|
||||||
"\n\n" + (data.useQHash ?
|
"\n\n" + (data.useQHash ?
|
||||||
"\n#include <QByteArray>"
|
"\n#include <QByteArray>"
|
||||||
"\n#include <QtGlobal>"
|
"\n#include <QtGlobal>"
|
||||||
@@ -8563,6 +8574,73 @@ void tst_Dumpers::dumper_data()
|
|||||||
+ Check("dir.entryInfoList.1", "[1]", quoted(tempDir + "/.."), "@QFileInfo") % NoCdbEngine
|
+ Check("dir.entryInfoList.1", "[1]", quoted(tempDir + "/.."), "@QFileInfo") % NoCdbEngine
|
||||||
+ Check("dir.entryList.0", "[0]", "\".\"", "@QString") % NoCdbEngine
|
+ Check("dir.entryList.0", "[0]", "\".\"", "@QString") % NoCdbEngine
|
||||||
+ Check("dir.entryList.1", "[1]", "\"..\"", "@QString") % NoCdbEngine;
|
+ Check("dir.entryList.1", "[1]", "\"..\"", "@QString") % NoCdbEngine;
|
||||||
|
|
||||||
|
// clang-format off
|
||||||
|
QTest::newRow("tl__expected") << Data{
|
||||||
|
R"(
|
||||||
|
#include <tl_expected/include/tl/expected.hpp>
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
enum class Test {
|
||||||
|
One,
|
||||||
|
Two,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class ErrCode : std::int8_t {
|
||||||
|
Good,
|
||||||
|
Bad,
|
||||||
|
};
|
||||||
|
|
||||||
|
class MyClass {
|
||||||
|
public:
|
||||||
|
MyClass(int x) : m_x{x} {}
|
||||||
|
|
||||||
|
private:
|
||||||
|
int m_x = 42;
|
||||||
|
};
|
||||||
|
|
||||||
|
static constexpr auto global = 42;
|
||||||
|
)",
|
||||||
|
|
||||||
|
R"(
|
||||||
|
const auto ok_void = tl::expected<void, ErrCode>{};
|
||||||
|
const auto ok_primitive = tl::expected<int, ErrCode>{42};
|
||||||
|
const auto ok_pointer = tl::expected<const int*, ErrCode>{&global};
|
||||||
|
const auto ok_enum = tl::expected<Test, ErrCode>{Test::Two};
|
||||||
|
const auto ok_class = tl::expected<MyClass, ErrCode>{MyClass{10}};
|
||||||
|
|
||||||
|
const auto err_primitive = tl::expected<ErrCode, int>{tl::make_unexpected(42)};
|
||||||
|
const auto err_pointer = tl::expected<ErrCode, const int*>{tl::make_unexpected(&global)};
|
||||||
|
const auto err_enum = tl::expected<ErrCode, ErrCode>{tl::make_unexpected(ErrCode::Bad)};
|
||||||
|
const auto err_class = tl::expected<ErrCode, MyClass>{tl::make_unexpected(MyClass{10})};
|
||||||
|
)",
|
||||||
|
|
||||||
|
"&ok_void, &ok_primitive, &ok_pointer, &ok_enum, &ok_class, &err_primitive, "
|
||||||
|
"&err_pointer, &err_enum, &err_class"
|
||||||
|
}
|
||||||
|
+ CoreProfile{}
|
||||||
|
+ InternalProfile{}
|
||||||
|
+ Check{"ok_void", "Expected", "tl::expected<void, ErrCode>"}
|
||||||
|
+ Check{"ok_primitive", "Expected", "tl::expected<int, ErrCode>"}
|
||||||
|
+ Check{"ok_primitive.inner", "42", "int"}
|
||||||
|
+ Check{"ok_pointer", "Expected", "tl::expected<const int*, ErrCode>"}
|
||||||
|
+ Check{"ok_pointer.inner", "42", "int"}
|
||||||
|
+ Check{"ok_enum", "Expected", "tl::expected<Test, ErrCode>"}
|
||||||
|
+ Check{"ok_enum.inner", "Test::Two (1)", "Test"} % GdbEngine
|
||||||
|
+ Check{"ok_enum.inner", "Two (1)", "Test"} % NoGdbEngine
|
||||||
|
+ Check{"ok_class", "Expected", "tl::expected<MyClass, ErrCode>"}
|
||||||
|
+ Check{"ok_class.inner.m_x", "10", "int"}
|
||||||
|
+ Check{"err_primitive", "Unexpected", "tl::expected<ErrCode, int>"}
|
||||||
|
+ Check{"err_primitive.inner", "42", "int"}
|
||||||
|
+ Check{"err_pointer", "Unexpected", "tl::expected<ErrCode, const int*>"}
|
||||||
|
+ Check{"err_pointer.inner", "42", "int"}
|
||||||
|
+ Check{"err_enum", "Unexpected", "tl::expected<ErrCode, ErrCode>"}
|
||||||
|
+ Check{"err_enum.inner", "ErrCode::Bad (1)", "ErrCode"} % GdbEngine
|
||||||
|
+ Check{"err_enum.inner", "Bad (1)", "ErrCode"} % NoGdbEngine
|
||||||
|
+ Check{"err_class", "Unexpected", "tl::expected<ErrCode, MyClass>"}
|
||||||
|
+ Check{"err_class.inner.m_x", "10", "int"};
|
||||||
|
//clang-format on
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, char *argv[])
|
int main(int argc, char *argv[])
|
||||||
|
Reference in New Issue
Block a user