2012-10-02 09:12:39 +02:00
|
|
|
/****************************************************************************
|
2011-03-04 12:15:19 +01:00
|
|
|
**
|
2016-01-15 14:57:40 +01:00
|
|
|
** Copyright (C) 2016 The Qt Company Ltd.
|
2011-03-04 12:15:19 +01:00
|
|
|
** Author: Nicolas Arnaud-Cormos, KDAB (nicolas.arnaud-cormos@kdab.com)
|
2016-01-15 14:57:40 +01:00
|
|
|
** Contact: https://www.qt.io/licensing/
|
2011-03-04 12:15:19 +01:00
|
|
|
**
|
2012-10-02 09:12:39 +02:00
|
|
|
** This file is part of Qt Creator.
|
2011-03-04 12:15:19 +01:00
|
|
|
**
|
2012-10-02 09:12:39 +02:00
|
|
|
** Commercial License Usage
|
|
|
|
|
** Licensees holding valid commercial Qt licenses may use this file in
|
|
|
|
|
** accordance with the commercial license agreement provided with the
|
|
|
|
|
** Software or, alternatively, in accordance with the terms contained in
|
2016-01-15 14:57:40 +01:00
|
|
|
** a written agreement between you and The Qt Company. For licensing terms
|
|
|
|
|
** and conditions see https://www.qt.io/terms-conditions. For further
|
|
|
|
|
** information use the contact form at https://www.qt.io/contact-us.
|
2011-03-04 12:15:19 +01:00
|
|
|
**
|
2016-01-15 14:57:40 +01:00
|
|
|
** GNU General Public License Usage
|
|
|
|
|
** Alternatively, this file may be used under the terms of the GNU
|
|
|
|
|
** General Public License version 3 as published by the Free Software
|
|
|
|
|
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
|
|
|
|
|
** included in the packaging of this file. Please review the following
|
|
|
|
|
** information to ensure the GNU General Public License requirements will
|
|
|
|
|
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
|
2011-03-04 12:15:19 +01:00
|
|
|
**
|
2012-10-02 09:12:39 +02:00
|
|
|
****************************************************************************/
|
2011-03-04 12:15:19 +01:00
|
|
|
|
|
|
|
|
#include "memchecktool.h"
|
|
|
|
|
#include "memcheckengine.h"
|
|
|
|
|
#include "memcheckerrorview.h"
|
2011-05-23 13:50:28 +02:00
|
|
|
#include "valgrindsettings.h"
|
2011-07-04 10:50:44 +02:00
|
|
|
#include "valgrindplugin.h"
|
2011-03-04 12:15:19 +01:00
|
|
|
|
2016-03-02 12:05:30 +01:00
|
|
|
#include <debugger/analyzer/analyzerconstants.h>
|
2016-02-24 14:42:52 +01:00
|
|
|
#include <debugger/analyzer/analyzermanager.h>
|
|
|
|
|
#include <debugger/analyzer/analyzerutils.h>
|
2016-03-02 12:05:30 +01:00
|
|
|
#include <debugger/analyzer/startremotedialog.h>
|
2011-03-04 12:15:19 +01:00
|
|
|
|
2013-08-08 17:37:37 +02:00
|
|
|
#include <valgrind/valgrindsettings.h>
|
2011-03-04 12:15:19 +01:00
|
|
|
#include <valgrind/xmlprotocol/errorlistmodel.h>
|
|
|
|
|
#include <valgrind/xmlprotocol/stackmodel.h>
|
|
|
|
|
#include <valgrind/xmlprotocol/error.h>
|
|
|
|
|
#include <valgrind/xmlprotocol/frame.h>
|
|
|
|
|
#include <valgrind/xmlprotocol/stack.h>
|
|
|
|
|
#include <valgrind/xmlprotocol/suppression.h>
|
|
|
|
|
|
|
|
|
|
#include <extensionsystem/iplugin.h>
|
|
|
|
|
#include <extensionsystem/pluginmanager.h>
|
|
|
|
|
|
2014-04-24 16:35:07 +02:00
|
|
|
#include <projectexplorer/deploymentdata.h>
|
2011-03-04 12:15:19 +01:00
|
|
|
#include <projectexplorer/projectexplorer.h>
|
|
|
|
|
#include <projectexplorer/project.h>
|
|
|
|
|
#include <projectexplorer/runconfiguration.h>
|
|
|
|
|
#include <projectexplorer/target.h>
|
2016-05-31 16:09:48 +02:00
|
|
|
#include <projectexplorer/taskhub.h>
|
2011-03-04 12:15:19 +01:00
|
|
|
#include <projectexplorer/session.h>
|
|
|
|
|
#include <projectexplorer/buildconfiguration.h>
|
|
|
|
|
|
|
|
|
|
#include <coreplugin/actionmanager/actioncontainer.h>
|
2013-05-30 17:26:51 +02:00
|
|
|
#include <coreplugin/actionmanager/actionmanager.h>
|
2011-03-04 12:15:19 +01:00
|
|
|
#include <coreplugin/actionmanager/command.h>
|
2013-05-30 17:26:51 +02:00
|
|
|
#include <coreplugin/editormanager/editormanager.h>
|
|
|
|
|
#include <coreplugin/icore.h>
|
2011-09-05 16:10:37 +02:00
|
|
|
#include <coreplugin/id.h>
|
2011-03-04 12:15:19 +01:00
|
|
|
|
|
|
|
|
#include <utils/fancymainwindow.h>
|
|
|
|
|
#include <utils/qtcassert.h>
|
2016-05-23 14:15:06 +02:00
|
|
|
#include <utils/utilsicons.h>
|
2011-03-04 12:15:19 +01:00
|
|
|
|
2016-03-02 12:05:30 +01:00
|
|
|
#include <QAction>
|
2012-02-15 10:42:41 +01:00
|
|
|
#include <QDir>
|
2016-03-02 12:05:30 +01:00
|
|
|
#include <QFile>
|
|
|
|
|
#include <QFileDialog>
|
|
|
|
|
#include <QFileInfo>
|
2012-02-15 10:42:41 +01:00
|
|
|
#include <QLabel>
|
|
|
|
|
#include <QMenu>
|
2016-03-02 12:05:30 +01:00
|
|
|
#include <QSortFilterProxyModel>
|
2012-02-15 10:42:41 +01:00
|
|
|
#include <QToolButton>
|
2011-03-04 12:15:19 +01:00
|
|
|
|
2017-04-12 10:06:41 +02:00
|
|
|
using namespace Core;
|
2016-03-02 13:57:37 +01:00
|
|
|
using namespace Debugger;
|
2013-01-10 11:36:15 +01:00
|
|
|
using namespace ProjectExplorer;
|
2016-03-02 13:57:37 +01:00
|
|
|
using namespace Utils;
|
2011-03-04 12:15:19 +01:00
|
|
|
using namespace Valgrind::XmlProtocol;
|
2016-03-08 15:03:31 +01:00
|
|
|
using namespace std::placeholders;
|
2011-03-04 12:15:19 +01:00
|
|
|
|
2011-05-23 13:50:28 +02:00
|
|
|
namespace Valgrind {
|
2011-03-10 16:11:20 +01:00
|
|
|
namespace Internal {
|
|
|
|
|
|
2016-03-07 17:33:58 +01:00
|
|
|
const char MEMCHECK_RUN_MODE[] = "MemcheckTool.MemcheckRunMode";
|
|
|
|
|
const char MEMCHECK_WITH_GDB_RUN_MODE[] = "MemcheckTool.MemcheckWithGdbRunMode";
|
|
|
|
|
|
|
|
|
|
const char MemcheckPerspectiveId[] = "Memcheck.Perspective";
|
|
|
|
|
const char MemcheckErrorDockId[] = "Memcheck.Dock.Error";
|
|
|
|
|
|
2016-03-08 15:03:31 +01:00
|
|
|
static ErrorListModel::RelevantFrameFinder makeFrameFinder(const QStringList &projectFiles)
|
2016-03-02 13:57:37 +01:00
|
|
|
{
|
2016-03-08 15:03:31 +01:00
|
|
|
return [projectFiles](const Error &error) {
|
2016-04-08 12:29:22 +02:00
|
|
|
const Frame defaultFrame = Frame();
|
2016-03-02 13:57:37 +01:00
|
|
|
const QVector<Stack> stacks = error.stacks();
|
|
|
|
|
if (stacks.isEmpty())
|
2016-04-08 12:29:22 +02:00
|
|
|
return defaultFrame;
|
2016-03-02 13:57:37 +01:00
|
|
|
const Stack &stack = stacks[0];
|
|
|
|
|
const QVector<Frame> frames = stack.frames();
|
|
|
|
|
if (frames.isEmpty())
|
2016-04-08 12:29:22 +02:00
|
|
|
return defaultFrame;
|
2016-03-02 13:57:37 +01:00
|
|
|
|
|
|
|
|
//find the first frame belonging to the project
|
2016-03-08 15:03:31 +01:00
|
|
|
if (!projectFiles.isEmpty()) {
|
2016-03-02 13:57:37 +01:00
|
|
|
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();
|
2016-03-08 15:03:31 +01:00
|
|
|
if (projectFiles.contains(f))
|
2016-03-02 13:57:37 +01:00
|
|
|
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();
|
2016-03-08 15:03:31 +01:00
|
|
|
};
|
|
|
|
|
}
|
2016-03-02 13:57:37 +01:00
|
|
|
|
2016-03-02 12:05:30 +01:00
|
|
|
|
|
|
|
|
class MemcheckErrorFilterProxyModel : public QSortFilterProxyModel
|
|
|
|
|
{
|
|
|
|
|
public:
|
|
|
|
|
void setAcceptedKinds(const QList<int> &acceptedKinds);
|
|
|
|
|
void setFilterExternalIssues(bool filter);
|
|
|
|
|
bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const;
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
QList<int> m_acceptedKinds;
|
2016-03-08 15:03:31 +01:00
|
|
|
bool m_filterExternalIssues = false;
|
2016-03-02 12:05:30 +01:00
|
|
|
};
|
|
|
|
|
|
2011-03-04 12:15:19 +01:00
|
|
|
void MemcheckErrorFilterProxyModel::setAcceptedKinds(const QList<int> &acceptedKinds)
|
|
|
|
|
{
|
|
|
|
|
if (m_acceptedKinds != acceptedKinds) {
|
|
|
|
|
m_acceptedKinds = acceptedKinds;
|
2016-05-10 12:57:20 +02:00
|
|
|
invalidateFilter();
|
2011-03-04 12:15:19 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void MemcheckErrorFilterProxyModel::setFilterExternalIssues(bool filter)
|
|
|
|
|
{
|
|
|
|
|
if (m_filterExternalIssues != filter) {
|
|
|
|
|
m_filterExternalIssues = filter;
|
2016-05-10 12:57:20 +02:00
|
|
|
invalidateFilter();
|
2011-03-04 12:15:19 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool MemcheckErrorFilterProxyModel::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const
|
|
|
|
|
{
|
2013-01-10 11:36:15 +01:00
|
|
|
// We only deal with toplevel items.
|
2011-03-04 12:15:19 +01:00
|
|
|
if (sourceParent.isValid())
|
|
|
|
|
return true;
|
|
|
|
|
|
2013-01-10 11:36:15 +01:00
|
|
|
// Because toplevel items have no parent, we can't use sourceParent to find them. we just use
|
2011-03-04 12:15:19 +01:00
|
|
|
// sourceParent as an invalid index, telling the model that the index we're looking for has no
|
|
|
|
|
// parent.
|
|
|
|
|
QAbstractItemModel *model = sourceModel();
|
|
|
|
|
QModelIndex sourceIndex = model->index(sourceRow, filterKeyColumn(), sourceParent);
|
|
|
|
|
if (!sourceIndex.isValid())
|
|
|
|
|
return true;
|
|
|
|
|
|
|
|
|
|
const Error error = sourceIndex.data(ErrorListModel::ErrorRole).value<Error>();
|
|
|
|
|
|
2013-01-10 11:36:15 +01:00
|
|
|
// Filter on kind
|
2011-03-04 12:15:19 +01:00
|
|
|
if (!m_acceptedKinds.contains(error.kind()))
|
|
|
|
|
return false;
|
|
|
|
|
|
2013-01-10 11:36:15 +01:00
|
|
|
// Filter non-project stuff
|
2011-03-04 12:15:19 +01:00
|
|
|
if (m_filterExternalIssues && !error.stacks().isEmpty()) {
|
|
|
|
|
// ALGORITHM: look at last five stack frames, if none of these is inside any open projects,
|
|
|
|
|
// assume this error was created by an external library
|
|
|
|
|
QSet<QString> validFolders;
|
2017-03-01 17:53:15 +01:00
|
|
|
for (Project *project : SessionManager::projects()) {
|
2014-05-02 12:53:36 +02:00
|
|
|
validFolders << project->projectDirectory().toString();
|
2013-01-10 11:36:15 +01:00
|
|
|
foreach (Target *target, project->targets()) {
|
2015-02-03 23:56:02 +02:00
|
|
|
foreach (const DeployableFile &file,
|
2014-04-24 16:35:07 +02:00
|
|
|
target->deploymentData().allFiles()) {
|
|
|
|
|
if (file.isExecutable())
|
|
|
|
|
validFolders << file.remoteDirectory();
|
|
|
|
|
}
|
2013-01-10 11:36:15 +01:00
|
|
|
foreach (BuildConfiguration *config, target->buildConfigurations())
|
2013-08-16 17:45:16 +02:00
|
|
|
validFolders << config->buildDirectory().toString();
|
2011-03-04 12:15:19 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const QVector< Frame > frames = error.stacks().first().frames();
|
|
|
|
|
|
|
|
|
|
const int framesToLookAt = qMin(6, frames.size());
|
|
|
|
|
|
|
|
|
|
bool inProject = false;
|
2013-01-10 11:36:15 +01:00
|
|
|
for (int i = 0; i < framesToLookAt; ++i) {
|
2011-03-04 12:15:19 +01:00
|
|
|
const Frame &frame = frames.at(i);
|
2011-05-11 16:26:34 +02:00
|
|
|
foreach (const QString &folder, validFolders) {
|
2014-07-09 10:11:56 +03:00
|
|
|
if (frame.directory().startsWith(folder)) {
|
2011-03-04 12:15:19 +01:00
|
|
|
inProject = true;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (!inProject)
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2015-03-19 00:59:04 +01:00
|
|
|
static void initKindFilterAction(QAction *action, const QVariantList &kinds)
|
2011-03-10 16:11:20 +01:00
|
|
|
{
|
|
|
|
|
action->setCheckable(true);
|
2015-03-19 00:59:04 +01:00
|
|
|
action->setData(kinds);
|
2011-03-10 16:11:20 +01:00
|
|
|
}
|
|
|
|
|
|
2016-03-02 12:05:30 +01:00
|
|
|
class MemcheckTool : public QObject
|
|
|
|
|
{
|
|
|
|
|
Q_DECLARE_TR_FUNCTIONS(Valgrind::Internal::MemcheckTool)
|
|
|
|
|
|
|
|
|
|
public:
|
2017-07-03 13:55:25 +02:00
|
|
|
MemcheckTool();
|
2016-03-02 12:05:30 +01:00
|
|
|
|
2017-05-09 10:25:11 +02:00
|
|
|
RunWorker *createRunWorker(RunControl *runControl);
|
2016-03-02 12:05:30 +01:00
|
|
|
|
|
|
|
|
private:
|
2016-03-02 13:57:37 +01:00
|
|
|
void updateRunActions();
|
2016-03-02 12:05:30 +01:00
|
|
|
void settingsDestroyed(QObject *settings);
|
|
|
|
|
void maybeActiveRunConfigurationChanged();
|
|
|
|
|
|
|
|
|
|
void engineFinished();
|
|
|
|
|
void loadingExternalXmlLogFileFinished();
|
|
|
|
|
|
|
|
|
|
void parserError(const Valgrind::XmlProtocol::Error &error);
|
|
|
|
|
void internalParserError(const QString &errorString);
|
|
|
|
|
void updateErrorFilter();
|
|
|
|
|
|
|
|
|
|
void loadExternalXmlLogFile();
|
|
|
|
|
|
|
|
|
|
void setBusyCursor(bool busy);
|
|
|
|
|
|
|
|
|
|
void clearErrorView();
|
|
|
|
|
void updateFromSettings();
|
|
|
|
|
int updateUiAfterFinishedHelper();
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
ValgrindBaseSettings *m_settings;
|
2016-03-08 15:03:31 +01:00
|
|
|
QMenu *m_filterMenu = 0;
|
2016-03-02 12:05:30 +01:00
|
|
|
|
2016-03-08 15:03:31 +01:00
|
|
|
Valgrind::XmlProtocol::ErrorListModel m_errorModel;
|
|
|
|
|
MemcheckErrorFilterProxyModel m_errorProxyModel;
|
|
|
|
|
MemcheckErrorView *m_errorView = 0;
|
2016-03-02 12:05:30 +01:00
|
|
|
|
|
|
|
|
QList<QAction *> m_errorFilterActions;
|
|
|
|
|
QAction *m_filterProjectAction;
|
|
|
|
|
QList<QAction *> m_suppressionActions;
|
2016-03-02 13:57:37 +01:00
|
|
|
QAction *m_startAction;
|
|
|
|
|
QAction *m_startWithGdbAction;
|
|
|
|
|
QAction *m_stopAction;
|
2016-03-02 12:05:30 +01:00
|
|
|
QAction *m_suppressionSeparator;
|
|
|
|
|
QAction *m_loadExternalLogFile;
|
|
|
|
|
QAction *m_goBack;
|
|
|
|
|
QAction *m_goNext;
|
2016-03-02 13:57:37 +01:00
|
|
|
bool m_toolBusy = false;
|
2016-03-02 12:05:30 +01:00
|
|
|
};
|
|
|
|
|
|
2017-07-03 13:55:25 +02:00
|
|
|
MemcheckTool::MemcheckTool()
|
2011-03-04 12:15:19 +01:00
|
|
|
{
|
2016-02-29 12:48:58 +01:00
|
|
|
m_settings = ValgrindPlugin::globalSettings();
|
2014-07-23 01:00:51 +02:00
|
|
|
|
2011-03-10 16:11:20 +01:00
|
|
|
setObjectName(QLatin1String("MemcheckTool"));
|
2011-06-27 15:43:15 +02:00
|
|
|
|
|
|
|
|
m_filterProjectAction = new QAction(tr("External Errors"), this);
|
2011-06-28 19:14:08 +02:00
|
|
|
m_filterProjectAction->setToolTip(
|
|
|
|
|
tr("Show issues originating outside currently opened projects."));
|
2011-06-27 15:43:15 +02:00
|
|
|
m_filterProjectAction->setCheckable(true);
|
|
|
|
|
|
|
|
|
|
m_suppressionSeparator = new QAction(tr("Suppressions"), this);
|
|
|
|
|
m_suppressionSeparator->setSeparator(true);
|
2011-06-28 19:14:08 +02:00
|
|
|
m_suppressionSeparator->setToolTip(
|
|
|
|
|
tr("These suppression files were used in the last memory analyzer run."));
|
2011-03-10 16:11:20 +01:00
|
|
|
|
|
|
|
|
QAction *a = new QAction(tr("Definite Memory Leaks"), this);
|
2017-02-22 15:09:35 +01:00
|
|
|
initKindFilterAction(a, {Leak_DefinitelyLost, Leak_IndirectlyLost});
|
2011-06-27 15:43:15 +02:00
|
|
|
m_errorFilterActions.append(a);
|
2011-03-10 16:11:20 +01:00
|
|
|
|
|
|
|
|
a = new QAction(tr("Possible Memory Leaks"), this);
|
2017-02-22 15:09:35 +01:00
|
|
|
initKindFilterAction(a, {Leak_PossiblyLost, Leak_StillReachable});
|
2011-06-27 15:43:15 +02:00
|
|
|
m_errorFilterActions.append(a);
|
2011-03-10 16:11:20 +01:00
|
|
|
|
|
|
|
|
a = new QAction(tr("Use of Uninitialized Memory"), this);
|
2017-02-22 15:09:35 +01:00
|
|
|
initKindFilterAction(a, {InvalidRead, InvalidWrite, InvalidJump, Overlap,
|
|
|
|
|
InvalidMemPool, UninitCondition, UninitValue,
|
|
|
|
|
SyscallParam, ClientCheck});
|
2011-06-27 15:43:15 +02:00
|
|
|
m_errorFilterActions.append(a);
|
2011-03-10 16:11:20 +01:00
|
|
|
|
2011-06-27 15:43:15 +02:00
|
|
|
a = new QAction(tr("Invalid Calls to \"free()\""), this);
|
2015-03-19 00:59:04 +01:00
|
|
|
initKindFilterAction(a, { InvalidFree, MismatchedFree });
|
2011-06-27 15:43:15 +02:00
|
|
|
m_errorFilterActions.append(a);
|
2016-03-02 12:05:30 +01:00
|
|
|
|
2016-03-02 13:57:37 +01:00
|
|
|
m_errorView = new MemcheckErrorView;
|
|
|
|
|
m_errorView->setObjectName(QLatin1String("MemcheckErrorView"));
|
|
|
|
|
m_errorView->setFrameStyle(QFrame::NoFrame);
|
|
|
|
|
m_errorView->setAttribute(Qt::WA_MacShowFocusRect, false);
|
2016-03-08 15:03:31 +01:00
|
|
|
m_errorModel.setRelevantFrameFinder(makeFrameFinder(QStringList()));
|
|
|
|
|
m_errorProxyModel.setSourceModel(&m_errorModel);
|
|
|
|
|
m_errorProxyModel.setDynamicSortFilter(true);
|
|
|
|
|
m_errorView->setModel(&m_errorProxyModel);
|
2016-03-02 13:57:37 +01:00
|
|
|
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"));
|
|
|
|
|
|
2016-05-12 11:57:29 +02:00
|
|
|
Debugger::registerPerspective(MemcheckPerspectiveId, new Perspective (tr("Memcheck"), {
|
2017-02-22 15:09:35 +01:00
|
|
|
{MemcheckErrorDockId, m_errorView, {}, Perspective::SplitVertical}
|
2016-05-12 11:57:29 +02:00
|
|
|
}));
|
2016-03-02 13:57:37 +01:00
|
|
|
|
|
|
|
|
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);
|
2017-09-15 11:25:39 +02:00
|
|
|
action->setIcon(Icons::OPENFILE.icon());
|
2016-03-02 13:57:37 +01:00
|
|
|
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);
|
2017-09-15 11:25:39 +02:00
|
|
|
action->setIcon(Icons::PREV_TOOLBAR.icon());
|
2016-03-02 13:57:37 +01:00
|
|
|
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);
|
2017-09-15 11:25:39 +02:00
|
|
|
action->setIcon(Icons::NEXT_TOOLBAR.icon());
|
2016-03-02 13:57:37 +01:00
|
|
|
action->setToolTip(tr("Go to next leak."));
|
|
|
|
|
connect(action, &QAction::triggered, m_errorView, &MemcheckErrorView::goNext);
|
|
|
|
|
m_goNext = action;
|
|
|
|
|
|
|
|
|
|
auto filterButton = new QToolButton;
|
2017-09-15 11:25:39 +02:00
|
|
|
filterButton->setIcon(Icons::FILTER.icon());
|
2016-03-02 13:57:37 +01:00
|
|
|
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);
|
2016-03-02 12:05:30 +01:00
|
|
|
|
2017-04-12 10:06:41 +02:00
|
|
|
ActionContainer *menu = ActionManager::actionContainer(Debugger::Constants::M_DEBUG_ANALYZER);
|
|
|
|
|
QString toolTip = tr("Valgrind Analyze Memory uses the Memcheck tool to find memory leaks.");
|
2016-03-02 12:05:30 +01:00
|
|
|
|
2017-09-15 11:25:39 +02:00
|
|
|
if (!HostOsInfo::isWindowsHost()) {
|
2017-04-12 10:06:41 +02:00
|
|
|
action = new QAction(this);
|
|
|
|
|
action->setText(tr("Valgrind Memory Analyzer"));
|
|
|
|
|
action->setToolTip(toolTip);
|
|
|
|
|
menu->addAction(ActionManager::registerAction(action, "Memcheck.Local"),
|
|
|
|
|
Debugger::Constants::G_ANALYZER_TOOLS);
|
|
|
|
|
QObject::connect(action, &QAction::triggered, this, [action] {
|
|
|
|
|
if (!Debugger::wantRunTool(DebugMode, action->text()))
|
|
|
|
|
return;
|
|
|
|
|
TaskHub::clearTasks(Debugger::Constants::ANALYZERTASK_ID);
|
|
|
|
|
Debugger::selectPerspective(MemcheckPerspectiveId);
|
|
|
|
|
ProjectExplorerPlugin::runStartupProject(MEMCHECK_RUN_MODE);
|
|
|
|
|
});
|
|
|
|
|
QObject::connect(m_startAction, &QAction::triggered, action, &QAction::triggered);
|
|
|
|
|
QObject::connect(m_startAction, &QAction::changed, action, [action, this] {
|
|
|
|
|
action->setEnabled(m_startAction->isEnabled());
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
action = new QAction(this);
|
|
|
|
|
action->setText(tr("Valgrind Memory Analyzer with GDB"));
|
|
|
|
|
action->setToolTip(tr("Valgrind Analyze Memory with GDB uses the "
|
2016-03-02 12:05:30 +01:00
|
|
|
"Memcheck tool to find memory leaks.\nWhen a problem is detected, "
|
|
|
|
|
"the application is interrupted and can be debugged."));
|
2017-04-12 10:06:41 +02:00
|
|
|
menu->addAction(ActionManager::registerAction(action, "MemcheckWithGdb.Local"),
|
|
|
|
|
Debugger::Constants::G_ANALYZER_TOOLS);
|
|
|
|
|
QObject::connect(action, &QAction::triggered, this, [action] {
|
|
|
|
|
if (!Debugger::wantRunTool(DebugMode, action->text()))
|
|
|
|
|
return;
|
|
|
|
|
TaskHub::clearTasks(Debugger::Constants::ANALYZERTASK_ID);
|
|
|
|
|
Debugger::selectPerspective(MemcheckPerspectiveId);
|
|
|
|
|
ProjectExplorerPlugin::runStartupProject(MEMCHECK_WITH_GDB_RUN_MODE);
|
|
|
|
|
});
|
|
|
|
|
QObject::connect(m_startWithGdbAction, &QAction::triggered, action, &QAction::triggered);
|
|
|
|
|
QObject::connect(m_startWithGdbAction, &QAction::changed, action, [action, this] {
|
|
|
|
|
action->setEnabled(m_startWithGdbAction->isEnabled());
|
|
|
|
|
});
|
2016-03-02 12:05:30 +01:00
|
|
|
}
|
|
|
|
|
|
2017-04-12 10:06:41 +02:00
|
|
|
action = new QAction(this);
|
|
|
|
|
action->setText(tr("Valgrind Memory Analyzer (External Application)"));
|
|
|
|
|
action->setToolTip(toolTip);
|
|
|
|
|
menu->addAction(ActionManager::registerAction(action, "Memcheck.Remote"),
|
|
|
|
|
Debugger::Constants::G_ANALYZER_REMOTE_TOOLS);
|
2017-09-07 17:05:47 +02:00
|
|
|
QObject::connect(action, &QAction::triggered, this, [action] {
|
2017-06-30 08:41:08 +02:00
|
|
|
auto runConfig = RunConfiguration::startupRunConfiguration();
|
2017-04-12 10:06:41 +02:00
|
|
|
if (!runConfig) {
|
|
|
|
|
showCannotStartDialog(action->text());
|
|
|
|
|
return;
|
|
|
|
|
}
|
2016-03-02 12:05:30 +01:00
|
|
|
StartRemoteDialog dlg;
|
|
|
|
|
if (dlg.exec() != QDialog::Accepted)
|
|
|
|
|
return;
|
2017-04-12 10:06:41 +02:00
|
|
|
TaskHub::clearTasks(Debugger::Constants::ANALYZERTASK_ID);
|
|
|
|
|
Debugger::selectPerspective(MemcheckPerspectiveId);
|
2017-05-09 10:25:11 +02:00
|
|
|
RunControl *rc = new RunControl(runConfig, MEMCHECK_RUN_MODE);
|
|
|
|
|
rc->createWorker(MEMCHECK_RUN_MODE);
|
2016-03-02 12:05:30 +01:00
|
|
|
const auto runnable = dlg.runnable();
|
|
|
|
|
rc->setRunnable(runnable);
|
|
|
|
|
rc->setDisplayName(runnable.executable);
|
2017-04-11 14:36:03 +02:00
|
|
|
ProjectExplorerPlugin::startRunControl(rc);
|
2016-03-02 12:05:30 +01:00
|
|
|
});
|
2016-03-02 13:57:37 +01:00
|
|
|
|
|
|
|
|
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);
|
2016-03-08 13:43:09 +01:00
|
|
|
|
|
|
|
|
updateFromSettings();
|
|
|
|
|
maybeActiveRunConfigurationChanged();
|
2016-03-02 13:57:37 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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 {
|
2016-03-09 15:34:55 +01:00
|
|
|
QString whyNot = tr("Start a Valgrind Memcheck analysis.");
|
|
|
|
|
bool canRun = ProjectExplorerPlugin::canRunStartupProject(MEMCHECK_RUN_MODE, &whyNot);
|
|
|
|
|
m_startAction->setToolTip(whyNot);
|
|
|
|
|
m_startAction->setEnabled(canRun);
|
|
|
|
|
whyNot = tr("Start a Valgrind Memcheck with GDB analysis.");
|
|
|
|
|
canRun = ProjectExplorerPlugin::canRunStartupProject(MEMCHECK_WITH_GDB_RUN_MODE, &whyNot);
|
|
|
|
|
m_startWithGdbAction->setToolTip(whyNot);
|
|
|
|
|
m_startWithGdbAction->setEnabled(canRun);
|
|
|
|
|
m_stopAction->setEnabled(false);
|
2016-03-02 13:57:37 +01:00
|
|
|
}
|
2011-03-04 12:15:19 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void MemcheckTool::settingsDestroyed(QObject *settings)
|
|
|
|
|
{
|
2011-04-04 14:39:29 +02:00
|
|
|
QTC_ASSERT(m_settings == settings, return);
|
2013-08-08 17:37:37 +02:00
|
|
|
m_settings = ValgrindPlugin::globalSettings();
|
2011-03-04 12:15:19 +01:00
|
|
|
}
|
|
|
|
|
|
2013-09-09 14:34:19 +02:00
|
|
|
void MemcheckTool::updateFromSettings()
|
|
|
|
|
{
|
|
|
|
|
foreach (QAction *action, m_errorFilterActions) {
|
|
|
|
|
bool contained = true;
|
|
|
|
|
foreach (const QVariant &v, action->data().toList()) {
|
|
|
|
|
bool ok;
|
|
|
|
|
int kind = v.toInt(&ok);
|
|
|
|
|
if (ok && !m_settings->visibleErrorKinds().contains(kind))
|
|
|
|
|
contained = false;
|
|
|
|
|
}
|
|
|
|
|
action->setChecked(contained);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
m_filterProjectAction->setChecked(!m_settings->filterExternalIssues());
|
|
|
|
|
m_errorView->settingsChanged(m_settings);
|
|
|
|
|
|
2015-01-30 11:02:24 +01:00
|
|
|
connect(m_settings, &ValgrindBaseSettings::visibleErrorKindsChanged,
|
2016-03-08 15:03:31 +01:00
|
|
|
&m_errorProxyModel, &MemcheckErrorFilterProxyModel::setAcceptedKinds);
|
|
|
|
|
m_errorProxyModel.setAcceptedKinds(m_settings->visibleErrorKinds());
|
2013-09-09 14:34:19 +02:00
|
|
|
|
2015-01-30 11:02:24 +01:00
|
|
|
connect(m_settings, &ValgrindBaseSettings::filterExternalIssuesChanged,
|
2016-03-08 15:03:31 +01:00
|
|
|
&m_errorProxyModel, &MemcheckErrorFilterProxyModel::setFilterExternalIssues);
|
|
|
|
|
m_errorProxyModel.setFilterExternalIssues(m_settings->filterExternalIssues());
|
2013-09-09 14:34:19 +02:00
|
|
|
}
|
|
|
|
|
|
2011-03-04 12:15:19 +01:00
|
|
|
void MemcheckTool::maybeActiveRunConfigurationChanged()
|
|
|
|
|
{
|
2016-03-02 13:57:37 +01:00
|
|
|
updateRunActions();
|
|
|
|
|
|
2013-08-08 17:37:37 +02:00
|
|
|
ValgrindBaseSettings *settings = 0;
|
2013-09-05 11:46:07 +02:00
|
|
|
if (Project *project = SessionManager::startupProject())
|
2013-01-10 11:36:15 +01:00
|
|
|
if (Target *target = project->activeTarget())
|
|
|
|
|
if (RunConfiguration *rc = target->activeRunConfiguration())
|
2013-08-12 17:04:10 +02:00
|
|
|
if (IRunConfigurationAspect *aspect = rc->extraAspect(ANALYZER_VALGRIND_SETTINGS))
|
|
|
|
|
settings = qobject_cast<ValgrindBaseSettings *>(aspect->currentSettings());
|
2011-03-04 12:15:19 +01:00
|
|
|
|
|
|
|
|
if (!settings) // fallback to global settings
|
2013-08-08 17:37:37 +02:00
|
|
|
settings = ValgrindPlugin::globalSettings();
|
2011-03-04 12:15:19 +01:00
|
|
|
|
|
|
|
|
if (m_settings == settings)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
// disconnect old settings class if any
|
|
|
|
|
if (m_settings) {
|
|
|
|
|
m_settings->disconnect(this);
|
2016-03-08 15:03:31 +01:00
|
|
|
m_settings->disconnect(&m_errorProxyModel);
|
2011-03-04 12:15:19 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// now make the new settings current, update and connect input widgets
|
|
|
|
|
m_settings = settings;
|
|
|
|
|
QTC_ASSERT(m_settings, return);
|
2015-01-30 11:02:24 +01:00
|
|
|
connect(m_settings, &ValgrindBaseSettings::destroyed, this, &MemcheckTool::settingsDestroyed);
|
2011-03-04 12:15:19 +01:00
|
|
|
|
2013-09-09 14:34:19 +02:00
|
|
|
updateFromSettings();
|
2011-03-04 12:15:19 +01:00
|
|
|
}
|
|
|
|
|
|
2017-05-09 10:25:11 +02:00
|
|
|
RunWorker *MemcheckTool::createRunWorker(RunControl *runControl)
|
2011-03-04 12:15:19 +01:00
|
|
|
{
|
2017-09-15 11:25:39 +02:00
|
|
|
m_errorModel.setRelevantFrameFinder(makeFrameFinder(runControl->project()->files(Project::AllFiles)));
|
2011-03-04 12:15:19 +01:00
|
|
|
|
2017-06-21 07:54:54 +02:00
|
|
|
auto runTool = new MemcheckToolRunner(runControl, runControl->runMode() == MEMCHECK_WITH_GDB_RUN_MODE);
|
2016-03-02 13:57:37 +01:00
|
|
|
|
2017-04-27 17:23:28 +02:00
|
|
|
connect(runTool, &MemcheckToolRunner::parserError, this, &MemcheckTool::parserError);
|
|
|
|
|
connect(runTool, &MemcheckToolRunner::internalParserError, this, &MemcheckTool::internalParserError);
|
2017-05-16 07:53:03 +02:00
|
|
|
connect(runTool, &MemcheckToolRunner::stopped, this, &MemcheckTool::engineFinished);
|
2017-04-27 17:23:28 +02:00
|
|
|
|
2017-07-13 15:24:04 +02:00
|
|
|
m_stopAction->disconnect();
|
2017-06-26 18:40:11 +02:00
|
|
|
connect(m_stopAction, &QAction::triggered, runControl, &RunControl::initiateStop);
|
2016-03-02 13:57:37 +01:00
|
|
|
|
|
|
|
|
m_toolBusy = true;
|
|
|
|
|
updateRunActions();
|
|
|
|
|
|
2011-12-13 14:01:52 +01:00
|
|
|
setBusyCursor(true);
|
2011-03-10 16:11:20 +01:00
|
|
|
clearErrorView();
|
2013-09-09 14:34:19 +02:00
|
|
|
m_loadExternalLogFile->setDisabled(true);
|
2011-03-04 12:15:19 +01:00
|
|
|
|
2017-09-15 11:25:39 +02:00
|
|
|
QString dir = runControl->project()->projectDirectory().toString() + '/';
|
|
|
|
|
const QString name = FileName::fromString(runTool->executable()).fileName();
|
2011-03-04 12:15:19 +01:00
|
|
|
|
2017-09-15 11:25:39 +02:00
|
|
|
m_errorView->setDefaultSuppressionFile(dir + name + ".supp");
|
2011-03-04 12:15:19 +01:00
|
|
|
|
2017-04-27 17:23:28 +02:00
|
|
|
foreach (const QString &file, runTool->suppressionFiles()) {
|
2017-09-15 11:25:39 +02:00
|
|
|
QAction *action = m_filterMenu->addAction(FileName::fromString(file).fileName());
|
2011-03-04 12:15:19 +01:00
|
|
|
action->setToolTip(file);
|
2017-09-15 11:25:39 +02:00
|
|
|
connect(action, &QAction::triggered, this, [file] {
|
|
|
|
|
EditorManager::openEditorAt(file, 0);
|
2016-01-20 23:48:30 +01:00
|
|
|
});
|
2011-06-27 15:43:15 +02:00
|
|
|
m_suppressionActions.append(action);
|
2011-03-04 12:15:19 +01:00
|
|
|
}
|
2017-06-27 17:30:32 +02:00
|
|
|
|
|
|
|
|
return runTool;
|
2011-03-04 12:15:19 +01:00
|
|
|
}
|
|
|
|
|
|
2013-09-09 14:34:19 +02:00
|
|
|
void MemcheckTool::loadExternalXmlLogFile()
|
|
|
|
|
{
|
2013-09-29 14:41:37 +03:00
|
|
|
const QString filePath = QFileDialog::getOpenFileName(
|
2017-09-15 11:25:39 +02:00
|
|
|
ICore::mainWindow(),
|
2013-09-29 14:41:37 +03:00
|
|
|
tr("Open Memcheck XML Log File"),
|
|
|
|
|
QString(),
|
|
|
|
|
tr("XML Files (*.xml);;All Files (*)"));
|
2013-09-09 14:34:19 +02:00
|
|
|
if (filePath.isEmpty())
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
QFile *logFile = new QFile(filePath);
|
|
|
|
|
if (!logFile->open(QIODevice::ReadOnly | QIODevice::Text)) {
|
|
|
|
|
delete logFile;
|
2016-05-31 16:09:48 +02:00
|
|
|
QString msg = tr("Memcheck: Failed to open file for reading: %1").arg(filePath);
|
|
|
|
|
TaskHub::addTask(Task::Error, msg, Debugger::Constants::ANALYZERTASK_ID);
|
|
|
|
|
TaskHub::requestPopup();
|
2013-09-09 14:34:19 +02:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
setBusyCursor(true);
|
|
|
|
|
clearErrorView();
|
|
|
|
|
m_loadExternalLogFile->setDisabled(true);
|
|
|
|
|
|
|
|
|
|
if (!m_settings || m_settings != ValgrindPlugin::globalSettings()) {
|
|
|
|
|
m_settings = ValgrindPlugin::globalSettings();
|
|
|
|
|
m_errorView->settingsChanged(m_settings);
|
|
|
|
|
updateFromSettings();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ThreadedParser *parser = new ThreadedParser;
|
2015-01-30 11:02:24 +01:00
|
|
|
connect(parser, &ThreadedParser::error, this, &MemcheckTool::parserError);
|
|
|
|
|
connect(parser, &ThreadedParser::internalError, this, &MemcheckTool::internalParserError);
|
|
|
|
|
connect(parser, &ThreadedParser::finished, this, &MemcheckTool::loadingExternalXmlLogFileFinished);
|
|
|
|
|
connect(parser, &ThreadedParser::finished, parser, &ThreadedParser::deleteLater);
|
2013-09-09 14:34:19 +02:00
|
|
|
|
|
|
|
|
parser->parse(logFile); // ThreadedParser owns the file
|
|
|
|
|
}
|
|
|
|
|
|
2015-02-03 23:56:02 +02:00
|
|
|
void MemcheckTool::parserError(const Error &error)
|
2011-03-04 12:15:19 +01:00
|
|
|
{
|
2016-03-08 15:03:31 +01:00
|
|
|
m_errorModel.addError(error);
|
2011-03-04 12:15:19 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void MemcheckTool::internalParserError(const QString &errorString)
|
|
|
|
|
{
|
2016-05-31 16:09:48 +02:00
|
|
|
QString msg = tr("Memcheck: Error occurred parsing Valgrind output: %1").arg(errorString);
|
|
|
|
|
TaskHub::addTask(Task::Error, msg, Debugger::Constants::ANALYZERTASK_ID);
|
|
|
|
|
TaskHub::requestPopup();
|
2011-03-04 12:15:19 +01:00
|
|
|
}
|
|
|
|
|
|
2011-03-10 16:11:20 +01:00
|
|
|
void MemcheckTool::clearErrorView()
|
2011-03-04 12:15:19 +01:00
|
|
|
{
|
2011-07-06 16:52:14 +02:00
|
|
|
QTC_ASSERT(m_errorView, return);
|
2016-03-08 15:03:31 +01:00
|
|
|
m_errorModel.clear();
|
2011-03-04 12:15:19 +01:00
|
|
|
|
|
|
|
|
qDeleteAll(m_suppressionActions);
|
|
|
|
|
m_suppressionActions.clear();
|
2011-06-27 15:43:15 +02:00
|
|
|
//QTC_ASSERT(filterMenu()->actions().last() == m_suppressionSeparator, qt_noop());
|
2011-03-04 12:15:19 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void MemcheckTool::updateErrorFilter()
|
|
|
|
|
{
|
2011-07-06 16:52:14 +02:00
|
|
|
QTC_ASSERT(m_errorView, return);
|
2011-03-04 12:15:19 +01:00
|
|
|
QTC_ASSERT(m_settings, return);
|
|
|
|
|
|
2013-08-08 17:37:37 +02:00
|
|
|
m_settings->setFilterExternalIssues(!m_filterProjectAction->isChecked());
|
2011-03-04 12:15:19 +01:00
|
|
|
|
|
|
|
|
QList<int> errorKinds;
|
|
|
|
|
foreach (QAction *a, m_errorFilterActions) {
|
|
|
|
|
if (!a->isChecked())
|
|
|
|
|
continue;
|
|
|
|
|
foreach (const QVariant &v, a->data().toList()) {
|
|
|
|
|
bool ok;
|
|
|
|
|
int kind = v.toInt(&ok);
|
|
|
|
|
if (ok)
|
|
|
|
|
errorKinds << kind;
|
|
|
|
|
}
|
|
|
|
|
}
|
2013-08-08 17:37:37 +02:00
|
|
|
m_settings->setVisibleErrorKinds(errorKinds);
|
2011-03-04 12:15:19 +01:00
|
|
|
}
|
2011-03-10 16:11:20 +01:00
|
|
|
|
2013-09-09 14:34:19 +02:00
|
|
|
int MemcheckTool::updateUiAfterFinishedHelper()
|
2011-03-16 13:49:28 +01:00
|
|
|
{
|
2016-03-08 15:03:31 +01:00
|
|
|
const int issuesFound = m_errorModel.rowCount();
|
2013-08-02 12:08:27 +02:00
|
|
|
m_goBack->setEnabled(issuesFound > 1);
|
|
|
|
|
m_goNext->setEnabled(issuesFound > 1);
|
2013-09-09 14:34:19 +02:00
|
|
|
m_loadExternalLogFile->setEnabled(true);
|
|
|
|
|
setBusyCursor(false);
|
|
|
|
|
return issuesFound;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void MemcheckTool::engineFinished()
|
|
|
|
|
{
|
2016-03-02 13:57:37 +01:00
|
|
|
m_toolBusy = false;
|
|
|
|
|
updateRunActions();
|
|
|
|
|
|
2013-09-09 14:34:19 +02:00
|
|
|
const int issuesFound = updateUiAfterFinishedHelper();
|
2016-03-02 13:57:37 +01:00
|
|
|
Debugger::showPermanentStatusMessage(
|
|
|
|
|
tr("Memory Analyzer Tool finished, %n issues were found.", 0, issuesFound));
|
2013-09-09 14:34:19 +02:00
|
|
|
}
|
2013-08-02 12:08:27 +02:00
|
|
|
|
2013-09-09 14:34:19 +02:00
|
|
|
void MemcheckTool::loadingExternalXmlLogFileFinished()
|
|
|
|
|
{
|
|
|
|
|
const int issuesFound = updateUiAfterFinishedHelper();
|
2016-03-02 13:57:37 +01:00
|
|
|
Debugger::showPermanentStatusMessage(
|
|
|
|
|
tr("Log file processed, %n issues were found.", 0, issuesFound));
|
2011-12-13 14:01:52 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void MemcheckTool::setBusyCursor(bool busy)
|
|
|
|
|
{
|
|
|
|
|
QCursor cursor(busy ? Qt::BusyCursor : Qt::ArrowCursor);
|
|
|
|
|
m_errorView->setCursor(cursor);
|
2011-06-29 18:48:08 +02:00
|
|
|
}
|
|
|
|
|
|
2016-03-02 12:05:30 +01:00
|
|
|
|
2017-07-03 13:55:25 +02:00
|
|
|
static MemcheckTool *theMemcheckTool;
|
2016-03-07 17:33:58 +01:00
|
|
|
|
|
|
|
|
void initMemcheckTool()
|
2016-03-02 12:05:30 +01:00
|
|
|
{
|
2017-07-03 13:55:25 +02:00
|
|
|
theMemcheckTool = new MemcheckTool;
|
|
|
|
|
|
|
|
|
|
auto producer = std::bind(&MemcheckTool::createRunWorker, theMemcheckTool, _1);
|
|
|
|
|
RunControl::registerWorker(MEMCHECK_RUN_MODE, producer);
|
|
|
|
|
RunControl::registerWorker(MEMCHECK_WITH_GDB_RUN_MODE, producer);
|
2016-03-02 12:05:30 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void destroyMemcheckTool()
|
|
|
|
|
{
|
2017-07-03 13:55:25 +02:00
|
|
|
delete theMemcheckTool;
|
|
|
|
|
theMemcheckTool = nullptr;
|
2016-03-02 12:05:30 +01:00
|
|
|
}
|
|
|
|
|
|
2011-03-10 16:11:20 +01:00
|
|
|
} // namespace Internal
|
2011-05-23 13:50:28 +02:00
|
|
|
} // namespace Valgrind
|