Debugger: Allow disabling individual breakpoint locations

... for breakpoints that resolve to multiple locations, like templates.

Toggling is done via the the breakpoint view context menu, for now
only available with GDB and not persistent.

Change-Id: I098ae13a5518e9f671c647680f8bd4413e7e5ccc
Reviewed-by: Christian Stenger <christian.stenger@qt.io>
This commit is contained in:
hjk
2018-01-31 10:46:57 +01:00
parent 46ad21a796
commit 7c41720479
6 changed files with 68 additions and 14 deletions

View File

@@ -73,11 +73,16 @@ using namespace Utils;
namespace Debugger {
namespace Internal {
class LocationItem : public TreeItem
class LocationItem : public TypedTreeItem<TreeItem, BreakpointItem>
{
public:
QVariant data(int column, int role) const
QVariant data(int column, int role) const final
{
if (role == Qt::DecorationRole && column == 0) {
return params.enabled ? Icons::BREAKPOINT.icon()
: Icons::BREAKPOINT_DISABLED.icon();
}
if (role == Qt::DisplayRole) {
switch (column) {
case BreakpointNumberColumn:
@@ -1951,20 +1956,35 @@ bool BreakHandler::setData(const QModelIndex &idx, const QVariant &value, int ro
bool BreakHandler::contextMenuEvent(const ItemViewEvent &ev)
{
const QModelIndexList selectedIndices = ev.selectedRows();
const Breakpoints selectedItems = findBreakpointsByIndex(selectedIndices);
const bool enabled = selectedItems.isEmpty() || selectedItems.at(0).isEnabled();
const Breakpoints selectedBreakpoints = findBreakpointsByIndex(selectedIndices);
const bool breakpointsEnabled = selectedBreakpoints.isEmpty() || selectedBreakpoints.at(0).isEnabled();
QList<LocationItem *> selectedLocations;
bool handlesIndividualLocations = false;
for (const QModelIndex &index : selectedIndices) {
if (LocationItem *location = itemForIndexAtLevel<2>(index)) {
if (selectedLocations.contains(location))
continue;
selectedLocations.append(location);
DebuggerEngine *engine = location->parent()->m_engine;
if (engine && engine->hasCapability(BreakIndividualLocationsCapability))
handlesIndividualLocations = true;
}
}
const bool locationsEnabled = selectedLocations.isEmpty() || selectedLocations.at(0)->params.enabled;
auto menu = new QMenu;
addAction(menu, tr("Add Breakpoint..."), true, [this] { addBreakpoint(); });
addAction(menu, tr("Delete Selected Breakpoints"),
!selectedItems.isEmpty(),
[this, selectedItems] { deleteBreakpoints(selectedItems); });
!selectedBreakpoints.isEmpty(),
[this, selectedBreakpoints] { deleteBreakpoints(selectedBreakpoints); });
addAction(menu, tr("Edit Selected Breakpoints..."),
!selectedItems.isEmpty(),
[this, selectedItems, ev] { editBreakpoints(selectedItems, ev.view()); });
!selectedBreakpoints.isEmpty(),
[this, selectedBreakpoints, ev] { editBreakpoints(selectedBreakpoints, ev.view()); });
// FIXME BP: m_engine->threadsHandler()->currentThreadId();
@@ -1979,11 +1999,30 @@ bool BreakHandler::contextMenuEvent(const ItemViewEvent &ev)
// });
addAction(menu,
selectedItems.size() > 1
? enabled ? tr("Disable Selected Breakpoints") : tr("Enable Selected Breakpoints")
: enabled ? tr("Disable Breakpoint") : tr("Enable Breakpoint"),
!selectedItems.isEmpty(),
[this, selectedItems, enabled] { setBreakpointsEnabled(selectedItems, !enabled); });
selectedBreakpoints.size() > 1
? breakpointsEnabled ? tr("Disable Selected Breakpoints") : tr("Enable Selected Breakpoints")
: breakpointsEnabled ? tr("Disable Breakpoint") : tr("Enable Breakpoint"),
!selectedBreakpoints.isEmpty(),
[this, selectedBreakpoints, breakpointsEnabled] {
setBreakpointsEnabled(selectedBreakpoints, !breakpointsEnabled);
}
);
addAction(menu,
selectedLocations.size() > 1
? locationsEnabled ? tr("Disable Selected Locations") : tr("Enable Selected Locations")
: locationsEnabled ? tr("Disable Location") : tr("Enable Location"),
!selectedLocations.isEmpty() && handlesIndividualLocations,
[this, selectedLocations, locationsEnabled] {
for (LocationItem *location : selectedLocations) {
location->params.enabled = !locationsEnabled;
location->update();
BreakpointItem *bp = location->parent();
if (bp->m_engine)
bp->m_engine->enableSubBreakpoint(location->params.id.toString(), !locationsEnabled);
}
}
);
menu->addSeparator();

View File

@@ -156,7 +156,8 @@ enum DebuggerCapabilities
WatchComplexExpressionsCapability = 1 << 26, // Used to filter out challenges for cdb.
AdditionalQmlStackCapability = 1 << 27, //!< C++ debugger engine is able to retrieve QML stack as well.
ResetInferiorCapability = 1 << 28, //!< restart program while debugging
NativeMixedCapability = 1 << 29
NativeMixedCapability = 1 << 29,
BreakIndividualLocationsCapability= 1 << 30 //!< Allows to enable/disable individual location for multi-location bps
};
enum LogChannel

View File

@@ -1421,6 +1421,11 @@ void DebuggerEngine::changeBreakpoint(Breakpoint bp)
QTC_CHECK(false);
}
void DebuggerEngine::enableSubBreakpoint(const QString &, bool)
{
QTC_CHECK(false);
}
void DebuggerEngine::assignValueInDebugger(WatchItem *,
const QString &, const QVariant &)
{

View File

@@ -314,6 +314,7 @@ public:
virtual void insertBreakpoint(Breakpoint bp); // FIXME: make pure
virtual void removeBreakpoint(Breakpoint bp); // FIXME: make pure
virtual void changeBreakpoint(Breakpoint bp); // FIXME: make pure
virtual void enableSubBreakpoint(const QString &locid, bool on);
virtual bool acceptsDebuggerCommands() const { return true; }
virtual void executeDebuggerCommand(const QString &command, DebuggerLanguages languages);

View File

@@ -1835,6 +1835,7 @@ bool GdbEngine::hasCapability(unsigned cap) const
| ReloadModuleSymbolsCapability
| BreakOnThrowAndCatchCapability
| BreakConditionCapability
| BreakIndividualLocationsCapability
| TracePointCapability
| ReturnFromFunctionCapability
| CreateFullBacktraceCapability
@@ -2704,6 +2705,12 @@ void GdbEngine::changeBreakpoint(Breakpoint bp)
runCommand(cmd);
}
void GdbEngine::enableSubBreakpoint(const QString &locId, bool on)
{
DebuggerCommand cmd((on ? "-break-enable " : "-break-disable ") + locId);
runCommand(cmd);
}
void GdbEngine::removeBreakpoint(Breakpoint bp)
{
QTC_CHECK(bp.state() == BreakpointRemoveRequested);

View File

@@ -197,6 +197,7 @@ private: ////////// General Interface //////////
void insertBreakpoint(Breakpoint bp) final;
void removeBreakpoint(Breakpoint bp) final;
void changeBreakpoint(Breakpoint bp) final;
void enableSubBreakpoint(const QString &locId, bool on) final;
void executeStep() final;
void executeStepOut() final;