debugger: new files for WatchData; move potentially shared code to watchutils.cpp

This commit is contained in:
hjk
2010-04-26 18:54:08 +02:00
parent 400eecf4ef
commit 9a8ac49c2c
11 changed files with 603 additions and 523 deletions

View File

@@ -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

View File

@@ -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);

View File

@@ -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;

View File

@@ -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

View File

@@ -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();

View 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

View 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

View File

@@ -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);
}
/////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////
// //

View File

@@ -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

View File

@@ -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

View File

@@ -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