forked from qt-creator/qt-creator
Debugger: Move struct sorting logic to generic parser
Backends only have to specify whether an object members are sortable in principle (e.g. all structs), and some numeric 'sortgroup' value for member items (higher values are always sorted on top). Change-Id: I10ce94580374fed48a35f058a575a1408d6801af Reviewed-by: David Schulz <david.schulz@theqtcompany.com> Reviewed-by: Christian Stenger <christian.stenger@theqtcompany.com>
This commit is contained in:
@@ -285,7 +285,6 @@ class Dumper(DumperBase):
|
|||||||
self.autoDerefPointers = int(args.get("autoderef", "0"))
|
self.autoDerefPointers = int(args.get("autoderef", "0"))
|
||||||
self.partialUpdate = int(args.get("partial", "0"))
|
self.partialUpdate = int(args.get("partial", "0"))
|
||||||
self.fallbackQtVersion = 0x50200
|
self.fallbackQtVersion = 0x50200
|
||||||
self.sortStructMembers = bool(args.get("sortstructs", True))
|
|
||||||
|
|
||||||
#warn("NAMESPACE: '%s'" % self.qtNamespace())
|
#warn("NAMESPACE: '%s'" % self.qtNamespace())
|
||||||
#warn("EXPANDED INAMES: %s" % self.expandedINames)
|
#warn("EXPANDED INAMES: %s" % self.expandedINames)
|
||||||
@@ -1144,6 +1143,7 @@ class Dumper(DumperBase):
|
|||||||
|
|
||||||
if self.currentIName in self.expandedINames:
|
if self.currentIName in self.expandedINames:
|
||||||
innerType = None
|
innerType = None
|
||||||
|
self.put('sortable="1"')
|
||||||
with Children(self, 1, childType=innerType):
|
with Children(self, 1, childType=innerType):
|
||||||
self.putFields(value)
|
self.putFields(value)
|
||||||
if not self.showQObjectNames:
|
if not self.showQObjectNames:
|
||||||
@@ -1215,15 +1215,6 @@ class Dumper(DumperBase):
|
|||||||
|
|
||||||
def putFields(self, value, dumpBase = True):
|
def putFields(self, value, dumpBase = True):
|
||||||
fields = value.type.fields()
|
fields = value.type.fields()
|
||||||
if self.sortStructMembers:
|
|
||||||
def sortOrder(field):
|
|
||||||
if field.is_base_class:
|
|
||||||
return 0
|
|
||||||
if field.name and field.name.startswith("_vptr."):
|
|
||||||
return 1
|
|
||||||
return 2
|
|
||||||
fields.sort(key = lambda field: "%d%s" % (sortOrder(field), field.name))
|
|
||||||
|
|
||||||
#warn("TYPE: %s" % value.type)
|
#warn("TYPE: %s" % value.type)
|
||||||
#warn("FIELDS: %s" % fields)
|
#warn("FIELDS: %s" % fields)
|
||||||
baseNumber = 0
|
baseNumber = 0
|
||||||
@@ -1257,6 +1248,7 @@ class Dumper(DumperBase):
|
|||||||
# int (**)(void)
|
# int (**)(void)
|
||||||
n = 100
|
n = 100
|
||||||
self.putType(" ")
|
self.putType(" ")
|
||||||
|
self.put('sortgroup="1"')
|
||||||
self.putValue(value[field.name])
|
self.putValue(value[field.name])
|
||||||
self.putNumChild(n)
|
self.putNumChild(n)
|
||||||
if self.isExpanded():
|
if self.isExpanded():
|
||||||
@@ -1280,6 +1272,7 @@ class Dumper(DumperBase):
|
|||||||
baseNumber += 1
|
baseNumber += 1
|
||||||
with UnnamedSubItem(self, "@%d" % baseNumber):
|
with UnnamedSubItem(self, "@%d" % baseNumber):
|
||||||
baseValue = value.cast(field.type)
|
baseValue = value.cast(field.type)
|
||||||
|
self.put('sortgroup="2"')
|
||||||
self.putBaseClassName(field.name)
|
self.putBaseClassName(field.name)
|
||||||
self.putAddress(baseValue.address)
|
self.putAddress(baseValue.address)
|
||||||
self.putItem(baseValue, False)
|
self.putItem(baseValue, False)
|
||||||
|
@@ -1092,6 +1092,7 @@ class Dumper(DumperBase):
|
|||||||
self.putQObjectNameValue(value)
|
self.putQObjectNameValue(value)
|
||||||
|
|
||||||
if self.currentIName in self.expandedINames:
|
if self.currentIName in self.expandedINames:
|
||||||
|
self.put('sortable="1"')
|
||||||
with Children(self):
|
with Children(self):
|
||||||
self.putFields(value)
|
self.putFields(value)
|
||||||
if not self.showQObjectNames:
|
if not self.showQObjectNames:
|
||||||
@@ -1134,8 +1135,6 @@ class Dumper(DumperBase):
|
|||||||
baseObject = value.Cast(baseClass)
|
baseObject = value.Cast(baseClass)
|
||||||
baseObjects.append(ChildItem(baseClass.GetName(), baseObject))
|
baseObjects.append(ChildItem(baseClass.GetName(), baseObject))
|
||||||
|
|
||||||
if self.sortStructMembers:
|
|
||||||
baseObjects.sort(key = lambda baseObject: str(baseObject.name))
|
|
||||||
for i in xrange(len(baseObjects)):
|
for i in xrange(len(baseObjects)):
|
||||||
baseObject = baseObjects[i]
|
baseObject = baseObjects[i]
|
||||||
with UnnamedSubItem(self, "@%d" % (i + 1)):
|
with UnnamedSubItem(self, "@%d" % (i + 1)):
|
||||||
@@ -1147,8 +1146,6 @@ class Dumper(DumperBase):
|
|||||||
if memberCount > 10000:
|
if memberCount > 10000:
|
||||||
memberCount = 10000
|
memberCount = 10000
|
||||||
children = [value.GetChildAtIndex(memberBase + i) for i in xrange(memberCount)]
|
children = [value.GetChildAtIndex(memberBase + i) for i in xrange(memberCount)]
|
||||||
if self.sortStructMembers:
|
|
||||||
children.sort(key = lambda child: str(child.GetName()))
|
|
||||||
for child in children:
|
for child in children:
|
||||||
# Only needed in the QVariant4 test.
|
# Only needed in the QVariant4 test.
|
||||||
if int(child.GetLoadAddress()) == 0xffffffffffffffff:
|
if int(child.GetLoadAddress()) == 0xffffffffffffffff:
|
||||||
@@ -1169,7 +1166,6 @@ class Dumper(DumperBase):
|
|||||||
|
|
||||||
self.expandedINames = set(args.get('expanded', []))
|
self.expandedINames = set(args.get('expanded', []))
|
||||||
self.autoDerefPointers = int(args.get('autoderef', '0'))
|
self.autoDerefPointers = int(args.get('autoderef', '0'))
|
||||||
self.sortStructMembers = bool(args.get('sortstructs', True));
|
|
||||||
self.useDynamicType = int(args.get('dyntype', '0'))
|
self.useDynamicType = int(args.get('dyntype', '0'))
|
||||||
self.useFancy = int(args.get('fancy', '0'))
|
self.useFancy = int(args.get('fancy', '0'))
|
||||||
self.passExceptions = int(args.get('passexceptions', '0'))
|
self.passExceptions = int(args.get('passexceptions', '0'))
|
||||||
|
@@ -2000,10 +2000,12 @@ void DebuggerEngine::updateLocalsView(const GdbMi &all)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const bool sortStructMembers = boolSetting(SortStructMembers);
|
||||||
|
|
||||||
GdbMi data = all["data"];
|
GdbMi data = all["data"];
|
||||||
foreach (const GdbMi &child, data.children()) {
|
foreach (const GdbMi &child, data.children()) {
|
||||||
WatchItem *item = new WatchItem;
|
WatchItem *item = new WatchItem;
|
||||||
item->parse(child);
|
item->parse(child, sortStructMembers);
|
||||||
const TypeInfo ti = d->m_typeInfoCache.value(item->type);
|
const TypeInfo ti = d->m_typeInfoCache.value(item->type);
|
||||||
if (ti.size && !item->size)
|
if (ti.size && !item->size)
|
||||||
item->size = ti.size;
|
item->size = ti.size;
|
||||||
|
@@ -4596,7 +4596,6 @@ void GdbEngine::doUpdateLocals(const UpdateParameters ¶ms)
|
|||||||
|
|
||||||
cmd.arg("resultvarname", m_resultVarName);
|
cmd.arg("resultvarname", m_resultVarName);
|
||||||
cmd.arg("partialvar", params.partialVariable);
|
cmd.arg("partialvar", params.partialVariable);
|
||||||
cmd.arg("sortstructs", boolSetting(SortStructMembers));
|
|
||||||
cmd.callback = CB(handleFetchVariables);
|
cmd.callback = CB(handleFetchVariables);
|
||||||
runCommand(cmd);
|
runCommand(cmd);
|
||||||
|
|
||||||
|
@@ -793,7 +793,6 @@ void LldbEngine::doUpdateLocals(const UpdateParameters ¶ms)
|
|||||||
cmd.arg("autoderef", boolSetting(AutoDerefPointers));
|
cmd.arg("autoderef", boolSetting(AutoDerefPointers));
|
||||||
cmd.arg("dyntype", boolSetting(UseDynamicType));
|
cmd.arg("dyntype", boolSetting(UseDynamicType));
|
||||||
cmd.arg("partialvar", params.partialVariable);
|
cmd.arg("partialvar", params.partialVariable);
|
||||||
cmd.arg("sortstructs", boolSetting(SortStructMembers));
|
|
||||||
cmd.arg("qobjectnames", boolSetting(ShowQObjectNames));
|
cmd.arg("qobjectnames", boolSetting(ShowQObjectNames));
|
||||||
|
|
||||||
StackFrame frame = stackHandler()->currentFrame();
|
StackFrame frame = stackHandler()->currentFrame();
|
||||||
|
@@ -514,9 +514,10 @@ void PdbEngine::refreshLocals(const GdbMi &vars)
|
|||||||
WatchHandler *handler = watchHandler();
|
WatchHandler *handler = watchHandler();
|
||||||
handler->resetValueCache();
|
handler->resetValueCache();
|
||||||
|
|
||||||
|
const bool sortStructMembers = boolSetting(SortStructMembers);
|
||||||
foreach (const GdbMi &child, vars.children()) {
|
foreach (const GdbMi &child, vars.children()) {
|
||||||
WatchItem *item = new WatchItem;
|
WatchItem *item = new WatchItem;
|
||||||
item->parse(child);
|
item->parse(child, sortStructMembers);
|
||||||
handler->insertItem(item);
|
handler->insertItem(item);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -118,6 +118,7 @@ WatchItem::WatchItem() :
|
|||||||
bitsize(0),
|
bitsize(0),
|
||||||
elided(0),
|
elided(0),
|
||||||
arrayIndex(-1),
|
arrayIndex(-1),
|
||||||
|
sortGroup(0),
|
||||||
wantsChildren(false),
|
wantsChildren(false),
|
||||||
valueEnabled(true),
|
valueEnabled(true),
|
||||||
valueEditable(true),
|
valueEditable(true),
|
||||||
@@ -380,7 +381,18 @@ static void decodeArrayData(WatchItem *item, const QByteArray &rawData,
|
|||||||
qDebug() << "ENCODING ERROR: " << encoding.toString();
|
qDebug() << "ENCODING ERROR: " << encoding.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
void WatchItem::parseHelper(const GdbMi &input)
|
static bool sortByName(const Utils::TreeItem *a, const Utils::TreeItem *b)
|
||||||
|
{
|
||||||
|
auto aa = static_cast<const WatchItem *>(a);
|
||||||
|
auto bb = static_cast<const WatchItem *>(b);
|
||||||
|
|
||||||
|
if (aa->sortGroup != bb->sortGroup)
|
||||||
|
return aa->sortGroup > bb->sortGroup;
|
||||||
|
|
||||||
|
return aa->name < bb->name;
|
||||||
|
}
|
||||||
|
|
||||||
|
void WatchItem::parseHelper(const GdbMi &input, bool maySort)
|
||||||
{
|
{
|
||||||
setChildrenUnneeded();
|
setChildrenUnneeded();
|
||||||
|
|
||||||
@@ -437,6 +449,10 @@ void WatchItem::parseHelper(const GdbMi &input)
|
|||||||
if (mi.isValid())
|
if (mi.isValid())
|
||||||
exp = mi.data();
|
exp = mi.data();
|
||||||
|
|
||||||
|
mi = input["sortgroup"];
|
||||||
|
if (mi.isValid())
|
||||||
|
sortGroup = mi.toInt();
|
||||||
|
|
||||||
mi = input["valueenabled"];
|
mi = input["valueenabled"];
|
||||||
if (mi.data() == "true")
|
if (mi.data() == "true")
|
||||||
valueEnabled = true;
|
valueEnabled = true;
|
||||||
@@ -500,14 +516,17 @@ void WatchItem::parseHelper(const GdbMi &input)
|
|||||||
QByteArray key = subinput["key"].data();
|
QByteArray key = subinput["key"].data();
|
||||||
if (!key.isEmpty())
|
if (!key.isEmpty())
|
||||||
child->name = decodeData(key, subinput["keyencoded"].data());
|
child->name = decodeData(key, subinput["keyencoded"].data());
|
||||||
child->parseHelper(subinput);
|
child->parseHelper(subinput, maySort);
|
||||||
appendChild(child);
|
appendChild(child);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (maySort && input["sortable"].toInt())
|
||||||
|
sortChildren(&sortByName);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void WatchItem::parse(const GdbMi &data)
|
void WatchItem::parse(const GdbMi &data, bool maySort)
|
||||||
{
|
{
|
||||||
iname = data["iname"].data();
|
iname = data["iname"].data();
|
||||||
|
|
||||||
@@ -517,7 +536,7 @@ void WatchItem::parse(const GdbMi &data)
|
|||||||
else
|
else
|
||||||
name = QString::fromLatin1(data["name"].data());
|
name = QString::fromLatin1(data["name"].data());
|
||||||
|
|
||||||
parseHelper(data);
|
parseHelper(data, maySort);
|
||||||
|
|
||||||
if (wname.isValid())
|
if (wname.isValid())
|
||||||
exp = name.toUtf8();
|
exp = name.toUtf8();
|
||||||
|
@@ -45,7 +45,7 @@ class WatchItem : public Utils::TreeItem
|
|||||||
public:
|
public:
|
||||||
WatchItem();
|
WatchItem();
|
||||||
|
|
||||||
void parse(const GdbMi &input);
|
void parse(const GdbMi &input, bool maySort);
|
||||||
|
|
||||||
bool isLocal() const;
|
bool isLocal() const;
|
||||||
bool isWatcher() const;
|
bool isWatcher() const;
|
||||||
@@ -117,13 +117,14 @@ public:
|
|||||||
uint bitsize; // Size in case of bit fields
|
uint bitsize; // Size in case of bit fields
|
||||||
int elided; // Full size if value was cut off, -1 if cut on unknown size, 0 otherwise
|
int elided; // Full size if value was cut off, -1 if cut on unknown size, 0 otherwise
|
||||||
int arrayIndex; // -1 if not an array member
|
int arrayIndex; // -1 if not an array member
|
||||||
|
uchar sortGroup; // 0 - ordinary member, 1 - vptr, 2 - base class
|
||||||
bool wantsChildren;
|
bool wantsChildren;
|
||||||
bool valueEnabled; // Value will be enabled or not
|
bool valueEnabled; // Value will be enabled or not
|
||||||
bool valueEditable; // Value will be editable
|
bool valueEditable; // Value will be editable
|
||||||
bool outdated; // \internal item is to be removed.
|
bool outdated; // \internal item is to be removed.
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void parseHelper(const GdbMi &input);
|
void parseHelper(const GdbMi &input, bool maySort);
|
||||||
Q_DECLARE_TR_FUNCTIONS(Debugger::Internal::WatchHandler)
|
Q_DECLARE_TR_FUNCTIONS(Debugger::Internal::WatchHandler)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@@ -1296,7 +1296,7 @@ void tst_Dumpers::dumper()
|
|||||||
"python theDumper.setupDumpers()\n"
|
"python theDumper.setupDumpers()\n"
|
||||||
"run " + nograb + "\n"
|
"run " + nograb + "\n"
|
||||||
"python theDumper.fetchVariables({"
|
"python theDumper.fetchVariables({"
|
||||||
"'token':2,'fancy':1,'forcens':1,'sortstructs':1,"
|
"'token':2,'fancy':1,'forcens':1,"
|
||||||
"'autoderef':1,'dyntype':1,'passexceptions':1,"
|
"'autoderef':1,'dyntype':1,'passexceptions':1,"
|
||||||
"'qobjectnames':1,"
|
"'qobjectnames':1,"
|
||||||
"'expanded':[" + expandedq + "]})\n";
|
"'expanded':[" + expandedq + "]})\n";
|
||||||
@@ -1435,7 +1435,7 @@ void tst_Dumpers::dumper()
|
|||||||
context.boostVersion = child["value"].toInt();
|
context.boostVersion = child["value"].toInt();
|
||||||
else {
|
else {
|
||||||
WatchItem *item = new WatchItem;
|
WatchItem *item = new WatchItem;
|
||||||
item->parse(child);
|
item->parse(child, true);
|
||||||
local.appendChild(item);
|
local.appendChild(item);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user