Debugger: Merge debug mode and analyze mode

On the user-visible side, only the 'Analyze' mode button disappears,
and instead a combobox to switch between different tools in appears
in the Debug mode toolbar.

Internally, that's quite some re-organzition: The centralized
'Analyze mode is busy' flag is gone, allowing us to run e.g.
ClangStaticAnalyzer and MemCheck in parallel.

Analyzer tools and debugger now share the same mechanism to
generate/load/save dock widgets.

Analyzer tools now create and handle their own start/stop button
when appropriate. In general, Analyzer tools can create/handle more
than one run control at a time.

Further consolidation is possible, e.g. RunControl state handling
could be merged into the base ProjectExplorer::RunControl to
avoid the still existing duplication in ~15 instances.

Change-Id: I91e5940ebc4211f98056d507cf2f7b5f8efe7f07
Reviewed-by: Christian Stenger <christian.stenger@theqtcompany.com>
This commit is contained in:
hjk
2016-03-02 13:57:37 +01:00
parent c326011feb
commit 92e301a054
79 changed files with 2135 additions and 2642 deletions

View File

@@ -35,7 +35,7 @@
#include <utils/qtcassert.h>
using namespace Analyzer;
using namespace Debugger;
using namespace Valgrind;
using namespace Valgrind::Internal;
@@ -48,7 +48,7 @@ CallgrindRunControl::CallgrindRunControl(ProjectExplorer::RunConfiguration *runC
connect(m_runner.parser(), &Callgrind::Parser::parserDataReady,
this, &CallgrindRunControl::slotFinished);
connect(&m_runner, &Callgrind::CallgrindRunner::statusMessage,
this, &AnalyzerManager::showPermanentStatusMessage);
this, &Debugger::showPermanentStatusMessage);
}
QStringList CallgrindRunControl::toolArguments() const
@@ -89,10 +89,10 @@ ValgrindRunner * CallgrindRunControl::runner()
return &m_runner;
}
bool CallgrindRunControl::startEngine()
void CallgrindRunControl::start()
{
appendMessage(tr("Profiling %1").arg(executable()) + QLatin1Char('\n'), Utils::NormalMessageFormat);
return ValgrindRunControl::startEngine();
return ValgrindRunControl::start();
}
void CallgrindRunControl::dump()

View File

@@ -41,7 +41,7 @@ class CallgrindRunControl : public ValgrindRunControl
public:
CallgrindRunControl(ProjectExplorer::RunConfiguration *runConfiguration);
bool startEngine() override;
void start() override;
Valgrind::Callgrind::ParseData *takeParserData();

View File

@@ -43,6 +43,7 @@
#include <valgrind/valgrindplugin.h>
#include <valgrind/valgrindsettings.h>
#include <debugger/debuggerconstants.h>
#include <debugger/analyzer/analyzerconstants.h>
#include <debugger/analyzer/analyzericons.h>
#include <debugger/analyzer/analyzermanager.h>
@@ -90,11 +91,12 @@
#include <QToolBar>
#include <QToolButton>
using namespace Analyzer;
using namespace Debugger;
using namespace Core;
using namespace Valgrind::Callgrind;
using namespace TextEditor;
using namespace ProjectExplorer;
using namespace Utils;
namespace Valgrind {
namespace Internal {
@@ -108,7 +110,6 @@ public:
~CallgrindTool();
ValgrindRunControl *createRunControl(RunConfiguration *runConfiguration);
void createWidgets();
void setParseData(ParseData *data);
CostDelegate::CostFormat costFormat() const;
@@ -164,6 +165,7 @@ public:
void editorOpened(IEditor *);
void requestContextMenu(TextEditorWidget *widget, int line, QMenu *menu);
void updateRunActions();
public:
DataModel m_dataModel;
@@ -200,15 +202,17 @@ public:
QVector<CallgrindTextMark *> m_textMarks;
QAction *m_startAction = 0;
QAction *m_stopAction = 0;
QAction *m_loadExternalLogFile;
QAction *m_dumpAction = 0;
QAction *m_resetAction = 0;
QAction *m_pauseAction = 0;
QString m_toggleCollectFunction;
bool m_toolBusy = false;
};
CallgrindTool::CallgrindTool(QObject *parent)
: QObject(parent)
{
@@ -231,6 +235,9 @@ CallgrindTool::CallgrindTool(QObject *parent)
connect(EditorManager::instance(), &EditorManager::editorOpened,
this, &CallgrindTool::editorOpened);
m_startAction = Debugger::createStartAction();
m_stopAction = Debugger::createStopAction();
ActionDescription desc;
desc.setToolTip(tr("Valgrind Function Profile uses the "
"Callgrind tool to record function calls when a program runs."));
@@ -243,13 +250,13 @@ CallgrindTool::CallgrindTool(QObject *parent)
});
desc.setToolMode(OptimizedMode);
desc.setRunMode(CALLGRIND_RUN_MODE);
desc.setMenuGroup(Analyzer::Constants::G_ANALYZER_TOOLS);
AnalyzerManager::registerAction(CallgrindLocalActionId, desc);
desc.setMenuGroup(Debugger::Constants::G_ANALYZER_TOOLS);
Debugger::registerAction(CallgrindLocalActionId, desc, m_startAction);
}
desc.setText(tr("Valgrind Function Profiler (External Application)"));
desc.setPerspectiveId(CallgrindPerspectiveId);
desc.setCustomToolStarter([this](ProjectExplorer::RunConfiguration *runConfig) {
desc.setCustomToolStarter([this](RunConfiguration *runConfig) {
StartRemoteDialog dlg;
if (dlg.exec() != QDialog::Accepted)
return;
@@ -263,17 +270,17 @@ CallgrindTool::CallgrindTool(QObject *parent)
rc->setDisplayName(runnable.executable);
ProjectExplorerPlugin::startRunControl(rc, CALLGRIND_RUN_MODE);
});
desc.setMenuGroup(Analyzer::Constants::G_ANALYZER_REMOTE_TOOLS);
AnalyzerManager::registerAction(CallgrindRemoteActionId, desc);
desc.setMenuGroup(Debugger::Constants::G_ANALYZER_REMOTE_TOOLS);
Debugger::registerAction(CallgrindRemoteActionId, desc);
// If there is a CppEditor context menu add our own context menu actions.
if (ActionContainer *editorContextMenu =
ActionManager::actionContainer(CppEditor::Constants::M_CONTEXT)) {
Context analyzerContext = Context(Analyzer::Constants::C_ANALYZEMODE);
Context analyzerContext = Context(Debugger::Constants::C_DEBUGMODE);
editorContextMenu->addSeparator(analyzerContext);
auto action = new QAction(tr("Profile Costs of This Function and Its Callees"), this);
action->setIcon(Analyzer::Icons::ANALYZER_CONTROL_START.icon());
action->setIcon(Debugger::Icons::ANALYZER_CONTROL_START.icon());
connect(action, &QAction::triggered, this,
&CallgrindTool::handleShowCostsOfFunction);
Command *cmd = ActionManager::registerAction(action, "Analyzer.Callgrind.ShowCostsOfFunction",
@@ -283,7 +290,214 @@ CallgrindTool::CallgrindTool(QObject *parent)
cmd->setAttribute(Command::CA_NonConfigurable);
}
createWidgets();
QSettings *coreSettings = ICore::settings();
//
// DockWidgets
//
m_visualization = new Visualisation;
m_visualization->setFrameStyle(QFrame::NoFrame);
m_visualization->setObjectName(QLatin1String("Valgrind.CallgrindTool.Visualisation"));
m_visualization->setWindowTitle(tr("Visualization"));
m_visualization->setModel(&m_dataModel);
connect(m_visualization, &Visualisation::functionActivated,
this, &CallgrindTool::visualisationFunctionSelected);
m_callersView = new CostView;
m_callersView->setObjectName(QLatin1String("Valgrind.CallgrindTool.CallersView"));
m_callersView->setWindowTitle(tr("Callers"));
m_callersView->setSettings(coreSettings, "Valgrind.CallgrindTool.CallersView");
m_callersView->sortByColumn(CallModel::CostColumn);
m_callersView->setFrameStyle(QFrame::NoFrame);
// enable sorting
m_callersProxy.setSourceModel(&m_callersModel);
m_callersView->setModel(&m_callersProxy);
m_callersView->hideColumn(CallModel::CalleeColumn);
connect(m_callersView, &QAbstractItemView::activated,
this, &CallgrindTool::callerFunctionSelected);
m_calleesView = new CostView;
m_calleesView->setObjectName(QLatin1String("Valgrind.CallgrindTool.CalleesView"));
m_calleesView->setWindowTitle(tr("Callees"));
m_calleesView->setSettings(coreSettings, "Valgrind.CallgrindTool.CalleesView");
m_calleesView->sortByColumn(CallModel::CostColumn);
m_calleesView->setFrameStyle(QFrame::NoFrame);
// enable sorting
m_calleesProxy.setSourceModel(&m_calleesModel);
m_calleesView->setModel(&m_calleesProxy);
m_calleesView->hideColumn(CallModel::CallerColumn);
connect(m_calleesView, &QAbstractItemView::activated,
this, &CallgrindTool::calleeFunctionSelected);
m_flatView = new CostView;
m_flatView->setObjectName(QLatin1String("Valgrind.CallgrindTool.FlatView"));
m_flatView->setWindowTitle(tr("Functions"));
m_flatView->setSettings(coreSettings, "Valgrind.CallgrindTool.FlatView");
m_flatView->sortByColumn(DataModel::SelfCostColumn);
m_flatView->setFrameStyle(QFrame::NoFrame);
m_flatView->setAttribute(Qt::WA_MacShowFocusRect, false);
m_flatView->setModel(&m_proxyModel);
connect(m_flatView, &QAbstractItemView::activated,
this, &CallgrindTool::dataFunctionSelected);
updateCostFormat();
//
// Control Widget
//
// load external log file
auto action = m_loadExternalLogFile = new QAction(this);
action->setIcon(Core::Icons::OPENFILE.icon());
action->setToolTip(tr("Load External Log File"));
connect(action, &QAction::triggered, this, &CallgrindTool::loadExternalLogFile);
// dump action
m_dumpAction = action = new QAction(this);
action->setDisabled(true);
action->setIcon(Core::Icons::REDO.icon());
//action->setText(tr("Dump"));
action->setToolTip(tr("Request the dumping of profile information. This will update the Callgrind visualization."));
connect(action, &QAction::triggered, this, &CallgrindTool::slotRequestDump);
// reset action
m_resetAction = action = new QAction(this);
action->setDisabled(true);
action->setIcon(Core::Icons::RELOAD.icon());
//action->setText(tr("Reset"));
action->setToolTip(tr("Reset all event counters."));
connect(action, &QAction::triggered, this, &CallgrindTool::resetRequested);
// pause action
m_pauseAction = action = new QAction(this);
action->setCheckable(true);
action->setIcon(ProjectExplorer::Icons::INTERRUPT_SMALL.icon());
//action->setText(tr("Ignore"));
action->setToolTip(tr("Pause event logging. No events are counted which will speed up program execution during profiling."));
connect(action, &QAction::toggled, this, &CallgrindTool::pauseToggled);
// navigation
// go back
m_goBack = action = new QAction(this);
action->setDisabled(true);
action->setIcon(Core::Icons::PREV.icon());
action->setToolTip(tr("Go back one step in history. This will select the previously selected item."));
connect(action, &QAction::triggered, &m_stackBrowser, &StackBrowser::goBack);
// go forward
m_goNext = action = new QAction(this);
action->setDisabled(true);
action->setIcon(Core::Icons::NEXT.icon());
action->setToolTip(tr("Go forward one step in history."));
connect(action, &QAction::triggered, &m_stackBrowser, &StackBrowser::goNext);
// event selection
m_eventCombo = new QComboBox;
m_eventCombo->setToolTip(tr("Selects which events from the profiling data are shown and visualized."));
connect(m_eventCombo, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged),
this, &CallgrindTool::setCostEvent);
updateEventCombo();
ToolbarDescription toolbar;
toolbar.addAction(m_startAction);
toolbar.addAction(m_stopAction);
toolbar.addAction(m_loadExternalLogFile);
toolbar.addAction(m_dumpAction);
toolbar.addAction(m_resetAction);
toolbar.addAction(m_pauseAction);
toolbar.addAction(m_goBack);
toolbar.addAction(m_goNext);
toolbar.addWidget(new Utils::StyledSeparator);
toolbar.addWidget(m_eventCombo);
// Cost formatting
{
auto menu = new QMenu;
auto group = new QActionGroup(this);
// Show costs as absolute numbers
m_costAbsolute = new QAction(tr("Absolute Costs"), this);
m_costAbsolute->setToolTip(tr("Show costs as absolute numbers."));
m_costAbsolute->setCheckable(true);
m_costAbsolute->setChecked(true);
connect(m_costAbsolute, &QAction::toggled, this, &CallgrindTool::updateCostFormat);
group->addAction(m_costAbsolute);
menu->addAction(m_costAbsolute);
// Show costs in percentages
m_costRelative = new QAction(tr("Relative Costs"), this);
m_costRelative->setToolTip(tr("Show costs relative to total inclusive cost."));
m_costRelative->setCheckable(true);
connect(m_costRelative, &QAction::toggled, this, &CallgrindTool::updateCostFormat);
group->addAction(m_costRelative);
menu->addAction(m_costRelative);
// Show costs relative to parent
m_costRelativeToParent = new QAction(tr("Relative Costs to Parent"), this);
m_costRelativeToParent->setToolTip(tr("Show costs relative to parent functions inclusive cost."));
m_costRelativeToParent->setCheckable(true);
connect(m_costRelativeToParent, &QAction::toggled, this, &CallgrindTool::updateCostFormat);
group->addAction(m_costRelativeToParent);
menu->addAction(m_costRelativeToParent);
auto button = new QToolButton;
button->setMenu(menu);
button->setPopupMode(QToolButton::InstantPopup);
button->setText(QLatin1String("$"));
button->setToolTip(tr("Cost Format"));
toolbar.addWidget(button);
}
ValgrindGlobalSettings *settings = ValgrindPlugin::globalSettings();
// Cycle detection
//action = new QAction(QLatin1String("Cycle Detection"), this); ///FIXME: icon
action = m_cycleDetection = new QAction(QLatin1String("O"), this); ///FIXME: icon
action->setToolTip(tr("Enable cycle detection to properly handle recursive or circular function calls."));
action->setCheckable(true);
connect(action, &QAction::toggled, &m_dataModel, &DataModel::enableCycleDetection);
connect(action, &QAction::toggled, settings, &ValgrindGlobalSettings::setDetectCycles);
// Shorter template signature
action = m_shortenTemplates = new QAction(QLatin1String("<>"), this);
action->setToolTip(tr("This removes template parameter lists when displaying function names."));
action->setCheckable(true);
connect(action, &QAction::toggled, &m_dataModel, &DataModel::setShortenTemplates);
connect(action, &QAction::toggled, settings, &ValgrindGlobalSettings::setShortenTemplates);
// Filtering
action = m_filterProjectCosts = new QAction(tr("Show Project Costs Only"), this);
action->setIcon(Core::Icons::FILTER.icon());
action->setToolTip(tr("Show only profiling info that originated from this project source."));
action->setCheckable(true);
connect(action, &QAction::toggled, this, &CallgrindTool::handleFilterProjectCosts);
// Filter
///FIXME: find workaround for https://bugreports.qt.io/browse/QTCREATORBUG-3247
m_searchFilter = new QLineEdit;
m_searchFilter->setPlaceholderText(tr("Filter..."));
connect(m_searchFilter, &QLineEdit::textChanged,
&m_updateTimer, static_cast<void(QTimer::*)()>(&QTimer::start));
setCostFormat(settings->costFormat());
enableCycleDetection(settings->detectCycles());
toolbar.addAction(m_cycleDetection);
toolbar.addAction(m_shortenTemplates);
toolbar.addAction(m_filterProjectCosts);
toolbar.addWidget(m_searchFilter);
Debugger::registerToolbar(CallgrindPerspectiveId, toolbar);
Debugger::registerPerspective(CallgrindPerspectiveId, { tr("Callgrind"), {
{ CallgrindFlatDockId, m_flatView, {}, Perspective::SplitVertical },
{ CallgrindCalleesDockId, m_calleesView, {}, Perspective::SplitVertical },
{ CallgrindCallersDockId, m_callersView, CallgrindCalleesDockId, Perspective::SplitHorizontal },
{ CallgrindVisualizationDockId, m_visualization, {}, Perspective::SplitVertical,
false, Qt::RightDockWidgetArea }
}});
connect(ProjectExplorerPlugin::instance(), &ProjectExplorerPlugin::updateRunActions,
this, &CallgrindTool::updateRunActions);
}
CallgrindTool::~CallgrindTool()
@@ -521,34 +735,28 @@ void CallgrindTool::updateEventCombo()
m_eventCombo->addItem(ParseData::prettyStringForEvent(event));
}
static QToolButton *createToolButton(QAction *action)
{
QToolButton *button = new QToolButton;
button->setDefaultAction(action);
//button->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
return button;
}
ValgrindRunControl *CallgrindTool::createRunControl(RunConfiguration *runConfiguration)
{
auto rc = new CallgrindRunControl(runConfiguration);
auto runControl = new CallgrindRunControl(runConfiguration);
connect(rc, &CallgrindRunControl::parserDataReady, this, &CallgrindTool::takeParserDataFromRunControl);
connect(rc, &AnalyzerRunControl::starting, this, &CallgrindTool::engineStarting);
connect(rc, &RunControl::finished, this, &CallgrindTool::engineFinished);
connect(runControl, &CallgrindRunControl::parserDataReady, this, &CallgrindTool::takeParserDataFromRunControl);
connect(runControl, &AnalyzerRunControl::starting, this, &CallgrindTool::engineStarting);
connect(runControl, &RunControl::finished, this, &CallgrindTool::engineFinished);
connect(this, &CallgrindTool::dumpRequested, rc, &CallgrindRunControl::dump);
connect(this, &CallgrindTool::resetRequested, rc, &CallgrindRunControl::reset);
connect(this, &CallgrindTool::pauseToggled, rc, &CallgrindRunControl::setPaused);
connect(this, &CallgrindTool::dumpRequested, runControl, &CallgrindRunControl::dump);
connect(this, &CallgrindTool::resetRequested, runControl, &CallgrindRunControl::reset);
connect(this, &CallgrindTool::pauseToggled, runControl, &CallgrindRunControl::setPaused);
connect(m_stopAction, &QAction::triggered, runControl, [runControl] { runControl->stop(); });
// initialize run control
rc->setPaused(m_pauseAction->isChecked());
runControl->setPaused(m_pauseAction->isChecked());
// we may want to toggle collect for one function only in this run
rc->setToggleCollectFunction(m_toggleCollectFunction);
runControl->setToggleCollectFunction(m_toggleCollectFunction);
m_toggleCollectFunction.clear();
QTC_ASSERT(m_visualization, return rc);
QTC_ASSERT(m_visualization, return runControl);
// apply project settings
if (runConfiguration) {
@@ -560,241 +768,32 @@ ValgrindRunControl *CallgrindTool::createRunControl(RunConfiguration *runConfigu
}
}
}
return rc;
m_toolBusy = true;
updateRunActions();
return runControl;
}
void CallgrindTool::createWidgets()
void CallgrindTool::updateRunActions()
{
QTC_ASSERT(!m_visualization, return);
QSettings *coreSettings = ICore::settings();
//
// DockWidgets
//
m_visualization = new Visualisation;
m_visualization->setFrameStyle(QFrame::NoFrame);
m_visualization->setObjectName(QLatin1String("Valgrind.CallgrindTool.Visualisation"));
m_visualization->setWindowTitle(tr("Visualization"));
m_visualization->setModel(&m_dataModel);
connect(m_visualization, &Visualisation::functionActivated,
this, &CallgrindTool::visualisationFunctionSelected);
m_callersView = new CostView;
m_callersView->setObjectName(QLatin1String("Valgrind.CallgrindTool.CallersView"));
m_callersView->setWindowTitle(tr("Callers"));
m_callersView->setSettings(coreSettings, "Valgrind.CallgrindTool.CallersView");
m_callersView->sortByColumn(CallModel::CostColumn);
m_callersView->setFrameStyle(QFrame::NoFrame);
// enable sorting
m_callersProxy.setSourceModel(&m_callersModel);
m_callersView->setModel(&m_callersProxy);
m_callersView->hideColumn(CallModel::CalleeColumn);
connect(m_callersView, &QAbstractItemView::activated,
this, &CallgrindTool::callerFunctionSelected);
m_calleesView = new CostView;
m_calleesView->setObjectName(QLatin1String("Valgrind.CallgrindTool.CalleesView"));
m_calleesView->setWindowTitle(tr("Callees"));
m_calleesView->setSettings(coreSettings, "Valgrind.CallgrindTool.CalleesView");
m_calleesView->sortByColumn(CallModel::CostColumn);
m_calleesView->setFrameStyle(QFrame::NoFrame);
// enable sorting
m_calleesProxy.setSourceModel(&m_calleesModel);
m_calleesView->setModel(&m_calleesProxy);
m_calleesView->hideColumn(CallModel::CallerColumn);
connect(m_calleesView, &QAbstractItemView::activated,
this, &CallgrindTool::calleeFunctionSelected);
m_flatView = new CostView;
m_flatView->setObjectName(QLatin1String("Valgrind.CallgrindTool.FlatView"));
m_flatView->setWindowTitle(tr("Functions"));
m_flatView->setSettings(coreSettings, "Valgrind.CallgrindTool.FlatView");
m_flatView->sortByColumn(DataModel::SelfCostColumn);
m_flatView->setFrameStyle(QFrame::NoFrame);
m_flatView->setAttribute(Qt::WA_MacShowFocusRect, false);
m_flatView->setModel(&m_proxyModel);
connect(m_flatView, &QAbstractItemView::activated,
this, &CallgrindTool::dataFunctionSelected);
updateCostFormat();
//
// Control Widget
//
auto layout = new QHBoxLayout;
layout->setMargin(0);
layout->setSpacing(0);
auto widget = new QWidget;
widget->setLayout(layout);
// load external log file
auto action = new QAction(this);
action->setIcon(Core::Icons::OPENFILE.icon());
action->setToolTip(tr("Load External Log File"));
connect(action, &QAction::triggered, this, &CallgrindTool::loadExternalLogFile);
layout->addWidget(createToolButton(action));
m_loadExternalLogFile = action;
// dump action
action = new QAction(this);
action->setDisabled(true);
action->setIcon(Core::Icons::REDO.icon());
//action->setText(tr("Dump"));
action->setToolTip(tr("Request the dumping of profile information. This will update the Callgrind visualization."));
connect(action, &QAction::triggered, this, &CallgrindTool::slotRequestDump);
layout->addWidget(createToolButton(action));
m_dumpAction = action;
// reset action
action = new QAction(this);
action->setDisabled(true);
action->setIcon(Core::Icons::RELOAD.icon());
//action->setText(tr("Reset"));
action->setToolTip(tr("Reset all event counters."));
connect(action, &QAction::triggered, this, &CallgrindTool::resetRequested);
layout->addWidget(createToolButton(action));
m_resetAction = action;
// pause action
action = new QAction(this);
action->setCheckable(true);
action->setIcon(ProjectExplorer::Icons::INTERRUPT_SMALL.icon());
//action->setText(tr("Ignore"));
action->setToolTip(tr("Pause event logging. No events are counted which will speed up program execution during profiling."));
connect(action, &QAction::toggled, this, &CallgrindTool::pauseToggled);
layout->addWidget(createToolButton(action));
m_pauseAction = action;
// navigation
// go back
action = new QAction(this);
action->setDisabled(true);
action->setIcon(Core::Icons::PREV.icon());
action->setToolTip(tr("Go back one step in history. This will select the previously selected item."));
connect(action, &QAction::triggered, &m_stackBrowser, &StackBrowser::goBack);
layout->addWidget(createToolButton(action));
m_goBack = action;
// go forward
action = new QAction(this);
action->setDisabled(true);
action->setIcon(Core::Icons::NEXT.icon());
action->setToolTip(tr("Go forward one step in history."));
connect(action, &QAction::triggered, &m_stackBrowser, &StackBrowser::goNext);
layout->addWidget(createToolButton(action));
m_goNext = action;
layout->addWidget(new Utils::StyledSeparator);
// event selection
m_eventCombo = new QComboBox;
m_eventCombo->setToolTip(tr("Selects which events from the profiling data are shown and visualized."));
connect(m_eventCombo, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged),
this, &CallgrindTool::setCostEvent);
updateEventCombo();
layout->addWidget(m_eventCombo);
// Cost formatting
{
auto menu = new QMenu(layout->parentWidget());
auto group = new QActionGroup(this);
// Show costs as absolute numbers
m_costAbsolute = new QAction(tr("Absolute Costs"), this);
m_costAbsolute->setToolTip(tr("Show costs as absolute numbers."));
m_costAbsolute->setCheckable(true);
m_costAbsolute->setChecked(true);
connect(m_costAbsolute, &QAction::toggled, this, &CallgrindTool::updateCostFormat);
group->addAction(m_costAbsolute);
menu->addAction(m_costAbsolute);
// Show costs in percentages
m_costRelative = new QAction(tr("Relative Costs"), this);
m_costRelative->setToolTip(tr("Show costs relative to total inclusive cost."));
m_costRelative->setCheckable(true);
connect(m_costRelative, &QAction::toggled, this, &CallgrindTool::updateCostFormat);
group->addAction(m_costRelative);
menu->addAction(m_costRelative);
// Show costs relative to parent
m_costRelativeToParent = new QAction(tr("Relative Costs to Parent"), this);
m_costRelativeToParent->setToolTip(tr("Show costs relative to parent functions inclusive cost."));
m_costRelativeToParent->setCheckable(true);
connect(m_costRelativeToParent, &QAction::toggled, this, &CallgrindTool::updateCostFormat);
group->addAction(m_costRelativeToParent);
menu->addAction(m_costRelativeToParent);
auto button = new QToolButton;
button->setMenu(menu);
button->setPopupMode(QToolButton::InstantPopup);
button->setText(QLatin1String("$"));
button->setToolTip(tr("Cost Format"));
layout->addWidget(button);
if (m_toolBusy) {
m_startAction->setEnabled(false);
m_startAction->setToolTip(tr("A Valgrind Callgrind analysis is still in progress."));
m_stopAction->setEnabled(true);
} else {
const bool projectUsable = SessionManager::startupProject() != 0;
if (projectUsable) {
m_startAction->setEnabled(true);
m_startAction->setToolTip(tr("Start a Valgrind Callgrind analysis."));
m_stopAction->setEnabled(false);
} else {
m_startAction->setEnabled(false);
m_startAction->setToolTip(tr("Start a Valgrind Callgrind analysis."));
m_stopAction->setEnabled(false);
}
}
ValgrindGlobalSettings *settings = ValgrindPlugin::globalSettings();
// Cycle detection
//action = new QAction(QLatin1String("Cycle Detection"), this); ///FIXME: icon
action = new QAction(QLatin1String("O"), this); ///FIXME: icon
action->setToolTip(tr("Enable cycle detection to properly handle recursive or circular function calls."));
action->setCheckable(true);
connect(action, &QAction::toggled, &m_dataModel, &DataModel::enableCycleDetection);
connect(action, &QAction::toggled, settings, &ValgrindGlobalSettings::setDetectCycles);
layout->addWidget(createToolButton(action));
m_cycleDetection = action;
// Shorter template signature
action = new QAction(QLatin1String("<>"), this);
action->setToolTip(tr("This removes template parameter lists when displaying function names."));
action->setCheckable(true);
connect(action, &QAction::toggled, &m_dataModel, &DataModel::setShortenTemplates);
connect(action, &QAction::toggled, settings, &ValgrindGlobalSettings::setShortenTemplates);
layout->addWidget(createToolButton(action));
m_shortenTemplates = action;
// Filtering
action = new QAction(tr("Show Project Costs Only"), this);
action->setIcon(Core::Icons::FILTER.icon());
action->setToolTip(tr("Show only profiling info that originated from this project source."));
action->setCheckable(true);
connect(action, &QAction::toggled, this, &CallgrindTool::handleFilterProjectCosts);
layout->addWidget(createToolButton(action));
m_filterProjectCosts = action;
// Filter
///FIXME: find workaround for https://bugreports.qt.io/browse/QTCREATORBUG-3247
auto filter = new QLineEdit;
filter->setPlaceholderText(tr("Filter..."));
connect(filter, &QLineEdit::textChanged,
&m_updateTimer, static_cast<void(QTimer::*)()>(&QTimer::start));
layout->addWidget(filter);
m_searchFilter = filter;
setCostFormat(settings->costFormat());
enableCycleDetection(settings->detectCycles());
layout->addWidget(new Utils::StyledSeparator);
layout->addStretch();
AnalyzerManager::registerDockWidget(CallgrindCallersDockId, m_callersView);
AnalyzerManager::registerDockWidget(CallgrindFlatDockId, m_flatView);
AnalyzerManager::registerDockWidget(CallgrindCalleesDockId, m_calleesView);
AnalyzerManager::registerDockWidget(CallgrindVisualizationDockId, m_visualization);
AnalyzerManager::registerPerspective(CallgrindPerspectiveId, {
{ CallgrindFlatDockId, Id(), Perspective::SplitVertical },
{ CallgrindCalleesDockId, Id(), Perspective::SplitVertical },
{ CallgrindCallersDockId, CallgrindCalleesDockId, Perspective::SplitHorizontal },
{ CallgrindVisualizationDockId, Id(), Perspective::SplitVertical,
false, Qt::RightDockWidgetArea }
});
AnalyzerManager::registerToolbar(CallgrindPerspectiveId, widget);
}
void CallgrindTool::clearTextMarks()
{
qDeleteAll(m_textMarks);
@@ -813,6 +812,9 @@ void CallgrindTool::engineStarting()
void CallgrindTool::engineFinished()
{
m_toolBusy = false;
updateRunActions();
// Enable/disable actions
m_resetAction->setEnabled(false);
m_dumpAction->setEnabled(false);
@@ -822,7 +824,7 @@ void CallgrindTool::engineFinished()
if (data)
showParserResults(data);
else
AnalyzerManager::showPermanentStatusMessage(tr("Profiling aborted."));
Debugger::showPermanentStatusMessage(tr("Profiling aborted."));
setBusyCursor(false);
}
@@ -841,7 +843,7 @@ void CallgrindTool::showParserResults(const ParseData *data)
} else {
msg = tr("Parsing failed.");
}
AnalyzerManager::showPermanentStatusMessage(msg);
Debugger::showPermanentStatusMessage(msg);
}
void CallgrindTool::editorOpened(IEditor *editor)
@@ -878,8 +880,7 @@ void CallgrindTool::handleShowCostsOfFunction()
const QString qualifiedFunctionName = view.prettyName(CPlusPlus::LookupContext::fullyQualifiedName(symbol));
m_toggleCollectFunction = qualifiedFunctionName + QLatin1String("()");
AnalyzerManager::selectAction(CallgrindLocalActionId, /* alsoRunIt = */ true);
m_startAction->trigger();
}
void CallgrindTool::slotRequestDump()
@@ -906,7 +907,7 @@ void CallgrindTool::loadExternalLogFile()
return;
}
AnalyzerManager::showPermanentStatusMessage(tr("Parsing Profile Data..."));
Debugger::showPermanentStatusMessage(tr("Parsing Profile Data..."));
QCoreApplication::processEvents();
Parser parser;

View File

@@ -44,7 +44,7 @@
#include <utils/qtcassert.h>
using namespace Analyzer;
using namespace Debugger;
using namespace ProjectExplorer;
using namespace Valgrind::XmlProtocol;
@@ -72,20 +72,20 @@ ValgrindRunner *MemcheckRunControl::runner()
return &m_runner;
}
bool MemcheckRunControl::startEngine()
void MemcheckRunControl::start()
{
m_runner.setParser(&m_parser);
appendMessage(tr("Analyzing memory of %1").arg(executable()) + QLatin1Char('\n'),
Utils::NormalMessageFormat);
return ValgrindRunControl::startEngine();
ValgrindRunControl::start();
}
void MemcheckRunControl::stopEngine()
RunControl::StopResult MemcheckRunControl::stop()
{
disconnect(&m_parser, &ThreadedParser::internalError,
this, &MemcheckRunControl::internalParserError);
ValgrindRunControl::stopEngine();
return ValgrindRunControl::stop();
}
QStringList MemcheckRunControl::toolArguments() const

View File

@@ -43,8 +43,8 @@ public:
MemcheckRunControl(ProjectExplorer::RunConfiguration *runConfiguration,
Core::Id runMode);
bool startEngine() override;
void stopEngine() override;
void start() override;
StopResult stop() override;
QStringList suppressionFiles() const;

View File

@@ -50,7 +50,7 @@ namespace Valgrind {
namespace Internal {
MemcheckErrorView::MemcheckErrorView(QWidget *parent)
: Analyzer::DetailedErrorView(parent),
: Debugger::DetailedErrorView(parent),
m_settings(0)
{
m_suppressAction = new QAction(this);

View File

@@ -36,7 +36,7 @@ namespace Internal {
class ValgrindBaseSettings;
class MemcheckErrorView : public Analyzer::DetailedErrorView
class MemcheckErrorView : public Debugger::DetailedErrorView
{
Q_OBJECT

View File

@@ -85,14 +85,60 @@
#include <QString>
#include <QToolButton>
using namespace Analyzer;
using namespace Debugger;
using namespace ProjectExplorer;
using namespace Utils;
using namespace Valgrind::XmlProtocol;
namespace Valgrind {
namespace Internal {
class FrameFinder;
class FrameFinder : public ErrorListModel::RelevantFrameFinder
{
public:
Frame findRelevant(const Error &error) const
{
const QVector<Stack> stacks = error.stacks();
if (stacks.isEmpty())
return Frame();
const Stack &stack = stacks[0];
const QVector<Frame> frames = stack.frames();
if (frames.isEmpty())
return Frame();
//find the first frame belonging to the project
if (!m_projectFiles.isEmpty()) {
foreach (const Frame &frame, frames) {
if (frame.directory().isEmpty() || frame.fileName().isEmpty())
continue;
//filepaths can contain "..", clean them:
const QString f = QFileInfo(frame.filePath()).absoluteFilePath();
if (m_projectFiles.contains(f))
return frame;
}
}
//if no frame belonging to the project was found, return the first one that is not malloc/new
foreach (const Frame &frame, frames) {
if (!frame.functionName().isEmpty() && frame.functionName() != QLatin1String("malloc")
&& !frame.functionName().startsWith(QLatin1String("operator new(")))
{
return frame;
}
}
//else fallback to the first frame
return frames.first();
}
void setFiles(const QStringList &files)
{
m_projectFiles = files;
}
private:
QStringList m_projectFiles;
};
class MemcheckErrorFilterProxyModel : public QSortFilterProxyModel
{
@@ -203,12 +249,13 @@ class MemcheckTool : public QObject
public:
MemcheckTool(QObject *parent);
QWidget *createWidgets();
void createWidgets();
MemcheckRunControl *createRunControl(ProjectExplorer::RunConfiguration *runConfiguration,
Core::Id runMode);
private:
void updateRunActions();
void settingsDestroyed(QObject *settings);
void maybeActiveRunConfigurationChanged();
@@ -240,10 +287,14 @@ private:
QList<QAction *> m_errorFilterActions;
QAction *m_filterProjectAction;
QList<QAction *> m_suppressionActions;
QAction *m_startAction;
QAction *m_startWithGdbAction;
QAction *m_stopAction;
QAction *m_suppressionSeparator;
QAction *m_loadExternalLogFile;
QAction *m_goBack;
QAction *m_goNext;
bool m_toolBusy = false;
};
MemcheckTool::MemcheckTool(QObject *parent)
@@ -288,7 +339,79 @@ MemcheckTool::MemcheckTool(QObject *parent)
using namespace std::placeholders;
AnalyzerManager::registerToolbar(MemcheckPerspectiveId, createWidgets());
QTC_ASSERT(!m_errorView, return);
m_errorView = new MemcheckErrorView;
m_errorView->setObjectName(QLatin1String("MemcheckErrorView"));
m_errorView->setFrameStyle(QFrame::NoFrame);
m_errorView->setAttribute(Qt::WA_MacShowFocusRect, false);
m_errorModel = new ErrorListModel(m_errorView);
m_frameFinder = new Internal::FrameFinder;
m_errorModel->setRelevantFrameFinder(QSharedPointer<Internal::FrameFinder>(m_frameFinder));
m_errorProxyModel = new MemcheckErrorFilterProxyModel(m_errorView);
m_errorProxyModel->setSourceModel(m_errorModel);
m_errorProxyModel->setDynamicSortFilter(true);
m_errorView->setModel(m_errorProxyModel);
m_errorView->setSelectionMode(QAbstractItemView::ExtendedSelection);
// make m_errorView->selectionModel()->selectedRows() return something
m_errorView->setSelectionBehavior(QAbstractItemView::SelectRows);
m_errorView->setVerticalScrollMode(QAbstractItemView::ScrollPerPixel);
m_errorView->setAutoScroll(false);
m_errorView->setObjectName(QLatin1String("Valgrind.MemcheckTool.ErrorView"));
m_errorView->setWindowTitle(tr("Memory Issues"));
Debugger::registerPerspective(MemcheckPerspectiveId, { tr("Memcheck"), {
{ MemcheckErrorDockId, m_errorView, {}, Perspective::SplitVertical }
}});
connect(ProjectExplorerPlugin::instance(), &ProjectExplorerPlugin::updateRunActions,
this, &MemcheckTool::maybeActiveRunConfigurationChanged);
//
// The Control Widget.
//
m_startAction = Debugger::createStartAction();
m_startWithGdbAction = Debugger::createStartAction();
m_stopAction = Debugger::createStopAction();
// Load external XML log file
auto action = new QAction(this);
action->setIcon(Core::Icons::OPENFILE.icon());
action->setToolTip(tr("Load External XML Log File"));
connect(action, &QAction::triggered, this, &MemcheckTool::loadExternalXmlLogFile);
m_loadExternalLogFile = action;
// Go to previous leak.
action = new QAction(this);
action->setDisabled(true);
action->setIcon(Core::Icons::PREV.icon());
action->setToolTip(tr("Go to previous leak."));
connect(action, &QAction::triggered, m_errorView, &MemcheckErrorView::goBack);
m_goBack = action;
// Go to next leak.
action = new QAction(this);
action->setDisabled(true);
action->setIcon(Core::Icons::NEXT.icon());
action->setToolTip(tr("Go to next leak."));
connect(action, &QAction::triggered, m_errorView, &MemcheckErrorView::goNext);
m_goNext = action;
auto filterButton = new QToolButton;
filterButton->setIcon(Core::Icons::FILTER.icon());
filterButton->setText(tr("Error Filter"));
filterButton->setPopupMode(QToolButton::InstantPopup);
filterButton->setProperty("noArrow", true);
m_filterMenu = new QMenu(filterButton);
foreach (QAction *filterAction, m_errorFilterActions)
m_filterMenu->addAction(filterAction);
m_filterMenu->addSeparator();
m_filterMenu->addAction(m_filterProjectAction);
m_filterMenu->addAction(m_suppressionSeparator);
connect(m_filterMenu, &QMenu::triggered, this, &MemcheckTool::updateErrorFilter);
filterButton->setMenu(m_filterMenu);
ActionDescription desc;
desc.setToolTip(tr("Valgrind Analyze Memory uses the "
@@ -300,8 +423,8 @@ MemcheckTool::MemcheckTool(QObject *parent)
desc.setRunControlCreator(std::bind(&MemcheckTool::createRunControl, this, _1, _2));
desc.setToolMode(DebugMode);
desc.setRunMode(MEMCHECK_RUN_MODE);
desc.setMenuGroup(Analyzer::Constants::G_ANALYZER_TOOLS);
AnalyzerManager::registerAction("Memcheck.Local", desc);
desc.setMenuGroup(Debugger::Constants::G_ANALYZER_TOOLS);
Debugger::registerAction("Memcheck.Local", desc, m_startAction);
desc.setText(tr("Valgrind Memory Analyzer with GDB"));
desc.setToolTip(tr("Valgrind Analyze Memory with GDB uses the "
@@ -311,8 +434,8 @@ MemcheckTool::MemcheckTool(QObject *parent)
desc.setRunControlCreator(std::bind(&MemcheckTool::createRunControl, this, _1, _2));
desc.setToolMode(DebugMode);
desc.setRunMode(MEMCHECK_WITH_GDB_RUN_MODE);
desc.setMenuGroup(Analyzer::Constants::G_ANALYZER_TOOLS);
AnalyzerManager::registerAction("MemcheckWithGdb.Local", desc);
desc.setMenuGroup(Debugger::Constants::G_ANALYZER_TOOLS);
Debugger::registerAction("MemcheckWithGdb.Local", desc, m_startWithGdbAction);
}
desc.setText(tr("Valgrind Memory Analyzer (External Application)"));
@@ -331,8 +454,42 @@ MemcheckTool::MemcheckTool(QObject *parent)
rc->setDisplayName(runnable.executable);
ProjectExplorerPlugin::startRunControl(rc, MEMCHECK_RUN_MODE);
});
desc.setMenuGroup(Analyzer::Constants::G_ANALYZER_REMOTE_TOOLS);
AnalyzerManager::registerAction("Memcheck.Remote", desc);
desc.setMenuGroup(Debugger::Constants::G_ANALYZER_REMOTE_TOOLS);
Debugger::registerAction("Memcheck.Remote", desc);
ToolbarDescription toolbar;
toolbar.addAction(m_startAction);
//toolbar.addAction(m_startWithGdbAction);
toolbar.addAction(m_stopAction);
toolbar.addAction(m_loadExternalLogFile);
toolbar.addAction(m_goBack);
toolbar.addAction(m_goNext);
toolbar.addWidget(filterButton);
Debugger::registerToolbar(MemcheckPerspectiveId, toolbar);
}
void MemcheckTool::updateRunActions()
{
if (m_toolBusy) {
m_startAction->setEnabled(false);
m_startAction->setToolTip(tr("A Valgrind Memcheck analysis is still in progress."));
m_startWithGdbAction->setEnabled(false);
m_startWithGdbAction->setToolTip(tr("A Valgrind Memcheck analysis is still in progress."));
m_stopAction->setEnabled(true);
} else {
const bool projectUsable = SessionManager::startupProject() != 0;
m_startAction->setToolTip(tr("Start a Valgrind Memcheck analysis."));
m_startWithGdbAction->setToolTip(tr("Start a Valgrind Memcheck with GDB analysis."));
if (projectUsable) {
m_startAction->setEnabled(true);
m_startWithGdbAction->setEnabled(true);
m_stopAction->setEnabled(false);
} else {
m_startAction->setEnabled(false);
m_startWithGdbAction->setEnabled(false);
m_stopAction->setEnabled(false);
}
}
}
void MemcheckTool::settingsDestroyed(QObject *settings)
@@ -368,6 +525,8 @@ void MemcheckTool::updateFromSettings()
void MemcheckTool::maybeActiveRunConfigurationChanged()
{
updateRunActions();
ValgrindBaseSettings *settings = 0;
if (Project *project = SessionManager::startupProject())
if (Target *target = project->activeTarget())
@@ -395,150 +554,6 @@ void MemcheckTool::maybeActiveRunConfigurationChanged()
updateFromSettings();
}
class FrameFinder : public ErrorListModel::RelevantFrameFinder
{
public:
Frame findRelevant(const Error &error) const
{
const QVector<Stack> stacks = error.stacks();
if (stacks.isEmpty())
return Frame();
const Stack &stack = stacks[0];
const QVector<Frame> frames = stack.frames();
if (frames.isEmpty())
return Frame();
//find the first frame belonging to the project
if (!m_projectFiles.isEmpty()) {
foreach (const Frame &frame, frames) {
if (frame.directory().isEmpty() || frame.fileName().isEmpty())
continue;
//filepaths can contain "..", clean them:
const QString f = QFileInfo(frame.filePath()).absoluteFilePath();
if (m_projectFiles.contains(f))
return frame;
}
}
//if no frame belonging to the project was found, return the first one that is not malloc/new
foreach (const Frame &frame, frames) {
if (!frame.functionName().isEmpty() && frame.functionName() != QLatin1String("malloc")
&& !frame.functionName().startsWith(QLatin1String("operator new(")))
{
return frame;
}
}
//else fallback to the first frame
return frames.first();
}
void setFiles(const QStringList &files)
{
m_projectFiles = files;
}
private:
QStringList m_projectFiles;
};
QWidget *MemcheckTool::createWidgets()
{
QTC_ASSERT(!m_errorView, return 0);
m_errorView = new MemcheckErrorView;
m_errorView->setObjectName(QLatin1String("MemcheckErrorView"));
m_errorView->setFrameStyle(QFrame::NoFrame);
m_errorView->setAttribute(Qt::WA_MacShowFocusRect, false);
m_errorModel = new ErrorListModel(m_errorView);
m_frameFinder = new Internal::FrameFinder;
m_errorModel->setRelevantFrameFinder(QSharedPointer<Internal::FrameFinder>(m_frameFinder));
m_errorProxyModel = new MemcheckErrorFilterProxyModel(m_errorView);
m_errorProxyModel->setSourceModel(m_errorModel);
m_errorProxyModel->setDynamicSortFilter(true);
m_errorView->setModel(m_errorProxyModel);
m_errorView->setSelectionMode(QAbstractItemView::ExtendedSelection);
// make m_errorView->selectionModel()->selectedRows() return something
m_errorView->setSelectionBehavior(QAbstractItemView::SelectRows);
m_errorView->setVerticalScrollMode(QAbstractItemView::ScrollPerPixel);
m_errorView->setAutoScroll(false);
m_errorView->setObjectName(QLatin1String("Valgrind.MemcheckTool.ErrorView"));
m_errorView->setWindowTitle(tr("Memory Issues"));
AnalyzerManager::registerDockWidget(MemcheckErrorDockId, m_errorView);
AnalyzerManager::registerPerspective(MemcheckPerspectiveId, {
{ MemcheckErrorDockId, Core::Id(), Perspective::SplitVertical }
});
connect(ProjectExplorerPlugin::instance(), &ProjectExplorerPlugin::updateRunActions,
this, &MemcheckTool::maybeActiveRunConfigurationChanged);
//
// The Control Widget.
//
QAction *action = 0;
QHBoxLayout *layout = new QHBoxLayout;
QToolButton *button = 0;
layout->setMargin(0);
layout->setSpacing(0);
// Load external XML log file
action = new QAction(this);
action->setIcon(Core::Icons::OPENFILE.icon());
action->setToolTip(tr("Load External XML Log File"));
connect(action, &QAction::triggered, this, &MemcheckTool::loadExternalXmlLogFile);
button = new QToolButton;
button->setDefaultAction(action);
layout->addWidget(button);
m_loadExternalLogFile = action;
// Go to previous leak.
action = new QAction(this);
action->setDisabled(true);
action->setIcon(Core::Icons::PREV.icon());
action->setToolTip(tr("Go to previous leak."));
connect(action, &QAction::triggered, m_errorView, &MemcheckErrorView::goBack);
button = new QToolButton;
button->setDefaultAction(action);
layout->addWidget(button);
m_goBack = action;
// Go to next leak.
action = new QAction(this);
action->setDisabled(true);
action->setIcon(Core::Icons::NEXT.icon());
action->setToolTip(tr("Go to next leak."));
connect(action, &QAction::triggered, m_errorView, &MemcheckErrorView::goNext);
button = new QToolButton;
button->setDefaultAction(action);
layout->addWidget(button);
m_goNext = action;
QToolButton *filterButton = new QToolButton;
filterButton->setIcon(Core::Icons::FILTER.icon());
filterButton->setText(tr("Error Filter"));
filterButton->setPopupMode(QToolButton::InstantPopup);
filterButton->setProperty("noArrow", true);
m_filterMenu = new QMenu(filterButton);
foreach (QAction *filterAction, m_errorFilterActions)
m_filterMenu->addAction(filterAction);
m_filterMenu->addSeparator();
m_filterMenu->addAction(m_filterProjectAction);
m_filterMenu->addAction(m_suppressionSeparator);
connect(m_filterMenu, &QMenu::triggered, this, &MemcheckTool::updateErrorFilter);
filterButton->setMenu(m_filterMenu);
layout->addWidget(filterButton);
layout->addStretch();
QWidget *widget = new QWidget;
widget->setObjectName(QLatin1String("MemCheckToolBarWidget"));
widget->setLayout(layout);
return widget;
}
MemcheckRunControl *MemcheckTool::createRunControl(RunConfiguration *runConfiguration,
Core::Id runMode)
{
@@ -555,6 +570,12 @@ MemcheckRunControl *MemcheckTool::createRunControl(RunConfiguration *runConfigur
connect(runControl, &MemcheckRunControl::parserError, this, &MemcheckTool::parserError);
connect(runControl, &MemcheckRunControl::internalParserError, this, &MemcheckTool::internalParserError);
connect(runControl, &MemcheckRunControl::finished, this, &MemcheckTool::engineFinished);
connect(m_stopAction, &QAction::triggered, runControl, [runControl] { runControl->stop(); });
m_toolBusy = true;
updateRunActions();
return runControl;
}
@@ -673,18 +694,19 @@ int MemcheckTool::updateUiAfterFinishedHelper()
void MemcheckTool::engineFinished()
{
m_toolBusy = false;
updateRunActions();
const int issuesFound = updateUiAfterFinishedHelper();
AnalyzerManager::showPermanentStatusMessage(issuesFound > 0
? AnalyzerManager::tr("Memory Analyzer Tool finished, %n issues were found.", 0, issuesFound)
: AnalyzerManager::tr("Memory Analyzer Tool finished, no issues were found."));
Debugger::showPermanentStatusMessage(
tr("Memory Analyzer Tool finished, %n issues were found.", 0, issuesFound));
}
void MemcheckTool::loadingExternalXmlLogFileFinished()
{
const int issuesFound = updateUiAfterFinishedHelper();
AnalyzerManager::showPermanentStatusMessage(issuesFound > 0
? AnalyzerManager::tr("Log file processed, %n issues were found.", 0, issuesFound)
: AnalyzerManager::tr("Log file processed, no issues were found."));
Debugger::showPermanentStatusMessage(
tr("Log file processed, %n issues were found.", 0, issuesFound));
}
void MemcheckTool::setBusyCursor(bool busy)

View File

@@ -43,7 +43,7 @@
#define VALGRIND_DEBUG_OUTPUT 0
using namespace Analyzer;
using namespace Debugger;
using namespace Core;
using namespace Utils;
using namespace ProjectExplorer;
@@ -65,10 +65,8 @@ ValgrindRunControl::ValgrindRunControl(RunConfiguration *runConfiguration, Core:
m_settings = ValgrindPlugin::globalSettings();
}
bool ValgrindRunControl::startEngine()
void ValgrindRunControl::start()
{
emit starting();
FutureProgress *fp = ProgressManager::addTimedTask(m_progress, progressTitle(), "valgrind", 100);
fp->setKeepOnFinish(FutureProgress::HideOnFinish);
connect(fp, &FutureProgress::canceled,
@@ -86,7 +84,6 @@ bool ValgrindRunControl::startEngine()
ValgrindRunner *run = runner();
run->setValgrindExecutable(m_settings->valgrindExecutable());
run->setValgrindArguments(genericToolArguments() + toolArguments());
QTC_ASSERT(!device().isNull(), return false);
run->setDevice(device());
run->setDebuggee(runnable().as<StandardRunnable>());
@@ -99,15 +96,24 @@ bool ValgrindRunControl::startEngine()
if (!run->start()) {
m_progress.cancel();
return false;
emit finished();
return;
}
return true;
m_isRunning = true;
emit started();
}
void ValgrindRunControl::stopEngine()
RunControl::StopResult ValgrindRunControl::stop()
{
m_isStopping = true;
runner()->stop();
return AsynchronousStop;
}
bool ValgrindRunControl::isRunning() const
{
return m_isRunning;
}
QString ValgrindRunControl::executable() const
@@ -139,7 +145,6 @@ QStringList ValgrindRunControl::genericToolArguments() const
void ValgrindRunControl::handleProgressCanceled()
{
AnalyzerManager::stopTool();
m_progress.reportCanceled();
m_progress.reportFinished();
}
@@ -151,6 +156,8 @@ void ValgrindRunControl::handleProgressFinished()
void ValgrindRunControl::runnerFinished()
{
m_isRunning = false;
appendMessage(tr("Analyzing finished.") + QLatin1Char('\n'), NormalMessageFormat);
emit finished();

View File

@@ -38,7 +38,7 @@
namespace Valgrind {
namespace Internal {
class ValgrindRunControl : public Analyzer::AnalyzerRunControl
class ValgrindRunControl : public Debugger::AnalyzerRunControl
{
Q_OBJECT
@@ -46,8 +46,9 @@ public:
ValgrindRunControl(ProjectExplorer::RunConfiguration *runConfiguration,
Core::Id runMode);
bool startEngine() override;
void stopEngine() override;
void start() override;
StopResult stop() override;
bool isRunning() const override;
QString executable() const;
@@ -70,6 +71,7 @@ private:
QStringList genericToolArguments() const;
private:
bool m_isRunning = false;
bool m_isStopping = false;
};

View File

@@ -36,7 +36,7 @@
#include <utils/qtcassert.h>
using namespace Analyzer;
using namespace Debugger;
using namespace ProjectExplorer;
namespace Valgrind {
@@ -56,7 +56,7 @@ bool ValgrindRunControlFactory::canRun(RunConfiguration *runConfiguration, Core:
RunControl *ValgrindRunControlFactory::create(RunConfiguration *runConfiguration, Core::Id mode, QString *errorMessage)
{
Q_UNUSED(errorMessage);
return AnalyzerManager::createRunControl(runConfiguration, mode);
return Debugger::createAnalyzerRunControl(runConfiguration, mode);
}
class ValgrindRunConfigurationAspect : public IRunConfigurationAspect

View File

@@ -188,8 +188,8 @@ QString ValgrindRunner::errorString() const
void ValgrindRunner::stop()
{
if (d->process)
d->process->close();
QTC_ASSERT(d->process, finished(); return);
d->process->close();
}
ValgrindProcess *ValgrindRunner::valgrindProcess() const

View File

@@ -191,8 +191,8 @@ ErrorItem::ErrorItem(const ErrorListModelPrivate *modelPrivate, const Error &err
static QVariant location(const Frame &frame, int role)
{
switch (role) {
case Analyzer::DetailedErrorView::LocationRole:
return QVariant::fromValue(Analyzer::DiagnosticLocation(frame.filePath(), frame.line(), 0));
case Debugger::DetailedErrorView::LocationRole:
return QVariant::fromValue(Debugger::DiagnosticLocation(frame.filePath(), frame.line(), 0));
case Qt::ToolTipRole:
return frame.filePath().isEmpty() ? QVariant() : QVariant(frame.filePath());
default:
@@ -202,14 +202,14 @@ static QVariant location(const Frame &frame, int role)
QVariant ErrorItem::data(int column, int role) const
{
if (column == Analyzer::DetailedErrorView::LocationColumn) {
if (column == Debugger::DetailedErrorView::LocationColumn) {
const Frame frame = m_modelPrivate->findRelevantFrame(m_error);
return location(frame, role);
}
// DiagnosticColumn
switch (role) {
case Analyzer::DetailedErrorView::FullTextRole: {
case Debugger::DetailedErrorView::FullTextRole: {
QString content;
QTextStream stream(&content);
@@ -257,7 +257,7 @@ StackItem::StackItem(const Stack &stack) : m_stack(stack)
QVariant StackItem::data(int column, int role) const
{
const ErrorItem * const errorItem = getErrorItem();
if (column == Analyzer::DetailedErrorView::LocationColumn)
if (column == Debugger::DetailedErrorView::LocationColumn)
return location(errorItem->modelPrivate()->findRelevantFrame(errorItem->error()), role);
// DiagnosticColumn
@@ -285,7 +285,7 @@ FrameItem::FrameItem(const Frame &frame) : m_frame(frame)
QVariant FrameItem::data(int column, int role) const
{
if (column == Analyzer::DetailedErrorView::LocationColumn)
if (column == Debugger::DetailedErrorView::LocationColumn)
return location(m_frame, role);
// DiagnosticColumn

View File

@@ -45,7 +45,7 @@ class ErrorListModel : public Utils::TreeModel
public:
enum Role {
ErrorRole = Analyzer::DetailedErrorView::FullTextRole + 1,
ErrorRole = Debugger::DetailedErrorView::FullTextRole + 1,
};
class RelevantFrameFinder