ClangTools: Run clang-tidy and clazy separately

They are two different tools and should not have been merged into a
single runner in the first place.
People can now actively decide to run clazy if they really want to,
rather than getting confronted with its increasingly irrelevant
complaints by default.
We keep the common settings widget for now.

Change-Id: I3c2b1db8c07ff5c128700d4a1deefd710967568a
Reviewed-by: <github-actions-qt-creator@cristianadam.eu>
Reviewed-by: David Schulz <david.schulz@qt.io>
This commit is contained in:
Christian Kandeler
2022-12-07 14:49:35 +01:00
parent ca6b14cf01
commit 8b49b091f7
10 changed files with 159 additions and 114 deletions

View File

@@ -66,8 +66,6 @@ using namespace Utils;
namespace ClangTools { namespace ClangTools {
namespace Internal { namespace Internal {
static ClangTool *s_instance;
static QString makeLink(const QString &text) static QString makeLink(const QString &text)
{ {
return QString("<a href=t>%1</a>").arg(text); return QString("<a href=t>%1</a>").arg(text);
@@ -355,23 +353,17 @@ static RunSettings runSettings()
return ClangToolsSettings::instance()->runSettings(); return ClangToolsSettings::instance()->runSettings();
} }
ClangTool *ClangTool::instance() ClangTool::ClangTool(const QString &name, Utils::Id id)
: m_name(name), m_perspective{id.toString(), name}
{ {
return s_instance; setObjectName(name);
}
ClangTool::ClangTool()
: m_name("Clang-Tidy and Clazy")
{
setObjectName("ClangTidyClazyTool");
s_instance = this;
m_diagnosticModel = new ClangToolsDiagnosticModel(this); m_diagnosticModel = new ClangToolsDiagnosticModel(this);
auto action = new QAction(tr("Analyze Project..."), this); auto action = new QAction(tr("Analyze Project with %1...").arg(name), this);
action->setIcon(Utils::Icons::RUN_SELECTED_TOOLBAR.icon()); action->setIcon(Utils::Icons::RUN_SELECTED_TOOLBAR.icon());
m_startAction = action; m_startAction = action;
action = new QAction(tr("Analyze Current File"), this); action = new QAction(tr("Analyze Current File with %1").arg(name), this);
action->setIcon(Utils::Icons::RUN_FILE.icon()); action->setIcon(Utils::Icons::RUN_FILE.icon());
m_startOnCurrentFileAction = action; m_startOnCurrentFileAction = action;
@@ -536,9 +528,9 @@ ClangTool::ClangTool()
m_perspective.addWindow(mainWidget, Perspective::SplitVertical, nullptr); m_perspective.addWindow(mainWidget, Perspective::SplitVertical, nullptr);
action = new QAction(tr("Clang-Tidy and Clazy..."), this); action = new QAction(name, this);
action->setToolTip(toolTip); action->setToolTip(toolTip);
menu->addAction(ActionManager::registerAction(action, "ClangTidyClazy.Action"), menu->addAction(ActionManager::registerAction(action, id),
Debugger::Constants::G_ANALYZER_TOOLS); Debugger::Constants::G_ANALYZER_TOOLS);
QObject::connect(action, &QAction::triggered, this, [this] { QObject::connect(action, &QAction::triggered, this, [this] {
startTool(FileSelectionType::AskUser); startTool(FileSelectionType::AskUser);
@@ -645,12 +637,12 @@ void ClangTool::startTool(ClangTool::FileSelection fileSelection,
// Run control // Run control
m_runControl = new RunControl(Constants::CLANGTIDYCLAZY_RUN_MODE); m_runControl = new RunControl(Constants::CLANGTIDYCLAZY_RUN_MODE);
m_runControl->setDisplayName(tr("Clang-Tidy and Clazy")); m_runControl->setDisplayName(m_name);
m_runControl->setIcon(ProjectExplorer::Icons::ANALYZER_START_SMALL_TOOLBAR); m_runControl->setIcon(ProjectExplorer::Icons::ANALYZER_START_SMALL_TOOLBAR);
m_runControl->setTarget(project->activeTarget()); m_runControl->setTarget(project->activeTarget());
m_stopAction->disconnect(); m_stopAction->disconnect();
connect(m_stopAction, &QAction::triggered, m_runControl, [this] { connect(m_stopAction, &QAction::triggered, m_runControl, [this] {
emit m_runControl->appendMessage(tr("Clang-Tidy and Clazy tool stopped by user."), emit m_runControl->appendMessage(tr("%1 tool stopped by user.").arg(m_name),
NormalMessageFormat); NormalMessageFormat);
m_runControl->initiateStop(); m_runControl->initiateStop();
setState(State::StoppedByUser); setState(State::StoppedByUser);
@@ -662,7 +654,8 @@ void ClangTool::startTool(ClangTool::FileSelection fileSelection,
|| std::get<FileSelectionType>(fileSelection) || std::get<FileSelectionType>(fileSelection)
== FileSelectionType::CurrentFile; == FileSelectionType::CurrentFile;
const bool buildBeforeAnalysis = !preventBuild && runSettings.buildBeforeAnalysis(); const bool buildBeforeAnalysis = !preventBuild && runSettings.buildBeforeAnalysis();
m_runWorker = new ClangToolRunWorker(m_runControl, m_runWorker = new ClangToolRunWorker(this,
m_runControl,
runSettings, runSettings,
diagnosticConfig, diagnosticConfig,
fileInfos, fileInfos,
@@ -1202,6 +1195,15 @@ void ClangTool::updateForCurrentState()
m_infoBarWidget->setDiagText(diagText); m_infoBarWidget->setDiagText(diagText);
} }
ClangTidyTool::ClangTidyTool() : ClangTool(tr("Clang-Tidy"), "ClangTidy.Perspective")
{
m_instance = this;
}
ClazyTool::ClazyTool() : ClangTool(tr("Clazy"), "Clazy.Perspective")
{
m_instance = this;
}
} // namespace Internal } // namespace Internal
} // namespace ClangTools } // namespace ClangTools

View File

@@ -46,17 +46,11 @@ class DiagnosticView;
class RunSettings; class RunSettings;
class SelectFixitsCheckBox; class SelectFixitsCheckBox;
const char ClangTidyClazyPerspectiveId[] = "ClangTidyClazy.Perspective";
class ClangTool : public QObject class ClangTool : public QObject
{ {
Q_OBJECT Q_OBJECT
public: public:
static ClangTool *instance();
ClangTool();
void selectPerspective(); void selectPerspective();
enum class FileSelectionType { enum class FileSelectionType {
@@ -93,6 +87,9 @@ public:
signals: signals:
void finished(const QString &errorText); // For testing. void finished(const QString &errorText); // For testing.
protected:
ClangTool(const QString &name, Utils::Id id);
private: private:
enum class State { enum class State {
Initial, Initial,
@@ -132,6 +129,7 @@ private:
FileInfoProviders fileInfoProviders(ProjectExplorer::Project *project, FileInfoProviders fileInfoProviders(ProjectExplorer::Project *project,
const FileInfos &allFileInfos); const FileInfos &allFileInfos);
const QString m_name;
ClangToolsDiagnosticModel *m_diagnosticModel = nullptr; ClangToolsDiagnosticModel *m_diagnosticModel = nullptr;
ProjectExplorer::RunControl *m_runControl = nullptr; ProjectExplorer::RunControl *m_runControl = nullptr;
ClangToolRunWorker *m_runWorker = nullptr; ClangToolRunWorker *m_runWorker = nullptr;
@@ -161,11 +159,27 @@ private:
QAction *m_clear = nullptr; QAction *m_clear = nullptr;
QAction *m_expandCollapse = nullptr; QAction *m_expandCollapse = nullptr;
Utils::Perspective m_perspective{ClangTidyClazyPerspectiveId, Utils::Perspective m_perspective;
::ClangTools::Internal::ClangTool::tr("Clang-Tidy and Clazy")}; };
class ClangTidyTool : public ClangTool
{
public:
ClangTidyTool();
static ClangTool *instance() { return m_instance; }
private: private:
const QString m_name; static inline ClangTool *m_instance = nullptr;
};
class ClazyTool : public ClangTool
{
public:
ClazyTool();
static ClangTool *instance() { return m_instance; }
private:
static inline ClangTool *m_instance = nullptr;
}; };
} // namespace Internal } // namespace Internal

View File

@@ -55,11 +55,6 @@ static Q_LOGGING_CATEGORY(LOG, "qtc.clangtools.runcontrol", QtWarningMsg)
namespace ClangTools { namespace ClangTools {
namespace Internal { namespace Internal {
static ClangTool *tool()
{
return ClangTool::instance();
}
class ProjectBuilder : public RunWorker class ProjectBuilder : public RunWorker
{ {
public: public:
@@ -138,12 +133,13 @@ static QDebug operator<<(QDebug debug, const AnalyzeUnits &analyzeUnits)
} }
ClangToolRunWorker::ClangToolRunWorker(RunControl *runControl, ClangToolRunWorker::ClangToolRunWorker(ClangTool *tool, RunControl *runControl,
const RunSettings &runSettings, const RunSettings &runSettings,
const CppEditor::ClangDiagnosticConfig &diagnosticConfig, const CppEditor::ClangDiagnosticConfig &diagnosticConfig,
const FileInfos &fileInfos, const FileInfos &fileInfos,
bool buildBeforeAnalysis) bool buildBeforeAnalysis)
: RunWorker(runControl) : RunWorker(runControl)
, m_tool(tool)
, m_runSettings(runSettings) , m_runSettings(runSettings)
, m_diagnosticConfig(diagnosticConfig) , m_diagnosticConfig(diagnosticConfig)
, m_fileInfos(fileInfos) , m_fileInfos(fileInfos)
@@ -174,15 +170,9 @@ ClangToolRunWorker::ClangToolRunWorker(RunControl *runControl,
QList<RunnerCreator> ClangToolRunWorker::runnerCreators() QList<RunnerCreator> ClangToolRunWorker::runnerCreators()
{ {
QList<RunnerCreator> creators; if (m_tool == ClangTidyTool::instance())
return {[this] { return createRunner<ClangTidyRunner>(); }};
if (m_diagnosticConfig.isClangTidyEnabled()) return {[this] { return createRunner<ClazyStandaloneRunner>(); }};
creators << [this] { return createRunner<ClangTidyRunner>(); };
if (m_diagnosticConfig.isClazyEnabled())
creators << [this] { return createRunner<ClazyStandaloneRunner>(); };
return creators;
} }
void ClangToolRunWorker::start() void ClangToolRunWorker::start()
@@ -195,7 +185,7 @@ void ClangToolRunWorker::start()
return; return;
} }
const QString &toolName = tool()->name(); const QString &toolName = m_tool->name();
Project *project = runControl()->project(); Project *project = runControl()->project();
m_projectInfo = CppEditor::CppModelManager::instance()->projectInfo(project); m_projectInfo = CppEditor::CppModelManager::instance()->projectInfo(project);
if (!m_projectInfo) { if (!m_projectInfo) {
@@ -334,7 +324,7 @@ void ClangToolRunWorker::onRunnerFinishedWithSuccess(ClangToolRunner *runner,
emit runnerFinished(); emit runnerFinished();
QString errorMessage; QString errorMessage;
const Diagnostics diagnostics = tool()->read(runner->outputFileFormat(), const Diagnostics diagnostics = m_tool->read(runner->outputFileFormat(),
outputFilePath, outputFilePath,
m_projectFiles, m_projectFiles,
&errorMessage); &errorMessage);
@@ -353,7 +343,7 @@ void ClangToolRunWorker::onRunnerFinishedWithSuccess(ClangToolRunner *runner,
// do not generate marks when we always analyze open files since marks from that // do not generate marks when we always analyze open files since marks from that
// analysis should be more up to date // analysis should be more up to date
const bool generateMarks = !m_runSettings.analyzeOpenFiles(); const bool generateMarks = !m_runSettings.analyzeOpenFiles();
tool()->onNewDiagnosticsAvailable(diagnostics, generateMarks); m_tool->onNewDiagnosticsAvailable(diagnostics, generateMarks);
} }
} }
@@ -401,7 +391,7 @@ void ClangToolRunWorker::updateProgressValue()
void ClangToolRunWorker::finalize() void ClangToolRunWorker::finalize()
{ {
const QString toolName = tool()->name(); const QString toolName = m_tool->name();
if (m_filesNotAnalyzed.size() != 0) { if (m_filesNotAnalyzed.size() != 0) {
appendMessage(tr("Error: Failed to analyze %n files.", nullptr, m_filesNotAnalyzed.size()), appendMessage(tr("Error: Failed to analyze %n files.", nullptr, m_filesNotAnalyzed.size()),
ErrorMessageFormat); ErrorMessageFormat);

View File

@@ -19,7 +19,7 @@
namespace ClangTools { namespace ClangTools {
namespace Internal { namespace Internal {
class ClangTool;
class ClangToolRunner; class ClangToolRunner;
class ProjectBuilder; class ProjectBuilder;
@@ -46,7 +46,8 @@ class ClangToolRunWorker : public ProjectExplorer::RunWorker
Q_OBJECT Q_OBJECT
public: public:
ClangToolRunWorker(ProjectExplorer::RunControl *runControl, ClangToolRunWorker(ClangTool *tool,
ProjectExplorer::RunControl *runControl,
const RunSettings &runSettings, const RunSettings &runSettings,
const CppEditor::ClangDiagnosticConfig &diagnosticConfig, const CppEditor::ClangDiagnosticConfig &diagnosticConfig,
const FileInfos &fileInfos, const FileInfos &fileInfos,
@@ -85,6 +86,7 @@ private:
void finalize(); void finalize();
private: private:
ClangTool * const m_tool;
RunSettings m_runSettings; RunSettings m_runSettings;
CppEditor::ClangDiagnosticConfig m_diagnosticConfig; CppEditor::ClangDiagnosticConfig m_diagnosticConfig;
FileInfos m_fileInfos; FileInfos m_fileInfos;

View File

@@ -8,8 +8,10 @@ namespace Constants {
const char PROJECT_PANEL_ID[] = "ClangTools"; const char PROJECT_PANEL_ID[] = "ClangTools";
const char RUN_ON_PROJECT[] = "ClangTools.RunOnProject"; const char RUN_CLANGTIDY_ON_PROJECT[] = "ClangTools.ClangTidy.RunOnProject";
const char RUN_ON_CURRENT_FILE[] = "ClangTools.RunOnCurrentFile"; const char RUN_CLAZY_ON_PROJECT[] = "ClangTools.Clazy.RunOnProject";
const char RUN_CLANGTIDY_ON_CURRENT_FILE[] = "ClangTools.ClangTidy.RunOnCurrentFile";
const char RUN_CLAZY_ON_CURRENT_FILE[] = "ClangTools.Clazy.RunOnCurrentFile";
const char SETTINGS_PAGE_ID[] = "Analyzer.ClangTools.Settings"; const char SETTINGS_PAGE_ID[] = "Analyzer.ClangTools.Settings";
const char SETTINGS_ID[] = "ClangTools"; const char SETTINGS_ID[] = "ClangTools";

View File

@@ -75,7 +75,8 @@ public:
return nullptr; return nullptr;
} }
ClangTool clangTool; ClangTidyTool clangTidyTool;
ClazyTool clazyTool;
ClangToolsOptionsPage optionsPage; ClangToolsOptionsPage optionsPage;
QMap<Core::IDocument *, DocumentClangToolRunner *> documentRunners; QMap<Core::IDocument *, DocumentClangToolRunner *> documentRunners;
DocumentQuickFixFactory quickFixFactory; DocumentQuickFixFactory quickFixFactory;
@@ -133,22 +134,31 @@ void ClangToolsPlugin::onCurrentEditorChanged()
void ClangToolsPlugin::registerAnalyzeActions() void ClangToolsPlugin::registerAnalyzeActions()
{ {
ActionManager::registerAction(d->clangTool.startAction(), Constants::RUN_ON_PROJECT); for (const auto &toolInfo : {std::make_tuple(ClangTidyTool::instance(),
Command *cmd = ActionManager::registerAction(d->clangTool.startOnCurrentFileAction(), Constants::RUN_CLANGTIDY_ON_PROJECT,
Constants::RUN_ON_CURRENT_FILE); Constants::RUN_CLANGTIDY_ON_CURRENT_FILE),
ActionContainer *mtoolscpp = ActionManager::actionContainer(CppEditor::Constants::M_TOOLS_CPP); std::make_tuple(ClazyTool::instance(),
if (mtoolscpp) Constants::RUN_CLAZY_ON_PROJECT,
mtoolscpp->addAction(cmd); Constants::RUN_CLAZY_ON_CURRENT_FILE)}) {
ClangTool * const tool = std::get<0>(toolInfo);
ActionManager::registerAction(tool->startAction(), std::get<1>(toolInfo));
Command *cmd = ActionManager::registerAction(tool->startOnCurrentFileAction(),
std::get<2>(toolInfo));
ActionContainer *mtoolscpp = ActionManager::actionContainer(CppEditor::Constants::M_TOOLS_CPP);
if (mtoolscpp)
mtoolscpp->addAction(cmd);
Core::ActionContainer *mcontext = Core::ActionManager::actionContainer( Core::ActionContainer *mcontext = Core::ActionManager::actionContainer(
CppEditor::Constants::M_CONTEXT); CppEditor::Constants::M_CONTEXT);
if (mcontext) if (mcontext)
mcontext->addAction(cmd, CppEditor::Constants::G_CONTEXT_FIRST); mcontext->addAction(cmd, CppEditor::Constants::G_CONTEXT_FIRST);
}
// add button to tool bar of C++ source files // add button to tool bar of C++ source files
connect(EditorManager::instance(), &EditorManager::editorOpened, this, [this, cmd](IEditor *editor) { connect(EditorManager::instance(), &EditorManager::editorOpened, this,
[this](IEditor *editor) {
if (editor->document()->filePath().isEmpty() if (editor->document()->filePath().isEmpty()
|| !Utils::mimeTypeForName(editor->document()->mimeType()).inherits("text/x-c++src")) || !Utils::mimeTypeForName(editor->document()->mimeType()).inherits("text/x-c++src"))
return; return;
auto *textEditor = qobject_cast<TextEditor::BaseTextEditor *>(editor); auto *textEditor = qobject_cast<TextEditor::BaseTextEditor *>(editor);
if (!textEditor) if (!textEditor)
@@ -157,12 +167,25 @@ void ClangToolsPlugin::registerAnalyzeActions()
if (!widget) if (!widget)
return; return;
const QIcon icon = Utils::Icon({{":/debugger/images/debugger_singleinstructionmode.png", const QIcon icon = Utils::Icon({{":/debugger/images/debugger_singleinstructionmode.png",
Utils::Theme::IconsBaseColor}}) Utils::Theme::IconsBaseColor}}).icon();
.icon(); const auto button = new QToolButton;
QAction *action = widget->toolBar()->addAction(icon, tr("Analyze File"), [this, editor] { button->setPopupMode(QToolButton::InstantPopup);
d->clangTool.startTool(editor->document()->filePath()); button->setIcon(icon);
}); button->setToolTip(tr("Analyze File..."));
cmd->augmentActionWithShortcutToolTip(action); widget->toolBar()->addWidget(button);
const auto toolsMenu = new QMenu(widget);
button->setMenu(toolsMenu);
for (const auto &toolInfo : {std::make_pair(ClangTidyTool::instance(),
Constants::RUN_CLANGTIDY_ON_CURRENT_FILE),
std::make_pair(ClazyTool::instance(),
Constants::RUN_CLAZY_ON_CURRENT_FILE)}) {
ClangTool * const tool = toolInfo.first;
Command * const cmd = ActionManager::command(toolInfo.second);
QAction * const action = toolsMenu->addAction(tool->name(), [this, editor, tool] {
tool->startTool(editor->document()->filePath());
});
cmd->augmentActionWithShortcutToolTip(action);
}
}); });
} }

View File

@@ -99,13 +99,15 @@ void PreconfiguredSessionTests::testPreconfiguredSession()
QVERIFY(switchToProjectAndTarget(project, target)); QVERIFY(switchToProjectAndTarget(project, target));
ClangTool::instance()->startTool(ClangTool::FileSelectionType::AllFiles); for (ClangTool * const tool : {ClangTidyTool::instance(), ClazyTool::instance()}) {
QSignalSpy waitUntilAnalyzerFinished(ClangTool::instance(), SIGNAL(finished(bool))); tool->startTool(ClangTool::FileSelectionType::AllFiles);
QVERIFY(waitUntilAnalyzerFinished.wait(30000)); QSignalSpy waitUntilAnalyzerFinished(tool, SIGNAL(finished(bool)));
const QList<QVariant> arguments = waitUntilAnalyzerFinished.takeFirst(); QVERIFY(waitUntilAnalyzerFinished.wait(30000));
const bool analyzerFinishedSuccessfully = arguments.first().toBool(); const QList<QVariant> arguments = waitUntilAnalyzerFinished.takeFirst();
QVERIFY(analyzerFinishedSuccessfully); const bool analyzerFinishedSuccessfully = arguments.first().toBool();
QCOMPARE(ClangTool::instance()->diagnostics().count(), 0); QVERIFY(analyzerFinishedSuccessfully);
QCOMPARE(tool->diagnostics().count(), 0);
}
} }
static const QList<Project *> validProjects(const QList<Project *> projectsOfSession) static const QList<Project *> validProjects(const QList<Project *> projectsOfSession)

View File

@@ -54,8 +54,10 @@ ClangToolsProjectSettingsWidget::ClangToolsProjectSettingsWidget(ProjectExplorer
setGlobalSettingsId(ClangTools::Constants::SETTINGS_PAGE_ID); setGlobalSettingsId(ClangTools::Constants::SETTINGS_PAGE_ID);
m_restoreGlobal = new QPushButton(tr("Restore Global Settings")); m_restoreGlobal = new QPushButton(tr("Restore Global Settings"));
auto gotoAnalyzerModeLabel = const auto gotoClangTidyModeLabel
new QLabel("<a href=\"target\">" + tr("Go to Analyzer") + "</a>"); = new QLabel("<a href=\"target\">" + tr("Go to Clang-Tidy") + "</a>");
const auto gotoClazyModeLabel
= new QLabel("<a href=\"target\">" + tr("Go to Clazy") + "</a>");
m_runSettingsWidget = new ClangTools::Internal::RunSettingsWidget(this); m_runSettingsWidget = new ClangTools::Internal::RunSettingsWidget(this);
@@ -67,7 +69,7 @@ ClangToolsProjectSettingsWidget::ClangToolsProjectSettingsWidget(ProjectExplorer
using namespace Utils::Layouting; using namespace Utils::Layouting;
Column { Column {
Row { m_restoreGlobal, st, gotoAnalyzerModeLabel }, Row { m_restoreGlobal, st, gotoClangTidyModeLabel, gotoClazyModeLabel },
m_runSettingsWidget, m_runSettingsWidget,
@@ -96,8 +98,11 @@ ClangToolsProjectSettingsWidget::ClangToolsProjectSettingsWidget(ProjectExplorer
m_runSettingsWidget->fromSettings(ClangToolsSettings::instance()->runSettings()); m_runSettingsWidget->fromSettings(ClangToolsSettings::instance()->runSettings());
}); });
connect(gotoAnalyzerModeLabel, &QLabel::linkActivated, [](const QString &) { connect(gotoClangTidyModeLabel, &QLabel::linkActivated, [](const QString &) {
ClangTool::instance()->selectPerspective(); ClangTidyTool::instance()->selectPerspective();
});
connect(gotoClazyModeLabel, &QLabel::linkActivated, [](const QString &) {
ClazyTool::instance()->selectPerspective();
}); });
// Run options // Run options

View File

@@ -86,7 +86,8 @@ static ClangDiagnosticConfig configFor(const QString &tidyChecks,
void ClangToolsUnitTests::testProject() void ClangToolsUnitTests::testProject()
{ {
QFETCH(QString, projectFilePath); QFETCH(QString, projectFilePath);
QFETCH(int, expectedDiagCount); QFETCH(int, expectedDiagCountClangTidy);
QFETCH(int, expectedDiagCountClazy);
QFETCH(ClangDiagnosticConfig, diagnosticConfig); QFETCH(ClangDiagnosticConfig, diagnosticConfig);
if (projectFilePath.contains("mingw")) { if (projectFilePath.contains("mingw")) {
const auto toolchain = ToolChainKitAspect::cxxToolChain(m_kit); const auto toolchain = ToolChainKitAspect::cxxToolChain(m_kit);
@@ -98,71 +99,75 @@ void ClangToolsUnitTests::testProject()
Tests::ProjectOpenerAndCloser projectManager; Tests::ProjectOpenerAndCloser projectManager;
QVERIFY(projectManager.open(projectFilePath, true, m_kit)); QVERIFY(projectManager.open(projectFilePath, true, m_kit));
// Run tool // Run tools
ClangTool *tool = ClangTool::instance(); for (ClangTool * const tool : {ClangTidyTool::instance(), ClazyTool::instance()}) {
tool->startTool(ClangTool::FileSelectionType::AllFiles, tool->startTool(ClangTool::FileSelectionType::AllFiles,
ClangToolsSettings::instance()->runSettings(), ClangToolsSettings::instance()->runSettings(),
diagnosticConfig); diagnosticConfig);
QSignalSpy waitForFinishedTool(tool, &ClangTool::finished); QSignalSpy waitForFinishedTool(tool, &ClangTool::finished);
QVERIFY(waitForFinishedTool.wait(m_timeout)); QVERIFY(waitForFinishedTool.wait(m_timeout));
// Check for errors // Check for errors
const QString errorText = waitForFinishedTool.takeFirst().constFirst().toString(); const QString errorText = waitForFinishedTool.takeFirst().constFirst().toString();
const bool finishedSuccessfully = errorText.isEmpty(); const bool finishedSuccessfully = errorText.isEmpty();
if (!finishedSuccessfully) if (!finishedSuccessfully)
qWarning("Error: %s", qPrintable(errorText)); qWarning("Error: %s", qPrintable(errorText));
QVERIFY(finishedSuccessfully); QVERIFY(finishedSuccessfully);
QCOMPARE(tool->diagnostics().count(), expectedDiagCount); QCOMPARE(tool->diagnostics().count(), tool == ClangTidyTool::instance()
? expectedDiagCountClangTidy : expectedDiagCountClazy);
}
} }
void ClangToolsUnitTests::testProject_data() void ClangToolsUnitTests::testProject_data()
{ {
QTest::addColumn<QString>("projectFilePath"); QTest::addColumn<QString>("projectFilePath");
QTest::addColumn<int>("expectedDiagCount"); QTest::addColumn<int>("expectedDiagCountClangTidy");
QTest::addColumn<int>("expectedDiagCountClazy");
QTest::addColumn<ClangDiagnosticConfig>("diagnosticConfig"); QTest::addColumn<ClangDiagnosticConfig>("diagnosticConfig");
// Test simple C++ project. // Test simple C++ project.
ClangDiagnosticConfig config = configFor("modernize-use-nullptr", QString()); ClangDiagnosticConfig config = configFor("modernize-use-nullptr", QString());
addTestRow("simple/simple.qbs", 1, config); addTestRow("simple/simple.qbs", 1, 0, config);
addTestRow("simple/simple.pro", 1, config); addTestRow("simple/simple.pro", 1, 0, config);
// Test simple Qt project. // Test simple Qt project.
config = configFor("readability-static-accessed-through-instance", QString()); config = configFor("readability-static-accessed-through-instance", QString());
addTestRow("qt-widgets-app/qt-widgets-app.qbs", 1, config); addTestRow("qt-widgets-app/qt-widgets-app.qbs", 1, 0, config);
addTestRow("qt-widgets-app/qt-widgets-app.pro", 1, config); addTestRow("qt-widgets-app/qt-widgets-app.pro", 1, 0, config);
// Test that libraries can be analyzed. // Test that libraries can be analyzed.
config = configFor(QString(), QString()); config = configFor(QString(), QString());
addTestRow("simple-library/simple-library.qbs", 0, config); addTestRow("simple-library/simple-library.qbs", 0, 0, config);
addTestRow("simple-library/simple-library.pro", 0, config); addTestRow("simple-library/simple-library.pro", 0, 0, config);
// Test that standard headers can be parsed. // Test that standard headers can be parsed.
addTestRow("stdc++11-includes/stdc++11-includes.qbs", 0, config); addTestRow("stdc++11-includes/stdc++11-includes.qbs", 0, 0, config);
addTestRow("stdc++11-includes/stdc++11-includes.pro", 0, config); addTestRow("stdc++11-includes/stdc++11-includes.pro", 0, 0, config);
// Test that qt essential headers can be parsed. // Test that qt essential headers can be parsed.
addTestRow("qt-essential-includes/qt-essential-includes.qbs", 0, config); addTestRow("qt-essential-includes/qt-essential-includes.qbs", 0, 0, config);
addTestRow("qt-essential-includes/qt-essential-includes.pro", 0, config); addTestRow("qt-essential-includes/qt-essential-includes.pro", 0, 0, config);
// Test that mingw includes can be parsed. // Test that mingw includes can be parsed.
addTestRow("mingw-includes/mingw-includes.qbs", 0, config); addTestRow("mingw-includes/mingw-includes.qbs", 0, 0, config);
addTestRow("mingw-includes/mingw-includes.pro", 0, config); addTestRow("mingw-includes/mingw-includes.pro", 0, 0, config);
// Test that tidy and clazy diagnostics are emitted for the same project. // Test that tidy and clazy diagnostics are emitted for the same project.
addTestRow("clangtidy_clazy/clangtidy_clazy.pro", addTestRow("clangtidy_clazy/clangtidy_clazy.pro",
1 /*tidy*/ + 1 /*clazy*/, 1, 1, configFor("misc-unconventional-assign-operator", "qgetenv"));
configFor("misc-unconventional-assign-operator", "qgetenv"));
} }
void ClangToolsUnitTests::addTestRow(const QByteArray &relativeFilePath, void ClangToolsUnitTests::addTestRow(const QByteArray &relativeFilePath,
int expectedDiagCount, int expectedDiagCountClangTidy,
int expectedDiagCountClazy,
const ClangDiagnosticConfig &diagnosticConfig) const ClangDiagnosticConfig &diagnosticConfig)
{ {
const QString absoluteFilePath = m_tmpDir->absolutePath(relativeFilePath); const QString absoluteFilePath = m_tmpDir->absolutePath(relativeFilePath);
const QString fileName = QFileInfo(absoluteFilePath).fileName(); const QString fileName = QFileInfo(absoluteFilePath).fileName();
QTest::newRow(fileName.toUtf8().constData()) QTest::newRow(fileName.toUtf8().constData())
<< absoluteFilePath << expectedDiagCount << diagnosticConfig; << absoluteFilePath << expectedDiagCountClangTidy << expectedDiagCountClazy
<< diagnosticConfig;
} }
int ClangToolsUnitTests::getTimeout() int ClangToolsUnitTests::getTimeout()

View File

@@ -30,7 +30,7 @@ private slots:
private: private:
void addTestRow(const QByteArray &relativeFilePath, void addTestRow(const QByteArray &relativeFilePath,
int expectedDiagCount, int expectedDiagCountClangTidy, int expectedDiagCountClazy,
const CppEditor::ClangDiagnosticConfig &diagnosticConfig); const CppEditor::ClangDiagnosticConfig &diagnosticConfig);
private: private: