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:
hjk
2016-04-05 11:14:40 +02:00
parent 58c326cb73
commit e9b1e493c2
9 changed files with 37 additions and 27 deletions

View File

@@ -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)

View File

@@ -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'))

View File

@@ -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;

View File

@@ -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);

View File

@@ -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();

View File

@@ -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);
}

View File

@@ -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();

View File

@@ -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)
};

View File

@@ -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);
}
}