summaryrefslogtreecommitdiff
path: root/src/plugins/clangtools
diff options
context:
space:
mode:
authorNikolai Kosjar <nikolai.kosjar@qt.io>2019-09-25 15:07:59 +0200
committerNikolai Kosjar <nikolai.kosjar@qt.io>2019-09-27 11:56:42 +0000
commitd5bae3c1eb9d262293da4e6a1d66119040efd1db (patch)
tree8ad11e3bbdd3702b25d5d6faddd1214d150db064 /src/plugins/clangtools
parent4750969c2b0c5574ed4d4ae23d5c69b5d97e1a87 (diff)
downloadqt-creator-d5bae3c1eb9d262293da4e6a1d66119040efd1db.tar.gz
ClangTools: Merge ClangTidyClazyTool into ClangTool
Change-Id: Ieb6c4994ddcff9339a9cfb25c82e23dd2d2e8912 Reviewed-by: Cristian Adam <cristian.adam@qt.io> Reviewed-by: Nikolai Kosjar <nikolai.kosjar@qt.io>
Diffstat (limited to 'src/plugins/clangtools')
-rw-r--r--src/plugins/clangtools/CMakeLists.txt1
-rw-r--r--src/plugins/clangtools/clangtidyclazytool.cpp559
-rw-r--r--src/plugins/clangtools/clangtidyclazytool.h87
-rw-r--r--src/plugins/clangtools/clangtool.cpp491
-rw-r--r--src/plugins/clangtools/clangtool.h52
-rw-r--r--src/plugins/clangtools/clangtoolruncontrol.cpp3
-rw-r--r--src/plugins/clangtools/clangtools.pro2
-rw-r--r--src/plugins/clangtools/clangtools.qbs2
-rw-r--r--src/plugins/clangtools/clangtoolsplugin.cpp11
-rw-r--r--src/plugins/clangtools/clangtoolspreconfiguredsessiontests.cpp8
-rw-r--r--src/plugins/clangtools/clangtoolsprojectsettingswidget.cpp4
-rw-r--r--src/plugins/clangtools/clangtoolsunittests.cpp6
12 files changed, 546 insertions, 680 deletions
diff --git a/src/plugins/clangtools/CMakeLists.txt b/src/plugins/clangtools/CMakeLists.txt
index fe34b67948..f5f2c2a84c 100644
--- a/src/plugins/clangtools/CMakeLists.txt
+++ b/src/plugins/clangtools/CMakeLists.txt
@@ -14,7 +14,6 @@ add_qtc_plugin(ClangTools
clangfixitsrefactoringchanges.cpp clangfixitsrefactoringchanges.h
clangselectablefilesdialog.cpp clangselectablefilesdialog.h clangselectablefilesdialog.ui
clangtidyclazyrunner.cpp clangtidyclazyrunner.h
- clangtidyclazytool.cpp clangtidyclazytool.h
clangtool.cpp clangtool.h
clangtoolruncontrol.cpp clangtoolruncontrol.h
clangtoolrunner.cpp clangtoolrunner.h
diff --git a/src/plugins/clangtools/clangtidyclazytool.cpp b/src/plugins/clangtools/clangtidyclazytool.cpp
deleted file mode 100644
index a5196765c6..0000000000
--- a/src/plugins/clangtools/clangtidyclazytool.cpp
+++ /dev/null
@@ -1,559 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of Qt Creator.
-**
-** 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
-** 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.
-**
-** 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.
-**
-****************************************************************************/
-
-#include "clangtidyclazytool.h"
-
-#include "clangfixitsrefactoringchanges.h"
-#include "clangselectablefilesdialog.h"
-#include "clangtoolruncontrol.h"
-#include "clangtoolsconstants.h"
-#include "clangtoolsdiagnosticmodel.h"
-#include "clangtoolslogfilereader.h"
-#include "clangtoolsdiagnosticview.h"
-#include "clangtoolsprojectsettings.h"
-#include "clangtoolssettings.h"
-
-#include <coreplugin/actionmanager/actioncontainer.h>
-#include <coreplugin/actionmanager/actionmanager.h>
-#include <coreplugin/icore.h>
-#include <coreplugin/messagebox.h>
-
-#include <debugger/analyzer/analyzermanager.h>
-
-#include <projectexplorer/kitinformation.h>
-#include <projectexplorer/projectexplorer.h>
-#include <projectexplorer/projectexplorericons.h>
-#include <projectexplorer/target.h>
-#include <projectexplorer/session.h>
-
-#include <utils/fancylineedit.h>
-#include <utils/utilsicons.h>
-
-#include <QAction>
-#include <QFileDialog>
-#include <QToolButton>
-
-using namespace Core;
-using namespace CppTools;
-using namespace Debugger;
-using namespace ProjectExplorer;
-using namespace Utils;
-
-namespace ClangTools {
-namespace Internal {
-
-static ClangTidyClazyTool *s_instance;
-
-class ApplyFixIts
-{
-public:
- class RefactoringFileInfo
- {
- public:
- bool isValid() const { return file.isValid(); }
-
- FixitsRefactoringFile file;
- QVector<DiagnosticItem *> diagnosticItems;
- bool hasScheduledFixits = false;
- };
-
- ApplyFixIts(const QVector<DiagnosticItem *> &diagnosticItems)
- {
- for (DiagnosticItem *diagnosticItem : diagnosticItems) {
- const QString &filePath = diagnosticItem->diagnostic().location.filePath;
- QTC_ASSERT(!filePath.isEmpty(), continue);
-
- // Get or create refactoring file
- RefactoringFileInfo &fileInfo = m_refactoringFileInfos[filePath];
- if (!fileInfo.isValid())
- fileInfo.file = FixitsRefactoringFile(filePath);
-
- // Append item
- fileInfo.diagnosticItems += diagnosticItem;
- if (diagnosticItem->fixItStatus() == FixitStatus::Scheduled)
- fileInfo.hasScheduledFixits = true;
- }
- }
-
- static void addFixitOperations(DiagnosticItem *diagnosticItem,
- const FixitsRefactoringFile &file, bool apply)
- {
- if (!diagnosticItem->hasNewFixIts())
- return;
-
- // Did we already created the fixit operations?
- ReplacementOperations currentOps = diagnosticItem->fixitOperations();
- if (!currentOps.isEmpty()) {
- for (ReplacementOperation *op : currentOps)
- op->apply = apply;
- return;
- }
-
- // Collect/construct the fixit operations
- ReplacementOperations replacements;
-
- for (const ExplainingStep &step : diagnosticItem->diagnostic().explainingSteps) {
- if (!step.isFixIt)
- continue;
-
- const Debugger::DiagnosticLocation start = step.ranges.first();
- const Debugger::DiagnosticLocation end = step.ranges.last();
- const int startPos = file.position(start.filePath, start.line, start.column);
- const int endPos = file.position(start.filePath, end.line, end.column);
-
- auto op = new ReplacementOperation;
- op->pos = startPos;
- op->length = endPos - startPos;
- op->text = step.message;
- op->fileName = start.filePath;
- op->apply = apply;
-
- replacements += op;
- }
-
- diagnosticItem->setFixitOperations(replacements);
- }
-
- void apply(ClangToolsDiagnosticModel *model)
- {
- for (auto it = m_refactoringFileInfos.begin(); it != m_refactoringFileInfos.end(); ++it) {
- RefactoringFileInfo &fileInfo = it.value();
-
- QVector<DiagnosticItem *> itemsScheduledOrSchedulable;
- QVector<DiagnosticItem *> itemsScheduled;
- QVector<DiagnosticItem *> itemsSchedulable;
-
- // Construct refactoring operations
- for (DiagnosticItem *diagnosticItem : fileInfo.diagnosticItems) {
- const FixitStatus fixItStatus = diagnosticItem->fixItStatus();
-
- const bool isScheduled = fixItStatus == FixitStatus::Scheduled;
- const bool isSchedulable = fileInfo.hasScheduledFixits
- && fixItStatus == FixitStatus::NotScheduled;
-
- if (isScheduled || isSchedulable) {
- addFixitOperations(diagnosticItem, fileInfo.file, isScheduled);
- itemsScheduledOrSchedulable += diagnosticItem;
- if (isScheduled)
- itemsScheduled += diagnosticItem;
- else
- itemsSchedulable += diagnosticItem;
- }
- }
-
- // Collect replacements
- ReplacementOperations ops;
- for (DiagnosticItem *item : itemsScheduledOrSchedulable)
- ops += item->fixitOperations();
-
- if (ops.empty())
- continue;
-
- // Apply file
- QVector<DiagnosticItem *> itemsApplied;
- QVector<DiagnosticItem *> itemsFailedToApply;
- QVector<DiagnosticItem *> itemsInvalidated;
-
- fileInfo.file.setReplacements(ops);
- model->removeWatchedPath(ops.first()->fileName);
- if (fileInfo.file.apply()) {
- itemsApplied = itemsScheduled;
- } else {
- itemsFailedToApply = itemsScheduled;
- itemsInvalidated = itemsSchedulable;
- }
- model->addWatchedPath(ops.first()->fileName);
-
- // Update DiagnosticItem state
- for (DiagnosticItem *diagnosticItem : itemsScheduled)
- diagnosticItem->setFixItStatus(FixitStatus::Applied);
- for (DiagnosticItem *diagnosticItem : itemsFailedToApply)
- diagnosticItem->setFixItStatus(FixitStatus::FailedToApply);
- for (DiagnosticItem *diagnosticItem : itemsInvalidated)
- diagnosticItem->setFixItStatus(FixitStatus::Invalidated);
- }
- }
-
-private:
- QMap<QString, RefactoringFileInfo> m_refactoringFileInfos;
-};
-
-ClangTidyClazyTool::ClangTidyClazyTool()
- : ClangTool("Clang-Tidy and Clazy")
-{
- setObjectName("ClangTidyClazyTool");
- s_instance = this;
-
- m_diagnosticFilterModel = new DiagnosticFilterModel(this);
- m_diagnosticFilterModel->setSourceModel(m_diagnosticModel);
- m_diagnosticFilterModel->setDynamicSortFilter(true);
-
- m_diagnosticView = new DiagnosticView;
- initDiagnosticView();
- m_diagnosticView->setModel(m_diagnosticFilterModel);
- m_diagnosticView->setSortingEnabled(true);
- m_diagnosticView->sortByColumn(Debugger::DetailedErrorView::DiagnosticColumn,
- Qt::AscendingOrder);
- m_diagnosticView->setObjectName(QLatin1String("ClangTidyClazyIssuesView"));
- m_diagnosticView->setWindowTitle(tr("Clang-Tidy and Clazy Diagnostics"));
-
- foreach (auto * const model,
- QList<QAbstractItemModel *>({m_diagnosticModel, m_diagnosticFilterModel})) {
- connect(model, &QAbstractItemModel::rowsInserted,
- this, &ClangTidyClazyTool::handleStateUpdate);
- connect(model, &QAbstractItemModel::rowsRemoved,
- this, &ClangTidyClazyTool::handleStateUpdate);
- connect(model, &QAbstractItemModel::modelReset,
- this, &ClangTidyClazyTool::handleStateUpdate);
- connect(model, &QAbstractItemModel::layoutChanged, // For QSortFilterProxyModel::invalidate()
- this, &ClangTidyClazyTool::handleStateUpdate);
- }
-
- // Go to previous diagnostic
- auto action = new QAction(this);
- action->setDisabled(true);
- action->setIcon(Utils::Icons::PREV_TOOLBAR.icon());
- action->setToolTip(tr("Go to previous diagnostic."));
- connect(action, &QAction::triggered, m_diagnosticView, &DetailedErrorView::goBack);
- m_goBack = action;
-
- // Go to next diagnostic
- action = new QAction(this);
- action->setDisabled(true);
- action->setIcon(Utils::Icons::NEXT_TOOLBAR.icon());
- action->setToolTip(tr("Go to next diagnostic."));
- connect(action, &QAction::triggered, m_diagnosticView, &DetailedErrorView::goNext);
- m_goNext = action;
-
- // Load diagnostics from file
- action = new QAction(this);
- action->setIcon(Utils::Icons::OPENFILE_TOOLBAR.icon());
- action->setToolTip(tr("Load Diagnostics from YAML Files exported with \"-export-fixes\"."));
- connect(action, &QAction::triggered, this, &ClangTidyClazyTool::loadDiagnosticsFromFiles);
- m_loadExported = action;
-
- // Clear data
- action = new QAction(this);
- action->setDisabled(true);
- action->setIcon(Utils::Icons::CLEAN_TOOLBAR.icon());
- action->setToolTip(tr("Clear"));
- connect(action, &QAction::triggered, [this](){
- m_clear->setEnabled(false);
- m_diagnosticModel->clear();
- Debugger::showPermanentStatusMessage(QString());
- });
- m_clear = action;
-
- // Expand/Collapse
- action = new QAction(this);
- action->setDisabled(true);
- action->setCheckable(true);
- action->setIcon(Utils::Icons::EXPAND_ALL_TOOLBAR.icon());
- action->setToolTip(tr("Expand All"));
- connect(action, &QAction::toggled, [this](bool checked){
- if (checked) {
- m_expandCollapse->setToolTip(tr("Collapse All"));
- m_diagnosticView->expandAll();
- } else {
- m_expandCollapse->setToolTip(tr("Expand All"));
- m_diagnosticView->collapseAll();
- }
- });
- m_expandCollapse = action;
-
- // Filter line edit
- m_filterLineEdit = new Utils::FancyLineEdit();
- m_filterLineEdit->setFiltering(true);
- m_filterLineEdit->setPlaceholderText(tr("Filter Diagnostics"));
- m_filterLineEdit->setHistoryCompleter("CppTools.ClangTidyClazyIssueFilter", true);
- connect(m_filterLineEdit, &Utils::FancyLineEdit::filterChanged, [this](const QString &filter) {
- m_diagnosticFilterModel->setFilterRegExp(
- QRegExp(filter, Qt::CaseSensitive, QRegExp::WildcardUnix));
- });
-
- // Apply fixits button
- m_applyFixitsButton = new QToolButton;
- m_applyFixitsButton->setText(tr("Apply Fixits"));
- m_applyFixitsButton->setEnabled(false);
- connect(m_diagnosticModel,
- &ClangToolsDiagnosticModel::fixItsToApplyCountChanged,
- [this](int c) {
- m_applyFixitsButton->setEnabled(c);
- static_cast<DiagnosticView *>(m_diagnosticView.data())->setSelectedFixItsCount(c);
- });
- connect(m_applyFixitsButton, &QToolButton::clicked, [this]() {
- QVector<DiagnosticItem *> diagnosticItems;
- m_diagnosticModel->forItemsAtLevel<2>([&](DiagnosticItem *item){
- diagnosticItems += item;
- });
-
- ApplyFixIts(diagnosticItems).apply(m_diagnosticModel);
- });
-
- ActionContainer *menu = ActionManager::actionContainer(Debugger::Constants::M_DEBUG_ANALYZER);
- const QString toolTip = tr("Clang-Tidy and Clazy use a customized Clang executable from the "
- "Clang project to search for diagnostics.");
-
- m_perspective.addWindow(m_diagnosticView, Perspective::SplitVertical, nullptr);
-
- action = new QAction(tr("Clang-Tidy and Clazy..."), this);
- action->setToolTip(toolTip);
- menu->addAction(ActionManager::registerAction(action, "ClangTidyClazy.Action"),
- Debugger::Constants::G_ANALYZER_TOOLS);
- QObject::connect(action, &QAction::triggered, this, [this]() {
- startTool(ClangTidyClazyTool::FileSelection::AskUser);
- });
- QObject::connect(m_startAction, &QAction::triggered, action, &QAction::triggered);
- QObject::connect(m_startAction, &QAction::changed, action, [action, this] {
- action->setEnabled(m_startAction->isEnabled());
- });
-
- QObject::connect(m_startOnCurrentFileAction, &QAction::triggered, this, [this] {
- startTool(ClangTidyClazyTool::FileSelection::CurrentFile);
- });
-
- m_perspective.addToolBarAction(m_startAction);
- m_perspective.addToolBarAction(m_startOnCurrentFileAction);
- m_perspective.addToolBarAction(m_stopAction);
- m_perspective.addToolBarAction(m_loadExported);
- m_perspective.addToolBarAction(m_clear);
- m_perspective.addToolBarAction(m_goBack);
- m_perspective.addToolBarAction(m_goNext);
- m_perspective.addToolBarAction(m_expandCollapse);
- m_perspective.addToolBarWidget(m_filterLineEdit);
- m_perspective.addToolBarWidget(m_applyFixitsButton);
-
- updateRunActions();
-
- connect(ProjectExplorerPlugin::instance(), &ProjectExplorerPlugin::updateRunActions,
- this, &ClangTidyClazyTool::updateRunActions);
-
-}
-
-ClangTidyClazyTool *ClangTidyClazyTool::instance()
-{
- return s_instance;
-}
-
-void ClangTidyClazyTool::selectPerspective()
-{
- m_perspective.select();
-}
-
-static RunSettings runSettings(Project *project)
-{
- auto *projectSettings = ClangToolsProjectSettingsManager::getSettings(project);
- if (projectSettings->useGlobalSettings())
- return ClangToolsSettings::instance()->runSettings();
- return projectSettings->runSettings();
-}
-
-void ClangTidyClazyTool::startTool(FileSelection fileSelection)
-{
- Project *project = SessionManager::startupProject();
- QTC_ASSERT(project, return);
- QTC_ASSERT(project->activeTarget(), return);
-
- auto runControl = new RunControl(Constants::CLANGTIDYCLAZY_RUN_MODE);
- runControl->setDisplayName(tr("Clang-Tidy and Clazy"));
- runControl->setIcon(ProjectExplorer::Icons::ANALYZER_START_SMALL_TOOLBAR);
- runControl->setTarget(project->activeTarget());
-
- const FileInfos fileInfos = collectFileInfos(project, fileSelection);
- if (fileInfos.empty())
- return;
-
- const bool preventBuild = fileSelection == FileSelection::CurrentFile;
- auto clangTool = new ClangToolRunWorker(runControl,
- runSettings(project),
- fileInfos,
- preventBuild);
-
- m_stopAction->disconnect();
- connect(m_stopAction, &QAction::triggered, runControl, [runControl] {
- runControl->appendMessage(tr("Clang-Tidy and Clazy tool stopped by user."),
- NormalMessageFormat);
- runControl->initiateStop();
- });
-
- connect(runControl, &RunControl::stopped, this, [this, clangTool] {
- bool success = clangTool->success();
- setToolBusy(false);
- m_running = false;
- handleStateUpdate();
- updateRunActions();
- emit finished(success);
- });
-
- m_perspective.select();
-
- m_diagnosticModel->clear();
-
- setToolBusy(true);
- m_diagnosticFilterModel->setProject(project);
- m_running = true;
- handleStateUpdate();
- updateRunActions();
-
- ProjectExplorerPlugin::startRunControl(runControl);
-}
-
-void ClangTidyClazyTool::updateRunActions()
-{
- if (m_toolBusy) {
- QString tooltipText = tr("Clang-Tidy and Clazy are still running.");
-
- m_startAction->setEnabled(false);
- m_startAction->setToolTip(tooltipText);
-
- m_startOnCurrentFileAction->setEnabled(false);
- m_startOnCurrentFileAction->setToolTip(tooltipText);
-
- m_stopAction->setEnabled(true);
- m_loadExported->setEnabled(false);
- m_clear->setEnabled(false);
- } else {
- QString toolTipStart = m_startAction->text();
- QString toolTipStartOnCurrentFile = m_startOnCurrentFileAction->text();
-
- Project *project = SessionManager::startupProject();
- Target *target = project ? project->activeTarget() : nullptr;
- const Core::Id cxx = ProjectExplorer::Constants::CXX_LANGUAGE_ID;
- bool canRun = target && project->projectLanguages().contains(cxx)
- && ToolChainKitAspect::toolChain(target->kit(), cxx);
- if (!canRun)
- toolTipStart = toolTipStartOnCurrentFile = tr("This is not a C/C++ project.");
-
- m_startAction->setEnabled(canRun);
- m_startAction->setToolTip(toolTipStart);
-
- m_startOnCurrentFileAction->setEnabled(canRun);
- m_startOnCurrentFileAction->setToolTip(toolTipStartOnCurrentFile);
-
- m_stopAction->setEnabled(false);
- m_loadExported->setEnabled(true);
- m_clear->setEnabled(m_diagnosticModel->diagnostics().count());
- }
-}
-
-void ClangTidyClazyTool::loadDiagnosticsFromFiles()
-{
- // Ask user for files
- const QStringList filePaths
- = QFileDialog::getOpenFileNames(Core::ICore::mainWindow(),
- tr("Select YAML Files with Diagnostics"),
- QDir::homePath(),
- tr("YAML Files (*.yml *.yaml);;All Files (*)"));
- if (filePaths.isEmpty())
- return;
-
- // Load files
- Diagnostics diagnostics;
- QString errors;
- for (const QString &filePath : filePaths) {
- QString currentError;
- diagnostics << readExportedDiagnostics(Utils::FilePath::fromString(filePath),
- {},
- &currentError);
-
- if (!currentError.isEmpty()) {
- if (!errors.isEmpty())
- errors.append("\n");
- errors.append(currentError);
- }
- }
-
- // Show errors
- if (!errors.isEmpty())
- AsynchronousMessageBox::critical(tr("Error Loading Diagnostics"), errors);
-
- // Show imported
- m_diagnosticModel->clear();
- onNewDiagnosticsAvailable(diagnostics);
-}
-
-void ClangTidyClazyTool::handleStateUpdate()
-{
- QTC_ASSERT(m_goBack, return);
- QTC_ASSERT(m_goNext, return);
- QTC_ASSERT(m_diagnosticModel, return);
- QTC_ASSERT(m_diagnosticFilterModel, return);
-
- const int issuesFound = m_diagnosticModel->diagnostics().count();
- const int issuesVisible = m_diagnosticFilterModel->rowCount();
- m_goBack->setEnabled(issuesVisible > 1);
- m_goNext->setEnabled(issuesVisible > 1);
- m_clear->setEnabled(issuesFound > 0);
- m_expandCollapse->setEnabled(issuesVisible);
-
- m_loadExported->setEnabled(!m_running);
-
- QString message;
- if (m_running) {
- if (issuesFound)
- message = tr("Running - %n diagnostics", nullptr, issuesFound);
- else
- message = tr("Running - No diagnostics");
- } else {
- if (issuesFound)
- message = tr("Finished - %n diagnostics", nullptr, issuesFound);
- else
- message = tr("Finished - No diagnostics");
- }
-
- Debugger::showPermanentStatusMessage(message);
-}
-
-Diagnostics ClangTidyClazyTool::read(OutputFileFormat outputFileFormat,
- const QString &logFilePath,
- const QString &mainFilePath,
- const QSet<Utils::FilePath> &projectFiles,
- QString *errorMessage) const
-{
- const auto acceptFromFilePath = [projectFiles](const Utils::FilePath &filePath) {
- return projectFiles.contains(filePath);
- };
-
- if (outputFileFormat == OutputFileFormat::Yaml) {
- return readExportedDiagnostics(Utils::FilePath::fromString(logFilePath),
- acceptFromFilePath,
- errorMessage);
- }
- return readSerializedDiagnostics(Utils::FilePath::fromString(logFilePath),
- Utils::FilePath::fromString(mainFilePath),
- acceptFromFilePath,
- errorMessage);
-}
-
-void ClangTidyClazyTool::onNewDiagnosticsAvailable(const Diagnostics &diagnostics)
-{
- ClangTool::onNewDiagnosticsAvailable(diagnostics);
- if (!m_diagnosticFilterModel->filterRegExp().pattern().isEmpty())
- m_diagnosticFilterModel->invalidateFilter();
-}
-
-} // namespace Internal
-} // namespace ClangTools
-
diff --git a/src/plugins/clangtools/clangtidyclazytool.h b/src/plugins/clangtools/clangtidyclazytool.h
deleted file mode 100644
index 5ae11ff440..0000000000
--- a/src/plugins/clangtools/clangtidyclazytool.h
+++ /dev/null
@@ -1,87 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of Qt Creator.
-**
-** 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
-** 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.
-**
-** 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.
-**
-****************************************************************************/
-
-#pragma once
-
-#include "clangtool.h"
-
-#include <debugger/debuggermainwindow.h>
-
-QT_BEGIN_NAMESPACE
-class QToolButton;
-QT_END_NAMESPACE
-
-namespace Utils { class FancyLineEdit; }
-
-namespace ClangTools {
-namespace Internal {
-
-class DiagnosticFilterModel;
-
-const char ClangTidyClazyPerspectiveId[] = "ClangTidyClazy.Perspective";
-
-class ClangTidyClazyTool final : public ClangTool
-{
- Q_OBJECT
-
-public:
- ClangTidyClazyTool();
-
- static ClangTidyClazyTool *instance();
-
- void selectPerspective();
-
- void startTool(FileSelection fileSelection) final;
-
- Diagnostics read(OutputFileFormat outputFileFormat,
- const QString &logFilePath,
- const QString &mainFilePath,
- const QSet<Utils::FilePath> &projectFiles,
- QString *errorMessage) const final;
-
- void onNewDiagnosticsAvailable(const Diagnostics &diagnostics) override;
-
-private:
- void handleStateUpdate() final;
-
- void updateRunActions();
- void loadDiagnosticsFromFiles();
-
- DiagnosticFilterModel *m_diagnosticFilterModel = nullptr;
-
- Utils::FancyLineEdit *m_filterLineEdit = nullptr;
- QToolButton *m_applyFixitsButton = nullptr;
-
- QAction *m_goBack = nullptr;
- QAction *m_goNext = nullptr;
- QAction *m_loadExported = nullptr;
- QAction *m_clear = nullptr;
- QAction *m_expandCollapse = nullptr;
-
- Utils::Perspective m_perspective{ClangTidyClazyPerspectiveId, tr("Clang-Tidy and Clazy")};
-};
-
-} // namespace Internal
-} // namespace ClangTools
diff --git a/src/plugins/clangtools/clangtool.cpp b/src/plugins/clangtools/clangtool.cpp
index a2ffb83c7b..da9e022b03 100644
--- a/src/plugins/clangtools/clangtool.cpp
+++ b/src/plugins/clangtools/clangtool.cpp
@@ -25,10 +25,16 @@
#include "clangtool.h"
+#include "clangfixitsrefactoringchanges.h"
#include "clangselectablefilesdialog.h"
+#include "clangtoolruncontrol.h"
#include "clangtoolsconstants.h"
#include "clangtoolsdiagnostic.h"
#include "clangtoolsdiagnosticmodel.h"
+#include "clangtoolsdiagnosticview.h"
+#include "clangtoolslogfilereader.h"
+#include "clangtoolsprojectsettings.h"
+#include "clangtoolssettings.h"
#include "clangtoolsutils.h"
#include <coreplugin/actionmanager/actioncontainer.h>
@@ -36,6 +42,7 @@
#include <coreplugin/coreconstants.h>
#include <coreplugin/editormanager/editormanager.h>
#include <coreplugin/icore.h>
+#include <coreplugin/messagebox.h>
#include <cpptools/cppmodelmanager.h>
@@ -44,19 +51,22 @@
#include <projectexplorer/kitinformation.h>
#include <projectexplorer/projectexplorer.h>
#include <projectexplorer/projectexplorericons.h>
-#include <projectexplorer/target.h>
#include <projectexplorer/session.h>
+#include <projectexplorer/target.h>
#include <utils/algorithm.h>
+#include <utils/fancylineedit.h>
#include <utils/fancymainwindow.h>
#include <utils/utilsicons.h>
#include <QAction>
+#include <QFileDialog>
#include <QLabel>
#include <QSortFilterProxyModel>
#include <QToolButton>
using namespace Core;
+using namespace CppTools;
using namespace Debugger;
using namespace ProjectExplorer;
using namespace Utils;
@@ -64,6 +74,142 @@ using namespace Utils;
namespace ClangTools {
namespace Internal {
+static ClangTool *s_instance;
+
+class ApplyFixIts
+{
+public:
+ class RefactoringFileInfo
+ {
+ public:
+ bool isValid() const { return file.isValid(); }
+
+ FixitsRefactoringFile file;
+ QVector<DiagnosticItem *> diagnosticItems;
+ bool hasScheduledFixits = false;
+ };
+
+ ApplyFixIts(const QVector<DiagnosticItem *> &diagnosticItems)
+ {
+ for (DiagnosticItem *diagnosticItem : diagnosticItems) {
+ const QString &filePath = diagnosticItem->diagnostic().location.filePath;
+ QTC_ASSERT(!filePath.isEmpty(), continue);
+
+ // Get or create refactoring file
+ RefactoringFileInfo &fileInfo = m_refactoringFileInfos[filePath];
+ if (!fileInfo.isValid())
+ fileInfo.file = FixitsRefactoringFile(filePath);
+
+ // Append item
+ fileInfo.diagnosticItems += diagnosticItem;
+ if (diagnosticItem->fixItStatus() == FixitStatus::Scheduled)
+ fileInfo.hasScheduledFixits = true;
+ }
+ }
+
+ static void addFixitOperations(DiagnosticItem *diagnosticItem,
+ const FixitsRefactoringFile &file, bool apply)
+ {
+ if (!diagnosticItem->hasNewFixIts())
+ return;
+
+ // Did we already created the fixit operations?
+ ReplacementOperations currentOps = diagnosticItem->fixitOperations();
+ if (!currentOps.isEmpty()) {
+ for (ReplacementOperation *op : currentOps)
+ op->apply = apply;
+ return;
+ }
+
+ // Collect/construct the fixit operations
+ ReplacementOperations replacements;
+
+ for (const ExplainingStep &step : diagnosticItem->diagnostic().explainingSteps) {
+ if (!step.isFixIt)
+ continue;
+
+ const Debugger::DiagnosticLocation start = step.ranges.first();
+ const Debugger::DiagnosticLocation end = step.ranges.last();
+ const int startPos = file.position(start.filePath, start.line, start.column);
+ const int endPos = file.position(start.filePath, end.line, end.column);
+
+ auto op = new ReplacementOperation;
+ op->pos = startPos;
+ op->length = endPos - startPos;
+ op->text = step.message;
+ op->fileName = start.filePath;
+ op->apply = apply;
+
+ replacements += op;
+ }
+
+ diagnosticItem->setFixitOperations(replacements);
+ }
+
+ void apply(ClangToolsDiagnosticModel *model)
+ {
+ for (auto it = m_refactoringFileInfos.begin(); it != m_refactoringFileInfos.end(); ++it) {
+ RefactoringFileInfo &fileInfo = it.value();
+
+ QVector<DiagnosticItem *> itemsScheduledOrSchedulable;
+ QVector<DiagnosticItem *> itemsScheduled;
+ QVector<DiagnosticItem *> itemsSchedulable;
+
+ // Construct refactoring operations
+ for (DiagnosticItem *diagnosticItem : fileInfo.diagnosticItems) {
+ const FixitStatus fixItStatus = diagnosticItem->fixItStatus();
+
+ const bool isScheduled = fixItStatus == FixitStatus::Scheduled;
+ const bool isSchedulable = fileInfo.hasScheduledFixits
+ && fixItStatus == FixitStatus::NotScheduled;
+
+ if (isScheduled || isSchedulable) {
+ addFixitOperations(diagnosticItem, fileInfo.file, isScheduled);
+ itemsScheduledOrSchedulable += diagnosticItem;
+ if (isScheduled)
+ itemsScheduled += diagnosticItem;
+ else
+ itemsSchedulable += diagnosticItem;
+ }
+ }
+
+ // Collect replacements
+ ReplacementOperations ops;
+ for (DiagnosticItem *item : itemsScheduledOrSchedulable)
+ ops += item->fixitOperations();
+
+ if (ops.empty())
+ continue;
+
+ // Apply file
+ QVector<DiagnosticItem *> itemsApplied;
+ QVector<DiagnosticItem *> itemsFailedToApply;
+ QVector<DiagnosticItem *> itemsInvalidated;
+
+ fileInfo.file.setReplacements(ops);
+ model->removeWatchedPath(ops.first()->fileName);
+ if (fileInfo.file.apply()) {
+ itemsApplied = itemsScheduled;
+ } else {
+ itemsFailedToApply = itemsScheduled;
+ itemsInvalidated = itemsSchedulable;
+ }
+ model->addWatchedPath(ops.first()->fileName);
+
+ // Update DiagnosticItem state
+ for (DiagnosticItem *diagnosticItem : itemsScheduled)
+ diagnosticItem->setFixItStatus(FixitStatus::Applied);
+ for (DiagnosticItem *diagnosticItem : itemsFailedToApply)
+ diagnosticItem->setFixItStatus(FixitStatus::FailedToApply);
+ for (DiagnosticItem *diagnosticItem : itemsInvalidated)
+ diagnosticItem->setFixItStatus(FixitStatus::Invalidated);
+ }
+ }
+
+private:
+ QMap<QString, RefactoringFileInfo> m_refactoringFileInfos;
+};
+
static FileInfos sortedFileInfos(const QVector<CppTools::ProjectPart::Ptr> &projectParts)
{
FileInfos fileInfos;
@@ -93,9 +239,24 @@ static FileInfos sortedFileInfos(const QVector<CppTools::ProjectPart::Ptr> &proj
return fileInfos;
}
-ClangTool::ClangTool(const QString &name)
- : m_name(name)
+static RunSettings runSettings(Project *project)
+{
+ auto *projectSettings = ClangToolsProjectSettingsManager::getSettings(project);
+ if (projectSettings->useGlobalSettings())
+ return ClangToolsSettings::instance()->runSettings();
+ return projectSettings->runSettings();
+}
+
+ClangTool *ClangTool::instance()
+{
+ return s_instance;
+}
+
+ClangTool::ClangTool()
+ : m_name("Clang-Tidy and Clazy")
{
+ setObjectName("ClangTidyClazyTool");
+ s_instance = this;
m_diagnosticModel = new ClangToolsDiagnosticModel(this);
const Utils::Icon RUN_FILE_OVERLAY(
@@ -120,6 +281,150 @@ ClangTool::ClangTool(const QString &name)
m_startOnCurrentFileAction = action;
m_stopAction = Debugger::createStopAction();
+
+ m_diagnosticFilterModel = new DiagnosticFilterModel(this);
+ m_diagnosticFilterModel->setSourceModel(m_diagnosticModel);
+ m_diagnosticFilterModel->setDynamicSortFilter(true);
+
+ m_diagnosticView = new DiagnosticView;
+ initDiagnosticView();
+ m_diagnosticView->setModel(m_diagnosticFilterModel);
+ m_diagnosticView->setSortingEnabled(true);
+ m_diagnosticView->sortByColumn(Debugger::DetailedErrorView::DiagnosticColumn,
+ Qt::AscendingOrder);
+ m_diagnosticView->setObjectName(QLatin1String("ClangTidyClazyIssuesView"));
+ m_diagnosticView->setWindowTitle(tr("Clang-Tidy and Clazy Diagnostics"));
+
+ foreach (auto * const model,
+ QList<QAbstractItemModel *>({m_diagnosticModel, m_diagnosticFilterModel})) {
+ connect(model, &QAbstractItemModel::rowsInserted,
+ this, &ClangTool::handleStateUpdate);
+ connect(model, &QAbstractItemModel::rowsRemoved,
+ this, &ClangTool::handleStateUpdate);
+ connect(model, &QAbstractItemModel::modelReset,
+ this, &ClangTool::handleStateUpdate);
+ connect(model, &QAbstractItemModel::layoutChanged, // For QSortFilterProxyModel::invalidate()
+ this, &ClangTool::handleStateUpdate);
+ }
+
+ // Go to previous diagnostic
+ action = new QAction(this);
+ action->setDisabled(true);
+ action->setIcon(Utils::Icons::PREV_TOOLBAR.icon());
+ action->setToolTip(tr("Go to previous diagnostic."));
+ connect(action, &QAction::triggered, m_diagnosticView, &DetailedErrorView::goBack);
+ m_goBack = action;
+
+ // Go to next diagnostic
+ action = new QAction(this);
+ action->setDisabled(true);
+ action->setIcon(Utils::Icons::NEXT_TOOLBAR.icon());
+ action->setToolTip(tr("Go to next diagnostic."));
+ connect(action, &QAction::triggered, m_diagnosticView, &DetailedErrorView::goNext);
+ m_goNext = action;
+
+ // Load diagnostics from file
+ action = new QAction(this);
+ action->setIcon(Utils::Icons::OPENFILE_TOOLBAR.icon());
+ action->setToolTip(tr("Load Diagnostics from YAML Files exported with \"-export-fixes\"."));
+ connect(action, &QAction::triggered, this, &ClangTool::loadDiagnosticsFromFiles);
+ m_loadExported = action;
+
+ // Clear data
+ action = new QAction(this);
+ action->setDisabled(true);
+ action->setIcon(Utils::Icons::CLEAN_TOOLBAR.icon());
+ action->setToolTip(tr("Clear"));
+ connect(action, &QAction::triggered, [this](){
+ m_clear->setEnabled(false);
+ m_diagnosticModel->clear();
+ Debugger::showPermanentStatusMessage(QString());
+ });
+ m_clear = action;
+
+ // Expand/Collapse
+ action = new QAction(this);
+ action->setDisabled(true);
+ action->setCheckable(true);
+ action->setIcon(Utils::Icons::EXPAND_ALL_TOOLBAR.icon());
+ action->setToolTip(tr("Expand All"));
+ connect(action, &QAction::toggled, [this](bool checked){
+ if (checked) {
+ m_expandCollapse->setToolTip(tr("Collapse All"));
+ m_diagnosticView->expandAll();
+ } else {
+ m_expandCollapse->setToolTip(tr("Expand All"));
+ m_diagnosticView->collapseAll();
+ }
+ });
+ m_expandCollapse = action;
+
+ // Filter line edit
+ m_filterLineEdit = new Utils::FancyLineEdit();
+ m_filterLineEdit->setFiltering(true);
+ m_filterLineEdit->setPlaceholderText(tr("Filter Diagnostics"));
+ m_filterLineEdit->setHistoryCompleter("CppTools.ClangTidyClazyIssueFilter", true);
+ connect(m_filterLineEdit, &Utils::FancyLineEdit::filterChanged, [this](const QString &filter) {
+ m_diagnosticFilterModel->setFilterRegExp(
+ QRegExp(filter, Qt::CaseSensitive, QRegExp::WildcardUnix));
+ });
+
+ // Apply fixits button
+ m_applyFixitsButton = new QToolButton;
+ m_applyFixitsButton->setText(tr("Apply Fixits"));
+ m_applyFixitsButton->setEnabled(false);
+ connect(m_diagnosticModel,
+ &ClangToolsDiagnosticModel::fixItsToApplyCountChanged,
+ [this](int c) {
+ m_applyFixitsButton->setEnabled(c);
+ static_cast<DiagnosticView *>(m_diagnosticView.data())->setSelectedFixItsCount(c);
+ });
+ connect(m_applyFixitsButton, &QToolButton::clicked, [this]() {
+ QVector<DiagnosticItem *> diagnosticItems;
+ m_diagnosticModel->forItemsAtLevel<2>([&](DiagnosticItem *item){
+ diagnosticItems += item;
+ });
+
+ ApplyFixIts(diagnosticItems).apply(m_diagnosticModel);
+ });
+
+ ActionContainer *menu = ActionManager::actionContainer(Debugger::Constants::M_DEBUG_ANALYZER);
+ const QString toolTip = tr("Clang-Tidy and Clazy use a customized Clang executable from the "
+ "Clang project to search for diagnostics.");
+
+ m_perspective.addWindow(m_diagnosticView, Perspective::SplitVertical, nullptr);
+
+ action = new QAction(tr("Clang-Tidy and Clazy..."), this);
+ action->setToolTip(toolTip);
+ menu->addAction(ActionManager::registerAction(action, "ClangTidyClazy.Action"),
+ Debugger::Constants::G_ANALYZER_TOOLS);
+ QObject::connect(action, &QAction::triggered, this, [this]() {
+ startTool(ClangTool::FileSelection::AskUser);
+ });
+ QObject::connect(m_startAction, &QAction::triggered, action, &QAction::triggered);
+ QObject::connect(m_startAction, &QAction::changed, action, [action, this] {
+ action->setEnabled(m_startAction->isEnabled());
+ });
+
+ QObject::connect(m_startOnCurrentFileAction, &QAction::triggered, this, [this] {
+ startTool(ClangTool::FileSelection::CurrentFile);
+ });
+
+ m_perspective.addToolBarAction(m_startAction);
+ m_perspective.addToolBarAction(m_startOnCurrentFileAction);
+ m_perspective.addToolBarAction(m_stopAction);
+ m_perspective.addToolBarAction(m_loadExported);
+ m_perspective.addToolBarAction(m_clear);
+ m_perspective.addToolBarAction(m_goBack);
+ m_perspective.addToolBarAction(m_goNext);
+ m_perspective.addToolBarAction(m_expandCollapse);
+ m_perspective.addToolBarWidget(m_filterLineEdit);
+ m_perspective.addToolBarWidget(m_applyFixitsButton);
+
+ updateRunActions();
+
+ connect(ProjectExplorerPlugin::instance(), &ProjectExplorerPlugin::updateRunActions,
+ this, &ClangTool::updateRunActions);
}
ClangTool::~ClangTool()
@@ -127,6 +432,78 @@ ClangTool::~ClangTool()
delete m_diagnosticView;
}
+void ClangTool::selectPerspective()
+{
+ m_perspective.select();
+}
+
+void ClangTool::startTool(ClangTool::FileSelection fileSelection)
+{
+ Project *project = SessionManager::startupProject();
+ QTC_ASSERT(project, return);
+ QTC_ASSERT(project->activeTarget(), return);
+
+ auto runControl = new RunControl(Constants::CLANGTIDYCLAZY_RUN_MODE);
+ runControl->setDisplayName(tr("Clang-Tidy and Clazy"));
+ runControl->setIcon(ProjectExplorer::Icons::ANALYZER_START_SMALL_TOOLBAR);
+ runControl->setTarget(project->activeTarget());
+
+ const FileInfos fileInfos = collectFileInfos(project, fileSelection);
+ if (fileInfos.empty())
+ return;
+
+ const bool preventBuild = fileSelection == FileSelection::CurrentFile;
+ auto clangTool = new ClangToolRunWorker(runControl,
+ runSettings(project),
+ fileInfos,
+ preventBuild);
+
+ m_stopAction->disconnect();
+ connect(m_stopAction, &QAction::triggered, runControl, [runControl] {
+ runControl->appendMessage(tr("Clang-Tidy and Clazy tool stopped by user."),
+ NormalMessageFormat);
+ runControl->initiateStop();
+ });
+
+ connect(runControl, &RunControl::stopped, this, [this, clangTool] {
+ bool success = clangTool->success();
+ setToolBusy(false);
+ m_running = false;
+ handleStateUpdate();
+ updateRunActions();
+ emit finished(success);
+ });
+
+ m_perspective.select();
+
+ m_diagnosticModel->clear();
+
+ setToolBusy(true);
+ m_diagnosticFilterModel->setProject(project);
+ m_running = true;
+ handleStateUpdate();
+ updateRunActions();
+
+ ProjectExplorerPlugin::startRunControl(runControl);
+}
+
+Diagnostics ClangTool::read(OutputFileFormat outputFileFormat, const QString &logFilePath, const QString &mainFilePath, const QSet<FilePath> &projectFiles, QString *errorMessage) const
+{
+ const auto acceptFromFilePath = [projectFiles](const Utils::FilePath &filePath) {
+ return projectFiles.contains(filePath);
+ };
+
+ if (outputFileFormat == OutputFileFormat::Yaml) {
+ return readExportedDiagnostics(Utils::FilePath::fromString(logFilePath),
+ acceptFromFilePath,
+ errorMessage);
+ }
+ return readSerializedDiagnostics(Utils::FilePath::fromString(logFilePath),
+ Utils::FilePath::fromString(mainFilePath),
+ acceptFromFilePath,
+ errorMessage);
+}
+
FileInfos ClangTool::collectFileInfos(Project *project, FileSelection fileSelection) const
{
auto projectInfo = CppTools::CppModelManager::instance()->projectInfo(project);
@@ -174,6 +551,42 @@ void ClangTool::initDiagnosticView()
m_diagnosticView->setAutoScroll(false);
}
+void ClangTool::loadDiagnosticsFromFiles()
+{
+ // Ask user for files
+ const QStringList filePaths
+ = QFileDialog::getOpenFileNames(Core::ICore::mainWindow(),
+ tr("Select YAML Files with Diagnostics"),
+ QDir::homePath(),
+ tr("YAML Files (*.yml *.yaml);;All Files (*)"));
+ if (filePaths.isEmpty())
+ return;
+
+ // Load files
+ Diagnostics diagnostics;
+ QString errors;
+ for (const QString &filePath : filePaths) {
+ QString currentError;
+ diagnostics << readExportedDiagnostics(Utils::FilePath::fromString(filePath),
+ {},
+ &currentError);
+
+ if (!currentError.isEmpty()) {
+ if (!errors.isEmpty())
+ errors.append("\n");
+ errors.append(currentError);
+ }
+ }
+
+ // Show errors
+ if (!errors.isEmpty())
+ AsynchronousMessageBox::critical(tr("Error Loading Diagnostics"), errors);
+
+ // Show imported
+ m_diagnosticModel->clear();
+ onNewDiagnosticsAvailable(diagnostics);
+}
+
QSet<Diagnostic> ClangTool::diagnostics() const
{
return Utils::filtered(m_diagnosticModel->diagnostics(), [](const Diagnostic &diagnostic) {
@@ -186,6 +599,78 @@ void ClangTool::onNewDiagnosticsAvailable(const Diagnostics &diagnostics)
{
QTC_ASSERT(m_diagnosticModel, return);
m_diagnosticModel->addDiagnostics(diagnostics);
+ if (!m_diagnosticFilterModel->filterRegExp().pattern().isEmpty())
+ m_diagnosticFilterModel->invalidateFilter();
+}
+
+void ClangTool::updateRunActions()
+{
+ if (m_toolBusy) {
+ QString tooltipText = tr("Clang-Tidy and Clazy are still running.");
+
+ m_startAction->setEnabled(false);
+ m_startAction->setToolTip(tooltipText);
+
+ m_startOnCurrentFileAction->setEnabled(false);
+ m_startOnCurrentFileAction->setToolTip(tooltipText);
+
+ m_stopAction->setEnabled(true);
+ m_loadExported->setEnabled(false);
+ m_clear->setEnabled(false);
+ } else {
+ QString toolTipStart = m_startAction->text();
+ QString toolTipStartOnCurrentFile = m_startOnCurrentFileAction->text();
+
+ Project *project = SessionManager::startupProject();
+ Target *target = project ? project->activeTarget() : nullptr;
+ const Core::Id cxx = ProjectExplorer::Constants::CXX_LANGUAGE_ID;
+ bool canRun = target && project->projectLanguages().contains(cxx)
+ && ToolChainKitAspect::toolChain(target->kit(), cxx);
+ if (!canRun)
+ toolTipStart = toolTipStartOnCurrentFile = tr("This is not a C/C++ project.");
+
+ m_startAction->setEnabled(canRun);
+ m_startAction->setToolTip(toolTipStart);
+
+ m_startOnCurrentFileAction->setEnabled(canRun);
+ m_startOnCurrentFileAction->setToolTip(toolTipStartOnCurrentFile);
+
+ m_stopAction->setEnabled(false);
+ m_loadExported->setEnabled(true);
+ m_clear->setEnabled(m_diagnosticModel->diagnostics().count());
+ }
+}
+
+void ClangTool::handleStateUpdate()
+{
+ QTC_ASSERT(m_goBack, return);
+ QTC_ASSERT(m_goNext, return);
+ QTC_ASSERT(m_diagnosticModel, return);
+ QTC_ASSERT(m_diagnosticFilterModel, return);
+
+ const int issuesFound = m_diagnosticModel->diagnostics().count();
+ const int issuesVisible = m_diagnosticFilterModel->rowCount();
+ m_goBack->setEnabled(issuesVisible > 1);
+ m_goNext->setEnabled(issuesVisible > 1);
+ m_clear->setEnabled(issuesFound > 0);
+ m_expandCollapse->setEnabled(issuesVisible);
+
+ m_loadExported->setEnabled(!m_running);
+
+ QString message;
+ if (m_running) {
+ if (issuesFound)
+ message = tr("Running - %n diagnostics", nullptr, issuesFound);
+ else
+ message = tr("Running - No diagnostics");
+ } else {
+ if (issuesFound)
+ message = tr("Finished - %n diagnostics", nullptr, issuesFound);
+ else
+ message = tr("Finished - No diagnostics");
+ }
+
+ Debugger::showPermanentStatusMessage(message);
}
void ClangTool::setToolBusy(bool busy)
diff --git a/src/plugins/clangtools/clangtool.h b/src/plugins/clangtools/clangtool.h
index c0b1565260..b61ed1ac44 100644
--- a/src/plugins/clangtools/clangtool.h
+++ b/src/plugins/clangtools/clangtool.h
@@ -29,38 +29,56 @@
#include "clangtoolsdiagnostic.h"
#include "clangtoolslogfilereader.h"
+#include <debugger/debuggermainwindow.h>
+
#include <projectexplorer/runconfiguration.h>
#include <cpptools/projectinfo.h>
-namespace Debugger { class DetailedErrorView; }
-namespace Utils { class FilePath; }
+QT_BEGIN_NAMESPACE
+class QToolButton;
+QT_END_NAMESPACE
+
+namespace Debugger {
+class DetailedErrorView;
+}
+namespace Utils {
+class FilePath;
+class FancyLineEdit;
+} // namespace Utils
namespace ClangTools {
namespace Internal {
class ClangToolsDiagnosticModel;
class Diagnostic;
+class DiagnosticFilterModel;
+
+const char ClangTidyClazyPerspectiveId[] = "ClangTidyClazy.Perspective";
class ClangTool : public QObject
{
Q_OBJECT
public:
- ClangTool(const QString &name);
+ static ClangTool *instance();
+
+ ClangTool();
~ClangTool() override;
+ void selectPerspective();
+
enum class FileSelection {
AllFiles,
CurrentFile,
AskUser,
};
- virtual void startTool(FileSelection fileSelection) = 0;
+ void startTool(FileSelection fileSelection);
- virtual Diagnostics read(OutputFileFormat outputFileFormat,
+ Diagnostics read(OutputFileFormat outputFileFormat,
const QString &logFilePath,
const QString &mainFilePath,
const QSet<Utils::FilePath> &projectFiles,
- QString *errorMessage) const = 0;
+ QString *errorMessage) const;
FileInfos collectFileInfos(ProjectExplorer::Project *project,
FileSelection fileSelection) const;
@@ -70,7 +88,7 @@ public:
const QString &name() const;
- virtual void onNewDiagnosticsAvailable(const Diagnostics &diagnostics);
+ void onNewDiagnosticsAvailable(const Diagnostics &diagnostics);
QAction *startAction() const { return m_startAction; }
QAction *startOnCurrentFileAction() const { return m_startOnCurrentFileAction; }
@@ -78,11 +96,14 @@ public:
signals:
void finished(bool success); // For testing.
-protected:
- virtual void handleStateUpdate() = 0;
+private:
+ void updateRunActions();
+ void handleStateUpdate();
void setToolBusy(bool busy);
+
void initDiagnosticView();
+ void loadDiagnosticsFromFiles();
ClangToolsDiagnosticModel *m_diagnosticModel = nullptr;
QPointer<Debugger::DetailedErrorView> m_diagnosticView;
@@ -93,6 +114,19 @@ protected:
bool m_running = false;
bool m_toolBusy = false;
+ DiagnosticFilterModel *m_diagnosticFilterModel = nullptr;
+
+ Utils::FancyLineEdit *m_filterLineEdit = nullptr;
+ QToolButton *m_applyFixitsButton = nullptr;
+
+ QAction *m_goBack = nullptr;
+ QAction *m_goNext = nullptr;
+ QAction *m_loadExported = nullptr;
+ QAction *m_clear = nullptr;
+ QAction *m_expandCollapse = nullptr;
+
+ Utils::Perspective m_perspective{ClangTidyClazyPerspectiveId, tr("Clang-Tidy and Clazy")};
+
private:
const QString m_name;
};
diff --git a/src/plugins/clangtools/clangtoolruncontrol.cpp b/src/plugins/clangtools/clangtoolruncontrol.cpp
index 9581fef4eb..2af11aa7ef 100644
--- a/src/plugins/clangtools/clangtoolruncontrol.cpp
+++ b/src/plugins/clangtools/clangtoolruncontrol.cpp
@@ -26,7 +26,6 @@
#include "clangtoolruncontrol.h"
#include "clangtidyclazyrunner.h"
-#include "clangtidyclazytool.h"
#include "clangtool.h"
#include "clangtoolslogfilereader.h"
#include "clangtoolsprojectsettings.h"
@@ -119,7 +118,7 @@ namespace Internal {
static ClangTool *tool()
{
- return ClangTidyClazyTool::instance();
+ return ClangTool::instance();
}
class ProjectBuilder : public RunWorker
diff --git a/src/plugins/clangtools/clangtools.pro b/src/plugins/clangtools/clangtools.pro
index 49d4cf83a5..6173e2eec1 100644
--- a/src/plugins/clangtools/clangtools.pro
+++ b/src/plugins/clangtools/clangtools.pro
@@ -21,7 +21,6 @@ SOURCES += \
clangtoolsdiagnosticview.cpp \
clangtoolsprojectsettingswidget.cpp \
clangtidyclazyrunner.cpp \
- clangtidyclazytool.cpp \
clangtool.cpp \
clangtoolruncontrol.cpp \
clangtoolrunner.cpp \
@@ -42,7 +41,6 @@ HEADERS += \
clangtoolsdiagnosticview.h \
clangtoolsprojectsettingswidget.h \
clangtidyclazyrunner.h \
- clangtidyclazytool.h \
clangtool.h \
clangtoolruncontrol.h \
clangtoolrunner.h \
diff --git a/src/plugins/clangtools/clangtools.qbs b/src/plugins/clangtools/clangtools.qbs
index e0742256d5..daca2934c1 100644
--- a/src/plugins/clangtools/clangtools.qbs
+++ b/src/plugins/clangtools/clangtools.qbs
@@ -39,8 +39,6 @@ QtcPlugin {
"clangselectablefilesdialog.ui",
"clangtidyclazyrunner.cpp",
"clangtidyclazyrunner.h",
- "clangtidyclazytool.cpp",
- "clangtidyclazytool.h",
"clangtool.cpp",
"clangtool.h",
"clangtoolruncontrol.cpp",
diff --git a/src/plugins/clangtools/clangtoolsplugin.cpp b/src/plugins/clangtools/clangtoolsplugin.cpp
index b432891110..12031dc589 100644
--- a/src/plugins/clangtools/clangtoolsplugin.cpp
+++ b/src/plugins/clangtools/clangtoolsplugin.cpp
@@ -25,10 +25,10 @@
#include "clangtoolsplugin.h"
+#include "clangtool.h"
#include "clangtoolsconstants.h"
-#include "clangtoolsprojectsettingswidget.h"
-#include "clangtidyclazytool.h"
#include "clangtoolsprojectsettings.h"
+#include "clangtoolsprojectsettingswidget.h"
#include "settingswidget.h"
#ifdef WITH_TESTS
@@ -98,7 +98,7 @@ private:
class ClangToolsPluginPrivate
{
public:
- ClangTidyClazyTool clangTidyClazyTool;
+ ClangTool clangTool;
ClangToolsOptionsPage optionsPage;
ClangToolsProjectSettingsManager settingsManager;
};
@@ -115,9 +115,8 @@ bool ClangToolsPlugin::initialize(const QStringList &arguments, QString *errorSt
d = new ClangToolsPluginPrivate;
- ActionManager::registerAction(d->clangTidyClazyTool.startAction(),
- Constants::RUN_ON_PROJECT);
- ActionManager::registerAction(d->clangTidyClazyTool.startOnCurrentFileAction(),
+ ActionManager::registerAction(d->clangTool.startAction(), Constants::RUN_ON_PROJECT);
+ ActionManager::registerAction(d->clangTool.startOnCurrentFileAction(),
Constants::RUN_ON_CURRENT_FILE);
auto panelFactory = new ProjectPanelFactory();
diff --git a/src/plugins/clangtools/clangtoolspreconfiguredsessiontests.cpp b/src/plugins/clangtools/clangtoolspreconfiguredsessiontests.cpp
index 5d711a8aef..2ed19354f2 100644
--- a/src/plugins/clangtools/clangtoolspreconfiguredsessiontests.cpp
+++ b/src/plugins/clangtools/clangtoolspreconfiguredsessiontests.cpp
@@ -25,8 +25,8 @@
#include "clangtoolspreconfiguredsessiontests.h"
+#include "clangtool.h"
#include "clangtoolsdiagnostic.h"
-#include "clangtidyclazytool.h"
#include "clangtoolsutils.h"
#include <coreplugin/icore.h>
@@ -121,13 +121,13 @@ void PreconfiguredSessionTests::testPreconfiguredSession()
QVERIFY(switchToProjectAndTarget(project, target));
- ClangTidyClazyTool::instance()->startTool(ClangTidyClazyTool::FileSelection::AllFiles);
- QSignalSpy waitUntilAnalyzerFinished(ClangTidyClazyTool::instance(), SIGNAL(finished(bool)));
+ ClangTool::instance()->startTool(ClangTool::FileSelection::AllFiles);
+ QSignalSpy waitUntilAnalyzerFinished(ClangTool::instance(), SIGNAL(finished(bool)));
QVERIFY(waitUntilAnalyzerFinished.wait(30000));
const QList<QVariant> arguments = waitUntilAnalyzerFinished.takeFirst();
const bool analyzerFinishedSuccessfully = arguments.first().toBool();
QVERIFY(analyzerFinishedSuccessfully);
- QCOMPARE(ClangTidyClazyTool::instance()->diagnostics().count(), 0);
+ QCOMPARE(ClangTool::instance()->diagnostics().count(), 0);
}
static QList<Project *> validProjects(const QList<Project *> projectsOfSession)
diff --git a/src/plugins/clangtools/clangtoolsprojectsettingswidget.cpp b/src/plugins/clangtools/clangtoolsprojectsettingswidget.cpp
index 765cd34012..c5b7c53a68 100644
--- a/src/plugins/clangtools/clangtoolsprojectsettingswidget.cpp
+++ b/src/plugins/clangtools/clangtoolsprojectsettingswidget.cpp
@@ -26,7 +26,7 @@
#include "clangtoolsprojectsettingswidget.h"
#include "ui_clangtoolsprojectsettingswidget.h"
-#include "clangtidyclazytool.h"
+#include "clangtool.h"
#include "clangtoolsconstants.h"
#include "clangtoolsprojectsettings.h"
@@ -90,7 +90,7 @@ ProjectSettingsWidget::ProjectSettingsWidget(ProjectExplorer::Project *project,
});
connect(m_ui->gotoAnalyzerModeLabel, &QLabel::linkActivated, [](const QString &){
- ClangTidyClazyTool::instance()->selectPerspective();
+ ClangTool::instance()->selectPerspective();
});
// Run options
diff --git a/src/plugins/clangtools/clangtoolsunittests.cpp b/src/plugins/clangtools/clangtoolsunittests.cpp
index 5a034c61b6..79b7bfcc94 100644
--- a/src/plugins/clangtools/clangtoolsunittests.cpp
+++ b/src/plugins/clangtools/clangtoolsunittests.cpp
@@ -25,7 +25,7 @@
#include "clangtoolsunittests.h"
-#include "clangtidyclazytool.h"
+#include "clangtool.h"
#include "clangtoolsdiagnostic.h"
#include "clangtoolssettings.h"
#include "clangtoolsutils.h"
@@ -109,7 +109,7 @@ void ClangToolsUnitTests::testProject()
CppTools::Tests::ProjectOpenerAndCloser projectManager;
const CppTools::ProjectInfo projectInfo = projectManager.open(projectFilePath, true);
QVERIFY(projectInfo.isValid());
- ClangTool *tool = ClangTidyClazyTool::instance();
+ ClangTool *tool = ClangTool::instance();
// Change configs
QSharedPointer<CppTools::CppCodeModelSettings> cppToolsSettings = CppTools::codeModelSettings();
@@ -136,7 +136,7 @@ void ClangToolsUnitTests::testProject()
clangToolsSettings->setRunSettings(runSettings);
clangToolsSettings->writeSettings();
- tool->startTool(ClangTidyClazyTool::FileSelection::AllFiles);
+ tool->startTool(ClangTool::FileSelection::AllFiles);
QSignalSpy waiter(tool, SIGNAL(finished(bool)));
QVERIFY(waiter.wait(30000));