diff options
Diffstat (limited to 'src/plugins/debugger')
112 files changed, 5829 insertions, 6839 deletions
diff --git a/src/plugins/debugger/breakhandler.cpp b/src/plugins/debugger/breakhandler.cpp index 75534a428a..a13f54326c 100644 --- a/src/plugins/debugger/breakhandler.cpp +++ b/src/plugins/debugger/breakhandler.cpp @@ -29,7 +29,6 @@ ****************************************************************************/ #include "breakhandler.h" -#include "breakpointmarker.h" #include "debuggeractions.h" #include "debuggercore.h" @@ -38,6 +37,7 @@ #include "simplifytype.h" #include <extensionsystem/invoker.h> +#include <texteditor/textmark.h> #include <utils/hostosinfo.h> #include <utils/qtcassert.h> @@ -49,17 +49,125 @@ #include <QDir> #include <QDebug> -#define BREAK_ASSERT(cond, action) if (cond) {} else { action; } -//#define BREAK_ASSERT(cond, action) QTC_ASSERT(cond, action) +using namespace Utils; + +namespace Debugger { +namespace Internal { + +struct LocationItem : public TreeItem +{ + QVariant data(int column, int role) const + { + if (role == Qt::DisplayRole) { + switch (column) { + case 0: + return params.id.toString(); + case 1: + return params.functionName; + case 4: + if (params.address) + return QString::fromLatin1("0x%1").arg(params.address, 0, 16); + } + } + return QVariant(); + } + + BreakpointResponse params; +}; + +class BreakpointMarker; + +class BreakpointItem : public QObject, public TreeItem +{ + Q_DECLARE_TR_FUNCTIONS(Debugger::Internal::BreakHandler) + +public: + ~BreakpointItem(); + + QVariant data(int column, int role) const; + + QIcon icon() const; + + void removeBreakpoint(); + void updateLineNumberFromMarker(int lineNumber); + void updateFileNameFromMarker(const QString &fileName); + void changeLineNumberFromMarker(int lineNumber); + bool isLocatedAt(const QString &fileName, int lineNumber, bool useMarkerPosition) const; + + bool needsChildren() const; + + void setMarkerFileAndLine(const QString &fileName, int lineNumber); + + void insertSubBreakpoint(const BreakpointResponse ¶ms); + QString markerFileName() const; + int markerLineNumber() const; + + bool needsChange() const; +private: + friend class BreakHandler; + friend class Breakpoint; + BreakpointItem(BreakHandler *handler); + + void destroyMarker(); + void updateMarker(); + void updateMarkerIcon(); + void scheduleSynchronization(); + + QString toToolTip() const; + void setState(BreakpointState state); + void deleteThis(); + bool isEngineRunning() const; + + BreakHandler * const m_handler; + const BreakpointModelId m_id; + BreakpointParameters m_params; + BreakpointState m_state; // Current state of breakpoint. + DebuggerEngine *m_engine; // Engine currently handling the breakpoint. + BreakpointResponse m_response; + BreakpointMarker *m_marker; +}; -////////////////////////////////////////////////////////////////// // -// BreakHandler +// BreakpointMarker // -////////////////////////////////////////////////////////////////// -namespace Debugger { -namespace Internal { +// The red blob on the left side in the cpp editor. +class BreakpointMarker : public TextEditor::TextMark +{ +public: + BreakpointMarker(BreakpointItem *b, const QString &fileName, int lineNumber) + : TextMark(fileName, lineNumber), m_bp(b) + { + setIcon(b->icon()); + setPriority(TextEditor::TextMark::NormalPriority); + } + + void removedFromEditor() + { + if (m_bp) + m_bp->removeBreakpoint(); + } + + void updateLineNumber(int lineNumber) + { + TextMark::updateLineNumber(lineNumber); + m_bp->updateLineNumberFromMarker(lineNumber); + } + + void updateFileName(const QString &fileName) + { + TextMark::updateFileName(fileName); + m_bp->updateFileNameFromMarker(fileName); + } + + bool isDraggable() const { return true; } + void dragToLine(int line) { m_bp->changeLineNumberFromMarker(line); } + bool isClickable() const { return true; } + void clicked() { m_bp->removeBreakpoint(); } + +public: + BreakpointItem *m_bp; +}; static QString stateToString(BreakpointState state) { @@ -135,14 +243,16 @@ static QString typeToString(BreakpointType type) BreakHandler::BreakHandler() : m_syncTimerId(-1) { + qRegisterMetaType<BreakpointModelId>(); + #if USE_BREAK_MODEL_TEST new ModelTest(this, 0); #endif + setHeader(QStringList() + << tr("Number") << tr("Function") << tr("File") << tr("Line") + << tr("Address") << tr("Condition") << tr("Ignore") << tr("Threads")); } -BreakHandler::~BreakHandler() -{} - QIcon BreakHandler::breakpointIcon() { static QIcon icon(_(":/debugger/images/breakpoint_16.png")); @@ -183,276 +293,260 @@ QIcon BreakHandler::emptyIcon() static inline bool fileNameMatch(const QString &f1, const QString &f2) { - if (Utils::HostOsInfo::fileNameCaseSensitivity() == Qt::CaseInsensitive) + if (HostOsInfo::fileNameCaseSensitivity() == Qt::CaseInsensitive) return f1.compare(f2, Qt::CaseInsensitive) == 0; return f1 == f2; } -static bool isSimilarTo(const BreakpointParameters &data, const BreakpointResponse &needle) +static bool isSimilarTo(const BreakpointParameters ¶ms, const BreakpointResponse &needle) { // Clear miss. - if (needle.type != UnknownBreakpointType && data.type != UnknownBreakpointType - && data.type != needle.type) + if (needle.type != UnknownBreakpointType && params.type != UnknownBreakpointType + && params.type != needle.type) return false; // Clear hit. - if (data.address && data.address == needle.address) + if (params.address && params.address == needle.address) return true; // Clear hit. - if (data == needle) + if (params == needle) return true; // At least at a position we were looking for. // FIXME: breaks multiple breakpoints at the same location - if (!data.fileName.isEmpty() - && fileNameMatch(data.fileName, needle.fileName) - && data.lineNumber == needle.lineNumber) + if (!params.fileName.isEmpty() + && fileNameMatch(params.fileName, needle.fileName) + && params.lineNumber == needle.lineNumber) return true; // At least at a position we were looking for. // FIXME: breaks multiple breakpoints at the same location - if (!data.fileName.isEmpty() - && fileNameMatch(data.fileName, needle.fileName) - && data.lineNumber == needle.lineNumber) + if (!params.fileName.isEmpty() + && fileNameMatch(params.fileName, needle.fileName) + && params.lineNumber == needle.lineNumber) return true; return false; } -BreakpointModelId BreakHandler::findSimilarBreakpoint(const BreakpointResponse &needle) const +Breakpoint BreakHandler::findSimilarBreakpoint(const BreakpointResponse &needle) const { // Search a breakpoint we might refer to. - ConstIterator it = m_storage.constBegin(), et = m_storage.constEnd(); - for ( ; it != et; ++it) { - const BreakpointModelId id = it.key(); - const BreakpointParameters &data = it->data; - const BreakpointResponse &response = it->response; - //qDebug() << "COMPARING " << data.toString() << " WITH " << needle.toString(); - if (response.id.isValid() && response.id.majorPart() == needle.id.majorPart()) - return id; - - if (isSimilarTo(data, needle)) - return id; + foreach (TreeItem *n, rootItem()->children()) { + BreakpointItem *b = static_cast<BreakpointItem *>(n); + //qDebug() << "COMPARING " << params.toString() << " WITH " << needle.toString(); + if (b->m_response.id.isValid() && b->m_response.id.majorPart() == needle.id.majorPart()) + return Breakpoint(b); + + if (isSimilarTo(b->m_params, needle)) + return Breakpoint(b); } - return BreakpointModelId(); + return Breakpoint(); } -BreakpointModelId BreakHandler::findBreakpointByResponseId(const BreakpointResponseId &id) const +Breakpoint BreakHandler::findBreakpointByResponseId(const BreakpointResponseId &id) const { - ConstIterator it = m_storage.constBegin(), et = m_storage.constEnd(); - for ( ; it != et; ++it) - if (it->response.id.majorPart() == id.majorPart()) - return it.key(); - return BreakpointModelId(); + foreach (TreeItem *n, rootItem()->children()) { + BreakpointItem *b = static_cast<BreakpointItem *>(n); + if (b->m_response.id.majorPart() == id.majorPart()) + return Breakpoint(b); + } + return Breakpoint(); } -BreakpointModelId BreakHandler::findBreakpointByFunction(const QString &functionName) const +Breakpoint BreakHandler::findBreakpointByFunction(const QString &functionName) const { - ConstIterator it = m_storage.constBegin(), et = m_storage.constEnd(); - for ( ; it != et; ++it) - if (it->data.functionName == functionName) - return it.key(); - return BreakpointModelId(); + foreach (TreeItem *n, rootItem()->children()) { + BreakpointItem *b = static_cast<BreakpointItem *>(n); + if (b->m_params.functionName == functionName) + return Breakpoint(b); + } + return Breakpoint(); } -BreakpointModelId BreakHandler::findBreakpointByAddress(quint64 address) const +Breakpoint BreakHandler::findBreakpointByAddress(quint64 address) const { - ConstIterator it = m_storage.constBegin(), et = m_storage.constEnd(); - for ( ; it != et; ++it) - if (it->data.address == address || it->response.address == address) - return it.key(); - return BreakpointModelId(); + foreach (TreeItem *n, rootItem()->children()) { + BreakpointItem *b = static_cast<BreakpointItem *>(n); + if (b->m_params.address == address || b->m_params.address == address) + return Breakpoint(b); + } + return Breakpoint(); } -BreakpointModelId BreakHandler::findBreakpointByFileAndLine(const QString &fileName, +Breakpoint BreakHandler::findBreakpointByFileAndLine(const QString &fileName, int lineNumber, bool useMarkerPosition) { - ConstIterator it = m_storage.constBegin(), et = m_storage.constEnd(); - for ( ; it != et; ++it) - if (it->isLocatedAt(fileName, lineNumber, useMarkerPosition)) - return it.key(); - return BreakpointModelId(); + foreach (TreeItem *n, rootItem()->children()) { + BreakpointItem *b = static_cast<BreakpointItem *>(n); + if (b->isLocatedAt(fileName, lineNumber, useMarkerPosition)) + return Breakpoint(b); + } + return Breakpoint(); } -const BreakpointParameters &BreakHandler::breakpointData(BreakpointModelId id) const +Breakpoint BreakHandler::breakpointById(BreakpointModelId id) const { - static BreakpointParameters dummy; - ConstIterator it = m_storage.find(id); - BREAK_ASSERT(it != m_storage.end(), return dummy); - return it->data; + foreach (TreeItem *n, rootItem()->children()) { + BreakpointItem *b = static_cast<BreakpointItem *>(n); + if (b->m_id == id) + return Breakpoint(b); + } + return Breakpoint(); } -BreakpointModelId BreakHandler::findWatchpoint(const BreakpointParameters &data) const +void BreakHandler::deletionHelper(BreakpointModelId id) { - ConstIterator it = m_storage.constBegin(), et = m_storage.constEnd(); - for ( ; it != et; ++it) - if (it->data.isWatchpoint() - && it->data.address == data.address - && it->data.size == data.size - && it->data.expression == data.expression - && it->data.bitpos == data.bitpos) - return it.key(); - return BreakpointModelId(); + Breakpoint b = breakpointById(id); + QTC_ASSERT(b, return); + removeItem(b.b); + delete b.b; +} + +Breakpoint BreakHandler::findWatchpoint(const BreakpointParameters ¶ms) const +{ + foreach (TreeItem *n, rootItem()->children()) { + BreakpointItem *b = static_cast<BreakpointItem *>(n); + if (b->m_params.isWatchpoint() + && b->m_params.address == params.address + && b->m_params.size == params.size + && b->m_params.expression == params.expression + && b->m_params.bitpos == params.bitpos) + return Breakpoint(b); + } + return Breakpoint(); } void BreakHandler::saveBreakpoints() { const QString one = _("1"); - //qDebug() << "SAVING BREAKPOINTS..."; QList<QVariant> list; - ConstIterator it = m_storage.constBegin(), et = m_storage.constEnd(); - for ( ; it != et; ++it) { - const BreakpointParameters &data = it->data; + foreach (TreeItem *n, rootItem()->children()) { + BreakpointItem *b = static_cast<BreakpointItem *>(n); + const BreakpointParameters ¶ms = b->m_params; QMap<QString, QVariant> map; - if (data.type != BreakpointByFileAndLine) - map.insert(_("type"), data.type); - if (!data.fileName.isEmpty()) - map.insert(_("filename"), data.fileName); - if (data.lineNumber) - map.insert(_("linenumber"), data.lineNumber); - if (!data.functionName.isEmpty()) - map.insert(_("funcname"), data.functionName); - if (data.address) - map.insert(_("address"), data.address); - if (!data.condition.isEmpty()) - map.insert(_("condition"), data.condition); - if (data.ignoreCount) - map.insert(_("ignorecount"), data.ignoreCount); - if (data.threadSpec >= 0) - map.insert(_("threadspec"), data.threadSpec); - if (!data.enabled) + if (params.type != BreakpointByFileAndLine) + map.insert(_("type"), params.type); + if (!params.fileName.isEmpty()) + map.insert(_("filename"), params.fileName); + if (params.lineNumber) + map.insert(_("linenumber"), params.lineNumber); + if (!params.functionName.isEmpty()) + map.insert(_("funcname"), params.functionName); + if (params.address) + map.insert(_("address"), params.address); + if (!params.condition.isEmpty()) + map.insert(_("condition"), params.condition); + if (params.ignoreCount) + map.insert(_("ignorecount"), params.ignoreCount); + if (params.threadSpec >= 0) + map.insert(_("threadspec"), params.threadSpec); + if (!params.enabled) map.insert(_("disabled"), one); - if (data.oneShot) + if (params.oneShot) map.insert(_("oneshot"), one); - if (data.pathUsage != BreakpointPathUsageEngineDefault) - map.insert(_("usefullpath"), QString::number(data.pathUsage)); - if (data.tracepoint) + if (params.pathUsage != BreakpointPathUsageEngineDefault) + map.insert(_("usefullpath"), QString::number(params.pathUsage)); + if (params.tracepoint) map.insert(_("tracepoint"), one); - if (!data.module.isEmpty()) - map.insert(_("module"), data.module); - if (!data.command.isEmpty()) - map.insert(_("command"), data.command); - if (!data.expression.isEmpty()) - map.insert(_("expression"), data.expression); - if (!data.message.isEmpty()) - map.insert(_("message"), data.message); + if (!params.module.isEmpty()) + map.insert(_("module"), params.module); + if (!params.command.isEmpty()) + map.insert(_("command"), params.command); + if (!params.expression.isEmpty()) + map.insert(_("expression"), params.expression); + if (!params.message.isEmpty()) + map.insert(_("message"), params.message); list.append(map); } setSessionValue("Breakpoints", list); - //qDebug() << "SAVED BREAKPOINTS" << this << list.size(); } void BreakHandler::loadBreakpoints() { - //qDebug() << "LOADING BREAKPOINTS..."; QVariant value = sessionValue("Breakpoints"); QList<QVariant> list = value.toList(); - //clear(); foreach (const QVariant &var, list) { const QMap<QString, QVariant> map = var.toMap(); - BreakpointParameters data(BreakpointByFileAndLine); + BreakpointParameters params(BreakpointByFileAndLine); QVariant v = map.value(_("filename")); if (v.isValid()) - data.fileName = v.toString(); + params.fileName = v.toString(); v = map.value(_("linenumber")); if (v.isValid()) - data.lineNumber = v.toString().toInt(); + params.lineNumber = v.toString().toInt(); v = map.value(_("condition")); if (v.isValid()) - data.condition = v.toString().toLatin1(); + params.condition = v.toString().toLatin1(); v = map.value(_("address")); if (v.isValid()) - data.address = v.toString().toULongLong(); + params.address = v.toString().toULongLong(); v = map.value(_("ignorecount")); if (v.isValid()) - data.ignoreCount = v.toString().toInt(); + params.ignoreCount = v.toString().toInt(); v = map.value(_("threadspec")); if (v.isValid()) - data.threadSpec = v.toString().toInt(); + params.threadSpec = v.toString().toInt(); v = map.value(_("funcname")); if (v.isValid()) - data.functionName = v.toString(); + params.functionName = v.toString(); v = map.value(_("disabled")); if (v.isValid()) - data.enabled = !v.toInt(); + params.enabled = !v.toInt(); v = map.value(_("oneshot")); if (v.isValid()) - data.oneShot = v.toInt(); + params.oneShot = v.toInt(); v = map.value(_("usefullpath")); if (v.isValid()) - data.pathUsage = static_cast<BreakpointPathUsage>(v.toInt()); + params.pathUsage = static_cast<BreakpointPathUsage>(v.toInt()); v = map.value(_("tracepoint")); if (v.isValid()) - data.tracepoint = bool(v.toInt()); + params.tracepoint = bool(v.toInt()); v = map.value(_("type")); if (v.isValid() && v.toInt() != UnknownBreakpointType) - data.type = BreakpointType(v.toInt()); + params.type = BreakpointType(v.toInt()); v = map.value(_("module")); if (v.isValid()) - data.module = v.toString(); + params.module = v.toString(); v = map.value(_("command")); if (v.isValid()) - data.command = v.toString(); + params.command = v.toString(); v = map.value(_("expression")); if (v.isValid()) - data.expression = v.toString(); + params.expression = v.toString(); v = map.value(_("message")); if (v.isValid()) - data.message = v.toString(); - if (data.isValid()) - appendBreakpoint(data); + params.message = v.toString(); + if (params.isValid()) + appendBreakpointInternal(params); else - qWarning("Not restoring invalid breakpoint: %s", qPrintable(data.toString())); + qWarning("Not restoring invalid breakpoint: %s", qPrintable(params.toString())); } - //qDebug() << "LOADED BREAKPOINTS" << this << list.size(); } void BreakHandler::updateMarkers() { - Iterator it = m_storage.begin(), et = m_storage.end(); - for ( ; it != et; ++it) - it->updateMarker(it.key()); -} - -QVariant BreakHandler::headerData(int section, - Qt::Orientation orientation, int role) const -{ - if (orientation == Qt::Horizontal && role == Qt::DisplayRole) { - static QString headers[] = { - tr("Number"), tr("Function"), tr("File"), tr("Line"), - tr("Address"), tr("Condition"), tr("Ignore"), tr("Threads") - }; - return headers[section]; - } - return QVariant(); + foreach (TreeItem *n, rootItem()->children()) + static_cast<BreakpointItem *>(n)->updateMarker(); } -BreakpointModelId BreakHandler::findBreakpointByIndex(const QModelIndex &index) const +Breakpoint BreakHandler::findBreakpointByIndex(const QModelIndex &index) const { - //qDebug() << "FIND: " << index << - // BreakpointId::fromInternalId(index.internalId()); - return BreakpointModelId::fromInternalId(index.internalId()); + TreeItem *item = itemFromIndex(index); + return Breakpoint(item && item->parent() == rootItem() ? static_cast<BreakpointItem *>(item) : 0); } -BreakpointModelIds BreakHandler::findBreakpointsByIndex(const QList<QModelIndex> &list) const +Breakpoints BreakHandler::findBreakpointsByIndex(const QList<QModelIndex> &list) const { - QSet<BreakpointModelId> ids; - foreach (const QModelIndex &index, list) - ids.insert(findBreakpointByIndex(index)); + QSet<Breakpoint> ids; + foreach (const QModelIndex &index, list) { + if (Breakpoint b = findBreakpointByIndex(index)) + ids.insert(Breakpoint(b)); + } return ids.toList(); } -Qt::ItemFlags BreakHandler::flags(const QModelIndex &index) const -{ -// switch (index.column()) { -// //case 0: -// // return Qt::ItemIsUserCheckable | Qt::ItemIsEnabled; -// default: - return QAbstractItemModel::flags(index); -// } -} - QString BreakHandler::displayFromThreadSpec(int spec) { return spec == -1 ? BreakHandler::tr("(all)") : QString::number(spec); @@ -465,95 +559,12 @@ int BreakHandler::threadSpecFromDisplay(const QString &str) return ok ? result : -1; } -QModelIndex BreakHandler::createIndex(int row, int column, quint32 id) const -{ - return QAbstractItemModel::createIndex(row, column, id); -} - -QModelIndex BreakHandler::createIndex(int row, int column, void *ptr) const -{ - QTC_CHECK(false); // This function is not used. - return QAbstractItemModel::createIndex(row, column, ptr); -} +const QString empty(QLatin1Char('-')); -int BreakHandler::columnCount(const QModelIndex &idx) const +QVariant BreakpointItem::data(int column, int role) const { - if (idx.column() > 0) - return 0; - const BreakpointModelId id = findBreakpointByIndex(idx); - return id.isMinor() ? 0 : 8; -} - -int BreakHandler::rowCount(const QModelIndex &idx) const -{ - if (idx.column() > 0) - return 0; - if (!idx.isValid()) - return m_storage.size(); - const BreakpointModelId id = findBreakpointByIndex(idx); - if (id.isMajor()) - return m_storage.value(id).subItems.size(); - return 0; -} - -QModelIndex BreakHandler::index(int row, int col, const QModelIndex &parent) const -{ - if (row < 0 || col < 0) - return QModelIndex(); - if (parent.column() > 0) - return QModelIndex(); - BreakpointModelId id = findBreakpointByIndex(parent); - if (id.isMajor()) { - ConstIterator it = m_storage.find(id); - if (row >= it->subItems.size()) - return QModelIndex(); - BreakpointModelId sub = id.child(row); - return createIndex(row, col, sub.toInternalId()); - } - if (id.isMinor()) - return QModelIndex(); - QTC_ASSERT(!id.isValid(), return QModelIndex()); - if (row >= m_storage.size()) - return QModelIndex(); - id = at(row); - return createIndex(row, col, id.toInternalId()); -} - -QModelIndex BreakHandler::parent(const QModelIndex &idx) const -{ - if (!idx.isValid()) - return QModelIndex(); - BreakpointModelId id = findBreakpointByIndex(idx); - if (id.isMajor()) - return QModelIndex(); - if (id.isMinor()) { - BreakpointModelId pid = id.parent(); - int row = indexOf(pid); - return createIndex(row, 0, pid.toInternalId()); - } - return QModelIndex(); -} - -QVariant BreakHandler::data(const QModelIndex &mi, int role) const -{ - static const QString empty = QString(QLatin1Char('-')); - - if (!mi.isValid()) - return QVariant(); - - BreakpointModelId id = findBreakpointByIndex(mi); - - BreakpointModelId pid = id; - if (id.isMinor()) - pid = id.parent(); - - ConstIterator it = m_storage.find(pid); - QTC_ASSERT(it != m_storage.end(), return QVariant()); - const BreakpointParameters &data = it->data; - const BreakpointResponse &response = it->response; - bool orig = false; - switch (it->state) { + switch (m_state) { case BreakpointInsertRequested: case BreakpointInsertProceeding: case BreakpointChangeRequested: @@ -568,53 +579,52 @@ QVariant BreakHandler::data(const QModelIndex &mi, int role) const break; }; - if (id.isMinor()) { - QTC_ASSERT(id.minorPart() <= it->subItems.size(), return QVariant()); - const BreakpointResponse &res = it->subItems.at(id.minorPart() - 1); - switch (mi.column()) { - case 0: - if (role == Qt::DisplayRole) - return id.toString(); - case 1: - if (role == Qt::DisplayRole) - return res.functionName; - case 4: - if (role == Qt::DisplayRole) - if (res.address) - return QString::fromLatin1("0x%1").arg(res.address, 0, 16); - } - return QVariant(); + if (role == Qt::ForegroundRole) { + static const QVariant gray(QColor(140, 140, 140)); + switch (m_state) { + case BreakpointInsertRequested: + case BreakpointInsertProceeding: + case BreakpointChangeRequested: + case BreakpointChangeProceeding: + case BreakpointRemoveRequested: + case BreakpointRemoveProceeding: + return gray; + case BreakpointInserted: + case BreakpointNew: + case BreakpointDead: + break; + }; } - switch (mi.column()) { + switch (column) { case 0: if (role == Qt::DisplayRole) - return id.toString(); + return m_id.toString(); if (role == Qt::DecorationRole) - return it->icon(); + return icon(); break; case 1: if (role == Qt::DisplayRole) { - if (!response.functionName.isEmpty()) - return simplifyType(response.functionName); - if (!data.functionName.isEmpty()) - return data.functionName; - if (data.type == BreakpointAtMain - || data.type == BreakpointAtThrow - || data.type == BreakpointAtCatch - || data.type == BreakpointAtFork - || data.type == BreakpointAtExec - //|| data.type == BreakpointAtVFork - || data.type == BreakpointAtSysCall) - return typeToString(data.type); - if (data.type == WatchpointAtAddress) { - quint64 address = response.address ? response.address : data.address; - return tr("Data at 0x%1").arg(address, 0, 16); + if (!m_response.functionName.isEmpty()) + return simplifyType(m_response.functionName); + if (!m_params.functionName.isEmpty()) + return m_params.functionName; + if (m_params.type == BreakpointAtMain + || m_params.type == BreakpointAtThrow + || m_params.type == BreakpointAtCatch + || m_params.type == BreakpointAtFork + || m_params.type == BreakpointAtExec + //|| m_params.type == BreakpointAtVFork + || m_params.type == BreakpointAtSysCall) + return typeToString(m_params.type); + if (m_params.type == WatchpointAtAddress) { + quint64 address = m_response.address ? m_response.address : m_params.address; + return BreakHandler::tr("Data at 0x%1").arg(address, 0, 16); } - if (data.type == WatchpointAtExpression) { - QString expression = !response.expression.isEmpty() - ? response.expression : data.expression; - return tr("Data at %1").arg(expression); + if (m_params.type == WatchpointAtExpression) { + QString expression = !m_response.expression.isEmpty() + ? m_response.expression : m_params.expression; + return BreakHandler::tr("Data at %1").arg(expression); } return empty; } @@ -622,17 +632,17 @@ QVariant BreakHandler::data(const QModelIndex &mi, int role) const case 2: if (role == Qt::DisplayRole) { QString str; - if (!response.fileName.isEmpty()) - str = response.fileName; - if (str.isEmpty() && !data.fileName.isEmpty()) - str = data.fileName; + if (!m_response.fileName.isEmpty()) + str = m_response.fileName; + if (str.isEmpty() && !m_params.fileName.isEmpty()) + str = m_params.fileName; if (str.isEmpty()) { - QString s = QFileInfo(str).fileName(); + QString s = FileName::fromString(str).fileName(); if (!s.isEmpty()) str = s; } // FIXME: better? - //if (data.multiple && str.isEmpty() && !response.fileName.isEmpty()) + //if (params.multiple && str.isEmpty() && !response.fileName.isEmpty()) // str = response.fileName; if (!str.isEmpty()) return QDir::toNativeSeparators(str); @@ -641,18 +651,18 @@ QVariant BreakHandler::data(const QModelIndex &mi, int role) const break; case 3: if (role == Qt::DisplayRole) { - if (response.lineNumber > 0) - return response.lineNumber; - if (data.lineNumber > 0) - return data.lineNumber; + if (m_response.lineNumber > 0) + return m_response.lineNumber; + if (m_params.lineNumber > 0) + return m_params.lineNumber; return empty; } if (role == Qt::UserRole + 1) - return data.lineNumber; + return m_params.lineNumber; break; case 4: if (role == Qt::DisplayRole) { - const quint64 address = orig ? data.address : response.address; + const quint64 address = orig ? m_params.address : m_response.address; if (address) return QString::fromLatin1("0x%1").arg(address, 0, 16); return QVariant(); @@ -660,196 +670,204 @@ QVariant BreakHandler::data(const QModelIndex &mi, int role) const break; case 5: if (role == Qt::DisplayRole) - return orig ? data.condition : response.condition; + return orig ? m_params.condition : m_response.condition; if (role == Qt::ToolTipRole) - return tr("Breakpoint will only be hit if this condition is met."); + return BreakHandler::tr("Breakpoint will only be hit if this condition is met."); if (role == Qt::UserRole + 1) - return data.condition; + return m_params.condition; break; case 6: if (role == Qt::DisplayRole) { const int ignoreCount = - orig ? data.ignoreCount : response.ignoreCount; + orig ? m_params.ignoreCount : m_response.ignoreCount; return ignoreCount ? QVariant(ignoreCount) : QVariant(QString()); } if (role == Qt::ToolTipRole) - return tr("Breakpoint will only be hit after being ignored so many times."); + return BreakHandler::tr("Breakpoint will only be hit after being ignored so many times."); if (role == Qt::UserRole + 1) - return data.ignoreCount; + return m_params.ignoreCount; break; case 7: if (role == Qt::DisplayRole) - return displayFromThreadSpec(orig ? data.threadSpec : response.threadSpec); + return BreakHandler::displayFromThreadSpec(orig ? m_params.threadSpec : m_response.threadSpec); if (role == Qt::ToolTipRole) - return tr("Breakpoint will only be hit in the specified thread(s)."); + return BreakHandler::tr("Breakpoint will only be hit in the specified thread(s)."); if (role == Qt::UserRole + 1) - return displayFromThreadSpec(data.threadSpec); + return BreakHandler::displayFromThreadSpec(m_params.threadSpec); break; } - switch (role) { - case Qt::ToolTipRole: - if (boolSetting(UseToolTipsInBreakpointsView)) - return QVariant(it->toToolTip()); - break; - } + + if (role == Qt::ToolTipRole && boolSetting(UseToolTipsInBreakpointsView)) + return toToolTip(); + return QVariant(); } -#define GETTER(type, getter) \ -type BreakHandler::getter(BreakpointModelId id) const \ +#define PROPERTY(type, getter, setter) \ +\ +type Breakpoint::getter() const \ { \ - ConstIterator it = m_storage.find(id); \ - BREAK_ASSERT(it != m_storage.end(), \ - qDebug() << "ID" << id << "NOT KNOWN"; \ - return type()); \ - return it->data.getter; \ -} - -#define SETTER(type, getter, setter) \ -void BreakHandler::setter(BreakpointModelId id, const type &value) \ + return parameters().getter; \ +} \ +\ +void Breakpoint::setter(const type &value) \ { \ - Iterator it = m_storage.find(id); \ - BREAK_ASSERT(it != m_storage.end(), \ - qDebug() << "ID" << id << "NOT KNOWN"; return); \ - if (it->data.getter == value) \ + QTC_ASSERT(b, return); \ + if (b->m_params.getter == value) \ return; \ - it->data.getter = value; \ - if (it->state != BreakpointNew) { \ - it->state = BreakpointChangeRequested; \ - scheduleSynchronization(); \ + b->m_params.getter = value; \ + if (b->m_state != BreakpointNew) { \ + b->m_state = BreakpointChangeRequested; \ + b->scheduleSynchronization(); \ } \ } -#define PROPERTY(type, getter, setter) \ - GETTER(type, getter) \ - SETTER(type, getter, setter) - - PROPERTY(BreakpointPathUsage, pathUsage, setPathUsage) PROPERTY(QString, fileName, setFileName) PROPERTY(QString, functionName, setFunctionName) PROPERTY(BreakpointType, type, setType) PROPERTY(int, threadSpec, setThreadSpec) PROPERTY(QByteArray, condition, setCondition) -GETTER(int, lineNumber) PROPERTY(quint64, address, setAddress) PROPERTY(QString, expression, setExpression) PROPERTY(QString, message, setMessage) PROPERTY(int, ignoreCount, setIgnoreCount) -bool BreakHandler::isEnabled(BreakpointModelId id) const +void BreakpointItem::scheduleSynchronization() { - ConstIterator it = m_storage.find(id); - BREAK_ASSERT(it != m_storage.end(), return false); - return it->data.enabled; + m_handler->scheduleSynchronization(); } -void BreakHandler::setEnabled(BreakpointModelId id, bool on) +const BreakpointParameters &Breakpoint::parameters() const { - Iterator it = m_storage.find(id); - BREAK_ASSERT(it != m_storage.end(), return); - //qDebug() << "SET ENABLED: " << id << it->data.isEnabled() << on; - if (it->data.enabled == on) - return; - it->data.enabled = on; - it->updateMarkerIcon(); - if (it->engine) { - it->state = BreakpointChangeRequested; - scheduleSynchronization(); - } + static BreakpointParameters p; + QTC_ASSERT(b, return p); + return b->m_params; +} + +void Breakpoint::addToCommand(DebuggerCommand *cmd) const +{ + cmd->arg("modelid", id().toByteArray()); + cmd->arg("type", type()); + cmd->arg("ignorecount", ignoreCount()); + cmd->arg("condition", condition().toHex()); + cmd->arg("function", functionName().toUtf8()); + cmd->arg("oneshot", isOneShot()); + cmd->arg("enabled", isEnabled()); + cmd->arg("fileName", fileName().toUtf8()); + cmd->arg("lineNumber", lineNumber()); + cmd->arg("address", address()); + cmd->arg("expression", expression()); +} + +BreakpointState Breakpoint::state() const +{ + QTC_ASSERT(b, return BreakpointState()); + return b->m_state; } -bool BreakHandler::isWatchpoint(BreakpointModelId id) const +int Breakpoint::lineNumber() const { return parameters().lineNumber; } + +bool Breakpoint::isEnabled() const { return parameters().enabled; } + +bool Breakpoint::isWatchpoint() const { return parameters().isWatchpoint(); } + +bool Breakpoint::isTracepoint() const { return parameters().isTracepoint(); } + +QIcon Breakpoint::icon() const { return b ? b->icon() : QIcon(); } + +DebuggerEngine *Breakpoint::engine() const { - ConstIterator it = m_storage.find(id); - BREAK_ASSERT(it != m_storage.end(), return false); - return it->data.isWatchpoint(); + return b ? b->m_engine : 0; } -bool BreakHandler::isTracepoint(BreakpointModelId id) const +const BreakpointResponse &Breakpoint::response() const { - ConstIterator it = m_storage.find(id); - BREAK_ASSERT(it != m_storage.end(), return false); - return it->data.tracepoint; + static BreakpointResponse r; + return b ? b->m_response : r; } -bool BreakHandler::isOneShot(BreakpointModelId id) const +bool Breakpoint::isOneShot() const { return parameters().oneShot; } + +void Breakpoint::removeAlienBreakpoint() { - ConstIterator it = m_storage.find(id); - BREAK_ASSERT(it != m_storage.end(), return false); - return it->data.oneShot; + b->deleteThis(); } -bool BreakHandler::needsChildren(BreakpointModelId id) const +void Breakpoint::removeBreakpoint() const { - ConstIterator it = m_storage.find(id); - BREAK_ASSERT(it != m_storage.end(), return false); - return it->response.multiple && it->subItems.isEmpty(); + b->removeBreakpoint(); } -void BreakHandler::setTracepoint(BreakpointModelId id, bool on) +Breakpoint::Breakpoint(BreakpointItem *b) + : b(b) +{} + +void Breakpoint::setEnabled(bool on) const { - Iterator it = m_storage.find(id); - BREAK_ASSERT(it != m_storage.end(), return); - if (it->data.tracepoint == on) + QTC_ASSERT(b, return); + if (b->m_params.enabled == on) return; - it->data.tracepoint = on; - it->updateMarkerIcon(); - - if (it->engine) { - it->state = BreakpointChangeRequested; - scheduleSynchronization(); + b->m_params.enabled = on; + b->updateMarkerIcon(); + if (b->m_engine) { + b->m_state = BreakpointChangeRequested; + b->scheduleSynchronization(); } } -void BreakHandler::setMarkerFileAndLine(BreakpointModelId id, - const QString &fileName, int lineNumber) +void Breakpoint::setMarkerFileAndLine(const QString &fileName, int lineNumber) { - Iterator it = m_storage.find(id); - BREAK_ASSERT(it != m_storage.end(), - qDebug() << "MARKER_FILE_AND_LINE: " << id; return); - if (it->response.fileName == fileName && it->response.lineNumber == lineNumber) - return; - it->response.fileName = fileName; - it->response.lineNumber = lineNumber; - it->destroyMarker(); - it->updateMarker(id); - emit layoutChanged(); + if (b) + b->setMarkerFileAndLine(fileName, lineNumber); } -BreakpointState BreakHandler::state(BreakpointModelId id) const +bool BreakpointItem::needsChildren() const { - ConstIterator it = m_storage.find(id); - BREAK_ASSERT(it != m_storage.end(), - qDebug() << "STATE: " << id; return BreakpointDead); - return it->state; + return m_response.multiple && rowCount() == 0; } -DebuggerEngine *BreakHandler::engine(BreakpointModelId id) const +void Breakpoint::setTracepoint(bool on) { - ConstIterator it = m_storage.find(id); - BREAK_ASSERT(it != m_storage.end(), qDebug() << id; return 0); - return it->engine; + if (b->m_params.tracepoint == on) + return; + b->m_params.tracepoint = on; + b->updateMarkerIcon(); + + if (b->m_engine) { + b->m_state = BreakpointChangeRequested; + b->scheduleSynchronization(); + } } -void BreakHandler::setEngine(BreakpointModelId id, DebuggerEngine *value) +void BreakpointItem::setMarkerFileAndLine(const QString &fileName, int lineNumber) { - Iterator it = m_storage.find(id); - BREAK_ASSERT(it != m_storage.end(), qDebug() << "SET ENGINE" << id; return); - QTC_ASSERT(it->state == BreakpointNew, qDebug() << "STATE: " << it->state <<id); - QTC_ASSERT(!it->engine, qDebug() << "NO ENGINE" << id; return); - it->engine = value; - it->state = BreakpointInsertRequested; - it->response = BreakpointResponse(); - it->updateMarker(id); - scheduleSynchronization(); + if (m_response.fileName == fileName && m_response.lineNumber == lineNumber) + return; + m_response.fileName = fileName; + m_response.lineNumber = lineNumber; + destroyMarker(); + updateMarker(); + update(); +} + +void Breakpoint::setEngine(DebuggerEngine *value) +{ + QTC_ASSERT(b->m_state == BreakpointNew, qDebug() << "STATE: " << b->m_state << b->m_id); + QTC_ASSERT(!b->m_engine, qDebug() << "NO ENGINE" << b->m_id; return); + b->m_engine = value; + b->m_state = BreakpointInsertRequested; + b->m_response = BreakpointResponse(); + b->updateMarker(); + //b->scheduleSynchronization(); } static bool isAllowedTransition(BreakpointState from, BreakpointState to) { switch (from) { case BreakpointNew: - return to == BreakpointInsertRequested; + return to == BreakpointInsertRequested + || to == BreakpointDead; case BreakpointInsertRequested: return to == BreakpointInsertProceeding; case BreakpointInsertProceeding: @@ -876,287 +894,234 @@ static bool isAllowedTransition(BreakpointState from, BreakpointState to) return false; } -bool BreakHandler::isEngineRunning(BreakpointModelId id) const +bool BreakpointItem::isEngineRunning() const { - if (const DebuggerEngine *e = engine(id)) { - const DebuggerState state = e->state(); - return state != DebuggerFinished && state != DebuggerNotReady; - } - return false; + if (!m_engine) + return false; + const DebuggerState state = m_engine->state(); + return state != DebuggerFinished && state != DebuggerNotReady; } -void BreakHandler::setState(BreakpointModelId id, BreakpointState state) +void BreakpointItem::setState(BreakpointState state) { - Iterator it = m_storage.find(id); - //qDebug() << "BREAKPOINT STATE TRANSITION, ID: " << id - // << " FROM: " << it->state << " TO: " << state; - BREAK_ASSERT(it != m_storage.end(), qDebug() << id; return); - QTC_ASSERT(isAllowedTransition(it->state, state), - qDebug() << "UNEXPECTED BREAKPOINT STATE TRANSITION" - << it->state << state); + //qDebug() << "BREAKPOINT STATE TRANSITION, ID: " << m_id + // << " FROM: " << state << " TO: " << state; + if (!isAllowedTransition(m_state, state)) { + qDebug() << "UNEXPECTED BREAKPOINT STATE TRANSITION" << m_state << state; + QTC_CHECK(false); + } - if (it->state == state) { - qDebug() << "STATE UNCHANGED: " << id << state; + if (m_state == state) { + qDebug() << "STATE UNCHANGED: " << m_id << m_state; return; } - it->state = state; + m_state = state; // FIXME: updateMarker() should recognize the need for icon changes. if (state == BreakpointInserted) { - it->destroyMarker(); - it->updateMarker(id); + destroyMarker(); + updateMarker(); } - layoutChanged(); + update(); +} + +void BreakpointItem::deleteThis() +{ + setState(BreakpointDead); + destroyMarker(); + + // This is called from b directly. So delay deletion of b. + ExtensionSystem::InvokerBase invoker; + invoker.addArgument(m_id); + invoker.setConnectionType(Qt::QueuedConnection); + invoker.invoke(m_handler, "deletionHelper"); + QTC_CHECK(invoker.wasSuccessful()); } -void BreakHandler::notifyBreakpointChangeAfterInsertNeeded(BreakpointModelId id) +void Breakpoint::gotoState(BreakpointState target, BreakpointState assumedCurrent) { - QTC_ASSERT(state(id) == BreakpointInsertProceeding, qDebug() << state(id)); - setState(id, BreakpointChangeRequested); + QTC_ASSERT(b, return); + QTC_ASSERT(b->m_state == assumedCurrent, qDebug() << b->m_state); + b->setState(target); } -void BreakHandler::notifyBreakpointInsertProceeding(BreakpointModelId id) +void Breakpoint::notifyBreakpointChangeAfterInsertNeeded() { - QTC_ASSERT(state(id) == BreakpointInsertRequested, qDebug() << state(id)); - setState(id, BreakpointInsertProceeding); + gotoState(BreakpointChangeRequested, BreakpointInsertProceeding); } -void BreakHandler::notifyBreakpointInsertOk(BreakpointModelId id) +void Breakpoint::notifyBreakpointInsertProceeding() { - QTC_ASSERT(state(id) == BreakpointInsertProceeding, qDebug() << state(id)); - setState(id, BreakpointInserted); - ConstIterator it = m_storage.find(id); - BREAK_ASSERT(it != m_storage.end(), return); + gotoState(BreakpointInsertProceeding, BreakpointInsertRequested); } -void BreakHandler::notifyBreakpointInsertFailed(BreakpointModelId id) +void Breakpoint::notifyBreakpointInsertOk() { - QTC_ASSERT(state(id) == BreakpointInsertProceeding, qDebug() << state(id)); - setState(id, BreakpointDead); + gotoState(BreakpointInserted, BreakpointInsertProceeding); } -void BreakHandler::notifyBreakpointRemoveProceeding(BreakpointModelId id) +void Breakpoint::notifyBreakpointInsertFailed() { - QTC_ASSERT(state(id) == BreakpointRemoveRequested, qDebug() << state(id)); - setState(id, BreakpointRemoveProceeding); + gotoState(BreakpointDead, BreakpointInsertProceeding); } -void BreakHandler::notifyBreakpointRemoveOk(BreakpointModelId id) +void Breakpoint::notifyBreakpointRemoveProceeding() { - QTC_ASSERT(state(id) == BreakpointRemoveProceeding, qDebug() << state(id)); - setState(id, BreakpointDead); - cleanupBreakpoint(id); + gotoState(BreakpointRemoveProceeding, BreakpointRemoveRequested); } -void BreakHandler::notifyBreakpointRemoveFailed(BreakpointModelId id) +void Breakpoint::notifyBreakpointRemoveOk() { - QTC_ASSERT(state(id) == BreakpointRemoveProceeding, qDebug() << state(id)); - setState(id, BreakpointDead); - cleanupBreakpoint(id); + QTC_ASSERT(b, return); + QTC_ASSERT(b->m_state == BreakpointRemoveProceeding, qDebug() << b->m_state); + b->deleteThis(); } -void BreakHandler::notifyBreakpointChangeProceeding(BreakpointModelId id) +void Breakpoint::notifyBreakpointRemoveFailed() { - QTC_ASSERT(state(id) == BreakpointChangeRequested, qDebug() << state(id)); - setState(id, BreakpointChangeProceeding); + QTC_ASSERT(b, return); + QTC_ASSERT(b->m_state == BreakpointRemoveProceeding, qDebug() << b->m_state); + b->deleteThis(); } -void BreakHandler::notifyBreakpointChangeOk(BreakpointModelId id) +void Breakpoint::notifyBreakpointChangeProceeding() { - QTC_ASSERT(state(id) == BreakpointChangeProceeding, qDebug() << state(id)); - setState(id, BreakpointInserted); + gotoState(BreakpointChangeProceeding, BreakpointChangeRequested); } -void BreakHandler::notifyBreakpointChangeFailed(BreakpointModelId id) +void Breakpoint::notifyBreakpointChangeOk() { - QTC_ASSERT(state(id) == BreakpointChangeProceeding, qDebug() << state(id)); - setState(id, BreakpointDead); + gotoState(BreakpointInserted, BreakpointChangeProceeding); } -void BreakHandler::notifyBreakpointReleased(BreakpointModelId id) +void Breakpoint::notifyBreakpointChangeFailed() { - //QTC_ASSERT(state(id) == BreakpointChangeProceeding, qDebug() << state(id)); - Iterator it = m_storage.find(id); - BREAK_ASSERT(it != m_storage.end(), return); - it->state = BreakpointNew; - it->engine = 0; - it->response = BreakpointResponse(); - it->subItems.clear(); - it->destroyMarker(); - it->updateMarker(id); - if (it->data.type == WatchpointAtAddress - || it->data.type == WatchpointAtExpression - || it->data.type == BreakpointByAddress) - it->data.enabled = false; - else - it->data.address = 0; - layoutChanged(); + gotoState(BreakpointDead, BreakpointChangeProceeding); } -void BreakHandler::notifyBreakpointAdjusted(BreakpointModelId id, - const BreakpointParameters &data) +void Breakpoint::notifyBreakpointReleased() { - QTC_ASSERT(state(id) == BreakpointInserted, qDebug() << state(id)); - Iterator it = m_storage.find(id); - BREAK_ASSERT(it != m_storage.end(), return); - it->data = data; - //if (it->needsChange()) - // setState(id, BreakpointChangeRequested); + QTC_ASSERT(b, return); + b->removeChildren(); + //QTC_ASSERT(b->m_state == BreakpointChangeProceeding, qDebug() << b->m_state); + b->m_state = BreakpointNew; + b->m_engine = 0; + b->m_response = BreakpointResponse(); + b->destroyMarker(); + b->updateMarker(); + if (b->m_params.type == WatchpointAtAddress + || b->m_params.type == WatchpointAtExpression + || b->m_params.type == BreakpointByAddress) + b->m_params.enabled = false; + else + b->m_params.address = 0; + b->update(); } -void BreakHandler::notifyBreakpointNeedsReinsertion(BreakpointModelId id) +void Breakpoint::notifyBreakpointAdjusted(const BreakpointParameters ¶ms) { - QTC_ASSERT(state(id) == BreakpointChangeProceeding, qDebug() << state(id)); - Iterator it = m_storage.find(id); - BREAK_ASSERT(it != m_storage.end(), return); - it->state = BreakpointInsertRequested; + QTC_ASSERT(b, return); + QTC_ASSERT(b->m_state == BreakpointInserted, qDebug() << b->m_state); + b->m_params = params; + //if (b->needsChange()) + // b->setState(BreakpointChangeRequested); } -void BreakHandler::removeAlienBreakpoint(BreakpointModelId id) +void Breakpoint::notifyBreakpointNeedsReinsertion() { - Iterator it = m_storage.find(id); - BREAK_ASSERT(it != m_storage.end(), return); - it->state = BreakpointDead; - cleanupBreakpoint(id); + QTC_ASSERT(b, return); + QTC_ASSERT(b->m_state == BreakpointChangeProceeding, qDebug() << b->m_state); + b->m_state = BreakpointInsertRequested; } -void BreakHandler::removeBreakpoint(BreakpointModelId id) +void BreakpointItem::removeBreakpoint() { - Iterator it = m_storage.find(id); - BREAK_ASSERT(it != m_storage.end(), return); - switch (it->state) { + switch (m_state) { case BreakpointRemoveRequested: break; case BreakpointInserted: case BreakpointInsertProceeding: - setState(id, BreakpointRemoveRequested); + setState(BreakpointRemoveRequested); scheduleSynchronization(); break; case BreakpointNew: - it->state = BreakpointDead; - cleanupBreakpoint(id); + deleteThis(); break; default: qWarning("Warning: Cannot remove breakpoint %s in state '%s'.", - qPrintable(id.toString()), qPrintable(stateToString(it->state))); - it->state = BreakpointRemoveRequested; + qPrintable(m_id.toString()), qPrintable(stateToString(m_state))); + m_state = BreakpointRemoveRequested; break; } } -// Ok to be not thread-safe. The order does not matter and only the gui -// produces authoritative ids. -static int currentId = 0; +void BreakHandler::appendBreakpoint(const BreakpointParameters ¶ms) +{ + appendBreakpointInternal(params); + scheduleSynchronization(); +} -void BreakHandler::appendBreakpoint(const BreakpointParameters &data) +void BreakHandler::appendBreakpointInternal(const BreakpointParameters ¶ms) { - if (!data.isValid()) { - qWarning("Not adding invalid breakpoint: %s", qPrintable(data.toString())); + if (!params.isValid()) { + qWarning("Not adding invalid breakpoint: %s", qPrintable(params.toString())); return; } - BreakpointModelId id(++currentId); - const int row = m_storage.size(); - beginInsertRows(QModelIndex(), row, row); - Iterator it = m_storage.insert(id, BreakpointItem()); - endInsertRows(); - - // Create marker after copy is inserted into hash. - it->data = data; - it->updateMarker(id); - - scheduleSynchronization(); + BreakpointItem *b = new BreakpointItem(this); + b->m_params = params; + b->updateMarker(); + rootItem()->appendChild(b); } void BreakHandler::handleAlienBreakpoint(const BreakpointResponse &response, DebuggerEngine *engine) { - BreakpointModelId id = findSimilarBreakpoint(response); - if (id.isValid()) { + Breakpoint b = findSimilarBreakpoint(response); + if (b) { if (response.id.isMinor()) - insertSubBreakpoint(id, response); + b.insertSubBreakpoint(response); else - setResponse(id, response); + b.setResponse(response); } else { - id = BreakpointModelId(++currentId); - const int row = m_storage.size(); - - beginInsertRows(QModelIndex(), row, row); - Iterator it = m_storage.insert(id, BreakpointItem()); - endInsertRows(); - - it->data = response; - it->response = response; - it->state = BreakpointInserted; - it->engine = engine; - it->updateMarker(id); - - layoutChanged(); - scheduleSynchronization(); + auto b = new BreakpointItem(this); + b->m_params = response; + b->m_response = response; + b->m_state = BreakpointInserted; + b->m_engine = engine; + b->updateMarker(); + rootItem()->appendChild(b); } } -BreakpointModelId BreakHandler::at(int n) const +void Breakpoint::insertSubBreakpoint(const BreakpointResponse ¶ms) { - if (n < 0 || n >= m_storage.size()) - return BreakpointModelId(); - ConstIterator it = m_storage.constBegin(); - for ( ; --n >= 0; ++it) - ; - return it.key(); + QTC_ASSERT(b, return); + b->insertSubBreakpoint(params); } -int BreakHandler::indexOf(BreakpointModelId id) const +void BreakpointItem::insertSubBreakpoint(const BreakpointResponse ¶ms) { - int row = 0; - ConstIterator it = m_storage.constBegin(), et = m_storage.constEnd(); - for ( ; it != et; ++it, ++row) - if (it.key() == id) - return row; - return -1; -} + QTC_ASSERT(params.id.isMinor(), return); -void BreakHandler::insertSubBreakpoint(BreakpointModelId id, - const BreakpointResponse &data) -{ - QTC_ASSERT(data.id.isMinor(), return); - QTC_ASSERT(id.isMajor(), return); - Iterator it = m_storage.find(id); + int minorPart = params.id.minorPart(); - if (it == m_storage.end()) { - qDebug() << "FAILED: " << id.toString(); - for (ConstIterator it = m_storage.constBegin(), et = m_storage.constEnd(); - it != et; ++it) { - qDebug() << " ID: " << it->response.id.toString(); - qDebug() << " DATA: " << it->data.toString(); - qDebug() << " RESP: " << it->response.toString(); + const QVector<TreeItem *> &children = TreeItem::children(); + foreach (TreeItem *n, children) { + LocationItem *l = static_cast<LocationItem *>(n); + if (l->params.id.minorPart() == minorPart) { + // This modifies an existing sub-breakpoint. + l->params = params; + l->update(); + return; } } - QTC_ASSERT(it != m_storage.end(), return); - int minorPart = data.id.minorPart(); - int pos = -1; - for (int i = 0; i != it->subItems.size(); ++i) { - if (it->subItems.at(i).id.minorPart() == minorPart) { - pos = i; - break; - } - } - if (pos == -1) { - // This is a new sub-breakpoint. - //qDebug() << "NEW ID" << id; - int row = indexOf(id); - QTC_ASSERT(row != -1, return); - QModelIndex idx = createIndex(row, 0, id.toInternalId()); - beginInsertRows(idx, it->subItems.size(), it->subItems.size()); - it->subItems.append(data); - endInsertRows(); - } else { - // This modifies an existing sub-breakpoint. - //qDebug() << "EXISTING ID" << id; - it->subItems[pos] = data; - layoutChanged(); - } + // This is a new sub-breakpoint. + LocationItem *l = new LocationItem; + l->params = params; + appendChild(l); + expand(); } void BreakHandler::saveSessionData() @@ -1166,12 +1131,7 @@ void BreakHandler::saveSessionData() void BreakHandler::loadSessionData() { - beginResetModel(); - Iterator it = m_storage.begin(), et = m_storage.end(); - for ( ; it != et; ++it) - it->destroyMarker(); - m_storage.clear(); - endResetModel(); + removeItems(); loadBreakpoints(); } @@ -1179,25 +1139,17 @@ void BreakHandler::breakByFunction(const QString &functionName) { // One breakpoint per function is enough for now. This does not handle // combinations of multiple conditions and ignore counts, though. - ConstIterator it = m_storage.constBegin(), et = m_storage.constEnd(); - for ( ; it != et; ++it) { - const BreakpointParameters &data = it->data; - if (data.functionName == functionName - && data.condition.isEmpty() - && data.ignoreCount == 0) + foreach (TreeItem *n, rootItem()->children()) { + BreakpointItem *b = static_cast<BreakpointItem *>(n); + const BreakpointParameters ¶ms = b->m_params; + if (params.functionName == functionName + && params.condition.isEmpty() + && params.ignoreCount == 0) return; } - BreakpointParameters data(BreakpointByFunction); - data.functionName = functionName; - appendBreakpoint(data); -} - -QIcon BreakHandler::icon(BreakpointModelId id) const -{ - ConstIterator it = m_storage.find(id); - BREAK_ASSERT(it != m_storage.end(), qDebug() << "NO ICON FOR ID" << id; - return pendingBreakpointIcon()); - return it->icon(); + BreakpointParameters params(BreakpointByFunction); + params.functionName = functionName; + appendBreakpoint(params); } void BreakHandler::scheduleSynchronization() @@ -1215,158 +1167,127 @@ void BreakHandler::timerEvent(QTimerEvent *event) Internal::synchronizeBreakpoints(); } -void BreakHandler::gotoLocation(BreakpointModelId id) const +void Breakpoint::gotoLocation() const { - ConstIterator it = m_storage.find(id); - BREAK_ASSERT(it != m_storage.end(), return); - DebuggerEngine *engine = currentEngine(); - if (it->data.type == BreakpointByAddress) { - if (engine) - engine->gotoLocation(it->data.address); - } else { - if (engine) - engine->gotoLocation( - Location(it->markerFileName(), it->markerLineNumber(), false)); + if (DebuggerEngine *engine = currentEngine()) { + if (b->m_params.type == BreakpointByAddress) + engine->gotoLocation(b->m_params.address); + else + engine->gotoLocation(Location(b->markerFileName(), b->markerLineNumber(), false)); } } -void BreakHandler::updateFileNameFromMarker(BreakpointModelId id, const QString &fileName) +void BreakpointItem::updateFileNameFromMarker(const QString &fileName) { - Iterator it = m_storage.find(id); - BREAK_ASSERT(it != m_storage.end(), return); - it->data.fileName = fileName; - emit layoutChanged(); + m_params.fileName = fileName; + update(); } -void BreakHandler::updateLineNumberFromMarker(BreakpointModelId id, int lineNumber) +void BreakpointItem::updateLineNumberFromMarker(int lineNumber) { - Iterator it = m_storage.find(id); - BREAK_ASSERT(it != m_storage.end(), return); // Ignore updates to the "real" line number while the debugger is // running, as this can be triggered by moving the breakpoint to // the next line that generated code. - if (it->data.lineNumber == lineNumber) + if (m_params.lineNumber == lineNumber) ; // Nothing - else if (isEngineRunning(id)) - it->data.lineNumber += lineNumber - it->response.lineNumber; + else if (isEngineRunning()) + m_params.lineNumber += lineNumber - m_response.lineNumber; else - it->data.lineNumber = lineNumber; - it->updateMarker(id); - emit layoutChanged(); + m_params.lineNumber = lineNumber; + updateMarker(); + update(); } -void BreakHandler::changeLineNumberFromMarker(BreakpointModelId id, int lineNumber) +void BreakpointItem::changeLineNumberFromMarker(int lineNumber) { + m_params.lineNumber = lineNumber; + // We need to delay this as it is called from a marker which will be destroyed. ExtensionSystem::InvokerBase invoker; - invoker.addArgument(id); - invoker.addArgument(lineNumber); + invoker.addArgument(m_id); invoker.setConnectionType(Qt::QueuedConnection); - invoker.invoke(this, "changeLineNumberFromMarkerHelper"); + invoker.invoke(m_handler, "changeLineNumberFromMarkerHelper"); QTC_CHECK(invoker.wasSuccessful()); } -void BreakHandler::changeLineNumberFromMarkerHelper(BreakpointModelId id, int lineNumber) +void BreakHandler::changeLineNumberFromMarkerHelper(BreakpointModelId id) { - BreakpointParameters data = breakpointData(id); - data.lineNumber = lineNumber; - removeBreakpoint(id); - appendBreakpoint(data); + Breakpoint b = breakpointById(id); + QTC_ASSERT(b, return); + BreakpointParameters params = b.parameters(); + removeItem(b.b); + delete b.b; + appendBreakpoint(params); } -BreakpointModelIds BreakHandler::allBreakpointIds() const +Breakpoints BreakHandler::allBreakpoints() const { - BreakpointModelIds ids; - ConstIterator it = m_storage.constBegin(), et = m_storage.constEnd(); - for ( ; it != et; ++it) - ids.append(it.key()); - return ids; + Breakpoints items; + foreach (TreeItem *n, rootItem()->children()) + items.append(Breakpoint(static_cast<BreakpointItem *>(n))); + return items; } -BreakpointModelIds BreakHandler::unclaimedBreakpointIds() const +Breakpoints BreakHandler::unclaimedBreakpoints() const { - return engineBreakpointIds(0); + return engineBreakpoints(0); } -BreakpointModelIds BreakHandler::engineBreakpointIds(DebuggerEngine *engine) const +Breakpoints BreakHandler::engineBreakpoints(DebuggerEngine *engine) const { - BreakpointModelIds ids; - ConstIterator it = m_storage.constBegin(), et = m_storage.constEnd(); - for ( ; it != et; ++it) - if (it->engine == engine) - ids.append(it.key()); - return ids; + Breakpoints items; + foreach (TreeItem *n, rootItem()->children()) { + BreakpointItem *b = static_cast<BreakpointItem *>(n); + if (b->m_engine == engine) + items.append(Breakpoint(b)); + } + return items; } QStringList BreakHandler::engineBreakpointPaths(DebuggerEngine *engine) const { QSet<QString> set; - ConstIterator it = m_storage.constBegin(), et = m_storage.constEnd(); - for ( ; it != et; ++it) { - if (it->engine == engine) { - if (it->data.type == BreakpointByFileAndLine) - set.insert(QFileInfo(it->data.fileName).dir().path()); + foreach (TreeItem *n, rootItem()->children()) { + BreakpointItem *b = static_cast<BreakpointItem *>(n); + if (b->m_engine == engine) { + if (b->m_params.type == BreakpointByFileAndLine) + set.insert(QFileInfo(b->m_params.fileName).dir().path()); } } return set.toList(); } -void BreakHandler::cleanupBreakpoint(BreakpointModelId id) +void Breakpoint::setResponse(const BreakpointResponse &response) { - QTC_ASSERT(state(id) == BreakpointDead, qDebug() << state(id)); - BreakpointItem item = m_storage.take(id); - item.destroyMarker(); - layoutChanged(); -} - -const BreakpointResponse &BreakHandler::response(BreakpointModelId id) const -{ - static BreakpointResponse dummy; - ConstIterator it = m_storage.find(id); - if (it == m_storage.end()) { - qDebug() << "NO RESPONSE FOR " << id; - return dummy; - } - return it->response; -} - -bool BreakHandler::needsChange(BreakpointModelId id) const -{ - ConstIterator it = m_storage.find(id); - BREAK_ASSERT(it != m_storage.end(), return false); - return it->needsChange(); + QTC_ASSERT(b, return); + b->m_response = response; + b->destroyMarker(); + b->updateMarker(); + // Take over corrected values from response. + if ((b->m_params.type == BreakpointByFileAndLine + || b->m_params.type == BreakpointByFunction) + && !response.module.isEmpty()) + b->m_params.module = response.module; } -void BreakHandler::setResponse(BreakpointModelId id, - const BreakpointResponse &response) +bool Internal::Breakpoint::needsChange() const { - Iterator it = m_storage.find(id); - BREAK_ASSERT(it != m_storage.end(), return); - it->response = response; - it->destroyMarker(); - it->updateMarker(id); - // Take over corrected values from response. - if ((it->data.type == BreakpointByFileAndLine - || it->data.type == BreakpointByFunction) - && !response.module.isEmpty()) - it->data.module = response.module; + return b && b->needsChange(); } -void BreakHandler::changeBreakpointData(BreakpointModelId id, - const BreakpointParameters &data, BreakpointParts parts) +void Breakpoint::changeBreakpointData(const BreakpointParameters ¶ms) { - Q_UNUSED(parts); - Iterator it = m_storage.find(id); - BREAK_ASSERT(it != m_storage.end(), return); - if (data == it->data) + if (!b) return; - it->data = data; - it->destroyMarker(); - it->updateMarker(id); - layoutChanged(); - if (it->needsChange() && it->engine && it->state != BreakpointNew) { - setState(id, BreakpointChangeRequested); - scheduleSynchronization(); + if (params == b->m_params) + return; + b->m_params = params; + b->destroyMarker(); + b->updateMarker(); + b->update(); + if (b->needsChange() && b->m_engine && b->m_state != BreakpointNew) { + b->setState(BreakpointChangeRequested); + b->m_handler->scheduleSynchronization(); } } @@ -1376,42 +1297,52 @@ void BreakHandler::changeBreakpointData(BreakpointModelId id, // ////////////////////////////////////////////////////////////////// -BreakHandler::BreakpointItem::BreakpointItem() - : state(BreakpointNew), engine(0), marker(0) +// Ok to be not thread-safe. The order does not matter and only the gui +// produces authoritative ids. +static int currentId = 0; + +BreakpointItem::BreakpointItem(BreakHandler *handler) + : m_handler(handler), m_id(++currentId), m_state(BreakpointNew), m_engine(0), m_marker(0) {} -void BreakHandler::BreakpointItem::destroyMarker() +BreakpointItem::~BreakpointItem() +{ + delete m_marker; +} + +void BreakpointItem::destroyMarker() { - BreakpointMarker *m = marker; - marker = 0; + BreakpointMarker *m = m_marker; + QTC_ASSERT(m, return); + m->m_bp = 0; + m_marker = 0; delete m; } -QString BreakHandler::BreakpointItem::markerFileName() const +QString BreakpointItem::markerFileName() const { // Some heuristics to find a "good" file name. - if (!data.fileName.isEmpty()) { - QFileInfo fi(data.fileName); + if (!m_params.fileName.isEmpty()) { + QFileInfo fi(m_params.fileName); if (fi.exists()) return fi.absoluteFilePath(); } - if (!response.fileName.isEmpty()) { - QFileInfo fi(response.fileName); + if (!m_response.fileName.isEmpty()) { + QFileInfo fi(m_response.fileName); if (fi.exists()) return fi.absoluteFilePath(); } - if (response.fileName.endsWith(data.fileName)) - return response.fileName; - if (data.fileName.endsWith(response.fileName)) - return data.fileName; - return response.fileName.size() > data.fileName.size() - ? response.fileName : data.fileName; + if (m_response.fileName.endsWith(m_params.fileName)) + return m_response.fileName; + if (m_params.fileName.endsWith(m_response.fileName)) + return m_params.fileName; + return m_response.fileName.size() > m_params.fileName.size() + ? m_response.fileName : m_params.fileName; } - -int BreakHandler::BreakpointItem::markerLineNumber() const +int BreakpointItem::markerLineNumber() const { - return response.lineNumber ? response.lineNumber : data.lineNumber; + return m_response.lineNumber ? m_response.lineNumber : m_params.lineNumber; } static void formatAddress(QTextStream &str, quint64 address) @@ -1424,94 +1355,94 @@ static void formatAddress(QTextStream &str, quint64 address) } } -bool BreakHandler::BreakpointItem::needsChange() const +bool BreakpointItem::needsChange() const { - if (!data.conditionsMatch(response.condition)) + if (!m_params.conditionsMatch(m_response.condition)) return true; - if (data.ignoreCount != response.ignoreCount) + if (m_params.ignoreCount != m_response.ignoreCount) return true; - if (data.enabled != response.enabled) + if (m_params.enabled != m_response.enabled) return true; - if (data.threadSpec != response.threadSpec) + if (m_params.threadSpec != m_response.threadSpec) return true; - if (data.command != response.command) + if (m_params.command != m_response.command) return true; - if (data.type == BreakpointByFileAndLine && data.lineNumber != response.lineNumber) + if (m_params.type == BreakpointByFileAndLine && m_params.lineNumber != m_response.lineNumber) return true; // FIXME: Too strict, functions may have parameter lists, or not. - // if (data.type == BreakpointByFunction && data.functionName != response.functionName) + // if (m_params.type == BreakpointByFunction && m_params.functionName != m_response.functionName) // return true; - // if (data.type == BreakpointByAddress && data.address != response.address) + // if (m_params.type == BreakpointByAddress && m_params.address != m_response.address) // return true; return false; } -bool BreakHandler::BreakpointItem::isLocatedAt +bool BreakpointItem::isLocatedAt (const QString &fileName, int lineNumber, bool useMarkerPosition) const { - int line = useMarkerPosition ? response.lineNumber : data.lineNumber; + int line = useMarkerPosition ? m_response.lineNumber : m_params.lineNumber; return lineNumber == line - && (fileNameMatch(fileName, response.fileName) + && (fileNameMatch(fileName, m_response.fileName) || fileNameMatch(fileName, markerFileName())); } -void BreakHandler::BreakpointItem::updateMarkerIcon() +void BreakpointItem::updateMarkerIcon() { - if (marker) { - marker->setIcon(icon()); - marker->updateMarker(); + if (m_marker) { + m_marker->setIcon(icon()); + m_marker->updateMarker(); } } -void BreakHandler::BreakpointItem::updateMarker(BreakpointModelId id) +void BreakpointItem::updateMarker() { QString file = markerFileName(); int line = markerLineNumber(); - if (marker && (file != marker->fileName() || line != marker->lineNumber())) + if (m_marker && (file != m_marker->fileName() || line != m_marker->lineNumber())) destroyMarker(); - if (!marker && !file.isEmpty() && line > 0) - marker = new BreakpointMarker(id, file, line); + if (!m_marker && !file.isEmpty() && line > 0) + m_marker = new BreakpointMarker(this, file, line); } -QIcon BreakHandler::BreakpointItem::icon() const +QIcon BreakpointItem::icon() const { // FIXME: This seems to be called on each cursor blink as soon as the // cursor is near a line with a breakpoint marker (+/- 2 lines or so). - if (data.isTracepoint()) + if (m_params.isTracepoint()) return BreakHandler::tracepointIcon(); - if (data.type == WatchpointAtAddress) + if (m_params.type == WatchpointAtAddress) return BreakHandler::watchpointIcon(); - if (data.type == WatchpointAtExpression) + if (m_params.type == WatchpointAtExpression) return BreakHandler::watchpointIcon(); - if (!data.enabled) + if (!m_params.enabled) return BreakHandler::disabledBreakpointIcon(); - if (state == BreakpointInserted) + if (m_state == BreakpointInserted) return BreakHandler::breakpointIcon(); return BreakHandler::pendingBreakpointIcon(); } -QString BreakHandler::BreakpointItem::toToolTip() const +QString BreakpointItem::toToolTip() const { QString rc; QTextStream str(&rc); str << "<html><body><table>" //<< "<tr><td>" << tr("ID:") << "</td><td>" << m_id << "</td></tr>" << "<tr><td>" << tr("State:") - << "</td><td>" << (data.enabled ? tr("Enabled") : tr("Disabled")); - if (response.pending) + << "</td><td>" << (m_params.enabled ? tr("Enabled") : tr("Disabled")); + if (m_response.pending) str << tr(", pending"); - str << ", " << state << " (" << stateToString(state) << ")</td></tr>"; - if (engine) { + str << ", " << m_state << " (" << stateToString(m_state) << ")</td></tr>"; + if (m_engine) { str << "<tr><td>" << tr("Engine:") - << "</td><td>" << engine->objectName() << "</td></tr>"; + << "</td><td>" << m_engine->objectName() << "</td></tr>"; } - if (!response.pending) { + if (!m_response.pending) { str << "<tr><td>" << tr("Breakpoint Number:") - << "</td><td>" << response.id.toString() << "</td></tr>"; + << "</td><td>" << m_response.id.toString() << "</td></tr>"; } str << "<tr><td>" << tr("Breakpoint Type:") - << "</td><td>" << typeToString(data.type) << "</td></tr>" + << "</td><td>" << typeToString(m_params.type) << "</td></tr>" << "<tr><td>" << tr("Marker File:") << "</td><td>" << QDir::toNativeSeparators(markerFileName()) << "</td></tr>" << "<tr><td>" << tr("Marker Line:") @@ -1521,77 +1452,77 @@ QString BreakHandler::BreakpointItem::toToolTip() const << "</th><th>" << tr("Requested") << "</th><th>" << tr("Obtained") << "</th></tr>" << "<tr><td>" << tr("Internal Number:") - << "</td><td>—</td><td>" << response.id.toString() << "</td></tr>"; - if (data.type == BreakpointByFunction) { + << "</td><td>—</td><td>" << m_response.id.toString() << "</td></tr>"; + if (m_params.type == BreakpointByFunction) { str << "<tr><td>" << tr("Function Name:") - << "</td><td>" << data.functionName - << "</td><td>" << response.functionName + << "</td><td>" << m_params.functionName + << "</td><td>" << m_response.functionName << "</td></tr>"; } - if (data.type == BreakpointByFileAndLine) { + if (m_params.type == BreakpointByFileAndLine) { str << "<tr><td>" << tr("File Name:") - << "</td><td>" << QDir::toNativeSeparators(data.fileName) - << "</td><td>" << QDir::toNativeSeparators(response.fileName) + << "</td><td>" << QDir::toNativeSeparators(m_params.fileName) + << "</td><td>" << QDir::toNativeSeparators(m_response.fileName) << "</td></tr>" << "<tr><td>" << tr("Line Number:") - << "</td><td>" << data.lineNumber - << "</td><td>" << response.lineNumber << "</td></tr>" + << "</td><td>" << m_params.lineNumber + << "</td><td>" << m_response.lineNumber << "</td></tr>" << "<tr><td>" << tr("Corrected Line Number:") << "</td><td>-" - << "</td><td>" << response.correctedLineNumber << "</td></tr>"; + << "</td><td>" << m_response.correctedLineNumber << "</td></tr>"; } - if (data.type == BreakpointByFunction || data.type == BreakpointByFileAndLine) { + if (m_params.type == BreakpointByFunction || m_params.type == BreakpointByFileAndLine) { str << "<tr><td>" << tr("Module:") - << "</td><td>" << data.module - << "</td><td>" << response.module + << "</td><td>" << m_params.module + << "</td><td>" << m_response.module << "</td></tr>"; } str << "<tr><td>" << tr("Breakpoint Address:") << "</td><td>"; - formatAddress(str, data.address); + formatAddress(str, m_params.address); str << "</td><td>"; - formatAddress(str, response.address); + formatAddress(str, m_response.address); str << "</td></tr>"; - if (response.multiple) { + if (m_response.multiple) { str << "<tr><td>" << tr("Multiple Addresses:") << "</td><td>" << "</td></tr>"; } - if (!data.command.isEmpty() || !response.command.isEmpty()) { + if (!m_params.command.isEmpty() || !m_response.command.isEmpty()) { str << "<tr><td>" << tr("Command:") - << "</td><td>" << data.command - << "</td><td>" << response.command + << "</td><td>" << m_params.command + << "</td><td>" << m_response.command << "</td></tr>"; } - if (!data.message.isEmpty() || !response.message.isEmpty()) { + if (!m_params.message.isEmpty() || !m_response.message.isEmpty()) { str << "<tr><td>" << tr("Message:") - << "</td><td>" << data.message - << "</td><td>" << response.message + << "</td><td>" << m_params.message + << "</td><td>" << m_response.message << "</td></tr>"; } - if (!data.condition.isEmpty() || !response.condition.isEmpty()) { + if (!m_params.condition.isEmpty() || !m_response.condition.isEmpty()) { str << "<tr><td>" << tr("Condition:") - << "</td><td>" << data.condition - << "</td><td>" << response.condition + << "</td><td>" << m_params.condition + << "</td><td>" << m_response.condition << "</td></tr>"; } - if (data.ignoreCount || response.ignoreCount) { + if (m_params.ignoreCount || m_response.ignoreCount) { str << "<tr><td>" << tr("Ignore Count:") << "</td><td>"; - if (data.ignoreCount) - str << data.ignoreCount; + if (m_params.ignoreCount) + str << m_params.ignoreCount; str << "</td><td>"; - if (response.ignoreCount) - str << response.ignoreCount; + if (m_response.ignoreCount) + str << m_response.ignoreCount; str << "</td></tr>"; } - if (data.threadSpec >= 0 || response.threadSpec >= 0) { + if (m_params.threadSpec >= 0 || m_response.threadSpec >= 0) { str << "<tr><td>" << tr("Thread Specification:") << "</td><td>"; - if (data.threadSpec >= 0) - str << data.threadSpec; + if (m_params.threadSpec >= 0) + str << m_params.threadSpec; str << "</td><td>"; - if (response.threadSpec >= 0) - str << response.threadSpec; + if (m_response.threadSpec >= 0) + str << m_response.threadSpec; str << "</td></tr>"; } str << "</table></body></html>"; @@ -1600,29 +1531,89 @@ QString BreakHandler::BreakpointItem::toToolTip() const void BreakHandler::setWatchpointAtAddress(quint64 address, unsigned size) { - BreakpointParameters data(WatchpointAtAddress); - data.address = address; - data.size = size; - BreakpointModelId id = findWatchpoint(data); - if (id) { + BreakpointParameters params(WatchpointAtAddress); + params.address = address; + params.size = size; + if (findWatchpoint(params)) { qDebug() << "WATCHPOINT EXISTS"; // removeBreakpoint(index); return; } - appendBreakpoint(data); + appendBreakpoint(params); } void BreakHandler::setWatchpointAtExpression(const QString &exp) { - BreakpointParameters data(WatchpointAtExpression); - data.expression = exp; - BreakpointModelId id = findWatchpoint(data); - if (id) { + BreakpointParameters params(WatchpointAtExpression); + params.expression = exp; + if (findWatchpoint(params)) { qDebug() << "WATCHPOINT EXISTS"; // removeBreakpoint(index); return; } - appendBreakpoint(data); + appendBreakpoint(params); +} + +bool Breakpoint::isValid() const +{ + return b && b->m_id.isValid(); +} + +uint Breakpoint::hash() const +{ + return b ? 0 : qHash(b->m_id); +} + +BreakpointModelId Breakpoint::id() const +{ + return b ? b->m_id : BreakpointModelId(); +} + +QString Breakpoint::msgWatchpointByExpressionTriggered(const int number, const QString &expr) const +{ + return id() + ? tr("Data breakpoint %1 (%2) at %3 triggered.") + .arg(id().toString()).arg(number).arg(expr) + : tr("Internal data breakpoint %1 at %2 triggered.") + .arg(number).arg(expr); +} + +QString Breakpoint::msgWatchpointByExpressionTriggered(const int number, const QString &expr, + const QString &threadId) const +{ + return id() + ? tr("Data breakpoint %1 (%2) at %3 in thread %4 triggered.") + .arg(id().toString()).arg(number).arg(expr).arg(threadId) + : tr("Internal data breakpoint %1 at %2 in thread %3 triggered.") + .arg(number).arg(expr).arg(threadId); +} + +QString Breakpoint::msgWatchpointByAddressTriggered(const int number, quint64 address) const +{ + return id() + ? tr("Data breakpoint %1 (%2) at 0x%3 triggered.") + .arg(id().toString()).arg(number).arg(address, 0, 16) + : tr("Internal data breakpoint %1 at 0x%2 triggered.") + .arg(number).arg(address, 0, 16); +} + +QString Breakpoint::msgWatchpointByAddressTriggered( + const int number, quint64 address, const QString &threadId) const +{ + return id() + ? tr("Data breakpoint %1 (%2) at 0x%3 in thread %4 triggered.") + .arg(id().toString()).arg(number).arg(address, 0, 16).arg(threadId) + : tr("Internal data breakpoint %1 at 0x%2 in thread %3 triggered.") + .arg(id().toString()).arg(number).arg(address, 0, 16).arg(threadId); +} + +QString Breakpoint::msgBreakpointTriggered(const int number, const QString &threadId) const +{ + return id() + ? tr("Stopped at breakpoint %1 (%2) in thread %3.") + .arg(id().toString()).arg(number).arg(threadId) + : tr("Stopped at internal breakpoint %1 in thread %2.") + .arg(number).arg(threadId); } } // namespace Internal diff --git a/src/plugins/debugger/breakhandler.h b/src/plugins/debugger/breakhandler.h index 7281d88faa..430f93c698 100644 --- a/src/plugins/debugger/breakhandler.h +++ b/src/plugins/debugger/breakhandler.h @@ -33,7 +33,10 @@ #include "breakpoint.h" -#include <QAbstractTableModel> +#include <utils/treemodel.h> + +#include <QCoreApplication> +#include <QPointer> ////////////////////////////////////////////////////////////////// // @@ -42,20 +45,132 @@ ////////////////////////////////////////////////////////////////// namespace Debugger { +namespace Internal { +class BreakpointItem; +class BreakHandler; +class DebuggerCommand; class DebuggerEngine; -namespace Internal { +// Non-owning "deletion-safe" wrapper around a BreakpointItem * +class Breakpoint +{ + Q_DECLARE_TR_FUNCTIONS(Debugger::Internal::BreakHandler) + +public: + Breakpoint() {} + + bool isValid() const; + operator const void *() const { return isValid() ? this : 0; } + bool operator!() const { return !isValid(); } + + uint hash() const; + + const BreakpointParameters ¶meters() const; + void addToCommand(DebuggerCommand *cmd) const; -class BreakpointMarker; + BreakpointModelId id() const; + bool isLocatedAt(const QString &fileName, int lineNumber, + bool useMarkerPosition) const; + + QIcon icon() const; + BreakpointState state() const; + void setEngine(DebuggerEngine *engine); + + // State transitions. + void notifyBreakpointChangeAfterInsertNeeded(); + void notifyBreakpointInsertProceeding(); + void notifyBreakpointInsertOk(); + void notifyBreakpointInsertFailed(); + void notifyBreakpointChangeOk(); + void notifyBreakpointChangeProceeding(); + void notifyBreakpointChangeFailed(); + void notifyBreakpointPending(); + void notifyBreakpointRemoveProceeding(); + void notifyBreakpointRemoveOk(); + void notifyBreakpointRemoveFailed(); + void notifyBreakpointReleased(); + void notifyBreakpointNeedsReinsertion(); + void notifyBreakpointAdjusted(const BreakpointParameters ¶ms); + + void update(); + + void gotoLocation() const; + + // Getter retrieves property value. + // Setter sets property value and triggers update if changed. + // Only use setters when it is safe to assume that the breakpoint still + // exist. That's not the case if the event loop could run after you + // obtained the BreakpointItem pointer. + BreakpointPathUsage pathUsage() const; + void setPathUsage(const BreakpointPathUsage &u); + QByteArray condition() const; + void setCondition(const QByteArray &condition); + int ignoreCount() const; + void setIgnoreCount(const int &count); + int threadSpec() const; + void setThreadSpec(const int &spec); + QString fileName() const; + void setFileName(const QString &fileName); + QString functionName() const; + void setFunctionName(const QString &functionName); + QString expression() const; + void setExpression(const QString &expression); + QString message() const; + void setMessage(const QString &m); + BreakpointType type() const; + void setType(const BreakpointType &type); + quint64 address() const; + void setAddress(const quint64 &address); + int lineNumber() const; + void changeBreakpointData(const BreakpointParameters &data); + bool isEnabled() const; + void setEnabled(bool on) const; + void updateFileNameFromMarker(const QString &fileName); + void updateLineNumberFromMarker(int lineNumber); + void changeLineNumberFromMarker(int lineNumber); + void setMarkerFileAndLine(const QString &fileName, int lineNumber); + bool isWatchpoint() const; + bool isTracepoint() const; + void setTracepoint(bool on); + DebuggerEngine *engine() const; + const BreakpointResponse &response() const; + void setResponse(const BreakpointResponse &data); + bool needsChange() const; + bool needsChildren() const; + + bool isOneShot() const; + void insertSubBreakpoint(const BreakpointResponse &data); + void removeAlienBreakpoint(); + void removeBreakpoint() const; + + QString msgWatchpointByAddressTriggered(int number, quint64 address) const; + QString msgWatchpointByAddressTriggered( + int number, quint64 address, const QString &threadId) const; + QString msgWatchpointByExpressionTriggered(int number, const QString &expr) const; + QString msgWatchpointByExpressionTriggered( + int number, const QString &expr, const QString &threadId) const; + QString msgBreakpointTriggered(int number, const QString &threadId) const; + +private: + void gotoState(BreakpointState target, BreakpointState assumedCurrent); -class BreakHandler : public QAbstractItemModel + friend class BreakHandler; + explicit Breakpoint(BreakpointItem *b); + + QPointer<BreakpointItem> b; +}; + +inline uint qHash(const Debugger::Internal::Breakpoint &b) { return b.hash(); } + +typedef QList<Breakpoint> Breakpoints; + +class BreakHandler : public Utils::TreeModel { Q_OBJECT public: BreakHandler(); - ~BreakHandler(); void loadSessionData(); void saveSessionData(); @@ -65,22 +180,19 @@ public: // The only way to add a new breakpoint. void appendBreakpoint(const BreakpointParameters &data); void handleAlienBreakpoint(const BreakpointResponse &response, DebuggerEngine *engine); - void insertSubBreakpoint(BreakpointModelId id, const BreakpointResponse &data); - void removeAlienBreakpoint(BreakpointModelId id); - BreakpointModelIds allBreakpointIds() const; - BreakpointModelIds engineBreakpointIds(DebuggerEngine *engine) const; - BreakpointModelIds unclaimedBreakpointIds() const; - int size() const { return m_storage.size(); } + Breakpoints allBreakpoints() const; + Breakpoints engineBreakpoints(DebuggerEngine *engine) const; + Breakpoints unclaimedBreakpoints() const; QStringList engineBreakpointPaths(DebuggerEngine *engine) const; // Find a breakpoint matching approximately the data in needle. - BreakpointModelId findSimilarBreakpoint(const BreakpointResponse &needle) const; - BreakpointModelId findBreakpointByResponseId(const BreakpointResponseId &resultId) const; - BreakpointModelId findWatchpoint(const BreakpointParameters &data) const; - BreakpointModelId findBreakpointByFunction(const QString &functionName) const; - BreakpointModelId findBreakpointByIndex(const QModelIndex &index) const; - BreakpointModelIds findBreakpointsByIndex(const QList<QModelIndex> &list) const; + Breakpoint findSimilarBreakpoint(const BreakpointResponse &needle) const; + Breakpoint findBreakpointByResponseId(const BreakpointResponseId &resultId) const; + Breakpoint findWatchpoint(const BreakpointParameters &data) const; + Breakpoint findBreakpointByFunction(const QString &functionName) const; + Breakpoint findBreakpointByIndex(const QModelIndex &index) const; + Breakpoints findBreakpointsByIndex(const QList<QModelIndex> &list) const; void updateMarkers(); static QIcon breakpointIcon(); @@ -90,77 +202,11 @@ public: static QIcon watchpointIcon(); static QIcon tracepointIcon(); - BreakpointModelId findBreakpointByFileAndLine(const QString &fileName, + Breakpoint findBreakpointByFileAndLine(const QString &fileName, int lineNumber, bool useMarkerPosition = true); - BreakpointModelId findBreakpointByAddress(quint64 address) const; + Breakpoint findBreakpointByAddress(quint64 address) const; void breakByFunction(const QString &functionName); - void removeBreakpoint(BreakpointModelId id); - QIcon icon(BreakpointModelId id) const; - void gotoLocation(BreakpointModelId id) const; - - // Getter retrieves property value. - // Setter sets property value and triggers update if changed. - BreakpointPathUsage pathUsage(BreakpointModelId id) const; - void setPathUsage(BreakpointModelId, const BreakpointPathUsage &u); - QByteArray condition(BreakpointModelId id) const; - void setCondition(BreakpointModelId, const QByteArray &condition); - int ignoreCount(BreakpointModelId id) const; - void setIgnoreCount(BreakpointModelId, const int &count); - int threadSpec(BreakpointModelId id) const; - void setThreadSpec(BreakpointModelId, const int &spec); - QString fileName(BreakpointModelId id) const; - void setFileName(BreakpointModelId, const QString &fileName); - QString functionName(BreakpointModelId id) const; - void setFunctionName(BreakpointModelId, const QString &functionName); - QString expression(BreakpointModelId id) const; - void setExpression(BreakpointModelId, const QString &expression); - QString message(BreakpointModelId id) const; - void setMessage(BreakpointModelId, const QString &m); - BreakpointType type(BreakpointModelId id) const; - void setType(BreakpointModelId id, const BreakpointType &type); - quint64 address(BreakpointModelId id) const; - void setAddress(BreakpointModelId id, const quint64 &address); - int lineNumber(BreakpointModelId id) const; - void changeBreakpointData(BreakpointModelId id, const BreakpointParameters &data, - BreakpointParts parts); - const BreakpointParameters &breakpointData(BreakpointModelId id) const; - BreakpointState state(BreakpointModelId id) const; - bool isEnabled(BreakpointModelId id) const; - void setEnabled(BreakpointModelId id, bool on); - void updateFileNameFromMarker(BreakpointModelId id, const QString &fileName); - void updateLineNumberFromMarker(BreakpointModelId id, int lineNumber); - void changeLineNumberFromMarker(BreakpointModelId id, int lineNumber); - void setMarkerFileAndLine(BreakpointModelId id, - const QString &fileName, int lineNumber); - bool isOneShot(BreakpointModelId id) const; - bool isWatchpoint(BreakpointModelId id) const; - bool isTracepoint(BreakpointModelId id) const; - void setTracepoint(BreakpointModelId, bool on); - DebuggerEngine *engine(BreakpointModelId id) const; - void setEngine(BreakpointModelId id, DebuggerEngine *engine); - const BreakpointResponse &response(BreakpointModelId id) const; - void setResponse(BreakpointModelId id, const BreakpointResponse &data); - bool needsChange(BreakpointModelId id) const; - bool needsChildren(BreakpointModelId id) const; - - // State transitions. - void notifyBreakpointChangeAfterInsertNeeded(BreakpointModelId id); - void notifyBreakpointInsertProceeding(BreakpointModelId id); - void notifyBreakpointInsertOk(BreakpointModelId id); - void notifyBreakpointInsertFailed(BreakpointModelId id); - void notifyBreakpointChangeOk(BreakpointModelId id); - void notifyBreakpointChangeProceeding(BreakpointModelId id); - void notifyBreakpointChangeFailed(BreakpointModelId id); - void notifyBreakpointPending(BreakpointModelId id); - void notifyBreakpointRemoveProceeding(BreakpointModelId id); - void notifyBreakpointRemoveOk(BreakpointModelId id); - void notifyBreakpointRemoveFailed(BreakpointModelId id); - void notifyBreakpointReleased(BreakpointModelId id); - void notifyBreakpointNeedsReinsertion(BreakpointModelId id); - void notifyBreakpointAdjusted(BreakpointModelId id, - const BreakpointParameters &data); - static QString displayFromThreadSpec(int spec); static int threadSpecFromDisplay(const QString &str); @@ -168,53 +214,19 @@ public: void setWatchpointAtAddress(quint64 address, unsigned size); void setWatchpointAtExpression(const QString &exp); + Breakpoint breakpointById(BreakpointModelId id) const; + private: - // QAbstractItemModel implementation. - int columnCount(const QModelIndex &parent) const; - int rowCount(const QModelIndex &parent) const; - QVariant data(const QModelIndex &index, int role) const; - QVariant headerData(int section, Qt::Orientation orientation, int role) const; - Qt::ItemFlags flags(const QModelIndex &index) const; - QModelIndex index(int row, int col, const QModelIndex &parent) const; - QModelIndex parent(const QModelIndex &parent) const; - QModelIndex createIndex(int row, int column, quint32 id) const; - QModelIndex createIndex(int row, int column, void *ptr) const; - - int indexOf(BreakpointModelId id) const; - BreakpointModelId at(int index) const; - bool isEngineRunning(BreakpointModelId id) const; - void setState(BreakpointModelId id, BreakpointState state); + friend class BreakpointItem; + friend class Breakpoint; + void loadBreakpoints(); void saveBreakpoints(); - void cleanupBreakpoint(BreakpointModelId id); - Q_SLOT void changeLineNumberFromMarkerHelper(Debugger::Internal::BreakpointModelId id, int lineNumber); - - struct BreakpointItem - { - BreakpointItem(); - - void destroyMarker(); - bool needsChange() const; - bool isLocatedAt(const QString &fileName, int lineNumber, - bool useMarkerPosition) const; - void updateMarker(BreakpointModelId id); - void updateMarkerIcon(); - QString toToolTip() const; - QString markerFileName() const; - int markerLineNumber() const; - QIcon icon() const; - - BreakpointParameters data; - BreakpointState state; // Current state of breakpoint. - DebuggerEngine *engine; // Engine currently handling the breakpoint. - BreakpointResponse response; - BreakpointMarker *marker; - QList<BreakpointResponse> subItems; - }; - typedef QHash<BreakpointModelId, BreakpointItem> BreakpointStorage; - typedef BreakpointStorage::ConstIterator ConstIterator; - typedef BreakpointStorage::Iterator Iterator; - BreakpointStorage m_storage; + + void appendBreakpointInternal(const BreakpointParameters &data); + + Q_SLOT void changeLineNumberFromMarkerHelper(Debugger::Internal::BreakpointModelId id); + Q_SLOT void deletionHelper(Debugger::Internal::BreakpointModelId id); void scheduleSynchronization(); void timerEvent(QTimerEvent *event); @@ -224,4 +236,6 @@ private: } // namespace Internal } // namespace Debugger +Q_DECLARE_METATYPE(Debugger::Internal::Breakpoint) + #endif // DEBUGGER_BREAKHANDLER_H diff --git a/src/plugins/debugger/breakpoint.cpp b/src/plugins/debugger/breakpoint.cpp index 859ed4956e..76a722c66b 100644 --- a/src/plugins/debugger/breakpoint.cpp +++ b/src/plugins/debugger/breakpoint.cpp @@ -94,18 +94,6 @@ QString BreakpointModelId::toString() const return QString::number(m_majorPart); } -BreakpointModelId BreakpointModelId::parent() const -{ - QTC_ASSERT(isMinor(), return BreakpointModelId()); - return BreakpointModelId(m_majorPart, 0); -} - -BreakpointModelId BreakpointModelId::child(int row) const -{ - QTC_ASSERT(isMajor(), return BreakpointModelId()); - return BreakpointModelId(m_majorPart, row + 1); -} - ////////////////////////////////////////////////////////////////// // diff --git a/src/plugins/debugger/breakpoint.h b/src/plugins/debugger/breakpoint.h index d53a292970..989c3528c8 100644 --- a/src/plugins/debugger/breakpoint.h +++ b/src/plugins/debugger/breakpoint.h @@ -63,8 +63,6 @@ public: { return m_majorPart == id.m_majorPart && m_minorPart == id.m_minorPart; } quint16 majorPart() const { return m_majorPart; } quint16 minorPart() const { return m_minorPart; } - BreakpointModelId parent() const; - BreakpointModelId child(int row) const; static BreakpointModelId fromInternalId(quint32 id) { return BreakpointModelId(id & 0xff, id >> 16); } @@ -199,7 +197,6 @@ inline void operator|=(BreakpointParts &p, BreakpointParts r) p = BreakpointParts(int(p) | int(r)); } - class BreakpointParameters { public: @@ -257,8 +254,6 @@ public: int correctedLineNumber; //!< Line number as seen by gdb. }; -typedef QList<BreakpointModelId> BreakpointModelIds; - inline uint qHash(const Debugger::Internal::BreakpointModelId &id) { return id.toInternalId(); diff --git a/src/plugins/debugger/breakpointmarker.cpp b/src/plugins/debugger/breakpointmarker.cpp deleted file mode 100644 index 5867d64bf9..0000000000 --- a/src/plugins/debugger/breakpointmarker.cpp +++ /dev/null @@ -1,88 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2015 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing -** -** This file is part of Qt Creator. -** -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms and -** conditions see http://www.qt.io/terms-conditions. For further information -** use the contact form at http://www.qt.io/contact-us. -** -** 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 or version 3 as published by the Free -** Software Foundation and appearing in the file LICENSE.LGPLv21 and -** LICENSE.LGPLv3 included in the packaging of this file. Please review the -** following information to ensure the GNU Lesser General Public License -** requirements will be met: https://www.gnu.org/licenses/lgpl.html and -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, The Qt Company gives you certain additional -** rights. These rights are described in The Qt Company LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -****************************************************************************/ - -#include "breakpointmarker.h" -#include "breakhandler.h" -#include "debuggercore.h" - -////////////////////////////////////////////////////////////////// -// -// BreakpointMarker -// -////////////////////////////////////////////////////////////////// - - -namespace Debugger { -namespace Internal { - -BreakpointMarker::BreakpointMarker(BreakpointModelId id, - const QString &fileName, int lineNumber) - : TextMark(fileName, lineNumber), m_id(id) -{ - setIcon(breakHandler()->icon(m_id)); - setPriority(TextEditor::TextMark::NormalPriority); - //qDebug() << "CREATE MARKER " << fileName << lineNumber; -} - -BreakpointMarker::~BreakpointMarker() -{ - //qDebug() << "REMOVE MARKER "; -} - -void BreakpointMarker::removedFromEditor() -{ - breakHandler()->removeBreakpoint(m_id); -} - -void BreakpointMarker::updateLineNumber(int lineNumber) -{ - TextMark::updateLineNumber(lineNumber); - breakHandler()->updateLineNumberFromMarker(m_id, lineNumber); -} - -void BreakpointMarker::dragToLine(int lineNumber) -{ - breakHandler()->changeLineNumberFromMarker(m_id, lineNumber); -} - -void BreakpointMarker::clicked() -{ - breakHandler()->removeBreakpoint(m_id); -} - -void BreakpointMarker::updateFileName(const QString &fileName) -{ - TextMark::updateFileName(fileName); - breakHandler()->updateFileNameFromMarker(m_id, fileName); -} - -} // namespace Internal -} // namespace Debugger - diff --git a/src/plugins/debugger/breakwindow.cpp b/src/plugins/debugger/breakwindow.cpp index fdc2364992..ff5434e298 100644 --- a/src/plugins/debugger/breakwindow.cpp +++ b/src/plugins/debugger/breakwindow.cpp @@ -49,7 +49,6 @@ #include <QKeyEvent> #include <QLabel> #include <QLineEdit> -#include <QMessageBox> #include <QMenu> #include <QSpinBox> #include <QTextEdit> @@ -81,7 +80,7 @@ class BreakpointDialog : public QDialog { Q_OBJECT public: - explicit BreakpointDialog(BreakpointModelId id, QWidget *parent = 0); + explicit BreakpointDialog(Breakpoint b, QWidget *parent = 0); bool showDialog(BreakpointParameters *data, BreakpointParts *parts); void setParameters(const BreakpointParameters &data); @@ -139,13 +138,13 @@ private: QDialogButtonBox *m_buttonBox; }; -BreakpointDialog::BreakpointDialog(BreakpointModelId id, QWidget *parent) +BreakpointDialog::BreakpointDialog(Breakpoint b, QWidget *parent) : QDialog(parent), m_enabledParts(~0), m_previousType(UnknownBreakpointType), m_firstTypeChange(true) { setWindowTitle(tr("Edit Breakpoint Properties")); - QGroupBox *groupBoxBasic = new QGroupBox(tr("Basic"), this); + auto groupBoxBasic = new QGroupBox(tr("Basic"), this); // Match BreakpointType (omitting unknown type). QStringList types; @@ -196,7 +195,7 @@ BreakpointDialog::BreakpointDialog(BreakpointModelId id, QWidget *parent) m_labelFunction = new QLabel(tr("Fun&ction:"), groupBoxBasic); m_labelFunction->setBuddy(m_lineEditFunction); - QGroupBox *groupBoxAdvanced = new QGroupBox(tr("Advanced"), this); + auto groupBoxAdvanced = new QGroupBox(tr("Advanced"), this); m_checkBoxTracepoint = new QCheckBox(groupBoxAdvanced); m_labelTracepoint = new QLabel(tr("T&racepoint only:"), groupBoxAdvanced); @@ -269,8 +268,8 @@ BreakpointDialog::BreakpointDialog(BreakpointModelId id, QWidget *parent) m_buttonBox = new QDialogButtonBox(this); m_buttonBox->setStandardButtons(QDialogButtonBox::Cancel|QDialogButtonBox::Ok); - if (id.isValid()) { - if (DebuggerEngine *engine = breakHandler()->engine(id)) { + if (b) { + if (DebuggerEngine *engine = b.engine()) { if (!engine->hasCapability(BreakConditionCapability)) m_enabledParts &= ~ConditionPart; if (!engine->hasCapability(BreakModuleCapability)) @@ -280,7 +279,7 @@ BreakpointDialog::BreakpointDialog(BreakpointModelId id, QWidget *parent) } } - QFormLayout *basicLayout = new QFormLayout(groupBoxBasic); + auto basicLayout = new QFormLayout(groupBoxBasic); basicLayout->addRow(m_labelType, m_comboBoxType); basicLayout->addRow(m_labelFileName, m_pathChooserFileName); basicLayout->addRow(m_labelLineNumber, m_lineEditLineNumber); @@ -290,7 +289,7 @@ BreakpointDialog::BreakpointDialog(BreakpointModelId id, QWidget *parent) basicLayout->addRow(m_labelFunction, m_lineEditFunction); basicLayout->addRow(m_labelOneShot, m_checkBoxOneShot); - QFormLayout *advancedLeftLayout = new QFormLayout(); + auto advancedLeftLayout = new QFormLayout(); advancedLeftLayout->setFieldGrowthPolicy(QFormLayout::AllNonFixedFieldsGrow); advancedLeftLayout->addRow(m_labelCondition, m_lineEditCondition); advancedLeftLayout->addRow(m_labelIgnoreCount, m_spinBoxIgnoreCount); @@ -298,18 +297,18 @@ BreakpointDialog::BreakpointDialog(BreakpointModelId id, QWidget *parent) advancedLeftLayout->addRow(m_labelUseFullPath, m_comboBoxPathUsage); advancedLeftLayout->addRow(m_labelModule, m_lineEditModule); - QFormLayout *advancedRightLayout = new QFormLayout(); + auto advancedRightLayout = new QFormLayout(); advancedRightLayout->setFieldGrowthPolicy(QFormLayout::ExpandingFieldsGrow); advancedRightLayout->addRow(m_labelCommands, m_textEditCommands); advancedRightLayout->addRow(m_labelTracepoint, m_checkBoxTracepoint); advancedRightLayout->addRow(m_labelMessage, m_lineEditMessage); - QHBoxLayout *horizontalLayout = new QHBoxLayout(groupBoxAdvanced); + auto horizontalLayout = new QHBoxLayout(groupBoxAdvanced); horizontalLayout->addLayout(advancedLeftLayout); horizontalLayout->addSpacing(15); horizontalLayout->addLayout(advancedRightLayout); - QVBoxLayout *verticalLayout = new QVBoxLayout(this); + auto verticalLayout = new QVBoxLayout(this); verticalLayout->addWidget(groupBoxBasic); verticalLayout->addSpacing(10); verticalLayout->addWidget(groupBoxAdvanced); @@ -317,9 +316,10 @@ BreakpointDialog::BreakpointDialog(BreakpointModelId id, QWidget *parent) verticalLayout->addWidget(m_buttonBox); verticalLayout->setStretchFactor(groupBoxAdvanced, 10); - connect(m_comboBoxType, SIGNAL(activated(int)), SLOT(typeChanged(int))); - connect(m_buttonBox, SIGNAL(accepted()), SLOT(accept())); - connect(m_buttonBox, SIGNAL(rejected()), SLOT(reject())); + connect(m_comboBoxType, static_cast<void(QComboBox::*)(int)>(&QComboBox::activated), + this, &BreakpointDialog::typeChanged); + connect(m_buttonBox, &QDialogButtonBox::accepted, this, &QDialog::accept); + connect(m_buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject); } void BreakpointDialog::setType(BreakpointType type) @@ -655,18 +655,18 @@ MultiBreakPointsDialog::MultiBreakPointsDialog(QWidget *parent) : m_buttonBox = new QDialogButtonBox(this); m_buttonBox->setStandardButtons(QDialogButtonBox::Cancel|QDialogButtonBox::Ok); - QFormLayout *formLayout = new QFormLayout; + auto formLayout = new QFormLayout; if (currentEngine()->hasCapability(BreakConditionCapability)) formLayout->addRow(tr("&Condition:"), m_lineEditCondition); formLayout->addRow(tr("&Ignore count:"), m_spinBoxIgnoreCount); formLayout->addRow(tr("&Thread specification:"), m_lineEditThreadSpec); - QVBoxLayout *verticalLayout = new QVBoxLayout(this); + auto verticalLayout = new QVBoxLayout(this); verticalLayout->addLayout(formLayout); verticalLayout->addWidget(m_buttonBox); - QObject::connect(m_buttonBox, SIGNAL(accepted()), this, SLOT(accept())); - QObject::connect(m_buttonBox, SIGNAL(rejected()), this, SLOT(reject())); + connect(m_buttonBox, &QDialogButtonBox::accepted, this, &QDialog::accept); + connect(m_buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject); } /////////////////////////////////////////////////////////////////////// @@ -679,8 +679,8 @@ BreakTreeView::BreakTreeView() { setWindowIcon(QIcon(QLatin1String(":/debugger/images/debugger_breakpoints.png"))); setSelectionMode(QAbstractItemView::ExtendedSelection); - connect(action(UseAddressInBreakpointsView), - SIGNAL(toggled(bool)), SLOT(showAddressColumn(bool))); + connect(action(UseAddressInBreakpointsView), &QAction::toggled, + this, &BreakTreeView::showAddressColumn); } void BreakTreeView::showAddressColumn(bool on) @@ -693,22 +693,21 @@ void BreakTreeView::keyPressEvent(QKeyEvent *ev) if (ev->key() == Qt::Key_Delete) { QItemSelectionModel *sm = selectionModel(); QTC_ASSERT(sm, return); - QModelIndexList si = sm->selectedIndexes(); + QModelIndexList si = sm->selectedRows(); if (si.isEmpty()) si.append(currentIndex()); - const BreakpointModelIds ids = breakHandler()->findBreakpointsByIndex(si); + const Breakpoints ids = breakHandler()->findBreakpointsByIndex(si); int row = qMin(model()->rowCount() - ids.size() - 1, currentIndex().row()); deleteBreakpoints(ids); - setCurrentIndex(si.at(0).sibling(row, 0)); + setCurrentIndex(model()->index(row, 0)); } else if (ev->key() == Qt::Key_Space) { QItemSelectionModel *sm = selectionModel(); QTC_ASSERT(sm, return); - const QModelIndexList selectedIds = sm->selectedIndexes(); + const QModelIndexList selectedIds = sm->selectedRows(); if (!selectedIds.isEmpty()) { - BreakHandler *handler = breakHandler(); - const BreakpointModelIds validIds = handler->findBreakpointsByIndex(selectedIds); - const bool isEnabled = validIds.isEmpty() || handler->isEnabled(validIds.at(0)); - setBreakpointsEnabled(validIds, !isEnabled); + const Breakpoints items = breakHandler()->findBreakpointsByIndex(selectedIds); + const bool isEnabled = items.isEmpty() || items.at(0).isEnabled(); + setBreakpointsEnabled(items, !isEnabled); foreach (const QModelIndex &id, selectedIds) update(id); } @@ -721,8 +720,9 @@ void BreakTreeView::mouseDoubleClickEvent(QMouseEvent *ev) QModelIndex indexUnderMouse = indexAt(ev->pos()); if (indexUnderMouse.isValid()) { if (indexUnderMouse.column() >= 4) { - BreakpointModelId id = breakHandler()->findBreakpointByIndex(indexUnderMouse); - editBreakpoints(BreakpointModelIds() << id); + Breakpoint b = breakHandler()->findBreakpointByIndex(indexUnderMouse); + QTC_ASSERT(b, return); + editBreakpoints(Breakpoints() << b); } } else { addBreakpoint(); @@ -735,27 +735,24 @@ void BreakTreeView::contextMenuEvent(QContextMenuEvent *ev) QMenu menu; QItemSelectionModel *sm = selectionModel(); QTC_ASSERT(sm, return); - QModelIndexList selectedIndices = sm->selectedIndexes(); + QModelIndexList selectedIndices = sm->selectedRows(); QModelIndex indexUnderMouse = indexAt(ev->pos()); if (selectedIndices.isEmpty() && indexUnderMouse.isValid()) selectedIndices.append(indexUnderMouse); BreakHandler *handler = breakHandler(); - BreakpointModelIds selectedIds; - foreach (BreakpointModelId id, handler->findBreakpointsByIndex(selectedIndices)) - if (id.isMajor()) - selectedIds.append(id); + Breakpoints selectedItems = handler->findBreakpointsByIndex(selectedIndices); const int rowCount = model()->rowCount(); - QAction *deleteAction = new QAction(tr("Delete Breakpoint"), &menu); - deleteAction->setEnabled(!selectedIds.empty()); + auto deleteAction = new QAction(tr("Delete Selected Breakpoints"), &menu); + deleteAction->setEnabled(!selectedItems.empty()); - QAction *deleteAllAction = new QAction(tr("Delete All Breakpoints"), &menu); + auto deleteAllAction = new QAction(tr("Delete All Breakpoints"), &menu); deleteAllAction->setEnabled(model()->rowCount() > 0); // Delete by file: Find indices of breakpoints of the same file. QAction *deleteByFileAction = 0; - BreakpointModelIds breakpointsInFile; + Breakpoints breakpointsInFile; if (indexUnderMouse.isValid()) { const QModelIndex index = indexUnderMouse.sibling(indexUnderMouse.row(), 2); const QString file = index.data().toString(); @@ -775,36 +772,33 @@ void BreakTreeView::contextMenuEvent(QContextMenuEvent *ev) deleteByFileAction->setEnabled(false); } - QAction *editBreakpointAction = - new QAction(tr("Edit Breakpoint..."), &menu); - editBreakpointAction->setEnabled(!selectedIds.isEmpty()); + auto editBreakpointAction = new QAction(tr("Edit Breakpoint..."), &menu); + editBreakpointAction->setEnabled(!selectedItems.isEmpty()); int threadId = 0; // FIXME BP: m_engine->threadsHandler()->currentThreadId(); QString associateTitle = threadId == -1 ? tr("Associate Breakpoint With All Threads") : tr("Associate Breakpoint With Thread %1").arg(threadId); - QAction *associateBreakpointAction = new QAction(associateTitle, &menu); - associateBreakpointAction->setEnabled(!selectedIds.isEmpty()); + auto associateBreakpointAction = new QAction(associateTitle, &menu); + associateBreakpointAction->setEnabled(!selectedItems.isEmpty()); - QAction *synchronizeAction = - new QAction(tr("Synchronize Breakpoints"), &menu); + auto synchronizeAction = new QAction(tr("Synchronize Breakpoints"), &menu); synchronizeAction->setEnabled(Internal::hasSnapshots()); - bool enabled = selectedIds.isEmpty() || handler->isEnabled(selectedIds.at(0)); + bool enabled = selectedItems.isEmpty() || selectedItems.at(0).isEnabled(); - const QString str5 = selectedIds.size() > 1 + const QString str5 = selectedItems.size() > 1 ? enabled ? tr("Disable Selected Breakpoints") : tr("Enable Selected Breakpoints") : enabled ? tr("Disable Breakpoint") : tr("Enable Breakpoint"); - QAction *toggleEnabledAction = new QAction(str5, &menu); - toggleEnabledAction->setEnabled(!selectedIds.isEmpty()); + auto toggleEnabledAction = new QAction(str5, &menu); + toggleEnabledAction->setEnabled(!selectedItems.isEmpty()); - QAction *addBreakpointAction = - new QAction(tr("Add Breakpoint..."), this); + auto addBreakpointAction = new QAction(tr("Add Breakpoint..."), this); menu.addAction(addBreakpointAction); menu.addAction(deleteAction); @@ -826,28 +820,27 @@ void BreakTreeView::contextMenuEvent(QContextMenuEvent *ev) QAction *act = menu.exec(ev->globalPos()); if (act == deleteAction) - deleteBreakpoints(selectedIds); + deleteBreakpoints(selectedItems); else if (act == deleteAllAction) deleteAllBreakpoints(); else if (act == deleteByFileAction) deleteBreakpoints(breakpointsInFile); else if (act == editBreakpointAction) - editBreakpoints(selectedIds); + editBreakpoints(selectedItems); else if (act == associateBreakpointAction) - associateBreakpoint(selectedIds, threadId); + associateBreakpoint(selectedItems, threadId); else if (act == synchronizeAction) ; //synchronizeBreakpoints(); else if (act == toggleEnabledAction) - setBreakpointsEnabled(selectedIds, !enabled); + setBreakpointsEnabled(selectedItems, !enabled); else if (act == addBreakpointAction) addBreakpoint(); } -void BreakTreeView::setBreakpointsEnabled(const BreakpointModelIds &ids, bool enabled) +void BreakTreeView::setBreakpointsEnabled(const Breakpoints &bps, bool enabled) { - BreakHandler *handler = breakHandler(); - foreach (const BreakpointModelId id, ids) - handler->setEnabled(id, enabled); + foreach (Breakpoint b, bps) + b.setEnabled(enabled); } void BreakTreeView::deleteAllBreakpoints() @@ -858,55 +851,56 @@ void BreakTreeView::deleteAllBreakpoints() "from all files in the current session?"), Core::ICore::settings(), QLatin1String("RemoveAllBreakpoints")) == QDialogButtonBox::Yes) - deleteBreakpoints(breakHandler()->allBreakpointIds()); + deleteBreakpoints(breakHandler()->allBreakpoints()); } -void BreakTreeView::deleteBreakpoints(const BreakpointModelIds &ids) +void BreakTreeView::deleteBreakpoints(const Breakpoints &bps) { - BreakHandler *handler = breakHandler(); - foreach (const BreakpointModelId id, ids) - handler->removeBreakpoint(id); + foreach (Breakpoint bp, bps) + bp.removeBreakpoint(); } -void BreakTreeView::editBreakpoint(BreakpointModelId id, QWidget *parent) +void BreakTreeView::editBreakpoint(Breakpoint bp, QWidget *parent) { - BreakpointParameters data = breakHandler()->breakpointData(id); + BreakpointParameters data = bp.parameters(); BreakpointParts parts = NoParts; - BreakpointDialog dialog(id, parent); - if (dialog.showDialog(&data, &parts)) - breakHandler()->changeBreakpointData(id, data, parts); + + BreakpointDialog dialog(bp, parent); + if (!dialog.showDialog(&data, &parts)) + return; + + bp.changeBreakpointData(data); } void BreakTreeView::addBreakpoint() { BreakpointParameters data(BreakpointByFileAndLine); BreakpointParts parts = NoParts; - BreakpointDialog dialog(BreakpointModelId(), this); + BreakpointDialog dialog(Breakpoint(), this); dialog.setWindowTitle(tr("Add Breakpoint")); if (dialog.showDialog(&data, &parts)) breakHandler()->appendBreakpoint(data); } -void BreakTreeView::editBreakpoints(const BreakpointModelIds &ids) +void BreakTreeView::editBreakpoints(const Breakpoints &bps) { - QTC_ASSERT(!ids.isEmpty(), return); + QTC_ASSERT(!bps.isEmpty(), return); - const BreakpointModelId id = ids.at(0); + const Breakpoint bp = bps.at(0); - if (ids.size() == 1) { - editBreakpoint(id, this); + if (bps.size() == 1) { + editBreakpoint(bp, this); return; } // This allows to change properties of multiple breakpoints at a time. - BreakHandler *handler = breakHandler(); + if (!bp) + return; + MultiBreakPointsDialog dialog; - const QString oldCondition = QString::fromLatin1(handler->condition(id)); - dialog.setCondition(oldCondition); - const int oldIgnoreCount = handler->ignoreCount(id); - dialog.setIgnoreCount(oldIgnoreCount); - const int oldThreadSpec = handler->threadSpec(id); - dialog.setThreadSpec(oldThreadSpec); + dialog.setCondition(QString::fromLatin1(bp.condition())); + dialog.setIgnoreCount(bp.ignoreCount()); + dialog.setThreadSpec(bp.threadSpec()); if (dialog.exec() == QDialog::Rejected) return; @@ -915,27 +909,27 @@ void BreakTreeView::editBreakpoints(const BreakpointModelIds &ids) const int newIgnoreCount = dialog.ignoreCount(); const int newThreadSpec = dialog.threadSpec(); - if (newCondition == oldCondition && newIgnoreCount == oldIgnoreCount - && newThreadSpec == oldThreadSpec) - return; - - foreach (const BreakpointModelId id, ids) { - handler->setCondition(id, newCondition.toLatin1()); - handler->setIgnoreCount(id, newIgnoreCount); - handler->setThreadSpec(id, newThreadSpec); + foreach (Breakpoint bp, bps) { + if (bp) { + bp.setCondition(newCondition.toLatin1()); + bp.setIgnoreCount(newIgnoreCount); + bp.setThreadSpec(newThreadSpec); + } } } -void BreakTreeView::associateBreakpoint(const BreakpointModelIds &ids, int threadId) +void BreakTreeView::associateBreakpoint(const Breakpoints &bps, int threadId) { - BreakHandler *handler = breakHandler(); - foreach (const BreakpointModelId id, ids) - handler->setThreadSpec(id, threadId); + foreach (Breakpoint bp, bps) { + if (bp) + bp.setThreadSpec(threadId); + } } void BreakTreeView::rowActivated(const QModelIndex &index) { - breakHandler()->gotoLocation(breakHandler()->findBreakpointByIndex(index)); + if (Breakpoint bp = breakHandler()->findBreakpointByIndex(index)) + bp.gotoLocation(); } } // namespace Internal diff --git a/src/plugins/debugger/breakwindow.h b/src/plugins/debugger/breakwindow.h index 5c9154859d..f66d3e5eea 100644 --- a/src/plugins/debugger/breakwindow.h +++ b/src/plugins/debugger/breakwindow.h @@ -31,7 +31,7 @@ #ifndef DEBUGGER_BREAKWINDOW_H #define DEBUGGER_BREAKWINDOW_H -#include "breakpoint.h" +#include "breakhandler.h" #include <utils/basetreeview.h> namespace Debugger { @@ -44,7 +44,7 @@ class BreakTreeView : public Utils::BaseTreeView public: BreakTreeView(); - static void editBreakpoint(BreakpointModelId id, QWidget *parent); + static void editBreakpoint(Breakpoint bp, QWidget *parent); private slots: void showAddressColumn(bool on); @@ -55,12 +55,12 @@ private: void keyPressEvent(QKeyEvent *ev); void mouseDoubleClickEvent(QMouseEvent *ev); - void deleteBreakpoints(const BreakpointModelIds &ids); + void deleteBreakpoints(const Breakpoints &bps); void deleteAllBreakpoints(); void addBreakpoint(); - void editBreakpoints(const BreakpointModelIds &ids); - void associateBreakpoint(const BreakpointModelIds &ids, int thread); - void setBreakpointsEnabled(const BreakpointModelIds &ids, bool enabled); + void editBreakpoints(const Breakpoints &bps); + void associateBreakpoint(const Breakpoints &bps, int thread); + void setBreakpointsEnabled(const Breakpoints &bps, bool enabled); }; } // namespace Internal diff --git a/src/plugins/debugger/cdb/cdbengine.cpp b/src/plugins/debugger/cdb/cdbengine.cpp index cb210b8f8e..a23fc804d7 100644 --- a/src/plugins/debugger/cdb/cdbengine.cpp +++ b/src/plugins/debugger/cdb/cdbengine.cpp @@ -55,6 +55,7 @@ #include <debugger/shared/hostutils.h> #include <coreplugin/icore.h> +#include <coreplugin/messagebox.h> #include <projectexplorer/taskhub.h> #include <texteditor/texteditor.h> @@ -72,7 +73,6 @@ #include <cpptools/cppworkingcopy.h> #include <QDir> -#include <QMessageBox> #include <cctype> @@ -340,17 +340,22 @@ CdbEngine::CdbEngine(const DebuggerStartParameters &sp) : m_watchPointY(0), m_ignoreCdbOutput(false) { - connect(action(OperateByInstruction), SIGNAL(triggered(bool)), - this, SLOT(operateByInstructionTriggered(bool))); - connect(action(VerboseLog), SIGNAL(triggered(bool)), - this, SLOT(verboseLogTriggered(bool))); - connect(action(CreateFullBacktrace), SIGNAL(triggered()), - this, SLOT(createFullBacktrace())); setObjectName(QLatin1String("CdbEngine")); - connect(&m_process, SIGNAL(finished(int)), this, SLOT(processFinished())); - connect(&m_process, SIGNAL(error(QProcess::ProcessError)), this, SLOT(processError())); - connect(&m_process, SIGNAL(readyReadStandardOutput()), this, SLOT(readyReadStandardOut())); - connect(&m_process, SIGNAL(readyReadStandardError()), this, SLOT(readyReadStandardOut())); + + connect(action(OperateByInstruction), &QAction::triggered, + this, &CdbEngine::operateByInstructionTriggered); + connect(action(VerboseLog), &QAction::triggered, + this, &CdbEngine::verboseLogTriggered); + connect(action(CreateFullBacktrace), &QAction::triggered, + this, &CdbEngine::createFullBacktrace); + connect(&m_process, static_cast<void(QProcess::*)(int)>(&QProcess::finished), + this, &CdbEngine::processFinished); + connect(&m_process, static_cast<void(QProcess::*)(QProcess::ProcessError)>(&QProcess::error), + this, &CdbEngine::processError); + connect(&m_process, &QProcess::readyReadStandardOutput, + this, &CdbEngine::readyReadStandardOut); + connect(&m_process, &QProcess::readyReadStandardError, + this, &CdbEngine::readyReadStandardOut); } void CdbEngine::init() @@ -534,7 +539,7 @@ void CdbEngine::consoleStubError(const QString &msg) STATE_DEBUG(state(), Q_FUNC_INFO, __LINE__, "notifyEngineIll") notifyEngineIll(); } - showMessageBox(QMessageBox::Critical, tr("Debugger Error"), msg); + Core::AsynchronousMessageBox::critical(tr("Debugger Error"), msg); } void CdbEngine::consoleStubProcessStarted() @@ -552,7 +557,7 @@ void CdbEngine::consoleStubProcessStarted() QString errorMessage; if (!launchCDB(attachParameters, &errorMessage)) { showMessage(errorMessage, LogError); - showMessageBox(QMessageBox::Critical, tr("Failed to Start the Debugger"), errorMessage); + Core::AsynchronousMessageBox::critical(tr("Failed to Start the Debugger"), errorMessage); STATE_DEBUG(state(), Q_FUNC_INFO, __LINE__, "notifyEngineSetupFailed") notifyEngineSetupFailed(); } @@ -599,7 +604,7 @@ void CdbEngine::setupEngine() qDebug("<setupEngine ok=%d", ok); if (!ok) { showMessage(errorMessage, LogError); - showMessageBox(QMessageBox::Critical, tr("Failed to Start the Debugger"), errorMessage); + Core::AsynchronousMessageBox::critical(tr("Failed to Start the Debugger"), errorMessage); STATE_DEBUG(state(), Q_FUNC_INFO, __LINE__, "notifyEngineSetupFailed") notifyEngineSetupFailed(); } @@ -1235,14 +1240,12 @@ void CdbEngine::executeRunToFunction(const QString &functionName) continueInferior(); } -void CdbEngine::setRegisterValue(int regnr, const QString &value) +void CdbEngine::setRegisterValue(const QByteArray &name, const QString &value) { - const Registers registers = registerHandler()->registers(); - QTC_ASSERT(regnr < registers.size(), return); // Value is decimal or 0x-hex-prefixed QByteArray cmd; ByteArrayInputStream str(cmd); - str << "r " << registers.at(regnr).name << '=' << value; + str << "r " << name << '=' << value; postCommand(cmd, 0); reloadRegisters(); } @@ -1854,29 +1857,14 @@ void CdbEngine::handlePid(const CdbExtensionCommandPtr &reply) } } -// Parse CDB gdbmi register syntax. -static Register parseRegister(const GdbMi &gdbmiReg) -{ - Register reg; - reg.name = gdbmiReg["name"].data(); - const GdbMi description = gdbmiReg["description"]; - if (description.type() != GdbMi::Invalid) { - reg.name += " ("; - reg.name += description.data(); - reg.name += ')'; - } - reg.value = gdbmiReg["value"].data(); - return reg; -} - void CdbEngine::handleModules(const CdbExtensionCommandPtr &reply) { if (reply->success) { GdbMi value; value.fromString(reply->reply); if (value.type() == GdbMi::List) { - Modules modules; - modules.reserve(value.childCount()); + ModulesHandler *handler = modulesHandler(); + handler->beginUpdateAll(); foreach (const GdbMi &gdbmiModule, value.children()) { Module module; module.moduleName = QString::fromLatin1(gdbmiModule["name"].data()); @@ -1885,9 +1873,9 @@ void CdbEngine::handleModules(const CdbExtensionCommandPtr &reply) module.endAddress = gdbmiModule["end"].data().toULongLong(0, 0); if (gdbmiModule["deferred"].type() == GdbMi::Invalid) module.symbolsRead = Module::ReadOk; - modules.push_back(module); + handler->updateModule(module); } - modulesHandler()->setModules(modules); + handler->endUpdateAll(); } else { showMessage(QString::fromLatin1("Parse error in modules response."), LogError); qWarning("Parse error in modules response:\n%s", reply->reply.constData()); @@ -1906,11 +1894,17 @@ void CdbEngine::handleRegisters(const CdbExtensionCommandPtr &reply) GdbMi value; value.fromString(reply->reply); if (value.type() == GdbMi::List) { - Registers registers; - registers.reserve(value.childCount()); - foreach (const GdbMi &gdbmiReg, value.children()) - registers.push_back(parseRegister(gdbmiReg)); - registerHandler()->setAndMarkRegisters(registers); + RegisterHandler *handler = registerHandler(); + foreach (const GdbMi &item, value.children()) { + Register reg; + reg.name = item["name"].data(); + reg.description = item["description"].data(); + reg.reportedType = item["type"].data(); + reg.value = item["value"].data(); + reg.size = item["size"].data().toInt(); + handler->updateRegister(reg); + } + handler->commitUpdates(); } else { showMessage(QString::fromLatin1("Parse error in registers response."), LogError); qWarning("Parse error in registers response:\n%s", reply->reply.constData()); @@ -1944,7 +1938,7 @@ void CdbEngine::handleLocals(const CdbExtensionCommandPtr &reply) WatchData dummy; dummy.iname = child["iname"].data(); dummy.name = QLatin1String(child["name"].data()); - parseWatchData(handler->expandedINames(), dummy, child, &watchData); + parseWatchData(dummy, child, &watchData); } // Fix the names of watch data. for (int i =0; i < watchData.size(); ++i) { @@ -2084,9 +2078,10 @@ unsigned CdbEngine::examineStopReason(const GdbMi &stopReason, // Step out creates temporary breakpoints with id 10000. int number = 0; BreakpointModelId id = cdbIdToBreakpointModelId(stopReason["breakpointId"]); - if (id.isValid()) { - if (breakHandler()->engineBreakpointIds(this).contains(id)) { - const BreakpointResponse parameters = breakHandler()->response(id); + Breakpoint bp = breakHandler()->breakpointById(id); + if (bp) { + if (bp.engine() == this) { + const BreakpointResponse parameters = bp.response(); if (!parameters.message.isEmpty()) { showMessage(parameters.message + QLatin1Char('\n'), AppOutput); showMessage(parameters.message, LogMisc); @@ -2107,16 +2102,16 @@ unsigned CdbEngine::examineStopReason(const GdbMi &stopReason, return StopReportLog; } } else { - id = BreakpointModelId(); + bp = Breakpoint(); } } QString tid = QString::number(threadId); - if (id && breakHandler()->type(id) == WatchpointAtAddress) - *message = msgWatchpointByAddressTriggered(id, number, breakHandler()->address(id), tid); - else if (id && breakHandler()->type(id) == WatchpointAtExpression) - *message = msgWatchpointByExpressionTriggered(id, number, breakHandler()->expression(id), tid); + if (bp.type() == WatchpointAtAddress) + *message = bp.msgWatchpointByAddressTriggered(number, bp.address(), tid); + else if (bp.type() == WatchpointAtExpression) + *message = bp.msgWatchpointByExpressionTriggered(number, bp.expression(), tid); else - *message = msgBreakpointTriggered(id, number, tid); + *message = bp.msgBreakpointTriggered(number, tid); rc |= StopReportStatusMessage|StopNotifyStop; return rc; } @@ -2328,6 +2323,7 @@ void CdbEngine::handleBreakInsert(const CdbBuiltinCommandPtr &cmd) if (!ok) return; const BreakpointModelId &originalId = cdbIdToBreakpointModelId(cdbBreakPointId); + Breakpoint bp = breakHandler()->breakpointById(originalId); // add break point for every match const QList<QByteArray>::const_iterator &end = reply.constEnd(); int subBreakPointID = 0; @@ -2347,7 +2343,7 @@ void CdbEngine::handleBreakInsert(const CdbBuiltinCommandPtr &cmd) continue; BreakpointModelId id(originalId.majorPart(), ++subBreakPointID); - BreakpointResponse res = breakHandler()->response(originalId); + BreakpointResponse res = bp.response(); res.type = BreakpointByAddress; res.address = address; m_insertSubBreakpointMap.insert(id, res); @@ -2759,12 +2755,11 @@ bool CdbEngine::stateAcceptsBreakpointChanges() const return false; } -bool CdbEngine::acceptsBreakpoint(BreakpointModelId id) const +bool CdbEngine::acceptsBreakpoint(Breakpoint bp) const { - const BreakpointParameters &data = breakHandler()->breakpointData(id); - if (!data.isCppBreakpoint()) + if (!bp.parameters().isCppBreakpoint()) return false; - switch (data.type) { + switch (bp.type()) { case UnknownBreakpointType: case LastBreakpointType: case BreakpointAtFork: @@ -2838,23 +2833,21 @@ unsigned BreakpointCorrectionContext::fixLineNumber(const QString &fileName, void CdbEngine::attemptBreakpointSynchronization() { - - if (debug) qDebug("attemptBreakpointSynchronization in %s", stateName(state())); // Check if there is anything to be done at all. BreakHandler *handler = breakHandler(); // Take ownership of the breakpoint. Requests insertion. TODO: Cpp only? - foreach (BreakpointModelId id, handler->unclaimedBreakpointIds()) - if (acceptsBreakpoint(id)) - handler->setEngine(id, this); + foreach (Breakpoint bp, handler->unclaimedBreakpoints()) + if (acceptsBreakpoint(bp)) + bp.setEngine(this); // Quick check: is there a need to change something? - Populate module cache bool changed = !m_insertSubBreakpointMap.isEmpty(); - const BreakpointModelIds ids = handler->engineBreakpointIds(this); + const Breakpoints bps = handler->engineBreakpoints(this); if (!changed) { - foreach (BreakpointModelId id, ids) { - switch (handler->state(id)) { + foreach (Breakpoint bp, bps) { + switch (bp.state()) { case BreakpointInsertRequested: case BreakpointRemoveRequested: case BreakpointChangeRequested: @@ -2863,7 +2856,7 @@ void CdbEngine::attemptBreakpointSynchronization() case BreakpointInserted: { // Collect the new modules matching the files. // In the future, that information should be obtained from the build system. - const BreakpointParameters &data = handler->breakpointData(id); + const BreakpointParameters &data = bp.parameters(); if (data.type == BreakpointByFileAndLine && !data.module.isEmpty()) m_fileNameModuleHash.insert(data.fileName, data.module); } @@ -2876,7 +2869,7 @@ void CdbEngine::attemptBreakpointSynchronization() if (debugBreakpoints) qDebug("attemptBreakpointSynchronizationI %dms accessible=%d, %s %d breakpoints, changed=%d", - elapsedLogTime(), m_accessible, stateName(state()), ids.size(), changed); + elapsedLogTime(), m_accessible, stateName(state()), bps.size(), changed); if (!changed) return; @@ -2891,8 +2884,9 @@ void CdbEngine::attemptBreakpointSynchronization() // handleBreakPoints will the complete that information and set it on the break handler. bool addedChanged = false; QScopedPointer<BreakpointCorrectionContext> lineCorrection; - foreach (BreakpointModelId id, ids) { - BreakpointParameters parameters = handler->breakpointData(id); + foreach (Breakpoint bp, bps) { + BreakpointParameters parameters = bp.parameters(); + BreakpointModelId id = bp.id(); BreakpointResponse response; response.fromParameters(parameters); response.id = BreakpointResponseId(id.majorPart(), id.minorPart()); @@ -2902,7 +2896,7 @@ void CdbEngine::attemptBreakpointSynchronization() if (it != m_fileNameModuleHash.constEnd()) parameters.module = it.value(); } - switch (handler->state(id)) { + switch (bp.state()) { case BreakpointInsertRequested: if (!m_autoBreakPointCorrection && parameters.type == BreakpointByFileAndLine @@ -2921,29 +2915,29 @@ void CdbEngine::attemptBreakpointSynchronization() } if (!parameters.enabled) postCommand("bd " + QByteArray::number(breakPointIdToCdbId(id)), 0); - handler->notifyBreakpointInsertProceeding(id); - handler->notifyBreakpointInsertOk(id); + bp.notifyBreakpointInsertProceeding(); + bp.notifyBreakpointInsertOk(); m_pendingBreakpointMap.insert(id, response); addedChanged = true; // Ensure enabled/disabled is correct in handler and line number is there. - handler->setResponse(id, response); + bp.setResponse(response); if (debugBreakpoints) qDebug("Adding %d %s\n", id.toInternalId(), qPrintable(response.toString())); break; case BreakpointChangeRequested: - handler->notifyBreakpointChangeProceeding(id); + bp.notifyBreakpointChangeProceeding(); if (debugBreakpoints) qDebug("Changing %d:\n %s\nTo %s\n", id.toInternalId(), - qPrintable(handler->response(id).toString()), + qPrintable(bp.response().toString()), qPrintable(parameters.toString())); - if (parameters.enabled != handler->response(id).enabled) { + if (parameters.enabled != bp.response().enabled) { // Change enabled/disabled breakpoints without triggering update. postCommand((parameters.enabled ? "be " : "bd ") + QByteArray::number(breakPointIdToCdbId(id)), 0); response.pending = false; response.enabled = parameters.enabled; - handler->setResponse(id, response); + bp.setResponse(response); } else { // Delete and re-add, triggering update addedChanged = true; @@ -2953,12 +2947,12 @@ void CdbEngine::attemptBreakpointSynchronization() &CdbEngine::handleBreakInsert); m_pendingBreakpointMap.insert(id, response); } - handler->notifyBreakpointChangeOk(id); + bp.notifyBreakpointChangeOk(); break; case BreakpointRemoveRequested: postCommand(cdbClearBreakpointCommand(id), 0); - handler->notifyBreakpointRemoveProceeding(id); - handler->notifyBreakpointRemoveOk(id); + bp.notifyBreakpointRemoveProceeding(); + bp.notifyBreakpointRemoveOk(); m_pendingBreakpointMap.remove(id); break; default: @@ -2991,7 +2985,7 @@ CdbEngine::NormalizedSourceFileName CdbEngine::sourceMapNormalizeFileNameFromDeb const QString fileName = cdbSourcePathMapping(QDir::toNativeSeparators(f), m_sourcePathMappings, DebuggerToSource); // Up/lower case normalization according to Windows. - const QString normalized = Utils::FileUtils::normalizePathName(fileName); + const QString normalized = FileUtils::normalizePathName(fileName); if (debugSourceMapping) qDebug(" sourceMapNormalizeFileNameFromDebugger %s->%s", qPrintable(fileName), qPrintable(normalized)); // Check if it really exists, that is normalize worked and QFileInfo confirms it. @@ -3301,12 +3295,12 @@ void CdbEngine::handleBreakPoints(const GdbMi &value) reportedResponse.pending, qPrintable(reportedResponse.toString())); if (reportedResponse.id.isValid() && !reportedResponse.pending) { - const BreakpointModelId mid = handler->findBreakpointByResponseId(reportedResponse.id); - if (!mid.isValid() && reportedResponse.type == BreakpointByFunction) + Breakpoint bp = handler->findBreakpointByResponseId(reportedResponse.id); + if (!bp && reportedResponse.type == BreakpointByFunction) continue; // Breakpoints from options, CrtDbgReport() and others. - QTC_ASSERT(mid.isValid(), continue); - const PendingBreakPointMap::iterator it = m_pendingBreakpointMap.find(mid); - const PendingBreakPointMap::iterator subIt = m_pendingSubBreakpointMap.find( + QTC_ASSERT(bp, continue); + const auto it = m_pendingBreakpointMap.find(bp.id()); + const auto subIt = m_pendingSubBreakpointMap.find( BreakpointModelId(reportedResponse.id.majorPart(), reportedResponse.id.minorPart())); if (it != m_pendingBreakpointMap.end() || subIt != m_pendingSubBreakpointMap.end()) { @@ -3321,16 +3315,16 @@ void CdbEngine::handleBreakPoints(const GdbMi &value) currentResponse.enabled = reportedResponse.enabled; currentResponse.fileName = reportedResponse.fileName; currentResponse.lineNumber = reportedResponse.lineNumber; - formatCdbBreakPointResponse(mid, currentResponse, str); + formatCdbBreakPointResponse(bp.id(), currentResponse, str); if (debugBreakpoints) qDebug(" Setting for %d: %s\n", currentResponse.id.majorPart(), qPrintable(currentResponse.toString())); if (it != m_pendingBreakpointMap.end()) { - handler->setResponse(mid, currentResponse); + bp.setResponse(currentResponse); m_pendingBreakpointMap.erase(it); } if (subIt != m_pendingSubBreakpointMap.end()) { - handler->insertSubBreakpoint(mid, currentResponse); + bp.insertSubBreakpoint(currentResponse); m_pendingSubBreakpointMap.erase(subIt); } } diff --git a/src/plugins/debugger/cdb/cdbengine.h b/src/plugins/debugger/cdb/cdbengine.h index cf2cb6ced6..ce7f263e63 100644 --- a/src/plugins/debugger/cdb/cdbengine.h +++ b/src/plugins/debugger/cdb/cdbengine.h @@ -32,6 +32,7 @@ #define DEBUGGER_CDBENGINE_H #include <debugger/debuggerengine.h> +#include <debugger/breakhandler.h> #include <projectexplorer/devicesupport/idevice.h> @@ -52,7 +53,7 @@ struct MemoryViewCookie; class ByteArrayInputStream; class GdbMi; -class CdbEngine : public Debugger::DebuggerEngine +class CdbEngine : public DebuggerEngine { Q_OBJECT @@ -90,7 +91,7 @@ public: const WatchUpdateFlags & flags = WatchUpdateFlags()); virtual bool hasCapability(unsigned cap) const; virtual void watchPoint(const QPoint &); - virtual void setRegisterValue(int regnr, const QString &value); + virtual void setRegisterValue(const QByteArray &name, const QString &value); virtual void executeStep(); virtual void executeStepOut(); @@ -111,7 +112,7 @@ public: virtual void selectThread(ThreadId threadId); virtual bool stateAcceptsBreakpointChanges() const; - virtual bool acceptsBreakpoint(BreakpointModelId id) const; + virtual bool acceptsBreakpoint(Breakpoint bp) const; virtual void attemptBreakpointSynchronization(); virtual void fetchDisassembler(DisassemblerAgent *agent); diff --git a/src/plugins/debugger/cdb/cdbparsehelpers.cpp b/src/plugins/debugger/cdb/cdbparsehelpers.cpp index 75b2870a11..57c19eb5ee 100644 --- a/src/plugins/debugger/cdb/cdbparsehelpers.cpp +++ b/src/plugins/debugger/cdb/cdbparsehelpers.cpp @@ -37,6 +37,7 @@ #include <debugger/shared/hostutils.h> #include <debugger/threaddata.h> +#include <utils/fileutils.h> #include <utils/qtcassert.h> #include <QDir> @@ -87,7 +88,7 @@ static inline QString cdbBreakPointFileName(const BreakpointParameters &bp, if (bp.fileName.isEmpty()) return bp.fileName; if (bp.pathUsage == BreakpointUseShortPath) - return QFileInfo(bp.fileName).fileName(); + return Utils::FileName::fromString(bp.fileName).fileName(); return cdbSourcePathMapping(QDir::toNativeSeparators(bp.fileName), sourcePathMapping, SourceToDebugger); } diff --git a/src/plugins/debugger/commonoptionspage.cpp b/src/plugins/debugger/commonoptionspage.cpp index 6aef1913e6..31f7e5c161 100644 --- a/src/plugins/debugger/commonoptionspage.cpp +++ b/src/plugins/debugger/commonoptionspage.cpp @@ -230,8 +230,8 @@ CommonOptionsPageWidget::CommonOptionsPageWidget Utils::SavedAction *registerAction = action(RegisterForPostMortem); m_group->insert(registerAction, checkBoxRegisterForPostMortem); - connect(registerAction, SIGNAL(toggled(bool)), - checkBoxRegisterForPostMortem, SLOT(setChecked(bool))); + connect(registerAction, &QAction::toggled, + checkBoxRegisterForPostMortem, &QAbstractButton::setChecked); } else { checkBoxRegisterForPostMortem->setVisible(false); } diff --git a/src/plugins/debugger/debugger.pro b/src/plugins/debugger/debugger.pro index edf9a72709..83e790c042 100644 --- a/src/plugins/debugger/debugger.pro +++ b/src/plugins/debugger/debugger.pro @@ -15,7 +15,6 @@ CONFIG += exceptions HEADERS += \ breakhandler.h \ breakpoint.h \ - breakpointmarker.h \ breakwindow.h \ commonoptionspage.h \ debugger_global.h \ @@ -25,7 +24,6 @@ HEADERS += \ debuggerinternalconstants.h \ debuggeritem.h \ debuggeritemmanager.h \ - debuggeritemmodel.h \ debuggerdialogs.h \ debuggerengine.h \ debuggermainwindow.h \ @@ -58,6 +56,7 @@ HEADERS += \ stackframe.h \ stackhandler.h \ stackwindow.h \ + terminal.h \ threadswindow.h \ watchhandler.h \ watchutils.h \ @@ -76,7 +75,6 @@ HEADERS += \ SOURCES += \ breakhandler.cpp \ breakpoint.cpp \ - breakpointmarker.cpp \ breakwindow.cpp \ commonoptionspage.cpp \ debuggeractions.cpp \ @@ -84,7 +82,6 @@ SOURCES += \ debuggerengine.cpp \ debuggeritem.cpp \ debuggeritemmanager.cpp \ - debuggeritemmodel.cpp \ debuggermainwindow.cpp \ debuggerplugin.cpp \ debuggerprotocol.cpp \ @@ -114,6 +111,7 @@ SOURCES += \ stackwindow.cpp \ threadshandler.cpp \ threadswindow.cpp \ + terminal.cpp \ watchdata.cpp \ watchhandler.cpp \ watchutils.cpp \ diff --git a/src/plugins/debugger/debugger.qbs b/src/plugins/debugger/debugger.qbs index e03c038beb..7001f560b3 100644 --- a/src/plugins/debugger/debugger.qbs +++ b/src/plugins/debugger/debugger.qbs @@ -28,7 +28,6 @@ QtcPlugin { files: [ "breakhandler.cpp", "breakhandler.h", "breakpoint.cpp", "breakpoint.h", - "breakpointmarker.cpp", "breakpointmarker.h", "breakwindow.cpp", "breakwindow.h", "commonoptionspage.cpp", "commonoptionspage.h", "debugger.qrc", @@ -41,7 +40,6 @@ QtcPlugin { "debuggerinternalconstants.h", "debuggeritem.cpp", "debuggeritem.h", "debuggeritemmanager.cpp", "debuggeritemmanager.h", - "debuggeritemmodel.cpp", "debuggeritemmodel.h", "debuggerkitconfigwidget.cpp", "debuggerkitconfigwidget.h", "debuggerkitinformation.cpp", "debuggerkitinformation.h", "debuggermainwindow.cpp", "debuggermainwindow.h", @@ -77,6 +75,7 @@ QtcPlugin { "stackframe.cpp", "stackframe.h", "stackhandler.cpp", "stackhandler.h", "stackwindow.cpp", "stackwindow.h", + "terminal.cpp", "terminal.h", "threaddata.h", "threadshandler.cpp", "threadshandler.h", "threadswindow.cpp", "threadswindow.h", diff --git a/src/plugins/debugger/debuggeractions.cpp b/src/plugins/debugger/debuggeractions.cpp index 234c44e434..e58367e479 100644 --- a/src/plugins/debugger/debuggeractions.cpp +++ b/src/plugins/debugger/debuggeractions.cpp @@ -34,6 +34,7 @@ #include "registerpostmortemaction.h" #endif +#include <coreplugin/coreconstants.h> #include <coreplugin/icore.h> #include <utils/savedaction.h> #include <utils/qtcassert.h> @@ -184,6 +185,18 @@ DebuggerSettings::DebuggerSettings() insertItem(OperateByInstruction, item); item = new SavedAction(this); + item->setText(tr("Native Mixed Mode")); + item->setCheckable(true); + item->setDefaultValue(true); + item->setIcon(QIcon(QLatin1String(Core::Constants::ICON_LINK))); + item->setToolTip(tr("This switches the debugger to native-mixed " + "operation mode. In this mode, stepping and data display will " + "be handled by the native debugger backend (GDB, LLDB or CDB) " + "for C++, QML and JS sources.")); + item->setIconVisibleInMenu(false); + insertItem(OperateNativeMixed, item); + + item = new SavedAction(this); item->setText(tr("Dereference Pointers Automatically")); item->setCheckable(true); item->setDefaultValue(true); diff --git a/src/plugins/debugger/debuggeractions.h b/src/plugins/debugger/debuggeractions.h index 99ffa70b50..2b3202fcd5 100644 --- a/src/plugins/debugger/debuggeractions.h +++ b/src/plugins/debugger/debuggeractions.h @@ -99,6 +99,7 @@ enum DebuggerActionCode LogTimeStamps, VerboseLog, OperateByInstruction, + OperateNativeMixed, CloseSourceBuffersOnExit, CloseMemoryBuffersOnExit, SwitchModeOnExit, diff --git a/src/plugins/debugger/debuggerconstants.h b/src/plugins/debugger/debuggerconstants.h index 0b1270225b..0bfb5f749b 100644 --- a/src/plugins/debugger/debuggerconstants.h +++ b/src/plugins/debugger/debuggerconstants.h @@ -61,6 +61,7 @@ const char NEXT[] = "Debugger.NextLine"; const char REVERSE[] = "Debugger.ReverseDirection"; const char RESET[] = "Debugger.Reset"; const char OPERATE_BY_INSTRUCTION[] = "Debugger.OperateByInstruction"; +const char OPERATE_NATIVE_MIXED[] = "Debugger.OperateNativeMixed"; const char QML_SHOW_APP_ON_TOP[] = "Debugger.QmlShowAppOnTop"; const char QML_UPDATE_ON_SAVE[] = "Debugger.QmlUpdateOnSave"; const char QML_SELECTTOOL[] = "Debugger.QmlSelectTool"; @@ -163,7 +164,8 @@ enum DebuggerCapabilities ShowModuleSectionsCapability = 0x200000, WatchComplexExpressionsCapability = 0x400000, // Used to filter out challenges for cdb. AdditionalQmlStackCapability = 0x800000, // C++ debugger engine is able to retrieve QML stack as well. - ResetInferiorCapability = 0x1000000 //!< restart program while debugging + ResetInferiorCapability = 0x1000000, //!< restart program while debugging + NativeMixedCapability = 0x2000000 }; enum LogChannel diff --git a/src/plugins/debugger/debuggercore.h b/src/plugins/debugger/debuggercore.h index 84b29f7ab6..d481867062 100644 --- a/src/plugins/debugger/debuggercore.h +++ b/src/plugins/debugger/debuggercore.h @@ -50,12 +50,10 @@ namespace CPlusPlus { class Snapshot; } namespace Utils { class SavedAction; } namespace Debugger { - -class DebuggerEngine; - namespace Internal { class BreakHandler; +class DebuggerEngine; class Symbol; class Section; class GlobalDebuggerOptions; @@ -112,6 +110,9 @@ DebuggerEngine *currentEngine(); QMessageBox *showMessageBox(int icon, const QString &title, const QString &text, int buttons = 0); +bool isNativeMixedActive(); +bool isNativeMixedEnabled(); + } // namespace Internal } // namespace Debugger diff --git a/src/plugins/debugger/debuggerdialogs.cpp b/src/plugins/debugger/debuggerdialogs.cpp index b6e9f937c3..fd4137f78c 100644 --- a/src/plugins/debugger/debuggerdialogs.cpp +++ b/src/plugins/debugger/debuggerdialogs.cpp @@ -105,19 +105,19 @@ namespace Internal { /////////////////////////////////////////////////////////////////////// DebuggerKitChooser::DebuggerKitChooser(Mode mode, QWidget *parent) - : ProjectExplorer::KitChooser(parent) - , m_hostAbi(ProjectExplorer::Abi::hostAbi()) + : KitChooser(parent) + , m_hostAbi(Abi::hostAbi()) , m_mode(mode) { } // Match valid debuggers and restrict local debugging to compatible toolchains. -bool DebuggerKitChooser::kitMatches(const ProjectExplorer::Kit *k) const +bool DebuggerKitChooser::kitMatches(const Kit *k) const { if (!DebuggerKitInformation::isValidDebugger(k)) return false; if (m_mode == LocalDebugging) { - const ProjectExplorer::ToolChain *tc = ToolChainKitInformation::toolChain(k); + const ToolChain *tc = ToolChainKitInformation::toolChain(k); return tc && tc->targetAbi().os() == m_hostAbi.os(); } return true; @@ -181,7 +181,7 @@ QString StartApplicationParameters::displayName() const { const int maxLength = 60; - QString name = QFileInfo(localExecutable).fileName() + QLatin1Char(' ') + processArgs; + QString name = FileName::fromString(localExecutable).fileName() + QLatin1Char(' ') + processArgs; if (name.size() > 60) { int index = name.lastIndexOf(QLatin1Char(' '), maxLength); if (index == -1) @@ -247,7 +247,7 @@ StartApplicationDialog::StartApplicationDialog(QWidget *parent) d->serverAddressEdit = new QLineEdit(this); d->localExecutablePathChooser = new PathChooser(this); - d->localExecutablePathChooser->setExpectedKind(PathChooser::File); + d->localExecutablePathChooser->setExpectedKind(PathChooser::ExistingCommand); d->localExecutablePathChooser->setPromptDialogTitle(tr("Select Executable")); d->localExecutablePathChooser->setHistoryCompleter(QLatin1String("LocalExecutable")); @@ -282,11 +282,11 @@ StartApplicationDialog::StartApplicationDialog(QWidget *parent) "If empty, $SYSROOT/usr/lib/debug will be chosen.")); d->debuginfoPathChooser->setHistoryCompleter(QLatin1String("Debugger.DebugLocation.History")); - QFrame *line = new QFrame(this); + auto line = new QFrame(this); line->setFrameShape(QFrame::HLine); line->setFrameShadow(QFrame::Sunken); - QFrame *line2 = new QFrame(this); + auto line2 = new QFrame(this); line2->setFrameShape(QFrame::HLine); line2->setFrameShadow(QFrame::Sunken); @@ -296,7 +296,7 @@ StartApplicationDialog::StartApplicationDialog(QWidget *parent) d->buttonBox->setStandardButtons(QDialogButtonBox::Cancel|QDialogButtonBox::Ok); d->buttonBox->button(QDialogButtonBox::Ok)->setDefault(true); - QFormLayout *formLayout = new QFormLayout(); + auto formLayout = new QFormLayout(); formLayout->setFieldGrowthPolicy(QFormLayout::AllNonFixedFieldsGrow); formLayout->addRow(tr("&Kit:"), d->kitChooser); formLayout->addRow(d->serverPortLabel, d->serverPortSpinBox); @@ -311,17 +311,18 @@ StartApplicationDialog::StartApplicationDialog(QWidget *parent) formLayout->addRow(line2); formLayout->addRow(tr("&Recent:"), d->historyComboBox); - QVBoxLayout *verticalLayout = new QVBoxLayout(this); + auto verticalLayout = new QVBoxLayout(this); verticalLayout->addLayout(formLayout); verticalLayout->addStretch(); verticalLayout->addWidget(line); verticalLayout->addWidget(d->buttonBox); - connect(d->localExecutablePathChooser, SIGNAL(changed(QString)), SLOT(updateState())); - connect(d->buttonBox, SIGNAL(accepted()), SLOT(accept())); - connect(d->buttonBox, SIGNAL(rejected()), SLOT(reject())); - connect(d->historyComboBox, SIGNAL(currentIndexChanged(int)), - SLOT(historyIndexChanged(int))); + connect(d->localExecutablePathChooser, &PathChooser::changed, + this, &StartApplicationDialog::updateState); + connect(d->buttonBox, &QDialogButtonBox::accepted, this, &QDialog::accept); + connect(d->buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject); + connect(d->historyComboBox, static_cast<void(QComboBox::*)(int)>(&QComboBox::currentIndexChanged), + this, &StartApplicationDialog::historyIndexChanged); updateState(); } @@ -493,20 +494,20 @@ AttachToQmlPortDialog::AttachToQmlPortDialog(QWidget *parent) d->portSpinBox->setMaximum(65535); d->portSpinBox->setValue(3768); - QDialogButtonBox *buttonBox = new QDialogButtonBox(this); + auto buttonBox = new QDialogButtonBox(this); buttonBox->setStandardButtons(QDialogButtonBox::Cancel|QDialogButtonBox::Ok); buttonBox->button(QDialogButtonBox::Ok)->setDefault(true); - QFormLayout *formLayout = new QFormLayout(); + auto formLayout = new QFormLayout(); formLayout->addRow(tr("Kit:"), d->kitChooser); formLayout->addRow(tr("&Port:"), d->portSpinBox); - QVBoxLayout *verticalLayout = new QVBoxLayout(this); + auto verticalLayout = new QVBoxLayout(this); verticalLayout->addLayout(formLayout); verticalLayout->addWidget(buttonBox); - connect(buttonBox, SIGNAL(accepted()), SLOT(accept())); - connect(buttonBox, SIGNAL(rejected()), SLOT(reject())); + connect(buttonBox, &QDialogButtonBox::accepted, this, &QDialog::accept); + connect(buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject); } AttachToQmlPortDialog::~AttachToQmlPortDialog() @@ -567,34 +568,38 @@ StartRemoteCdbDialog::StartRemoteCdbDialog(QWidget *parent) : setWindowTitle(tr("Start a CDB Remote Session")); setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint); - QGroupBox *groupBox = new QGroupBox; + auto groupBox = new QGroupBox; - QLabel *helpLabel = new QLabel(cdbRemoteHelp()); + auto helpLabel = new QLabel(cdbRemoteHelp()); helpLabel->setWordWrap(true); helpLabel->setTextInteractionFlags(Qt::TextBrowserInteraction); - QLabel *label = new QLabel(tr("&Connection:")); + auto label = new QLabel(tr("&Connection:")); label->setBuddy(m_lineEdit); m_lineEdit->setMinimumWidth(400); - QDialogButtonBox *box = new QDialogButtonBox(QDialogButtonBox::Ok|QDialogButtonBox::Cancel); + auto box = new QDialogButtonBox(QDialogButtonBox::Ok|QDialogButtonBox::Cancel); - QFormLayout *formLayout = new QFormLayout; + auto formLayout = new QFormLayout; formLayout->addRow(helpLabel); formLayout->addRow(label, m_lineEdit); groupBox->setLayout(formLayout); - QVBoxLayout *vLayout = new QVBoxLayout(this); + auto vLayout = new QVBoxLayout(this); vLayout->addWidget(groupBox); vLayout->addWidget(box); m_okButton = box->button(QDialogButtonBox::Ok); m_okButton->setEnabled(false); - connect(m_lineEdit, SIGNAL(textChanged(QString)), this, SLOT(textChanged(QString))); - connect(m_lineEdit, SIGNAL(returnPressed()), m_okButton, SLOT(animateClick())); - connect(box, SIGNAL(accepted()), this, SLOT(accept())); - connect(box, SIGNAL(rejected()), this, SLOT(reject())); + connect(m_lineEdit, &QLineEdit::textChanged, + this, &StartRemoteCdbDialog::textChanged); + connect(m_lineEdit, &QLineEdit::returnPressed, + [this] { m_okButton->animateClick(); }); + connect(box, &QDialogButtonBox::accepted, + this, &StartRemoteCdbDialog::accept); + connect(box, &QDialogButtonBox::rejected, + this, &QDialog::reject); } void StartRemoteCdbDialog::accept() @@ -636,18 +641,20 @@ AddressDialog::AddressDialog(QWidget *parent) : { setWindowTitle(tr("Select Start Address")); setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint); - QHBoxLayout *hLayout = new QHBoxLayout; + + auto hLayout = new QHBoxLayout; hLayout->addWidget(new QLabel(tr("Enter an address:") + QLatin1Char(' '))); hLayout->addWidget(m_lineEdit); - QVBoxLayout *vLayout = new QVBoxLayout; + + auto vLayout = new QVBoxLayout; vLayout->addLayout(hLayout); vLayout->addWidget(m_box); setLayout(vLayout); - connect(m_box, SIGNAL(accepted()), this, SLOT(accept())); - connect(m_box, SIGNAL(rejected()), this, SLOT(reject())); - connect(m_lineEdit, SIGNAL(returnPressed()), this, SLOT(accept())); - connect(m_lineEdit, SIGNAL(textChanged(QString)), this, SLOT(textChanged())); + connect(m_box, &QDialogButtonBox::accepted, this, &AddressDialog::accept); + connect(m_box, &QDialogButtonBox::rejected, this, &QDialog::reject); + connect(m_lineEdit, &QLineEdit::returnPressed, this, &AddressDialog::accept); + connect(m_lineEdit, &QLineEdit::textChanged, this, &AddressDialog::textChanged); setOkButtonEnabled(false); } @@ -732,20 +739,20 @@ StartRemoteEngineDialog::StartRemoteEngineDialog(QWidget *parent) d->buttonBox = new QDialogButtonBox(this); d->buttonBox->setStandardButtons(QDialogButtonBox::Cancel|QDialogButtonBox::Ok); - QFormLayout *formLayout = new QFormLayout(); + auto formLayout = new QFormLayout(); formLayout->addRow(tr("&Host:"), d->host); formLayout->addRow(tr("&Username:"), d->username); formLayout->addRow(tr("&Password:"), d->password); formLayout->addRow(tr("&Engine path:"), d->enginePath); formLayout->addRow(tr("&Inferior path:"), d->inferiorPath); - QVBoxLayout *verticalLayout = new QVBoxLayout(this); + auto verticalLayout = new QVBoxLayout(this); verticalLayout->addLayout(formLayout); verticalLayout->addItem(new QSpacerItem(0, 0, QSizePolicy::Minimum, QSizePolicy::Expanding)); verticalLayout->addWidget(d->buttonBox); - connect(d->buttonBox, SIGNAL(accepted()), this, SLOT(accept())); - connect(d->buttonBox, SIGNAL(rejected()), this, SLOT(reject())); + connect(d->buttonBox, &QDialogButtonBox::accepted, this, &QDialog::accept); + connect(d->buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject); } StartRemoteEngineDialog::~StartRemoteEngineDialog() diff --git a/src/plugins/debugger/debuggerengine.cpp b/src/plugins/debugger/debuggerengine.cpp index a0b2d2d6d7..d79bee0df0 100644 --- a/src/plugins/debugger/debuggerengine.cpp +++ b/src/plugins/debugger/debuggerengine.cpp @@ -45,6 +45,7 @@ #include "registerhandler.h" #include "sourcefileshandler.h" #include "stackhandler.h" +#include "terminal.h" #include "threadshandler.h" #include "watchhandler.h" #include <debugger/shared/peutils.h> @@ -52,6 +53,7 @@ #include <coreplugin/editormanager/editormanager.h> #include <coreplugin/editormanager/ieditor.h> #include <coreplugin/icore.h> +#include <coreplugin/messagebox.h> #include <coreplugin/progressmanager/progressmanager.h> #include <coreplugin/progressmanager/futureprogress.h> @@ -72,8 +74,6 @@ #include <QFileInfo> #include <QDir> -#include <QMessageBox> - using namespace Core; using namespace Debugger::Internal; using namespace ProjectExplorer; @@ -100,18 +100,6 @@ const char PrefixDebugExecutable[] = "DebuggedExecutable"; namespace Debugger { -Internal::Location::Location(const StackFrame &frame, bool marker) -{ - init(); - m_fileName = frame.file; - m_lineNumber = frame.line; - m_needsMarker = marker; - m_functionName = frame.function; - m_hasDebugInfo = frame.isUsable(); - m_address = frame.address; - m_from = frame.from; -} - QDebug operator<<(QDebug d, DebuggerState state) { //return d << DebuggerEngine::stateName(state) << '(' << int(state) << ')'; @@ -134,6 +122,20 @@ QDebug operator<<(QDebug str, const DebuggerStartParameters &sp) return str; } +namespace Internal { + +Location::Location(const StackFrame &frame, bool marker) +{ + init(); + m_fileName = frame.file; + m_lineNumber = frame.line; + m_needsMarker = marker; + m_functionName = frame.function; + m_hasDebugInfo = frame.isUsable(); + m_address = frame.address; + m_from = frame.from; +} + ////////////////////////////////////////////////////////////////////// // @@ -175,9 +177,12 @@ public: m_memoryAgent(engine), m_isStateDebugging(false) { - connect(&m_locationTimer, SIGNAL(timeout()), SLOT(resetLocation())); - connect(action(IntelFlavor), SIGNAL(valueChanged(QVariant)), - SLOT(reloadDisassembly())); + connect(&m_locationTimer, &QTimer::timeout, + this, &DebuggerEnginePrivate::resetLocation); + connect(action(IntelFlavor), &Utils::SavedAction::valueChanged, + this, &DebuggerEnginePrivate::reloadDisassembly); + connect(action(OperateNativeMixed), &QAction::triggered, + engine, &DebuggerEngine::reloadFullStack); Utils::globalMacroExpander()->registerFileVariables(PrefixDebugExecutable, tr("Debugged executable"), @@ -298,6 +303,7 @@ public: // State of RemoteSetup signal/slots. RemoteSetupState m_remoteSetupState; + Terminal m_terminal; qint64 m_inferiorPid; ModulesHandler m_modulesHandler; @@ -310,7 +316,7 @@ public: DisassemblerAgent m_disassemblerAgent; MemoryAgent m_memoryAgent; - QScopedPointer<TextEditor::TextMark> m_locationMark; + QScopedPointer<TextMark> m_locationMark; QTimer m_locationTimer; bool m_isStateDebugging; @@ -476,9 +482,9 @@ void DebuggerEngine::changeMemory(MemoryAgent *, QObject *, Q_UNUSED(data); } -void DebuggerEngine::setRegisterValue(int regnr, const QString &value) +void DebuggerEngine::setRegisterValue(const QByteArray &name, const QString &value) { - Q_UNUSED(regnr); + Q_UNUSED(name); Q_UNUSED(value); } @@ -520,7 +526,7 @@ void DebuggerEngine::startDebugger(DebuggerRunControl *runControl) d->m_progress.setProgressRange(0, 1000); FutureProgress *fp = ProgressManager::addTask(d->m_progress.future(), tr("Launching Debugger"), "Debugger.Launcher"); - connect(fp, SIGNAL(canceled()), this, SLOT(quitDebugger())); + connect(fp, &FutureProgress::canceled, this, &DebuggerEngine::quitDebugger); fp->setKeepOnFinish(FutureProgress::HideOnFinish); d->m_progress.reportStarted(); @@ -541,6 +547,20 @@ void DebuggerEngine::startDebugger(DebuggerRunControl *runControl) d->m_lastGoodState = DebuggerNotReady; d->m_targetState = DebuggerNotReady; d->m_progress.setProgressValue(200); + + d->m_terminal.setup(); + if (d->m_terminal.isUsable()) { + connect(&d->m_terminal, &Terminal::stdOutReady, [this, runControl](const QString &msg) { + runControl->appendMessage(msg, Utils::StdOutFormatSameLine); + }); + connect(&d->m_terminal, &Terminal::stdErrReady, [this, runControl](const QString &msg) { + runControl->appendMessage(msg, Utils::StdErrFormatSameLine); + }); + connect(&d->m_terminal, &Terminal::error, [this, runControl](const QString &msg) { + runControl->appendMessage(msg, Utils::ErrorMessageFormat); + }); + } + d->queueSetupEngine(); } @@ -577,9 +597,9 @@ void DebuggerEngine::gotoLocation(const Location &loc) editor->document()->setProperty(Constants::OPENED_BY_DEBUGGER, true); if (loc.needsMarker()) { - d->m_locationMark.reset(new TextEditor::TextMark(file, line)); + d->m_locationMark.reset(new TextMark(file, line)); d->m_locationMark->setIcon(Internal::locationMarkIcon()); - d->m_locationMark->setPriority(TextEditor::TextMark::HighPriority); + d->m_locationMark->setPriority(TextMark::HighPriority); } //qDebug() << "MEMORY: " << d->m_memoryAgent.hasVisibleEditor(); @@ -782,6 +802,7 @@ void DebuggerEngine::notifyInferiorSetupOk() #ifdef WITH_BENCHMARK CALLGRIND_START_INSTRUMENTATION; #endif + aboutToNotifyInferiorSetupOk(); showMessage(_("NOTE: INFERIOR SETUP OK")); QTC_ASSERT(state() == InferiorSetupRequested, qDebug() << this << state()); setState(InferiorSetupOk); @@ -1204,9 +1225,8 @@ void DebuggerEngine::setState(DebuggerState state, bool forced) if (state == DebuggerFinished) { // Give up ownership on claimed breakpoints. - BreakHandler *handler = breakHandler(); - foreach (BreakpointModelId id, handler->engineBreakpointIds(this)) - handler->notifyBreakpointReleased(id); + foreach (Breakpoint bp, breakHandler()->engineBreakpoints(this)) + bp.notifyBreakpointReleased(); DebuggerToolTipManager::deregisterEngine(this); } @@ -1382,7 +1402,12 @@ DebuggerRunControl *DebuggerEngine::runControl() const return d->runControl(); } -bool DebuggerEngine::setToolTipExpression(TextEditor::TextEditorWidget *, +Terminal *DebuggerEngine::terminal() const +{ + return &d->m_terminal; +} + +bool DebuggerEngine::setToolTipExpression(TextEditorWidget *, const DebuggerToolTipContext &) { return false; @@ -1497,36 +1522,36 @@ void DebuggerEngine::attemptBreakpointSynchronization() BreakHandler *handler = breakHandler(); - foreach (BreakpointModelId id, handler->unclaimedBreakpointIds()) { + foreach (Breakpoint bp, handler->unclaimedBreakpoints()) { // Take ownership of the breakpoint. Requests insertion. - if (acceptsBreakpoint(id)) { + if (acceptsBreakpoint(bp)) { showMessage(_("TAKING OWNERSHIP OF BREAKPOINT %1 IN STATE %2") - .arg(id.toString()).arg(handler->state(id))); - handler->setEngine(id, this); + .arg(bp.id().toString()).arg(bp.state())); + bp.setEngine(this); } else { showMessage(_("BREAKPOINT %1 IN STATE %2 IS NOT ACCEPTABLE") - .arg(id.toString()).arg(handler->state(id))); + .arg(bp.id().toString()).arg(bp.state())); } } bool done = true; - foreach (BreakpointModelId id, handler->engineBreakpointIds(this)) { - switch (handler->state(id)) { + foreach (Breakpoint bp, handler->engineBreakpoints(this)) { + switch (bp.state()) { case BreakpointNew: // Should not happen once claimed. QTC_CHECK(false); continue; case BreakpointInsertRequested: done = false; - insertBreakpoint(id); + insertBreakpoint(bp); continue; case BreakpointChangeRequested: done = false; - changeBreakpoint(id); + changeBreakpoint(bp); continue; case BreakpointRemoveRequested: done = false; - removeBreakpoint(id); + removeBreakpoint(bp); continue; case BreakpointChangeProceeding: case BreakpointInsertProceeding: @@ -1543,7 +1568,7 @@ void DebuggerEngine::attemptBreakpointSynchronization() QTC_CHECK(false); continue; } - QTC_ASSERT(false, qDebug() << "UNKNOWN STATE" << id << state()); + QTC_ASSERT(false, qDebug() << "UNKNOWN STATE" << bp.id() << state()); } if (done) { @@ -1554,24 +1579,33 @@ void DebuggerEngine::attemptBreakpointSynchronization() } } -void DebuggerEngine::insertBreakpoint(BreakpointModelId id) +bool DebuggerEngine::acceptsBreakpoint(Breakpoint bp) const +{ + Q_UNUSED(bp); + return false; +} + +void DebuggerEngine::insertBreakpoint(Breakpoint bp) { - BreakpointState state = breakHandler()->state(id); - QTC_ASSERT(state == BreakpointInsertRequested, qDebug() << id << this << state); + BreakpointState state = bp.state(); + QTC_ASSERT(state == BreakpointInsertRequested, + qDebug() << bp.id() << this << state); QTC_CHECK(false); } -void DebuggerEngine::removeBreakpoint(BreakpointModelId id) +void DebuggerEngine::removeBreakpoint(Breakpoint bp) { - BreakpointState state = breakHandler()->state(id); - QTC_ASSERT(state == BreakpointRemoveRequested, qDebug() << id << this << state); + BreakpointState state = bp.state(); + QTC_ASSERT(state == BreakpointRemoveRequested, + qDebug() << bp.id() << this << state); QTC_CHECK(false); } -void DebuggerEngine::changeBreakpoint(BreakpointModelId id) +void DebuggerEngine::changeBreakpoint(Breakpoint bp) { - BreakpointState state = breakHandler()->state(id); - QTC_ASSERT(state == BreakpointChangeRequested, qDebug() << id << this << state); + BreakpointState state = bp.state(); + QTC_ASSERT(state == BreakpointChangeRequested, + qDebug() << bp.id() << this << state); QTC_CHECK(false); } @@ -1650,56 +1684,6 @@ bool DebuggerEngine::isDying() const return targetState() == DebuggerFinished; } -QString DebuggerEngine::msgWatchpointByExpressionTriggered(BreakpointModelId id, - const int number, const QString &expr) -{ - return id - ? tr("Data breakpoint %1 (%2) at %3 triggered.") - .arg(id.toString()).arg(number).arg(expr) - : tr("Internal data breakpoint %1 at %2 triggered.") - .arg(number).arg(expr); -} - -QString DebuggerEngine::msgWatchpointByExpressionTriggered(BreakpointModelId id, - const int number, const QString &expr, const QString &threadId) -{ - return id - ? tr("Data breakpoint %1 (%2) at %3 in thread %4 triggered.") - .arg(id.toString()).arg(number).arg(expr).arg(threadId) - : tr("Internal data breakpoint %1 at %2 in thread %3 triggered.") - .arg(number).arg(expr).arg(threadId); -} - -QString DebuggerEngine::msgWatchpointByAddressTriggered(BreakpointModelId id, - const int number, quint64 address) -{ - return id - ? tr("Data breakpoint %1 (%2) at 0x%3 triggered.") - .arg(id.toString()).arg(number).arg(address, 0, 16) - : tr("Internal data breakpoint %1 at 0x%2 triggered.") - .arg(number).arg(address, 0, 16); -} - -QString DebuggerEngine::msgWatchpointByAddressTriggered(BreakpointModelId id, - const int number, quint64 address, const QString &threadId) -{ - return id - ? tr("Data breakpoint %1 (%2) at 0x%3 in thread %4 triggered.") - .arg(id.toString()).arg(number).arg(address, 0, 16).arg(threadId) - : tr("Internal data breakpoint %1 at 0x%2 in thread %3 triggered.") - .arg(id.toString()).arg(number).arg(address, 0, 16).arg(threadId); -} - -QString DebuggerEngine::msgBreakpointTriggered(BreakpointModelId id, - const int number, const QString &threadId) -{ - return id - ? tr("Stopped at breakpoint %1 (%2) in thread %3.") - .arg(id.toString()).arg(number).arg(threadId) - : tr("Stopped at internal breakpoint %1 in thread %2.") - .arg(number).arg(threadId); -} - QString DebuggerEngine::msgStopped(const QString &reason) { return reason.isEmpty() ? tr("Stopped.") : tr("Stopped: \"%1\"").arg(reason); @@ -1733,7 +1717,7 @@ void DebuggerEngine::showStoppedBySignalMessageBox(QString meaning, QString name "<table><tr><td>Signal name : </td><td>%1</td></tr>" "<tr><td>Signal meaning : </td><td>%2</td></tr></table>") .arg(name, meaning); - showMessageBox(QMessageBox::Information, tr("Signal received"), msg); + AsynchronousMessageBox::information(tr("Signal received"), msg); } void DebuggerEngine::showStoppedByExceptionMessageBox(const QString &description) @@ -1741,14 +1725,12 @@ void DebuggerEngine::showStoppedByExceptionMessageBox(const QString &description const QString msg = tr("<p>The inferior stopped because it triggered an exception.<p>%1"). arg(description); - showMessageBox(QMessageBox::Information, tr("Exception Triggered"), msg); + AsynchronousMessageBox::information(tr("Exception Triggered"), msg); } -void DebuggerEngine::openMemoryView(quint64 startAddr, unsigned flags, - const QList<MemoryMarkup> &ml, const QPoint &pos, - const QString &title, QWidget *parent) +void DebuggerEngine::openMemoryView(const MemoryViewSetupData &data) { - d->m_memoryAgent.createBinEditor(startAddr, flags, ml, pos, title, parent); + d->m_memoryAgent.createBinEditor(data); } void DebuggerEngine::updateMemoryViews() @@ -1783,7 +1765,7 @@ void DebuggerEngine::validateExecutable(DebuggerStartParameters *sp) const bool warnOnRelease = boolSetting(WarnOnReleaseBuilds); QString detailedWarning; switch (sp->toolChainAbi.binaryFormat()) { - case ProjectExplorer::Abi::PEFormat: { + case Abi::PEFormat: { if (!warnOnRelease || (sp->masterEngineType != CdbEngineType)) return; if (!binary.endsWith(QLatin1String(".exe"), Qt::CaseInsensitive)) @@ -1798,7 +1780,7 @@ void DebuggerEngine::validateExecutable(DebuggerStartParameters *sp) } break; } - case ProjectExplorer::Abi::ElfFormat: { + case Abi::ElfFormat: { Utils::ElfReader reader(binary); Utils::ElfData elfData = reader.readHeaders(); @@ -1897,13 +1879,14 @@ void DebuggerEngine::validateExecutable(DebuggerStartParameters *sp) return; } if (warnOnRelease) { - showMessageBox(QMessageBox::Information, tr("Warning"), + AsynchronousMessageBox::information(tr("Warning"), tr("This does not seem to be a \"Debug\" build.\n" "Setting breakpoints by file name and line number may fail.") + QLatin1Char('\n') + detailedWarning); } } +} // namespace Internal } // namespace Debugger #include "debuggerengine.moc" diff --git a/src/plugins/debugger/debuggerengine.h b/src/plugins/debugger/debuggerengine.h index 71c5ec831a..a7313a9c7c 100644 --- a/src/plugins/debugger/debuggerengine.h +++ b/src/plugins/debugger/debuggerengine.h @@ -33,8 +33,8 @@ #include "debugger_global.h" #include "debuggerconstants.h" +#include "debuggerprotocol.h" #include "debuggerstartparameters.h" -#include "breakpoint.h" // For BreakpointModelId. #include "threaddata.h" // For ThreadId. #include <QObject> @@ -42,7 +42,6 @@ QT_BEGIN_NAMESPACE class QDebug; class QPoint; -class QMessageBox; class QAbstractItemModel; QT_END_NAMESPACE @@ -51,7 +50,6 @@ namespace Core { class IOptionsPage; } namespace Debugger { -class DebuggerEnginePrivate; class DebuggerRunControl; class DebuggerStartParameters; @@ -60,6 +58,7 @@ DEBUGGER_EXPORT QDebug operator<<(QDebug str, DebuggerState state); namespace Internal { +class DebuggerEnginePrivate; class DebuggerPluginPrivate; class DisassemblerAgent; class MemoryAgent; @@ -72,11 +71,12 @@ class StackFrame; class SourceFilesHandler; class ThreadsHandler; class WatchHandler; -class BreakpointParameters; +class Breakpoint; class QmlAdapter; class QmlCppEngine; class DebuggerToolTipContext; -class MemoryMarkup; +class MemoryViewSetupData; +class Terminal; struct WatchUpdateFlags { @@ -130,11 +130,7 @@ public: quint64 address; }; -} // namespace Internal - - -// FIXME: DEBUGGER_EXPORT? -class DEBUGGER_EXPORT DebuggerEngine : public QObject +class DebuggerEngine : public QObject { Q_OBJECT @@ -163,10 +159,7 @@ public: MemoryView = 0x4 //!< Open a separate view (using the pos-parameter). }; - virtual void openMemoryView(quint64 startAddr, unsigned flags, - const QList<Internal::MemoryMarkup> &ml, - const QPoint &pos, - const QString &title = QString(), QWidget *parent = 0); + virtual void openMemoryView(const MemoryViewSetupData &data); virtual void fetchMemory(Internal::MemoryAgent *, QObject *, quint64 addr, quint64 length); virtual void changeMemory(Internal::MemoryAgent *, QObject *, @@ -190,7 +183,7 @@ public: virtual void loadAdditionalQmlStack(); virtual void reloadDebuggingHelpers(); - virtual void setRegisterValue(int regnr, const QString &value); + virtual void setRegisterValue(const QByteArray &name, const QString &value); virtual void addOptionPages(QList<Core::IOptionsPage*> *) const; virtual bool hasCapability(unsigned cap) const = 0; virtual void debugLastCommand() {} @@ -201,13 +194,12 @@ public: virtual void createSnapshot(); virtual void updateAll(); - typedef Internal::BreakpointModelId BreakpointModelId; virtual bool stateAcceptsBreakpointChanges() const { return true; } virtual void attemptBreakpointSynchronization(); - virtual bool acceptsBreakpoint(BreakpointModelId id) const = 0; - virtual void insertBreakpoint(BreakpointModelId id); // FIXME: make pure - virtual void removeBreakpoint(BreakpointModelId id); // FIXME: make pure - virtual void changeBreakpoint(BreakpointModelId id); // FIXME: make pure + virtual bool acceptsBreakpoint(Breakpoint bp) const = 0; + virtual void insertBreakpoint(Breakpoint bp); // FIXME: make pure + virtual void removeBreakpoint(Breakpoint bp); // FIXME: make pure + virtual void changeBreakpoint(Breakpoint bp); // FIXME: make pure virtual bool acceptsDebuggerCommands() const { return true; } virtual void executeDebuggerCommand(const QString &command, DebuggerLanguages languages); @@ -264,9 +256,6 @@ public: bool isMasterEngine() const; DebuggerEngine *masterEngine() const; - virtual bool setupQmlStep(bool /*on*/) { return false; } - virtual void readyToExecuteQmlStep() {} - virtual bool canDisplayTooltip() const { return state() == InferiorStopOk; } virtual void notifyInferiorIll(); @@ -286,6 +275,7 @@ signals: * a server start script should be used, but none is given. */ void requestRemoteSetup(); + void aboutToNotifyInferiorSetupOk(); protected: // The base notify*() function implementation should be sufficient @@ -319,7 +309,9 @@ protected: virtual void notifyInferiorStopOk(); virtual void notifyInferiorSpontaneousStop(); virtual void notifyInferiorStopFailed(); - Q_SLOT virtual void notifyInferiorExited(); + + public: + virtual void notifyInferiorExited(); protected: virtual void notifyInferiorShutdownOk(); @@ -362,17 +354,8 @@ protected: void setMasterEngine(DebuggerEngine *masterEngine); DebuggerRunControl *runControl() const; + Terminal *terminal() const; - static QString msgWatchpointByAddressTriggered(BreakpointModelId id, - int number, quint64 address); - static QString msgWatchpointByAddressTriggered(BreakpointModelId id, - int number, quint64 address, const QString &threadId); - static QString msgWatchpointByExpressionTriggered(BreakpointModelId id, - int number, const QString &expr); - static QString msgWatchpointByExpressionTriggered(BreakpointModelId id, - int number, const QString &expr, const QString &threadId); - static QString msgBreakpointTriggered(BreakpointModelId id, - int number, const QString &threadId); static QString msgStopped(const QString &reason = QString()); static QString msgStoppedBySignal(const QString &meaning, const QString &name); static QString msgStoppedByException(const QString &description, @@ -396,9 +379,9 @@ protected: private: // Wrapper engine needs access to state of its subengines. - friend class Internal::QmlCppEngine; - friend class Internal::DebuggerPluginPrivate; - friend class Internal::QmlAdapter; + friend class QmlCppEngine; + friend class DebuggerPluginPrivate; + friend class QmlAdapter; virtual void setState(DebuggerState state, bool forced = false); @@ -406,6 +389,7 @@ private: DebuggerEnginePrivate *d; }; +} // namespace Internal } // namespace Debugger Q_DECLARE_METATYPE(Debugger::Internal::ContextData) diff --git a/src/plugins/debugger/debuggeritem.cpp b/src/plugins/debugger/debuggeritem.cpp index def87bde11..f011a861db 100644 --- a/src/plugins/debugger/debuggeritem.cpp +++ b/src/plugins/debugger/debuggeritem.cpp @@ -142,9 +142,18 @@ void DebuggerItem::reinitializeFromFile() .arg(version / 10000).arg((version / 100) % 100).arg(version % 100); return; } - if (ba.contains("lldb") || ba.startsWith("LLDB")) { + if (ba.startsWith("lldb") || ba.startsWith("LLDB")) { m_engineType = LldbEngineType; m_abis = Abi::abisOfBinary(m_command); + + // Version + if (ba.startsWith(("lldb version "))) { // Linux typically. + int pos1 = strlen("lldb version "); + int pos2 = ba.indexOf(' ', pos1); + m_version = QString::fromLatin1(ba.mid(pos1, pos2 - pos1)); + } else if (ba.startsWith("lldb-") || ba.startsWith("LLDB-")) { // Mac typically. + m_version = QString::fromLatin1(ba.mid(5)); + } return; } if (ba.startsWith("Python")) { @@ -223,7 +232,7 @@ void DebuggerItem::setEngineType(const DebuggerEngineType &engineType) m_engineType = engineType; } -void DebuggerItem::setCommand(const Utils::FileName &command) +void DebuggerItem::setCommand(const FileName &command) { m_command = command; } @@ -248,7 +257,7 @@ void DebuggerItem::setAutoDetectionSource(const QString &autoDetectionSource) m_autoDetectionSource = autoDetectionSource; } -void DebuggerItem::setAbis(const QList<ProjectExplorer::Abi> &abis) +void DebuggerItem::setAbis(const QList<Abi> &abis) { m_abis = abis; } diff --git a/src/plugins/debugger/debuggeritem.h b/src/plugins/debugger/debuggeritem.h index ffffb2086b..6117e6c5f3 100644 --- a/src/plugins/debugger/debuggeritem.h +++ b/src/plugins/debugger/debuggeritem.h @@ -97,6 +97,7 @@ public: QStringList abiNames() const; bool operator==(const DebuggerItem &other) const; + bool operator!=(const DebuggerItem &other) const { return !operator==(other); } private: DebuggerItem(const QVariant &id); diff --git a/src/plugins/debugger/debuggeritemmanager.cpp b/src/plugins/debugger/debuggeritemmanager.cpp index b4a38c2927..f7cad5d96c 100644 --- a/src/plugins/debugger/debuggeritemmanager.cpp +++ b/src/plugins/debugger/debuggeritemmanager.cpp @@ -29,8 +29,6 @@ ****************************************************************************/ #include "debuggeritemmanager.h" - -#include "debuggeritemmodel.h" #include "debuggerkitinformation.h" #include <coreplugin/icore.h> @@ -46,26 +44,36 @@ #include <QFileInfo> #include <QProcess> +using namespace Core; using namespace ProjectExplorer; using namespace Utils; namespace Debugger { -static const char DEBUGGER_COUNT_KEY[] = "DebuggerItem.Count"; -static const char DEBUGGER_DATA_KEY[] = "DebuggerItem."; -static const char DEBUGGER_LEGACY_FILENAME[] = "/qtcreator/profiles.xml"; -static const char DEBUGGER_FILE_VERSION_KEY[] = "Version"; -static const char DEBUGGER_FILENAME[] = "/qtcreator/debuggers.xml"; +const char DEBUGGER_COUNT_KEY[] = "DebuggerItem.Count"; +const char DEBUGGER_DATA_KEY[] = "DebuggerItem."; +const char DEBUGGER_LEGACY_FILENAME[] = "/qtcreator/profiles.xml"; +const char DEBUGGER_FILE_VERSION_KEY[] = "Version"; +const char DEBUGGER_FILENAME[] = "/qtcreator/debuggers.xml"; + +namespace { +QList<DebuggerItem> m_debuggers; +PersistentSettingsWriter *m_writer = 0; +} // -------------------------------------------------------------------------- // DebuggerItemManager // -------------------------------------------------------------------------- -static DebuggerItemManager *m_instance = 0; +static void addDebugger(const DebuggerItem &item) +{ + QTC_ASSERT(item.id().isValid(), return); + m_debuggers.append(item); +} static FileName userSettingsFileName() { - QFileInfo settingsLocation(Core::ICore::settings()->fileName()); + QFileInfo settingsLocation(ICore::settings()->fileName()); return FileName::fromString(settingsLocation.absolutePath() + QLatin1String(DEBUGGER_FILENAME)); } @@ -111,27 +119,15 @@ static void readDebuggers(const FileName &fileName, bool isSystem) } } -QList<DebuggerItem> DebuggerItemManager::m_debuggers; -PersistentSettingsWriter * DebuggerItemManager::m_writer = 0; - -DebuggerItemManager::DebuggerItemManager(QObject *parent) - : QObject(parent) +DebuggerItemManager::DebuggerItemManager() { - m_instance = this; m_writer = new PersistentSettingsWriter(userSettingsFileName(), QLatin1String("QtCreatorDebuggers")); - connect(Core::ICore::instance(), SIGNAL(saveSettingsRequested()), - this, SLOT(saveDebuggers())); -} - -DebuggerItemManager *DebuggerItemManager::instance() -{ - return m_instance; + connect(ICore::instance(), &ICore::saveSettingsRequested, + this, &DebuggerItemManager::saveDebuggers); } DebuggerItemManager::~DebuggerItemManager() { - disconnect(Core::ICore::instance(), SIGNAL(saveSettingsRequested()), - this, SLOT(saveDebuggers())); delete m_writer; } @@ -227,7 +223,7 @@ void DebuggerItemManager::autoDetectGdbOrLldbDebuggers() } */ - QFileInfoList suspects; + QList<FileName> suspects; if (HostOsInfo::isMacHost()) { QProcess lldbInfo; @@ -238,43 +234,38 @@ void DebuggerItemManager::autoDetectGdbOrLldbDebuggers() lldbInfo.waitForFinished(); } else { QByteArray lPath = lldbInfo.readAll(); - suspects.append(QFileInfo(QString::fromLocal8Bit(lPath.data(), lPath.size() -1))); + const QFileInfo fi(QString::fromLocal8Bit(lPath.data(), lPath.size() -1)); + if (fi.exists() && fi.isExecutable() && !fi.isDir()) + suspects.append(FileName::fromString(fi.absoluteFilePath())); } } QStringList path = Environment::systemEnvironment().path(); + path.removeDuplicates(); + QDir dir; + dir.setNameFilters(filters); + dir.setFilter(QDir::Files | QDir::Executable); foreach (const QString &base, path) { - QDir dir(base); - dir.setNameFilters(filters); - suspects += dir.entryInfoList(); + dir.setPath(base); + foreach (const QString &entry, dir.entryList()) + suspects.append(FileName::fromString(dir.absoluteFilePath(entry))); } - foreach (const QFileInfo &fi, suspects) { - if (fi.exists() && fi.isExecutable() && !fi.isDir()) { - FileName command = FileName::fromString(fi.absoluteFilePath()); - if (findByCommand(command)) - continue; - DebuggerItem item; - item.createId(); - item.setCommand(command); - item.reinitializeFromFile(); - //: %1: Debugger engine type (GDB, LLDB, CDB...), %2: Path - item.setDisplayName(tr("System %1 at %2") - .arg(item.engineTypeName()).arg(QDir::toNativeSeparators(fi.absoluteFilePath()))); - item.setAutoDetected(true); - addDebugger(item); - } + foreach (const FileName &command, suspects) { + if (findByCommand(command)) + continue; + DebuggerItem item; + item.createId(); + item.setCommand(command); + item.reinitializeFromFile(); + //: %1: Debugger engine type (GDB, LLDB, CDB...), %2: Path + item.setDisplayName(tr("System %1 at %2") + .arg(item.engineTypeName()).arg(command.toUserOutput())); + item.setAutoDetected(true); + addDebugger(item); } } -void DebuggerItemManager::readLegacyDebuggers() -{ - QFileInfo systemLocation(Core::ICore::settings(QSettings::SystemScope)->fileName()); - readLegacyDebuggers(FileName::fromString(systemLocation.absolutePath() + QLatin1String(DEBUGGER_LEGACY_FILENAME))); - QFileInfo userLocation(Core::ICore::settings()->fileName()); - readLegacyDebuggers(FileName::fromString(userLocation.absolutePath() + QLatin1String(DEBUGGER_LEGACY_FILENAME))); -} - void DebuggerItemManager::readLegacyDebuggers(const FileName &file) { PersistentSettingsReader reader; @@ -341,7 +332,7 @@ const DebuggerItem *DebuggerItemManager::findByEngineType(DebuggerEngineType eng void DebuggerItemManager::restoreDebuggers() { // Read debuggers from SDK - QFileInfo systemSettingsFile(Core::ICore::settings(QSettings::SystemScope)->fileName()); + QFileInfo systemSettingsFile(ICore::settings(QSettings::SystemScope)->fileName()); readDebuggers(FileName::fromString(systemSettingsFile.absolutePath() + QLatin1String(DEBUGGER_FILENAME)), true); // Read all debuggers from user file. @@ -352,7 +343,10 @@ void DebuggerItemManager::restoreDebuggers() autoDetectGdbOrLldbDebuggers(); // Add debuggers from pre-3.x profiles.xml - readLegacyDebuggers(); + QFileInfo systemLocation(ICore::settings(QSettings::SystemScope)->fileName()); + readLegacyDebuggers(FileName::fromString(systemLocation.absolutePath() + QLatin1String(DEBUGGER_LEGACY_FILENAME))); + QFileInfo userLocation(ICore::settings()->fileName()); + readLegacyDebuggers(FileName::fromString(userLocation.absolutePath() + QLatin1String(DEBUGGER_LEGACY_FILENAME))); } void DebuggerItemManager::saveDebuggers() @@ -372,7 +366,7 @@ void DebuggerItemManager::saveDebuggers() } } data.insert(QLatin1String(DEBUGGER_COUNT_KEY), count); - m_writer->save(data, Core::ICore::mainWindow()); + m_writer->save(data, ICore::mainWindow()); // Do not save default debuggers as they are set by the SDK. } @@ -390,44 +384,23 @@ QVariant DebuggerItemManager::registerDebugger(const DebuggerItem &item) } } - // If item already has an id, add it. Otherwise, create a new id. - if (item.id().isValid()) - return addDebugger(item); - + // If item already has an id, use it. Otherwise, create a new id. DebuggerItem di = item; - di.createId(); - return addDebugger(di); -} + if (!di.id().isValid()) + di.createId(); -void DebuggerItemManager::deregisterDebugger(const QVariant &id) -{ - if (findById(id)) - removeDebugger(id); + addDebugger(di); + return di.id(); } -QVariant DebuggerItemManager::addDebugger(const DebuggerItem &item) -{ - QTC_ASSERT(item.id().isValid(), return QVariant()); - m_debuggers.append(item); - QVariant id = item.id(); - emit m_instance->debuggerAdded(id); - return id; -} - -void DebuggerItemManager::removeDebugger(const QVariant &id) +void DebuggerItemManager::deregisterDebugger(const QVariant &id) { - bool ok = false; for (int i = 0, n = m_debuggers.size(); i != n; ++i) { if (m_debuggers.at(i).id() == id) { - emit m_instance->aboutToRemoveDebugger(id); m_debuggers.removeAt(i); - emit m_instance->debuggerRemoved(id); - ok = true; break; } } - - QTC_ASSERT(ok, return); } QString DebuggerItemManager::uniqueDisplayName(const QString &base) @@ -439,26 +412,18 @@ QString DebuggerItemManager::uniqueDisplayName(const QString &base) return base; } -void DebuggerItemManager::setItemData(const QVariant &id, const QString &displayName, const FileName &fileName) +void DebuggerItemManager::updateOrAddDebugger(const DebuggerItem &treeItem) { for (int i = 0, n = m_debuggers.size(); i != n; ++i) { DebuggerItem &item = m_debuggers[i]; - if (item.id() == id) { - bool changed = false; - if (item.displayName() != displayName) { - item.setDisplayName(displayName); - changed = true; - } - if (item.command() != fileName) { - item.setCommand(fileName); - item.reinitializeFromFile(); - changed = true; - } - if (changed) - emit m_instance->debuggerUpdated(id); - break; + if (item.id() == treeItem.id()) { + item = treeItem; + return; } } + + // This is a new item. + addDebugger(treeItem); } } // namespace Debugger; diff --git a/src/plugins/debugger/debuggeritemmanager.h b/src/plugins/debugger/debuggeritemmanager.h index 5bddfccbb5..25afa1b2df 100644 --- a/src/plugins/debugger/debuggeritemmanager.h +++ b/src/plugins/debugger/debuggeritemmanager.h @@ -33,35 +33,27 @@ #include "debugger_global.h" #include "debuggeritem.h" -#include "debuggeritemmodel.h" #include <QList> #include <QObject> #include <QString> -namespace Utils { class PersistentSettingsWriter; } - namespace Debugger { -namespace Internal { class DebuggerPlugin; } - // ----------------------------------------------------------------------- // DebuggerItemManager // ----------------------------------------------------------------------- class DEBUGGER_EXPORT DebuggerItemManager : public QObject { - Q_OBJECT - public: - static DebuggerItemManager *instance(); + DebuggerItemManager(); ~DebuggerItemManager(); static QList<DebuggerItem> debuggers(); static QVariant registerDebugger(const DebuggerItem &item); static void deregisterDebugger(const QVariant &id); - static void setItemData(const QVariant &id, const QString& displayName, const Utils::FileName &fileName); static const DebuggerItem *findByCommand(const Utils::FileName &command); static const DebuggerItem *findById(const QVariant &id); @@ -70,30 +62,13 @@ public: static void restoreDebuggers(); static QString uniqueDisplayName(const QString &base); - static void removeDebugger(const QVariant &id); - static QVariant addDebugger(const DebuggerItem &item); - -signals: - void debuggerAdded(const QVariant &id); - void aboutToRemoveDebugger(const QVariant &id); - void debuggerRemoved(const QVariant &id); - void debuggerUpdated(const QVariant &id); - -public slots: - void saveDebuggers(); + static void updateOrAddDebugger(const DebuggerItem &item); + static void saveDebuggers(); private: - explicit DebuggerItemManager(QObject *parent = 0); static void autoDetectGdbOrLldbDebuggers(); static void autoDetectCdbDebuggers(); - static void readLegacyDebuggers(); static void readLegacyDebuggers(const Utils::FileName &file); - - static Utils::PersistentSettingsWriter *m_writer; - static QList<DebuggerItem> m_debuggers; - - friend class Internal::DebuggerItemModel; - friend class Internal::DebuggerPlugin; // Enable constrcutor for DebuggerPlugin }; } // namespace Debugger diff --git a/src/plugins/debugger/debuggeritemmodel.cpp b/src/plugins/debugger/debuggeritemmodel.cpp deleted file mode 100644 index 9b24144510..0000000000 --- a/src/plugins/debugger/debuggeritemmodel.cpp +++ /dev/null @@ -1,311 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2015 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing -** -** This file is part of Qt Creator. -** -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms and -** conditions see http://www.qt.io/terms-conditions. For further information -** use the contact form at http://www.qt.io/contact-us. -** -** 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 or version 3 as published by the Free -** Software Foundation and appearing in the file LICENSE.LGPLv21 and -** LICENSE.LGPLv3 included in the packaging of this file. Please review the -** following information to ensure the GNU Lesser General Public License -** requirements will be met: https://www.gnu.org/licenses/lgpl.html and -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, The Qt Company gives you certain additional -** rights. These rights are described in The Qt Company LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -****************************************************************************/ - -#include "debuggeritemmodel.h" - -#include "debuggeritem.h" -#include "debuggeritemmanager.h" - -#include <utils/qtcassert.h> - -namespace Debugger { -namespace Internal { - -const int AbiRole = Qt::UserRole + 2; - -static QList<QStandardItem *> describeItem(const DebuggerItem &item) -{ - QList<QStandardItem *> row; - row.append(new QStandardItem(item.displayName())); - row.append(new QStandardItem(item.command().toUserOutput())); - row.append(new QStandardItem(item.engineTypeName())); - row.at(0)->setData(item.id()); - row.at(0)->setData(item.abiNames(), AbiRole); - row.at(0)->setEditable(false); - row.at(1)->setEditable(false); - row.at(1)->setData(item.toMap()); - row.at(2)->setEditable(false); - row.at(2)->setData(static_cast<int>(item.engineType())); - row.at(0)->setSelectable(true); - row.at(1)->setSelectable(true); - row.at(2)->setSelectable(true); - return row; -} - -static QList<QStandardItem *> createRow(const QString &display) -{ - QList<QStandardItem *> row; - row.append(new QStandardItem(display)); - row.append(new QStandardItem()); - row.append(new QStandardItem()); - row.at(0)->setEditable(false); - row.at(1)->setEditable(false); - row.at(2)->setEditable(false); - row.at(0)->setSelectable(false); - row.at(1)->setSelectable(false); - row.at(2)->setSelectable(false); - return row; -} - -// -------------------------------------------------------------------------- -// DebuggerItemModel -// -------------------------------------------------------------------------- - -DebuggerItemModel::DebuggerItemModel(QObject *parent) - : QStandardItemModel(parent) -{ - setColumnCount(3); - - QList<QStandardItem *> row = createRow(tr("Auto-detected")); - m_autoRoot = row.at(0); - appendRow(row); - - row = createRow(tr("Manual")); - m_manualRoot = row.at(0); - appendRow(row); - - foreach (const DebuggerItem &item, DebuggerItemManager::debuggers()) - addDebuggerStandardItem(item, false); - - QObject *manager = DebuggerItemManager::instance(); - connect(manager, SIGNAL(debuggerAdded(QVariant)), - this, SLOT(onDebuggerAdded(QVariant))); - connect(manager, SIGNAL(debuggerUpdated(QVariant)), - this, SLOT(onDebuggerUpdate(QVariant))); - connect(manager, SIGNAL(debuggerRemoved(QVariant)), - this, SLOT(onDebuggerRemoval(QVariant))); -} - -QVariant DebuggerItemModel::headerData(int section, Qt::Orientation orientation, int role) const -{ - if (role == Qt::DisplayRole && orientation == Qt::Horizontal) { - switch (section) { - case 0: - return tr("Name"); - case 1: - return tr("Path"); - case 2: - return tr("Type"); - } - } - return QVariant(); -} - -bool DebuggerItemModel::addDebuggerStandardItem(const DebuggerItem &item, bool changed) -{ - if (findStandardItemById(item.id())) - return false; - - QList<QStandardItem *> row = describeItem(item); - foreach (QStandardItem *cell, row) { - QFont font = cell->font(); - font.setBold(changed); - cell->setFont(font); - } - (item.isAutoDetected() ? m_autoRoot : m_manualRoot)->appendRow(row); - return true; -} - -bool DebuggerItemModel::removeDebuggerStandardItem(const QVariant &id) -{ - QStandardItem *sitem = findStandardItemById(id); - QTC_ASSERT(sitem, return false); - QStandardItem *parent = sitem->parent(); - QTC_ASSERT(parent, return false); - // This will trigger a change of m_currentDebugger via changing the - // view selection. - parent->removeRow(sitem->row()); - return true; -} - -bool DebuggerItemModel::updateDebuggerStandardItem(const DebuggerItem &item, bool changed) -{ - QStandardItem *sitem = findStandardItemById(item.id()); - QTC_ASSERT(sitem, return false); - QStandardItem *parent = sitem->parent(); - QTC_ASSERT(parent, return false); - - // Do not mark items as changed if they actually are not: - const DebuggerItem *orig = DebuggerItemManager::findById(item.id()); - if (orig && *orig == item) - changed = false; - - int row = sitem->row(); - QFont font = sitem->font(); - font.setBold(changed); - parent->child(row, 0)->setData(item.displayName(), Qt::DisplayRole); - parent->child(row, 0)->setData(item.abiNames(), AbiRole); - parent->child(row, 0)->setFont(font); - parent->child(row, 1)->setData(item.command().toUserOutput(), Qt::DisplayRole); - parent->child(row, 1)->setFont(font); - parent->child(row, 2)->setData(item.engineTypeName(), Qt::DisplayRole); - parent->child(row, 2)->setData(static_cast<int>(item.engineType())); - parent->child(row, 2)->setFont(font); - return true; -} - -DebuggerItem DebuggerItemModel::debuggerItem(QStandardItem *sitem) const -{ - DebuggerItem item = DebuggerItem(QVariant()); - if (sitem && sitem->parent()) { - item.setAutoDetected(sitem->parent() == m_autoRoot); - - QStandardItem *i = sitem->parent()->child(sitem->row(), 0); - item.m_id = i->data(); - item.setDisplayName(i->data(Qt::DisplayRole).toString()); - - QStringList abis = i->data(AbiRole).toStringList(); - QList<ProjectExplorer::Abi> abiList; - foreach (const QString &abi, abis) - abiList << ProjectExplorer::Abi(abi); - item.setAbis(abiList); - - i = sitem->parent()->child(sitem->row(), 1); - item.setCommand(Utils::FileName::fromUserInput(i->data(Qt::DisplayRole).toString())); - - i = sitem->parent()->child(sitem->row(), 2); - item.setEngineType(static_cast<DebuggerEngineType>(i->data().toInt())); - } - return item; -} - -QList<DebuggerItem> DebuggerItemModel::debuggerItems() const -{ - QList<DebuggerItem> result; - for (int i = 0, n = m_autoRoot->rowCount(); i != n; ++i) - result << debuggerItem(m_autoRoot->child(i)); - for (int i = 0, n = m_manualRoot->rowCount(); i != n; ++i) - result << debuggerItem(m_manualRoot->child(i)); - return result; -} - -QStandardItem *DebuggerItemModel::currentStandardItem() const -{ - return findStandardItemById(m_currentDebugger); -} - -QStandardItem *DebuggerItemModel::findStandardItemById(const QVariant &id) const -{ - for (int i = 0, n = m_autoRoot->rowCount(); i != n; ++i) { - QStandardItem *sitem = m_autoRoot->child(i); - if (sitem->data() == id) - return sitem; - } - for (int i = 0, n = m_manualRoot->rowCount(); i != n; ++i) { - QStandardItem *sitem = m_manualRoot->child(i); - if (sitem->data() == id) - return sitem; - } - return 0; -} - -QModelIndex DebuggerItemModel::currentIndex() const -{ - QStandardItem *current = currentStandardItem(); - return current ? current->index() : QModelIndex(); -} - -QModelIndex DebuggerItemModel::lastIndex() const -{ - int n = m_manualRoot->rowCount(); - QStandardItem *current = m_manualRoot->child(n - 1); - return current ? current->index() : QModelIndex(); -} - -void DebuggerItemModel::onDebuggerAdded(const QVariant &id) -{ - const DebuggerItem *item = DebuggerItemManager::findById(id); - QTC_ASSERT(item, return); - if (!addDebuggerStandardItem(*item, false)) - updateDebuggerStandardItem(*item, false); // already had it added, so just update it. -} - -void DebuggerItemModel::onDebuggerUpdate(const QVariant &id) -{ - const DebuggerItem *item = DebuggerItemManager::findById(id); - QTC_ASSERT(item, return); - updateDebuggerStandardItem(*item, false); -} - -void DebuggerItemModel::onDebuggerRemoval(const QVariant &id) -{ - removeDebuggerStandardItem(id); -} - -void DebuggerItemModel::addDebugger(const DebuggerItem &item) -{ - addDebuggerStandardItem(item, true); -} - -void DebuggerItemModel::removeDebugger(const QVariant &id) -{ - if (!removeDebuggerStandardItem(id)) // Nothing there! - return; - - if (DebuggerItemManager::findById(id)) - m_removedItems.append(id); -} - -void DebuggerItemModel::updateDebugger(const DebuggerItem &item) -{ - updateDebuggerStandardItem(item, true); -} - -void DebuggerItemModel::apply() -{ - foreach (const QVariant &id, m_removedItems) - DebuggerItemManager::deregisterDebugger(id); - - foreach (const DebuggerItem &item, debuggerItems()) { - const DebuggerItem *managed = DebuggerItemManager::findById(item.id()); - if (managed) { - if (*managed == item) - continue; - else - DebuggerItemManager::setItemData(item.id(), item.displayName(), item.command()); - } else { - DebuggerItemManager::registerDebugger(item); - } - } -} - -void DebuggerItemModel::setCurrentIndex(const QModelIndex &index) -{ - QStandardItem *sit = itemFromIndex(index); - m_currentDebugger = sit ? sit->data() : QVariant(); -} - -DebuggerItem DebuggerItemModel::currentDebugger() const -{ - return debuggerItem(currentStandardItem()); -} - -} // namespace Internal -} // namespace Debugger diff --git a/src/plugins/debugger/debuggeritemmodel.h b/src/plugins/debugger/debuggeritemmodel.h deleted file mode 100644 index 682bd60247..0000000000 --- a/src/plugins/debugger/debuggeritemmodel.h +++ /dev/null @@ -1,93 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2015 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing -** -** This file is part of Qt Creator. -** -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms and -** conditions see http://www.qt.io/terms-conditions. For further information -** use the contact form at http://www.qt.io/contact-us. -** -** 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 or version 3 as published by the Free -** Software Foundation and appearing in the file LICENSE.LGPLv21 and -** LICENSE.LGPLv3 included in the packaging of this file. Please review the -** following information to ensure the GNU Lesser General Public License -** requirements will be met: https://www.gnu.org/licenses/lgpl.html and -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, The Qt Company gives you certain additional -** rights. These rights are described in The Qt Company LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -****************************************************************************/ - -#ifndef DEBUGGER_DEBUGGERITEMMODEL_H -#define DEBUGGER_DEBUGGERITEMMODEL_H - -#include "debuggeritem.h" - -#include <QStandardItemModel> -#include <QVariant> - -namespace Debugger { -namespace Internal { - -// ----------------------------------------------------------------------- -// DebuggerItemModel -//------------------------------------------------------------------------ - -class DebuggerItemModel : public QStandardItemModel -{ - Q_OBJECT - -public: - DebuggerItemModel(QObject *parent = 0); - - QModelIndex currentIndex() const; - QModelIndex lastIndex() const; - void setCurrentIndex(const QModelIndex &index); - QVariant currentDebuggerId() const { return m_currentDebugger; } - DebuggerItem currentDebugger() const; - void addDebugger(const DebuggerItem &item); - void removeDebugger(const QVariant &id); - void updateDebugger(const DebuggerItem &item); - - void apply(); - -private slots: - void onDebuggerAdded(const QVariant &id); - void onDebuggerUpdate(const QVariant &id); - void onDebuggerRemoval(const QVariant &id); - -private: - QStandardItem *currentStandardItem() const; - QStandardItem *findStandardItemById(const QVariant &id) const; - QVariant headerData(int section, Qt::Orientation orientation, int role) const; - - bool addDebuggerStandardItem(const DebuggerItem &item, bool changed); - bool removeDebuggerStandardItem(const QVariant &id); - bool updateDebuggerStandardItem(const DebuggerItem &item, bool changed); - - DebuggerItem debuggerItem(QStandardItem *sitem) const; - QList<DebuggerItem> debuggerItems() const; - - QVariant m_currentDebugger; - - QStandardItem *m_autoRoot; - QStandardItem *m_manualRoot; - QStringList removed; - - QList<QVariant> m_removedItems; -}; - -} // namespace Internal -} // namespace Debugger - -#endif // DEBUGGER_DEBUGGERITEMMODEL_H diff --git a/src/plugins/debugger/debuggerkitconfigwidget.cpp b/src/plugins/debugger/debuggerkitconfigwidget.cpp index 40f7e18c2a..1812cb76e0 100644 --- a/src/plugins/debugger/debuggerkitconfigwidget.cpp +++ b/src/plugins/debugger/debuggerkitconfigwidget.cpp @@ -31,7 +31,6 @@ #include "debuggerkitconfigwidget.h" #include "debuggeritemmanager.h" -#include "debuggeritemmodel.h" #include "debuggerkitinformation.h" #include <coreplugin/icore.h> @@ -64,8 +63,6 @@ using namespace ProjectExplorer; namespace Debugger { namespace Internal { -class DebuggerItemConfigWidget; - // ----------------------------------------------------------------------- // DebuggerKitConfigWidget // ----------------------------------------------------------------------- @@ -88,14 +85,6 @@ DebuggerKitConfigWidget::DebuggerKitConfigWidget(Kit *workingCopy, const KitInfo m_manageButton->setContentsMargins(0, 0, 0, 0); connect(m_manageButton, &QAbstractButton::clicked, this, &DebuggerKitConfigWidget::manageDebuggers); - - DebuggerItemManager *manager = DebuggerItemManager::instance(); - connect(manager, &DebuggerItemManager::debuggerAdded, - this, &DebuggerKitConfigWidget::onDebuggerAdded); - connect(manager, &DebuggerItemManager::debuggerUpdated, - this, &DebuggerKitConfigWidget::onDebuggerUpdated); - connect(manager, &DebuggerItemManager::debuggerRemoved, - this, &DebuggerKitConfigWidget::onDebuggerRemoved); } DebuggerKitConfigWidget::~DebuggerKitConfigWidget() @@ -150,31 +139,6 @@ void DebuggerKitConfigWidget::currentDebuggerChanged(int) m_kit->setValue(DebuggerKitInformation::id(), id); } -void DebuggerKitConfigWidget::onDebuggerAdded(const QVariant &id) -{ - const DebuggerItem *item = DebuggerItemManager::findById(id); - QTC_ASSERT(item, return); - m_comboBox->addItem(item->displayName(), id); -} - -void DebuggerKitConfigWidget::onDebuggerUpdated(const QVariant &id) -{ - const DebuggerItem *item = DebuggerItemManager::findById(id); - QTC_ASSERT(item, return); - const int pos = indexOf(id); - if (pos < 0) - return; - m_comboBox->setItemText(pos, item->displayName()); -} - -void DebuggerKitConfigWidget::onDebuggerRemoved(const QVariant &id) -{ - if (const int pos = indexOf(id)) { - m_comboBox->removeItem(pos); - refresh(); - } -} - int DebuggerKitConfigWidget::indexOf(const QVariant &id) { QTC_ASSERT(id.isValid(), return -1); diff --git a/src/plugins/debugger/debuggerkitconfigwidget.h b/src/plugins/debugger/debuggerkitconfigwidget.h index fc5d569e84..cbe4e8b594 100644 --- a/src/plugins/debugger/debuggerkitconfigwidget.h +++ b/src/plugins/debugger/debuggerkitconfigwidget.h @@ -31,8 +31,6 @@ #ifndef DEBUGGER_DEBUGGERKITCONFIGWIDGET_H #define DEBUGGER_DEBUGGERKITCONFIGWIDGET_H -#include "debuggeritemmodel.h" - #include <coreplugin/dialogs/ioptionspage.h> #include <projectexplorer/kitconfigwidget.h> #include <projectexplorer/abi.h> @@ -72,14 +70,10 @@ public: QWidget *buttonWidget() const; QWidget *mainWidget() const; -private slots: +private: void manageDebuggers(); void currentDebuggerChanged(int idx); - void onDebuggerAdded(const QVariant &id); - void onDebuggerUpdated(const QVariant &id); - void onDebuggerRemoved(const QVariant &id); -private: int indexOf(const QVariant &id); QVariant currentId() const; void updateComboBox(const QVariant &id); diff --git a/src/plugins/debugger/debuggerkitinformation.cpp b/src/plugins/debugger/debuggerkitinformation.cpp index 06e24d80f3..f41f0edea2 100644 --- a/src/plugins/debugger/debuggerkitinformation.cpp +++ b/src/plugins/debugger/debuggerkitinformation.cpp @@ -306,13 +306,28 @@ void DebuggerKitInformation::addToMacroExpander(Kit *kit, MacroExpander *expande expander->registerVariable("Debugger:Type", tr("Type of Debugger Backend"), [this, kit]() -> QString { const DebuggerItem *item = debugger(kit); - return item ? item->engineTypeName() : tr("unknown"); + return item ? item->engineTypeName() : tr("Unknown debugger type"); }); - // FIXME: Use better strings. + expander->registerVariable("Debugger:Name", tr("Debugger"), [this, kit]() -> QString { const DebuggerItem *item = debugger(kit); - return item ? item->displayName() : tr("unknown"); + return item ? item->displayName() : tr("Unknown debugger"); + }); + + expander->registerVariable("Debugger:Version", tr("Debugger"), + [this, kit]() -> QString { + const DebuggerItem *item = debugger(kit); + return item && !item->version().isEmpty() + ? item->version() : tr("Unknown debugger version"); + }); + + expander->registerVariable("Debugger:Abi", tr("Debugger"), + [this, kit]() -> QString { + const DebuggerItem *item = debugger(kit); + return item && !item->abis().isEmpty() + ? item->abiNames().join(QLatin1Char(' ')) + : tr("Unknown debugger ABI"); }); } @@ -321,14 +336,14 @@ KitInformation::ItemList DebuggerKitInformation::toUserOutput(const Kit *k) cons return ItemList() << qMakePair(tr("Debugger"), displayString(k)); } -FileName DebuggerKitInformation::debuggerCommand(const ProjectExplorer::Kit *k) +FileName DebuggerKitInformation::debuggerCommand(const Kit *k) { const DebuggerItem *item = debugger(k); QTC_ASSERT(item, return FileName()); return item->command(); } -DebuggerEngineType DebuggerKitInformation::engineType(const ProjectExplorer::Kit *k) +DebuggerEngineType DebuggerKitInformation::engineType(const Kit *k) { const DebuggerItem *item = debugger(k); QTC_ASSERT(item, return NoEngineType); diff --git a/src/plugins/debugger/debuggermainwindow.cpp b/src/plugins/debugger/debuggermainwindow.cpp index 8f433d05fd..b2610ebf43 100644 --- a/src/plugins/debugger/debuggermainwindow.cpp +++ b/src/plugins/debugger/debuggermainwindow.cpp @@ -89,16 +89,16 @@ public: bool isQmlActive() const; void setSimpleDockWidgetArrangement(); // Debuggable languages are registered with this function. - void addLanguage(DebuggerLanguage language, const Core::Context &context); + void addLanguage(DebuggerLanguage language, const Context &context); QDockWidget *dockWidget(const QString &objectName) const { return q->findChild<QDockWidget *>(objectName); } public slots: void resetDebuggerLayout(); - void updateUiForProject(ProjectExplorer::Project *project); - void updateUiForTarget(ProjectExplorer::Target *target); - void updateUiForRunConfiguration(ProjectExplorer::RunConfiguration *rc); + void updateUiForProject(Project *project); + void updateUiForTarget(Target *target); + void updateUiForRunConfiguration(RunConfiguration *rc); void updateUiForCurrentRunConfiguration(); void updateActiveLanguages(); void updateDockWidgetSettings(); @@ -162,26 +162,24 @@ DebuggerMainWindowPrivate::DebuggerMainWindowPrivate(DebuggerMainWindow *mw) void DebuggerMainWindowPrivate::updateUiForProject(Project *project) { if (m_previousProject) { - disconnect(m_previousProject, - SIGNAL(activeTargetChanged(ProjectExplorer::Target*)), - this, SLOT(updateUiForTarget(ProjectExplorer::Target*))); + disconnect(m_previousProject, &Project::activeTargetChanged, + this, &DebuggerMainWindowPrivate::updateUiForTarget); } m_previousProject = project; if (!project) { updateUiForTarget(0); return; } - connect(project, SIGNAL(activeTargetChanged(ProjectExplorer::Target*)), - SLOT(updateUiForTarget(ProjectExplorer::Target*))); + connect(project, &Project::activeTargetChanged, + this, &DebuggerMainWindowPrivate::updateUiForTarget); updateUiForTarget(project->activeTarget()); } void DebuggerMainWindowPrivate::updateUiForTarget(Target *target) { if (m_previousTarget) { - disconnect(m_previousTarget, - SIGNAL(activeRunConfigurationChanged(ProjectExplorer::RunConfiguration*)), - this, SLOT(updateUiForRunConfiguration(ProjectExplorer::RunConfiguration*))); + disconnect(m_previousTarget, &Target::activeRunConfigurationChanged, + this, &DebuggerMainWindowPrivate::updateUiForRunConfiguration); } m_previousTarget = target; @@ -191,9 +189,8 @@ void DebuggerMainWindowPrivate::updateUiForTarget(Target *target) return; } - connect(target, - SIGNAL(activeRunConfigurationChanged(ProjectExplorer::RunConfiguration*)), - SLOT(updateUiForRunConfiguration(ProjectExplorer::RunConfiguration*))); + connect(target, &Target::activeRunConfigurationChanged, + this, &DebuggerMainWindowPrivate::updateUiForRunConfiguration); updateUiForRunConfiguration(target->activeRunConfiguration()); } @@ -201,16 +198,15 @@ void DebuggerMainWindowPrivate::updateUiForTarget(Target *target) void DebuggerMainWindowPrivate::updateUiForRunConfiguration(RunConfiguration *rc) { if (m_previousRunConfiguration) - disconnect(m_previousRunConfiguration->extraAspect<Debugger::DebuggerRunConfigurationAspect>(), - SIGNAL(requestRunActionsUpdate()), - this, SLOT(updateUiForCurrentRunConfiguration())); + disconnect(m_previousRunConfiguration, &RunConfiguration::requestRunActionsUpdate, + this, &DebuggerMainWindowPrivate::updateUiForCurrentRunConfiguration); m_previousRunConfiguration = rc; updateUiForCurrentRunConfiguration(); if (!rc) return; - connect(m_previousRunConfiguration->extraAspect<Debugger::DebuggerRunConfigurationAspect>(), - SIGNAL(requestRunActionsUpdate()), - SLOT(updateUiForCurrentRunConfiguration())); + + connect(m_previousRunConfiguration, &RunConfiguration::requestRunActionsUpdate, + this, &DebuggerMainWindowPrivate::updateUiForCurrentRunConfiguration); } void DebuggerMainWindowPrivate::updateUiForCurrentRunConfiguration() @@ -298,30 +294,30 @@ void DebuggerMainWindow::onModeChanged(IMode *mode) void DebuggerMainWindowPrivate::createViewsMenuItems() { Context debugcontext(Constants::C_DEBUGMODE); - m_viewsMenu = Core::ActionManager::actionContainer(Id(Core::Constants::M_WINDOW_VIEWS)); + m_viewsMenu = ActionManager::actionContainer(Id(Core::Constants::M_WINDOW_VIEWS)); QTC_ASSERT(m_viewsMenu, return); QAction *openMemoryEditorAction = new QAction(this); openMemoryEditorAction->setText(tr("Memory...")); - connect(openMemoryEditorAction, SIGNAL(triggered()), - SLOT(openMemoryEditor())); + connect(openMemoryEditorAction, &QAction::triggered, + this, &DebuggerMainWindowPrivate::openMemoryEditor); // Add menu items Command *cmd = 0; - cmd = Core::ActionManager::registerAction(openMemoryEditorAction, + cmd = ActionManager::registerAction(openMemoryEditorAction, "Debugger.Views.OpenMemoryEditor", debugcontext); cmd->setAttribute(Command::CA_Hide); m_viewsMenu->addAction(cmd, Core::Constants::G_DEFAULT_THREE); - cmd = Core::ActionManager::registerAction(q->menuSeparator1(), + cmd = ActionManager::registerAction(q->menuSeparator1(), "Debugger.Views.Separator1", debugcontext); cmd->setAttribute(Command::CA_Hide); m_viewsMenu->addAction(cmd, Core::Constants::G_DEFAULT_THREE); - cmd = Core::ActionManager::registerAction(q->autoHideTitleBarsAction(), + cmd = ActionManager::registerAction(q->autoHideTitleBarsAction(), "Debugger.Views.AutoHideTitleBars", debugcontext); cmd->setAttribute(Command::CA_Hide); m_viewsMenu->addAction(cmd, Core::Constants::G_DEFAULT_THREE); - cmd = Core::ActionManager::registerAction(q->menuSeparator2(), + cmd = ActionManager::registerAction(q->menuSeparator2(), "Debugger.Views.Separator2", debugcontext); cmd->setAttribute(Command::CA_Hide); m_viewsMenu->addAction(cmd, Core::Constants::G_DEFAULT_THREE); @@ -407,8 +403,8 @@ QDockWidget *DebuggerMainWindow::createDockWidget(const DebuggerLanguage &langua Context globalContext(Core::Constants::C_GLOBAL); QAction *toggleViewAction = dockWidget->toggleViewAction(); - Command *cmd = Core::ActionManager::registerAction(toggleViewAction, - Core::Id("Debugger.").withSuffix(widget->objectName()), globalContext); + Command *cmd = ActionManager::registerAction(toggleViewAction, + Id("Debugger.").withSuffix(widget->objectName()), globalContext); cmd->setAttribute(Command::CA_Hide); dockWidget->installEventFilter(&d->m_resizeEventFilter); @@ -430,10 +426,10 @@ void DebuggerMainWindow::addStagedMenuEntries() QWidget *DebuggerMainWindow::createContents(IMode *mode) { - connect(SessionManager::instance(), SIGNAL(startupProjectChanged(ProjectExplorer::Project*)), - d, SLOT(updateUiForProject(ProjectExplorer::Project*))); + connect(SessionManager::instance(), &SessionManager::startupProjectChanged, + d, &DebuggerMainWindowPrivate::updateUiForProject); - d->m_viewsMenu = Core::ActionManager::actionContainer(Core::Id(Core::Constants::M_WINDOW_VIEWS)); + d->m_viewsMenu = ActionManager::actionContainer(Id(Core::Constants::M_WINDOW_VIEWS)); QTC_ASSERT(d->m_viewsMenu, return 0); //d->m_mainWindow = new Internal::DebuggerMainWindow(this); @@ -444,17 +440,17 @@ QWidget *DebuggerMainWindow::createContents(IMode *mode) connect(autoHideTitleBarsAction(), SIGNAL(triggered()), d, SLOT(updateDockWidgetSettings())); - QBoxLayout *editorHolderLayout = new QVBoxLayout; + auto editorHolderLayout = new QVBoxLayout; editorHolderLayout->setMargin(0); editorHolderLayout->setSpacing(0); - QWidget *editorAndFindWidget = new QWidget; + auto editorAndFindWidget = new QWidget; editorAndFindWidget->setLayout(editorHolderLayout); auto editorManagerPlaceHolder = new EditorManagerPlaceHolder(mode); editorHolderLayout->addWidget(editorManagerPlaceHolder); editorHolderLayout->addWidget(new FindToolBarPlaceHolder(editorAndFindWidget)); - MiniSplitter *documentAndRightPane = new MiniSplitter; + auto documentAndRightPane = new MiniSplitter; documentAndRightPane->addWidget(editorAndFindWidget); documentAndRightPane->addWidget(new RightPanePlaceHolder(mode)); documentAndRightPane->setStretchFactor(0, 1); @@ -466,18 +462,18 @@ QWidget *DebuggerMainWindow::createContents(IMode *mode) hackyName.replace(QLatin1Char('&'), QString()); d->m_viewButton->setText(hackyName); - Utils::StyledBar *debugToolBar = new Utils::StyledBar; + auto debugToolBar = new Utils::StyledBar; debugToolBar->setProperty("topBorder", true); - QHBoxLayout *debugToolBarLayout = new QHBoxLayout(debugToolBar); + auto debugToolBarLayout = new QHBoxLayout(debugToolBar); debugToolBarLayout->setMargin(0); debugToolBarLayout->setSpacing(0); debugToolBarLayout->addWidget(d->m_debugToolBar); debugToolBarLayout->addWidget(new Utils::StyledSeparator); debugToolBarLayout->addWidget(d->m_viewButton); - connect(d->m_viewButton, SIGNAL(clicked()), this, SLOT(showViewsMenu())); + connect(d->m_viewButton, &QAbstractButton::clicked, this, &DebuggerMainWindow::showViewsMenu); - QDockWidget *dock = new QDockWidget(DebuggerMainWindowPrivate::tr("Debugger Toolbar")); + auto dock = new QDockWidget(DebuggerMainWindowPrivate::tr("Debugger Toolbar")); dock->setObjectName(QLatin1String("Debugger Toolbar")); dock->setWidget(debugToolBar); dock->setFeatures(QDockWidget::NoDockWidgetFeatures); @@ -487,10 +483,10 @@ QWidget *DebuggerMainWindow::createContents(IMode *mode) addDockWidget(Qt::BottomDockWidgetArea, dock); setToolBarDockWidget(dock); - QWidget *centralWidget = new QWidget; + auto centralWidget = new QWidget; setCentralWidget(centralWidget); - QVBoxLayout *centralLayout = new QVBoxLayout(centralWidget); + auto centralLayout = new QVBoxLayout(centralWidget); centralWidget->setLayout(centralLayout); centralLayout->setMargin(0); centralLayout->setSpacing(0); @@ -499,9 +495,9 @@ QWidget *DebuggerMainWindow::createContents(IMode *mode) centralLayout->setStretch(1, 0); // Right-side window with editor, output etc. - MiniSplitter *mainWindowSplitter = new MiniSplitter; + auto mainWindowSplitter = new MiniSplitter; mainWindowSplitter->addWidget(this); - QWidget *outputPane = new OutputPanePlaceHolder(mode, mainWindowSplitter); + auto outputPane = new OutputPanePlaceHolder(mode, mainWindowSplitter); outputPane->setObjectName(QLatin1String("DebuggerOutputPanePlaceHolder")); mainWindowSplitter->addWidget(outputPane); mainWindowSplitter->setStretchFactor(0, 10); @@ -509,7 +505,7 @@ QWidget *DebuggerMainWindow::createContents(IMode *mode) mainWindowSplitter->setOrientation(Qt::Vertical); // Navigation and right-side window. - MiniSplitter *splitter = new MiniSplitter; + auto splitter = new MiniSplitter; splitter->setFocusProxy(editorManagerPlaceHolder); splitter->addWidget(new NavigationWidgetPlaceHolder(mode)); splitter->addWidget(mainWindowSplitter); diff --git a/src/plugins/debugger/debuggermainwindow.h b/src/plugins/debugger/debuggermainwindow.h index 1dbf5f4712..c6a0e1118c 100644 --- a/src/plugins/debugger/debuggermainwindow.h +++ b/src/plugins/debugger/debuggermainwindow.h @@ -36,16 +36,11 @@ #include <utils/fancymainwindow.h> -namespace Core { -class Context; -class IMode; -} +namespace Core { class IMode; } namespace Debugger { - -class DebuggerEngine; - namespace Internal { + class DebuggerMainWindowPrivate; // DebuggerMainWindow dock widget names diff --git a/src/plugins/debugger/debuggeroptionspage.cpp b/src/plugins/debugger/debuggeroptionspage.cpp index d0b04a9b32..0484757ca8 100644 --- a/src/plugins/debugger/debuggeroptionspage.cpp +++ b/src/plugins/debugger/debuggeroptionspage.cpp @@ -29,15 +29,14 @@ ****************************************************************************/ #include "debuggeroptionspage.h" - #include "debuggeritemmanager.h" -#include "debuggeritemmodel.h" #include <projectexplorer/projectexplorerconstants.h> #include <utils/detailswidget.h> #include <utils/pathchooser.h> #include <utils/qtcassert.h> +#include <utils/treemodel.h> #include <utils/winutils.h> #include <QFileInfo> @@ -55,19 +54,176 @@ using namespace Utils; namespace Debugger { namespace Internal { -static const char debuggingToolsWikiLinkC[] = "http://qt-project.org/wiki/Qt_Creator_Windows_Debugging"; +const char debuggingToolsWikiLinkC[] = "http://qt-project.org/wiki/Qt_Creator_Windows_Debugging"; + +// -------------------------------------------------------------------------- +// DebuggerTreeItem +// -------------------------------------------------------------------------- + +class DebuggerTreeItem : public TreeItem +{ +public: + DebuggerTreeItem(const DebuggerItem &item, bool changed) : m_item(item), m_changed(changed) {} + + QVariant data(int column, int role) const + { + switch (role) { + case Qt::DisplayRole: + switch (column) { + case 0: return m_item.displayName(); + case 1: return m_item.command().toUserOutput(); + case 2: return m_item.engineTypeName(); + } + + case Qt::FontRole: { + QFont font; + font.setBold(m_changed); + return font; + } + } + return QVariant(); + } + + DebuggerItem m_item; + bool m_changed; +}; + +// -------------------------------------------------------------------------- +// DebuggerItemModel +// -------------------------------------------------------------------------- + +class DebuggerItemModel : public TreeModel +{ + Q_DECLARE_TR_FUNCTIONS(Debugger::DebuggerOptionsPage) + +public: + DebuggerItemModel(); + + QModelIndex lastIndex() const; + void setCurrentIndex(const QModelIndex &index); + DebuggerItem *currentDebugger() const; + void addDebugger(const DebuggerItem &item, bool changed); + void updateDebugger(const DebuggerItem &item); + void removeCurrentDebugger(); + void apply(); + +private: + DebuggerTreeItem *m_currentTreeItem; + QStringList removed; + + QList<QVariant> m_removedItems; +}; + +DebuggerItemModel::DebuggerItemModel() + : m_currentTreeItem(0) +{ + setHeader(QStringList() << tr("Name") << tr("Location") << tr("Type")); + rootItem()->appendChild(new TreeItem(QStringList() << tr("Auto-detected") << QString() << QString())); + rootItem()->appendChild(new TreeItem(QStringList() << tr("Manual") << QString() << QString())); + + foreach (const DebuggerItem &item, DebuggerItemManager::debuggers()) + addDebugger(item, false); +} + +void DebuggerItemModel::addDebugger(const DebuggerItem &item, bool changed) +{ + int group = item.isAutoDetected() ? 0 : 1; + rootItem()->child(group)->appendChild(new DebuggerTreeItem(item, changed)); +} + +void DebuggerItemModel::updateDebugger(const DebuggerItem &item) +{ + auto matcher = [item](DebuggerTreeItem *n) { return n->m_item.m_id == item.id(); }; + DebuggerTreeItem *treeItem = findItemAtLevel<DebuggerTreeItem *>(2, matcher); + QTC_ASSERT(treeItem, return); + + TreeItem *parent = treeItem->parent(); + QTC_ASSERT(parent, return); + + const DebuggerItem *orig = DebuggerItemManager::findById(item.id()); + treeItem->m_changed = !orig || *orig != item; + treeItem->m_item = item; + treeItem->update(); // Notify views. +} + +QModelIndex DebuggerItemModel::lastIndex() const +{ + TreeItem *manualGroup = rootItem()->lastChild(); + TreeItem *lastItem = manualGroup->lastChild(); + return lastItem ? indexFromItem(lastItem) : QModelIndex(); +} + +DebuggerItem *DebuggerItemModel::currentDebugger() const +{ + return m_currentTreeItem ? &m_currentTreeItem->m_item : 0; +} + +void DebuggerItemModel::removeCurrentDebugger() +{ + QTC_ASSERT(m_currentTreeItem, return); + QVariant id = m_currentTreeItem->m_item.id(); + DebuggerTreeItem *treeItem = m_currentTreeItem; + m_currentTreeItem = 0; + removeItem(treeItem); + delete treeItem; + m_removedItems.append(id); +} + +void DebuggerItemModel::apply() +{ + foreach (const QVariant &id, m_removedItems) + DebuggerItemManager::deregisterDebugger(id); + + foreach (auto item, treeLevelItems<DebuggerTreeItem *>(2)) { + item->m_changed = false; + DebuggerItemManager::updateOrAddDebugger(item->m_item); + } +} + +void DebuggerItemModel::setCurrentIndex(const QModelIndex &index) +{ + TreeItem *treeItem = itemFromIndex(index); + m_currentTreeItem = treeItem && treeItem->level() == 2 ? static_cast<DebuggerTreeItem *>(treeItem) : 0; +} // ----------------------------------------------------------------------- // DebuggerItemConfigWidget // ----------------------------------------------------------------------- -DebuggerItemConfigWidget::DebuggerItemConfigWidget(DebuggerItemModel *model) : - m_model(model) +class DebuggerItemConfigWidget : public QWidget +{ + Q_DECLARE_TR_FUNCTIONS(Debugger::DebuggerOptionsPage) + +public: + explicit DebuggerItemConfigWidget(DebuggerItemModel *model); + void load(const DebuggerItem *item); + void store() const; + +private: + void binaryPathHasChanged(); + DebuggerItem item() const; + void setAbis(const QStringList &abiNames); + + DebuggerItemModel *m_model; + QLineEdit *m_displayNameLineEdit; + QLineEdit *m_typeLineEdit; + QLabel *m_cdbLabel; + QLineEdit *m_versionLabel; + PathChooser *m_binaryChooser; + QLineEdit *m_abis; + bool m_autodetected; + DebuggerEngineType m_engineType; + QVariant m_id; +}; + +DebuggerItemConfigWidget::DebuggerItemConfigWidget(DebuggerItemModel *model) + : m_model(model) { - QTC_CHECK(model); - m_displayNameLineEdit = new QLineEdit(this); + m_typeLineEdit = new QLineEdit(this); + m_typeLineEdit->setEnabled(false); + m_binaryChooser = new PathChooser(this); m_binaryChooser->setExpectedKind(PathChooser::ExistingCommand); m_binaryChooser->setMinimumWidth(400); @@ -87,21 +243,21 @@ DebuggerItemConfigWidget::DebuggerItemConfigWidget(DebuggerItemModel *model) : QFormLayout *formLayout = new QFormLayout(this); formLayout->setFieldGrowthPolicy(QFormLayout::AllNonFixedFieldsGrow); formLayout->addRow(new QLabel(tr("Name:")), m_displayNameLineEdit); -// formLayout->addRow(new QLabel(tr("Type:")), m_engineTypeComboBox); formLayout->addRow(m_cdbLabel); formLayout->addRow(new QLabel(tr("Path:")), m_binaryChooser); + formLayout->addRow(new QLabel(tr("Type:")), m_typeLineEdit); formLayout->addRow(new QLabel(tr("ABIs:")), m_abis); formLayout->addRow(new QLabel(tr("Version:")), m_versionLabel); - connect(m_binaryChooser, SIGNAL(changed(QString)), this, SLOT(binaryPathHasChanged())); + connect(m_binaryChooser, &PathChooser::changed, + this, &DebuggerItemConfigWidget::binaryPathHasChanged); + connect(m_displayNameLineEdit, &QLineEdit::textChanged, + this, &DebuggerItemConfigWidget::store); } DebuggerItem DebuggerItemConfigWidget::item() const { DebuggerItem item(m_id); - if (m_id.isNull()) - return item; - item.setDisplayName(m_displayNameLineEdit->text()); item.setCommand(m_binaryChooser->fileName()); item.setAutoDetected(m_autodetected); @@ -117,12 +273,10 @@ DebuggerItem DebuggerItemConfigWidget::item() const return item; } - void DebuggerItemConfigWidget::store() const { - DebuggerItem i = item(); - if (i.isValid()) - m_model->updateDebugger(i); + if (!m_id.isNull()) + m_model->updateDebugger(item()); } void DebuggerItemConfigWidget::setAbis(const QStringList &abiNames) @@ -130,50 +284,26 @@ void DebuggerItemConfigWidget::setAbis(const QStringList &abiNames) m_abis->setText(abiNames.join(QLatin1String(", "))); } -void DebuggerItemConfigWidget::handleCommandChange() +void DebuggerItemConfigWidget::load(const DebuggerItem *item) { - // Use DebuggerItemManager as a cache: - const DebuggerItem *existing - = DebuggerItemManager::findByCommand(m_binaryChooser->fileName()); - if (existing) { - setAbis(existing->abiNames()); - m_versionLabel->setText(existing->version()); - m_engineType = existing->engineType(); - } else { - QFileInfo fi = QFileInfo(m_binaryChooser->path()); - if (fi.isExecutable()) { - DebuggerItem tmp = item(); - tmp.reinitializeFromFile(); - setAbis(tmp.abiNames()); - m_versionLabel->setText(tmp.version()); - m_engineType = tmp.engineType(); - } else { - setAbis(QStringList()); - m_versionLabel->setText(QString()); - m_engineType = NoEngineType; - } - } - m_model->updateDebugger(item()); -} - -void DebuggerItemConfigWidget::setItem(const DebuggerItem &item) -{ - store(); // store away the (changed) settings for future use - m_id = QVariant(); // reset Id to avoid intermediate signal handling + if (!item) + return; // Set values: - m_autodetected = item.isAutoDetected(); + m_autodetected = item->isAutoDetected(); - m_displayNameLineEdit->setEnabled(!item.isAutoDetected()); - m_displayNameLineEdit->setText(item.displayName()); + m_displayNameLineEdit->setEnabled(!item->isAutoDetected()); + m_displayNameLineEdit->setText(item->displayName()); - m_binaryChooser->setReadOnly(item.isAutoDetected()); - m_binaryChooser->setFileName(item.command()); + m_typeLineEdit->setText(item->engineTypeName()); + + m_binaryChooser->setReadOnly(item->isAutoDetected()); + m_binaryChooser->setFileName(item->command()); QString text; QString versionCommand; - if (item.engineType() == CdbEngineType) { + if (item->engineType() == CdbEngineType) { const bool is64bit = is64BitWindowsSystem(); const QString versionString = is64bit ? tr("64-bit version") : tr("32-bit version"); //: Label text for path configuration. %2 is "x-bit version". @@ -189,20 +319,10 @@ void DebuggerItemConfigWidget::setItem(const DebuggerItem &item) m_cdbLabel->setText(text); m_cdbLabel->setVisible(!text.isEmpty()); m_binaryChooser->setCommandVersionArguments(QStringList(versionCommand)); - m_versionLabel->setText(item.version()); - setAbis(item.abiNames()); - m_engineType = item.engineType(); - m_id = item.id(); -} - -void DebuggerItemConfigWidget::apply() -{ - DebuggerItem current = m_model->currentDebugger(); - if (!current.isValid()) - return; // Nothing was selected here. - - store(); - setItem(item()); + m_versionLabel->setText(item->version()); + setAbis(item->abiNames()); + m_engineType = item->engineType(); + m_id = item->id(); } void DebuggerItemConfigWidget::binaryPathHasChanged() @@ -211,58 +331,57 @@ void DebuggerItemConfigWidget::binaryPathHasChanged() if (!m_id.isValid()) return; - handleCommandChange(); + DebuggerItem tmp; + QFileInfo fi = QFileInfo(m_binaryChooser->path()); + if (fi.isExecutable()) { + tmp = item(); + tmp.reinitializeFromFile(); + } + + setAbis(tmp.abiNames()); + m_versionLabel->setText(tmp.version()); + m_engineType = tmp.engineType(); + m_typeLineEdit->setText(tmp.engineTypeName()); + + store(); } // -------------------------------------------------------------------------- -// DebuggerOptionsPage +// DebuggerConfigWidget // -------------------------------------------------------------------------- -DebuggerOptionsPage::DebuggerOptionsPage() +class DebuggerConfigWidget : public QWidget { - m_model = 0; - m_debuggerView = 0; - m_container = 0; - m_addButton = 0; - m_cloneButton = 0; - m_delButton = 0; +public: + DebuggerConfigWidget() + { + m_addButton = new QPushButton(tr("Add"), this); - setId(ProjectExplorer::Constants::DEBUGGER_SETTINGS_PAGE_ID); - setDisplayName(tr("Debuggers")); - setCategory(ProjectExplorer::Constants::PROJECTEXPLORER_SETTINGS_CATEGORY); - setDisplayCategory(QCoreApplication::translate("ProjectExplorer", - ProjectExplorer::Constants::PROJECTEXPLORER_SETTINGS_TR_CATEGORY)); - setCategoryIcon(QLatin1String(ProjectExplorer::Constants::PROJECTEXPLORER_SETTINGS_CATEGORY_ICON)); -} - -QWidget *DebuggerOptionsPage::widget() -{ - if (!m_configWidget) { - m_configWidget = new QWidget; + m_cloneButton = new QPushButton(tr("Clone"), this); + m_cloneButton->setEnabled(false); - m_addButton = new QPushButton(tr("Add"), m_configWidget); - m_cloneButton = new QPushButton(tr("Clone"), m_configWidget); - m_delButton = new QPushButton(tr("Remove"), m_configWidget); + m_delButton = new QPushButton(tr("Remove"), this); + m_delButton->setEnabled(false); - m_container = new DetailsWidget(m_configWidget); + m_container = new DetailsWidget(this); m_container->setState(DetailsWidget::NoSummary); m_container->setVisible(false); - m_debuggerView = new QTreeView(m_configWidget); - m_model = new DebuggerItemModel(m_debuggerView); - m_debuggerView->setModel(m_model); + m_debuggerView = new QTreeView(this); + m_debuggerView->setModel(&m_model); m_debuggerView->setUniformRowHeights(true); + m_debuggerView->setRootIsDecorated(false); m_debuggerView->setSelectionMode(QAbstractItemView::SingleSelection); m_debuggerView->setSelectionBehavior(QAbstractItemView::SelectRows); m_debuggerView->expandAll(); - QHeaderView *header = m_debuggerView->header(); + auto header = m_debuggerView->header(); header->setStretchLastSection(false); header->setSectionResizeMode(0, QHeaderView::ResizeToContents); header->setSectionResizeMode(1, QHeaderView::ResizeToContents); header->setSectionResizeMode(2, QHeaderView::Stretch); - QVBoxLayout *buttonLayout = new QVBoxLayout(); + auto buttonLayout = new QVBoxLayout(); buttonLayout->setSpacing(6); buttonLayout->setContentsMargins(0, 0, 0, 0); buttonLayout->addWidget(m_addButton); @@ -270,54 +389,62 @@ QWidget *DebuggerOptionsPage::widget() buttonLayout->addWidget(m_delButton); buttonLayout->addItem(new QSpacerItem(10, 40, QSizePolicy::Minimum, QSizePolicy::Expanding)); - QVBoxLayout *verticalLayout = new QVBoxLayout(); + auto verticalLayout = new QVBoxLayout(); verticalLayout->addWidget(m_debuggerView); verticalLayout->addWidget(m_container); - QHBoxLayout *horizontalLayout = new QHBoxLayout(m_configWidget); + auto horizontalLayout = new QHBoxLayout(this); horizontalLayout->addLayout(verticalLayout); horizontalLayout->addLayout(buttonLayout); - connect(m_debuggerView->selectionModel(), SIGNAL(selectionChanged(QItemSelection,QItemSelection)), - this, SLOT(debuggerSelectionChanged())); + connect(m_debuggerView->selectionModel(), &QItemSelectionModel::currentChanged, + this, &DebuggerConfigWidget::currentDebuggerChanged, Qt::QueuedConnection); - connect(m_addButton, SIGNAL(clicked()), this, SLOT(addDebugger()), Qt::QueuedConnection); - connect(m_cloneButton, SIGNAL(clicked()), this, SLOT(cloneDebugger()), Qt::QueuedConnection); - connect(m_delButton, SIGNAL(clicked()), this, SLOT(removeDebugger()), Qt::QueuedConnection); + connect(m_addButton, &QAbstractButton::clicked, + this, &DebuggerConfigWidget::addDebugger, Qt::QueuedConnection); + connect(m_cloneButton, &QAbstractButton::clicked, + this, &DebuggerConfigWidget::cloneDebugger, Qt::QueuedConnection); + connect(m_delButton, &QAbstractButton::clicked, + this, &DebuggerConfigWidget::removeDebugger, Qt::QueuedConnection); - m_itemConfigWidget = new DebuggerItemConfigWidget(m_model); + m_itemConfigWidget = new DebuggerItemConfigWidget(&m_model); m_container->setWidget(m_itemConfigWidget); - - updateState(); } - return m_configWidget; -} -void DebuggerOptionsPage::apply() + void cloneDebugger(); + void addDebugger(); + void removeDebugger(); + void currentDebuggerChanged(const QModelIndex &newCurrent); + void updateState(); + + DebuggerItemModel m_model; + QTreeView *m_debuggerView; + QPushButton *m_addButton; + QPushButton *m_cloneButton; + QPushButton *m_delButton; + DetailsWidget *m_container; + DebuggerItemConfigWidget *m_itemConfigWidget; +}; + +void DebuggerConfigWidget::cloneDebugger() { - m_itemConfigWidget->apply(); - m_model->apply(); -} - -void DebuggerOptionsPage::cloneDebugger() -{ - DebuggerItem item = m_model->currentDebugger(); - if (!item.isValid()) + DebuggerItem *item = m_model.currentDebugger(); + if (!item) return; DebuggerItem newItem; newItem.createId(); newItem.setAutoDetected(false); - newItem.setCommand(item.command()); - newItem.setEngineType(item.engineType()); - newItem.setAbis(item.abis()); - newItem.setDisplayName(DebuggerItemManager::uniqueDisplayName(tr("Clone of %1").arg(item.displayName()))); + newItem.setCommand(item->command()); + newItem.setEngineType(item->engineType()); + newItem.setAbis(item->abis()); + newItem.setDisplayName(DebuggerItemManager::uniqueDisplayName(tr("Clone of %1").arg(item->displayName()))); newItem.setAutoDetected(false); - m_model->addDebugger(newItem); - m_debuggerView->setCurrentIndex(m_model->lastIndex()); + m_model.addDebugger(newItem, true); + m_debuggerView->setCurrentIndex(m_model.lastIndex()); } -void DebuggerOptionsPage::addDebugger() +void DebuggerConfigWidget::addDebugger() { DebuggerItem item; item.createId(); @@ -325,72 +452,60 @@ void DebuggerOptionsPage::addDebugger() item.setEngineType(NoEngineType); item.setDisplayName(DebuggerItemManager::uniqueDisplayName(tr("New Debugger"))); item.setAutoDetected(false); - m_model->addDebugger(item); - m_debuggerView->setCurrentIndex(m_model->lastIndex()); + m_model.addDebugger(item, true); + m_debuggerView->setCurrentIndex(m_model.lastIndex()); } -void DebuggerOptionsPage::removeDebugger() +void DebuggerConfigWidget::removeDebugger() { - QVariant id = m_model->currentDebuggerId(); - m_model->removeDebugger(id); - m_debuggerView->setCurrentIndex(m_model->lastIndex()); + m_model.removeCurrentDebugger(); + m_debuggerView->setCurrentIndex(m_model.lastIndex()); } -void DebuggerOptionsPage::finish() +void DebuggerConfigWidget::currentDebuggerChanged(const QModelIndex &newCurrent) { - delete m_configWidget; - - // Children of m_configWidget. - m_model = 0; - m_container = 0; - m_debuggerView = 0; - m_addButton = 0; - m_cloneButton = 0; - m_delButton = 0; -} + m_model.setCurrentIndex(newCurrent); -void DebuggerOptionsPage::debuggerSelectionChanged() -{ - QTC_ASSERT(m_container, return); + DebuggerItem *item = m_model.currentDebugger(); - QModelIndex mi = m_debuggerView->currentIndex(); - mi = mi.sibling(mi.row(), 0); - m_model->setCurrentIndex(mi); + m_itemConfigWidget->load(item); + m_container->setVisible(item); + m_cloneButton->setEnabled(item && item->isValid() && item->canClone()); + m_delButton->setEnabled(item && !item->isAutoDetected()); +} - DebuggerItem item = m_model->currentDebugger(); +// -------------------------------------------------------------------------- +// DebuggerOptionsPage +// -------------------------------------------------------------------------- - m_itemConfigWidget->setItem(item); - m_container->setVisible(item.isValid()); - updateState(); +DebuggerOptionsPage::DebuggerOptionsPage() +{ + setId(ProjectExplorer::Constants::DEBUGGER_SETTINGS_PAGE_ID); + setDisplayName(tr("Debuggers")); + setCategory(ProjectExplorer::Constants::PROJECTEXPLORER_SETTINGS_CATEGORY); + setDisplayCategory(QCoreApplication::translate("ProjectExplorer", + ProjectExplorer::Constants::PROJECTEXPLORER_SETTINGS_TR_CATEGORY)); + setCategoryIcon(QLatin1String(ProjectExplorer::Constants::PROJECTEXPLORER_SETTINGS_CATEGORY_ICON)); } -void DebuggerOptionsPage::debuggerModelChanged() +QWidget *DebuggerOptionsPage::widget() { - QTC_ASSERT(m_container, return); - - QVariant id = m_model->currentDebuggerId(); - const DebuggerItem *item = DebuggerItemManager::findById(id); - if (!item) - return; - - m_itemConfigWidget->setItem(*item); - m_container->setVisible(m_model->currentDebuggerId().isValid()); - m_debuggerView->setCurrentIndex(m_model->currentIndex()); - updateState(); + if (!m_configWidget) + m_configWidget = new DebuggerConfigWidget; + return m_configWidget; } -void DebuggerOptionsPage::updateState() +void DebuggerOptionsPage::apply() { - if (!m_cloneButton) - return; - - DebuggerItem item = m_model->currentDebugger(); - - bool canCopy = item.isValid() && item.canClone(); - bool canDelete = m_model->currentIndex().parent().isValid() && !item.isAutoDetected(); + QTC_ASSERT(m_configWidget, return); + m_configWidget->m_itemConfigWidget->store(); + m_configWidget->m_model.apply(); +} - m_cloneButton->setEnabled(canCopy); - m_delButton->setEnabled(canDelete); +void DebuggerOptionsPage::finish() +{ + delete m_configWidget; + m_configWidget = 0; } } // namespace Internal diff --git a/src/plugins/debugger/debuggeroptionspage.h b/src/plugins/debugger/debuggeroptionspage.h index df9b169853..5db065b49c 100644 --- a/src/plugins/debugger/debuggeroptionspage.h +++ b/src/plugins/debugger/debuggeroptionspage.h @@ -31,73 +31,19 @@ #ifndef DEBUGGER_DEBUGGEROPTIONSPAGE_H #define DEBUGGER_DEBUGGEROPTIONSPAGE_H -#include "debuggeritem.h" - #include <coreplugin/dialogs/ioptionspage.h> +#include <QCoreApplication> #include <QPointer> -#include <QWidget> - -QT_BEGIN_NAMESPACE -class QLabel; -class QLineEdit; -class QPushButton; -class QTreeView; -QT_END_NAMESPACE - -namespace Utils { -class DetailsWidget; -class PathChooser; -} // namespace Utils namespace Debugger { namespace Internal { -class DebuggerItemModel; -class DebuggerItemConfigWidget; -class DebuggerKitConfigWidget; - -// ----------------------------------------------------------------------- -// DebuggerItemConfigWidget -// ----------------------------------------------------------------------- - -class DebuggerItemConfigWidget : public QWidget -{ - Q_OBJECT - -public: - explicit DebuggerItemConfigWidget(DebuggerItemModel *model); - void setItem(const DebuggerItem &item); - void apply(); - -private slots: - void binaryPathHasChanged(); - -private: - DebuggerItem item() const; - void store() const; - void setAbis(const QStringList &abiNames); - - void handleCommandChange(); - - QLineEdit *m_displayNameLineEdit; - QLabel *m_cdbLabel; - QLineEdit *m_versionLabel; - Utils::PathChooser *m_binaryChooser; - QLineEdit *m_abis; - DebuggerItemModel *m_model; - bool m_autodetected; - DebuggerEngineType m_engineType; - QVariant m_id; -}; - -// -------------------------------------------------------------------------- -// DebuggerOptionsPage -// -------------------------------------------------------------------------- +class DebuggerConfigWidget; class DebuggerOptionsPage : public Core::IOptionsPage { - Q_OBJECT + Q_DECLARE_TR_FUNCTIONS(Debugger::DebuggerOptionsPage) public: DebuggerOptionsPage(); @@ -106,24 +52,8 @@ public: void apply(); void finish(); -private slots: - void debuggerSelectionChanged(); - void debuggerModelChanged(); - void updateState(); - void cloneDebugger(); - void addDebugger(); - void removeDebugger(); - private: - QPointer<QWidget> m_configWidget; - - DebuggerItemModel *m_model; - DebuggerItemConfigWidget *m_itemConfigWidget; - QTreeView *m_debuggerView; - Utils::DetailsWidget *m_container; - QPushButton *m_addButton; - QPushButton *m_cloneButton; - QPushButton *m_delButton; + QPointer<DebuggerConfigWidget> m_configWidget; }; } // namespace Internal diff --git a/src/plugins/debugger/debuggerplugin.cpp b/src/plugins/debugger/debuggerplugin.cpp index aaddbd5e9d..6ab869034c 100644 --- a/src/plugins/debugger/debuggerplugin.cpp +++ b/src/plugins/debugger/debuggerplugin.cpp @@ -78,6 +78,7 @@ #include <coreplugin/imode.h> #include <coreplugin/coreconstants.h> #include <coreplugin/icore.h> +#include <coreplugin/messagebox.h> #include <coreplugin/messagemanager.h> #include <coreplugin/modemanager.h> @@ -93,6 +94,7 @@ #include <projectexplorer/devicesupport/deviceprocesslist.h> #include <projectexplorer/devicesupport/deviceprocessesdialog.h> #include <projectexplorer/projectexplorer.h> +#include <projectexplorer/projecttree.h> #include <projectexplorer/projectexplorersettings.h> #include <projectexplorer/project.h> #include <projectexplorer/session.h> @@ -387,19 +389,6 @@ namespace PE = ProjectExplorer::Constants; namespace Debugger { namespace Internal { -// To be passed through margin menu action's data -struct BreakpointMenuContextData : public ContextData -{ - enum Mode - { - Breakpoint, - MessageTracePoint - }; - - BreakpointMenuContextData() : mode(Breakpoint) {} - Mode mode; -}; - struct TestCallBack { TestCallBack() : receiver(0), slot(0) {} @@ -414,27 +403,13 @@ struct TestCallBack } // namespace Internal } // namespace Debugger -Q_DECLARE_METATYPE(Debugger::Internal::BreakpointMenuContextData) Q_DECLARE_METATYPE(Debugger::Internal::TestCallBack) - namespace Debugger { namespace Internal { -// FIXME: Outdated? -// The createCdbEngine function takes a list of options pages it can add to. -// This allows for having a "enabled" toggle on the page independently -// of the engine. That's good for not enabling the related ActiveX control -// unnecessarily. - void addCdbOptionPages(QList<IOptionsPage*> *opts); void addGdbOptionPages(QList<IOptionsPage*> *opts); -void addScriptOptionPages(QList<IOptionsPage*> *opts); -void addTcfOptionPages(QList<IOptionsPage*> *opts); - -#ifdef WITH_LLDB -void addLldbOptionPages(QList<IOptionsPage*> *opts); -#endif static QToolButton *toolButton(QAction *action) { @@ -443,12 +418,12 @@ static QToolButton *toolButton(QAction *action) return button; } -static void setProxyAction(ProxyAction *proxy, Core::Id id) +static void setProxyAction(ProxyAction *proxy, Id id) { proxy->setAction(ActionManager::command(id)->action()); } -static QToolButton *toolButton(Core::Id id) +static QToolButton *toolButton(Id id) { return toolButton(ActionManager::command(id)->action()); } @@ -461,8 +436,6 @@ static QToolButton *toolButton(Core::Id id) class DummyEngine : public DebuggerEngine { - Q_OBJECT - public: DummyEngine() : DebuggerEngine(DebuggerStartParameters()) {} ~DummyEngine() {} @@ -473,7 +446,7 @@ public: void shutdownEngine() {} void shutdownInferior() {} bool hasCapability(unsigned cap) const; - bool acceptsBreakpoint(BreakpointModelId) const { return false; } + bool acceptsBreakpoint(Breakpoint) const { return false; } bool acceptsDebuggerCommands() const { return false; } void selectThread(ThreadId) {} }; @@ -481,7 +454,7 @@ public: bool DummyEngine::hasCapability(unsigned cap) const { // This can only be a first approximation of what to expect when running. - Project *project = ProjectExplorerPlugin::currentProject(); + Project *project = ProjectTree::currentProject(); if (!project) return 0; Target *target = project->activeTarget(); @@ -494,6 +467,7 @@ bool DummyEngine::hasCapability(unsigned cap) const return cap & (WatchpointByAddressCapability | BreakConditionCapability | TracePointCapability + | OperateNativeMixed | OperateByInstructionCapability); // This is a Qml or unknown engine. @@ -578,7 +552,7 @@ static bool currentTextEditorPosition(ContextData *data) return false; const TextDocument *document = textEditor->textDocument(); QTC_ASSERT(document, return false); - data->fileName = document->filePath(); + data->fileName = document->filePath().toString(); if (document->property(Constants::OPENED_WITH_DISASSEMBLY).toBool()) { int lineNumber = textEditor->currentLine(); QString line = textEditor->textDocument()->plainText() @@ -639,7 +613,6 @@ public: } DebuggerRunControl *attachToRunningProcess(Kit *kit, DeviceProcessItem process); -public slots: void writeSettings() { m_debuggerSettings->writeSettings(); @@ -652,20 +625,16 @@ public slots: m_currentEngine->selectThread(id); } - void breakpointSetMarginActionTriggered() + void breakpointSetMarginActionTriggered(bool isMessageOnly, const ContextData &data) { - const QAction *action = qobject_cast<const QAction *>(sender()); - QTC_ASSERT(action, return); - const BreakpointMenuContextData data = - action->data().value<BreakpointMenuContextData>(); QString message; - if (data.mode == BreakpointMenuContextData::MessageTracePoint) { + if (isMessageOnly) { if (data.address) { //: Message tracepoint: Address hit. message = tr("0x%1 hit").arg(data.address, 0, 16); } else { //: Message tracepoint: %1 file, %2 line %3 function hit. - message = tr("%1:%2 %3() hit").arg(QFileInfo(data.fileName).fileName()). + message = tr("%1:%2 %3() hit").arg(FileName::fromString(data.fileName).fileName()). arg(data.lineNumber). arg(cppFunctionAt(data.fileName, data.lineNumber)); } @@ -686,30 +655,6 @@ public slots: toggleBreakpointByFileAndLine(data.fileName, data.lineNumber, message); } - void breakpointRemoveMarginActionTriggered() - { - const QAction *act = qobject_cast<QAction *>(sender()); - QTC_ASSERT(act, return); - BreakpointModelId id = act->data().value<BreakpointModelId>(); - m_breakHandler->removeBreakpoint(id); - } - - void breakpointEnableMarginActionTriggered() - { - const QAction *act = qobject_cast<QAction *>(sender()); - QTC_ASSERT(act, return); - BreakpointModelId id = act->data().value<BreakpointModelId>(); - breakHandler()->setEnabled(id, true); - } - - void breakpointDisableMarginActionTriggered() - { - const QAction *act = qobject_cast<QAction *>(sender()); - QTC_ASSERT(act, return); - BreakpointModelId id = act->data().value<BreakpointModelId>(); - breakHandler()->setEnabled(id, false); - } - void updateWatchersHeader(int section, int, int newSize) { m_watchersView->header()->resizeSection(section, newSize); @@ -743,12 +688,12 @@ public slots: } } - void editorOpened(Core::IEditor *editor); - void updateBreakMenuItem(Core::IEditor *editor); + void editorOpened(IEditor *editor); + void updateBreakMenuItem(IEditor *editor); void setBusyCursor(bool busy); - void requestMark(TextEditor::TextEditorWidget *widget, int lineNumber, - TextEditor::TextMarkRequestKind kind); - void requestContextMenu(TextEditor::TextEditorWidget *widget, + void requestMark(TextEditorWidget *widget, int lineNumber, + TextMarkRequestKind kind); + void requestContextMenu(TextEditorWidget *widget, int lineNumber, QMenu *menu); void activatePreviousMode(); @@ -758,7 +703,7 @@ public slots: const QString &tracePointMessage = QString()); void toggleBreakpointByAddress(quint64 address, const QString &tracePointMessage = QString()); - void onModeChanged(Core::IMode *mode); + void onModeChanged(IMode *mode); void onCoreAboutToOpen(); void showSettingsDialog(); void updateDebugWithoutDeployMenu(); @@ -776,7 +721,7 @@ public slots: void attachToFoundProcess(); void continueOnAttach(Debugger::DebuggerState state); void attachToQmlPort(); - void runScheduled(); + Q_SLOT void runScheduled(); void attachCore(); void enableReverseDebuggingTriggered(const QVariant &value); @@ -800,11 +745,11 @@ public slots: void cleanupViews(); void setInitialState(); - void fontSettingsChanged(const TextEditor::FontSettings &settings); + void fontSettingsChanged(const FontSettings &settings); void updateState(DebuggerEngine *engine); void updateWatchersWindow(bool showWatch, bool showReturn); - void onCurrentProjectChanged(ProjectExplorer::Project *project); + void onCurrentProjectChanged(Project *project); void sessionLoaded(); void aboutToUnloadSession(); @@ -815,7 +760,7 @@ public slots: #ifdef WITH_TESTS public slots: void testLoadProject(const QString &proFile, const TestCallBack &cb); - void testProjectLoaded(ProjectExplorer::Project *project); + void testProjectLoaded(Project *project); void testProjectEvaluated(); void testProjectBuilt(bool success); void testUnloadProject(); @@ -957,31 +902,6 @@ public slots: } } - void slotEditBreakpoint() - { - const QAction *act = qobject_cast<QAction *>(sender()); - QTC_ASSERT(act, return); - const BreakpointModelId id = act->data().value<BreakpointModelId>(); - QTC_ASSERT(id > 0, return); - BreakTreeView::editBreakpoint(id, ICore::dialogParent()); - } - - void slotRunToLine() - { - const QAction *action = qobject_cast<const QAction *>(sender()); - QTC_ASSERT(action, return); - const BreakpointMenuContextData data = action->data().value<BreakpointMenuContextData>(); - currentEngine()->executeRunToLine(data); - } - - void slotJumpToLine() - { - const QAction *action = qobject_cast<const QAction *>(sender()); - QTC_ASSERT(action, return); - const BreakpointMenuContextData data = action->data().value<BreakpointMenuContextData>(); - currentEngine()->executeJumpToLine(data); - } - void slotDisassembleFunction() { const QAction *action = qobject_cast<const QAction *>(sender()); @@ -1356,9 +1276,9 @@ bool DebuggerPluginPrivate::initialize(const QStringList &arguments, // Cpp/Qml ui setup m_mainWindow = new DebuggerMainWindow; - TaskHub::addCategory(Debugger::Constants::TASK_CATEGORY_DEBUGGER_DEBUGINFO, + TaskHub::addCategory(TASK_CATEGORY_DEBUGGER_DEBUGINFO, tr("Debug Information")); - TaskHub::addCategory(Debugger::Constants::TASK_CATEGORY_DEBUGGER_RUNTIME, + TaskHub::addCategory(TASK_CATEGORY_DEBUGGER_RUNTIME, tr("Debugger Runtime")); return true; @@ -1410,7 +1330,7 @@ void DebuggerPluginPrivate::onCurrentProjectChanged(Project *project) m_startAction->setEnabled(canRun); m_startAction->setToolTip(whyNot); m_debugWithoutDeployAction->setEnabled(canRun); - setProxyAction(m_visibleStartAction, Core::Id(Constants::DEBUG)); + setProxyAction(m_visibleStartAction, Id(Constants::DEBUG)); } void DebuggerPluginPrivate::debugProject() @@ -1521,7 +1441,7 @@ void DebuggerPluginPrivate::attachToProcess(bool startServerOnly) DebuggerKitChooser::RemoteDebugging : DebuggerKitChooser::LocalDebugging; DebuggerKitChooser *kitChooser = new DebuggerKitChooser(mode); DeviceProcessesDialog *dlg = new DeviceProcessesDialog(kitChooser, ICore::dialogParent()); - dlg->addAcceptButton(ProjectExplorer::DeviceProcessesDialog::tr("&Attach to Process")); + dlg->addAcceptButton(DeviceProcessesDialog::tr("&Attach to Process")); dlg->showAllDevices(); if (dlg->exec() == QDialog::Rejected) { delete dlg; @@ -1588,8 +1508,8 @@ DebuggerRunControl *DebuggerPluginPrivate::attachToRunningProcess(Kit *kit, IDevice::ConstPtr device = DeviceKitInformation::device(kit); QTC_ASSERT(device, return 0); if (process.pid == 0) { - QMessageBox::warning(ICore::dialogParent(), tr("Warning"), - tr("Cannot attach to process with PID 0")); + AsynchronousMessageBox::warning(tr("Warning"), + tr("Cannot attach to process with PID 0")); return 0; } @@ -1597,14 +1517,14 @@ DebuggerRunControl *DebuggerPluginPrivate::attachToRunningProcess(Kit *kit, if (const ToolChain *tc = ToolChainKitInformation::toolChain(kit)) isWindows = tc->targetAbi().os() == Abi::WindowsOS; if (isWindows && isWinProcessBeingDebugged(process.pid)) { - QMessageBox::warning(ICore::mainWindow(), tr("Process Already Under Debugger Control"), + AsynchronousMessageBox::warning(tr("Process Already Under Debugger Control"), tr("The process %1 is already under the control of a debugger.\n" "Qt Creator cannot attach to it.").arg(process.pid)); return 0; } if (device->type() != PE::DESKTOP_DEVICE_TYPE) { - QMessageBox::warning(ICore::mainWindow(), tr("Not a Desktop Device Type"), + AsynchronousMessageBox::warning(tr("Not a Desktop Device Type"), tr("It is only possible to attach to a locally running process.")); return 0; } @@ -1727,13 +1647,13 @@ void DebuggerPluginPrivate::updateBreakMenuItem(IEditor *editor) void DebuggerPluginPrivate::requestContextMenu(TextEditorWidget *widget, int lineNumber, QMenu *menu) { - BreakpointMenuContextData args; + ContextData args; args.lineNumber = lineNumber; bool contextUsable = true; - BreakpointModelId id = BreakpointModelId(); + Breakpoint bp; TextDocument *document = widget->textDocument(); - args.fileName = document->filePath(); + args.fileName = document->filePath().toString(); if (document->property(Constants::OPENED_WITH_DISASSEMBLY).toBool()) { QString line = document->plainText() .section(QLatin1Char('\n'), lineNumber - 1, lineNumber - 1); @@ -1742,87 +1662,77 @@ void DebuggerPluginPrivate::requestContextMenu(TextEditorWidget *widget, needle.address = DisassemblerLine::addressFromDisassemblyLine(line); args.address = needle.address; needle.lineNumber = -1; - id = breakHandler()->findSimilarBreakpoint(needle); + bp = breakHandler()->findSimilarBreakpoint(needle); contextUsable = args.address != 0; } else { - id = breakHandler() + bp = breakHandler() ->findBreakpointByFileAndLine(args.fileName, lineNumber); - if (!id) - id = breakHandler()->findBreakpointByFileAndLine(args.fileName, lineNumber, false); + if (!bp) + bp = breakHandler()->findBreakpointByFileAndLine(args.fileName, lineNumber, false); } - if (id) { + if (bp) { + QString id = bp.id().toString(); + // Remove existing breakpoint. - QAction *act = new QAction(menu); - act->setData(QVariant::fromValue(id)); - act->setText(tr("Remove Breakpoint %1").arg(id.toString())); - connect(act, SIGNAL(triggered()), - SLOT(breakpointRemoveMarginActionTriggered())); - menu->addAction(act); + auto act = menu->addAction(tr("Remove Breakpoint %1").arg(id)); + connect(act, &QAction::triggered, [bp] { bp.removeBreakpoint(); }); // Enable/disable existing breakpoint. - act = new QAction(menu); - act->setData(QVariant::fromValue(id)); - if (breakHandler()->isEnabled(id)) { - act->setText(tr("Disable Breakpoint %1").arg(id.toString())); - connect(act, SIGNAL(triggered()), - SLOT(breakpointDisableMarginActionTriggered())); + if (bp.isEnabled()) { + act = menu->addAction(tr("Disable Breakpoint %1").arg(id)); + connect(act, &QAction::triggered, [bp] { bp.setEnabled(false); }); } else { - act->setText(tr("Enable Breakpoint %1").arg(id.toString())); - connect(act, SIGNAL(triggered()), - SLOT(breakpointEnableMarginActionTriggered())); + act = menu->addAction(tr("Enable Breakpoint %1").arg(id)); + connect(act, &QAction::triggered, [bp] { bp.setEnabled(true); }); } - menu->addAction(act); // Edit existing breakpoint. - act = new QAction(menu); - act->setText(tr("Edit Breakpoint %1...").arg(id.toString())); - connect(act, SIGNAL(triggered()), SLOT(slotEditBreakpoint())); - act->setData(QVariant::fromValue(id)); - menu->addAction(act); + act = menu->addAction(tr("Edit Breakpoint %1...").arg(id)); + connect(act, &QAction::triggered, [bp] { + BreakTreeView::editBreakpoint(bp, ICore::dialogParent()); + }); + } else { // Handle non-existing breakpoint. const QString text = args.address ? tr("Set Breakpoint at 0x%1").arg(args.address, 0, 16) : tr("Set Breakpoint at Line %1").arg(lineNumber); - QAction *act = new QAction(text, menu); - act->setData(QVariant::fromValue(args)); + auto act = menu->addAction(text); act->setEnabled(contextUsable); - connect(act, SIGNAL(triggered()), - SLOT(breakpointSetMarginActionTriggered())); - menu->addAction(act); + connect(act, &QAction::triggered, [this, args] { + breakpointSetMarginActionTriggered(false, args); + }); + // Message trace point - args.mode = BreakpointMenuContextData::MessageTracePoint; const QString tracePointText = args.address ? tr("Set Message Tracepoint at 0x%1...").arg(args.address, 0, 16) : tr("Set Message Tracepoint at Line %1...").arg(lineNumber); - act = new QAction(tracePointText, menu); - act->setData(QVariant::fromValue(args)); + act = menu->addAction(tracePointText); act->setEnabled(contextUsable); - connect(act, SIGNAL(triggered()), - SLOT(breakpointSetMarginActionTriggered())); - menu->addAction(act); + connect(act, &QAction::triggered, [this, args] { + breakpointSetMarginActionTriggered(true, args); + }); } + // Run to, jump to line below in stopped state. if (currentEngine()->state() == InferiorStopOk && contextUsable) { menu->addSeparator(); if (currentEngine()->hasCapability(RunToLineCapability)) { - const QString runText = args.address + auto act = menu->addAction(args.address ? DebuggerEngine::tr("Run to Address 0x%1").arg(args.address, 0, 16) - : DebuggerEngine::tr("Run to Line %1").arg(args.lineNumber); - QAction *runToLineAction = new QAction(runText, menu); - runToLineAction->setData(QVariant::fromValue(args)); - connect(runToLineAction, SIGNAL(triggered()), SLOT(slotRunToLine())); - menu->addAction(runToLineAction); + : DebuggerEngine::tr("Run to Line %1").arg(args.lineNumber)); + connect(act, &QAction::triggered, [this, args] { + currentEngine()->executeRunToLine(args); + }); } if (currentEngine()->hasCapability(JumpToLineCapability)) { - const QString jumpText = args.address + auto act = menu->addAction(args.address ? DebuggerEngine::tr("Jump to Address 0x%1").arg(args.address, 0, 16) - : DebuggerEngine::tr("Jump to Line %1").arg(args.lineNumber); - QAction *jumpToLineAction = new QAction(jumpText, menu); - jumpToLineAction->setData(QVariant::fromValue(args)); - connect(jumpToLineAction, SIGNAL(triggered()), SLOT(slotJumpToLine())); - menu->addAction(jumpToLineAction); + : DebuggerEngine::tr("Jump to Line %1").arg(args.lineNumber)); + connect(act, &QAction::triggered, [this, args] { + currentEngine()->executeJumpToLine(args); + }); } // Disassemble current function in stopped state. if (currentEngine()->state() == InferiorStopOk @@ -1835,7 +1745,7 @@ void DebuggerPluginPrivate::requestContextMenu(TextEditorWidget *widget, .arg(frame.function); QAction *disassembleAction = new QAction(text, menu); disassembleAction->setData(QVariant::fromValue(frame)); - connect(disassembleAction, SIGNAL(triggered()), SLOT(slotDisassembleFunction())); + connect(disassembleAction, &QAction::triggered, this, &DebuggerPluginPrivate::slotDisassembleFunction); menu->addAction(disassembleAction ); } } @@ -1853,7 +1763,7 @@ void DebuggerPluginPrivate::toggleBreakpoint() quint64 address = DisassemblerLine::addressFromDisassemblyLine(line); toggleBreakpointByAddress(address); } else if (lineNumber >= 0) { - toggleBreakpointByFileAndLine(textEditor->document()->filePath(), lineNumber); + toggleBreakpointByFileAndLine(textEditor->document()->filePath().toString(), lineNumber); } } @@ -1861,13 +1771,12 @@ void DebuggerPluginPrivate::toggleBreakpointByFileAndLine(const QString &fileNam int lineNumber, const QString &tracePointMessage) { BreakHandler *handler = m_breakHandler; - BreakpointModelId id = - handler->findBreakpointByFileAndLine(fileName, lineNumber, true); - if (!id) - id = handler->findBreakpointByFileAndLine(fileName, lineNumber, false); + Breakpoint bp = handler->findBreakpointByFileAndLine(fileName, lineNumber, true); + if (!bp) + bp = handler->findBreakpointByFileAndLine(fileName, lineNumber, false); - if (id) { - handler->removeBreakpoint(id); + if (bp) { + bp.removeBreakpoint(); } else { BreakpointParameters data(BreakpointByFileAndLine); if (boolSetting(BreakpointsFullPathByDefault)) @@ -1884,10 +1793,8 @@ void DebuggerPluginPrivate::toggleBreakpointByAddress(quint64 address, const QString &tracePointMessage) { BreakHandler *handler = m_breakHandler; - BreakpointModelId id = handler->findBreakpointByAddress(address); - - if (id) { - handler->removeBreakpoint(id); + if (Breakpoint bp = handler->findBreakpointByAddress(address)) { + bp.removeBreakpoint(); } else { BreakpointParameters data(BreakpointByAddress); data.tracepoint = !tracePointMessage.isEmpty(); @@ -1910,7 +1817,7 @@ void DebuggerPluginPrivate::requestMark(TextEditorWidget *widget, int lineNumber quint64 address = DisassemblerLine::addressFromDisassemblyLine(line); toggleBreakpointByAddress(address); } else { - toggleBreakpointByFileAndLine(document->filePath(), lineNumber); + toggleBreakpointByFileAndLine(document->filePath().toString(), lineNumber); } } @@ -1958,7 +1865,7 @@ static void changeFontSize(QWidget *widget, qreal size) } void DebuggerPluginPrivate::fontSettingsChanged - (const TextEditor::FontSettings &settings) + (const FontSettings &settings) { if (!boolSetting(FontSizeFollowsEditor)) return; @@ -1992,7 +1899,7 @@ void DebuggerPluginPrivate::cleanupViews() bool keepIt = true; if (document->isModified()) keepIt = true; - else if (document->filePath().contains(_("qeventdispatcher"))) + else if (document->filePath().toString().contains(_("qeventdispatcher"))) keepIt = false; else if (isMemory) keepIt = !closeMemory; @@ -2069,7 +1976,6 @@ void DebuggerPluginPrivate::setInitialState() action(AutoDerefPointers)->setEnabled(true); action(ExpandStack)->setEnabled(false); - } void DebuggerPluginPrivate::updateWatchersWindow(bool showWatch, bool showReturn) @@ -2107,7 +2013,7 @@ void DebuggerPluginPrivate::updateState(DebuggerEngine *engine) m_exitAction->setEnabled(false); m_startAction->setEnabled(true); m_debugWithoutDeployAction->setEnabled(true); - setProxyAction(m_visibleStartAction, Core::Id(Constants::DEBUG)); + setProxyAction(m_visibleStartAction, Id(Constants::DEBUG)); m_hiddenStopAction->setAction(m_undisturbableAction); } else if (state == InferiorStopOk) { // F5 continues, Shift-F5 kills. It is "continuable". @@ -2116,7 +2022,7 @@ void DebuggerPluginPrivate::updateState(DebuggerEngine *engine) m_exitAction->setEnabled(true); m_startAction->setEnabled(false); m_debugWithoutDeployAction->setEnabled(false); - setProxyAction(m_visibleStartAction, Core::Id(Constants::CONTINUE)); + setProxyAction(m_visibleStartAction, Id(Constants::CONTINUE)); m_hiddenStopAction->setAction(m_exitAction); m_localsAndExpressionsWindow->setShowLocals(true); } else if (state == InferiorRunOk) { @@ -2126,7 +2032,7 @@ void DebuggerPluginPrivate::updateState(DebuggerEngine *engine) m_exitAction->setEnabled(true); m_startAction->setEnabled(false); m_debugWithoutDeployAction->setEnabled(false); - setProxyAction(m_visibleStartAction, Core::Id(Constants::INTERRUPT)); + setProxyAction(m_visibleStartAction, Id(Constants::INTERRUPT)); m_hiddenStopAction->setAction(m_interruptAction); m_localsAndExpressionsWindow->setShowLocals(false); } else if (state == DebuggerFinished) { @@ -2138,7 +2044,7 @@ void DebuggerPluginPrivate::updateState(DebuggerEngine *engine) m_exitAction->setEnabled(false); m_startAction->setEnabled(canRun); m_debugWithoutDeployAction->setEnabled(canRun); - setProxyAction(m_visibleStartAction, Core::Id(Constants::DEBUG)); + setProxyAction(m_visibleStartAction, Id(Constants::DEBUG)); m_hiddenStopAction->setAction(m_undisturbableAction); m_codeModelSnapshot = CPlusPlus::Snapshot(); setBusyCursor(false); @@ -2526,16 +2432,27 @@ QMessageBox *showMessageBox(int icon, const QString &title, return mb; } +bool isNativeMixedEnabled() +{ + static bool enabled = qEnvironmentVariableIsSet("QTC_DEBUGGER_NATIVE_MIXED"); + return enabled; +} + +bool isNativeMixedActive() +{ + return isNativeMixedEnabled() && boolSetting(OperateNativeMixed); +} + void DebuggerPluginPrivate::extensionsInitialized() { const QKeySequence debugKey = QKeySequence(UseMacShortcuts ? tr("Ctrl+Y") : tr("F5")); - QSettings *settings = Core::ICore::settings(); + QSettings *settings = ICore::settings(); m_debuggerSettings = new DebuggerSettings; m_debuggerSettings->readSettings(); - connect(ICore::instance(), SIGNAL(coreAboutToClose()), this, SLOT(coreShutdown())); + connect(ICore::instance(), &ICore::coreAboutToClose, this, &DebuggerPluginPrivate::coreShutdown); const Context globalcontext(CC::C_GLOBAL); const Context cppDebuggercontext(C_CPPDEBUGGER); @@ -2608,22 +2525,22 @@ void DebuggerPluginPrivate::extensionsInitialized() m_snapshotWindow = addSearch(m_snapshotView, tr("Snapshots"), DOCKWIDGET_SNAPSHOTS); // Watchers - connect(m_localsView->header(), SIGNAL(sectionResized(int,int,int)), - SLOT(updateWatchersHeader(int,int,int)), Qt::QueuedConnection); + connect(m_localsView->header(), &QHeaderView::sectionResized, + this, &DebuggerPluginPrivate::updateWatchersHeader, Qt::QueuedConnection); QAction *act = 0; act = m_continueAction = new QAction(tr("Continue"), this); act->setIcon(m_continueIcon); - connect(act, SIGNAL(triggered()), SLOT(handleExecContinue())); + connect(act, &QAction::triggered, this, &DebuggerPluginPrivate::handleExecContinue); act = m_exitAction = new QAction(tr("Stop Debugger"), this); act->setIcon(m_exitIcon); - connect(act, SIGNAL(triggered()), SLOT(handleExecExit())); + connect(act, &QAction::triggered, this, &DebuggerPluginPrivate::handleExecExit); act = m_interruptAction = new QAction(tr("Interrupt"), this); act->setIcon(m_interruptIcon); - connect(act, SIGNAL(triggered()), SLOT(handleExecInterrupt())); + connect(act, &QAction::triggered, this, &DebuggerPluginPrivate::handleExecInterrupt); // A "disabled pause" seems to be a good choice. act = m_undisturbableAction = new QAction(tr("Debugger is Busy"), this); @@ -2633,46 +2550,46 @@ void DebuggerPluginPrivate::extensionsInitialized() act = m_abortAction = new QAction(tr("Abort Debugging"), this); act->setToolTip(tr("Aborts debugging and " "resets the debugger to the initial state.")); - connect(act, SIGNAL(triggered()), SLOT(handleAbort())); + connect(act, &QAction::triggered, this, &DebuggerPluginPrivate::handleAbort); act = m_resetAction = new QAction(tr("Restart Debugging"),this); act->setToolTip(tr("Restart the debugging session.")); act->setIcon(m_resetIcon); - connect(act,SIGNAL(triggered()),SLOT(handleReset())); + connect(act, &QAction::triggered, this, &DebuggerPluginPrivate::handleReset); act = m_nextAction = new QAction(tr("Step Over"), this); act->setIcon(QIcon(QLatin1String(":/debugger/images/debugger_stepover_small.png"))); - connect(act, SIGNAL(triggered()), SLOT(handleExecNext())); + connect(act, &QAction::triggered, this, &DebuggerPluginPrivate::handleExecNext); act = m_stepAction = new QAction(tr("Step Into"), this); act->setIcon(QIcon(QLatin1String(":/debugger/images/debugger_stepinto_small.png"))); - connect(act, SIGNAL(triggered()), SLOT(handleExecStep())); + connect(act, &QAction::triggered, this, &DebuggerPluginPrivate::handleExecStep); act = m_stepOutAction = new QAction(tr("Step Out"), this); act->setIcon(QIcon(QLatin1String(":/debugger/images/debugger_stepout_small.png"))); - connect(act, SIGNAL(triggered()), SLOT(handleExecStepOut())); + connect(act, &QAction::triggered, this, &DebuggerPluginPrivate::handleExecStepOut); act = m_runToLineAction = new QAction(tr("Run to Line"), this); - connect(act, SIGNAL(triggered()), SLOT(handleExecRunToLine())); + connect(act, &QAction::triggered, this, &DebuggerPluginPrivate::handleExecRunToLine); act = m_runToSelectedFunctionAction = new QAction(tr("Run to Selected Function"), this); - connect(act, SIGNAL(triggered()), SLOT(handleExecRunToSelectedFunction())); + connect(act, &QAction::triggered, this, &DebuggerPluginPrivate::handleExecRunToSelectedFunction); act = m_returnFromFunctionAction = new QAction(tr("Immediately Return From Inner Function"), this); - connect(act, SIGNAL(triggered()), SLOT(handleExecReturn())); + connect(act, &QAction::triggered, this, &DebuggerPluginPrivate::handleExecReturn); act = m_jumpToLineAction = new QAction(tr("Jump to Line"), this); - connect(act, SIGNAL(triggered()), SLOT(handleExecJumpToLine())); + connect(act, &QAction::triggered, this, &DebuggerPluginPrivate::handleExecJumpToLine); m_breakAction = new QAction(tr("Toggle Breakpoint"), this); act = m_watchAction1 = new QAction(tr("Add Expression Evaluator"), this); - connect(act, SIGNAL(triggered()), SLOT(handleAddToWatchWindow())); + connect(act, &QAction::triggered, this, &DebuggerPluginPrivate::handleAddToWatchWindow); act = m_watchAction2 = new QAction(tr("Add Expression Evaluator"), this); - connect(act, SIGNAL(triggered()), SLOT(handleAddToWatchWindow())); + connect(act, &QAction::triggered, this, &DebuggerPluginPrivate::handleAddToWatchWindow); //m_snapshotAction = new QAction(tr("Create Snapshot"), this); //m_snapshotAction->setProperty(Role, RequestCreateSnapshotRole); @@ -2688,10 +2605,10 @@ void DebuggerPluginPrivate::extensionsInitialized() act->setIconVisibleInMenu(false); act = m_frameDownAction = new QAction(tr("Move to Called Frame"), this); - connect(act, SIGNAL(triggered()), SLOT(handleFrameDown())); + connect(act, &QAction::triggered, this, &DebuggerPluginPrivate::handleFrameDown); act = m_frameUpAction = new QAction(tr("Move to Calling Frame"), this); - connect(act, SIGNAL(triggered()), SLOT(handleFrameUp())); + connect(act, &QAction::triggered, this, &DebuggerPluginPrivate::handleFrameUp); connect(action(OperateByInstruction), SIGNAL(triggered(bool)), SLOT(handleOperateByInstructionTriggered(bool))); @@ -2701,16 +2618,16 @@ void DebuggerPluginPrivate::extensionsInitialized() // Dock widgets QDockWidget *dock = 0; dock = m_mainWindow->createDockWidget(CppLanguage, m_modulesWindow); - connect(dock->toggleViewAction(), SIGNAL(toggled(bool)), - SLOT(modulesDockToggled(bool)), Qt::QueuedConnection); + connect(dock->toggleViewAction(), &QAction::toggled, + this, &DebuggerPluginPrivate::modulesDockToggled, Qt::QueuedConnection); dock = m_mainWindow->createDockWidget(CppLanguage, m_registerWindow); - connect(dock->toggleViewAction(), SIGNAL(toggled(bool)), - SLOT(registerDockToggled(bool)), Qt::QueuedConnection); + connect(dock->toggleViewAction(), &QAction::toggled, + this, &DebuggerPluginPrivate::registerDockToggled, Qt::QueuedConnection); dock = m_mainWindow->createDockWidget(CppLanguage, m_sourceFilesWindow); - connect(dock->toggleViewAction(), SIGNAL(toggled(bool)), - SLOT(sourceFilesDockToggled(bool)), Qt::QueuedConnection); + connect(dock->toggleViewAction(), &QAction::toggled, + this, &DebuggerPluginPrivate::sourceFilesDockToggled, Qt::QueuedConnection); dock = m_mainWindow->createDockWidget(AnyLanguage, m_logWindow); dock->setProperty(DOCKWIDGET_DEFAULT_AREA, Qt::TopDockWidgetArea); @@ -2741,49 +2658,49 @@ void DebuggerPluginPrivate::extensionsInitialized() debuggerIcon.addFile(QLatin1String(":/projectexplorer/images/debugger_start.png")); act->setIcon(debuggerIcon); act->setText(tr("Start Debugging")); - connect(act, SIGNAL(triggered()), this, SLOT(debugProject())); + connect(act, &QAction::triggered, this, &DebuggerPluginPrivate::debugProject); act = m_debugWithoutDeployAction = new QAction(this); act->setText(tr("Start Debugging Without Deployment")); - connect(act, SIGNAL(triggered()), this, SLOT(debugProjectWithoutDeploy())); + connect(act, &QAction::triggered, this, &DebuggerPluginPrivate::debugProjectWithoutDeploy); act = m_startAndDebugApplicationAction = new QAction(this); act->setText(tr("Start and Debug External Application...")); - connect(act, SIGNAL(triggered()), SLOT(startAndDebugApplication())); + connect(act, &QAction::triggered, this, &DebuggerPluginPrivate::startAndDebugApplication); act = m_attachToCoreAction = new QAction(this); act->setText(tr("Load Core File...")); - connect(act, SIGNAL(triggered()), SLOT(attachCore())); + connect(act, &QAction::triggered, this, &DebuggerPluginPrivate::attachCore); act = m_attachToRemoteServerAction = new QAction(this); act->setText(tr("Attach to Remote Debug Server...")); - connect(act, SIGNAL(triggered()), SLOT(attachToRemoteServer())); + connect(act, &QAction::triggered, this, &DebuggerPluginPrivate::attachToRemoteServer); act = m_startRemoteServerAction = new QAction(this); act->setText(tr("Start Remote Debug Server Attached to Process...")); - connect(act, SIGNAL(triggered()), SLOT(startRemoteServer())); + connect(act, &QAction::triggered, this, &DebuggerPluginPrivate::startRemoteServer); act = m_attachToRunningApplication = new QAction(this); act->setText(tr("Attach to Running Application...")); - connect(act, SIGNAL(triggered()), SLOT(attachToRunningApplication())); + connect(act, &QAction::triggered, this, &DebuggerPluginPrivate::attachToRunningApplication); act = m_attachToUnstartedApplication = new QAction(this); act->setText(tr("Attach to Unstarted Application...")); - connect(act, SIGNAL(triggered()), SLOT(attachToUnstartedApplicationDialog())); + connect(act, &QAction::triggered, this, &DebuggerPluginPrivate::attachToUnstartedApplicationDialog); act = m_attachToQmlPortAction = new QAction(this); act->setText(tr("Attach to QML Port...")); - connect(act, SIGNAL(triggered()), SLOT(attachToQmlPort())); + connect(act, &QAction::triggered, this, &DebuggerPluginPrivate::attachToQmlPort); if (HostOsInfo::isWindowsHost()) { m_startRemoteCdbAction = new QAction(tr("Attach to Remote CDB Session..."), this); - connect(m_startRemoteCdbAction, SIGNAL(triggered()), - SLOT(startRemoteCdbSession())); + connect(m_startRemoteCdbAction, &QAction::triggered, + this, &DebuggerPluginPrivate::startRemoteCdbSession); } act = m_detachAction = new QAction(this); act->setText(tr("Detach Debugger")); - connect(act, SIGNAL(triggered()), SLOT(handleExecDetach())); + connect(act, &QAction::triggered, this, &DebuggerPluginPrivate::handleExecDetach); // "Start Debugging" sub-menu // groups: @@ -2816,17 +2733,17 @@ void DebuggerPluginPrivate::extensionsInitialized() cmd = ActionManager::registerAction(m_attachToRunningApplication, "Debugger.AttachToRemoteProcess", globalcontext); cmd->setDescription(tr("Attach to Running Application")); - mstart->addAction(cmd, Debugger::Constants::G_GENERAL); + mstart->addAction(cmd, G_GENERAL); cmd = ActionManager::registerAction(m_attachToUnstartedApplication, "Debugger.AttachToUnstartedProcess", globalcontext); cmd->setDescription(tr("Attach to Unstarted Application")); - mstart->addAction(cmd, Debugger::Constants::G_GENERAL); + mstart->addAction(cmd, G_GENERAL); cmd = ActionManager::registerAction(m_startAndDebugApplicationAction, "Debugger.StartAndDebugApplication", globalcontext); cmd->setAttribute(Command::CA_Hide); - mstart->addAction(cmd, Debugger::Constants::G_GENERAL); + mstart->addAction(cmd, G_GENERAL); cmd = ActionManager::registerAction(m_attachToCoreAction, "Debugger.AttachCore", globalcontext); @@ -2964,12 +2881,23 @@ void DebuggerPluginPrivate::extensionsInitialized() cmd->setAttribute(Command::CA_Hide); debugMenu->addAction(cmd); + if (isNativeMixedEnabled()) { + SavedAction *act = action(OperateNativeMixed); + act->setValue(true); + cmd = ActionManager::registerAction(act, + Constants::OPERATE_NATIVE_MIXED, globalcontext); + cmd->setAttribute(Command::CA_Hide); + debugMenu->addAction(cmd); + connect(cmd->action(), &QAction::triggered, + [this] { currentEngine()->updateAll(); }); + } + cmd = ActionManager::registerAction(m_breakAction, "Debugger.ToggleBreak", globalcontext); cmd->setDefaultKeySequence(QKeySequence(UseMacShortcuts ? tr("F8") : tr("F9"))); debugMenu->addAction(cmd); - connect(m_breakAction, SIGNAL(triggered()), - SLOT(toggleBreakpoint())); + connect(m_breakAction, &QAction::triggered, + this, &DebuggerPluginPrivate::toggleBreakpoint); debugMenu->addSeparator(globalcontext); @@ -3032,32 +2960,26 @@ void DebuggerPluginPrivate::extensionsInitialized() QList<IOptionsPage *> engineOptionPages; addGdbOptionPages(&engineOptionPages); addCdbOptionPages(&engineOptionPages); -#ifdef WITH_LLDB - addLldbOptionPages(&engineOptionPages); -#endif - - // addScriptOptionPages(&engineOptionPages); - // addTcfOptionPages(&engineOptionPages); foreach (IOptionsPage *op, engineOptionPages) m_plugin->addAutoReleasedObject(op); m_plugin->addAutoReleasedObject(new LocalsAndExpressionsOptionsPage); m_plugin->addAutoReleasedObject(new DebuggerOptionsPage); - connect(ModeManager::instance(), SIGNAL(currentModeChanged(Core::IMode*)), - SLOT(onModeChanged(Core::IMode*))); - connect(ICore::instance(), SIGNAL(coreAboutToOpen()), - SLOT(onCoreAboutToOpen())); - connect(ProjectExplorerPlugin::instance(), SIGNAL(settingsChanged()), - this, SLOT(updateDebugWithoutDeployMenu())); + connect(ModeManager::instance(), &ModeManager::currentModeChanged, + this, &DebuggerPluginPrivate::onModeChanged); + connect(ICore::instance(), &ICore::coreAboutToOpen, + this, &DebuggerPluginPrivate::onCoreAboutToOpen); + connect(ProjectExplorerPlugin::instance(), &ProjectExplorerPlugin::settingsChanged, + this, &DebuggerPluginPrivate::updateDebugWithoutDeployMenu); // Debug mode setup DebugMode *debugMode = new DebugMode; QWidget *widget = m_mainWindow->createContents(debugMode); - Core::IContext *modeContextObject = new Core::IContext(this); - modeContextObject->setContext(Core::Context(CC::C_EDITORMANAGER)); + IContext *modeContextObject = new IContext(this); + modeContextObject->setContext(Context(CC::C_EDITORMANAGER)); modeContextObject->setWidget(widget); - Core::ICore::addContextObject(modeContextObject); + ICore::addContextObject(modeContextObject); debugMode->setWidget(widget); m_plugin->addAutoReleasedObject(debugMode); @@ -3112,6 +3034,8 @@ void DebuggerPluginPrivate::extensionsInitialized() hbox->addWidget(toolButton(Constants::STEPOUT)); hbox->addWidget(toolButton(Constants::RESET)); hbox->addWidget(toolButton(Constants::OPERATE_BY_INSTRUCTION)); + if (isNativeMixedEnabled()) + hbox->addWidget(toolButton(Constants::OPERATE_NATIVE_MIXED)); //hbox->addWidget(new StyledSeparator); m_reverseToolButton = toolButton(Constants::REVERSE); @@ -3347,8 +3271,11 @@ bool isDockVisible(const QString &objectName) void openMemoryEditor() { AddressDialog dialog; - if (dialog.exec() == QDialog::Accepted) - currentEngine()->openMemoryView(dialog.address(), 0, QList<MemoryMarkup>(), QPoint()); + if (dialog.exec() == QDialog::Accepted) { + MemoryViewSetupData data; + data.startAddress = dialog.address(); + currentEngine()->openMemoryView(data); + } } void setThreads(const QStringList &list, int index) @@ -3437,7 +3364,7 @@ void DebuggerPlugin::extensionsInitialized() void DebuggerPluginPrivate::testLoadProject(const QString &proFile, const TestCallBack &cb) { - connect(ProjectExplorerPlugin::instance(), &ProjectExplorerPlugin::currentProjectChanged, + connect(ProjectTree::instance(), &ProjectTree::currentProjectChanged, this, &DebuggerPluginPrivate::testProjectLoaded); m_testCallbacks.append(cb); @@ -3471,7 +3398,7 @@ void DebuggerPluginPrivate::testProjectEvaluated() QVERIFY(!fileName.isEmpty()); qWarning("Project %s loaded", qPrintable(fileName)); connect(BuildManager::instance(), SIGNAL(buildQueueFinished(bool)), - SLOT(testProjectBuilt(bool))); + this, SLOT(testProjectBuilt(bool))); ProjectExplorerPlugin::buildProject(m_testProject); } @@ -3578,7 +3505,7 @@ void DebuggerPluginPrivate::testBenchmark1() { #ifdef WITH_BENCHMARK CALLGRIND_START_INSTRUMENTATION; - volatile Core::Id id1 = Core::Id(DEBUGGER_COMMON_SETTINGS_ID); + volatile Id id1 = Id(DEBUGGER_COMMON_SETTINGS_ID); CALLGRIND_STOP_INSTRUMENTATION; CALLGRIND_DUMP_STATS; diff --git a/src/plugins/debugger/debuggerprotocol.cpp b/src/plugins/debugger/debuggerprotocol.cpp index 3bb5db075c..5393e89d8f 100644 --- a/src/plugins/debugger/debuggerprotocol.cpp +++ b/src/plugins/debugger/debuggerprotocol.cpp @@ -395,19 +395,19 @@ qulonglong GdbMi::toAddress() const // ////////////////////////////////////////////////////////////////////////////////// -QByteArray GdbResponse::stringFromResultClass(GdbResultClass resultClass) +QByteArray DebuggerResponse::stringFromResultClass(ResultClass resultClass) { switch (resultClass) { - case GdbResultDone: return "done"; - case GdbResultRunning: return "running"; - case GdbResultConnected: return "connected"; - case GdbResultError: return "error"; - case GdbResultExit: return "exit"; + case ResultDone: return "done"; + case ResultRunning: return "running"; + case ResultConnected: return "connected"; + case ResultError: return "error"; + case ResultExit: return "exit"; default: return "unknown"; } } -QByteArray GdbResponse::toString() const +QByteArray DebuggerResponse::toString() const { QByteArray result; if (token != -1) @@ -716,10 +716,136 @@ QString decodeData(const QByteArray &ba, int encoding) } return dateTime.toString(); } + case Hex2EncodedFloat4: { + const QByteArray s = QByteArray::fromHex(ba); + QTC_ASSERT(s.size() == 4, break); + union { char c[4]; float f; } u = { { s[3], s[2], s[1], s[0] } }; + return QString::number(u.f); + } + case Hex2EncodedFloat8: { + const QByteArray s = QByteArray::fromHex(ba); + QTC_ASSERT(s.size() == 8, break); + union { char c[8]; double d; } u = { { s[7], s[6], s[5], s[4], s[3], s[2], s[1], s[0] } }; + return QString::number(u.d); + } } qDebug() << "ENCODING ERROR: " << encoding; return QCoreApplication::translate("Debugger", "<Encoding error>"); } +////////////////////////////////////////////////////////////////////////////////// +// +// DebuggerCommand +// +////////////////////////////////////////////////////////////////////////////////// + +void DebuggerCommand::argHelper(const char *name, const QByteArray &data) +{ + args.append('"'); + args.append(name); + args.append("\":"); + args.append(data); + args.append(","); +} + +QByteArray DebuggerCommand::toData(const QList<QByteArray> &value) +{ + QByteArray res; + foreach (const QByteArray &item, value) { + if (!res.isEmpty()) + res.append(','); + res += item; + } + return '[' + res + ']'; +} + +QByteArray DebuggerCommand::toData(const QHash<QByteArray, QByteArray> &value) +{ + QByteArray res; + QHashIterator<QByteArray, QByteArray> it(value); + while (it.hasNext()) { + it.next(); + if (!res.isEmpty()) + res.append(','); + res += '"' + it.key() + "\":" + it.value(); + } + return '{' + res + '}'; +} + +void DebuggerCommand::arg(const char *name, int value) +{ + argHelper(name, QByteArray::number(value)); +} + +void DebuggerCommand::arg(const char *name, qlonglong value) +{ + argHelper(name, QByteArray::number(value)); +} + +void DebuggerCommand::arg(const char *name, qulonglong value) +{ + argHelper(name, QByteArray::number(value)); +} + +void DebuggerCommand::arg(const char *name, const QString &value) +{ + arg(name, value.toUtf8().data()); +} + +void DebuggerCommand::arg(const char *name, const QByteArray &value) +{ + arg(name, value.data()); +} + +void DebuggerCommand::arg(const char *name, const char *value) +{ + args.append('"'); + args.append(name); + args.append("\":\""); + args.append(value); + args.append("\","); +} + +void DebuggerCommand::arg(const char *value) +{ + args.append("\""); + args.append(value); + args.append("\","); +} + +void DebuggerCommand::beginList(const char *name) +{ + if (name) { + args += '"'; + args += name; + args += "\":"; + } + args += '['; +} + +void DebuggerCommand::endList() +{ + if (args.endsWith(',')) + args.chop(1); + args += "],"; +} + +void DebuggerCommand::beginGroup(const char *name) +{ + if (name) { + args += '"'; + args += name; + args += "\":"; + } + args += '{'; +} + +void DebuggerCommand::endGroup() +{ + if (args.endsWith(',')) + args.chop(1); + args += "},"; +} + } // namespace Internal } // namespace Debugger diff --git a/src/plugins/debugger/debuggerprotocol.h b/src/plugins/debugger/debuggerprotocol.h index dc8908fe13..943fe8b442 100644 --- a/src/plugins/debugger/debuggerprotocol.h +++ b/src/plugins/debugger/debuggerprotocol.h @@ -32,10 +32,52 @@ #define DEBUGGER_PROTOCOL_H #include <QVariant> +#include <QTime> + +#include <functional> namespace Debugger { namespace Internal { +class DebuggerResponse; + +// Convenience structure to build up backend commands. +class DebuggerCommand +{ +public: + typedef std::function<void(const DebuggerResponse &)> Callback; + + DebuggerCommand() : flags(0) {} + DebuggerCommand(const char *f, int flags = 0, Callback cb = Callback()) + : function(f), callback(cb), flags(flags) + {} + DebuggerCommand(const QByteArray &f) : function(f), flags(0) {} + + void arg(const char *name); + void arg(const char *name, int value); + void arg(const char *name, qlonglong value); + void arg(const char *name, qulonglong value); + void arg(const char *name, const QString &value); + void arg(const char *name, const QByteArray &value); + void arg(const char *name, const char *value); + void beginList(const char *name = 0); + void endList(); + void beginGroup(const char *name = 0); + void endGroup(); + + static QByteArray toData(const QList<QByteArray> &value); + static QByteArray toData(const QHash<QByteArray, QByteArray> &value); + + QByteArray function; + QByteArray args; + Callback callback; + QTime postTime; + int flags; + +private: + void argHelper(const char *name, const QByteArray &value); +}; + /* output ==> @@ -141,28 +183,27 @@ public: void dumpChildren(QByteArray *str, bool multiline, int indent) const; }; -enum GdbResultClass +enum ResultClass { // "done" | "running" | "connected" | "error" | "exit" - GdbResultUnknown, - GdbResultDone, - GdbResultRunning, - GdbResultConnected, - GdbResultError, - GdbResultExit + ResultUnknown, + ResultDone, + ResultRunning, + ResultConnected, + ResultError, + ResultExit }; -class GdbResponse +class DebuggerResponse { public: - GdbResponse() : token(-1), resultClass(GdbResultUnknown) {} + DebuggerResponse() : token(-1), resultClass(ResultUnknown) {} QByteArray toString() const; - static QByteArray stringFromResultClass(GdbResultClass resultClass); + static QByteArray stringFromResultClass(ResultClass resultClass); int token; - GdbResultClass resultClass; + ResultClass resultClass; GdbMi data; - QVariant cookie; QByteArray logStreamOutput; QByteArray consoleStreamOutput; }; diff --git a/src/plugins/debugger/debuggerrunconfigurationaspect.cpp b/src/plugins/debugger/debuggerrunconfigurationaspect.cpp index aba7ead634..6356815491 100644 --- a/src/plugins/debugger/debuggerrunconfigurationaspect.cpp +++ b/src/plugins/debugger/debuggerrunconfigurationaspect.cpp @@ -122,18 +122,18 @@ DebuggerRunConfigWidget::DebuggerRunConfigWidget(DebuggerRunConfigurationAspect connect(m_qmlDebuggerInfoLabel, SIGNAL(linkActivated(QString)), Core::HelpManager::instance(), SLOT(handleHelpRequest(QString))); - connect(m_useQmlDebugger, SIGNAL(toggled(bool)), - SLOT(useQmlDebuggerToggled(bool))); - connect(m_useQmlDebugger, SIGNAL(clicked(bool)), - SLOT(useQmlDebuggerClicked(bool))); - connect(m_useCppDebugger, SIGNAL(clicked(bool)), - SLOT(useCppDebuggerClicked(bool))); - connect(m_debugServerPort, SIGNAL(valueChanged(int)), - SLOT(qmlDebugServerPortChanged(int))); - connect(m_useMultiProcess, SIGNAL(toggled(bool)), - SLOT(useMultiProcessToggled(bool))); - - QHBoxLayout *qmlLayout = new QHBoxLayout; + connect(m_useQmlDebugger, &QAbstractButton::toggled, + this, &DebuggerRunConfigWidget::useQmlDebuggerToggled); + connect(m_useQmlDebugger, &QAbstractButton::clicked, + this, &DebuggerRunConfigWidget::useQmlDebuggerClicked); + connect(m_useCppDebugger, &QAbstractButton::clicked, + this, &DebuggerRunConfigWidget::useCppDebuggerClicked); + connect(m_debugServerPort, static_cast<void(QSpinBox::*)(int)>(&QSpinBox::valueChanged), + this, &DebuggerRunConfigWidget::qmlDebugServerPortChanged); + connect(m_useMultiProcess, &QAbstractButton::toggled, + this, &DebuggerRunConfigWidget::useMultiProcessToggled); + + auto qmlLayout = new QHBoxLayout; qmlLayout->setMargin(0); qmlLayout->addWidget(m_useQmlDebugger); qmlLayout->addWidget(m_debugServerPortLabel); @@ -141,7 +141,7 @@ DebuggerRunConfigWidget::DebuggerRunConfigWidget(DebuggerRunConfigurationAspect qmlLayout->addWidget(m_qmlDebuggerInfoLabel); qmlLayout->addStretch(); - QVBoxLayout *layout = new QVBoxLayout; + auto layout = new QVBoxLayout; layout->setMargin(0); layout->addWidget(m_useCppDebugger); layout->addLayout(qmlLayout); @@ -234,13 +234,13 @@ DebuggerRunConfigurationAspect::DebuggerRunConfigurationAspect( void DebuggerRunConfigurationAspect::setUseQmlDebugger(bool value) { m_useQmlDebugger = value ? EnabledLanguage : DisabledLanguage; - emit requestRunActionsUpdate(); + runConfiguration()->requestRunActionsUpdate(); } void DebuggerRunConfigurationAspect::setUseCppDebugger(bool value) { m_useCppDebugger = value ? EnabledLanguage : DisabledLanguage; - emit requestRunActionsUpdate(); + runConfiguration()->requestRunActionsUpdate(); } bool DebuggerRunConfigurationAspect::useCppDebugger() const diff --git a/src/plugins/debugger/debuggerruncontrol.cpp b/src/plugins/debugger/debuggerruncontrol.cpp index ea2c1bb61c..48c5cb24d6 100644 --- a/src/plugins/debugger/debuggerruncontrol.cpp +++ b/src/plugins/debugger/debuggerruncontrol.cpp @@ -108,6 +108,13 @@ DebuggerRunControl::DebuggerRunControl(RunConfiguration *runConfiguration, Debug { setIcon(QLatin1String(ProjectExplorer::Constants::ICON_DEBUG_SMALL)); connect(this, &RunControl::finished, this, &DebuggerRunControl::handleFinished); + + connect(engine, &DebuggerEngine::requestRemoteSetup, + this, &DebuggerRunControl::requestRemoteSetup); + connect(engine, &DebuggerEngine::stateChanged, + this, &DebuggerRunControl::stateChanged); + connect(engine, &DebuggerEngine::aboutToNotifyInferiorSetupOk, + this, &DebuggerRunControl::aboutToNotifyInferiorSetupOk); } DebuggerRunControl::~DebuggerRunControl() @@ -141,10 +148,9 @@ void DebuggerRunControl::start() if (m_engine->startParameters().startMode == StartInternal) { QStringList unhandledIds; - foreach (const BreakpointModelId &id, breakHandler()->allBreakpointIds()) { - if (m_engine->breakHandler()->breakpointData(id).enabled - && !m_engine->acceptsBreakpoint(id)) - unhandledIds.append(id.toString()); + foreach (Breakpoint bp, breakHandler()->allBreakpoints()) { + if (bp.isEnabled() && !m_engine->acceptsBreakpoint(bp)) + unhandledIds.append(bp.id().toString()); } if (!unhandledIds.isEmpty()) { QString warningMessage = @@ -186,6 +192,16 @@ void DebuggerRunControl::startFailed() m_engine->handleStartFailed(); } +void DebuggerRunControl::notifyEngineRemoteServerRunning(const QByteArray &msg, int pid) +{ + m_engine->notifyEngineRemoteServerRunning(msg, pid); +} + +void DebuggerRunControl::notifyEngineRemoteSetupFinished(const RemoteSetupResult &result) +{ + m_engine->notifyEngineRemoteSetupFinished(result); +} + void DebuggerRunControl::handleFinished() { appendMessage(tr("Debugging has finished") + QLatin1Char('\n'), NormalMessageFormat); @@ -222,15 +238,39 @@ void DebuggerRunControl::debuggingFinished() emit finished(); } +void DebuggerRunControl::showMessage(const QString &msg, int channel) +{ + m_engine->showMessage(msg, channel); +} + bool DebuggerRunControl::isRunning() const { return m_running; } -DebuggerEngine *DebuggerRunControl::engine() +DebuggerStartParameters &DebuggerRunControl::startParameters() +{ + return m_engine->startParameters(); +} + +void DebuggerRunControl::notifyInferiorIll() +{ + m_engine->notifyInferiorIll(); +} + +void DebuggerRunControl::notifyInferiorExited() +{ + m_engine->notifyInferiorExited(); +} + +void DebuggerRunControl::quitDebugger() +{ + m_engine->quitDebugger(); +} + +void DebuggerRunControl::abortDebugger() { - QTC_CHECK(m_engine); - return m_engine; + m_engine->abortDebugger(); } //////////////////////////////////////////////////////////////////////// @@ -255,7 +295,7 @@ bool DebuggerRunControlFactory::fillParametersFromLocalRunConfiguration QTC_ASSERT(runConfiguration, return false); auto rc = qobject_cast<const LocalApplicationRunConfiguration *>(runConfiguration); QTC_ASSERT(rc, return false); - EnvironmentAspect *environmentAspect = rc->extraAspect<ProjectExplorer::EnvironmentAspect>(); + EnvironmentAspect *environmentAspect = rc->extraAspect<EnvironmentAspect>(); QTC_ASSERT(environmentAspect, return false); Target *target = runConfiguration->target(); @@ -291,7 +331,7 @@ bool DebuggerRunControlFactory::fillParametersFromLocalRunConfiguration sp->languages |= CppLanguage; if (debuggerAspect->useQmlDebugger()) { - const ProjectExplorer::IDevice::ConstPtr device = + const IDevice::ConstPtr device = DeviceKitInformation::device(runConfiguration->target()->kit()); QTC_ASSERT(device->type() == ProjectExplorer::Constants::DESKTOP_DEVICE_TYPE, return sp); QTcpServer server; @@ -338,46 +378,12 @@ RunControl *DebuggerRunControlFactory::create if (mode == DebugRunModeWithBreakOnMain) sp.breakOnMain = true; - return doCreate(sp, runConfiguration, errorMessage); -} - -static bool fixupEngineTypes(DebuggerStartParameters &sp, RunConfiguration *rc, QString *errorMessage) -{ - if (sp.masterEngineType != NoEngineType) - return true; - - if (sp.executable.endsWith(_(".py"))) { - sp.masterEngineType = PdbEngineType; - return true; - } - - if (rc) { - DebuggerRunConfigurationAspect *aspect - = rc->extraAspect<Debugger::DebuggerRunConfigurationAspect>(); - if (const Target *target = rc->target()) - if (!DebuggerRunControlFactory::fillParametersFromKit(&sp, target->kit(), errorMessage)) - return false; - const bool useCppDebugger = aspect->useCppDebugger() && (sp.languages & CppLanguage); - const bool useQmlDebugger = aspect->useQmlDebugger() && (sp.languages & QmlLanguage); - if (useQmlDebugger) { - if (useCppDebugger) { - sp.masterEngineType = QmlCppEngineType; - sp.firstSlaveEngineType = sp.cppEngineType; - sp.secondSlaveEngineType = QmlCppEngineType; - } else { - sp.masterEngineType = QmlEngineType; - } - } else { - sp.masterEngineType = sp.cppEngineType; - } - return true; - } - sp.masterEngineType = sp.cppEngineType; - return true; + sp.runConfiguration = runConfiguration; + return doCreate(sp, errorMessage); } DebuggerRunControl *DebuggerRunControlFactory::doCreate - (const DebuggerStartParameters &sp0, RunConfiguration *rc, QString *errorMessage) + (const DebuggerStartParameters &sp0, QString *errorMessage) { TaskHub::clearTasks(Debugger::Constants::TASK_CATEGORY_DEBUGGER_DEBUGINFO); TaskHub::clearTasks(Debugger::Constants::TASK_CATEGORY_DEBUGGER_RUNTIME); @@ -395,8 +401,34 @@ DebuggerRunControl *DebuggerRunControlFactory::doCreate } } - if (!fixupEngineTypes(sp, rc, errorMessage)) - return 0; + if (sp.masterEngineType == NoEngineType) { + if (sp.executable.endsWith(_(".py"))) { + sp.masterEngineType = PdbEngineType; + } else { + if (RunConfiguration *rc = sp.runConfiguration) { + DebuggerRunConfigurationAspect *aspect + = rc->extraAspect<Debugger::DebuggerRunConfigurationAspect>(); + if (const Target *target = rc->target()) + if (!DebuggerRunControlFactory::fillParametersFromKit(&sp, target->kit(), errorMessage)) + return 0; + const bool useCppDebugger = aspect->useCppDebugger() && (sp.languages & CppLanguage); + const bool useQmlDebugger = aspect->useQmlDebugger() && (sp.languages & QmlLanguage); + if (useQmlDebugger) { + if (useCppDebugger) { + sp.masterEngineType = QmlCppEngineType; + sp.firstSlaveEngineType = sp.cppEngineType; + sp.secondSlaveEngineType = QmlCppEngineType; + } else { + sp.masterEngineType = QmlEngineType; + } + } else { + sp.masterEngineType = sp.cppEngineType; + } + } else { + sp.masterEngineType = sp.cppEngineType; + } + } + } QString error; DebuggerEngine *engine = createEngine(sp.masterEngineType, sp, &error); @@ -406,7 +438,7 @@ DebuggerRunControl *DebuggerRunControlFactory::doCreate *errorMessage = error; return 0; } - return new DebuggerRunControl(rc, engine); + return new DebuggerRunControl(sp.runConfiguration, engine); } IRunConfigurationAspect *DebuggerRunControlFactory::createRunConfigurationAspect(RunConfiguration *rc) @@ -417,7 +449,7 @@ IRunConfigurationAspect *DebuggerRunControlFactory::createRunConfigurationAspect DebuggerRunControl *DebuggerRunControlFactory::createAndScheduleRun(const DebuggerStartParameters &sp) { QString errorMessage; - DebuggerRunControl *rc = doCreate(sp, 0, &errorMessage); + DebuggerRunControl *rc = doCreate(sp, &errorMessage); if (!rc) { ProjectExplorerPlugin::showRunErrorMessage(errorMessage); return 0; @@ -451,7 +483,7 @@ bool DebuggerRunControlFactory::fillParametersFromKit(DebuggerStartParameters *s sp->executable = executableForPid(sp->attachPID); } if (!sp->executable.isEmpty()) - abis = Abi::abisOfBinary(Utils::FileName::fromString(sp->executable)); + abis = Abi::abisOfBinary(FileName::fromString(sp->executable)); } if (!abis.isEmpty()) { // Try exact abis. diff --git a/src/plugins/debugger/debuggerruncontrol.h b/src/plugins/debugger/debuggerruncontrol.h index c09aa46c1b..9b7b15d8e8 100644 --- a/src/plugins/debugger/debuggerruncontrol.h +++ b/src/plugins/debugger/debuggerruncontrol.h @@ -40,7 +40,10 @@ namespace ProjectExplorer { class Kit; } namespace Debugger { -class DebuggerEngine; +class RemoteSetupResult; + +namespace Internal { class DebuggerEngine; } + class DebuggerStartParameters; class DEBUGGER_EXPORT DebuggerRunControl @@ -59,20 +62,32 @@ public: QString displayName() const; void startFailed(); + void notifyEngineRemoteServerRunning(const QByteArray &msg, int pid); + void notifyEngineRemoteSetupFinished(const RemoteSetupResult &result); + void notifyInferiorIll(); + Q_SLOT void notifyInferiorExited(); + void quitDebugger(); + void abortDebugger(); void debuggingFinished(); - DebuggerEngine *engine(); + + void showMessage(const QString &msg, int channel = LogDebug); + + DebuggerStartParameters &startParameters(); signals: - void engineRequestSetup(); + void requestRemoteSetup(); + void aboutToNotifyInferiorSetupOk(); + void stateChanged(Debugger::DebuggerState state); private slots: void handleFinished(); private: friend class DebuggerRunControlFactory; - DebuggerRunControl(ProjectExplorer::RunConfiguration *runConfiguration, DebuggerEngine *engine); + DebuggerRunControl(ProjectExplorer::RunConfiguration *runConfiguration, + Internal::DebuggerEngine *engine); - DebuggerEngine *m_engine; + Internal::DebuggerEngine *m_engine; bool m_running; }; @@ -91,7 +106,7 @@ public: bool canRun(ProjectExplorer::RunConfiguration *runConfiguration, ProjectExplorer::RunMode mode) const; - static DebuggerEngine *createEngine(DebuggerEngineType et, + static Internal::DebuggerEngine *createEngine(DebuggerEngineType et, const DebuggerStartParameters &sp, QString *errorMessage); @@ -103,8 +118,7 @@ public: static DebuggerRunControl *createAndScheduleRun(const DebuggerStartParameters &sp); - static DebuggerRunControl *doCreate(const DebuggerStartParameters &sp, - ProjectExplorer::RunConfiguration *rc, QString *errorMessage); + static DebuggerRunControl *doCreate(const DebuggerStartParameters &sp, QString *errorMessage); ProjectExplorer::IRunConfigurationAspect *createRunConfigurationAspect( ProjectExplorer::RunConfiguration *rc); diff --git a/src/plugins/debugger/debuggersourcepathmappingwidget.cpp b/src/plugins/debugger/debuggersourcepathmappingwidget.cpp index 1f081559b5..1f9dfaa43e 100644 --- a/src/plugins/debugger/debuggersourcepathmappingwidget.cpp +++ b/src/plugins/debugger/debuggersourcepathmappingwidget.cpp @@ -228,40 +228,41 @@ DebuggerSourcePathMappingWidget::DebuggerSourcePathMappingWidget(QWidget *parent m_treeView->setSelectionMode(QAbstractItemView::SingleSelection); m_treeView->setSelectionBehavior(QAbstractItemView::SelectRows); m_treeView->setModel(m_model); - connect(m_treeView->selectionModel(), - SIGNAL(currentRowChanged(QModelIndex,QModelIndex)), - SLOT(slotCurrentRowChanged(QModelIndex,QModelIndex))); + connect(m_treeView->selectionModel(), &QItemSelectionModel::currentRowChanged, + this, &DebuggerSourcePathMappingWidget::slotCurrentRowChanged); // Top list/Right part: Buttons. - QVBoxLayout *buttonLayout = new QVBoxLayout; + auto buttonLayout = new QVBoxLayout; buttonLayout->addWidget(m_addButton); buttonLayout->addWidget(m_addQtButton); m_addQtButton->setVisible(sizeof(qtBuildPaths) > 0); m_addQtButton->setToolTip(tr("Add a mapping for Qt's source folders " "when using an unpatched version of Qt.")); buttonLayout->addWidget(m_removeButton); - connect(m_addButton, SIGNAL(clicked()), this, SLOT(slotAdd())); - connect(m_addQtButton, SIGNAL(clicked()), this, SLOT(slotAddQt())); - - connect(m_removeButton, SIGNAL(clicked()), this, SLOT(slotRemove())); + connect(m_addButton, &QAbstractButton::clicked, + this, &DebuggerSourcePathMappingWidget::slotAdd); + connect(m_addQtButton, &QAbstractButton::clicked, + this, &DebuggerSourcePathMappingWidget::slotAddQt); + connect(m_removeButton, &QAbstractButton::clicked, + this, &DebuggerSourcePathMappingWidget::slotRemove); buttonLayout->addItem(new QSpacerItem(0, 0, QSizePolicy::Ignored, QSizePolicy::MinimumExpanding)); // Assemble top - QHBoxLayout *treeHLayout = new QHBoxLayout; + auto treeHLayout = new QHBoxLayout; treeHLayout->addWidget(m_treeView); treeHLayout->addLayout(buttonLayout); // Edit part m_targetChooser->setExpectedKind(PathChooser::ExistingDirectory); m_targetChooser->setHistoryCompleter(QLatin1String("Debugger.MappingTarget.History")); - connect(m_sourceLineEdit, SIGNAL(textChanged(QString)), - this, SLOT(slotEditSourceFieldChanged())); - connect(m_targetChooser, SIGNAL(changed(QString)), - this, SLOT(slotEditTargetFieldChanged())); - QFormLayout *editLayout = new QFormLayout; + connect(m_sourceLineEdit, &QLineEdit::textChanged, + this, &DebuggerSourcePathMappingWidget::slotEditSourceFieldChanged); + connect(m_targetChooser, &PathChooser::changed, + this, &DebuggerSourcePathMappingWidget::slotEditTargetFieldChanged); + auto editLayout = new QFormLayout; const QString sourceToolTip = tr("The source path contained in the " "debug information of the executable as reported by the debugger"); - QLabel *editSourceLabel = new QLabel(tr("&Source path:")); + auto editSourceLabel = new QLabel(tr("&Source path:")); editSourceLabel->setToolTip(sourceToolTip); m_sourceLineEdit->setToolTip(sourceToolTip); editSourceLabel->setBuddy(m_sourceLineEdit); @@ -269,7 +270,7 @@ DebuggerSourcePathMappingWidget::DebuggerSourcePathMappingWidget(QWidget *parent const QString targetToolTip = tr("The actual location of the source " "tree on the local machine"); - QLabel *editTargetLabel = new QLabel(tr("&Target path:")); + auto editTargetLabel = new QLabel(tr("&Target path:")); editTargetLabel->setToolTip(targetToolTip); editTargetLabel->setBuddy(m_targetChooser); m_targetChooser->setToolTip(targetToolTip); @@ -279,7 +280,7 @@ DebuggerSourcePathMappingWidget::DebuggerSourcePathMappingWidget(QWidget *parent chooser->addSupportedWidget(m_targetChooser->lineEdit()); // Main layout - QVBoxLayout *mainLayout = new QVBoxLayout; + auto mainLayout = new QVBoxLayout; mainLayout->addLayout(treeHLayout); mainLayout->addLayout(editLayout); setLayout(mainLayout); diff --git a/src/plugins/debugger/debuggerstartparameters.h b/src/plugins/debugger/debuggerstartparameters.h index 3233511ce0..d89af005cc 100644 --- a/src/plugins/debugger/debuggerstartparameters.h +++ b/src/plugins/debugger/debuggerstartparameters.h @@ -39,9 +39,11 @@ #include <utils/environment.h> #include <projectexplorer/abi.h> #include <projectexplorer/kit.h> +#include <projectexplorer/runconfiguration.h> #include <projectexplorer/devicesupport/idevice.h> #include <QMetaType> +#include <QVector> namespace Debugger { @@ -81,6 +83,7 @@ public: firstSlaveEngineType(NoEngineType), secondSlaveEngineType(NoEngineType), cppEngineType(NoEngineType), + runConfiguration(0), isSnapshot(false), attachPID(-1), useTerminal(false), @@ -111,6 +114,7 @@ public: QString debuggerCommand; ProjectExplorer::Abi toolChainAbi; ProjectExplorer::IDevice::ConstPtr device; + QPointer<ProjectExplorer::RunConfiguration> runConfiguration; QString platform; QString executable; @@ -156,6 +160,9 @@ public: bool useContinueInsteadOfRun; // if connected to a hw debugger run is not possible but continue is used QByteArray commandsAfterConnect; // additional commands to post after connection to debug target + // Used by Valgrind + QVector<QByteArray> expectedSignals; + QStringList solibSearchPath; DebuggerStartMode startMode; DebuggerCloseMode closeMode; diff --git a/src/plugins/debugger/debuggertooltipmanager.cpp b/src/plugins/debugger/debuggertooltipmanager.cpp index 7fa9e63ee5..5855b03366 100644 --- a/src/plugins/debugger/debuggertooltipmanager.cpp +++ b/src/plugins/debugger/debuggertooltipmanager.cpp @@ -44,7 +44,7 @@ #include <texteditor/texteditor.h> #include <utils/tooltip/tooltip.h> -#include <utils/tooltip/tipcontents.h> +#include <utils/treemodel.h> #include <utils/qtcassert.h> #include <QAbstractItemModel> @@ -66,6 +66,7 @@ using namespace Core; using namespace TextEditor; +using namespace Utils; namespace Debugger { namespace Internal { @@ -94,9 +95,9 @@ const char dateAttributeC[] = "date"; const char treeElementC[] = "tree"; const char treeExpressionAttributeC[] = "expression"; const char treeInameAttributeC[] = "iname"; -const char modelElementC[] = "model"; -const char modelColumnCountAttributeC[] = "columncount"; -const char modelRowElementC[] = "row"; +// const char modelElementC[] = "model"; +// const char modelColumnCountAttributeC[] = "columncount"; +// const char modelRowElementC[] = "row"; const char modelItemElementC[] = "item"; static void purgeClosedToolTips(); @@ -179,299 +180,176 @@ void DraggableLabel::mouseMoveEvent(QMouseEvent * event) QLabel::mouseMoveEvent(event); } -// Helper for building a QStandardItemModel of a tree form (see TreeModelVisitor). -// The recursion/building is based on the scheme: \code -// <row><item1><item2> -// <row><item11><item12></row> -// </row> -// \endcode - -class StandardItemTreeModelBuilder -{ -public: - typedef QList<QStandardItem *> StandardItemRow; - - explicit StandardItemTreeModelBuilder(QStandardItemModel *m, Qt::ItemFlags f = Qt::ItemIsSelectable); - - void addItem(const QString &); - void startRow(); - void endRow(); - -private: - void pushRow(); - - QStandardItemModel *m_model; - const Qt::ItemFlags m_flags; - StandardItemRow m_row; - QStack<QStandardItem *> m_rowParents; -}; - -StandardItemTreeModelBuilder::StandardItemTreeModelBuilder(QStandardItemModel *m, Qt::ItemFlags f) : - m_model(m), m_flags(f) -{ - m_model->removeRows(0, m_model->rowCount()); -} - -void StandardItemTreeModelBuilder::addItem(const QString &s) -{ - QStandardItem *item = new QStandardItem(s); - item->setFlags(m_flags); - m_row.push_back(item); -} - -void StandardItemTreeModelBuilder::pushRow() -{ - if (m_rowParents.isEmpty()) - m_model->appendRow(m_row); - else - m_rowParents.top()->appendRow(m_row); - m_rowParents.push(m_row.front()); - m_row.clear(); -} - -void StandardItemTreeModelBuilder::startRow() -{ - // Push parent in case rows are nested. This is a Noop for the very first row. - if (!m_row.isEmpty()) - pushRow(); -} - -void StandardItemTreeModelBuilder::endRow() -{ - if (!m_row.isEmpty()) // Push row if no child rows have been encountered - pushRow(); - m_rowParents.pop(); -} +///////////////////////////////////////////////////////////////////////// +// +// ToolTipWatchItem +// +///////////////////////////////////////////////////////////////////////// -// Helper visitor base class for recursing over a tree model -// (see StandardItemTreeModelBuilder for the scheme). -class TreeModelVisitor +class ToolTipWatchItem : public Utils::TreeItem { public: - virtual void run() { run(QModelIndex()); } - -protected: - TreeModelVisitor(const QAbstractItemModel *model) : m_model(model) {} - - virtual void rowStarted() {} - virtual void handleItem(const QModelIndex &m) = 0; - virtual void rowEnded() {} + ToolTipWatchItem() : expandable(false) {} + ToolTipWatchItem(WatchItem *item); - const QAbstractItemModel *model() const { return m_model; } + bool hasChildren() const { return expandable; } + bool canFetchMore() const { return children().isEmpty() && expandable && model(); } + void fetchMore() {} + QVariant data(int column, int role) const; -private: - void run(const QModelIndex &parent); - - const QAbstractItemModel *m_model; -}; - -void TreeModelVisitor::run(const QModelIndex &parent) -{ - const int columnCount = m_model->columnCount(parent); - const int rowCount = m_model->rowCount(parent); - for (int r = 0; r < rowCount; r++) { - rowStarted(); - QModelIndex left; - for (int c = 0; c < columnCount; c++) { - const QModelIndex index = m_model->index(r, c, parent); - handleItem(index); - if (!c) - left = index; - } - if (left.isValid()) - run(left); - rowEnded(); - } -} - -// Visitor writing out a tree model in XML format. -class XmlWriterTreeModelVisitor : public TreeModelVisitor -{ public: - XmlWriterTreeModelVisitor(const QAbstractItemModel *model, QXmlStreamWriter &w); - - virtual void run(); - -protected: - virtual void rowStarted() { m_writer.writeStartElement(QLatin1String(modelRowElementC)); } - virtual void handleItem(const QModelIndex &m); - virtual void rowEnded() { m_writer.writeEndElement(); } - -private: - const QString m_modelItemElement; - QXmlStreamWriter &m_writer; + QString name; + QString value; + QString type; + QColor color; + bool expandable; + QByteArray iname; }; -XmlWriterTreeModelVisitor::XmlWriterTreeModelVisitor(const QAbstractItemModel *model, QXmlStreamWriter &w) : - TreeModelVisitor(model), m_modelItemElement(QLatin1String(modelItemElementC)), m_writer(w) +ToolTipWatchItem::ToolTipWatchItem(WatchItem *item) { + name = item->displayName(); + value = item->displayValue(); + type = item->displayType(); + iname = item->d.iname; + color = item->color(); + expandable = item->d.hasChildren; + foreach (TreeItem *child, item->children()) + appendChild(new ToolTipWatchItem(static_cast<WatchItem *>(child))); } -void XmlWriterTreeModelVisitor::run() -{ - m_writer.writeStartElement(QLatin1String(modelElementC)); - const int columnCount = model()->columnCount(); - m_writer.writeAttribute(QLatin1String(modelColumnCountAttributeC), QString::number(columnCount)); - TreeModelVisitor::run(); - m_writer.writeEndElement(); -} - -void XmlWriterTreeModelVisitor::handleItem(const QModelIndex &m) -{ - const QString value = m.data(Qt::DisplayRole).toString(); - if (value.isEmpty()) - m_writer.writeEmptyElement(m_modelItemElement); - else - m_writer.writeTextElement(m_modelItemElement, value); -} +///////////////////////////////////////////////////////////////////////// +// +// ToolTipModel +// +///////////////////////////////////////////////////////////////////////// -// TreeModelVisitor for debugging/copying models -class DumpTreeModelVisitor : public TreeModelVisitor +class ToolTipModel : public TreeModel { public: - enum Mode + ToolTipModel() { - DebugMode, // For debugging, "|'data'|" - ClipboardMode // Tab-delimited "\tdata" for clipboard (see stack window) - }; - explicit DumpTreeModelVisitor(const QAbstractItemModel *model, Mode m, QTextStream &s); - -protected: - virtual void rowStarted(); - virtual void handleItem(const QModelIndex &m); - virtual void rowEnded(); - -private: - const Mode m_mode; - - QTextStream &m_stream; - int m_level; - unsigned m_itemsInRow; -}; - -DumpTreeModelVisitor::DumpTreeModelVisitor(const QAbstractItemModel *model, Mode m, QTextStream &s) : - TreeModelVisitor(model), m_mode(m), m_stream(s), m_level(0), m_itemsInRow(0) -{ - if (m_mode == DebugMode) - m_stream << model->metaObject()->className() << '/' << model->objectName(); -} - -void DumpTreeModelVisitor::rowStarted() -{ - m_level++; - if (m_itemsInRow) { // Nested row. - m_stream << '\n'; - m_itemsInRow = 0; - } - switch (m_mode) { - case DebugMode: - m_stream << QString(2 * m_level, QLatin1Char(' ')); - break; - case ClipboardMode: - m_stream << QString(m_level, QLatin1Char('\t')); - break; + QStringList headers; + headers.append(tr("Name")); + headers.append(tr("Value")); + headers.append(tr("Type")); + setHeader(headers); + m_enabled = true; + auto item = new ToolTipWatchItem; + item->expandable = true; + setRootItem(item); } -} -void DumpTreeModelVisitor::handleItem(const QModelIndex &m) -{ - const QString data = m.data().toString(); - switch (m_mode) { - case DebugMode: - if (m.column()) - m_stream << '|'; - m_stream << '\'' << data << '\''; - break; - case ClipboardMode: - if (m.column()) - m_stream << '\t'; - m_stream << data; - break; + void expandNode(const QModelIndex &idx) + { + m_expandedINames.insert(idx.data(LocalsINameRole).toByteArray()); + if (canFetchMore(idx)) + fetchMore(idx); } - m_itemsInRow++; -} -void DumpTreeModelVisitor::rowEnded() -{ - if (m_itemsInRow) { - m_stream << '\n'; - m_itemsInRow = 0; + void collapseNode(const QModelIndex &idx) + { + m_expandedINames.remove(idx.data(LocalsINameRole).toByteArray()); } - m_level--; -} -/* -static QDebug operator<<(QDebug d, const QAbstractItemModel &model) -{ - QString s; - QTextStream str(&s); - Debugger::Internal::DumpTreeModelVisitor v(&model, Debugger::Internal::DumpTreeModelVisitor::DebugMode, str); - v.run(); - qCDebug(tooltip).nospace() << s; - return d; -} -*/ + void fetchMore(const QModelIndex &idx) + { + if (!idx.isValid()) + return; + auto item = dynamic_cast<ToolTipWatchItem *>(itemFromIndex(idx)); + if (!item) + return; + QByteArray iname = item->iname; + if (!m_engine) + return; -/*! - \class Debugger::Internal::TooltipFilterModel + WatchItem *it = m_engine->watchHandler()->findItem(iname); + QTC_ASSERT(it, return); + it->fetchMore(); + } - \brief The TooltipFilterModel class is a model for tooltips filtering an - item on the watchhandler matching its tree on the iname. + void restoreTreeModel(QXmlStreamReader &r); - In addition, suppress the model's tooltip data to avoid a tooltip on a tooltip. -*/ + QPointer<DebuggerEngine> m_engine; + QSet<QByteArray> m_expandedINames; + bool m_enabled; +}; -class TooltipFilterModel : public QSortFilterProxyModel -{ -public: - TooltipFilterModel() {} +QVariant ToolTipWatchItem::data(int column, int role) const +{ + switch (role) { + case Qt::DisplayRole: { + switch (column) { + case 0: + return name; + case 1: + return value; + case 2: + return type; + } + } - QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const - { - return role == Qt::ToolTipRole - ? QVariant() : QSortFilterProxyModel::data(index, role); - } + case LocalsINameRole: + return iname; - static bool isSubIname(const QByteArray &haystack, const QByteArray &needle) - { - return haystack.size() > needle.size() - && haystack.startsWith(needle) - && haystack.at(needle.size()) == '.'; - } + case Qt::ForegroundRole: + if (model() && static_cast<ToolTipModel *>(model())->m_enabled) { + if (column == 1) + return color; + return QVariant(); + } + return QColor(140, 140, 140); - bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const - { - const QModelIndex nameIndex = sourceModel()->index(sourceRow, 0, sourceParent); - const QByteArray iname = nameIndex.data(LocalsINameRole).toByteArray(); -// DEBUG("ACCEPTING FILTER" << iname -// << (iname == m_iname || isSubIname(iname, m_iname) || isSubIname(m_iname, iname)); - return iname == m_iname || isSubIname(iname, m_iname) || isSubIname(m_iname, iname); + default: + break; } + return QVariant(); +} - QByteArray m_iname; -}; - -///////////////////////////////////////////////////////////////////////// -// -// TreeModelCopyVisitor builds a QStandardItem from a tree model (copy). -// -///////////////////////////////////////////////////////////////////////// - -class TreeModelCopyVisitor : public TreeModelVisitor +void ToolTipModel::restoreTreeModel(QXmlStreamReader &r) { -public: - TreeModelCopyVisitor(const QAbstractItemModel *source, QStandardItemModel *target) : - TreeModelVisitor(source), m_builder(target) - {} - -protected: - virtual void rowStarted() { m_builder.startRow(); } - virtual void handleItem(const QModelIndex &m) { m_builder.addItem(m.data().toString()); } - virtual void rowEnded() { m_builder.endRow(); } + Q_UNUSED(r); +#if 0 +// Helper for building a QStandardItemModel of a tree form (see TreeModelVisitor). +// The recursion/building is based on the scheme: \code +// <row><item1><item2> +// <row><item11><item12></row> +// </row> +// \endcode -private: - StandardItemTreeModelBuilder m_builder; -}; + bool withinModel = true; + while (withinModel && !r.atEnd()) { + const QXmlStreamReader::TokenType token = r.readNext(); + switch (token) { + case QXmlStreamReader::StartElement: { + const QStringRef element = r.name(); + // Root model element with column count. + if (element == QLatin1String(modelElementC)) { + if (const int cc = r.attributes().value(QLatin1String(modelColumnCountAttributeC)).toString().toInt()) + columnCount = cc; + m->setColumnCount(columnCount); + } else if (element == QLatin1String(modelRowElementC)) { + builder.startRow(); + } else if (element == QLatin1String(modelItemElementC)) { + builder.addItem(r.readElementText()); + } + } + break; // StartElement + case QXmlStreamReader::EndElement: { + const QStringRef element = r.name(); + // Row closing: pop off parent. + if (element == QLatin1String(modelRowElementC)) + builder.endRow(); + else if (element == QLatin1String(modelElementC)) + withinModel = false; + } + break; // EndElement + default: + break; + } // switch + } // while +#endif +} /*! \class Debugger::Internal::DebuggerToolTipTreeView @@ -491,16 +369,24 @@ public: void computeSize(); + void setEngine(DebuggerEngine *engine); private: - void expandNode(const QModelIndex &idx); - void collapseNode(const QModelIndex &idx); int computeHeight(const QModelIndex &index) const; + WatchHandler *watchHandler() const + { + return m_model.m_engine->watchHandler(); + } + QSize m_size; + +public: + ToolTipModel m_model; + void reexpand(const QModelIndex &idx); }; -DebuggerToolTipTreeView::DebuggerToolTipTreeView(QWidget *parent) : - QTreeView(parent) +DebuggerToolTipTreeView::DebuggerToolTipTreeView(QWidget *parent) + : QTreeView(parent) { setHeaderHidden(true); setEditTriggers(NoEditTriggers); @@ -509,25 +395,20 @@ DebuggerToolTipTreeView::DebuggerToolTipTreeView(QWidget *parent) : setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); + setModel(&m_model); + connect(this, &QTreeView::collapsed, this, &DebuggerToolTipTreeView::computeSize, Qt::QueuedConnection); connect(this, &QTreeView::expanded, this, &DebuggerToolTipTreeView::computeSize, Qt::QueuedConnection); - connect(this, &QTreeView::expanded, - this, &DebuggerToolTipTreeView::expandNode); - connect(this, &QTreeView::collapsed, - this, &DebuggerToolTipTreeView::collapseNode); + connect(this, &QTreeView::expanded, &m_model, &ToolTipModel::expandNode); + connect(this, &QTreeView::collapsed, &m_model, &ToolTipModel::collapseNode); } -void DebuggerToolTipTreeView::expandNode(const QModelIndex &idx) +void DebuggerToolTipTreeView::setEngine(DebuggerEngine *engine) { - model()->setData(idx, true, LocalsExpandedRole); -} - -void DebuggerToolTipTreeView::collapseNode(const QModelIndex &idx) -{ - model()->setData(idx, false, LocalsExpandedRole); + m_model.m_engine = engine; } int DebuggerToolTipTreeView::computeHeight(const QModelIndex &index) const @@ -539,6 +420,26 @@ int DebuggerToolTipTreeView::computeHeight(const QModelIndex &index) const return s; } +void DebuggerToolTipTreeView::reexpand(const QModelIndex &idx) +{ + TreeItem *item = m_model.itemFromIndex(idx); + QTC_ASSERT(item, return); + QByteArray iname = item->data(0, LocalsINameRole).toByteArray(); + bool shouldExpand = m_model.m_expandedINames.contains(iname); + if (shouldExpand) { + if (!isExpanded(idx)) { + expand(idx); + for (int i = 0, n = model()->rowCount(idx); i != n; ++i) { + QModelIndex idx1 = model()->index(i, 0, idx); + reexpand(idx1); + } + } + } else { + if (isExpanded(idx)) + collapse(idx); + } +} + void DebuggerToolTipTreeView::computeSize() { int columns = 30; // Decoration @@ -546,13 +447,14 @@ void DebuggerToolTipTreeView::computeSize() bool rootDecorated = false; if (QAbstractItemModel *m = model()) { - WatchTreeView::reexpand(this, m->index(0, 0)); + reexpand(m->index(0, 0)); const int columnCount = m->columnCount(); rootDecorated = m->rowCount() > 0; - if (rootDecorated) - for (int i = 0; i < columnCount; ++i) { - resizeColumnToContents(i); - columns += sizeHintForColumn(i); + if (rootDecorated) { + for (int i = 0; i < columnCount; ++i) { + resizeColumnToContents(i); + columns += sizeHintForColumn(i); + } } if (columns < 100) columns = 100; // Prevent toolbar from shrinking when displaying 'Previous' @@ -592,17 +494,6 @@ void DebuggerToolTipTreeView::computeSize() setRootIsDecorated(rootDecorated); } -QString DebuggerToolTipManager::treeModelClipboardContents(const QAbstractItemModel *model) -{ - QString rc; - QTC_ASSERT(model, return rc); - QTextStream str(&rc); - DumpTreeModelVisitor v(model, DumpTreeModelVisitor::ClipboardMode, str); - v.run(); - return rc; -} - - ///////////////////////////////////////////////////////////////////////// // // DebuggerToolTipWidget @@ -612,49 +503,7 @@ QString DebuggerToolTipManager::treeModelClipboardContents(const QAbstractItemMo class DebuggerToolTipWidget : public QWidget { public: - DebuggerToolTipWidget() - { - setAttribute(Qt::WA_DeleteOnClose); - - isPinned = false; - const QIcon pinIcon(QLatin1String(":/debugger/images/pin.xpm")); - - pinButton = new QToolButton; - pinButton->setIcon(pinIcon); - - auto copyButton = new QToolButton; - copyButton->setIcon(QIcon(QLatin1String(Core::Constants::ICON_COPY))); - - titleLabel = new DraggableLabel(this); - titleLabel->setMinimumWidth(40); // Ensure a draggable area even if text is empty. - titleLabel->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Preferred); - - auto toolBar = new QToolBar(this); - toolBar->setProperty("_q_custom_style_disabled", QVariant(true)); - const QList<QSize> pinIconSizes = pinIcon.availableSizes(); - if (!pinIconSizes.isEmpty()) - toolBar->setIconSize(pinIconSizes.front()); - toolBar->addWidget(pinButton); - toolBar->addWidget(copyButton); - toolBar->addWidget(titleLabel); - - treeView = new DebuggerToolTipTreeView(this); - treeView->setFocusPolicy(Qt::NoFocus); - - auto mainLayout = new QVBoxLayout(this); - mainLayout->setSizeConstraint(QLayout::SetFixedSize); - mainLayout->setContentsMargins(0, 0, 0, 0); - mainLayout->addWidget(toolBar); - mainLayout->addWidget(treeView); - - connect(copyButton, &QAbstractButton::clicked, [this] { - QString clipboardText = DebuggerToolTipManager::treeModelClipboardContents(treeView->model()); - QClipboard *clipboard = QApplication::clipboard(); - clipboard->setText(clipboardText, QClipboard::Selection); - clipboard->setText(clipboardText, QClipboard::Clipboard); - }); - DEBUG("CREATE DEBUGGERTOOLTIP WIDGET"); - } + DebuggerToolTipWidget(); ~DebuggerToolTipWidget() { @@ -688,7 +537,7 @@ public: if (parentWidget()) { // We are currently within a text editor tooltip: // Rip out of parent widget and re-show as a tooltip - Utils::WidgetContent::pinToolTip(this, ICore::mainWindow()); + ToolTip::pinToolTip(this, ICore::mainWindow()); } else { // We have just be restored from session data. setWindowFlags(Qt::ToolTip); @@ -703,6 +552,58 @@ public: DebuggerToolTipTreeView *treeView; }; +DebuggerToolTipWidget::DebuggerToolTipWidget() +{ + setAttribute(Qt::WA_DeleteOnClose); + + isPinned = false; + const QIcon pinIcon(QLatin1String(":/debugger/images/pin.xpm")); + + pinButton = new QToolButton; + pinButton->setIcon(pinIcon); + + auto copyButton = new QToolButton; + copyButton->setToolTip(DebuggerToolTipManager::tr("Copy Contents to Clipboard")); + copyButton->setIcon(QIcon(QLatin1String(Core::Constants::ICON_COPY))); + + titleLabel = new DraggableLabel(this); + titleLabel->setMinimumWidth(40); // Ensure a draggable area even if text is empty. + titleLabel->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Preferred); + + auto toolBar = new QToolBar(this); + toolBar->setProperty("_q_custom_style_disabled", QVariant(true)); + const QList<QSize> pinIconSizes = pinIcon.availableSizes(); + if (!pinIconSizes.isEmpty()) + toolBar->setIconSize(pinIconSizes.front()); + toolBar->addWidget(pinButton); + toolBar->addWidget(copyButton); + toolBar->addWidget(titleLabel); + + treeView = new DebuggerToolTipTreeView(this); + treeView->setFocusPolicy(Qt::NoFocus); + + auto mainLayout = new QVBoxLayout(this); + mainLayout->setSizeConstraint(QLayout::SetFixedSize); + mainLayout->setContentsMargins(0, 0, 0, 0); + mainLayout->addWidget(toolBar); + mainLayout->addWidget(treeView); + + connect(copyButton, &QAbstractButton::clicked, [this] { + QString text; + QTextStream str(&text); + treeView->m_model.rootItem()->walkTree([&str](TreeItem *item) { + auto titem = static_cast<ToolTipWatchItem *>(item); + str << QString(item->level(), QLatin1Char('\t')) + << titem->name << '\t' << titem->value << '\t' << titem->type << '\n'; + }); + QClipboard *clipboard = QApplication::clipboard(); + clipboard->setText(text, QClipboard::Selection); + clipboard->setText(text, QClipboard::Clipboard); + }); + DEBUG("CREATE DEBUGGERTOOLTIP WIDGET"); +} + + ///////////////////////////////////////////////////////////////////////// // // DebuggerToolTipHolder @@ -724,7 +625,7 @@ public: DebuggerToolTipHolder(const DebuggerToolTipContext &context); ~DebuggerToolTipHolder(); - void acquireEngine(); + void acquireEngine(DebuggerEngine *engine); void releaseEngine(); void saveSessionData(QXmlStreamWriter &w) const; @@ -732,19 +633,15 @@ public: void positionShow(const TextEditorWidget *editorWidget); - void handleItemIsExpanded(const QModelIndex &sourceIdx); - void updateTooltip(const StackFrame &frame); + void updateTooltip(DebuggerEngine *engine); void setState(DebuggerTootipState newState); void destroy(); public: QPointer<DebuggerToolTipWidget> widget; - QPointer<DebuggerEngine> engine; QDate creationDate; DebuggerToolTipContext context; - TooltipFilterModel filterModel; //!< Pointing to a valid watchModel - QStandardItemModel defaultModel; DebuggerTootipState state; }; @@ -756,15 +653,6 @@ static void hideAllToolTips() tooltip->widget->hide(); } -void DebuggerToolTipHolder::handleItemIsExpanded(const QModelIndex &sourceIdx) -{ - QTC_ASSERT(filterModel.sourceModel() == sourceIdx.model(), return); - QModelIndex mappedIdx = filterModel.mapFromSource(sourceIdx); - QTC_ASSERT(widget.data(), return); - if (!widget->treeView->isExpanded(mappedIdx)) - widget->treeView->expand(mappedIdx); -} - /*! \class Debugger::Internal::DebuggerToolTipContext @@ -803,6 +691,12 @@ bool DebuggerToolTipContext::isSame(const DebuggerToolTipContext &other) const && iname == other.iname; } +QString DebuggerToolTipContext::toolTip() const +{ + return DebuggerToolTipManager::tr("Expression %1 in function %2 from line %3 to %4") + .arg(expression).arg(function).arg(scopeFromLine).arg(scopeToLine); +} + QDebug operator<<(QDebug d, const DebuggerToolTipContext &c) { QDebug nsp = d.nospace(); @@ -859,14 +753,11 @@ DebuggerToolTipHolder::DebuggerToolTipHolder(const DebuggerToolTipContext &conte state = New; - filterModel.m_iname = context.iname; - QObject::connect(widget->pinButton, &QAbstractButton::clicked, [this] { - if (widget->isPinned) { + if (widget->isPinned) widget->close(); - } else { + else widget->pin(); - } }); DEBUG("CREATE DEBUGGERTOOLTIPHOLDER" << context.iname); } @@ -885,39 +776,35 @@ DebuggerToolTipHolder::~DebuggerToolTipHolder() // If we are in "Acquired" or "Released", this is an update // after normal WatchModel update. -void DebuggerToolTipHolder::updateTooltip(const StackFrame &frame) +void DebuggerToolTipHolder::updateTooltip(DebuggerEngine *engine) { + widget->treeView->setEngine(engine); + + if (!engine) { + setState(Released); + return; + } + + StackFrame frame = engine->stackHandler()->currentFrame(); + const bool sameFrame = context.matchesFrame(frame); DEBUG("UPDATE TOOLTIP: STATE " << state << context.iname << "PINNED: " << widget->isPinned << "SHOW NEEDED: " << widget->isPinned << "SAME FRAME: " << sameFrame); + if (state == PendingUnshown) { - const Utils::WidgetContent widgetContent(widget, true); - Utils::ToolTip::show(context.mousePosition, widgetContent, Internal::mainWindow()); + ToolTip::show(context.mousePosition, widget, Internal::mainWindow()); setState(PendingShown); } - if (state == PendingShown) { - acquireEngine(); - Utils::ToolTip::move(context.mousePosition, Internal::mainWindow()); - } else if (state == Acquired && !sameFrame) { + if (sameFrame) { + acquireEngine(engine); + } else { releaseEngine(); - } else if (state == Released && sameFrame) { - acquireEngine(); - } - - if (state == Acquired) { - // Save data to stream and restore to the backup m_defaultModel. - // Doing it on releaseEngine() is too later. - defaultModel.removeRows(0, defaultModel.rowCount()); - TreeModelCopyVisitor v(&filterModel, &defaultModel); - v.run(); - - widget->treeView->expand(filterModel.index(0, 0)); - WatchTreeView::reexpand(widget->treeView, filterModel.index(0, 0)); } + widget->titleLabel->setToolTip(context.toolTip()); } void DebuggerToolTipHolder::setState(DebuggerTootipState newState) @@ -948,29 +835,38 @@ void DebuggerToolTipHolder::destroy() } } -void DebuggerToolTipHolder::acquireEngine() +void DebuggerToolTipHolder::acquireEngine(DebuggerEngine *engine) { DEBUG("ACQUIRE ENGINE: STATE " << state); setState(Acquired); QTC_ASSERT(widget, return); widget->titleLabel->setText(context.expression); - widget->treeView->setModel(&filterModel); - widget->treeView->setRootIndex(filterModel.index(0, 0)); - widget->treeView->expand(filterModel.index(0, 0)); - WatchTreeView::reexpand(widget->treeView, filterModel.index(0, 0)); + //widget->treeView->setEnabled(true); + widget->treeView->m_model.m_enabled = true; + + WatchItem *item = engine->watchHandler()->findItem(context.iname); + if (item) { + auto clone = new ToolTipWatchItem(item); + widget->treeView->m_model.rootItem()->removeChildren(); + widget->treeView->m_model.rootItem()->appendChild(clone); + } + WatchTreeView::reexpand(widget->treeView, QModelIndex()); + widget->treeView->computeSize(); } void DebuggerToolTipHolder::releaseEngine() { + if (state == Released) + return; DEBUG("RELEASE ENGINE: STATE " << state); setState(Released); QTC_ASSERT(widget, return); + widget->treeView->m_model.m_enabled = false; + widget->treeView->m_model.layoutChanged(); widget->titleLabel->setText(DebuggerToolTipManager::tr("%1 (Previous)").arg(context.expression)); - widget->treeView->setModel(&defaultModel); - widget->treeView->setRootIndex(defaultModel.index(0, 0)); - widget->treeView->expandAll(); +// widget->treeView->setEnabled(false); } void DebuggerToolTipHolder::positionShow(const TextEditorWidget *editorWidget) @@ -1023,44 +919,7 @@ static DebuggerToolTipHolder *findOrCreateTooltip(const DebuggerToolTipContext & return newTooltip; } -static void restoreTreeModel(QXmlStreamReader &r, QStandardItemModel *m) -{ - StandardItemTreeModelBuilder builder(m); - int columnCount = 1; - bool withinModel = true; - while (withinModel && !r.atEnd()) { - const QXmlStreamReader::TokenType token = r.readNext(); - switch (token) { - case QXmlStreamReader::StartElement: { - const QStringRef element = r.name(); - // Root model element with column count. - if (element == QLatin1String(modelElementC)) { - if (const int cc = r.attributes().value(QLatin1String(modelColumnCountAttributeC)).toString().toInt()) - columnCount = cc; - m->setColumnCount(columnCount); - } else if (element == QLatin1String(modelRowElementC)) { - builder.startRow(); - } else if (element == QLatin1String(modelItemElementC)) { - builder.addItem(r.readElementText()); - } - } - break; // StartElement - case QXmlStreamReader::EndElement: { - const QStringRef element = r.name(); - // Row closing: pop off parent. - if (element == QLatin1String(modelRowElementC)) - builder.endRow(); - else if (element == QLatin1String(modelElementC)) - withinModel = false; - } - break; // EndElement - default: - break; - } // switch - } // while -} - -// Parse a 'yyyyMMdd' date +//// Parse a 'yyyyMMdd' date static QDate dateFromString(const QString &date) { return date.size() == 8 ? @@ -1068,56 +927,6 @@ static QDate dateFromString(const QString &date) QDate(); } -static void loadSessionDataHelper(QXmlStreamReader &r) -{ - if (!readStartElement(r, toolTipElementC)) - return; - const QXmlStreamAttributes attributes = r.attributes(); - DebuggerToolTipContext context; - context.fileName = attributes.value(QLatin1String(fileNameAttributeC)).toString(); - context.position = attributes.value(QLatin1String(textPositionAttributeC)).toString().toInt(); - context.line = attributes.value(QLatin1String(textLineAttributeC)).toString().toInt(); - context.column = attributes.value(QLatin1String(textColumnAttributeC)).toString().toInt(); - context.function = attributes.value(QLatin1String(functionAttributeC)).toString(); - QPoint offset; - const QString offsetXAttribute = QLatin1String(offsetXAttributeC); - const QString offsetYAttribute = QLatin1String(offsetYAttributeC); - if (attributes.hasAttribute(offsetXAttribute)) - offset.setX(attributes.value(offsetXAttribute).toString().toInt()); - if (attributes.hasAttribute(offsetYAttribute)) - offset.setY(attributes.value(offsetYAttribute).toString().toInt()); - context.mousePosition = offset; - - context.iname = attributes.value(QLatin1String(treeInameAttributeC)).toString().toLatin1(); - context.expression = attributes.value(QLatin1String(treeExpressionAttributeC)).toString(); - -// const QStringRef className = attributes.value(QLatin1String(toolTipClassAttributeC)); - context.engineType = attributes.value(QLatin1String(engineTypeAttributeC)).toString(); - context.creationDate = dateFromString(attributes.value(QLatin1String(dateAttributeC)).toString()); - bool readTree = context.isValid(); - if (!context.creationDate.isValid() || context.creationDate.daysTo(QDate::currentDate()) > toolTipsExpiryDays) { - // DEBUG("Expiring tooltip " << context.fileName << '@' << context.position << " from " << creationDate) - //readTree = false; - } else { //if (className != QLatin1String("Debugger::Internal::DebuggerToolTipWidget")) { - //qWarning("Unable to create debugger tool tip widget of class %s", qPrintable(className.toString())); - //readTree = false; - } - - if (readTree) { - DebuggerToolTipHolder *tw = findOrCreateTooltip(context); - restoreTreeModel(r, &tw->defaultModel); - tw->widget->pin(); - tw->widget->titleLabel->setText(DebuggerToolTipManager::tr("%1 (Restored").arg(context.expression)); - tw->widget->treeView->setModel(&tw->defaultModel); - tw->widget->treeView->setRootIndex(tw->defaultModel.index(0, 0)); - tw->widget->treeView->expandAll(); - } else { - r.readElementText(QXmlStreamReader::SkipChildElements); // Skip - } - - r.readNext(); // Skip </tree> -} - void DebuggerToolTipHolder::saveSessionData(QXmlStreamWriter &w) const { w.writeStartElement(QLatin1String(toolTipElementC)); @@ -1140,10 +949,18 @@ void DebuggerToolTipHolder::saveSessionData(QXmlStreamWriter &w) const attributes.append(QLatin1String(treeInameAttributeC), QLatin1String(context.iname)); w.writeAttributes(attributes); - w.writeStartElement(QLatin1String(treeElementC)); - XmlWriterTreeModelVisitor v(&filterModel, w); - v.run(); - w.writeEndElement(); + w.writeStartElement(QLatin1String(treeElementC)); + widget->treeView->m_model.rootItem()->walkTree([&w](TreeItem *item) { + const QString modelItemElement = QLatin1String(modelItemElementC); + for (int i = 0; i < 3; ++i) { + const QString value = item->data(i, Qt::DisplayRole).toString(); + if (value.isEmpty()) + w.writeEmptyElement(modelItemElement); + else + w.writeTextElement(modelItemElement, value); + } + }); + w.writeEndElement(); w.writeEndElement(); } @@ -1191,7 +1008,7 @@ void DebuggerToolTipManager::slotUpdateVisibleToolTips() return; } - const QString fileName = toolTipEditor->textDocument()->filePath(); + const QString fileName = toolTipEditor->textDocument()->filePath().toString(); if (fileName.isEmpty()) { hideAllToolTips(); return; @@ -1206,21 +1023,6 @@ void DebuggerToolTipManager::slotUpdateVisibleToolTips() } } -void DebuggerToolTipManager::slotItemIsExpanded(const QModelIndex &idx) -{ - foreach (DebuggerToolTipHolder *tooltip, m_tooltips) - tooltip->handleItemIsExpanded(idx); -} - -void DebuggerToolTipManager::slotColumnAdjustmentRequested() -{ - foreach (DebuggerToolTipHolder *tooltip, m_tooltips) { - QTC_ASSERT(tooltip, continue); - QTC_ASSERT(tooltip->widget, continue); - tooltip->widget->treeView->computeSize(); - } -} - void DebuggerToolTipManager::updateEngine(DebuggerEngine *engine) { QTC_ASSERT(engine, return); @@ -1230,21 +1032,15 @@ void DebuggerToolTipManager::updateEngine(DebuggerEngine *engine) // Stack frame changed: All tooltips of that file acquire the engine, // all others release (arguable, this could be more precise?) - StackFrame frame = engine->stackHandler()->currentFrame(); foreach (DebuggerToolTipHolder *tooltip, m_tooltips) - tooltip->updateTooltip(frame); + tooltip->updateTooltip(engine); slotUpdateVisibleToolTips(); // Move tooltip when stepping in same file. } - void DebuggerToolTipManager::registerEngine(DebuggerEngine *engine) { + Q_UNUSED(engine) DEBUG("REGISTER ENGINE"); - WatchModelBase *watchModel = engine->watchHandler()->model(); - connect(watchModel, &WatchModelBase::itemIsExpanded, - m_instance, &DebuggerToolTipManager::slotItemIsExpanded); - connect(watchModel, &WatchModelBase::columnAdjustmentRequested, - m_instance, &DebuggerToolTipManager::slotColumnAdjustmentRequested); } void DebuggerToolTipManager::deregisterEngine(DebuggerEngine *engine) @@ -1252,22 +1048,18 @@ void DebuggerToolTipManager::deregisterEngine(DebuggerEngine *engine) DEBUG("DEREGISTER ENGINE"); QTC_ASSERT(engine, return); - // FIXME: For now remove all. purgeClosedToolTips(); - foreach (DebuggerToolTipHolder *tooltip, m_tooltips) - tooltip->destroy(); - purgeClosedToolTips(); - return; - WatchModelBase *watchModel = engine->watchHandler()->model(); - disconnect(watchModel, &WatchModelBase::itemIsExpanded, - m_instance, &DebuggerToolTipManager::slotItemIsExpanded); - disconnect(watchModel, &WatchModelBase::columnAdjustmentRequested, - m_instance, &DebuggerToolTipManager::slotColumnAdjustmentRequested); foreach (DebuggerToolTipHolder *tooltip, m_tooltips) if (tooltip->context.engineType == engine->objectName()) tooltip->releaseEngine(); + saveSessionData(); + + // FIXME: For now remove all. + foreach (DebuggerToolTipHolder *tooltip, m_tooltips) + tooltip->destroy(); + purgeClosedToolTips(); } bool DebuggerToolTipManager::hasToolTips() @@ -1282,20 +1074,61 @@ void DebuggerToolTipManager::sessionAboutToChange() void DebuggerToolTipManager::loadSessionData() { - return; // FIXME - const QString data = sessionValue(sessionSettingsKeyC).toString(); QXmlStreamReader r(data); r.readNextStartElement(); - if (r.tokenType() == QXmlStreamReader::StartElement && r.name() == QLatin1String(sessionDocumentC)) - while (!r.atEnd()) - loadSessionDataHelper(r); + if (r.tokenType() == QXmlStreamReader::StartElement && r.name() == QLatin1String(sessionDocumentC)) { + while (!r.atEnd()) { + if (readStartElement(r, toolTipElementC)) { + const QXmlStreamAttributes attributes = r.attributes(); + DebuggerToolTipContext context; + context.fileName = attributes.value(QLatin1String(fileNameAttributeC)).toString(); + context.position = attributes.value(QLatin1String(textPositionAttributeC)).toString().toInt(); + context.line = attributes.value(QLatin1String(textLineAttributeC)).toString().toInt(); + context.column = attributes.value(QLatin1String(textColumnAttributeC)).toString().toInt(); + context.function = attributes.value(QLatin1String(functionAttributeC)).toString(); + QPoint offset; + const QString offsetXAttribute = QLatin1String(offsetXAttributeC); + const QString offsetYAttribute = QLatin1String(offsetYAttributeC); + if (attributes.hasAttribute(offsetXAttribute)) + offset.setX(attributes.value(offsetXAttribute).toString().toInt()); + if (attributes.hasAttribute(offsetYAttribute)) + offset.setY(attributes.value(offsetYAttribute).toString().toInt()); + context.mousePosition = offset; + + context.iname = attributes.value(QLatin1String(treeInameAttributeC)).toString().toLatin1(); + context.expression = attributes.value(QLatin1String(treeExpressionAttributeC)).toString(); + + // const QStringRef className = attributes.value(QLatin1String(toolTipClassAttributeC)); + context.engineType = attributes.value(QLatin1String(engineTypeAttributeC)).toString(); + context.creationDate = dateFromString(attributes.value(QLatin1String(dateAttributeC)).toString()); + bool readTree = context.isValid(); + if (!context.creationDate.isValid() || context.creationDate.daysTo(QDate::currentDate()) > toolTipsExpiryDays) { + // DEBUG("Expiring tooltip " << context.fileName << '@' << context.position << " from " << creationDate) + //readTree = false; + } else { //if (className != QLatin1String("Debugger::Internal::DebuggerToolTipWidget")) { + //qWarning("Unable to create debugger tool tip widget of class %s", qPrintable(className.toString())); + //readTree = false; + } + + if (readTree) { + DebuggerToolTipHolder *tw = findOrCreateTooltip(context); + tw->widget->treeView->m_model.restoreTreeModel(r); + tw->widget->pin(); + tw->widget->titleLabel->setText(DebuggerToolTipManager::tr("%1 (Restored)").arg(context.expression)); + tw->widget->treeView->expandAll(); + } else { + r.readElementText(QXmlStreamReader::SkipChildElements); // Skip + } + + r.readNext(); // Skip </tree> + } + } + } } void DebuggerToolTipManager::saveSessionData() { - return; // FIXME - QString data; purgeClosedToolTips(); @@ -1308,6 +1141,7 @@ void DebuggerToolTipManager::saveSessionData() tooltip->saveSessionData(w); w.writeEndDocument(); + return; // FIXME setSessionValue(sessionSettingsKeyC, QVariant(data)); } @@ -1341,7 +1175,7 @@ static void slotTooltipOverrideRequested DebuggerToolTipContext context; context.engineType = engine->objectName(); - context.fileName = editorWidget->textDocument()->filePath(); + context.fileName = editorWidget->textDocument()->filePath().toString(); context.position = pos; editorWidget->convertPosition(pos, &context.line, &context.column); QString raw = cppExpressionAt(editorWidget, context.position, &context.line, &context.column, @@ -1349,8 +1183,8 @@ static void slotTooltipOverrideRequested context.expression = fixCppExpression(raw); if (context.expression.isEmpty()) { - const Utils::TextContent text(DebuggerToolTipManager::tr("No valid expression")); - Utils::ToolTip::show(point, text, Internal::mainWindow()); + ToolTip::show(point, DebuggerToolTipManager::tr("No valid expression"), + Internal::mainWindow()); *handled = true; return; } @@ -1375,21 +1209,17 @@ static void slotTooltipOverrideRequested return; } - tooltip->filterModel.setSourceModel(engine->watchHandler()->model()); - if (localVariable) { DEBUG("SYNC IN STATE" << tooltip->state); if (tooltip->state == New) { tooltip->setState(PendingUnshown); tooltip->setState(PendingShown); - tooltip->acquireEngine(); - const Utils::WidgetContent widgetContent(tooltip->widget, true); - Utils::ToolTip::show(point, widgetContent, Internal::mainWindow()); + ToolTip::show(point, tooltip->widget, Internal::mainWindow()); } else { - tooltip->acquireEngine(); - Utils::ToolTip::move(point, Internal::mainWindow()); + ToolTip::move(point, Internal::mainWindow()); } *handled = true; + tooltip->updateTooltip(engine); } else { DEBUG("ASYNC TIP IN STATE" << tooltip->state); if (tooltip->state == New) @@ -1400,8 +1230,8 @@ static void slotTooltipOverrideRequested QTC_CHECK(false); *handled = engine->setToolTipExpression(editorWidget, context); if (!*handled) { - const Utils::TextContent text(DebuggerToolTipManager::tr("Expression too complex")); - Utils::ToolTip::show(point, text, Internal::mainWindow()); + ToolTip::show(point, DebuggerToolTipManager::tr("Expression too complex"), + Internal::mainWindow()); tooltip->destroy(); } } @@ -1512,5 +1342,6 @@ static void purgeClosedToolTips() } } + } // namespace Internal } // namespace Debugger diff --git a/src/plugins/debugger/debuggertooltipmanager.h b/src/plugins/debugger/debuggertooltipmanager.h index f45df7df0e..0538c8089a 100644 --- a/src/plugins/debugger/debuggertooltipmanager.h +++ b/src/plugins/debugger/debuggertooltipmanager.h @@ -42,11 +42,9 @@ class QAbstractItemModel; QT_END_NAMESPACE namespace Debugger { - -class DebuggerEngine; - namespace Internal { +class DebuggerEngine; class StackFrame; class DebuggerToolTipContext @@ -56,6 +54,7 @@ public: bool isValid() const { return !expression.isEmpty(); } bool matchesFrame(const StackFrame &frame) const; bool isSame(const DebuggerToolTipContext &other) const; + QString toolTip() const; QString fileName; int position; @@ -91,8 +90,6 @@ public: virtual bool eventFilter(QObject *, QEvent *); - static QString treeModelClipboardContents(const QAbstractItemModel *model); - void debugModeEntered(); void leavingDebugMode(); void sessionAboutToChange(); @@ -103,8 +100,6 @@ public: public slots: static void slotUpdateVisibleToolTips(); - void slotItemIsExpanded(const QModelIndex &idx); - void slotColumnAdjustmentRequested(); }; } // namespace Internal diff --git a/src/plugins/debugger/disassembleragent.cpp b/src/plugins/debugger/disassembleragent.cpp index eef3a9281b..f7a96c3ca5 100644 --- a/src/plugins/debugger/disassembleragent.cpp +++ b/src/plugins/debugger/disassembleragent.cpp @@ -332,25 +332,24 @@ void DisassemblerAgent::updateBreakpointMarkers() if (!d->document) return; - BreakHandler *handler = breakHandler(); - BreakpointModelIds ids = handler->engineBreakpointIds(d->engine); - if (ids.isEmpty()) + Breakpoints bps = breakHandler()->engineBreakpoints(d->engine); + if (bps.isEmpty()) return; const DisassemblerLines contents = d->contentsAtCurrentLocation(); - foreach (TextEditor::TextMark *marker, d->breakpointMarks) + foreach (TextMark *marker, d->breakpointMarks) d->document->removeMark(marker); qDeleteAll(d->breakpointMarks); d->breakpointMarks.clear(); - foreach (BreakpointModelId id, ids) { - const quint64 address = handler->response(id).address; + foreach (Breakpoint bp, bps) { + const quint64 address = bp.response().address; if (!address) continue; const int lineNumber = contents.lineForAddress(address); if (!lineNumber) continue; TextMark *marker = new TextMark(QString(), lineNumber); - marker->setIcon(handler->icon(id)); + marker->setIcon(bp.icon()); marker->setPriority(TextMark::NormalPriority); d->breakpointMarks.append(marker); d->document->addMark(marker); diff --git a/src/plugins/debugger/disassembleragent.h b/src/plugins/debugger/disassembleragent.h index cb6c02f53f..d99714cec0 100644 --- a/src/plugins/debugger/disassembleragent.h +++ b/src/plugins/debugger/disassembleragent.h @@ -34,13 +34,12 @@ #include <QObject> namespace Debugger { +namespace Internal { class DebuggerEngine; - -namespace Internal { +class DisassemblerAgentPrivate; class DisassemblerLines; class Location; -class DisassemblerAgentPrivate; class DisassemblerAgent : public QObject { diff --git a/src/plugins/debugger/gdb/attachgdbadapter.cpp b/src/plugins/debugger/gdb/attachgdbadapter.cpp index 84e5fdfeae..aef3139c49 100644 --- a/src/plugins/debugger/gdb/attachgdbadapter.cpp +++ b/src/plugins/debugger/gdb/attachgdbadapter.cpp @@ -36,14 +36,9 @@ #include <utils/qtcassert.h> - namespace Debugger { namespace Internal { -#define CB(callback) \ - static_cast<GdbEngine::GdbCommandCallback>(&GdbAttachEngine::callback), \ - STRINGIFY(callback) - /////////////////////////////////////////////////////////////////////// // // AttachGdbAdapter @@ -72,7 +67,8 @@ void GdbAttachEngine::setupInferior() { QTC_ASSERT(state() == InferiorSetupRequested, qDebug() << state()); const qint64 pid = startParameters().attachPID; - postCommand("attach " + QByteArray::number(pid), CB(handleAttach)); + postCommand("attach " + QByteArray::number(pid), NoFlags, + [this](const DebuggerResponse &r) { handleAttach(r); }); // Task 254674 does not want to remove them //qq->breakHandler()->removeAllBreakpoints(); } @@ -85,17 +81,17 @@ void GdbAttachEngine::runEngine() handleStop1(GdbMi()); } -void GdbAttachEngine::handleAttach(const GdbResponse &response) +void GdbAttachEngine::handleAttach(const DebuggerResponse &response) { QTC_ASSERT(state() == InferiorSetupRequested, qDebug() << state()); switch (response.resultClass) { - case GdbResultDone: - case GdbResultRunning: + case ResultDone: + case ResultRunning: showMessage(_("INFERIOR ATTACHED")); showMessage(msgAttachedToStoppedInferior(), StatusBar); handleInferiorPrepared(); break; - case GdbResultError: + case ResultError: if (response.data["msg"].data() == "ptrace: Operation not permitted.") { notifyInferiorSetupFailed(msgPtraceError(startParameters().startMode)); break; diff --git a/src/plugins/debugger/gdb/attachgdbadapter.h b/src/plugins/debugger/gdb/attachgdbadapter.h index d67d70404e..6d03609ef2 100644 --- a/src/plugins/debugger/gdb/attachgdbadapter.h +++ b/src/plugins/debugger/gdb/attachgdbadapter.h @@ -57,7 +57,7 @@ private: void interruptInferior2(); void shutdownEngine(); - void handleAttach(const GdbResponse &response); + void handleAttach(const DebuggerResponse &response); }; } // namespace Internal diff --git a/src/plugins/debugger/gdb/coregdbadapter.cpp b/src/plugins/debugger/gdb/coregdbadapter.cpp index cfddb8aff7..aeb404a06a 100644 --- a/src/plugins/debugger/gdb/coregdbadapter.cpp +++ b/src/plugins/debugger/gdb/coregdbadapter.cpp @@ -30,6 +30,8 @@ #include "coregdbadapter.h" +#include <coreplugin/messagebox.h> + #include <debugger/debuggercore.h> #include <debugger/debuggerprotocol.h> #include <debugger/debuggerstartparameters.h> @@ -39,7 +41,6 @@ #include <utils/qtcassert.h> #include <QDir> -#include <QMessageBox> #include <QTemporaryFile> using namespace Utils; @@ -47,9 +48,7 @@ using namespace Utils; namespace Debugger { namespace Internal { -#define CB(callback) \ - static_cast<GdbEngine::GdbCommandCallback>(&GdbCoreEngine::callback), \ - STRINGIFY(callback) +#define CB(callback) [this](const DebuggerResponse &r) { callback(r); } /////////////////////////////////////////////////////////////////////// // @@ -185,7 +184,7 @@ void GdbCoreEngine::continueSetupEngine() if (cinfo.isCore) { m_executable = cinfo.foundExecutableName; if (m_executable.isEmpty()) { - showMessageBox(QMessageBox::Warning, + Core::AsynchronousMessageBox::warning( tr("Error Loading Symbols"), tr("No executable to load symbols from specified core.")); notifyEngineSetupFailed(); @@ -196,7 +195,7 @@ void GdbCoreEngine::continueSetupEngine() if (isCore) { startGdb(); } else { - showMessageBox(QMessageBox::Warning, + Core::AsynchronousMessageBox::warning( tr("Error Loading Core File"), tr("The specified file does not appear to be a core file.")); notifyEngineSetupFailed(); @@ -214,17 +213,17 @@ void GdbCoreEngine::setupInferior() // Do that first, otherwise no symbols are loaded. QFileInfo fi(m_executable); QByteArray path = fi.absoluteFilePath().toLocal8Bit(); - postCommand("-file-exec-and-symbols \"" + path + '"', + postCommand("-file-exec-and-symbols \"" + path + '"', NoFlags, CB(handleFileExecAndSymbols)); } -void GdbCoreEngine::handleFileExecAndSymbols(const GdbResponse &response) +void GdbCoreEngine::handleFileExecAndSymbols(const DebuggerResponse &response) { QTC_ASSERT(state() == InferiorSetupRequested, qDebug() << state()); QString core = coreFileName(); - if (response.resultClass == GdbResultDone) { + if (response.resultClass == ResultDone) { showMessage(tr("Symbols found."), StatusBar); - postCommand("target core " + core.toLocal8Bit(), + postCommand("target core " + core.toLocal8Bit(), NoFlags, CB(handleTargetCore)); return; } @@ -239,17 +238,17 @@ void GdbCoreEngine::handleFileExecAndSymbols(const GdbResponse &response) notifyInferiorSetupFailed(msg); } -void GdbCoreEngine::handleTargetCore(const GdbResponse &response) +void GdbCoreEngine::handleTargetCore(const DebuggerResponse &response) { QTC_ASSERT(state() == InferiorSetupRequested, qDebug() << state()); - if (response.resultClass == GdbResultDone) { + if (response.resultClass == ResultDone) { showMessage(tr("Attached to core."), StatusBar); handleInferiorPrepared(); // Due to the auto-solib-add off setting, we don't have any // symbols yet. Load them in order of importance. - reloadStack(true); + reloadStack(); reloadModulesInternal(); - postCommand("p 5", CB(handleRoundTrip)); + postCommand("p 5", NoFlags, CB(handleRoundTrip)); return; } QString msg = tr("Attach to core \"%1\" failed:") @@ -259,7 +258,7 @@ void GdbCoreEngine::handleTargetCore(const GdbResponse &response) notifyInferiorSetupFailed(msg); } -void GdbCoreEngine::handleRoundTrip(const GdbResponse &response) +void GdbCoreEngine::handleRoundTrip(const DebuggerResponse &response) { Q_UNUSED(response); loadSymbolsForStack(); @@ -303,7 +302,8 @@ void GdbCoreEngine::unpackCoreIfNeeded() m_coreUnpackProcess = new QProcess(this); m_coreUnpackProcess->setWorkingDirectory(QDir::tempPath()); m_coreUnpackProcess->start(QLatin1String("lzop"), arguments); - connect(m_coreUnpackProcess, SIGNAL(finished(int)), SLOT(continueSetupEngine())); + connect(m_coreUnpackProcess, static_cast<void (QProcess::*)(int)>(&QProcess::finished), + this, &GdbCoreEngine::continueSetupEngine); } else if (m_coreName.endsWith(QLatin1String(".gz"))) { m_tempCoreName = tempCoreFilename(); showMessage(msg.arg(m_tempCoreName)); @@ -313,8 +313,9 @@ void GdbCoreEngine::unpackCoreIfNeeded() m_coreUnpackProcess = new QProcess(this); m_coreUnpackProcess->setWorkingDirectory(QDir::tempPath()); m_coreUnpackProcess->start(QLatin1String("gzip"), arguments); - connect(m_coreUnpackProcess, SIGNAL(readyRead()), SLOT(writeCoreChunk())); - connect(m_coreUnpackProcess, SIGNAL(finished(int)), SLOT(continueSetupEngine())); + connect(m_coreUnpackProcess, &QProcess::readyRead, this, &GdbCoreEngine::writeCoreChunk); + connect(m_coreUnpackProcess, static_cast<void (QProcess::*)(int)>(&QProcess::finished), + this, &GdbCoreEngine::continueSetupEngine); } else { continueSetupEngine(); } diff --git a/src/plugins/debugger/gdb/coregdbadapter.h b/src/plugins/debugger/gdb/coregdbadapter.h index 4522789c54..965a8bcd1f 100644 --- a/src/plugins/debugger/gdb/coregdbadapter.h +++ b/src/plugins/debugger/gdb/coregdbadapter.h @@ -59,6 +59,7 @@ public: bool isCore; }; static CoreInfo readExecutableNameFromCore(const QString &debuggerCmd, const QString &coreFile); + private: void setupEngine(); void setupInferior(); @@ -66,9 +67,9 @@ private: void interruptInferior(); void shutdownEngine(); - void handleFileExecAndSymbols(const GdbResponse &response); - void handleTargetCore(const GdbResponse &response); - void handleRoundTrip(const GdbResponse &response); + void handleFileExecAndSymbols(const DebuggerResponse &response); + void handleTargetCore(const DebuggerResponse &response); + void handleRoundTrip(const DebuggerResponse &response); void unpackCoreIfNeeded(); QString coreFileName() const; QString coreName() const; diff --git a/src/plugins/debugger/gdb/gdbengine.cpp b/src/plugins/debugger/gdb/gdbengine.cpp index 8072f737ed..56ae99126c 100644 --- a/src/plugins/debugger/gdb/gdbengine.cpp +++ b/src/plugins/debugger/gdb/gdbengine.cpp @@ -52,6 +52,7 @@ #include <debugger/disassembleragent.h> #include <debugger/memoryagent.h> #include <debugger/sourceutils.h> +#include <debugger/terminal.h> #include <debugger/breakhandler.h> #include <debugger/moduleshandler.h> @@ -65,6 +66,7 @@ #include <debugger/shared/hostutils.h> #include <coreplugin/icore.h> +#include <coreplugin/messagebox.h> #include <projectexplorer/devicesupport/deviceprocess.h> #include <projectexplorer/itaskhandler.h> #include <projectexplorer/taskhub.h> @@ -77,11 +79,11 @@ #include <utils/qtcprocess.h> #include <utils/savedaction.h> +#include <QBuffer> #include <QDirIterator> -#include <QTemporaryFile> - #include <QMessageBox> #include <QPushButton> +#include <QTemporaryFile> using namespace Core; using namespace ProjectExplorer; @@ -94,8 +96,7 @@ enum { debugPending = 0 }; #define PENDING_DEBUG(s) do { if (debugPending) qDebug() << s; } while (0) -#define CB(callback) &GdbEngine::callback, STRINGIFY(callback) - +#define CB(callback) [this](const DebuggerResponse &r) { callback(r); } QByteArray GdbEngine::tooltipIName(const QString &exp) { @@ -141,7 +142,7 @@ static int ¤tToken() return token; } -static QByteArray parsePlainConsoleStream(const GdbResponse &response) +static QByteArray parsePlainConsoleStream(const DebuggerResponse &response) { QByteArray out = response.consoleStreamOutput; // FIXME: proper decoding needed @@ -221,7 +222,6 @@ GdbEngine::GdbEngine(const DebuggerStartParameters &startParameters) m_pendingBreakpointRequests = 0; m_commandsDoneCallback = 0; m_stackNeeded = false; - m_preparedForQmlBreak = false; m_terminalTrap = startParameters.useTerminal; m_fullStartDone = false; m_systemDumpersLoaded = false; @@ -231,16 +231,17 @@ GdbEngine::GdbEngine(const DebuggerStartParameters &startParameters) //ExtensionSystem::PluginManager::addObject(m_debugInfoTaskHandler); m_commandTimer.setSingleShot(true); - connect(&m_commandTimer, SIGNAL(timeout()), SLOT(commandTimeout())); + connect(&m_commandTimer, &QTimer::timeout, + this, &GdbEngine::commandTimeout); - connect(action(AutoDerefPointers), SIGNAL(valueChanged(QVariant)), - SLOT(reloadLocals())); - connect(action(CreateFullBacktrace), SIGNAL(triggered()), - SLOT(createFullBacktrace())); - connect(action(UseDebuggingHelpers), SIGNAL(valueChanged(QVariant)), - SLOT(reloadLocals())); - connect(action(UseDynamicType), SIGNAL(valueChanged(QVariant)), - SLOT(reloadLocals())); + connect(action(AutoDerefPointers), &SavedAction::valueChanged, + this, &GdbEngine::reloadLocals); + connect(action(CreateFullBacktrace), &QAction::triggered, + this, &GdbEngine::createFullBacktrace); + connect(action(UseDebuggingHelpers), &SavedAction::valueChanged, + this, &GdbEngine::reloadLocals); + connect(action(UseDynamicType), &SavedAction::valueChanged, + this, &GdbEngine::reloadLocals); } GdbEngine::~GdbEngine() @@ -534,7 +535,7 @@ void GdbEngine::handleResponse(const QByteArray &buff) result = GdbMi(); result.fromString(ba); BreakHandler *handler = breakHandler(); - BreakpointModelId id; + Breakpoint bp; BreakpointResponse br; foreach (const GdbMi &bkpt, result.children()) { const QByteArray nr = bkpt["number"].data(); @@ -546,17 +547,15 @@ void GdbEngine::handleResponse(const QByteArray &buff) updateResponse(sub, bkpt); sub.id = rid; sub.type = br.type; - handler->insertSubBreakpoint(id, sub); + bp.insertSubBreakpoint(sub); } else { // A primary breakpoint. - id = handler->findBreakpointByResponseId(rid); + bp = handler->findBreakpointByResponseId(rid); //qDebug() << "NR: " << nr << "RID: " << rid - // << "ID: " << id; - //BreakpointModelId id = - // handler->findBreakpointByResponseId(rid); - br = handler->response(id); + // << "ID: " << bp.id(); + br = bp.response(); updateResponse(br, bkpt); - handler->setResponse(id, br); + bp.setResponse(br); } } } @@ -576,16 +575,14 @@ void GdbEngine::handleResponse(const QByteArray &buff) } else if (asyncClass == "breakpoint-deleted") { // "breakpoint-deleted" "{id="1"}" // New in FSF gdb since 2011-04-27. - BreakHandler *handler = breakHandler(); QByteArray nr = result["id"].data(); BreakpointResponseId rid(nr); - BreakpointModelId id = handler->findBreakpointByResponseId(rid); - if (id.isValid()) { + if (Breakpoint bp = breakHandler()->findBreakpointByResponseId(rid)) { // This also triggers when a temporary breakpoint is hit. // We do not really want that, as this loses all information. // FIXME: Use a special marker for this case? - if (!handler->isOneShot(id)) - handler->removeAlienBreakpoint(id); + if (!bp.isOneShot()) + bp.removeAlienBreakpoint(); } } else if (asyncClass == "cmd-param-changed") { // New since 2012-08-09 @@ -641,15 +638,6 @@ void GdbEngine::handleResponse(const QByteArray &buff) const Task::TaskType type = isFatalWinException(exCode) ? Task::Error : Task::Warning; TaskHub::addTask(type, m_lastWinException, Constants::TASK_CATEGORY_DEBUGGER_RUNTIME); } - - if (data.startsWith("QMLBP:")) { - int pos1 = 6; - int pos2 = data.indexOf(' ', pos1); - m_qmlBreakpointResponseId2 = BreakpointResponseId(data.mid(pos1, pos2 - pos1)); - //qDebug() << "FOUND QMLBP: " << m_qmlBreakpointNumbers[2]; - //qDebug() << "CURRENT: " << m_qmlBreakpointNumbers; - } - break; } @@ -696,7 +684,7 @@ void GdbEngine::handleResponse(const QByteArray &buff) } case '^': { - GdbResponse response; + DebuggerResponse response; response.token = token; @@ -706,17 +694,17 @@ void GdbEngine::handleResponse(const QByteArray &buff) QByteArray resultClass = QByteArray::fromRawData(from, inner - from); if (resultClass == "done") - response.resultClass = GdbResultDone; + response.resultClass = ResultDone; else if (resultClass == "running") - response.resultClass = GdbResultRunning; + response.resultClass = ResultRunning; else if (resultClass == "connected") - response.resultClass = GdbResultConnected; + response.resultClass = ResultConnected; else if (resultClass == "error") - response.resultClass = GdbResultError; + response.resultClass = ResultError; else if (resultClass == "exit") - response.resultClass = GdbResultExit; + response.resultClass = ResultExit; else - response.resultClass = GdbResultUnknown; + response.resultClass = ResultUnknown; from = inner; if (from != to) { @@ -803,6 +791,9 @@ void GdbEngine::interruptInferior() QTC_ASSERT(state() == InferiorStopRequested, qDebug() << "INTERRUPT INFERIOR: " << state(); return); + if (terminal()->sendInterrupt()) + return; + if (usesExecInterrupt()) { postCommand("-exec-interrupt", Immediate); } else { @@ -839,7 +830,7 @@ void GdbEngine::handleInterruptDeviceInferior(const QString &error) void GdbEngine::interruptInferiorTemporarily() { - foreach (const GdbCommand &cmd, m_commandsToRunOnTemporaryBreak) { + foreach (const DebuggerCommand &cmd, m_commandsToRunOnTemporaryBreak) { if (cmd.flags & LosesChild) { notifyInferiorIll(); return; @@ -862,40 +853,33 @@ void GdbEngine::maybeHandleInferiorPidChanged(const QString &pid0) notifyInferiorPid(pid); } -void GdbEngine::postCommand(const QByteArray &command, GdbCommandCallback callback, - const char *callbackName, const QVariant &cookie) +void GdbEngine::runCommand(const DebuggerCommand &command) { - postCommand(command, NoFlags, callback, callbackName, cookie); + QByteArray cmd = command.function + "({" + command.args + "})"; + postCommand("python theDumper." + cmd, command.flags, command.callback); } -void GdbEngine::postCommand(const QByteArray &command, GdbCommandFlags flags, - GdbCommandCallback callback, const char *callbackName, - const QVariant &cookie) +void GdbEngine::postCommand(const QByteArray &command, int flags, + DebuggerCommand::Callback callback) { - GdbCommand cmd; - cmd.command = command; + DebuggerCommand cmd; + cmd.function = command; cmd.flags = flags; cmd.callback = callback; - cmd.callbackName = callbackName; - cmd.cookie = cookie; - postCommandHelper(cmd); -} -void GdbEngine::postCommandHelper(const GdbCommand &cmd) -{ if (!stateAcceptsGdbCommands(state())) { - PENDING_DEBUG(_("NO GDB PROCESS RUNNING, CMD IGNORED: " + cmd.command)); + PENDING_DEBUG(_("NO GDB PROCESS RUNNING, CMD IGNORED: " + cmd.function)); showMessage(_("NO GDB PROCESS RUNNING, CMD IGNORED: %1 %2") - .arg(_(cmd.command)).arg(state())); + .arg(_(cmd.function)).arg(state())); return; } if (cmd.flags & RebuildBreakpointModel) { ++m_pendingBreakpointRequests; - PENDING_DEBUG(" BRWAKPOINT MODEL:" << cmd.command << "=>" << cmd.callbackName + PENDING_DEBUG(" BRWAKPOINT MODEL:" << cmd.function << "INCREMENTS PENDING TO" << m_pendingBreakpointRequests); } else { - PENDING_DEBUG(" OTHER (IN):" << cmd.command << "=>" << cmd.callbackName + PENDING_DEBUG(" OTHER (IN):" << cmd.function << "LEAVES PENDING WATCH AT" << m_uncompleted.size() << "LEAVES PENDING BREAKPOINT AT" << m_pendingBreakpointRequests); } @@ -916,7 +900,7 @@ void GdbEngine::postCommandHelper(const GdbCommand &cmd) flushCommand(cmd); } else { // Queue the commands that we cannot send at once. - showMessage(_("QUEUING COMMAND " + cmd.command)); + showMessage(_("QUEUING COMMAND " + cmd.function)); m_commandsToRunOnTemporaryBreak.append(cmd); if (state() == InferiorStopRequested) { if (cmd.flags & LosesChild) @@ -929,10 +913,10 @@ void GdbEngine::postCommandHelper(const GdbCommand &cmd) interruptInferiorTemporarily(); } else { qDebug() << "ATTEMPTING TO QUEUE COMMAND " - << cmd.command << "IN INAPPROPRIATE STATE" << state(); + << cmd.function << "IN INAPPROPRIATE STATE" << state(); } } - } else if (!cmd.command.isEmpty()) { + } else if (!cmd.function.isEmpty()) { flushCommand(cmd); } } @@ -941,17 +925,16 @@ void GdbEngine::flushQueuedCommands() { showStatusMessage(tr("Processing queued commands"), 1000); while (!m_commandsToRunOnTemporaryBreak.isEmpty()) { - GdbCommand cmd = m_commandsToRunOnTemporaryBreak.takeFirst(); - showMessage(_("RUNNING QUEUED COMMAND " + cmd.command + ' ' - + (cmd.callbackName ? cmd.callbackName : "<unnamed callback>"))); + DebuggerCommand cmd = m_commandsToRunOnTemporaryBreak.takeFirst(); + showMessage(_("RUNNING QUEUED COMMAND " + cmd.function)); flushCommand(cmd); } } -void GdbEngine::flushCommand(const GdbCommand &cmd0) +void GdbEngine::flushCommand(const DebuggerCommand &cmd0) { if (!stateAcceptsGdbCommands(state())) { - showMessage(_(cmd0.command), LogInput); + showMessage(_(cmd0.function), LogInput); showMessage(_("GDB PROCESS ACCEPTS NO CMD IN STATE %1 ").arg(state())); return; } @@ -960,13 +943,13 @@ void GdbEngine::flushCommand(const GdbCommand &cmd0) const int token = ++currentToken(); - GdbCommand cmd = cmd0; + DebuggerCommand cmd = cmd0; cmd.postTime = QTime::currentTime(); - m_cookieForToken[token] = cmd; + m_commandForToken[token] = cmd; if (cmd.flags & ConsoleCommand) - cmd.command = "-interpreter-exec console \"" + cmd.command + '"'; - cmd.command = QByteArray::number(token) + cmd.command; - showMessage(_(cmd.command), LogInput); + cmd.function = "-interpreter-exec console \"" + cmd.function + '"'; + cmd.function = QByteArray::number(token) + cmd.function; + showMessage(_(cmd.function), LogInput); if (m_scheduledTestResponses.contains(token)) { // Fake response for test cases. @@ -978,7 +961,7 @@ void GdbEngine::flushCommand(const GdbCommand &cmd0) QMetaObject::invokeMethod(this, "handleResponse", Q_ARG(QByteArray, buffer)); } else { - write(cmd.command + "\r\n"); + write(cmd.function + "\r\n"); // Start Watchdog. if (m_commandTimer.interval() <= 20000) @@ -987,7 +970,7 @@ void GdbEngine::flushCommand(const GdbCommand &cmd0) // sent and a response could be retrieved. We don't want the watchdog // to bark in that case since the only possible outcome is a dead // process anyway. - if (!cmd.command.endsWith("-gdb-exit")) + if (!cmd.function.endsWith("-gdb-exit")) m_commandTimer.start(); //if (cmd.flags & LosesChild) @@ -1003,23 +986,20 @@ int GdbEngine::commandTimeoutTime() const void GdbEngine::commandTimeout() { - QList<int> keys = m_cookieForToken.keys(); + QList<int> keys = m_commandForToken.keys(); Utils::sort(keys); bool killIt = false; foreach (int key, keys) { - const GdbCommand &cmd = m_cookieForToken.value(key); + const DebuggerCommand &cmd = m_commandForToken.value(key); if (!(cmd.flags & NonCriticalResponse)) killIt = true; - QByteArray msg = QByteArray::number(key); - msg += ": " + cmd.command + " => "; - msg += cmd.callbackName ? cmd.callbackName : "<unnamed callback>"; - showMessage(_(msg)); + showMessage(_(QByteArray::number(key) + ": " + cmd.function)); } if (killIt) { QStringList commands; - foreach (const GdbCommand &cookie, m_cookieForToken) + foreach (const DebuggerCommand &cmd, m_commandForToken) commands << QString(_("\"%1\"")).arg( - QString::fromLatin1(cookie.command)); + QString::fromLatin1(cmd.function)); showMessage(_("TIMED OUT WAITING FOR GDB REPLY. " "COMMANDS STILL IN PROGRESS: ") + commands.join(_(", "))); int timeOut = m_commandTimer.interval(); @@ -1047,7 +1027,7 @@ void GdbEngine::commandTimeout() } } -void GdbEngine::handleResultRecord(GdbResponse *response) +void GdbEngine::handleResultRecord(DebuggerResponse *response) { //qDebug() << "TOKEN:" << response->token // << " ACCEPTABLE:" << m_oldestAcceptableToken; @@ -1057,7 +1037,7 @@ void GdbEngine::handleResultRecord(GdbResponse *response) if (token == -1) return; - if (!m_cookieForToken.contains(token)) { + if (!m_commandForToken.contains(token)) { // In theory this should not happen (rather the error should be // reported in the "first" response to the command) in practice it // does. We try to handle a few situations we are aware of gracefully. @@ -1065,14 +1045,14 @@ void GdbEngine::handleResultRecord(GdbResponse *response) showMessage(_("COOKIE FOR TOKEN %1 ALREADY EATEN (%2). " "TWO RESPONSES FOR ONE COMMAND?").arg(token). arg(QString::fromLatin1(stateName(state())))); - if (response->resultClass == GdbResultError) { + if (response->resultClass == ResultError) { QByteArray msg = response->data["msg"].data(); if (msg == "Cannot find new threads: generic error") { // Handle a case known to occur on Linux/gdb 6.8 when debugging moc // with helpers enabled. In this case we get a second response with // msg="Cannot find new threads: generic error" showMessage(_("APPLYING WORKAROUND #1")); - showMessageBox(QMessageBox::Critical, + AsynchronousMessageBox::critical( tr("Executable failed"), QString::fromLocal8Bit(msg)); showStatusMessage(tr("Process failed to start")); //shutdown(); @@ -1098,7 +1078,7 @@ void GdbEngine::handleResultRecord(GdbResponse *response) //showStatusMessage(tr("Executable failed: %1") // .arg(QString::fromLocal8Bit(msg))); //shutdown(); - //showMessageBox(QMessageBox::Critical, + //Core::AsynchronousMessageBox::critical( // tr("Executable failed"), QString::fromLocal8Bit(msg)); } else if (msg.contains("Cannot insert breakpoint")) { // For breakpoints set by address to non-existent addresses we @@ -1112,7 +1092,7 @@ void GdbEngine::handleResultRecord(GdbResponse *response) // long as the breakpoints are enabled. // FIXME: Should we silently disable the offending breakpoints? showMessage(_("APPLYING WORKAROUND #5")); - showMessageBox(QMessageBox::Critical, + AsynchronousMessageBox::critical( tr("Setting breakpoints failed"), QString::fromLocal8Bit(msg)); QTC_CHECK(state() == InferiorRunOk); notifyInferiorSpontaneousStop(); @@ -1128,17 +1108,17 @@ void GdbEngine::handleResultRecord(GdbResponse *response) if (!m_lastWinException.isEmpty()) logMsg = m_lastWinException + QLatin1Char('\n'); logMsg += QString::fromLocal8Bit(msg); - showMessageBox(QMessageBox::Critical, tr("Executable Failed"), logMsg); + AsynchronousMessageBox::critical(tr("Executable Failed"), logMsg); showStatusMessage(tr("Executable failed: %1").arg(logMsg)); } } return; } - GdbCommand cmd = m_cookieForToken.take(token); + DebuggerCommand cmd = m_commandForToken.take(token); if (boolSetting(LogTimeStamps)) { showMessage(_("Response time: %1: %2 s") - .arg(_(cmd.command)) + .arg(_(cmd.function)) .arg(cmd.postTime.msecsTo(QTime::currentTime()) / 1000.), LogTime); } @@ -1148,33 +1128,31 @@ void GdbEngine::handleResultRecord(GdbResponse *response) return; } - response->cookie = cmd.cookie; - bool isExpectedResult = - (response->resultClass == GdbResultError) // Can always happen. - || (response->resultClass == GdbResultRunning && (cmd.flags & RunRequest)) - || (response->resultClass == GdbResultExit && (cmd.flags & ExitRequest)) - || (response->resultClass == GdbResultDone); - // GdbResultDone can almost "always" happen. Known examples are: - // (response->resultClass == GdbResultDone && cmd.command == "continue") + (response->resultClass == ResultError) // Can always happen. + || (response->resultClass == ResultRunning && (cmd.flags & RunRequest)) + || (response->resultClass == ResultExit && (cmd.flags & ExitRequest)) + || (response->resultClass == ResultDone); + // ResultDone can almost "always" happen. Known examples are: + // (response->resultClass == ResultDone && cmd.function == "continue") // Happens with some incarnations of gdb 6.8 for "jump to line" - // (response->resultClass == GdbResultDone && cmd.command.startsWith("jump")) - // (response->resultClass == GdbResultDone && cmd.command.startsWith("detach")) + // (response->resultClass == ResultDone && cmd.function.startsWith("jump")) + // (response->resultClass == ResultDone && cmd.function.startsWith("detach")) // Happens when stepping finishes very quickly and issues *stopped and ^done // instead of ^running and *stopped - // (response->resultClass == GdbResultDone && (cmd.flags & RunRequest)); + // (response->resultClass == ResultDone && (cmd.flags & RunRequest)); if (!isExpectedResult) { const DebuggerStartParameters &sp = startParameters(); Abi abi = sp.toolChainAbi; if (abi.os() == Abi::WindowsOS - && cmd.command.startsWith("attach") + && cmd.function.startsWith("attach") && (sp.startMode == AttachExternal || sp.useTerminal)) { // Ignore spurious 'running' responses to 'attach'. } else { - QByteArray rsp = GdbResponse::stringFromResultClass(response->resultClass); - rsp = "UNEXPECTED RESPONSE '" + rsp + "' TO COMMAND '" + cmd.command + "'"; + QByteArray rsp = DebuggerResponse::stringFromResultClass(response->resultClass); + rsp = "UNEXPECTED RESPONSE '" + rsp + "' TO COMMAND '" + cmd.function + "'"; qWarning() << rsp << " AT " __FILE__ ":" STRINGIFY(__LINE__); showMessage(_(rsp)); } @@ -1184,18 +1162,18 @@ void GdbEngine::handleResultRecord(GdbResponse *response) --m_nonDiscardableCount; if (cmd.callback) - (this->*cmd.callback)(*response); + cmd.callback(*response); if (cmd.flags & RebuildBreakpointModel) { --m_pendingBreakpointRequests; - PENDING_DEBUG(" BREAKPOINT" << cmd.command << "=>" << cmd.callbackName + PENDING_DEBUG(" BREAKPOINT" << cmd.function << "DECREMENTS PENDING TO" << m_uncompleted.size()); if (m_pendingBreakpointRequests <= 0) { PENDING_DEBUG("\n\n ... AND TRIGGERS BREAKPOINT MODEL UPDATE\n"); attemptBreakpointSynchronization(); } } else { - PENDING_DEBUG(" OTHER (OUT):" << cmd.command << "=>" << cmd.callbackName + PENDING_DEBUG(" OTHER (OUT):" << cmd.function << "LEAVES PENDING WATCH AT" << m_uncompleted.size() << "LEAVES PENDING BREAKPOINT AT" << m_pendingBreakpointRequests); } @@ -1213,17 +1191,17 @@ void GdbEngine::handleResultRecord(GdbResponse *response) // An optimization would be requesting the continue immediately when the // event loop is entered, and let individual commands have a flag to suppress // that behavior. - if (m_commandsDoneCallback && m_cookieForToken.isEmpty()) { + if (m_commandsDoneCallback && m_commandForToken.isEmpty()) { showMessage(_("ALL COMMANDS DONE; INVOKING CALLBACK")); CommandsDoneCallback cont = m_commandsDoneCallback; m_commandsDoneCallback = 0; - if (response->resultClass != GdbResultRunning) //only start if the thing is not already running + if (response->resultClass != ResultRunning) //only start if the thing is not already running (this->*cont)(); } else { - PENDING_DEBUG("MISSING TOKENS: " << m_cookieForToken.keys()); + PENDING_DEBUG("MISSING TOKENS: " << m_commandForToken.keys()); } - if (m_cookieForToken.isEmpty()) + if (m_commandForToken.isEmpty()) m_commandTimer.stop(); } @@ -1239,8 +1217,8 @@ void GdbEngine::executeDebuggerCommand(const QString &command, DebuggerLanguages if (!(languages & CppLanguage)) return; QTC_CHECK(acceptsDebuggerCommands()); - GdbCommand cmd; - cmd.command = command.toLatin1(); + DebuggerCommand cmd; + cmd.function = command.toLatin1(); flushCommand(cmd); } @@ -1250,18 +1228,20 @@ void GdbEngine::updateAll() //PENDING_DEBUG("UPDATING ALL\n"); QTC_CHECK(state() == InferiorUnrunnable || state() == InferiorStopOk); reloadModulesInternal(); - postCommand("-stack-list-frames", CB(handleStackListFrames), - QVariant::fromValue<StackCookie>(StackCookie(false, true))); + DebuggerCommand cmd = stackCommand(action(MaximalStackDepth)->value().toInt()); + cmd.flags = NoFlags; + cmd.callback = [this](const DebuggerResponse &r) { handleStackListFrames(r, false); }; + runCommand(cmd); stackHandler()->setCurrentIndex(0); - postCommand("-thread-info", CB(handleThreadInfo), 0); + postCommand("-thread-info", NoFlags, CB(handleThreadInfo)); reloadRegisters(); updateLocals(); } -void GdbEngine::handleQuerySources(const GdbResponse &response) +void GdbEngine::handleQuerySources(const DebuggerResponse &response) { m_sourcesListUpdating = false; - if (response.resultClass == GdbResultDone) { + if (response.resultClass == ResultDone) { QMap<QString, QString> oldShortToFull = m_shortToFullName; m_shortToFullName.clear(); m_fullToShortName.clear(); @@ -1286,13 +1266,13 @@ void GdbEngine::handleQuerySources(const GdbResponse &response) } } -void GdbEngine::handleExecuteJumpToLine(const GdbResponse &response) +void GdbEngine::handleExecuteJumpToLine(const DebuggerResponse &response) { - if (response.resultClass == GdbResultRunning) { + if (response.resultClass == ResultRunning) { // All is fine. Waiting for a *running // and the temporary breakpoint to be hit. notifyInferiorRunOk(); // Only needed for gdb < 7.0. - } else if (response.resultClass == GdbResultError) { + } else if (response.resultClass == ResultError) { // Could be "Unreasonable jump request" or similar. QString out = tr("Cannot jump. Stopped"); QByteArray msg = response.data["msg"].data(); @@ -1300,20 +1280,20 @@ void GdbEngine::handleExecuteJumpToLine(const GdbResponse &response) out += QString::fromLatin1(". " + msg); showStatusMessage(out); notifyInferiorRunFailed(); - } else if (response.resultClass == GdbResultDone) { + } else if (response.resultClass == ResultDone) { // This happens on old gdb. Trigger the effect of a '*stopped'. showStatusMessage(tr("Jumped. Stopped")); notifyInferiorSpontaneousStop(); - handleStop2(response); + handleStop2(response.data); } } -void GdbEngine::handleExecuteRunToLine(const GdbResponse &response) +void GdbEngine::handleExecuteRunToLine(const DebuggerResponse &response) { - if (response.resultClass == GdbResultRunning) { + if (response.resultClass == ResultRunning) { // All is fine. Waiting for a *running // and the temporary breakpoint to be hit. - } else if (response.resultClass == GdbResultDone) { + } else if (response.resultClass == ResultDone) { // This happens on old gdb (Mac). gdb is not stopped yet, // but merely accepted the continue. // >&"continue\n" @@ -1382,7 +1362,7 @@ void GdbEngine::handleStopResponse(const GdbMi &data) if (!m_fullStartDone) { m_fullStartDone = true; postCommand("sharedlibrary .*"); - postCommand("p 3", CB(handleStop1)); + postCommand("p 3", NoFlags, [this, data](const DebuggerResponse &) { handleStop1(data); }); gotoHandleStop1 = false; } @@ -1391,8 +1371,10 @@ void GdbEngine::handleStopResponse(const GdbMi &data) int lineNumber = 0; QString fullName; + QByteArray function; if (frame.isValid()) { const GdbMi lineNumberG = frame["line"]; + function = frame["func"].data(); if (lineNumberG.isValid()) { lineNumber = lineNumberG.toInt(); fullName = cleanupFullName(QString::fromLocal8Bit(frame["fullname"].data())); @@ -1403,31 +1385,28 @@ void GdbEngine::handleStopResponse(const GdbMi &data) showMessage(_("INVALID STOPPED REASON"), LogWarning); } - if (rid.isValid() && frame.isValid() - && !isQmlStepBreakpoint(rid) - && !isQFatalBreakpoint(rid)) { + if (rid.isValid() && frame.isValid() && !isQFatalBreakpoint(rid)) { // Use opportunity to update the breakpoint marker position. - BreakHandler *handler = breakHandler(); //qDebug() << " PROBLEM: " << m_qmlBreakpointNumbers << rid // << isQmlStepBreakpoint1(rid) // << isQmlStepBreakpoint2(rid) - BreakpointModelId id = handler->findBreakpointByResponseId(rid); - const BreakpointResponse &response = handler->response(id); + Breakpoint bp = breakHandler()->findBreakpointByResponseId(rid); + const BreakpointResponse &response = bp.response(); QString fileName = response.fileName; if (fileName.isEmpty()) - fileName = handler->fileName(id); + fileName = bp.fileName(); if (fileName.isEmpty()) fileName = fullName; if (!fileName.isEmpty()) - handler->setMarkerFileAndLine(id, fileName, lineNumber); + bp.setMarkerFileAndLine(fileName, lineNumber); } //qDebug() << "BP " << rid << data.toString(); // Quickly set the location marker. if (lineNumber && !boolSetting(OperateByInstruction) && QFileInfo::exists(fullName) - && !isQmlStepBreakpoint(rid) - && !isQFatalBreakpoint(rid)) + && !isQFatalBreakpoint(rid) + && function != "qt_v4TriggeredBreakpointHook") gotoLocation(Location(fullName, lineNumber)); if (!m_commandsToRunOnTemporaryBreak.isEmpty()) { @@ -1469,9 +1448,6 @@ void GdbEngine::handleStopResponse(const GdbMi &data) QTC_ASSERT(state() == InferiorStopOk, qDebug() << state()); - if (isQmlStepBreakpoint1(rid)) - return; - if (gotoHandleStop1) handleStop1(data); } @@ -1481,11 +1457,6 @@ static QByteArray stopSignal(const Abi &abi) return (abi.os() == Abi::WindowsOS) ? QByteArray("SIGTRAP") : QByteArray("SIGINT"); } -void GdbEngine::handleStop1(const GdbResponse &response) -{ - handleStop1(response.cookie.value<GdbMi>()); -} - void GdbEngine::handleStop1(const GdbMi &data) { QTC_ASSERT(state() == InferiorStopOk, qDebug() << state()); @@ -1550,17 +1521,14 @@ void GdbEngine::handleStop1(const GdbMi &data) if (!m_systemDumpersLoaded) { m_systemDumpersLoaded = true; if (m_gdbVersion >= 70400 && boolSetting(LoadGdbDumpers)) - postCommand("importPlainDumpers"); + postCommand("importPlainDumpers on"); + else + postCommand("importPlainDumpers off"); } handleStop2(data); } -void GdbEngine::handleStop2(const GdbResponse &response) -{ - handleStop2(response.cookie.value<GdbMi>()); -} - void GdbEngine::handleStop2(const GdbMi &data) { QTC_ASSERT(state() == InferiorStopOk, qDebug() << state()); @@ -1628,14 +1596,13 @@ void GdbEngine::handleStop2(const GdbMi &data) // thread-id="1",stopped-threads="all",core="2" const GdbMi wpt = data["wpt"]; const BreakpointResponseId rid(wpt["number"].data()); - const BreakpointModelId id = breakHandler()->findBreakpointByResponseId(rid); + const Breakpoint bp = breakHandler()->findBreakpointByResponseId(rid); const quint64 bpAddress = wpt["exp"].data().mid(1).toULongLong(0, 0); QString msg; - if (id && breakHandler()->type(id) == WatchpointAtExpression) - msg = msgWatchpointByExpressionTriggered(id, rid.majorPart(), - breakHandler()->expression(id)); - if (id && breakHandler()->type(id) == WatchpointAtAddress) - msg = msgWatchpointByAddressTriggered(id, rid.majorPart(), bpAddress); + if (bp.type() == WatchpointAtExpression) + msg = bp.msgWatchpointByExpressionTriggered(rid.majorPart(), bp.expression()); + if (bp.type() == WatchpointAtAddress) + msg = bp.msgWatchpointByAddressTriggered(rid.majorPart(), bpAddress); GdbMi value = data["value"]; GdbMi oldValue = value["old"]; GdbMi newValue = value["new"]; @@ -1651,8 +1618,8 @@ void GdbEngine::handleStop2(const GdbMi &data) gNumber = data["number"]; const BreakpointResponseId rid(gNumber.data()); const QByteArray threadId = data["thread-id"].data(); - const BreakpointModelId id = breakHandler()->findBreakpointByResponseId(rid); - showStatusMessage(msgBreakpointTriggered(id, rid.majorPart(), _(threadId))); + const Breakpoint bp = breakHandler()->findBreakpointByResponseId(rid); + showStatusMessage(bp.msgBreakpointTriggered(rid.majorPart(), _(threadId))); m_currentThread = threadId; } else { QString reasontr = msgStopped(_(reason)); @@ -1661,7 +1628,7 @@ void GdbEngine::handleStop2(const GdbMi &data) QByteArray meaning = data["signal-meaning"].data(); // Ignore these as they are showing up regularly when // stopping debugging. - if (name == stopSignal(sp.toolChainAbi)) { + if (name == stopSignal(sp.toolChainAbi) || sp.expectedSignals.contains(name)) { showMessage(_(name + " CONSIDERED HARMLESS. CONTINUING.")); } else { showMessage(_("HANDLING SIGNAL " + name)); @@ -1692,9 +1659,9 @@ void GdbEngine::handleStop2() postCommand("-thread-info", Discardable, CB(handleThreadInfo)); } -void GdbEngine::handleInfoProc(const GdbResponse &response) +void GdbEngine::handleInfoProc(const DebuggerResponse &response) { - if (response.resultClass == GdbResultDone) { + if (response.resultClass == ResultDone) { static QRegExp re(_("\\bprocess ([0-9]+)\n")); QTC_ASSERT(re.isValid(), return); if (re.indexIn(_(response.consoleStreamOutput)) != -1) @@ -1702,10 +1669,10 @@ void GdbEngine::handleInfoProc(const GdbResponse &response) } } -void GdbEngine::handleShowVersion(const GdbResponse &response) +void GdbEngine::handleShowVersion(const DebuggerResponse &response) { showMessage(_("PARSING VERSION: " + response.toString())); - if (response.resultClass == GdbResultDone) { + if (response.resultClass == ResultDone) { bool isMacGdb = false; int gdbBuildVersion = -1; m_gdbVersion = 100; @@ -1737,52 +1704,18 @@ void GdbEngine::handleShowVersion(const GdbResponse &response) } } -void GdbEngine::handleListFeatures(const GdbResponse &response) +void GdbEngine::handleListFeatures(const DebuggerResponse &response) { showMessage(_("FEATURES: " + response.toString())); } -void GdbEngine::handlePythonSetup(const GdbResponse &response) +void GdbEngine::handlePythonSetup(const DebuggerResponse &response) { QTC_ASSERT(state() == EngineSetupRequested, qDebug() << state()); - if (response.resultClass == GdbResultDone) { - bool needSetup = false; - - const QString path = stringSetting(ExtraDumperFile); - if (!path.isEmpty()) { - QFileInfo fi(path); - postCommand("python sys.path.insert(1, '" + fi.absolutePath().toUtf8() + "')"); - postCommand("python from " + fi.baseName().toUtf8() + " import *"); - needSetup = true; - } - - const QString commands = stringSetting(ExtraDumperCommands); - if (!commands.isEmpty()) { - postCommand(commands.toLocal8Bit()); - needSetup = true; - } - - if (needSetup) - postCommand("bbsetup"); - + if (response.resultClass == ResultDone) { GdbMi data; data.fromStringMultiple(response.consoleStreamOutput); - const GdbMi dumpers = data["dumpers"]; - foreach (const GdbMi &dumper, dumpers.children()) { - QByteArray type = dumper["type"].data(); - QStringList formats(tr("Raw structure")); - foreach (const QByteArray &format, - dumper["formats"].data().split(',')) { - if (format == "Normal") - formats.append(tr("Normal")); - else if (format == "Displayed") - formats.append(tr("Displayed")); - else if (!format.isEmpty()) - formats.append(_(format)); - } - watchHandler()->addTypeFormats(type, formats); - } - + watchHandler()->addDumpers(data["dumpers"]); loadInitScript(); QTC_ASSERT(state() == EngineSetupRequested, qDebug() << state()); showMessage(_("ENGINE SUCCESSFULLY STARTED")); @@ -1793,7 +1726,7 @@ void GdbEngine::handlePythonSetup(const GdbResponse &response) QString out1 = _("The selected build of GDB does not support Python scripting."); QString out2 = _("It cannot be used in Qt Creator."); showStatusMessage(out1 + QLatin1Char(' ') + out2); - showMessageBox(QMessageBox::Critical, tr("Execution Error"), out1 + _("<br>") + out2); + AsynchronousMessageBox::critical(tr("Execution Error"), out1 + _("<br>") + out2); } notifyEngineSetupFailed(); } @@ -1801,14 +1734,14 @@ void GdbEngine::handlePythonSetup(const GdbResponse &response) void GdbEngine::showExecutionError(const QString &message) { - showMessageBox(QMessageBox::Critical, tr("Execution Error"), + AsynchronousMessageBox::critical(tr("Execution Error"), tr("Cannot continue debugged process:") + QLatin1Char('\n') + message); } -void GdbEngine::handleExecuteContinue(const GdbResponse &response) +void GdbEngine::handleExecuteContinue(const DebuggerResponse &response) { QTC_ASSERT(state() == InferiorRunRequested, qDebug() << state()); - if (response.resultClass == GdbResultRunning) { + if (response.resultClass == ResultRunning) { // All is fine. Waiting for a *running. notifyInferiorRunOk(); // Only needed for gdb < 7.0. return; @@ -1822,7 +1755,7 @@ void GdbEngine::handleExecuteContinue(const GdbResponse &response) flushQueuedCommands(); QTC_ASSERT(state() == InferiorStopOk, qDebug() << state()); showStatusMessage(tr("Stopped."), 5000); - reloadStack(true); + reloadStack(); } else if (msg.startsWith("Cannot access memory at address")) { // Happens on single step on ARM prolog and epilogs. } else if (msg.startsWith("\"finish\" not meaningful in the outermost frame")) { @@ -1890,7 +1823,7 @@ QString GdbEngine::cleanupFullName(const QString &fileName) } cleanFilePath.clear(); - const QString base = QFileInfo(fileName).fileName(); + const QString base = FileName::fromString(fileName).fileName(); QMap<QString, QString>::const_iterator jt = m_baseNameToFullName.find(base); while (jt != m_baseNameToFullName.end() && jt.key() == base) { @@ -1918,10 +1851,10 @@ void GdbEngine::shutdownInferior() QTC_ASSERT(false, notifyInferiorShutdownFailed()); } -void GdbEngine::handleInferiorShutdown(const GdbResponse &response) +void GdbEngine::handleInferiorShutdown(const DebuggerResponse &response) { QTC_ASSERT(state() == InferiorShutdownRequested, qDebug() << state()); - if (response.resultClass == GdbResultDone) { + if (response.resultClass == ResultDone) { notifyInferiorShutdownOk(); return; } @@ -1933,7 +1866,7 @@ void GdbEngine::handleInferiorShutdown(const GdbResponse &response) notifyInferiorShutdownOk(); return; } - showMessageBox(QMessageBox::Critical, + AsynchronousMessageBox::critical( tr("Failed to shut down application"), msgInferiorStopFailed(QString::fromLocal8Bit(ba))); notifyInferiorShutdownFailed(); @@ -1953,11 +1886,15 @@ void GdbEngine::notifyAdapterShutdownOk() .arg(lastGoodState()).arg(m_gdbProc->state())); m_commandsDoneCallback = 0; switch (m_gdbProc->state()) { - case QProcess::Running: + case QProcess::Running: { if (startParameters().closeMode == KillAndExitMonitorAtClose) postCommand("monitor exit"); - postCommand("-gdb-exit", GdbEngine::ExitRequest, CB(handleGdbExit)); + DebuggerCommand cmd("exitGdb"); + cmd.flags = GdbEngine::ExitRequest; + cmd.callback = CB(handleGdbExit); + runCommand(cmd); break; + } case QProcess::NotRunning: // Cannot find executable. notifyEngineShutdownOk(); @@ -1970,9 +1907,9 @@ void GdbEngine::notifyAdapterShutdownOk() } } -void GdbEngine::handleGdbExit(const GdbResponse &response) +void GdbEngine::handleGdbExit(const DebuggerResponse &response) { - if (response.resultClass == GdbResultExit) { + if (response.resultClass == ResultExit) { showMessage(_("GDB CLAIMS EXIT; WAITING")); // Don't set state here, this will be handled in handleGdbFinished() //notifyEngineShutdownOk(); @@ -1993,7 +1930,7 @@ void GdbEngine::detachDebugger() postCommand("detach", GdbEngine::ExitRequest, CB(handleDetach)); } -void GdbEngine::handleDetach(const GdbResponse &response) +void GdbEngine::handleDetach(const DebuggerResponse &response) { Q_UNUSED(response); QTC_ASSERT(state() == InferiorStopOk, qDebug() << state()); @@ -2054,6 +1991,7 @@ bool GdbEngine::hasCapability(unsigned cap) const | WatchComplexExpressionsCapability | MemoryAddressCapability | AdditionalQmlStackCapability + | NativeMixedCapability | ResetInferiorCapability)) return true; @@ -2097,22 +2035,27 @@ void GdbEngine::executeStep() setTokenBarrier(); notifyInferiorRunRequested(); showStatusMessage(tr("Step requested..."), 5000); + if (isNativeMixedActive()) { + runCommand("prepareQmlStep"); + postCommand("-exec-continue", RunRequest, CB(handleExecuteContinue)); + return; + } if (isReverseDebugging()) postCommand("reverse-step", RunRequest, CB(handleExecuteStep)); else postCommand("-exec-step", RunRequest, CB(handleExecuteStep)); } -void GdbEngine::handleExecuteStep(const GdbResponse &response) +void GdbEngine::handleExecuteStep(const DebuggerResponse &response) { - if (response.resultClass == GdbResultDone) { + if (response.resultClass == ResultDone) { // Step was finishing too quick, and a '*stopped' messages should // have preceded it, so just ignore this result. QTC_CHECK(state() == InferiorStopOk); return; } QTC_ASSERT(state() == InferiorRunRequested, qDebug() << state()); - if (response.resultClass == GdbResultRunning) { + if (response.resultClass == ResultRunning) { // All is fine. Waiting for a *running. notifyInferiorRunOk(); // Only needed for gdb < 7.0. return; @@ -2169,6 +2112,11 @@ void GdbEngine::executeNext() setTokenBarrier(); notifyInferiorRunRequested(); showStatusMessage(tr("Step next requested..."), 5000); + if (isNativeMixedActive()) { + runCommand("prepareQmlStep"); + postCommand("-exec-continue", RunRequest, CB(handleExecuteContinue)); + return; + } if (isReverseDebugging()) { postCommand("reverse-next", RunRequest, CB(handleExecuteNext)); } else { @@ -2179,16 +2127,16 @@ void GdbEngine::executeNext() } } -void GdbEngine::handleExecuteNext(const GdbResponse &response) +void GdbEngine::handleExecuteNext(const DebuggerResponse &response) { - if (response.resultClass == GdbResultDone) { + if (response.resultClass == ResultDone) { // Step was finishing too quick, and a '*stopped' messages should // have preceded it, so just ignore this result. QTC_CHECK(state() == InferiorStopOk); return; } QTC_ASSERT(state() == InferiorRunRequested, qDebug() << state()); - if (response.resultClass == GdbResultRunning) { + if (response.resultClass == ResultRunning) { // All is fine. Waiting for a *running. notifyInferiorRunOk(); // Only needed for gdb < 7.0. return; @@ -2206,7 +2154,7 @@ void GdbEngine::handleExecuteNext(const GdbResponse &response) showExecutionError(QString::fromLocal8Bit(msg)); notifyInferiorRunFailed(); } else { - showMessageBox(QMessageBox::Critical, tr("Execution Error"), + AsynchronousMessageBox::critical(tr("Execution Error"), tr("Cannot continue debugged process:") + QLatin1Char('\n') + QString::fromLocal8Bit(msg)); notifyInferiorIll(); } @@ -2293,9 +2241,9 @@ void GdbEngine::executeReturn() postCommand("-exec-finish", RunRequest, CB(handleExecuteReturn)); } -void GdbEngine::handleExecuteReturn(const GdbResponse &response) +void GdbEngine::handleExecuteReturn(const DebuggerResponse &response) { - if (response.resultClass == GdbResultDone) { + if (response.resultClass == ResultDone) { notifyInferiorStopOk(); updateAll(); return; @@ -2315,14 +2263,12 @@ void GdbEngine::setTokenBarrier() { //QTC_ASSERT(m_nonDiscardableCount == 0, /**/); bool good = true; - QHashIterator<int, GdbCommand> it(m_cookieForToken); + QHashIterator<int, DebuggerCommand> it(m_commandForToken); while (it.hasNext()) { it.next(); if (!(it.value().flags & Discardable)) { - qDebug() << "TOKEN: " << it.key() - << "CMD:" << it.value().command - << " FLAGS:" << it.value().flags - << " CALLBACK:" << it.value().callbackName; + qDebug() << "TOKEN: " << it.key() << "CMD:" << it.value().function + << " FLAGS:" << it.value().flags; good = false; } } @@ -2457,14 +2403,12 @@ QString GdbEngine::breakLocation(const QString &file) const { QString where = m_fullToShortName.value(file); if (where.isEmpty()) - return QFileInfo(file).fileName(); + return FileName::fromString(file).fileName(); return where; } -QByteArray GdbEngine::breakpointLocation(BreakpointModelId id) +QByteArray GdbEngine::breakpointLocation(const BreakpointParameters &data) { - BreakHandler *handler = breakHandler(); - const BreakpointParameters &data = handler->breakpointData(id); QTC_ASSERT(data.type != UnknownBreakpointType, return QByteArray()); // FIXME: Non-GCC-runtime if (data.type == BreakpointAtThrow) @@ -2492,12 +2436,8 @@ QByteArray GdbEngine::breakpointLocation(BreakpointModelId id) + QByteArray::number(data.lineNumber) + '"'; } -QByteArray GdbEngine::breakpointLocation2(BreakpointModelId id) +QByteArray GdbEngine::breakpointLocation2(const BreakpointParameters &data) { - BreakHandler *handler = breakHandler(); - - const BreakpointParameters &data = handler->breakpointData(id); - BreakpointPathUsage usage = data.pathUsage; if (usage == BreakpointPathUsageEngineDefault) usage = BreakpointUseShortPath; @@ -2508,12 +2448,10 @@ QByteArray GdbEngine::breakpointLocation2(BreakpointModelId id) + QByteArray::number(data.lineNumber); } -void GdbEngine::handleWatchInsert(const GdbResponse &response) +void GdbEngine::handleWatchInsert(const DebuggerResponse &response, Breakpoint bp) { - BreakpointModelId id = response.cookie.value<BreakpointModelId>(); - if (response.resultClass == GdbResultDone) { - BreakHandler *handler = breakHandler(); - BreakpointResponse br = handler->response(id); + if (bp && response.resultClass == ResultDone) { + BreakpointResponse br = bp.response(); // "Hardware watchpoint 2: *0xbfffed40\n" QByteArray ba = response.consoleStreamOutput; GdbMi wpt = response.data["wpt"]; @@ -2524,9 +2462,9 @@ void GdbEngine::handleWatchInsert(const GdbResponse &response) QByteArray exp = wpt["exp"].data(); if (exp.startsWith('*')) br.address = exp.mid(1).toULongLong(0, 0); - handler->setResponse(id, br); - QTC_CHECK(!handler->needsChange(id)); - handler->notifyBreakpointInsertOk(id); + bp.setResponse(br); + QTC_CHECK(!bp.needsChange()); + bp.notifyBreakpointInsertOk(); } else if (ba.startsWith("Hardware watchpoint ") || ba.startsWith("Watchpoint ")) { // Non-Mac: "Hardware watchpoint 2: *0xbfffed40\n" @@ -2536,27 +2474,25 @@ void GdbEngine::handleWatchInsert(const GdbResponse &response) br.id = BreakpointResponseId(ba.mid(begin, end - begin)); if (address.startsWith('*')) br.address = address.mid(1).toULongLong(0, 0); - handler->setResponse(id, br); - QTC_CHECK(!handler->needsChange(id)); - handler->notifyBreakpointInsertOk(id); + bp.setResponse(br); + QTC_CHECK(!bp.needsChange()); + bp.notifyBreakpointInsertOk(); } else { showMessage(_("CANNOT PARSE WATCHPOINT FROM " + ba)); } } } -void GdbEngine::handleCatchInsert(const GdbResponse &response) +void GdbEngine::handleCatchInsert(const DebuggerResponse &response, Breakpoint bp) { - BreakHandler *handler = breakHandler(); - BreakpointModelId id = response.cookie.value<BreakpointModelId>(); - if (response.resultClass == GdbResultDone) - handler->notifyBreakpointInsertOk(id); + if (bp && response.resultClass == ResultDone) + bp.notifyBreakpointInsertOk(); } -void GdbEngine::handleBkpt(const GdbMi &bkpt, const BreakpointModelId &id) +void GdbEngine::handleBkpt(const GdbMi &bkpt, Breakpoint bp) { - BreakHandler *handler = breakHandler(); - BreakpointResponse br = handler->response(id); + BreakpointResponse br = bp.response(); + QTC_ASSERT(bp, return); const QByteArray nr = bkpt["number"].data(); const BreakpointResponseId rid(nr); QTC_ASSERT(rid.isValid(), return); @@ -2565,8 +2501,8 @@ void GdbEngine::handleBkpt(const GdbMi &bkpt, const BreakpointModelId &id) BreakpointResponse sub; updateResponse(sub, bkpt); sub.id = rid; - sub.type = br.type; - handler->insertSubBreakpoint(id, sub); + sub.type = bp.type(); + bp.insertSubBreakpoint(sub); return; } @@ -2582,33 +2518,31 @@ void GdbEngine::handleBkpt(const GdbMi &bkpt, const BreakpointModelId &id) updateResponse(sub, loc); sub.id = subrid; sub.type = br.type; - handler->insertSubBreakpoint(id, sub); + bp.insertSubBreakpoint(sub); } } // A (the?) primary breakpoint. updateResponse(br, bkpt); br.id = rid; - handler->setResponse(id, br); + bp.setResponse(br); } -void GdbEngine::handleBreakInsert1(const GdbResponse &response) +void GdbEngine::handleBreakInsert1(const DebuggerResponse &response, Breakpoint bp) { - BreakHandler *handler = breakHandler(); - const BreakpointModelId id = response.cookie.value<BreakpointModelId>(); - if (handler->state(id) == BreakpointRemoveRequested) { - if (response.resultClass == GdbResultDone) { + if (bp.state() == BreakpointRemoveRequested) { + if (response.resultClass == ResultDone) { // This delete was deferred. Act now. const GdbMi mainbkpt = response.data["bkpt"]; - handler->notifyBreakpointRemoveProceeding(id); + bp.notifyBreakpointRemoveProceeding(); QByteArray nr = mainbkpt["number"].data(); postCommand("-break-delete " + nr, NeedsStop | RebuildBreakpointModel); - handler->notifyBreakpointRemoveOk(id); + bp.notifyBreakpointRemoveOk(); return; } } - if (response.resultClass == GdbResultDone) { + if (response.resultClass == ResultDone) { // The result is a list with the first entry marked "bkpt" // and "unmarked" rest. The "bkpt" one seems to always be // the "main" entry. Use the "main" entry to retrieve the @@ -2619,19 +2553,19 @@ void GdbEngine::handleBreakInsert1(const GdbResponse &response) const BreakpointResponseId mainrid(mainnr); if (!isHiddenBreakpoint(mainrid)) { foreach (const GdbMi &bkpt, response.data.children()) - handleBkpt(bkpt, id); - if (handler->needsChange(id)) { - handler->notifyBreakpointChangeAfterInsertNeeded(id); - changeBreakpoint(id); + handleBkpt(bkpt, bp); + if (bp.needsChange()) { + bp.notifyBreakpointChangeAfterInsertNeeded(); + changeBreakpoint(bp); } else { - handler->notifyBreakpointInsertOk(id); + bp.notifyBreakpointInsertOk(); } } } else if (response.data["msg"].data().contains("Unknown option")) { // Older version of gdb don't know the -a option to set tracepoints // ^error,msg="mi_cmd_break_insert: Unknown option ``a''" - const QString fileName = handler->fileName(id); - const int lineNumber = handler->lineNumber(id); + const QString fileName = bp.fileName(); + const int lineNumber = bp.lineNumber(); QByteArray cmd = "trace " "\"" + GdbMi::escapeCString(fileName.toLocal8Bit()) + "\":" + QByteArray::number(lineNumber); @@ -2640,18 +2574,17 @@ void GdbEngine::handleBreakInsert1(const GdbResponse &response) // Some versions of gdb like "GNU gdb (GDB) SUSE (6.8.91.20090930-2.4)" // know how to do pending breakpoints using CLI but not MI. So try // again with MI. - QByteArray cmd = "break " + breakpointLocation2(id); - QVariant vid = QVariant::fromValue(id); + QByteArray cmd = "break " + breakpointLocation2(bp.parameters()); postCommand(cmd, NeedsStop | RebuildBreakpointModel, - CB(handleBreakInsert2), vid); + [this, bp](const DebuggerResponse &r) { handleBreakInsert2(r, bp); }); } } -void GdbEngine::handleBreakInsert2(const GdbResponse &response) +void GdbEngine::handleBreakInsert2(const DebuggerResponse &response, Breakpoint bp) { - if (response.resultClass == GdbResultDone) { - BreakpointModelId id = response.cookie.value<BreakpointModelId>(); - breakHandler()->notifyBreakpointInsertOk(id); + if (response.resultClass == ResultDone) { + QTC_ASSERT(bp, return); + bp.notifyBreakpointInsertOk(); } else { // Note: gdb < 60800 doesn't "do" pending breakpoints. // Not much we can do about it except implementing the @@ -2660,57 +2593,57 @@ void GdbEngine::handleBreakInsert2(const GdbResponse &response) } } -void GdbEngine::handleBreakDisable(const GdbResponse &response) +void GdbEngine::handleBreakDelete(const DebuggerResponse &response, Breakpoint bp) { - QTC_CHECK(response.resultClass == GdbResultDone); - const BreakpointModelId id = response.cookie.value<BreakpointModelId>(); - BreakHandler *handler = breakHandler(); + if (response.resultClass == ResultDone) + bp.notifyBreakpointRemoveOk(); + else + bp.notifyBreakpointRemoveFailed(); +} + +void GdbEngine::handleBreakDisable(const DebuggerResponse &response, Breakpoint bp) +{ + QTC_CHECK(response.resultClass == ResultDone); // This should only be the requested state. - QTC_ASSERT(!handler->isEnabled(id), /* Prevent later recursion */); - BreakpointResponse br = handler->response(id); + QTC_ASSERT(!bp.isEnabled(), /* Prevent later recursion */); + BreakpointResponse br = bp.response(); br.enabled = false; - handler->setResponse(id, br); - changeBreakpoint(id); // Maybe there's more to do. + bp.setResponse(br); + changeBreakpoint(bp); // Maybe there's more to do. } -void GdbEngine::handleBreakEnable(const GdbResponse &response) +void GdbEngine::handleBreakEnable(const DebuggerResponse &response, Breakpoint bp) { - QTC_CHECK(response.resultClass == GdbResultDone); - const BreakpointModelId id = response.cookie.value<BreakpointModelId>(); - BreakHandler *handler = breakHandler(); + QTC_CHECK(response.resultClass == ResultDone); // This should only be the requested state. - QTC_ASSERT(handler->isEnabled(id), /* Prevent later recursion */); - BreakpointResponse br = handler->response(id); + QTC_ASSERT(bp.isEnabled(), /* Prevent later recursion */); + BreakpointResponse br = bp.response(); br.enabled = true; - handler->setResponse(id, br); - changeBreakpoint(id); // Maybe there's more to do. + bp.setResponse(br); + changeBreakpoint(bp); // Maybe there's more to do. } -void GdbEngine::handleBreakThreadSpec(const GdbResponse &response) +void GdbEngine::handleBreakThreadSpec(const DebuggerResponse &response, Breakpoint bp) { - QTC_CHECK(response.resultClass == GdbResultDone); - const BreakpointModelId id = response.cookie.value<BreakpointModelId>(); - BreakHandler *handler = breakHandler(); - BreakpointResponse br = handler->response(id); - br.threadSpec = handler->threadSpec(id); - handler->setResponse(id, br); - handler->notifyBreakpointNeedsReinsertion(id); - insertBreakpoint(id); + QTC_CHECK(response.resultClass == ResultDone); + BreakpointResponse br = bp.response(); + br.threadSpec = bp.threadSpec(); + bp.setResponse(br); + bp.notifyBreakpointNeedsReinsertion(); + insertBreakpoint(bp); } -void GdbEngine::handleBreakLineNumber(const GdbResponse &response) +void GdbEngine::handleBreakLineNumber(const DebuggerResponse &response, Breakpoint bp) { - QTC_CHECK(response.resultClass == GdbResultDone); - const BreakpointModelId id = response.cookie.value<BreakpointModelId>(); - BreakHandler *handler = breakHandler(); - BreakpointResponse br = handler->response(id); - br.lineNumber = handler->lineNumber(id); - handler->setResponse(id, br); - handler->notifyBreakpointNeedsReinsertion(id); - insertBreakpoint(id); + QTC_CHECK(response.resultClass == ResultDone); + BreakpointResponse br = bp.response(); + br.lineNumber = bp.lineNumber(); + bp.setResponse(br); + bp.notifyBreakpointNeedsReinsertion(); + insertBreakpoint(bp); } -void GdbEngine::handleBreakIgnore(const GdbResponse &response) +void GdbEngine::handleBreakIgnore(const DebuggerResponse &response, Breakpoint bp) { // gdb 6.8: // ignore 2 0: @@ -2722,39 +2655,35 @@ void GdbEngine::handleBreakIgnore(const GdbResponse &response) // 29^done // // gdb 6.3 does not produce any console output - QTC_CHECK(response.resultClass == GdbResultDone); + QTC_CHECK(response.resultClass == ResultDone); //QString msg = _(response.consoleStreamOutput); - BreakpointModelId id = response.cookie.value<BreakpointModelId>(); - BreakHandler *handler = breakHandler(); - BreakpointResponse br = handler->response(id); + BreakpointResponse br = bp.response(); //if (msg.contains(__("Will stop next time breakpoint"))) // response.ignoreCount = _("0"); //else if (msg.contains(__("Will ignore next"))) // response.ignoreCount = data->ignoreCount; // FIXME: this assumes it is doing the right thing... - const BreakpointParameters ¶meters = handler->breakpointData(id); + const BreakpointParameters ¶meters = bp.parameters(); br.ignoreCount = parameters.ignoreCount; br.command = parameters.command; - handler->setResponse(id, br); - changeBreakpoint(id); // Maybe there's more to do. + bp.setResponse(br); + changeBreakpoint(bp); // Maybe there's more to do. } -void GdbEngine::handleBreakCondition(const GdbResponse &response) +void GdbEngine::handleBreakCondition(const DebuggerResponse &, Breakpoint bp) { // Can happen at invalid condition strings. - //QTC_CHECK(response.resultClass == GdbResultDone) - const BreakpointModelId id = response.cookie.value<BreakpointModelId>(); - BreakHandler *handler = breakHandler(); + //QTC_CHECK(response.resultClass == ResultDone) // We just assume it was successful. Otherwise we had to parse // the output stream data. // The following happens on Mac: // QByteArray msg = response.data.findChild("msg").data(); // if (msg.startsWith("Error parsing breakpoint condition. " // " Will try again when we hit the breakpoint.")) - BreakpointResponse br = handler->response(id); - br.condition = handler->condition(id); - handler->setResponse(id, br); - changeBreakpoint(id); // Maybe there's more to do. + BreakpointResponse br = bp.response(); + br.condition = bp.condition(); + bp.setResponse(br); + changeBreakpoint(bp); // Maybe there's more to do. } bool GdbEngine::stateAcceptsBreakpointChanges() const @@ -2771,40 +2700,53 @@ bool GdbEngine::stateAcceptsBreakpointChanges() const } } -bool GdbEngine::acceptsBreakpoint(BreakpointModelId id) const +bool GdbEngine::acceptsBreakpoint(Breakpoint bp) const { - return breakHandler()->breakpointData(id).isCppBreakpoint() - && startParameters().startMode != AttachCore; + if (startParameters().startMode == AttachCore) + return false; + // We handle QML breakpoint unless specifically + if (isNativeMixedEnabled() && !(startParameters().languages & QmlLanguage)) + return true; + return bp.parameters().isCppBreakpoint(); } -void GdbEngine::insertBreakpoint(BreakpointModelId id) +void GdbEngine::insertBreakpoint(Breakpoint bp) { // Set up fallback in case of pending breakpoints which aren't handled // by the MI interface. - BreakHandler *handler = breakHandler(); - QTC_CHECK(handler->state(id) == BreakpointInsertRequested); - handler->notifyBreakpointInsertProceeding(id); - BreakpointType type = handler->type(id); - QVariant vid = QVariant::fromValue(id); + QTC_CHECK(bp.state() == BreakpointInsertRequested); + bp.notifyBreakpointInsertProceeding(); + + const BreakpointParameters &data = bp.parameters(); + + if (!data.isCppBreakpoint()) { + DebuggerCommand cmd("insertQmlBreakpoint"); + bp.addToCommand(&cmd); + runCommand(cmd); + bp.notifyBreakpointInsertOk(); + return; + } + + BreakpointType type = bp.type(); if (type == WatchpointAtAddress) { - postCommand("watch " + addressSpec(handler->address(id)), + postCommand("watch " + addressSpec(bp.address()), NeedsStop | RebuildBreakpointModel | ConsoleCommand, - CB(handleWatchInsert), vid); + [this, bp](const DebuggerResponse &r) { handleWatchInsert(r, bp); }); return; } if (type == WatchpointAtExpression) { - postCommand("watch " + handler->expression(id).toLocal8Bit(), + postCommand("watch " + bp.expression().toLocal8Bit(), NeedsStop | RebuildBreakpointModel | ConsoleCommand, - CB(handleWatchInsert), vid); + [this, bp](const DebuggerResponse &r) { handleWatchInsert(r, bp); }); return; } if (type == BreakpointAtFork) { postCommand("catch fork", NeedsStop | RebuildBreakpointModel | ConsoleCommand, - CB(handleCatchInsert), vid); + [this, bp](const DebuggerResponse &r) { handleCatchInsert(r, bp); }); postCommand("catch vfork", NeedsStop | RebuildBreakpointModel | ConsoleCommand, - CB(handleCatchInsert), vid); + [this, bp](const DebuggerResponse &r) { handleCatchInsert(r, bp); }); return; } //if (type == BreakpointAtVFork) { @@ -2815,72 +2757,70 @@ void GdbEngine::insertBreakpoint(BreakpointModelId id) if (type == BreakpointAtExec) { postCommand("catch exec", NeedsStop | RebuildBreakpointModel | ConsoleCommand, - CB(handleCatchInsert), vid); + [this, bp](const DebuggerResponse &r) { handleCatchInsert(r, bp); }); return; } if (type == BreakpointAtSysCall) { postCommand("catch syscall", NeedsStop | RebuildBreakpointModel | ConsoleCommand, - CB(handleCatchInsert), vid); + [this, bp](const DebuggerResponse &r) { handleCatchInsert(r, bp); }); return; } QByteArray cmd; - if (handler->isTracepoint(id)) { + if (bp.isTracepoint()) { cmd = "-break-insert -a -f "; } else { - int spec = handler->threadSpec(id); + int spec = bp.threadSpec(); cmd = "-break-insert "; if (spec >= 0) cmd += "-p " + QByteArray::number(spec); cmd += " -f "; } - if (handler->isOneShot(id)) + if (bp.isOneShot()) cmd += "-t "; - if (!handler->isEnabled(id)) + if (!bp.isEnabled()) cmd += "-d "; - if (int ignoreCount = handler->ignoreCount(id)) + if (int ignoreCount = bp.ignoreCount()) cmd += "-i " + QByteArray::number(ignoreCount) + ' '; - QByteArray condition = handler->condition(id); + QByteArray condition = bp.condition(); if (!condition.isEmpty()) cmd += " -c \"" + condition + "\" "; - cmd += breakpointLocation(id); + cmd += breakpointLocation(bp.parameters()); postCommand(cmd, NeedsStop | RebuildBreakpointModel, - CB(handleBreakInsert1), vid); + [this, bp](const DebuggerResponse &r) { handleBreakInsert1(r, bp); }); } -void GdbEngine::changeBreakpoint(BreakpointModelId id) +void GdbEngine::changeBreakpoint(Breakpoint bp) { - BreakHandler *handler = breakHandler(); - const BreakpointParameters &data = handler->breakpointData(id); + const BreakpointParameters &data = bp.parameters(); QTC_ASSERT(data.type != UnknownBreakpointType, return); - const BreakpointResponse &response = handler->response(id); + const BreakpointResponse &response = bp.response(); QTC_ASSERT(response.id.isValid(), return); const QByteArray bpnr = response.id.toByteArray(); - const BreakpointState state = handler->state(id); + const BreakpointState state = bp.state(); if (state == BreakpointChangeRequested) - handler->notifyBreakpointChangeProceeding(id); - const BreakpointState state2 = handler->state(id); + bp.notifyBreakpointChangeProceeding(); + const BreakpointState state2 = bp.state(); QTC_ASSERT(state2 == BreakpointChangeProceeding, qDebug() << state2); - QVariant vid = QVariant::fromValue(id); if (!response.pending && data.threadSpec != response.threadSpec) { // The only way to change this seems to be to re-set the bp completely. postCommand("-break-delete " + bpnr, NeedsStop | RebuildBreakpointModel, - CB(handleBreakThreadSpec), vid); + [this, bp](const DebuggerResponse &r) { handleBreakThreadSpec(r, bp); }); return; } if (!response.pending && data.lineNumber != response.lineNumber) { // The only way to change this seems to be to re-set the bp completely. postCommand("-break-delete " + bpnr, NeedsStop | RebuildBreakpointModel, - CB(handleBreakLineNumber), vid); + [this, bp](const DebuggerResponse &r) { handleBreakLineNumber(r, bp); }); return; } if (data.command != response.command) { @@ -2893,51 +2833,57 @@ void GdbEngine::changeBreakpoint(BreakpointModelId id) } } postCommand(breakCommand, NeedsStop | RebuildBreakpointModel, - CB(handleBreakIgnore), vid); + [this, bp](const DebuggerResponse &r) { handleBreakIgnore(r, bp); }); return; } if (!data.conditionsMatch(response.condition)) { postCommand("condition " + bpnr + ' ' + data.condition, NeedsStop | RebuildBreakpointModel, - CB(handleBreakCondition), vid); + [this, bp](const DebuggerResponse &r) { handleBreakCondition(r, bp); }); return; } if (data.ignoreCount != response.ignoreCount) { postCommand("ignore " + bpnr + ' ' + QByteArray::number(data.ignoreCount), NeedsStop | RebuildBreakpointModel, - CB(handleBreakIgnore), vid); + [this, bp](const DebuggerResponse &r) { handleBreakIgnore(r, bp); }); return; } if (!data.enabled && response.enabled) { postCommand("-break-disable " + bpnr, NeedsStop | RebuildBreakpointModel, - CB(handleBreakDisable), vid); + [this, bp](const DebuggerResponse &r) { handleBreakDisable(r, bp); }); return; } if (data.enabled && !response.enabled) { postCommand("-break-enable " + bpnr, NeedsStop | RebuildBreakpointModel, - CB(handleBreakEnable), vid); + [this, bp](const DebuggerResponse &r) { handleBreakEnable(r, bp); }); return; } - handler->notifyBreakpointChangeOk(id); + bp.notifyBreakpointChangeOk(); } -void GdbEngine::removeBreakpoint(BreakpointModelId id) +void GdbEngine::removeBreakpoint(Breakpoint bp) { - BreakHandler *handler = breakHandler(); - QTC_CHECK(handler->state(id) == BreakpointRemoveRequested); - BreakpointResponse br = handler->response(id); + QTC_CHECK(bp.state() == BreakpointRemoveRequested); + BreakpointResponse br = bp.response(); + + const BreakpointParameters &data = bp.parameters(); + if (!data.isCppBreakpoint()) { + DebuggerCommand cmd("removeQmlBreakpoint"); + bp.addToCommand(&cmd); + runCommand(cmd); + bp.notifyBreakpointRemoveOk(); + return; + } + if (br.id.isValid()) { // We already have a fully inserted breakpoint. - handler->notifyBreakpointRemoveProceeding(id); - showMessage(_("DELETING BP %1 IN %2").arg(br.id.toString()) - .arg(handler->fileName(id))); + bp.notifyBreakpointRemoveProceeding(); + showMessage(_("DELETING BP %1 IN %2").arg(br.id.toString()).arg(bp.fileName())); postCommand("-break-delete " + br.id.toByteArray(), - NeedsStop | RebuildBreakpointModel); - // Pretend it succeeds without waiting for response. Feels better. - // FIXME: Really? - handler->notifyBreakpointRemoveOk(id); + NeedsStop | RebuildBreakpointModel, + [this, bp](const DebuggerResponse &r) { handleBreakDelete(r, bp); }); } else { // Breakpoint was scheduled to be inserted, but we haven't had // an answer so far. Postpone activity by doing nothing. @@ -2956,7 +2902,7 @@ void GdbEngine::loadSymbols(const QString &modulePath) // FIXME: gdb does not understand quoted names here (tested with 6.8) postCommand("sharedlibrary " + dotEscape(modulePath.toLocal8Bit())); reloadModulesInternal(); - reloadStack(true); + reloadStack(); updateLocals(); } @@ -2964,7 +2910,7 @@ void GdbEngine::loadAllSymbols() { postCommand("sharedlibrary .*"); reloadModulesInternal(); - reloadStack(true); + reloadStack(); updateLocals(); } @@ -2987,30 +2933,15 @@ void GdbEngine::loadSymbolsForStack() } if (needUpdate) { //reloadModulesInternal(); - reloadStack(true); + reloadStack(); updateLocals(); } } -void GdbEngine::requestModuleSymbols(const QString &modulePath) +static void handleShowModuleSymbols(const DebuggerResponse &response, + const QString &modulePath, const QString &fileName) { - QTemporaryFile tf(QDir::tempPath() + _("/gdbsymbols")); - if (!tf.open()) - return; - QString fileName = tf.fileName(); - tf.close(); - postCommand("maint print msymbols \"" + fileName.toLocal8Bit() - + "\" " + modulePath.toLocal8Bit(), - NeedsStop, CB(handleShowModuleSymbols), - QVariant(modulePath + QLatin1Char('@') + fileName)); -} - -void GdbEngine::handleShowModuleSymbols(const GdbResponse &response) -{ - const QString cookie = response.cookie.toString(); - const QString modulePath = cookie.section(QLatin1Char('@'), 0, 0); - const QString fileName = cookie.section(QLatin1Char('@'), 1, 1); - if (response.resultClass == GdbResultDone) { + if (response.resultClass == ResultDone) { Symbols symbols; QFile file(fileName); file.open(QIODevice::ReadOnly); @@ -3061,24 +2992,38 @@ void GdbEngine::handleShowModuleSymbols(const GdbResponse &response) file.remove(); Internal::showModuleSymbols(modulePath, symbols); } else { - showMessageBox(QMessageBox::Critical, tr("Cannot Read Symbols"), - tr("Cannot read symbols for module \"%1\".").arg(fileName)); + AsynchronousMessageBox::critical(GdbEngine::tr("Cannot Read Symbols"), + GdbEngine::tr("Cannot read symbols for module \"%1\".").arg(fileName)); } } +void GdbEngine::requestModuleSymbols(const QString &modulePath) +{ + QTemporaryFile tf(QDir::tempPath() + _("/gdbsymbols")); + if (!tf.open()) + return; + QString fileName = tf.fileName(); + tf.close(); + postCommand("maint print msymbols \"" + fileName.toLocal8Bit() + + "\" " + modulePath.toLocal8Bit(), NeedsStop, + [modulePath, fileName](const DebuggerResponse &r) { + handleShowModuleSymbols(r, modulePath, fileName); }); +} + void GdbEngine::requestModuleSections(const QString &moduleName) { // There seems to be no way to get the symbols from a single .so. - postCommand("maint info section ALLOBJ", - NeedsStop, CB(handleShowModuleSections), moduleName); + postCommand("maint info section ALLOBJ", NeedsStop, + [this, moduleName](const DebuggerResponse &r) { + handleShowModuleSections(r, moduleName); }); } -void GdbEngine::handleShowModuleSections(const GdbResponse &response) +void GdbEngine::handleShowModuleSections(const DebuggerResponse &response, + const QString &moduleName) { // ~" Object file: /usr/lib/i386-linux-gnu/libffi.so.6\n" // ~" 0xb44a6114->0xb44a6138 at 0x00000114: .note.gnu.build-id ALLOC LOAD READONLY DATA HAS_CONTENTS\n" - if (response.resultClass == GdbResultDone) { - const QString moduleName = response.cookie.toString(); + if (response.resultClass == ResultDone) { const QStringList lines = QString::fromLocal8Bit(response.consoleStreamOutput).split(QLatin1Char('\n')); const QString prefix = QLatin1String(" Object file: "); const QString needle = prefix + moduleName; @@ -3127,9 +3072,9 @@ static QString nameFromPath(const QString &path) return QFileInfo(path).baseName(); } -void GdbEngine::handleModulesList(const GdbResponse &response) +void GdbEngine::handleModulesList(const DebuggerResponse &response) { - if (response.resultClass == GdbResultDone) { + if (response.resultClass == ResultDone) { ModulesHandler *handler = modulesHandler(); Module module; // That's console-based output, likely Linux or Windows, @@ -3227,11 +3172,11 @@ void GdbEngine::selectThread(ThreadId threadId) CB(handleStackSelectThread)); } -void GdbEngine::handleStackSelectThread(const GdbResponse &) +void GdbEngine::handleStackSelectThread(const DebuggerResponse &) { QTC_CHECK(state() == InferiorUnrunnable || state() == InferiorStopOk); showStatusMessage(tr("Retrieving data for stack view..."), 3000); - reloadStack(true); // Will reload registers. + reloadStack(); // Will reload registers. updateLocals(); } @@ -3239,8 +3184,10 @@ void GdbEngine::reloadFullStack() { PENDING_DEBUG("RELOAD FULL STACK"); resetLocation(); - postCommand("-stack-list-frames", Discardable, CB(handleStackListFrames), - QVariant::fromValue<StackCookie>(StackCookie(true, true))); + DebuggerCommand cmd = stackCommand(-1); + cmd.flags = Discardable; + cmd.callback = [this](const DebuggerResponse &r) { handleStackListFrames(r, true); }; + runCommand(cmd); } void GdbEngine::loadAdditionalQmlStack() @@ -3277,7 +3224,7 @@ static QString msgCannotLoadQmlStack(const QString &why) return _("Unable to load QML stack: ") + why; } -void GdbEngine::handleQmlStackFrameArguments(const GdbResponse &response) +void GdbEngine::handleQmlStackFrameArguments(const DebuggerResponse &response) { if (!response.data.isValid()) { showMessage(msgCannotLoadQmlStack(_("No stack obtained.")), LogError); @@ -3292,10 +3239,10 @@ void GdbEngine::handleQmlStackFrameArguments(const GdbResponse &response) QByteArray command = "-data-evaluate-expression \"qt_v4StackTrace((QV4::ExecutionContext *)0x"; command += QByteArray::number(contextAddress, 16); command += ")\""; - postCommand(command, CB(handleQmlStackTrace)); + postCommand(command, NoFlags, CB(handleQmlStackTrace)); } -void GdbEngine::handleQmlStackTrace(const GdbResponse &response) +void GdbEngine::handleQmlStackTrace(const DebuggerResponse &response) { if (!response.data.isValid()) { showMessage(msgCannotLoadQmlStack(_("No result obtained.")), LogError); @@ -3327,15 +3274,21 @@ void GdbEngine::handleQmlStackTrace(const GdbResponse &response) stackHandler()->prependFrames(qmlFrames); } -void GdbEngine::reloadStack(bool forceGotoLocation) +DebuggerCommand GdbEngine::stackCommand(int depth) +{ + DebuggerCommand cmd("stackListFrames"); + cmd.arg("limit", depth); + cmd.arg("options", isNativeMixedActive() ? "nativemixed" : ""); + return cmd; +} + +void GdbEngine::reloadStack() { PENDING_DEBUG("RELOAD STACK"); - QByteArray cmd = "-stack-list-frames"; - int stackDepth = action(MaximalStackDepth)->value().toInt(); - if (stackDepth) - cmd += " 0 " + QByteArray::number(stackDepth); - postCommand(cmd, Discardable, CB(handleStackListFrames), - QVariant::fromValue<StackCookie>(StackCookie(false, forceGotoLocation))); + DebuggerCommand cmd = stackCommand(action(MaximalStackDepth)->value().toInt()); + cmd.flags = Discardable; + cmd.callback = [this](const DebuggerResponse &r) { handleStackListFrames(r, false); }; + runCommand(cmd); } StackFrame GdbEngine::parseStackFrame(const GdbMi &frameMi, int level) @@ -3352,15 +3305,24 @@ StackFrame GdbEngine::parseStackFrame(const GdbMi &frameMi, int level) frame.from = _(frameMi["from"].data()); frame.line = frameMi["line"].toInt(); frame.address = frameMi["addr"].toAddress(); - frame.usable = QFileInfo(frame.file).isReadable(); - if (frameMi["language"].data() == "js") + GdbMi usable = frameMi["usable"]; + if (usable.isValid()) + frame.usable = usable.data().toInt(); + else + frame.usable = QFileInfo(frame.file).isReadable(); + if (frameMi["language"].data() == "js" + || frame.file.endsWith(QLatin1String(".js")) + || frame.file.endsWith(QLatin1String(".qml"))) { + frame.file = QFile::decodeName(frameMi["file"].data()); frame.language = QmlLanguage; + frame.fixQmlFrame(startParameters()); + } return frame; } -void GdbEngine::handleStackListFrames(const GdbResponse &response) +void GdbEngine::handleStackListFrames(const DebuggerResponse &response, bool isFull) { - if (response.resultClass != GdbResultDone) { + if (response.resultClass != ResultDone) { // That always happens on symbian gdb with // ^error,data={msg="Previous frame identical to this frame (corrupt stack?)" // logStreamOutput: "Previous frame identical to this frame (corrupt stack?)\n" @@ -3369,10 +3331,12 @@ void GdbEngine::handleStackListFrames(const GdbResponse &response) return; } - StackCookie cookie = response.cookie.value<StackCookie>(); QList<StackFrame> stackFrames; - GdbMi stack = response.data["stack"]; + GdbMi stack = response.data["stack"]; // C++ + if (!stack.isValid() || stack.childCount() == 0) // Mixed. + stack.fromStringMultiple(response.consoleStreamOutput); + if (!stack.isValid()) { qDebug() << "FIXME: stack:" << stack.toString(); return; @@ -3391,8 +3355,7 @@ void GdbEngine::handleStackListFrames(const GdbResponse &response) targetFrame = i; } - bool canExpand = !cookie.isFull - && (n >= action(MaximalStackDepth)->value().toInt()); + bool canExpand = !isFull && (n >= action(MaximalStackDepth)->value().toInt()); action(ExpandStack)->setEnabled(canExpand); stackHandler()->setFrames(stackFrames, canExpand); @@ -3429,34 +3392,28 @@ void GdbEngine::activateFrame(int frameIndex) } QTC_ASSERT(frameIndex < handler->stackSize(), return); - - if (handler->frameAt(frameIndex).language == QmlLanguage) { - gotoLocation(handler->frameAt(frameIndex)); - return; - } - // Assuming the command always succeeds this saves a roundtrip. - // Otherwise the lines below would need to get triggered - // after a response to this -stack-select-frame here. handler->setCurrentIndex(frameIndex); - QByteArray cmd = "-stack-select-frame"; - //if (!m_currentThread.isEmpty()) - // cmd += " --thread " + m_currentThread; - cmd += ' '; - cmd += QByteArray::number(frameIndex); - postCommand(cmd, Discardable, CB(handleStackSelectFrame)); gotoLocation(stackHandler()->currentFrame()); + + if (handler->frameAt(frameIndex).language != QmlLanguage) { + // Assuming the command always succeeds this saves a roundtrip. + // Otherwise the lines below would need to get triggered + // after a response to this -stack-select-frame here. + QByteArray cmd = "-stack-select-frame"; + //if (!m_currentThread.isEmpty()) + // cmd += " --thread " + m_currentThread; + cmd += ' '; + cmd += QByteArray::number(frameIndex); + postCommand(cmd, Discardable); + } + updateLocals(); reloadRegisters(); } -void GdbEngine::handleStackSelectFrame(const GdbResponse &response) +void GdbEngine::handleThreadInfo(const DebuggerResponse &response) { - Q_UNUSED(response); -} - -void GdbEngine::handleThreadInfo(const GdbResponse &response) -{ - if (response.resultClass == GdbResultDone) { + if (response.resultClass == ResultDone) { ThreadsHandler *handler = threadsHandler(); handler->updateThreads(response.data); // This is necessary as the current thread might not be in the list. @@ -3471,7 +3428,7 @@ void GdbEngine::handleThreadInfo(const GdbResponse &response) action(MaximalStackDepth)->value().toByteArray(), Discardable, CB(handleThreadNames)); } - reloadStack(false); // Will trigger register reload. + reloadStack(); // Will trigger register reload. } else { // Fall back for older versions: Try to get at least a list // of running threads. @@ -3479,7 +3436,7 @@ void GdbEngine::handleThreadInfo(const GdbResponse &response) } } -void GdbEngine::handleThreadListIds(const GdbResponse &response) +void GdbEngine::handleThreadListIds(const DebuggerResponse &response) { // "72^done,{thread-ids={thread-id="2",thread-id="1"},number-of-threads="2"} // In gdb 7.1+ additionally: current-thread-id="1" @@ -3490,12 +3447,12 @@ void GdbEngine::handleThreadListIds(const GdbResponse &response) thread.id = ThreadId(items.at(index).toInt()); handler->updateThread(thread); } - reloadStack(false); // Will trigger register reload. + reloadStack(); // Will trigger register reload. } -void GdbEngine::handleThreadNames(const GdbResponse &response) +void GdbEngine::handleThreadNames(const DebuggerResponse &response) { - if (response.resultClass == GdbResultDone) { + if (response.resultClass == ResultDone) { ThreadsHandler *handler = threadsHandler(); GdbMi names; names.fromString(response.consoleStreamOutput); @@ -3525,20 +3482,20 @@ void GdbEngine::createSnapshot() fileName = tf.fileName(); tf.close(); // This must not be quoted, it doesn't work otherwise. - postCommand("gcore " + fileName.toLocal8Bit(), - NeedsStop|ConsoleCommand, CB(handleMakeSnapshot), fileName); + postCommand("gcore " + fileName.toLocal8Bit(), NeedsStop|ConsoleCommand, + [this, fileName](const DebuggerResponse &r) { handleMakeSnapshot(r, fileName); }); } else { - showMessageBox(QMessageBox::Critical, tr("Snapshot Creation Error"), + AsynchronousMessageBox::critical(tr("Snapshot Creation Error"), tr("Cannot create snapshot file.")); } } -void GdbEngine::handleMakeSnapshot(const GdbResponse &response) +void GdbEngine::handleMakeSnapshot(const DebuggerResponse &response, const QString &coreFile) { - if (response.resultClass == GdbResultDone) { + if (response.resultClass == ResultDone) { DebuggerStartParameters sp = startParameters(); sp.startMode = AttachCore; - sp.coreFile = response.cookie.toString(); + sp.coreFile = coreFile; //snapshot.setDate(QDateTime::currentDateTime()); StackFrames frames = stackHandler()->frames(); QString function = _("<unknown>"); @@ -3551,7 +3508,7 @@ void GdbEngine::handleMakeSnapshot(const GdbResponse &response) DebuggerRunControlFactory::createAndScheduleRun(sp); } else { QByteArray msg = response.data["msg"].data(); - showMessageBox(QMessageBox::Critical, tr("Snapshot Creation Error"), + AsynchronousMessageBox::critical(tr("Snapshot Creation Error"), tr("Cannot create snapshot:") + QLatin1Char('\n') + QString::fromLocal8Bit(msg)); } } @@ -3570,69 +3527,144 @@ void GdbEngine::reloadRegisters() if (state() != InferiorStopOk && state() != InferiorUnrunnable) return; - if (!m_registerNamesListed) { - postCommand("-data-list-register-names", CB(handleRegisterListNames)); - m_registerNamesListed = true; + + if (true) { + if (!m_registerNamesListed) { + postCommand("-data-list-register-names", NoFlags, CB(handleRegisterListNames)); + m_registerNamesListed = true; + } + // Can cause i386-linux-nat.c:571: internal-error: Got request + // for bad register number 41.\nA problem internal to GDB has been detected. + postCommand("-data-list-register-values r", + Discardable, CB(handleRegisterListValues)); + } else { + postCommand("maintenance print cooked-registers", NoFlags, CB(handleMaintPrintRegisters)); } +} - postCommand("-data-list-register-values r", - Discardable, CB(handleRegisterListValues)); +static QByteArray readWord(const QByteArray &ba, int *pos) +{ + const int n = ba.size(); + while (*pos < n && ba.at(*pos) == ' ') + ++*pos; + const int start = *pos; + while (*pos < n && ba.at(*pos) != ' ' && ba.at(*pos) != '\n') + ++*pos; + return ba.mid(start, *pos - start); } -void GdbEngine::setRegisterValue(int nr, const QString &value) +void GdbEngine::handleMaintPrintRegisters(const DebuggerResponse &response) { - Register reg = registerHandler()->registers().at(nr); - postCommand("set $" + reg.name + "=" + value.toLatin1()); + if (response.resultClass != ResultDone) + return; + + const QByteArray &ba = response.consoleStreamOutput; + RegisterHandler *handler = registerHandler(); + //0 1 2 3 4 5 6 + //0123456789012345678901234567890123456789012345678901234567890 + // Name Nr Rel Offset Size Type Raw value + // rax 0 0 0 8 int64_t 0x0000000000000000 + // rip 16 16 128 8 *1 0x0000000000400dc9 + // eflags 17 17 136 4 i386_eflags 0x00000246 + // cs 18 18 140 4 int32_t 0x00000033 + // xmm15 55 55 516 16 vec128 0x00000000000000000000000000000000 + // mxcsr 56 56 532 4 i386_mxcsr 0x00001fa0 + // '' + // st6 30 30 224 10 _i387_ext 0x00000000000000000000 + // st7 31 31 234 10 _i387_ext 0x00000000000000000000 + // fctrl 32 32 244 4 int 0x0000037f + + const int n = ba.size(); + int pos = 0; + while (true) { + // Skip first line, and until '\n' after each line finished. + while (pos < n && ba.at(pos) != '\n') + ++pos; + if (pos >= n) + break; + ++pos; // skip \n + Register reg; + reg.name = readWord(ba, &pos); + if (reg.name == "''" || reg.name == "*1:" || reg.name.isEmpty()) + continue; + readWord(ba, &pos); // Nr + readWord(ba, &pos); // Rel + readWord(ba, &pos); // Offset + reg.size = readWord(ba, &pos).toInt(); + reg.reportedType = readWord(ba, &pos); + reg.value = readWord(ba, &pos); + handler->updateRegister(reg); + } + handler->commitUpdates(); +} +void GdbEngine::setRegisterValue(const QByteArray &name, const QString &value) +{ + postCommand("set $" + name + "=" + value.toLatin1()); reloadRegisters(); } -void GdbEngine::handleRegisterListNames(const GdbResponse &response) +void GdbEngine::handleRegisterListNames(const DebuggerResponse &response) { - if (response.resultClass != GdbResultDone) { + if (response.resultClass != ResultDone) { m_registerNamesListed = false; return; } - Registers registers; - int gdbRegisterNumber = 0, internalIndex = 0; - - // This both handles explicitly having space for all the registers and - // initializes all indices to 0, giving missing registers a sane default - // in the event of something wacky. GdbMi names = response.data["register-names"]; - m_registerNumbers.resize(names.childCount()); + m_registerNames.clear(); + int gdbRegisterNumber = 0; foreach (const GdbMi &item, names.children()) { - // Since we throw away missing registers to eliminate empty rows - // we need to maintain a mapping of GDB register numbers to their - // respective indices in the register list. - if (!item.data().isEmpty()) { - m_registerNumbers[gdbRegisterNumber] = internalIndex++; - registers.append(Register(item.data())); - } - gdbRegisterNumber++; + if (!item.data().isEmpty()) + m_registerNames[gdbRegisterNumber] = item.data(); + ++gdbRegisterNumber; } - - registerHandler()->setRegisters(registers); } -void GdbEngine::handleRegisterListValues(const GdbResponse &response) +void GdbEngine::handleRegisterListValues(const DebuggerResponse &response) { - if (response.resultClass != GdbResultDone) + if (response.resultClass != ResultDone) return; - Registers registers = registerHandler()->registers(); - const int registerCount = registers.size(); - const int gdbRegisterCount = m_registerNumbers.size(); - + RegisterHandler *handler = registerHandler(); // 24^done,register-values=[{number="0",value="0xf423f"},...] const GdbMi values = response.data["register-values"]; - QTC_ASSERT(registerCount == values.children().size(), return); foreach (const GdbMi &item, values.children()) { + Register reg; const int number = item["number"].toInt(); - if (number >= 0 && number < gdbRegisterCount) - registers[m_registerNumbers[number]].value = item["value"].data(); + reg.name = m_registerNames[number]; + QByteArray data = item["value"].data(); + if (data.startsWith("0x")) { + reg.value = data; + } else { + // This is what GDB considers machine readable output: + // value="{v4_float = {0x00000000, 0x00000000, 0x00000000, 0x00000000}, + // v2_double = {0x0000000000000000, 0x0000000000000000}, + // v16_int8 = {0x00 <repeats 16 times>}, + // v8_int16 = {0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000}, + // v4_int32 = {0x00000000, 0x00000000, 0x00000000, 0x00000000}, + // v2_int64 = {0x0000000000000000, 0x0000000000000000}, + // uint128 = <error reading variable>}"} + // Try to make sense of it using the int32 chunks: + QByteArray result = "0x"; + const int pos1 = data.indexOf("_int32"); + const int pos2 = data.indexOf('{', pos1) + 1; + const int pos3 = data.indexOf('}', pos2); + QByteArray inner = data.mid(pos2, pos3 - pos2); + QList<QByteArray> list = inner.split(','); + for (int i = list.size(); --i >= 0; ) { + QByteArray chunk = list.at(i); + if (chunk.startsWith(' ')) + chunk.remove(0, 1); + if (chunk.startsWith("0x")) + chunk.remove(0, 2); + QTC_ASSERT(chunk.size() == 8, continue); + result.append(chunk); + } + reg.value = result; + } + handler->updateRegister(reg); } - registerHandler()->setAndMarkRegisters(registers); + handler->commitUpdates(); } @@ -3650,8 +3682,6 @@ bool GdbEngine::setToolTipExpression(TextEditor::TextEditorWidget *editor, UpdateParameters params; params.tryPartial = true; - params.tooltipOnly = true; - params.tooltipExpression = context.expression; params.varList = context.iname; updateLocalsPython(params); return true; @@ -3699,9 +3729,7 @@ void GdbEngine::updateWatchData(const WatchData &data, const WatchUpdateFlags &f // << (m_pendingBreakpointRequests == 0); UpdateParameters params; - params.tooltipOnly = data.iname.startsWith("tooltip"); - params.tryPartial = flags.tryIncremental - && m_pendingBreakpointRequests == 0; + params.tryPartial = flags.tryIncremental && m_pendingBreakpointRequests == 0; params.varList = data.iname; updateLocalsPython(params); @@ -3722,7 +3750,7 @@ void GdbEngine::rebuildWatchModel() DebuggerToolTipManager::updateEngine(this); } -void GdbEngine::handleVarAssign(const GdbResponse &) +void GdbEngine::handleVarAssign(const DebuggerResponse &) { // Everything might have changed, force re-evaluation. setTokenBarrier(); @@ -3757,17 +3785,13 @@ void GdbEngine::insertData(const WatchData &data) void GdbEngine::assignValueInDebugger(const WatchData *data, const QString &expression, const QVariant &value) { - if (!isIntOrFloatType(data->type)) { - QByteArray cmd = "bbedit " - + data->type.toHex() + ',' - + expression.toUtf8().toHex() + ',' - + value.toString().toUtf8().toHex(); - postCommand(cmd, Discardable, CB(handleVarAssign)); - } else { - postCommand("set variable (" + expression.toLatin1() + ")=" - + GdbMi::escapeCString(value.toString().toLatin1()), - Discardable, CB(handleVarAssign)); - } + DebuggerCommand cmd("assignValue"); + cmd.arg("type", data->type.toHex()); + cmd.arg("expr", expression.toLatin1().toHex()); + cmd.arg("value", value.toString().toLatin1().toHex()); + cmd.arg("simpleType", isIntOrFloatType(data->type)); + cmd.callback = CB(handleVarAssign); + runCommand(cmd); } void GdbEngine::watchPoint(const QPoint &pnt) @@ -3779,9 +3803,9 @@ void GdbEngine::watchPoint(const QPoint &pnt) NeedsStop, CB(handleWatchPoint)); } -void GdbEngine::handleWatchPoint(const GdbResponse &response) +void GdbEngine::handleWatchPoint(const DebuggerResponse &response) { - if (response.resultClass == GdbResultDone) { + if (response.resultClass == ResultDone) { // "$5 = (void *) 0xbfa7ebfc\n" const QByteArray ba = parsePlainConsoleStream(response); const int pos0x = ba.indexOf("0x"); @@ -3832,10 +3856,10 @@ void GdbEngine::changeMemory(MemoryAgent *agent, QObject *token, ac.token = token; ac.base = addr; ac.length = data.size(); - postCommand(cmd, NeedsStop, CB(handleChangeMemory), QVariant::fromValue(ac)); + postCommand(cmd, NeedsStop, CB(handleChangeMemory)); } -void GdbEngine::handleChangeMemory(const GdbResponse &response) +void GdbEngine::handleChangeMemory(const DebuggerResponse &response) { Q_UNUSED(response); } @@ -3856,21 +3880,20 @@ void GdbEngine::fetchMemory(MemoryAgent *agent, QObject *token, quint64 addr, void GdbEngine::fetchMemoryHelper(const MemoryAgentCookie &ac) { postCommand("-data-read-memory 0x" + QByteArray::number(ac.base + ac.offset, 16) + " x 1 1 " - + QByteArray::number(ac.length), - NeedsStop, CB(handleFetchMemory), QVariant::fromValue(ac)); + + QByteArray::number(ac.length), NeedsStop, + [this, ac](const DebuggerResponse &r) { handleFetchMemory(r, ac); }); } -void GdbEngine::handleFetchMemory(const GdbResponse &response) +void GdbEngine::handleFetchMemory(const DebuggerResponse &response, MemoryAgentCookie ac) { // ^done,addr="0x08910c88",nr-bytes="16",total-bytes="16", // next-row="0x08910c98",prev-row="0x08910c78",next-page="0x08910c98", // prev-page="0x08910c78",memory=[{addr="0x08910c88", // data=["1","0","0","0","5","0","0","0","0","0","0","0","0","0","0","0"]}] - MemoryAgentCookie ac = response.cookie.value<MemoryAgentCookie>(); --*ac.pendingRequests; showMessage(QString::fromLatin1("PENDING: %1").arg(*ac.pendingRequests)); QTC_ASSERT(ac.agent, return); - if (response.resultClass == GdbResultDone) { + if (response.resultClass == ResultDone) { GdbMi memory = response.data["memory"]; QTC_ASSERT(memory.children().size() <= 1, return); if (memory.children().isEmpty()) @@ -3946,25 +3969,34 @@ static inline QByteArray disassemblerCommand(const Location &location, bool mixe return command; } -void GdbEngine::fetchDisassemblerByCliPointMixed(const DisassemblerAgentCookie &ac0) +void GdbEngine::fetchDisassemblerByCliPointMixed(const DisassemblerAgentCookie &ac) { - DisassemblerAgentCookie ac = ac0; QTC_ASSERT(ac.agent, return); postCommand(disassemblerCommand(ac.agent->location(), true), Discardable|ConsoleCommand, - CB(handleFetchDisassemblerByCliPointMixed), - QVariant::fromValue(ac)); + [this, ac](const DebuggerResponse &response) { + if (response.resultClass == ResultDone) + if (handleCliDisassemblerResult(response.consoleStreamOutput, ac.agent)) + return; + // 'point, plain' can take far too long. + // Skip this feature and immediately fall back to the 'range' version: + fetchDisassemblerByCliRangeMixed(ac); + }); } -void GdbEngine::fetchDisassemblerByCliRangeMixed(const DisassemblerAgentCookie &ac0) +void GdbEngine::fetchDisassemblerByCliRangeMixed(const DisassemblerAgentCookie &ac) { - DisassemblerAgentCookie ac = ac0; QTC_ASSERT(ac.agent, return); const quint64 address = ac.agent->address(); QByteArray start = QByteArray::number(address - 20, 16); QByteArray end = QByteArray::number(address + 100, 16); QByteArray cmd = "disassemble /rm 0x" + start + ",0x" + end; postCommand(cmd, Discardable|ConsoleCommand, - CB(handleFetchDisassemblerByCliRangeMixed), QVariant::fromValue(ac)); + [this, ac](const DebuggerResponse &response) { + if (response.resultClass == ResultDone) + if (handleCliDisassemblerResult(response.consoleStreamOutput, ac.agent)) + return; + fetchDisassemblerByCliRangePlain(ac); + }); } @@ -3977,7 +4009,18 @@ void GdbEngine::fetchDisassemblerByCliRangePlain(const DisassemblerAgentCookie & QByteArray end = QByteArray::number(address + 100, 16); QByteArray cmd = "disassemble /r 0x" + start + ",0x" + end; postCommand(cmd, Discardable, - CB(handleFetchDisassemblerByCliRangePlain), QVariant::fromValue(ac)); + [this, ac](const DebuggerResponse &response) { + if (response.resultClass == ResultDone) + if (handleCliDisassemblerResult(response.consoleStreamOutput, ac.agent)) + return; + // Finally, give up. + //76^error,msg="No function contains program counter for selected..." + //76^error,msg="No function contains specified address." + //>568^error,msg="Line number 0 out of range; + QByteArray msg = response.data["msg"].data(); + showStatusMessage(tr("Disassembler failed: %1") + .arg(QString::fromLocal8Bit(msg)), 5000); + }); } struct LineData @@ -3990,6 +4033,7 @@ struct LineData bool GdbEngine::handleCliDisassemblerResult(const QByteArray &output, DisassemblerAgent *agent) { + QTC_ASSERT(agent, return true); // First line is something like // "Dump of assembler code from 0xb7ff598f to 0xb7ff5a07:" DisassemblerLines dlines; @@ -4033,50 +4077,6 @@ bool GdbEngine::handleCliDisassemblerResult(const QByteArray &output, Disassembl return false; } -void GdbEngine::handleFetchDisassemblerByCliPointMixed(const GdbResponse &response) -{ - DisassemblerAgentCookie ac = response.cookie.value<DisassemblerAgentCookie>(); - QTC_ASSERT(ac.agent, return); - - if (response.resultClass == GdbResultDone) - if (handleCliDisassemblerResult(response.consoleStreamOutput, ac.agent)) - return; - - // 'point, plain' can take far too long. - // Skip this feature and immediately fall back to the 'range' version: - fetchDisassemblerByCliRangeMixed(ac); -} - -void GdbEngine::handleFetchDisassemblerByCliRangeMixed(const GdbResponse &response) -{ - DisassemblerAgentCookie ac = response.cookie.value<DisassemblerAgentCookie>(); - QTC_ASSERT(ac.agent, return); - - if (response.resultClass == GdbResultDone) - if (handleCliDisassemblerResult(response.consoleStreamOutput, ac.agent)) - return; - - fetchDisassemblerByCliRangePlain(ac); -} - -void GdbEngine::handleFetchDisassemblerByCliRangePlain(const GdbResponse &response) -{ - DisassemblerAgentCookie ac = response.cookie.value<DisassemblerAgentCookie>(); - QTC_ASSERT(ac.agent, return); - - if (response.resultClass == GdbResultDone) - if (handleCliDisassemblerResult(response.consoleStreamOutput, ac.agent)) - return; - - // Finally, give up. - //76^error,msg="No function contains program counter for selected..." - //76^error,msg="No function contains specified address." - //>568^error,msg="Line number 0 out of range; - QByteArray msg = response.data["msg"].data(); - showStatusMessage(tr("Disassembler failed: %1") - .arg(QString::fromLocal8Bit(msg)), 5000); -} - // Binary/configuration check logic. static QString gdbBinary(const DebuggerStartParameters &sp) @@ -4129,14 +4129,10 @@ void GdbEngine::startGdb(const QStringList &args) gdbArgs << _("-n"); gdbArgs += args; - connect(m_gdbProc, SIGNAL(error(QProcess::ProcessError)), - SLOT(handleGdbError(QProcess::ProcessError))); - connect(m_gdbProc, SIGNAL(finished(int,QProcess::ExitStatus)), - SLOT(handleGdbFinished(int,QProcess::ExitStatus))); - connect(m_gdbProc, SIGNAL(readyReadStandardOutput()), - SLOT(readGdbStandardOutput())); - connect(m_gdbProc, SIGNAL(readyReadStandardError()), - SLOT(readGdbStandardError())); + connect(m_gdbProc, &GdbProcess::error, this, &GdbEngine::handleGdbError); + connect(m_gdbProc, &GdbProcess::finished, this, &GdbEngine::handleGdbFinished); + connect(m_gdbProc, &GdbProcess::readyReadStandardOutput, this, &GdbEngine::readGdbStandardOutput); + connect(m_gdbProc, &GdbProcess::readyReadStandardError, this, &GdbEngine::readGdbStandardError); showMessage(_("STARTING ") + m_gdb + _(" ") + gdbArgs.join(QLatin1Char(' '))); m_gdbProc->start(m_gdb, gdbArgs); @@ -4149,9 +4145,9 @@ void GdbEngine::startGdb(const QStringList &args) } showMessage(_("GDB STARTED, INITIALIZING IT")); - postCommand("show version", CB(handleShowVersion)); + postCommand("show version", NoFlags, CB(handleShowVersion)); //postCommand("-list-features", CB(handleListFeatures)); - postCommand("show debug-file-directory", CB(handleDebugInfoLocation)); + postCommand("show debug-file-directory", NoFlags, CB(handleDebugInfoLocation)); //postCommand("-enable-timings"); //postCommand("set print static-members off"); // Seemingly doesn't work. @@ -4277,6 +4273,9 @@ void GdbEngine::startGdb(const QStringList &args) const QByteArray dumperSourcePath = ICore::resourcePath().toLocal8Bit() + "/debugger/"; + if (terminal()->isUsable()) + postCommand("set inferior-tty " + terminal()->slaveDevice()); + const QFileInfo gdbBinaryFile(m_gdb); const QByteArray uninstalledData = gdbBinaryFile.absolutePath().toLocal8Bit() + "/data-directory/python"; @@ -4284,14 +4283,26 @@ void GdbEngine::startGdb(const QStringList &args) const GdbCommandFlags flags = ConsoleCommand | Immediate; postCommand("python sys.path.insert(1, '" + dumperSourcePath + "')", flags); postCommand("python sys.path.append('" + uninstalledData + "')", flags); - postCommand("python from gdbbridge import *", flags, CB(handlePythonSetup)); + postCommand("python from gdbbridge import *", flags); + + const QString path = stringSetting(ExtraDumperFile); + if (!path.isEmpty()) { + DebuggerCommand cmd("addDumperModule"); + cmd.arg("path", path.toUtf8()); + runCommand(cmd); + } + + const QString commands = stringSetting(ExtraDumperCommands); + if (!commands.isEmpty()) + postCommand(commands.toLocal8Bit(), flags); + + runCommand(DebuggerCommand("setupDumper", flags, CB(handlePythonSetup))); } void GdbEngine::handleGdbStartFailed() { } - void GdbEngine::loadInitScript() { const QString script = startParameters().overrideStartScript; @@ -4299,7 +4310,7 @@ void GdbEngine::loadInitScript() if (QFileInfo(script).isReadable()) { postCommand("source " + script.toLocal8Bit()); } else { - showMessageBox(QMessageBox::Warning, + AsynchronousMessageBox::warning( tr("Cannot find debugger initialization script"), tr("The debugger settings point to a script file at \"%1\" " "which is not accessible. If a script file is not needed, " @@ -4315,7 +4326,8 @@ void GdbEngine::loadInitScript() void GdbEngine::reloadDebuggingHelpers() { - postCommand("bbsetup"); + runCommand("reloadDumper"); + reloadLocals(); } void GdbEngine::handleGdbError(QProcess::ProcessError error) @@ -4336,7 +4348,7 @@ void GdbEngine::handleGdbError(QProcess::ProcessError error) default: //m_gdbProc->kill(); //notifyEngineIll(); - showMessageBox(QMessageBox::Critical, tr("GDB I/O Error"), msg); + AsynchronousMessageBox::critical(tr("GDB I/O Error"), msg); break; } } @@ -4364,7 +4376,7 @@ void GdbEngine::handleGdbFinished(int code, QProcess::ExitStatus type) const QString msg = type == QProcess::CrashExit ? tr("The gdb process terminated.") : tr("The gdb process terminated unexpectedly (code %1)").arg(code); - showMessageBox(QMessageBox::Critical, tr("Unexpected GDB Exit"), msg); + AsynchronousMessageBox::critical(tr("Unexpected GDB Exit"), msg); break; } } @@ -4394,10 +4406,9 @@ void GdbEngine::resetInferior() if (state() == InferiorStopOk) { postCommand(command, ConsoleCommand|Immediate); } else { - GdbCommand gdbCmd; - gdbCmd.command = command; - gdbCmd.flags = ConsoleCommand; - m_commandsToRunOnTemporaryBreak.append(gdbCmd); + DebuggerCommand cmd(command); + cmd.flags = ConsoleCommand; + m_commandsToRunOnTemporaryBreak.append(cmd); } } } @@ -4457,7 +4468,7 @@ void GdbEngine::handleInferiorPrepared() attemptBreakpointSynchronization(); } - if (m_cookieForToken.isEmpty()) { + if (m_commandForToken.isEmpty()) { finishInferiorSetup(); } else { QTC_CHECK(m_commandsDoneCallback == 0); @@ -4479,19 +4490,19 @@ void GdbEngine::finishInferiorSetup() postCommand("-break-insert -f '" + qtNamespace() + "QMessageLogger::warning'"); } if (boolSetting(BreakOnFatal)) { - postCommand("-break-insert -f '" + qtNamespace() + "qFatal'", - CB(handleBreakOnQFatal), QVariant(false)); - postCommand("-break-insert -f '" + qtNamespace() + "QMessageLogger::fatal'", - CB(handleBreakOnQFatal), QVariant(true)); + postCommand("-break-insert -f '" + qtNamespace() + "qFatal'", NoFlags, + [this](const DebuggerResponse &r) { handleBreakOnQFatal(r, false); }); + postCommand("-break-insert -f '" + qtNamespace() + "QMessageLogger::fatal'", NoFlags, + [this](const DebuggerResponse &r) { handleBreakOnQFatal(r, true); }); } else { notifyInferiorSetupOk(); } } } -void GdbEngine::handleDebugInfoLocation(const GdbResponse &response) +void GdbEngine::handleDebugInfoLocation(const DebuggerResponse &response) { - if (response.resultClass == GdbResultDone) { + if (response.resultClass == ResultDone) { const QByteArray debugInfoLocation = startParameters().debugInfoLocation.toLocal8Bit(); if (QFile::exists(QString::fromLocal8Bit(debugInfoLocation))) { const QByteArray curDebugInfoLocations = response.consoleStreamOutput.split('"').value(1); @@ -4506,9 +4517,9 @@ void GdbEngine::handleDebugInfoLocation(const GdbResponse &response) } } -void GdbEngine::handleBreakOnQFatal(const GdbResponse &response) +void GdbEngine::handleBreakOnQFatal(const DebuggerResponse &response, bool continueSetup) { - if (response.resultClass == GdbResultDone) { + if (response.resultClass == ResultDone) { GdbMi bkpt = response.data["bkpt"]; GdbMi number = bkpt["number"]; BreakpointResponseId rid(number.data()); @@ -4519,7 +4530,7 @@ void GdbEngine::handleBreakOnQFatal(const GdbResponse &response) } // Continue setup. - if (response.cookie.toBool()) + if (continueSetup) notifyInferiorSetupOk(); } @@ -4531,7 +4542,7 @@ void GdbEngine::notifyInferiorSetupFailed(const QString &msg) return; // Adapter crashed meanwhile, so this notification is meaningless. } showMessage(_("INFERIOR START FAILED")); - showMessageBox(QMessageBox::Critical, tr("Failed to start application"), msg); + AsynchronousMessageBox::critical(tr("Failed to start application"), msg); DebuggerEngine::notifyInferiorSetupFailed(); } @@ -4553,7 +4564,7 @@ void GdbEngine::handleAdapterCrashed(const QString &msg) m_gdbProc->kill(); if (!msg.isEmpty()) - showMessageBox(QMessageBox::Critical, tr("Adapter crashed"), msg); + AsynchronousMessageBox::critical(tr("Adapter crashed"), msg); } void GdbEngine::createFullBacktrace() @@ -4562,9 +4573,9 @@ void GdbEngine::createFullBacktrace() NeedsStop|ConsoleCommand, CB(handleCreateFullBacktrace)); } -void GdbEngine::handleCreateFullBacktrace(const GdbResponse &response) +void GdbEngine::handleCreateFullBacktrace(const DebuggerResponse &response) { - if (response.resultClass == GdbResultDone) { + if (response.resultClass == ResultDone) { Internal::openTextEditor(_("Backtrace $"), _(response.consoleStreamOutput + response.logStreamOutput)); } @@ -4573,65 +4584,17 @@ void GdbEngine::handleCreateFullBacktrace(const GdbResponse &response) void GdbEngine::resetCommandQueue() { m_commandTimer.stop(); - if (!m_cookieForToken.isEmpty()) { + if (!m_commandForToken.isEmpty()) { QString msg; QTextStream ts(&msg); ts << "RESETING COMMAND QUEUE. LEFT OVER TOKENS: "; - foreach (const GdbCommand &cookie, m_cookieForToken) - ts << "CMD:" << cookie.command << cookie.callbackName; - m_cookieForToken.clear(); + foreach (const DebuggerCommand &cmd, m_commandForToken) + ts << "CMD:" << cmd.function; + m_commandForToken.clear(); showMessage(msg); } } -bool GdbEngine::setupQmlStep(bool on) -{ - QTC_ASSERT(isSlaveEngine(), return false); - m_qmlBreakpointResponseId1 = BreakpointResponseId(); - m_qmlBreakpointResponseId2 = BreakpointResponseId(); - //qDebug() << "CLEAR: " << m_qmlBreakpointNumbers; - postCommand("tbreak '" + qtNamespace() + "QScript::FunctionWrapper::proxyCall'\n" - "commands\n" - "set $d=(void*)((FunctionWrapper*)callee)->data->function\n" - "tbreak *$d\nprintf \"QMLBP:%d \\n\",$bpnum\ncontinue\nend", - NeedsStop, CB(handleSetQmlStepBreakpoint)); - m_preparedForQmlBreak = on; - return true; -} - -void GdbEngine::handleSetQmlStepBreakpoint(const GdbResponse &response) -{ - //QTC_ASSERT(state() == EngineRunRequested, qDebug() << state()); - if (response.resultClass == GdbResultDone) { - // logStreamOutput: "tbreak 'myns::QScript::FunctionWrapper::proxyCall'\n" - // consoleStreamOutput: "Temporary breakpoint 1 at 0xf166e7: - // file bridge/qscriptfunction.cpp, line 75.\n"} - QByteArray ba = parsePlainConsoleStream(response); - const int pos2 = ba.indexOf(" at 0x"); - const int pos1 = ba.lastIndexOf(" ", pos2 - 1) + 1; - QByteArray mid = ba.mid(pos1, pos2 - pos1); - m_qmlBreakpointResponseId1 = BreakpointResponseId(mid); - //qDebug() << "SET: " << m_qmlBreakpointResponseId1; - } - QTC_ASSERT(masterEngine(), return); - masterEngine()->readyToExecuteQmlStep(); -} - -bool GdbEngine::isQmlStepBreakpoint(const BreakpointResponseId &id) const -{ - return isQmlStepBreakpoint1(id) || isQmlStepBreakpoint2(id); -} - -bool GdbEngine::isQmlStepBreakpoint1(const BreakpointResponseId &id) const -{ - return id.isValid() && m_qmlBreakpointResponseId1 == id; -} - -bool GdbEngine::isQmlStepBreakpoint2(const BreakpointResponseId &id) const -{ - return id.isValid() && m_qmlBreakpointResponseId2 == id; -} - bool GdbEngine::isQFatalBreakpoint(const BreakpointResponseId &id) const { return id.isValid() && m_qFatalBreakpointResponseId == id; @@ -4639,7 +4602,7 @@ bool GdbEngine::isQFatalBreakpoint(const BreakpointResponseId &id) const bool GdbEngine::isHiddenBreakpoint(const BreakpointResponseId &id) const { - return isQFatalBreakpoint(id) || isQmlStepBreakpoint(id); + return isQFatalBreakpoint(id); } bool GdbEngine::usesExecInterrupt() const @@ -4673,8 +4636,8 @@ bool GdbEngine::attemptQuickStart() const // Don't try if there are breakpoints we might be able to handle. BreakHandler *handler = breakHandler(); - foreach (BreakpointModelId id, handler->unclaimedBreakpointIds()) { - if (acceptsBreakpoint(id)) + foreach (Breakpoint bp, handler->unclaimedBreakpoints()) { + if (acceptsBreakpoint(bp)) return false; } @@ -4761,7 +4724,7 @@ QByteArray GdbEngine::dotEscape(QByteArray str) void GdbEngine::debugLastCommand() { - postCommand(m_lastDebuggableCommand, Discardable); + runCommand(m_lastDebuggableCommand); } // @@ -4791,79 +4754,67 @@ void addGdbOptionPages(QList<IOptionsPage *> *opts) opts->push_back(new GdbOptionsPage2()); } - void GdbEngine::updateLocalsPython(const UpdateParameters ¶ms) { //m_pendingWatchRequests = 0; m_pendingBreakpointRequests = 0; m_processedNames.clear(); - WatchHandler *handler = watchHandler(); - QByteArray expanded = "expanded:" + handler->expansionRequests() + ' '; - expanded += "typeformats:" + handler->typeFormatRequests() + ' '; - expanded += "formats:" + handler->individualFormatRequests(); + DebuggerCommand cmd("showData"); + watchHandler()->appendFormatRequests(&cmd); - QByteArray cutOff = " stringcutoff:" - + action(MaximalStringLength)->value().toByteArray() - + " displaystringlimit:" - + action(DisplayStringLimit)->value().toByteArray(); + cmd.arg("stringcutoff", action(MaximalStringLength)->value().toByteArray()); + cmd.arg("displaystringlimit", action(DisplayStringLimit)->value().toByteArray()); // Re-create tooltip items that are not filters on existing local variables in // the tooltip model. - QByteArray watchers; + cmd.beginList("watchers"); DebuggerToolTipContexts toolTips = DebuggerToolTipManager::pendingTooltips(this); foreach (const DebuggerToolTipContext &p, toolTips) { - if (!watchers.isEmpty()) - watchers += "##"; - watchers += p.expression.toLatin1(); - watchers += '#'; - watchers += p.iname; + cmd.beginGroup(); + cmd.arg("iname", p.iname); + cmd.arg("exp", p.expression.toLatin1().toHex()); + cmd.endGroup(); } - QHash<QByteArray, int> watcherNames = handler->watcherNames(); - QHashIterator<QByteArray, int> it(watcherNames); + QHashIterator<QByteArray, int> it(WatchHandler::watcherNames()); while (it.hasNext()) { it.next(); - if (!watchers.isEmpty()) - watchers += "##"; - watchers += it.key() + "#watch." + QByteArray::number(it.value()); + cmd.beginGroup(); + cmd.arg("iname", "watch." + QByteArray::number(it.value())); + cmd.arg("exp", it.key().toHex()); + cmd.endGroup(); } + cmd.endList(); const static bool alwaysVerbose = !qgetenv("QTC_DEBUGGER_PYTHON_VERBOSE").isEmpty(); - QByteArray options; - if (alwaysVerbose) - options += "pe,"; - if (boolSetting(UseDebuggingHelpers)) - options += "fancy,"; - if (boolSetting(AutoDerefPointers)) - options += "autoderef,"; - if (boolSetting(UseDynamicType)) - options += "dyntype,"; - if (options.isEmpty()) - options += "defaults,"; - if (params.tryPartial) - options += "partial,"; - if (params.tooltipOnly) - options += "tooltiponly,"; - options.chop(1); - - QByteArray resultVar; - if (!m_resultVarName.isEmpty()) - resultVar = "resultvarname:" + m_resultVarName + ' '; - - m_lastDebuggableCommand = - "bb options:pe," + options + " vars:" + params.varList + ' ' - + expanded + " watchers:" + watchers.toHex() + cutOff; - - postCommand("bb options:" + options + " vars:" + params.varList + ' ' - + resultVar + expanded + " watchers:" + watchers.toHex() + cutOff, - Discardable, CB(handleStackFramePython), QVariant(params.tryPartial)); -} - -void GdbEngine::handleStackFramePython(const GdbResponse &response) -{ - if (response.resultClass == GdbResultDone) { - const bool partial = response.cookie.toBool(); + + cmd.arg("passExceptions", alwaysVerbose); + cmd.arg("fancy", boolSetting(UseDebuggingHelpers)); + cmd.arg("autoderef", boolSetting(AutoDerefPointers)); + cmd.arg("dyntype", boolSetting(UseDynamicType)); + cmd.arg("nativemixed", isNativeMixedActive()); + cmd.arg("partial", params.tryPartial); + + if (isNativeMixedActive()) { + StackFrame frame = stackHandler()->currentFrame(); + if (frame.language == QmlLanguage) + cmd.arg("qmlcontext", "0x" + QByteArray::number(frame.address, 16)); + } + + cmd.arg("resultvarname", m_resultVarName); + cmd.arg("vars", params.varList); + cmd.flags = Discardable; + cmd.callback = [this, params](const DebuggerResponse &r) { handleStackFramePython(r, params.tryPartial); }; + runCommand(cmd); + + cmd.arg("passExceptions", true); + m_lastDebuggableCommand = cmd; +} + +void GdbEngine::handleStackFramePython(const DebuggerResponse &response, bool partial) +{ + if (response.resultClass == ResultDone) { QByteArray out = response.consoleStreamOutput; while (out.endsWith(' ') || out.endsWith('\n')) out.chop(1); @@ -4884,27 +4835,7 @@ void GdbEngine::handleStackFramePython(const GdbResponse &response) } WatchHandler *handler = watchHandler(); - QList<WatchData> list; - - if (!partial) { - list.append(*handler->findData("local")); - list.append(*handler->findData("watch")); - list.append(*handler->findData("return")); - } - foreach (const GdbMi &child, data.children()) { - WatchData dummy; - dummy.iname = child["iname"].data(); - GdbMi wname = child["wname"]; - if (wname.isValid()) { - // Happens (only) for watched expressions. - dummy.name = QString::fromUtf8(QByteArray::fromHex(wname.data())); - dummy.exp = dummy.name.toUtf8(); - } else { - dummy.name = _(child["name"].data()); - } - parseWatchData(handler->expandedINames(), dummy, child, &list); - } const GdbMi typeInfo = all["typeinfo"]; if (typeInfo.type() == GdbMi::List) { foreach (const GdbMi &s, typeInfo.children()) { @@ -4915,13 +4846,24 @@ void GdbEngine::handleStackFramePython(const GdbResponse &response) TypeInfo(size.data().toUInt())); } } - for (int i = 0; i != list.size(); ++i) { - const TypeInfo ti = m_typeInfoCache.value(list.at(i).type); + + QSet<QByteArray> toDelete; + if (!partial) { + foreach (WatchItem *item, handler->model()->treeLevelItems<WatchItem *>(2)) + toDelete.insert(item->d.iname); + } + + foreach (const GdbMi &child, data.children()) { + WatchItem *item = new WatchItem(child); + const TypeInfo ti = m_typeInfoCache.value(item->d.type); if (ti.size) - list[i].size = ti.size; + item->d.size = ti.size; + + handler->insertItem(item); + toDelete.remove(item->d.iname); } - handler->insertData(list); + handler->purgeOutdatedItems(toDelete); //PENDING_DEBUG("AFTER handleStackFrame()"); // FIXME: This should only be used when updateLocals() was @@ -4960,10 +4902,7 @@ QString GdbEngine::msgPtraceError(DebuggerStartMode sm) "For more details, see /etc/sysctl.d/10-ptrace.conf\n"); } - } // namespace Internal } // namespace Debugger -Q_DECLARE_METATYPE(Debugger::Internal::MemoryAgentCookie) -Q_DECLARE_METATYPE(Debugger::Internal::DisassemblerAgentCookie) Q_DECLARE_METATYPE(Debugger::Internal::GdbMi) diff --git a/src/plugins/debugger/gdb/gdbengine.h b/src/plugins/debugger/gdb/gdbengine.h index f443ed68e3..eb48e45dfc 100644 --- a/src/plugins/debugger/gdb/gdbengine.h +++ b/src/plugins/debugger/gdb/gdbengine.h @@ -33,6 +33,7 @@ #include <debugger/debuggerengine.h> +#include <debugger/breakhandler.h> #include <debugger/watchhandler.h> #include <debugger/watchutils.h> #include <debugger/debuggertooltipmanager.h> @@ -52,15 +53,17 @@ namespace Internal { class GdbProcess; class DebugInfoTask; class DebugInfoTaskHandler; -class GdbResponse; +class DebuggerResponse; class GdbMi; class MemoryAgentCookie; +class BreakpointParameters; +class BreakpointResponse; class WatchData; class DisassemblerAgentCookie; class DisassemblerLines; -class GdbEngine : public Debugger::DebuggerEngine +class GdbEngine : public DebuggerEngine { Q_OBJECT @@ -97,8 +100,8 @@ private: ////////// General State ////////// protected: ////////// Gdb Process Management ////////// void startGdb(const QStringList &args = QStringList()); - void handleInferiorShutdown(const GdbResponse &response); - void handleGdbExit(const GdbResponse &response); + void handleInferiorShutdown(const DebuggerResponse &response); + void handleGdbExit(const DebuggerResponse &response); void loadInitScript(); @@ -113,7 +116,7 @@ protected: ////////// Gdb Process Management ////////// // This notifies the base of a successful inferior setup. void finishInferiorSetup(); - void handleDebugInfoLocation(const GdbResponse &response); + void handleDebugInfoLocation(const DebuggerResponse &response); // The adapter is still running just fine, but it failed to acquire a debuggee. void notifyInferiorSetupFailed(const QString &msg); @@ -126,12 +129,13 @@ protected: ////////// Gdb Process Management ////////// void handleAdapterCrashed(const QString &msg); private slots: + friend class GdbPlainEngine; void handleInterruptDeviceInferior(const QString &error); void handleGdbFinished(int, QProcess::ExitStatus status); void handleGdbError(QProcess::ProcessError error); + void readDebugeeOutput(const QByteArray &data); void readGdbStandardOutput(); void readGdbStandardError(); - void readDebugeeOutput(const QByteArray &data); private: QTextCodec *m_outputCodec; @@ -155,9 +159,9 @@ private: ////////// Gdb Command Management ////////// Discardable = 2, // We can live without receiving an answer. NonCriticalResponse = 8, - // Callback expects GdbResultRunning instead of GdbResultDone. + // Callback expects ResultRunning instead of ResultDone. RunRequest = 16, - // Callback expects GdbResultExit instead of GdbResultDone. + // Callback expects ResultExit instead of ResultDone. ExitRequest = 32, // Auto-set inferior shutdown related states. LosesChild = 64, @@ -170,40 +174,17 @@ private: ////////// Gdb Command Management ////////// }; Q_DECLARE_FLAGS(GdbCommandFlags, GdbCommandFlag) - protected: - typedef void (GdbEngine::*GdbCommandCallback)(const GdbResponse &response); - - struct GdbCommand - { - GdbCommand() - : flags(0), callback(0), callbackName(0) - {} - - int flags; - GdbCommandCallback callback; - const char *callbackName; - QByteArray command; - QVariant cookie; - QTime postTime; - }; - // Type and cookie are sender-internal data, opaque for the "event // queue". resultNeeded == true increments m_pendingResults on // send and decrements on receipt, effectively preventing // watch model updates before everything is finished. - void flushCommand(const GdbCommand &cmd); + void flushCommand(const DebuggerCommand &cmd); protected: + void runCommand(const DebuggerCommand &command); void postCommand(const QByteArray &command, - GdbCommandFlags flags, - GdbCommandCallback callback = 0, - const char *callbackName = 0, - const QVariant &cookie = QVariant()); - void postCommand(const QByteArray &command, - GdbCommandCallback callback = 0, - const char *callbackName = 0, - const QVariant &cookie = QVariant()); + int flags = NoFlags, + DebuggerCommand::Callback callback = DebuggerCommand::Callback()); private: - void postCommandHelper(const GdbCommand &cmd); void flushQueuedCommands(); Q_SLOT void commandTimeout(); void setTokenBarrier(); @@ -211,7 +192,7 @@ private: // Sets up an "unexpected result" for the following commeand. void scheduleTestResponse(int testCase, const QByteArray &response); - QHash<int, GdbCommand> m_cookieForToken; + QHash<int, DebuggerCommand> m_commandForToken; int commandTimeoutTime() const; QTimer m_commandTimer; @@ -230,16 +211,14 @@ private: // This function is called after all previous responses have been received. CommandsDoneCallback m_commandsDoneCallback; - QList<GdbCommand> m_commandsToRunOnTemporaryBreak; + QList<DebuggerCommand> m_commandsToRunOnTemporaryBreak; private: ////////// Gdb Output, State & Capability Handling ////////// protected: Q_SLOT void handleResponse(const QByteArray &buff); void handleStopResponse(const GdbMi &data); - void handleResultRecord(GdbResponse *response); - void handleStop1(const GdbResponse &response); + void handleResultRecord(DebuggerResponse *response); void handleStop1(const GdbMi &data); - void handleStop2(const GdbResponse &response); void handleStop2(const GdbMi &data); Q_SLOT void handleStop2(); StackFrame parseStackFrame(const GdbMi &mi, int level); @@ -248,9 +227,9 @@ protected: bool isSynchronous() const { return true; } // Gdb initialization sequence - void handleShowVersion(const GdbResponse &response); - void handleListFeatures(const GdbResponse &response); - void handlePythonSetup(const GdbResponse &response); + void handleShowVersion(const DebuggerResponse &response); + void handleListFeatures(const DebuggerResponse &response); + void handlePythonSetup(const DebuggerResponse &response); int m_gdbVersion; // 7.6.1 is 70601 bool m_isQnxGdb; @@ -259,10 +238,10 @@ private: ////////// Inferior Management ////////// // This should be always the last call in a function. bool stateAcceptsBreakpointChanges() const; - bool acceptsBreakpoint(BreakpointModelId id) const; - void insertBreakpoint(BreakpointModelId id); - void removeBreakpoint(BreakpointModelId id); - void changeBreakpoint(BreakpointModelId id); + bool acceptsBreakpoint(Breakpoint bp) const; + void insertBreakpoint(Breakpoint bp); + void removeBreakpoint(Breakpoint bp); + void changeBreakpoint(Breakpoint bp); void executeStep(); void executeStepOut(); @@ -283,15 +262,15 @@ private: ////////// Inferior Management ////////// void executeJumpToLine(const ContextData &data); void executeReturn(); - void handleExecuteContinue(const GdbResponse &response); - void handleExecuteStep(const GdbResponse &response); - void handleExecuteNext(const GdbResponse &response); - void handleExecuteReturn(const GdbResponse &response); - void handleExecuteJumpToLine(const GdbResponse &response); - void handleExecuteRunToLine(const GdbResponse &response); + void handleExecuteContinue(const DebuggerResponse &response); + void handleExecuteStep(const DebuggerResponse &response); + void handleExecuteNext(const DebuggerResponse &response); + void handleExecuteReturn(const DebuggerResponse &response); + void handleExecuteJumpToLine(const DebuggerResponse &response); + void handleExecuteRunToLine(const DebuggerResponse &response); void maybeHandleInferiorPidChanged(const QString &pid); - void handleInfoProc(const GdbResponse &response); + void handleInfoProc(const DebuggerResponse &response); QString msgPtraceError(DebuggerStartMode sm); private: ////////// View & Data Stuff ////////// @@ -303,21 +282,21 @@ private: ////////// View & Data Stuff ////////// // Breakpoint specific stuff // void handleBreakModifications(const GdbMi &bkpts); - void handleBreakIgnore(const GdbResponse &response); - void handleBreakDisable(const GdbResponse &response); - void handleBreakEnable(const GdbResponse &response); - void handleBreakInsert1(const GdbResponse &response); - void handleBreakInsert2(const GdbResponse &response); - void handleTraceInsert2(const GdbResponse &response); - void handleBreakCondition(const GdbResponse &response); - void handleBreakThreadSpec(const GdbResponse &response); - void handleBreakLineNumber(const GdbResponse &response); - void handleWatchInsert(const GdbResponse &response); - void handleCatchInsert(const GdbResponse &response); - void handleBkpt(const GdbMi &bkpt, const BreakpointModelId &id); + void handleBreakIgnore(const DebuggerResponse &response, Breakpoint bp); + void handleBreakDisable(const DebuggerResponse &response, Breakpoint bp); + void handleBreakEnable(const DebuggerResponse &response, Breakpoint bp); + void handleBreakInsert1(const DebuggerResponse &response, Breakpoint bp); + void handleBreakInsert2(const DebuggerResponse &response, Breakpoint bp); + void handleBreakDelete(const DebuggerResponse &response, Breakpoint bp); + void handleBreakCondition(const DebuggerResponse &response, Breakpoint bp); + void handleBreakThreadSpec(const DebuggerResponse &response, Breakpoint bp); + void handleBreakLineNumber(const DebuggerResponse &response, Breakpoint bp); + void handleWatchInsert(const DebuggerResponse &response, Breakpoint bp); + void handleCatchInsert(const DebuggerResponse &response, Breakpoint bp); + void handleBkpt(const GdbMi &bkpt, Breakpoint bp); void updateResponse(BreakpointResponse &response, const GdbMi &bkpt); - QByteArray breakpointLocation(BreakpointModelId id); // For gdb/MI. - QByteArray breakpointLocation2(BreakpointModelId id); // For gdb/CLI fallback. + QByteArray breakpointLocation(const BreakpointParameters &data); // For gdb/MI. + QByteArray breakpointLocation2(const BreakpointParameters &data); // For gdb/CLI fallback. QString breakLocation(const QString &file) const; // @@ -333,24 +312,24 @@ private: ////////// View & Data Stuff ////////// void examineModules(); void reloadModulesInternal(); - void handleModulesList(const GdbResponse &response); - void handleShowModuleSymbols(const GdbResponse &response); - void handleShowModuleSections(const GdbResponse &response); + void handleModulesList(const DebuggerResponse &response); + void handleShowModuleSections(const DebuggerResponse &response, const QString &moduleName); // // Snapshot specific stuff // virtual void createSnapshot(); - void handleMakeSnapshot(const GdbResponse &response); + void handleMakeSnapshot(const DebuggerResponse &response, const QString &coreFile); // // Register specific stuff // Q_SLOT void reloadRegisters(); - void setRegisterValue(int nr, const QString &value); - void handleRegisterListNames(const GdbResponse &response); - void handleRegisterListValues(const GdbResponse &response); - QVector<int> m_registerNumbers; // Map GDB register numbers to indices + void setRegisterValue(const QByteArray &name, const QString &value); + void handleRegisterListNames(const DebuggerResponse &response); + void handleRegisterListValues(const DebuggerResponse &response); + void handleMaintPrintRegisters(const DebuggerResponse &response); + QHash<int, QByteArray> m_registerNames; // Map GDB register numbers to indices // // Disassembler specific stuff @@ -360,19 +339,16 @@ private: ////////// View & Data Stuff ////////// void fetchDisassemblerByCliPointMixed(const DisassemblerAgentCookie &ac); void fetchDisassemblerByCliRangeMixed(const DisassemblerAgentCookie &ac); void fetchDisassemblerByCliRangePlain(const DisassemblerAgentCookie &ac); - void handleFetchDisassemblerByCliPointMixed(const GdbResponse &response); - void handleFetchDisassemblerByCliRangeMixed(const GdbResponse &response); - void handleFetchDisassemblerByCliRangePlain(const GdbResponse &response); bool handleCliDisassemblerResult(const QByteArray &response, DisassemblerAgent *agent); - void handleBreakOnQFatal(const GdbResponse &response); + void handleBreakOnQFatal(const DebuggerResponse &response, bool continueSetup); // // Source file specific stuff // void reloadSourceFiles(); void reloadSourceFilesInternal(); - void handleQuerySources(const GdbResponse &response); + void handleQuerySources(const DebuggerResponse &response); QString fullName(const QString &fileName); QString cleanupFullName(const QString &fileName); @@ -389,17 +365,17 @@ private: ////////// View & Data Stuff ////////// // protected: void updateAll(); - void handleStackListFrames(const GdbResponse &response); - void handleStackSelectThread(const GdbResponse &response); - void handleStackSelectFrame(const GdbResponse &response); - void handleThreadListIds(const GdbResponse &response); - void handleThreadInfo(const GdbResponse &response); - void handleThreadNames(const GdbResponse &response); - Q_SLOT void reloadStack(bool forceGotoLocation); + void handleStackListFrames(const DebuggerResponse &response, bool isFull); + void handleStackSelectThread(const DebuggerResponse &response); + void handleThreadListIds(const DebuggerResponse &response); + void handleThreadInfo(const DebuggerResponse &response); + void handleThreadNames(const DebuggerResponse &response); + DebuggerCommand stackCommand(int depth); + Q_SLOT void reloadStack(); Q_SLOT virtual void reloadFullStack(); virtual void loadAdditionalQmlStack(); - void handleQmlStackFrameArguments(const GdbResponse &response); - void handleQmlStackTrace(const GdbResponse &response); + void handleQmlStackFrameArguments(const DebuggerResponse &response); + void handleQmlStackTrace(const DebuggerResponse &response); int currentFrame() const; QList<GdbMi> m_currentFunctionArgs; @@ -415,13 +391,13 @@ protected: virtual void fetchMemory(MemoryAgent *agent, QObject *token, quint64 addr, quint64 length); void fetchMemoryHelper(const MemoryAgentCookie &cookie); - void handleChangeMemory(const GdbResponse &response); + void handleChangeMemory(const DebuggerResponse &response); virtual void changeMemory(MemoryAgent *agent, QObject *token, quint64 addr, const QByteArray &data); - void handleFetchMemory(const GdbResponse &response); + void handleFetchMemory(const DebuggerResponse &response, MemoryAgentCookie ac); virtual void watchPoint(const QPoint &); - void handleWatchPoint(const GdbResponse &response); + void handleWatchPoint(const DebuggerResponse &response); void updateWatchData(const WatchData &data, const WatchUpdateFlags &flags); void rebuildWatchModel(); @@ -429,17 +405,17 @@ protected: void insertData(const WatchData &data); - void handleVarAssign(const GdbResponse &response); - void handleDetach(const GdbResponse &response); + void handleVarAssign(const DebuggerResponse &response); + void handleDetach(const DebuggerResponse &response); void handleThreadGroupCreated(const GdbMi &result); void handleThreadGroupExited(const GdbMi &result); Q_SLOT void createFullBacktrace(); - void handleCreateFullBacktrace(const GdbResponse &response); + void handleCreateFullBacktrace(const DebuggerResponse &response); void updateLocals(); void updateLocalsPython(const UpdateParameters ¶meters); - void handleStackFramePython(const GdbResponse &response); + void handleStackFramePython(const DebuggerResponse &response, bool partial); void setLocals(const QList<GdbMi> &locals); @@ -472,17 +448,6 @@ protected: // For short-circuiting stack and thread list evaluation. bool m_stackNeeded; - // - // Qml - // - BreakpointResponseId m_qmlBreakpointResponseId1; - BreakpointResponseId m_qmlBreakpointResponseId2; - bool m_preparedForQmlBreak; - bool setupQmlStep(bool on); - void handleSetQmlStepBreakpoint(const GdbResponse &response); - bool isQmlStepBreakpoint(const BreakpointResponseId &id) const; - bool isQmlStepBreakpoint1(const BreakpointResponseId &id) const; - bool isQmlStepBreakpoint2(const BreakpointResponseId &id) const; bool isQFatalBreakpoint(const BreakpointResponseId &id) const; bool isHiddenBreakpoint(const BreakpointResponseId &id) const; @@ -522,7 +487,7 @@ protected: static QByteArray dotEscape(QByteArray str); void debugLastCommand(); - QByteArray m_lastDebuggableCommand; + DebuggerCommand m_lastDebuggableCommand; protected: virtual void write(const QByteArray &data); diff --git a/src/plugins/debugger/gdb/gdboptionspage.cpp b/src/plugins/debugger/gdb/gdboptionspage.cpp index 545c0e8e05..259f7acefe 100644 --- a/src/plugins/debugger/gdb/gdboptionspage.cpp +++ b/src/plugins/debugger/gdb/gdboptionspage.cpp @@ -311,7 +311,7 @@ QWidget *GdbOptionsPage::widget() void GdbOptionsPage::apply() { if (m_widget) - m_widget->group.apply(Core::ICore::settings()); + m_widget->group.apply(ICore::settings()); } void GdbOptionsPage::finish() @@ -457,7 +457,7 @@ QWidget *GdbOptionsPage2::widget() void GdbOptionsPage2::apply() { if (m_widget) - m_widget->group.apply(Core::ICore::settings()); + m_widget->group.apply(ICore::settings()); } void GdbOptionsPage2::finish() diff --git a/src/plugins/debugger/gdb/gdbplainengine.cpp b/src/plugins/debugger/gdb/gdbplainengine.cpp index 4b955e60d9..c19bdde3a8 100644 --- a/src/plugins/debugger/gdb/gdbplainengine.cpp +++ b/src/plugins/debugger/gdb/gdbplainengine.cpp @@ -45,19 +45,16 @@ namespace Debugger { namespace Internal { -#define CB(callback) \ - static_cast<GdbEngine::GdbCommandCallback>(&GdbPlainEngine::callback), \ - STRINGIFY(callback) +#define CB(callback) [this](const DebuggerResponse &r) { callback(r); } GdbPlainEngine::GdbPlainEngine(const DebuggerStartParameters &startParameters) : GdbEngine(startParameters) { // Output - connect(&m_outputCollector, SIGNAL(byteDelivery(QByteArray)), - this, SLOT(readDebugeeOutput(QByteArray))); + connect(&m_outputCollector, &OutputCollector::byteDelivery, + this, &GdbEngine::readDebugeeOutput); } - void GdbPlainEngine::setupInferior() { QTC_ASSERT(state() == InferiorSetupRequested, qDebug() << state()); @@ -66,13 +63,13 @@ void GdbPlainEngine::setupInferior() postCommand("-exec-arguments " + toLocalEncoding(args)); } postCommand("-file-exec-and-symbols \"" + execFilePath() + '"', - CB(handleFileExecAndSymbols)); + NoFlags, CB(handleFileExecAndSymbols)); } -void GdbPlainEngine::handleFileExecAndSymbols(const GdbResponse &response) +void GdbPlainEngine::handleFileExecAndSymbols(const DebuggerResponse &response) { QTC_ASSERT(state() == InferiorSetupRequested, qDebug() << state()); - if (response.resultClass == GdbResultDone) { + if (response.resultClass == ResultDone) { handleInferiorPrepared(); } else { QByteArray ba = response.data["msg"].data(); @@ -92,10 +89,10 @@ void GdbPlainEngine::runEngine() postCommand("-exec-run", GdbEngine::RunRequest, CB(handleExecRun)); } -void GdbPlainEngine::handleExecRun(const GdbResponse &response) +void GdbPlainEngine::handleExecRun(const DebuggerResponse &response) { QTC_ASSERT(state() == EngineRunRequested, qDebug() << state()); - if (response.resultClass == GdbResultRunning) { + if (response.resultClass == ResultRunning) { //notifyEngineRunOkAndInferiorRunRequested(); notifyEngineRunAndInferiorRunOk(); // For gdb < 7.0 //showStatusMessage(tr("Running...")); diff --git a/src/plugins/debugger/gdb/gdbplainengine.h b/src/plugins/debugger/gdb/gdbplainengine.h index 1cf33e9263..fc889c9d28 100644 --- a/src/plugins/debugger/gdb/gdbplainengine.h +++ b/src/plugins/debugger/gdb/gdbplainengine.h @@ -46,8 +46,8 @@ public: explicit GdbPlainEngine(const DebuggerStartParameters &startParameters); private: - void handleExecRun(const GdbResponse &response); - void handleFileExecAndSymbols(const GdbResponse &response); + void handleExecRun(const DebuggerResponse &response); + void handleFileExecAndSymbols(const DebuggerResponse &response); void setupInferior(); void runEngine(); diff --git a/src/plugins/debugger/gdb/gdbprocess.cpp b/src/plugins/debugger/gdb/gdbprocess.cpp index 4987fa0d75..7115923b6a 100644 --- a/src/plugins/debugger/gdb/gdbprocess.cpp +++ b/src/plugins/debugger/gdb/gdbprocess.cpp @@ -31,6 +31,7 @@ #include "gdbprocess.h" #include <debugger/debuggerconstants.h> +#include <debugger/debuggercore.h> #include <debugger/procinterrupt.h> namespace Debugger { @@ -115,8 +116,11 @@ void GdbProcess::setProcessEnvironment(const QProcessEnvironment &env) m_gdbProc.setProcessEnvironment(env); } -void GdbProcess::setEnvironment(const QStringList &env) +void GdbProcess::setEnvironment(const QStringList &env_) { + QStringList env = env_; + if (isNativeMixedActive()) + env.append(QLatin1String("QV4_FORCE_INTERPRETER=1")); // FIXME: REMOVE! m_gdbProc.setEnvironment(Utils::Environment(env)); } diff --git a/src/plugins/debugger/gdb/remotegdbserveradapter.cpp b/src/plugins/debugger/gdb/remotegdbserveradapter.cpp index b5c7b72d88..137a41ed2d 100644 --- a/src/plugins/debugger/gdb/remotegdbserveradapter.cpp +++ b/src/plugins/debugger/gdb/remotegdbserveradapter.cpp @@ -38,19 +38,20 @@ #include <debugger/debuggerstartparameters.h> #include <debugger/debuggerstringutils.h> +#include <coreplugin/messagebox.h> + #include <utils/hostosinfo.h> #include <utils/qtcassert.h> #include <utils/qtcprocess.h> #include <QFileInfo> -#include <QMessageBox> + +using namespace Utils; namespace Debugger { namespace Internal { -#define CB(callback) \ - static_cast<GdbEngine::GdbCommandCallback>(&GdbRemoteServerEngine::callback), \ - STRINGIFY(callback) +#define CB(callback) [this](const DebuggerResponse &r) { callback(r); } /////////////////////////////////////////////////////////////////////// // @@ -61,16 +62,17 @@ namespace Internal { GdbRemoteServerEngine::GdbRemoteServerEngine(const DebuggerStartParameters &startParameters) : GdbEngine(startParameters), m_startAttempted(false) { - if (Utils::HostOsInfo::isWindowsHost()) + if (HostOsInfo::isWindowsHost()) m_gdbProc->setUseCtrlCStub(startParameters.useCtrlCStub); // This is only set for QNX/BlackBerry - connect(&m_uploadProc, SIGNAL(error(QProcess::ProcessError)), - SLOT(uploadProcError(QProcess::ProcessError))); - connect(&m_uploadProc, SIGNAL(readyReadStandardOutput()), - SLOT(readUploadStandardOutput())); - connect(&m_uploadProc, SIGNAL(readyReadStandardError()), - SLOT(readUploadStandardError())); - connect(&m_uploadProc, SIGNAL(finished(int)), - SLOT(uploadProcFinished())); + + connect(&m_uploadProc, static_cast<void (QProcess::*)(QProcess::ProcessError)>(&QProcess::error), + this, &GdbRemoteServerEngine::uploadProcError); + connect(&m_uploadProc, &QProcess::readyReadStandardOutput, + this, &GdbRemoteServerEngine::readUploadStandardOutput); + connect(&m_uploadProc, &QProcess::readyReadStandardError, + this, &GdbRemoteServerEngine::readUploadStandardError); + connect(&m_uploadProc, static_cast<void (QProcess::*)(int)>(&QProcess::finished), + this, &GdbRemoteServerEngine::uploadProcFinished); } void GdbRemoteServerEngine::setupEngine() @@ -81,9 +83,9 @@ void GdbRemoteServerEngine::setupEngine() // Provide script information about the environment QString arglist; - Utils::QtcProcess::addArg(&arglist, startParameters().serverStartScript); - Utils::QtcProcess::addArg(&arglist, startParameters().executable); - Utils::QtcProcess::addArg(&arglist, startParameters().remoteChannel); + QtcProcess::addArg(&arglist, startParameters().serverStartScript); + QtcProcess::addArg(&arglist, startParameters().executable); + QtcProcess::addArg(&arglist, startParameters().remoteChannel); m_uploadProc.start(_("/bin/sh ") + arglist); m_uploadProc.waitForStarted(); @@ -130,7 +132,7 @@ void GdbRemoteServerEngine::uploadProcError(QProcess::ProcessError error) } showMessage(msg, StatusBar); - showMessageBox(QMessageBox::Critical, tr("Error"), msg); + Core::AsynchronousMessageBox::critical(tr("Error"), msg); } void GdbRemoteServerEngine::readUploadStandardOutput() @@ -173,12 +175,12 @@ void GdbRemoteServerEngine::setupInferior() //const QByteArray sysroot = sp.sysroot.toLocal8Bit(); //const QByteArray remoteArch = sp.remoteArchitecture.toLatin1(); - const QString args = isMasterEngine() ? startParameters().processArgs : masterEngine()->startParameters().processArgs; + const QString args = isMasterEngine() ? startParameters().processArgs + : masterEngine()->startParameters().processArgs; // if (!remoteArch.isEmpty()) // postCommand("set architecture " + remoteArch); - const QString solibSearchPath - = sp.solibSearchPath.join(Utils::HostOsInfo::pathListSeparator()); + const QString solibSearchPath = sp.solibSearchPath.join(HostOsInfo::pathListSeparator()); if (!solibSearchPath.isEmpty()) postCommand("set solib-search-path " + solibSearchPath.toLocal8Bit()); @@ -205,7 +207,7 @@ void GdbRemoteServerEngine::setupInferior() // mi_execute_async_cli_command: Assertion `is_running (inferior_ptid)' // failed.\nA problem internal to GDB has been detected,[...] if (boolSetting(TargetAsync)) - postCommand("set target-async on", CB(handleSetTargetAsync)); + postCommand("set target-async on", NoFlags, CB(handleSetTargetAsync)); if (executableFileName.isEmpty()) { showMessage(tr("No symbol file given."), StatusBar); @@ -215,21 +217,21 @@ void GdbRemoteServerEngine::setupInferior() if (!executableFileName.isEmpty()) { postCommand("-file-exec-and-symbols \"" + executableFileName.toLocal8Bit() + '"', - CB(handleFileExecAndSymbols)); + NoFlags, CB(handleFileExecAndSymbols)); } } -void GdbRemoteServerEngine::handleSetTargetAsync(const GdbResponse &response) +void GdbRemoteServerEngine::handleSetTargetAsync(const DebuggerResponse &response) { QTC_ASSERT(state() == InferiorSetupRequested, qDebug() << state()); - if (response.resultClass == GdbResultError) + if (response.resultClass == ResultError) qDebug() << "Adapter too old: does not support asynchronous mode."; } -void GdbRemoteServerEngine::handleFileExecAndSymbols(const GdbResponse &response) +void GdbRemoteServerEngine::handleFileExecAndSymbols(const DebuggerResponse &response) { QTC_ASSERT(state() == InferiorSetupRequested, qDebug() << state()); - if (response.resultClass == GdbResultDone) { + if (response.resultClass == ResultDone) { callTargetRemote(); } else { QByteArray reason = response.data["msg"].data(); @@ -265,17 +267,17 @@ void GdbRemoteServerEngine::callTargetRemote() } if (m_isQnxGdb) - postCommand("target qnx " + channel, CB(handleTargetQnx)); + postCommand("target qnx " + channel, NoFlags, CB(handleTargetQnx)); else if (startParameters().multiProcess) - postCommand("target extended-remote " + channel, CB(handleTargetExtendedRemote)); + postCommand("target extended-remote " + channel, NoFlags, CB(handleTargetExtendedRemote)); else - postCommand("target remote " + channel, CB(handleTargetRemote), 10); + postCommand("target remote " + channel, NoFlags, CB(handleTargetRemote)); } -void GdbRemoteServerEngine::handleTargetRemote(const GdbResponse &response) +void GdbRemoteServerEngine::handleTargetRemote(const DebuggerResponse &response) { QTC_ASSERT(state() == InferiorSetupRequested, qDebug() << state()); - if (response.resultClass == GdbResultDone) { + if (response.resultClass == ResultDone) { // gdb server will stop the remote application itself. showMessage(_("INFERIOR STARTED")); showMessage(msgAttachedToStoppedInferior(), StatusBar); @@ -293,10 +295,10 @@ void GdbRemoteServerEngine::handleTargetRemote(const GdbResponse &response) } } -void GdbRemoteServerEngine::handleTargetExtendedRemote(const GdbResponse &response) +void GdbRemoteServerEngine::handleTargetExtendedRemote(const DebuggerResponse &response) { QTC_ASSERT(state() == InferiorSetupRequested, qDebug() << state()); - if (response.resultClass == GdbResultDone) { + if (response.resultClass == ResultDone) { showMessage(_("ATTACHED TO GDB SERVER STARTED")); showMessage(msgAttachedToStoppedInferior(), StatusBar); QString postAttachCommands = stringSetting(GdbPostAttachCommands); @@ -307,10 +309,10 @@ void GdbRemoteServerEngine::handleTargetExtendedRemote(const GdbResponse &respon if (startParameters().attachPID > 0) { // attach to pid if valid // gdb server will stop the remote application itself. postCommand("attach " + QByteArray::number(startParameters().attachPID), - CB(handleTargetExtendedAttach)); + NoFlags, CB(handleTargetExtendedAttach)); } else { postCommand("-gdb-set remote exec-file " + startParameters().remoteExecutable.toLatin1(), - CB(handleTargetExtendedAttach)); + NoFlags, CB(handleTargetExtendedAttach)); } } else { QString msg = msgConnectRemoteServerFailed( @@ -319,10 +321,10 @@ void GdbRemoteServerEngine::handleTargetExtendedRemote(const GdbResponse &respon } } -void GdbRemoteServerEngine::handleTargetExtendedAttach(const GdbResponse &response) +void GdbRemoteServerEngine::handleTargetExtendedAttach(const DebuggerResponse &response) { QTC_ASSERT(state() == InferiorSetupRequested, qDebug() << state()); - if (response.resultClass == GdbResultDone) { + if (response.resultClass == ResultDone) { // gdb server will stop the remote application itself. handleInferiorPrepared(); } else { @@ -332,17 +334,11 @@ void GdbRemoteServerEngine::handleTargetExtendedAttach(const GdbResponse &respon } } -void GdbRemoteServerEngine::notifyInferiorSetupOk() -{ - emit aboutToNotifyInferiorSetupOk(); - GdbEngine::notifyInferiorSetupOk(); -} - -void GdbRemoteServerEngine::handleTargetQnx(const GdbResponse &response) +void GdbRemoteServerEngine::handleTargetQnx(const DebuggerResponse &response) { QTC_ASSERT(m_isQnxGdb, qDebug() << m_isQnxGdb); QTC_ASSERT(state() == InferiorSetupRequested, qDebug() << state()); - if (response.resultClass == GdbResultDone) { + if (response.resultClass == ResultDone) { // gdb server will stop the remote application itself. showMessage(_("INFERIOR STARTED")); showMessage(msgAttachedToStoppedInferior(), StatusBar); @@ -350,9 +346,9 @@ void GdbRemoteServerEngine::handleTargetQnx(const GdbResponse &response) const qint64 pid = isMasterEngine() ? startParameters().attachPID : masterEngine()->startParameters().attachPID; const QString remoteExecutable = isMasterEngine() ? startParameters().remoteExecutable : masterEngine()->startParameters().remoteExecutable; if (pid > -1) - postCommand("attach " + QByteArray::number(pid), CB(handleAttach)); + postCommand("attach " + QByteArray::number(pid), NoFlags, CB(handleAttach)); else if (!remoteExecutable.isEmpty()) - postCommand("set nto-executable " + remoteExecutable.toLatin1(), CB(handleSetNtoExecutable)); + postCommand("set nto-executable " + remoteExecutable.toLatin1(), NoFlags, CB(handleSetNtoExecutable)); else handleInferiorPrepared(); } else { @@ -363,18 +359,18 @@ void GdbRemoteServerEngine::handleTargetQnx(const GdbResponse &response) } } -void GdbRemoteServerEngine::handleAttach(const GdbResponse &response) +void GdbRemoteServerEngine::handleAttach(const DebuggerResponse &response) { QTC_ASSERT(state() == InferiorSetupRequested, qDebug() << state()); switch (response.resultClass) { - case GdbResultDone: - case GdbResultRunning: { + case ResultDone: + case ResultRunning: { showMessage(_("INFERIOR ATTACHED")); showMessage(msgAttachedToStoppedInferior(), StatusBar); handleInferiorPrepared(); break; } - case GdbResultError: + case ResultError: if (response.data["msg"].data() == "ptrace: Operation not permitted.") { notifyInferiorSetupFailed(msgPtraceError(startParameters().startMode)); break; @@ -386,18 +382,18 @@ void GdbRemoteServerEngine::handleAttach(const GdbResponse &response) } } -void GdbRemoteServerEngine::handleSetNtoExecutable(const GdbResponse &response) +void GdbRemoteServerEngine::handleSetNtoExecutable(const DebuggerResponse &response) { QTC_ASSERT(state() == InferiorSetupRequested, qDebug() << state()); switch (response.resultClass) { - case GdbResultDone: - case GdbResultRunning: { + case ResultDone: + case ResultRunning: { showMessage(_("EXECUTABLE SET")); showMessage(msgAttachedToStoppedInferior(), StatusBar); handleInferiorPrepared(); break; } - case GdbResultError: + case ResultError: default: QString msg = QString::fromLocal8Bit(response.data["msg"].data()); notifyInferiorSetupFailed(msg); @@ -418,10 +414,10 @@ void GdbRemoteServerEngine::runEngine() } } -void GdbRemoteServerEngine::handleExecRun(const GdbResponse &response) +void GdbRemoteServerEngine::handleExecRun(const DebuggerResponse &response) { QTC_ASSERT(state() == EngineRunRequested, qDebug() << state()); - if (response.resultClass == GdbResultRunning) { + if (response.resultClass == ResultRunning) { notifyEngineRunAndInferiorRunOk(); showMessage(_("INFERIOR STARTED")); showMessage(msgInferiorSetupOk(), StatusBar); @@ -438,7 +434,7 @@ void GdbRemoteServerEngine::interruptInferior2() if (boolSetting(TargetAsync)) { postCommand("-exec-interrupt", GdbEngine::Immediate, CB(handleInterruptInferior)); - } else if (m_isQnxGdb && Utils::HostOsInfo::isWindowsHost()) { + } else if (m_isQnxGdb && HostOsInfo::isWindowsHost()) { m_gdbProc->winInterruptByCtrlC(); } else { bool ok = m_gdbProc->interrupt(); @@ -451,9 +447,9 @@ void GdbRemoteServerEngine::interruptInferior2() } } -void GdbRemoteServerEngine::handleInterruptInferior(const GdbResponse &response) +void GdbRemoteServerEngine::handleInterruptInferior(const DebuggerResponse &response) { - if (response.resultClass == GdbResultDone) { + if (response.resultClass == ResultDone) { // The gdb server will trigger extra output that we will pick up // to do a proper state transition. } else { diff --git a/src/plugins/debugger/gdb/remotegdbserveradapter.h b/src/plugins/debugger/gdb/remotegdbserveradapter.h index 9966ac057f..2b0c732d81 100644 --- a/src/plugins/debugger/gdb/remotegdbserveradapter.h +++ b/src/plugins/debugger/gdb/remotegdbserveradapter.h @@ -66,7 +66,6 @@ signals: * a server start script should be used, but none is given. */ void requestSetup(); - void aboutToNotifyInferiorSetupOk(); private: Q_SLOT void readUploadStandardOutput(); @@ -77,18 +76,17 @@ private: void notifyEngineRemoteServerRunning(const QByteArray &serverChannel, int inferiorPid); void notifyEngineRemoteSetupFinished(const RemoteSetupResult &result); - void notifyInferiorSetupOk(); - void handleSetTargetAsync(const GdbResponse &response); - void handleFileExecAndSymbols(const GdbResponse &response); - void handleTargetRemote(const GdbResponse &response); - void handleTargetExtendedRemote(const GdbResponse &response); - void handleTargetExtendedAttach(const GdbResponse &response); - void handleTargetQnx(const GdbResponse &response); - void handleAttach(const GdbResponse &response); - void handleSetNtoExecutable(const GdbResponse &response); - void handleInterruptInferior(const GdbResponse &response); - void handleExecRun(const GdbResponse &response); + void handleSetTargetAsync(const DebuggerResponse &response); + void handleFileExecAndSymbols(const DebuggerResponse &response); + void handleTargetRemote(const DebuggerResponse &response); + void handleTargetExtendedRemote(const DebuggerResponse &response); + void handleTargetExtendedAttach(const DebuggerResponse &response); + void handleTargetQnx(const DebuggerResponse &response); + void handleAttach(const DebuggerResponse &response); + void handleSetNtoExecutable(const DebuggerResponse &response); + void handleInterruptInferior(const DebuggerResponse &response); + void handleExecRun(const DebuggerResponse &response); QProcess m_uploadProc; bool m_startAttempted; diff --git a/src/plugins/debugger/gdb/startgdbserverdialog.cpp b/src/plugins/debugger/gdb/startgdbserverdialog.cpp index 6c224b5b6c..346668ea19 100644 --- a/src/plugins/debugger/gdb/startgdbserverdialog.cpp +++ b/src/plugins/debugger/gdb/startgdbserverdialog.cpp @@ -37,6 +37,7 @@ #include <debugger/debuggerstartparameters.h> #include <coreplugin/icore.h> +#include <coreplugin/messagebox.h> #include <projectexplorer/kitchooser.h> #include <projectexplorer/devicesupport/deviceprocesslist.h> #include <projectexplorer/devicesupport/deviceprocessesdialog.h> @@ -45,7 +46,6 @@ #include <utils/portlist.h> #include <utils/qtcassert.h> -#include <QMessageBox> #include <QFileInfo> using namespace Core; @@ -90,7 +90,7 @@ GdbServerStarter::~GdbServerStarter() void GdbServerStarter::handleRemoteError(const QString &errorMsg) { - QMessageBox::critical(0, tr("Remote Error"), errorMsg); + AsynchronousMessageBox::critical(tr("Remote Error"), errorMsg); } void GdbServerStarter::portGathererError(const QString &text) @@ -103,8 +103,10 @@ void GdbServerStarter::portGathererError(const QString &text) void GdbServerStarter::run() { QTC_ASSERT(d->device, return); - connect(&d->gatherer, SIGNAL(error(QString)), SLOT(portGathererError(QString))); - connect(&d->gatherer, SIGNAL(portListReady()), SLOT(portListReady())); + connect(&d->gatherer, &DeviceUsedPortsGatherer::error, + this, &GdbServerStarter::portGathererError); + connect(&d->gatherer, &DeviceUsedPortsGatherer::portListReady, + this, &GdbServerStarter::portListReady); d->gatherer.start(d->device); } @@ -118,11 +120,16 @@ void GdbServerStarter::portListReady() return; } - connect(&d->runner, SIGNAL(connectionError()), SLOT(handleConnectionError())); - connect(&d->runner, SIGNAL(processStarted()), SLOT(handleProcessStarted())); - connect(&d->runner, SIGNAL(readyReadStandardOutput()), SLOT(handleProcessOutputAvailable())); - connect(&d->runner, SIGNAL(readyReadStandardError()), SLOT(handleProcessErrorOutput())); - connect(&d->runner, SIGNAL(processClosed(int)), SLOT(handleProcessClosed(int))); + connect(&d->runner, &SshRemoteProcessRunner::connectionError, + this, &GdbServerStarter::handleConnectionError); + connect(&d->runner, &SshRemoteProcessRunner::processStarted, + this, &GdbServerStarter::handleProcessStarted); + connect(&d->runner, &SshRemoteProcessRunner::readyReadStandardOutput, + this, &GdbServerStarter::handleProcessOutputAvailable); + connect(&d->runner, &SshRemoteProcessRunner::readyReadStandardError, + this, &GdbServerStarter::handleProcessErrorOutput); + connect(&d->runner, &SshRemoteProcessRunner::processClosed, + this, &GdbServerStarter::handleProcessClosed); QByteArray gdbServerPath = d->device->debugServerPath().toUtf8(); if (gdbServerPath.isEmpty()) @@ -191,15 +198,15 @@ void GdbServerStarter::attach(int port) localExecutable = candidate; } if (localExecutable.isEmpty()) { - QMessageBox::warning(ICore::mainWindow(), tr("Warning"), + AsynchronousMessageBox::warning(tr("Warning"), tr("Cannot find local executable for remote process \"%1\".") .arg(d->process.exe)); return; } - QList<Abi> abis = Abi::abisOfBinary(Utils::FileName::fromString(localExecutable)); + QList<Abi> abis = Abi::abisOfBinary(FileName::fromString(localExecutable)); if (abis.isEmpty()) { - QMessageBox::warning(ICore::mainWindow(), tr("Warning"), + AsynchronousMessageBox::warning(tr("Warning"), tr("Cannot find ABI for remote process \"%1\".") .arg(d->process.exe)); return; diff --git a/src/plugins/debugger/gdb/termgdbadapter.cpp b/src/plugins/debugger/gdb/termgdbadapter.cpp index 33bf3a176e..8a9b20355b 100644 --- a/src/plugins/debugger/gdb/termgdbadapter.cpp +++ b/src/plugins/debugger/gdb/termgdbadapter.cpp @@ -39,18 +39,13 @@ #include <utils/hostosinfo.h> #include <utils/qtcassert.h> #include <coreplugin/icore.h> - -#include <QMessageBox> +#include <coreplugin/messagebox.h> using namespace Utils; namespace Debugger { namespace Internal { -#define CB(callback) \ - static_cast<GdbEngine::GdbCommandCallback>(&GdbTermEngine::callback), \ - STRINGIFY(callback) - /////////////////////////////////////////////////////////////////////// // // TermGdbAdapter @@ -63,11 +58,11 @@ GdbTermEngine::GdbTermEngine(const DebuggerStartParameters &startParameters) #ifdef Q_OS_WIN // Windows up to xp needs a workaround for attaching to freshly started processes. see proc_stub_win if (QSysInfo::WindowsVersion >= QSysInfo::WV_VISTA) - m_stubProc.setMode(Utils::ConsoleProcess::Suspend); + m_stubProc.setMode(ConsoleProcess::Suspend); else - m_stubProc.setMode(Utils::ConsoleProcess::Debug); + m_stubProc.setMode(ConsoleProcess::Debug); #else - m_stubProc.setMode(Utils::ConsoleProcess::Debug); + m_stubProc.setMode(ConsoleProcess::Debug); m_stubProc.setSettings(Core::ICore::settings()); #endif } @@ -95,9 +90,12 @@ void GdbTermEngine::setupEngine() // Set environment + dumper preload. m_stubProc.setEnvironment(startParameters().environment); - connect(&m_stubProc, SIGNAL(processError(QString)), SLOT(stubError(QString))); - connect(&m_stubProc, SIGNAL(processStarted()), SLOT(stubStarted())); - connect(&m_stubProc, SIGNAL(stubStopped()), SLOT(stubExited())); + connect(&m_stubProc, &ConsoleProcess::processError, + this, &GdbTermEngine::stubError); + connect(&m_stubProc, &ConsoleProcess::processStarted, + this, &GdbTermEngine::stubStarted); + connect(&m_stubProc, &ConsoleProcess::stubStopped, + this, &GdbTermEngine::stubExited); // FIXME: Starting the stub implies starting the inferior. This is // fairly unclean as far as the state machine and error reporting go. @@ -136,17 +134,17 @@ void GdbTermEngine::runEngine() { QTC_ASSERT(state() == EngineRunRequested, qDebug() << state()); const qint64 attachedPID = m_stubProc.applicationPID(); - postCommand("attach " + QByteArray::number(attachedPID), - CB(handleStubAttached)); + postCommand("attach " + QByteArray::number(attachedPID), NoFlags, + [this](const DebuggerResponse &r) { handleStubAttached(r); }); } -void GdbTermEngine::handleStubAttached(const GdbResponse &response) +void GdbTermEngine::handleStubAttached(const DebuggerResponse &response) { QTC_ASSERT(state() == InferiorSetupRequested, qDebug() << state()); switch (response.resultClass) { - case GdbResultDone: - case GdbResultRunning: + case ResultDone: + case ResultRunning: if (startParameters().toolChainAbi.os() != ProjectExplorer::Abi::WindowsOS) { showMessage(_("INFERIOR ATTACHED")); } else { @@ -165,7 +163,7 @@ void GdbTermEngine::handleStubAttached(const GdbResponse &response) notifyEngineRunAndInferiorStopOk(); continueInferiorInternal(); break; - case GdbResultError: + case ResultError: if (response.data["msg"].data() == "ptrace: Operation not permitted.") { showMessage(msgPtraceError(startParameters().startMode)); notifyEngineRunFailed(); @@ -188,7 +186,7 @@ void GdbTermEngine::interruptInferior2() void GdbTermEngine::stubError(const QString &msg) { - showMessageBox(QMessageBox::Critical, tr("Debugger Error"), msg); + Core::AsynchronousMessageBox::critical(tr("Debugger Error"), msg); } void GdbTermEngine::stubExited() diff --git a/src/plugins/debugger/gdb/termgdbadapter.h b/src/plugins/debugger/gdb/termgdbadapter.h index 6af88b39a1..2ffebbabb0 100644 --- a/src/plugins/debugger/gdb/termgdbadapter.h +++ b/src/plugins/debugger/gdb/termgdbadapter.h @@ -60,7 +60,7 @@ private: void interruptInferior2(); void shutdownEngine(); - void handleStubAttached(const GdbResponse &response); + void handleStubAttached(const DebuggerResponse &response); Q_SLOT void stubStarted(); Q_SLOT void stubExited(); diff --git a/src/plugins/debugger/imageviewer.cpp b/src/plugins/debugger/imageviewer.cpp index 21c3501ea3..26015f9fc6 100644 --- a/src/plugins/debugger/imageviewer.cpp +++ b/src/plugins/debugger/imageviewer.cpp @@ -104,11 +104,11 @@ ImageViewer::ImageViewer(QWidget *parent) , m_imageWidget(new ImageWidget) , m_infoLabel(new QLabel) { - QVBoxLayout *mainLayout = new QVBoxLayout(this); + auto mainLayout = new QVBoxLayout(this); mainLayout->addWidget(m_infoLabel); mainLayout->addWidget(m_scrollArea); m_scrollArea->setWidget(m_imageWidget); - connect(m_imageWidget, SIGNAL(clicked(QString)), this, SLOT(clicked(QString))); + connect(m_imageWidget, &ImageWidget::clicked, this, &ImageViewer::clicked); } void ImageViewer::setImage(const QImage &i) diff --git a/src/plugins/debugger/lldb/lldbengine.cpp b/src/plugins/debugger/lldb/lldbengine.cpp index 5fb75784fa..359403bfa4 100644 --- a/src/plugins/debugger/lldb/lldbengine.cpp +++ b/src/plugins/debugger/lldb/lldbengine.cpp @@ -50,25 +50,26 @@ #include <debugger/watchhandler.h> #include <debugger/watchutils.h> +#include <coreplugin/messagebox.h> +#include <coreplugin/idocument.h> +#include <coreplugin/icore.h> + +#include <texteditor/texteditor.h> + #include <utils/qtcassert.h> #include <utils/savedaction.h> #include <utils/qtcprocess.h> -#include <texteditor/texteditor.h> -#include <coreplugin/idocument.h> -#include <coreplugin/icore.h> - +#include <QApplication> #include <QDateTime> #include <QDebug> #include <QDir> #include <QFileInfo> #include <QTimer> -#include <QVariant> - -#include <QApplication> -#include <QMessageBox> #include <QToolTip> +#include <QVariant> +using namespace Core; using namespace Utils; namespace Debugger { @@ -91,25 +92,25 @@ LldbEngine::LldbEngine(const DebuggerStartParameters &startParameters) #ifdef Q_OS_WIN // Windows up to xp needs a workaround for attaching to freshly started processes. see proc_stub_win if (QSysInfo::WindowsVersion >= QSysInfo::WV_VISTA) - m_stubProc.setMode(Utils::ConsoleProcess::Suspend); + m_stubProc.setMode(ConsoleProcess::Suspend); else - m_stubProc.setMode(Utils::ConsoleProcess::Debug); + m_stubProc.setMode(ConsoleProcess::Debug); #else - m_stubProc.setMode(Utils::ConsoleProcess::Debug); - m_stubProc.setSettings(Core::ICore::settings()); + m_stubProc.setMode(ConsoleProcess::Debug); + m_stubProc.setSettings(ICore::settings()); #endif } - connect(action(AutoDerefPointers), SIGNAL(valueChanged(QVariant)), - SLOT(updateLocals())); - connect(action(CreateFullBacktrace), SIGNAL(triggered()), - SLOT(createFullBacktrace())); - connect(action(UseDebuggingHelpers), SIGNAL(valueChanged(QVariant)), - SLOT(updateLocals())); - connect(action(UseDynamicType), SIGNAL(valueChanged(QVariant)), - SLOT(updateLocals())); - connect(action(IntelFlavor), SIGNAL(valueChanged(QVariant)), - SLOT(updateAll())); + connect(action(AutoDerefPointers), &SavedAction::valueChanged, + this, &LldbEngine::updateLocals); + connect(action(CreateFullBacktrace), &QAction::triggered, + this, &LldbEngine::createFullBacktrace); + connect(action(UseDebuggingHelpers), &SavedAction::valueChanged, + this, &LldbEngine::updateLocals); + connect(action(UseDynamicType), &SavedAction::valueChanged, + this, &LldbEngine::updateLocals); + connect(action(IntelFlavor), &SavedAction::valueChanged, + this, &LldbEngine::updateAll); } LldbEngine::~LldbEngine() @@ -120,18 +121,19 @@ LldbEngine::~LldbEngine() void LldbEngine::executeDebuggerCommand(const QString &command, DebuggerLanguages) { - runCommand(Command("executeDebuggerCommand").arg("command", command)); + DebuggerCommand cmd("executeDebuggerCommand"); + cmd.arg("command", command); + runCommand(cmd); } -void LldbEngine::runCommand(const Command &command) +void LldbEngine::runCommand(const DebuggerCommand &command) { QTC_ASSERT(m_lldbProc.state() == QProcess::Running, notifyEngineIll()); ++m_lastToken; QByteArray token = QByteArray::number(m_lastToken); - QByteArray cmd = "{\"cmd\":\"" + command.function + "\"," - + command.args + "\"token\":" + token + "}\n"; - showMessage(_(token + cmd), LogInput); - m_lldbProc.write(cmd); + QByteArray cmd = command.function + "({" + command.args + "})"; + showMessage(_(token + cmd + '\n'), LogInput); + m_lldbProc.write("sc db." + cmd + "\n"); } void LldbEngine::debugLastCommand() @@ -142,7 +144,7 @@ void LldbEngine::debugLastCommand() void LldbEngine::shutdownInferior() { QTC_ASSERT(state() == InferiorShutdownRequested, qDebug() << state()); - runCommand(Command("shutdownInferior")); + runCommand(DebuggerCommand("shutdownInferior")); } void LldbEngine::shutdownEngine() @@ -174,9 +176,9 @@ bool LldbEngine::prepareCommand() DebuggerStartParameters &sp = startParameters(); QtcProcess::SplitError perr; sp.processArgs = QtcProcess::prepareArgs(sp.processArgs, &perr, - Utils::HostOsInfo::hostOs(), + HostOsInfo::hostOs(), &sp.environment, &sp.workingDirectory).toWindowsArgs(); - if (perr != Utils::QtcProcess::SplitOk) { + if (perr != QtcProcess::SplitOk) { // perr == BadQuoting is never returned on Windows // FIXME? QTCREATORBUG-2809 notifyEngineSetupFailed(); @@ -207,9 +209,9 @@ void LldbEngine::setupEngine() // Set environment + dumper preload. m_stubProc.setEnvironment(startParameters().environment); - connect(&m_stubProc, SIGNAL(processError(QString)), SLOT(stubError(QString))); - connect(&m_stubProc, SIGNAL(processStarted()), SLOT(stubStarted())); - connect(&m_stubProc, SIGNAL(stubStopped()), SLOT(stubExited())); + connect(&m_stubProc, &ConsoleProcess::processError, this, &LldbEngine::stubError); + connect(&m_stubProc, &ConsoleProcess::processStarted, this, &LldbEngine::stubStarted); + connect(&m_stubProc, &ConsoleProcess::stubStopped, this, &LldbEngine::stubExited); // FIXME: Starting the stub implies starting the inferior. This is // fairly unclean as far as the state machine and error reporting go. @@ -233,28 +235,24 @@ void LldbEngine::setupEngine() void LldbEngine::startLldb() { m_lldbCmd = startParameters().debuggerCommand; - connect(&m_lldbProc, SIGNAL(error(QProcess::ProcessError)), - SLOT(handleLldbError(QProcess::ProcessError))); - connect(&m_lldbProc, SIGNAL(finished(int,QProcess::ExitStatus)), - SLOT(handleLldbFinished(int,QProcess::ExitStatus))); - connect(&m_lldbProc, SIGNAL(readyReadStandardOutput()), - SLOT(readLldbStandardOutput())); - connect(&m_lldbProc, SIGNAL(readyReadStandardError()), - SLOT(readLldbStandardError())); - - connect(this, SIGNAL(outputReady(QByteArray)), - SLOT(handleResponse(QByteArray)), Qt::QueuedConnection); - - QStringList args; - args.append(_("-i")); - args.append(Core::ICore::resourcePath() + _("/debugger/lldbbridge.py")); - args.append(m_lldbCmd); - showMessage(_("STARTING LLDB: python ") + args.join(QLatin1Char(' '))); + connect(&m_lldbProc, static_cast<void (QProcess::*)(QProcess::ProcessError)>(&QProcess::error), + this, &LldbEngine::handleLldbError); + connect(&m_lldbProc, static_cast<void (QProcess::*)(int, QProcess::ExitStatus)>(&QProcess::finished), + this, &LldbEngine::handleLldbFinished); + connect(&m_lldbProc, &QProcess::readyReadStandardOutput, + this, &LldbEngine::readLldbStandardOutput); + connect(&m_lldbProc, &QProcess::readyReadStandardError, + this, &LldbEngine::readLldbStandardError); + + connect(this, &LldbEngine::outputReady, + this, &LldbEngine::handleResponse, Qt::QueuedConnection); + + showMessage(_("STARTING LLDB: ") + m_lldbCmd); m_lldbProc.setEnvironment(startParameters().environment.toStringList()); if (!startParameters().workingDirectory.isEmpty()) m_lldbProc.setWorkingDirectory(startParameters().workingDirectory); - m_lldbProc.start(_("python"), args); + m_lldbProc.start(m_lldbCmd); if (!m_lldbProc.waitForStarted()) { const QString msg = tr("Unable to start LLDB \"%1\": %2") @@ -262,8 +260,23 @@ void LldbEngine::startLldb() notifyEngineSetupFailed(); showMessage(_("ADAPTER START FAILED")); if (!msg.isEmpty()) - Core::ICore::showWarningWithOptions(tr("Adapter start failed."), msg); + ICore::showWarningWithOptions(tr("Adapter start failed."), msg); } + + showMessage(_("ADAPTER STARTED")); + showStatusMessage(tr("Setting up inferior...")); + + const QByteArray dumperSourcePath = + ICore::resourcePath().toLocal8Bit() + "/debugger/"; + + m_lldbProc.write("sc sys.path.insert(1, '" + dumperSourcePath + "')\n"); + m_lldbProc.write("sc from lldbbridge import *\n"); + m_lldbProc.write("sc print(dir())\n"); + m_lldbProc.write("sc db = Dumper()\n"); + m_lldbProc.write("sc db.report('lldbversion=\"%s\"' % lldb.SBDebugger.GetVersionString())\n"); + + showMessage(_("ENGINE SUCCESSFULLY STARTED")); + notifyEngineSetupOk(); } void LldbEngine::setupInferior() @@ -272,35 +285,48 @@ void LldbEngine::setupInferior() const QString path = stringSetting(ExtraDumperFile); if (!path.isEmpty()) { - QFileInfo fi(path); - - Command cmd1("executeDebuggerCommand"); - cmd1.arg("command", "python sys.path.insert(1, '" + fi.absolutePath().toUtf8() + "')"); - runCommand(cmd1); - - Command cmd2("executeDebuggerCommand"); - cmd2.arg("python from " + fi.baseName().toUtf8() + " import *"); - runCommand(cmd2); + DebuggerCommand cmd("addDumperModule"); + cmd.arg("path", path.toUtf8()); + runCommand(cmd); } const QString commands = stringSetting(ExtraDumperCommands); if (!commands.isEmpty()) { - Command cmd("executeDebuggerCommand"); - cmd.arg(commands.toUtf8()); + DebuggerCommand cmd("executeDebuggerCommand"); + cmd.arg("commands", commands.toUtf8()); runCommand(cmd); } + DebuggerCommand cmd1("loadDumperFiles"); + runCommand(cmd1); + QString executable; - Utils::QtcProcess::Arguments args; - Utils::QtcProcess::prepareCommand(QFileInfo(sp.executable).absoluteFilePath(), - sp.processArgs, &executable, &args); + QtcProcess::Arguments args; + QtcProcess::prepareCommand(QFileInfo(sp.executable).absoluteFilePath(), + sp.processArgs, &executable, &args); - Command cmd("setupInferior"); + DebuggerCommand cmd("setupInferior"); cmd.arg("executable", executable); cmd.arg("breakOnMain", sp.breakOnMain); cmd.arg("useTerminal", sp.useTerminal); cmd.arg("startMode", sp.startMode); + cmd.beginList("bkpts"); + foreach (Breakpoint bp, breakHandler()->unclaimedBreakpoints()) { + if (acceptsBreakpoint(bp)) { + showMessage(_("TAKING OWNERSHIP OF BREAKPOINT %1 IN STATE %2") + .arg(bp.id().toString()).arg(bp.state())); + bp.setEngine(this); + cmd.beginGroup(); + bp.addToCommand(&cmd); + cmd.endGroup(); + } else { + showMessage(_("BREAKPOINT %1 IN STATE %2 IS NOT ACCEPTABLE") + .arg(bp.id().toString()).arg(bp.state())); + } + } + cmd.endList(); + cmd.beginList("processArgs"); foreach (const QString &arg, args.toUnixArgs()) cmd.arg(arg.toUtf8().toHex()); @@ -340,19 +366,7 @@ void LldbEngine::setupInferior() void LldbEngine::runEngine() { - QTC_ASSERT(state() == EngineRunRequested, qDebug() << state()); - - Command cmd("handleBreakpoints"); - if (attemptBreakpointSynchronizationHelper(&cmd)) { - runEngine2(); - } else { - cmd.arg("continuation", "runEngine2"); - runCommand(cmd); - } -} - -void LldbEngine::runEngine2() -{ + QTC_ASSERT(state() == EngineRunRequested, qDebug() << state(); return); showStatusMessage(tr("Running requested..."), 5000); runCommand("runEngine"); } @@ -414,6 +428,8 @@ void LldbEngine::handleResponse(const QByteArray &response) const QByteArray name = item.name(); if (name == "data") refreshLocals(item); + else if (name == "dumpers") + watchHandler()->addDumpers(item); else if (name == "stack") refreshStack(item); else if (name == "stack-position") @@ -446,8 +462,6 @@ void LldbEngine::handleResponse(const QByteArray &response) refreshDisassembly(item); else if (name == "memory") refreshMemory(item); - else if (name == "continuation") - runContinuation(item); else if (name == "full-backtrace") showFullBacktrace(item); else if (name == "statusmessage") { @@ -465,17 +479,11 @@ void LldbEngine::showFullBacktrace(const GdbMi &data) QString::fromUtf8(QByteArray::fromHex(data.data()))); } -void LldbEngine::runContinuation(const GdbMi &data) -{ - const QByteArray target = data.data(); - QMetaObject::invokeMethod(this, target, Qt::QueuedConnection); -} - void LldbEngine::executeRunToLine(const ContextData &data) { resetLocation(); notifyInferiorRunRequested(); - Command cmd("executeRunToLocation"); + DebuggerCommand cmd("executeRunToLocation"); cmd.arg("file", data.fileName); cmd.arg("line", data.lineNumber); cmd.arg("address", data.address); @@ -486,14 +494,16 @@ void LldbEngine::executeRunToFunction(const QString &functionName) { resetLocation(); notifyInferiorRunRequested(); - runCommand(Command("executeRunToFunction").arg("function", functionName)); + DebuggerCommand cmd("executeRunToFunction"); + cmd.arg("function", functionName); + runCommand(cmd); } void LldbEngine::executeJumpToLine(const ContextData &data) { resetLocation(); notifyInferiorRunRequested(); - Command cmd("executeJumpToLocation"); + DebuggerCommand cmd("executeJumpToLocation"); cmd.arg("file", data.fileName); cmd.arg("line", data.lineNumber); cmd.arg("address", data.address); @@ -508,13 +518,14 @@ void LldbEngine::activateFrame(int frameIndex) const int n = stackHandler()->stackSize(); if (frameIndex == n) { - Command cmd("reportStack"); + DebuggerCommand cmd("reportStack"); + cmd.arg("nativeMixed", isNativeMixedActive()); cmd.arg("stacklimit", n * 10 + 3); runCommand(cmd); return; } - Command cmd("activateFrame"); + DebuggerCommand cmd("activateFrame"); cmd.arg("index", frameIndex); cmd.arg("thread", threadsHandler()->currentThread().raw()); runCommand(cmd); @@ -525,117 +536,61 @@ void LldbEngine::activateFrame(int frameIndex) void LldbEngine::selectThread(ThreadId threadId) { - runCommand(Command("selectThread").arg("id", threadId.raw())); + DebuggerCommand cmd("selectThread"); + cmd.arg("id", threadId.raw()); + runCommand(cmd); } -bool LldbEngine::acceptsBreakpoint(BreakpointModelId id) const +bool LldbEngine::stateAcceptsBreakpointChanges() const { - return breakHandler()->breakpointData(id).isCppBreakpoint() - && startParameters().startMode != AttachCore; + switch (state()) { + case InferiorSetupRequested: + case InferiorRunRequested: + case InferiorRunOk: + case InferiorStopRequested: + case InferiorStopOk: + return true; + default: + return false; + } } -bool LldbEngine::attemptBreakpointSynchronizationHelper(Command *cmd) +bool LldbEngine::acceptsBreakpoint(Breakpoint bp) const { - BreakHandler *handler = breakHandler(); - - foreach (BreakpointModelId id, handler->unclaimedBreakpointIds()) { - // Take ownership of the breakpoint. Requests insertion. - if (acceptsBreakpoint(id)) { - showMessage(_("TAKING OWNERSHIP OF BREAKPOINT %1 IN STATE %2") - .arg(id.toString()).arg(handler->state(id))); - handler->setEngine(id, this); - } else { - showMessage(_("BREAKPOINT %1 IN STATE %2 IS NOT ACCEPTABLE") - .arg(id.toString()).arg(handler->state(id))); - } - } + if (startParameters().startMode == AttachCore) + return false; + // We handle QML breakpoint unless specifically disabled. + if (isNativeMixedEnabled() && !(startParameters().languages & QmlLanguage)) + return true; + return bp.parameters().isCppBreakpoint(); +} - bool done = true; - cmd->beginList("bkpts"); - foreach (BreakpointModelId id, handler->engineBreakpointIds(this)) { - const BreakpointResponse &response = handler->response(id); - const BreakpointState bpState = handler->state(id); - switch (bpState) { - case BreakpointNew: - // Should not happen once claimed. - QTC_CHECK(false); - break; - case BreakpointInsertRequested: - done = false; - cmd->beginGroup() - .arg("operation", "add") - .arg("modelid", id.toByteArray()) - .arg("type", handler->type(id)) - .arg("ignorecount", handler->ignoreCount(id)) - .arg("condition", handler->condition(id).toHex()) - .arg("function", handler->functionName(id).toUtf8()) - .arg("oneshot", handler->isOneShot(id)) - .arg("enabled", handler->isEnabled(id)) - .arg("file", handler->fileName(id).toUtf8()) - .arg("line", handler->lineNumber(id)) - .arg("address", handler->address(id)) - .arg("expression", handler->expression(id)) - .endGroup(); - handler->notifyBreakpointInsertProceeding(id); - break; - case BreakpointChangeRequested: - done = false; - cmd->beginGroup() - .arg("operation", "change") - .arg("modelid", id.toByteArray()) - .arg("lldbid", response.id.toByteArray()) - .arg("type", handler->type(id)) - .arg("ignorecount", handler->ignoreCount(id)) - .arg("condition", handler->condition(id).toHex()) - .arg("function", handler->functionName(id).toUtf8()) - .arg("oneshot", handler->isOneShot(id)) - .arg("enabled", handler->isEnabled(id)) - .arg("file", handler->fileName(id).toUtf8()) - .arg("line", handler->lineNumber(id)) - .arg("address", handler->address(id)) - .arg("expression", handler->expression(id)) - .endGroup(); - handler->notifyBreakpointChangeProceeding(id); - break; - case BreakpointRemoveRequested: - done = false; - cmd->beginGroup() - .arg("operation", "remove") - .arg("modelid", id.toByteArray()) - .arg("lldbid", response.id.toByteArray()) - .endGroup(); - handler->notifyBreakpointRemoveProceeding(id); - break; - case BreakpointChangeProceeding: - case BreakpointInsertProceeding: - case BreakpointRemoveProceeding: - case BreakpointInserted: - case BreakpointDead: - QTC_ASSERT(false, qDebug() << "UNEXPECTED STATE" << bpState << "FOR BP " << id); - break; - default: - QTC_ASSERT(false, qDebug() << "UNKNOWN STATE" << bpState << "FOR BP" << id); - } - } - cmd->endList(); - return done; +void LldbEngine::insertBreakpoint(Breakpoint bp) +{ + DebuggerCommand cmd("insertBreakpoint"); + bp.addToCommand(&cmd); + bp.notifyBreakpointInsertProceeding(); + runCommand(cmd); } -void LldbEngine::attemptBreakpointSynchronization() +void LldbEngine::changeBreakpoint(Breakpoint bp) { - showMessage(_("ATTEMPT BREAKPOINT SYNCHRONIZATION")); - if (!stateAcceptsBreakpointChanges()) { - showMessage(_("BREAKPOINT SYNCHRONIZATION NOT POSSIBLE IN CURRENT STATE")); - return; - } + const BreakpointResponse &response = bp.response(); + DebuggerCommand cmd("changeBreakpoint"); + cmd.arg("lldbid", response.id.toByteArray()); + bp.addToCommand(&cmd); + bp.notifyBreakpointChangeProceeding(); + runCommand(cmd); +} - Command cmd("handleBreakpoints"); - if (!attemptBreakpointSynchronizationHelper(&cmd)) { - showMessage(_("BREAKPOINTS ARE NOT FULLY SYNCHRONIZED")); - runCommand(cmd); - } else { - showMessage(_("BREAKPOINTS ARE SYNCHRONIZED")); - } +void LldbEngine::removeBreakpoint(Breakpoint bp) +{ + const BreakpointResponse &response = bp.response(); + DebuggerCommand cmd("removeBreakpoint"); + cmd.arg("modelid", bp.id().toByteArray()); + cmd.arg("lldbid", response.id.toByteArray()); + bp.notifyBreakpointRemoveProceeding(); + runCommand(cmd); } void LldbEngine::updateBreakpointData(const GdbMi &bkpt, bool added) @@ -643,9 +598,10 @@ void LldbEngine::updateBreakpointData(const GdbMi &bkpt, bool added) BreakHandler *handler = breakHandler(); BreakpointResponseId rid = BreakpointResponseId(bkpt["lldbid"].data()); BreakpointModelId id = BreakpointModelId(bkpt["modelid"].data()); - if (!id.isValid()) - id = handler->findBreakpointByResponseId(rid); - BreakpointResponse response = handler->response(id); + Breakpoint bp = handler->breakpointById(id); + if (!bp.isValid()) + bp = handler->findBreakpointByResponseId(rid); + BreakpointResponse response = bp.response(); if (added) response.id = rid; QTC_CHECK(response.id == rid); @@ -669,7 +625,7 @@ void LldbEngine::updateBreakpointData(const GdbMi &bkpt, bool added) sub.functionName = location["func"].toUtf8(); sub.fileName = location["file"].toUtf8(); sub.lineNumber = location["line"].toInt(); - handler->insertSubBreakpoint(id, sub); + bp.insertSubBreakpoint(sub); } } else if (numChild == 1) { const GdbMi location = locations.childAt(0); @@ -679,11 +635,11 @@ void LldbEngine::updateBreakpointData(const GdbMi &bkpt, bool added) // This can happen for pending breakpoints. showMessage(_("NO LOCATIONS (YET) FOR BP %1").arg(response.toString())); } - handler->setResponse(id, response); + bp.setResponse(response); if (added) - handler->notifyBreakpointInsertOk(id); + bp.notifyBreakpointInsertOk(); else - handler->notifyBreakpointChangeOk(id); + bp.notifyBreakpointChangeOk(); } void LldbEngine::refreshDisassembly(const GdbMi &data) @@ -736,23 +692,25 @@ void LldbEngine::refreshOutput(const GdbMi &output) void LldbEngine::refreshAddedBreakpoint(const GdbMi &bkpt) { BreakpointModelId id = BreakpointModelId(bkpt["modelid"].data()); - QTC_CHECK(breakHandler()->state(id) == BreakpointInsertProceeding); + Breakpoint bp = breakHandler()->breakpointById(id); + QTC_CHECK(bp.state() == BreakpointInsertProceeding); updateBreakpointData(bkpt, true); } void LldbEngine::refreshChangedBreakpoint(const GdbMi &bkpt) { BreakpointModelId id = BreakpointModelId(bkpt["modelid"].data()); - QTC_CHECK(!id.isValid() || breakHandler()->state(id) == BreakpointChangeProceeding); + Breakpoint bp = breakHandler()->breakpointById(id); + QTC_CHECK(!bp.isValid() || bp.state() == BreakpointChangeProceeding); updateBreakpointData(bkpt, false); } void LldbEngine::refreshRemovedBreakpoint(const GdbMi &bkpt) { - BreakHandler *handler = breakHandler(); BreakpointModelId id = BreakpointModelId(bkpt["modelid"].data()); - QTC_CHECK(handler->state(id) == BreakpointRemoveProceeding); - handler->notifyBreakpointRemoveOk(id); + Breakpoint bp = breakHandler()->breakpointById(id); + QTC_CHECK(bp.state() == BreakpointRemoveProceeding); + bp.notifyBreakpointRemoveOk(); } void LldbEngine::loadSymbols(const QString &moduleName) @@ -771,7 +729,8 @@ void LldbEngine::reloadModules() void LldbEngine::refreshModules(const GdbMi &modules) { - Modules mods; + ModulesHandler *handler = modulesHandler(); + handler->beginUpdateAll(); foreach (const GdbMi &item, modules.children()) { Module module; module.modulePath = item["file"].toUtf8(); @@ -779,14 +738,16 @@ void LldbEngine::refreshModules(const GdbMi &modules) module.symbolsRead = Module::UnknownReadState; module.startAddress = item["loaded_addr"].toAddress(); module.endAddress = 0; // FIXME: End address not easily available. - mods.append(module); + handler->updateModule(module); } - modulesHandler()->setModules(mods); + handler->endUpdateAll(); } void LldbEngine::requestModuleSymbols(const QString &moduleName) { - runCommand(Command("listSymbols").arg("module", moduleName)); + DebuggerCommand cmd("listSymbols"); + cmd.arg("module", moduleName); + runCommand(cmd); } void LldbEngine::refreshSymbols(const GdbMi &symbols) @@ -827,8 +788,6 @@ bool LldbEngine::setToolTipExpression(TextEditor::TextEditorWidget *editorWidget UpdateParameters params; params.tryPartial = true; - params.tooltipOnly = true; - params.tooltipExpression = context.expression; params.varList = context.iname; doUpdateLocals(params); @@ -844,14 +803,16 @@ void LldbEngine::updateAll() void LldbEngine::reloadFullStack() { - Command cmd("reportStack"); + DebuggerCommand cmd("reportStack"); + cmd.arg("nativeMixed", isNativeMixedActive()); cmd.arg("stacklimit", -1); runCommand(cmd); } void LldbEngine::updateStack() { - Command cmd("reportStack"); + DebuggerCommand cmd("reportStack"); + cmd.arg("nativeMixed", isNativeMixedActive()); cmd.arg("stacklimit", action(MaximalStackDepth)->value().toInt()); runCommand(cmd); } @@ -866,7 +827,7 @@ void LldbEngine::assignValueInDebugger(const Internal::WatchData *data, const QString &expression, const QVariant &value) { Q_UNUSED(data); - Command cmd("assignValue"); + DebuggerCommand cmd("assignValue"); cmd.arg("exp", expression.toLatin1().toHex()); cmd.arg("value", value.toString().toLatin1().toHex()); runCommand(cmd); @@ -887,12 +848,9 @@ void LldbEngine::updateLocals() void LldbEngine::doUpdateLocals(UpdateParameters params) { - WatchHandler *handler = watchHandler(); - - Command cmd("updateData"); - cmd.arg("expanded", handler->expansionRequests()); - cmd.arg("typeformats", handler->typeFormatRequests()); - cmd.arg("formats", handler->individualFormatRequests()); + DebuggerCommand cmd("updateData"); + cmd.arg("nativeMixed", isNativeMixedActive()); + watchHandler()->appendFormatRequests(&cmd); const static bool alwaysVerbose = !qgetenv("QTC_DEBUGGER_PYTHON_VERBOSE").isEmpty(); cmd.arg("passexceptions", alwaysVerbose); @@ -900,7 +858,6 @@ void LldbEngine::doUpdateLocals(UpdateParameters params) cmd.arg("autoderef", boolSetting(AutoDerefPointers)); cmd.arg("dyntype", boolSetting(UseDynamicType)); cmd.arg("partial", params.tryPartial); - cmd.arg("tooltiponly", params.tooltipOnly); cmd.beginList("watchers"); @@ -908,19 +865,19 @@ void LldbEngine::doUpdateLocals(UpdateParameters params) QHashIterator<QByteArray, int> it(WatchHandler::watcherNames()); while (it.hasNext()) { it.next(); - cmd.beginGroup() - .arg("iname", "watch." + QByteArray::number(it.value())) - .arg("exp", it.key().toHex()) - .endGroup(); + cmd.beginGroup(); + cmd.arg("iname", "watch." + QByteArray::number(it.value())); + cmd.arg("exp", it.key().toHex()); + cmd.endGroup(); } // Tooltips DebuggerToolTipContexts toolTips = DebuggerToolTipManager::pendingTooltips(this); foreach (const DebuggerToolTipContext &p, toolTips) { - cmd.beginGroup() - .arg("iname", p.iname) - .arg("exp", p.expression.toLatin1().toHex()) - .endGroup(); + cmd.beginGroup(); + cmd.arg("iname", p.iname); + cmd.arg("exp", p.expression.toLatin1().toHex()); + cmd.endGroup(); } cmd.endList(); @@ -949,8 +906,7 @@ void LldbEngine::handleLldbError(QProcess::ProcessError error) default: //setState(EngineShutdownRequested, true); m_lldbProc.kill(); - showMessageBox(QMessageBox::Critical, tr("LLDB I/O Error"), - errorMessage(error)); + AsynchronousMessageBox::critical(tr("LLDB I/O Error"), errorMessage(error)); break; } } @@ -1016,29 +972,18 @@ void LldbEngine::refreshLocals(const GdbMi &vars) //const bool partial = response.cookie.toBool(); WatchHandler *handler = watchHandler(); handler->resetValueCache(); - QList<WatchData> list; - //if (!partial) { - list.append(*handler->findData("local")); - list.append(*handler->findData("watch")); - list.append(*handler->findData("tooltip")); - list.append(*handler->findData("return")); - //} + QSet<QByteArray> toDelete; + foreach (WatchItem *item, handler->model()->treeLevelItems<WatchItem *>(2)) + toDelete.insert(item->d.iname); foreach (const GdbMi &child, vars.children()) { - WatchData dummy; - dummy.iname = child["iname"].data(); - GdbMi wname = child["wname"]; - if (wname.isValid()) { - // Happens (only) for watched expressions. - dummy.exp = QByteArray::fromHex(wname.data()); - dummy.name = QString::fromUtf8(dummy.exp); - } else { - dummy.name = child["name"].toUtf8(); - } - parseWatchData(handler->expandedINames(), dummy, child, &list); + WatchItem *item = new WatchItem(child); + handler->insertItem(item); + toDelete.remove(item->d.iname); } - handler->insertData(list); + + handler->purgeOutdatedItems(toDelete); DebuggerToolTipManager::updateEngine(this); } @@ -1055,7 +1000,17 @@ void LldbEngine::refreshStack(const GdbMi &stack) frame.from = item["func"].toUtf8(); frame.line = item["line"].toInt(); frame.address = item["addr"].toAddress(); - frame.usable = QFileInfo(frame.file).isReadable(); + GdbMi usable = item["usable"]; + if (usable.isValid()) + frame.usable = usable.data().toInt(); + else + frame.usable = QFileInfo(frame.file).isReadable(); + if (item["language"].data() == "js" + || frame.file.endsWith(QLatin1String(".js")) + || frame.file.endsWith(QLatin1String(".qml"))) { + frame.language = QmlLanguage; + frame.fixQmlFrame(startParameters()); + } frames.append(frame); } bool canExpand = stack["hasmore"].toInt(); @@ -1085,16 +1040,15 @@ void LldbEngine::setStackPosition(int index) void LldbEngine::refreshRegisters(const GdbMi ®isters) { RegisterHandler *handler = registerHandler(); - Registers regs; foreach (const GdbMi &item, registers.children()) { Register reg; reg.name = item["name"].data(); reg.value = item["value"].data(); - //reg.type = item["type"].data(); - regs.append(reg); + reg.size = item["size"].data().toInt(); + reg.reportedType = item["type"].data(); + handler->updateRegister(reg); } - //handler->setRegisters(registers); - handler->setAndMarkRegisters(regs); + handler->commitUpdates(); } void LldbEngine::refreshThreads(const GdbMi &threads) @@ -1205,7 +1159,7 @@ void LldbEngine::fetchDisassembler(DisassemblerAgent *agent) m_disassemblerAgents.insert(p, id); } const Location &loc = agent->location(); - Command cmd("disassemble"); + DebuggerCommand cmd("disassemble"); cmd.arg("cookie", id); cmd.arg("address", loc.address()); cmd.arg("function", loc.functionName()); @@ -1227,7 +1181,7 @@ void LldbEngine::fetchMemory(MemoryAgent *agent, QObject *editorToken, m_memoryAgents.insert(agent, id); } m_memoryAgentTokens.insert(id, editorToken); - Command cmd("fetchMemory"); + DebuggerCommand cmd("fetchMemory"); cmd.arg("address", addr); cmd.arg("length", length); cmd.arg("cookie", id); @@ -1243,20 +1197,21 @@ void LldbEngine::changeMemory(MemoryAgent *agent, QObject *editorToken, m_memoryAgents.insert(agent, id); m_memoryAgentTokens.insert(id, editorToken); } - Command cmd("writeMemory"); + DebuggerCommand cmd("writeMemory"); cmd.arg("address", addr); cmd.arg("data", data.toHex()); cmd.arg("cookie", id); runCommand(cmd); } -void LldbEngine::setRegisterValue(int regnr, const QString &value) +void LldbEngine::setRegisterValue(const QByteArray &name, const QString &value) { - Register reg = registerHandler()->registers().at(regnr); - runCommand(Command("setRegister").arg("name", reg.name).arg("value", value)); + DebuggerCommand cmd("setRegister"); + cmd.arg("name", name); + cmd.arg("value", value); + runCommand(cmd); } - bool LldbEngine::hasCapability(unsigned cap) const { if (cap & (ReverseSteppingCapability @@ -1308,132 +1263,13 @@ void LldbEngine::notifyEngineRemoteSetupFinished(const RemoteSetupResult &result showMessage(_("ADAPTER START FAILED")); if (!result.reason.isEmpty()) { const QString title = tr("Adapter start failed"); - Core::ICore::showWarningWithOptions(title, result.reason); + ICore::showWarningWithOptions(title, result.reason); } notifyEngineSetupFailed(); return; } } -/////////////////////////////////////////////////////////////////////// -// -// Command -// -/////////////////////////////////////////////////////////////////////// - -const LldbEngine::Command &LldbEngine::Command::argHelper(const char *name, const QByteArray &data) const -{ - args.append('"'); - args.append(name); - args.append("\":"); - args.append(data); - args.append(","); - return *this; -} - -QByteArray LldbEngine::Command::toData(const QList<QByteArray> &value) -{ - QByteArray res; - foreach (const QByteArray &item, value) { - if (!res.isEmpty()) - res.append(','); - res += item; - } - return '[' + res + ']'; -} - -QByteArray LldbEngine::Command::toData(const QHash<QByteArray, QByteArray> &value) -{ - QByteArray res; - QHashIterator<QByteArray, QByteArray> it(value); - while (it.hasNext()) { - it.next(); - if (!res.isEmpty()) - res.append(','); - res += '"' + it.key() + "\":" + it.value(); - } - return '{' + res + '}'; -} - -const LldbEngine::Command &LldbEngine::Command::arg(const char *name, int value) const -{ - return argHelper(name, QByteArray::number(value)); -} - -const LldbEngine::Command &LldbEngine::Command::arg(const char *name, qlonglong value) const -{ - return argHelper(name, QByteArray::number(value)); -} - -const LldbEngine::Command &LldbEngine::Command::arg(const char *name, qulonglong value) const -{ - return argHelper(name, QByteArray::number(value)); -} - -const LldbEngine::Command &LldbEngine::Command::arg(const char *name, const QString &value) const -{ - return arg(name, value.toUtf8().data()); -} - -const LldbEngine::Command &LldbEngine::Command::arg(const char *name, const QByteArray &value) const -{ - return arg(name, value.data()); -} - -const LldbEngine::Command &LldbEngine::Command::arg(const char *name, const char *value) const -{ - args.append('"'); - args.append(name); - args.append("\":\""); - args.append(value); - args.append("\","); - return *this; -} - -const LldbEngine::Command &LldbEngine::Command::arg(const char *value) const -{ - args.append("\""); - args.append(value); - args.append("\","); - return *this; -} - -const LldbEngine::Command &LldbEngine::Command::beginList(const char *name) const -{ - if (name) { - args += '"'; - args += name; - args += "\":"; - } - args += '['; - return *this; -} - -void LldbEngine::Command::endList() const -{ - if (args.endsWith(',')) - args.chop(1); - args += "],"; -} - -const LldbEngine::Command &LldbEngine::Command::beginGroup(const char *name) const -{ - if (name) { - args += '"'; - args += name; - args += "\":"; - } - args += '{'; - return *this; -} - -void LldbEngine::Command::endGroup() const -{ - if (args.endsWith(',')) - args.chop(1); - args += "},"; -} - void LldbEngine::stubStarted() { startLldb(); @@ -1441,7 +1277,7 @@ void LldbEngine::stubStarted() void LldbEngine::stubError(const QString &msg) { - showMessageBox(QMessageBox::Critical, tr("Debugger Error"), msg); + AsynchronousMessageBox::critical(tr("Debugger Error"), msg); } void LldbEngine::stubExited() diff --git a/src/plugins/debugger/lldb/lldbengine.h b/src/plugins/debugger/lldb/lldbengine.h index cb209a79cf..02fef25d6e 100644 --- a/src/plugins/debugger/lldb/lldbengine.h +++ b/src/plugins/debugger/lldb/lldbengine.h @@ -66,33 +66,6 @@ public: ~LldbEngine(); private: - // Convenience struct to build up backend commands. - struct Command - { - Command() {} - Command(const char *f) : function(f) {} - - const Command &arg(const char *name) const; - const Command &arg(const char *name, int value) const; - const Command &arg(const char *name, qlonglong value) const; - const Command &arg(const char *name, qulonglong value) const; - const Command &arg(const char *name, const QString &value) const; - const Command &arg(const char *name, const QByteArray &value) const; - const Command &arg(const char *name, const char *value) const; - const Command &beginList(const char *name = 0) const; - void endList() const; - const Command &beginGroup(const char *name = 0) const; - void endGroup() const; - - static QByteArray toData(const QList<QByteArray> &value); - static QByteArray toData(const QHash<QByteArray, QByteArray> &value); - - QByteArray function; - mutable QByteArray args; - private: - const Command &argHelper(const char *name, const QByteArray &value) const; - }; - // DebuggerEngine implementation void executeStep(); void executeStepOut(); @@ -122,9 +95,12 @@ private: void activateFrame(int index); void selectThread(ThreadId threadId); - bool acceptsBreakpoint(BreakpointModelId id) const; - void attemptBreakpointSynchronization(); - bool attemptBreakpointSynchronizationHelper(Command *command); + // This should be always the last call in a function. + bool stateAcceptsBreakpointChanges() const; + bool acceptsBreakpoint(Breakpoint bp) const; + void insertBreakpoint(Breakpoint bp); + void removeBreakpoint(Breakpoint bp); + void changeBreakpoint(Breakpoint bp); void assignValueInDebugger(const WatchData *data, const QString &expr, const QVariant &value); @@ -143,7 +119,7 @@ private: bool supportsThreads() const { return true; } bool isSynchronous() const { return true; } void updateWatchData(const WatchData &data, const WatchUpdateFlags &flags); - void setRegisterValue(int regnr, const QString &value); + void setRegisterValue(const QByteArray &name, const QString &value); void fetchMemory(Internal::MemoryAgent *, QObject *, quint64 addr, quint64 length); void changeMemory(Internal::MemoryAgent *, QObject *, quint64 addr, const QByteArray &data); @@ -161,7 +137,6 @@ private: Q_SLOT void readLldbStandardOutput(); Q_SLOT void readLldbStandardError(); Q_SLOT void handleResponse(const QByteArray &data); - Q_SLOT void runEngine2(); Q_SLOT void updateAll(); Q_SLOT void updateStack(); Q_SLOT void updateLocals(); @@ -184,7 +159,6 @@ private: void refreshAddedBreakpoint(const GdbMi &bkpts); void refreshChangedBreakpoint(const GdbMi &bkpts); void refreshRemovedBreakpoint(const GdbMi &bkpts); - void runContinuation(const GdbMi &data); void showFullBacktrace(const GdbMi &data); typedef void (LldbEngine::*LldbCommandContinuation)(); @@ -202,9 +176,9 @@ private: void handleChildren(const WatchData &data0, const GdbMi &item, QList<WatchData> *list); - void runCommand(const Command &cmd); + void runCommand(const DebuggerCommand &cmd); void debugLastCommand(); - Command m_lastDebuggableCommand; + DebuggerCommand m_lastDebuggableCommand; QByteArray m_inbuffer; QString m_scriptFileName; diff --git a/src/plugins/debugger/loadcoredialog.cpp b/src/plugins/debugger/loadcoredialog.cpp index d6188aba55..e2b8063a43 100644 --- a/src/plugins/debugger/loadcoredialog.cpp +++ b/src/plugins/debugger/loadcoredialog.cpp @@ -82,14 +82,13 @@ public: QString localFile() const { return m_localFile; } QString remoteFile() const { return m_remoteFile; } -private slots: - void handleSftpOperationFinished(QSsh::SftpJobId, const QString &error); +private: + void handleSftpOperationFinished(SftpJobId, const QString &error); void handleSftpOperationFailed(const QString &errorMessage); void handleConnectionError(const QString &errorMessage); void handleRemoteError(const QString &errorMessage); void selectFile(); -private: QSortFilterProxyModel m_model; SftpFileSystemModel m_fileSystemModel; QTreeView *m_fileSystemView; @@ -128,13 +127,15 @@ SelectRemoteFileDialog::SelectRemoteFileDialog(QWidget *parent) layout->addWidget(m_textBrowser); layout->addWidget(m_buttonBox); - QObject::connect(m_buttonBox, SIGNAL(rejected()), SLOT(reject())); - QObject::connect(m_buttonBox, SIGNAL(accepted()), SLOT(selectFile())); + connect(m_buttonBox, &QDialogButtonBox::rejected, + this, &QDialog::reject); + connect(m_buttonBox, &QDialogButtonBox::accepted, + this, &SelectRemoteFileDialog::selectFile); - connect(&m_fileSystemModel, SIGNAL(sftpOperationFailed(QString)), - SLOT(handleSftpOperationFailed(QString))); - connect(&m_fileSystemModel, SIGNAL(connectionError(QString)), - SLOT(handleConnectionError(QString))); + connect(&m_fileSystemModel, &SftpFileSystemModel::sftpOperationFailed, + this, &SelectRemoteFileDialog::handleSftpOperationFailed); + connect(&m_fileSystemModel, &SftpFileSystemModel::connectionError, + this, &SelectRemoteFileDialog::handleConnectionError); } void SelectRemoteFileDialog::attachToDevice(Kit *k) @@ -143,7 +144,7 @@ void SelectRemoteFileDialog::attachToDevice(Kit *k) QTC_ASSERT(k, return); IDevice::ConstPtr device = DeviceKitInformation::device(k); QTC_ASSERT(device, return); - QSsh::SshConnectionParameters sshParams = device->sshParameters(); + SshConnectionParameters sshParams = device->sshParameters(); m_fileSystemModel.setSshConnection(sshParams); } @@ -159,7 +160,7 @@ void SelectRemoteFileDialog::handleConnectionError(const QString &errorMessage) //reject(); } -void SelectRemoteFileDialog::handleSftpOperationFinished(QSsh::SftpJobId, const QString &error) +void SelectRemoteFileDialog::handleSftpOperationFinished(SftpJobId, const QString &error) { if (error.isEmpty()) { m_textBrowser->append(tr("Download of remote file succeeded.")); @@ -184,8 +185,8 @@ void SelectRemoteFileDialog::selectFile() m_buttonBox->button(QDialogButtonBox::Ok)->setEnabled(false); m_fileSystemView->setEnabled(false); - connect(&m_fileSystemModel, SIGNAL(sftpOperationFinished(QSsh::SftpJobId,QString)), - SLOT(handleSftpOperationFinished(QSsh::SftpJobId,QString))); + connect(&m_fileSystemModel, &SftpFileSystemModel::sftpOperationFinished, + this, &SelectRemoteFileDialog::handleSftpOperationFinished); { QTemporaryFile localFile(QDir::tempPath() + QLatin1String("/remotecore-XXXXXX")); @@ -271,7 +272,7 @@ AttachCoreDialog::AttachCoreDialog(QWidget *parent) d->forceLocalLabel->setBuddy(d->forceLocalCheckBox); d->remoteCoreFileName = new QLineEdit(this); - d->selectRemoteCoreButton = new QPushButton(tr("Browse..."), this); + d->selectRemoteCoreButton = new QPushButton(PathChooser::browseButtonLabel(), this); d->localCoreFileName = new PathChooser(this); d->localCoreFileName->setHistoryCompleter(QLatin1String("Debugger.CoreFile.History")); @@ -323,14 +324,14 @@ AttachCoreDialog::~AttachCoreDialog() int AttachCoreDialog::exec() { - connect(d->selectRemoteCoreButton, SIGNAL(clicked()), SLOT(selectRemoteCoreFile())); - connect(d->remoteCoreFileName, SIGNAL(textChanged(QString)), SLOT(coreFileChanged(QString))); - connect(d->localExecFileName, SIGNAL(changed(QString)), SLOT(changed())); - connect(d->localCoreFileName, SIGNAL(changed(QString)), SLOT(coreFileChanged(QString))); - connect(d->forceLocalCheckBox, SIGNAL(stateChanged(int)), SLOT(changed())); - connect(d->kitChooser, SIGNAL(currentIndexChanged(int)), SLOT(changed())); - connect(d->buttonBox, SIGNAL(rejected()), SLOT(reject())); - connect(d->buttonBox, SIGNAL(accepted()), SLOT(accept())); + connect(d->selectRemoteCoreButton, &QAbstractButton::clicked, this, &AttachCoreDialog::selectRemoteCoreFile); + connect(d->remoteCoreFileName, &QLineEdit::textChanged, this, &AttachCoreDialog::coreFileChanged); + connect(d->localExecFileName, &PathChooser::changed, this, &AttachCoreDialog::changed); + connect(d->localCoreFileName, &PathChooser::changed, this, &AttachCoreDialog::coreFileChanged); + connect(d->forceLocalCheckBox, &QCheckBox::stateChanged, this, &AttachCoreDialog::changed); + connect(d->kitChooser, &KitChooser::currentIndexChanged, this, &AttachCoreDialog::changed); + connect(d->buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject); + connect(d->buttonBox, &QDialogButtonBox::accepted, this, &QDialog::accept); changed(); AttachCoreDialogPrivate::State st = d->getDialogState(*this); @@ -364,7 +365,7 @@ bool AttachCoreDialog::useLocalCoreFile() const void AttachCoreDialog::coreFileChanged(const QString &core) { - if (!Utils::HostOsInfo::isWindowsHost() && QFile::exists(core)) { + if (!HostOsInfo::isWindowsHost() && QFile::exists(core)) { Kit *k = d->kitChooser->currentKit(); QTC_ASSERT(k, return); FileName cmd = DebuggerKitInformation::debuggerCommand(k); @@ -441,7 +442,7 @@ QString AttachCoreDialog::remoteCoreFile() const return d->remoteCoreFileName->text(); } -void AttachCoreDialog::setKitId(Core::Id id) +void AttachCoreDialog::setKitId(Id id) { d->kitChooser->setCurrentKitId(id); } diff --git a/src/plugins/debugger/logwindow.cpp b/src/plugins/debugger/logwindow.cpp index c40b091ec2..3c233dcc5d 100644 --- a/src/plugins/debugger/logwindow.cpp +++ b/src/plugins/debugger/logwindow.cpp @@ -145,27 +145,27 @@ class DebuggerPane : public QPlainTextEdit Q_OBJECT public: - DebuggerPane(QWidget *parent) + DebuggerPane(LogWindow *parent) : QPlainTextEdit(parent) { setFrameStyle(QFrame::NoFrame); m_clearContentsAction = new QAction(this); m_clearContentsAction->setText(tr("Clear Contents")); m_clearContentsAction->setEnabled(true); - connect(m_clearContentsAction, SIGNAL(triggered(bool)), - parent, SLOT(clearContents())); + connect(m_clearContentsAction, &QAction::triggered, + parent, &LogWindow::clearContents); m_saveContentsAction = new QAction(this); m_saveContentsAction->setText(tr("Save Contents")); m_saveContentsAction->setEnabled(true); - connect(m_saveContentsAction, SIGNAL(triggered()), - this, SLOT(saveContents())); + connect(m_saveContentsAction, &QAction::triggered, + this, &DebuggerPane::saveContents); m_reloadDebuggingHelpersAction = new QAction(this); m_reloadDebuggingHelpersAction->setText(tr("Reload Debugging Helpers")); m_reloadDebuggingHelpersAction->setEnabled(true); - connect(m_reloadDebuggingHelpersAction, SIGNAL(triggered()), - this, SLOT(reloadDebuggingHelpers())); + connect(m_reloadDebuggingHelpersAction, &QAction::triggered, + this, &DebuggerPane::reloadDebuggingHelpers); } void contextMenuEvent(QContextMenuEvent *ev) @@ -209,11 +209,10 @@ public: setUndoRedoEnabled(true); } -private slots: +private: void saveContents(); void reloadDebuggingHelpers(); -private: QAction *m_clearContentsAction; QAction *m_saveContentsAction; QAction *m_reloadDebuggingHelpersAction; @@ -239,7 +238,7 @@ class InputPane : public DebuggerPane { Q_OBJECT public: - InputPane(QWidget *parent) + InputPane(LogWindow *parent) : DebuggerPane(parent) { (void) new InputHighlighter(this); @@ -305,7 +304,7 @@ class CombinedPane : public DebuggerPane { Q_OBJECT public: - CombinedPane(QWidget *parent) + CombinedPane(LogWindow *parent) : DebuggerPane(parent) { (void) new OutputHighlighter(this); @@ -354,7 +353,7 @@ LogWindow::LogWindow(QWidget *parent) m_ignoreNextInputEcho = false; - QSplitter *m_splitter = new Core::MiniSplitter(Qt::Horizontal); + auto m_splitter = new Core::MiniSplitter(Qt::Horizontal); m_splitter->setParent(this); // Mixed input/output. @@ -374,25 +373,25 @@ LogWindow::LogWindow(QWidget *parent) m_commandEdit->setFrame(false); m_commandEdit->setHistoryCompleter(QLatin1String("DebuggerInput")); - QToolButton *repeatButton = new QToolButton(this); + auto repeatButton = new QToolButton(this); repeatButton->setIcon(QIcon(QLatin1String(":/debugger/images/debugger_stepover_small.png"))); repeatButton->setIconSize(QSize(12, 12)); repeatButton->setToolTip(tr("Repeat last command for debug reasons.")); - QHBoxLayout *commandBox = new QHBoxLayout; + auto commandBox = new QHBoxLayout; commandBox->addWidget(repeatButton); commandBox->addWidget(new QLabel(tr("Command:"), this)); commandBox->addWidget(m_commandEdit); commandBox->setMargin(2); commandBox->setSpacing(6); - QVBoxLayout *leftBox = new QVBoxLayout; + auto leftBox = new QVBoxLayout; leftBox->addWidget(m_inputText); leftBox->addItem(commandBox); leftBox->setMargin(0); leftBox->setSpacing(0); - QWidget *leftDummy = new QWidget; + auto leftDummy = new QWidget; leftDummy->setLayout(leftBox); m_splitter->addWidget(leftDummy); @@ -400,14 +399,14 @@ LogWindow::LogWindow(QWidget *parent) m_splitter->setStretchFactor(0, 1); m_splitter->setStretchFactor(1, 3); - QVBoxLayout *layout = new QVBoxLayout(this); + auto layout = new QVBoxLayout(this); layout->setMargin(0); layout->setSpacing(0); layout->addWidget(m_splitter); layout->addWidget(new Core::FindToolBarPlaceHolder(this)); setLayout(layout); - Aggregation::Aggregate *aggregate = new Aggregation::Aggregate; + auto aggregate = new Aggregation::Aggregate; aggregate->add(m_combinedText); aggregate->add(new Core::BaseTextFind(m_combinedText)); @@ -419,14 +418,15 @@ LogWindow::LogWindow(QWidget *parent) SIGNAL(statusMessageRequested(QString,int))); connect(m_inputText, SIGNAL(commandSelected(int)), m_combinedText, SLOT(gotoResult(int))); - connect(m_commandEdit, SIGNAL(returnPressed()), - SLOT(sendCommand())); + connect(m_commandEdit, &QLineEdit::returnPressed, + this, &LogWindow::sendCommand); connect(m_inputText, SIGNAL(executeLineRequested()), SLOT(executeLine())); - connect(repeatButton, SIGNAL(clicked()), - SLOT(repeatLastCommand())); + connect(repeatButton, &QAbstractButton::clicked, + this, &LogWindow::repeatLastCommand); - connect(&m_outputTimer, SIGNAL(timeout()), SLOT(doOutput())); + connect(&m_outputTimer, &QTimer::timeout, + this, &LogWindow::doOutput); setMinimumHeight(60); } diff --git a/src/plugins/debugger/memoryagent.cpp b/src/plugins/debugger/memoryagent.cpp index 4eede82072..18835e2363 100644 --- a/src/plugins/debugger/memoryagent.cpp +++ b/src/plugins/debugger/memoryagent.cpp @@ -40,13 +40,12 @@ #include <coreplugin/coreconstants.h> #include <coreplugin/editormanager/ieditor.h> #include <coreplugin/editormanager/editormanager.h> +#include <coreplugin/messagebox.h> #include <utils/qtcassert.h> #include <extensionsystem/pluginmanager.h> #include <extensionsystem/invoker.h> -#include <QMessageBox> - #include <cstring> using namespace Core; @@ -136,15 +135,12 @@ void MemoryAgent::connectBinEditorWidget(QWidget *w) connect(w, SIGNAL(addWatchpointRequested(quint64,uint)), SLOT(handleWatchpointRequest(quint64,uint))); } -bool MemoryAgent::doCreateBinEditor(quint64 addr, unsigned flags, - const QList<MemoryMarkup> &ml, const QPoint &pos, - QString title, QWidget *parent) +bool MemoryAgent::doCreateBinEditor(const MemoryViewSetupData &data) { - const bool readOnly = (flags & DebuggerEngine::MemoryReadOnly) != 0; - if (title.isEmpty()) - title = tr("Memory at 0x%1").arg(addr, 0, 16); + const bool readOnly = (data.flags & DebuggerEngine::MemoryReadOnly) != 0; + QString title = data.title.isEmpty() ? tr("Memory at 0x%1").arg(data.startAddress, 0, 16) : data.title; // Separate view? - if (flags & DebuggerEngine::MemoryView) { + if (data.flags & DebuggerEngine::MemoryView) { // Ask BIN editor plugin for factory service and have it create a bin editor widget. QWidget *binEditor = 0; if (QObject *factory = ExtensionSystem::PluginManager::getObjectByClassName(QLatin1String("BinEditor::BinEditorWidgetFactory"))) @@ -156,24 +152,22 @@ bool MemoryAgent::doCreateBinEditor(quint64 addr, unsigned flags, MemoryView::setBinEditorNewWindowRequestAllowed(binEditor, true); MemoryView *topLevel = 0; // Memory view tracking register value, providing its own updating mechanism. - if (flags & DebuggerEngine::MemoryTrackRegister) { - RegisterMemoryView *rmv = new RegisterMemoryView(binEditor, parent); - rmv->init(m_engine->registerHandler(), int(addr)); - topLevel = rmv; + if (data.flags & DebuggerEngine::MemoryTrackRegister) { + topLevel = new RegisterMemoryView(binEditor, data.startAddress, data.registerName, m_engine->registerHandler(), data.parent); } else { // Ordinary memory view - MemoryView::setBinEditorMarkup(binEditor, ml); - MemoryView::setBinEditorRange(binEditor, addr, MemoryAgent::DataRange, MemoryAgent::BinBlockSize); - topLevel = new MemoryView(binEditor, parent); + MemoryView::setBinEditorMarkup(binEditor, data.markup); + MemoryView::setBinEditorRange(binEditor, data.startAddress, MemoryAgent::DataRange, MemoryAgent::BinBlockSize); + topLevel = new MemoryView(binEditor, data.parent); topLevel->setWindowTitle(title); } m_views << topLevel; - topLevel->move(pos); + topLevel->move(data.pos); topLevel->show(); return true; } // Editor: Register tracking not supported. - QTC_ASSERT(!(flags & DebuggerEngine::MemoryTrackRegister), return false); + QTC_ASSERT(!(data.flags & DebuggerEngine::MemoryTrackRegister), return false); if (!title.endsWith(QLatin1Char('$'))) title.append(QLatin1String(" $")); IEditor *editor = EditorManager::openEditorWithContents( @@ -186,18 +180,16 @@ bool MemoryAgent::doCreateBinEditor(quint64 addr, unsigned flags, connectBinEditorWidget(editorBinEditor); MemoryView::setBinEditorReadOnly(editorBinEditor, readOnly); MemoryView::setBinEditorNewWindowRequestAllowed(editorBinEditor, true); - MemoryView::setBinEditorRange(editorBinEditor, addr, MemoryAgent::DataRange, MemoryAgent::BinBlockSize); - MemoryView::setBinEditorMarkup(editorBinEditor, ml); + MemoryView::setBinEditorRange(editorBinEditor, data.startAddress, MemoryAgent::DataRange, MemoryAgent::BinBlockSize); + MemoryView::setBinEditorMarkup(editorBinEditor, data.markup); m_editors << editor; return true; } -void MemoryAgent::createBinEditor(quint64 addr, unsigned flags, - const QList<MemoryMarkup> &ml, const QPoint &pos, - const QString &title, QWidget *parent) +void MemoryAgent::createBinEditor(const MemoryViewSetupData &data) { - if (!doCreateBinEditor(addr, flags, ml, pos, title, parent)) - showMessageBox(QMessageBox::Warning, + if (!doCreateBinEditor(data)) + AsynchronousMessageBox::warning( tr("No Memory Viewer Available"), tr("The memory contents cannot be shown as no viewer plugin " "for binary data has been loaded.")); @@ -205,7 +197,9 @@ void MemoryAgent::createBinEditor(quint64 addr, unsigned flags, void MemoryAgent::createBinEditor(quint64 addr) { - createBinEditor(addr, 0, QList<MemoryMarkup>(), QPoint(), QString(), 0); + MemoryViewSetupData data; + data.startAddress = addr; + createBinEditor(data); } void MemoryAgent::fetchLazyData(quint64 block) @@ -240,7 +234,7 @@ void MemoryAgent::handleWatchpointRequest(quint64 address, uint size) void MemoryAgent::updateContents() { - foreach (const QPointer<Core::IEditor> &e, m_editors) + foreach (const QPointer<IEditor> &e, m_editors) if (e) MemoryView::binEditorUpdateContents(e->widget()); // Update all views except register views, which trigger on diff --git a/src/plugins/debugger/memoryagent.h b/src/plugins/debugger/memoryagent.h index 5967c38c2b..33386f126e 100644 --- a/src/plugins/debugger/memoryagent.h +++ b/src/plugins/debugger/memoryagent.h @@ -34,21 +34,20 @@ #include "debuggerconstants.h" #include <QObject> +#include <QPoint> #include <QPointer> #include <QColor> -QT_FORWARD_DECLARE_CLASS(QPoint) - namespace Core { class IEditor; } namespace ProjectExplorer { class Abi; } namespace Debugger { +namespace Internal { class DebuggerEngine; - -namespace Internal { class MemoryView; + class MemoryMarkup { public: @@ -62,6 +61,20 @@ public: QString toolTip; }; +class MemoryViewSetupData +{ +public: + MemoryViewSetupData() : parent(0), startAddress(0), flags(0) {} + + QWidget *parent; + quint64 startAddress; + QByteArray registerName; + unsigned flags; + QList<Internal::MemoryMarkup> markup; + QPoint pos; + QString title; +}; + class MemoryAgent : public QObject { Q_OBJECT @@ -80,9 +93,7 @@ public: public slots: // Called by engine to create a new view. - void createBinEditor(quint64 startAddr, unsigned flags, - const QList<MemoryMarkup> &ml, const QPoint &pos, - const QString &title, QWidget *parent); + void createBinEditor(const MemoryViewSetupData &data); void createBinEditor(quint64 startAddr); // Called by engine to create a tooltip. void addLazyData(QObject *editorToken, quint64 addr, const QByteArray &data); @@ -101,9 +112,7 @@ private slots: private: void connectBinEditorWidget(QWidget *w); - bool doCreateBinEditor(quint64 startAddr, unsigned flags, - const QList<MemoryMarkup> &ml, const QPoint &pos, - QString title, QWidget *parent); + bool doCreateBinEditor(const MemoryViewSetupData &data); QList<QPointer<Core::IEditor> > m_editors; QList<QPointer<MemoryView> > m_views; diff --git a/src/plugins/debugger/memoryview.cpp b/src/plugins/debugger/memoryview.cpp index aefb1e469d..a7850668b0 100644 --- a/src/plugins/debugger/memoryview.cpp +++ b/src/plugins/debugger/memoryview.cpp @@ -138,24 +138,27 @@ void MemoryView::setMarkup(const QList<MemoryMarkup> &m) \sa Debugger::Internal::MemoryAgent, Debugger::DebuggerEngine */ -RegisterMemoryView::RegisterMemoryView(QWidget *binEditor, QWidget *parent) : +RegisterMemoryView::RegisterMemoryView(QWidget *binEditor, quint64 addr, + const QByteArray ®Name, + RegisterHandler *handler, QWidget *parent) : MemoryView(binEditor, parent), - m_registerIndex(0), m_registerAddress(0) + m_registerName(regName), m_registerAddress(addr) { + connect(handler, &QAbstractItemModel::modelReset, this, &QWidget::close); + connect(handler, &RegisterHandler::registerChanged, this, &RegisterMemoryView::onRegisterChanged); + updateContents(); } -void RegisterMemoryView::slotRegisterSet(const QModelIndex &index) +void RegisterMemoryView::onRegisterChanged(const QByteArray &name, quint64 value) { - if (m_registerIndex != index.row()) - return; - const QVariant newAddressV = index.data(Qt::EditRole); - if (newAddressV.type() == QVariant::ULongLong) - setRegisterAddress(newAddressV.toULongLong()); + if (name == m_registerName) + setRegisterAddress(value); } -QString RegisterMemoryView::title(const QString ®isterName, quint64 a) +QString RegisterMemoryView::title(const QByteArray ®isterName, quint64 a) { - return tr("Memory at Register \"%1\" (0x%2)").arg(registerName).arg(a, 0, 16); + return tr("Memory at Register \"%1\" (0x%2)") + .arg(QString::fromUtf8(registerName)).arg(a, 0, 16); } void RegisterMemoryView::setRegisterAddress(quint64 v) @@ -171,25 +174,13 @@ void RegisterMemoryView::setRegisterAddress(quint64 v) setMarkup(registerMarkup(v, m_registerName)); } -QList<MemoryMarkup> RegisterMemoryView::registerMarkup(quint64 a, const QString &name) +QList<MemoryMarkup> RegisterMemoryView::registerMarkup(quint64 a, const QByteArray ®Name) { QList<MemoryMarkup> result; result.push_back(MemoryMarkup(a, 1, QColor(Qt::blue).lighter(), - tr("Register \"%1\"").arg(name))); + tr("Register \"%1\"").arg(QString::fromUtf8(regName)))); return result; } -void RegisterMemoryView::init(RegisterHandler *h, int registerIndex) -{ - m_registerIndex = registerIndex; - m_registerName = QString::fromLatin1(h->registerAt(registerIndex).name); - // Known issue: CDB might reset the model by changing the special - // registers it reports. - connect(h, SIGNAL(modelReset()), this, SLOT(close())); - connect(h, SIGNAL(registerSet(QModelIndex)), - this, SLOT(slotRegisterSet(QModelIndex))); - setRegisterAddress(h->registerAt(m_registerIndex).editValue().toULongLong()); -} - } // namespace Internal } // namespace Debugger diff --git a/src/plugins/debugger/memoryview.h b/src/plugins/debugger/memoryview.h index a88d6742d4..aa81540ecb 100644 --- a/src/plugins/debugger/memoryview.h +++ b/src/plugins/debugger/memoryview.h @@ -69,21 +69,17 @@ class RegisterMemoryView : public MemoryView { Q_OBJECT public: - explicit RegisterMemoryView(QWidget *binEditor, QWidget *parent = 0); + explicit RegisterMemoryView(QWidget *binEditor, quint64 addr, const QByteArray ®Name, + RegisterHandler *rh, QWidget *parent = 0); - void init(RegisterHandler *rh, int index); - - static QList<MemoryMarkup> registerMarkup(quint64 a, const QString &name); - static QString title(const QString ®isterName, quint64 a = 0); - -private slots: - void slotRegisterSet(const QModelIndex &index); + static QList<MemoryMarkup> registerMarkup(quint64 a, const QByteArray ®Name); + static QString title(const QByteArray ®isterName, quint64 a = 0); private: + void onRegisterChanged(const QByteArray &name, quint64 value); void setRegisterAddress(quint64 v); - int m_registerIndex; - QString m_registerName; + QByteArray m_registerName; quint64 m_registerAddress; }; diff --git a/src/plugins/debugger/moduleshandler.cpp b/src/plugins/debugger/moduleshandler.cpp index f404d561f3..3e793a424b 100644 --- a/src/plugins/debugger/moduleshandler.cpp +++ b/src/plugins/debugger/moduleshandler.cpp @@ -31,7 +31,9 @@ #include "moduleshandler.h" #include <utils/qtcassert.h> +#include <utils/treemodel.h> +#include <QCoreApplication> #include <QDebug> #include <QSortFilterProxyModel> @@ -46,211 +48,109 @@ using namespace Utils; namespace Debugger { namespace Internal { -class ModulesModel : public QAbstractItemModel +class ModuleItem : public TreeItem { public: - explicit ModulesModel(QObject *parent) - : QAbstractItemModel(parent) - {} + QVariant data(int column, int role) const; - int columnCount(const QModelIndex &parent) const - { return parent.isValid() ? 0 : 5; } - int rowCount(const QModelIndex &parent) const - { return parent.isValid() ? 0 : m_modules.size(); } - QModelIndex parent(const QModelIndex &) const { return QModelIndex(); } - QModelIndex index(int row, int column, const QModelIndex &) const - { return createIndex(row, column); } - QVariant headerData(int section, Qt::Orientation orientation, int role) const; - QVariant data(const QModelIndex &index, int role) const; - - void clearModel(); - void removeModule(const QString &modulePath); - void setModules(const Modules &modules); - void updateModule(const Module &module); - - int indexOfModule(const QString &modulePath) const; - - Modules m_modules; +public: + Module module; + bool updated; }; - -QVariant ModulesModel::headerData(int section, - Qt::Orientation orientation, int role) const +QVariant ModuleItem::data(int column, int role) const { - if (orientation == Qt::Horizontal && role == Qt::DisplayRole) { - static QString headers[] = { - ModulesHandler::tr("Module Name") + QLatin1String(" "), - ModulesHandler::tr("Module Path") + QLatin1String(" "), - ModulesHandler::tr("Symbols Read") + QLatin1String(" "), - ModulesHandler::tr("Symbols Type") + QLatin1String(" "), - ModulesHandler::tr("Start Address") + QLatin1String(" "), - ModulesHandler::tr("End Address") + QLatin1String(" ") - }; - return headers[section]; - } - return QVariant(); -} - -QVariant ModulesModel::data(const QModelIndex &index, int role) const -{ - int row = index.row(); - if (row < 0 || row >= m_modules.size()) - return QVariant(); - - const Module &module = m_modules.at(row); - - switch (index.column()) { - case 0: - if (role == Qt::DisplayRole) - return module.moduleName; - // FIXME: add icons - //if (role == Qt::DecorationRole) - // return module.symbolsRead ? icon2 : icon; - break; - case 1: - if (role == Qt::DisplayRole) - return module.modulePath; - if (role == Qt::ToolTipRole) { - QString msg; - if (!module.elfData.buildId.isEmpty()) - msg += QString::fromLatin1("Build Id: " + module.elfData.buildId); - if (!module.elfData.debugLink.isEmpty()) - msg += QString::fromLatin1("Debug Link: " + module.elfData.debugLink); - return msg; + switch (column) { + case 0: + if (role == Qt::DisplayRole) + return module.moduleName; + // FIXME: add icons + //if (role == Qt::DecorationRole) + // return module.symbolsRead ? icon2 : icon; + break; + case 1: + if (role == Qt::DisplayRole) + return module.modulePath; + if (role == Qt::ToolTipRole) { + QString msg; + if (!module.elfData.buildId.isEmpty()) + msg += QString::fromLatin1("Build Id: " + module.elfData.buildId); + if (!module.elfData.debugLink.isEmpty()) + msg += QString::fromLatin1("Debug Link: " + module.elfData.debugLink); + return msg; + } + break; + case 2: + if (role == Qt::DisplayRole) + switch (module.symbolsRead) { + case Module::UnknownReadState: return ModulesHandler::tr("Unknown"); + case Module::ReadFailed: return ModulesHandler::tr("No"); + case Module::ReadOk: return ModulesHandler::tr("Yes"); } - break; - case 2: - if (role == Qt::DisplayRole) - switch (module.symbolsRead) { - case Module::UnknownReadState: return ModulesHandler::tr("Unknown"); - case Module::ReadFailed: return ModulesHandler::tr("No"); - case Module::ReadOk: return ModulesHandler::tr("Yes"); - } - break; - case 3: - if (role == Qt::DisplayRole) - switch (module.elfData.symbolsType) { - case UnknownSymbols: - return ModulesHandler::tr("Unknown"); - case NoSymbols: - return ModulesHandler::tr("None"); - case PlainSymbols: - return ModulesHandler::tr("Plain"); - case FastSymbols: - return ModulesHandler::tr("Fast"); - case LinkedSymbols: - return ModulesHandler::tr("debuglnk"); - case BuildIdSymbols: - return ModulesHandler::tr("buildid"); - } - else if (role == Qt::ToolTipRole) - switch (module.elfData.symbolsType) { - case UnknownSymbols: - return ModulesHandler::tr( - "It is unknown whether this module contains debug " - "information.\nUse \"Examine Symbols\" from the " - "context menu to initiate a check."); - case NoSymbols: - return ModulesHandler::tr( - "This module neither contains nor references debug " - "information.\nStepping into the module or setting " - "breakpoints by file and line will not work."); - case PlainSymbols: - return ModulesHandler::tr( - "This module contains debug information.\nStepping " - "into the module or setting breakpoints by file and " - "line is expected to work."); - case FastSymbols: - return ModulesHandler::tr( - "This module contains debug information.\nStepping " - "into the module or setting breakpoints by file and " - "line is expected to work."); - case LinkedSymbols: - case BuildIdSymbols: - return ModulesHandler::tr( - "This module does not contain debug information " - "itself, but contains a reference to external " - "debug information."); - } - break; - case 4: - if (role == Qt::DisplayRole) - if (module.startAddress) - return QString(QLatin1String("0x") - + QString::number(module.startAddress, 16)); - break; - case 5: - if (role == Qt::DisplayRole) { - if (module.endAddress) - return QString(QLatin1String("0x") - + QString::number(module.endAddress, 16)); - //: End address of loaded module - return ModulesHandler::tr("<unknown>", "address"); + break; + case 3: + if (role == Qt::DisplayRole) + switch (module.elfData.symbolsType) { + case UnknownSymbols: + return ModulesHandler::tr("Unknown"); + case NoSymbols: + return ModulesHandler::tr("None"); + case PlainSymbols: + return ModulesHandler::tr("Plain"); + case FastSymbols: + return ModulesHandler::tr("Fast"); + case LinkedSymbols: + return ModulesHandler::tr("debuglnk"); + case BuildIdSymbols: + return ModulesHandler::tr("buildid"); } - break; - } - return QVariant(); -} - -void ModulesModel::setModules(const Modules &m) -{ - beginResetModel(); - m_modules = m; - endResetModel(); -} - -void ModulesModel::clearModel() -{ - if (!m_modules.isEmpty()) { - beginResetModel(); - m_modules.clear(); - endResetModel(); - } -} - -int ModulesModel::indexOfModule(const QString &modulePath) const -{ - // Recent modules are more likely to be unloaded first. - for (int i = m_modules.size() - 1; i >= 0; i--) - if (m_modules.at(i).modulePath == modulePath) - return i; - return -1; -} - -void ModulesModel::removeModule(const QString &modulePath) -{ - const int row = indexOfModule(modulePath); - QTC_ASSERT(row != -1, return); - beginRemoveRows(QModelIndex(), row, row); - m_modules.remove(row); - endRemoveRows(); -} - -void ModulesModel::updateModule(const Module &module) -{ - const int row = indexOfModule(module.modulePath); - const QString path = module.modulePath; - if (path.isEmpty()) - return; - try { // MinGW occasionallly throws std::bad_alloc. - ElfReader reader(path); - ElfData elfData = reader.readHeaders(); - - if (row == -1) { - const int n = m_modules.size(); - beginInsertRows(QModelIndex(), n, n); - m_modules.push_back(module); - m_modules.back().elfData = elfData; - endInsertRows(); - } else { - m_modules[row] = module; - m_modules[row].elfData = elfData; - dataChanged(index(row, 0, QModelIndex()), index(row, 4, QModelIndex())); + else if (role == Qt::ToolTipRole) + switch (module.elfData.symbolsType) { + case UnknownSymbols: + return ModulesHandler::tr( + "It is unknown whether this module contains debug " + "information.\nUse \"Examine Symbols\" from the " + "context menu to initiate a check."); + case NoSymbols: + return ModulesHandler::tr( + "This module neither contains nor references debug " + "information.\nStepping into the module or setting " + "breakpoints by file and line will not work."); + case PlainSymbols: + return ModulesHandler::tr( + "This module contains debug information.\nStepping " + "into the module or setting breakpoints by file and " + "line is expected to work."); + case FastSymbols: + return ModulesHandler::tr( + "This module contains debug information.\nStepping " + "into the module or setting breakpoints by file and " + "line is expected to work."); + case LinkedSymbols: + case BuildIdSymbols: + return ModulesHandler::tr( + "This module does not contain debug information " + "itself, but contains a reference to external " + "debug information."); + } + break; + case 4: + if (role == Qt::DisplayRole) + if (module.startAddress) + return QString(QLatin1String("0x") + + QString::number(module.startAddress, 16)); + break; + case 5: + if (role == Qt::DisplayRole) { + if (module.endAddress) + return QString(QLatin1String("0x") + + QString::number(module.endAddress, 16)); + //: End address of loaded module + return ModulesHandler::tr("<unknown>", "address"); } - } catch(...) { - qWarning("%s: An exception occurred while reading module '%s'", - Q_FUNC_INFO, qPrintable(module.modulePath)); + break; } + return QVariant(); } ////////////////////////////////////////////////////////////////// @@ -259,11 +159,32 @@ void ModulesModel::updateModule(const Module &module) // ////////////////////////////////////////////////////////////////// +static ModuleItem *moduleFromPath(TreeItem *root, const QString &modulePath) +{ + // Recent modules are more likely to be unloaded first. + for (int i = root->rowCount(); --i >= 0; ) { + auto item = static_cast<ModuleItem *>(root->child(i)); + if (item->module.modulePath == modulePath) + return item; + } + return 0; +} + ModulesHandler::ModulesHandler(DebuggerEngine *engine) { m_engine = engine; - m_model = new ModulesModel(this); + + QString pad = QLatin1String(" "); + m_model = new TreeModel(this); m_model->setObjectName(QLatin1String("ModulesModel")); + m_model->setHeader(QStringList() + << ModulesHandler::tr("Module Name") + pad + << ModulesHandler::tr("Module Path") + pad + << ModulesHandler::tr("Symbols Read") + pad + << ModulesHandler::tr("Symbols Type") + pad + << ModulesHandler::tr("Start Address") + pad + << ModulesHandler::tr("End Address") + pad); + m_proxyModel = new QSortFilterProxyModel(this); m_proxyModel->setObjectName(QLatin1String("ModulesProxyModel")); m_proxyModel->setSourceModel(m_model); @@ -276,27 +197,65 @@ QAbstractItemModel *ModulesHandler::model() const void ModulesHandler::removeAll() { - m_model->clearModel(); + m_model->removeItems(); +} + +Modules ModulesHandler::modules() const +{ + Modules mods; + TreeItem *root = m_model->rootItem(); + for (int i = root->rowCount(); --i >= 0; ) + mods.append(static_cast<ModuleItem *>(root->child(i))->module); + return mods; } void ModulesHandler::removeModule(const QString &modulePath) { - m_model->removeModule(modulePath); + if (ModuleItem *item = moduleFromPath(m_model->rootItem(), modulePath)) + m_model->removeItem(item); } void ModulesHandler::updateModule(const Module &module) { - m_model->updateModule(module); + const QString path = module.modulePath; + if (path.isEmpty()) + return; + + ModuleItem *item = moduleFromPath(m_model->rootItem(), path); + if (item) { + item->module = module; + } else { + item = new ModuleItem; + item->module = module; + m_model->rootItem()->appendChild(item); + } + + try { // MinGW occasionallly throws std::bad_alloc. + ElfReader reader(path); + item->module.elfData = reader.readHeaders(); + item->update(); + } catch(...) { + qWarning("%s: An exception occurred while reading module '%s'", + Q_FUNC_INFO, qPrintable(module.modulePath)); + } + item->updated = true; } -void ModulesHandler::setModules(const Modules &modules) +void ModulesHandler::beginUpdateAll() { - m_model->setModules(modules); + TreeItem *root = m_model->rootItem(); + for (int i = root->rowCount(); --i >= 0; ) + static_cast<ModuleItem *>(root->child(i))->updated = false; } -Modules ModulesHandler::modules() const +void ModulesHandler::endUpdateAll() { - return m_model->m_modules; + TreeItem *root = m_model->rootItem(); + for (int i = root->rowCount(); --i >= 0; ) { + auto item = static_cast<ModuleItem *>(root->child(i)); + if (!item->updated) + m_model->removeItem(item); + } } } // namespace Internal diff --git a/src/plugins/debugger/moduleshandler.h b/src/plugins/debugger/moduleshandler.h index 61b68e7ac3..bad6d1c879 100644 --- a/src/plugins/debugger/moduleshandler.h +++ b/src/plugins/debugger/moduleshandler.h @@ -32,6 +32,7 @@ #define DEBUGGER_MODULESHANDLER_H #include <utils/elfreader.h> +#include <utils/treemodel.h> QT_BEGIN_NAMESPACE class QAbstractItemModel; @@ -39,12 +40,9 @@ class QSortFilterProxyModel; QT_END_NAMESPACE namespace Debugger { - -class DebuggerEngine; - namespace Internal { -class ModulesModel; +class DebuggerEngine; ////////////////////////////////////////////////////////////////// // @@ -111,7 +109,6 @@ public: typedef QVector<Module> Modules; - ////////////////////////////////////////////////////////////////// // // ModulesHandler @@ -127,16 +124,18 @@ public: QAbstractItemModel *model() const; - void setModules(const Modules &modules); void removeModule(const QString &modulePath); void updateModule(const Module &module); - Modules modules() const; + void beginUpdateAll(); + void endUpdateAll(); + void removeAll(); + Modules modules() const; private: DebuggerEngine *m_engine; - ModulesModel *m_model; + Utils::TreeModel *m_model; QSortFilterProxyModel *m_proxyModel; }; diff --git a/src/plugins/debugger/moduleswindow.cpp b/src/plugins/debugger/moduleswindow.cpp index 19ebd36362..e9605587d6 100644 --- a/src/plugins/debugger/moduleswindow.cpp +++ b/src/plugins/debugger/moduleswindow.cpp @@ -57,8 +57,8 @@ ModulesTreeView::ModulesTreeView() { setSortingEnabled(true); - connect(this, SIGNAL(activated(QModelIndex)), - SLOT(moduleActivated(QModelIndex))); + connect(this, &QAbstractItemView::activated, + this, &ModulesTreeView::moduleActivated); } void ModulesTreeView::moduleActivated(const QModelIndex &index) diff --git a/src/plugins/debugger/pdb/pdbengine.cpp b/src/plugins/debugger/pdb/pdbengine.cpp index 559b2a8f8a..a6a2acb226 100644 --- a/src/plugins/debugger/pdb/pdbengine.cpp +++ b/src/plugins/debugger/pdb/pdbengine.cpp @@ -52,6 +52,7 @@ #include <texteditor/texteditor.h> #include <coreplugin/idocument.h> #include <coreplugin/icore.h> +#include <coreplugin/messagebox.h> #include <QDateTime> #include <QDebug> @@ -61,7 +62,6 @@ #include <QVariant> #include <QApplication> -#include <QMessageBox> #include <QToolTip> @@ -157,17 +157,17 @@ void PdbEngine::setupEngine() m_pdb = _("python"); showMessage(_("STARTING PDB ") + m_pdb); - connect(&m_pdbProc, SIGNAL(error(QProcess::ProcessError)), - SLOT(handlePdbError(QProcess::ProcessError))); - connect(&m_pdbProc, SIGNAL(finished(int,QProcess::ExitStatus)), - SLOT(handlePdbFinished(int,QProcess::ExitStatus))); - connect(&m_pdbProc, SIGNAL(readyReadStandardOutput()), - SLOT(readPdbStandardOutput())); - connect(&m_pdbProc, SIGNAL(readyReadStandardError()), - SLOT(readPdbStandardError())); + connect(&m_pdbProc, static_cast<void(QProcess::*)(QProcess::ProcessError)>(&QProcess::error), + this, &PdbEngine::handlePdbError); + connect(&m_pdbProc, static_cast<void(QProcess::*)(int,QProcess::ExitStatus)>(&QProcess::finished), + this, &PdbEngine::handlePdbFinished); + connect(&m_pdbProc, &QProcess::readyReadStandardOutput, + this, &PdbEngine::readPdbStandardOutput); + connect(&m_pdbProc, &QProcess::readyReadStandardError, + this, &PdbEngine::readPdbStandardError); - connect(this, SIGNAL(outputReady(QByteArray)), - SLOT(handleOutput2(QByteArray)), Qt::QueuedConnection); + connect(this, &PdbEngine::outputReady, + this, &PdbEngine::handleOutput2, Qt::QueuedConnection); // We will stop immediately, so setup a proper callback. PdbCommand cmd; @@ -198,7 +198,7 @@ void PdbEngine::setupInferior() QString fileName = QFileInfo(startParameters().executable).absoluteFilePath(); QFile scriptFile(fileName); if (!scriptFile.open(QIODevice::ReadOnly|QIODevice::Text)) { - showMessageBox(QMessageBox::Critical, tr("Python Error"), + Core::AsynchronousMessageBox::critical(tr("Python Error"), _("Cannot open script file %1:\n%2"). arg(fileName, scriptFile.errorString())); notifyInferiorSetupFailed(); @@ -327,34 +327,31 @@ void PdbEngine::selectThread(ThreadId threadId) Q_UNUSED(threadId) } -bool PdbEngine::acceptsBreakpoint(BreakpointModelId id) const +bool PdbEngine::acceptsBreakpoint(Breakpoint bp) const { - const QString fileName = breakHandler()->fileName(id); + const QString fileName = bp.fileName(); return fileName.endsWith(QLatin1String(".py")); } -void PdbEngine::insertBreakpoint(BreakpointModelId id) +void PdbEngine::insertBreakpoint(Breakpoint bp) { - BreakHandler *handler = breakHandler(); - QTC_CHECK(handler->state(id) == BreakpointInsertRequested); - handler->notifyBreakpointInsertProceeding(id); + QTC_CHECK(bp.state() == BreakpointInsertRequested); + bp.notifyBreakpointInsertProceeding(); QByteArray loc; - if (handler->type(id) == BreakpointByFunction) - loc = handler->functionName(id).toLatin1(); + if (bp.type() == BreakpointByFunction) + loc = bp.functionName().toLatin1(); else - loc = handler->fileName(id).toLocal8Bit() + ':' - + QByteArray::number(handler->lineNumber(id)); + loc = bp.fileName().toLocal8Bit() + ':' + + QByteArray::number(bp.lineNumber()); - postCommand("break " + loc, CB(handleBreakInsert), QVariant(id)); + postCommand("break " + loc, CB(handleBreakInsert), QVariant::fromValue(bp)); } void PdbEngine::handleBreakInsert(const PdbResponse &response) { //qDebug() << "BP RESPONSE: " << response.data; // "Breakpoint 1 at /pdb/math.py:10" - BreakpointModelId id(response.cookie.toInt()); - BreakHandler *handler = breakHandler(); QTC_ASSERT(response.data.startsWith("Breakpoint "), return); int pos1 = response.data.indexOf(" at "); QTC_ASSERT(pos1 != -1, return); @@ -366,22 +363,21 @@ void PdbEngine::handleBreakInsert(const PdbResponse &response) br.id = BreakpointResponseId(bpnr); br.fileName = _(file); br.lineNumber = line.toInt(); - handler->setResponse(id, br); - QTC_CHECK(!handler->needsChange(id)); - handler->notifyBreakpointInsertOk(id); + Breakpoint bp = response.cookie.value<Breakpoint>(); + bp.setResponse(br); + QTC_CHECK(!bp.needsChange()); + bp.notifyBreakpointInsertOk(); } -void PdbEngine::removeBreakpoint(BreakpointModelId id) +void PdbEngine::removeBreakpoint(Breakpoint bp) { - BreakHandler *handler = breakHandler(); - QTC_CHECK(handler->state(id) == BreakpointRemoveRequested); - handler->notifyBreakpointRemoveProceeding(id); - BreakpointResponse br = handler->response(id); - showMessage(_("DELETING BP %1 IN %2").arg(br.id.toString()) - .arg(handler->fileName(id))); + QTC_CHECK(bp.state() == BreakpointRemoveRequested); + bp.notifyBreakpointRemoveProceeding(); + BreakpointResponse br = bp.response(); + showMessage(_("DELETING BP %1 IN %2").arg(br.id.toString()).arg(bp.fileName())); postCommand("clear " + br.id.toByteArray()); // Pretend it succeeds without waiting for response. - handler->notifyBreakpointRemoveOk(id); + bp.notifyBreakpointRemoveOk(); } void PdbEngine::loadSymbols(const QString &moduleName) @@ -402,7 +398,8 @@ void PdbEngine::handleListModules(const PdbResponse &response) { GdbMi out; out.fromString(response.data.trimmed()); - Modules modules; + ModulesHandler *handler = modulesHandler(); + handler->beginUpdateAll(); foreach (const GdbMi &item, out.children()) { Module module; module.moduleName = _(item["name"].data()); @@ -417,9 +414,9 @@ void PdbEngine::handleListModules(const PdbResponse &response) path = _("(builtin)"); } module.modulePath = path; - modules.append(module); + handler->updateModule(module); } - modulesHandler()->setModules(modules); + handler->endUpdateAll(); } void PdbEngine::requestModuleSymbols(const QString &moduleName) @@ -555,8 +552,8 @@ void PdbEngine::handlePdbError(QProcess::ProcessError error) default: //setState(EngineShutdownRequested, true); m_pdbProc.kill(); - showMessageBox(QMessageBox::Critical, tr("Pdb I/O Error"), - errorMessage(error)); + Core::AsynchronousMessageBox::critical(tr("Pdb I/O Error"), + errorMessage(error)); break; } } @@ -728,7 +725,7 @@ void PdbEngine::updateLocals() options.chop(1); postCommand("qdebug('" + options + "','" - + handler->expansionRequests() + "','" +// + handler->expansionRequests() + "','" + handler->typeFormatRequests() + "','" + handler->individualFormatRequests() + "','" + watchers.toHex() + "')", CB(handleListLocals)); @@ -803,16 +800,19 @@ void PdbEngine::handleListLocals(const PdbResponse &response) //qDebug() << "ALL: " << all.toString(); //GdbMi data = all.findChild("data"); - QList<WatchData> list; WatchHandler *handler = watchHandler(); + + QSet<QByteArray> toDelete; + foreach (WatchItem *item, handler->model()->treeLevelItems<WatchItem *>(2)) + toDelete.insert(item->d.iname); + foreach (const GdbMi &child, all.children()) { - WatchData dummy; - dummy.iname = child["iname"].data(); - dummy.name = _(child["name"].data()); - //qDebug() << "CHILD: " << child.toString(); - parseWatchData(handler->expandedINames(), dummy, child, &list); + WatchItem *item = new WatchItem(child); + handler->insertItem(item); + toDelete.remove(item->d.iname); } - handler->insertData(list); + + handler->purgeOutdatedItems(toDelete); } bool PdbEngine::hasCapability(unsigned cap) const @@ -825,6 +825,5 @@ DebuggerEngine *createPdbEngine(const DebuggerStartParameters &startParameters) return new PdbEngine(startParameters); } - } // namespace Internal } // namespace Debugger diff --git a/src/plugins/debugger/pdb/pdbengine.h b/src/plugins/debugger/pdb/pdbengine.h index 2a1cd55ced..41dc68a119 100644 --- a/src/plugins/debugger/pdb/pdbengine.h +++ b/src/plugins/debugger/pdb/pdbengine.h @@ -89,9 +89,9 @@ private: void activateFrame(int index); void selectThread(ThreadId threadId); - bool acceptsBreakpoint(BreakpointModelId id) const; - void insertBreakpoint(BreakpointModelId id); - void removeBreakpoint(BreakpointModelId id); + bool acceptsBreakpoint(Breakpoint bp) const; + void insertBreakpoint(Breakpoint bp); + void removeBreakpoint(Breakpoint bp); void assignValueInDebugger(const WatchData *data, const QString &expr, const QVariant &value); @@ -116,11 +116,11 @@ private: QString errorMessage(QProcess::ProcessError error) const; bool hasCapability(unsigned cap) const; - Q_SLOT void handlePdbFinished(int, QProcess::ExitStatus status); - Q_SLOT void handlePdbError(QProcess::ProcessError error); - Q_SLOT void readPdbStandardOutput(); - Q_SLOT void readPdbStandardError(); - Q_SLOT void handleOutput2(const QByteArray &data); + void handlePdbFinished(int, QProcess::ExitStatus status); + void handlePdbError(QProcess::ProcessError error); + void readPdbStandardOutput(); + void readPdbStandardError(); + void handleOutput2(const QByteArray &data); void handleResponse(const QByteArray &ba); void handleOutput(const QByteArray &data); void updateAll(); diff --git a/src/plugins/debugger/qml/baseqmldebuggerclient.cpp b/src/plugins/debugger/qml/baseqmldebuggerclient.cpp index c1b443b985..5a7f9287a1 100644 --- a/src/plugins/debugger/qml/baseqmldebuggerclient.cpp +++ b/src/plugins/debugger/qml/baseqmldebuggerclient.cpp @@ -29,6 +29,7 @@ ****************************************************************************/ #include "baseqmldebuggerclient.h" +#include <debugger/breakhandler.h> #include <utils/qtcassert.h> @@ -52,7 +53,7 @@ BaseQmlDebuggerClient::~BaseQmlDebuggerClient() delete d; } -bool BaseQmlDebuggerClient::acceptsBreakpoint(const BreakpointModelId &/*id*/) +bool BaseQmlDebuggerClient::acceptsBreakpoint(Breakpoint /*bp*/) { return false; } diff --git a/src/plugins/debugger/qml/baseqmldebuggerclient.h b/src/plugins/debugger/qml/baseqmldebuggerclient.h index cb0d63b139..409a3dc9c5 100644 --- a/src/plugins/debugger/qml/baseqmldebuggerclient.h +++ b/src/plugins/debugger/qml/baseqmldebuggerclient.h @@ -67,11 +67,11 @@ public: virtual void activateFrame(int index) = 0; - virtual bool acceptsBreakpoint(const BreakpointModelId &id); - virtual void insertBreakpoint(const BreakpointModelId &id, int adjustedLine, + virtual bool acceptsBreakpoint(Breakpoint bp); + virtual void insertBreakpoint(Breakpoint bp, int adjustedLine, int adjustedColumn = -1) = 0; - virtual void removeBreakpoint(const BreakpointModelId &id) = 0; - virtual void changeBreakpoint(const BreakpointModelId &id) = 0; + virtual void removeBreakpoint(Breakpoint bp) = 0; + virtual void changeBreakpoint(Breakpoint bp) = 0; virtual void synchronizeBreakpoints() = 0; virtual void assignValueInDebugger(const WatchData *data, diff --git a/src/plugins/debugger/qml/qmladapter.cpp b/src/plugins/debugger/qml/qmladapter.cpp index 2557753a4e..73f29d0400 100644 --- a/src/plugins/debugger/qml/qmladapter.cpp +++ b/src/plugins/debugger/qml/qmladapter.cpp @@ -57,21 +57,25 @@ QmlAdapter::QmlAdapter(DebuggerEngine *engine, QObject *parent) { m_connectionTimer.setInterval(4000); m_connectionTimer.setSingleShot(true); - connect(&m_connectionTimer, SIGNAL(timeout()), SLOT(checkConnectionState())); + connect(&m_connectionTimer, &QTimer::timeout, this, &QmlAdapter::checkConnectionState); m_conn = new QmlDebugConnection(this); - connect(m_conn, SIGNAL(stateMessage(QString)), SLOT(showConnectionStateMessage(QString))); - connect(m_conn, SIGNAL(errorMessage(QString)), SLOT(showConnectionErrorMessage(QString))); - connect(m_conn, SIGNAL(error(QDebugSupport::Error)), - SLOT(connectionErrorOccurred(QDebugSupport::Error))); - connect(m_conn, SIGNAL(opened()), &m_connectionTimer, SLOT(stop())); - connect(m_conn, SIGNAL(opened()), SIGNAL(connected())); - connect(m_conn, SIGNAL(closed()), SIGNAL(disconnected())); + connect(m_conn, &QmlDebugConnection::stateMessage, + this, &QmlAdapter::showConnectionStateMessage); + connect(m_conn, &QmlDebugConnection::errorMessage, + this, &QmlAdapter::showConnectionErrorMessage); + connect(m_conn, &QmlDebugConnection::error, + this, &QmlAdapter::connectionErrorOccurred); + connect(m_conn, &QmlDebugConnection::opened, + &m_connectionTimer, &QTimer::stop); + connect(m_conn, &QmlDebugConnection::opened, + this, &QmlAdapter::connected); + connect(m_conn, &QmlDebugConnection::closed, + this, &QmlAdapter::disconnected); createDebuggerClients(); m_msgClient = new QDebugMessageClient(m_conn); - connect(m_msgClient, SIGNAL(newState(QmlDebug::QmlDebugClient::State)), - this, SLOT(clientStateChanged(QmlDebug::QmlDebugClient::State))); + connect(m_msgClient, &QDebugMessageClient::newState, this, &QmlAdapter::clientStateChanged); } @@ -125,7 +129,7 @@ void QmlAdapter::clientStateChanged(QmlDebugClient::State state) void QmlAdapter::debugClientStateChanged(QmlDebugClient::State state) { - if (state != QmlDebug::QmlDebugClient::Enabled) + if (state != QmlDebugClient::Enabled) return; QmlDebugClient *client = qobject_cast<QmlDebugClient*>(sender()); QTC_ASSERT(client, return); @@ -150,16 +154,16 @@ bool QmlAdapter::isConnected() const void QmlAdapter::createDebuggerClients() { QScriptDebuggerClient *debugClient1 = new QScriptDebuggerClient(m_conn); - connect(debugClient1, SIGNAL(newState(QmlDebug::QmlDebugClient::State)), - this, SLOT(clientStateChanged(QmlDebug::QmlDebugClient::State))); - connect(debugClient1, SIGNAL(newState(QmlDebug::QmlDebugClient::State)), - this, SLOT(debugClientStateChanged(QmlDebug::QmlDebugClient::State))); + connect(debugClient1, &QScriptDebuggerClient::newState, + this, &QmlAdapter::clientStateChanged); + connect(debugClient1, &QScriptDebuggerClient::newState, + this, &QmlAdapter::debugClientStateChanged); QmlV8DebuggerClient *debugClient2 = new QmlV8DebuggerClient(m_conn); - connect(debugClient2, SIGNAL(newState(QmlDebug::QmlDebugClient::State)), - this, SLOT(clientStateChanged(QmlDebug::QmlDebugClient::State))); - connect(debugClient2, SIGNAL(newState(QmlDebug::QmlDebugClient::State)), - this, SLOT(debugClientStateChanged(QmlDebug::QmlDebugClient::State))); + connect(debugClient2, &QmlV8DebuggerClient::newState, + this, &QmlAdapter::clientStateChanged); + connect(debugClient2, &QmlV8DebuggerClient::newState, + this, &QmlAdapter::debugClientStateChanged); m_debugClients.insert(debugClient1->name(),debugClient1); m_debugClients.insert(debugClient2->name(),debugClient2); @@ -206,21 +210,21 @@ QDebugMessageClient *QmlAdapter::messageClient() const } void QmlAdapter::logServiceStateChange(const QString &service, float version, - QmlDebug::QmlDebugClient::State newState) + QmlDebugClient::State newState) { switch (newState) { - case QmlDebug::QmlDebugClient::Unavailable: { + case QmlDebugClient::Unavailable: { showConnectionStateMessage(_("Status of \"%1\" Version: %2 changed to 'unavailable'."). arg(service).arg(QString::number(version))); break; } - case QmlDebug::QmlDebugClient::Enabled: { + case QmlDebugClient::Enabled: { showConnectionStateMessage(_("Status of \"%1\" Version: %2 changed to 'enabled'."). arg(service).arg(QString::number(version))); break; } - case QmlDebug::QmlDebugClient::NotConnected: { + case QmlDebugClient::NotConnected: { showConnectionStateMessage(_("Status of \"%1\" Version: %2 changed to 'not connected'."). arg(service).arg(QString::number(version))); break; diff --git a/src/plugins/debugger/qml/qmladapter.h b/src/plugins/debugger/qml/qmladapter.h index bba06ea8e4..e9f3936878 100644 --- a/src/plugins/debugger/qml/qmladapter.h +++ b/src/plugins/debugger/qml/qmladapter.h @@ -43,11 +43,10 @@ class QDebugMessageClient; } namespace Debugger { - -class DebuggerEngine; - namespace Internal { + class BaseQmlDebuggerClient; +class DebuggerEngine; class QmlAdapterPrivate; class QmlAdapter : public QObject diff --git a/src/plugins/debugger/qml/qmlcppengine.cpp b/src/plugins/debugger/qml/qmlcppengine.cpp index f6813113be..1d01a19020 100644 --- a/src/plugins/debugger/qml/qmlcppengine.cpp +++ b/src/plugins/debugger/qml/qmlcppengine.cpp @@ -30,8 +30,10 @@ #include "qmlcppengine.h" #include "qmlengine.h" + #include <debugger/debuggerruncontrol.h> #include <debugger/debuggerstartparameters.h> +#include <debugger/breakhandler.h> #include <debugger/stackhandler.h> #include <debugger/watchhandler.h> @@ -184,9 +186,9 @@ void QmlCppEngine::reloadFullStack() m_cppEngine->reloadFullStack(); } -void QmlCppEngine::setRegisterValue(int regnr, const QString &value) +void QmlCppEngine::setRegisterValue(const QByteArray &name, const QString &value) { - m_cppEngine->setRegisterValue(regnr, value); + m_cppEngine->setRegisterValue(name, value); } @@ -244,10 +246,10 @@ void QmlCppEngine::attemptBreakpointSynchronization() } } -bool QmlCppEngine::acceptsBreakpoint(BreakpointModelId id) const +bool QmlCppEngine::acceptsBreakpoint(Breakpoint bp) const { - return m_cppEngine->acceptsBreakpoint(id) - || m_qmlEngine->acceptsBreakpoint(id); + return m_cppEngine->acceptsBreakpoint(bp) + || m_qmlEngine->acceptsBreakpoint(bp); } void QmlCppEngine::selectThread(ThreadId threadId) @@ -285,26 +287,10 @@ void QmlCppEngine::detachDebugger() void QmlCppEngine::executeStep() { -// TODO: stepping from qml -> cpp requires more thought -// if (m_activeEngine == m_qmlEngine) { -// QTC_CHECK(m_cppEngine->state() == InferiorRunOk); -// if (m_cppEngine->setupQmlStep(true)) -// return; // Wait for callback to readyToExecuteQmlStep() -// } else { -// notifyInferiorRunRequested(); -// m_cppEngine->executeStep(); -// } - notifyInferiorRunRequested(); m_activeEngine->executeStep(); } -void QmlCppEngine::readyToExecuteQmlStep() -{ - notifyInferiorRunRequested(); - m_qmlEngine->executeStep(); -} - void QmlCppEngine::executeStepOut() { notifyInferiorRunRequested(); @@ -424,7 +410,6 @@ void QmlCppEngine::notifyInferiorShutdownOk() void QmlCppEngine::notifyInferiorSetupOk() { EDEBUG("\nMASTER INFERIOR SETUP OK"); - emit aboutToNotifyInferiorSetupOk(); DebuggerEngine::notifyInferiorSetupOk(); } @@ -774,6 +759,18 @@ void QmlCppEngine::resetLocation() DebuggerEngine::resetLocation(); } +void QmlCppEngine::reloadDebuggingHelpers() +{ + if (m_cppEngine) + m_cppEngine->reloadDebuggingHelpers(); +} + +void QmlCppEngine::debugLastCommand() +{ + if (m_cppEngine) + m_cppEngine->debugLastCommand(); +} + DebuggerEngine *QmlCppEngine::cppEngine() const { return m_cppEngine; diff --git a/src/plugins/debugger/qml/qmlcppengine.h b/src/plugins/debugger/qml/qmlcppengine.h index 665d343119..898803ee69 100644 --- a/src/plugins/debugger/qml/qmlcppengine.h +++ b/src/plugins/debugger/qml/qmlcppengine.h @@ -68,7 +68,7 @@ public: void reloadSourceFiles(); void reloadFullStack(); - void setRegisterValue(int regnr, const QString &value); + void setRegisterValue(const QByteArray &name, const QString &value); bool hasCapability(unsigned cap) const; bool isSynchronous() const; @@ -78,7 +78,7 @@ public: void updateAll(); void attemptBreakpointSynchronization(); - bool acceptsBreakpoint(BreakpointModelId id) const; + bool acceptsBreakpoint(Breakpoint bp) const; void selectThread(ThreadId threadId); void assignValueInDebugger(const WatchData *data, @@ -97,6 +97,8 @@ public: protected: void detachDebugger(); + void reloadDebuggingHelpers(); + void debugLastCommand(); void executeStep(); void executeStepOut(); void executeNext(); @@ -128,15 +130,11 @@ protected: void notifyInferiorSetupOk(); void notifyEngineRemoteServerRunning(const QByteArray &, int pid); -signals: - void aboutToNotifyInferiorSetupOk(); - private: void engineStateChanged(DebuggerState newState); void setState(DebuggerState newState, bool forced = false); void slaveEngineStateChanged(DebuggerEngine *slaveEngine, DebuggerState state); - void readyToExecuteQmlStep(); void setActiveEngine(DebuggerEngine *engine); private: diff --git a/src/plugins/debugger/qml/qmlengine.cpp b/src/plugins/debugger/qml/qmlengine.cpp index 4924fce386..8f8422d14d 100644 --- a/src/plugins/debugger/qml/qmlengine.cpp +++ b/src/plugins/debugger/qml/qmlengine.cpp @@ -249,9 +249,9 @@ public: quint32 *column; }; -QmlJS::ConsoleManagerInterface *qmlConsoleManager() +ConsoleManagerInterface *qmlConsoleManager() { - return QmlJS::ConsoleManagerInterface::instance(); + return ConsoleManagerInterface::instance(); } /////////////////////////////////////////////////////////////////////// @@ -351,12 +351,6 @@ QmlEngine::~QmlEngine() Core::EditorManager::closeDocuments(documentsToClose.toList()); } -void QmlEngine::notifyInferiorSetupOk() -{ - emit aboutToNotifyInferiorSetupOk(); - DebuggerEngine::notifyInferiorSetupOk(); -} - void QmlEngine::setupInferior() { QTC_ASSERT(state() == InferiorSetupRequested, qDebug() << state()); @@ -803,21 +797,20 @@ void QmlEngine::selectThread(ThreadId threadId) Q_UNUSED(threadId) } -void QmlEngine::insertBreakpoint(BreakpointModelId id) +void QmlEngine::insertBreakpoint(Breakpoint bp) { - BreakHandler *handler = breakHandler(); - BreakpointState state = handler->state(id); - QTC_ASSERT(state == BreakpointInsertRequested, qDebug() << id << this << state); - handler->notifyBreakpointInsertProceeding(id); + BreakpointState state = bp.state(); + QTC_ASSERT(state == BreakpointInsertRequested, qDebug() << bp << this << state); + bp.notifyBreakpointInsertProceeding(); - const BreakpointParameters ¶ms = handler->breakpointData(id); + const BreakpointParameters ¶ms = bp.parameters(); quint32 line = params.lineNumber; quint32 column = 0; if (params.type == BreakpointByFileAndLine) { bool valid = false; if (!adjustBreakpointLineAndColumn(params.fileName, &line, &column, &valid)) { - pendingBreakpoints.insertMulti(params.fileName, id); + pendingBreakpoints.insertMulti(params.fileName, bp); return; } if (!valid) @@ -825,65 +818,61 @@ void QmlEngine::insertBreakpoint(BreakpointModelId id) } if (m_adapter.activeDebuggerClient()) { - m_adapter.activeDebuggerClient()->insertBreakpoint(id, line, column); + m_adapter.activeDebuggerClient()->insertBreakpoint(bp, line, column); } else { foreach (BaseQmlDebuggerClient *client, m_adapter.debuggerClients()) { - client->insertBreakpoint(id, line, column); + client->insertBreakpoint(bp, line, column); } } } -void QmlEngine::removeBreakpoint(BreakpointModelId id) +void QmlEngine::removeBreakpoint(Breakpoint bp) { - BreakHandler *handler = breakHandler(); - - const BreakpointParameters ¶ms = handler->breakpointData(id); + const BreakpointParameters ¶ms = bp.parameters(); if (params.type == BreakpointByFileAndLine && pendingBreakpoints.contains(params.fileName)) { - QHash<QString, BreakpointModelId>::iterator i = - pendingBreakpoints.find(params.fileName); - while (i != pendingBreakpoints.end() && i.key() == params.fileName) { - if (i.value() == id) { - pendingBreakpoints.erase(i); + auto it = pendingBreakpoints.find(params.fileName); + while (it != pendingBreakpoints.end() && it.key() == params.fileName) { + if (it.value() == bp.id()) { + pendingBreakpoints.erase(it); return; } - ++i; + ++it; } } - BreakpointState state = handler->state(id); - QTC_ASSERT(state == BreakpointRemoveRequested, qDebug() << id << this << state); - handler->notifyBreakpointRemoveProceeding(id); + BreakpointState state = bp.state(); + QTC_ASSERT(state == BreakpointRemoveRequested, qDebug() << bp << this << state); + bp.notifyBreakpointRemoveProceeding(); if (m_adapter.activeDebuggerClient()) { - m_adapter.activeDebuggerClient()->removeBreakpoint(id); + m_adapter.activeDebuggerClient()->removeBreakpoint(bp); } else { foreach (BaseQmlDebuggerClient *client, m_adapter.debuggerClients()) { - client->removeBreakpoint(id); + client->removeBreakpoint(bp); } } - if (handler->state(id) == BreakpointRemoveProceeding) - handler->notifyBreakpointRemoveOk(id); + if (bp.state() == BreakpointRemoveProceeding) + bp.notifyBreakpointRemoveOk(); } -void QmlEngine::changeBreakpoint(BreakpointModelId id) +void QmlEngine::changeBreakpoint(Breakpoint bp) { - BreakHandler *handler = breakHandler(); - BreakpointState state = handler->state(id); - QTC_ASSERT(state == BreakpointChangeRequested, qDebug() << id << this << state); - handler->notifyBreakpointChangeProceeding(id); + BreakpointState state = bp.state(); + QTC_ASSERT(state == BreakpointChangeRequested, qDebug() << bp << this << state); + bp.notifyBreakpointChangeProceeding(); if (m_adapter.activeDebuggerClient()) { - m_adapter.activeDebuggerClient()->changeBreakpoint(id); + m_adapter.activeDebuggerClient()->changeBreakpoint(bp); } else { foreach (BaseQmlDebuggerClient *client, m_adapter.debuggerClients()) { - client->changeBreakpoint(id); + client->changeBreakpoint(bp); } } - if (handler->state(id) == BreakpointChangeProceeding) - handler->notifyBreakpointChangeOk(id); + if (bp.state() == BreakpointChangeProceeding) + bp.notifyBreakpointChangeOk(); } void QmlEngine::attemptBreakpointSynchronization() @@ -896,26 +885,26 @@ void QmlEngine::attemptBreakpointSynchronization() BreakHandler *handler = breakHandler(); DebuggerEngine *bpOwner = isSlaveEngine() ? masterEngine() : this; - foreach (BreakpointModelId id, handler->unclaimedBreakpointIds()) { + foreach (Breakpoint bp, handler->unclaimedBreakpoints()) { // Take ownership of the breakpoint. Requests insertion. - if (acceptsBreakpoint(id)) - handler->setEngine(id, bpOwner); + if (acceptsBreakpoint(bp)) + bp.setEngine(bpOwner); } - foreach (BreakpointModelId id, handler->engineBreakpointIds(bpOwner)) { - switch (handler->state(id)) { + foreach (Breakpoint bp, handler->engineBreakpoints(bpOwner)) { + switch (bp.state()) { case BreakpointNew: // Should not happen once claimed. QTC_CHECK(false); continue; case BreakpointInsertRequested: - insertBreakpoint(id); + insertBreakpoint(bp); continue; case BreakpointChangeRequested: - changeBreakpoint(id); + changeBreakpoint(bp); continue; case BreakpointRemoveRequested: - removeBreakpoint(id); + removeBreakpoint(bp); continue; case BreakpointChangeProceeding: case BreakpointInsertProceeding: @@ -924,7 +913,7 @@ void QmlEngine::attemptBreakpointSynchronization() case BreakpointDead: continue; } - QTC_ASSERT(false, qDebug() << "UNKNOWN STATE" << id << state()); + QTC_ASSERT(false, qDebug() << "UNKNOWN STATE" << bp << state()); } DebuggerEngine::attemptBreakpointSynchronization(); @@ -938,9 +927,9 @@ void QmlEngine::attemptBreakpointSynchronization() } } -bool QmlEngine::acceptsBreakpoint(BreakpointModelId id) const +bool QmlEngine::acceptsBreakpoint(Breakpoint bp) const { - if (!breakHandler()->breakpointData(id).isCppBreakpoint()) + if (!bp.parameters().isCppBreakpoint()) return true; //If it is a Cpp Breakpoint query if the type can be also handled by the debugger client @@ -949,7 +938,7 @@ bool QmlEngine::acceptsBreakpoint(BreakpointModelId id) const //This is because the older client does not support BreakpointOnQmlSignalHandler bool acceptBreakpoint = false; if (m_adapter.activeDebuggerClient()) - acceptBreakpoint = m_adapter.activeDebuggerClient()->acceptsBreakpoint(id); + acceptBreakpoint = m_adapter.activeDebuggerClient()->acceptsBreakpoint(bp); return acceptBreakpoint; } @@ -1052,7 +1041,7 @@ void QmlEngine::synchronizeWatchers() } } -QmlJS::ConsoleItem *constructLogItemTree(QmlJS::ConsoleItem *parent, +ConsoleItem *constructLogItemTree(ConsoleItem *parent, const QVariant &result, const QString &key = QString()) { @@ -1146,14 +1135,14 @@ void QmlEngine::disconnected() notifyInferiorExited(); } -void QmlEngine::documentUpdated(QmlJS::Document::Ptr doc) +void QmlEngine::documentUpdated(Document::Ptr doc) { QString fileName = doc->fileName(); if (pendingBreakpoints.contains(fileName)) { - QList<BreakpointModelId> ids = pendingBreakpoints.values(fileName); + QList<Breakpoint> bps = pendingBreakpoints.values(fileName); pendingBreakpoints.remove(fileName); - foreach (const BreakpointModelId &id, ids) - insertBreakpoint(id); + foreach (const Breakpoint bp, bps) + insertBreakpoint(bp); } } @@ -1178,7 +1167,7 @@ void QmlEngine::updateCurrentContext() synchronizeWatchers(); - QmlJS::ConsoleManagerInterface *consoleManager = qmlConsoleManager(); + ConsoleManagerInterface *consoleManager = qmlConsoleManager(); if (consoleManager) consoleManager->setContext(tr("Context:") + QLatin1Char(' ') + context); } diff --git a/src/plugins/debugger/qml/qmlengine.h b/src/plugins/debugger/qml/qmlengine.h index 9b8b9987bf..baddc4ae65 100644 --- a/src/plugins/debugger/qml/qmlengine.h +++ b/src/plugins/debugger/qml/qmlengine.h @@ -60,7 +60,6 @@ public: DebuggerEngine *masterEngine = 0); ~QmlEngine(); - void notifyInferiorSetupOk(); void notifyEngineRemoteServerRunning(const QByteArray &, int pid); void notifyEngineRemoteSetupFinished(const RemoteSetupResult &result); @@ -85,12 +84,11 @@ public: void updateScriptSource(const QString &fileName, int lineOffset, int columnOffset, const QString &source); - void insertBreakpoint(BreakpointModelId id); + void insertBreakpoint(Breakpoint bp); signals: void tooltipRequested(const QPoint &mousePos, TextEditor::TextEditorWidget *editorWidget, int cursorPos); - void aboutToNotifyInferiorSetupOk(); private slots: void disconnected(); @@ -142,9 +140,9 @@ private: void selectThread(ThreadId threadId); void attemptBreakpointSynchronization(); - void removeBreakpoint(BreakpointModelId id); - void changeBreakpoint(BreakpointModelId id); - bool acceptsBreakpoint(BreakpointModelId id) const; + void removeBreakpoint(Breakpoint bp); + void changeBreakpoint(Breakpoint bp); + bool acceptsBreakpoint(Breakpoint bp) const; void assignValueInDebugger(const WatchData *data, const QString &expr, const QVariant &value); @@ -192,7 +190,7 @@ private: QHash<QString, QTextDocument*> m_sourceDocuments; QHash<QString, QWeakPointer<TextEditor::BaseTextEditor> > m_sourceEditors; InteractiveInterpreter m_interpreter; - QHash<QString,BreakpointModelId> pendingBreakpoints; + QHash<QString,Breakpoint> pendingBreakpoints; QList<quint32> queryIds; bool m_retryOnConnectFail; bool m_automaticConnect; diff --git a/src/plugins/debugger/qml/qmlinspectoradapter.cpp b/src/plugins/debugger/qml/qmlinspectoradapter.cpp index 3c711f98e7..08edb3588b 100644 --- a/src/plugins/debugger/qml/qmlinspectoradapter.cpp +++ b/src/plugins/debugger/qml/qmlinspectoradapter.cpp @@ -299,7 +299,7 @@ void QmlInspectorAdapter::createPreviewForEditor(Core::IEditor *newEditor) != QmlJSEditor::Constants::C_QMLJSEDITOR_ID) return; - QString filename = newEditor->document()->filePath(); + QString filename = newEditor->document()->filePath().toString(); QmlJS::ModelManagerInterface *modelManager = QmlJS::ModelManagerInterface::instance(); if (modelManager) { @@ -330,7 +330,7 @@ void QmlInspectorAdapter::createPreviewForEditor(Core::IEditor *newEditor) connect(preview, SIGNAL(reloadRequest()), this, SLOT(onReload())); - m_textPreviews.insert(newEditor->document()->filePath(), preview); + m_textPreviews.insert(newEditor->document()->filePath().toString(), preview); preview->associateEditor(newEditor); preview->updateDebugIds(); } @@ -340,7 +340,7 @@ void QmlInspectorAdapter::createPreviewForEditor(Core::IEditor *newEditor) void QmlInspectorAdapter::removePreviewForEditor(Core::IEditor *editor) { if (QmlLiveTextPreview *preview - = m_textPreviews.value(editor->document()->filePath())) { + = m_textPreviews.value(editor->document()->filePath().toString())) { preview->unassociateEditor(editor); } } @@ -364,7 +364,7 @@ void QmlInspectorAdapter::updatePendingPreviewDocuments(QmlJS::Document::Ptr doc Core::IEditor *editor = editors.takeFirst(); createPreviewForEditor(editor); QmlLiveTextPreview *preview - = m_textPreviews.value(editor->document()->filePath()); + = m_textPreviews.value(editor->document()->filePath().toString()); foreach (Core::IEditor *editor, editors) preview->associateEditor(editor); } @@ -460,7 +460,7 @@ void QmlInspectorAdapter::initializePreviews() QList<Core::IEditor *> editors = Core::DocumentModel::editorsForDocument(document); createPreviewForEditor(editors.takeFirst()); QmlLiveTextPreview *preview - = m_textPreviews.value(document->filePath()); + = m_textPreviews.value(document->filePath().toString()); foreach (Core::IEditor *editor, editors) preview->associateEditor(editor); } diff --git a/src/plugins/debugger/qml/qmlinspectoradapter.h b/src/plugins/debugger/qml/qmlinspectoradapter.h index 6a481dd926..a39f196aba 100644 --- a/src/plugins/debugger/qml/qmlinspectoradapter.h +++ b/src/plugins/debugger/qml/qmlinspectoradapter.h @@ -47,11 +47,9 @@ class FileReference; } namespace Debugger { - -class DebuggerEngine; - namespace Internal { +class DebuggerEngine; class WatchTreeView; class QmlAdapter; class QmlInspectorAgent; diff --git a/src/plugins/debugger/qml/qmlinspectoragent.cpp b/src/plugins/debugger/qml/qmlinspectoragent.cpp index 4bf64ed312..0e34026b37 100644 --- a/src/plugins/debugger/qml/qmlinspectoragent.cpp +++ b/src/plugins/debugger/qml/qmlinspectoragent.cpp @@ -37,11 +37,11 @@ #include <debugger/watchhandler.h> #include <qmldebug/qmldebugconstants.h> +#include <utils/fileutils.h> #include <utils/qtcassert.h> #include <utils/savedaction.h> #include <QElapsedTimer> -#include <QFileInfo> #include <QLoggingCategory> using namespace QmlDebug; @@ -68,7 +68,8 @@ QmlInspectorAgent::QmlInspectorAgent(DebuggerEngine *engine, QObject *parent) SIGNAL(valueChanged(QVariant)), SLOT(updateState())); m_delayQueryTimer.setSingleShot(true); m_delayQueryTimer.setInterval(100); - connect(&m_delayQueryTimer, SIGNAL(timeout()), SLOT(queryEngineContext())); + connect(&m_delayQueryTimer, &QTimer::timeout, + this, &QmlInspectorAgent::queryEngineContext); } quint32 QmlInspectorAgent::queryExpressionResult(int debugId, @@ -395,14 +396,14 @@ void QmlInspectorAgent::setEngineClient(BaseEngineDebugClient *client) m_engineClient = client; if (m_engineClient) { - connect(m_engineClient, SIGNAL(newState(QmlDebug::QmlDebugClient::State)), - this, SLOT(updateState())); - connect(m_engineClient, SIGNAL(result(quint32,QVariant,QByteArray)), - this, SLOT(onResult(quint32,QVariant,QByteArray))); - connect(m_engineClient, SIGNAL(newObject(int,int,int)), - this, SLOT(newObject(int,int,int))); - connect(m_engineClient, SIGNAL(valueChanged(int,QByteArray,QVariant)), - this, SLOT(onValueChanged(int,QByteArray,QVariant))); + connect(m_engineClient, &BaseEngineDebugClient::newState, + this, &QmlInspectorAgent::updateState); + connect(m_engineClient, &BaseEngineDebugClient::result, + this, &QmlInspectorAgent::onResult); + connect(m_engineClient, &BaseEngineDebugClient::newObject, + this, &QmlInspectorAgent::newObject); + connect(m_engineClient, &BaseEngineDebugClient::valueChanged, + this, &QmlInspectorAgent::onValueChanged); } updateState(); @@ -583,7 +584,7 @@ void QmlInspectorAgent::fetchContextObjectsForLocation(const QString &file, log(LogSend, QString::fromLatin1("FETCH_OBJECTS_FOR_LOCATION %1:%2:%3").arg(file) .arg(QString::number(lineNumber)).arg(QString::number(columnNumber))); - quint32 queryId = m_engineClient->queryObjectsForLocation(QFileInfo(file).fileName(), + quint32 queryId = m_engineClient->queryObjectsForLocation(Utils::FileName::fromString(file).fileName(), lineNumber, columnNumber); qCDebug(qmlInspectorLog) << __FUNCTION__ << '(' << file << ':' << lineNumber << ':' << columnNumber << ')' << " - query id" << queryId; diff --git a/src/plugins/debugger/qml/qmlinspectoragent.h b/src/plugins/debugger/qml/qmlinspectoragent.h index 3c19a19c4a..3c01307f15 100644 --- a/src/plugins/debugger/qml/qmlinspectoragent.h +++ b/src/plugins/debugger/qml/qmlinspectoragent.h @@ -37,11 +37,9 @@ #include <qmldebug/baseenginedebugclient.h> namespace Debugger { - -class DebuggerEngine; - namespace Internal { +class DebuggerEngine; class WatchData; //map <filename, editorRevision> -> <lineNumber, columnNumber> -> debugId diff --git a/src/plugins/debugger/qml/qmllivetextpreview.cpp b/src/plugins/debugger/qml/qmllivetextpreview.cpp index 6877d373bd..80ef6220c7 100644 --- a/src/plugins/debugger/qml/qmllivetextpreview.cpp +++ b/src/plugins/debugger/qml/qmllivetextpreview.cpp @@ -346,8 +346,8 @@ void MapObjectWithDebugReference::process(UiObjectBinding *ast) /*! * Manages a Qml/JS document for the inspector */ -QmlLiveTextPreview::QmlLiveTextPreview(const QmlJS::Document::Ptr &doc, - const QmlJS::Document::Ptr &initDoc, +QmlLiveTextPreview::QmlLiveTextPreview(const Document::Ptr &doc, + const Document::Ptr &initDoc, QmlInspectorAdapter *inspectorAdapter, QObject *parent) : QObject(parent) @@ -362,8 +362,8 @@ QmlLiveTextPreview::QmlLiveTextPreview(const QmlJS::Document::Ptr &doc, { QTC_CHECK(doc->fileName() == initDoc->fileName()); - QmlJS::ModelManagerInterface *modelManager - = QmlJS::ModelManagerInterface::instance(); + ModelManagerInterface *modelManager + = ModelManagerInterface::instance(); if (modelManager) { connect(modelManager, SIGNAL(documentChangedOnDisk(QmlJS::Document::Ptr)), SLOT(documentChanged(QmlJS::Document::Ptr))); @@ -424,7 +424,7 @@ void QmlLiveTextPreview::unassociateEditor(Core::IEditor *oldEditor) } } -void QmlLiveTextPreview::resetInitialDoc(const QmlJS::Document::Ptr &doc) +void QmlLiveTextPreview::resetInitialDoc(const Document::Ptr &doc) { m_initialDoc = doc; m_previousDoc = doc; @@ -463,7 +463,7 @@ void QmlLiveTextPreview::updateDebugIds() if (it != m_inspectorAdapter->agent()->debugIdHash().constEnd()) { // Map all the object that comes from the document as it has been loaded // by the server. - const QmlJS::Document::Ptr &doc = m_initialDoc; + const Document::Ptr &doc = m_initialDoc; MapObjectWithDebugReference visitor; visitor.ids = (*it); @@ -477,7 +477,7 @@ void QmlLiveTextPreview::updateDebugIds() } } - const QmlJS::Document::Ptr &doc = m_previousDoc; + const Document::Ptr &doc = m_previousDoc; if (!doc->qmlProgram()) return; @@ -500,7 +500,7 @@ void QmlLiveTextPreview::updateDebugIds() = m_createdObjects.constBegin(); it != m_createdObjects.constEnd(); ++it) { - const QmlJS::Document::Ptr &doc = it.key(); + const Document::Ptr &doc = it.key(); DebugIdHash::const_iterator id_it = m_inspectorAdapter->agent()->debugIdHash().constFind( qMakePair<QString, int>(doc->fileName(), doc->editorRevision())); @@ -527,14 +527,14 @@ void QmlLiveTextPreview::updateDebugIds() changeSelectedElements(m_lastOffsets, QString()); } -void QmlLiveTextPreview::changeSelectedElements(const QList<QmlJS::AST::UiObjectMember*> offsetObjects, +void QmlLiveTextPreview::changeSelectedElements(const QList<UiObjectMember*> offsetObjects, const QString &wordAtCursor) { if (m_editors.isEmpty() || !m_previousDoc) return; QList<int> offsets; - foreach (QmlJS::AST::UiObjectMember *member, offsetObjects) + foreach (UiObjectMember *member, offsetObjects) offsets << member->firstSourceLocation().offset; if (!changeSelectedElements(offsets, wordAtCursor) && m_initialDoc && offsetObjects.count()) { @@ -588,7 +588,7 @@ bool QmlLiveTextPreview::changeSelectedElements(const QList<int> offsets, return true; } -void QmlLiveTextPreview::documentChanged(QmlJS::Document::Ptr doc) +void QmlLiveTextPreview::documentChanged(Document::Ptr doc) { if (doc->fileName() != m_previousDoc->fileName()) return; @@ -650,11 +650,11 @@ void QmlLiveTextPreview::onAutomaticUpdateFailed() QList<int> QmlLiveTextPreview::objectReferencesForOffset(quint32 offset) { QList<int> result; - QHashIterator<QmlJS::AST::UiObjectMember*, QList<int> > iter(m_debugIds); - QmlJS::AST::UiObjectMember *possibleNode = 0; + QHashIterator<UiObjectMember*, QList<int> > iter(m_debugIds); + UiObjectMember *possibleNode = 0; while (iter.hasNext()) { iter.next(); - QmlJS::AST::UiObjectMember *member = iter.key(); + UiObjectMember *member = iter.key(); quint32 startOffset = member->firstSourceLocation().offset; quint32 endOffset = member->lastSourceLocation().offset; if (startOffset <= offset && offset <= endOffset) { diff --git a/src/plugins/debugger/qml/qmlv8debuggerclient.cpp b/src/plugins/debugger/qml/qmlv8debuggerclient.cpp index f4c0816450..0e119956ca 100644 --- a/src/plugins/debugger/qml/qmlv8debuggerclient.cpp +++ b/src/plugins/debugger/qml/qmlv8debuggerclient.cpp @@ -471,7 +471,7 @@ void QmlV8DebuggerClientPrivate::setBreakpoint(const QString type, const QString args.setProperty(_(TYPE), QScriptValue(type)); if (type == _(SCRIPTREGEXP)) args.setProperty(_(TARGET), - QScriptValue(QFileInfo(target).fileName())); + QScriptValue(Utils::FileName::fromString(target).fileName())); else args.setProperty(_(TARGET), QScriptValue(target)); @@ -842,23 +842,22 @@ void QmlV8DebuggerClient::activateFrame(int index) d->engine->stackHandler()->setCurrentIndex(index); } -bool QmlV8DebuggerClient::acceptsBreakpoint(const BreakpointModelId &id) +bool QmlV8DebuggerClient::acceptsBreakpoint(Breakpoint bp) { - BreakpointType type = d->engine->breakHandler()->breakpointData(id).type; + BreakpointType type = bp.type(); return (type == BreakpointOnQmlSignalEmit || type == BreakpointByFileAndLine || type == BreakpointAtJavaScriptThrow); } -void QmlV8DebuggerClient::insertBreakpoint(const BreakpointModelId &id, +void QmlV8DebuggerClient::insertBreakpoint(Breakpoint bp, int adjustedLine, int adjustedColumn) { - BreakHandler *handler = d->engine->breakHandler(); - const BreakpointParameters ¶ms = handler->breakpointData(id); + const BreakpointParameters ¶ms = bp.parameters(); if (params.type == BreakpointAtJavaScriptThrow) { - handler->notifyBreakpointInsertOk(id); + bp.notifyBreakpointInsertOk(); d->setExceptionBreak(AllExceptions, params.enabled); } else if (params.type == BreakpointByFileAndLine) { @@ -868,19 +867,18 @@ void QmlV8DebuggerClient::insertBreakpoint(const BreakpointModelId &id, } else if (params.type == BreakpointOnQmlSignalEmit) { d->setBreakpoint(QString(_(EVENT)), params.functionName, params.enabled); - d->engine->breakHandler()->notifyBreakpointInsertOk(id); + bp.notifyBreakpointInsertOk(); } - d->breakpointsSync.insert(d->sequence, id); + d->breakpointsSync.insert(d->sequence, bp.id()); } -void QmlV8DebuggerClient::removeBreakpoint(const BreakpointModelId &id) +void QmlV8DebuggerClient::removeBreakpoint(Breakpoint bp) { - BreakHandler *handler = d->engine->breakHandler(); - const BreakpointParameters ¶ms = handler->breakpointData(id); + const BreakpointParameters ¶ms = bp.parameters(); - int breakpoint = d->breakpoints.value(id); - d->breakpoints.remove(id); + int breakpoint = d->breakpoints.value(bp.id()); + d->breakpoints.remove(bp.id()); if (params.type == BreakpointAtJavaScriptThrow) d->setExceptionBreak(AllExceptions); @@ -890,25 +888,25 @@ void QmlV8DebuggerClient::removeBreakpoint(const BreakpointModelId &id) d->clearBreakpoint(breakpoint); } -void QmlV8DebuggerClient::changeBreakpoint(const BreakpointModelId &id) +void QmlV8DebuggerClient::changeBreakpoint(Breakpoint bp) { - BreakHandler *handler = d->engine->breakHandler(); - const BreakpointParameters ¶ms = handler->breakpointData(id); + const BreakpointParameters ¶ms = bp.parameters(); - BreakpointResponse br = handler->response(id); + BreakpointResponse br = bp.response(); if (params.type == BreakpointAtJavaScriptThrow) { d->setExceptionBreak(AllExceptions, params.enabled); br.enabled = params.enabled; - handler->setResponse(id, br); + bp.setResponse(br); } else if (params.type == BreakpointOnQmlSignalEmit) { d->setBreakpoint(QString(_(EVENT)), params.functionName, params.enabled); br.enabled = params.enabled; - handler->setResponse(id, br); + bp.setResponse(br); } else { //V8 supports only minimalistic changes in breakpoint //Remove the breakpoint and add again - handler->notifyBreakpointChangeOk(id); - handler->removeBreakpoint(id); + bp.notifyBreakpointChangeOk(); + bp.removeBreakpoint(); + BreakHandler *handler = d->engine->breakHandler(); handler->appendBreakpoint(params); } } @@ -984,7 +982,8 @@ void QmlV8DebuggerClient::expandObject(const QByteArray &iname, quint64 objectId void QmlV8DebuggerClient::setEngine(QmlEngine *engine) { d->engine = engine; - connect(this, SIGNAL(stackFrameCompleted()), engine, SIGNAL(stackFrameCompleted())); + connect(this, &QmlV8DebuggerClient::stackFrameCompleted, + engine, &QmlEngine::stackFrameCompleted); } void QmlV8DebuggerClient::getSourceFiles() @@ -1086,12 +1085,12 @@ void QmlV8DebuggerClient::messageReceived(const QByteArray &data) //The breakpoint requested line should be same as //actual line BreakHandler *handler = d->engine->breakHandler(); - if (handler->state(id) != BreakpointInserted) { - BreakpointResponse br = handler->response(id); - br.lineNumber = breakpointData.value(_("line") - ).toInt() + 1; - handler->setResponse(id, br); - handler->notifyBreakpointInsertOk(id); + Breakpoint bp = handler->breakpointById(id); + if (bp.state() != BreakpointInserted) { + BreakpointResponse br = bp.response(); + br.lineNumber = breakpointData.value(_("line")).toInt() + 1; + bp.setResponse(br); + bp.notifyBreakpointInsertOk(); } } @@ -1211,10 +1210,10 @@ void QmlV8DebuggerClient::messageReceived(const QByteArray &data) BreakHandler *handler = d->engine->breakHandler(); foreach (int v8Id, v8BreakpointIds) { - const BreakpointModelId internalId = d->breakpoints.key(v8Id); - - if (internalId.isValid()) { - const BreakpointParameters ¶ms = handler->breakpointData(internalId); + const BreakpointModelId id = d->breakpoints.key(v8Id); + Breakpoint bp = handler->breakpointById(id); + if (bp.isValid()) { + const BreakpointParameters ¶ms = bp.parameters(); d->clearBreakpoint(v8Id); d->setBreakpoint(QString(_(SCRIPTREGEXP)), @@ -1224,7 +1223,7 @@ void QmlV8DebuggerClient::messageReceived(const QByteArray &data) newColumn, QString(QString::fromLatin1(params.condition)), params.ignoreCount); - d->breakpointsSync.insert(d->sequence, internalId); + d->breakpointsSync.insert(d->sequence, id); } } d->continueDebugging(Continue); @@ -1242,17 +1241,18 @@ void QmlV8DebuggerClient::messageReceived(const QByteArray &data) BreakHandler *handler = d->engine->breakHandler(); foreach (int v8Id, v8BreakpointIds) { const BreakpointModelId id = d->breakpoints.key(v8Id); - if (id.isValid()) { - BreakpointResponse br = handler->response(id); + Breakpoint bp = handler->breakpointById(id); + if (bp) { + BreakpointResponse br = bp.response(); if (br.functionName.isEmpty()) { br.functionName = invocationText; - handler->setResponse(id, br); + bp.setResponse(br); } - if (handler->state(id) != BreakpointInserted) { + if (bp.state() != BreakpointInserted) { br.lineNumber = breakData.value( _("sourceLine")).toInt() + 1; - handler->setResponse(id, br); - handler->notifyBreakpointInsertOk(id); + bp.setResponse(br); + bp.notifyBreakpointInsertOk(); } } } diff --git a/src/plugins/debugger/qml/qmlv8debuggerclient.h b/src/plugins/debugger/qml/qmlv8debuggerclient.h index 07f360c9d9..524084a11f 100644 --- a/src/plugins/debugger/qml/qmlv8debuggerclient.h +++ b/src/plugins/debugger/qml/qmlv8debuggerclient.h @@ -77,11 +77,11 @@ public: void activateFrame(int index); - bool acceptsBreakpoint(const BreakpointModelId &id); - void insertBreakpoint(const BreakpointModelId &id, int adjustedLine, + bool acceptsBreakpoint(Breakpoint bp); + void insertBreakpoint(Breakpoint bp, int adjustedLine, int adjustedColumn = -1); - void removeBreakpoint(const BreakpointModelId &id); - void changeBreakpoint(const BreakpointModelId &id); + void removeBreakpoint(Breakpoint bp); + void changeBreakpoint(Breakpoint bp); void synchronizeBreakpoints(); void assignValueInDebugger(const WatchData *data, diff --git a/src/plugins/debugger/qml/qscriptdebuggerclient.cpp b/src/plugins/debugger/qml/qscriptdebuggerclient.cpp index 20944d9083..923a1bcb89 100644 --- a/src/plugins/debugger/qml/qscriptdebuggerclient.cpp +++ b/src/plugins/debugger/qml/qscriptdebuggerclient.cpp @@ -37,8 +37,9 @@ #include <debugger/debuggerstringutils.h> #include <qmldebug/qmldebugclient.h> +#include <coreplugin/messagebox.h> + #include <QFileInfo> -#include <QMessageBox> #include <utils/qtcassert.h> using QmlDebug::QmlDebugStream; @@ -219,9 +220,9 @@ void QScriptDebuggerClient::startSession() BreakHandler *handler = d->engine->breakHandler(); DebuggerEngine * engine = d->engine->isSlaveEngine() ? d->engine->masterEngine() : d->engine; - foreach (BreakpointModelId id, handler->engineBreakpointIds(engine)) { - QTC_CHECK(handler->state(id) == BreakpointInsertProceeding); - handler->notifyBreakpointInsertOk(id); + foreach (Breakpoint bp, handler->engineBreakpoints(engine)) { + QTC_CHECK(bp.state() == BreakpointInsertProceeding); + bp.notifyBreakpointInsertOk(); } d->sessionStarted = true; } @@ -246,46 +247,42 @@ void QScriptDebuggerClient::activateFrame(int index) sendMessage(reply); } -void QScriptDebuggerClient::insertBreakpoint(const BreakpointModelId &id, +void QScriptDebuggerClient::insertBreakpoint(Breakpoint bp, int adjustedLine, int /*adjustedColumn*/) { - BreakHandler *handler = d->engine->breakHandler(); - JSAgentBreakpointData bp; - bp.fileUrl = QUrl::fromLocalFile(handler->fileName(id)).toString().toUtf8(); - bp.lineNumber = adjustedLine; - bp.functionName = handler->functionName(id).toUtf8(); - d->breakpoints.insert(bp); + JSAgentBreakpointData jsbp; + jsbp.fileUrl = QUrl::fromLocalFile(bp.fileName()).toString().toUtf8(); + jsbp.lineNumber = adjustedLine; + jsbp.functionName = bp.functionName().toUtf8(); + d->breakpoints.insert(jsbp); - BreakpointResponse br = handler->response(id); + BreakpointResponse br = bp.response(); br.lineNumber = adjustedLine; - handler->setResponse(id, br); - if (d->sessionStarted && handler->state(id) == BreakpointInsertProceeding) - handler->notifyBreakpointInsertOk(id); + bp.setResponse(br); + if (d->sessionStarted && bp.state() == BreakpointInsertProceeding) + bp.notifyBreakpointInsertOk(); } -void QScriptDebuggerClient::removeBreakpoint(const BreakpointModelId &id) +void QScriptDebuggerClient::removeBreakpoint(Breakpoint bp) { - BreakHandler *handler = d->engine->breakHandler(); - JSAgentBreakpointData bp; - bp.fileUrl = QUrl::fromLocalFile(handler->fileName(id)).toString().toUtf8(); - bp.lineNumber = handler->lineNumber(id); - bp.functionName = handler->functionName(id).toUtf8(); - d->breakpoints.remove(bp); + JSAgentBreakpointData jsbp; + jsbp.fileUrl = QUrl::fromLocalFile(bp.fileName()).toString().toUtf8(); + jsbp.lineNumber = bp.lineNumber(); + jsbp.functionName = bp.functionName().toUtf8(); + d->breakpoints.remove(jsbp); } -void QScriptDebuggerClient::changeBreakpoint(const BreakpointModelId &id) +void QScriptDebuggerClient::changeBreakpoint(Breakpoint bp) { - BreakHandler *handler = d->engine->breakHandler(); - if (handler->isEnabled(id)) { - BreakpointResponse br = handler->response(id); - insertBreakpoint(id, br.lineNumber); - } else { - removeBreakpoint(id); - } - BreakpointResponse br = handler->response(id); - br.enabled = handler->isEnabled(id); - handler->setResponse(id, br); + if (bp.isEnabled()) + insertBreakpoint(bp, bp.response().lineNumber); + else + removeBreakpoint(bp); + + BreakpointResponse br = bp.response(); + br.enabled = bp.isEnabled(); + bp.setResponse(br); } void QScriptDebuggerClient::synchronizeBreakpoints() @@ -448,7 +445,7 @@ void QScriptDebuggerClient::messageReceived(const QByteArray &data) .arg(error.toHtmlEscaped()) : tr("<p>An uncaught exception occurred in \"%1\":</p><p>%2</p>") .arg(QLatin1String(stackFrames.value(0).fileUrl), error.toHtmlEscaped()); - showMessageBox(QMessageBox::Information, tr("Uncaught Exception"), msg); + Core::AsynchronousMessageBox::information(tr("Uncaught Exception"), msg); } else { QString file; int line = -1; @@ -585,7 +582,8 @@ void QScriptDebuggerClient::insertLocalsAndWatches(QList<WatchData> &locals, void QScriptDebuggerClient::setEngine(QmlEngine *engine) { d->engine = engine; - connect(this, SIGNAL(stackFrameCompleted()), engine, SIGNAL(stackFrameCompleted())); + connect(this, &QScriptDebuggerClient::stackFrameCompleted, + engine, &DebuggerEngine::stackFrameCompleted); } void QScriptDebuggerClientPrivate::logSendMessage(const QString &msg) const diff --git a/src/plugins/debugger/qml/qscriptdebuggerclient.h b/src/plugins/debugger/qml/qscriptdebuggerclient.h index 7865bc6b68..a09a1839c2 100644 --- a/src/plugins/debugger/qml/qscriptdebuggerclient.h +++ b/src/plugins/debugger/qml/qscriptdebuggerclient.h @@ -62,10 +62,10 @@ public: void activateFrame(int index); - void insertBreakpoint(const BreakpointModelId &id, int adjustedLine, + void insertBreakpoint(Breakpoint bp, int adjustedLine, int adjustedColumn = -1); - void removeBreakpoint(const BreakpointModelId &id); - void changeBreakpoint(const BreakpointModelId &id); + void removeBreakpoint(Breakpoint bp); + void changeBreakpoint(Breakpoint bp); void synchronizeBreakpoints(); void assignValueInDebugger(const WatchData *data, const QString &expression, diff --git a/src/plugins/debugger/registerhandler.cpp b/src/plugins/debugger/registerhandler.cpp index 61e3de0b2d..d40536acbb 100644 --- a/src/plugins/debugger/registerhandler.cpp +++ b/src/plugins/debugger/registerhandler.cpp @@ -46,518 +46,537 @@ namespace Internal { // ////////////////////////////////////////////////////////////////// -enum RegisterType -{ - RegisterUnknown, - //RegisterDummy, // like AH if EAX is present. - RegisterI8, - RegisterI16, - RegisterI32, - RegisterI64, - RegisterI128, - RegisterF32, - RegisterF64, - RegisterF80, - RegisterXMM, - RegisterMMX, - RegisterNeon, - RegisterFlags32 -}; - static struct RegisterNameAndType { const char *name; - RegisterType type; + RegisterKind kind; + int size; } theNameAndType[] = { // ARM - { "r0", RegisterI32 }, - { "r1", RegisterI32 }, - { "r2", RegisterI32 }, - { "r3", RegisterI32 }, - { "r4", RegisterI32 }, - { "r5", RegisterI32 }, - { "r6", RegisterI32 }, - { "r7", RegisterI32 }, - { "r8", RegisterI32 }, - { "r9", RegisterI32 }, - { "r10", RegisterI32 }, - { "r11", RegisterI32 }, - { "r12", RegisterI32 }, - { "sp", RegisterI32 }, - { "lr", RegisterI32 }, - { "pc", RegisterI32 }, - { "cpsr", RegisterFlags32 }, - { "d0", RegisterI64 }, - { "d1", RegisterI64 }, - { "d2", RegisterI64 }, - { "d3", RegisterI64 }, - { "d4", RegisterI64 }, - { "d5", RegisterI64 }, - { "d6", RegisterI64 }, - { "d7", RegisterI64 }, - { "d8", RegisterI64 }, - { "d9", RegisterI64 }, - { "d10", RegisterI64 }, - { "d11", RegisterI64 }, - { "d12", RegisterI64 }, - { "d13", RegisterI64 }, - { "d14", RegisterI64 }, - { "d15", RegisterI64 }, - { "d16", RegisterI64 }, - { "d17", RegisterI64 }, - { "d18", RegisterI64 }, - { "d19", RegisterI64 }, - { "d20", RegisterI64 }, - { "d21", RegisterI64 }, - { "d22", RegisterI64 }, - { "d23", RegisterI64 }, - { "d24", RegisterI64 }, - { "d25", RegisterI64 }, - { "d26", RegisterI64 }, - { "d27", RegisterI64 }, - { "d28", RegisterI64 }, - { "d29", RegisterI64 }, - { "d30", RegisterI64 }, - { "d31", RegisterI64 }, - { "fpscr", RegisterFlags32 }, - { "s0", RegisterI32 }, - { "s1", RegisterI32 }, - { "s2", RegisterI32 }, - { "s3", RegisterI32 }, - { "s4", RegisterI32 }, - { "s5", RegisterI32 }, - { "s6", RegisterI32 }, - { "s7", RegisterI32 }, - { "s8", RegisterI32 }, - { "s9", RegisterI32 }, - { "s10", RegisterI32 }, - { "s11", RegisterI32 }, - { "s12", RegisterI32 }, - { "s13", RegisterI32 }, - { "s14", RegisterI32 }, - { "s15", RegisterI32 }, - { "s16", RegisterI32 }, - { "s17", RegisterI32 }, - { "s18", RegisterI32 }, - { "s19", RegisterI32 }, - { "s20", RegisterI32 }, - { "s21", RegisterI32 }, - { "s22", RegisterI32 }, - { "s23", RegisterI32 }, - { "s24", RegisterI32 }, - { "s25", RegisterI32 }, - { "s26", RegisterI32 }, - { "s27", RegisterI32 }, - { "s28", RegisterI32 }, - { "s29", RegisterI32 }, - { "s30", RegisterI32 }, - { "s31", RegisterI32 }, - { "q0", RegisterI128 }, - { "q1", RegisterI128 }, - { "q2", RegisterI128 }, - { "q3", RegisterI128 }, - { "q4", RegisterI128 }, - { "q5", RegisterI128 }, - { "q6", RegisterI128 }, - { "q7", RegisterI128 }, - { "q8", RegisterI128 }, - { "q9", RegisterI128 }, - { "q10", RegisterI128 }, - { "q11", RegisterI128 }, - { "q12", RegisterI128 }, - { "q13", RegisterI128 }, - { "q14", RegisterI128 }, - { "q15", RegisterI128 }, + { "r0", IntegerRegister, 4 }, + { "r1", IntegerRegister, 4 }, + { "r2", IntegerRegister, 4 }, + { "r3", IntegerRegister, 4 }, + { "r4", IntegerRegister, 4 }, + { "r5", IntegerRegister, 4 }, + { "r6", IntegerRegister, 4 }, + { "r7", IntegerRegister, 4 }, + { "r8", IntegerRegister, 4 }, + { "r9", IntegerRegister, 4 }, + { "r10", IntegerRegister, 4 }, + { "r11", IntegerRegister, 4 }, + { "r12", IntegerRegister, 4 }, + { "sp", IntegerRegister, 4 }, + { "lr", IntegerRegister, 4 }, + { "pc", IntegerRegister, 4 }, + { "cpsr", FlagRegister, 4 }, + { "d0", IntegerRegister, 8 }, + { "d1", IntegerRegister, 8 }, + { "d2", IntegerRegister, 8 }, + { "d3", IntegerRegister, 8 }, + { "d4", IntegerRegister, 8 }, + { "d5", IntegerRegister, 8 }, + { "d6", IntegerRegister, 8 }, + { "d7", IntegerRegister, 8 }, + { "d8", IntegerRegister, 8 }, + { "d9", IntegerRegister, 8 }, + { "d10", IntegerRegister, 8 }, + { "d11", IntegerRegister, 8 }, + { "d12", IntegerRegister, 8 }, + { "d13", IntegerRegister, 8 }, + { "d14", IntegerRegister, 8 }, + { "d15", IntegerRegister, 8 }, + { "d16", IntegerRegister, 8 }, + { "d17", IntegerRegister, 8 }, + { "d18", IntegerRegister, 8 }, + { "d19", IntegerRegister, 8 }, + { "d20", IntegerRegister, 8 }, + { "d21", IntegerRegister, 8 }, + { "d22", IntegerRegister, 8 }, + { "d23", IntegerRegister, 8 }, + { "d24", IntegerRegister, 8 }, + { "d25", IntegerRegister, 8 }, + { "d26", IntegerRegister, 8 }, + { "d27", IntegerRegister, 8 }, + { "d28", IntegerRegister, 8 }, + { "d29", IntegerRegister, 8 }, + { "d30", IntegerRegister, 8 }, + { "d31", IntegerRegister, 8 }, + { "fpscr", FlagRegister, 4 }, + { "s0", IntegerRegister, 4 }, + { "s1", IntegerRegister, 4 }, + { "s2", IntegerRegister, 4 }, + { "s3", IntegerRegister, 4 }, + { "s4", IntegerRegister, 4 }, + { "s5", IntegerRegister, 4 }, + { "s6", IntegerRegister, 4 }, + { "s7", IntegerRegister, 4 }, + { "s8", IntegerRegister, 4 }, + { "s9", IntegerRegister, 4 }, + { "s10", IntegerRegister, 4 }, + { "s11", IntegerRegister, 4 }, + { "s12", IntegerRegister, 4 }, + { "s13", IntegerRegister, 4 }, + { "s14", IntegerRegister, 4 }, + { "s15", IntegerRegister, 4 }, + { "s16", IntegerRegister, 4 }, + { "s17", IntegerRegister, 4 }, + { "s18", IntegerRegister, 4 }, + { "s19", IntegerRegister, 4 }, + { "s20", IntegerRegister, 4 }, + { "s21", IntegerRegister, 4 }, + { "s22", IntegerRegister, 4 }, + { "s23", IntegerRegister, 4 }, + { "s24", IntegerRegister, 4 }, + { "s25", IntegerRegister, 4 }, + { "s26", IntegerRegister, 4 }, + { "s27", IntegerRegister, 4 }, + { "s28", IntegerRegister, 4 }, + { "s29", IntegerRegister, 4 }, + { "s30", IntegerRegister, 4 }, + { "s31", IntegerRegister, 4 }, + { "q0", IntegerRegister, 16 }, + { "q1", IntegerRegister, 16 }, + { "q2", IntegerRegister, 16 }, + { "q3", IntegerRegister, 16 }, + { "q4", IntegerRegister, 16 }, + { "q5", IntegerRegister, 16 }, + { "q6", IntegerRegister, 16 }, + { "q7", IntegerRegister, 16 }, + { "q8", IntegerRegister, 16 }, + { "q9", IntegerRegister, 16 }, + { "q10", IntegerRegister, 16 }, + { "q11", IntegerRegister, 16 }, + { "q12", IntegerRegister, 16 }, + { "q13", IntegerRegister, 16 }, + { "q14", IntegerRegister, 16 }, + { "q15", IntegerRegister, 16 }, // Intel - { "eax", RegisterI32 }, - { "ecx", RegisterI32 }, - { "edx", RegisterI32 }, - { "ebx", RegisterI32 }, - { "esp", RegisterI32 }, - { "ebp", RegisterI32 }, - { "esi", RegisterI32 }, - { "edi", RegisterI32 }, - { "eip", RegisterI32 }, - { "eflags", RegisterFlags32 }, - { "cs", RegisterI32 }, - { "ss", RegisterI32 }, - { "ds", RegisterI32 }, - { "es", RegisterI32 }, - { "fs", RegisterI32 }, - { "gs", RegisterI32 }, - { "st0", RegisterF80 }, - { "st1", RegisterF80 }, - { "st2", RegisterF80 }, - { "st3", RegisterF80 }, - { "st4", RegisterF80 }, - { "st5", RegisterF80 }, - { "st6", RegisterF80 }, - { "st7", RegisterF80 }, - { "fctrl", RegisterFlags32 }, - { "fstat", RegisterFlags32 }, - { "ftag", RegisterFlags32 }, - { "fiseg", RegisterFlags32 }, - { "fioff", RegisterFlags32 }, - { "foseg", RegisterFlags32 }, - { "fooff", RegisterFlags32 }, - { "fop", RegisterFlags32 }, - { "xmm0", RegisterXMM }, - { "xmm1", RegisterXMM }, - { "xmm2", RegisterXMM }, - { "xmm3", RegisterXMM }, - { "xmm4", RegisterXMM }, - { "xmm5", RegisterXMM }, - { "xmm6", RegisterXMM }, - { "xmm7", RegisterXMM }, - { "mxcsr", RegisterFlags32 }, - { "orig_eax", RegisterI32 }, - { "al", RegisterI8 }, - { "cl", RegisterI8 }, - { "dl", RegisterI8 }, - { "bl", RegisterI8 }, - { "ah", RegisterI8 }, - { "ch", RegisterI8 }, - { "dh", RegisterI8 }, - { "bh", RegisterI8 }, - { "ax", RegisterI16 }, - { "cx", RegisterI16 }, - { "dx", RegisterI16 }, - { "bx", RegisterI16 }, - { "bp", RegisterI16 }, - { "si", RegisterI16 }, - { "di", RegisterI16 }, - { "mm0", RegisterMMX }, - { "mm1", RegisterMMX }, - { "mm2", RegisterMMX }, - { "mm3", RegisterMMX }, - { "mm4", RegisterMMX }, - { "mm5", RegisterMMX }, - { "mm6", RegisterMMX }, - { "mm7", RegisterMMX } + { "eax", IntegerRegister, 4 }, + { "ecx", IntegerRegister, 4 }, + { "edx", IntegerRegister, 4 }, + { "ebx", IntegerRegister, 4 }, + { "esp", IntegerRegister, 4 }, + { "ebp", IntegerRegister, 4 }, + { "esi", IntegerRegister, 4 }, + { "edi", IntegerRegister, 4 }, + { "eip", IntegerRegister, 4 }, + { "rax", IntegerRegister, 8 }, + { "rcx", IntegerRegister, 8 }, + { "rdx", IntegerRegister, 8 }, + { "rbx", IntegerRegister, 8 }, + { "rsp", IntegerRegister, 8 }, + { "rbp", IntegerRegister, 8 }, + { "rsi", IntegerRegister, 8 }, + { "rdi", IntegerRegister, 8 }, + { "rip", IntegerRegister, 8 }, + { "eflags", FlagRegister, 4 }, + { "cs", IntegerRegister, 2 }, + { "ss", IntegerRegister, 2 }, + { "ds", IntegerRegister, 2 }, + { "es", IntegerRegister, 2 }, + { "fs", IntegerRegister, 2 }, + { "gs", IntegerRegister, 2 }, + { "st0", FloatRegister, 10 }, + { "st1", FloatRegister, 10 }, + { "st2", FloatRegister, 10 }, + { "st3", FloatRegister, 10 }, + { "st4", FloatRegister, 10 }, + { "st5", FloatRegister, 10 }, + { "st6", FloatRegister, 10 }, + { "st7", FloatRegister, 10 }, + { "fctrl", FlagRegister, 4 }, + { "fstat", FlagRegister, 4 }, + { "ftag", FlagRegister, 4 }, + { "fiseg", FlagRegister, 4 }, + { "fioff", FlagRegister, 4 }, + { "foseg", FlagRegister, 4 }, + { "fooff", FlagRegister, 4 }, + { "fop", FlagRegister, 4 }, + { "mxcsr", FlagRegister, 4 }, + { "orig_eax", IntegerRegister, 4 }, + { "al", IntegerRegister, 1 }, + { "cl", IntegerRegister, 1 }, + { "dl", IntegerRegister, 1 }, + { "bl", IntegerRegister, 1 }, + { "ah", IntegerRegister, 1 }, + { "ch", IntegerRegister, 1 }, + { "dh", IntegerRegister, 1 }, + { "bh", IntegerRegister, 1 }, + { "ax", IntegerRegister, 2 }, + { "cx", IntegerRegister, 2 }, + { "dx", IntegerRegister, 2 }, + { "bx", IntegerRegister, 2 }, + { "bp", IntegerRegister, 2 }, + { "si", IntegerRegister, 2 }, + { "di", IntegerRegister, 2 } }; -static RegisterType guessType(const QByteArray &name) +////////////////////////////////////////////////////////////////// +// +// RegisterValue +// +////////////////////////////////////////////////////////////////// + +// FIXME: This should not really be needed. Instead the guessing, if any, +// should done by the engines. +static void fixup(Register *reg, RegisterKind kind, int size) { - static QHash<QByteArray, RegisterType> theTypes; - if (theTypes.isEmpty()) { - for (int i = 0; i != sizeof(theNameAndType) / sizeof(theNameAndType[0]); ++i) - theTypes[theNameAndType[i].name] = theNameAndType[i].type; - } - return theTypes.value(name, RegisterUnknown); + reg->kind = kind; + if (!reg->size) + reg->size = size; } -static int childCountFromType(int type) +void Register::guessMissingData() { - switch (type) { - case RegisterUnknown: return 0; - case RegisterI8: return 0; - case RegisterI16: return 1; - case RegisterI32: return 2; - case RegisterI64: return 3; - case RegisterI128: return 4; - case RegisterF32: return 0; - case RegisterF64: return 0; - case RegisterF80: return 0; - case RegisterXMM: return 3; - case RegisterMMX: return 3; - case RegisterNeon: return 3; - case RegisterFlags32: return 0; + if (name.startsWith("xmm")) { + fixup(this, VectorRegister, 16); + return; } + + for (int i = 0; i != sizeof(theNameAndType) / sizeof(theNameAndType[0]); ++i) { + if (theNameAndType[i].name == name) { + fixup(this, theNameAndType[i].kind, theNameAndType[i].size); + return; + } + } + + if (reportedType == "int") + fixup(this, IntegerRegister, 4); + else if (reportedType == "float") + fixup(this, IntegerRegister, 8); + else if (reportedType == "_i387_ext") + fixup(this, IntegerRegister, 10); + else if (reportedType == "*1" || reportedType == "long") + fixup(this, IntegerRegister, 0); + else if (reportedType.contains("vec")) + fixup(this, VectorRegister, 0); + else if (reportedType.startsWith("int")) + fixup(this, IntegerRegister, 0); +} + +static QString subTypeName(RegisterKind kind, int size) +{ + if (kind == IntegerRegister) + return QString::fromLatin1("[i%1]").arg(size * 8); + if (kind == FloatRegister) + return QString::fromLatin1("[f%1]").arg(size * 8); QTC_ASSERT(false, /**/); - return 0; + return QString(); } -static int bitWidthFromType(int type, int subType) +static uint decodeHexChar(unsigned char c) { - const uint integer[] = { 8, 16, 32, 64, 128 }; - const uint xmm[] = { 8, 16, 32, 64, 128 }; - const uint mmx[] = { 8, 16, 32, 64, 128 }; - const uint neon[] = { 8, 16, 32, 64, 128 }; - - switch (type) { - case RegisterUnknown: return 0; - case RegisterI8: return 8; - case RegisterI16: return integer[subType]; - case RegisterI32: return integer[subType]; - case RegisterI64: return integer[subType]; - case RegisterI128: return integer[subType]; - case RegisterF32: return 0; - case RegisterF64: return 0; - case RegisterF80: return 0; - case RegisterXMM: return xmm[subType]; - case RegisterMMX: return mmx[subType]; - case RegisterNeon: return neon[subType]; - case RegisterFlags32: return 0; + c -= '0'; + if (c < 10) + return c; + c -= 'A' - '0'; + if (c < 6) + return 10 + c; + c -= 'a' - 'A'; + if (c < 6) + return 10 + c; + return uint(-1); +} + +void RegisterValue::operator=(const QByteArray &ba) +{ + uint shift = 0; + int j = 0; + v.u64[1] = v.u64[0] = 0; + for (int i = ba.size(); --i >= 0 && j < 16; ++j) { + quint64 d = decodeHexChar(ba.at(i)); + if (d == uint(-1)) + return; + v.u64[0] |= (d << shift); + shift += 4; + } + j = 0; + shift = 0; + for (int i = ba.size() - 16; --i >= 0 && j < 16; ++j) { + quint64 d = decodeHexChar(ba.at(i)); + if (d == uint(-1)) + return; + v.u64[1] |= (d << shift); + shift += 4; } - QTC_ASSERT(false, /**/); - return 0; } -static const uint TopLevelId = UINT_MAX; -static bool isTopLevelItem(const QModelIndex &index) +bool RegisterValue::operator==(const RegisterValue &other) { - return quintptr(index.internalId()) == quintptr(TopLevelId); + return v.u64[0] == other.v.u64[0] && v.u64[1] == other.v.u64[1]; } -Register::Register(const QByteArray &name_) - : name(name_), changed(true) +static QByteArray format(quint64 v, int base, int size) { - type = guessType(name); + QByteArray result = QByteArray::number(v, base); + if (base == 16) + result.prepend(QByteArray(2*size - result.size(), '0')); + return result; } +QByteArray RegisterValue::toByteArray(int base, RegisterKind kind, int size) const +{ + if (kind == FloatRegister) { + if (size == 4) + return QByteArray::number(v.f[0]); + if (size == 8) + return QByteArray::number(v.d[0]); + } + + QByteArray result; + if (size > 8) { + result += format(v.u64[1], base, size - 8); + size = 8; + if (base != 16) + result += ','; + } + result += format(v.u64[0], base, size); + if (base == 16) + result.prepend("0x"); + return result; +} + +RegisterValue RegisterValue::subValue(int size, int index) const +{ + RegisterValue value; + switch (size) { + case 1: + value.v.u8[0] = v.u8[index]; + break; + case 2: + value.v.u16[0] = v.u16[index]; + break; + case 4: + value.v.u32[0] = v.u32[index]; + break; + case 8: + value.v.u64[0] = v.u64[index]; + break; + } + return value; +} ////////////////////////////////////////////////////////////////// // -// RegisterHandler +// RegisterSubItem and RegisterItem // ////////////////////////////////////////////////////////////////// -RegisterHandler::RegisterHandler() +class RegisterSubItem : public Utils::TreeItem { - setObjectName(QLatin1String("RegisterModel")); - m_base = 16; - calculateWidth(); -#if USE_REGISTER_MODEL_TEST - new ModelTest(this, 0); -#endif -} +public: + RegisterSubItem(RegisterKind subKind, int subSize, int count) + : m_subKind(subKind), m_subSize(subSize), m_count(count), m_changed(false) + {} + + QVariant data(int column, int role) const; + + Qt::ItemFlags flags(int column) const + { + //return column == 1 ? Qt::ItemIsSelectable|Qt::ItemIsEnabled|Qt::ItemIsEditable + // : Qt::ItemIsSelectable|Qt::ItemIsEnabled; + Q_UNUSED(column); + return Qt::ItemIsSelectable|Qt::ItemIsEnabled; + } -int RegisterHandler::rowCount(const QModelIndex &idx) const -{ - if (idx.column() > 0) - return 0; - if (!idx.isValid()) - return m_registers.size(); // Top level. - if (!isTopLevelItem(idx)) - return 0; // Sub-Items don't have children. - if (idx.row() >= m_registers.size()) - return 0; - return childCountFromType(m_registers[idx.row()].type); -} + RegisterKind m_subKind; + int m_subSize; + int m_count; + bool m_changed; +}; -int RegisterHandler::columnCount(const QModelIndex &idx) const +class RegisterItem : public Utils::TreeItem { - if (idx.column() > 0) - return 0; - if (!idx.isValid()) - return 2; - if (!isTopLevelItem(idx)) - return 0; // Sub-Items don't have children. - return 2; -} +public: + explicit RegisterItem(const Register ®); -QModelIndex RegisterHandler::index(int row, int col, const QModelIndex &parent) const -{ - if (row < 0 || col < 0 || col >= 2) - return QModelIndex(); - if (!parent.isValid()) // Top level. - return createIndex(row, col, TopLevelId); - if (!isTopLevelItem(parent)) // Sub-Item has no children. - return QModelIndex(); - if (parent.column() > 0) - return QModelIndex(); - return createIndex(row, col, parent.row()); -} + QVariant data(int column, int role) const; + Qt::ItemFlags flags(int column) const; -QModelIndex RegisterHandler::parent(const QModelIndex &idx) const + quint64 addressValue() const; + + Register m_reg; + int m_base; + bool m_changed; +}; + +RegisterItem::RegisterItem(const Register ®) : + m_reg(reg), m_base(16), m_changed(true) { - if (!idx.isValid()) - return QModelIndex(); - if (!isTopLevelItem(idx)) - return createIndex(idx.internalId(), 0, TopLevelId); - return QModelIndex(); + if (m_reg.kind == UnknownRegister) + m_reg.guessMissingData(); + + if (m_reg.kind == IntegerRegister || m_reg.kind == VectorRegister) { + for (int s = m_reg.size / 2; s; s = s / 2) + appendChild(new RegisterSubItem(IntegerRegister, s, m_reg.size / s)); + } + if (m_reg.kind == IntegerRegister || m_reg.kind == VectorRegister) { + for (int s = m_reg.size; s >= 4; s = s / 2) + appendChild(new RegisterSubItem(FloatRegister, s, m_reg.size / s)); + } } -// Editor value: Preferably number, else string. -QVariant Register::editValue() const +Qt::ItemFlags RegisterItem::flags(int column) const { - bool ok = true; - // Try to convert to number? - const qulonglong v = value.toULongLong(&ok, 0); // Autodetect format - if (ok) - return QVariant(v); - return QVariant(value); + const Qt::ItemFlags notEditable = Qt::ItemIsSelectable|Qt::ItemIsEnabled; + // Can edit registers if they are hex numbers and not arrays. + if (column == 1) // && IntegerWatchLineEdit::isUnsignedHexNumber(QLatin1String(m_reg.display))) + return notEditable | Qt::ItemIsEditable; + return notEditable; } -// Editor value: Preferably padded number, else padded string. -QString Register::displayValue(int base, int strlen) const +quint64 RegisterItem::addressValue() const { - const QVariant editV = editValue(); - if (editV.type() == QVariant::ULongLong) - return QString::fromLatin1("%1").arg(editV.toULongLong(), strlen, base); - const QString stringValue = editV.toString(); - if (stringValue.size() < strlen) - return QString(strlen - stringValue.size(), QLatin1Char(' ')) + QLatin1String(value); - return stringValue; + return m_reg.value.v.u64[0]; } -QVariant RegisterHandler::data(const QModelIndex &index, int role) const +QVariant RegisterItem::data(int column, int role) const { - if (!index.isValid()) - return QVariant(); + switch (role) { + case RegisterNameRole: + return m_reg.name; - QModelIndex topLevel = index.parent(); - const int mainRow = topLevel.isValid() ? topLevel.row() : index.row(); + case RegisterIsBigRole: + return m_reg.value.v.u64[1] > 0; - if (mainRow >= m_registers.size()) - return QVariant(); + case RegisterChangedRole: + return m_changed; + case RegisterNumberBaseRole: + return m_base; - const Register ® = m_registers.at(mainRow); + case RegisterAsAddressRole: + return addressValue(); - if (topLevel.isValid()) { - // - // Nested - // - int subType = index.row(); - int bitWidth = bitWidthFromType(reg.type, subType); - - switch (role) { case Qt::DisplayRole: - switch (index.column()) { - case 0: { - switch (bitWidth) { - case 8: return QLatin1String("[Bytes]"); - case 16: return QLatin1String("[Words]"); - case 32: return QLatin1String("[DWords]"); - case 64: return QLatin1String("[QWords]"); - case 128: return QLatin1String("[TWords]"); - case -32: return QLatin1String("[Single]"); - case -64: return QLatin1String("[Double]"); - return QVariant(bitWidth); + switch (column) { + case 0: { + QByteArray res = m_reg.name; + if (!m_reg.description.isEmpty()) + res += " (" + m_reg.description + ')'; + return res; + } + case 1: { + return m_reg.value.toByteArray(m_base, m_reg.kind, m_reg.size); } } - } - default: - break; - } - } else { - // - // Toplevel - // + case Qt::ToolTipRole: + return QString::fromLatin1("Current Value: %1\nPreviousValue: %2") + .arg(QString::fromLatin1(m_reg.value.toByteArray(m_base, m_reg.kind, m_reg.size))) + .arg(QString::fromLatin1(m_reg.previousValue.toByteArray(m_base, m_reg.kind, m_reg.size))); - switch (role) { - case Qt::DisplayRole: - switch (index.column()) { - case 0: { - const QString padding = QLatin1String(" "); - return QVariant(padding + QLatin1String(reg.name) + padding); - //return QVariant(reg.name); - } - case 1: // Display: Pad value for alignment - return reg.displayValue(m_base, m_strlen); - } // switch column case Qt::EditRole: // Edit: Unpadded for editing - return reg.editValue(); + return m_reg.value.toByteArray(m_base, m_reg.kind, m_reg.size); + case Qt::TextAlignmentRole: - return index.column() == 1 ? QVariant(Qt::AlignRight) : QVariant(); + return column == 1 ? QVariant(Qt::AlignRight) : QVariant(); + default: break; - } } return QVariant(); } -QVariant RegisterHandler::headerData(int section, Qt::Orientation orientation, - int role) const +QVariant RegisterSubItem::data(int column, int role) const { - if (orientation == Qt::Horizontal && role == Qt::DisplayRole) { - switch (section) { - case 0: return tr("Name"); - case 1: return tr("Value (Base %1)").arg(m_base); - }; - } - return QVariant(); -} + switch (role) { + case RegisterChangedRole: + return m_changed; -Qt::ItemFlags RegisterHandler::flags(const QModelIndex &idx) const -{ - if (!idx.isValid()) - return Qt::ItemFlags(); + case RegisterNumberBaseRole: + return 16; - const Qt::ItemFlags notEditable = Qt::ItemIsSelectable|Qt::ItemIsEnabled; - // Can edit registers if they are hex numbers and not arrays. - if (idx.column() == 1 - && IntegerWatchLineEdit::isUnsignedHexNumber(QLatin1String(m_registers.at(idx.row()).value))) - return notEditable | Qt::ItemIsEditable; - return notEditable; -} + case RegisterAsAddressRole: + return 0; -void RegisterHandler::removeAll() -{ - beginResetModel(); - m_registers.clear(); - endResetModel(); -} + case Qt::DisplayRole: + switch (column) { + case 0: + return subTypeName(m_subKind, m_subSize); + case 1: { + QTC_ASSERT(parent(), return QVariant()); + RegisterItem *registerItem = static_cast<RegisterItem *>(parent()); + RegisterValue value = registerItem->m_reg.value; + QByteArray ba; + for (int i = 0; i != m_count; ++i) { + ba += value.subValue(m_subSize, i).toByteArray(16, m_subKind, m_subSize); + int tab = 5 * (i + 1) * m_subSize; + ba += QByteArray(tab - ba.size(), ' '); + } + return ba; + } + } + default: + break; + } -bool RegisterHandler::isEmpty() const -{ - return m_registers.isEmpty(); + return QVariant(); } -// Compare register sets by name -static inline bool compareRegisterSet(const Registers &r1, const Registers &r2) -{ - if (r1.size() != r2.size()) - return false; - const int size = r1.size(); - for (int r = 0; r < size; r++) - if (r1.at(r).name != r2.at(r).name) - return false; - return true; -} +////////////////////////////////////////////////////////////////// +// +// RegisterHandler +// +////////////////////////////////////////////////////////////////// -void RegisterHandler::setRegisters(const Registers ®isters) +RegisterHandler::RegisterHandler() { - beginResetModel(); - m_registers = registers; - const int size = m_registers.size(); - for (int r = 0; r < size; r++) - m_registers[r].changed = false; - calculateWidth(); - endResetModel(); + setObjectName(QLatin1String("RegisterModel")); + setHeader(QStringList() << tr("Name") << tr("Value")); + +#if USE_REGISTER_MODEL_TEST + new ModelTest(this, 0); +#endif } -void RegisterHandler::setAndMarkRegisters(const Registers ®isters) +void RegisterHandler::updateRegister(const Register &r) { - if (!compareRegisterSet(m_registers, registers)) { - setRegisters(registers); + RegisterItem *reg = m_registerByName.value(r.name, 0); + if (!reg) { + reg = new RegisterItem(r); + m_registerByName[r.name] = reg; + rootItem()->appendChild(reg); return; } - const int size = m_registers.size(); - for (int r = 0; r != size; ++r) { - const QModelIndex regIndex = index(r, 1, QModelIndex()); - if (m_registers.at(r).value != registers.at(r).value) { - // Indicate red if values change, keep changed. - m_registers[r].changed = m_registers.at(r).changed - || !m_registers.at(r).value.isEmpty(); - m_registers[r].value = registers.at(r).value; - emit dataChanged(regIndex, regIndex); - } - emit registerSet(regIndex); // Notify attached memory views. - } -} -Registers RegisterHandler::registers() const -{ - return m_registers; + if (r.size > 0) + reg->m_reg.size = r.size; + if (!r.description.isEmpty()) + reg->m_reg.description = r.description; + if (reg->m_reg.value != r.value) { + // Indicate red if values change, keep changed. + reg->m_changed = true; + reg->m_reg.previousValue = reg->m_reg.value; + reg->m_reg.value = r.value; + emit registerChanged(reg->m_reg.name, reg->addressValue()); // Notify attached memory views. + } else { + reg->m_changed = false; + } } -void RegisterHandler::calculateWidth() +void RegisterHandler::setNumberBase(const QByteArray &name, int base) { - m_strlen = (m_base == 2 ? 64 : m_base == 8 ? 32 : m_base == 10 ? 26 : 16); + RegisterItem *reg = m_registerByName.value(name, 0); + QTC_ASSERT(reg, return); + reg->m_base = base; + QModelIndex index = indexFromItem(reg); + emit dataChanged(index, index); } -void RegisterHandler::setNumberBase(int base) +RegisterMap RegisterHandler::registerMap() const { - if (m_base != base) { - beginResetModel(); - m_base = base; - calculateWidth(); - endResetModel(); + RegisterMap result; + Utils::TreeItem *root = rootItem(); + for (int i = 0, n = root->rowCount(); i != n; ++i) { + RegisterItem *reg = static_cast<RegisterItem *>(root->child(i)); + quint64 value = reg->addressValue(); + if (value) + result.insert(value, reg->m_reg.name); } + return result; } } // namespace Internal diff --git a/src/plugins/debugger/registerhandler.h b/src/plugins/debugger/registerhandler.h index a2c843dd6e..f22b52a14d 100644 --- a/src/plugins/debugger/registerhandler.h +++ b/src/plugins/debugger/registerhandler.h @@ -31,35 +31,73 @@ #ifndef DEBUGGER_REGISTERHANDLER_H #define DEBUGGER_REGISTERHANDLER_H +#include <utils/treemodel.h> + #include <QAbstractTableModel> +#include <QHash> #include <QVector> namespace Debugger { namespace Internal { -class Register +enum RegisterDataRole { -public: - Register() : type(0), changed(true) {} - Register(const QByteArray &name_); + RegisterNameRole = Qt::UserRole, + RegisterIsBigRole, + RegisterChangedRole, + RegisterNumberBaseRole, + RegisterAsAddressRole +}; + +enum RegisterKind +{ + UnknownRegister, + IntegerRegister, + FloatRegister, + VectorRegister, + FlagRegister, + OtherRegister +}; - QVariant editValue() const; - QString displayValue(int base, int strlen) const; +class RegisterValue +{ +public: + RegisterValue() { v.u64[1] = v.u64[0] = 0; } + void operator=(const QByteArray &ba); + bool operator==(const RegisterValue &other); + bool operator!=(const RegisterValue &other) { return !operator==(other); } + QByteArray toByteArray(int base, RegisterKind kind, int size) const; + RegisterValue subValue(int size, int index) const; + + union { + quint8 u8[16]; + quint16 u16[8]; + quint32 u32[4]; + quint64 u64[2]; + float f[4]; + double d[2]; + } v; +}; +class Register +{ public: + Register() { size = 0; kind = UnknownRegister; } + void guessMissingData(); + QByteArray name; - /* Value should be an integer for which autodetection by passing - * base=0 to QString::toULongLong() should work (C-language conventions). - * Values that cannot be converted (such as 128bit MMX-registers) are - * passed through. */ - QByteArray value; - int type; - bool changed; + QByteArray reportedType; + RegisterValue value; + RegisterValue previousValue; + QByteArray description; + int size; + RegisterKind kind; }; -typedef QVector<Register> Registers; +class RegisterItem; +typedef QMap<quint64, QByteArray> RegisterMap; -class RegisterHandler : public QAbstractTableModel +class RegisterHandler : public Utils::TreeModel { Q_OBJECT @@ -68,34 +106,17 @@ public: QAbstractItemModel *model() { return this; } - bool isEmpty() const; // nothing known so far? - // Set up register names (gdb) - void setRegisters(const Registers ®isters); - // Set register values - void setAndMarkRegisters(const Registers ®isters); - Registers registers() const; - Register registerAt(int i) const { return m_registers.at(i); } - void removeAll(); - Q_SLOT void setNumberBase(int base); - int numberBase() const { return m_base; } + void updateRegister(const Register ®); + + void setNumberBase(const QByteArray &name, int base); + void commitUpdates() { emit layoutChanged(); } + RegisterMap registerMap() const; signals: - void registerSet(const QModelIndex &r); // Register was set, for memory views + void registerChanged(const QByteArray &name, quint64 value); // For memory views private: - void calculateWidth(); - int rowCount(const QModelIndex &idx = QModelIndex()) const; - int columnCount(const QModelIndex &idx = QModelIndex()) const; - QModelIndex index(int row, int col, const QModelIndex &parent) const; - QModelIndex parent(const QModelIndex &idx) const; - QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const; - QVariant headerData(int section, Qt::Orientation orientation, - int role = Qt::DisplayRole) const; - Qt::ItemFlags flags(const QModelIndex &idx) const; - - Registers m_registers; - int m_base; - int m_strlen; // approximate width of a value in chars. + QHash<QByteArray, RegisterItem *> m_registerByName; }; } // namespace Internal diff --git a/src/plugins/debugger/registerwindow.cpp b/src/plugins/debugger/registerwindow.cpp index c75af5547a..724feeb8eb 100644 --- a/src/plugins/debugger/registerwindow.cpp +++ b/src/plugins/debugger/registerwindow.cpp @@ -30,6 +30,7 @@ #include "registerwindow.h" #include "memoryview.h" +#include "memoryagent.h" #include "debuggeractions.h" #include "debuggerdialogs.h" #include "debuggercore.h" @@ -42,22 +43,13 @@ #include <utils/qtcassert.h> #include <QDebug> - #include <QItemDelegate> #include <QMenu> #include <QPainter> - namespace Debugger { namespace Internal { -static RegisterHandler *currentHandler() -{ - DebuggerEngine *engine = currentEngine(); - QTC_ASSERT(engine, return 0); - return engine->registerHandler(); -} - /////////////////////////////////////////////////////////////////////// // // RegisterDelegate @@ -74,10 +66,9 @@ public: QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &, const QModelIndex &index) const { - Register reg = currentHandler()->registerAt(index.row()); IntegerWatchLineEdit *lineEdit = new IntegerWatchLineEdit(parent); - const int base = currentHandler()->numberBase(); - const bool big = reg.value.size() > 16; + const int base = index.data(RegisterNumberBaseRole).toInt(); + const bool big = index.data(RegisterIsBigRole).toBool(); // Big integers are assumed to be hexadecimal. lineEdit->setBigInt(big); lineEdit->setBase(big ? 16 : base); @@ -101,11 +92,11 @@ public: return; IntegerWatchLineEdit *lineEdit = qobject_cast<IntegerWatchLineEdit*>(editor); QTC_ASSERT(lineEdit, return); - const int base = currentHandler()->numberBase(); + const int base = index.data(RegisterNumberBaseRole).toInt(); QString value = lineEdit->text(); if (base == 16 && !value.startsWith(QLatin1String("0x"))) value.insert(0, QLatin1String("0x")); - currentEngine()->setRegisterValue(index.row(), value); + currentEngine()->setRegisterValue(index.data(RegisterNameRole).toByteArray(), value); } void updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, @@ -118,28 +109,38 @@ public: const QModelIndex &index) const { if (index.column() == 1) { - bool paintRed = currentHandler()->registerAt(index.row()).changed; + const bool paintRed = index.data(RegisterChangedRole).toBool(); QPen oldPen = painter->pen(); + const QColor lightColor(140, 140, 140); if (paintRed) painter->setPen(QColor(200, 0, 0)); + else + painter->setPen(lightColor); // FIXME: performance? this changes only on real font changes. QFontMetrics fm(option.font); - int charWidth = fm.width(QLatin1Char('x')); - for (int i = '1'; i <= '9'; ++i) - charWidth = qMax(charWidth, fm.width(QLatin1Char(i))); - for (int i = 'a'; i <= 'f'; ++i) - charWidth = qMax(charWidth, fm.width(QLatin1Char(i))); + int charWidth = qMax(fm.width(QLatin1Char('x')), fm.width(QLatin1Char('0'))); QString str = index.data(Qt::DisplayRole).toString(); int x = option.rect.x(); + bool light = !paintRed; for (int i = 0; i < str.size(); ++i) { - QRect r = option.rect; - r.setX(x); - r.setWidth(charWidth); + const QChar c = str.at(i); + const int uc = c.unicode(); + if (light && (uc != 'x' && uc != '0')) { + light = false; + painter->setPen(oldPen.color()); + } + if (uc == ' ') { + light = true; + painter->setPen(lightColor); + } else { + QRect r = option.rect; + r.setX(x); + r.setWidth(charWidth); + painter->drawText(r, Qt::AlignHCenter, c); + } x += charWidth; - painter->drawText(r, Qt::AlignHCenter, QString(str.at(i))); } - if (paintRed) - painter->setPen(oldPen); + painter->setPen(oldPen); } else { QItemDelegate::paint(painter, option, index); } @@ -156,6 +157,7 @@ public: RegisterTreeView::RegisterTreeView() { setItemDelegate(new RegisterDelegate(this)); + setRootIsDecorated(true); } void RegisterTreeView::contextMenuEvent(QContextMenuEvent *ev) @@ -164,7 +166,8 @@ void RegisterTreeView::contextMenuEvent(QContextMenuEvent *ev) DebuggerEngine *engine = currentEngine(); QTC_ASSERT(engine, return); - RegisterHandler *handler = currentHandler(); + RegisterHandler *handler = engine->registerHandler(); + const bool actionsEnabled = engine->debuggerActionsEnabled(); const DebuggerState state = engine->state(); @@ -174,13 +177,8 @@ void RegisterTreeView::contextMenuEvent(QContextMenuEvent *ev) menu.addSeparator(); - Register aRegister; const QModelIndex idx = indexAt(ev->pos()); - if (idx.isValid()) - aRegister = handler->registers().at(idx.row()); - const QVariant addressV = aRegister.editValue(); - const quint64 address = addressV.type() == QVariant::ULongLong - ? addressV.toULongLong() : 0; + const quint64 address = idx.data(RegisterAsAddressRole).toULongLong(); QAction *actViewMemory = menu.addAction(QString()); QAction *actEditMemory = menu.addAction(QString()); @@ -188,12 +186,14 @@ void RegisterTreeView::contextMenuEvent(QContextMenuEvent *ev) QAction *actShowDisassembler = menu.addAction(tr("Open Disassembler...")); actShowDisassembler->setEnabled(engine->hasCapability(DisassemblerCapability)); + const QByteArray registerName = idx.data(RegisterNameRole).toByteArray(); + const QString registerNameStr = QString::fromUtf8(registerName); if (address) { const bool canShow = actionsEnabled && engine->hasCapability(ShowMemoryCapability); actEditMemory->setText(tr("Open Memory Editor at 0x%1").arg(address, 0, 16)); actEditMemory->setEnabled(canShow); actViewMemory->setText(tr("Open Memory View at Value of Register %1 0x%2") - .arg(QString::fromLatin1(aRegister.name)).arg(address, 0, 16)); + .arg(registerNameStr).arg(address, 0, 16)); actShowDisassemblerAt->setText(tr("Open Disassembler at 0x%1") .arg(address, 0, 16)); actShowDisassemblerAt->setEnabled(engine->hasCapability(DisassemblerCapability)); @@ -207,7 +207,7 @@ void RegisterTreeView::contextMenuEvent(QContextMenuEvent *ev) } menu.addSeparator(); - const int base = handler->numberBase(); + const int base = idx.data(RegisterNumberBaseRole).toInt(); QAction *act16 = menu.addAction(tr("Hexadecimal")); act16->setCheckable(true); act16->setChecked(base == 16); @@ -230,14 +230,20 @@ void RegisterTreeView::contextMenuEvent(QContextMenuEvent *ev) if (act == actReload) { engine->reloadRegisters(); } else if (act == actEditMemory) { - const QString registerName = QString::fromLatin1(aRegister.name); - engine->openMemoryView(address, 0, - RegisterMemoryView::registerMarkup(address, registerName), - QPoint(), RegisterMemoryView::title(registerName), 0); + MemoryViewSetupData data; + data.startAddress = address; + data.registerName = registerName; + data.markup = RegisterMemoryView::registerMarkup(address, registerName); + data.title = RegisterMemoryView::title(registerName); + engine->openMemoryView(data); } else if (act == actViewMemory) { - engine->openMemoryView(idx.row(), - DebuggerEngine::MemoryTrackRegister|DebuggerEngine::MemoryView, - QList<MemoryMarkup>(), position, QString(), this); + MemoryViewSetupData data; + data.startAddress = address; + data.flags = DebuggerEngine::MemoryTrackRegister|DebuggerEngine::MemoryView, + data.registerName = registerName; + data.pos = position; + data.parent = this; + engine->openMemoryView(data); } else if (act == actShowDisassembler) { AddressDialog dialog; if (address) @@ -247,13 +253,13 @@ void RegisterTreeView::contextMenuEvent(QContextMenuEvent *ev) } else if (act == actShowDisassemblerAt) { engine->openDisassemblerView(Location(address)); } else if (act == act16) - handler->setNumberBase(16); + handler->setNumberBase(registerName, 16); else if (act == act10) - handler->setNumberBase(10); + handler->setNumberBase(registerName, 10); else if (act == act8) - handler->setNumberBase(8); + handler->setNumberBase(registerName, 8); else if (act == act2) - handler->setNumberBase(2); + handler->setNumberBase(registerName, 2); } void RegisterTreeView::reloadRegisters() diff --git a/src/plugins/debugger/shared/cdbsymbolpathlisteditor.cpp b/src/plugins/debugger/shared/cdbsymbolpathlisteditor.cpp index 020837c718..7e0628120a 100644 --- a/src/plugins/debugger/shared/cdbsymbolpathlisteditor.cpp +++ b/src/plugins/debugger/shared/cdbsymbolpathlisteditor.cpp @@ -31,6 +31,7 @@ #include "cdbsymbolpathlisteditor.h" #include <coreplugin/icore.h> +#include <coreplugin/messagebox.h> #include <utils/pathchooser.h> #include <utils/checkablemessagebox.h> @@ -67,8 +68,8 @@ CacheDirectoryDialog::CacheDirectoryDialog(QWidget *parent) : setLayout(mainLayout); - connect(m_buttonBox, SIGNAL(accepted()), this, SLOT(accept())); - connect(m_buttonBox, SIGNAL(rejected()), this, SLOT(reject())); + connect(m_buttonBox, &QDialogButtonBox::accepted, this, &CacheDirectoryDialog::accept); + connect(m_buttonBox, &QDialogButtonBox::rejected, this, &CacheDirectoryDialog::reject); } void CacheDirectoryDialog::setPath(const QString &p) @@ -98,15 +99,15 @@ void CacheDirectoryDialog::accept() } // Does a file of the same name exist? if (fi.exists()) { - QMessageBox::warning(this, tr("Already Exists"), - tr("A file named \"%1\" already exists.").arg(cache)); + Core::AsynchronousMessageBox::warning(tr("Already Exists"), + tr("A file named \"%1\" already exists.").arg(cache)); return; } // Create QDir root(QDir::root()); if (!root.mkpath(cache)) { - QMessageBox::warning(this, tr("Cannot Create"), - tr("The folder \"%1\" could not be created.").arg(cache)); + Core::AsynchronousMessageBox::warning(tr("Cannot Create"), + tr("The folder \"%1\" could not be created.").arg(cache)); return; } QDialog::accept(); diff --git a/src/plugins/debugger/snapshothandler.h b/src/plugins/debugger/snapshothandler.h index 9cd3ee35e9..0a7c0f0441 100644 --- a/src/plugins/debugger/snapshothandler.h +++ b/src/plugins/debugger/snapshothandler.h @@ -35,18 +35,16 @@ #include <QPointer> namespace Debugger { +namespace Internal { class DebuggerEngine; -namespace Internal { - //////////////////////////////////////////////////////////////////////// // // SnapshotModel // //////////////////////////////////////////////////////////////////////// - class SnapshotHandler : public QAbstractTableModel { Q_OBJECT diff --git a/src/plugins/debugger/sourceagent.cpp b/src/plugins/debugger/sourceagent.cpp index 69e438d895..937836c229 100644 --- a/src/plugins/debugger/sourceagent.cpp +++ b/src/plugins/debugger/sourceagent.cpp @@ -40,16 +40,16 @@ #include <cppeditor/cppeditorconstants.h> +#include <utils/fileutils.h> #include <utils/qtcassert.h> #include <QDebug> -#include <QFileInfo> - #include <QTextBlock> #include <limits.h> using namespace Core; +using namespace TextEditor; namespace Debugger { namespace Internal { @@ -61,9 +61,9 @@ public: ~SourceAgentPrivate(); public: - QPointer<TextEditor::BaseTextEditor> editor; + QPointer<BaseTextEditor> editor; QPointer<DebuggerEngine> engine; - TextEditor::TextMark *locationMark; + TextMark *locationMark; QString path; QString producer; }; @@ -73,7 +73,6 @@ SourceAgentPrivate::SourceAgentPrivate() , locationMark(0) , producer(QLatin1String("remote")) { - } SourceAgentPrivate::~SourceAgentPrivate() @@ -104,14 +103,11 @@ void SourceAgent::setSourceProducerName(const QString &name) void SourceAgent::setContent(const QString &filePath, const QString &content) { QTC_ASSERT(d, return); - using namespace Core; - using namespace TextEditor; - d->path = filePath; if (!d->editor) { QString titlePattern = d->producer + QLatin1String(": ") - + QFileInfo(filePath).fileName(); + + Utils::FileName::fromString(filePath).fileName(); d->editor = qobject_cast<BaseTextEditor *>( EditorManager::openEditorWithContents( CppEditor::Constants::CPPEDITOR_ID, @@ -143,9 +139,11 @@ void SourceAgent::updateLocationMarker() d->locationMark = 0; if (d->engine->stackHandler()->currentFrame().file == d->path) { int lineNumber = d->engine->stackHandler()->currentFrame().line; - d->locationMark = new TextEditor::TextMark(QString(), lineNumber); - d->locationMark->setIcon(Internal::locationMarkIcon()); - d->locationMark->setPriority(TextEditor::TextMark::HighPriority); + + d->locationMark = new TextMark(QString(), lineNumber); + d->locationMark->setIcon(locationMarkIcon()); + d->locationMark->setPriority(TextMark::HighPriority); + d->editor->textDocument()->addMark(d->locationMark); QTextCursor tc = d->editor->textCursor(); QTextBlock block = tc.document()->findBlockByNumber(lineNumber - 1); diff --git a/src/plugins/debugger/sourceagent.h b/src/plugins/debugger/sourceagent.h index c2c301d59f..3727023e7d 100644 --- a/src/plugins/debugger/sourceagent.h +++ b/src/plugins/debugger/sourceagent.h @@ -34,16 +34,15 @@ #include <QString> namespace Debugger { - -class DebuggerEngine; - namespace Internal { +class DebuggerEngine; class SourceAgentPrivate; + class SourceAgent { public: - explicit SourceAgent(Debugger::DebuggerEngine *engine); + explicit SourceAgent(DebuggerEngine *engine); ~SourceAgent(); void setSourceProducerName(const QString &name); void resetLocation(); diff --git a/src/plugins/debugger/sourceutils.cpp b/src/plugins/debugger/sourceutils.cpp index 0c6e96e502..9e1d80bf9b 100644 --- a/src/plugins/debugger/sourceutils.cpp +++ b/src/plugins/debugger/sourceutils.cpp @@ -264,7 +264,7 @@ bool getUninitializedVariables(const Snapshot &snapshot, bool isCppEditor(TextEditorWidget *editorWidget) { const TextDocument *document = editorWidget->textDocument(); - return ProjectFile::classify(document->filePath()) != ProjectFile::Unclassified; + return ProjectFile::classify(document->filePath().toString()) != ProjectFile::Unclassified; } QString cppFunctionAt(const QString &fileName, int line, int column) @@ -282,7 +282,6 @@ QString cppExpressionAt(TextEditorWidget *editorWidget, int pos, int *line, int *column, QString *function, int *scopeFromLine, int *scopeToLine) { - *line = *column = 0; if (function) function->clear(); @@ -297,15 +296,13 @@ QString cppExpressionAt(TextEditorWidget *editorWidget, int pos, // Fetch the expression's code. ExpressionUnderCursor expressionUnderCursor; expr = expressionUnderCursor(tc); - *column = tc.positionInBlock(); - *line = tc.blockNumber(); - } else { - *column = tc.positionInBlock(); - *line = tc.blockNumber(); } + *column = tc.positionInBlock(); + *line = tc.blockNumber() + 1; + if (!expr.isEmpty()) { - QString fileName = editorWidget->textDocument()->filePath(); + QString fileName = editorWidget->textDocument()->filePath().toString(); const Snapshot snapshot = CppModelManager::instance()->snapshot(); if (const Document::Ptr document = snapshot.document(fileName)) { QString func = document->functionAt(*line, *column, scopeFromLine, scopeToLine); diff --git a/src/plugins/debugger/stackhandler.cpp b/src/plugins/debugger/stackhandler.cpp index dfeeb66084..ec5fe96641 100644 --- a/src/plugins/debugger/stackhandler.cpp +++ b/src/plugins/debugger/stackhandler.cpp @@ -34,11 +34,11 @@ #include "debuggercore.h" #include "simplifytype.h" +#include <utils/fileutils.h> #include <utils/qtcassert.h> #include <utils/savedaction.h> #include <QDebug> -#include <QFileInfo> namespace Debugger { namespace Internal { @@ -64,8 +64,8 @@ StackHandler::StackHandler() m_contentsValid = false; m_currentIndex = -1; m_canExpand = false; - connect(action(OperateByInstruction), SIGNAL(triggered()), - this, SLOT(resetModel())); + connect(action(OperateByInstruction), &QAction::triggered, + this, &StackHandler::resetModel); } StackHandler::~StackHandler() @@ -80,7 +80,7 @@ int StackHandler::rowCount(const QModelIndex &parent) const int StackHandler::columnCount(const QModelIndex &parent) const { - return parent.isValid() ? 0 : 5; + return parent.isValid() ? 0 : StackColumnCount; } QVariant StackHandler::data(const QModelIndex &index, int role) const @@ -89,11 +89,11 @@ QVariant StackHandler::data(const QModelIndex &index, int role) const return QVariant(); if (index.row() == m_stackFrames.size()) { - if (role == Qt::DisplayRole && index.column() == 0) + if (role == Qt::DisplayRole && index.column() == StackLevelColumn) return tr("..."); - if (role == Qt::DisplayRole && index.column() == 1) + if (role == Qt::DisplayRole && index.column() == StackFunctionNameColumn) return tr("<More>"); - if (role == Qt::DecorationRole && index.column() == 0) + if (role == Qt::DecorationRole && index.column() == StackLevelColumn) return m_emptyIcon; return QVariant(); } @@ -102,15 +102,15 @@ QVariant StackHandler::data(const QModelIndex &index, int role) const if (role == Qt::DisplayRole) { switch (index.column()) { - case 0: // Stack frame level + case StackLevelColumn: return QString::number(frame.level); - case 1: // Function name + case StackFunctionNameColumn: return simplifyType(frame.function); - case 2: // File name - return frame.file.isEmpty() ? frame.from : QFileInfo(frame.file).fileName(); - case 3: // Line number + case StackFileNameColumn: + return frame.file.isEmpty() ? frame.from : Utils::FileName::fromString(frame.file).fileName(); + case StackLineNumberColumn: return frame.line > 0 ? QVariant(frame.line) : QVariant(); - case 4: // Address + case StackAddressColumn: if (frame.address) return QString::fromLatin1("0x%1").arg(frame.address, 0, 16); return QString(); @@ -118,7 +118,7 @@ QVariant StackHandler::data(const QModelIndex &index, int role) const return QVariant(); } - if (role == Qt::DecorationRole && index.column() == 0) { + if (role == Qt::DecorationRole && index.column() == StackLevelColumn) { // Return icon that indicates whether this is the active stack frame return (m_contentsValid && index.row() == m_currentIndex) ? m_positionIcon : m_emptyIcon; diff --git a/src/plugins/debugger/stackhandler.h b/src/plugins/debugger/stackhandler.h index 3e8bcbf57f..26d94bff4c 100644 --- a/src/plugins/debugger/stackhandler.h +++ b/src/plugins/debugger/stackhandler.h @@ -38,21 +38,16 @@ namespace Debugger { namespace Internal { -//////////////////////////////////////////////////////////////////////// -// -// StackCookie -// -//////////////////////////////////////////////////////////////////////// - -struct StackCookie +enum StackColumns { - StackCookie() : isFull(true), gotoLocation(false) {} - StackCookie(bool full, bool jump) : isFull(full), gotoLocation(jump) {} - bool isFull; - bool gotoLocation; + StackLevelColumn, + StackFunctionNameColumn, + StackFileNameColumn, + StackLineNumberColumn, + StackAddressColumn, + StackColumnCount = StackAddressColumn, }; - //////////////////////////////////////////////////////////////////////// // // StackModel @@ -110,7 +105,4 @@ private: } // namespace Internal } // namespace Debugger -Q_DECLARE_METATYPE(Debugger::Internal::StackCookie) - - #endif // DEBUGGER_STACKHANDLER_H diff --git a/src/plugins/debugger/stackwindow.cpp b/src/plugins/debugger/stackwindow.cpp index 15db90da04..4c863307c0 100644 --- a/src/plugins/debugger/stackwindow.cpp +++ b/src/plugins/debugger/stackwindow.cpp @@ -37,6 +37,7 @@ #include "debuggerdialogs.h" #include "memoryagent.h" +#include <coreplugin/messagebox.h> #include <utils/savedaction.h> @@ -50,7 +51,6 @@ #include <QContextMenuEvent> #include <QInputDialog> #include <QFileDialog> -#include <QMessageBox> #include <QMenu> namespace Debugger { @@ -71,7 +71,7 @@ StackTreeView::StackTreeView() void StackTreeView::showAddressColumn(bool on) { - setColumnHidden(4, !on); + setColumnHidden(StackAddressColumn, !on); } void StackTreeView::rowActivated(const QModelIndex &index) @@ -82,8 +82,8 @@ void StackTreeView::rowActivated(const QModelIndex &index) void StackTreeView::setModel(QAbstractItemModel *model) { BaseTreeView::setModel(model); - resizeColumnToContents(0); - resizeColumnToContents(3); + resizeColumnToContents(StackLevelColumn); + resizeColumnToContents(StackLineNumberColumn); showAddressColumn(action(UseAddressInStackView)->isChecked()); } @@ -127,7 +127,7 @@ void saveTaskFile(QWidget *parent, const StackHandler *sh) const QString fileName = fileDialog.selectedFiles().front(); file.setFileName(fileName); if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) { - QMessageBox::warning(parent, StackTreeView::tr("Cannot Open Task File"), + Core::AsynchronousMessageBox::warning(StackTreeView::tr("Cannot Open Task File"), StackTreeView::tr("Cannot open \"%1\": %2").arg(QDir::toNativeSeparators(fileName), file.errorString())); } } @@ -214,12 +214,13 @@ void StackTreeView::contextMenuEvent(QContextMenuEvent *ev) if (act == actCopyContents) { copyContentsToClipboard(); } else if (act == actShowMemory) { - const QString title = tr("Memory at Frame #%1 (%2) 0x%3"). - arg(row).arg(frame.function).arg(address, 0, 16); - QList<MemoryMarkup> ml; - ml.push_back(MemoryMarkup(address, 1, QColor(Qt::blue).lighter(), + MemoryViewSetupData data; + data.startAddress = address; + data.title = tr("Memory at Frame #%1 (%2) 0x%3"). + arg(row).arg(frame.function).arg(address, 0, 16); + data.markup.push_back(MemoryMarkup(address, 1, QColor(Qt::blue).lighter(), tr("Frame #%1 (%2)").arg(row).arg(frame.function))); - engine->openMemoryView(address, 0, ml, QPoint(), title); + engine->openMemoryView(data); } else if (act == actShowDisassemblerAtAddress) { AddressDialog dialog; if (address) diff --git a/src/plugins/debugger/terminal.cpp b/src/plugins/debugger/terminal.cpp new file mode 100644 index 0000000000..e133f36572 --- /dev/null +++ b/src/plugins/debugger/terminal.cpp @@ -0,0 +1,169 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://www.qt.io/licensing. For further information +** use the contact form at http://www.qt.io/contact-us. +** +** 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 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +****************************************************************************/ + +#include "terminal.h" + +#include <QDebug> +#include <QIODevice> +#include <QSocketNotifier> + +#include <utils/qtcassert.h> + +#ifdef Q_OS_UNIX +# define DEBUGGER_USE_TERMINAL +#endif + +#ifdef DEBUGGER_USE_TERMINAL +# include <errno.h> +# include <fcntl.h> +# include <stdlib.h> +# include <string.h> +# include <unistd.h> +# include <sys/ioctl.h> +# include <sys/stat.h> +#endif + +namespace Debugger { +namespace Internal { + +static QString currentError() +{ + int err = errno; + return QString::fromLatin1(strerror(err)); +} + +Terminal::Terminal(QObject *parent) + : QObject(parent), m_isUsable(false), m_masterFd(-1), m_masterReader(0) +{ +} + +void Terminal::setup() +{ +#ifdef DEBUGGER_USE_TERMINAL + if (!qEnvironmentVariableIsSet("QTC_USE_PTY")) + return; + + m_masterFd = ::open("/dev/ptmx", O_RDWR); + if (m_masterFd < 0) { + error(tr("Terminal: Cannot open /dev/ptmx: %1").arg(currentError())); + return; + } + + const char *sName = ptsname(m_masterFd); + if (!sName) { + error(tr("Terminal: ptsname failed: %1").arg(currentError())); + return; + } + m_slaveName = sName; + + struct stat s; + int r = ::stat(m_slaveName.constData(), &s); + if (r != 0) { + error(tr("Terminal: Error: %1").arg(currentError())); + return; + } + if (!S_ISCHR(s.st_mode)) { + error(tr("Terminal: Slave is no character device")); + return; + } + + m_masterReader = new QSocketNotifier(m_masterFd, QSocketNotifier::Read, this); + connect(m_masterReader, &QSocketNotifier::activated, + this, &Terminal::onSlaveReaderActivated); + + r = grantpt(m_masterFd); + if (r != 0) { + error(tr("Terminal: grantpt failed: %1").arg(currentError())); + return; + } + + r = unlockpt(m_masterFd); + if (r != 0) { + error(tr("Terminal: unlock failed: %1").arg(currentError())); + return; + } + + m_isUsable = true; +#endif +} + +bool Terminal::isUsable() const +{ + return m_isUsable; +} + +int Terminal::write(const QByteArray &msg) +{ +#ifdef DEBUGGER_USE_TERMINAL + return ::write(m_masterFd, msg.constData(), msg.size()); +#else + Q_UNUSED(msg); + return -1; +#endif +} + +bool Terminal::sendInterrupt() +{ +#ifdef DEBUGGER_USE_TERMINAL + if (!m_isUsable) + return false; + ssize_t written = ::write(m_masterFd, "\003", 1); + return written == 1; +#else + return false; +#endif +} + +void Terminal::onSlaveReaderActivated(int fd) +{ +#ifdef DEBUGGER_USE_TERMINAL + ssize_t available = 0; + int ret = ::ioctl(fd, FIONREAD, (char *) &available); + if (ret != 0) + return; + + QByteArray buffer(available, Qt::Uninitialized); + ssize_t got = ::read(fd, buffer.data(), available); + int err = errno; + if (got < 0) { + error(tr("Terminal: Read failed: %1").arg(QString::fromLatin1(strerror(err)))); + return; + } + buffer.resize(got); + if (got >= 0) + stdOutReady(QString::fromUtf8(buffer)); +#else + Q_UNUSED(fd); +#endif +} + +} // namespace Internal +} // namespace Debugger + diff --git a/src/plugins/debugger/breakpointmarker.h b/src/plugins/debugger/terminal.h index fee89edd65..3ddfffe2f5 100644 --- a/src/plugins/debugger/breakpointmarker.h +++ b/src/plugins/debugger/terminal.h @@ -28,36 +28,45 @@ ** ****************************************************************************/ -#ifndef DEBUGGER_BREAKPOINTMARKER_H -#define DEBUGGER_BREAKPOINTMARKER_H +#ifndef DEBUGGER_TERMINAL_H +#define DEBUGGER_TERMINAL_H -#include "breakpoint.h" - -#include <texteditor/textmark.h> +#include <QCoreApplication> +#include <QSocketNotifier> namespace Debugger { namespace Internal { -// The red blob on the left side in the cpp editor. -class BreakpointMarker : public TextEditor::TextMark +class Terminal : public QObject { + Q_OBJECT + public: - BreakpointMarker(BreakpointModelId id, const QString &fileName, int lineNumber); - ~BreakpointMarker(); - void removedFromEditor(); - void updateLineNumber(int lineNumber); - void updateFileName(const QString &fileName); - bool isDraggable() const { return true; } - void dragToLine(int lineNumber); - bool isClickable() const { return true; } - void clicked(); + Terminal(QObject *parent = 0); + + void setup(); + bool isUsable() const; + + QByteArray slaveDevice() const { return m_slaveName; } + + int write(const QByteArray &msg); + bool sendInterrupt(); + +signals: + void stdOutReady(const QString &); + void stdErrReady(const QString &); + void error(const QString &); private: - BreakpointModelId m_id; - friend class BreakHandler; + void onSlaveReaderActivated(int fd); + + bool m_isUsable; + int m_masterFd; + QSocketNotifier *m_masterReader; + QByteArray m_slaveName; }; } // namespace Internal } // namespace Debugger -#endif +#endif // DEBUGGER_TERMINAL_H diff --git a/src/plugins/debugger/unstartedappwatcherdialog.cpp b/src/plugins/debugger/unstartedappwatcherdialog.cpp index 9c9aa3741e..5c683aa40e 100644 --- a/src/plugins/debugger/unstartedappwatcherdialog.cpp +++ b/src/plugins/debugger/unstartedappwatcherdialog.cpp @@ -39,7 +39,7 @@ #include <projectexplorer/target.h> #include <projectexplorer/project.h> #include <projectexplorer/kitmanager.h> -#include <projectexplorer/projectexplorer.h> +#include <projectexplorer/projecttree.h> #include <projectexplorer/runconfiguration.h> #include <projectexplorer/buildconfiguration.h> #include <projectexplorer/localapplicationrunconfiguration.h> @@ -88,7 +88,7 @@ UnstartedAppWatcherDialog::UnstartedAppWatcherDialog(QWidget *parent) m_kitChooser->populate(); m_kitChooser->setVisible(true); - Project *project = ProjectExplorerPlugin::currentProject(); + Project *project = ProjectTree::currentProject(); if (project && project->activeTarget() && project->activeTarget()->kit()) m_kitChooser->setCurrentKitId(project->activeTarget()->kit()->id()); else if (KitManager::defaultKit()) @@ -147,12 +147,17 @@ UnstartedAppWatcherDialog::UnstartedAppWatcherDialog(QWidget *parent) mainLayout->addRow(buttonsLine); setLayout(mainLayout); - connect(m_pathChooser, SIGNAL(beforeBrowsing()), this, SLOT(selectExecutable())); - connect(m_watchingPushButton, SIGNAL(toggled(bool)), this, SLOT(startStopWatching(bool))); - connect(m_pathChooser, SIGNAL(pathChanged(QString)), this, SLOT(stopAndCheckExecutable())); - connect(m_closePushButton, SIGNAL(clicked()), this, SLOT(reject())); - connect(&m_timer, SIGNAL(timeout()), this, SLOT(findProcess())); - connect(m_kitChooser, &ProjectExplorer::KitChooser::currentIndexChanged, + connect(m_pathChooser, &Utils::PathChooser::beforeBrowsing, + this, &UnstartedAppWatcherDialog::selectExecutable); + connect(m_watchingPushButton, &QAbstractButton::toggled, + this, &UnstartedAppWatcherDialog::startStopWatching); + connect(m_pathChooser, &Utils::PathChooser::pathChanged, this, + &UnstartedAppWatcherDialog::stopAndCheckExecutable); + connect(m_closePushButton, &QAbstractButton::clicked, + this, &QDialog::reject); + connect(&m_timer, &QTimer::timeout, + this, &UnstartedAppWatcherDialog::findProcess); + connect(m_kitChooser, &KitChooser::currentIndexChanged, this, &UnstartedAppWatcherDialog::kitChanged); kitChanged(); @@ -163,7 +168,7 @@ void UnstartedAppWatcherDialog::selectExecutable() { QString path; - Project *project = ProjectExplorerPlugin::currentProject(); + Project *project = ProjectTree::currentProject(); if (project && project->activeTarget() && project->activeTarget()->activeRunConfiguration()) { diff --git a/src/plugins/debugger/unstartedappwatcherdialog.h b/src/plugins/debugger/unstartedappwatcherdialog.h index 618a9f6381..5edb21781f 100644 --- a/src/plugins/debugger/unstartedappwatcherdialog.h +++ b/src/plugins/debugger/unstartedappwatcherdialog.h @@ -62,20 +62,19 @@ public: ProjectExplorer::DeviceProcessItem currentProcess() const; bool hideOnAttach() const; bool continueOnAttach() const; + void startWatching(); -public slots: +signals: + void processFound(); + +private: void selectExecutable(); - void startWatching(); void pidFound(const ProjectExplorer::DeviceProcessItem &p); void startStopWatching(bool start); void findProcess(); void stopAndCheckExecutable(); void kitChanged(); -signals: - void processFound(); - -private: enum UnstartedAppWacherState { InvalidWacherState, diff --git a/src/plugins/debugger/watchdata.cpp b/src/plugins/debugger/watchdata.cpp index 08647b04ff..197677caf0 100644 --- a/src/plugins/debugger/watchdata.cpp +++ b/src/plugins/debugger/watchdata.cpp @@ -156,6 +156,15 @@ bool WatchData::isEqual(const WatchData &other) const && error == other.error; } +bool WatchData::isAncestorOf(const QByteArray &childIName) const +{ + if (iname.size() >= childIName.size()) + return false; + if (!childIName.startsWith(iname)) + return false; + return childIName.at(iname.size()) == '.'; +} + bool WatchData::isVTablePointer() const { // First case: Cdb only. No user type can be named like this, this is safe. @@ -526,7 +535,7 @@ QString decodeItemHelper(const double &t) } template <class T> -void decodeArrayHelper(QList<WatchData> *list, const WatchData &tmplate, +void decodeArrayHelper(std::function<void(const WatchData &)> itemHandler, const WatchData &tmplate, const QByteArray &rawData) { const QByteArray ba = QByteArray::fromHex(rawData); @@ -542,62 +551,59 @@ void decodeArrayHelper(QList<WatchData> *list, const WatchData &tmplate, data.address += i * sizeof(T); data.exp = exp + QByteArray::number(data.address, 16); data.setAllUnneeded(); - list->append(data); + itemHandler(data); } } -static void decodeArray(QList<WatchData> *list, const WatchData &tmplate, +void decodeArrayData(std::function<void(const WatchData &)> itemHandler, const WatchData &tmplate, const QByteArray &rawData, int encoding) { switch (encoding) { case Hex2EncodedInt1: - decodeArrayHelper<signed char>(list, tmplate, rawData); + decodeArrayHelper<signed char>(itemHandler, tmplate, rawData); break; case Hex2EncodedInt2: - decodeArrayHelper<short>(list, tmplate, rawData); + decodeArrayHelper<short>(itemHandler, tmplate, rawData); break; case Hex2EncodedInt4: - decodeArrayHelper<int>(list, tmplate, rawData); + decodeArrayHelper<int>(itemHandler, tmplate, rawData); break; case Hex2EncodedInt8: - decodeArrayHelper<qint64>(list, tmplate, rawData); + decodeArrayHelper<qint64>(itemHandler, tmplate, rawData); break; case Hex2EncodedUInt1: - decodeArrayHelper<uchar>(list, tmplate, rawData); + decodeArrayHelper<uchar>(itemHandler, tmplate, rawData); break; case Hex2EncodedUInt2: - decodeArrayHelper<ushort>(list, tmplate, rawData); + decodeArrayHelper<ushort>(itemHandler, tmplate, rawData); break; case Hex2EncodedUInt4: - decodeArrayHelper<uint>(list, tmplate, rawData); + decodeArrayHelper<uint>(itemHandler, tmplate, rawData); break; case Hex2EncodedUInt8: - decodeArrayHelper<quint64>(list, tmplate, rawData); + decodeArrayHelper<quint64>(itemHandler, tmplate, rawData); break; case Hex2EncodedFloat4: - decodeArrayHelper<float>(list, tmplate, rawData); + decodeArrayHelper<float>(itemHandler, tmplate, rawData); break; case Hex2EncodedFloat8: - decodeArrayHelper<double>(list, tmplate, rawData); + decodeArrayHelper<double>(itemHandler, tmplate, rawData); break; default: qDebug() << "ENCODING ERROR: " << encoding; } } -void parseWatchData(const QSet<QByteArray> &expandedINames, - const WatchData &data0, const GdbMi &item, - QList<WatchData> *list) +void parseChildrenData(const WatchData &data0, const GdbMi &item, + std::function<void(const WatchData &)> itemHandler, + std::function<void(const WatchData &, const GdbMi &)> childHandler, + std::function<void(const WatchData &childTemplate, const QByteArray &encodedData, int encoding)> arrayDecoder) { //qDebug() << "HANDLE CHILDREN: " << data0.toString() << item.toString(); WatchData data = data0; - bool isExpanded = expandedINames.contains(data.iname); - if (!isExpanded) - data.setChildrenUnneeded(); + data.setChildrenUnneeded(); GdbMi children = item["children"]; - if (children.isValid() || !isExpanded) - data.setChildrenUnneeded(); data.updateType(item["type"]); GdbMi mi = item["editvalue"]; @@ -640,7 +646,7 @@ void parseWatchData(const QSet<QByteArray> &expandedINames, setWatchDataValueEditable(data, item["valueeditable"]); data.updateChildCount(item["numchild"]); //qDebug() << "\nAPPEND TO LIST: " << data.toString() << "\n"; - list->append(data); + itemHandler(data); bool ok = false; qulonglong addressBase = item["addrbase"].data().toULongLong(&ok, 0); @@ -657,7 +663,7 @@ void parseWatchData(const QSet<QByteArray> &expandedINames, int encoding = item["arrayencoding"].toInt(); childtemplate.iname = data.iname + '.'; childtemplate.address = addressBase; - decodeArray(list, childtemplate, mi.data(), encoding); + arrayDecoder(childtemplate, mi.data(), encoding); } else { for (int i = 0, n = children.children().size(); i != n; ++i) { const GdbMi &child = children.children().at(i); @@ -687,11 +693,28 @@ void parseWatchData(const QSet<QByteArray> &expandedINames, int encoding = child["keyencoded"].toInt(); data1.name = decodeData(key, encoding); } - parseWatchData(expandedINames, data1, child, list); + childHandler(data1, child); } } } +void parseWatchData(const WatchData &data0, const GdbMi &input, + QList<WatchData> *list) +{ + auto itemHandler = [list](const WatchData &data) { + list->append(data); + }; + auto childHandler = [list](const WatchData &innerData, const GdbMi &innerInput) { + parseWatchData(innerData, innerInput, list); + }; + auto arrayDecoder = [itemHandler](const WatchData &childTemplate, + const QByteArray &encodedData, int encoding) { + decodeArrayData(itemHandler, childTemplate, encodedData, encoding); + }; + + parseChildrenData(data0, input, itemHandler, childHandler, arrayDecoder); +} + } // namespace Internal } // namespace Debugger diff --git a/src/plugins/debugger/watchdata.h b/src/plugins/debugger/watchdata.h index cef0a6095d..b00de93220 100644 --- a/src/plugins/debugger/watchdata.h +++ b/src/plugins/debugger/watchdata.h @@ -34,6 +34,8 @@ #include <QCoreApplication> #include <QMetaType> +#include <functional> + namespace Debugger { namespace Internal { @@ -96,6 +98,7 @@ public: bool isVTablePointer() const; bool isEqual(const WatchData &other) const; + bool isAncestorOf(const QByteArray &childIName) const; void setError(const QString &); void setValue(const QString &); @@ -151,9 +154,20 @@ public: qint32 source; // Originated from dumper or symbol evaluation? (CDB only) }; -void parseWatchData(const QSet<QByteArray> &expandedINames, - const WatchData &parent, const GdbMi &child, - QList<WatchData> *insertions); +void decodeArrayData(std::function<void(const WatchData &)> itemHandler, + const WatchData &tmplate, + const QByteArray &rawData, + int encoding); + +void parseChildrenData(const WatchData &parent, const GdbMi &child, + std::function<void(const WatchData &)> itemHandler, + std::function<void(const WatchData &, const GdbMi &)> childHandler, + std::function<void(const WatchData &childTemplate, + const QByteArray &encodedData, + int encoding)> arrayDecoder); + +void parseWatchData(const WatchData &parent, const GdbMi &child, + QList<WatchData> *insertions); } // namespace Internal } // namespace Debugger diff --git a/src/plugins/debugger/watchhandler.cpp b/src/plugins/debugger/watchhandler.cpp index a45a9dee19..cb5ac6f30d 100644 --- a/src/plugins/debugger/watchhandler.cpp +++ b/src/plugins/debugger/watchhandler.cpp @@ -41,10 +41,13 @@ #include "imageviewer.h" #include "watchutils.h" +#include <coreplugin/icore.h> + #include <utils/algorithm.h> #include <utils/basetreeview.h> #include <utils/qtcassert.h> #include <utils/savedaction.h> +#include <utils/checkablemessagebox.h> #include <QDebug> #include <QFile> @@ -55,12 +58,7 @@ #include <cstring> #include <ctype.h> -//#define USE_WATCH_MODEL_TEST 0 -//#define USE_EXPENSIVE_CHECKS 0 - -#if USE_WATCH_MODEL_TEST -#include <modeltest.h> -#endif +using namespace Utils; namespace Debugger { namespace Internal { @@ -70,13 +68,6 @@ enum { debugModel = 0 }; #define MODEL_DEBUG(s) do { if (debugModel) qDebug() << s; } while (0) -#if USE_EXPENSIVE_CHECKS -#define CHECK(s) s -#else -#define CHECK(s) -#endif - - static QHash<QByteArray, int> theWatcherNames; static QHash<QByteArray, int> theTypeFormats; static QHash<QByteArray, int> theIndividualFormats; @@ -109,36 +100,6 @@ static QByteArray stripForFormat(const QByteArray &ba) return res; } -//////////////////////////////////////////////////////////////////// -// -// WatchItem -// -//////////////////////////////////////////////////////////////////// - -// Used to make sure the item cache is notified of construction and -// destruction of items. - -class WatchItem; -typedef QList<WatchItem *> WatchItems; - -WatchItem *itemConstructor(WatchModel *model, const QByteArray &iname); -void itemDestructor(WatchModel *model, WatchItem *item); - -class WatchItem : public WatchData -{ -public: - WatchItem *parent; // Not owned. - WatchItems children; // Not owned. Handled via itemDestructor(). - -private: - friend WatchItem *itemConstructor(WatchModel *model, const QByteArray &iname); - friend void itemDestructor(WatchModel *model, WatchItem *item); - - WatchItem() { parent = 0; } - ~WatchItem() { parent = 0; } - WatchItem(const WatchItem &); // Not implemented. -}; - /////////////////////////////////////////////////////////////////////// // // SeparatedView @@ -232,79 +193,33 @@ public: class WatchModel : public WatchModelBase { -private: - explicit WatchModel(WatchHandler *handler); - ~WatchModel(); - - friend WatchItem *itemConstructor(WatchModel *model, const QByteArray &iname); - friend void itemDestructor(WatchModel *model, WatchItem *item); - public: - int rowCount(const QModelIndex &idx = QModelIndex()) const; - int columnCount(const QModelIndex &idx) const; + explicit WatchModel(WatchHandler *handler); static QString nameForFormat(int format); TypeFormatList typeFormatList(const WatchData &value) const; -private: - QVariant data(const QModelIndex &idx, int role) const; bool setData(const QModelIndex &idx, const QVariant &value, int role); - QModelIndex index(int, int, const QModelIndex &idx) const; - QModelIndex parent(const QModelIndex &idx) const; - bool hasChildren(const QModelIndex &idx) const; - Qt::ItemFlags flags(const QModelIndex &idx) const; - QVariant headerData(int section, Qt::Orientation orientation, - int role = Qt::DisplayRole) const; - bool canFetchMore(const QModelIndex &parent) const; - void fetchMore(const QModelIndex &parent); - - void invalidateAll(const QModelIndex &parentIndex = QModelIndex()); - void resetValueCacheRecursively(WatchItem *item); - - WatchItem *createItem(const QByteArray &iname, const QString &name, WatchItem *parent); - - friend class WatchHandler; - - WatchItem *watchItem(const QModelIndex &) const; - QModelIndex watchIndex(const WatchItem *needle) const; - QModelIndex watchIndexHelper(const WatchItem *needle, - const WatchItem *parentItem, const QModelIndex &parentIndex) const; void insertDataItem(const WatchData &data, bool destructive); void reinsertAllData(); void reinsertAllDataHelper(WatchItem *item, QList<WatchData> *data); - bool ancestorChanged(const QSet<QByteArray> &parentINames, WatchItem *item) const; void insertBulkData(const QList<WatchData> &data); QString displayForAutoTest(const QByteArray &iname) const; void reinitialize(bool includeInspectData = false); - void destroyItem(WatchItem *item); // With model notification. - void destroyChildren(WatchItem *item); // With model notification. - void destroyHelper(const WatchItems &items); // Without model notification. - void emitDataChanged(int column, - const QModelIndex &parentIndex = QModelIndex()); friend QDebug operator<<(QDebug d, const WatchModel &m); - void dump(); - void dumpHelper(WatchItem *item); - void emitAllChanged(); - void showInEditorHelper(QString *contents, WatchItem *item, int level); void setCurrentItem(const QByteArray &iname); - QString displayType(const WatchData &typeIn) const; - QString displayName(const WatchItem *item) const; - QString displayValue(const WatchData &data) const; - QString formattedValue(const WatchData &data) const; QString removeNamespaces(QString str) const; - void formatRequests(QByteArray *out, const WatchItem *item) const; DebuggerEngine *engine() const; - int itemFormat(const WatchData &data) const; bool contentIsValid() const; WatchHandler *m_handler; // Not owned. - WatchItem *m_root; // Owned. + WatchItem *root() const { return static_cast<WatchItem *>(rootItem()); } WatchItem *m_localsRoot; // Not owned. WatchItem *m_inspectorRoot; // Not owned. WatchItem *m_watchRoot; // Not owned. @@ -312,110 +227,51 @@ private: WatchItem *m_tooltipRoot; // Not owned. QSet<QByteArray> m_expandedINames; - QSet<QByteArray> m_fetchTriggered; TypeFormatList builtinTypeFormatList(const WatchData &data) const; QStringList dumperTypeFormatList(const WatchData &data) const; DumperTypeFormats m_reportedTypeFormats; WatchItem *createItem(const QByteArray &iname); - WatchItem *createItem(const WatchData &data); - void assignData(WatchItem *item, const WatchData &data); WatchItem *findItem(const QByteArray &iname) const; friend class WatchItem; - typedef QHash<QByteArray, WatchItem *> Cache; - Cache m_cache; typedef QHash<QByteArray, QString> ValueCache; ValueCache m_valueCache; - #if USE_EXPENSIVE_CHECKS - QHash<const WatchItem *, QByteArray> m_cache2; - void checkTree(); - void checkItem(const WatchItem *item) const; - void checkTree(WatchItem *item, QSet<QByteArray> *inames); - #endif - void checkIndex(const QModelIndex &index) const; + void insertItem(WatchItem *item); + void reexpandItems(); }; WatchModel::WatchModel(WatchHandler *handler) : m_handler(handler) { setObjectName(QLatin1String("WatchModel")); - m_root = createItem(QByteArray(), tr("Root"), 0); - // Note: Needs to stay - m_localsRoot = createItem("local", tr("Locals"), m_root); - m_inspectorRoot = createItem("inspect", tr("Inspector"), m_root); - m_watchRoot = createItem("watch", tr("Expressions"), m_root); - m_returnRoot = createItem("return", tr("Return Value"), m_root); - m_tooltipRoot = createItem("tooltip", tr("Tooltip"), m_root); - - connect(action(SortStructMembers), &Utils::SavedAction::valueChanged, + + setHeader(QStringList() << tr("Name") << tr("Value") << tr("Type")); + auto root = new WatchItem; + root->appendChild(m_localsRoot = new WatchItem("local", tr("Locals"))); + root->appendChild(m_inspectorRoot = new WatchItem("inspect", tr("Inspector"))); + root->appendChild(m_watchRoot = new WatchItem("watch", tr("Expressions"))); + root->appendChild(m_returnRoot = new WatchItem("return", tr("Return Value"))); + root->appendChild(m_tooltipRoot = new WatchItem("tooltip", tr("Tooltip"))); + setRootItem(root); + + connect(action(SortStructMembers), &SavedAction::valueChanged, this, &WatchModel::reinsertAllData); - connect(action(ShowStdNamespace), &Utils::SavedAction::valueChanged, + connect(action(ShowStdNamespace), &SavedAction::valueChanged, this, &WatchModel::reinsertAllData); - connect(action(ShowQtNamespace), &Utils::SavedAction::valueChanged, + connect(action(ShowQtNamespace), &SavedAction::valueChanged, this, &WatchModel::reinsertAllData); } -WatchModel::~WatchModel() -{ - CHECK(checkItem(m_root)); - destroyChildren(m_root); - itemDestructor(this, m_root); - QTC_CHECK(m_cache.isEmpty()); -} - -WatchItem *itemConstructor(WatchModel *model, const QByteArray &iname) -{ - QTC_CHECK(!model->m_cache.contains(iname)); - WatchItem *item = new WatchItem(); - item->iname = iname; - model->m_cache[iname] = item; - CHECK(model->m_cache2[item] = iname); - CHECK(model->checkItem(item)); - return item; -} - -void itemDestructor(WatchModel *model, WatchItem *item) -{ - QTC_ASSERT(model->m_cache.value(item->iname) == item, return); - CHECK(model->checkItem(item)); - CHECK(model->m_cache2.remove(item)); - model->m_cache.remove(item->iname); - delete item; -} - -WatchItem *WatchModel::createItem(const QByteArray &iname, const QString &name, WatchItem *parent) -{ - WatchItem *item = itemConstructor(this, iname); - item->name = name; - item->hasChildren = true; // parent == 0; - item->state = 0; - item->parent = parent; - if (parent) - parent->children.append(item); - return item; -} - void WatchModel::reinitialize(bool includeInspectData) { - CHECK(checkTree()); - //MODEL_DEBUG("REMOVING " << n << " CHILDREN OF " << m_root->iname); - QTC_CHECK(m_root->children.size() == 5); - destroyChildren(m_localsRoot); - destroyChildren(m_watchRoot); - destroyChildren(m_returnRoot); - destroyChildren(m_tooltipRoot); - if (includeInspectData) { - destroyChildren(m_inspectorRoot); - QTC_CHECK(m_cache.size() == 6); - } - CHECK(checkTree()); -} - -void WatchModel::emitAllChanged() -{ - emit layoutChanged(); + m_localsRoot->removeChildren(); + m_watchRoot->removeChildren(); + m_returnRoot->removeChildren(); + m_tooltipRoot->removeChildren(); + if (includeInspectData) + m_inspectorRoot->removeChildren(); } DebuggerEngine *WatchModel::engine() const @@ -423,122 +279,40 @@ DebuggerEngine *WatchModel::engine() const return m_handler->m_engine; } -void WatchModel::dump() -{ - qDebug() << "\n"; - foreach (WatchItem *child, m_root->children) - dumpHelper(child); -} - -void WatchModel::dumpHelper(WatchItem *item) -{ - qDebug() << "ITEM: " << item->iname - << (item->parent ? item->parent->iname : "<none>"); - foreach (WatchItem *child, item->children) - dumpHelper(child); -} - -void WatchModel::destroyHelper(const WatchItems &items) -{ - for (int i = items.size(); --i >= 0; ) { - WatchItem *item = items.at(i); - destroyHelper(item->children); - itemDestructor(this, item); - } -} - -void WatchModel::destroyItem(WatchItem *item) -{ - const QByteArray iname = item->iname; - CHECK(checkTree()); - QTC_ASSERT(m_cache.contains(iname), return); - - // Deregister from model and parent. - // It's sufficient to do this non-recursively. - WatchItem *parent = item->parent; - QTC_ASSERT(parent, return); - QModelIndex parentIndex = watchIndex(parent); - checkIndex(parentIndex); - const int i = parent->children.indexOf(item); - //MODEL_DEBUG("NEED TO REMOVE: " << item->iname << "AT" << n); - beginRemoveRows(parentIndex, i, i); - parent->children.removeAt(i); - endRemoveRows(); - - // Destroy contents. - destroyHelper(item->children); - itemDestructor(this, item); - QTC_ASSERT(!m_cache.contains(iname), return); - CHECK(checkTree()); -} - -void WatchModel::destroyChildren(WatchItem *item) -{ - CHECK(checkTree()); - QTC_ASSERT(m_cache.contains(item->iname), return); - if (item->children.isEmpty()) - return; - - WatchItems items = item->children; - - // Deregister from model and parent. - // It's sufficient to do this non-recursively. - QModelIndex idx = watchIndex(item); - checkIndex(idx); - beginRemoveRows(idx, 0, items.size() - 1); - item->children.clear(); - endRemoveRows(); - - // Destroy contents. - destroyHelper(items); - CHECK(checkTree()); -} - WatchItem *WatchModel::findItem(const QByteArray &iname) const { - return m_cache.value(iname, 0); + return root()->findItem(iname); } -void WatchModel::checkIndex(const QModelIndex &index) const +WatchItem *WatchItem::findItem(const QByteArray &iname) { - if (index.isValid()) { - QTC_CHECK(index.model() == this); - } else { - QTC_CHECK(index.model() == 0); + if (d.iname == iname) + return this; + foreach (TreeItem *child, children()) { + auto witem = static_cast<WatchItem *>(child); + if (witem->d.iname == iname) + return witem; + if (witem->d.isAncestorOf(iname)) + return witem->findItem(iname); } -} - -WatchItem *WatchModel::createItem(const WatchData &data) -{ - WatchItem *item = itemConstructor(this, data.iname); - static_cast<WatchData &>(*item) = data; - return item; -} - -void WatchModel::assignData(WatchItem *item, const WatchData &data) -{ - CHECK(checkItem(item)); - QTC_ASSERT(data.iname == item->iname, - m_cache.remove(item->iname); - m_cache[data.iname] = item); - static_cast<WatchData &>(*item) = data; - CHECK(checkItem(item)); + return 0; } void WatchModel::reinsertAllData() { QList<WatchData> list; - reinsertAllDataHelper(m_root, &list); + foreach (TreeItem *child, rootItem()->children()) + reinsertAllDataHelper(static_cast<WatchItem *>(child), &list); reinitialize(true); insertBulkData(list); } void WatchModel::reinsertAllDataHelper(WatchItem *item, QList<WatchData> *data) { - data->append(*item); + data->append(item->d); data->back().setAllUnneeded(); - foreach (WatchItem *child, item->children) - reinsertAllDataHelper(child, data); + foreach (TreeItem *child, item->children()) + reinsertAllDataHelper(static_cast<WatchItem *>(child), data); } static QByteArray parentName(const QByteArray &iname) @@ -714,68 +488,66 @@ static QString translate(const QString &str) return quoteUnprintable(str); } -QString WatchModel::formattedValue(const WatchData &data) const +QString WatchItem::formattedValue() const { - const QString &value = data.value; - - if (data.type == "bool") { - if (value == QLatin1String("0")) + if (d.type == "bool") { + if (d.value == QLatin1String("0")) return QLatin1String("false"); - if (value == QLatin1String("1")) + if (d.value == QLatin1String("1")) return QLatin1String("true"); - return value; + return d.value; } - const int format = itemFormat(data); + const int format = itemFormat(); // Append quoted, printable character also for decimal. - if (data.type.endsWith("char") || data.type.endsWith("QChar")) { + if (d.type.endsWith("char") || d.type.endsWith("QChar")) { bool ok; - const int code = value.toInt(&ok); - return ok ? reformatCharacter(code, format) : value; + const int code = d.value.toInt(&ok); + return ok ? reformatCharacter(code, format) : d.value; } if (format == HexadecimalIntegerFormat || format == DecimalIntegerFormat || format == OctalIntegerFormat || format == BinaryIntegerFormat) { - bool isSigned = value.startsWith(QLatin1Char('-')); - quint64 raw = isSigned ? quint64(value.toLongLong()): value.toULongLong(); - return reformatInteger(raw, format, data.size, isSigned); + bool isSigned = d.value.startsWith(QLatin1Char('-')); + quint64 raw = isSigned ? quint64(d.value.toLongLong()) : d.value.toULongLong(); + return reformatInteger(raw, format, d.size, isSigned); } if (format == ScientificFloatFormat) { - double d = value.toDouble(); - return QString::number(d, 'e'); + double dd = d.value.toDouble(); + return QString::number(dd, 'e'); } if (format == CompactFloatFormat) { - double d = value.toDouble(); - return QString::number(d, 'g'); + double dd = d.value.toDouble(); + return QString::number(dd, 'g'); } - if (data.type == "va_list") - return value; + if (d.type == "va_list") + return d.value; - if (!isPointerType(data.type) && !data.isVTablePointer()) { + if (!isPointerType(d.type) && !d.isVTablePointer()) { bool ok = false; - qulonglong integer = value.toULongLong(&ok, 0); + qulonglong integer = d.value.toULongLong(&ok, 0); if (ok) { - const int format = itemFormat(data); - return reformatInteger(integer, format, data.size, false); + const int format = itemFormat(); + return reformatInteger(integer, format, d.size, false); } } - if (data.elided) { - QString v = value; + if (d.elided) { + QString v = d.value; v.chop(1); v = translate(v); - QString len = data.elided > 0 ? QString::number(data.elided) + QString len = d.elided > 0 ? QString::number(d.elided) : QLatin1String("unknown length"); return v + QLatin1String("\"... (") + len + QLatin1Char(')'); } - return translate(value); + return translate(d.value); } // Get a pointer address from pointer values reported by the debugger. @@ -791,7 +563,7 @@ static inline quint64 pointerValue(QString data) } // Return the type used for editing -static inline int editType(const WatchData &d) +int WatchItem::editType() const { if (d.type == "bool") return QVariant::Bool; @@ -806,9 +578,9 @@ static inline int editType(const WatchData &d) } // Convert to editable (see above) -static inline QVariant editValue(const WatchData &d) +QVariant WatchItem::editValue() const { - switch (editType(d)) { + switch (editType()) { case QVariant::Bool: return d.value != QLatin1String("0") && d.value != QLatin1String("false"); case QVariant::ULongLong: @@ -836,161 +608,28 @@ static inline QVariant editValue(const WatchData &d) return QVariant(translate(stringValue)); } -bool WatchModel::canFetchMore(const QModelIndex &idx) const +bool WatchItem::canFetchMore() const { - if (!idx.isValid()) + if (!d.hasChildren) return false; - WatchItem *item = watchItem(idx); - QTC_ASSERT(item, return false); - if (!contentIsValid() && !item->isInspect()) + if (!watchModel()) return false; - if (!item->iname.contains('.')) + if (!watchModel()->contentIsValid() && !d.isInspect()) return false; - return !m_fetchTriggered.contains(item->iname); + return !fetchTriggered; } -void WatchModel::fetchMore(const QModelIndex &idx) +void WatchItem::fetchMore() { - checkIndex(idx); - if (!idx.isValid()) - return; // Triggered by ModelTester. - WatchItem *item = watchItem(idx); - QTC_ASSERT(item, return); - QTC_ASSERT(!m_fetchTriggered.contains(item->iname), return); - m_expandedINames.insert(item->iname); - m_fetchTriggered.insert(item->iname); - if (item->children.isEmpty()) { - WatchData data = *item; - data.setChildrenNeeded(); + QTC_ASSERT(!fetchTriggered, return); + watchModel()->m_expandedINames.insert(d.iname); + fetchTriggered = true; + if (children().isEmpty()) { + d.setChildrenNeeded(); WatchUpdateFlags flags; flags.tryIncremental = true; - engine()->updateWatchData(data, flags); - } -} - -QModelIndex WatchModel::index(int row, int column, const QModelIndex &parent) const -{ - checkIndex(parent); - if (!hasIndex(row, column, parent)) - return QModelIndex(); - - const WatchItem *item = watchItem(parent); - QTC_ASSERT(item, return QModelIndex()); - if (row >= item->children.size()) - return QModelIndex(); - return createIndex(row, column, (void*)(item->children.at(row))); -} - -QModelIndex WatchModel::parent(const QModelIndex &idx) const -{ - checkIndex(idx); - if (!idx.isValid()) - return QModelIndex(); - - const WatchItem *item = watchItem(idx); - const WatchItem *parent = item->parent; - if (!parent || parent == m_root) - return QModelIndex(); - - const WatchItem *grandparent = parent->parent; - if (!grandparent) - return QModelIndex(); - - const auto &uncles = grandparent->children; - for (int i = 0, n = uncles.size(); i < n; ++i) - if (uncles.at(i) == parent) - return createIndex(i, 0, (void*) parent); - - return QModelIndex(); -} - -int WatchModel::rowCount(const QModelIndex &idx) const -{ - checkIndex(idx); - if (!idx.isValid()) - return m_root->children.size(); - if (idx.column() > 0) - return 0; - return watchItem(idx)->children.size(); -} - -int WatchModel::columnCount(const QModelIndex &idx) const -{ - checkIndex(idx); - return 3; -} - -bool WatchModel::hasChildren(const QModelIndex &parent) const -{ - checkIndex(parent); - WatchItem *item = watchItem(parent); - return !item || item->hasChildren; -} - -WatchItem *WatchModel::watchItem(const QModelIndex &idx) const -{ - checkIndex(idx); - WatchItem *item = idx.isValid() - ? static_cast<WatchItem*>(idx.internalPointer()) : m_root; - CHECK(checkItem(item)); - return item; -} - -QModelIndex WatchModel::watchIndex(const WatchItem *item) const -{ - CHECK(checkItem(item)); - return watchIndexHelper(item, m_root, QModelIndex()); -} - -QModelIndex WatchModel::watchIndexHelper(const WatchItem *needle, - const WatchItem *parentItem, const QModelIndex &parentIndex) const -{ - checkIndex(parentIndex); - if (needle == parentItem) - return parentIndex; - for (int i = parentItem->children.size(); --i >= 0; ) { - const WatchItem *childItem = parentItem->children.at(i); - QModelIndex childIndex = index(i, 0, parentIndex); - QModelIndex idx = watchIndexHelper(needle, childItem, childIndex); - checkIndex(idx); - if (idx.isValid()) - return idx; + watchModel()->engine()->updateWatchData(d, flags); } - return QModelIndex(); -} - -void WatchModel::emitDataChanged(int column, const QModelIndex &parentIndex) -{ - checkIndex(parentIndex); - QModelIndex idx1 = index(0, column, parentIndex); - QModelIndex idx2 = index(rowCount(parentIndex) - 1, column, parentIndex); - if (idx1.isValid() && idx2.isValid()) - emit dataChanged(idx1, idx2); - //qDebug() << "CHANGING:\n" << idx1 << "\n" << idx2 << "\n" - // << data(parentIndex, INameRole).toString(); - checkIndex(idx1); - checkIndex(idx2); - for (int i = rowCount(parentIndex); --i >= 0; ) - emitDataChanged(column, index(i, 0, parentIndex)); -} - -void WatchModel::invalidateAll(const QModelIndex &parentIndex) -{ - checkIndex(parentIndex); - QModelIndex idx1 = index(0, 0, parentIndex); - QModelIndex idx2 = index(rowCount(parentIndex) - 1, columnCount(parentIndex) - 1, parentIndex); - checkIndex(idx1); - checkIndex(idx2); - if (idx1.isValid() && idx2.isValid()) - emit dataChanged(idx1, idx2); -} - -void WatchModel::resetValueCacheRecursively(WatchItem *item) -{ - m_valueCache[item->iname] = item->value; - const WatchItems &items = item->children; - for (int i = items.size(); --i >= 0; ) - resetValueCacheRecursively(items.at(i)); } // Truncate value for item view, maintaining quotes. @@ -1005,12 +644,12 @@ static QString truncateValue(QString v) return v; } -int WatchModel::itemFormat(const WatchData &data) const +int WatchItem::itemFormat() const { - const int individualFormat = theIndividualFormats.value(data.iname, AutomaticFormat); + const int individualFormat = theIndividualFormats.value(d.iname, AutomaticFormat); if (individualFormat != AutomaticFormat) return individualFormat; - return theTypeFormats.value(stripForFormat(data.type), AutomaticFormat); + return theTypeFormats.value(stripForFormat(d.type), AutomaticFormat); } bool WatchModel::contentIsValid() const @@ -1022,57 +661,32 @@ bool WatchModel::contentIsValid() const return m_handler->m_contentsValid; } -#if USE_EXPENSIVE_CHECKS -void WatchModel::checkTree() -{ - QSet<QByteArray> inames; - checkTree(m_root, &inames); - QSet<QByteArray> current = m_cache.keys().toSet(); - Q_ASSERT(inames == current); -} - -void WatchModel::checkTree(WatchItem *item, QSet<QByteArray> *inames) -{ - checkItem(item); - inames->insert(item->iname); - for (int i = 0, n = item->children.size(); i != n; ++i) - checkTree(item->children.at(i), inames); -} - -void WatchModel::checkItem(const WatchItem *item) const -{ - Q_ASSERT(item->children.size() < 1000 * 1000); - Q_ASSERT(m_cache2.contains(item)); - Q_ASSERT(m_cache2.value(item) == item->iname); - Q_ASSERT(m_cache.value(item->iname) == item); -} -#endif - -static QString expression(const WatchItem *item) +QString WatchItem::expression() const { - if (!item->exp.isEmpty()) - return QString::fromLatin1(item->exp); - if (item->address && !item->type.isEmpty()) { + if (!d.exp.isEmpty()) + return QString::fromLatin1(d.exp); + if (d.address && !d.type.isEmpty()) { return QString::fromLatin1("*(%1*)%2"). - arg(QLatin1String(item->type), QLatin1String(item->hexAddress())); + arg(QLatin1String(d.type), QLatin1String(d.hexAddress())); } - if (const WatchItem *parent = item->parent) { - if (!parent->exp.isEmpty()) - return QString::fromLatin1("(%1).%2") - .arg(QString::fromLatin1(parent->exp), item->name); + if (const WatchItem *p = parentItem()) { + if (!p->d.exp.isEmpty()) + return QString::fromLatin1("(%1).%2").arg(QString::fromLatin1(p->d.exp), d.name); } return QString(); } -QString WatchModel::displayName(const WatchItem *item) const +QString WatchItem::displayName() const { QString result; - if (item->parent == m_returnRoot) - result = tr("returned value"); - else if (item->name == QLatin1String("*")) - result = QLatin1Char('*') + item->parent->name; + if (!parentItem()) + return result; + if (d.iname.startsWith("return")) + result = WatchModel::tr("returned value"); + else if (parentItem()->d.name == QLatin1String("*")) + result = QLatin1Char('*') + parentItem()->d.name; else - result = removeNamespaces(item->name); + result = watchModel()->removeNamespaces(d.name); // Simplyfy names that refer to base classes. if (result.startsWith(QLatin1Char('['))) { @@ -1084,144 +698,142 @@ QString WatchModel::displayName(const WatchItem *item) const return result; } -QString WatchModel::displayValue(const WatchData &data) const +QString WatchItem::displayValue() const { - QString result = removeNamespaces(truncateValue(formattedValue(data))); - if (result.isEmpty() && data.address) - result += QString::fromLatin1("@0x" + QByteArray::number(data.address, 16)); -// if (data.origaddr) -// result += QString::fromLatin1(" (0x" + QByteArray::number(data.origaddr, 16) + ')'); + QString result = watchModel()->removeNamespaces(truncateValue(formattedValue())); + if (result.isEmpty() && d.address) + result += QString::fromLatin1("@0x" + QByteArray::number(d.address, 16)); +// if (d.origaddr) +// result += QString::fromLatin1(" (0x" + QByteArray::number(d.origaddr, 16) + ')'); return result; } -QString WatchModel::displayType(const WatchData &data) const +QString WatchItem::displayType() const { - QString result = data.displayedType.isEmpty() - ? niceTypeHelper(data.type) - : data.displayedType; - if (data.bitsize) - result += QString::fromLatin1(":%1").arg(data.bitsize); + QString result = d.displayedType.isEmpty() + ? niceTypeHelper(d.type) + : d.displayedType; + if (d.bitsize) + result += QString::fromLatin1(":%1").arg(d.bitsize); result.remove(QLatin1Char('\'')); - result = removeNamespaces(result); + result = watchModel()->removeNamespaces(result); return result; } -QVariant WatchModel::data(const QModelIndex &idx, int role) const +QColor WatchItem::color() const { - checkIndex(idx); - if (!idx.isValid()) - return QVariant(); // Triggered by ModelTester. - - const WatchItem *item = watchItem(idx); - const WatchItem &data = *item; + static const QColor red(200, 0, 0); + static const QColor gray(140, 140, 140); + if (watchModel()) { + if (!d.valueEnabled) + return gray; + if (!watchModel()->contentIsValid() && !d.isInspect()) + return gray; + if (d.value.isEmpty()) // This might still show 0x... + return gray; + if (d.value != watchModel()->m_valueCache.value(d.iname)) + return red; + } + return QColor(); +} +QVariant WatchItem::data(int column, int role) const +{ switch (role) { case LocalsEditTypeRole: - return QVariant(editType(data)); + return QVariant(editType()); case LocalsNameRole: - return QVariant(data.name); + return QVariant(d.name); case LocalsIntegerBaseRole: - if (isPointerType(data.type)) // Pointers using 0x-convention + if (isPointerType(d.type)) // Pointers using 0x-convention return QVariant(16); - return QVariant(formatToIntegerBase(itemFormat(data))); + return QVariant(formatToIntegerBase(itemFormat())); case Qt::EditRole: { - switch (idx.column()) { + switch (column) { case 0: - return QVariant(expression(item)); + return QVariant(expression()); case 1: - return editValue(data); + return editValue(); case 2: // FIXME:: To be tested: Can debuggers handle those? - if (!data.displayedType.isEmpty()) - return data.displayedType; - return QString::fromUtf8(data.type); + if (!d.displayedType.isEmpty()) + return d.displayedType; + return QString::fromUtf8(d.type); } } case Qt::DisplayRole: { - switch (idx.column()) { + switch (column) { case 0: - return displayName(item); + return displayName(); case 1: - return displayValue(data); + return displayValue(); case 2: - return displayType(data); + return displayType(); } } case Qt::ToolTipRole: return boolSetting(UseToolTipsInLocalsView) - ? data.toToolTip() : QVariant(); - - case Qt::ForegroundRole: { - static const QVariant red(QColor(200, 0, 0)); - static const QVariant gray(QColor(140, 140, 140)); - if (idx.column() == 1) { - if (!data.valueEnabled) - return gray; - if (!contentIsValid() && !data.isInspect()) - return gray; - if (data.value.isEmpty()) // This might still show 0x... - return gray; - if (data.value != m_valueCache.value(data.iname)) - return red; - } - break; - } + ? d.toToolTip() : QVariant(); + + case Qt::ForegroundRole: + if (column == 1) + return color(); case LocalsExpressionRole: - return QVariant(expression(item)); + return QVariant(expression()); case LocalsRawExpressionRole: - return data.exp; + return d.exp; case LocalsINameRole: - return data.iname; + return d.iname; case LocalsExpandedRole: - return m_expandedINames.contains(data.iname); + return watchModel()->m_expandedINames.contains(d.iname); case LocalsTypeFormatListRole: - return QVariant::fromValue(typeFormatList(data)); + return QVariant::fromValue(watchModel()->typeFormatList(d)); case LocalsTypeRole: - return removeNamespaces(displayType(data)); + return watchModel()->removeNamespaces(displayType()); case LocalsRawTypeRole: - return QString::fromLatin1(data.type); + return QString::fromLatin1(d.type); case LocalsTypeFormatRole: - return theTypeFormats.value(stripForFormat(data.type), AutomaticFormat); + return theTypeFormats.value(stripForFormat(d.type), AutomaticFormat); case LocalsIndividualFormatRole: - return theIndividualFormats.value(data.iname, AutomaticFormat); + return theIndividualFormats.value(d.iname, AutomaticFormat); case LocalsRawValueRole: - return data.value; + return d.value; case LocalsObjectAddressRole: - return data.address; + return d.address; case LocalsPointerAddressRole: - return data.origaddr; + return d.origaddr; case LocalsIsWatchpointAtObjectAddressRole: { BreakpointParameters bp(WatchpointAtAddress); - bp.address = data.address; - return engine()->breakHandler()->findWatchpoint(bp) != 0; + bp.address = d.address; + return watchModel()->engine()->breakHandler()->findWatchpoint(bp) != 0; } case LocalsSizeRole: - return QVariant(data.size); + return QVariant(d.size); case LocalsIsWatchpointAtPointerAddressRole: - if (isPointerType(data.type)) { + if (isPointerType(d.type)) { BreakpointParameters bp(WatchpointAtAddress); - bp.address = pointerValue(data.value); - return engine()->breakHandler()->findWatchpoint(bp) != 0; + bp.address = pointerValue(d.value); + return watchModel()->engine()->breakHandler()->findWatchpoint(bp) != 0; } return false; @@ -1233,12 +845,12 @@ QVariant WatchModel::data(const QModelIndex &idx, int role) const bool WatchModel::setData(const QModelIndex &idx, const QVariant &value, int role) { - checkIndex(idx); - if (!idx.isValid()) return false; // Triggered by ModelTester. - WatchItem &data = *watchItem(idx); + WatchItem *item = static_cast<WatchItem *>(itemFromIndex(idx)); + QTC_ASSERT(item, return false); + const WatchData &data = item->d; switch (role) { case Qt::EditRole: @@ -1246,10 +858,10 @@ bool WatchModel::setData(const QModelIndex &idx, const QVariant &value, int role case 0: // Watch expression: See delegate. break; case 1: // Change value - engine()->assignValueInDebugger(&data, expression(&data), value); + engine()->assignValueInDebugger(&data, item->expression(), value); break; case 2: // TODO: Implement change type. - engine()->assignValueInDebugger(&data, expression(&data), value); + engine()->assignValueInDebugger(&data, item->expression(), value); break; } case LocalsExpandedRole: @@ -1283,66 +895,46 @@ bool WatchModel::setData(const QModelIndex &idx, const QVariant &value, int role return true; } -Qt::ItemFlags WatchModel::flags(const QModelIndex &idx) const +Qt::ItemFlags WatchItem::flags(int column) const { - checkIndex(idx); - if (!idx.isValid()) - return Qt::ItemFlags(); - - WatchItem *item = watchItem(idx); - QTC_ASSERT(item, return Qt::ItemFlags()); - const WatchData &data = *item; - if (!contentIsValid() && !data.isInspect()) + QTC_ASSERT(model(), return Qt::ItemFlags()); + if (!watchModel()->contentIsValid() && !d.isInspect()) 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 Qt::ItemFlags notEditable - = Qt::ItemIsSelectable | Qt::ItemIsEnabled; - static const Qt::ItemFlags editable = notEditable | Qt::ItemIsEditable; + const Qt::ItemFlags notEditable = Qt::ItemIsSelectable | Qt::ItemIsEnabled; + const Qt::ItemFlags editable = notEditable | Qt::ItemIsEditable; // Disable editing if debuggee is positively running except for Inspector data - const bool isRunning = engine() && engine()->state() == InferiorRunOk; - if (isRunning && engine() && !engine()->hasCapability(AddWatcherWhileRunningCapability) && - !data.isInspect()) + DebuggerEngine *engine = watchModel()->engine(); + const bool isRunning = engine && engine->state() == InferiorRunOk; + if (isRunning && engine && !engine->hasCapability(AddWatcherWhileRunningCapability) && + !d.isInspect()) return notEditable; - if (data.isWatcher()) { - if (idx.column() == 0 && data.iname.count('.') == 1) + if (d.isWatcher()) { + if (column == 0 && d.iname.count('.') == 1) return editable; // Watcher names are editable. - if (!data.name.isEmpty()) { + if (!d.name.isEmpty()) { // FIXME: Forcing types is not implemented yet. //if (idx.column() == 2) // return editable; // Watcher types can be set by force. - if (idx.column() == 1 && data.valueEditable) + if (column == 1 && d.valueEditable) return editable; // Watcher values are sometimes editable. } - } else if (data.isLocal()) { - if (idx.column() == 1 && data.valueEditable) + } else if (d.isLocal()) { + if (column == 1 && d.valueEditable) return editable; // Locals values are sometimes editable. - } else if (data.isInspect()) { - if (idx.column() == 1 && data.valueEditable) + } else if (d.isInspect()) { + if (column == 1 && d.valueEditable) return editable; // Inspector values are sometimes editable. } return notEditable; } -QVariant WatchModel::headerData(int section, Qt::Orientation orientation, int role) const -{ - if (orientation == Qt::Vertical) - return QVariant(); - if (role == Qt::DisplayRole) { - switch (section) { - case 0: return QString(tr("Name") + QLatin1String(" ")); - case 1: return QString(tr("Value") + QLatin1String(" ")); - case 2: return QString(tr("Type") + QLatin1String(" ")); - } - } - return QVariant(); -} - static inline QString msgArrayFormat(int n) { return WatchModel::tr("Array of %n items", 0, n); @@ -1486,148 +1078,85 @@ inline bool operator<(const WatchDataSortKey &k1, const WatchDataSortKey &k2) return watchDataLessThan(k1.iname, k1.sortId, k2.iname, k2.sortId); } -bool watchItemSorter(const WatchItem *item1, const WatchItem *item2) +bool watchItemSorter(const TreeItem *item1, const TreeItem *item2) { - return watchDataLessThan(item1->iname, item1->sortId, item2->iname, item2->sortId); + const WatchItem *it1 = static_cast<const WatchItem *>(item1); + const WatchItem *it2 = static_cast<const WatchItem *>(item2); + return watchDataLessThan(it1->d.iname, it1->d.sortId, it2->d.iname, it2->d.sortId); } -static int findInsertPosition(const QList<WatchItem *> &list, const WatchItem *item) +static int findInsertPosition(const QVector<TreeItem *> &list, const WatchItem *item) { sortWatchDataAlphabetically = boolSetting(SortStructMembers); - const QList<WatchItem *>::const_iterator it = - qLowerBound(list.begin(), list.end(), item, watchItemSorter); + const auto it = qLowerBound(list.begin(), list.end(), item, watchItemSorter); return it - list.begin(); } void WatchModel::insertDataItem(const WatchData &data, bool destructive) { -#if USE_WATCH_MODEL_TEST - (void) new ModelTest(this, this); -#endif - m_fetchTriggered.remove(data.iname); - CHECK(checkTree()); - QTC_ASSERT(!data.iname.isEmpty(), qDebug() << data.toString(); return); if (WatchItem *item = findItem(data.iname)) { // Remove old children. + item->fetchTriggered = false; if (destructive) - destroyChildren(item); + item->removeChildren(); // Overwrite old entry. - assignData(item, data); - QModelIndex idx = watchIndex(item); - checkIndex(idx); - emit dataChanged(idx, idx.sibling(idx.row(), 2)); + item->d = data; + item->update(); } else { // Add new entry. WatchItem *parent = findItem(parentName(data.iname)); QTC_ASSERT(parent, return); - WatchItem *newItem = createItem(data); - newItem->parent = parent; - const int row = findInsertPosition(parent->children, newItem); - QModelIndex idx = watchIndex(parent); - checkIndex(idx); - beginInsertRows(idx, row, row); - parent->children.insert(row, newItem); - endInsertRows(); - if (m_expandedINames.contains(parent->iname)) - emit itemIsExpanded(idx); + WatchItem *newItem = new WatchItem; + newItem->d = data; + const int row = findInsertPosition(parent->children(), newItem); + parent->insertChild(row, newItem); + if (m_expandedINames.contains(parent->d.iname)) { + emit inameIsExpanded(parent->d.iname); + emit itemIsExpanded(indexFromItem(parent)); + } } } -// Identify items that have to be removed, i.e. current items that -// have an ancestor in the list, but do not appear in the list themselves. -bool WatchModel::ancestorChanged(const QSet<QByteArray> &inames, WatchItem *item) const -{ - if (item == m_root) - return false; - WatchItem *parent = item->parent; - if (inames.contains(parent->iname)) - return true; - return ancestorChanged(inames, parent); -} - void WatchModel::insertBulkData(const QList<WatchData> &list) { -#if 1 for (int i = 0, n = list.size(); i != n; ++i) { const WatchData &data = list.at(i); insertDataItem(data, true); m_handler->showEditValue(data); } -#else - // Destroy unneeded items. - QSet<QByteArray> inames; - for (int i = list.size(); --i >= 0; ) - inames.insert(list.at(i).iname); - - QList<QByteArray> toDestroy; - for (Cache::const_iterator it = m_cache.begin(), et = m_cache.end(); it != et; ++it) - if (!inames.contains(it.key()) && ancestorChanged(inames, it.value())) - toDestroy.append(it.key()); - - for (int i = 0, n = toDestroy.size(); i != n; ++i) { - // Can be destroyed as child of a previous item. - WatchItem *item = findItem(toDestroy.at(i)); - if (item) - destroyItem(item); - } - - // All remaining items are changed or new. - for (int i = 0, n = list.size(); i != n; ++i) - insertDataItem(list.at(i), false); -#endif - CHECK(checkTree()); emit columnAdjustmentRequested(); } -static void debugRecursion(QDebug &d, const WatchItem *item, int depth) -{ - d << QString(2 * depth, QLatin1Char(' ')) << item->toString() << '\n'; - foreach (const WatchItem *child, item->children) - debugRecursion(d, child, depth + 1); -} - -QDebug operator<<(QDebug d, const WatchModel &m) +int WatchItem::requestedFormat() const { - QDebug nospace = d.nospace(); - if (m.m_root) - debugRecursion(nospace, m.m_root, 0); - return d; -} - -void WatchModel::formatRequests(QByteArray *out, const WatchItem *item) const -{ - int format = theIndividualFormats.value(item->iname, AutomaticFormat); + int format = theIndividualFormats.value(d.iname, AutomaticFormat); if (format == AutomaticFormat) - format = theTypeFormats.value(stripForFormat(item->type), AutomaticFormat); - if (format != AutomaticFormat) - *out += item->iname + ":format=" + QByteArray::number(format) + ','; - foreach (const WatchItem *child, item->children) - formatRequests(out, child); + format = theTypeFormats.value(stripForFormat(d.type), AutomaticFormat); + return format; } -void WatchModel::showInEditorHelper(QString *contents, WatchItem *item, int depth) +void WatchItem::showInEditorHelper(QString *contents, int depth) const { const QChar tab = QLatin1Char('\t'); const QChar nl = QLatin1Char('\n'); contents->append(QString(depth, tab)); - contents->append(item->name); + contents->append(d.name); contents->append(tab); - contents->append(item->value); + contents->append(d.value); contents->append(tab); - contents->append(QString::fromLatin1(item->type)); + contents->append(QString::fromLatin1(d.type)); contents->append(nl); - foreach (WatchItem *child, item->children) - showInEditorHelper(contents, child, depth + 1); + foreach (const TreeItem *child, children()) + static_cast<const WatchItem *>(child)->showInEditorHelper(contents, depth + 1); } void WatchModel::setCurrentItem(const QByteArray &iname) { if (WatchItem *item = findItem(iname)) { - QModelIndex idx = watchIndex(item); - checkIndex(idx); + QModelIndex idx = indexFromItem(item); emit currentIndexRequested(idx); } } @@ -1664,7 +1193,6 @@ void WatchHandler::cleanup() m_model->m_expandedINames.clear(); theWatcherNames.remove(QByteArray()); m_model->reinitialize(); - m_model->m_fetchTriggered.clear(); m_separatedView->hide(); } @@ -1698,6 +1226,32 @@ void WatchHandler::insertIncompleteData(const WatchData &data) } } +void WatchHandler::insertItem(WatchItem *item) +{ + m_model->insertItem(item); +} + +void WatchModel::insertItem(WatchItem *item) +{ + WatchItem *existing = findItem(item->d.iname); + if (existing) + removeItem(existing); + + WatchItem *parent = findItem(parentName(item->d.iname)); + QTC_ASSERT(parent, return); + const int row = findInsertPosition(parent->children(), item); + parent->insertChild(row, item); +} + +void WatchModel::reexpandItems() +{ + foreach (const QByteArray &iname, m_expandedINames) { + WatchItem *item = findItem(iname); + emit itemIsExpanded(indexFromItem(item)); + emit inameIsExpanded(iname); + } +} + void WatchHandler::insertData(const WatchData &data) { QList<WatchData> list; @@ -1722,7 +1276,24 @@ void WatchHandler::removeAllData(bool includeInspectData) void WatchHandler::resetValueCache() { m_model->m_valueCache.clear(); - m_model->resetValueCacheRecursively(m_model->m_root); + TreeItem *root = m_model->rootItem(); + root->walkTree([this, root](TreeItem *item) { + auto watchItem = static_cast<WatchItem *>(item); + m_model->m_valueCache[watchItem->d.iname] = watchItem->d.value; + }); +} + +void WatchHandler::purgeOutdatedItems(const QSet<QByteArray> &inames) +{ + foreach (const QByteArray &iname, inames) { + WatchItem *item = findItem(iname); + m_model->removeItem(item); + } + + m_model->layoutChanged(); + m_model->reexpandItems(); + m_contentsValid = true; + updateWatchersWindow(); } void WatchHandler::removeData(const QByteArray &iname) @@ -1730,11 +1301,12 @@ void WatchHandler::removeData(const QByteArray &iname) WatchItem *item = m_model->findItem(iname); if (!item) return; - if (item->isWatcher()) { - theWatcherNames.remove(item->exp); + if (item->d.isWatcher()) { + theWatcherNames.remove(item->d.exp); saveWatchers(); } - m_model->destroyItem(item); + m_model->removeItem(item); + delete item; updateWatchersWindow(); } @@ -1742,7 +1314,7 @@ void WatchHandler::removeChildren(const QByteArray &iname) { WatchItem *item = m_model->findItem(iname); if (item) - m_model->destroyChildren(item); + item->removeChildren(); updateWatchersWindow(); } @@ -1883,7 +1455,15 @@ void WatchHandler::clearWatches() { if (theWatcherNames.isEmpty()) return; - m_model->destroyChildren(m_model->m_watchRoot); + + const QDialogButtonBox::StandardButton ret = CheckableMessageBox::doNotAskAgainQuestion( + Core::ICore::mainWindow(), tr("Remove All Expression Evaluators"), + tr("Are you sure you want to remove all expression evaluators?"), + Core::ICore::settings(), QLatin1String("RemoveAllWatchers")); + if (ret != QDialogButtonBox::Yes) + return; + + m_model->m_watchRoot->removeChildren(); theWatcherNames.clear(); m_watcherCounter = 0; updateWatchersWindow(); @@ -1895,8 +1475,8 @@ void WatchHandler::updateWatchersWindow() // Force show/hide of watchers and return view. static int previousShowWatch = -1; static int previousShowReturn = -1; - int showWatch = !m_model->m_watchRoot->children.isEmpty(); - int showReturn = !m_model->m_returnRoot->children.isEmpty(); + int showWatch = !m_model->m_watchRoot->children().isEmpty(); + int showReturn = !m_model->m_returnRoot->children().isEmpty(); if (showWatch == previousShowWatch && showReturn == previousShowReturn) return; previousShowWatch = showWatch; @@ -1981,7 +1561,7 @@ void WatchHandler::loadSessionData() theWatcherNames.clear(); m_watcherCounter = 0; QVariant value = sessionValue("Watchers"); - m_model->destroyChildren(m_model->m_watchRoot); + m_model->m_watchRoot->removeChildren(); foreach (const QString &exp, value.toStringList()) watchExpression(exp); } @@ -1993,18 +1573,25 @@ WatchModelBase *WatchHandler::model() const const WatchData *WatchHandler::watchData(const QModelIndex &idx) const { - return m_model->watchItem(idx); + TreeItem *item = m_model->itemFromIndex(idx); + return item ? &static_cast<WatchItem *>(item)->d : 0; } void WatchHandler::fetchMore(const QByteArray &iname) const { - QModelIndex idx = m_model->watchIndex(m_model->findItem(iname)); - m_model->checkIndex(idx); - model()->fetchMore(idx); + WatchItem *item = m_model->findItem(iname); + if (item) + item->fetchMore(); } const WatchData *WatchHandler::findData(const QByteArray &iname) const { + const WatchItem *item = m_model->findItem(iname); + return item ? &item->d : 0; +} + +WatchItem *WatchHandler::findItem(const QByteArray &iname) const +{ return m_model->findItem(iname); } @@ -2035,36 +1622,20 @@ void WatchHandler::setFormat(const QByteArray &type0, int format) else theTypeFormats[type] = format; saveFormats(); - m_model->emitDataChanged(1); + m_model->reinsertAllData(); } int WatchHandler::format(const QByteArray &iname) const { int result = AutomaticFormat; - if (const WatchData *item = m_model->findItem(iname)) { - int result = theIndividualFormats.value(item->iname, AutomaticFormat); + if (const WatchItem *item = m_model->findItem(iname)) { + int result = theIndividualFormats.value(item->d.iname, AutomaticFormat); if (result == AutomaticFormat) - result = theTypeFormats.value(stripForFormat(item->type), AutomaticFormat); + result = theTypeFormats.value(stripForFormat(item->d.type), AutomaticFormat); } return result; } -QByteArray WatchHandler::expansionRequests() const -{ - QByteArray ba; - m_model->formatRequests(&ba, m_model->m_root); - if (!m_model->m_expandedINames.isEmpty()) { - QSetIterator<QByteArray> jt(m_model->m_expandedINames); - while (jt.hasNext()) { - QByteArray iname = jt.next(); - ba.append(iname); - ba.append(','); - } - ba.chop(1); - } - return ba; -} - QByteArray WatchHandler::typeFormatRequests() const { QByteArray ba; @@ -2105,6 +1676,55 @@ QByteArray WatchHandler::individualFormatRequests() const return ba; } +void WatchHandler::appendFormatRequests(DebuggerCommand *cmd) +{ + cmd->beginList("expanded"); + QSetIterator<QByteArray> jt(m_model->m_expandedINames); + while (jt.hasNext()) { + QByteArray iname = jt.next(); + //WatchItem *item = m_model->findItem(iname); + cmd->arg(iname); + //cmd->arg("format", item->requestedFormat()); + } + cmd->endList(); + + cmd->beginGroup("typeformats"); + QHashIterator<QByteArray, int> it(theTypeFormats); + while (it.hasNext()) { + it.next(); + const int format = it.value(); + if (format >= RawFormat && format < ArtificialFormatBase) + cmd->arg(it.key(), format); + } + cmd->endGroup(); + + cmd->beginGroup("formats"); + QHashIterator<QByteArray, int> it2(theIndividualFormats); + while (it2.hasNext()) { + it2.next(); + const int format = it2.value(); + if (format >= RawFormat && format < ArtificialFormatBase) + cmd->arg(it2.key(), format); + } + cmd->endGroup(); +} + +void WatchHandler::addDumpers(const GdbMi &dumpers) +{ + foreach (const GdbMi &dumper, dumpers.children()) { + QStringList formats(tr("Raw structure")); + foreach (const QByteArray &format, dumper["formats"].data().split(',')) { + if (format == "Normal") + formats.append(tr("Normal")); + else if (format == "Displayed") + formats.append(tr("Displayed")); + else if (!format.isEmpty()) + formats.append(QString::fromLatin1(format)); + } + addTypeFormats(dumper["type"].data(), formats); + } +} + void WatchHandler::addTypeFormats(const QByteArray &type, const QStringList &formats) { m_model->m_reportedTypeFormats.insert(QLatin1String(stripForFormat(type)), formats); @@ -2113,7 +1733,7 @@ void WatchHandler::addTypeFormats(const QByteArray &type, const QStringList &for QString WatchHandler::editorContents() { QString contents; - m_model->showInEditorHelper(&contents, m_model->m_root, 0); + m_model->root()->showInEditorHelper(&contents, 0); return contents; } @@ -2152,16 +1772,7 @@ void WatchHandler::scheduleResetLocation() void WatchHandler::resetLocation() { - if (m_resetLocationScheduled) { - m_resetLocationScheduled = false; - //m_model->invalidateAll(); FIXME - } -} - -bool WatchHandler::isValidToolTip(const QByteArray &iname) const -{ - WatchItem *item = m_model->findItem(iname); - return item && !item->type.trimmed().isEmpty(); + m_resetLocationScheduled = false; } void WatchHandler::setCurrentItem(const QByteArray &iname) @@ -2177,7 +1788,7 @@ QHash<QByteArray, int> WatchHandler::watcherNames() void WatchHandler::setUnprintableBase(int base) { theUnprintableBase = base; - m_model->emitAllChanged(); + m_model->layoutChanged(); } int WatchHandler::unprintableBase() @@ -2219,6 +1830,83 @@ TypeFormatItem TypeFormatList::find(int format) const return TypeFormatItem(); } +//////////////////////////////////////////////////////////////////// +// +// WatchItem +// +//////////////////////////////////////////////////////////////////// + +WatchItem::WatchItem() + : fetchTriggered(false) +{} + +WatchItem::WatchItem(const QByteArray &i, const QString &n) +{ + fetchTriggered = false; + d.iname = i; + d.name = n; +} + +WatchItem::WatchItem(const WatchData &data) + : d(data), fetchTriggered(false) +{ +} + +WatchItem::WatchItem(const GdbMi &data) + : fetchTriggered(false) +{ + d.iname = data["iname"].data(); + + GdbMi wname = data["wname"]; + if (wname.isValid()) // Happens (only) for watched expressions. + d.name = QString::fromUtf8(QByteArray::fromHex(wname.data())); + else + d.name = QString::fromLatin1(data["name"].data()); + + parseWatchData(data); + + if (wname.isValid()) + d.exp = d.name.toUtf8(); +} + +WatchItem *WatchItem::parentItem() const +{ + return dynamic_cast<WatchItem *>(parent()); +} + +const WatchModel *WatchItem::watchModel() const +{ + return static_cast<const WatchModel *>(model()); +} + +WatchModel *WatchItem::watchModel() +{ + return static_cast<WatchModel *>(model()); +} + +void WatchItem::parseWatchData(const GdbMi &input) +{ + auto itemHandler = [this](const WatchData &data) { + d = data; + }; + auto childHandler = [this](const WatchData &innerData, const GdbMi &innerInput) { + WatchItem *item = new WatchItem(innerData); + item->parseWatchData(innerInput); + appendChild(item); + }; + + auto itemAdder = [this](const WatchData &data) { + appendChild(new WatchItem(data)); + }; + + auto arrayDecoder = [itemAdder](const WatchData &childTemplate, + const QByteArray &encodedData, int encoding) { + decodeArrayData(itemAdder, childTemplate, encodedData, encoding); + }; + + parseChildrenData(d, input, itemHandler, childHandler, arrayDecoder); +} + } // namespace Internal } // namespace Debugger diff --git a/src/plugins/debugger/watchhandler.h b/src/plugins/debugger/watchhandler.h index e5f5f9b9a4..444bef881f 100644 --- a/src/plugins/debugger/watchhandler.h +++ b/src/plugins/debugger/watchhandler.h @@ -33,16 +33,58 @@ #include "watchdata.h" -#include <QAbstractItemModel> +#include <utils/treemodel.h> + #include <QPointer> #include <QVector> namespace Debugger { namespace Internal { +class DebuggerCommand; class SeparatedView; class WatchModel; +class WatchItem : public Utils::TreeItem +{ +public: + WatchItem(); + WatchItem(const QByteArray &i, const QString &n); + explicit WatchItem(const WatchData &data); + explicit WatchItem(const GdbMi &data); + + WatchItem *parentItem() const; + const WatchModel *watchModel() const; + WatchModel *watchModel(); + + QVariant data(int column, int role) const; + Qt::ItemFlags flags(int column) const; + + bool canFetchMore() const; + void fetchMore(); + + QString displayName() const; + QString displayType() const; + QString displayValue() const; + QString formattedValue() const; + QString expression() const; + + int itemFormat() const; + + QVariant editValue() const; + int editType() const; + QColor color() const; + + int requestedFormat() const; + void showInEditorHelper(QString *contents, int depth) const; + WatchItem *findItem(const QByteArray &iname); + void parseWatchData(const GdbMi &input); + +public: + WatchData d; + bool fetchTriggered; +}; + // Special formats. Keep in sync with dumper.py. enum DisplayFormat { @@ -108,25 +150,22 @@ public: Q_DECLARE_METATYPE(Debugger::Internal::TypeFormatList) namespace Debugger { +namespace Internal { class DebuggerEngine; -namespace Internal { - class UpdateParameters { public: - UpdateParameters() { tryPartial = tooltipOnly = false; } + UpdateParameters() { tryPartial = false; } bool tryPartial; - bool tooltipOnly; QByteArray varList; - QString tooltipExpression; }; typedef QHash<QString, QStringList> DumperTypeFormats; // Type name -> Dumper Formats -class WatchModelBase : public QAbstractItemModel +class WatchModelBase : public Utils::TreeModel { Q_OBJECT @@ -136,6 +175,7 @@ public: signals: void currentIndexRequested(const QModelIndex &idx); void itemIsExpanded(const QModelIndex &idx); + void inameIsExpanded(const QByteArray &iname); void columnAdjustmentRequested(); }; @@ -159,6 +199,7 @@ public: const WatchData *watchData(const QModelIndex &) const; void fetchMore(const QByteArray &iname) const; const WatchData *findData(const QByteArray &iname) const; + WatchItem *findItem(const QByteArray &iname) const; const WatchData *findCppLocalVariable(const QString &name) const; bool hasItem(const QByteArray &iname) const; @@ -171,12 +212,12 @@ public: static QStringList watchedExpressions(); static QHash<QByteArray, int> watcherNames(); - QByteArray expansionRequests() const; QByteArray typeFormatRequests() const; QByteArray individualFormatRequests() const; int format(const QByteArray &iname) const; + void addDumpers(const GdbMi &dumpers); void addTypeFormats(const QByteArray &type, const QStringList &formats); void setTypeFormats(const DumperTypeFormats &typeFormats); DumperTypeFormats typeFormats() const; @@ -190,18 +231,20 @@ public: void scheduleResetLocation(); void resetLocation(); - bool isValidToolTip(const QByteArray &iname) const; void setCurrentItem(const QByteArray &iname); void updateWatchersWindow(); + void appendFormatRequests(DebuggerCommand *cmd); void insertData(const WatchData &data); // Convenience. void insertData(const QList<WatchData> &list); void insertIncompleteData(const WatchData &data); + void insertItem(WatchItem *item); void removeData(const QByteArray &iname); void removeChildren(const QByteArray &iname); void removeAllData(bool includeInspectData = false); void resetValueCache(); + void purgeOutdatedItems(const QSet<QByteArray> &inames); private: friend class WatchModel; diff --git a/src/plugins/debugger/watchwindow.cpp b/src/plugins/debugger/watchwindow.cpp index 55b2e7da4e..2ea8632e58 100644 --- a/src/plugins/debugger/watchwindow.cpp +++ b/src/plugins/debugger/watchwindow.cpp @@ -44,9 +44,12 @@ #include <texteditor/syntaxhighlighter.h> +#include <coreplugin/messagebox.h> + +#include <utils/fancylineedit.h> #include <utils/qtcassert.h> #include <utils/savedaction.h> -#include <utils/fancylineedit.h> +#include <utils/treemodel.h> #include <QApplication> #include <QClipboard> @@ -55,11 +58,11 @@ #include <QInputDialog> #include <QItemDelegate> #include <QMenu> -#include <QMessageBox> #include <QMetaProperty> #include <QMimeData> #include <QScrollBar> #include <QTimer> +#include <QTextStream> // For InputDialog, move to Utils? #include <coreplugin/helpmanager.h> @@ -68,14 +71,6 @@ #include <QButtonGroup> #include <QDialogButtonBox> -//#define USE_WATCH_MODEL_TEST 1 - -#if USE_WATCH_MODEL_TEST -#include <modeltest.h> -#endif - -Q_DECLARE_METATYPE(QModelIndex) - ///////////////////////////////////////////////////////////////////// // // WatchDelegate @@ -85,8 +80,6 @@ Q_DECLARE_METATYPE(QModelIndex) namespace Debugger { namespace Internal { -const char CurrentIndex[] = "CurrentIndex"; - class WatchDelegate : public QItemDelegate { public: @@ -177,21 +170,6 @@ static inline uint sizeOf(const QModelIndex &m) return m.data(LocalsSizeRole).toUInt(); } -// Create a map of value->name for register markup. -typedef QMap<quint64, QString> RegisterMap; -typedef RegisterMap::const_iterator RegisterMapConstIt; - -RegisterMap registerMap(const DebuggerEngine *engine) -{ - RegisterMap result; - foreach (const Register ®, engine->registerHandler()->registers()) { - const QVariant v = reg.editValue(); - if (v.type() == QVariant::ULongLong) - result.insert(v.toULongLong(), QString::fromLatin1(reg.name)); - } - return result; -} - // Helper functionality to indicate the area of a member variable in // a vector representing the memory area by a unique color // number and tooltip. Parts of it will be overwritten when recursing @@ -313,13 +291,12 @@ static MemoryMarkupList if (sizeIsEstimate && !childCount) return result; // Fixme: Exact size not known, no point in filling if no children. // Punch in registers as 1-byte markers on top. - const RegisterMapConstIt regcEnd = registerMap.constEnd(); - for (RegisterMapConstIt it = registerMap.constBegin(); it != regcEnd; ++it) { + for (auto it = registerMap.constBegin(), end = registerMap.constEnd(); it != end; ++it) { if (it.key() >= address) { const quint64 offset = it.key() - address; if (offset < size) { ranges[offset] = ColorNumberToolTip(registerColorNumber, - WatchTreeView::tr("Register <i>%1</i>").arg(it.value())); + WatchTreeView::tr("Register <i>%1</i>").arg(QString::fromUtf8(it.value()))); } else { break; // Sorted. } @@ -380,27 +357,27 @@ static void addVariableMemoryView(DebuggerEngine *engine, bool separateView, const QPoint &p, QWidget *parent) { const QColor background = parent->palette().color(QPalette::Normal, QPalette::Base); - const quint64 address = atPointerAddress ? pointerAddressOf(m) : addressOf(m); + MemoryViewSetupData data; + data.startAddress = atPointerAddress ? pointerAddressOf(m) : addressOf(m); + if (!data.startAddress) + return; // Fixme: Get the size of pointee (see variableMemoryMarkup())? const QString rootToolTip = variableToolTip(nameOf(m), typeOf(m), 0); const quint64 typeSize = sizeOf(m); const bool sizeIsEstimate = atPointerAddress || !typeSize; const quint64 size = sizeIsEstimate ? 1024 : typeSize; - if (!address) - return; - const QList<MemoryMarkup> markup = - variableMemoryMarkup(m.model(), m, nameOf(m), rootToolTip, - address, size, - registerMap(engine), + data.markup = variableMemoryMarkup(m.model(), m, nameOf(m), rootToolTip, + data.startAddress, size, + engine->registerHandler()->registerMap(), sizeIsEstimate, background); - const unsigned flags = separateView - ? DebuggerEngine::MemoryView|DebuggerEngine::MemoryReadOnly : 0; - const QString title = atPointerAddress + data.flags = separateView ? DebuggerEngine::MemoryView|DebuggerEngine::MemoryReadOnly : 0; + QString pat = atPointerAddress ? WatchTreeView::tr("Memory at Pointer's Address \"%1\" (0x%2)") - .arg(nameOf(m)).arg(address, 0, 16) - : WatchTreeView::tr("Memory at Object's Address \"%1\" (0x%2)") - .arg(nameOf(m)).arg(address, 0, 16); - engine->openMemoryView(address, flags, markup, p, title, parent); + : WatchTreeView::tr("Memory at Object's Address \"%1\" (0x%2)"); + data.title = pat.arg(nameOf(m)).arg(data.startAddress, 0, 16); + data.pos = p; + data.parent = parent; + engine->openMemoryView(data); } // Add a memory view of the stack layout showing local variables @@ -436,16 +413,15 @@ static void addStackLayoutMemoryView(DebuggerEngine *engine, bool separateView, end += 8 - remainder; // Anything found and everything in a sensible range (static data in-between)? if (end <= start || end - start > 100 * 1024) { - QMessageBox::information(parent, + Core::AsynchronousMessageBox::information( WatchTreeView::tr("Cannot Display Stack Layout"), WatchTreeView::tr("Could not determine a suitable address range.")); return; } // Take a look at the register values. Extend the range a bit if suitable // to show stack/stack frame pointers. - const RegisterMap regMap = registerMap(engine); - const RegisterMapConstIt regcEnd = regMap.constEnd(); - for (RegisterMapConstIt it = regMap.constBegin(); it != regcEnd; ++it) { + const RegisterMap regMap = engine->registerHandler()->registerMap(); + for (auto it = regMap.constBegin(), cend = regMap.constEnd(); it != cend; ++it) { const quint64 value = it.key(); if (value < start && start - value < 512) start = value; @@ -453,16 +429,18 @@ static void addStackLayoutMemoryView(DebuggerEngine *engine, bool separateView, end = value + 1; } // Indicate all variables. + MemoryViewSetupData data; const QColor background = parent->palette().color(QPalette::Normal, QPalette::Base); - const MemoryMarkupList markup = - variableMemoryMarkup(m, localsIndex, QString(), + data.startAddress = start; + data.markup = variableMemoryMarkup(m, localsIndex, QString(), QString(), start, end - start, regMap, true, background); - const unsigned flags = separateView + data.flags = separateView ? (DebuggerEngine::MemoryView|DebuggerEngine::MemoryReadOnly) : 0; - const QString title = - WatchTreeView::tr("Memory Layout of Local Variables at 0x%1").arg(start, 0, 16); - engine->openMemoryView(start, flags, markup, p, title, parent); + data.title = WatchTreeView::tr("Memory Layout of Local Variables at 0x%1").arg(start, 0, 16); + data.pos = p; + data.parent = parent; + engine->openMemoryView(data); } ///////////////////////////////////////////////////////////////////// @@ -484,10 +462,8 @@ WatchTreeView::WatchTreeView(WatchType type) setAcceptDrops(true); setDropIndicatorShown(true); - connect(this, SIGNAL(expanded(QModelIndex)), - SLOT(expandNode(QModelIndex))); - connect(this, SIGNAL(collapsed(QModelIndex)), - SLOT(collapseNode(QModelIndex))); + connect(this, &QTreeView::expanded, this, &WatchTreeView::expandNode); + connect(this, &QTreeView::collapsed, this, &WatchTreeView::collapseNode); } void WatchTreeView::expandNode(const QModelIndex &idx) @@ -615,28 +591,23 @@ void WatchTreeView::fillFormatMenu(QMenu *formatMenu, const QModelIndex &mi) formatMenu->addAction(tr("Treat All Characters as Printable")); showUnprintableUnicode->setCheckable(true); showUnprintableUnicode->setChecked(unprintableBase == 0); - showUnprintableUnicode->setData(0); showUnprintableEscape = formatMenu->addAction(tr("Show Unprintable Characters as Escape Sequences")); showUnprintableEscape->setCheckable(true); showUnprintableEscape->setChecked(unprintableBase == -1); - showUnprintableEscape->setData(-1); showUnprintableOctal = formatMenu->addAction(tr("Show Unprintable Characters as Octal")); showUnprintableOctal->setCheckable(true); showUnprintableOctal->setChecked(unprintableBase == 8); - showUnprintableOctal->setData(8); showUnprintableHexadecimal = formatMenu->addAction(tr("Show Unprintable Characters as Hexadecimal")); showUnprintableHexadecimal->setCheckable(true); showUnprintableHexadecimal->setChecked(unprintableBase == 16); - showUnprintableHexadecimal->setData(16); - - connect(showUnprintableUnicode, SIGNAL(triggered()), SLOT(onShowUnprintable())); - connect(showUnprintableEscape, SIGNAL(triggered()), SLOT(onShowUnprintable())); - connect(showUnprintableOctal, SIGNAL(triggered()), SLOT(onShowUnprintable())); - connect(showUnprintableHexadecimal, SIGNAL(triggered()), SLOT(onShowUnprintable())); + connect(showUnprintableUnicode, &QAction::triggered, [this] { showUnprintable(0); }); + connect(showUnprintableEscape, &QAction::triggered, [this] { showUnprintable(-1); }); + connect(showUnprintableOctal, &QAction::triggered, [this] { showUnprintable(8); }); + connect(showUnprintableHexadecimal, &QAction::triggered, [this] { showUnprintable(16); }); const QString spacer = QLatin1String(" "); formatMenu->addSeparator(); @@ -651,19 +622,22 @@ void WatchTreeView::fillFormatMenu(QMenu *formatMenu, const QModelIndex &mi) QAction *clearIndividualFormatAction = formatMenu->addAction(spacer + msg); clearIndividualFormatAction->setCheckable(true); clearIndividualFormatAction->setChecked(individualFormat == AutomaticFormat); - connect(clearIndividualFormatAction, SIGNAL(triggered()), - SLOT(onClearIndividualFormat())); + connect(clearIndividualFormatAction, &QAction::triggered, [this] { + const QModelIndexList active = activeRows(); + foreach (const QModelIndex &idx, active) + setModelData(LocalsIndividualFormatRole, AutomaticFormat, idx); + }); for (int i = 0; i != alternativeFormats.size(); ++i) { const QString display = spacer + alternativeFormats.at(i).display; const int format = alternativeFormats.at(i).format; QAction *act = new QAction(display, formatMenu); - act->setData(format); act->setCheckable(true); act->setChecked(format == individualFormat); - act->setProperty(CurrentIndex, QVariant::fromValue(mi)); formatMenu->addAction(act); - connect(act, SIGNAL(triggered()), SLOT(onIndividualFormatChange())); + connect(act, &QAction::triggered, [this, act, format, mi] { + setModelData(LocalsIndividualFormatRole, format, mi); + }); } formatMenu->addSeparator(); @@ -673,58 +647,30 @@ void WatchTreeView::fillFormatMenu(QMenu *formatMenu, const QModelIndex &mi) QAction *clearTypeFormatAction = formatMenu->addAction(spacer + tr("Automatic")); clearTypeFormatAction->setCheckable(true); clearTypeFormatAction->setChecked(typeFormat == AutomaticFormat); - connect(clearTypeFormatAction, SIGNAL(triggered()), SLOT(onClearTypeFormat())); + connect(clearTypeFormatAction, &QAction::triggered, [this] { + const QModelIndexList active = activeRows(); + foreach (const QModelIndex &idx, active) + setModelData(LocalsTypeFormatRole, AutomaticFormat, idx); + }); for (int i = 0; i != alternativeFormats.size(); ++i) { const QString display = spacer + alternativeFormats.at(i).display; QAction *act = new QAction(display, formatMenu); const int format = alternativeFormats.at(i).format; - act->setData(format); act->setCheckable(true); act->setChecked(format == typeFormat); - act->setProperty(CurrentIndex, QVariant::fromValue(mi)); formatMenu->addAction(act); - connect(act, SIGNAL(triggered()), SLOT(onTypeFormatChange())); + connect(act, &QAction::triggered, [this, act, format, mi] { + setModelData(LocalsTypeFormatRole, format, mi); + }); } } -void WatchTreeView::onClearTypeFormat() +void WatchTreeView::showUnprintable(int base) { - const QModelIndexList active = activeRows(); - foreach (const QModelIndex &idx, active) - setModelData(LocalsTypeFormatRole, AutomaticFormat, idx); -} - -void WatchTreeView::onClearIndividualFormat() -{ - const QModelIndexList active = activeRows(); - foreach (const QModelIndex &idx, active) - setModelData(LocalsIndividualFormatRole, AutomaticFormat, idx); -} - -void WatchTreeView::onShowUnprintable() -{ - QAction *act = qobject_cast<QAction *>(sender()); - QTC_ASSERT(act, return); DebuggerEngine *engine = currentEngine(); WatchHandler *handler = engine->watchHandler(); - handler->setUnprintableBase(act->data().toInt()); -} - -void WatchTreeView::onTypeFormatChange() -{ - QAction *act = qobject_cast<QAction *>(sender()); - QTC_ASSERT(act, return); - QModelIndex idx = act->property(CurrentIndex).value<QModelIndex>(); - setModelData(LocalsTypeFormatRole, act->data(), idx); -} - -void WatchTreeView::onIndividualFormatChange() -{ - QAction *act = qobject_cast<QAction *>(sender()); - QTC_ASSERT(act, return); - QModelIndex idx = act->property(CurrentIndex).value<QModelIndex>(); - setModelData(LocalsIndividualFormatRole, act->data(), idx); + handler->setUnprintableBase(base); } void WatchTreeView::contextMenuEvent(QContextMenuEvent *ev) @@ -810,11 +756,16 @@ void WatchTreeView::contextMenuEvent(QContextMenuEvent *ev) break; p = pp; } + + bool showExpressionActions = (canHandleWatches || state == DebuggerNotReady) && m_type == WatchersType; + QString removeExp = p.data(LocalsExpressionRole).toString(); QAction actRemoveWatchExpression(removeWatchActionText(removeExp), 0); - actRemoveWatchExpression.setEnabled( - (canHandleWatches || state == DebuggerNotReady) - && !exp.isEmpty() && m_type == WatchersType); + actRemoveWatchExpression.setEnabled(showExpressionActions && !exp.isEmpty()); + + QAction actRemoveAllWatchExpression(tr("Remove All Expression Evaluators"), 0); + actRemoveAllWatchExpression.setEnabled(showExpressionActions + && !handler->watchedExpressions().isEmpty()); QMenu formatMenu(tr("Change Local Display Format...")); if (mi0.isValid()) @@ -891,6 +842,7 @@ void WatchTreeView::contextMenuEvent(QContextMenuEvent *ev) menu.addAction(&actInsertNewWatchItem); menu.addAction(&actWatchExpression); menu.addAction(&actRemoveWatchExpression); + menu.addAction(&actRemoveAllWatchExpression); menu.addAction(&actSelectWidgetToWatch); menu.addSeparator(); @@ -929,8 +881,11 @@ void WatchTreeView::contextMenuEvent(QContextMenuEvent *ev) AddressDialog dialog; if (address) dialog.setAddress(address); - if (dialog.exec() == QDialog::Accepted) - currentEngine()->openMemoryView(dialog.address(), false, MemoryMarkupList(), QPoint()); + if (dialog.exec() == QDialog::Accepted) { + MemoryViewSetupData data; + data.startAddress = dialog.address(); + currentEngine()->openMemoryView(data); + } } else if (act == &actOpenMemoryViewAtObjectAddress) { addVariableMemoryView(currentEngine(), true, mi0, false, ev->globalPos(), this); } else if (act == &actOpenMemoryViewAtPointerAddress) { @@ -950,8 +905,20 @@ void WatchTreeView::contextMenuEvent(QContextMenuEvent *ev) watchExpression(exp, name); } else if (act == &actRemoveWatchExpression) { handler->removeData(p.data(LocalsINameRole).toByteArray()); + } else if (act == &actRemoveAllWatchExpression) { + handler->clearWatches(); } else if (act == &actCopy) { - copyToClipboard(DebuggerToolTipManager::treeModelClipboardContents(model())); + QString text; + QTextStream str(&text); + handler->model()->rootItem()->walkTree([&str](Utils::TreeItem *item) { + str << QString(item->level(), QLatin1Char('\t')) + << item->data(0, Qt::DisplayRole).toString() << '\t' + << item->data(1, Qt::DisplayRole).toString() << '\t' + << item->data(2, Qt::DisplayRole).toString() << '\n'; + }); + QClipboard *clipboard = QApplication::clipboard(); + clipboard->setText(text, QClipboard::Selection); + clipboard->setText(text, QClipboard::Clipboard); } else if (act == &actCopyValue) { copyToClipboard(mi1.data().toString()); } else if (act == &actShowInEditor) { @@ -995,14 +962,14 @@ void WatchTreeView::setModel(QAbstractItemModel *model) header()->hide(); } - connect(model, SIGNAL(layoutChanged()), SLOT(resetHelper())); - connect(model, SIGNAL(currentIndexRequested(QModelIndex)), - SLOT(setCurrentIndex(QModelIndex))); - connect(model, SIGNAL(itemIsExpanded(QModelIndex)), - SLOT(handleItemIsExpanded(QModelIndex))); -#if USE_WATCH_MODEL_TEST - (void) new ModelTest(&m_filter, this); -#endif + auto watchModel = qobject_cast<WatchModelBase *>(model); + QTC_ASSERT(watchModel, return); + connect(model, &QAbstractItemModel::layoutChanged, + this, &WatchTreeView::resetHelper); + connect(watchModel, &WatchModelBase::currentIndexRequested, + this, &QAbstractItemView::setCurrentIndex); + connect(watchModel, &WatchModelBase::itemIsExpanded, + this, &WatchTreeView::handleItemIsExpanded); } void WatchTreeView::rowActivated(const QModelIndex &index) @@ -1046,8 +1013,10 @@ void WatchTreeView::resetHelper() void WatchTreeView::reset() { BaseTreeView::reset(); - setRootIndex(model()->index(m_type, 0)); - resetHelper(); + if (model()) { + setRootIndex(model()->index(m_type, 0)); + resetHelper(); + } } void WatchTreeView::doItemsLayout() @@ -1106,8 +1075,8 @@ public: setLayout(layout); connect(m_buttons, SIGNAL(accepted()), m_lineEdit, SLOT(onEditingFinished())); - connect(m_buttons, SIGNAL(accepted()), SLOT(accept())); - connect(m_buttons, SIGNAL(rejected()), SLOT(reject())); + connect(m_buttons, &QDialogButtonBox::accepted, this, &QDialog::accept); + connect(m_buttons, &QDialogButtonBox::rejected, this, &QDialog::reject); connect(m_hint, SIGNAL(linkActivated(QString)), Core::HelpManager::instance(), SLOT(handleHelpRequest(QString))); } diff --git a/src/plugins/debugger/watchwindow.h b/src/plugins/debugger/watchwindow.h index 21bc41c607..8ba2a76ab9 100644 --- a/src/plugins/debugger/watchwindow.h +++ b/src/plugins/debugger/watchwindow.h @@ -67,20 +67,13 @@ public slots: signals: void currentIndexChanged(const QModelIndex ¤tIndex); -private slots: +private: void resetHelper(); void expandNode(const QModelIndex &idx); void collapseNode(const QModelIndex &idx); - void adjustSlider(); - - void onClearIndividualFormat(); - void onClearTypeFormat(); - void onShowUnprintable(); + Q_SLOT void adjustSlider(); // Used by single-shot timer. - void onTypeFormatChange(); - void onIndividualFormatChange(); - -private: + void showUnprintable(int base); void doItemsLayout(); void keyPressEvent(QKeyEvent *ev); void contextMenuEvent(QContextMenuEvent *ev); |