forked from qt-creator/qt-creator
debugger: new files for WatchData; move potentially shared code to watchutils.cpp
This commit is contained in:
@@ -27,7 +27,6 @@ HEADERS += breakhandler.h \
|
|||||||
debuggerrunner.h \
|
debuggerrunner.h \
|
||||||
debuggertooltip.h \
|
debuggertooltip.h \
|
||||||
debuggerstringutils.h \
|
debuggerstringutils.h \
|
||||||
watchutils.h \
|
|
||||||
idebuggerengine.h \
|
idebuggerengine.h \
|
||||||
moduleshandler.h \
|
moduleshandler.h \
|
||||||
moduleswindow.h \
|
moduleswindow.h \
|
||||||
@@ -42,6 +41,7 @@ HEADERS += breakhandler.h \
|
|||||||
sourcefileswindow.h \
|
sourcefileswindow.h \
|
||||||
threadswindow.h \
|
threadswindow.h \
|
||||||
watchhandler.h \
|
watchhandler.h \
|
||||||
|
watchutils.h \
|
||||||
watchwindow.h \
|
watchwindow.h \
|
||||||
name_demangler.h \
|
name_demangler.h \
|
||||||
debuggeruiswitcher.h \
|
debuggeruiswitcher.h \
|
||||||
@@ -57,7 +57,6 @@ SOURCES += breakhandler.cpp \
|
|||||||
debuggerplugin.cpp \
|
debuggerplugin.cpp \
|
||||||
debuggerrunner.cpp \
|
debuggerrunner.cpp \
|
||||||
debuggertooltip.cpp \
|
debuggertooltip.cpp \
|
||||||
watchutils.cpp \
|
|
||||||
moduleshandler.cpp \
|
moduleshandler.cpp \
|
||||||
moduleswindow.cpp \
|
moduleswindow.cpp \
|
||||||
outputcollector.cpp \
|
outputcollector.cpp \
|
||||||
@@ -70,8 +69,10 @@ SOURCES += breakhandler.cpp \
|
|||||||
stackwindow.cpp \
|
stackwindow.cpp \
|
||||||
sourcefileswindow.cpp \
|
sourcefileswindow.cpp \
|
||||||
threadswindow.cpp \
|
threadswindow.cpp \
|
||||||
|
watchdata.cpp \
|
||||||
watchhandler.cpp \
|
watchhandler.cpp \
|
||||||
watchwindow.cpp \
|
watchwindow.cpp \
|
||||||
|
watchutils.cpp \
|
||||||
name_demangler.cpp \
|
name_demangler.cpp \
|
||||||
debuggeruiswitcher.cpp \
|
debuggeruiswitcher.cpp \
|
||||||
debuggermainwindow.cpp
|
debuggermainwindow.cpp
|
||||||
|
|||||||
@@ -418,7 +418,8 @@ void GdbEngine::handleDebuggingHelperValue2Classic(const GdbResponse &response)
|
|||||||
setWatchDataType(data, response.data.findChild("type"));
|
setWatchDataType(data, response.data.findChild("type"));
|
||||||
setWatchDataDisplayedType(data, response.data.findChild("displaytype"));
|
setWatchDataDisplayedType(data, response.data.findChild("displaytype"));
|
||||||
QList<WatchData> list;
|
QList<WatchData> list;
|
||||||
handleChildren(data, contents, &list);
|
parseWatchData(manager()->watchHandler()->expandedINames(),
|
||||||
|
data, contents, &list);
|
||||||
//for (int i = 0; i != list.size(); ++i)
|
//for (int i = 0; i != list.size(); ++i)
|
||||||
// qDebug() << "READ: " << list.at(i).toString();
|
// qDebug() << "READ: " << list.at(i).toString();
|
||||||
manager()->watchHandler()->insertBulkData(list);
|
manager()->watchHandler()->insertBulkData(list);
|
||||||
|
|||||||
@@ -251,7 +251,6 @@ void GdbEngine::initializeVariables()
|
|||||||
|
|
||||||
m_fullToShortName.clear();
|
m_fullToShortName.clear();
|
||||||
m_shortToFullName.clear();
|
m_shortToFullName.clear();
|
||||||
m_varToType.clear();
|
|
||||||
|
|
||||||
invalidateSourcesList();
|
invalidateSourcesList();
|
||||||
m_sourcesListUpdating = false;
|
m_sourcesListUpdating = false;
|
||||||
@@ -3236,65 +3235,6 @@ void GdbEngine::setToolTipExpression(const QPoint &mousePos,
|
|||||||
//
|
//
|
||||||
//////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
void GdbEngine::setWatchDataValue(WatchData &data, const GdbMi &item)
|
|
||||||
{
|
|
||||||
GdbMi value = item.findChild("value");
|
|
||||||
if (value.isValid()) {
|
|
||||||
int encoding = item.findChild("valueencoded").data().toInt();
|
|
||||||
data.setValue(decodeData(value.data(), encoding));
|
|
||||||
} else {
|
|
||||||
data.setValueNeeded();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void GdbEngine::setWatchDataValueToolTip(WatchData &data, const GdbMi &mi,
|
|
||||||
int encoding)
|
|
||||||
{
|
|
||||||
if (mi.isValid())
|
|
||||||
data.setValueToolTip(decodeData(mi.data(), encoding));
|
|
||||||
}
|
|
||||||
|
|
||||||
void GdbEngine::setWatchDataChildCount(WatchData &data, const GdbMi &mi)
|
|
||||||
{
|
|
||||||
if (mi.isValid())
|
|
||||||
data.setHasChildren(mi.data().toInt() > 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
void GdbEngine::setWatchDataValueEnabled(WatchData &data, const GdbMi &mi)
|
|
||||||
{
|
|
||||||
if (mi.data() == "true")
|
|
||||||
data.valueEnabled = true;
|
|
||||||
else if (mi.data() == "false")
|
|
||||||
data.valueEnabled = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void GdbEngine::setWatchDataValueEditable(WatchData &data, const GdbMi &mi)
|
|
||||||
{
|
|
||||||
if (mi.data() == "true")
|
|
||||||
data.valueEditable = true;
|
|
||||||
else if (mi.data() == "false")
|
|
||||||
data.valueEditable = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void GdbEngine::setWatchDataExpression(WatchData &data, const GdbMi &mi)
|
|
||||||
{
|
|
||||||
if (mi.isValid())
|
|
||||||
data.exp = mi.data();
|
|
||||||
}
|
|
||||||
|
|
||||||
void GdbEngine::setWatchDataAddress(WatchData &data, const GdbMi &mi)
|
|
||||||
{
|
|
||||||
if (mi.isValid())
|
|
||||||
setWatchDataAddressHelper(data, mi.data());
|
|
||||||
}
|
|
||||||
|
|
||||||
void GdbEngine::setWatchDataAddressHelper(WatchData &data, const QByteArray &addr)
|
|
||||||
{
|
|
||||||
data.addr = addr;
|
|
||||||
if (data.exp.isEmpty() && !data.addr.startsWith("$"))
|
|
||||||
data.exp = "*(" + gdbQuoteTypes(data.type).toLatin1() + "*)" + data.addr;
|
|
||||||
}
|
|
||||||
|
|
||||||
void GdbEngine::setAutoDerefPointers(const QVariant &on)
|
void GdbEngine::setAutoDerefPointers(const QVariant &on)
|
||||||
{
|
{
|
||||||
Q_UNUSED(on)
|
Q_UNUSED(on)
|
||||||
@@ -3443,25 +3383,6 @@ void GdbEngine::handleVarAssign(const GdbResponse &)
|
|||||||
updateLocals();
|
updateLocals();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Find the "type" and "displayedtype" children of root and set up type.
|
|
||||||
void GdbEngine::setWatchDataType(WatchData &data, const GdbMi &item)
|
|
||||||
{
|
|
||||||
if (item.isValid()) {
|
|
||||||
const QString miData = _(item.data());
|
|
||||||
if (!data.framekey.isEmpty())
|
|
||||||
m_varToType[data.framekey] = miData;
|
|
||||||
data.setType(miData);
|
|
||||||
} else if (data.type.isEmpty()) {
|
|
||||||
data.setTypeNeeded();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void GdbEngine::setWatchDataDisplayedType(WatchData &data, const GdbMi &item)
|
|
||||||
{
|
|
||||||
if (item.isValid())
|
|
||||||
data.displayedType = _(item.data());
|
|
||||||
}
|
|
||||||
|
|
||||||
void GdbEngine::handleVarCreate(const GdbResponse &response)
|
void GdbEngine::handleVarCreate(const GdbResponse &response)
|
||||||
{
|
{
|
||||||
WatchData data = response.cookie.value<WatchData>();
|
WatchData data = response.cookie.value<WatchData>();
|
||||||
@@ -3502,84 +3423,6 @@ void GdbEngine::handleDebuggingHelperSetup(const GdbResponse &response)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void GdbEngine::handleChildren(const WatchData &data0, const GdbMi &item,
|
|
||||||
QList<WatchData> *list)
|
|
||||||
{
|
|
||||||
//qDebug() << "HANDLE CHILDREN: " << data0.toString() << item.toString();
|
|
||||||
WatchData data = data0;
|
|
||||||
if (!manager()->watchHandler()->isExpandedIName(data.iname))
|
|
||||||
data.setChildrenUnneeded();
|
|
||||||
|
|
||||||
GdbMi children = item.findChild("children");
|
|
||||||
if (children.isValid() || !manager()->watchHandler()->isExpandedIName(data.iname))
|
|
||||||
data.setChildrenUnneeded();
|
|
||||||
|
|
||||||
setWatchDataType(data, item.findChild("type"));
|
|
||||||
GdbMi mi = item.findChild("editvalue");
|
|
||||||
if (mi.isValid())
|
|
||||||
data.editvalue = mi.data();
|
|
||||||
mi = item.findChild("editformat");
|
|
||||||
if (mi.isValid())
|
|
||||||
data.editformat = mi.data().toInt();
|
|
||||||
mi = item.findChild("typeformats");
|
|
||||||
if (mi.isValid())
|
|
||||||
data.typeFormats = QString::fromUtf8(mi.data());
|
|
||||||
|
|
||||||
setWatchDataValue(data, item);
|
|
||||||
setWatchDataAddress(data, item.findChild("addr"));
|
|
||||||
setWatchDataExpression(data, item.findChild("exp"));
|
|
||||||
setWatchDataValueEnabled(data, item.findChild("valueenabled"));
|
|
||||||
setWatchDataValueEditable(data, item.findChild("valueeditable"));
|
|
||||||
setWatchDataChildCount(data, item.findChild("numchild"));
|
|
||||||
//qDebug() << "\nAPPEND TO LIST: " << data.toString() << "\n";
|
|
||||||
list->append(data);
|
|
||||||
|
|
||||||
bool ok = false;
|
|
||||||
qulonglong addressBase = item.findChild("addrbase").data().toULongLong(&ok, 0);
|
|
||||||
qulonglong addressStep = item.findChild("addrstep").data().toULongLong();
|
|
||||||
|
|
||||||
// Try not to repeat data too often.
|
|
||||||
WatchData childtemplate;
|
|
||||||
setWatchDataType(childtemplate, item.findChild("childtype"));
|
|
||||||
setWatchDataChildCount(childtemplate, item.findChild("childnumchild"));
|
|
||||||
//qDebug() << "CHILD TEMPLATE:" << childtemplate.toString();
|
|
||||||
|
|
||||||
int i = 0;
|
|
||||||
foreach (const GdbMi &child, children.children()) {
|
|
||||||
WatchData data1 = childtemplate;
|
|
||||||
GdbMi name = child.findChild("name");
|
|
||||||
if (name.isValid())
|
|
||||||
data1.name = _(name.data());
|
|
||||||
else
|
|
||||||
data1.name = QString::number(i);
|
|
||||||
GdbMi iname = child.findChild("iname");
|
|
||||||
if (iname.isValid())
|
|
||||||
data1.iname = iname.data();
|
|
||||||
else
|
|
||||||
data1.iname = data.iname + '.' + data1.name.toLatin1();
|
|
||||||
if (!data1.name.isEmpty() && data1.name.at(0).isDigit())
|
|
||||||
data1.name = _c('[') + data1.name + _c(']');
|
|
||||||
if (addressStep) {
|
|
||||||
const QByteArray addr = "0x" + QByteArray::number(addressBase, 16);
|
|
||||||
setWatchDataAddressHelper(data1, addr);
|
|
||||||
addressBase += addressStep;
|
|
||||||
}
|
|
||||||
QByteArray key = child.findChild("key").data();
|
|
||||||
if (!key.isEmpty()) {
|
|
||||||
int encoding = child.findChild("keyencoded").data().toInt();
|
|
||||||
QString skey = decodeData(key, encoding);
|
|
||||||
if (skey.size() > 13) {
|
|
||||||
skey = skey.left(12);
|
|
||||||
skey += _("...");
|
|
||||||
}
|
|
||||||
//data1.name += " (" + skey + ")";
|
|
||||||
data1.name = skey;
|
|
||||||
}
|
|
||||||
handleChildren(data1, child, list);
|
|
||||||
++i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void GdbEngine::updateLocals(const QVariant &cookie)
|
void GdbEngine::updateLocals(const QVariant &cookie)
|
||||||
{
|
{
|
||||||
m_pendingWatchRequests = 0;
|
m_pendingWatchRequests = 0;
|
||||||
|
|||||||
@@ -459,8 +459,6 @@ private: ////////// View & Data Stuff //////////
|
|||||||
|
|
||||||
// FIXME: BaseClass. called to improve situation for a watch item
|
// FIXME: BaseClass. called to improve situation for a watch item
|
||||||
void updateSubItemClassic(const WatchData &data);
|
void updateSubItemClassic(const WatchData &data);
|
||||||
void handleChildren(const WatchData &parent, const GdbMi &child,
|
|
||||||
QList<WatchData> *insertions);
|
|
||||||
|
|
||||||
void virtual updateWatchData(const WatchData &data);
|
void virtual updateWatchData(const WatchData &data);
|
||||||
Q_SLOT void updateWatchDataHelper(const WatchData &data);
|
Q_SLOT void updateWatchDataHelper(const WatchData &data);
|
||||||
@@ -503,11 +501,8 @@ private: ////////// View & Data Stuff //////////
|
|||||||
QMap<QByteArray, int> *seen);
|
QMap<QByteArray, int> *seen);
|
||||||
void setLocals(const QList<GdbMi> &locals);
|
void setLocals(const QList<GdbMi> &locals);
|
||||||
void handleStackListArgumentsClassic(const GdbResponse &response);
|
void handleStackListArgumentsClassic(const GdbResponse &response);
|
||||||
void setWatchDataType(WatchData &data, const GdbMi &mi);
|
|
||||||
void setWatchDataDisplayedType(WatchData &data, const GdbMi &mi);
|
|
||||||
|
|
||||||
QSet<QByteArray> m_processedNames;
|
QSet<QByteArray> m_processedNames;
|
||||||
QMap<QString, QString> m_varToType;
|
|
||||||
|
|
||||||
private: ////////// Dumper Management //////////
|
private: ////////// Dumper Management //////////
|
||||||
QString qtDumperLibraryName() const;
|
QString qtDumperLibraryName() const;
|
||||||
@@ -538,16 +533,6 @@ private: ////////// Convenience Functions //////////
|
|||||||
static QString m_toolTipExpression;
|
static QString m_toolTipExpression;
|
||||||
static QPoint m_toolTipPos;
|
static QPoint m_toolTipPos;
|
||||||
static QByteArray tooltipINameForExpression(const QByteArray &exp);
|
static QByteArray tooltipINameForExpression(const QByteArray &exp);
|
||||||
|
|
||||||
static void setWatchDataValue(WatchData &data, const GdbMi &item);
|
|
||||||
static void setWatchDataValueToolTip(WatchData &data, const GdbMi &mi,
|
|
||||||
int encoding = 0);
|
|
||||||
static void setWatchDataChildCount(WatchData &data, const GdbMi &mi);
|
|
||||||
static void setWatchDataValueEnabled(WatchData &data, const GdbMi &mi);
|
|
||||||
static void setWatchDataValueEditable(WatchData &data, const GdbMi &mi);
|
|
||||||
static void setWatchDataExpression(WatchData &data, const GdbMi &mi);
|
|
||||||
static void setWatchDataAddress(WatchData &data, const GdbMi &mi);
|
|
||||||
static void setWatchDataAddressHelper(WatchData &data, const QByteArray &addr);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Internal
|
} // namespace Internal
|
||||||
|
|||||||
@@ -125,14 +125,15 @@ void GdbEngine::handleStackFramePython(const GdbResponse &response)
|
|||||||
|
|
||||||
GdbMi data = all.findChild("data");
|
GdbMi data = all.findChild("data");
|
||||||
QList<WatchData> list;
|
QList<WatchData> list;
|
||||||
|
WatchHandler *watchHandler = manager()->watchHandler();
|
||||||
foreach (const GdbMi &child, data.children()) {
|
foreach (const GdbMi &child, data.children()) {
|
||||||
WatchData dummy;
|
WatchData dummy;
|
||||||
dummy.iname = child.findChild("iname").data();
|
dummy.iname = child.findChild("iname").data();
|
||||||
dummy.name = _(child.findChild("name").data());
|
dummy.name = _(child.findChild("name").data());
|
||||||
//qDebug() << "CHILD: " << child.toString();
|
//qDebug() << "CHILD: " << child.toString();
|
||||||
handleChildren(dummy, child, &list);
|
parseWatchData(watchHandler->expandedINames(), dummy, child, &list);
|
||||||
}
|
}
|
||||||
manager()->watchHandler()->insertBulkData(list);
|
watchHandler->insertBulkData(list);
|
||||||
//for (int i = 0; i != list.size(); ++i)
|
//for (int i = 0; i != list.size(); ++i)
|
||||||
// qDebug() << "LOCAL: " << list.at(i).toString();
|
// qDebug() << "LOCAL: " << list.at(i).toString();
|
||||||
|
|
||||||
|
|||||||
265
src/plugins/debugger/watchdata.cpp
Normal file
265
src/plugins/debugger/watchdata.cpp
Normal file
@@ -0,0 +1,265 @@
|
|||||||
|
|
||||||
|
#include "watchdata.h"
|
||||||
|
#include "watchutils.h"
|
||||||
|
|
||||||
|
#include <QtCore/QTextStream>
|
||||||
|
#include <QtCore/QDebug>
|
||||||
|
|
||||||
|
#include <QtGui/QApplication>
|
||||||
|
#include <QtGui/QTextDocument> // Qt::escape
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// WatchData
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
namespace Debugger {
|
||||||
|
namespace Internal {
|
||||||
|
|
||||||
|
WatchData::WatchData() :
|
||||||
|
editformat(0),
|
||||||
|
hasChildren(false),
|
||||||
|
generation(-1),
|
||||||
|
valueEnabled(true),
|
||||||
|
valueEditable(true),
|
||||||
|
error(false),
|
||||||
|
source(0),
|
||||||
|
state(InitialState),
|
||||||
|
changed(false)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
bool WatchData::isEqual(const WatchData &other) const
|
||||||
|
{
|
||||||
|
return iname == other.iname
|
||||||
|
&& exp == other.exp
|
||||||
|
&& name == other.name
|
||||||
|
&& value == other.value
|
||||||
|
&& editvalue == other.editvalue
|
||||||
|
&& valuetooltip == other.valuetooltip
|
||||||
|
&& type == other.type
|
||||||
|
&& displayedType == other.displayedType
|
||||||
|
&& variable == other.variable
|
||||||
|
&& addr == other.addr
|
||||||
|
&& framekey == other.framekey
|
||||||
|
&& hasChildren == other.hasChildren
|
||||||
|
&& valueEnabled == other.valueEnabled
|
||||||
|
&& valueEditable == other.valueEditable
|
||||||
|
&& error == other.error;
|
||||||
|
}
|
||||||
|
|
||||||
|
void WatchData::setError(const QString &msg)
|
||||||
|
{
|
||||||
|
setAllUnneeded();
|
||||||
|
value = msg;
|
||||||
|
setHasChildren(false);
|
||||||
|
valueEnabled = false;
|
||||||
|
valueEditable = false;
|
||||||
|
error = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void WatchData::setValue(const QString &value0)
|
||||||
|
{
|
||||||
|
value = value0;
|
||||||
|
if (value == "{...}") {
|
||||||
|
value.clear();
|
||||||
|
hasChildren = true; // at least one...
|
||||||
|
}
|
||||||
|
// strip off quoted characters for chars.
|
||||||
|
if (value.endsWith(QLatin1Char('\'')) && type.endsWith(QLatin1String("char"))) {
|
||||||
|
const int blankPos = value.indexOf(QLatin1Char(' '));
|
||||||
|
if (blankPos != -1)
|
||||||
|
value.truncate(blankPos);
|
||||||
|
}
|
||||||
|
|
||||||
|
// avoid duplicated information
|
||||||
|
if (value.startsWith(QLatin1Char('(')) && value.contains(") 0x"))
|
||||||
|
value = value.mid(value.lastIndexOf(") 0x") + 2);
|
||||||
|
|
||||||
|
// doubles are sometimes displayed as "@0x6141378: 1.2".
|
||||||
|
// I don't want that.
|
||||||
|
if (/*isIntOrFloatType(type) && */ value.startsWith("@0x")
|
||||||
|
&& value.contains(':')) {
|
||||||
|
value = value.mid(value.indexOf(':') + 2);
|
||||||
|
setHasChildren(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
// "numchild" is sometimes lying
|
||||||
|
//MODEL_DEBUG("\n\n\nPOINTER: " << type << value);
|
||||||
|
if (isPointerType(type))
|
||||||
|
setHasChildren(value != "0x0" && value != "<null>"
|
||||||
|
&& !isCharPointerType(type));
|
||||||
|
|
||||||
|
// pointer type information is available in the 'type'
|
||||||
|
// column. No need to duplicate it here.
|
||||||
|
if (value.startsWith(QLatin1Char('(') + type + ") 0x"))
|
||||||
|
value = value.section(QLatin1Char(' '), -1, -1);
|
||||||
|
|
||||||
|
setValueUnneeded();
|
||||||
|
}
|
||||||
|
|
||||||
|
void WatchData::setValueToolTip(const QString &tooltip)
|
||||||
|
{
|
||||||
|
valuetooltip = tooltip;
|
||||||
|
}
|
||||||
|
|
||||||
|
void WatchData::setType(const QString &str, bool guessChildrenFromType)
|
||||||
|
{
|
||||||
|
type = str.trimmed();
|
||||||
|
bool changed = true;
|
||||||
|
while (changed) {
|
||||||
|
if (type.endsWith(QLatin1String("const")))
|
||||||
|
type.chop(5);
|
||||||
|
else if (type.endsWith(QLatin1Char(' ')))
|
||||||
|
type.chop(1);
|
||||||
|
else if (type.endsWith(QLatin1Char('&')))
|
||||||
|
type.chop(1);
|
||||||
|
else if (type.startsWith(QLatin1String("const ")))
|
||||||
|
type = type.mid(6);
|
||||||
|
else if (type.startsWith(QLatin1String("volatile ")))
|
||||||
|
type = type.mid(9);
|
||||||
|
else if (type.startsWith(QLatin1String("class ")))
|
||||||
|
type = type.mid(6);
|
||||||
|
else if (type.startsWith(QLatin1String("struct ")))
|
||||||
|
type = type.mid(6);
|
||||||
|
else if (type.startsWith(QLatin1Char(' ')))
|
||||||
|
type = type.mid(1);
|
||||||
|
else
|
||||||
|
changed = false;
|
||||||
|
}
|
||||||
|
setTypeUnneeded();
|
||||||
|
if (guessChildrenFromType) {
|
||||||
|
switch (guessChildren(type)) {
|
||||||
|
case HasChildren:
|
||||||
|
setHasChildren(true);
|
||||||
|
break;
|
||||||
|
case HasNoChildren:
|
||||||
|
setHasChildren(false);
|
||||||
|
break;
|
||||||
|
case HasPossiblyChildren:
|
||||||
|
setHasChildren(true); // FIXME: bold assumption
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void WatchData::setAddress(const QByteArray &a)
|
||||||
|
{
|
||||||
|
addr = a;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString WatchData::toString() const
|
||||||
|
{
|
||||||
|
const char *doubleQuoteComma = "\",";
|
||||||
|
QString res;
|
||||||
|
QTextStream str(&res);
|
||||||
|
str << QLatin1Char('{');
|
||||||
|
if (!iname.isEmpty())
|
||||||
|
str << "iname=\"" << iname << doubleQuoteComma;
|
||||||
|
if (!name.isEmpty() && name != iname)
|
||||||
|
str << "name=\"" << name << doubleQuoteComma;
|
||||||
|
if (error)
|
||||||
|
str << "error,";
|
||||||
|
if (!addr.isEmpty())
|
||||||
|
str << "addr=\"" << addr << doubleQuoteComma;
|
||||||
|
if (!exp.isEmpty())
|
||||||
|
str << "exp=\"" << exp << doubleQuoteComma;
|
||||||
|
|
||||||
|
if (!variable.isEmpty())
|
||||||
|
str << "variable=\"" << variable << doubleQuoteComma;
|
||||||
|
|
||||||
|
if (isValueNeeded())
|
||||||
|
str << "value=<needed>,";
|
||||||
|
if (isValueKnown() && !value.isEmpty())
|
||||||
|
str << "value=\"" << value << doubleQuoteComma;
|
||||||
|
|
||||||
|
if (!editvalue.isEmpty())
|
||||||
|
str << "editvalue=\"<...>\",";
|
||||||
|
// str << "editvalue=\"" << editvalue << doubleQuoteComma;
|
||||||
|
|
||||||
|
if (isTypeNeeded())
|
||||||
|
str << "type=<needed>,";
|
||||||
|
if (isTypeKnown() && !type.isEmpty())
|
||||||
|
str << "type=\"" << type << doubleQuoteComma;
|
||||||
|
|
||||||
|
if (isHasChildrenNeeded())
|
||||||
|
str << "hasChildren=<needed>,";
|
||||||
|
if (isHasChildrenKnown())
|
||||||
|
str << "hasChildren=\"" << (hasChildren ? "true" : "false") << doubleQuoteComma;
|
||||||
|
|
||||||
|
if (isChildrenNeeded())
|
||||||
|
str << "children=<needed>,";
|
||||||
|
if (source)
|
||||||
|
str << "source=" << source;
|
||||||
|
str.flush();
|
||||||
|
if (res.endsWith(QLatin1Char(',')))
|
||||||
|
res.truncate(res.size() - 1);
|
||||||
|
return res + QLatin1Char('}');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Format a tooltip fow with aligned colon.
|
||||||
|
static void formatToolTipRow(QTextStream &str,
|
||||||
|
const QString &category, const QString &value)
|
||||||
|
{
|
||||||
|
str << "<tr><td>" << category << "</td><td> : </td><td>"
|
||||||
|
<< Qt::escape(value) << "</td></tr>";
|
||||||
|
}
|
||||||
|
|
||||||
|
static QString typeToolTip(const WatchData &wd)
|
||||||
|
{
|
||||||
|
if (wd.displayedType.isEmpty())
|
||||||
|
return wd.type;
|
||||||
|
QString rc = wd.displayedType;
|
||||||
|
rc += QLatin1String(" (");
|
||||||
|
rc += wd.type;
|
||||||
|
rc += QLatin1Char(')');
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString WatchData::toToolTip() const
|
||||||
|
{
|
||||||
|
if (!valuetooltip.isEmpty())
|
||||||
|
return QString::number(valuetooltip.size());
|
||||||
|
QString res;
|
||||||
|
QTextStream str(&res);
|
||||||
|
str << "<html><body><table>";
|
||||||
|
formatToolTipRow(str, QCoreApplication::translate("Debugger::Internal::WatchHandler", "Name"), name);
|
||||||
|
formatToolTipRow(str, QCoreApplication::translate("Debugger::Internal::WatchHandler", "Expression"), exp);
|
||||||
|
formatToolTipRow(str, QCoreApplication::translate("Debugger::Internal::WatchHandler", "Type"), typeToolTip(*this));
|
||||||
|
QString val = value;
|
||||||
|
if (value.size() > 1000) {
|
||||||
|
val.truncate(1000);
|
||||||
|
val += QCoreApplication::translate("Debugger::Internal::WatchHandler", " ... <cut off>");
|
||||||
|
}
|
||||||
|
formatToolTipRow(str, QCoreApplication::translate("Debugger::Internal::WatchHandler", "Value"), val);
|
||||||
|
formatToolTipRow(str, QCoreApplication::translate("Debugger::Internal::WatchHandler", "Object Address"), addr);
|
||||||
|
formatToolTipRow(str, QCoreApplication::translate("Debugger::Internal::WatchHandler", "Internal ID"), iname);
|
||||||
|
formatToolTipRow(str, QCoreApplication::translate("Debugger::Internal::WatchHandler", "Generation"),
|
||||||
|
QString::number(generation));
|
||||||
|
str << "</table></body></html>";
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString WatchData::msgNotInScope()
|
||||||
|
{
|
||||||
|
static const QString rc = QCoreApplication::translate("Debugger::Internal::WatchData", "<not in scope>");
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
const QString &WatchData::shadowedNameFormat()
|
||||||
|
{
|
||||||
|
static const QString format = QCoreApplication::translate("Debugger::Internal::WatchData", "%1 <shadowed %2>");
|
||||||
|
return format;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString WatchData::shadowedName(const QString &name, int seen)
|
||||||
|
{
|
||||||
|
if (seen <= 0)
|
||||||
|
return name;
|
||||||
|
return shadowedNameFormat().arg(name, seen);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Internal
|
||||||
|
} // namespace Debugger
|
||||||
|
|
||||||
142
src/plugins/debugger/watchdata.h
Normal file
142
src/plugins/debugger/watchdata.h
Normal file
@@ -0,0 +1,142 @@
|
|||||||
|
/**************************************************************************
|
||||||
|
**
|
||||||
|
** This file is part of Qt Creator
|
||||||
|
**
|
||||||
|
** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
|
||||||
|
**
|
||||||
|
** Contact: Nokia Corporation (qt-info@nokia.com)
|
||||||
|
**
|
||||||
|
** Commercial Usage
|
||||||
|
**
|
||||||
|
** Licensees holding valid Qt Commercial licenses may use this file in
|
||||||
|
** accordance with the Qt Commercial License Agreement provided with the
|
||||||
|
** Software or, alternatively, in accordance with the terms contained in
|
||||||
|
** a written agreement between you and Nokia.
|
||||||
|
**
|
||||||
|
** GNU Lesser General Public License Usage
|
||||||
|
**
|
||||||
|
** Alternatively, this file may be used under the terms of the GNU Lesser
|
||||||
|
** General Public License version 2.1 as published by the Free Software
|
||||||
|
** Foundation and appearing in the file LICENSE.LGPL included in the
|
||||||
|
** packaging of this file. Please review the following information to
|
||||||
|
** ensure the GNU Lesser General Public License version 2.1 requirements
|
||||||
|
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||||
|
**
|
||||||
|
** If you are unsure which license is appropriate for your use, please
|
||||||
|
** contact the sales department at http://qt.nokia.com/contact.
|
||||||
|
**
|
||||||
|
**************************************************************************/
|
||||||
|
|
||||||
|
#ifndef DEBUGGER_WATCHDATA_H
|
||||||
|
#define DEBUGGER_WATCHDATA_H
|
||||||
|
|
||||||
|
#include <QtCore/QMetaType>
|
||||||
|
#include <QtCore/QtGlobal>
|
||||||
|
#include <QtCore/QObject>
|
||||||
|
#include <QtScript/QScriptValue>
|
||||||
|
|
||||||
|
namespace Debugger {
|
||||||
|
namespace Internal {
|
||||||
|
|
||||||
|
class WatchData
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
WatchData();
|
||||||
|
|
||||||
|
enum State
|
||||||
|
{
|
||||||
|
Complete = 0,
|
||||||
|
HasChildrenNeeded = 1,
|
||||||
|
ValueNeeded = 2,
|
||||||
|
TypeNeeded = 4,
|
||||||
|
ChildrenNeeded = 8,
|
||||||
|
|
||||||
|
NeededMask = ValueNeeded
|
||||||
|
| TypeNeeded
|
||||||
|
| ChildrenNeeded
|
||||||
|
| HasChildrenNeeded,
|
||||||
|
|
||||||
|
InitialState = ValueNeeded
|
||||||
|
| TypeNeeded
|
||||||
|
| ChildrenNeeded
|
||||||
|
| HasChildrenNeeded
|
||||||
|
};
|
||||||
|
|
||||||
|
void setValue(const QString &);
|
||||||
|
void setType(const QString &, bool guessChildrenFromType = true);
|
||||||
|
void setValueToolTip(const QString &);
|
||||||
|
void setError(const QString &);
|
||||||
|
void setAddress(const QByteArray &);
|
||||||
|
|
||||||
|
bool isSomethingNeeded() const { return state & NeededMask; }
|
||||||
|
void setAllNeeded() { state = NeededMask; }
|
||||||
|
void setAllUnneeded() { state = State(0); }
|
||||||
|
|
||||||
|
bool isTypeNeeded() const { return state & TypeNeeded; }
|
||||||
|
bool isTypeKnown() const { return !(state & TypeNeeded); }
|
||||||
|
void setTypeNeeded() { state = State(state | TypeNeeded); }
|
||||||
|
void setTypeUnneeded() { state = State(state & ~TypeNeeded); }
|
||||||
|
|
||||||
|
bool isValueNeeded() const { return state & ValueNeeded; }
|
||||||
|
bool isValueKnown() const { return !(state & ValueNeeded); }
|
||||||
|
void setValueNeeded() { state = State(state | ValueNeeded); }
|
||||||
|
void setValueUnneeded() { state = State(state & ~ValueNeeded); }
|
||||||
|
|
||||||
|
bool isChildrenNeeded() const { return state & ChildrenNeeded; }
|
||||||
|
bool isChildrenKnown() const { return !(state & ChildrenNeeded); }
|
||||||
|
void setChildrenNeeded() { state = State(state | ChildrenNeeded); }
|
||||||
|
void setChildrenUnneeded() { state = State(state & ~ChildrenNeeded); }
|
||||||
|
|
||||||
|
bool isHasChildrenNeeded() const { return state & HasChildrenNeeded; }
|
||||||
|
bool isHasChildrenKnown() const { return !(state & HasChildrenNeeded); }
|
||||||
|
void setHasChildrenNeeded() { state = State(state | HasChildrenNeeded); }
|
||||||
|
void setHasChildrenUnneeded() { state = State(state & ~HasChildrenNeeded); }
|
||||||
|
void setHasChildren(bool c) { hasChildren = c; setHasChildrenUnneeded();
|
||||||
|
if (!c) setChildrenUnneeded(); }
|
||||||
|
|
||||||
|
QString toString() const;
|
||||||
|
QString toToolTip() const;
|
||||||
|
bool isLocal() const { return iname.startsWith("local."); }
|
||||||
|
bool isWatcher() const { return iname.startsWith("watch."); }
|
||||||
|
bool isValid() const { return !iname.isEmpty(); }
|
||||||
|
|
||||||
|
bool isEqual(const WatchData &other) const;
|
||||||
|
|
||||||
|
static QString msgNotInScope();
|
||||||
|
static QString shadowedName(const QString &name, int seen);
|
||||||
|
static const QString &shadowedNameFormat();
|
||||||
|
|
||||||
|
public:
|
||||||
|
QByteArray iname; // Internal name sth like 'local.baz.public.a'
|
||||||
|
QByteArray exp; // The expression
|
||||||
|
QString name; // Displayed name
|
||||||
|
QString value; // Displayed value
|
||||||
|
QByteArray editvalue; // Displayed value
|
||||||
|
int editformat; // Format of displayed value
|
||||||
|
QString valuetooltip; // Tooltip in value column
|
||||||
|
QString typeFormats; // Selection of formats of displayed value
|
||||||
|
QString type; // Type for further processing
|
||||||
|
QString displayedType;// Displayed type (optional)
|
||||||
|
QByteArray variable; // Name of internal Gdb variable if created
|
||||||
|
QByteArray addr; // Displayed address
|
||||||
|
QString framekey; // Key for type cache
|
||||||
|
QScriptValue scriptValue; // If needed...
|
||||||
|
bool hasChildren;
|
||||||
|
int generation; // When updated?
|
||||||
|
bool valueEnabled; // Value will be greyed out or not
|
||||||
|
bool valueEditable; // Value will be editable
|
||||||
|
bool error;
|
||||||
|
|
||||||
|
public:
|
||||||
|
int source; // Originated from dumper or symbol evaluation? (CDB only)
|
||||||
|
int state;
|
||||||
|
bool changed;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Internal
|
||||||
|
} // namespace Debugger
|
||||||
|
|
||||||
|
Q_DECLARE_METATYPE(Debugger::Internal::WatchData);
|
||||||
|
|
||||||
|
|
||||||
|
#endif // DEBUGGER_WATCHDATA_H
|
||||||
@@ -103,254 +103,6 @@ public:
|
|||||||
QList<WatchItem *> children; // fetched children
|
QList<WatchItem *> children; // fetched children
|
||||||
};
|
};
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
|
||||||
//
|
|
||||||
// WatchData
|
|
||||||
//
|
|
||||||
////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
WatchData::WatchData() :
|
|
||||||
editformat(0),
|
|
||||||
hasChildren(false),
|
|
||||||
generation(-1),
|
|
||||||
valueEnabled(true),
|
|
||||||
valueEditable(true),
|
|
||||||
error(false),
|
|
||||||
source(0),
|
|
||||||
state(InitialState),
|
|
||||||
changed(false)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
bool WatchData::isEqual(const WatchData &other) const
|
|
||||||
{
|
|
||||||
return iname == other.iname
|
|
||||||
&& exp == other.exp
|
|
||||||
&& name == other.name
|
|
||||||
&& value == other.value
|
|
||||||
&& editvalue == other.editvalue
|
|
||||||
&& valuetooltip == other.valuetooltip
|
|
||||||
&& type == other.type
|
|
||||||
&& displayedType == other.displayedType
|
|
||||||
&& variable == other.variable
|
|
||||||
&& addr == other.addr
|
|
||||||
&& framekey == other.framekey
|
|
||||||
&& hasChildren == other.hasChildren
|
|
||||||
&& valueEnabled == other.valueEnabled
|
|
||||||
&& valueEditable == other.valueEditable
|
|
||||||
&& error == other.error;
|
|
||||||
}
|
|
||||||
|
|
||||||
void WatchData::setError(const QString &msg)
|
|
||||||
{
|
|
||||||
setAllUnneeded();
|
|
||||||
value = msg;
|
|
||||||
setHasChildren(false);
|
|
||||||
valueEnabled = false;
|
|
||||||
valueEditable = false;
|
|
||||||
error = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void WatchData::setValue(const QString &value0)
|
|
||||||
{
|
|
||||||
value = value0;
|
|
||||||
if (value == "{...}") {
|
|
||||||
value.clear();
|
|
||||||
hasChildren = true; // at least one...
|
|
||||||
}
|
|
||||||
// strip off quoted characters for chars.
|
|
||||||
if (value.endsWith(QLatin1Char('\'')) && type.endsWith(QLatin1String("char"))) {
|
|
||||||
const int blankPos = value.indexOf(QLatin1Char(' '));
|
|
||||||
if (blankPos != -1)
|
|
||||||
value.truncate(blankPos);
|
|
||||||
}
|
|
||||||
|
|
||||||
// avoid duplicated information
|
|
||||||
if (value.startsWith(QLatin1Char('(')) && value.contains(") 0x"))
|
|
||||||
value = value.mid(value.lastIndexOf(") 0x") + 2);
|
|
||||||
|
|
||||||
// doubles are sometimes displayed as "@0x6141378: 1.2".
|
|
||||||
// I don't want that.
|
|
||||||
if (/*isIntOrFloatType(type) && */ value.startsWith("@0x")
|
|
||||||
&& value.contains(':')) {
|
|
||||||
value = value.mid(value.indexOf(':') + 2);
|
|
||||||
setHasChildren(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
// "numchild" is sometimes lying
|
|
||||||
//MODEL_DEBUG("\n\n\nPOINTER: " << type << value);
|
|
||||||
if (isPointerType(type))
|
|
||||||
setHasChildren(value != "0x0" && value != "<null>"
|
|
||||||
&& !isCharPointerType(type));
|
|
||||||
|
|
||||||
// pointer type information is available in the 'type'
|
|
||||||
// column. No need to duplicate it here.
|
|
||||||
if (value.startsWith(QLatin1Char('(') + type + ") 0x"))
|
|
||||||
value = value.section(QLatin1Char(' '), -1, -1);
|
|
||||||
|
|
||||||
setValueUnneeded();
|
|
||||||
}
|
|
||||||
|
|
||||||
void WatchData::setValueToolTip(const QString &tooltip)
|
|
||||||
{
|
|
||||||
valuetooltip = tooltip;
|
|
||||||
}
|
|
||||||
|
|
||||||
void WatchData::setType(const QString &str, bool guessChildrenFromType)
|
|
||||||
{
|
|
||||||
type = str.trimmed();
|
|
||||||
bool changed = true;
|
|
||||||
while (changed) {
|
|
||||||
if (type.endsWith(QLatin1String("const")))
|
|
||||||
type.chop(5);
|
|
||||||
else if (type.endsWith(QLatin1Char(' ')))
|
|
||||||
type.chop(1);
|
|
||||||
else if (type.endsWith(QLatin1Char('&')))
|
|
||||||
type.chop(1);
|
|
||||||
else if (type.startsWith(QLatin1String("const ")))
|
|
||||||
type = type.mid(6);
|
|
||||||
else if (type.startsWith(QLatin1String("volatile ")))
|
|
||||||
type = type.mid(9);
|
|
||||||
else if (type.startsWith(QLatin1String("class ")))
|
|
||||||
type = type.mid(6);
|
|
||||||
else if (type.startsWith(QLatin1String("struct ")))
|
|
||||||
type = type.mid(6);
|
|
||||||
else if (type.startsWith(QLatin1Char(' ')))
|
|
||||||
type = type.mid(1);
|
|
||||||
else
|
|
||||||
changed = false;
|
|
||||||
}
|
|
||||||
setTypeUnneeded();
|
|
||||||
if (guessChildrenFromType) {
|
|
||||||
switch (guessChildren(type)) {
|
|
||||||
case HasChildren:
|
|
||||||
setHasChildren(true);
|
|
||||||
break;
|
|
||||||
case HasNoChildren:
|
|
||||||
setHasChildren(false);
|
|
||||||
break;
|
|
||||||
case HasPossiblyChildren:
|
|
||||||
setHasChildren(true); // FIXME: bold assumption
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void WatchData::setAddress(const QByteArray &a)
|
|
||||||
{
|
|
||||||
addr = a;
|
|
||||||
}
|
|
||||||
|
|
||||||
QString WatchData::toString() const
|
|
||||||
{
|
|
||||||
const char *doubleQuoteComma = "\",";
|
|
||||||
QString res;
|
|
||||||
QTextStream str(&res);
|
|
||||||
str << QLatin1Char('{');
|
|
||||||
if (!iname.isEmpty())
|
|
||||||
str << "iname=\"" << iname << doubleQuoteComma;
|
|
||||||
if (!name.isEmpty() && name != iname)
|
|
||||||
str << "name=\"" << name << doubleQuoteComma;
|
|
||||||
if (error)
|
|
||||||
str << "error,";
|
|
||||||
if (!addr.isEmpty())
|
|
||||||
str << "addr=\"" << addr << doubleQuoteComma;
|
|
||||||
if (!exp.isEmpty())
|
|
||||||
str << "exp=\"" << exp << doubleQuoteComma;
|
|
||||||
|
|
||||||
if (!variable.isEmpty())
|
|
||||||
str << "variable=\"" << variable << doubleQuoteComma;
|
|
||||||
|
|
||||||
if (isValueNeeded())
|
|
||||||
str << "value=<needed>,";
|
|
||||||
if (isValueKnown() && !value.isEmpty())
|
|
||||||
str << "value=\"" << value << doubleQuoteComma;
|
|
||||||
|
|
||||||
if (!editvalue.isEmpty())
|
|
||||||
str << "editvalue=\"<...>\",";
|
|
||||||
// str << "editvalue=\"" << editvalue << doubleQuoteComma;
|
|
||||||
|
|
||||||
if (isTypeNeeded())
|
|
||||||
str << "type=<needed>,";
|
|
||||||
if (isTypeKnown() && !type.isEmpty())
|
|
||||||
str << "type=\"" << type << doubleQuoteComma;
|
|
||||||
|
|
||||||
if (isHasChildrenNeeded())
|
|
||||||
str << "hasChildren=<needed>,";
|
|
||||||
if (isHasChildrenKnown())
|
|
||||||
str << "hasChildren=\"" << (hasChildren ? "true" : "false") << doubleQuoteComma;
|
|
||||||
|
|
||||||
if (isChildrenNeeded())
|
|
||||||
str << "children=<needed>,";
|
|
||||||
if (source)
|
|
||||||
str << "source=" << source;
|
|
||||||
str.flush();
|
|
||||||
if (res.endsWith(QLatin1Char(',')))
|
|
||||||
res.truncate(res.size() - 1);
|
|
||||||
return res + QLatin1Char('}');
|
|
||||||
}
|
|
||||||
|
|
||||||
// Format a tooltip fow with aligned colon.
|
|
||||||
static void formatToolTipRow(QTextStream &str,
|
|
||||||
const QString &category, const QString &value)
|
|
||||||
{
|
|
||||||
str << "<tr><td>" << category << "</td><td> : </td><td>"
|
|
||||||
<< Qt::escape(value) << "</td></tr>";
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline QString typeToolTip(const WatchData &wd)
|
|
||||||
{
|
|
||||||
if (wd.displayedType.isEmpty())
|
|
||||||
return wd.type;
|
|
||||||
QString rc = wd.displayedType;
|
|
||||||
rc += QLatin1String(" (");
|
|
||||||
rc += wd.type;
|
|
||||||
rc += QLatin1Char(')');
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
|
|
||||||
QString WatchData::toToolTip() const
|
|
||||||
{
|
|
||||||
if (!valuetooltip.isEmpty())
|
|
||||||
return QString::number(valuetooltip.size());
|
|
||||||
QString res;
|
|
||||||
QTextStream str(&res);
|
|
||||||
str << "<html><body><table>";
|
|
||||||
formatToolTipRow(str, WatchHandler::tr("Name"), name);
|
|
||||||
formatToolTipRow(str, WatchHandler::tr("Expression"), exp);
|
|
||||||
formatToolTipRow(str, WatchHandler::tr("Type"), typeToolTip(*this));
|
|
||||||
QString val = value;
|
|
||||||
if (value.size() > 1000) {
|
|
||||||
val.truncate(1000);
|
|
||||||
val += WatchHandler::tr(" ... <cut off>");
|
|
||||||
}
|
|
||||||
formatToolTipRow(str, WatchHandler::tr("Value"), val);
|
|
||||||
formatToolTipRow(str, WatchHandler::tr("Object Address"), addr);
|
|
||||||
formatToolTipRow(str, WatchHandler::tr("Internal ID"), iname);
|
|
||||||
formatToolTipRow(str, WatchHandler::tr("Generation"),
|
|
||||||
QString::number(generation));
|
|
||||||
str << "</table></body></html>";
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
QString WatchData::msgNotInScope()
|
|
||||||
{
|
|
||||||
static const QString rc = QCoreApplication::translate("Debugger::Internal::WatchData", "<not in scope>");
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
|
|
||||||
const QString &WatchData::shadowedNameFormat()
|
|
||||||
{
|
|
||||||
static const QString format = QCoreApplication::translate("Debugger::Internal::WatchData", "%1 <shadowed %2>");
|
|
||||||
return format;
|
|
||||||
}
|
|
||||||
|
|
||||||
QString WatchData::shadowedName(const QString &name, int seen)
|
|
||||||
{
|
|
||||||
if (seen <= 0)
|
|
||||||
return name;
|
|
||||||
return shadowedNameFormat().arg(name, seen);
|
|
||||||
}
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////
|
||||||
//
|
//
|
||||||
|
|||||||
@@ -30,6 +30,8 @@
|
|||||||
#ifndef DEBUGGER_WATCHHANDLER_H
|
#ifndef DEBUGGER_WATCHHANDLER_H
|
||||||
#define DEBUGGER_WATCHHANDLER_H
|
#define DEBUGGER_WATCHHANDLER_H
|
||||||
|
|
||||||
|
#include "watchdata.h"
|
||||||
|
|
||||||
#include <QtCore/QPointer>
|
#include <QtCore/QPointer>
|
||||||
#include <QtCore/QObject>
|
#include <QtCore/QObject>
|
||||||
#include <QtCore/QHash>
|
#include <QtCore/QHash>
|
||||||
@@ -51,101 +53,6 @@ class WatchItem;
|
|||||||
class WatchHandler;
|
class WatchHandler;
|
||||||
enum WatchType { LocalsWatch, WatchersWatch, TooltipsWatch };
|
enum WatchType { LocalsWatch, WatchersWatch, TooltipsWatch };
|
||||||
|
|
||||||
class WatchData
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
WatchData();
|
|
||||||
|
|
||||||
enum State
|
|
||||||
{
|
|
||||||
Complete = 0,
|
|
||||||
HasChildrenNeeded = 1,
|
|
||||||
ValueNeeded = 2,
|
|
||||||
TypeNeeded = 4,
|
|
||||||
ChildrenNeeded = 8,
|
|
||||||
|
|
||||||
NeededMask = ValueNeeded
|
|
||||||
| TypeNeeded
|
|
||||||
| ChildrenNeeded
|
|
||||||
| HasChildrenNeeded,
|
|
||||||
|
|
||||||
InitialState = ValueNeeded
|
|
||||||
| TypeNeeded
|
|
||||||
| ChildrenNeeded
|
|
||||||
| HasChildrenNeeded
|
|
||||||
};
|
|
||||||
|
|
||||||
void setValue(const QString &);
|
|
||||||
void setType(const QString &, bool guessChildrenFromType = true);
|
|
||||||
void setValueToolTip(const QString &);
|
|
||||||
void setError(const QString &);
|
|
||||||
void setAddress(const QByteArray &);
|
|
||||||
|
|
||||||
bool isSomethingNeeded() const { return state & NeededMask; }
|
|
||||||
void setAllNeeded() { state = NeededMask; }
|
|
||||||
void setAllUnneeded() { state = State(0); }
|
|
||||||
|
|
||||||
bool isTypeNeeded() const { return state & TypeNeeded; }
|
|
||||||
bool isTypeKnown() const { return !(state & TypeNeeded); }
|
|
||||||
void setTypeNeeded() { state = State(state | TypeNeeded); }
|
|
||||||
void setTypeUnneeded() { state = State(state & ~TypeNeeded); }
|
|
||||||
|
|
||||||
bool isValueNeeded() const { return state & ValueNeeded; }
|
|
||||||
bool isValueKnown() const { return !(state & ValueNeeded); }
|
|
||||||
void setValueNeeded() { state = State(state | ValueNeeded); }
|
|
||||||
void setValueUnneeded() { state = State(state & ~ValueNeeded); }
|
|
||||||
|
|
||||||
bool isChildrenNeeded() const { return state & ChildrenNeeded; }
|
|
||||||
bool isChildrenKnown() const { return !(state & ChildrenNeeded); }
|
|
||||||
void setChildrenNeeded() { state = State(state | ChildrenNeeded); }
|
|
||||||
void setChildrenUnneeded() { state = State(state & ~ChildrenNeeded); }
|
|
||||||
|
|
||||||
bool isHasChildrenNeeded() const { return state & HasChildrenNeeded; }
|
|
||||||
bool isHasChildrenKnown() const { return !(state & HasChildrenNeeded); }
|
|
||||||
void setHasChildrenNeeded() { state = State(state | HasChildrenNeeded); }
|
|
||||||
void setHasChildrenUnneeded() { state = State(state & ~HasChildrenNeeded); }
|
|
||||||
void setHasChildren(bool c) { hasChildren = c; setHasChildrenUnneeded();
|
|
||||||
if (!c) setChildrenUnneeded(); }
|
|
||||||
|
|
||||||
QString toString() const;
|
|
||||||
QString toToolTip() const;
|
|
||||||
bool isLocal() const { return iname.startsWith("local."); }
|
|
||||||
bool isWatcher() const { return iname.startsWith("watch."); }
|
|
||||||
bool isValid() const { return !iname.isEmpty(); }
|
|
||||||
|
|
||||||
bool isEqual(const WatchData &other) const;
|
|
||||||
|
|
||||||
static QString msgNotInScope();
|
|
||||||
static QString shadowedName(const QString &name, int seen);
|
|
||||||
static const QString &shadowedNameFormat();
|
|
||||||
|
|
||||||
public:
|
|
||||||
QByteArray iname; // Internal name sth like 'local.baz.public.a'
|
|
||||||
QByteArray exp; // The expression
|
|
||||||
QString name; // Displayed name
|
|
||||||
QString value; // Displayed value
|
|
||||||
QByteArray editvalue; // Displayed value
|
|
||||||
int editformat; // Format of displayed value
|
|
||||||
QString valuetooltip; // Tooltip in value column
|
|
||||||
QString typeFormats; // Selection of formats of displayed value
|
|
||||||
QString type; // Type for further processing
|
|
||||||
QString displayedType;// Displayed type (optional)
|
|
||||||
QByteArray variable; // Name of internal Gdb variable if created
|
|
||||||
QByteArray addr; // Displayed address
|
|
||||||
QString framekey; // Key for type cache
|
|
||||||
QScriptValue scriptValue; // If needed...
|
|
||||||
bool hasChildren;
|
|
||||||
int generation; // When updated?
|
|
||||||
bool valueEnabled; // Value will be greyed out or not
|
|
||||||
bool valueEditable; // Value will be editable
|
|
||||||
bool error;
|
|
||||||
|
|
||||||
public:
|
|
||||||
int source; // Originated from dumper or symbol evaluation? (CDB only)
|
|
||||||
int state;
|
|
||||||
bool changed;
|
|
||||||
};
|
|
||||||
|
|
||||||
enum WatchRoles
|
enum WatchRoles
|
||||||
{
|
{
|
||||||
INameRole = Qt::UserRole,
|
INameRole = Qt::UserRole,
|
||||||
@@ -305,6 +212,4 @@ private:
|
|||||||
} // namespace Internal
|
} // namespace Internal
|
||||||
} // namespace Debugger
|
} // namespace Debugger
|
||||||
|
|
||||||
Q_DECLARE_METATYPE(Debugger::Internal::WatchData);
|
|
||||||
|
|
||||||
#endif // DEBUGGER_WATCHHANDLER_H
|
#endif // DEBUGGER_WATCHHANDLER_H
|
||||||
|
|||||||
@@ -28,8 +28,10 @@
|
|||||||
**************************************************************************/
|
**************************************************************************/
|
||||||
|
|
||||||
#include "watchutils.h"
|
#include "watchutils.h"
|
||||||
#include "watchhandler.h"
|
#include "watchdata.h"
|
||||||
|
#include "debuggerstringutils.h"
|
||||||
#include "gdb/gdbmi.h"
|
#include "gdb/gdbmi.h"
|
||||||
|
|
||||||
#include <utils/qtcassert.h>
|
#include <utils/qtcassert.h>
|
||||||
|
|
||||||
#include <coreplugin/ifile.h>
|
#include <coreplugin/ifile.h>
|
||||||
@@ -1543,5 +1545,166 @@ QDebug operator<<(QDebug in, const QtDumperHelper::TypeData &d)
|
|||||||
return in;
|
return in;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// GdbMi interaction
|
||||||
|
//
|
||||||
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
void setWatchDataValue(WatchData &data, const GdbMi &item)
|
||||||
|
{
|
||||||
|
GdbMi value = item.findChild("value");
|
||||||
|
if (value.isValid()) {
|
||||||
|
int encoding = item.findChild("valueencoded").data().toInt();
|
||||||
|
data.setValue(decodeData(value.data(), encoding));
|
||||||
|
} else {
|
||||||
|
data.setValueNeeded();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void setWatchDataValueToolTip(WatchData &data, const GdbMi &mi,
|
||||||
|
int encoding)
|
||||||
|
{
|
||||||
|
if (mi.isValid())
|
||||||
|
data.setValueToolTip(decodeData(mi.data(), encoding));
|
||||||
|
}
|
||||||
|
|
||||||
|
void setWatchDataChildCount(WatchData &data, const GdbMi &mi)
|
||||||
|
{
|
||||||
|
if (mi.isValid())
|
||||||
|
data.setHasChildren(mi.data().toInt() > 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void setWatchDataValueEnabled(WatchData &data, const GdbMi &mi)
|
||||||
|
{
|
||||||
|
if (mi.data() == "true")
|
||||||
|
data.valueEnabled = true;
|
||||||
|
else if (mi.data() == "false")
|
||||||
|
data.valueEnabled = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setWatchDataValueEditable(WatchData &data, const GdbMi &mi)
|
||||||
|
{
|
||||||
|
if (mi.data() == "true")
|
||||||
|
data.valueEditable = true;
|
||||||
|
else if (mi.data() == "false")
|
||||||
|
data.valueEditable = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setWatchDataExpression(WatchData &data, const GdbMi &mi)
|
||||||
|
{
|
||||||
|
if (mi.isValid())
|
||||||
|
data.exp = mi.data();
|
||||||
|
}
|
||||||
|
|
||||||
|
void setWatchDataAddress(WatchData &data, const GdbMi &mi)
|
||||||
|
{
|
||||||
|
if (mi.isValid())
|
||||||
|
setWatchDataAddressHelper(data, mi.data());
|
||||||
|
}
|
||||||
|
|
||||||
|
void setWatchDataAddressHelper(WatchData &data, const QByteArray &addr)
|
||||||
|
{
|
||||||
|
data.addr = addr;
|
||||||
|
if (data.exp.isEmpty() && !data.addr.startsWith("$"))
|
||||||
|
data.exp = "*(" + gdbQuoteTypes(data.type).toLatin1() + "*)" + data.addr;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find the "type" and "displayedtype" children of root and set up type.
|
||||||
|
void setWatchDataType(WatchData &data, const GdbMi &item)
|
||||||
|
{
|
||||||
|
if (item.isValid())
|
||||||
|
data.setType(_(item.data()));
|
||||||
|
else if (data.type.isEmpty())
|
||||||
|
data.setTypeNeeded();
|
||||||
|
}
|
||||||
|
|
||||||
|
void setWatchDataDisplayedType(WatchData &data, const GdbMi &item)
|
||||||
|
{
|
||||||
|
if (item.isValid())
|
||||||
|
data.displayedType = _(item.data());
|
||||||
|
}
|
||||||
|
|
||||||
|
void parseWatchData(const QSet<QByteArray> &expandedINames,
|
||||||
|
const WatchData &data0, const GdbMi &item, QList<WatchData> *list)
|
||||||
|
{
|
||||||
|
//qDebug() << "HANDLE CHILDREN: " << data0.toString() << item.toString();
|
||||||
|
WatchData data = data0;
|
||||||
|
bool isExpanded = expandedINames.contains(data.iname);
|
||||||
|
if (!isExpanded)
|
||||||
|
data.setChildrenUnneeded();
|
||||||
|
|
||||||
|
GdbMi children = item.findChild("children");
|
||||||
|
if (children.isValid() || !isExpanded)
|
||||||
|
data.setChildrenUnneeded();
|
||||||
|
|
||||||
|
setWatchDataType(data, item.findChild("type"));
|
||||||
|
GdbMi mi = item.findChild("editvalue");
|
||||||
|
if (mi.isValid())
|
||||||
|
data.editvalue = mi.data();
|
||||||
|
mi = item.findChild("editformat");
|
||||||
|
if (mi.isValid())
|
||||||
|
data.editformat = mi.data().toInt();
|
||||||
|
mi = item.findChild("typeformats");
|
||||||
|
if (mi.isValid())
|
||||||
|
data.typeFormats = QString::fromUtf8(mi.data());
|
||||||
|
|
||||||
|
setWatchDataValue(data, item);
|
||||||
|
setWatchDataAddress(data, item.findChild("addr"));
|
||||||
|
setWatchDataExpression(data, item.findChild("exp"));
|
||||||
|
setWatchDataValueEnabled(data, item.findChild("valueenabled"));
|
||||||
|
setWatchDataValueEditable(data, item.findChild("valueeditable"));
|
||||||
|
setWatchDataChildCount(data, item.findChild("numchild"));
|
||||||
|
//qDebug() << "\nAPPEND TO LIST: " << data.toString() << "\n";
|
||||||
|
list->append(data);
|
||||||
|
|
||||||
|
bool ok = false;
|
||||||
|
qulonglong addressBase = item.findChild("addrbase").data().toULongLong(&ok, 0);
|
||||||
|
qulonglong addressStep = item.findChild("addrstep").data().toULongLong();
|
||||||
|
|
||||||
|
// Try not to repeat data too often.
|
||||||
|
WatchData childtemplate;
|
||||||
|
setWatchDataType(childtemplate, item.findChild("childtype"));
|
||||||
|
setWatchDataChildCount(childtemplate, item.findChild("childnumchild"));
|
||||||
|
//qDebug() << "CHILD TEMPLATE:" << childtemplate.toString();
|
||||||
|
|
||||||
|
int i = 0;
|
||||||
|
foreach (const GdbMi &child, children.children()) {
|
||||||
|
WatchData data1 = childtemplate;
|
||||||
|
GdbMi name = child.findChild("name");
|
||||||
|
if (name.isValid())
|
||||||
|
data1.name = _(name.data());
|
||||||
|
else
|
||||||
|
data1.name = QString::number(i);
|
||||||
|
GdbMi iname = child.findChild("iname");
|
||||||
|
if (iname.isValid())
|
||||||
|
data1.iname = iname.data();
|
||||||
|
else
|
||||||
|
data1.iname = data.iname + '.' + data1.name.toLatin1();
|
||||||
|
if (!data1.name.isEmpty() && data1.name.at(0).isDigit())
|
||||||
|
data1.name = _c('[') + data1.name + _c(']');
|
||||||
|
if (addressStep) {
|
||||||
|
const QByteArray addr = "0x" + QByteArray::number(addressBase, 16);
|
||||||
|
setWatchDataAddressHelper(data1, addr);
|
||||||
|
addressBase += addressStep;
|
||||||
|
}
|
||||||
|
QByteArray key = child.findChild("key").data();
|
||||||
|
if (!key.isEmpty()) {
|
||||||
|
int encoding = child.findChild("keyencoded").data().toInt();
|
||||||
|
QString skey = decodeData(key, encoding);
|
||||||
|
if (skey.size() > 13) {
|
||||||
|
skey = skey.left(12);
|
||||||
|
skey += _("...");
|
||||||
|
}
|
||||||
|
//data1.name += " (" + skey + ")";
|
||||||
|
data1.name = skey;
|
||||||
|
}
|
||||||
|
parseWatchData(expandedINames, data1, child, list);
|
||||||
|
++i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
} // namespace Internal
|
} // namespace Internal
|
||||||
} // namespace Debugger
|
} // namespace Debugger
|
||||||
|
|||||||
@@ -30,6 +30,7 @@
|
|||||||
#ifndef WATCHUTILS_H
|
#ifndef WATCHUTILS_H
|
||||||
#define WATCHUTILS_H
|
#define WATCHUTILS_H
|
||||||
|
|
||||||
|
#include <QtCore/QSet>
|
||||||
#include <QtCore/QString>
|
#include <QtCore/QString>
|
||||||
#include <QtCore/QMap>
|
#include <QtCore/QMap>
|
||||||
|
|
||||||
@@ -238,6 +239,27 @@ QDebug operator<<(QDebug in, const QtDumperHelper::TypeData &d);
|
|||||||
// remove the default template argument in std:: containers
|
// remove the default template argument in std:: containers
|
||||||
QString removeDefaultTemplateArguments(QString type);
|
QString removeDefaultTemplateArguments(QString type);
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// GdbMi interaction
|
||||||
|
//
|
||||||
|
|
||||||
|
void setWatchDataValue(WatchData &data, const GdbMi &item);
|
||||||
|
void setWatchDataValueToolTip(WatchData &data, const GdbMi &mi,
|
||||||
|
int encoding);
|
||||||
|
void setWatchDataChildCount(WatchData &data, const GdbMi &mi);
|
||||||
|
void setWatchDataValueEnabled(WatchData &data, const GdbMi &mi);
|
||||||
|
void setWatchDataValueEditable(WatchData &data, const GdbMi &mi);
|
||||||
|
void setWatchDataExpression(WatchData &data, const GdbMi &mi);
|
||||||
|
void setWatchDataAddress(WatchData &data, const GdbMi &mi);
|
||||||
|
void setWatchDataAddressHelper(WatchData &data, const QByteArray &addr);
|
||||||
|
void setWatchDataType(WatchData &data, const GdbMi &mi);
|
||||||
|
void setWatchDataDisplayedType(WatchData &data, const GdbMi &mi);
|
||||||
|
|
||||||
|
void parseWatchData(const QSet<QByteArray> &expandedINames,
|
||||||
|
const WatchData &parent, const GdbMi &child,
|
||||||
|
QList<WatchData> *insertions);
|
||||||
|
|
||||||
} // namespace Internal
|
} // namespace Internal
|
||||||
} // namespace Debugger
|
} // namespace Debugger
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user