aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/plugins/clangcodemodel/clangeditordocumentprocessor.cpp13
-rw-r--r--src/plugins/clangtools/clangstaticanalyzertool.cpp5
-rw-r--r--src/plugins/clangtools/clangstaticanalyzertool.h3
-rw-r--r--src/plugins/clangtools/clangtidyclazyruncontrol.cpp66
-rw-r--r--src/plugins/clangtools/clangtidyclazyruncontrol.h47
-rw-r--r--src/plugins/clangtools/clangtidyclazyrunner.cpp101
-rw-r--r--src/plugins/clangtools/clangtidyclazyrunner.h47
-rw-r--r--src/plugins/clangtools/clangtidyclazytool.cpp196
-rw-r--r--src/plugins/clangtools/clangtidyclazytool.h58
-rw-r--r--src/plugins/clangtools/clangtool.h1
-rw-r--r--src/plugins/clangtools/clangtoolruncontrol.cpp5
-rw-r--r--src/plugins/clangtools/clangtoolruncontrol.h2
-rw-r--r--src/plugins/clangtools/clangtoolrunner.cpp2
-rw-r--r--src/plugins/clangtools/clangtoolrunner.h2
-rw-r--r--src/plugins/clangtools/clangtools.pro10
-rw-r--r--src/plugins/clangtools/clangtools.qbs14
-rw-r--r--src/plugins/clangtools/clangtoolsdiagnosticmodel.cpp2
-rw-r--r--src/plugins/clangtools/clangtoolslogfilereader.cpp173
-rw-r--r--src/plugins/clangtools/clangtoolslogfilereader.h5
-rw-r--r--src/plugins/clangtools/clangtoolsplugin.cpp2
-rw-r--r--src/plugins/cpptools/clangdiagnosticconfig.cpp13
-rw-r--r--src/plugins/cpptools/clangdiagnosticconfig.h2
-rw-r--r--tests/auto/clangtools/clangtoolslogfilereader/clangtoolslogfilereader.pro3
-rw-r--r--tests/auto/clangtools/clangtoolslogfilereader/clangtoolslogfilereader.qbs10
24 files changed, 765 insertions, 17 deletions
diff --git a/src/plugins/clangcodemodel/clangeditordocumentprocessor.cpp b/src/plugins/clangcodemodel/clangeditordocumentprocessor.cpp
index 05e5f37fa7..b9ac36fd76 100644
--- a/src/plugins/clangcodemodel/clangeditordocumentprocessor.cpp
+++ b/src/plugins/clangcodemodel/clangeditordocumentprocessor.cpp
@@ -528,17 +528,12 @@ private:
if (tidyMode == Mode::Disabled)
return;
- QString checks;
- if (tidyMode == Mode::ChecksPrefixList) {
- checks = QStringLiteral("-*") + diagnosticConfig.clangTidyChecksPrefixes();
- } else if (tidyMode == Mode::ChecksString) {
- checks = diagnosticConfig.clangTidyChecksString();
- checks = checks.simplified();
- checks.replace(" ", "");
- }
-
addXclangArg("-add-plugin", "clang-tidy");
+ if (tidyMode == Mode::File)
+ return;
+
+ const QString checks = diagnosticConfig.clangTidyChecks();
if (!checks.isEmpty())
addXclangArg("-plugin-arg-clang-tidy", "-checks=" + checks);
}
diff --git a/src/plugins/clangtools/clangstaticanalyzertool.cpp b/src/plugins/clangtools/clangstaticanalyzertool.cpp
index a3873e16ca..651d794a27 100644
--- a/src/plugins/clangtools/clangstaticanalyzertool.cpp
+++ b/src/plugins/clangtools/clangstaticanalyzertool.cpp
@@ -226,10 +226,11 @@ void ClangStaticAnalyzerTool::handleStateUpdate()
Debugger::showPermanentStatusMessage(message);
}
-QList<Diagnostic> ClangStaticAnalyzerTool::read(const QString &filePath,
+QList<Diagnostic> ClangStaticAnalyzerTool::read(const QString &,
+ const QString &logFilePath,
QString *errorMessage) const
{
- return LogFileReader::readPlist(filePath, errorMessage);
+ return LogFileReader::readPlist(logFilePath, errorMessage);
}
} // namespace Internal
diff --git a/src/plugins/clangtools/clangstaticanalyzertool.h b/src/plugins/clangtools/clangstaticanalyzertool.h
index 8816e36a3c..e44330eddc 100644
--- a/src/plugins/clangtools/clangstaticanalyzertool.h
+++ b/src/plugins/clangtools/clangstaticanalyzertool.h
@@ -49,7 +49,8 @@ public:
void startTool() final;
- QList<Diagnostic> read(const QString &filePath,
+ QList<Diagnostic> read(const QString &,
+ const QString &logFilePath,
QString *errorMessage) const final;
private:
diff --git a/src/plugins/clangtools/clangtidyclazyruncontrol.cpp b/src/plugins/clangtools/clangtidyclazyruncontrol.cpp
new file mode 100644
index 0000000000..a3ec062c22
--- /dev/null
+++ b/src/plugins/clangtools/clangtidyclazyruncontrol.cpp
@@ -0,0 +1,66 @@
+/****************************************************************************
+**
+** 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 "clangtidyclazyruncontrol.h"
+
+#include "clangtidyclazyrunner.h"
+#include "clangtidyclazytool.h"
+
+using namespace ProjectExplorer;
+
+namespace ClangTools {
+namespace Internal {
+
+ClangTidyClazyRunControl::ClangTidyClazyRunControl(RunControl *runControl, Target *target)
+ : ClangToolRunControl(runControl, target)
+{
+ setDisplayName("ClangTidyClazyRunner");
+ init();
+}
+
+ClangToolRunner *ClangTidyClazyRunControl::createRunner()
+{
+ QTC_ASSERT(!m_clangExecutable.isEmpty(), return 0);
+ QTC_ASSERT(!m_clangLogFileDir.isEmpty(), return 0);
+
+ auto runner = new ClangTidyClazyRunner(m_clangExecutable,
+ m_clangLogFileDir,
+ m_environment,
+ this);
+ connect(runner, &ClangTidyClazyRunner::finishedWithSuccess,
+ this, &ClangTidyClazyRunControl::onRunnerFinishedWithSuccess);
+ connect(runner, &ClangTidyClazyRunner::finishedWithFailure,
+ this, &ClangTidyClazyRunControl::onRunnerFinishedWithFailure);
+ return runner;
+}
+
+ClangTool *ClangTidyClazyRunControl::tool()
+{
+ return ClangTidyClazyTool::instance();
+}
+
+} // namespace Internal
+} // namespace ClangTools
+
diff --git a/src/plugins/clangtools/clangtidyclazyruncontrol.h b/src/plugins/clangtools/clangtidyclazyruncontrol.h
new file mode 100644
index 0000000000..59073608fe
--- /dev/null
+++ b/src/plugins/clangtools/clangtidyclazyruncontrol.h
@@ -0,0 +1,47 @@
+/****************************************************************************
+**
+** 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 "clangtoolruncontrol.h"
+
+namespace ClangTools {
+namespace Internal {
+
+class ClangTidyClazyRunControl final : public ClangToolRunControl
+{
+ Q_OBJECT
+
+public:
+ ClangTidyClazyRunControl(ProjectExplorer::RunControl *runControl,
+ ProjectExplorer::Target *target);
+
+protected:
+ ClangToolRunner *createRunner() final;
+ ClangTool *tool() final;
+};
+
+} // namespace Internal
+} // namespace ClangTools
diff --git a/src/plugins/clangtools/clangtidyclazyrunner.cpp b/src/plugins/clangtools/clangtidyclazyrunner.cpp
new file mode 100644
index 0000000000..c3418525c4
--- /dev/null
+++ b/src/plugins/clangtools/clangtidyclazyrunner.cpp
@@ -0,0 +1,101 @@
+/****************************************************************************
+**
+** 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 "clangtidyclazyrunner.h"
+
+#include <cpptools/cppcodemodelsettings.h>
+#include <cpptools/cpptoolsreuse.h>
+
+#include <utils/synchronousprocess.h>
+
+#include <QDebug>
+#include <QDir>
+#include <QLoggingCategory>
+
+static Q_LOGGING_CATEGORY(LOG, "qtc.clangtools.runner")
+
+namespace ClangTools {
+namespace Internal {
+
+ClangTidyClazyRunner::ClangTidyClazyRunner(const QString &clangExecutable,
+ const QString &clangLogFileDir,
+ const Utils::Environment &environment,
+ QObject *parent)
+ : ClangToolRunner(clangExecutable,
+ clangLogFileDir,
+ environment,
+ tr("Clang-Tidy and Clazy"),
+ parent)
+{
+}
+
+static void addXclangArg(QStringList &arguments,
+ const QString &argName,
+ const QString &argValue = QString())
+{
+ arguments << QString("-Xclang")
+ << argName;
+ if (!argValue.isEmpty()) {
+ arguments << QString("-Xclang")
+ << argValue;
+ }
+}
+
+QStringList ClangTidyClazyRunner::constructCommandLineArguments(const QStringList &options)
+{
+ using namespace CppTools;
+ QStringList arguments;
+
+ if (LOG().isDebugEnabled())
+ arguments << QString("-v");
+
+ arguments << QString("-fsyntax-only")
+ << QString("-serialize-diagnostics")
+ << QString(m_logFile);
+
+ const ClangDiagnosticConfig config = CppTools::codeModelSettings()->clangDiagnosticConfig();
+
+ const ClangDiagnosticConfig::TidyMode tidyMode = config.clangTidyMode();
+ if (tidyMode != ClangDiagnosticConfig::TidyMode::Disabled) {
+ addXclangArg(arguments, QString("-add-plugin"), QString("clang-tidy"));
+ if (tidyMode != ClangDiagnosticConfig::TidyMode::File) {
+ const QString tidyChecks = config.clangTidyChecks();
+ addXclangArg(arguments, QString("-plugin-arg-clang-tidy"), "-checks=" + tidyChecks);
+ }
+ }
+
+ const QString clazyChecks = config.clazyChecks();
+ if (!clazyChecks.isEmpty()) {
+ addXclangArg(arguments, QString("-add-plugin"), QString("clang-lazy"));
+ addXclangArg(arguments, QString("-plugin-arg-clang-lazy"), config.clazyChecks());
+ }
+
+ arguments += options;
+ arguments << QDir::toNativeSeparators(filePath());
+ return arguments;
+}
+
+} // namespace Internal
+} // namespace ClangTools
diff --git a/src/plugins/clangtools/clangtidyclazyrunner.h b/src/plugins/clangtools/clangtidyclazyrunner.h
new file mode 100644
index 0000000000..e723653192
--- /dev/null
+++ b/src/plugins/clangtools/clangtidyclazyrunner.h
@@ -0,0 +1,47 @@
+/****************************************************************************
+**
+** 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 "clangtoolrunner.h"
+
+namespace ClangTools {
+namespace Internal {
+
+class ClangTidyClazyRunner final : public ClangToolRunner
+{
+ Q_OBJECT
+
+public:
+ ClangTidyClazyRunner(const QString &clangExecutable,
+ const QString &clangLogFileDir,
+ const Utils::Environment &environment,
+ QObject *parent = nullptr);
+protected:
+ QStringList constructCommandLineArguments(const QStringList &options) final;
+};
+
+} // namespace Internal
+} // namespace ClangTools
diff --git a/src/plugins/clangtools/clangtidyclazytool.cpp b/src/plugins/clangtools/clangtidyclazytool.cpp
new file mode 100644
index 0000000000..ddd1cab9e2
--- /dev/null
+++ b/src/plugins/clangtools/clangtidyclazytool.cpp
@@ -0,0 +1,196 @@
+/****************************************************************************
+**
+** 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 "clangtoolsconstants.h"
+#include "clangtoolsdiagnosticmodel.h"
+#include "clangtoolslogfilereader.h"
+#include "clangtidyclazyruncontrol.h"
+
+#include <coreplugin/actionmanager/actioncontainer.h>
+#include <coreplugin/actionmanager/actionmanager.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/utilsicons.h>
+
+#include <QAction>
+
+using namespace Core;
+using namespace Debugger;
+using namespace ProjectExplorer;
+using namespace Utils;
+
+namespace ClangTools {
+namespace Internal {
+
+static ClangTidyClazyTool *s_instance;
+
+ClangTidyClazyTool::ClangTidyClazyTool()
+ : ClangTool("Clang-Tidy and Clazy")
+{
+ setObjectName("ClangTidyClazyTool");
+ s_instance = this;
+
+ m_diagnosticView = new Debugger::DetailedErrorView;
+ initDiagnosticView();
+ m_diagnosticView->setModel(m_diagnosticModel);
+ m_diagnosticView->setObjectName(QLatin1String("ClangTidyClazyIssuesView"));
+ m_diagnosticView->setWindowTitle(tr("Clang-Tidy and Clazy Issues"));
+
+ 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 errors and warnings.");
+
+ Debugger::registerPerspective(ClangTidyClazyPerspectiveId, new Perspective(
+ tr("Clang-Tidy and Clazy"),
+ {{ClangTidyClazyDockId, m_diagnosticView, {}, Perspective::SplitVertical}}
+ ));
+
+ auto *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, &ClangTidyClazyTool::startTool);
+ QObject::connect(m_startAction, &QAction::triggered, action, &QAction::triggered);
+ QObject::connect(m_startAction, &QAction::changed, action, [action, this] {
+ action->setEnabled(m_startAction->isEnabled());
+ });
+
+ ToolbarDescription tidyClazyToolbar;
+ tidyClazyToolbar.addAction(m_startAction);
+ tidyClazyToolbar.addAction(m_stopAction);
+ Debugger::registerToolbar(ClangTidyClazyPerspectiveId, tidyClazyToolbar);
+
+ updateRunActions();
+
+ connect(ProjectExplorerPlugin::instance(), &ProjectExplorerPlugin::updateRunActions,
+ this, &ClangTidyClazyTool::updateRunActions);
+
+}
+
+ClangTidyClazyTool *ClangTidyClazyTool::instance()
+{
+ return s_instance;
+}
+
+void ClangTidyClazyTool::startTool()
+{
+ auto runControl = new RunControl(nullptr, Constants::CLANGTIDYCLAZY_RUN_MODE);
+ runControl->setDisplayName(tr("Clang-Tidy and Clazy"));
+ runControl->setIcon(ProjectExplorer::Icons::ANALYZER_START_SMALL_TOOLBAR);
+
+ Project *project = SessionManager::startupProject();
+ QTC_ASSERT(project, return);
+
+ auto clangTool = new ClangTidyClazyRunControl(runControl, project->activeTarget());
+
+ 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);
+ });
+
+ Debugger::selectPerspective(ClangTidyClazyPerspectiveId);
+
+ m_diagnosticModel->clear();
+ setToolBusy(true);
+ m_running = true;
+ handleStateUpdate();
+ updateRunActions();
+
+ ProjectExplorerPlugin::startRunControl(runControl);
+}
+
+void ClangTidyClazyTool::updateRunActions()
+{
+ if (m_toolBusy) {
+ m_startAction->setEnabled(false);
+ QString tooltipText = tr("Clang-Tidy and Clazy are still running.");
+ m_startAction->setToolTip(tooltipText);
+ m_stopAction->setEnabled(true);
+ } else {
+ QString toolTip = tr("Start Clang-Tidy and Clazy.");
+ 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)
+ && ToolChainKitInformation::toolChain(target->kit(), cxx);
+ if (!canRun)
+ toolTip = tr("This is not a C++ project.");
+
+ m_startAction->setToolTip(toolTip);
+ m_startAction->setEnabled(canRun);
+ m_stopAction->setEnabled(false);
+ }
+}
+
+void ClangTidyClazyTool::handleStateUpdate()
+{
+ QTC_ASSERT(m_diagnosticModel, return);
+
+ const int issuesFound = m_diagnosticModel->diagnostics().count();
+ QString message;
+ if (m_running)
+ message = tr("Clang-Tidy and Clazy are running.");
+ else
+ message = tr("Clang-Tidy and Clazy finished.");
+
+ message += QLatin1Char(' ');
+ if (issuesFound == 0)
+ message += tr("No issues found.");
+ else
+ message += tr("%n issues found.", nullptr, issuesFound);
+
+ Debugger::showPermanentStatusMessage(message);
+}
+
+QList<Diagnostic> ClangTidyClazyTool::read(const QString &filePath,
+ const QString &logFilePath,
+ QString *errorMessage) const
+{
+ return LogFileReader::readSerialized(filePath, logFilePath, errorMessage);
+}
+
+} // namespace Internal
+} // namespace ClangTools
+
diff --git a/src/plugins/clangtools/clangtidyclazytool.h b/src/plugins/clangtools/clangtidyclazytool.h
new file mode 100644
index 0000000000..e9e998b914
--- /dev/null
+++ b/src/plugins/clangtools/clangtidyclazytool.h
@@ -0,0 +1,58 @@
+/****************************************************************************
+**
+** 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"
+
+namespace ClangTools {
+namespace Internal {
+
+const char ClangTidyClazyPerspectiveId[] = "ClangTidyClazy.Perspective";
+const char ClangTidyClazyDockId[] = "ClangTidyClazy.Dock";
+
+class ClangTidyClazyTool final : public ClangTool
+{
+ Q_OBJECT
+
+public:
+ ClangTidyClazyTool();
+
+ static ClangTidyClazyTool *instance();
+
+ void startTool() final;
+
+ QList<Diagnostic> read(const QString &filePath,
+ const QString &logFilePath,
+ QString *errorMessage) const final;
+
+private:
+ void handleStateUpdate() final;
+
+ void updateRunActions();
+};
+
+} // namespace Internal
+} // namespace ClangTools
diff --git a/src/plugins/clangtools/clangtool.h b/src/plugins/clangtools/clangtool.h
index b0fb84b68c..e7f11bb0cc 100644
--- a/src/plugins/clangtools/clangtool.h
+++ b/src/plugins/clangtools/clangtool.h
@@ -47,6 +47,7 @@ public:
virtual void startTool() = 0;
virtual QList<Diagnostic> read(const QString &filePath,
+ const QString &logFilePath,
QString *errorMessage) const = 0;
// For testing.
diff --git a/src/plugins/clangtools/clangtoolruncontrol.cpp b/src/plugins/clangtools/clangtoolruncontrol.cpp
index 7c71c31da9..4e0b609dd1 100644
--- a/src/plugins/clangtools/clangtoolruncontrol.cpp
+++ b/src/plugins/clangtools/clangtoolruncontrol.cpp
@@ -351,12 +351,13 @@ void ClangToolRunControl::analyzeNextFile()
Utils::StdOutFormat);
}
-void ClangToolRunControl::onRunnerFinishedWithSuccess(const QString &logFilePath)
+void ClangToolRunControl::onRunnerFinishedWithSuccess(const QString &filePath,
+ const QString &logFilePath)
{
qCDebug(LOG) << "onRunnerFinishedWithSuccess:" << logFilePath;
QString errorMessage;
- const QList<Diagnostic> diagnostics = tool()->read(logFilePath, &errorMessage);
+ const QList<Diagnostic> diagnostics = tool()->read(filePath, logFilePath, &errorMessage);
if (!errorMessage.isEmpty()) {
qCDebug(LOG) << "onRunnerFinishedWithSuccess: Error reading log file:" << errorMessage;
const QString filePath = qobject_cast<ClangToolRunner *>(sender())->filePath();
diff --git a/src/plugins/clangtools/clangtoolruncontrol.h b/src/plugins/clangtools/clangtoolruncontrol.h
index 195a215090..c8339a40bc 100644
--- a/src/plugins/clangtools/clangtoolruncontrol.h
+++ b/src/plugins/clangtools/clangtoolruncontrol.h
@@ -73,7 +73,7 @@ protected:
virtual ClangToolRunner *createRunner() = 0;
- void onRunnerFinishedWithSuccess(const QString &logFilePath);
+ void onRunnerFinishedWithSuccess(const QString &filePath, const QString &logFilePath);
void onRunnerFinishedWithFailure(const QString &errorMessage, const QString &errorDetails);
private:
diff --git a/src/plugins/clangtools/clangtoolrunner.cpp b/src/plugins/clangtools/clangtoolrunner.cpp
index 6de55f85b5..79b027a930 100644
--- a/src/plugins/clangtools/clangtoolrunner.cpp
+++ b/src/plugins/clangtools/clangtoolrunner.cpp
@@ -121,7 +121,7 @@ void ClangToolRunner::onProcessFinished(int exitCode, QProcess::ExitStatus exitS
if (exitCode == 0) {
qCDebug(LOG).noquote() << "Output:\n" << Utils::SynchronousProcess::normalizeNewlines(
QString::fromLocal8Bit(m_processOutput));
- emit finishedWithSuccess(actualLogFile());
+ emit finishedWithSuccess(m_filePath, actualLogFile());
}
else
emit finishedWithFailure(finishedWithBadExitCode(m_name, exitCode), processCommandlineAndOutput());
diff --git a/src/plugins/clangtools/clangtoolrunner.h b/src/plugins/clangtools/clangtoolrunner.h
index 9cc3ee3185..5473890dd8 100644
--- a/src/plugins/clangtools/clangtoolrunner.h
+++ b/src/plugins/clangtools/clangtoolrunner.h
@@ -56,7 +56,7 @@ public:
signals:
void started();
- void finishedWithSuccess(const QString &logFilePath);
+ void finishedWithSuccess(const QString &filePath, const QString &logFilePath);
void finishedWithFailure(const QString &errorMessage, const QString &errorDetails);
protected:
diff --git a/src/plugins/clangtools/clangtools.pro b/src/plugins/clangtools/clangtools.pro
index 7b8a194a1b..021d31b5c6 100644
--- a/src/plugins/clangtools/clangtools.pro
+++ b/src/plugins/clangtools/clangtools.pro
@@ -1,4 +1,8 @@
include(../../qtcreatorplugin.pri)
+include(../../shared/clang/clang_installation.pri)
+
+LIBS += $$LIBCLANG_LIBS
+INCLUDEPATH += $$LLVM_INCLUDEPATH
SOURCES += \
clangstaticanalyzerconfigwidget.cpp \
@@ -9,6 +13,9 @@ SOURCES += \
clangstaticanalyzerruncontrol.cpp \
clangstaticanalyzerrunner.cpp \
clangstaticanalyzertool.cpp \
+ clangtidyclazyruncontrol.cpp \
+ clangtidyclazyrunner.cpp \
+ clangtidyclazytool.cpp \
clangtool.cpp \
clangtoolruncontrol.cpp \
clangtoolrunner.cpp \
@@ -28,6 +35,9 @@ HEADERS += \
clangstaticanalyzerruncontrol.h \
clangstaticanalyzerrunner.h \
clangstaticanalyzertool.h \
+ clangtidyclazyruncontrol.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 f744e4c604..8da24c41c4 100644
--- a/src/plugins/clangtools/clangtools.qbs
+++ b/src/plugins/clangtools/clangtools.qbs
@@ -10,6 +10,7 @@ QtcPlugin {
Depends { name: "ProjectExplorer" }
Depends { name: "QtcSsh" }
Depends { name: "Utils" }
+ Depends { name: "libclang"; required: false }
Depends { name: "Qt.widgets" }
@@ -18,6 +19,13 @@ QtcPlugin {
"QmakeProjectManager",
]
+ condition: libclang.present
+
+ cpp.includePaths: base.concat(libclang.llvmIncludeDir)
+ cpp.libraryPaths: base.concat(libclang.llvmLibDir)
+ cpp.dynamicLibraries: base.concat(libclang.llvmLibs)
+ cpp.rpaths: base.concat(libclang.llvmLibDir)
+
files: [
"clangstaticanalyzerconfigwidget.cpp",
"clangstaticanalyzerconfigwidget.h",
@@ -37,6 +45,12 @@ QtcPlugin {
"clangstaticanalyzerrunner.h",
"clangstaticanalyzertool.cpp",
"clangstaticanalyzertool.h",
+ "clangtidyclazyruncontrol.cpp",
+ "clangtidyclazyruncontrol.h",
+ "clangtidyclazyrunner.cpp",
+ "clangtidyclazyrunner.h",
+ "clangtidyclazytool.cpp",
+ "clangtidyclazytool.h",
"clangtool.cpp",
"clangtool.h",
"clangtoolruncontrol.cpp",
diff --git a/src/plugins/clangtools/clangtoolsdiagnosticmodel.cpp b/src/plugins/clangtools/clangtoolsdiagnosticmodel.cpp
index ac10caf268..2d6fb001b2 100644
--- a/src/plugins/clangtools/clangtoolsdiagnosticmodel.cpp
+++ b/src/plugins/clangtools/clangtoolsdiagnosticmodel.cpp
@@ -298,6 +298,8 @@ QVariant ExplainingStepItem::data(int column, int role) const
}
case Qt::ToolTipRole:
return createExplainingStepToolTipString(m_step);
+ case Qt::DecorationRole:
+ return (m_step.message.startsWith("fix-it:")) ? iconData("fix-it") : QVariant();
default:
return QVariant();
}
diff --git a/src/plugins/clangtools/clangtoolslogfilereader.cpp b/src/plugins/clangtools/clangtoolslogfilereader.cpp
index 22e4b6f161..23bda8a8d5 100644
--- a/src/plugins/clangtools/clangtoolslogfilereader.cpp
+++ b/src/plugins/clangtools/clangtoolslogfilereader.cpp
@@ -33,8 +33,13 @@
#include <QRegularExpression>
#include <QXmlStreamReader>
+#include <utils/executeondestruction.h>
+#include <utils/fileutils.h>
+#include <utils/hostosinfo.h>
#include <utils/qtcassert.h>
+#include <clang-c/Index.h>
+
namespace ClangTools {
namespace Internal {
@@ -74,6 +79,12 @@ private:
QList<Diagnostic> m_diagnostics;
};
+class ClangSerializedDiagnosticsReader
+{
+public:
+ QList<Diagnostic> read(const QString &filePath, const QString &logFilePath);
+};
+
static bool checkFilePath(const QString &filePath, QString *errorMessage)
{
QFileInfo fi(filePath);
@@ -133,6 +144,16 @@ QList<Diagnostic> LogFileReader::readPlist(const QString &filePath, QString *err
}
}
+QList<Diagnostic> LogFileReader::readSerialized(const QString &filePath, const QString &logFilePath,
+ QString *errorMessage)
+{
+ if (!checkFilePath(filePath, errorMessage))
+ return QList<Diagnostic>();
+
+ ClangSerializedDiagnosticsReader reader;
+ return reader.read(filePath, logFilePath);
+}
+
ClangStaticAnalyzerLogFileReader::ClangStaticAnalyzerLogFileReader(const QString &filePath)
: m_filePath(filePath)
{
@@ -390,5 +411,157 @@ int ClangStaticAnalyzerLogFileReader::readInteger(bool *convertedSuccessfully)
return -1;
}
+static QString fromCXString(CXString &&cxString)
+{
+ QString result = QString::fromUtf8(clang_getCString(cxString));
+ clang_disposeString(cxString);
+ return result;
+}
+
+static Debugger::DiagnosticLocation diagLocationFromSourceLocation(CXSourceLocation cxLocation)
+{
+ CXFile file;
+ unsigned line;
+ unsigned column;
+ clang_getSpellingLocation(cxLocation, &file, &line, &column, nullptr);
+
+ Debugger::DiagnosticLocation location;
+ location.filePath = fromCXString(clang_getFileName(file));
+ location.line = line;
+ location.column = column;
+ return location;
+}
+
+static QString cxDiagnosticType(const CXDiagnostic cxDiagnostic)
+{
+ const CXDiagnosticSeverity severity = clang_getDiagnosticSeverity(cxDiagnostic);
+ switch (severity) {
+ case CXDiagnostic_Note:
+ return QString("note");
+ case CXDiagnostic_Warning:
+ return QString("warning");
+ case CXDiagnostic_Error:
+ return QString("error");
+ case CXDiagnostic_Fatal:
+ return QString("fatal");
+ case CXDiagnostic_Ignored:
+ return QString("ignored");
+ }
+ return QString("ignored");
+}
+
+static ExplainingStep buildChildDiagnostic(const CXDiagnostic cxDiagnostic)
+{
+ ExplainingStep diagnosticStep;
+ QString type = cxDiagnosticType(cxDiagnostic);
+ if (type == QStringLiteral("ignored"))
+ return diagnosticStep;
+
+ const CXSourceLocation cxLocation = clang_getDiagnosticLocation(cxDiagnostic);
+ diagnosticStep.location = diagLocationFromSourceLocation(cxLocation);
+ diagnosticStep.message = type + ": " + fromCXString(clang_getDiagnosticSpelling(cxDiagnostic));
+ return diagnosticStep;
+}
+
+static bool isInvalidDiagnosticLocation(const Diagnostic &diagnostic, const ExplainingStep &child,
+ const QString &nativeFilePath)
+{
+ // When main file is considered included by itself - this diagnostic has invalid location.
+ // This case usually happens when original diagnostic comes from system header but
+ // has main file name set in the source location instead (which is incorrect).
+ return child.message.indexOf(nativeFilePath) >= 0
+ && child.message.indexOf("in file included from") >= 0
+ && diagnostic.location.filePath == nativeFilePath;
+}
+
+static ExplainingStep buildFixIt(const CXDiagnostic cxDiagnostic, unsigned index)
+{
+ ExplainingStep fixItStep;
+ CXSourceRange cxFixItRange;
+ fixItStep.message = "fix-it: " + fromCXString(clang_getDiagnosticFixIt(cxDiagnostic, index,
+ &cxFixItRange));
+ fixItStep.location = diagLocationFromSourceLocation(clang_getRangeStart(cxFixItRange));
+ fixItStep.ranges.push_back(fixItStep.location);
+ fixItStep.ranges.push_back(diagLocationFromSourceLocation(clang_getRangeEnd(cxFixItRange)));
+ return fixItStep;
+}
+
+static Diagnostic buildDiagnostic(const CXDiagnostic cxDiagnostic, const QString &nativeFilePath)
+{
+ Diagnostic diagnostic;
+ diagnostic.type = cxDiagnosticType(cxDiagnostic);
+ if (diagnostic.type == QStringLiteral("ignored"))
+ return diagnostic;
+
+ const CXSourceLocation cxLocation = clang_getDiagnosticLocation(cxDiagnostic);
+ if (clang_Location_isInSystemHeader(cxLocation))
+ return diagnostic;
+
+ diagnostic.location = diagLocationFromSourceLocation(cxLocation);
+ if (diagnostic.location.filePath != nativeFilePath)
+ return diagnostic;
+
+ CXDiagnosticSet cxChildDiagnostics = clang_getChildDiagnostics(cxDiagnostic);
+ Utils::ExecuteOnDestruction onBuildExit([&]() {
+ clang_disposeDiagnosticSet(cxChildDiagnostics);
+ });
+
+ for (unsigned i = 0; i < clang_getNumDiagnosticsInSet(cxChildDiagnostics); ++i) {
+ CXDiagnostic cxDiagnostic = clang_getDiagnosticInSet(cxChildDiagnostics, i);
+ Utils::ExecuteOnDestruction cleanUpDiagnostic([&]() {
+ clang_disposeDiagnostic(cxDiagnostic);
+ });
+ const ExplainingStep diagnosticStep = buildChildDiagnostic(cxDiagnostic);
+ if (diagnosticStep.isValid())
+ continue;
+
+ if (isInvalidDiagnosticLocation(diagnostic, diagnosticStep, nativeFilePath))
+ return diagnostic;
+
+ diagnostic.explainingSteps.push_back(diagnosticStep);
+ }
+
+ for (unsigned i = 0; i < clang_getDiagnosticNumFixIts(cxDiagnostic); ++i)
+ diagnostic.explainingSteps.push_back(buildFixIt(cxDiagnostic, i));
+
+ diagnostic.description = fromCXString(clang_getDiagnosticSpelling(cxDiagnostic));
+ diagnostic.category = fromCXString(clang_getDiagnosticCategoryText(cxDiagnostic));
+
+ return diagnostic;
+}
+
+QList<Diagnostic> ClangSerializedDiagnosticsReader::read(const QString &filePath,
+ const QString &logFilePath)
+{
+ QList<Diagnostic> list;
+ CXLoadDiag_Error error;
+ CXString errorString;
+
+ CXDiagnosticSet diagnostics = clang_loadDiagnostics(logFilePath.toStdString().c_str(),
+ &error,
+ &errorString);
+ if (error != CXLoadDiag_None || !diagnostics)
+ return list;
+
+ Utils::ExecuteOnDestruction onReadExit([&]() {
+ clang_disposeDiagnosticSet(diagnostics);
+ });
+
+ const QString nativeFilePath = QDir::toNativeSeparators(filePath);
+ for (unsigned i = 0; i < clang_getNumDiagnosticsInSet(diagnostics); ++i) {
+ CXDiagnostic cxDiagnostic = clang_getDiagnosticInSet(diagnostics, i);
+ Utils::ExecuteOnDestruction cleanUpDiagnostic([&]() {
+ clang_disposeDiagnostic(cxDiagnostic);
+ });
+ const Diagnostic diagnostic = buildDiagnostic(cxDiagnostic, nativeFilePath);
+ if (!diagnostic.isValid())
+ continue;
+
+ list.push_back(diagnostic);
+ }
+
+ return list;
+}
+
} // namespace Internal
} // namespace ClangTools
diff --git a/src/plugins/clangtools/clangtoolslogfilereader.h b/src/plugins/clangtools/clangtoolslogfilereader.h
index 9b66dd854c..b93884e345 100644
--- a/src/plugins/clangtools/clangtoolslogfilereader.h
+++ b/src/plugins/clangtools/clangtoolslogfilereader.h
@@ -30,6 +30,8 @@
#include <QList>
#include <QCoreApplication>
+namespace Utils { class FileName; }
+
namespace ClangTools {
namespace Internal {
@@ -38,6 +40,9 @@ class LogFileReader
Q_DECLARE_TR_FUNCTIONS(ClangTools::Internal::LogFileReader)
public:
static QList<Diagnostic> readPlist(const QString &filePath, QString *errorMessage);
+ static QList<Diagnostic> readSerialized(const QString &filePath,
+ const QString &logFilePath,
+ QString *errorMessage);
};
} // namespace Internal
diff --git a/src/plugins/clangtools/clangtoolsplugin.cpp b/src/plugins/clangtools/clangtoolsplugin.cpp
index 9ce1af6de6..0b08ab957b 100644
--- a/src/plugins/clangtools/clangtoolsplugin.cpp
+++ b/src/plugins/clangtools/clangtoolsplugin.cpp
@@ -30,6 +30,7 @@
#include "clangstaticanalyzerprojectsettingswidget.h"
#include "clangstaticanalyzerruncontrol.h"
#include "clangstaticanalyzertool.h"
+#include "clangtidyclazytool.h"
#ifdef WITH_TESTS
#include "clangstaticanalyzerpreconfiguredsessiontests.h"
@@ -104,6 +105,7 @@ class ClangToolsPluginPrivate
{
public:
ClangStaticAnalyzerTool staticAnalyzerTool;
+ ClangTidyClazyTool clangTidyClazyTool;
ClangStaticAnalyzerOptionsPage optionsPage;
};
diff --git a/src/plugins/cpptools/clangdiagnosticconfig.cpp b/src/plugins/cpptools/clangdiagnosticconfig.cpp
index 724f4404e5..c760ed218a 100644
--- a/src/plugins/cpptools/clangdiagnosticconfig.cpp
+++ b/src/plugins/cpptools/clangdiagnosticconfig.cpp
@@ -94,6 +94,19 @@ void ClangDiagnosticConfig::setClangTidyMode(TidyMode mode)
m_clangTidyMode = mode;
}
+QString ClangDiagnosticConfig::clangTidyChecks() const
+{
+ QString checks;
+ if (m_clangTidyMode == TidyMode::ChecksPrefixList) {
+ checks = QStringLiteral("-*") + clangTidyChecksPrefixes();
+ } else if (m_clangTidyMode == TidyMode::ChecksString) {
+ checks = clangTidyChecksString();
+ checks = checks.simplified();
+ checks.replace(" ", "");
+ }
+ return checks;
+}
+
QString ClangDiagnosticConfig::clangTidyChecksPrefixes() const
{
return m_clangTidyChecksPrefixes;
diff --git a/src/plugins/cpptools/clangdiagnosticconfig.h b/src/plugins/cpptools/clangdiagnosticconfig.h
index 36dd9f2dfd..6423aca181 100644
--- a/src/plugins/cpptools/clangdiagnosticconfig.h
+++ b/src/plugins/cpptools/clangdiagnosticconfig.h
@@ -54,6 +54,8 @@ public:
QStringList clangOptions() const;
void setClangOptions(const QStringList &options);
+ QString clangTidyChecks() const;
+
QString clangTidyChecksPrefixes() const;
void setClangTidyChecksPrefixes(const QString &checks);
diff --git a/tests/auto/clangtools/clangtoolslogfilereader/clangtoolslogfilereader.pro b/tests/auto/clangtools/clangtoolslogfilereader/clangtoolslogfilereader.pro
index 5271b5f18e..2a72297f91 100644
--- a/tests/auto/clangtools/clangtoolslogfilereader/clangtoolslogfilereader.pro
+++ b/tests/auto/clangtools/clangtoolslogfilereader/clangtoolslogfilereader.pro
@@ -4,6 +4,9 @@ TARGET = tst_clangtoolslogfilereader
DEFINES += SRCDIR=\\\"$$PWD/\\\"
+LIBS += $$LIBCLANG_LIBS
+INCLUDEPATH += $$LLVM_INCLUDEPATH
+
SOURCES += \
tst_clangtoolslogfilereader.cpp \
$$PLUGINDIR/clangtoolsdiagnostic.cpp \
diff --git a/tests/auto/clangtools/clangtoolslogfilereader/clangtoolslogfilereader.qbs b/tests/auto/clangtools/clangtoolslogfilereader/clangtoolslogfilereader.qbs
index 993733954c..2a1a5b0a25 100644
--- a/tests/auto/clangtools/clangtoolslogfilereader/clangtoolslogfilereader.qbs
+++ b/tests/auto/clangtools/clangtoolslogfilereader/clangtoolslogfilereader.qbs
@@ -3,8 +3,18 @@ import "../clangtoolsautotest.qbs" as ClangToolsAutotest
ClangToolsAutotest {
name: "ClangToolsLogFileReader Autotest"
+
+ Depends { name: "libclang"; required: false }
+
cpp.defines: base.concat('SRCDIR="' + sourceDirectory + '"')
+ condition: libclang.present
+
+ cpp.includePaths: base.concat(libclang.llvmIncludeDir)
+ cpp.libraryPaths: base.concat(libclang.llvmLibDir)
+ cpp.dynamicLibraries: base.concat(libclang.llvmLibs)
+ cpp.rpaths: base.concat(libclang.llvmLibDir)
+
Group {
name: "sources from plugin"
prefix: pluginDir + '/'