summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKai Koehne <kai.koehne@theqtcompany.com>2014-11-18 15:08:43 +0100
committerKai Koehne <kai.koehne@theqtcompany.com>2014-11-18 15:08:49 +0100
commit9328c87ba4325b88b981753ba46faa34e9532704 (patch)
treeec2265a70c91e1af1d5266b96cbd5d4eb0006f6b
parentf6eb83490a3f4a793eea1dad3d0d23e4d2fc801c (diff)
parent37b8e7252e13a3b74c7e94a908f5818e60127c89 (diff)
downloadqt-creator-9328c87ba4325b88b981753ba46faa34e9532704.tar.gz
Merge branch '3.3'
Change-Id: Ibf7466649a400f8a652f284be8edd7e33a5f969a
-rw-r--r--plugins/clangstaticanalyzer/ClangStaticAnalyzer.json.in1
-rw-r--r--plugins/clangstaticanalyzer/clangstaticanalyzer.qbs47
-rw-r--r--plugins/clangstaticanalyzer/clangstaticanalyzerdiagnostic.cpp5
-rw-r--r--plugins/clangstaticanalyzer/clangstaticanalyzerdiagnostic.h2
-rw-r--r--plugins/clangstaticanalyzer/clangstaticanalyzerdiagnosticview.cpp3
-rw-r--r--plugins/clangstaticanalyzer/clangstaticanalyzerplugin.cpp5
-rw-r--r--plugins/clangstaticanalyzer/clangstaticanalyzerruncontrol.cpp210
-rw-r--r--plugins/clangstaticanalyzer/clangstaticanalyzerruncontrol.h23
-rw-r--r--plugins/clangstaticanalyzer/clangstaticanalyzerruncontrolfactory.cpp35
-rw-r--r--plugins/clangstaticanalyzer/clangstaticanalyzerruncontrolfactory.h8
-rw-r--r--plugins/clangstaticanalyzer/clangstaticanalyzerrunner.cpp21
-rw-r--r--plugins/clangstaticanalyzer/clangstaticanalyzerrunner.h3
-rw-r--r--plugins/clangstaticanalyzer/clangstaticanalyzertool.cpp87
-rw-r--r--plugins/clangstaticanalyzer/clangstaticanalyzertool.h5
14 files changed, 361 insertions, 94 deletions
diff --git a/plugins/clangstaticanalyzer/ClangStaticAnalyzer.json.in b/plugins/clangstaticanalyzer/ClangStaticAnalyzer.json.in
index 77cc31b40d..13c2aa5b82 100644
--- a/plugins/clangstaticanalyzer/ClangStaticAnalyzer.json.in
+++ b/plugins/clangstaticanalyzer/ClangStaticAnalyzer.json.in
@@ -3,6 +3,7 @@
\"Version\" : \"$$QTCREATOR_VERSION\",
\"CompatVersion\" : \"$$QTCREATOR_COMPAT_VERSION\",
\"Experimental\" : true,
+ \"Platform\" : \"(Linux.*)|(OS X.*)\",
\"Vendor\" : \"Digia Plc\",
\"Copyright\" : \"(C) 2014 Digia Plc\",
\"License\" : [ \"Commercial Usage\",
diff --git a/plugins/clangstaticanalyzer/clangstaticanalyzer.qbs b/plugins/clangstaticanalyzer/clangstaticanalyzer.qbs
new file mode 100644
index 0000000000..6c2612a69c
--- /dev/null
+++ b/plugins/clangstaticanalyzer/clangstaticanalyzer.qbs
@@ -0,0 +1,47 @@
+import qbs
+
+QtcPlugin {
+ name: "ClangStaticAnalyzer"
+
+ Depends { name: "AnalyzerBase" }
+ Depends { name: "Core" }
+ Depends { name: "CppTools" }
+ Depends { name: "ExtensionSystem" }
+ Depends { name: "LicenseChecker" }
+ Depends { name: "ProjectExplorer" }
+ Depends { name: "QtcSsh" } // TODO: export + recursive dependencies broken in qbs
+ Depends { name: "Utils" }
+
+ Depends { name: "Qt.widgets" }
+ Depends { name: "Qt.network" } // TODO: See above
+
+ files: [
+ "clangstaticanalyzerconfigwidget.cpp",
+ "clangstaticanalyzerconfigwidget.h",
+ "clangstaticanalyzerconfigwidget.ui",
+ "clangstaticanalyzerconstants.h",
+ "clangstaticanalyzerdiagnostic.cpp",
+ "clangstaticanalyzerdiagnostic.h",
+ "clangstaticanalyzerdiagnosticmodel.cpp",
+ "clangstaticanalyzerdiagnosticmodel.h",
+ "clangstaticanalyzerdiagnosticview.cpp",
+ "clangstaticanalyzerdiagnosticview.h",
+ "clangstaticanalyzerlogfilereader.cpp",
+ "clangstaticanalyzerlogfilereader.h",
+ "clangstaticanalyzerplugin.cpp",
+ "clangstaticanalyzerplugin.h",
+ "clangstaticanalyzerruncontrol.cpp",
+ "clangstaticanalyzerruncontrol.h",
+ "clangstaticanalyzerruncontrolfactory.cpp",
+ "clangstaticanalyzerruncontrolfactory.h",
+ "clangstaticanalyzerrunner.cpp",
+ "clangstaticanalyzerrunner.h",
+ "clangstaticanalyzersettings.cpp",
+ "clangstaticanalyzersettings.h",
+ "clangstaticanalyzertool.cpp",
+ "clangstaticanalyzertool.h",
+ "clangstaticanalyzerutils.cpp",
+ "clangstaticanalyzerutils.h",
+ "clangstaticanalyzer_global.h",
+ ]
+}
diff --git a/plugins/clangstaticanalyzer/clangstaticanalyzerdiagnostic.cpp b/plugins/clangstaticanalyzer/clangstaticanalyzerdiagnostic.cpp
index e9152ffa47..09d810dfc9 100644
--- a/plugins/clangstaticanalyzer/clangstaticanalyzerdiagnostic.cpp
+++ b/plugins/clangstaticanalyzer/clangstaticanalyzerdiagnostic.cpp
@@ -46,5 +46,10 @@ bool ExplainingStep::isValid() const
return location.isValid() && !ranges.isEmpty() && !message.isEmpty();
}
+bool Diagnostic::isValid() const
+{
+ return !description.isEmpty();
+}
+
} // namespace Internal
} // namespace ClangStaticAnalyzer
diff --git a/plugins/clangstaticanalyzer/clangstaticanalyzerdiagnostic.h b/plugins/clangstaticanalyzer/clangstaticanalyzerdiagnostic.h
index 3348cfa416..75df6218a9 100644
--- a/plugins/clangstaticanalyzer/clangstaticanalyzerdiagnostic.h
+++ b/plugins/clangstaticanalyzer/clangstaticanalyzerdiagnostic.h
@@ -56,6 +56,8 @@ public:
class Diagnostic
{
public:
+ bool isValid() const;
+
QString description;
QString category;
QString type;
diff --git a/plugins/clangstaticanalyzer/clangstaticanalyzerdiagnosticview.cpp b/plugins/clangstaticanalyzer/clangstaticanalyzerdiagnosticview.cpp
index fd9e216ed7..6d00968c86 100644
--- a/plugins/clangstaticanalyzer/clangstaticanalyzerdiagnosticview.cpp
+++ b/plugins/clangstaticanalyzer/clangstaticanalyzerdiagnosticview.cpp
@@ -168,6 +168,7 @@ DetailedErrorDelegate::SummaryLineInfo ClangStaticAnalyzerDiagnosticDelegate::su
const QModelIndex &index) const
{
const Diagnostic diagnostic = index.data(Qt::UserRole).value<Diagnostic>();
+ QTC_ASSERT(diagnostic.isValid(), return SummaryLineInfo());
DetailedErrorDelegate::SummaryLineInfo info;
info.errorText = diagnostic.description;
@@ -188,6 +189,8 @@ QWidget *ClangStaticAnalyzerDiagnosticDelegate::createDetailsWidget(const QFont
QVBoxLayout *layout = new QVBoxLayout;
const Diagnostic diagnostic = index.data(Qt::UserRole).value<Diagnostic>();
+ if (!diagnostic.isValid())
+ return widget;
// Add summary label
QLabel *summaryLineLabel = createSummaryLabel(diagnostic);
diff --git a/plugins/clangstaticanalyzer/clangstaticanalyzerplugin.cpp b/plugins/clangstaticanalyzer/clangstaticanalyzerplugin.cpp
index 0a321d64e8..e635305b97 100644
--- a/plugins/clangstaticanalyzer/clangstaticanalyzerplugin.cpp
+++ b/plugins/clangstaticanalyzer/clangstaticanalyzerplugin.cpp
@@ -121,10 +121,9 @@ bool ClangStaticAnalyzerPlugin::initializeEnterpriseFeatures(const QStringList &
Q_UNUSED(arguments);
Q_UNUSED(errorString);
- addAutoReleasedObject(new ClangStaticAnalyzerOptionsPage);
- addAutoReleasedObject(new ClangStaticAnalyzerRunControlFactory);
-
m_analyzerTool = new ClangStaticAnalyzerTool(this);
+ addAutoReleasedObject(new ClangStaticAnalyzerRunControlFactory(m_analyzerTool));
+ addAutoReleasedObject(new ClangStaticAnalyzerOptionsPage);
const QString toolTip = tr("Clang Static Analyzer uses the analyzer from the clang project "
"to find bugs.");
diff --git a/plugins/clangstaticanalyzer/clangstaticanalyzerruncontrol.cpp b/plugins/clangstaticanalyzer/clangstaticanalyzerruncontrol.cpp
index e0c7b11e71..f9b3506102 100644
--- a/plugins/clangstaticanalyzer/clangstaticanalyzerruncontrol.cpp
+++ b/plugins/clangstaticanalyzer/clangstaticanalyzerruncontrol.cpp
@@ -37,6 +37,8 @@
#include <projectexplorer/project.h>
#include <projectexplorer/target.h>
+#include <utils/algorithm.h>
+
#include <QLoggingCategory>
#include <QTemporaryDir>
@@ -49,48 +51,124 @@ namespace ClangStaticAnalyzer {
namespace Internal {
ClangStaticAnalyzerRunControl::ClangStaticAnalyzerRunControl(
- const Analyzer::AnalyzerStartParameters &startParams,
- ProjectExplorer::RunConfiguration *runConfiguration)
+ const Analyzer::AnalyzerStartParameters &startParams,
+ ProjectExplorer::RunConfiguration *runConfiguration,
+ const ProjectInfo &projectInfo)
: AnalyzerRunControl(startParams, runConfiguration)
+ , m_projectInfo(projectInfo)
, m_initialFilesToProcessSize(0)
+ , m_filesAnalyzed(0)
+ , m_filesNotAnalyzed(0)
+{
+}
+
+// Removes (1) filePath (2) -o <somePath>
+static QStringList tweakedArguments(const QString &filePath, const QStringList &arguments)
{
+ QStringList newArguments;
+
+ bool skip = false;
+ foreach (const QString &argument, arguments) {
+ if (skip) {
+ skip = false;
+ continue;
+ } else if (argument == QLatin1String("-o")) {
+ skip = true;
+ continue;
+ } else if (argument == filePath) {
+ continue; // TODO: Let it in?
+ }
+
+ newArguments << argument;
+ }
+ QTC_CHECK(skip == false);
+
+ return newArguments;
}
-static QList<ClangStaticAnalyzerRunControl::SourceFileConfiguration> calculateFilesToProcess(
- Project *project)
+static QStringList argumentsFromProjectPart(const CppTools::ProjectPart::Ptr &projectPart,
+ CppTools::ProjectFile::Kind fileKind)
{
- typedef ClangStaticAnalyzerRunControl::SourceFileConfiguration SourceFileConfiguration;
- QTC_ASSERT(project, return QList<SourceFileConfiguration>());
- ProjectInfo projectInfo = CppModelManager::instance()->projectInfo(project);
- QTC_ASSERT(projectInfo, return QList<SourceFileConfiguration>());
+ QStringList result;
+
+ const bool objcExt = projectPart->languageExtensions & ProjectPart::ObjectiveCExtensions;
+ result += CppTools::CompilerOptionsBuilder::createLanguageOption(fileKind, objcExt);
+ result += CppTools::CompilerOptionsBuilder::createOptionsForLanguage(
+ projectPart->languageVersion,
+ projectPart->languageExtensions);
+ result += CppTools::CompilerOptionsBuilder::createDefineOptions(projectPart->toolchainDefines);
+ result += CppTools::CompilerOptionsBuilder::createDefineOptions(projectPart->projectDefines);
+ result += CppTools::CompilerOptionsBuilder::createHeaderPathOptions(projectPart->headerPaths);
+ result += QLatin1String("-fPIC"); // TODO: Remove?
+
+ return result;
+}
+
+static QList<ClangStaticAnalyzerRunControl::AnalyzeUnit> unitsToAnalyzeFromCompilerCallData(
+ const ProjectInfo::CompilerCallData &compilerCallData)
+{
+ typedef ClangStaticAnalyzerRunControl::AnalyzeUnit AnalyzeUnit;
+ qCDebug(LOG) << "Taking arguments for analyzing from CompilerCallData.";
+
+ QList<ClangStaticAnalyzerRunControl::AnalyzeUnit> unitsToAnalyze;
+
+ QHashIterator<QString, QList<QStringList> > it(compilerCallData);
+ while (it.hasNext()) {
+ it.next();
+ const QString file = it.key();
+ const QList<QStringList> compilerCalls = it.value();
+ foreach (const QStringList &options, compilerCalls) {
+ const QStringList arguments = tweakedArguments(file, options);
+ unitsToAnalyze << AnalyzeUnit(file, arguments);
+ }
+ }
+
+ return unitsToAnalyze;
+}
+
+static QList<ClangStaticAnalyzerRunControl::AnalyzeUnit> unitsToAnalyzeFromProjectParts(
+ const QList<ProjectPart::Ptr> projectParts)
+{
+ typedef ClangStaticAnalyzerRunControl::AnalyzeUnit AnalyzeUnit;
+ qCDebug(LOG) << "Taking arguments for analyzing from ProjectParts.";
+
+ QList<ClangStaticAnalyzerRunControl::AnalyzeUnit> unitsToAnalyze;
- QList<SourceFileConfiguration> files;
- const QList<ProjectPart::Ptr> projectParts = projectInfo.projectParts();
foreach (const ProjectPart::Ptr &projectPart, projectParts) {
+ if (!projectPart->selectedForBuilding)
+ continue;
+
foreach (const ProjectFile &file, projectPart->files) {
if (file.path == CppModelManager::configurationFileName())
continue;
QTC_CHECK(file.kind != ProjectFile::Unclassified);
- if (ProjectFile::isSource(file.kind))
- files << SourceFileConfiguration(file, projectPart);
+ if (ProjectFile::isSource(file.kind)) {
+ const QStringList arguments = argumentsFromProjectPart(projectPart, file.kind);
+ unitsToAnalyze << AnalyzeUnit(file.path, arguments);
+ }
}
}
- return files;
+ return unitsToAnalyze;
+}
+
+static QList<ClangStaticAnalyzerRunControl::AnalyzeUnit> unitsToAnalyze(
+ const CppTools::ProjectInfo &projectInfo)
+{
+ QTC_ASSERT(projectInfo.isValid(), return QList<ClangStaticAnalyzerRunControl::AnalyzeUnit>());
+
+ const ProjectInfo::CompilerCallData compilerCallData = projectInfo.compilerCallData();
+ if (!compilerCallData.isEmpty())
+ return unitsToAnalyzeFromCompilerCallData(compilerCallData);
+ return unitsToAnalyzeFromProjectParts(projectInfo.projectParts());
}
bool ClangStaticAnalyzerRunControl::startEngine()
{
emit starting(this);
- RunConfiguration *runConfig = runConfiguration();
- QTC_ASSERT(runConfig, emit finished(); return false);
- Target *target = runConfig->target();
- QTC_ASSERT(target, emit finished(); return false);
- Project *project = target->project();
- QTC_ASSERT(project, emit finished(); return false);
-
- const QString projectFile = project->projectFilePath().toString();
+ QTC_ASSERT(m_projectInfo.isValid(), emit finished(); return false);
+ const QString projectFile = m_projectInfo.project()->projectFilePath().toString();
appendMessage(tr("Running Clang Static Analyzer on %1").arg(projectFile) + QLatin1Char('\n'),
Utils::NormalMessageFormat);
@@ -118,14 +196,18 @@ bool ClangStaticAnalyzerRunControl::startEngine()
m_clangLogFileDir = temporaryDir.path();
// Collect files
- const QList<SourceFileConfiguration> filesToProcess = calculateFilesToProcess(project);
+ QList<AnalyzeUnit> unitsToProcess = unitsToAnalyze(m_projectInfo);
+ Utils::sort(unitsToProcess, [](const AnalyzeUnit &a1, const AnalyzeUnit &a2) -> bool {
+ return a1.file < a2.file;
+ });
+
qCDebug(LOG) << "Files to process:";
- foreach (const SourceFileConfiguration &fileConfig, filesToProcess) {
- qCDebug(LOG) << fileConfig.file.path + QLatin1String(" [")
- + fileConfig.projectPart->projectFile + QLatin1Char(']');
- }
- m_filesToProcess = filesToProcess;
- m_initialFilesToProcessSize = m_filesToProcess.count();
+ foreach (const AnalyzeUnit &fileConfig, unitsToProcess)
+ qCDebug(LOG) << fileConfig.file;
+ m_unitsToProcess = unitsToProcess;
+ m_initialFilesToProcessSize = m_unitsToProcess.count();
+ m_filesAnalyzed = 0;
+ m_filesNotAnalyzed = 0;
// Set up progress information
using namespace Core;
@@ -141,7 +223,7 @@ bool ClangStaticAnalyzerRunControl::startEngine()
m_runners.clear();
const int parallelRuns = ClangStaticAnalyzerSettings::instance()->simultaneousProcesses();
QTC_ASSERT(parallelRuns >= 1, emit finished(); return false);
- while (m_runners.size() < parallelRuns && !m_filesToProcess.isEmpty())
+ while (m_runners.size() < parallelRuns && !m_unitsToProcess.isEmpty())
analyzeNextFile();
return true;
}
@@ -155,8 +237,11 @@ void ClangStaticAnalyzerRunControl::stopEngine()
delete runner;
}
m_runners.clear();
- m_filesToProcess.clear();
- analyzeNextFile(); // emits finished
+ m_unitsToProcess.clear();
+ appendMessage(tr("Clang Static Analyzer stopped by user.") + QLatin1Char('\n'),
+ Utils::NormalMessageFormat);
+ m_progress.reportFinished();
+ emit finished();
}
void ClangStaticAnalyzerRunControl::analyzeNextFile()
@@ -164,9 +249,13 @@ void ClangStaticAnalyzerRunControl::analyzeNextFile()
if (m_progress.isFinished())
return; // The previous call already reported that we are finished.
- if (m_filesToProcess.isEmpty()) {
+ if (m_unitsToProcess.isEmpty()) {
if (m_runners.size() == 0) {
- appendMessage(tr("Clang Static Analyzer finished.") + QLatin1Char('\n'),
+ appendMessage(tr("Clang Static Analyzer finished: "
+ "Processed %1 files successfully, %2 failed.")
+ .arg(m_filesAnalyzed)
+ .arg(m_filesNotAnalyzed)
+ + QLatin1Char('\n'),
Utils::NormalMessageFormat);
m_progress.reportFinished();
emit finished();
@@ -174,14 +263,15 @@ void ClangStaticAnalyzerRunControl::analyzeNextFile()
return;
}
- const SourceFileConfiguration config = m_filesToProcess.takeFirst();
- const QString filePath = config.file.path;
- const QStringList options = config.createClangOptions();
+ const AnalyzeUnit unit = m_unitsToProcess.takeFirst();
+ qCDebug(LOG) << "analyzeNextFile:" << unit.file;
ClangStaticAnalyzerRunner *runner = createRunner();
m_runners.insert(runner);
- qCDebug(LOG) << "analyzeNextFile:" << filePath;
- QTC_ASSERT(runner->run(filePath, options), return);
+ QTC_ASSERT(runner->run(unit.file, unit.arguments), return);
+
+ appendMessage(tr("Analyzing \"%1\".").arg(unit.file) + QLatin1Char('\n'),
+ Utils::StdOutFormat);
}
ClangStaticAnalyzerRunner *ClangStaticAnalyzerRunControl::createRunner()
@@ -201,21 +291,36 @@ ClangStaticAnalyzerRunner *ClangStaticAnalyzerRunControl::createRunner()
void ClangStaticAnalyzerRunControl::onRunnerFinishedWithSuccess(const QString &logFilePath)
{
qCDebug(LOG) << "onRunnerFinishedWithSuccess:" << logFilePath;
- handleFinished();
QString errorMessage;
const QList<Diagnostic> diagnostics = LogFileReader::read(logFilePath, &errorMessage);
- QTC_CHECK(errorMessage.isEmpty());
- if (!errorMessage.isEmpty())
+ if (!errorMessage.isEmpty()) {
qCDebug(LOG) << "onRunnerFinishedWithSuccess: Error reading log file:" << errorMessage;
- if (!diagnostics.isEmpty())
- emit newDiagnosticsAvailable(diagnostics);
+ const QString filePath = qobject_cast<ClangStaticAnalyzerRunner *>(sender())->filePath();
+ appendMessage(tr("Failed to analyze \"%1\": %2").arg(filePath, errorMessage)
+ + QLatin1Char('\n')
+ , Utils::StdErrFormat);
+ } else {
+ ++m_filesAnalyzed;
+ if (!diagnostics.isEmpty())
+ emit newDiagnosticsAvailable(diagnostics);
+ }
+
+ handleFinished();
}
void ClangStaticAnalyzerRunControl::onRunnerFinishedWithFailure(const QString &errorMessage,
const QString &errorDetails)
{
qCDebug(LOG) << "onRunnerFinishedWithFailure:" << errorMessage << errorDetails;
+
+ ++m_filesNotAnalyzed;
+ const QString filePath = qobject_cast<ClangStaticAnalyzerRunner *>(sender())->filePath();
+ appendMessage(tr("Failed to analyze \"%1\": %2").arg(filePath, errorMessage)
+ + QLatin1Char('\n')
+ , Utils::StdErrFormat);
+ appendMessage(errorDetails, Utils::StdErrFormat);
+
handleFinished();
}
@@ -236,24 +341,7 @@ void ClangStaticAnalyzerRunControl::onProgressCanceled()
void ClangStaticAnalyzerRunControl::updateProgressValue()
{
- m_progress.setProgressValue(m_initialFilesToProcessSize - m_filesToProcess.size());
-}
-
-QStringList ClangStaticAnalyzerRunControl::SourceFileConfiguration::createClangOptions() const
-{
- QStringList result;
-
- const bool objcExt = projectPart->languageExtensions & ProjectPart::ObjectiveCExtensions;
- result += CppTools::CompilerOptionsBuilder::createLanguageOption(file.kind, objcExt);
- result += CppTools::CompilerOptionsBuilder::createOptionsForLanguage(
- projectPart->languageVersion,
- projectPart->languageExtensions);
- result += CppTools::CompilerOptionsBuilder::createDefineOptions(projectPart->toolchainDefines);
- result += CppTools::CompilerOptionsBuilder::createDefineOptions(projectPart->projectDefines);
- result += CppTools::CompilerOptionsBuilder::createHeaderPathOptions(projectPart->headerPaths);
- result += QLatin1String("-fPIC"); // TODO: Remove?
-
- return result;
+ m_progress.setProgressValue(m_initialFilesToProcessSize - m_unitsToProcess.size());
}
} // namespace Internal
diff --git a/plugins/clangstaticanalyzer/clangstaticanalyzerruncontrol.h b/plugins/clangstaticanalyzer/clangstaticanalyzerruncontrol.h
index 661594bf11..cc56f107f6 100644
--- a/plugins/clangstaticanalyzer/clangstaticanalyzerruncontrol.h
+++ b/plugins/clangstaticanalyzer/clangstaticanalyzerruncontrol.h
@@ -36,21 +36,18 @@ class ClangStaticAnalyzerRunControl : public Analyzer::AnalyzerRunControl
Q_OBJECT
public:
- struct SourceFileConfiguration {
- SourceFileConfiguration(const CppTools::ProjectFile &projectFile,
- const CppTools::ProjectPart::Ptr &projectPart)
- : file(projectFile)
- , projectPart(projectPart) {}
+ struct AnalyzeUnit {
+ AnalyzeUnit(const QString &file, const QStringList &options)
+ : file(file), arguments(options) {}
- QStringList createClangOptions() const;
-
- CppTools::ProjectFile file;
- CppTools::ProjectPart::Ptr projectPart;
+ QString file;
+ QStringList arguments; // without file itself and "-o somePath"
};
public:
explicit ClangStaticAnalyzerRunControl(const Analyzer::AnalyzerStartParameters &startParams,
- ProjectExplorer::RunConfiguration *runConfiguration);
+ ProjectExplorer::RunConfiguration *runConfiguration,
+ const CppTools::ProjectInfo &projectInfo);
bool startEngine();
void stopEngine();
@@ -70,12 +67,16 @@ private:
void updateProgressValue();
private:
+ const CppTools::ProjectInfo m_projectInfo;
+
QString m_clangExecutable;
QString m_clangLogFileDir;
QFutureInterface<void> m_progress;
- QList<SourceFileConfiguration> m_filesToProcess;
+ QList<AnalyzeUnit> m_unitsToProcess;
QSet<ClangStaticAnalyzerRunner *> m_runners;
int m_initialFilesToProcessSize;
+ int m_filesAnalyzed;
+ int m_filesNotAnalyzed;
};
} // namespace Internal
diff --git a/plugins/clangstaticanalyzer/clangstaticanalyzerruncontrolfactory.cpp b/plugins/clangstaticanalyzer/clangstaticanalyzerruncontrolfactory.cpp
index a8896b4565..94f7f27163 100644
--- a/plugins/clangstaticanalyzer/clangstaticanalyzerruncontrolfactory.cpp
+++ b/plugins/clangstaticanalyzer/clangstaticanalyzerruncontrolfactory.cpp
@@ -22,21 +22,31 @@
#include <analyzerbase/analyzerruncontrol.h>
#include <analyzerbase/analyzerstartparameters.h>
+#include <cpptools/cppmodelmanager.h>
+#include <cpptools/cppprojects.h>
+
#include <projectexplorer/gcctoolchain.h>
#include <projectexplorer/kit.h>
#include <projectexplorer/kitinformation.h>
+#include <projectexplorer/session.h>
#include <projectexplorer/target.h>
#include <projectexplorer/toolchain.h>
+#include <utils/qtcassert.h>
+
using namespace Analyzer;
using namespace ProjectExplorer;
namespace ClangStaticAnalyzer {
namespace Internal {
-ClangStaticAnalyzerRunControlFactory::ClangStaticAnalyzerRunControlFactory(QObject *parent)
+ClangStaticAnalyzerRunControlFactory::ClangStaticAnalyzerRunControlFactory(
+ ClangStaticAnalyzerTool *tool,
+ QObject *parent)
: IRunControlFactory(parent)
+ , m_tool(tool)
{
+ QTC_CHECK(m_tool);
}
bool ClangStaticAnalyzerRunControlFactory::canRun(RunConfiguration *runConfiguration,
@@ -58,9 +68,30 @@ RunControl *ClangStaticAnalyzerRunControlFactory::create(RunConfiguration *runCo
RunMode runMode,
QString *errorMessage)
{
- Q_UNUSED(errorMessage);
Q_UNUSED(runMode);
+ using namespace CppTools;
+ const ProjectInfo projectInfoBeforeBuild = m_tool->projectInfoBeforeBuild();
+ QTC_ASSERT(projectInfoBeforeBuild.isValid(), return 0);
+
+ Project *project = SessionManager::startupProject();
+ 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;
+ }
+
AnalyzerStartParameters sp;
sp.runMode = runMode;
sp.startMode = StartLocal;
diff --git a/plugins/clangstaticanalyzer/clangstaticanalyzerruncontrolfactory.h b/plugins/clangstaticanalyzer/clangstaticanalyzerruncontrolfactory.h
index ec3b2d8c9c..a325691972 100644
--- a/plugins/clangstaticanalyzer/clangstaticanalyzerruncontrolfactory.h
+++ b/plugins/clangstaticanalyzer/clangstaticanalyzerruncontrolfactory.h
@@ -19,6 +19,8 @@
#ifndef CLANGSTATICANALYZERRUNCONTROLFACTORY_H
#define CLANGSTATICANALYZERRUNCONTROLFACTORY_H
+#include "clangstaticanalyzertool.h"
+
#include <projectexplorer/runconfiguration.h>
namespace ClangStaticAnalyzer {
@@ -29,7 +31,8 @@ class ClangStaticAnalyzerRunControlFactory : public ProjectExplorer::IRunControl
Q_OBJECT
public:
- explicit ClangStaticAnalyzerRunControlFactory(QObject *parent = 0);
+ explicit ClangStaticAnalyzerRunControlFactory(ClangStaticAnalyzerTool *tool,
+ QObject *parent = 0);
bool canRun(ProjectExplorer::RunConfiguration *runConfiguration,
ProjectExplorer::RunMode runMode) const;
@@ -37,6 +40,9 @@ public:
ProjectExplorer::RunControl *create(ProjectExplorer::RunConfiguration *runConfiguration,
ProjectExplorer::RunMode runMode,
QString *errorMessage);
+
+private:
+ ClangStaticAnalyzerTool *m_tool;
};
} // namespace Internal
diff --git a/plugins/clangstaticanalyzer/clangstaticanalyzerrunner.cpp b/plugins/clangstaticanalyzer/clangstaticanalyzerrunner.cpp
index ed8efb93f8..5c469a07a2 100644
--- a/plugins/clangstaticanalyzer/clangstaticanalyzerrunner.cpp
+++ b/plugins/clangstaticanalyzer/clangstaticanalyzerrunner.cpp
@@ -20,6 +20,8 @@
#include "clangstaticanalyzerconstants.h"
+#include <utils/synchronousprocess.h>
+
#include <QDebug>
#include <QDir>
#include <QFileInfo>
@@ -83,14 +85,7 @@ ClangStaticAnalyzerRunner::ClangStaticAnalyzerRunner(const QString &clangExecuta
ClangStaticAnalyzerRunner::~ClangStaticAnalyzerRunner()
{
- const QProcess::ProcessState processState = m_process.state();
- if (processState == QProcess::Starting || processState == QProcess::Running) {
- m_process.terminate();
- if (!m_process.waitForFinished(500)) {
- m_process.kill();
- m_process.waitForFinished();
- }
- }
+ Utils::SynchronousProcess::stopProcess(m_process);
}
bool ClangStaticAnalyzerRunner::run(const QString &filePath, const QStringList &compilerOptions)
@@ -99,6 +94,7 @@ bool ClangStaticAnalyzerRunner::run(const QString &filePath, const QStringList &
QTC_CHECK(!compilerOptions.contains(QLatin1String("-o")));
QTC_CHECK(!compilerOptions.contains(filePath));
+ m_filePath = filePath;
m_processOutput.clear();
m_logFile = createLogFile(filePath);
@@ -112,6 +108,11 @@ bool ClangStaticAnalyzerRunner::run(const QString &filePath, const QStringList &
return true;
}
+QString ClangStaticAnalyzerRunner::filePath() const
+{
+ return m_filePath;
+}
+
void ClangStaticAnalyzerRunner::onProcessStarted()
{
emit started();
@@ -161,8 +162,8 @@ QString ClangStaticAnalyzerRunner::createLogFile(const QString &filePath) const
QString ClangStaticAnalyzerRunner::processCommandlineAndOutput() const
{
return QObject::tr("Command line: \"%1\"\n"
- "Process Error: \"%2\"\n"
- "Output:\n\"%3\"")
+ "Process Error: %2\n"
+ "Output:\n%3")
.arg(m_commandLine,
QString::number(m_process.error()),
QString::fromLocal8Bit(m_processOutput));
diff --git a/plugins/clangstaticanalyzer/clangstaticanalyzerrunner.h b/plugins/clangstaticanalyzer/clangstaticanalyzerrunner.h
index b535ec1077..461f694e2e 100644
--- a/plugins/clangstaticanalyzer/clangstaticanalyzerrunner.h
+++ b/plugins/clangstaticanalyzer/clangstaticanalyzerrunner.h
@@ -45,6 +45,8 @@ public:
// (2) -o output-file
bool run(const QString &filePath, const QStringList &compilerOptions = QStringList());
+ QString filePath() const;
+
signals:
void started();
void finishedWithSuccess(const QString &logFilePath);
@@ -62,6 +64,7 @@ private:
private:
QString m_clangExecutable;
QString m_clangLogFileDir;
+ QString m_filePath;
QString m_logFile;
QString m_commandLine;
QProcess m_process;
diff --git a/plugins/clangstaticanalyzer/clangstaticanalyzertool.cpp b/plugins/clangstaticanalyzer/clangstaticanalyzertool.cpp
index 143043d73f..5042267776 100644
--- a/plugins/clangstaticanalyzer/clangstaticanalyzertool.cpp
+++ b/plugins/clangstaticanalyzer/clangstaticanalyzertool.cpp
@@ -24,10 +24,15 @@
#include <analyzerbase/analyzermanager.h>
#include <coreplugin/coreconstants.h>
+#include <coreplugin/icore.h>
+#include <cpptools/cppmodelmanager.h>
+#include <projectexplorer/buildconfiguration.h>
#include <projectexplorer/projectexplorer.h>
#include <projectexplorer/projectexplorerconstants.h>
#include <projectexplorer/session.h>
+#include <projectexplorer/target.h>
+#include <utils/checkablemessagebox.h>
#include <utils/fancymainwindow.h>
#include <QDockWidget>
@@ -129,7 +134,22 @@ AnalyzerRunControl *ClangStaticAnalyzerTool::createRunControl(
const AnalyzerStartParameters &sp,
ProjectExplorer::RunConfiguration *runConfiguration)
{
- ClangStaticAnalyzerRunControl *engine = new ClangStaticAnalyzerRunControl(sp, runConfiguration);
+ 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 = SessionManager::startupProject();
+ 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();
+
+ ClangStaticAnalyzerRunControl *engine
+ = new ClangStaticAnalyzerRunControl(sp, runConfiguration, projectInfoAfterBuild);
connect(engine, &ClangStaticAnalyzerRunControl::starting,
this, &ClangStaticAnalyzerTool::onEngineIsStarting);
connect(engine, &ClangStaticAnalyzerRunControl::newDiagnosticsAvailable,
@@ -139,20 +159,73 @@ AnalyzerRunControl *ClangStaticAnalyzerTool::createRunControl(
return engine;
}
+static bool dontStartAfterHintForDebugMode()
+{
+ const Project *project = SessionManager::startupProject();
+ BuildConfiguration::BuildType buildType = BuildConfiguration::Unknown;
+ if (project) {
+ if (const Target *target = project->activeTarget()) {
+ if (const BuildConfiguration *buildConfig = target->activeBuildConfiguration())
+ buildType = buildConfig->buildType();
+ }
+ }
+
+ if (buildType == BuildConfiguration::Release) {
+ const QString wrongMode = ClangStaticAnalyzerTool::tr("Release");
+ const QString toolName = ClangStaticAnalyzerTool::tr("Clang Static Analyzer");
+ const QString title = ClangStaticAnalyzerTool::tr("Run %1 in %2 Mode?").arg(toolName)
+ .arg(wrongMode);
+ const QString message = ClangStaticAnalyzerTool::tr(
+ "<html><head/><body>"
+ "<p>You are trying to run the tool \"%1\" on an application in %2 mode. The tool is "
+ "designed to be used in Debug mode since enabled assertions can reduce the number of "
+ "false positives.</p>"
+ "<p>Do you want to continue and run the tool in %2 mode?</p>"
+ "</body></html>")
+ .arg(toolName).arg(wrongMode);
+ if (Utils::CheckableMessageBox::doNotAskAgainQuestion(Core::ICore::mainWindow(),
+ title, message, Core::ICore::settings(),
+ QLatin1String("ClangStaticAnalyzerCorrectModeWarning"),
+ QDialogButtonBox::Yes|QDialogButtonBox::Cancel,
+ QDialogButtonBox::Cancel, QDialogButtonBox::Yes) != QDialogButtonBox::Yes)
+ return true;
+ }
+
+ return false;
+}
+
void ClangStaticAnalyzerTool::startTool(StartMode mode)
{
QTC_ASSERT(mode == Analyzer::StartLocal, return);
AnalyzerManager::showMode();
- if (Project *pro = SessionManager::startupProject())
- ProjectExplorerPlugin::instance()->runProject(pro, runMode());
+
+ if (dontStartAfterHintForDebugMode())
+ return;
+
+ m_diagnosticModel->clear();
+ setBusyCursor(true);
+ Project *project = SessionManager::startupProject();
+ QTC_ASSERT(project, return);
+ m_projectInfoBeforeBuild = CppTools::CppModelManager::instance()->projectInfo(project);
+ QTC_ASSERT(m_projectInfoBeforeBuild.isValid(), return);
+ ProjectExplorerPlugin::instance()->runProject(project, runMode());
+}
+
+CppTools::ProjectInfo ClangStaticAnalyzerTool::projectInfoBeforeBuild() const
+{
+ return m_projectInfoBeforeBuild;
+}
+
+void ClangStaticAnalyzerTool::resetCursorAndProjectInfoBeforeBuild()
+{
+ setBusyCursor(false);
+ m_projectInfoBeforeBuild = CppTools::ProjectInfo();
}
void ClangStaticAnalyzerTool::onEngineIsStarting()
{
QTC_ASSERT(m_diagnosticModel, return);
- m_diagnosticModel->clear();
- setBusyCursor(true);
}
void ClangStaticAnalyzerTool::onNewDiagnosticsAvailable(const QList<Diagnostic> &diagnostics)
@@ -166,10 +239,12 @@ void ClangStaticAnalyzerTool::onEngineFinished()
QTC_ASSERT(m_goBack, return);
QTC_ASSERT(m_goNext, return);
QTC_ASSERT(m_diagnosticModel, return);
+
+ resetCursorAndProjectInfoBeforeBuild();
+
const int issuesFound = m_diagnosticModel->rowCount();
m_goBack->setEnabled(issuesFound > 1);
m_goNext->setEnabled(issuesFound > 1);
- setBusyCursor(false);
AnalyzerManager::showStatusMessage(issuesFound > 0
? AnalyzerManager::tr("Clang Static Analyzer finished, %n issues were found.", 0, issuesFound)
diff --git a/plugins/clangstaticanalyzer/clangstaticanalyzertool.h b/plugins/clangstaticanalyzer/clangstaticanalyzertool.h
index 2cb1393a7a..8f3bb1f196 100644
--- a/plugins/clangstaticanalyzer/clangstaticanalyzertool.h
+++ b/plugins/clangstaticanalyzer/clangstaticanalyzertool.h
@@ -20,6 +20,7 @@
#define CLANGSTATICANALYZERTOOL_H
#include <analyzerbase/ianalyzertool.h>
+#include <cpptools/cppprojects.h>
namespace Analyzer { class DetailedErrorView; }
@@ -36,6 +37,8 @@ class ClangStaticAnalyzerTool : public Analyzer::IAnalyzerTool
public:
explicit ClangStaticAnalyzerTool(QObject *parent = 0);
+ CppTools::ProjectInfo projectInfoBeforeBuild() const;
+ void resetCursorAndProjectInfoBeforeBuild();
private:
QWidget *createWidgets();
@@ -50,6 +53,8 @@ private:
void setBusyCursor(bool busy);
private:
+ CppTools::ProjectInfo m_projectInfoBeforeBuild;
+
ClangStaticAnalyzerDiagnosticModel *m_diagnosticModel;
Analyzer::DetailedErrorView *m_diagnosticView;