Commit e9b1e493 authored by hjk's avatar hjk

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: default avatarDavid Schulz <david.schulz@theqtcompany.com>
Reviewed-by: default avatarChristian Stenger <christian.stenger@theqtcompany.com>
parent 58c326cb
......@@ -285,7 +285,6 @@ class Dumper(DumperBase):
self.autoDerefPointers = int(args.get("autoderef", "0"))
self.partialUpdate = int(args.get("partial", "0"))
self.fallbackQtVersion = 0x50200
self.sortStructMembers = bool(args.get("sortstructs", True))
#warn("NAMESPACE: '%s'" % self.qtNamespace())
#warn("EXPANDED INAMES: %s" % self.expandedINames)
......@@ -1144,6 +1143,7 @@ class Dumper(DumperBase):
if self.currentIName in self.expandedINames:
innerType = None
self.put('sortable="1"')
with Children(self, 1, childType=innerType):
self.putFields(value)
if not self.showQObjectNames:
......@@ -1215,15 +1215,6 @@ class Dumper(DumperBase):
def putFields(self, value, dumpBase = True):
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("FIELDS: %s" % fields)
baseNumber = 0
......@@ -1257,6 +1248,7 @@ class Dumper(DumperBase):
# int (**)(void)
n = 100
self.putType(" ")
self.put('sortgroup="1"')
self.putValue(value[field.name])
self.putNumChild(n)
if self.isExpanded():
......@@ -1280,6 +1272,7 @@ class Dumper(DumperBase):
baseNumber += 1
with UnnamedSubItem(self, "@%d" % baseNumber):
baseValue = value.cast(field.type)
self.put('sortgroup="2"')
self.putBaseClassName(field.name)
self.putAddress(baseValue.address)
self.putItem(baseValue, False)
......
......@@ -1092,6 +1092,7 @@ class Dumper(DumperBase):
self.putQObjectNameValue(value)
if self.currentIName in self.expandedINames:
self.put('sortable="1"')
with Children(self):
self.putFields(value)
if not self.showQObjectNames:
......@@ -1134,8 +1135,6 @@ class Dumper(DumperBase):
baseObject = value.Cast(baseClass)
baseObjects.append(ChildItem(baseClass.GetName(), baseObject))
if self.sortStructMembers:
baseObjects.sort(key = lambda baseObject: str(baseObject.name))
for i in xrange(len(baseObjects)):
baseObject = baseObjects[i]
with UnnamedSubItem(self, "@%d" % (i + 1)):
......@@ -1147,8 +1146,6 @@ class Dumper(DumperBase):
if memberCount > 10000:
memberCount = 10000
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:
# Only needed in the QVariant4 test.
if int(child.GetLoadAddress()) == 0xffffffffffffffff:
......@@ -1169,7 +1166,6 @@ class Dumper(DumperBase):
self.expandedINames = set(args.get('expanded', []))
self.autoDerefPointers = int(args.get('autoderef', '0'))
self.sortStructMembers = bool(args.get('sortstructs', True));
self.useDynamicType = int(args.get('dyntype', '0'))
self.useFancy = int(args.get('fancy', '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"];
foreach (const GdbMi &child, data.children()) {
WatchItem *item = new WatchItem;
item->parse(child);
item->parse(child, sortStructMembers);
const TypeInfo ti = d->m_typeInfoCache.value(item->type);
if (ti.size && !item->size)
item->size = ti.size;
......
......@@ -4596,7 +4596,6 @@ void GdbEngine::doUpdateLocals(const UpdateParameters &params)
cmd.arg("resultvarname", m_resultVarName);
cmd.arg("partialvar", params.partialVariable);
cmd.arg("sortstructs", boolSetting(SortStructMembers));
cmd.callback = CB(handleFetchVariables);
runCommand(cmd);
......
......@@ -793,7 +793,6 @@ void LldbEngine::doUpdateLocals(const UpdateParameters &params)
cmd.arg("autoderef", boolSetting(AutoDerefPointers));
cmd.arg("dyntype", boolSetting(UseDynamicType));
cmd.arg("partialvar", params.partialVariable);
cmd.arg("sortstructs", boolSetting(SortStructMembers));
cmd.arg("qobjectnames", boolSetting(ShowQObjectNames));
StackFrame frame = stackHandler()->currentFrame();
......
......@@ -514,9 +514,10 @@ void PdbEngine::refreshLocals(const GdbMi &vars)
WatchHandler *handler = watchHandler();
handler->resetValueCache();
const bool sortStructMembers = boolSetting(SortStructMembers);
foreach (const GdbMi &child, vars.children()) {
WatchItem *item = new WatchItem;
item->parse(child);
item->parse(child, sortStructMembers);
handler->insertItem(item);
}
......
......@@ -118,6 +118,7 @@ WatchItem::WatchItem() :
bitsize(0),
elided(0),
arrayIndex(-1),
sortGroup(0),
wantsChildren(false),
valueEnabled(true),
valueEditable(true),
......@@ -380,7 +381,18 @@ static void decodeArrayData(WatchItem *item, const QByteArray &rawData,
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();
......@@ -437,6 +449,10 @@ void WatchItem::parseHelper(const GdbMi &input)
if (mi.isValid())
exp = mi.data();
mi = input["sortgroup"];
if (mi.isValid())
sortGroup = mi.toInt();
mi = input["valueenabled"];
if (mi.data() == "true")
valueEnabled = true;
......@@ -500,14 +516,17 @@ void WatchItem::parseHelper(const GdbMi &input)
QByteArray key = subinput["key"].data();
if (!key.isEmpty())
child->name = decodeData(key, subinput["keyencoded"].data());
child->parseHelper(subinput);
child->parseHelper(subinput, maySort);
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();
......@@ -517,7 +536,7 @@ void WatchItem::parse(const GdbMi &data)
else
name = QString::fromLatin1(data["name"].data());
parseHelper(data);
parseHelper(data, maySort);
if (wname.isValid())
exp = name.toUtf8();
......
......@@ -45,7 +45,7 @@ class WatchItem : public Utils::TreeItem
public:
WatchItem();
void parse(const GdbMi &input);
void parse(const GdbMi &input, bool maySort);
bool isLocal() const;
bool isWatcher() const;
......@@ -117,13 +117,14 @@ public:
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 arrayIndex; // -1 if not an array member
uchar sortGroup; // 0 - ordinary member, 1 - vptr, 2 - base class
bool wantsChildren;
bool valueEnabled; // Value will be enabled or not
bool valueEditable; // Value will be editable
bool outdated; // \internal item is to be removed.
private:
void parseHelper(const GdbMi &input);
void parseHelper(const GdbMi &input, bool maySort);
Q_DECLARE_TR_FUNCTIONS(Debugger::Internal::WatchHandler)
};
......
......@@ -1296,7 +1296,7 @@ void tst_Dumpers::dumper()
"python theDumper.setupDumpers()\n"
"run " + nograb + "\n"
"python theDumper.fetchVariables({"
"'token':2,'fancy':1,'forcens':1,'sortstructs':1,"
"'token':2,'fancy':1,'forcens':1,"
"'autoderef':1,'dyntype':1,'passexceptions':1,"
"'qobjectnames':1,"
"'expanded':[" + expandedq + "]})\n";
......@@ -1435,7 +1435,7 @@ void tst_Dumpers::dumper()
context.boostVersion = child["value"].toInt();
else {
WatchItem *item = new WatchItem;
item->parse(child);
item->parse(child, true);
local.appendChild(item);
}
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment