Commit b295aec1 authored by hjk's avatar hjk
Browse files

debugger: fix several small issues in the dumper code

Fix typo in QChar helper.
Add a auto tests for some of the dumpers.
Make the dumpers compilable for Qt < 4.5 for better regression tests.
Make manual tests compile with Qt < 4.5.
parent 62d78361
......@@ -44,11 +44,14 @@
#include <QtCore/QObject>
#include <QtCore/QPointer>
#include <QtCore/QString>
#include <QtCore/QSharedPointer>
#include <QtCore/QSharedDataPointer>
#include <QtCore/QTextCodec>
#include <QtCore/QVector>
#if QT_VERSION >= 0x040500
#include <QtCore/QSharedPointer>
#include <QtCore/QSharedDataPointer>
#include <QtCore/QWeakPointer>
#endif
int qtGhVersion = QT_VERSION;
......@@ -180,6 +183,9 @@ struct Sender { QObject *sender; int signal; int ref; };
int method;
uint connectionType : 3; // 0 == auto, 1 == direct, 2 == queued, 4 == blocking
QBasicAtomicPointer<int> argumentTypes;
//senders linked list
//Connection *next;
//Connection **prev;
};
typedef QList<Connection *> ConnectionList;
......@@ -191,11 +197,11 @@ struct Sender { QObject *sender; int signal; int ref; };
int signalAt(const SenderList &l, int i) { return l.at(i)->method; }
#endif
class QObjectPrivate : public QObjectData
class ObjectPrivate : public QObjectData
{
public:
QObjectPrivate() {}
virtual ~QObjectPrivate() {}
ObjectPrivate() {}
virtual ~ObjectPrivate() {}
QList<QObject *> pendingChildInsertedEvents;
void *threadData;
......@@ -222,10 +228,18 @@ QT_END_NAMESPACE
// This can be mangled typenames of nested templates, each char-by-char
// comma-separated integer list...
Q_DECL_EXPORT char qDumpInBuffer[10000];
// The output buffer.
Q_DECL_EXPORT char qDumpOutBuffer[1000000];
#ifdef MACROSDEBUG
Q_DECL_EXPORT char xDumpInBuffer[10000];
Q_DECL_EXPORT char xDumpOutBuffer[1000000];
#define inBuffer xDumpInBuffer
#define outBuffer xDumpOutBuffer
#else
Q_DECL_EXPORT char qDumpInBuffer[10000];
Q_DECL_EXPORT char qDumpOutBuffer[1000000];
#define inBuffer qDumpInBuffer
#define outBuffer qDumpOutBuffer
#endif
namespace {
......@@ -476,15 +490,15 @@ QDumper::QDumper()
{
success = false;
full = false;
qDumpOutBuffer[0] = 'f'; // marks output as 'wrong'
outBuffer[0] = 'f'; // marks output as 'wrong'
pos = 1;
}
QDumper::~QDumper()
{
qDumpOutBuffer[pos++] = '\0';
outBuffer[pos++] = '\0';
if (success)
qDumpOutBuffer[0] = (full ? '+' : 't');
outBuffer[0] = (full ? '+' : 't');
}
void QDumper::setupTemplateParameters()
......@@ -510,49 +524,49 @@ void QDumper::setupTemplateParameters()
QDumper &QDumper::operator<<(unsigned long long c)
{
checkFill();
pos += sprintf(qDumpOutBuffer + pos, "%llu", c);
pos += sprintf(outBuffer + pos, "%llu", c);
return *this;
}
QDumper &QDumper::operator<<(unsigned long c)
{
checkFill();
pos += sprintf(qDumpOutBuffer + pos, "%lu", c);
pos += sprintf(outBuffer + pos, "%lu", c);
return *this;
}
QDumper &QDumper::operator<<(float d)
{
checkFill();
pos += sprintf(qDumpOutBuffer + pos, "%f", d);
pos += sprintf(outBuffer + pos, "%f", d);
return *this;
}
QDumper &QDumper::operator<<(double d)
{
checkFill();
pos += sprintf(qDumpOutBuffer + pos, "%f", d);
pos += sprintf(outBuffer + pos, "%f", d);
return *this;
}
QDumper &QDumper::operator<<(unsigned int i)
{
checkFill();
pos += sprintf(qDumpOutBuffer + pos, "%u", i);
pos += sprintf(outBuffer + pos, "%u", i);
return *this;
}
QDumper &QDumper::operator<<(long c)
{
checkFill();
pos += sprintf(qDumpOutBuffer + pos, "%ld", c);
pos += sprintf(outBuffer + pos, "%ld", c);
return *this;
}
QDumper &QDumper::operator<<(int i)
{
checkFill();
pos += sprintf(qDumpOutBuffer + pos, "%d", i);
pos += sprintf(outBuffer + pos, "%d", i);
return *this;
}
......@@ -576,7 +590,7 @@ QDumper &QDumper::operator<<(const void *p)
void QDumper::checkFill()
{
if (pos >= int(sizeof(qDumpOutBuffer)) - 100)
if (pos >= int(sizeof(outBuffer)) - 100)
full = true;
}
......@@ -584,14 +598,14 @@ void QDumper::put(char c)
{
checkFill();
if (!full)
qDumpOutBuffer[pos++] = c;
outBuffer[pos++] = c;
}
void QDumper::addCommaIfNeeded()
{
if (pos == 0)
return;
char c = qDumpOutBuffer[pos - 1];
char c = outBuffer[pos - 1];
if (c == '}' || c == '"' || c == ']')
put(',');
}
......@@ -736,8 +750,8 @@ void QDumper::putEllipsis()
#define DUMPUNKNOWN_MESSAGE "<internal error>"
static void qDumpUnknown(QDumper &d, const char *why = 0)
{
P(d, "iname", d.iname);
P(d, "addr", d.data);
//P(d, "iname", d.iname);
//P(d, "addr", d.data);
if (!why)
why = DUMPUNKNOWN_MESSAGE;
P(d, "value", why);
......@@ -792,7 +806,7 @@ static void qDumpInnerValueHelper(QDumper &d, const char *type, const void *addr
if (isEqual(type, "QChar")) {
d.addCommaIfNeeded();
QChar c = *(QChar *)addr;
char str[] = "'?', usc=\0";
char str[] = "'?', ucs=\0";
if (c.isPrint() && c.unicode() < 127)
str[1] = char(c.unicode());
P(d, field, str << c.unicode());
......@@ -1007,7 +1021,7 @@ static void qDumpQChar(QDumper &d)
{
d.addCommaIfNeeded();
QChar c = *(QChar *)d.data;
char str[] = "'?', usc=\0";
char str[] = "'?', ucs=\0";
if (c.isPrint() && c.unicode() < 127)
str[1] = char(c.unicode());
P(d, "value", str << c.unicode());
......@@ -1740,7 +1754,7 @@ static void qDumpQObject(QDumper &d)
#if 0
d.beginHash();
P(d, "name", "senders");
P(d, "exp", "(*(class '"NS"QObjectPrivate'*)" << dfunc(ob) << ")->senders");
P(d, "exp", "(*(class '"NS"ObjectPrivate'*)" << dfunc(ob) << ")->senders");
P(d, "type", NS"QList<"NS"QObjectPrivateSender>");
d.endHash();
#endif
......@@ -1862,7 +1876,7 @@ const char * qConnectionTypes[] ={
static const ConnectionList &qConnectionList(const QObject *ob, int signalNumber)
{
static const ConnectionList emptyList;
const QObjectPrivate *p = reinterpret_cast<const QObjectPrivate *>(dfunc(ob));
const ObjectPrivate *p = reinterpret_cast<const ObjectPrivate *>(dfunc(ob));
if (!p->connectionLists)
return emptyList;
typedef QVector<ConnectionList> ConnLists;
......@@ -1963,7 +1977,7 @@ static void qDumpQObjectSlot(QDumper &d)
d << ",children=[";
int numchild = 0;
const QObject *ob = reinterpret_cast<const QObject *>(d.data);
const QObjectPrivate *p = reinterpret_cast<const QObjectPrivate *>(dfunc(ob));
const ObjectPrivate *p = reinterpret_cast<const ObjectPrivate *>(dfunc(ob));
for (int s = 0; s != p->senders.size(); ++s) {
const QObject *sender = senderAt(p->senders, s);
int signal = signalAt(p->senders, s);
......@@ -2003,7 +2017,7 @@ static void qDumpQObjectSlotList(QDumper &d)
{
const QObject *ob = reinterpret_cast<const QObject *>(d.data);
#if QT_VERSION >= 0x040400
const QObjectPrivate *p = reinterpret_cast<const QObjectPrivate *>(dfunc(ob));
const ObjectPrivate *p = reinterpret_cast<const ObjectPrivate *>(dfunc(ob));
#endif
const QMetaObject *mo = ob->metaObject();
......@@ -2011,11 +2025,10 @@ static void qDumpQObjectSlotList(QDumper &d)
for (int i = mo->methodCount(); --i >= 0; )
count += (mo->method(i).methodType() == QMetaMethod::Slot);
P(d, "addr", d.data);
P(d, "numchild", count);
#if QT_VERSION >= 0x040400
if (d.dumpChildren) {
d << ",children=[";
#if QT_VERSION >= 0x040400
for (int i = 0; i != mo->methodCount(); ++i) {
const QMetaMethod & method = mo->method(i);
if (method.methodType() == QMetaMethod::Slot) {
......@@ -2042,9 +2055,9 @@ static void qDumpQObjectSlotList(QDumper &d)
d.endHash();
}
}
#endif
d << "]";
}
#endif
d.disarm();
}
......@@ -2105,6 +2118,7 @@ static void qDumpQSet(QDumper &d)
d.disarm();
}
#if QT_VERSION >= 0x040500
static void qDumpQSharedPointer(QDumper &d)
{
const QSharedPointer<int> &ptr =
......@@ -2143,6 +2157,7 @@ static void qDumpQSharedPointer(QDumper &d)
}
d.disarm();
}
#endif // QT_VERSION >= 0x040500
static void qDumpQString(QDumper &d)
{
......@@ -2342,6 +2357,7 @@ static void qDumpQVector(QDumper &d)
d.disarm();
}
#if QT_VERSION >= 0x040500
static void qDumpQWeakPointer(QDumper &d)
{
const int v = sizeof(void *);
......@@ -2379,6 +2395,7 @@ static void qDumpQWeakPointer(QDumper &d)
}
d.disarm();
}
#endif // QT_VERSION >= 0x040500
static void qDumpStdList(QDumper &d)
{
......@@ -2645,7 +2662,6 @@ static void qDumpStdVectorBool(QDumper &d)
static void handleProtocolVersion2and3(QDumper & d)
{
if (!d.outertype[0]) {
qDumpUnknown(d);
return;
......@@ -2772,8 +2788,10 @@ static void handleProtocolVersion2and3(QDumper & d)
case 'S':
if (isEqual(type, "QSet"))
qDumpQSet(d);
#if QT_VERSION >= 0x040500
else if (isEqual(type, "QSharedPointer"))
qDumpQSharedPointer(d);
#endif
else if (isEqual(type, "QString"))
qDumpQString(d);
else if (isEqual(type, "QStringList"))
......@@ -2810,8 +2828,11 @@ static void handleProtocolVersion2and3(QDumper & d)
qDumpQVector(d);
break;
case 'W':
#if QT_VERSION >= 0x040500
if (isEqual(type, "QWeakPointer"))
qDumpQWeakPointer(d);
#endif
break;
}
if (!d.success)
......@@ -2832,11 +2853,7 @@ void *qDumpObjectData440(
int protocolVersion,
int token,
void *data,
#ifdef Q_CC_MSVC // CDB cannot handle boolean parameters
int dumpChildren,
#else
bool dumpChildren,
#endif
int extraInt0,
int extraInt1,
int extraInt2,
......@@ -2856,6 +2873,7 @@ void *qDumpObjectData440(
"\""NS"QAbstractItem\","
"\""NS"QAbstractItemModel\","
"\""NS"QByteArray\","
"\""NS"QChar\","
"\""NS"QDateTime\","
"\""NS"QDir\","
"\""NS"QFile\","
......@@ -2870,9 +2888,6 @@ void *qDumpObjectData440(
"\""NS"QMap\","
"\""NS"QMapNode\","
"\""NS"QModelIndex\","
#if QT_VERSION >= 0x040500
"\""NS"QMultiMap\","
#endif
"\""NS"QObject\","
"\""NS"QObjectMethodList\"," // hack to get nested properties display
"\""NS"QObjectPropertyList\","
......@@ -2882,13 +2897,16 @@ void *qDumpObjectData440(
"\""NS"QObjectSlotList\","
// << "\""NS"QRegion\","
"\""NS"QSet\","
"\""NS"QSharedPointer\","
"\""NS"QString\","
"\""NS"QStringList\","
"\""NS"QTextCodec\","
"\""NS"QVariant\","
"\""NS"QVector\","
#if QT_VERSION >= 0x040500
"\""NS"QMultiMap\","
"\""NS"QSharedPointer\","
"\""NS"QWeakPointer\","
#endif
#if USE_QT_GUI
"\""NS"QWidget\","
#endif
......@@ -2947,7 +2965,7 @@ void *qDumpObjectData440(
d.extraInt[2] = extraInt2;
d.extraInt[3] = extraInt3;
const char *inbuffer = qDumpInBuffer;
const char *inbuffer = inBuffer;
d.outertype = inbuffer; while (*inbuffer) ++inbuffer; ++inbuffer;
d.iname = inbuffer; while (*inbuffer) ++inbuffer; ++inbuffer;
d.exp = inbuffer; while (*inbuffer) ++inbuffer; ++inbuffer;
......@@ -2960,5 +2978,5 @@ void *qDumpObjectData440(
else {
qDebug() << "Unsupported protocol version" << protocolVersion;
}
return qDumpOutBuffer;
return outBuffer;
}
/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** Commercial Usage
**
** Licensees holding valid Qt Commercial licenses may use this file in
** accordance with the Qt Commercial License Agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Nokia.
**
** GNU Lesser General Public License Usage
**
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** If you are unsure which license is appropriate for your use, please
** contact the sales department at http://www.qtsoftware.com/contact.
**
**************************************************************************/
#ifndef GDBMACROS_H
#define GDBMACROS_H
#ifdef MACROSDEBUG
Q_DECL_EXPORT extern char xDumpInBuffer[];
Q_DECL_EXPORT extern char xDumpOutBuffer[];
#else
Q_DECL_EXPORT extern char qDumpInBuffer[];
Q_DECL_EXPORT extern char qDumpOutBuffer[];
#endif
extern "C" Q_DECL_EXPORT
void *qDumpObjectData440(int protocolVersion, int token, void *data,
int dumpChildren, int extraInt0, int extraInt1, int extraInt2, int extraInt3);
#endif // GDBMACROS_H
......@@ -186,7 +186,7 @@ void WatchData::setType(const QString &str)
setHasChildren(false);
}
void WatchData::setAddress(const QString & str)
void WatchData::setAddress(const QString &str)
{
addr = str;
}
......@@ -196,8 +196,7 @@ WatchData WatchData::pointerChildPlaceHolder() const
WatchData data1;
data1.iname = iname + QLatin1String(".*");
data1.name = QLatin1Char('*') + name;
data1
.exp = QLatin1String("(*(") + exp + QLatin1String("))");
data1.exp = QLatin1String("(*(") + exp + QLatin1String("))");
data1.type = stripPointerType(type);
data1.setValueNeeded();
return data1;
......
......@@ -2,12 +2,16 @@
QT = core testlib
DEBUGGERDIR = ../../../src/plugins/debugger
UTILSDIR = ../../../src/libs
UTILSDIR = ../../../src/libs
MACROSDIR = ../../../share/qtcreator/gdbmacros
SOURCES += \
$$DEBUGGERDIR/gdb/gdbmi.cpp \
$$DEBUGGERDIR/tcf/json.cpp \
$$MACROSDIR/gdbmacros.cpp \
main.cpp \
INCLUDEPATH += $$DEBUGGERDIR $$UTILSDIR
DEFINES += MACROSDEBUG
INCLUDEPATH += $$DEBUGGERDIR $$UTILSDIR $$MACROSDIR
#include "gdb/gdbmi.h"
#include "tcf/json.h"
#include <QtCore/QObject>
#include <QtCore/QProcess>
#include <QtCore/QFileInfo>
#include <QtTest/QtTest>
#include <QtCore/private/qobject_p.h>
//#include <QtTest/qtest_gui.h>
#include "gdb/gdbmi.h"
#include "tcf/json.h"
#include "gdbmacros.h"
#undef NS
#ifdef QT_NAMESPACE
# define STRINGIFY0(s) #s
# define STRINGIFY1(s) STRINGIFY0(s)
# define NS STRINGIFY1(QT_NAMESPACE) "::"
#else
# define NS ""
#endif
using namespace Debugger;
using namespace Debugger::Internal;
......@@ -98,6 +112,12 @@ private slots:
void niceType();
void niceType_data();
void dumperCompatibility();
void dumpQHash();
void dumpQObject();
void dumpQString();
void dumpStdVector();
public slots:
void runQtc();
......@@ -154,6 +174,10 @@ void tst_Debugger::infoBreak()
QCOMPARE(re.cap(4), QString("124"));
}
//
// type simplification
//
static QString chopConst(QString type)
{
while (1) {
......@@ -175,7 +199,6 @@ QString niceType(QString type)
{
type.replace('*', '@');
int pos;
for (int i = 0; i < 10; ++i) {
int start = type.indexOf("std::allocator<");
if (start == -1)
......@@ -299,6 +322,166 @@ void tst_Debugger::niceType_data()
<< "std::map<const char*, Foo>";
}
//
// Dumpers
//
static void testDumper(QByteArray expected0, void *data, QByteArray outertype,
bool dumpChildren, QByteArray innertype = "", QByteArray exp = "",
int extraInt0 = 0, int extraInt1 = 0, int extraInt2 = 0, int extraInt3 = 0)
{
sprintf(xDumpInBuffer, "%s%c%s%c%s%c%s%c%s%c",
outertype.data(), 0, "iname", 0, exp.data(), 0,
innertype.data(), 0, "iname", 0);
void *res = qDumpObjectData440(2, 42, data, dumpChildren,
extraInt0, extraInt1, extraInt2, extraInt3);
QString expected(expected0);
char buf[100];
sprintf(buf, "%p", data);
if (!expected.startsWith('t') && !expected.startsWith('f'))
expected = "tiname='$I',addr='$A'," + expected;
expected.replace("$I", "iname");
expected.replace("$T", QByteArray(outertype));
expected.replace("$A", QByteArray(buf));
expected.replace('\'', '"');
QString actual____ = QString::fromLatin1(xDumpOutBuffer);
actual____.replace('\'', '"');
QCOMPARE(res, xDumpOutBuffer);
if (actual____ != expected) {
QStringList l1 = actual____.split(",");
QStringList l2 = expected.split(",");
for (int i = 0; i < l1.size() && i < l2.size(); ++i) {
if (l1.at(i) == l2.at(i))
qDebug() << "== " << l1.at(i);
else
qDebug() << "!= " << l1.at(i) << l2.at(i);
}
if (l1.size() != l2.size())
qDebug() << "!= size: " << l1.size() << l2.size();
}
QCOMPARE(actual____, expected);
}
QByteArray str(const void *p)
{
char buf[100];
sprintf(buf, "%p", p);
return buf;
}
static const void *deref(const void *p)
{
return *reinterpret_cast<const char* const*>(p);
}
void tst_Debugger::dumperCompatibility()
{
}
void tst_Debugger::dumpQHash()
{
QHash<QString, QList<int> > hash;
hash.insert("Hallo", QList<int>());
hash.insert("Welt", QList<int>() << 1);
hash.insert("!", QList<int>() << 1 << 2);
hash.insert("!", QList<int>() << 1 << 2);
}
void tst_Debugger::dumpQObject()
{
QObject parent;
testDumper("value='',valueencoded='2',type='$T',displayedtype='QObject',"
"numchild='4'",
&parent, NS"QObject", false);
testDumper("value='',valueencoded='2',type='$T',displayedtype='QObject',"
"numchild='4',children=["
"{name='properties',exp='*(class '$T'*)$A',type='$TPropertyList',"
"value='<1 items>',numchild='1'},"
"{name='signals',exp='*(class '$T'*)$A',type='$TSignalList',"
"value='<2 items>',numchild='2'},"
"{name='slots',exp='*(class '$T'*)$A',type='$TSlotList',"
"value='<2 items>',numchild='2'},"
"{name='parent',value='0x0',type='$T *'},"
"{name='className',value='QObject',type='',numchild='0'}]",
&parent, NS"QObject", true);
testDumper("numchild='2',children=[{name='2',value='deleteLater()',"
"numchild='0',exp='*(class 'QObject'*)$A',type='QObjectSlot'},"
"{name='3',value='_q_reregisterTimers(void*)',"
"numchild='0',exp='*(class 'QObject'*)$A',type='QObjectSlot'}]",
&parent, NS"QObjectSlotList", true);
parent.setObjectName("A Parent");
testDumper("value='QQAgAFAAYQByAGUAbgB0AA==',valueencoded='2',type='$T',"
"displayedtype='QObject',numchild='4'",
&parent, NS"QObject", false);
QObject child(&parent);
testDumper("value='',valueencoded='2',type='$T',"
"displayedtype='QObject',numchild='4'",
&child, NS"QObject", false);
child.setObjectName("A Child");