diff --git a/src/plugins/debugger/gdb/gdbengine.cpp b/src/plugins/debugger/gdb/gdbengine.cpp index 523bcf31c8bf06bcf6e9ec773205eaf0bdc33f4c..168b660478828c6c49b9c9682efaa60eb4e6d085 100644 --- a/src/plugins/debugger/gdb/gdbengine.cpp +++ b/src/plugins/debugger/gdb/gdbengine.cpp @@ -3613,7 +3613,6 @@ WatchData GdbEngine::localVariable(const GdbMi &item, data.iname = "local." + name; data.name = nam; data.exp = name; - data.framekey = m_currentFrame + data.name; setWatchDataType(data, item.findChild("type")); if (uninitializedVariables.contains(data.name)) { data.setError(WatchData::msgNotInScope()); diff --git a/src/plugins/debugger/qml/qmlengine.cpp b/src/plugins/debugger/qml/qmlengine.cpp index 3a03e0da8d069808d7a2603dfbec1c4b67cb70e4..44024385c66ea4f2c054d2a067cda1e02c1215b1 100644 --- a/src/plugins/debugger/qml/qmlengine.cpp +++ b/src/plugins/debugger/qml/qmlengine.cpp @@ -90,7 +90,7 @@ QDataStream& operator>>(QDataStream& s, WatchData &data) QString value; QString type; bool hasChildren; - s >> data.exp >> data.name >> value >> type >> hasChildren >> data.objectId; + s >> data.exp >> data.name >> value >> type >> hasChildren >> data.id; data.setType(type.toUtf8(), false); data.setValue(value); data.setHasChildren(hasChildren); @@ -535,7 +535,7 @@ void QmlEngine::updateWatchData(const Internal::WatchData &data, const Internal: if (!data.name.isEmpty() && data.isChildrenNeeded() && watchHandler()->isExpandedIName(data.iname)) - expandObject(data.iname, data.objectId); + expandObject(data.iname, data.id); { QByteArray reply; @@ -630,7 +630,7 @@ void QmlEngine::messageReceived(const QByteArray &message) if (watchHandler()->expandedINames().contains(data.iname)) { needPing = true; - expandObject(data.iname, data.objectId); + expandObject(data.iname, data.id); } } @@ -640,7 +640,7 @@ void QmlEngine::messageReceived(const QByteArray &message) if (watchHandler()->expandedINames().contains(data.iname)) { needPing = true; - expandObject(data.iname, data.objectId); + expandObject(data.iname, data.id); } } @@ -710,7 +710,7 @@ void QmlEngine::messageReceived(const QByteArray &message) if (watchHandler()->expandedINames().contains(data.iname)) { needPing = true; - expandObject(data.iname, data.objectId); + expandObject(data.iname, data.id); } } if (needPing) @@ -726,7 +726,7 @@ void QmlEngine::messageReceived(const QByteArray &message) watchHandler()->insertData(data); if (watchHandler()->expandedINames().contains(data.iname)) { needPing = true; - expandObject(data.iname, data.objectId); + expandObject(data.iname, data.id); } } if (needPing) diff --git a/src/plugins/debugger/script/scriptengine.cpp b/src/plugins/debugger/script/scriptengine.cpp index 9fb2e337a25d4e657d1a96251064b2668bb1d3ee..09ac194e3d0e9c1a885260500c859cb64fda0e09 100644 --- a/src/plugins/debugger/script/scriptengine.cpp +++ b/src/plugins/debugger/script/scriptengine.cpp @@ -702,9 +702,11 @@ void ScriptEngine::updateLocals() m_scriptEngine->setAgent(0); WatchData data; + data.id = m_watchIdCounter++; + m_watchIdToScriptValue.insert(data.id, context->activationObject()); data.iname = "local"; data.name = _(data.iname); - data.scriptValue = context->activationObject(); + watchHandler()->beginCycle(); updateSubItem(data); watchHandler()->endCycle(); @@ -744,8 +746,8 @@ void ScriptEngine::updateSubItem(const WatchData &data0) //SDEBUG("\nUPDATE SUBITEM: " << data.toString() << data.scriptValue.toString()); QTC_ASSERT(data.isValid(), return); + const QScriptValue &ob = m_watchIdToScriptValue.value(data.id); if (data.isTypeNeeded() || data.isValueNeeded()) { - const QScriptValue &ob = data.scriptValue; if (ob.isArray()) { data.setType("Array", false); data.setValue(QString(QLatin1Char(' '))); @@ -802,14 +804,15 @@ void ScriptEngine::updateSubItem(const WatchData &data0) } if (data.isChildrenNeeded()) { - QScriptValueIterator it(data.scriptValue); + QScriptValueIterator it(ob); while (it.hasNext()) { it.next(); WatchData data1; data1.iname = data.iname + '.' + it.name().toLatin1(); data1.exp = it.name().toLatin1(); data1.name = it.name(); - data1.scriptValue = it.value(); + data.id = m_watchIdCounter++; + m_watchIdToScriptValue.insert(data.id, it.value()); if (watchHandler()->isExpandedIName(data1.iname)) { data1.setChildrenNeeded(); } else { @@ -822,7 +825,7 @@ void ScriptEngine::updateSubItem(const WatchData &data0) } if (data.isHasChildrenNeeded()) { - QScriptValueIterator it(data.scriptValue); + QScriptValueIterator it(ob); data.setHasChildren(it.hasNext()); } diff --git a/src/plugins/debugger/script/scriptengine.h b/src/plugins/debugger/script/scriptengine.h index bd615eeea4eaea2e66943b8228d5aed86314bb83..82b6894fa78e1e0219f50ce6fa138ecf6dba2c73 100644 --- a/src/plugins/debugger/script/scriptengine.h +++ b/src/plugins/debugger/script/scriptengine.h @@ -34,6 +34,7 @@ #include <QtCore/QSharedPointer> #include <QtCore/QScopedPointer> +#include <QtCore/QHash> QT_BEGIN_NAMESPACE class QScriptEngine; @@ -114,6 +115,8 @@ private: QString m_scriptContents; QString m_scriptFileName; QScopedPointer<ScriptAgent> m_scriptAgent; + QHash<quint64,QScriptValue> m_watchIdToScriptValue; + quint64 m_watchIdCounter; bool m_stopped; bool m_stopOnNextLine; diff --git a/src/plugins/debugger/watchdata.cpp b/src/plugins/debugger/watchdata.cpp index b21d1609f6a460c6c05856852d41f433f20127d4..880ed4fb5268e84d7b6d1abd261b323963545941 100644 --- a/src/plugins/debugger/watchdata.cpp +++ b/src/plugins/debugger/watchdata.cpp @@ -1,12 +1,10 @@ #include "watchdata.h" -#include "watchutils.h" #include <QtCore/QTextStream> #include <QtCore/QDebug> -#include <QtGui/QApplication> -#include <QtGui/QTextDocument> // Qt::escape +#include <QtCore/QCoreApplication> //////////////////////////////////////////////////////////////////// // @@ -17,19 +15,107 @@ namespace Debugger { namespace Internal { +enum GuessChildrenResult { HasChildren, HasNoChildren, HasPossiblyChildren }; +static QString qt_escape(const QString& plain) +{ + QString rich; + rich.reserve(int(plain.length() * 1.1)); + for (int i = 0; i < plain.length(); ++i) { + if (plain.at(i) == QLatin1Char('<')) + rich += QLatin1String("<"); + else if (plain.at(i) == QLatin1Char('>')) + rich += QLatin1String(">"); + else if (plain.at(i) == QLatin1Char('&')) + rich += QLatin1String("&"); + else if (plain.at(i) == QLatin1Char('"')) + rich += QLatin1String("""); + else + rich += plain.at(i); + } + return rich; +} + +bool isPointerType(const QByteArray &type) +{ + return type.endsWith('*') || type.endsWith("* const"); +} + +bool isCharPointerType(const QByteArray &type) +{ + return type == "char *" || type == "const char *" || type == "char const *"; +} + +bool isIntType(const QByteArray &type) +{ + if (type.isEmpty()) + return false; + switch (type.at(0)) { + case 'b': + return type == "bool"; + case 'c': + return type == "char"; + case 'i': + return type == "int" || type == "int64"; + case 'l': + return type == "long" + || type == "long long"; + case 'p': + return type == "ptrdiff_t"; + case 'q': + return type == "qint16" || type == "quint16" + || type == "qint32" || type == "quint32" + || type == "qint64" || type == "quint64"; + case 's': + return type == "short" + || type == "signed" + || type == "size_t" + || type == "std::size_t" + || type == "std::ptrdiff_t" + || type.startsWith("signed "); + case 'u': + return type == "unsigned" + || type.startsWith("unsigned "); + default: + return false; + } +} + +bool isFloatType(const QByteArray &type) +{ + return type == "float" || type == "double" || type == "qreal"; +} + +bool isIntOrFloatType(const QByteArray &type) +{ + return isIntType(type) || isFloatType(type); +} + +GuessChildrenResult guessChildren(const QByteArray &type) +{ + if (isIntOrFloatType(type)) + return HasNoChildren; + if (isCharPointerType(type)) + return HasNoChildren; + if (isPointerType(type)) + return HasChildren; + if (type.endsWith("QString")) + return HasNoChildren; + return HasPossiblyChildren; +} + WatchData::WatchData() : + id(0), + state(InitialState), editformat(0), address(0), - hasChildren(false), generation(-1), + hasChildren(false), valueEnabled(true), valueEditable(true), error(false), - source(0), - objectId(0), - state(InitialState), changed(false), - sortId(0) + sortId(0), + source(0) { } @@ -45,7 +131,6 @@ bool WatchData::isEqual(const WatchData &other) const && displayedType == other.displayedType && variable == other.variable && address == other.address - && framekey == other.framekey && hasChildren == other.hasChildren && valueEnabled == other.valueEnabled && valueEditable == other.valueEditable @@ -213,8 +298,6 @@ QString WatchData::toString() const if (isChildrenNeeded()) str << "children=<needed>,"; - if (source) - str << "source=" << source; str.flush(); if (res.endsWith(QLatin1Char(','))) res.truncate(res.size() - 1); @@ -226,7 +309,7 @@ static void formatToolTipRow(QTextStream &str, const QString &category, const QString &value) { str << "<tr><td>" << category << "</td><td> : </td><td>" - << Qt::escape(value) << "</td></tr>"; + << qt_escape(value) << "</td></tr>"; } static QString typeToolTip(const WatchData &wd) @@ -247,19 +330,19 @@ QString WatchData::toToolTip() const QString res; QTextStream str(&res); str << "<html><body><table>"; - formatToolTipRow(str, QCoreApplication::translate("Debugger::Internal::WatchHandler", "Name"), name); - formatToolTipRow(str, QCoreApplication::translate("Debugger::Internal::WatchHandler", "Expression"), exp); - formatToolTipRow(str, QCoreApplication::translate("Debugger::Internal::WatchHandler", "Type"), typeToolTip(*this)); + formatToolTipRow(str, tr("Name"), name); + formatToolTipRow(str, tr("Expression"), exp); + formatToolTipRow(str, tr("Type"), typeToolTip(*this)); QString val = value; if (value.size() > 1000) { val.truncate(1000); - val += QCoreApplication::translate("Debugger::Internal::WatchHandler", " ... <cut off>"); + val += tr(" ... <cut off>"); } - formatToolTipRow(str, QCoreApplication::translate("Debugger::Internal::WatchHandler", "Value"), val); - formatToolTipRow(str, QCoreApplication::translate("Debugger::Internal::WatchHandler", "Object Address"), + formatToolTipRow(str, tr("Value"), val); + formatToolTipRow(str, tr("Object Address"), QString::fromAscii(hexAddress())); - formatToolTipRow(str, QCoreApplication::translate("Debugger::Internal::WatchHandler", "Internal ID"), iname); - formatToolTipRow(str, QCoreApplication::translate("Debugger::Internal::WatchHandler", "Generation"), + formatToolTipRow(str, tr("Internal ID"), iname); + formatToolTipRow(str, tr("Generation"), QString::number(generation)); str << "</table></body></html>"; return res; diff --git a/src/plugins/debugger/watchdata.h b/src/plugins/debugger/watchdata.h index f36fce1fe6502227234279e8d6ed3b27a49ed643..370ef897abb58c928bc59c21e9ead818140ec70e 100644 --- a/src/plugins/debugger/watchdata.h +++ b/src/plugins/debugger/watchdata.h @@ -33,6 +33,7 @@ #include <QtCore/QMetaType> #include <QtCore/QtGlobal> #include <QtCore/QObject> +#include <QtCore/QCoreApplication> #include <QtScript/QScriptValue> namespace Debugger { @@ -45,11 +46,11 @@ public: enum State { - Complete = 0, + Complete = 0, HasChildrenNeeded = 1, - ValueNeeded = 2, - TypeNeeded = 4, - ChildrenNeeded = 8, + ValueNeeded = 2, + TypeNeeded = 4, + ChildrenNeeded = 8, NeededMask = ValueNeeded | TypeNeeded @@ -62,81 +63,84 @@ public: | HasChildrenNeeded }; - void setValue(const QString &); - void setType(const QByteArray &, bool guessChildrenFromType = true); - void setValueToolTip(const QString &); - void setError(const QString &); - void setAddress(const quint64 &); - void setHexAddress(const QByteArray &a); - bool isSomethingNeeded() const { return state & NeededMask; } - void setAllNeeded() { state = NeededMask; } - void setAllUnneeded() { state = State(0); } + void setAllNeeded() { state = NeededMask; } + void setAllUnneeded() { state = State(0); } bool isTypeNeeded() const { return state & TypeNeeded; } - bool isTypeKnown() const { return !(state & TypeNeeded); } - void setTypeNeeded() { state = State(state | TypeNeeded); } - void setTypeUnneeded() { state = State(state & ~TypeNeeded); } + bool isTypeKnown() const { return !(state & TypeNeeded); } + void setTypeNeeded() { state = State(state | TypeNeeded); } + void setTypeUnneeded() { state = State(state & ~TypeNeeded); } bool isValueNeeded() const { return state & ValueNeeded; } - bool isValueKnown() const { return !(state & ValueNeeded); } - void setValueNeeded() { state = State(state | ValueNeeded); } - void setValueUnneeded() { state = State(state & ~ValueNeeded); } + bool isValueKnown() const { return !(state & ValueNeeded); } + void setValueNeeded() { state = State(state | ValueNeeded); } + void setValueUnneeded() { state = State(state & ~ValueNeeded); } bool isChildrenNeeded() const { return state & ChildrenNeeded; } - bool isChildrenKnown() const { return !(state & ChildrenNeeded); } - void setChildrenNeeded() { state = State(state | ChildrenNeeded); } + bool isChildrenKnown() const { return !(state & ChildrenNeeded); } + void setChildrenNeeded() { state = State(state | ChildrenNeeded); } void setChildrenUnneeded() { state = State(state & ~ChildrenNeeded); } bool isHasChildrenNeeded() const { return state & HasChildrenNeeded; } - bool isHasChildrenKnown() const { return !(state & HasChildrenNeeded); } - void setHasChildrenNeeded() { state = State(state | HasChildrenNeeded); } + bool isHasChildrenKnown() const { return !(state & HasChildrenNeeded); } + void setHasChildrenNeeded() { state = State(state | HasChildrenNeeded); } void setHasChildrenUnneeded() { state = State(state & ~HasChildrenNeeded); } - void setHasChildren(bool c) { hasChildren = c; setHasChildrenUnneeded(); - if (!c) setChildrenUnneeded(); } + void setHasChildren(bool c) { hasChildren = c; setHasChildrenUnneeded(); + if (!c) setChildrenUnneeded(); } - QString toString() const; - QString toToolTip() const; - bool isLocal() const { return iname.startsWith("local."); } + bool isLocal() const { return iname.startsWith("local."); } bool isWatcher() const { return iname.startsWith("watch."); } - bool isValid() const { return !iname.isEmpty(); } + bool isValid() const { return !iname.isEmpty(); } bool isEqual(const WatchData &other) const; - quint64 coreAddress() const; - QByteArray hexAddress() const; + + void setError(const QString &); + void setValue(const QString &); + void setValueToolTip(const QString &); + void setType(const QByteArray &, bool guessChildrenFromType = true); + void setAddress(const quint64 &); + void setHexAddress(const QByteArray &a); + + QString toString() const; + QString toToolTip() const; static QString msgNotInScope(); static QString shadowedName(const QString &name, int seen); static const QString &shadowedNameFormat(); + quint64 coreAddress() const; + QByteArray hexAddress() const; + public: - QByteArray iname; // Internal name sth like 'local.baz.public.a' - QByteArray exp; // The expression - QString name; // Displayed name - QString value; // Displayed value - QByteArray editvalue; // Displayed value - int editformat; // Format of displayed value - QString valuetooltip; // Tooltip in value column - QString typeFormats; // Selection of formats of displayed value + quint64 id; // Token for the engine for internal mapping + qint32 state; // 'needed' flags; + QByteArray iname; // Internal name sth like 'local.baz.public.a' + QByteArray exp; // The expression + QString name; // Displayed name + QString value; // Displayed value + QByteArray editvalue; // Displayed value + qint32 editformat; // Format of displayed value + QString valuetooltip; // Tooltip in value column + QString typeFormats; // Selection of formats of displayed value QByteArray type; // Type for further processing - QString displayedType;// Displayed type (optional) - QByteArray variable; // Name of internal Gdb variable if created - quint64 address; // Displayed address - QString framekey; // Key for type cache - QScriptValue scriptValue; // If needed... + QString displayedType;// Displayed type (optional) + quint64 address; // Displayed address + qint32 generation; // When updated? bool hasChildren; - int generation; // When updated? - bool valueEnabled; // Value will be greyed out or not - bool valueEditable; // Value will be editable + bool valueEnabled; // Value will be greyed out or not + bool valueEditable; // Value will be editable bool error; + bool changed; + qint32 sortId; QByteArray dumperFlags; + Q_DECLARE_TR_FUNCTIONS(Debugger::Internal::WatchHandler) + public: - int source; // Originated from dumper or symbol evaluation? (CDB only) - quint64 objectId; // Object id used for the QMLEngine - int state; - bool changed; - int sortId; + // FIXME: this is engine specific data that should be mapped internally + QByteArray variable; // Name of internal Gdb variable if created + qint32 source; // Originated from dumper or symbol evaluation? (CDB only) }; } // namespace Internal diff --git a/src/plugins/debugger/watchutils.cpp b/src/plugins/debugger/watchutils.cpp index dd0a1dff049cb22b540d3f4b610654a627a63bea..7c02512cb9571dd96258a5e223503c3c5fff17fe 100644 --- a/src/plugins/debugger/watchutils.cpp +++ b/src/plugins/debugger/watchutils.cpp @@ -273,16 +273,6 @@ bool isKeyWord(const QString &exp) || exp == QLatin1String("while"); } -bool isPointerType(const QByteArray &type) -{ - return type.endsWith('*') || type.endsWith("* const"); -} - -bool isCharPointerType(const QByteArray &type) -{ - return type == "char *" || type == "const char *" || type == "char const *"; -} - bool startsWithDigit(const QString &str) { return !str.isEmpty() && str.at(0).isDigit(); @@ -540,69 +530,11 @@ QString extractTypeFromPTypeOutput(const QString &str) return res.simplified(); } -bool isIntType(const QByteArray &type) -{ - if (type.isEmpty()) - return false; - switch (type.at(0)) { - case 'b': - return type == "bool"; - case 'c': - return type == "char"; - case 'i': - return type == "int" || type == "int64"; - case 'l': - return type == "long" - || type == "long long"; - case 'p': - return type == "ptrdiff_t"; - case 'q': - return type == "qint16" || type == "quint16" - || type == "qint32" || type == "quint32" - || type == "qint64" || type == "quint64"; - case 's': - return type == "short" - || type == "signed" - || type == "size_t" - || type == "std::size_t" - || type == "std::ptrdiff_t" - || type.startsWith("signed "); - case 'u': - return type == "unsigned" - || type.startsWith("unsigned "); - default: - return false; - } -} - bool isSymbianIntType(const QByteArray &type) { return type == "TInt" || type == "TBool"; } -bool isFloatType(const QByteArray &type) -{ - return type == "float" || type == "double" || type == "qreal"; -} - -bool isIntOrFloatType(const QByteArray &type) -{ - return isIntType(type) || isFloatType(type); -} - -GuessChildrenResult guessChildren(const QByteArray &type) -{ - if (isIntOrFloatType(type)) - return HasNoChildren; - if (isCharPointerType(type)) - return HasNoChildren; - if (isPointerType(type)) - return HasChildren; - if (type.endsWith("QString")) - return HasNoChildren; - return HasPossiblyChildren; -} - QByteArray sizeofTypeExpression(const QByteArray &type, QtDumperHelper::Debugger debugger) { if (type.endsWith('*'))