Commit 314f77fa authored by hjk's avatar hjk

ClangStaticAnalyzer: Move closer to new target/tool split

The ClangStaticAnalyzer is a tool.

Change-Id: I1462997a99e49486b47accb302d3f5b7b0b672b6
Reviewed-by: Nikolai Kosjar's avatarNikolai Kosjar <nikolai.kosjar@qt.io>
parent 5b720923
......@@ -124,8 +124,8 @@ bool ClangStaticAnalyzerPlugin::initialize(const QStringList &arguments, QString
panelFactory->setCreateWidgetFunction([](Project *project) { return new ProjectSettingsWidget(project); });
ProjectPanelFactory::registerFactory(panelFactory);
m_analyzerTool = new ClangStaticAnalyzerTool(this);
addAutoReleasedObject(new ClangStaticAnalyzerRunControlFactory(m_analyzerTool));
addAutoReleasedObject(new ClangStaticAnalyzerTool);
addAutoReleasedObject(new ClangStaticAnalyzerRunControlFactory);
addAutoReleasedObject(new ClangStaticAnalyzerOptionsPage);
return true;
......@@ -150,8 +150,8 @@ QList<QObject *> ClangStaticAnalyzerPlugin::createTestObjects() const
{
QList<QObject *> tests;
#ifdef WITH_TESTS
tests << new ClangStaticAnalyzerPreconfiguredSessionTests(m_analyzerTool);
tests << new ClangStaticAnalyzerUnitTests(m_analyzerTool);
tests << new ClangStaticAnalyzerPreconfiguredSessionTests;
tests << new ClangStaticAnalyzerUnitTests;
#endif
return tests;
}
......
......@@ -30,7 +30,6 @@
namespace ClangStaticAnalyzer {
namespace Internal {
class ClangStaticAnalyzerTool;
class ClangStaticAnalyzerSettings;
class ClangStaticAnalyzerPlugin : public ExtensionSystem::IPlugin
......@@ -49,8 +48,6 @@ public:
private:
QList<QObject *> createTestObjects() const;
ClangStaticAnalyzerTool *m_analyzerTool;
};
} // namespace Internal
......
......@@ -96,14 +96,6 @@ private:
namespace ClangStaticAnalyzer {
namespace Internal {
ClangStaticAnalyzerPreconfiguredSessionTests::ClangStaticAnalyzerPreconfiguredSessionTests(
ClangStaticAnalyzerTool *analyzerTool,
QObject *parent)
: QObject(parent)
, m_analyzerTool(*analyzerTool)
{
}
void ClangStaticAnalyzerPreconfiguredSessionTests::initTestCase()
{
const QString preconfiguredSessionName = QLatin1String("ClangStaticAnalyzerPreconfiguredSession");
......@@ -127,13 +119,13 @@ void ClangStaticAnalyzerPreconfiguredSessionTests::testPreconfiguredSession()
QVERIFY(switchToProjectAndTarget(project, target));
m_analyzerTool.startTool();
QSignalSpy waitUntilAnalyzerFinished(&m_analyzerTool, SIGNAL(finished(bool)));
ClangStaticAnalyzerTool::instance()->startTool();
QSignalSpy waitUntilAnalyzerFinished(ClangStaticAnalyzerTool::instance(), SIGNAL(finished(bool)));
QVERIFY(waitUntilAnalyzerFinished.wait(30000));
const QList<QVariant> arguments = waitUntilAnalyzerFinished.takeFirst();
const bool analyzerFinishedSuccessfully = arguments.first().toBool();
QVERIFY(analyzerFinishedSuccessfully);
QCOMPARE(m_analyzerTool.diagnostics().count(), 0);
QCOMPARE(ClangStaticAnalyzerTool::instance()->diagnostics().count(), 0);
}
static QList<Project *> validProjects(const QList<Project *> projectsOfSession)
......
......@@ -35,16 +35,11 @@ class Target;
namespace ClangStaticAnalyzer {
namespace Internal {
class ClangStaticAnalyzerTool;
class ClangStaticAnalyzerPreconfiguredSessionTests: public QObject
{
Q_OBJECT
public:
ClangStaticAnalyzerPreconfiguredSessionTests(ClangStaticAnalyzerTool *analyzerTool,
QObject *parent = 0);
private slots:
void initTestCase();
......@@ -54,8 +49,6 @@ private slots:
private:
bool switchToProjectAndTarget(ProjectExplorer::Project *project,
ProjectExplorer::Target *target);
ClangStaticAnalyzerTool &m_analyzerTool;
};
} // namespace Internal
......
......@@ -28,6 +28,7 @@
#include "clangstaticanalyzerlogfilereader.h"
#include "clangstaticanalyzerrunner.h"
#include "clangstaticanalyzersettings.h"
#include "clangstaticanalyzertool.h"
#include "clangstaticanalyzerutils.h"
#include <debugger/analyzer/analyzerconstants.h>
......@@ -57,6 +58,7 @@
#include <utils/hostosinfo.h>
#include <utils/temporarydirectory.h>
#include <QAction>
#include <QLoggingCategory>
using namespace CppTools;
......@@ -67,21 +69,52 @@ static Q_LOGGING_CATEGORY(LOG, "qtc.clangstaticanalyzer.runcontrol")
namespace ClangStaticAnalyzer {
namespace Internal {
ClangStaticAnalyzerRunControl::ClangStaticAnalyzerRunControl(
RunConfiguration *runConfiguration,
Core::Id runMode,
const ProjectInfo &projectInfo)
: RunControl(runConfiguration, runMode)
, m_projectInfo(projectInfo)
, m_initialFilesToProcessSize(0)
, m_filesAnalyzed(0)
, m_filesNotAnalyzed(0)
ClangStaticAnalyzerToolRunner::ClangStaticAnalyzerToolRunner(RunControl *runControl,
QString *errorMessage)
: ToolRunner(runControl)
{
setDisplayName(tr("Clang Static Analyzer"));
setIcon(ProjectExplorer::Icons::ANALYZER_START_SMALL_TOOLBAR);
setSupportsReRunning(false);
runControl->setDisplayName(tr("Clang Static Analyzer"));
runControl->setIcon(ProjectExplorer::Icons::ANALYZER_START_SMALL_TOOLBAR);
runControl->setSupportsReRunning(false);
RunConfiguration *runConfiguration = runControl->runConfiguration();
auto tool = ClangStaticAnalyzerTool::instance();
connect(tool->stopAction(), &QAction::triggered, runControl, &RunControl::stop);
ProjectInfo projectInfoBeforeBuild = tool->projectInfoBeforeBuild();
QTC_ASSERT(projectInfoBeforeBuild.isValid(), return);
QTC_ASSERT(runConfiguration, return);
Target * const target = runConfiguration->target();
QTC_ASSERT(target, return);
Project * const project = target->project();
QTC_ASSERT(project, return);
// so pass on the updated Project Info unless no configuration change
// (defines/includes/files) happened.
const CppTools::ProjectInfo projectInfoAfterBuild
= CppTools::CppModelManager::instance()->projectInfo(project);
if (projectInfoAfterBuild.configurationOrFilesChanged(projectInfoBeforeBuild)) {
// If it's more than a release/debug build configuration change, e.g.
// a version control checkout, files might be not valid C++ anymore
// or even gone, so better stop here.
tool->resetCursorAndProjectInfoBeforeBuild();
if (errorMessage) {
*errorMessage = tr(
"The project configuration changed since the start of the Clang Static Analyzer. "
"Please re-run with current configuration.");
}
return;
}
// Some projects provides CompilerCallData once a build is finished,
QTC_ASSERT(!projectInfoAfterBuild.configurationOrFilesChanged(projectInfoBeforeBuild),
return);
m_projectInfo = projectInfoAfterBuild;
Target *target = runConfiguration->target();
BuildConfiguration *buildConfiguration = target->activeBuildConfiguration();
QTC_ASSERT(buildConfiguration, return);
m_environment = buildConfiguration->environment();
......@@ -89,6 +122,7 @@ ClangStaticAnalyzerRunControl::ClangStaticAnalyzerRunControl(
ToolChain *toolChain = ToolChainKitInformation::toolChain(target->kit(), ProjectExplorer::Constants::CXX_LANGUAGE_ID);
QTC_ASSERT(toolChain, return);
m_targetTriple = toolChain->originalTargetTriple();
m_toolChainType = toolChain->typeId();
}
static void prependWordWidthArgumentIfNotIncluded(QStringList *arguments,
......@@ -409,7 +443,7 @@ static QHash<QString, ProjectPart::Ptr> generateCallGroupToProjectPartMapping(
return mapping;
}
AnalyzeUnits ClangStaticAnalyzerRunControl::sortedUnitsToAnalyze()
AnalyzeUnits ClangStaticAnalyzerToolRunner::sortedUnitsToAnalyze()
{
QTC_ASSERT(m_projectInfo.isValid(), return AnalyzeUnits());
......@@ -443,12 +477,6 @@ static QDebug operator<<(QDebug debug, const AnalyzeUnits &analyzeUnits)
return debug;
}
static Core::Id toolchainType(ProjectExplorer::RunConfiguration *runConfiguration)
{
QTC_ASSERT(runConfiguration, return Core::Id());
return ToolChainKitInformation::toolChain(runConfiguration->target()->kit(), ProjectExplorer::Constants::CXX_LANGUAGE_ID)->typeId();
}
static QString executableForVersionCheck(Core::Id toolchainType, const QString &executable)
{
if (toolchainType == ProjectExplorer::Constants::MSVC_TOOLCHAIN_TYPEID) {
......@@ -464,20 +492,19 @@ static QString executableForVersionCheck(Core::Id toolchainType, const QString &
return executable;
}
void ClangStaticAnalyzerRunControl::start()
void ClangStaticAnalyzerToolRunner::start()
{
m_success = false;
emit starting();
ClangStaticAnalyzerTool::instance()->onEngineIsStarting();
QTC_ASSERT(m_projectInfo.isValid(), reportApplicationStop(); return);
QTC_ASSERT(m_projectInfo.isValid(), reportFailure(); return);
const Utils::FileName projectFile = m_projectInfo.project()->projectFilePath();
appendMessage(tr("Running Clang Static Analyzer on %1").arg(projectFile.toUserOutput())
+ QLatin1Char('\n'), Utils::NormalMessageFormat);
// Check clang executable
bool isValidClangExecutable;
const Core::Id theToolchainType = toolchainType(runConfiguration());
const QString executable = clangExecutableFromSettings(theToolchainType,
const QString executable = clangExecutableFromSettings(m_toolChainType,
&isValidClangExecutable);
if (!isValidClangExecutable) {
const QString errorMessage = tr("Clang Static Analyzer: Invalid executable \"%1\", stop.")
......@@ -485,12 +512,12 @@ void ClangStaticAnalyzerRunControl::start()
appendMessage(errorMessage + QLatin1Char('\n'), Utils::ErrorMessageFormat);
TaskHub::addTask(Task::Error, errorMessage, Debugger::Constants::ANALYZERTASK_ID);
TaskHub::requestPopup();
reportApplicationStop();
reportFailure();
return;
}
// Check clang version
const QString versionCheckExecutable = executableForVersionCheck(theToolchainType, executable);
const QString versionCheckExecutable = executableForVersionCheck(m_toolChainType, executable);
const ClangExecutableVersion version = clangExecutableVersion(versionCheckExecutable);
if (!version.isValid()) {
const QString warningMessage
......@@ -522,7 +549,7 @@ void ClangStaticAnalyzerRunControl::start()
appendMessage(errorMessage + QLatin1Char('\n'), Utils::ErrorMessageFormat);
TaskHub::addTask(Task::Error, errorMessage, Debugger::Constants::ANALYZERTASK_ID);
TaskHub::requestPopup();
reportApplicationStop();
reportFailure(errorMessage);
return;
}
m_clangLogFileDir = temporaryDir.path();
......@@ -542,7 +569,7 @@ void ClangStaticAnalyzerRunControl::start()
= ProgressManager::addTask(m_progress.future(), tr("Analyzing"), "ClangStaticAnalyzer");
futureProgress->setKeepOnFinish(FutureProgress::HideOnFinish);
connect(futureProgress, &FutureProgress::canceled,
this, &ClangStaticAnalyzerRunControl::onProgressCanceled);
this, &ClangStaticAnalyzerToolRunner::onProgressCanceled);
m_progress.setProgressRange(0, m_initialFilesToProcessSize);
m_progress.reportStarted();
......@@ -550,7 +577,7 @@ void ClangStaticAnalyzerRunControl::start()
qCDebug(LOG) << "Environment:" << m_environment;
m_runners.clear();
const int parallelRuns = ClangStaticAnalyzerSettings::instance()->simultaneousProcesses();
QTC_ASSERT(parallelRuns >= 1, reportApplicationStop(); return);
QTC_ASSERT(parallelRuns >= 1, reportFailure(); return);
m_success = true;
if (m_unitsToProcess.isEmpty()) {
......@@ -558,13 +585,13 @@ void ClangStaticAnalyzerRunControl::start()
return;
}
reportApplicationStart();
reportSuccess();
while (m_runners.size() < parallelRuns && !m_unitsToProcess.isEmpty())
analyzeNextFile();
}
void ClangStaticAnalyzerRunControl::stop()
void ClangStaticAnalyzerToolRunner::stop()
{
QSetIterator<ClangStaticAnalyzerRunner *> i(m_runners);
while (i.hasNext()) {
......@@ -577,10 +604,15 @@ void ClangStaticAnalyzerRunControl::stop()
appendMessage(tr("Clang Static Analyzer stopped by user.") + QLatin1Char('\n'),
Utils::NormalMessageFormat);
m_progress.reportFinished();
reportApplicationStop();
reportStopped();
}
void ClangStaticAnalyzerToolRunner::onFinished()
{
ClangStaticAnalyzerTool::instance()->onEngineFinished(m_success);
}
void ClangStaticAnalyzerRunControl::analyzeNextFile()
void ClangStaticAnalyzerToolRunner::analyzeNextFile()
{
if (m_progress.isFinished())
return; // The previous call already reported that we are finished.
......@@ -603,7 +635,7 @@ void ClangStaticAnalyzerRunControl::analyzeNextFile()
Utils::StdOutFormat);
}
ClangStaticAnalyzerRunner *ClangStaticAnalyzerRunControl::createRunner()
ClangStaticAnalyzerRunner *ClangStaticAnalyzerToolRunner::createRunner()
{
QTC_ASSERT(!m_clangExecutable.isEmpty(), return 0);
QTC_ASSERT(!m_clangLogFileDir.isEmpty(), return 0);
......@@ -613,13 +645,13 @@ ClangStaticAnalyzerRunner *ClangStaticAnalyzerRunControl::createRunner()
m_environment,
this);
connect(runner, &ClangStaticAnalyzerRunner::finishedWithSuccess,
this, &ClangStaticAnalyzerRunControl::onRunnerFinishedWithSuccess);
this, &ClangStaticAnalyzerToolRunner::onRunnerFinishedWithSuccess);
connect(runner, &ClangStaticAnalyzerRunner::finishedWithFailure,
this, &ClangStaticAnalyzerRunControl::onRunnerFinishedWithFailure);
this, &ClangStaticAnalyzerToolRunner::onRunnerFinishedWithFailure);
return runner;
}
void ClangStaticAnalyzerRunControl::onRunnerFinishedWithSuccess(const QString &logFilePath)
void ClangStaticAnalyzerToolRunner::onRunnerFinishedWithSuccess(const QString &logFilePath)
{
qCDebug(LOG) << "onRunnerFinishedWithSuccess:" << logFilePath;
......@@ -634,14 +666,14 @@ void ClangStaticAnalyzerRunControl::onRunnerFinishedWithSuccess(const QString &l
} else {
++m_filesAnalyzed;
if (!diagnostics.isEmpty())
emit newDiagnosticsAvailable(diagnostics);
ClangStaticAnalyzerTool::instance()->onNewDiagnosticsAvailable(diagnostics);
}
handleFinished();
}
void ClangStaticAnalyzerRunControl::onRunnerFinishedWithFailure(const QString &errorMessage,
const QString &errorDetails)
void ClangStaticAnalyzerToolRunner::onRunnerFinishedWithFailure(const QString &errorMessage,
const QString &errorDetails)
{
qCDebug(LOG).noquote() << "onRunnerFinishedWithFailure:"
<< errorMessage << '\n' << errorDetails;
......@@ -658,7 +690,7 @@ void ClangStaticAnalyzerRunControl::onRunnerFinishedWithFailure(const QString &e
handleFinished();
}
void ClangStaticAnalyzerRunControl::handleFinished()
void ClangStaticAnalyzerToolRunner::handleFinished()
{
m_runners.remove(qobject_cast<ClangStaticAnalyzerRunner *>(sender()));
updateProgressValue();
......@@ -666,18 +698,18 @@ void ClangStaticAnalyzerRunControl::handleFinished()
analyzeNextFile();
}
void ClangStaticAnalyzerRunControl::onProgressCanceled()
void ClangStaticAnalyzerToolRunner::onProgressCanceled()
{
m_progress.reportCanceled();
stop();
}
void ClangStaticAnalyzerRunControl::updateProgressValue()
void ClangStaticAnalyzerToolRunner::updateProgressValue()
{
m_progress.setProgressValue(m_initialFilesToProcessSize - m_unitsToProcess.size());
}
void ClangStaticAnalyzerRunControl::finalize()
void ClangStaticAnalyzerToolRunner::finalize()
{
appendMessage(tr("Clang Static Analyzer finished: "
"Processed %1 files successfully, %2 failed.")
......@@ -693,7 +725,7 @@ void ClangStaticAnalyzerRunControl::finalize()
}
m_progress.reportFinished();
reportApplicationStop();
reportStopped();
}
} // namespace Internal
......
......@@ -47,24 +47,19 @@ struct AnalyzeUnit {
};
typedef QList<AnalyzeUnit> AnalyzeUnits;
class ClangStaticAnalyzerRunControl : public ProjectExplorer::RunControl
class ClangStaticAnalyzerToolRunner : public ProjectExplorer::ToolRunner
{
Q_OBJECT
public:
ClangStaticAnalyzerRunControl(ProjectExplorer::RunConfiguration *runConfiguration,
Core::Id runMode,
const CppTools::ProjectInfo &projectInfo);
ClangStaticAnalyzerToolRunner(ProjectExplorer::RunControl *runControl, QString *errorMessage);
void start() override;
void stop() override;
void onFinished() override;
bool success() const { return m_success; } // For testing.
signals:
void newDiagnosticsAvailable(const QList<Diagnostic> &diagnostics);
void starting();
private:
AnalyzeUnits sortedUnitsToAnalyze();
void analyzeNextFile();
......@@ -80,8 +75,9 @@ private:
void finalize();
private:
const CppTools::ProjectInfo m_projectInfo;
CppTools::ProjectInfo m_projectInfo;
QString m_targetTriple;
Core::Id m_toolChainType;
Utils::Environment m_environment;
QString m_clangExecutable;
......@@ -89,10 +85,10 @@ private:
QFutureInterface<void> m_progress;
AnalyzeUnits m_unitsToProcess;
QSet<ClangStaticAnalyzerRunner *> m_runners;
int m_initialFilesToProcessSize;
int m_filesAnalyzed;
int m_filesNotAnalyzed;
bool m_success;
int m_initialFilesToProcessSize = 0;
int m_filesAnalyzed = 0;
int m_filesNotAnalyzed = 0;
bool m_success = false;
};
} // namespace Internal
......
......@@ -26,20 +26,12 @@
#include "clangstaticanalyzerruncontrolfactory.h"
#include "clangstaticanalyzerconstants.h"
#include "clangstaticanalyzerruncontrol.h"
#include <coreplugin/icontext.h>
#include <cpptools/cppmodelmanager.h>
#include <projectexplorer/buildconfiguration.h>
#include <projectexplorer/gcctoolchain.h>
#include <projectexplorer/kit.h>
#include <projectexplorer/kitinformation.h>
#include <projectexplorer/project.h>
#include <projectexplorer/projectexplorerconstants.h>
#include <projectexplorer/session.h>
#include <projectexplorer/target.h>
#include <projectexplorer/toolchain.h>
#include <utils/qtcassert.h>
......@@ -48,66 +40,30 @@ using namespace ProjectExplorer;
namespace ClangStaticAnalyzer {
namespace Internal {
ClangStaticAnalyzerRunControlFactory::ClangStaticAnalyzerRunControlFactory(
ClangStaticAnalyzerTool *tool,
QObject *parent)
: IRunControlFactory(parent)
, m_tool(tool)
{
QTC_CHECK(m_tool);
}
bool ClangStaticAnalyzerRunControlFactory::canRun(RunConfiguration *runConfiguration,
Core::Id runMode) const
{
if (runMode != Constants::CLANGSTATICANALYZER_RUN_MODE)
return false;
Project *project = runConfiguration->target()->project();
QTC_ASSERT(project, return false);
const Core::Context context = project->projectLanguages();
if (!context.contains(ProjectExplorer::Constants::CXX_LANGUAGE_ID))
return false;
Target *target = runConfiguration->target();
QTC_ASSERT(target, return false);
Kit *kit = target->kit();
QTC_ASSERT(kit, return false);
ToolChain *toolChain = ToolChainKitInformation::toolChain(kit, ProjectExplorer::Constants::CXX_LANGUAGE_ID);
return toolChain;
Project *project = target->project();
QTC_ASSERT(project, return false);
const Core::Id cxx = ProjectExplorer::Constants::CXX_LANGUAGE_ID;
return project->projectLanguages().contains(cxx)
&& ToolChainKitInformation::toolChain(target->kit(), cxx);
}
RunControl *ClangStaticAnalyzerRunControlFactory::create(RunConfiguration *runConfiguration,
Core::Id runMode,
QString *errorMessage)
{
using namespace CppTools;
const ProjectInfo projectInfoBeforeBuild = m_tool->projectInfoBeforeBuild();
QTC_ASSERT(projectInfoBeforeBuild.isValid(), return 0);
QTC_ASSERT(runConfiguration, return 0);
Target * const target = runConfiguration->target();
QTC_ASSERT(target, return 0);
Project * const project = target->project();
QTC_ASSERT(project, return 0);
const ProjectInfo projectInfoAfterBuild = CppModelManager::instance()->projectInfo(project);
if (projectInfoAfterBuild.configurationOrFilesChanged(projectInfoBeforeBuild)) {
// If it's more than a release/debug build configuration change, e.g.
// a version control checkout, files might be not valid C++ anymore
// or even gone, so better stop here.
m_tool->resetCursorAndProjectInfoBeforeBuild();
if (errorMessage) {
*errorMessage = tr(
"The project configuration changed since the start of the Clang Static Analyzer. "
"Please re-run with current configuration.");
}
return 0;
}
return m_tool->createRunControl(runConfiguration, runMode);
auto runControl = new RunControl(runConfiguration, runMode);
(void) new ClangStaticAnalyzerToolRunner(runControl, errorMessage);
return runControl;
}
} // namespace Internal
......
......@@ -25,8 +25,6 @@
#pragma once
#include "clangstaticanalyzertool.h"
#include <projectexplorer/runconfiguration.h>
namespace ClangStaticAnalyzer {
......@@ -37,17 +35,11 @@ class ClangStaticAnalyzerRunControlFactory : public ProjectExplorer::IRunControl
Q_OBJECT
public:
explicit ClangStaticAnalyzerRunControlFactory(ClangStaticAnalyzerTool *tool,
QObject *parent = 0);
bool canRun(ProjectExplorer::RunConfiguration *runConfiguration,
Core::Id runMode) const override;
ProjectExplorer::RunControl *create(ProjectExplorer::RunConfiguration *runConfiguration,
Core::Id runMode, QString *errorMessage) override;
private:
ClangStaticAnalyzerTool *m_tool;
};
} // namespace Internal
......
......@@ -80,16 +80,12 @@ private:
QWidget *createConfigurationWidget() override { return 0; }
};
ClangStaticAnalyzerTool::ClangStaticAnalyzerTool(QObject *parent)
: QObject(parent)
, m_diagnosticModel(0)
, m_diagnosticFilterModel(0)
, m_diagnosticView(0)
, m_goBack(0)
, m_goNext(0)
, m_running(false)
static ClangStaticAnalyzerTool *s_instance;
ClangStaticAnalyzerTool::ClangStaticAnalyzerTool()
{
setObjectName(QLatin1String("ClangStaticAnalyzerTool"));
setObjectName("ClangStaticAnalyzerTool");
s_instance = this;
//
// Diagnostic View
......@@ -173,37 +169,14 @@ ClangStaticAnalyzerTool::ClangStaticAnalyzerTool(QObject *parent)
this, &ClangStaticAnalyzerTool::updateRunActions);