forked from qt-creator/qt-creator
ClangStaticAnalyzer: Move closer to new target/tool split
The ClangStaticAnalyzer is a tool. Change-Id: I1462997a99e49486b47accb302d3f5b7b0b672b6 Reviewed-by: Nikolai Kosjar <nikolai.kosjar@qt.io>
This commit is contained in:
@@ -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 ClangStaticAnalyzerRunControl::analyzeNextFile()
|
||||
void ClangStaticAnalyzerToolRunner::onFinished()
|
||||
{
|
||||
ClangStaticAnalyzerTool::instance()->onEngineFinished(m_success);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
RunControl *ClangStaticAnalyzerTool::createRunControl(RunConfiguration *runConfiguration,
|
||||
Core::Id runMode)
|
||||
ClangStaticAnalyzerTool::~ClangStaticAnalyzerTool()
|
||||
{
|
||||
QTC_ASSERT(runConfiguration, return 0);
|
||||
QTC_ASSERT(m_projectInfoBeforeBuild.isValid(), return 0);
|
||||
|
||||
// Some projects provides CompilerCallData once a build is finished,
|
||||
// so pass on the updated Project Info unless no configuration change
|
||||
// (defines/includes/files) happened.
|
||||
Project *project = runConfiguration->target()->project();
|
||||
QTC_ASSERT(project, return 0);
|
||||
const CppTools::ProjectInfo projectInfoAfterBuild
|
||||
= CppTools::CppModelManager::instance()->projectInfo(project);
|
||||
QTC_ASSERT(!projectInfoAfterBuild.configurationOrFilesChanged(m_projectInfoBeforeBuild),
|
||||
return 0);
|
||||
m_projectInfoBeforeBuild = CppTools::ProjectInfo();
|
||||
}
|
||||
|
||||
auto runControl = new ClangStaticAnalyzerRunControl(runConfiguration, runMode,
|
||||
projectInfoAfterBuild);
|
||||
connect(runControl, &ClangStaticAnalyzerRunControl::starting,
|
||||
this, &ClangStaticAnalyzerTool::onEngineIsStarting);
|
||||
connect(runControl, &ClangStaticAnalyzerRunControl::newDiagnosticsAvailable,
|
||||
this, &ClangStaticAnalyzerTool::onNewDiagnosticsAvailable);
|
||||
connect(runControl, &ClangStaticAnalyzerRunControl::finished,
|
||||
this, &ClangStaticAnalyzerTool::onEngineFinished);
|
||||
|
||||
connect(m_stopAction, &QAction::triggered, runControl, [runControl] { runControl->stop(); });
|
||||
|
||||
m_toolBusy = true;
|
||||
updateRunActions();
|
||||
return runControl;
|
||||
ClangStaticAnalyzerTool *ClangStaticAnalyzerTool::instance()
|
||||
{
|
||||
return s_instance;
|
||||
}
|
||||
|
||||
static bool dontStartAfterHintForDebugMode(Project *project)
|
||||
@@ -255,6 +228,9 @@ void ClangStaticAnalyzerTool::startTool()
|
||||
m_running = true;
|
||||
handleStateUpdate();
|
||||
|
||||
m_toolBusy = true;
|
||||
updateRunActions();
|
||||
|
||||
Target * const target = project->activeTarget();
|
||||
QTC_ASSERT(target, return);
|
||||
DummyRunConfiguration *& rc = m_runConfigs[target];
|
||||
@@ -299,12 +275,12 @@ void ClangStaticAnalyzerTool::onNewDiagnosticsAvailable(const QList<Diagnostic>
|
||||
m_diagnosticModel->addDiagnostics(diagnostics);
|
||||
}
|
||||
|
||||
void ClangStaticAnalyzerTool::onEngineFinished()
|
||||
void ClangStaticAnalyzerTool::onEngineFinished(bool success)
|
||||
{
|
||||
resetCursorAndProjectInfoBeforeBuild();
|
||||
m_running = false;
|
||||
handleStateUpdate();
|
||||
emit finished(static_cast<ClangStaticAnalyzerRunControl *>(sender())->success());
|
||||
emit finished(success);
|
||||
m_toolBusy = false;
|
||||
updateRunActions();
|
||||
}
|
||||
|
||||
@@ -47,26 +47,28 @@ class ClangStaticAnalyzerTool : public QObject
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit ClangStaticAnalyzerTool(QObject *parent = 0);
|
||||
ClangStaticAnalyzerTool();
|
||||
~ClangStaticAnalyzerTool();
|
||||
|
||||
static ClangStaticAnalyzerTool *instance();
|
||||
QAction *stopAction() { return m_stopAction; }
|
||||
|
||||
CppTools::ProjectInfo projectInfoBeforeBuild() const;
|
||||
void resetCursorAndProjectInfoBeforeBuild();
|
||||
|
||||
// For testing.
|
||||
bool isRunning() const { return m_running; }
|
||||
QList<Diagnostic> diagnostics() const;
|
||||
|
||||
ProjectExplorer::RunControl *createRunControl(ProjectExplorer::RunConfiguration *runConfiguration,
|
||||
Core::Id runMode);
|
||||
void startTool();
|
||||
|
||||
void onEngineIsStarting();
|
||||
void onNewDiagnosticsAvailable(const QList<Diagnostic> &diagnostics);
|
||||
void onEngineFinished(bool success);
|
||||
|
||||
signals:
|
||||
void finished(bool success); // For testing.
|
||||
|
||||
private:
|
||||
void onEngineIsStarting();
|
||||
void onNewDiagnosticsAvailable(const QList<Diagnostic> &diagnostics);
|
||||
void onEngineFinished();
|
||||
|
||||
void setBusyCursor(bool busy);
|
||||
void handleStateUpdate();
|
||||
void updateRunActions();
|
||||
@@ -74,16 +76,16 @@ private:
|
||||
private:
|
||||
CppTools::ProjectInfo m_projectInfoBeforeBuild;
|
||||
|
||||
ClangStaticAnalyzerDiagnosticModel *m_diagnosticModel;
|
||||
ClangStaticAnalyzerDiagnosticFilterModel *m_diagnosticFilterModel;
|
||||
ClangStaticAnalyzerDiagnosticView *m_diagnosticView;
|
||||
ClangStaticAnalyzerDiagnosticModel *m_diagnosticModel = nullptr;
|
||||
ClangStaticAnalyzerDiagnosticFilterModel *m_diagnosticFilterModel = nullptr;
|
||||
ClangStaticAnalyzerDiagnosticView *m_diagnosticView = nullptr;
|
||||
|
||||
QAction *m_startAction = 0;
|
||||
QAction *m_stopAction = 0;
|
||||
QAction *m_goBack;
|
||||
QAction *m_goNext;
|
||||
QAction *m_startAction = nullptr;
|
||||
QAction *m_stopAction = nullptr;
|
||||
QAction *m_goBack = nullptr;
|
||||
QAction *m_goNext = nullptr;
|
||||
QHash<ProjectExplorer::Target *, DummyRunConfiguration *> m_runConfigs;
|
||||
bool m_running;
|
||||
bool m_running = false;
|
||||
bool m_toolBusy = false;
|
||||
};
|
||||
|
||||
|
||||
@@ -48,14 +48,6 @@ using namespace Utils;
|
||||
namespace ClangStaticAnalyzer {
|
||||
namespace Internal {
|
||||
|
||||
ClangStaticAnalyzerUnitTests::ClangStaticAnalyzerUnitTests(ClangStaticAnalyzerTool *analyzerTool,
|
||||
QObject *parent)
|
||||
: QObject(parent)
|
||||
, m_analyzerTool(analyzerTool)
|
||||
, m_tmpDir(0)
|
||||
{
|
||||
}
|
||||
|
||||
void ClangStaticAnalyzerUnitTests::initTestCase()
|
||||
{
|
||||
const QList<Kit *> allKits = KitManager::kits();
|
||||
@@ -87,12 +79,13 @@ void ClangStaticAnalyzerUnitTests::testProject()
|
||||
CppTools::Tests::ProjectOpenerAndCloser projectManager;
|
||||
const CppTools::ProjectInfo projectInfo = projectManager.open(projectFilePath, true);
|
||||
QVERIFY(projectInfo.isValid());
|
||||
m_analyzerTool->startTool();
|
||||
QSignalSpy waiter(m_analyzerTool, SIGNAL(finished(bool)));
|
||||
auto tool = ClangStaticAnalyzerTool::instance();
|
||||
tool->startTool();
|
||||
QSignalSpy waiter(tool, SIGNAL(finished(bool)));
|
||||
QVERIFY(waiter.wait(30000));
|
||||
const QList<QVariant> arguments = waiter.takeFirst();
|
||||
QVERIFY(arguments.first().toBool());
|
||||
QCOMPARE(m_analyzerTool->diagnostics().count(), expectedDiagCount);
|
||||
QCOMPARE(tool->diagnostics().count(), expectedDiagCount);
|
||||
}
|
||||
|
||||
void ClangStaticAnalyzerUnitTests::testProject_data()
|
||||
|
||||
@@ -31,14 +31,13 @@ namespace CppTools { namespace Tests { class TemporaryCopiedDir; } }
|
||||
|
||||
namespace ClangStaticAnalyzer {
|
||||
namespace Internal {
|
||||
class ClangStaticAnalyzerTool;
|
||||
|
||||
class ClangStaticAnalyzerUnitTests : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
ClangStaticAnalyzerUnitTests(ClangStaticAnalyzerTool *analyzerTool, QObject *parent = 0);
|
||||
ClangStaticAnalyzerUnitTests() {}
|
||||
|
||||
private slots:
|
||||
void initTestCase();
|
||||
@@ -50,8 +49,7 @@ private:
|
||||
void addTestRow(const QByteArray &relativeFilePath, int expectedDiagCount);
|
||||
|
||||
private:
|
||||
ClangStaticAnalyzerTool * const m_analyzerTool;
|
||||
CppTools::Tests::TemporaryCopiedDir *m_tmpDir;
|
||||
CppTools::Tests::TemporaryCopiedDir *m_tmpDir = nullptr;
|
||||
};
|
||||
|
||||
} // namespace Internal
|
||||
|
||||
Reference in New Issue
Block a user