diff --git a/CMakeLists.txt b/CMakeLists.txt
index b215ac5ded..24357ba946 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1,84 +1,72 @@
project(kdevclangtidy)
set(VERSION_MAJOR 0)
set(VERSION_MINOR 0)
set(VERSION_PATCH 1)
# KDevplatform dependency version
set(KDEVPLATFORM_VERSION "${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH}")
cmake_minimum_required(VERSION 2.8.12)
find_package (ECM 0.0.9 REQUIRED NO_MODULE)
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${ECM_MODULE_PATH})
include(ECMAddTests)
include(KDEInstallDirs)
include(KDECMakeSettings)
include(KDECompilerSettings)
include(FeatureSummary)
find_package(Qt5 REQUIRED Core Widgets Test)
find_package(KF5 REQUIRED COMPONENTS IconThemes ItemModels ThreadWeaver TextEditor I18n)
find_package(KDevPlatform ${KDEVPLATFORM_VERSION} REQUIRED)
-# find clang-tidy executable and sets it in plugin.h.in
-find_program(CLANG_TIDY_EXEC NAMES "clang-tidy")
-if(NOT CLANG_TIDY_EXEC)
- message(ERROR "clang-tidy program not found")
-else()
- configure_file("${PROJECT_SOURCE_DIR}/src/plugin/plugin.h.in"
- "${PROJECT_SOURCE_DIR}/src/plugin/plugin.h" )
-
- configure_file("${PROJECT_SOURCE_DIR}/res/clangtidyconfig.kcfg.in"
- "${PROJECT_SOURCE_DIR}/res/clangtidyconfig.kcfg" )
-endif()
-
set(CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake ${CMAKE_MODULE_PATH})
include_directories(
${kdevclangtidy_BINARY_DIR}
${kdevclangtidy_SOURCE_DIR}/src
)
set(kdevclangtidy_PART_SRCS
src/debug.cpp
src/job.cpp
src/plugin.cpp
src/config/configgroup.cpp
src/config/perprojectconfigpage.cpp
src/config/clangtidypreferences.cpp
src/parsers/clangtidyparser.cpp
src/parsers/replacementparser.cpp
)
include (cmake/ClangFormatAll.cmake)
ki18n_wrap_ui( kdevclangtidy_PART_SRCS ${kdevclangtidy_PART_UI}
src/config/ui/clangtidysettings.ui
src/config/ui/perprojectconfig.ui
)
kconfig_add_kcfg_files(kdevclangtidy_PART_SRCS res/clangtidyconfig.kcfgc)
kdevplatform_add_plugin(kdevclangtidy JSON res/kdevclangtidy.json SOURCES
${kdevclangtidy_PART_SRCS} ${kdevclangtidy_CONFIG_SRCS})
target_link_libraries(kdevclangtidy
KDev::Interfaces
KDev::Project
KDev::Language
KDev::OutputView
KDev::Util
KDev::Shell
KF5::ConfigCore
KF5::IconThemes
KF5::KIOCore
KF5::WidgetsAddons
KF5::TextEditor
Qt5::Network
)
install(FILES res/kdevclangtidy.rc DESTINATION ${KXMLGUI_INSTALL_DIR}/kdevclangtidy)
add_subdirectory(tests)
feature_summary(WHAT ALL FATAL_ON_MISSING_REQUIRED_PACKAGES)
diff --git a/res/clangtidyconfig.kcfg b/res/clangtidyconfig.kcfg
index e0d0112816..9fb01ae63d 100644
--- a/res/clangtidyconfig.kcfg
+++ b/res/clangtidyconfig.kcfg
@@ -1,14 +1,14 @@
- file:///usr/bin/clang-tidy
+ The full path to the clang-tidy executableThe full path to the clang-tidy executable.
diff --git a/res/clangtidyconfig.kcfg.in b/res/clangtidyconfig.kcfg.in
deleted file mode 100644
index 6f80342b5b..0000000000
--- a/res/clangtidyconfig.kcfg.in
+++ /dev/null
@@ -1,14 +0,0 @@
-
-
-
-
- file://@CLANG_TIDY_EXEC@
-
- The full path to the clang-tidy executable
- The full path to the clang-tidy executable.
-
-
-
diff --git a/src/config/clangtidypreferences.cpp b/src/config/clangtidypreferences.cpp
index 091ab7d809..658c26eeca 100644
--- a/src/config/clangtidypreferences.cpp
+++ b/src/config/clangtidypreferences.cpp
@@ -1,72 +1,72 @@
/*
* This file is part of KDevelop
*
* Copyright 2016 Carlos Nihelton
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
#include "config/clangtidypreferences.h"
#include "clangtidyconfig.h"
#include "config/configgroup.h"
#include "ui_clangtidysettings.h"
#include
using KDevelop::IPlugin;
using ClangTidy::ConfigGroup;
using KDevelop::ConfigPage;
ClangtidyPreferences::ClangtidyPreferences(IPlugin* plugin, QWidget* parent)
: ConfigPage(plugin, ClangtidySettings::self(), parent)
{
QVBoxLayout* layout = new QVBoxLayout(this);
QWidget* widget = new QWidget(this);
ui = new Ui::ClangtidySettings();
ui->setupUi(widget);
layout->addWidget(widget);
}
ClangtidyPreferences::~ClangtidyPreferences()
{
delete ui;
}
ConfigPage::ConfigPageType ClangtidyPreferences::configPageType() const
{
return ConfigPage::AnalyzerConfigPage;
}
QString ClangtidyPreferences::name() const
{
return i18n("clang-tidy");
}
QString ClangtidyPreferences::fullName() const
{
return i18n("Configure clang-tidy settings");
}
QIcon ClangtidyPreferences::icon() const
{
return QIcon::fromTheme(QStringLiteral("dialog-ok"));
}
void ClangtidyPreferences::apply()
{
- ConfigGroup projConf = KSharedConfig::openConfig()->group("Clangtidy");
- projConf.writeEntry(ConfigGroup::ExecutablePath, ui->kcfg_clangtidyPath->text());
+ ConfigGroup configGroup = KSharedConfig::openConfig()->group("Clangtidy");
+ configGroup.writeEntry(ConfigGroup::ExecutablePath, ui->kcfg_clangtidyPath->text());
}
diff --git a/src/plugin.cpp b/src/plugin.cpp
index fcd90287a1..450e399964 100644
--- a/src/plugin.cpp
+++ b/src/plugin.cpp
@@ -1,293 +1,290 @@
/*
* This file is part of KDevelop
*
* Copyright 2016 Carlos Nihelton
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
#include "plugin.h"
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "config/clangtidypreferences.h"
#include "config/perprojectconfigpage.h"
#include "job.h"
using namespace KDevelop;
K_PLUGIN_FACTORY_WITH_JSON(ClangtidyFactory, "res/kdevclangtidy.json", registerPlugin();)
namespace ClangTidy
{
Plugin::Plugin(QObject* parent, const QVariantList& /*unused*/)
: IPlugin("kdevclangtidy", parent)
, m_model(new KDevelop::ProblemModel(parent))
{
qCDebug(KDEV_CLANGTIDY) << "setting clangtidy rc file";
setXMLFile("kdevclangtidy.rc");
QAction* act_checkfile;
act_checkfile = actionCollection()->addAction("clangtidy_file", this, SLOT(runClangtidyFile()));
act_checkfile->setStatusTip(i18n("Launches clang-tidy for current file"));
act_checkfile->setText(i18n("clang-tidy"));
/* TODO: Uncomment this only when discover a safe way to run clang-tidy on
the whole project.
// QAction* act_check_all_files;
// act_check_all_files = actionCollection()->addAction ( "clangtidy_all",
this, SLOT ( runClangtidyAll() ) );
// act_check_all_files->setStatusTip ( i18n ( "Launches clangtidy for all
translation "
// "units of current project" ) );
// act_check_all_files->setText ( i18n ( "clang-tidy (all)" ) );
*/
IExecutePlugin* iface = KDevelop::ICore::self()
->pluginController()
->pluginForExtension("org.kdevelop.IExecutePlugin")
->extension();
Q_ASSERT(iface);
ProblemModelSet* pms = core()->languageController()->problemModelSet();
pms->addModel(QStringLiteral("Clangtidy"), i18n("Clang-Tidy"), m_model.data());
m_config = KSharedConfig::openConfig()->group("Clangtidy");
- auto clangtidyPath = m_config.readEntry(ConfigGroup::ExecutablePath);
-
- // TODO(cnihelton): auto detect clang-tidy executable instead of hard-coding
- // it.
- if (clangtidyPath.isEmpty()) {
- clangtidyPath = QString(CLANG_TIDY_PATH);
+ auto clangTidyPath = m_config.readEntry(ConfigGroup::ExecutablePath);
+ if (clangTidyPath.isEmpty()) {
+ clangTidyPath = QStandardPaths::findExecutable("clang-tidy");
}
- collectAllAvailableChecks(clangtidyPath);
+ collectAllAvailableChecks(clangTidyPath);
m_config.writeEntry(ConfigGroup::AdditionalParameters, "");
for (auto check : m_allChecks) {
bool enable = check.contains("cert") || check.contains("-core.") || check.contains("-cplusplus")
|| check.contains("-deadcode") || check.contains("-security") || check.contains("cppcoreguide");
if (enable) {
m_activeChecks << check;
} else {
m_activeChecks.removeAll(check);
}
}
m_activeChecks.removeDuplicates();
m_config.writeEntry(ConfigGroup::EnabledChecks, m_activeChecks.join(','));
}
void Plugin::unload()
{
ProblemModelSet* pms = core()->languageController()->problemModelSet();
pms->removeModel(QStringLiteral("Clangtidy"));
}
-void Plugin::collectAllAvailableChecks(QString clangtidyPath)
+void Plugin::collectAllAvailableChecks(QString clangTidyPath)
{
m_allChecks.clear();
KProcess tidy;
- tidy << clangtidyPath << QLatin1String("-checks=*") << QLatin1String("--list-checks");
+ tidy << clangTidyPath << QLatin1String("-checks=*") << QLatin1String("--list-checks");
tidy.setOutputChannelMode(KProcess::OnlyStdoutChannel);
tidy.start();
if (!tidy.waitForStarted()) {
qCDebug(KDEV_CLANGTIDY) << "Unable to execute clang-tidy.";
return;
}
tidy.closeWriteChannel();
if (!tidy.waitForFinished()) {
qCDebug(KDEV_CLANGTIDY) << "Failed during clang-tidy execution.";
return;
}
QTextStream ios(&tidy);
QString each;
while (ios.readLineInto(&each)) {
m_allChecks.append(each.trimmed());
}
if (m_allChecks.size() > 3) {
m_allChecks.removeAt(m_allChecks.length() - 1);
m_allChecks.removeAt(0);
}
m_allChecks.removeDuplicates();
}
void Plugin::runClangtidy(bool allFiles)
{
KDevelop::IDocument* doc = core()->documentController()->activeDocument();
if (doc == nullptr) {
QMessageBox::critical(nullptr, i18n("Error starting clang-tidy"),
i18n("No suitable active file, unable to deduce project."));
return;
}
KDevelop::IProject* project = core()->projectController()->findProjectForUrl(doc->url());
if (project == nullptr) {
QMessageBox::critical(nullptr, i18n("Error starting clang-tidy"), i18n("Active file isn't in a project"));
return;
}
m_config = project->projectConfiguration()->group("Clangtidy");
if (!m_config.isValid()) {
QMessageBox::critical(nullptr, i18n("Error starting clang-tidy"),
i18n("Can't load parameters. They must be set in the "
"project settings."));
return;
}
- auto clangtidyPath = m_config.readEntry(ConfigGroup::ExecutablePath);
+ ConfigGroup configGroup = KSharedConfig::openConfig()->group("Clangtidy");
+ auto clangTidyPath = configGroup.readEntry(ConfigGroup::ExecutablePath);
auto buildSystem = project->buildSystemManager();
Job::Parameters params;
params.projectRootDir = project->path().toLocalFile();
- // TODO: auto detect clang-tidy executable instead of hard-coding it.
- if (clangtidyPath.isEmpty()) {
- params.executablePath = QStringLiteral("/usr/bin/clang-tidy");
+ if (clangTidyPath.isEmpty()) {
+ params.executablePath = QStandardPaths::findExecutable("/usr/bin/clang-tidy");
} else {
- params.executablePath = clangtidyPath;
+ params.executablePath = clangTidyPath;
}
if (allFiles) {
params.filePath = project->path().toUrl().toLocalFile();
} else {
params.filePath = doc->url().toLocalFile();
}
params.buildDir = buildSystem->buildDirectory(project->projectItem()).toLocalFile();
params.additionalParameters = m_config.readEntry(ConfigGroup::AdditionalParameters);
params.analiseTempDtors = m_config.readEntry(ConfigGroup::AnaliseTempDtors);
params.enabledChecks = m_activeChecks.join(',');
params.useConfigFile = m_config.readEntry(ConfigGroup::UseConfigFile);
params.dumpConfig = m_config.readEntry(ConfigGroup::DumpConfig);
params.enableChecksProfile = m_config.readEntry(ConfigGroup::EnableChecksProfile);
params.exportFixes = m_config.readEntry(ConfigGroup::ExportFixes);
params.extraArgs = m_config.readEntry(ConfigGroup::ExtraArgs);
params.extraArgsBefore = m_config.readEntry(ConfigGroup::ExtraArgsBefore);
params.autoFix = m_config.readEntry(ConfigGroup::AutoFix);
params.headerFilter = m_config.readEntry(ConfigGroup::HeaderFilter);
params.lineFilter = m_config.readEntry(ConfigGroup::LineFilter);
params.listChecks = m_config.readEntry(ConfigGroup::ListChecks);
params.checkSystemHeaders = m_config.readEntry(ConfigGroup::CheckSystemHeaders);
if (!params.dumpConfig.isEmpty()) {
auto job = new ClangTidy::Job(params, this);
core()->runController()->registerJob(job);
params.dumpConfig = QString();
}
auto job2 = new ClangTidy::Job(params, this);
connect(job2, SIGNAL(finished(KJob*)), this, SLOT(result(KJob*)));
core()->runController()->registerJob(job2);
}
void Plugin::runClangtidyFile()
{
bool allFiles = false;
runClangtidy(allFiles);
}
void Plugin::runClangtidyAll()
{
bool allFiles = true;
runClangtidy(allFiles);
}
void Plugin::loadOutput()
{
}
void Plugin::result(KJob* job)
{
Job* aj = dynamic_cast(job);
if (aj == nullptr) {
return;
}
if (aj->status() == KDevelop::OutputExecuteJob::JobStatus::JobSucceeded) {
m_model->setProblems(aj->problems());
core()->uiController()->findToolView(i18nd("kdevproblemreporter", "Problems"), nullptr,
KDevelop::IUiController::FindFlags::Raise);
}
}
KDevelop::ContextMenuExtension Plugin::contextMenuExtension(KDevelop::Context* context)
{
KDevelop::IDocument* doc = core()->documentController()->activeDocument();
KDevelop::ContextMenuExtension extension = KDevelop::IPlugin::contextMenuExtension(context);
if (context->type() == KDevelop::Context::EditorContext) {
auto mime = doc->mimeType().name();
if (mime == QLatin1String("text/x-c++src") || mime == QLatin1String("text/x-csrc")) {
QAction* action = new QAction(QIcon::fromTheme("dialog-ok"), i18n("Check unit with clang-tidy"), this);
connect(action, SIGNAL(triggered(bool)), this, SLOT(runClangtidyFile()));
extension.addAction(KDevelop::ContextMenuExtension::ExtensionGroup, action);
}
}
return extension;
}
KDevelop::ConfigPage* Plugin::perProjectConfigPage(int number, const ProjectConfigOptions& options, QWidget* parent)
{
if (number != 0) {
return nullptr;
}
auto config = new PerProjectConfigPage(options.project, parent);
config->setActiveChecksReceptorList(&m_activeChecks);
config->setList(m_allChecks);
return config;
}
KDevelop::ConfigPage* Plugin::configPage(int number, QWidget* parent)
{
if (number != 0) {
return nullptr;
}
return new ClangtidyPreferences(this, parent);
}
} // namespace ClangTidy
#include "plugin.moc"
diff --git a/src/plugin.h.in b/src/plugin.h.in
deleted file mode 100644
index 80cfe013cd..0000000000
--- a/src/plugin.h.in
+++ /dev/null
@@ -1,107 +0,0 @@
-/*
- * This file is part of KDevelop
- *
- * Copyright 2016 Carlos Nihelton
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- * 02110-1301, USA.
- */
-
-#ifndef CLANGTIDY_PLUGIN_H
-#define CLANGTIDY_PLUGIN_H
-
-#include
-#include
-
-#include
-#include
-#include
-
-#include
-#include
-#include
-
-#include "config/configgroup.h"
-#include "qCDebug/debug.h"
-
-class KJob;
-
-namespace KDevelop
-{
-class ProblemModel;
-}
-
-#define CLANG_TIDY_PATH "@CLANG_TIDY_EXEC@"
-
-namespace ClangTidy
-{
-/**
- * \class
- * \brief implements the support for clang-tidy inside KDevelop by using the IPlugin interface.
- */
-class Plugin : public KDevelop::IPlugin
-{
- Q_OBJECT
-
-public:
- Plugin(QObject* parent, const QVariantList& = QVariantList());
- ~Plugin() = default;
- void unload() override;
- KDevelop::ContextMenuExtension contextMenuExtension(KDevelop::Context* context) override;
- int configPages() const override { return 1; }
- /**
- * \function
- * \return the session configuration page for clang-tidy plugin.
- */
- KDevelop::ConfigPage* configPage(int number, QWidget* parent) override;
- int perProjectConfigPages() const override { return 1; }
- /**
- * \function
- * \return the clang-tidy configuration page for the current project.
- */
- KDevelop::ConfigPage* perProjectConfigPage(int number, const KDevelop::ProjectConfigOptions& options,
- QWidget* parent) override;
- /**
- *\function
- *\returns all available checks, obtained from clang-tidy program, ran with with "--checks=* --list-checks"
- * parameters.
- */
- QStringList allAvailableChecks() { return m_allChecks; }
-protected:
- /**
- * \function
- * \brief collects all available checks by running clang-tidy with the following parameters: "--checks=*
- * --list-checks".
- * \param clangtidyPath QString - the system path for the clang-tidy program.
- */
- void collectAllAvailableChecks(QString clangtidyPath);
-
-private slots:
- void loadOutput();
- void runClangtidy(bool allFiles);
- void runClangtidyFile();
- void runClangtidyAll();
- void result(KJob* job);
-
-private:
- ConfigGroup m_config;
- QScopedPointer m_model;
- QStringList m_allChecks;
- QStringList m_activeChecks;
-};
-
-} // namespace ClangTidy
-
-#endif // CLANGTIDY_PLUGIN_H