forked from qt-creator/qt-creator
Great debugger helper bug fixing spree.
- Fix extractTemplate() not to kill blanks in case there is no blank after a comma, fix hardcoded types accordingly. - Make niceType()'s regexps ignore blanks after commas, add unsigned short as char_type and cache the mappings, making them work for CDB. - CDB: Parse map output of dumpers correctly, generally don't confuse the parser by unknown keywords encountered when parsing children, thus enabling simple QMap types. - Make dumpInnerValueHelper output std::string types.
This commit is contained in:
@@ -844,6 +844,26 @@ static void qDumpUnknown(QDumper &d, const char *why = 0)
|
||||
d.disarm();
|
||||
}
|
||||
|
||||
static inline void dumpStdStringValue(QDumper &d, const std::string &str)
|
||||
{
|
||||
d.beginItem("value");
|
||||
d.putBase64Encoded(str.c_str(), str.size());
|
||||
d.endItem();
|
||||
d.putItem("valueencoded", "1");
|
||||
d.putItem("type", "std::string");
|
||||
d.putItem("numchild", "0");
|
||||
}
|
||||
|
||||
static inline void dumpStdWStringValue(QDumper &d, const std::wstring &str)
|
||||
{
|
||||
d.beginItem("value");
|
||||
d.putBase64Encoded((const char *)str.c_str(), str.size() * sizeof(wchar_t));
|
||||
d.endItem();
|
||||
d.putItem("valueencoded", (sizeof(wchar_t) == 2 ? "2" : "3"));
|
||||
d.putItem("type", "std::wstring");
|
||||
d.putItem("numchild", "0");
|
||||
}
|
||||
|
||||
static void qDumpInnerValueHelper(QDumper &d, const char *type, const void *addr,
|
||||
const char *field = "value")
|
||||
{
|
||||
@@ -928,6 +948,16 @@ static void qDumpInnerValueHelper(QDumper &d, const char *type, const void *addr
|
||||
d.putItem(field, *(QString*)addr);
|
||||
}
|
||||
return;
|
||||
case 't':
|
||||
if (isEqual(type, "std::string")
|
||||
|| isEqual(type, "std::basic_string<char,std::char_traits<char>,std::allocator<char> >")) {
|
||||
d.putCommaIfNeeded();
|
||||
dumpStdStringValue(d, *reinterpret_cast<const std::string*>(addr));
|
||||
} else if (isEqual(type, "std::wstring")
|
||||
|| isEqual(type, "std::basic_string<unsigned short,std::char_traits<unsigned short>,std::allocator<unsigned short> >")) {
|
||||
dumpStdWStringValue(d, *reinterpret_cast<const std::wstring*>(addr));
|
||||
}
|
||||
return;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
@@ -944,7 +974,6 @@ static void qDumpInnerValue(QDumper &d, const char *type, const void *addr)
|
||||
qDumpInnerValueHelper(d, type, addr);
|
||||
}
|
||||
|
||||
|
||||
static void qDumpInnerValueOrPointer(QDumper &d,
|
||||
const char *type, const char *strippedtype, const void *addr)
|
||||
{
|
||||
@@ -2753,37 +2782,28 @@ static void qDumpStdString(QDumper &d)
|
||||
{
|
||||
const std::string &str = *reinterpret_cast<const std::string *>(d.data);
|
||||
|
||||
if (!str.empty()) {
|
||||
const std::string::size_type size = str.size();
|
||||
if (int(size) < 0)
|
||||
return;
|
||||
if (size) {
|
||||
qCheckAccess(str.c_str());
|
||||
qCheckAccess(str.c_str() + str.size() - 1);
|
||||
qCheckAccess(str.c_str() + size - 1);
|
||||
}
|
||||
|
||||
d.beginItem("value");
|
||||
d.putBase64Encoded(str.c_str(), str.size());
|
||||
d.endItem();
|
||||
d.putItem("valueencoded", "1");
|
||||
d.putItem("type", "std::string");
|
||||
d.putItem("numchild", "0");
|
||||
|
||||
dumpStdStringValue(d, str);
|
||||
d.disarm();
|
||||
}
|
||||
|
||||
static void qDumpStdWString(QDumper &d)
|
||||
{
|
||||
const std::wstring &str = *reinterpret_cast<const std::wstring *>(d.data);
|
||||
|
||||
if (!str.empty()) {
|
||||
const std::wstring::size_type size = str.size();
|
||||
if (int(size) < 0)
|
||||
return;
|
||||
if (size) {
|
||||
qCheckAccess(str.c_str());
|
||||
qCheckAccess(str.c_str() + str.size() - 1);
|
||||
qCheckAccess(str.c_str() + size - 1);
|
||||
}
|
||||
|
||||
d.beginItem("value");
|
||||
d.putBase64Encoded((const char *)str.c_str(), str.size() * sizeof(wchar_t));
|
||||
d.endItem();
|
||||
d.putItem("valueencoded", (sizeof(wchar_t) == 2 ? "2" : "3"));
|
||||
d.putItem("type", "std::wstring");
|
||||
d.putItem("numchild", "0");
|
||||
|
||||
dumpStdWStringValue(d, str);
|
||||
d.disarm();
|
||||
}
|
||||
|
||||
@@ -3164,6 +3184,8 @@ void *qDumpObjectData440(
|
||||
.put("std::string=\"").put(sizeof(std::string)).put("\",")
|
||||
.put("std::wstring=\"").put(sizeof(std::wstring)).put("\",")
|
||||
.put("std::allocator=\"").put(sizeof(std::allocator<int>)).put("\",")
|
||||
.put("std::char_traits<char>=\"").put(sizeof(std::char_traits<char>)).put("\",")
|
||||
.put("std::char_traits<unsigned short>=\"").put(sizeof(std::char_traits<unsigned short>)).put("\",")
|
||||
#if QT_VERSION >= 0x040500
|
||||
.put(NS"QSharedPointer=\"").put(sizeof(QSharedPointer<int>)).put("\",")
|
||||
.put(NS"QSharedDataPointer=\"").put(sizeof(QSharedDataPointer<QSharedData>)).put("\",")
|
||||
|
||||
@@ -256,6 +256,18 @@ static int dumpStdStringVector()
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dumpStdWStringVector()
|
||||
{
|
||||
std::vector<std::wstring> test;
|
||||
test.push_back(L"item1");
|
||||
test.push_back(L"item2");
|
||||
prepareInBuffer("std::vector", "local.wstringvector", "local.wstringvector", "std::wstring");
|
||||
qDumpObjectData440(2, 42, testAddress(&test), 1, sizeof(std::wstring), sizeof(std::list<int>::allocator_type), 0, 0);
|
||||
fputs(qDumpOutBuffer, stdout);
|
||||
fputc('\n', stdout);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dumpStdIntSet()
|
||||
{
|
||||
std::set<int> test;
|
||||
@@ -335,6 +347,8 @@ static bool dumpType(const char *arg)
|
||||
{ dumpStdIntVector(); return true; }
|
||||
if (!qstrcmp(arg, "vector<string>"))
|
||||
{ dumpStdStringVector(); return true; }
|
||||
if (!qstrcmp(arg, "vector<wstring>"))
|
||||
{ dumpStdWStringVector(); return true; }
|
||||
if (!qstrcmp(arg, "set<int>"))
|
||||
{ dumpStdIntSet(); return true; }
|
||||
if (!qstrcmp(arg, "set<string>"))
|
||||
|
||||
@@ -544,12 +544,23 @@ static inline QString msgDumpFailed(const WatchData &wd, const QString *why)
|
||||
return QString::fromLatin1("Unable to dump '%1' (%2): %3").arg(wd.name, wd.type, *why);
|
||||
}
|
||||
|
||||
static inline QString msgNotHandled(const QString &type)
|
||||
{
|
||||
return QString::fromLatin1("The type '%1' is not handled.").arg(type);
|
||||
}
|
||||
|
||||
CdbDumperHelper::DumpResult CdbDumperHelper::dumpType(const WatchData &wd, bool dumpChildren, int source,
|
||||
QList<WatchData> *result, QString *errorMessage)
|
||||
{
|
||||
// Check failure cache and supported types
|
||||
if (m_state == Disabled || m_failedTypes.contains(wd.type))
|
||||
if (m_state == Disabled) {
|
||||
*errorMessage = QLatin1String("Dumpers are disabled");
|
||||
return DumpNotHandled;
|
||||
}
|
||||
if (m_failedTypes.contains(wd.type)) {
|
||||
*errorMessage = msgNotHandled(wd.type);
|
||||
return DumpNotHandled;
|
||||
}
|
||||
|
||||
// Ensure types are parsed and known.
|
||||
if (!ensureInitialized(errorMessage)) {
|
||||
@@ -562,8 +573,10 @@ CdbDumperHelper::DumpResult CdbDumperHelper::dumpType(const WatchData &wd, bool
|
||||
const QtDumperHelper::TypeData td = m_helper.typeData(wd.type);
|
||||
if (loadDebug)
|
||||
qDebug() << "dumpType" << wd.type << td;
|
||||
if (td.type == QtDumperHelper::UnknownType)
|
||||
if (td.type == QtDumperHelper::UnknownType) {
|
||||
*errorMessage = msgNotHandled(wd.type);
|
||||
return DumpNotHandled;
|
||||
}
|
||||
|
||||
// Now evaluate
|
||||
const QString message = QCoreApplication::translate("Debugger::Internal::CdbDumperHelper",
|
||||
|
||||
@@ -257,7 +257,7 @@ bool CdbStackFrameContext::completeData(const WatchData &incompleteLocal,
|
||||
foreach(const WatchData &dwd, dumperResult)
|
||||
wh->insertData(dwd);
|
||||
} else {
|
||||
const QString msg = QString::fromLatin1("Unable to further expand dumper watch data: %1 (%2): %3/%4").arg(incompleteLocal.name, incompleteLocal.type).arg(int(dr)).arg(*errorMessage);
|
||||
const QString msg = QString::fromLatin1("Unable to further expand dumper watch data: '%1' (%2): %3/%4").arg(incompleteLocal.name, incompleteLocal.type).arg(int(dr)).arg(*errorMessage);
|
||||
qWarning("%s", qPrintable(msg));
|
||||
WatchData wd = incompleteLocal;
|
||||
wd.setAllUnneeded();
|
||||
|
||||
@@ -144,7 +144,7 @@ void ToolTipWidget::done()
|
||||
}
|
||||
|
||||
void ToolTipWidget::run(const QPoint &point, QAbstractItemModel *model,
|
||||
const QModelIndex &index, const QString &msg)
|
||||
const QModelIndex &index, const QString & /* msg */)
|
||||
{
|
||||
move(point);
|
||||
setModel(model);
|
||||
|
||||
@@ -390,9 +390,29 @@ static QString chopConst(QString type)
|
||||
return type;
|
||||
}
|
||||
|
||||
QString niceType(QString type)
|
||||
static inline QRegExp stdStringRegExp(const QString &charType)
|
||||
{
|
||||
type.replace('*', '@');
|
||||
QString rc = QLatin1String("basic_string<");
|
||||
rc += charType;
|
||||
rc += QLatin1String(",[ ]?std::char_traits<");
|
||||
rc += charType;
|
||||
rc += QLatin1String(">,[ ]?std::allocator<");
|
||||
rc += charType;
|
||||
rc += QLatin1String("> >");
|
||||
const QRegExp re(rc);
|
||||
Q_ASSERT(re.isValid());
|
||||
return re;
|
||||
}
|
||||
|
||||
QString niceType(const QString typeIn)
|
||||
{
|
||||
static QMap<QString, QString> cache;
|
||||
const QMap<QString, QString>::const_iterator it = cache.constFind(typeIn);
|
||||
if (it != cache.constEnd()) {
|
||||
return it.value();
|
||||
}
|
||||
QString type = typeIn;
|
||||
type.replace(QLatin1Char('*'), QLatin1Char('@'));
|
||||
|
||||
for (int i = 0; i < 10; ++i) {
|
||||
int start = type.indexOf("std::allocator<");
|
||||
@@ -414,33 +434,37 @@ QString niceType(QString type)
|
||||
QString alloc = type.mid(start, pos + 1 - start).trimmed();
|
||||
QString inner = alloc.mid(15, alloc.size() - 16).trimmed();
|
||||
|
||||
if (inner == QLatin1String("char"))
|
||||
// std::string
|
||||
type.replace(QLatin1String("basic_string<char, std::char_traits<char>, "
|
||||
"std::allocator<char> >"), QLatin1String("string"));
|
||||
else if (inner == QLatin1String("wchar_t"))
|
||||
// std::wstring
|
||||
type.replace(QLatin1String("basic_string<wchar_t, std::char_traits<wchar_t>, "
|
||||
"std::allocator<wchar_t> >"), QLatin1String("wstring"));
|
||||
|
||||
if (inner == QLatin1String("char")) { // std::string
|
||||
static const QRegExp stringRegexp = stdStringRegExp(inner);
|
||||
type.replace(stringRegexp, QLatin1String("string"));
|
||||
} else if (inner == QLatin1String("wchar_t")) { // std::wstring
|
||||
static const QRegExp wchartStringRegexp = stdStringRegExp(inner);
|
||||
type.replace(wchartStringRegexp, QLatin1String("wstring"));
|
||||
} else if (inner == QLatin1String("unsigned short")) { // std::wstring/MSVC
|
||||
static const QRegExp usStringRegexp = stdStringRegExp(inner);
|
||||
type.replace(usStringRegexp, QLatin1String("wstring"));
|
||||
}
|
||||
// std::vector, std::deque, std::list
|
||||
QRegExp re1(QString("(vector|list|deque)<%1, %2\\s*>").arg(inner, alloc));
|
||||
static const QRegExp re1(QString::fromLatin1("(vector|list|deque)<%1,[ ]?%2\\s*>").arg(inner, alloc));
|
||||
Q_ASSERT(re1.isValid());
|
||||
if (re1.indexIn(type) != -1)
|
||||
type.replace(re1.cap(0), QString("%1<%2>").arg(re1.cap(1), inner));
|
||||
|
||||
type.replace(re1.cap(0), QString::fromLatin1("%1<%2>").arg(re1.cap(1), inner));
|
||||
|
||||
// std::stack
|
||||
QRegExp re6(QString("stack<%1, std::deque<%2> >").arg(inner, inner));
|
||||
re6.setMinimal(true);
|
||||
static QRegExp re6(QString::fromLatin1("stack<%1,[ ]?std::deque<%2> >").arg(inner, inner));
|
||||
if (!re6.isMinimal())
|
||||
re6.setMinimal(true);
|
||||
Q_ASSERT(re6.isValid());
|
||||
if (re6.indexIn(type) != -1)
|
||||
type.replace(re6.cap(0), QString("stack<%1>").arg(inner));
|
||||
type.replace(re6.cap(0), QString::fromLatin1("stack<%1>").arg(inner));
|
||||
|
||||
// std::set
|
||||
QRegExp re4(QString("set<%1, std::less<%2>, %3\\s*>").arg(inner, inner, alloc));
|
||||
re4.setMinimal(true);
|
||||
static QRegExp re4(QString::fromLatin1("set<%1,[ ]?std::less<%2>,[ ]?%3\\s*>").arg(inner, inner, alloc));
|
||||
if (!re4.isMinimal())
|
||||
re4.setMinimal(true);
|
||||
Q_ASSERT(re4.isValid());
|
||||
if (re4.indexIn(type) != -1)
|
||||
type.replace(re4.cap(0), QString("set<%1>").arg(inner));
|
||||
|
||||
type.replace(re4.cap(0), QString::fromLatin1("set<%1>").arg(inner));
|
||||
|
||||
// std::map
|
||||
if (inner.startsWith("std::pair<")) {
|
||||
@@ -460,22 +484,26 @@ QString niceType(QString type)
|
||||
QString key = chopConst(ckey);
|
||||
QString value = inner.mid(pos + 2, inner.size() - 3 - pos);
|
||||
|
||||
QRegExp re5(QString("map<%1, %2, std::less<%3>, %4\\s*>")
|
||||
static QRegExp re5(QString("map<%1,[ ]?%2,[ ]?std::less<%3>,[ ]?%4\\s*>")
|
||||
.arg(key, value, key, alloc));
|
||||
re5.setMinimal(true);
|
||||
if (!re5.isMinimal())
|
||||
re5.setMinimal(true);
|
||||
Q_ASSERT(re5.isValid());
|
||||
if (re5.indexIn(type) != -1)
|
||||
type.replace(re5.cap(0), QString("map<%1, %2>").arg(key, value));
|
||||
else {
|
||||
QRegExp re7(QString("map<const %1, %2, std::less<const %3>, %4\\s*>")
|
||||
static QRegExp re7(QString("map<const %1,[ ]?%2,[ ]?std::less<const %3>,[ ]?%4\\s*>")
|
||||
.arg(key, value, key, alloc));
|
||||
re7.setMinimal(true);
|
||||
if (!re7.isMinimal())
|
||||
re7.setMinimal(true);
|
||||
if (re7.indexIn(type) != -1)
|
||||
type.replace(re7.cap(0), QString("map<const %1, %2>").arg(key, value));
|
||||
}
|
||||
}
|
||||
}
|
||||
type.replace('@', '*');
|
||||
type.replace(QLatin1Char('@'), QLatin1Char('*'));
|
||||
type.replace(QLatin1String(" >"), QString(QLatin1Char('>')));
|
||||
cache.insert(typeIn, type); // For simplicity, also cache unmodified types
|
||||
return type;
|
||||
}
|
||||
|
||||
|
||||
@@ -266,30 +266,43 @@ bool extractTemplate(const QString &type, QString *tmplate, QString *inner)
|
||||
// Input "Template<Inner1,Inner2,...>::Foo" will return "Template::Foo" in
|
||||
// 'tmplate' and "Inner1@Inner2@..." etc in 'inner'. Result indicates
|
||||
// whether parsing was successful
|
||||
// Gdb inserts a blank after each comma which we would like to avoid
|
||||
tmplate->clear();
|
||||
inner->clear();
|
||||
if (!type.contains(QLatin1Char('<')))
|
||||
return false;
|
||||
int level = 0;
|
||||
bool skipSpace = false;
|
||||
const int size = type.size();
|
||||
|
||||
for (int i = 0; i != type.size(); ++i) {
|
||||
for (int i = 0; i != size; ++i) {
|
||||
const QChar c = type.at(i);
|
||||
if (c == QLatin1Char(' ') && skipSpace) {
|
||||
skipSpace = false;
|
||||
} else if (c == QLatin1Char('<')) {
|
||||
const char asciiChar = c.toAscii();
|
||||
switch (asciiChar) {
|
||||
case '<':
|
||||
*(level == 0 ? tmplate : inner) += c;
|
||||
++level;
|
||||
} else if (c == QLatin1Char('>')) {
|
||||
break;
|
||||
case '>':
|
||||
--level;
|
||||
*(level == 0 ? tmplate : inner) += c;
|
||||
} else if (c == QLatin1Char(',')) {
|
||||
break;
|
||||
case ',':
|
||||
*inner += (level == 1) ? QLatin1Char('@') : QLatin1Char(',');
|
||||
skipSpace = true;
|
||||
} else {
|
||||
*(level == 0 ? tmplate : inner) += c;
|
||||
break;
|
||||
default:
|
||||
if (!skipSpace || asciiChar != ' ') {
|
||||
*(level == 0 ? tmplate : inner) += c;
|
||||
skipSpace = false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
*tmplate = tmplate->trimmed();
|
||||
*tmplate = tmplate->remove(QLatin1String("<>"));
|
||||
*inner = inner->trimmed();
|
||||
//qDebug() << "EXTRACT TEMPLATE: " << *tmplate << *inner << " FROM " << type;
|
||||
// qDebug() << "EXTRACT TEMPLATE: " << *tmplate << *inner << " FROM " << type;
|
||||
return !inner->isEmpty();
|
||||
}
|
||||
|
||||
@@ -408,7 +421,7 @@ bool isCppEditor(Core::IEditor *editor)
|
||||
// Find the function the cursor is in to use a scope.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// Return the Cpp expression, and, if desired, the function
|
||||
@@ -442,7 +455,7 @@ QString cppExpressionAt(TextEditor::ITextEditor *editor, int pos,
|
||||
const QTextCursor tc = plaintext->textCursor();
|
||||
*column = tc.columnNumber();
|
||||
*line = tc.blockNumber();
|
||||
}
|
||||
}
|
||||
|
||||
if (function && !expr.isEmpty())
|
||||
if (const Core::IFile *file = editor->file())
|
||||
@@ -455,6 +468,7 @@ QString cppExpressionAt(TextEditor::ITextEditor *editor, int pos,
|
||||
// --------------- QtDumperResult
|
||||
|
||||
QtDumperResult::Child::Child() :
|
||||
keyEncoded(0),
|
||||
valueEncoded(0),
|
||||
childCount(0),
|
||||
valuedisabled(false)
|
||||
@@ -475,6 +489,7 @@ void QtDumperResult::clear()
|
||||
value.clear();
|
||||
address.clear();
|
||||
type.clear();
|
||||
extra.clear();
|
||||
displayedType.clear();
|
||||
valueEncoded = 0;
|
||||
valuedisabled = false;
|
||||
@@ -509,8 +524,17 @@ QList<WatchData> QtDumperResult::toWatchData(int source) const
|
||||
wchild.source = source;
|
||||
wchild.iname = iname;
|
||||
wchild.iname += dot;
|
||||
wchild.iname += dchild.name;
|
||||
wchild.name = dchild.name;
|
||||
wchild.iname += dchild.name;
|
||||
// Use key entry as name (which is used for map nodes)
|
||||
if (dchild.key.isEmpty()) {
|
||||
wchild.name = dchild.name;
|
||||
} else {
|
||||
wchild.name = decodeData(dchild.key, dchild.keyEncoded);
|
||||
if (wchild.name.size() > 13) {
|
||||
wchild.name.truncate(12);
|
||||
wchild.name += QLatin1String("...");
|
||||
}
|
||||
}
|
||||
wchild.exp = dchild.exp;
|
||||
wchild.valuedisabled = dchild.valuedisabled;
|
||||
wchild.setType(dchild.type.isEmpty() ? childType : dchild.type);
|
||||
@@ -533,18 +557,21 @@ QDebug operator<<(QDebug in, const QtDumperResult &d)
|
||||
<< " address=" << d.address
|
||||
<< " value=" << d.value
|
||||
<< " disabled=" << d.valuedisabled
|
||||
<< " encoded=" << d.valueEncoded << " internal=" << d.internal;
|
||||
<< " encoded=" << d.valueEncoded << " internal=" << d.internal
|
||||
<< " extra='" << d.extra << "'\n";
|
||||
const int realChildCount = d.children.size();
|
||||
if (d.childCount || realChildCount) {
|
||||
nospace << " childCount=" << d.childCount << '/' << realChildCount
|
||||
nospace << "childCount=" << d.childCount << '/' << realChildCount
|
||||
<< " childType=" << d.childType << '\n';
|
||||
for (int i = 0; i < realChildCount; i++) {
|
||||
const QtDumperResult::Child &c = d.children.at(i);
|
||||
nospace << " #" << i << " addr=" << c.address
|
||||
<< " disabled=" << c.valuedisabled
|
||||
<< " type=" << c.type << " exp=" << c.exp
|
||||
<< " name=" << c.name << " encoded=" << c.valueEncoded
|
||||
<< " value=" << c.value
|
||||
<< " name=" << c.name;
|
||||
if (!c.key.isEmpty())
|
||||
nospace << " keyencoded=" << c.keyEncoded << " key=" << c.key;
|
||||
nospace << " valueencoded=" << c.valueEncoded << " value=" << c.value
|
||||
<< "childcount=" << c.childCount << '\n';
|
||||
}
|
||||
}
|
||||
@@ -770,6 +797,7 @@ class DumperParser
|
||||
public:
|
||||
explicit DumperParser(const char *s) : m_s(s) {}
|
||||
bool run();
|
||||
virtual ~DumperParser() {}
|
||||
|
||||
protected:
|
||||
// handle 'key="value"'
|
||||
@@ -833,9 +861,9 @@ bool DumperParser::parseHash(int level, const char *&pos)
|
||||
return false;
|
||||
pos = equalsPtr + 1;
|
||||
if (!*pos)
|
||||
return false;
|
||||
return false;
|
||||
if (!parseValue(level + 1, pos))
|
||||
return false;
|
||||
return false;
|
||||
if (*pos == ',')
|
||||
pos++;
|
||||
}
|
||||
@@ -871,7 +899,7 @@ bool DumperParser::parseValue(int level, const char *&pos)
|
||||
if (*pos == ',')
|
||||
pos++;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
// A hash '{a="b",b="c"}'
|
||||
case '{': {
|
||||
@@ -879,7 +907,7 @@ bool DumperParser::parseValue(int level, const char *&pos)
|
||||
return false;
|
||||
pos++;
|
||||
if (!parseHash(level + 1, pos))
|
||||
return false;
|
||||
return false;
|
||||
return handleHashEnd();
|
||||
}
|
||||
return false;
|
||||
@@ -952,7 +980,7 @@ public:
|
||||
|
||||
protected:
|
||||
virtual bool handleKeyword(const char *k, int size);
|
||||
virtual bool handleListStart();
|
||||
virtual bool handleListStart();
|
||||
virtual bool handleListEnd();
|
||||
virtual bool handleHashEnd();
|
||||
virtual bool handleValue(const char *k, int size);
|
||||
@@ -972,7 +1000,7 @@ QueryDumperParser::QueryDumperParser(const char *s) :
|
||||
{
|
||||
}
|
||||
|
||||
bool QueryDumperParser::handleKeyword(const char *k, int size)
|
||||
bool QueryDumperParser::handleKeyword(const char *k, int size)
|
||||
{
|
||||
switch (m_mode) {
|
||||
case ExpectingSizes:
|
||||
@@ -1064,7 +1092,6 @@ bool QtDumperHelper::parseQuery(const char *data, Debugger debugger)
|
||||
foreach (const QueryDumperParser::SizeEntry &se, parser.data().sizes)
|
||||
addSize(se.first, se.second);
|
||||
m_expressionCache = parser.data().expressionCache;
|
||||
qDebug() << m_expressionCache;
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -1081,13 +1108,15 @@ void QtDumperHelper::addSize(const QString &name, int size)
|
||||
return;
|
||||
}
|
||||
do {
|
||||
// CDB helpers
|
||||
if (name == QLatin1String("std::string")) {
|
||||
m_sizeCache.insert(QLatin1String("std::basic_string<char,std::char_traits<char>,std::allocator<char>>"), size);
|
||||
m_sizeCache.insert(QLatin1String("std::basic_string<char,std::char_traits<char>,std::allocator<char> >"), size);
|
||||
m_sizeCache.insert(QLatin1String("basic_string<char,char_traits<char>,allocator<char> >"), size);
|
||||
break;
|
||||
}
|
||||
if (name == QLatin1String("std::wstring")) {
|
||||
// FIXME: check space between > > below?
|
||||
m_sizeCache.insert(QLatin1String("std::basic_string<unsigned short,std::char_traits<unsignedshort>,std::allocator<unsignedshort> >"), size);
|
||||
m_sizeCache.insert(QLatin1String("basic_string<unsigned short,char_traits<unsignedshort>,allocator<unsignedshort> >"), size);
|
||||
m_sizeCache.insert(QLatin1String("std::basic_string<unsigned short,std::char_traits<unsigned short>,std::allocator<unsigned short> >"), size);
|
||||
break;
|
||||
}
|
||||
} while (false);
|
||||
@@ -1297,10 +1326,16 @@ void QtDumperHelper::evaluationParameters(const WatchData &data,
|
||||
// But we need the offset of the second item in the value pair.
|
||||
// We read the type of the pair from the allocator argument because
|
||||
// that gets the constness "right" (in the sense that gdb can
|
||||
// read it back;
|
||||
// read it back: "std::allocator<std::pair<Key,Value> >"
|
||||
// -> "std::pair<Key,Value>". Different debuggers have varying
|
||||
// amounts of terminating blanks...
|
||||
QString pairType = inners.at(3);
|
||||
// remove 'std::allocator<...>':
|
||||
pairType = pairType.mid(15, pairType.size() - 15 - 2);
|
||||
int bracketPos = pairType.indexOf(QLatin1Char('<'));
|
||||
if (bracketPos != -1)
|
||||
pairType.remove(0, bracketPos + 1);
|
||||
bracketPos = pairType.indexOf(QLatin1Char('>'));
|
||||
if (bracketPos != -1)
|
||||
pairType.truncate(bracketPos + 1);
|
||||
extraArgs[2] = QLatin1String("(size_t)&(('");
|
||||
extraArgs[2] += pairType;
|
||||
extraArgs[2] += QLatin1String("'*)0)->second");
|
||||
@@ -1377,12 +1412,15 @@ private:
|
||||
ExpectingType, ExpectingDisplayedType, ExpectingInternal,
|
||||
ExpectingValueDisabled, ExpectingValueEncoded,
|
||||
ExpectingCommonChildType, ExpectingChildCount,
|
||||
ExpectingExtra,
|
||||
IgnoreNext,
|
||||
ChildModeStart,
|
||||
ExpectingChildren,ExpectingChildName, ExpectingChildAddress,
|
||||
ExpectingChildExpression, ExpectingChildType,
|
||||
ExpectingChildKey, ExpectingChildKeyEncoded,
|
||||
ExpectingChildValue, ExpectingChildValueEncoded,
|
||||
ExpectingChildValueDisabled, ExpectingChildChildCount
|
||||
ExpectingChildValueDisabled, ExpectingChildChildCount,
|
||||
IgnoreNextChildMode
|
||||
};
|
||||
|
||||
static inline Mode nextMode(Mode in, const char *keyword, int size);
|
||||
@@ -1405,6 +1443,8 @@ ValueDumperParser::Mode ValueDumperParser::nextMode(Mode in, const char *keyword
|
||||
case 3:
|
||||
if (!qstrncmp(keyword, "exp", size))
|
||||
return ExpectingChildExpression;
|
||||
if (!qstrncmp(keyword, "key", size))
|
||||
return ExpectingChildKey;
|
||||
break;
|
||||
case 4:
|
||||
if (!qstrncmp(keyword, "addr", size))
|
||||
@@ -1419,6 +1459,8 @@ ValueDumperParser::Mode ValueDumperParser::nextMode(Mode in, const char *keyword
|
||||
return ExpectingIName;
|
||||
if (!qstrncmp(keyword, "value", size))
|
||||
return in > ChildModeStart ? ExpectingChildValue : ExpectingValue;
|
||||
if (!qstrncmp(keyword, "extra", size))
|
||||
return ExpectingExtra;
|
||||
break;
|
||||
case 8:
|
||||
if (!qstrncmp(keyword, "children", size))
|
||||
@@ -1431,7 +1473,11 @@ ValueDumperParser::Mode ValueDumperParser::nextMode(Mode in, const char *keyword
|
||||
case 9:
|
||||
if (!qstrncmp(keyword, "childtype", size))
|
||||
return ExpectingCommonChildType;
|
||||
break;
|
||||
break;
|
||||
case 10:
|
||||
if (!qstrncmp(keyword, "keyencoded", size))
|
||||
return ExpectingChildKeyEncoded;
|
||||
break;
|
||||
case 12:
|
||||
if (!qstrncmp(keyword, "valueencoded", size))
|
||||
return in > ChildModeStart ? ExpectingChildValueEncoded : ExpectingValueEncoded;
|
||||
@@ -1442,10 +1488,10 @@ ValueDumperParser::Mode ValueDumperParser::nextMode(Mode in, const char *keyword
|
||||
if (!qstrncmp(keyword, "displayedtype", size))
|
||||
return ExpectingDisplayedType;
|
||||
if (!qstrncmp(keyword, "childnumchild", size))
|
||||
return IgnoreNext;
|
||||
return IgnoreNextChildMode;
|
||||
break;
|
||||
}
|
||||
return IgnoreNext;
|
||||
return in > ChildModeStart ? IgnoreNextChildMode : IgnoreNext;
|
||||
}
|
||||
|
||||
bool ValueDumperParser::handleKeyword(const char *k, int size)
|
||||
@@ -1491,6 +1537,9 @@ bool ValueDumperParser::handleValue(const char *k, int size)
|
||||
case ExpectingDisplayedType:
|
||||
m_result.displayedType = QString::fromLatin1(valueBA);
|
||||
break;
|
||||
case ExpectingExtra:
|
||||
m_result.extra = valueBA;
|
||||
break;
|
||||
case ExpectingInternal:
|
||||
m_result.internal = valueBA == "true";
|
||||
break;
|
||||
@@ -1501,6 +1550,7 @@ bool ValueDumperParser::handleValue(const char *k, int size)
|
||||
m_result.childCount = QString::fromLatin1(valueBA).toInt();
|
||||
break;
|
||||
case ExpectingChildren:
|
||||
case IgnoreNextChildMode:
|
||||
case IgnoreNext:
|
||||
break;
|
||||
case ExpectingChildName:
|
||||
@@ -1509,6 +1559,12 @@ bool ValueDumperParser::handleValue(const char *k, int size)
|
||||
case ExpectingChildAddress:
|
||||
m_result.children.back().address = QString::fromLatin1(valueBA);
|
||||
break;
|
||||
case ExpectingChildKeyEncoded:
|
||||
m_result.children.back().keyEncoded = QString::fromLatin1(valueBA).toInt();
|
||||
break;
|
||||
case ExpectingChildKey:
|
||||
m_result.children.back().key = valueBA;
|
||||
break;
|
||||
case ExpectingChildValue:
|
||||
m_result.children.back().value = valueBA;
|
||||
break;
|
||||
@@ -1532,7 +1588,7 @@ bool ValueDumperParser::handleValue(const char *k, int size)
|
||||
}
|
||||
|
||||
bool QtDumperHelper::parseValue(const char *data, QtDumperResult *r)
|
||||
{
|
||||
{
|
||||
ValueDumperParser parser(data);
|
||||
if (!parser.run())
|
||||
return false;
|
||||
@@ -1541,7 +1597,7 @@ bool QtDumperHelper::parseValue(const char *data, QtDumperResult *r)
|
||||
if (r->childCount < r->children.size())
|
||||
r->childCount = r->children.size();
|
||||
if (debug)
|
||||
qDebug() << '\n' << data << *r;
|
||||
qDebug() << '\n' << data << '\n' << *r;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -90,13 +90,15 @@ struct QtDumperResult
|
||||
struct Child {
|
||||
Child();
|
||||
|
||||
int valueEncoded;
|
||||
int keyEncoded;
|
||||
int valueEncoded;
|
||||
int childCount;
|
||||
bool valuedisabled;
|
||||
QString name;
|
||||
QString address;
|
||||
QString exp;
|
||||
QString type;
|
||||
QByteArray key;
|
||||
QByteArray value;
|
||||
};
|
||||
|
||||
@@ -107,6 +109,7 @@ struct QtDumperResult
|
||||
QString iname;
|
||||
QString address;
|
||||
QString type;
|
||||
QString extra;
|
||||
QString displayedType;
|
||||
QByteArray value;
|
||||
int valueEncoded;
|
||||
|
||||
Reference in New Issue
Block a user