diff --git a/src/plugins/debugger/cdb/cdbengine.cpp b/src/plugins/debugger/cdb/cdbengine.cpp index fd27371ff50..6e13f5302f9 100644 --- a/src/plugins/debugger/cdb/cdbengine.cpp +++ b/src/plugins/debugger/cdb/cdbengine.cpp @@ -1012,30 +1012,62 @@ void CdbEngine::executeJumpToLine(const QString & /* fileName */, int /*lineNumb warning(tr("Jump to line is not implemented")); } -void CdbEngine::assignValueInDebugger(const QString &expr, const QString &value) +void CdbEngine::assignValueInDebugger(const WatchData *w, const QString &expr, const QVariant &valueV) { if (debugCDB) - qDebug() << Q_FUNC_INFO << expr << value; + qDebug() << Q_FUNC_INFO << w->iname << expr << valueV; const int frameIndex = stackHandler()->currentIndex(); QString errorMessage; bool success = false; + QApplication::setOverrideCursor(Qt::BusyCursor); + const QString iname = QLatin1String(w->iname); + const QString type = QLatin1String(w->type); + const QString newValue = valueV.toString(); + showMessage(tr("Assigning '%1' to '%2' (%3)...").arg(newValue, iname, type), LogMisc); do { - QString newValue; + // Value must be scalar + const QVariant::Type type = valueV.type(); + if (type != QVariant::Double && type != QVariant::Bool + && type != QVariant::Int && type != QVariant::LongLong + && type != QVariant::UInt&& type != QVariant::ULongLong) { + errorMessage = tr("Cannot assign only scalar values."); + break; + } + // Check the assigneable type + const bool isInt = isIntType(w->type); + const bool isFloat = !isInt && isFloatType(w->type); + const bool isPointer = !isInt && !isFloat && isPointerType(w->type); + if (!isInt && !isFloat & !isPointer) { + errorMessage = tr("Cannot assign values of type '%1'. Only POD-types can be assigned.").arg(type); + break; + } CdbSymbolGroupContext *sg = m_d->getSymbolGroupContext(frameIndex, &errorMessage); if (!sg) break; - if (!sg->assignValue(expr, value, &newValue, &errorMessage)) + QString newValueObtained; + if (!sg->assignValue(w->iname, newValue, &newValueObtained, &errorMessage)) break; + // Fix the crappy values returned by the symbol group (0n, etc). + // Return pointers as hex + if (isInt || isPointer) { + const QVariant v = CdbCore::SymbolGroupContext::getIntValue(newValueObtained); + if (v.isValid()) + newValueObtained = isPointer ? + (QLatin1String("0x") + QString::number(v.toULongLong(), 16)): + v.toString(); + } // Update view - if (WatchData *fwd = watchHandler()->findItem(expr.toLatin1())) { - fwd->setValue(newValue); + if (WatchData *fwd = watchHandler()->findItem(w->iname)) { + fwd->setValue(newValueObtained); watchHandler()->insertData(*fwd); watchHandler()->updateWatchers(); } success = true; } while (false); + QApplication::restoreOverrideCursor(); if (!success) { - const QString msg = tr("Unable to assign the value '%1' to '%2': %3").arg(value, expr, errorMessage); + const QString msg = tr("Unable to assign the value '%1' to '%2' (%3): %4"). + arg(newValue, expr, type, errorMessage); warning(msg); } } diff --git a/src/plugins/debugger/cdb/cdbengine.h b/src/plugins/debugger/cdb/cdbengine.h index 8dba973dd34..818b327b0e4 100644 --- a/src/plugins/debugger/cdb/cdbengine.h +++ b/src/plugins/debugger/cdb/cdbengine.h @@ -77,7 +77,7 @@ public: virtual void executeRunToLine(const QString &fileName, int lineNumber); virtual void executeRunToFunction(const QString &functionName); virtual void executeJumpToLine(const QString &fileName, int lineNumber); - virtual void assignValueInDebugger(const QString &expr, const QString &value); + virtual void assignValueInDebugger(const WatchData *w, const QString &expr, const QVariant &value); virtual void executeDebuggerCommand(const QString &command); virtual void activateFrame(int index); diff --git a/src/plugins/debugger/cdb/cdbsymbolgroupcontext.cpp b/src/plugins/debugger/cdb/cdbsymbolgroupcontext.cpp index 2f4bce52ca9..fae1a564244 100644 --- a/src/plugins/debugger/cdb/cdbsymbolgroupcontext.cpp +++ b/src/plugins/debugger/cdb/cdbsymbolgroupcontext.cpp @@ -225,21 +225,17 @@ bool WatchHandleDumperInserter::expandPointerToDumpable(const WatchData &wd, QSt bool handled = false; do { - if (wd.error || !isPointerType(wd.type)) + // Must be a clas pointer item and a non-null-pointer. + if (wd.error || !(wd.source & CdbSymbolGroupContext::ClassPointerBit) + || !isPointerType(wd.type)) break; - const int classPos = wd.value.indexOf(" class "); - if (classPos == -1) - break; - // Fix CDB word separator '0x00000000`0012fe10'. - QString hexAddrS = wd.value.mid(0, classPos); - if (hexAddrS.size() > 11 && hexAddrS.at(10) == QLatin1Char('`')) - hexAddrS.remove(10, 1); - if (m_hexNullPattern.exactMatch(hexAddrS)) + quint64 address = 0; + if (!CdbCore::SymbolGroupContext::getUnsignedHexValue(wd.value, &address) || address == 0) break; const QByteArray type = stripPointerType(wd.type); WatchData derefedWd; derefedWd.setType(type); - derefedWd.setHexAddress(hexAddrS.toAscii()); + derefedWd.address = address; derefedWd.name = QString(QLatin1Char('*')); derefedWd.iname = wd.iname + ".*"; derefedWd.source = OwnerDumper | CdbSymbolGroupContext::ChildrenKnownBit; @@ -348,19 +344,42 @@ CdbSymbolGroupContext *CdbSymbolGroupContext::create(const QString &prefix, // Fix display values: Pass through strings, convert unsigned integers // to decimal ('0x5454`fedf'), remove inner templates from // "0x4343 class list<>". -static inline QString fixValue(const QString &value, const QByteArray &type) +static inline QString fixValue(const QString &value, const QByteArray &type, bool *isClassPointer) { - // Pass through strings - if (value.endsWith(QLatin1Char('"'))) + *isClassPointer = false; + // Pass through complete strings. Note that char pointers + // (0x00A "hallo") will be reformatted below. + const QChar doubleQuote = QLatin1Char('"'); + if (value.startsWith(doubleQuote) && value.endsWith(doubleQuote)) return value; - const int size = value.size(); // Real Integer numbers Unsigned hex numbers (0x)/decimal numbers (0n) if (type != "bool" && isIntType(type)) { const QVariant intValue = CdbCore::SymbolGroupContext::getIntValue(value); if (intValue.isValid()) return intValue.toString(); } - return size < 20 ? value : CdbCore::SymbolGroupContext::removeInnerTemplateType(value); + /* Pointers: Fix the address and strip off lengthy class type specifications + * "0x00000000`000045AA "hallo" -> "0x45AA "hallo" + * "0x00000000`000045AA class Bla *" -> "0x45AA" */ + if (isPointerType(type)) { + quint64 ptrValue; + int endPos; + if (CdbCore::SymbolGroupContext::getUnsignedHexValue(value, &ptrValue, &endPos)) { + QString fixedValue = QString::fromAscii("0x%1").arg(ptrValue, 0, 16); + // What is the second token... + if (endPos < value.size() - 1) { + const QString token = value.mid(endPos + 1); + if (token.startsWith(QLatin1String("class")) || token.startsWith(QLatin1String("struct"))) { + *isClassPointer = true; + } else { + fixedValue += QLatin1Char(' '); + fixedValue += token; + } + } // has token + return fixedValue; + } // pointer value conversion ok + } + return value; } unsigned CdbSymbolGroupContext::watchDataAt(unsigned long index, WatchData *wd) @@ -378,8 +397,10 @@ unsigned CdbSymbolGroupContext::watchDataAt(unsigned long index, WatchData *wd) if (rc & OutOfScope) { wd->setError(WatchData::msgNotInScope()); } else { - wd->setValue(fixValue(value, type.toUtf8())); - + bool isClassPointer; + wd->setValue(fixValue(value, type.toUtf8(), &isClassPointer)); + if (isClassPointer) + wd->source |= CdbSymbolGroupContext::ClassPointerBit; const bool hasChildren = rc & HasChildren; wd->setHasChildren(hasChildren); if (hasChildren) diff --git a/src/plugins/debugger/cdb/cdbsymbolgroupcontext.h b/src/plugins/debugger/cdb/cdbsymbolgroupcontext.h index f0dd2e67858..ac276f5e5b4 100644 --- a/src/plugins/debugger/cdb/cdbsymbolgroupcontext.h +++ b/src/plugins/debugger/cdb/cdbsymbolgroupcontext.h @@ -65,7 +65,11 @@ class CdbSymbolGroupContext : public CdbCore::SymbolGroupContext public: // Mask bits for the source field of watch data. - enum { SourceMask = 0xFF, ChildrenKnownBit = 0x0100 }; + enum { SourceMask = 0xFF, + // We know the children although the WatchModel does not believe us. + ChildrenKnownBit = 0x0100, + // Is a pointer to a potentially dumpeable class. + ClassPointerBit = 0x0200 }; static CdbSymbolGroupContext *create(const QString &prefix, CIDebugSymbolGroup *symbolGroup, diff --git a/src/plugins/debugger/cdb/symbolgroupcontext.cpp b/src/plugins/debugger/cdb/symbolgroupcontext.cpp index a921f50b4d4..569d20c5e44 100644 --- a/src/plugins/debugger/cdb/symbolgroupcontext.cpp +++ b/src/plugins/debugger/cdb/symbolgroupcontext.cpp @@ -440,21 +440,25 @@ QString SymbolGroupContext::symbolINameAt(unsigned long index) const // Return hexadecimal pointer value from a CDB pointer value // which look like "0x000032a" or "0x00000000`0250124a" or // "0x1`0250124a" on 64-bit systems. -bool SymbolGroupContext::getUnsignedHexValue(QString stringValue, quint64 *value) +bool SymbolGroupContext::getUnsignedHexValue(QString stringValue, quint64 *value, + int *endPos /* = 0 */) { + if (endPos) + *endPos = -1; *value = 0; if (!stringValue.startsWith(QLatin1String("0x"))) return false; - stringValue.remove(0, 2); - // Chop off character values (0x76 'a') + // Chop off character values (0x76 'a') and return right end position const int blankPos = stringValue.indexOf(QLatin1Char(' ')); + if (endPos) + *endPos = blankPos != -1 ? blankPos : stringValue.size(); if (blankPos != -1) stringValue.truncate(blankPos); + stringValue.remove(0, 2); // Remove '0x', as checked above // Remove 64bit separator if (stringValue.size() > 9) { - const int sepPos = stringValue.size() - 9; - if (stringValue.at(sepPos) == QLatin1Char('`')) - stringValue.remove(sepPos, 1); + if (stringValue.at(8) == QLatin1Char('`')) + stringValue.remove(8, 1); } bool ok; *value = stringValue.toULongLong(&ok, 16); diff --git a/src/plugins/debugger/cdb/symbolgroupcontext.h b/src/plugins/debugger/cdb/symbolgroupcontext.h index 2c10d315752..214af95dfc0 100644 --- a/src/plugins/debugger/cdb/symbolgroupcontext.h +++ b/src/plugins/debugger/cdb/symbolgroupcontext.h @@ -115,7 +115,7 @@ public: // For 64bit values (returned as dec), potentially '0n..'. static bool getDecimalIntValue(QString stringValue, qint64 *value); // For pointers and 64bit values (returned as hex) - static bool getUnsignedHexValue(QString stringValue, quint64 *value); + static bool getUnsignedHexValue(QString stringValue, quint64 *value, int *endPos = 0); // Convenience to return an integer (hex/decimal) as matching variant (signed/unsigned). static QVariant getIntValue(const QString &stringValue); diff --git a/src/plugins/debugger/debuggerengine.cpp b/src/plugins/debugger/debuggerengine.cpp index 5f05753b058..0af9b3d6eb0 100644 --- a/src/plugins/debugger/debuggerengine.cpp +++ b/src/plugins/debugger/debuggerengine.cpp @@ -1671,7 +1671,7 @@ void DebuggerEngine::selectThread(int) { } -void DebuggerEngine::assignValueInDebugger(const QString &, const QString &) +void DebuggerEngine::assignValueInDebugger(const Internal::WatchData *, const QString &, const QVariant &) { } diff --git a/src/plugins/debugger/debuggerengine.h b/src/plugins/debugger/debuggerengine.h index 6f2df32ee19..f42ffd26e11 100644 --- a/src/plugins/debugger/debuggerengine.h +++ b/src/plugins/debugger/debuggerengine.h @@ -184,7 +184,7 @@ public: virtual void attemptBreakpointSynchronization(); virtual void selectThread(int index); - virtual void assignValueInDebugger(const QString &expr, const QString &value); + virtual void assignValueInDebugger(const Internal::WatchData *w, const QString &expr, const QVariant &value); virtual void removeTooltip(); // Convenience diff --git a/src/plugins/debugger/gdb/gdbengine.cpp b/src/plugins/debugger/gdb/gdbengine.cpp index 9782d8319d3..44764e86c5a 100644 --- a/src/plugins/debugger/gdb/gdbengine.cpp +++ b/src/plugins/debugger/gdb/gdbengine.cpp @@ -3647,11 +3647,11 @@ void GdbEngine::insertData(const WatchData &data0) watchHandler()->insertData(data); } -void GdbEngine::assignValueInDebugger(const QString &expression, const QString &value) +void GdbEngine::assignValueInDebugger(const Internal::WatchData *, const QString &expression, const QVariant &value) { postCommand("-var-delete assign"); postCommand("-var-create assign * " + expression.toLatin1()); - postCommand("-var-assign assign " + GdbMi::escapeCString(value.toLatin1()), + postCommand("-var-assign assign " + GdbMi::escapeCString(value.toString().toLatin1()), Discardable, CB(handleVarAssign)); } diff --git a/src/plugins/debugger/gdb/gdbengine.h b/src/plugins/debugger/gdb/gdbengine.h index 817ec77672d..2def4f25bdf 100644 --- a/src/plugins/debugger/gdb/gdbengine.h +++ b/src/plugins/debugger/gdb/gdbengine.h @@ -450,7 +450,7 @@ private: ////////// View & Data Stuff ////////// virtual void setToolTipExpression(const QPoint &mousePos, TextEditor::ITextEditor *editor, int cursorPos); - virtual void assignValueInDebugger(const QString &expr, const QString &value); + virtual void assignValueInDebugger(const Internal::WatchData *w, const QString &expr, const QVariant &value); virtual void fetchMemory(MemoryViewAgent *agent, QObject *token, quint64 addr, quint64 length); diff --git a/src/plugins/debugger/pdb/pdbengine.cpp b/src/plugins/debugger/pdb/pdbengine.cpp index 70fa64043db..dd55400e008 100644 --- a/src/plugins/debugger/pdb/pdbengine.cpp +++ b/src/plugins/debugger/pdb/pdbengine.cpp @@ -543,14 +543,13 @@ void PdbEngine::setToolTipExpression(const QPoint &mousePos, // ////////////////////////////////////////////////////////////////////// -void PdbEngine::assignValueInDebugger(const QString &expression, - const QString &value) +void PdbEngine::assignValueInDebugger(const Internal::WatchData *, const QString &expression, const QVariant &value) { Q_UNUSED(expression); Q_UNUSED(value); - SDEBUG("ASSIGNING: " << (expression + QLatin1Char('=') + value)); + SDEBUG("ASSIGNING: " << (expression + QLatin1Char('=') + value.toString())); #if 0 - m_scriptEngine->evaluate(expression + QLatin1Char('=') + value); + m_scriptEngine->evaluate(expression + QLatin1Char('=') + value.toString()); updateLocals(); #endif } diff --git a/src/plugins/debugger/pdb/pdbengine.h b/src/plugins/debugger/pdb/pdbengine.h index 879cde497ba..c65509ba6fc 100644 --- a/src/plugins/debugger/pdb/pdbengine.h +++ b/src/plugins/debugger/pdb/pdbengine.h @@ -90,7 +90,7 @@ private: void attemptBreakpointSynchronization(); - void assignValueInDebugger(const QString &expr, const QString &value); + void assignValueInDebugger(const Internal::WatchData *w, const QString &expr, const QVariant &value); void executeDebuggerCommand(const QString &command); void loadSymbols(const QString &moduleName); diff --git a/src/plugins/debugger/qml/qmlcppengine.cpp b/src/plugins/debugger/qml/qmlcppengine.cpp index 52e5517219e..90489310c9b 100644 --- a/src/plugins/debugger/qml/qmlcppengine.cpp +++ b/src/plugins/debugger/qml/qmlcppengine.cpp @@ -227,9 +227,9 @@ void QmlCppEngine::selectThread(int index) d->m_cppEngine->selectThread(index); } -void QmlCppEngine::assignValueInDebugger(const QString &expr, const QString &value) +void QmlCppEngine::assignValueInDebugger(const Internal::WatchData *w, const QString &expr, const QVariant &value) { - d->m_activeEngine->assignValueInDebugger(expr, value); + d->m_activeEngine->assignValueInDebugger(w, expr, value); } QAbstractItemModel *QmlCppEngine::commandModel() const diff --git a/src/plugins/debugger/qml/qmlcppengine.h b/src/plugins/debugger/qml/qmlcppengine.h index 258bad3e26f..9bdf2a6781b 100644 --- a/src/plugins/debugger/qml/qmlcppengine.h +++ b/src/plugins/debugger/qml/qmlcppengine.h @@ -54,7 +54,7 @@ public: virtual void attemptBreakpointSynchronization(); virtual void selectThread(int index); - virtual void assignValueInDebugger(const QString &expr, const QString &value); + virtual void assignValueInDebugger(const Internal::WatchData *w, const QString &expr, const QVariant &value); QAbstractItemModel *commandModel() const; QAbstractItemModel *modulesModel() const; diff --git a/src/plugins/debugger/qml/qmlengine.cpp b/src/plugins/debugger/qml/qmlengine.cpp index e714f03c433..4545bc3d9b5 100644 --- a/src/plugins/debugger/qml/qmlengine.cpp +++ b/src/plugins/debugger/qml/qmlengine.cpp @@ -488,8 +488,8 @@ void QmlEngine::setToolTipExpression(const QPoint &mousePos, TextEditor::ITextEd // ////////////////////////////////////////////////////////////////////// -void QmlEngine::assignValueInDebugger(const QString &expression, - const QString &value) +void QmlEngine::assignValueInDebugger(const Internal::WatchData *, + const QString &expression, const QVariant &valueV) { QRegExp inObject("@([0-9a-fA-F]+)->(.+)"); if (inObject.exactMatch(expression)) { @@ -500,7 +500,7 @@ void QmlEngine::assignValueInDebugger(const QString &expression, QByteArray reply; QDataStream rs(&reply, QIODevice::WriteOnly); rs << QByteArray("SET_PROPERTY"); - rs << expression.toUtf8() << objectId << property << value; + rs << expression.toUtf8() << objectId << property << valueV.toString(); sendMessage(reply); } } diff --git a/src/plugins/debugger/qml/qmlengine.h b/src/plugins/debugger/qml/qmlengine.h index b50d877ea9c..5f12e25eee5 100644 --- a/src/plugins/debugger/qml/qmlengine.h +++ b/src/plugins/debugger/qml/qmlengine.h @@ -94,7 +94,7 @@ private: void attemptBreakpointSynchronization(); - void assignValueInDebugger(const QString &expr, const QString &value); + void assignValueInDebugger(const Internal::WatchData *w, const QString &expr, const QVariant &value); void loadSymbols(const QString &moduleName); void loadAllSymbols(); void requestModuleSymbols(const QString &moduleName); diff --git a/src/plugins/debugger/registerhandler.cpp b/src/plugins/debugger/registerhandler.cpp index 5c2d85352cb..3d641b3587b 100644 --- a/src/plugins/debugger/registerhandler.cpp +++ b/src/plugins/debugger/registerhandler.cpp @@ -54,7 +54,7 @@ using namespace Debugger::Constants; ////////////////////////////////////////////////////////////////// RegisterHandler::RegisterHandler(DebuggerEngine *engine) - : m_engine(engine) + : m_engine(engine), m_base(15) { setNumberBase(16); } diff --git a/src/plugins/debugger/script/scriptengine.cpp b/src/plugins/debugger/script/scriptengine.cpp index f5b36383bbc..9fb2e337a25 100644 --- a/src/plugins/debugger/script/scriptengine.cpp +++ b/src/plugins/debugger/script/scriptengine.cpp @@ -581,11 +581,11 @@ void ScriptEngine::setToolTipExpression(const QPoint &mousePos, // ////////////////////////////////////////////////////////////////////// -void ScriptEngine::assignValueInDebugger(const QString &expression, - const QString &value) +void ScriptEngine::assignValueInDebugger(const Internal::WatchData *, + const QString &expression, const QVariant &value) { - SDEBUG("ASSIGNING: " << (expression + QLatin1Char('=') + value)); - m_scriptEngine->evaluate(expression + QLatin1Char('=') + value); + SDEBUG("ASSIGNING: " << (expression + QLatin1Char('=') + value.toString())); + m_scriptEngine->evaluate(expression + QLatin1Char('=') + value.toString()); updateLocals(); } diff --git a/src/plugins/debugger/script/scriptengine.h b/src/plugins/debugger/script/scriptengine.h index 7aa58d01303..bd615eeea4e 100644 --- a/src/plugins/debugger/script/scriptengine.h +++ b/src/plugins/debugger/script/scriptengine.h @@ -88,7 +88,7 @@ private: void attemptBreakpointSynchronization(); - void assignValueInDebugger(const QString &expr, const QString &value); + void assignValueInDebugger(const Internal::WatchData *w, const QString &expr, const QVariant &value); void executeDebuggerCommand(const QString &command); void loadSymbols(const QString &moduleName); diff --git a/src/plugins/debugger/tcf/tcfengine.cpp b/src/plugins/debugger/tcf/tcfengine.cpp index 3e76236ecbb..0aa335f98d4 100644 --- a/src/plugins/debugger/tcf/tcfengine.cpp +++ b/src/plugins/debugger/tcf/tcfengine.cpp @@ -543,10 +543,9 @@ void TcfEngine::setToolTipExpression(const QPoint &mousePos, TextEditor::ITextEd // ////////////////////////////////////////////////////////////////////// -void TcfEngine::assignValueInDebugger(const QString &expression, - const QString &value) +void TcfEngine::assignValueInDebugger(const Internal::WatchData *, const QString &expression, const QVariant &value) { - XSDEBUG("ASSIGNING: " << expression + '=' + value); + XSDEBUG("ASSIGNING: " << expression + '=' + value.toString()); updateLocals(); } diff --git a/src/plugins/debugger/tcf/tcfengine.h b/src/plugins/debugger/tcf/tcfengine.h index a6172652d91..f6746066158 100644 --- a/src/plugins/debugger/tcf/tcfengine.h +++ b/src/plugins/debugger/tcf/tcfengine.h @@ -93,7 +93,7 @@ private: void attemptBreakpointSynchronization(); - void assignValueInDebugger(const QString &expr, const QString &value); + void assignValueInDebugger(const Internal::WatchData *w, const QString &expr, const QVariant &value); void executeDebuggerCommand(const QString &command); void loadSymbols(const QString &moduleName); diff --git a/src/plugins/debugger/watchhandler.cpp b/src/plugins/debugger/watchhandler.cpp index 4f3104a9942..cf511648ff9 100644 --- a/src/plugins/debugger/watchhandler.cpp +++ b/src/plugins/debugger/watchhandler.cpp @@ -59,7 +59,7 @@ #include #include - +#include // creates debug output for accesses to the model //#define DEBUG_MODEL 1 @@ -487,6 +487,23 @@ static inline QString formattedValue(const WatchData &data, int format) return result; } +// Get a pointer address from pointer values reported by the debugger. +// Fix CDB formatting of pointers "0x00000000`000003fd class foo *", or +// "0x00000000`000003fd "Hallo"", or check gdb formatting of characters. +static inline quint64 pointerValue(QString data) +{ + if (data.isEmpty() || !data.startsWith(QLatin1String("0x"))) + return 0; + data.remove(0, 2); + const int blankPos = data.indexOf(QLatin1Char(' ')); + if (blankPos != -1) + data.truncate(blankPos); + data.remove(QLatin1Char('`')); + bool ok; + const quint64 address = data.toULongLong(&ok, 16); + return ok ? address : quint64(0); +} + // Return the type used for editing static inline int editType(const WatchData &d) { @@ -496,6 +513,9 @@ static inline int editType(const WatchData &d) return d.type.contains('u') ? QVariant::ULongLong : QVariant::LongLong; if (isFloatType(d.type)) return QVariant::Double; + // Check for pointers using hex values (0xAD00 "Hallo") + if (isPointerType(d.type) && d.value.startsWith(QLatin1String("0x"))) + return QVariant::ULongLong; return QVariant::String; } @@ -506,11 +526,11 @@ static inline QVariant editValue(const WatchData &d) case QVariant::Bool: return d.value != QLatin1String("0") && d.value != QLatin1String("false"); case QVariant::ULongLong: + if (isPointerType(d.type)) // Fix pointer values (0xAD00 "Hallo" -> 0xAD00) + return QVariant(pointerValue(d.value)); return QVariant(d.value.toULongLong()); - break; case QVariant::LongLong: return QVariant(d.value.toLongLong()); - break; case QVariant::Double: return QVariant(d.value.toDouble()); default: @@ -647,23 +667,6 @@ static inline QString truncateValue(QString v) return v; } -// Get a pointer address from pointer values reported by the debugger. -// Fix CDB formatting of pointers "0x00000000`000003fd class foo *", -// check gdb formatting of characters. -static inline quint64 pointerValue(QString data) -{ - if (data.isEmpty() || !data.startsWith(QLatin1String("0x"))) - return 0; - data.remove(0, 2); - const int blankPos = data.indexOf(QLatin1Char(' ')); - if (blankPos != -1) - data.truncate(blankPos); - data.remove(QLatin1Char('`')); - bool ok; - const quint64 address = data.toULongLong(&ok, 16); - return ok ? address : quint64(0); -} - int WatchModel::itemFormat(const WatchData &data) const { const int individualFormat = m_handler->m_individualFormats.value(data.iname, -1); @@ -672,6 +675,22 @@ int WatchModel::itemFormat(const WatchData &data) const return m_handler->m_typeFormats.value(data.type, -1); } +static inline QString expression(const WatchItem *item) +{ + if (!item->exp.isEmpty()) + return QString::fromAscii(item->exp); + if (item->address && !item->type.isEmpty()) { + return QString::fromAscii("*(%1*)%2"). + arg(QLatin1String(item->type), QLatin1String(item->hexAddress())); + } + if (const WatchItem *parent = item->parent) { + if (!parent->exp.isEmpty()) + return QString::fromAscii("(%1).%2") + .arg(QString::fromLatin1(parent->exp), item->name); + } + return QString(); +} + QVariant WatchModel::data(const QModelIndex &idx, int role) const { switch (role) { @@ -689,6 +708,8 @@ QVariant WatchModel::data(const QModelIndex &idx, int role) const case LocalsEditTypeRole: return QVariant(editType(data)); case LocalsIntegerBaseRole: + if (isPointerType(data.type)) // Pointers using 0x-convention + return QVariant(16); return QVariant(formatToIntegerBase(itemFormat(data))); case Qt::EditRole: case Qt::DisplayRole: { @@ -728,20 +749,8 @@ QVariant WatchModel::data(const QModelIndex &idx, int role) const break; } - case LocalsExpressionRole: { - if (!data.exp.isEmpty()) - return data.exp; - if (data.address && !data.type.isEmpty()) { - return QString::fromAscii("*(%1*)%2"). - arg(QLatin1String(data.type), QLatin1String(data.hexAddress())); - } - WatchItem *parent = item->parent; - if (parent && !parent->exp.isEmpty()) - return QString::fromAscii("(%1).%2") - .arg(QString::fromLatin1(parent->exp), data.name); - return QVariant(); - } - + case LocalsExpressionRole: + return QVariant(expression(item)); case LocalsINameRole: return data.iname; @@ -806,22 +815,6 @@ QVariant WatchModel::data(const QModelIndex &idx, int role) const bool WatchModel::setData(const QModelIndex &index, const QVariant &value, int role) { switch (role) { - case RequestAssignValueRole: { - QString str = value.toString(); - int i = str.indexOf('='); - if (i != -1) - engine()->assignValueInDebugger(str.left(i), str.mid(i + 1)); - return true; - } - - case RequestAssignTypeRole: { - QString str = value.toString(); - int i = str.indexOf('='); - if (i != -1) - engine()->assignValueInDebugger(str.left(i), str.mid(i + 1)); - return true; - } - case RequestShowInEditorRole: { m_handler->showInEditor(); return true; @@ -895,33 +888,36 @@ bool WatchModel::setData(const QModelIndex &index, const QVariant &value, int ro case RequestWatchExpressionRole: m_handler->watchExpression(value.toString()); break; + + case RequestAssignValueRole: + engine()->assignValueInDebugger(&data, expression(&data), value); + return true; + case RequestAssignTypeRole: // TODO: Implement. + engine()->assignValueInDebugger(&data, expression(&data), value); + return true; } + emit dataChanged(index, index); return true; } Qt::ItemFlags WatchModel::flags(const QModelIndex &idx) const { - using namespace Qt; - if (!idx.isValid()) - return ItemFlags(); + return Qt::ItemFlags(); // enabled, editable, selectable, checkable, and can be used both as the // source of a drag and drop operation and as a drop target. - static const ItemFlags notEditable = - ItemIsSelectable - // | ItemIsDragEnabled - // | ItemIsDropEnabled - // | ItemIsUserCheckable - // | ItemIsTristate - | ItemIsEnabled; + static const Qt::ItemFlags notEditable = Qt::ItemIsSelectable| Qt::ItemIsEnabled; + static const Qt::ItemFlags editable = notEditable | Qt::ItemIsEditable; - static const ItemFlags editable = notEditable | ItemIsEditable; + // Disable editing if debuggee is positively running. + const bool isRunning = engine() && engine()->state() == InferiorRunOk; + if (isRunning) + return notEditable; const WatchData &data = *watchItem(idx); - if (data.isWatcher()) { if (idx.column() == 0 && data.iname.count('.') == 1) return editable; // Watcher names are editable. @@ -1341,6 +1337,7 @@ QByteArray WatchHandler::watcherName(const QByteArray &exp) void WatchHandler::watchExpression(const QString &exp) { + QTC_ASSERT(m_engine && (m_engine->debuggerCapabilities() & AddWatcherCapability), return ; ); // Do not insert multiple placeholders. if (exp.isEmpty() && m_watcherNames.contains(QByteArray())) return; @@ -1727,6 +1724,5 @@ void WatchHandler::removeTooltip() m_tooltips->reinitialize(); m_tooltips->emitAllChanged(); } - } // namespace Internal } // namespace Debugger diff --git a/src/plugins/debugger/watchutils.cpp b/src/plugins/debugger/watchutils.cpp index 3e89ea9fafa..73016f69610 100644 --- a/src/plugins/debugger/watchutils.cpp +++ b/src/plugins/debugger/watchutils.cpp @@ -550,7 +550,7 @@ bool isIntType(const QByteArray &type) case 'c': return type == "char"; case 'i': - return type == "int"; + return type == "int" || type == "int64"; case 'l': return type == "long" || type == "long long"; diff --git a/src/plugins/debugger/watchwindow.cpp b/src/plugins/debugger/watchwindow.cpp index f459d2c35d5..7b50eb10aa3 100644 --- a/src/plugins/debugger/watchwindow.cpp +++ b/src/plugins/debugger/watchwindow.cpp @@ -93,36 +93,42 @@ public: { if (index.column() == 1) { editor->setProperty("modelData", index.data(Qt::EditRole)); - } else { - QLineEdit *lineEdit = qobject_cast(editor); - QTC_ASSERT(lineEdit, return); + return; + } + QLineEdit *lineEdit = qobject_cast(editor); + QTC_ASSERT(lineEdit, return); + if (index.column() == 0) { + // Watch window: Edit expression in name column. lineEdit->setText(index.data(LocalsExpressionRole).toString()); + } else { + // To be implemented: Edit type (of a pointer, say). + lineEdit->setText(index.data(Qt::EditRole).toString()); } } void setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const { - const QString exp = index.data(LocalsExpressionRole).toString(); if (index.column() == 1) { // The value column. const QVariant value = editor->property("modelData"); QTC_ASSERT(value.isValid(), return); - const QString command = exp + QLatin1Char('=') + value.toString(); - model->setData(index, QVariant(command), RequestAssignValueRole); + model->setData(index, value, RequestAssignValueRole); return; } //qDebug() << "SET MODEL DATA"; - QLineEdit *lineEdit = qobject_cast(editor); + const QLineEdit *lineEdit = qobject_cast(editor); QTC_ASSERT(lineEdit, return); const QString value = lineEdit->text(); - model->setData(index, value, Qt::EditRole); if (index.column() == 2) { // The type column. - model->setData(index, QString(exp + '=' + value), RequestAssignTypeRole); + model->setData(index, QVariant(value), RequestAssignTypeRole); } else if (index.column() == 0) { - // The watcher name column. - model->setData(index, exp, RequestRemoveWatchExpressionRole); - model->setData(index, value, RequestWatchExpressionRole); + // The watcher name column: Change the expression. + const QString exp = index.data(LocalsExpressionRole).toString(); + if (exp != value ) { + model->setData(index, exp, RequestRemoveWatchExpressionRole); + model->setData(index, value, RequestWatchExpressionRole); + } } }