2014-09-25 11:11:58 +02:00
|
|
|
/****************************************************************************
|
|
|
|
|
**
|
2016-01-14 10:59:10 +01:00
|
|
|
** Copyright (C) 2016 The Qt Company Ltd.
|
|
|
|
|
** Contact: https://www.qt.io/licensing/
|
2014-09-25 11:11:58 +02:00
|
|
|
**
|
2016-01-14 10:59:10 +01:00
|
|
|
** This file is part of Qt Creator.
|
2014-09-25 11:11:58 +02:00
|
|
|
**
|
2016-01-14 10:59:10 +01:00
|
|
|
** Commercial License Usage
|
|
|
|
|
** Licensees holding valid commercial Qt licenses may use this file in
|
|
|
|
|
** accordance with the commercial license agreement provided with the
|
2014-09-25 11:11:58 +02:00
|
|
|
** Software or, alternatively, in accordance with the terms contained in
|
2016-01-14 10:59:10 +01:00
|
|
|
** a written agreement between you and The Qt Company. For licensing terms
|
|
|
|
|
** and conditions see https://www.qt.io/terms-conditions. For further
|
|
|
|
|
** information use the contact form at https://www.qt.io/contact-us.
|
2014-09-25 11:11:58 +02:00
|
|
|
**
|
2016-01-14 10:59:10 +01:00
|
|
|
** GNU General Public License Usage
|
|
|
|
|
** Alternatively, this file may be used under the terms of the GNU
|
|
|
|
|
** General Public License version 3 as published by the Free Software
|
|
|
|
|
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
|
|
|
|
|
** included in the packaging of this file. Please review the following
|
|
|
|
|
** information to ensure the GNU General Public License requirements will
|
|
|
|
|
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
|
2014-09-25 11:11:58 +02:00
|
|
|
**
|
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
|
|
#include "clangstaticanalyzerruncontrol.h"
|
|
|
|
|
|
|
|
|
|
#include "clangstaticanalyzerlogfilereader.h"
|
|
|
|
|
#include "clangstaticanalyzerrunner.h"
|
|
|
|
|
#include "clangstaticanalyzersettings.h"
|
|
|
|
|
#include "clangstaticanalyzerutils.h"
|
|
|
|
|
|
2016-05-31 16:09:48 +02:00
|
|
|
#include <debugger/analyzer/analyzerconstants.h>
|
2014-09-25 11:11:58 +02:00
|
|
|
|
|
|
|
|
#include <clangcodemodel/clangutils.h>
|
|
|
|
|
|
|
|
|
|
#include <coreplugin/progressmanager/futureprogress.h>
|
|
|
|
|
#include <coreplugin/progressmanager/progressmanager.h>
|
|
|
|
|
|
2016-01-13 12:11:07 +01:00
|
|
|
#include <cpptools/compileroptionsbuilder.h>
|
2014-09-25 11:11:58 +02:00
|
|
|
#include <cpptools/cppmodelmanager.h>
|
|
|
|
|
#include <cpptools/cppprojectfile.h>
|
2016-01-13 12:11:07 +01:00
|
|
|
#include <cpptools/projectinfo.h>
|
2014-09-25 11:11:58 +02:00
|
|
|
|
2015-04-15 15:52:17 +02:00
|
|
|
#include <projectexplorer/abi.h>
|
2016-01-05 08:58:01 +01:00
|
|
|
#include <projectexplorer/buildconfiguration.h>
|
2015-01-23 15:25:45 +01:00
|
|
|
#include <projectexplorer/kitinformation.h>
|
2014-09-25 11:11:58 +02:00
|
|
|
#include <projectexplorer/project.h>
|
2016-05-30 16:56:46 +02:00
|
|
|
#include <projectexplorer/projectexplorericons.h>
|
2015-04-15 15:52:17 +02:00
|
|
|
#include <projectexplorer/runconfiguration.h>
|
2014-10-24 10:21:32 +02:00
|
|
|
#include <projectexplorer/target.h>
|
2015-02-26 16:24:53 +01:00
|
|
|
#include <projectexplorer/taskhub.h>
|
2016-01-13 12:11:07 +01:00
|
|
|
#include <projectexplorer/toolchain.h>
|
2014-09-25 11:11:58 +02:00
|
|
|
|
2014-11-07 12:15:13 +01:00
|
|
|
#include <utils/algorithm.h>
|
2016-07-12 16:27:15 +02:00
|
|
|
#include <utils/hostosinfo.h>
|
2014-11-07 12:15:13 +01:00
|
|
|
|
2014-09-25 11:11:58 +02:00
|
|
|
#include <QLoggingCategory>
|
|
|
|
|
#include <QTemporaryDir>
|
|
|
|
|
|
|
|
|
|
using namespace CppTools;
|
|
|
|
|
using namespace ProjectExplorer;
|
|
|
|
|
|
2014-10-20 13:08:49 +02:00
|
|
|
static Q_LOGGING_CATEGORY(LOG, "qtc.clangstaticanalyzer.runcontrol")
|
2014-09-25 11:11:58 +02:00
|
|
|
|
|
|
|
|
namespace ClangStaticAnalyzer {
|
|
|
|
|
namespace Internal {
|
|
|
|
|
|
|
|
|
|
ClangStaticAnalyzerRunControl::ClangStaticAnalyzerRunControl(
|
2016-01-05 08:58:01 +01:00
|
|
|
RunConfiguration *runConfiguration,
|
|
|
|
|
Core::Id runMode,
|
2014-11-05 13:28:44 +01:00
|
|
|
const ProjectInfo &projectInfo)
|
2016-05-31 08:31:17 +02:00
|
|
|
: RunControl(runConfiguration, runMode)
|
2014-11-05 13:28:44 +01:00
|
|
|
, m_projectInfo(projectInfo)
|
2014-09-25 11:11:58 +02:00
|
|
|
, m_initialFilesToProcessSize(0)
|
2014-10-30 17:35:52 +01:00
|
|
|
, m_filesAnalyzed(0)
|
|
|
|
|
, m_filesNotAnalyzed(0)
|
2014-09-25 11:11:58 +02:00
|
|
|
{
|
2016-04-20 15:21:38 +02:00
|
|
|
setDisplayName(tr("Clang Static Analyzer"));
|
2016-05-30 16:56:46 +02:00
|
|
|
setIcon(ProjectExplorer::Icons::ANALYZER_START_SMALL_TOOLBAR);
|
|
|
|
|
|
2016-01-05 08:58:01 +01:00
|
|
|
Target *target = runConfiguration->target();
|
|
|
|
|
BuildConfiguration *buildConfiguration = target->activeBuildConfiguration();
|
|
|
|
|
QTC_ASSERT(buildConfiguration, return);
|
|
|
|
|
m_environment = buildConfiguration->environment();
|
2016-04-01 13:09:21 +02:00
|
|
|
|
|
|
|
|
ToolChain *toolChain = ToolChainKitInformation::toolChain(target->kit());
|
|
|
|
|
QTC_ASSERT(toolChain, return);
|
2016-04-20 16:46:31 +02:00
|
|
|
m_extraToolChainInfo.wordWidth = toolChain->targetAbi().wordWidth();
|
2016-04-01 13:09:21 +02:00
|
|
|
m_extraToolChainInfo.targetTriple = toolChain->originalTargetTriple();
|
2014-09-25 11:11:58 +02:00
|
|
|
}
|
|
|
|
|
|
2015-04-15 15:52:17 +02:00
|
|
|
static void prependWordWidthArgumentIfNotIncluded(QStringList *arguments, unsigned char wordWidth)
|
|
|
|
|
{
|
|
|
|
|
QTC_ASSERT(arguments, return);
|
|
|
|
|
|
|
|
|
|
const QString m64Argument = QLatin1String("-m64");
|
|
|
|
|
const QString m32Argument = QLatin1String("-m32");
|
|
|
|
|
|
|
|
|
|
const QString argument = wordWidth == 64 ? m64Argument : m32Argument;
|
|
|
|
|
if (!arguments->contains(argument))
|
|
|
|
|
arguments->prepend(argument);
|
|
|
|
|
|
2015-04-15 18:21:02 +02:00
|
|
|
QTC_CHECK(!arguments->contains(m32Argument) || !arguments->contains(m64Argument));
|
2015-04-15 15:52:17 +02:00
|
|
|
}
|
|
|
|
|
|
2016-03-04 15:33:33 +01:00
|
|
|
static void prependTargetTripleIfNotIncludedAndNotEmpty(QStringList *arguments,
|
|
|
|
|
const QString &targetTriple)
|
|
|
|
|
{
|
|
|
|
|
QTC_ASSERT(arguments, return);
|
|
|
|
|
|
|
|
|
|
if (targetTriple.isEmpty())
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
const QString targetOption = QLatin1String("-target");
|
|
|
|
|
|
|
|
|
|
if (!arguments->contains(targetOption)) {
|
|
|
|
|
arguments->prepend(targetTriple);
|
|
|
|
|
arguments->prepend(targetOption);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-04-05 14:58:42 +02:00
|
|
|
// Removes (1) inputFile (2) -o <somePath>.
|
|
|
|
|
QStringList inputAndOutputArgumentsRemoved(const QString &inputFile, const QStringList &arguments)
|
2014-09-25 11:11:58 +02:00
|
|
|
{
|
2014-10-30 11:57:09 +01:00
|
|
|
QStringList newArguments;
|
|
|
|
|
|
|
|
|
|
bool skip = false;
|
|
|
|
|
foreach (const QString &argument, arguments) {
|
|
|
|
|
if (skip) {
|
|
|
|
|
skip = false;
|
|
|
|
|
continue;
|
|
|
|
|
} else if (argument == QLatin1String("-o")) {
|
|
|
|
|
skip = true;
|
|
|
|
|
continue;
|
2016-04-05 14:58:42 +02:00
|
|
|
} else if (QDir::fromNativeSeparators(argument) == inputFile) {
|
2014-10-30 11:57:09 +01:00
|
|
|
continue; // TODO: Let it in?
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
newArguments << argument;
|
|
|
|
|
}
|
|
|
|
|
QTC_CHECK(skip == false);
|
|
|
|
|
|
2016-04-05 14:58:42 +02:00
|
|
|
return newArguments;
|
|
|
|
|
}
|
|
|
|
|
|
2015-06-26 13:53:50 +02:00
|
|
|
static QString createLanguageOptionMsvc(ProjectFile::Kind fileKind)
|
2014-10-30 11:57:09 +01:00
|
|
|
{
|
2015-06-26 13:53:50 +02:00
|
|
|
switch (fileKind) {
|
|
|
|
|
case ProjectFile::CHeader:
|
|
|
|
|
case ProjectFile::CSource:
|
|
|
|
|
return QLatin1String("/TC");
|
|
|
|
|
break;
|
|
|
|
|
case ProjectFile::CXXHeader:
|
|
|
|
|
case ProjectFile::CXXSource:
|
|
|
|
|
return QLatin1String("/TP");
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
return QString();
|
2014-10-30 11:57:09 +01:00
|
|
|
}
|
|
|
|
|
|
2015-06-26 13:53:50 +02:00
|
|
|
class ClangStaticAnalyzerOptionsBuilder : public CompilerOptionsBuilder
|
|
|
|
|
{
|
|
|
|
|
public:
|
2015-11-05 11:50:39 +01:00
|
|
|
static QStringList build(const CppTools::ProjectPart &projectPart,
|
2015-06-26 13:53:50 +02:00
|
|
|
CppTools::ProjectFile::Kind fileKind,
|
2016-04-01 13:09:21 +02:00
|
|
|
const ExtraToolChainInfo &extraParams)
|
2015-06-26 13:53:50 +02:00
|
|
|
{
|
|
|
|
|
ClangStaticAnalyzerOptionsBuilder optionsBuilder(projectPart);
|
2016-04-08 14:19:23 +02:00
|
|
|
|
|
|
|
|
optionsBuilder.addTargetTriple();
|
2015-06-26 13:53:50 +02:00
|
|
|
optionsBuilder.addLanguageOption(fileKind);
|
|
|
|
|
optionsBuilder.addOptionsForLanguage(false);
|
2016-04-12 13:11:01 +02:00
|
|
|
optionsBuilder.enableExceptions();
|
2015-06-26 13:53:50 +02:00
|
|
|
|
|
|
|
|
// In gcc headers, lots of built-ins are referenced that clang does not understand.
|
|
|
|
|
// Therefore, prevent the inclusion of the header that references them. Of course, this
|
|
|
|
|
// will break if code actually requires stuff from there, but that should be the less common
|
|
|
|
|
// case.
|
2015-11-05 11:50:39 +01:00
|
|
|
const Core::Id type = projectPart.toolchainType;
|
2015-07-07 15:37:10 +02:00
|
|
|
if (type == ProjectExplorer::Constants::MINGW_TOOLCHAIN_TYPEID
|
|
|
|
|
|| type == ProjectExplorer::Constants::GCC_TOOLCHAIN_TYPEID)
|
2015-06-26 13:53:50 +02:00
|
|
|
optionsBuilder.addDefine("#define _X86INTRIN_H_INCLUDED\n");
|
|
|
|
|
|
2016-07-07 11:45:46 +02:00
|
|
|
if (type != ProjectExplorer::Constants::MSVC_TOOLCHAIN_TYPEID)
|
|
|
|
|
optionsBuilder.addDefines(projectPart.toolchainDefines);
|
|
|
|
|
optionsBuilder.addDefines(projectPart.projectDefines);
|
2016-07-07 10:51:41 +02:00
|
|
|
optionsBuilder.undefineClangVersionMacrosForMsvc();
|
2016-04-11 17:34:02 +02:00
|
|
|
optionsBuilder.undefineCppLanguageFeatureMacrosForMsvc2015();
|
2015-06-26 13:53:50 +02:00
|
|
|
optionsBuilder.addHeaderPathOptions();
|
2016-04-11 11:53:50 +02:00
|
|
|
optionsBuilder.addMsvcCompatibilityVersion();
|
2015-06-26 13:53:50 +02:00
|
|
|
|
2016-04-12 13:11:01 +02:00
|
|
|
if (type != ProjectExplorer::Constants::MSVC_TOOLCHAIN_TYPEID)
|
2015-06-26 13:53:50 +02:00
|
|
|
optionsBuilder.add(QLatin1String("-fPIC")); // TODO: Remove?
|
|
|
|
|
|
|
|
|
|
QStringList options = optionsBuilder.options();
|
2016-04-01 13:09:21 +02:00
|
|
|
prependWordWidthArgumentIfNotIncluded(&options, extraParams.wordWidth);
|
2016-03-04 15:33:33 +01:00
|
|
|
|
2015-06-26 13:53:50 +02:00
|
|
|
return options;
|
|
|
|
|
}
|
|
|
|
|
|
2015-11-05 11:50:39 +01:00
|
|
|
ClangStaticAnalyzerOptionsBuilder(const CppTools::ProjectPart &projectPart)
|
2015-06-26 13:53:50 +02:00
|
|
|
: CompilerOptionsBuilder(projectPart)
|
2015-11-05 11:50:39 +01:00
|
|
|
, m_isMsvcToolchain(m_projectPart.toolchainType == ProjectExplorer::Constants::MSVC_TOOLCHAIN_TYPEID)
|
2015-06-26 13:53:50 +02:00
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
2016-07-07 10:51:41 +02:00
|
|
|
public:
|
|
|
|
|
void undefineClangVersionMacrosForMsvc()
|
|
|
|
|
{
|
|
|
|
|
if (m_projectPart.toolchainType == ProjectExplorer::Constants::MSVC_TOOLCHAIN_TYPEID) {
|
|
|
|
|
static QStringList macroNames {
|
|
|
|
|
"__clang__",
|
|
|
|
|
"__clang_major__",
|
|
|
|
|
"__clang_minor__",
|
|
|
|
|
"__clang_patchlevel__",
|
|
|
|
|
"__clang_version__"
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
foreach (const QString ¯oName, macroNames)
|
|
|
|
|
add(QLatin1String("/U") + macroName);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-04-11 11:53:50 +02:00
|
|
|
private:
|
2016-04-08 14:19:23 +02:00
|
|
|
void addTargetTriple() override
|
|
|
|
|
{
|
|
|
|
|
// For MSVC toolchains we use clang-cl.exe, so there is nothing to do here since
|
|
|
|
|
// 1) clang-cl.exe does not understand the "-triple" option
|
|
|
|
|
// 2) clang-cl.exe already hardcodes the right triple value (even if built with mingw)
|
|
|
|
|
if (m_projectPart.toolchainType != ProjectExplorer::Constants::MSVC_TOOLCHAIN_TYPEID)
|
|
|
|
|
CompilerOptionsBuilder::addTargetTriple();
|
|
|
|
|
}
|
|
|
|
|
|
2015-06-26 13:53:50 +02:00
|
|
|
void addLanguageOption(ProjectFile::Kind fileKind) override
|
|
|
|
|
{
|
|
|
|
|
if (m_isMsvcToolchain)
|
|
|
|
|
add(createLanguageOptionMsvc(fileKind));
|
|
|
|
|
else
|
|
|
|
|
CompilerOptionsBuilder::addLanguageOption(fileKind);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void addOptionsForLanguage(bool checkForBorlandExtensions) override
|
|
|
|
|
{
|
|
|
|
|
if (m_isMsvcToolchain)
|
|
|
|
|
return;
|
|
|
|
|
CompilerOptionsBuilder::addOptionsForLanguage(checkForBorlandExtensions);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QString includeOption() const override
|
|
|
|
|
{
|
|
|
|
|
if (m_isMsvcToolchain)
|
|
|
|
|
return QLatin1String("/I");
|
|
|
|
|
return CompilerOptionsBuilder::includeOption();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QString defineOption() const override
|
|
|
|
|
{
|
|
|
|
|
if (m_isMsvcToolchain)
|
|
|
|
|
return QLatin1String("/D");
|
|
|
|
|
return CompilerOptionsBuilder::defineOption();
|
|
|
|
|
}
|
|
|
|
|
|
2016-04-12 13:11:01 +02:00
|
|
|
void enableExceptions() override
|
|
|
|
|
{
|
|
|
|
|
if (m_isMsvcToolchain)
|
|
|
|
|
add(QLatin1String("/EHsc"));
|
|
|
|
|
else
|
|
|
|
|
CompilerOptionsBuilder::enableExceptions();
|
|
|
|
|
}
|
|
|
|
|
|
2015-06-26 13:53:50 +02:00
|
|
|
private:
|
|
|
|
|
bool m_isMsvcToolchain;
|
|
|
|
|
};
|
|
|
|
|
|
2016-04-11 11:53:50 +02:00
|
|
|
static QStringList createMsCompatibilityVersionOption(const ProjectPart &projectPart)
|
|
|
|
|
{
|
|
|
|
|
ClangStaticAnalyzerOptionsBuilder optionsBuilder(projectPart);
|
|
|
|
|
optionsBuilder.addMsvcCompatibilityVersion();
|
|
|
|
|
const QStringList option = optionsBuilder.options();
|
|
|
|
|
|
|
|
|
|
return option;
|
|
|
|
|
}
|
|
|
|
|
|
2016-04-11 17:34:02 +02:00
|
|
|
static QStringList createOptionsToUndefineCppLanguageFeatureMacrosForMsvc2015(
|
|
|
|
|
const ProjectPart &projectPart)
|
|
|
|
|
{
|
|
|
|
|
ClangStaticAnalyzerOptionsBuilder optionsBuilder(projectPart);
|
|
|
|
|
optionsBuilder.undefineCppLanguageFeatureMacrosForMsvc2015();
|
|
|
|
|
|
|
|
|
|
return optionsBuilder.options();
|
|
|
|
|
}
|
|
|
|
|
|
2016-07-07 10:51:41 +02:00
|
|
|
static QStringList createOptionsToUndefineClangVersionMacrosForMsvc(const ProjectPart &projectPart)
|
|
|
|
|
{
|
|
|
|
|
ClangStaticAnalyzerOptionsBuilder optionsBuilder(projectPart);
|
|
|
|
|
optionsBuilder.undefineClangVersionMacrosForMsvc();
|
|
|
|
|
|
|
|
|
|
return optionsBuilder.options();
|
|
|
|
|
}
|
|
|
|
|
|
2016-07-12 16:27:15 +02:00
|
|
|
static QStringList createHeaderPathsOptionsForClangOnMac(const ProjectPart &projectPart)
|
|
|
|
|
{
|
|
|
|
|
QStringList options;
|
|
|
|
|
|
|
|
|
|
if (Utils::HostOsInfo::isMacHost()
|
|
|
|
|
&& projectPart.toolchainType == ProjectExplorer::Constants::CLANG_TOOLCHAIN_TYPEID) {
|
|
|
|
|
ClangStaticAnalyzerOptionsBuilder optionsBuilder(projectPart);
|
|
|
|
|
optionsBuilder.addHeaderPathOptions();
|
|
|
|
|
options = optionsBuilder.options();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return options;
|
|
|
|
|
}
|
|
|
|
|
|
2016-04-11 11:53:50 +02:00
|
|
|
static QStringList tweakedArguments(const ProjectPart &projectPart,
|
|
|
|
|
const QString &filePath,
|
|
|
|
|
const QStringList &arguments,
|
|
|
|
|
const ExtraToolChainInfo &extraParams)
|
|
|
|
|
{
|
|
|
|
|
QStringList newArguments = inputAndOutputArgumentsRemoved(filePath, arguments);
|
|
|
|
|
prependWordWidthArgumentIfNotIncluded(&newArguments, extraParams.wordWidth);
|
|
|
|
|
prependTargetTripleIfNotIncludedAndNotEmpty(&newArguments, extraParams.targetTriple);
|
2016-07-12 16:27:15 +02:00
|
|
|
newArguments.append(createHeaderPathsOptionsForClangOnMac(projectPart));
|
2016-04-11 11:53:50 +02:00
|
|
|
newArguments.append(createMsCompatibilityVersionOption(projectPart));
|
2016-07-07 10:51:41 +02:00
|
|
|
newArguments.append(createOptionsToUndefineClangVersionMacrosForMsvc(projectPart));
|
2016-04-11 17:34:02 +02:00
|
|
|
newArguments.append(createOptionsToUndefineCppLanguageFeatureMacrosForMsvc2015(projectPart));
|
2016-04-11 11:53:50 +02:00
|
|
|
|
|
|
|
|
return newArguments;
|
|
|
|
|
}
|
|
|
|
|
|
2015-04-16 13:16:09 +02:00
|
|
|
static AnalyzeUnits unitsToAnalyzeFromCompilerCallData(
|
2016-04-11 11:53:50 +02:00
|
|
|
const QHash<QString, ProjectPart::Ptr> &projectFileToProjectPart,
|
2015-04-15 15:52:17 +02:00
|
|
|
const ProjectInfo::CompilerCallData &compilerCallData,
|
2016-04-01 13:09:21 +02:00
|
|
|
const ExtraToolChainInfo &extraParams)
|
2014-10-30 11:57:09 +01:00
|
|
|
{
|
|
|
|
|
qCDebug(LOG) << "Taking arguments for analyzing from CompilerCallData.";
|
|
|
|
|
|
2015-04-16 13:16:09 +02:00
|
|
|
AnalyzeUnits unitsToAnalyze;
|
2014-10-30 11:57:09 +01:00
|
|
|
|
2016-04-11 13:13:07 +02:00
|
|
|
foreach (const ProjectInfo::CompilerCallGroup &compilerCallGroup, compilerCallData) {
|
2016-04-11 11:53:50 +02:00
|
|
|
const ProjectPart::Ptr projectPart
|
|
|
|
|
= projectFileToProjectPart.value(compilerCallGroup.groupId);
|
|
|
|
|
QTC_ASSERT(projectPart, continue);
|
|
|
|
|
|
2016-04-11 13:13:07 +02:00
|
|
|
QHashIterator<QString, QList<QStringList> > it(compilerCallGroup.callsPerSourceFile);
|
|
|
|
|
while (it.hasNext()) {
|
|
|
|
|
it.next();
|
|
|
|
|
const QString file = it.key();
|
|
|
|
|
const QList<QStringList> compilerCalls = it.value();
|
|
|
|
|
foreach (const QStringList &options, compilerCalls) {
|
2016-04-11 11:53:50 +02:00
|
|
|
const QStringList arguments = tweakedArguments(*projectPart,
|
|
|
|
|
file,
|
|
|
|
|
options,
|
|
|
|
|
extraParams);
|
2016-04-11 13:13:07 +02:00
|
|
|
unitsToAnalyze << AnalyzeUnit(file, arguments);
|
|
|
|
|
}
|
2014-10-30 11:57:09 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return unitsToAnalyze;
|
|
|
|
|
}
|
|
|
|
|
|
2015-04-16 13:16:09 +02:00
|
|
|
static AnalyzeUnits unitsToAnalyzeFromProjectParts(const QList<ProjectPart::Ptr> projectParts,
|
2016-04-01 13:09:21 +02:00
|
|
|
const ExtraToolChainInfo &extraParams)
|
2014-10-30 11:57:09 +01:00
|
|
|
{
|
|
|
|
|
qCDebug(LOG) << "Taking arguments for analyzing from ProjectParts.";
|
|
|
|
|
|
2015-04-16 13:16:09 +02:00
|
|
|
AnalyzeUnits unitsToAnalyze;
|
2014-09-25 11:11:58 +02:00
|
|
|
|
|
|
|
|
foreach (const ProjectPart::Ptr &projectPart, projectParts) {
|
2014-11-03 14:52:23 +01:00
|
|
|
if (!projectPart->selectedForBuilding)
|
|
|
|
|
continue;
|
|
|
|
|
|
2014-09-25 11:11:58 +02:00
|
|
|
foreach (const ProjectFile &file, projectPart->files) {
|
|
|
|
|
if (file.path == CppModelManager::configurationFileName())
|
|
|
|
|
continue;
|
|
|
|
|
QTC_CHECK(file.kind != ProjectFile::Unclassified);
|
2014-10-30 11:57:09 +01:00
|
|
|
if (ProjectFile::isSource(file.kind)) {
|
2015-06-26 13:53:50 +02:00
|
|
|
const QStringList arguments
|
2015-11-05 11:50:39 +01:00
|
|
|
= ClangStaticAnalyzerOptionsBuilder::build(*projectPart.data(),
|
|
|
|
|
file.kind,
|
2016-04-01 13:09:21 +02:00
|
|
|
extraParams);
|
2014-10-30 11:57:09 +01:00
|
|
|
unitsToAnalyze << AnalyzeUnit(file.path, arguments);
|
|
|
|
|
}
|
2014-09-25 11:11:58 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2014-10-30 11:57:09 +01:00
|
|
|
return unitsToAnalyze;
|
|
|
|
|
}
|
|
|
|
|
|
2016-04-11 11:53:50 +02:00
|
|
|
static QHash<QString, ProjectPart::Ptr> generateProjectFileToProjectPartMapping(
|
|
|
|
|
const QList<ProjectPart::Ptr> &projectParts)
|
|
|
|
|
{
|
|
|
|
|
QHash<QString, ProjectPart::Ptr> mapping;
|
|
|
|
|
|
|
|
|
|
foreach (const ProjectPart::Ptr &projectPart, projectParts) {
|
|
|
|
|
QTC_ASSERT(projectPart, continue);
|
|
|
|
|
mapping[projectPart->projectFile] = projectPart;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return mapping;
|
|
|
|
|
}
|
|
|
|
|
|
2015-04-16 13:33:57 +02:00
|
|
|
AnalyzeUnits ClangStaticAnalyzerRunControl::sortedUnitsToAnalyze()
|
2014-10-30 11:57:09 +01:00
|
|
|
{
|
2015-04-16 13:16:09 +02:00
|
|
|
QTC_ASSERT(m_projectInfo.isValid(), return AnalyzeUnits());
|
2014-10-30 11:57:09 +01:00
|
|
|
|
2015-04-16 13:33:57 +02:00
|
|
|
AnalyzeUnits units;
|
2015-01-23 15:25:45 +01:00
|
|
|
const ProjectInfo::CompilerCallData compilerCallData = m_projectInfo.compilerCallData();
|
2016-04-11 11:53:50 +02:00
|
|
|
if (compilerCallData.isEmpty()) {
|
2016-04-01 13:09:21 +02:00
|
|
|
units = unitsToAnalyzeFromProjectParts(m_projectInfo.projectParts(), m_extraToolChainInfo);
|
2016-04-11 11:53:50 +02:00
|
|
|
} else {
|
|
|
|
|
const QHash<QString, ProjectPart::Ptr> projectFileToProjectPart
|
|
|
|
|
= generateProjectFileToProjectPartMapping(m_projectInfo.projectParts());
|
|
|
|
|
units = unitsToAnalyzeFromCompilerCallData(projectFileToProjectPart,
|
|
|
|
|
compilerCallData,
|
|
|
|
|
m_extraToolChainInfo);
|
|
|
|
|
}
|
2015-04-16 13:33:57 +02:00
|
|
|
|
|
|
|
|
Utils::sort(units, [](const AnalyzeUnit &a1, const AnalyzeUnit &a2) -> bool {
|
|
|
|
|
return a1.file < a2.file;
|
|
|
|
|
});
|
|
|
|
|
return units;
|
2014-09-25 11:11:58 +02:00
|
|
|
}
|
|
|
|
|
|
2015-04-15 11:48:26 +02:00
|
|
|
static QDebug operator<<(QDebug debug, const Utils::Environment &environment)
|
|
|
|
|
{
|
|
|
|
|
foreach (const QString &entry, environment.toStringList())
|
|
|
|
|
debug << "\n " << entry;
|
|
|
|
|
return debug;
|
|
|
|
|
}
|
|
|
|
|
|
2015-04-16 13:33:57 +02:00
|
|
|
static QDebug operator<<(QDebug debug, const AnalyzeUnits &analyzeUnits)
|
|
|
|
|
{
|
|
|
|
|
foreach (const AnalyzeUnit &unit, analyzeUnits)
|
|
|
|
|
debug << "\n " << unit.file;
|
|
|
|
|
return debug;
|
|
|
|
|
}
|
|
|
|
|
|
2015-07-07 15:24:47 +02:00
|
|
|
static Core::Id toolchainType(ProjectExplorer::RunConfiguration *runConfiguration)
|
2015-06-26 13:53:50 +02:00
|
|
|
{
|
2015-07-07 15:24:47 +02:00
|
|
|
QTC_ASSERT(runConfiguration, return Core::Id());
|
|
|
|
|
return ToolChainKitInformation::toolChain(runConfiguration->target()->kit())->typeId();
|
2015-06-26 13:53:50 +02:00
|
|
|
}
|
|
|
|
|
|
2016-03-02 13:57:37 +01:00
|
|
|
void ClangStaticAnalyzerRunControl::start()
|
2014-09-25 11:11:58 +02:00
|
|
|
{
|
2015-05-04 14:57:03 +02:00
|
|
|
m_success = false;
|
2016-01-20 23:48:30 +01:00
|
|
|
emit starting();
|
2014-09-25 11:11:58 +02:00
|
|
|
|
2016-03-02 13:57:37 +01:00
|
|
|
QTC_ASSERT(m_projectInfo.isValid(), emit finished(); return);
|
2015-06-11 15:47:35 +02:00
|
|
|
const Utils::FileName projectFile = m_projectInfo.project()->projectFilePath();
|
|
|
|
|
appendMessage(tr("Running Clang Static Analyzer on %1").arg(projectFile.toUserOutput())
|
|
|
|
|
+ QLatin1Char('\n'), Utils::NormalMessageFormat);
|
2014-10-29 10:40:00 +01:00
|
|
|
|
2014-09-25 11:11:58 +02:00
|
|
|
// Check clang executable
|
|
|
|
|
bool isValidClangExecutable;
|
2015-06-26 13:53:50 +02:00
|
|
|
const QString executable = clangExecutableFromSettings(toolchainType(runConfiguration()),
|
|
|
|
|
&isValidClangExecutable);
|
2014-09-25 11:11:58 +02:00
|
|
|
if (!isValidClangExecutable) {
|
2015-02-26 16:24:53 +01:00
|
|
|
const QString errorMessage = tr("Clang Static Analyzer: Invalid executable \"%1\", stop.")
|
|
|
|
|
.arg(executable);
|
|
|
|
|
appendMessage(errorMessage + QLatin1Char('\n'), Utils::ErrorMessageFormat);
|
2016-05-31 16:09:48 +02:00
|
|
|
TaskHub::addTask(Task::Error, errorMessage, Debugger::Constants::ANALYZERTASK_ID);
|
|
|
|
|
TaskHub::requestPopup();
|
2014-09-25 11:11:58 +02:00
|
|
|
emit finished();
|
2016-03-02 13:57:37 +01:00
|
|
|
return;
|
2014-09-25 11:11:58 +02:00
|
|
|
}
|
2016-07-12 18:50:47 +02:00
|
|
|
|
|
|
|
|
// Check clang version
|
|
|
|
|
const ClangExecutableVersion version = clangExecutableVersion(executable);
|
|
|
|
|
if (!version.isValid()) {
|
|
|
|
|
const QString warningMessage
|
|
|
|
|
= tr("Clang Static Analyzer: Running with possibly unsupported version, "
|
|
|
|
|
"could not determine version from executable \"%1\".")
|
|
|
|
|
.arg(executable);
|
|
|
|
|
appendMessage(warningMessage + QLatin1Char('\n'), Utils::StdErrFormat);
|
|
|
|
|
TaskHub::addTask(Task::Warning, warningMessage, Debugger::Constants::ANALYZERTASK_ID);
|
|
|
|
|
TaskHub::requestPopup();
|
|
|
|
|
} else if (!version.isSupportedVersion()) {
|
|
|
|
|
const QString warningMessage
|
|
|
|
|
= tr("Clang Static Analyzer: Running with unsupported version %1, "
|
|
|
|
|
"supported version is %2.")
|
|
|
|
|
.arg(version.toString())
|
|
|
|
|
.arg(ClangExecutableVersion::supportedVersionAsString());
|
|
|
|
|
appendMessage(warningMessage + QLatin1Char('\n'), Utils::StdErrFormat);
|
|
|
|
|
TaskHub::addTask(Task::Warning, warningMessage, Debugger::Constants::ANALYZERTASK_ID);
|
|
|
|
|
TaskHub::requestPopup();
|
|
|
|
|
}
|
|
|
|
|
|
2014-09-25 11:11:58 +02:00
|
|
|
m_clangExecutable = executable;
|
|
|
|
|
|
|
|
|
|
// Create log dir
|
|
|
|
|
QTemporaryDir temporaryDir(QDir::tempPath() + QLatin1String("/qtc-clangstaticanalyzer-XXXXXX"));
|
|
|
|
|
temporaryDir.setAutoRemove(false);
|
|
|
|
|
if (!temporaryDir.isValid()) {
|
2015-02-26 16:24:53 +01:00
|
|
|
const QString errorMessage
|
|
|
|
|
= tr("Clang Static Analyzer: Failed to create temporary dir, stop.");
|
|
|
|
|
appendMessage(errorMessage + QLatin1Char('\n'), Utils::ErrorMessageFormat);
|
2016-05-31 16:09:48 +02:00
|
|
|
TaskHub::addTask(Task::Error, errorMessage, Debugger::Constants::ANALYZERTASK_ID);
|
|
|
|
|
TaskHub::requestPopup();
|
2014-09-25 11:11:58 +02:00
|
|
|
emit finished();
|
2016-03-02 13:57:37 +01:00
|
|
|
return;
|
2014-09-25 11:11:58 +02:00
|
|
|
}
|
|
|
|
|
m_clangLogFileDir = temporaryDir.path();
|
|
|
|
|
|
|
|
|
|
// Collect files
|
2015-04-16 13:33:57 +02:00
|
|
|
const AnalyzeUnits unitsToProcess = sortedUnitsToAnalyze();
|
|
|
|
|
qCDebug(LOG) << "Files to process:" << unitsToProcess;
|
2014-11-07 12:15:13 +01:00
|
|
|
m_unitsToProcess = unitsToProcess;
|
2014-10-30 11:57:09 +01:00
|
|
|
m_initialFilesToProcessSize = m_unitsToProcess.count();
|
2014-10-30 17:35:52 +01:00
|
|
|
m_filesAnalyzed = 0;
|
|
|
|
|
m_filesNotAnalyzed = 0;
|
2014-09-25 11:11:58 +02:00
|
|
|
|
|
|
|
|
// Set up progress information
|
|
|
|
|
using namespace Core;
|
2015-01-28 17:04:03 +01:00
|
|
|
m_progress = QFutureInterface<void>();
|
2014-09-25 11:11:58 +02:00
|
|
|
FutureProgress *futureProgress
|
|
|
|
|
= ProgressManager::addTask(m_progress.future(), tr("Analyzing"), "ClangStaticAnalyzer");
|
|
|
|
|
futureProgress->setKeepOnFinish(FutureProgress::HideOnFinish);
|
|
|
|
|
connect(futureProgress, &FutureProgress::canceled,
|
|
|
|
|
this, &ClangStaticAnalyzerRunControl::onProgressCanceled);
|
|
|
|
|
m_progress.setProgressRange(0, m_initialFilesToProcessSize);
|
|
|
|
|
m_progress.reportStarted();
|
|
|
|
|
|
|
|
|
|
// Start process(es)
|
2016-01-05 08:58:01 +01:00
|
|
|
qCDebug(LOG) << "Environment:" << m_environment;
|
2014-10-28 09:44:26 +01:00
|
|
|
m_runners.clear();
|
2014-09-25 11:11:58 +02:00
|
|
|
const int parallelRuns = ClangStaticAnalyzerSettings::instance()->simultaneousProcesses();
|
2016-03-02 13:57:37 +01:00
|
|
|
QTC_ASSERT(parallelRuns >= 1, emit finished(); return);
|
2015-05-04 14:57:03 +02:00
|
|
|
m_success = true;
|
2016-03-02 13:57:37 +01:00
|
|
|
m_running = true;
|
2015-07-09 15:28:09 +02:00
|
|
|
|
|
|
|
|
if (m_unitsToProcess.isEmpty()) {
|
|
|
|
|
finalize();
|
2016-03-02 13:57:37 +01:00
|
|
|
return;
|
2015-07-09 15:28:09 +02:00
|
|
|
}
|
2016-03-02 13:57:37 +01:00
|
|
|
|
|
|
|
|
emit started();
|
|
|
|
|
|
2014-10-30 11:57:09 +01:00
|
|
|
while (m_runners.size() < parallelRuns && !m_unitsToProcess.isEmpty())
|
2014-09-25 11:11:58 +02:00
|
|
|
analyzeNextFile();
|
|
|
|
|
}
|
|
|
|
|
|
2016-03-02 13:57:37 +01:00
|
|
|
RunControl::StopResult ClangStaticAnalyzerRunControl::stop()
|
2014-09-25 11:11:58 +02:00
|
|
|
{
|
2014-10-28 09:44:26 +01:00
|
|
|
QSetIterator<ClangStaticAnalyzerRunner *> i(m_runners);
|
|
|
|
|
while (i.hasNext()) {
|
|
|
|
|
ClangStaticAnalyzerRunner *runner = i.next();
|
|
|
|
|
QObject::disconnect(runner, 0, this, 0);
|
|
|
|
|
delete runner;
|
|
|
|
|
}
|
|
|
|
|
m_runners.clear();
|
2014-10-30 11:57:09 +01:00
|
|
|
m_unitsToProcess.clear();
|
2014-10-30 17:35:52 +01:00
|
|
|
appendMessage(tr("Clang Static Analyzer stopped by user.") + QLatin1Char('\n'),
|
|
|
|
|
Utils::NormalMessageFormat);
|
|
|
|
|
m_progress.reportFinished();
|
2016-03-02 13:57:37 +01:00
|
|
|
m_running = false;
|
2014-10-30 17:35:52 +01:00
|
|
|
emit finished();
|
2016-03-02 13:57:37 +01:00
|
|
|
return RunControl::StoppedSynchronously;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool ClangStaticAnalyzerRunControl::isRunning() const
|
|
|
|
|
{
|
|
|
|
|
return m_running;
|
2014-09-25 11:11:58 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void ClangStaticAnalyzerRunControl::analyzeNextFile()
|
|
|
|
|
{
|
|
|
|
|
if (m_progress.isFinished())
|
|
|
|
|
return; // The previous call already reported that we are finished.
|
|
|
|
|
|
2014-10-30 11:57:09 +01:00
|
|
|
if (m_unitsToProcess.isEmpty()) {
|
2015-07-09 15:28:09 +02:00
|
|
|
if (m_runners.isEmpty())
|
|
|
|
|
finalize();
|
2014-09-25 11:11:58 +02:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2014-10-30 11:57:09 +01:00
|
|
|
const AnalyzeUnit unit = m_unitsToProcess.takeFirst();
|
|
|
|
|
qCDebug(LOG) << "analyzeNextFile:" << unit.file;
|
2014-09-25 11:11:58 +02:00
|
|
|
|
|
|
|
|
ClangStaticAnalyzerRunner *runner = createRunner();
|
2014-10-28 09:44:26 +01:00
|
|
|
m_runners.insert(runner);
|
2014-10-30 11:57:09 +01:00
|
|
|
QTC_ASSERT(runner->run(unit.file, unit.arguments), return);
|
|
|
|
|
|
2015-06-11 15:47:35 +02:00
|
|
|
appendMessage(tr("Analyzing \"%1\".").arg(
|
|
|
|
|
Utils::FileName::fromString(unit.file).toUserOutput()) + QLatin1Char('\n'),
|
2014-10-30 17:35:52 +01:00
|
|
|
Utils::StdOutFormat);
|
2014-09-25 11:11:58 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ClangStaticAnalyzerRunner *ClangStaticAnalyzerRunControl::createRunner()
|
|
|
|
|
{
|
|
|
|
|
QTC_ASSERT(!m_clangExecutable.isEmpty(), return 0);
|
|
|
|
|
QTC_ASSERT(!m_clangLogFileDir.isEmpty(), return 0);
|
|
|
|
|
|
2016-01-05 08:58:01 +01:00
|
|
|
auto runner = new ClangStaticAnalyzerRunner(m_clangExecutable,
|
|
|
|
|
m_clangLogFileDir,
|
|
|
|
|
m_environment,
|
|
|
|
|
this);
|
2014-09-25 11:11:58 +02:00
|
|
|
connect(runner, &ClangStaticAnalyzerRunner::finishedWithSuccess,
|
|
|
|
|
this, &ClangStaticAnalyzerRunControl::onRunnerFinishedWithSuccess);
|
|
|
|
|
connect(runner, &ClangStaticAnalyzerRunner::finishedWithFailure,
|
|
|
|
|
this, &ClangStaticAnalyzerRunControl::onRunnerFinishedWithFailure);
|
|
|
|
|
return runner;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void ClangStaticAnalyzerRunControl::onRunnerFinishedWithSuccess(const QString &logFilePath)
|
|
|
|
|
{
|
|
|
|
|
qCDebug(LOG) << "onRunnerFinishedWithSuccess:" << logFilePath;
|
|
|
|
|
|
|
|
|
|
QString errorMessage;
|
|
|
|
|
const QList<Diagnostic> diagnostics = LogFileReader::read(logFilePath, &errorMessage);
|
2014-10-30 17:35:52 +01:00
|
|
|
if (!errorMessage.isEmpty()) {
|
2014-09-25 11:11:58 +02:00
|
|
|
qCDebug(LOG) << "onRunnerFinishedWithSuccess: Error reading log file:" << errorMessage;
|
2014-10-30 17:35:52 +01:00
|
|
|
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();
|
2014-09-25 11:11:58 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void ClangStaticAnalyzerRunControl::onRunnerFinishedWithFailure(const QString &errorMessage,
|
|
|
|
|
const QString &errorDetails)
|
|
|
|
|
{
|
2016-07-05 10:40:34 +02:00
|
|
|
qCDebug(LOG).noquote() << "onRunnerFinishedWithFailure:"
|
|
|
|
|
<< errorMessage << '\n' << errorDetails;
|
2014-10-30 17:35:52 +01:00
|
|
|
|
|
|
|
|
++m_filesNotAnalyzed;
|
2015-05-04 14:57:03 +02:00
|
|
|
m_success = false;
|
2014-10-30 17:35:52 +01:00
|
|
|
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);
|
2016-05-31 16:09:48 +02:00
|
|
|
TaskHub::addTask(Task::Warning, errorMessage, Debugger::Constants::ANALYZERTASK_ID);
|
|
|
|
|
TaskHub::addTask(Task::Warning, errorDetails, Debugger::Constants::ANALYZERTASK_ID);
|
2014-09-25 11:11:58 +02:00
|
|
|
handleFinished();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void ClangStaticAnalyzerRunControl::handleFinished()
|
|
|
|
|
{
|
2014-10-28 09:44:26 +01:00
|
|
|
m_runners.remove(qobject_cast<ClangStaticAnalyzerRunner *>(sender()));
|
2014-09-25 11:11:58 +02:00
|
|
|
updateProgressValue();
|
|
|
|
|
sender()->deleteLater();
|
|
|
|
|
analyzeNextFile();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void ClangStaticAnalyzerRunControl::onProgressCanceled()
|
|
|
|
|
{
|
|
|
|
|
m_progress.reportCanceled();
|
2016-05-15 12:23:44 +03:00
|
|
|
stop();
|
2014-09-25 11:11:58 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void ClangStaticAnalyzerRunControl::updateProgressValue()
|
|
|
|
|
{
|
2014-10-30 11:57:09 +01:00
|
|
|
m_progress.setProgressValue(m_initialFilesToProcessSize - m_unitsToProcess.size());
|
2014-10-23 15:31:35 +02:00
|
|
|
}
|
|
|
|
|
|
2015-07-09 15:28:09 +02:00
|
|
|
void ClangStaticAnalyzerRunControl::finalize()
|
|
|
|
|
{
|
|
|
|
|
appendMessage(tr("Clang Static Analyzer finished: "
|
|
|
|
|
"Processed %1 files successfully, %2 failed.")
|
|
|
|
|
.arg(m_filesAnalyzed)
|
|
|
|
|
.arg(m_filesNotAnalyzed)
|
|
|
|
|
+ QLatin1Char('\n'),
|
|
|
|
|
Utils::NormalMessageFormat);
|
|
|
|
|
|
2016-02-08 10:23:53 +01:00
|
|
|
if (m_filesNotAnalyzed != 0) {
|
2016-05-31 16:09:48 +02:00
|
|
|
QString msg = tr("Clang Static Analyzer: Not all files could be analyzed.");
|
|
|
|
|
TaskHub::addTask(Task::Error, msg, Debugger::Constants::ANALYZERTASK_ID);
|
|
|
|
|
TaskHub::requestPopup();
|
2015-07-09 15:28:09 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
m_progress.reportFinished();
|
2016-03-11 09:35:41 +01:00
|
|
|
m_running = false;
|
2015-07-09 15:28:09 +02:00
|
|
|
emit finished();
|
|
|
|
|
}
|
|
|
|
|
|
2014-09-25 11:11:58 +02:00
|
|
|
} // namespace Internal
|
|
|
|
|
} // namespace ClangStaticAnalyzer
|