diff --git a/src/config/clangtidypreferences.cpp b/src/config/clangtidypreferences.cpp index 32e9e9bdb7..50b9ac27f2 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) +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 = new Ui::ClangTidySettings(); ui->setupUi(widget); layout->addWidget(widget); } -ClangtidyPreferences::~ClangtidyPreferences() +ClangTidyPreferences::~ClangTidyPreferences() { delete ui; } -ConfigPage::ConfigPageType ClangtidyPreferences::configPageType() const +ConfigPage::ConfigPageType ClangTidyPreferences::configPageType() const { return ConfigPage::AnalyzerConfigPage; } -QString ClangtidyPreferences::name() const +QString ClangTidyPreferences::name() const { return i18n("Clang-Tidy"); } -QString ClangtidyPreferences::fullName() const +QString ClangTidyPreferences::fullName() const { return i18n("Configure clang-tidy settings"); } -QIcon ClangtidyPreferences::icon() const +QIcon ClangTidyPreferences::icon() const { return QIcon::fromTheme(QStringLiteral("dialog-ok")); } -void ClangtidyPreferences::apply() +void ClangTidyPreferences::apply() { ConfigGroup configGroup = KSharedConfig::openConfig()->group("Clangtidy"); configGroup.writeEntry(ConfigGroup::ExecutablePath, ui->kcfg_clangtidyPath->text()); } diff --git a/src/config/clangtidypreferences.h b/src/config/clangtidypreferences.h index a55675a550..297b0d39d0 100644 --- a/src/config/clangtidypreferences.h +++ b/src/config/clangtidypreferences.h @@ -1,53 +1,53 @@ /* * 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 CLANGTIDYPREFERENCES_H #define CLANGTIDYPREFERENCES_H #include namespace Ui { -class ClangtidySettings; +class ClangTidySettings; }; /** * \class * \brief Implements the session configuration page for clang-tidy. */ -class ClangtidyPreferences : public KDevelop::ConfigPage +class ClangTidyPreferences : public KDevelop::ConfigPage { Q_OBJECT public: - explicit ClangtidyPreferences(KDevelop::IPlugin* plugin = nullptr, QWidget* parent = nullptr); - ~ClangtidyPreferences() override; + explicit ClangTidyPreferences(KDevelop::IPlugin* plugin = nullptr, QWidget* parent = nullptr); + ~ClangTidyPreferences() override; ConfigPage::ConfigPageType configPageType() const override; QString name() const override; QString fullName() const override; QIcon icon() const override; public slots: void apply() override; private: - Ui::ClangtidySettings* ui; + Ui::ClangTidySettings* ui; }; #endif diff --git a/src/config/ui/clangtidysettings.ui b/src/config/ui/clangtidysettings.ui index ffe532c56c..7b144e8828 100644 --- a/src/config/ui/clangtidysettings.ui +++ b/src/config/ui/clangtidysettings.ui @@ -1,75 +1,75 @@ - ClangtidySettings - + ClangTidySettings + 0 0 400 300 Cppcheck Settings Paths - Clang-tidy executable + Clang-&tidy executable Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter kcfg_clangtidyPath Qt::Vertical 20 186 KUrlRequester QFrame
kurlrequester.h
1
diff --git a/src/plugin.cpp b/src/plugin.cpp index 677c10a8af..c54f918b32 100644 --- a/src/plugin.cpp +++ b/src/plugin.cpp @@ -1,324 +1,324 @@ /* * 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)) { 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 (Current File)")); /* 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); if (clangTidyPath.isEmpty()) { clangTidyPath = QStandardPaths::findExecutable("clang-tidy"); } 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) { m_allChecks.clear(); KProcess tidy; 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) { auto 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; } runClangtidy(doc->url(), allFiles); } void Plugin::runClangtidy(const QUrl& url, bool allFiles) { KDevelop::IProject* project = core()->projectController()->findProjectForUrl(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; } ConfigGroup configGroup = KSharedConfig::openConfig()->group("Clangtidy"); auto clangTidyPath = configGroup.readEntry(ConfigGroup::ExecutablePath); auto buildSystem = project->buildSystemManager(); Job::Parameters params; params.projectRootDir = project->path().toLocalFile(); if (clangTidyPath.isEmpty()) { params.executablePath = QStandardPaths::findExecutable("clang-tidy"); } else { params.executablePath = clangTidyPath; } if (allFiles) { params.filePath = project->path().toUrl().toLocalFile(); } else { params.filePath = 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); m_runningJob = job2; } bool Plugin::isRunning() const { return !m_runningJob.isNull(); } 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) { ContextMenuExtension extension = KDevelop::IPlugin::contextMenuExtension(context); if (context->hasType(KDevelop::Context::EditorContext) && !isRunning()) { IDocument* doc = core()->documentController()->activeDocument(); const auto mime = doc->mimeType().name(); if (mime == QLatin1String("text/x-c++src") || mime == QLatin1String("text/x-csrc")) { auto action = new QAction(QIcon::fromTheme("dialog-ok"), i18n("Clang-Tidy"), this); connect(action, &QAction::triggered, this, &Plugin::runClangtidyFile); extension.addAction(KDevelop::ContextMenuExtension::AnalyzeGroup, action); } } if (context->hasType(KDevelop::Context::ProjectItemContext) && !isRunning()) { auto pContext = dynamic_cast(context); if (pContext->items().size() != 1) return extension; auto item = pContext->items().first(); switch (item->type()) { case KDevelop::ProjectBaseItem::File: break; default: return extension; } auto action = new QAction(QIcon::fromTheme("dialog-ok"), i18n("Clang-Tidy"), this); connect(action, &QAction::triggered, this, [this, item]() { runClangtidy(item->path().toUrl()); }); extension.addAction(KDevelop::ContextMenuExtension::AnalyzeGroup, 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); + return new ClangTidyPreferences(this, parent); } } // namespace ClangTidy #include "plugin.moc" diff --git a/tests/data/nihon_plugin.cpp b/tests/data/nihon_plugin.cpp index 74df83f467..1f420d343b 100644 --- a/tests/data/nihon_plugin.cpp +++ b/tests/data/nihon_plugin.cpp @@ -1,423 +1,423 @@ /************************************************************************************* * Copyright (C) 2016 by 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 * * * * Now let's read a beautiful song: * 夢のつづき 追いかけていたはずなのに 曲がりくねった 細い道 人につまずく あの頃みたいにって 戻りたい訳じゃないの 無くしてきた空を 探してる わかってくれますように 犠牲になったような 悲しい顔はやめてよ 罪の最後は涙じゃないよ ずっと苦しく背負ってくんだ 出口見えない感情迷路に 誰を待ってるの? 白いノートに綴ったように もっと素直に吐き出したいよ 何から 逃れたいんだ …現実ってやつ? 叶えるために 生きてるんだって 忘れちゃいそうな 夜の真ん中 無難になんて やってられないから …帰る場所もないの この想いを 消してしまうには まだ人生長いでしょ?(I'm on the way) 懐かしくなる こんな痛みも歓迎じゃん 謝らなくちゃいけないよね ah ごめんね うまく言えなくて 心配かけたままだったね あの日かかえた全部 あしたかかえる全部 順番つけたりは しないから わかってくれますように そっと目を閉じたんだ 見たくないものまで 見えんだもん いらないウワサにちょっと 初めて聞く発言どっち? 2回会ったら友達だって?? ウソはやめてね 赤いハートが苛立つように 身体ん中燃えているんだ ホントは 期待してんの …現実ってやつ? 叶えるために 生きてるんだって 叫びたくなるよ 聞こえていますか? 無難になんて やってられないから …帰る場所もないの 優しさには いつも感謝してる だから強くなりたい(I'm on the way) 進むために 敵も味方も歓迎じゃん どうやって次のドア 開けるんだっけ?考えてる? もう引き返せない 物語 始まってるんだ 目を覚ませ 目を覚ませ この想いを 消してしまうには まだ人生長いでしょ? やり残してるコト やり直してみたいから もう一度ゆこう 叶えるために 生きてるんだって 叫びたくなるよ 聞こえていますか? 無難になんて やってられないから …帰る場所もないの 優しさには いつも感謝してる だから強くなりたい(I'm on the way) 懐かしくなる こんな痛みも歓迎じゃん *************************************************************************************/ #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 #include "./config/clangtidypreferences.h" #include "./config/perprojectconfigpage.h" #include "debug.h" #include "job.h" #include "plugin.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 Clangtidy 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"), 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("/usr/bin/clang-tidy"); } 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) { m_allChecks.clear(); KProcess tidy; 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) { 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) { 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 Clangtidy"), i18n("Can't load parameters. They must be set in the project settings.")); return; } auto clangtidyPath = m_config.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"); } else { 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()) { Job* job = new ClangTidy::Job(params, this); core()->runController()->registerJob(job); params.dumpConfig = QString(); } Job* 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) { return; } if (aj->status() == KDevelop::OutputExecuteJob::JobStatus::JobSucceeded) { m_model->setProblems(aj->problems()); core()->uiController()->findToolView(i18nd("kdevproblemreporter", "Problems"), 0, 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("document-new"), i18n("Check current unit with clang-tidy"), this); connect(action, SIGNAL(triggered(bool)), this, SLOT(runClangtidyFile())); extension.addAction(KDevelop::ContextMenuExtension::AnalyzeGroup, action); } } return extension; } KDevelop::ConfigPage* Plugin::perProjectConfigPage(int number, const ProjectConfigOptions& options, QWidget* parent) { if (number != 0) { return nullptr; } else { 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; } else { - return new ClangtidyPreferences(this, parent); + return new ClangTidyPreferences(this, parent); } } } #include "plugin.moc" diff --git a/tests/data/plugin.cpp b/tests/data/plugin.cpp index 5cc83999ba..8f49b7747c 100644 --- a/tests/data/plugin.cpp +++ b/tests/data/plugin.cpp @@ -1,290 +1,290 @@ /************************************************************************************* * Copyright (C) 2016 by 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 #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 "debug.h" #include "job.h" #include "plugin.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 Clangtidy 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"), 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("/usr/bin/clang-tidy"); } 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) { m_allChecks.clear(); KProcess tidy; 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) { 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) { 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 Clangtidy"), i18n("Can't load parameters. They must be set in the project settings.")); return; } auto clangtidyPath = m_config.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"); } else { 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()) { Job* job = new ClangTidy::Job(params, this); core()->runController()->registerJob(job); params.dumpConfig = QString(); } Job* 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) { return; } if (aj->status() == KDevelop::OutputExecuteJob::JobStatus::JobSucceeded) { m_model->setProblems(aj->problems()); core()->uiController()->findToolView(i18nd("kdevproblemreporter", "Problems"), 0, 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("document-new"), i18n("Check current unit with clang-tidy"), this); connect(action, SIGNAL(triggered(bool)), this, SLOT(runClangtidyFile())); extension.addAction(KDevelop::ContextMenuExtension::AnalyzeGroup, action); } } return extension; } KDevelop::ConfigPage* Plugin::perProjectConfigPage(int number, const ProjectConfigOptions& options, QWidget* parent) { if (number != 0) { return nullptr; } else { 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; } else { - return new ClangtidyPreferences(this, parent); + return new ClangTidyPreferences(this, parent); } } } #include "plugin.moc" diff --git a/tests/test_plugin.cpp b/tests/test_plugin.cpp index 95a35575ac..91931cbf3d 100644 --- a/tests/test_plugin.cpp +++ b/tests/test_plugin.cpp @@ -1,51 +1,51 @@ /* * 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 "test_plugin.h" #include #include #include #include "plugin/plugin.h" #include using namespace KDevelop; // using namespace ClangTidy; -void TestClangtidyPlugin::initTestCase() +void TestClangTidyPlugin::initTestCase() { AutoTestShell::init(); TestCore::initialize(Core::NoUi); } -void TestClangtidyPlugin::cleanupTestCase() +void TestClangTidyPlugin::cleanupTestCase() { TestCore::shutdown(); } -void TestClangtidyPlugin::testPlugin() +void TestClangTidyPlugin::testPlugin() { ClangTidy::Plugin plugin(nullptr); QCOMPARE(plugin.configPages(), 1); QVERIFY(!plugin.allAvailableChecks().isEmpty()); } -QTEST_GUILESS_MAIN(TestClangtidyPlugin); +QTEST_GUILESS_MAIN(TestClangTidyPlugin); diff --git a/tests/test_plugin.h b/tests/test_plugin.h index efe20a8d9f..53b5063d41 100644 --- a/tests/test_plugin.h +++ b/tests/test_plugin.h @@ -1,37 +1,37 @@ /* * 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 TEST_PLUGIN_H #define TEST_PLUGIN_H #include -class TestClangtidyPlugin : public QObject +class TestClangTidyPlugin : public QObject { Q_OBJECT private slots: void initTestCase(); void cleanupTestCase(); void testPlugin(); }; #endif // TEST_PLUGIN_H