forked from qt-creator/qt-creator
Add support for MSVC.
Via clang-cl, which supports the --analyze option now. Change-Id: Idbefe048eaa80e8c5bdb2244cb30c26ba7c71ef5 Reviewed-by: Nikolai Kosjar <nikolai.kosjar@theqtcompany.com>
This commit is contained in:
@@ -3,7 +3,6 @@
|
|||||||
\"Version\" : \"$$QTCREATOR_VERSION\",
|
\"Version\" : \"$$QTCREATOR_VERSION\",
|
||||||
\"CompatVersion\" : \"$$QTCREATOR_COMPAT_VERSION\",
|
\"CompatVersion\" : \"$$QTCREATOR_COMPAT_VERSION\",
|
||||||
\"Experimental\" : true,
|
\"Experimental\" : true,
|
||||||
\"Platform\" : \"(Linux.*)|(OS X.*)\",
|
|
||||||
\"Vendor\" : \"Digia Plc\",
|
\"Vendor\" : \"Digia Plc\",
|
||||||
\"Copyright\" : \"(C) 2014 Digia Plc\",
|
\"Copyright\" : \"(C) 2014 Digia Plc\",
|
||||||
\"License\" : [ \"Commercial Usage\",
|
\"License\" : [ \"Commercial Usage\",
|
||||||
|
|||||||
@@ -34,6 +34,7 @@
|
|||||||
#include <cpptools/cppprojects.h>
|
#include <cpptools/cppprojects.h>
|
||||||
#include <cpptools/cppprojectfile.h>
|
#include <cpptools/cppprojectfile.h>
|
||||||
|
|
||||||
|
#include <projectexplorer/kitinformation.h>
|
||||||
#include <projectexplorer/project.h>
|
#include <projectexplorer/project.h>
|
||||||
#include <projectexplorer/target.h>
|
#include <projectexplorer/target.h>
|
||||||
|
|
||||||
@@ -56,6 +57,8 @@ ClangStaticAnalyzerRunControl::ClangStaticAnalyzerRunControl(
|
|||||||
const ProjectInfo &projectInfo)
|
const ProjectInfo &projectInfo)
|
||||||
: AnalyzerRunControl(startParams, runConfiguration)
|
: AnalyzerRunControl(startParams, runConfiguration)
|
||||||
, m_projectInfo(projectInfo)
|
, m_projectInfo(projectInfo)
|
||||||
|
, m_toolchainType(ProjectExplorer::ToolChainKitInformation
|
||||||
|
::toolChain(runConfiguration->target()->kit())->type())
|
||||||
, m_initialFilesToProcessSize(0)
|
, m_initialFilesToProcessSize(0)
|
||||||
, m_filesAnalyzed(0)
|
, m_filesAnalyzed(0)
|
||||||
, m_filesNotAnalyzed(0)
|
, m_filesNotAnalyzed(0)
|
||||||
@@ -75,7 +78,7 @@ static QStringList tweakedArguments(const QString &filePath, const QStringList &
|
|||||||
} else if (argument == QLatin1String("-o")) {
|
} else if (argument == QLatin1String("-o")) {
|
||||||
skip = true;
|
skip = true;
|
||||||
continue;
|
continue;
|
||||||
} else if (argument == filePath) {
|
} else if (QDir::fromNativeSeparators(argument) == filePath) {
|
||||||
continue; // TODO: Let it in?
|
continue; // TODO: Let it in?
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -87,18 +90,29 @@ static QStringList tweakedArguments(const QString &filePath, const QStringList &
|
|||||||
}
|
}
|
||||||
|
|
||||||
static QStringList argumentsFromProjectPart(const CppTools::ProjectPart::Ptr &projectPart,
|
static QStringList argumentsFromProjectPart(const CppTools::ProjectPart::Ptr &projectPart,
|
||||||
CppTools::ProjectFile::Kind fileKind)
|
CppTools::ProjectFile::Kind fileKind,
|
||||||
|
const QString &toolchainType)
|
||||||
{
|
{
|
||||||
QStringList result;
|
QStringList result;
|
||||||
|
|
||||||
const bool objcExt = projectPart->languageExtensions & ProjectPart::ObjectiveCExtensions;
|
const bool objcExt = projectPart->languageExtensions & ProjectPart::ObjectiveCExtensions;
|
||||||
result += CppTools::CompilerOptionsBuilder::createLanguageOption(fileKind, objcExt);
|
result += CppTools::CompilerOptionsBuilder::createLanguageOption(fileKind, objcExt,
|
||||||
|
toolchainType);
|
||||||
result += CppTools::CompilerOptionsBuilder::createOptionsForLanguage(
|
result += CppTools::CompilerOptionsBuilder::createOptionsForLanguage(
|
||||||
projectPart->languageVersion,
|
projectPart->languageVersion,
|
||||||
projectPart->languageExtensions);
|
projectPart->languageExtensions, false,
|
||||||
result += CppTools::CompilerOptionsBuilder::createDefineOptions(projectPart->toolchainDefines);
|
toolchainType);
|
||||||
result += CppTools::CompilerOptionsBuilder::createDefineOptions(projectPart->projectDefines);
|
result += CppTools::CompilerOptionsBuilder::createDefineOptions(projectPart->toolchainDefines,
|
||||||
result += CppTools::CompilerOptionsBuilder::createHeaderPathOptions(projectPart->headerPaths);
|
false, toolchainType);
|
||||||
|
result += CppTools::CompilerOptionsBuilder::createDefineOptions(projectPart->projectDefines,
|
||||||
|
false, toolchainType);
|
||||||
|
result += CppTools::CompilerOptionsBuilder::createHeaderPathOptions(
|
||||||
|
projectPart->headerPaths,
|
||||||
|
CompilerOptionsBuilder::IsBlackListed(),
|
||||||
|
toolchainType);
|
||||||
|
if (toolchainType == QLatin1String("msvc"))
|
||||||
|
result += QLatin1String("/EHsc"); // clang-cl does not understand exceptions
|
||||||
|
else
|
||||||
result += QLatin1String("-fPIC"); // TODO: Remove?
|
result += QLatin1String("-fPIC"); // TODO: Remove?
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
@@ -127,7 +141,7 @@ static QList<ClangStaticAnalyzerRunControl::AnalyzeUnit> unitsToAnalyzeFromCompi
|
|||||||
}
|
}
|
||||||
|
|
||||||
static QList<ClangStaticAnalyzerRunControl::AnalyzeUnit> unitsToAnalyzeFromProjectParts(
|
static QList<ClangStaticAnalyzerRunControl::AnalyzeUnit> unitsToAnalyzeFromProjectParts(
|
||||||
const QList<ProjectPart::Ptr> projectParts)
|
const QList<ProjectPart::Ptr> projectParts, const QString &toolchainType)
|
||||||
{
|
{
|
||||||
typedef ClangStaticAnalyzerRunControl::AnalyzeUnit AnalyzeUnit;
|
typedef ClangStaticAnalyzerRunControl::AnalyzeUnit AnalyzeUnit;
|
||||||
qCDebug(LOG) << "Taking arguments for analyzing from ProjectParts.";
|
qCDebug(LOG) << "Taking arguments for analyzing from ProjectParts.";
|
||||||
@@ -143,7 +157,8 @@ static QList<ClangStaticAnalyzerRunControl::AnalyzeUnit> unitsToAnalyzeFromProje
|
|||||||
continue;
|
continue;
|
||||||
QTC_CHECK(file.kind != ProjectFile::Unclassified);
|
QTC_CHECK(file.kind != ProjectFile::Unclassified);
|
||||||
if (ProjectFile::isSource(file.kind)) {
|
if (ProjectFile::isSource(file.kind)) {
|
||||||
const QStringList arguments = argumentsFromProjectPart(projectPart, file.kind);
|
const QStringList arguments
|
||||||
|
= argumentsFromProjectPart(projectPart, file.kind, toolchainType);
|
||||||
unitsToAnalyze << AnalyzeUnit(file.path, arguments);
|
unitsToAnalyze << AnalyzeUnit(file.path, arguments);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -152,15 +167,14 @@ static QList<ClangStaticAnalyzerRunControl::AnalyzeUnit> unitsToAnalyzeFromProje
|
|||||||
return unitsToAnalyze;
|
return unitsToAnalyze;
|
||||||
}
|
}
|
||||||
|
|
||||||
static QList<ClangStaticAnalyzerRunControl::AnalyzeUnit> unitsToAnalyze(
|
QList<ClangStaticAnalyzerRunControl::AnalyzeUnit> ClangStaticAnalyzerRunControl::unitsToAnalyze()
|
||||||
const CppTools::ProjectInfo &projectInfo)
|
|
||||||
{
|
{
|
||||||
QTC_ASSERT(projectInfo.isValid(), return QList<ClangStaticAnalyzerRunControl::AnalyzeUnit>());
|
QTC_ASSERT(m_projectInfo.isValid(), return QList<ClangStaticAnalyzerRunControl::AnalyzeUnit>());
|
||||||
|
|
||||||
const ProjectInfo::CompilerCallData compilerCallData = projectInfo.compilerCallData();
|
const ProjectInfo::CompilerCallData compilerCallData = m_projectInfo.compilerCallData();
|
||||||
if (!compilerCallData.isEmpty())
|
if (!compilerCallData.isEmpty())
|
||||||
return unitsToAnalyzeFromCompilerCallData(compilerCallData);
|
return unitsToAnalyzeFromCompilerCallData(compilerCallData);
|
||||||
return unitsToAnalyzeFromProjectParts(projectInfo.projectParts());
|
return unitsToAnalyzeFromProjectParts(m_projectInfo.projectParts(), m_toolchainType);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ClangStaticAnalyzerRunControl::startEngine()
|
bool ClangStaticAnalyzerRunControl::startEngine()
|
||||||
@@ -174,7 +188,8 @@ bool ClangStaticAnalyzerRunControl::startEngine()
|
|||||||
|
|
||||||
// Check clang executable
|
// Check clang executable
|
||||||
bool isValidClangExecutable;
|
bool isValidClangExecutable;
|
||||||
const QString executable = clangExecutableFromSettings(&isValidClangExecutable);
|
const QString executable
|
||||||
|
= clangExecutableFromSettings(m_toolchainType, &isValidClangExecutable);
|
||||||
if (!isValidClangExecutable) {
|
if (!isValidClangExecutable) {
|
||||||
emit appendMessage(tr("Clang Static Analyzer: Invalid executable \"%1\", stop.")
|
emit appendMessage(tr("Clang Static Analyzer: Invalid executable \"%1\", stop.")
|
||||||
.arg(executable) + QLatin1Char('\n'),
|
.arg(executable) + QLatin1Char('\n'),
|
||||||
@@ -196,7 +211,7 @@ bool ClangStaticAnalyzerRunControl::startEngine()
|
|||||||
m_clangLogFileDir = temporaryDir.path();
|
m_clangLogFileDir = temporaryDir.path();
|
||||||
|
|
||||||
// Collect files
|
// Collect files
|
||||||
QList<AnalyzeUnit> unitsToProcess = unitsToAnalyze(m_projectInfo);
|
QList<AnalyzeUnit> unitsToProcess = unitsToAnalyze();
|
||||||
Utils::sort(unitsToProcess, [](const AnalyzeUnit &a1, const AnalyzeUnit &a2) -> bool {
|
Utils::sort(unitsToProcess, [](const AnalyzeUnit &a1, const AnalyzeUnit &a2) -> bool {
|
||||||
return a1.file < a2.file;
|
return a1.file < a2.file;
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -56,6 +56,7 @@ signals:
|
|||||||
void newDiagnosticsAvailable(const QList<Diagnostic> &diagnostics);
|
void newDiagnosticsAvailable(const QList<Diagnostic> &diagnostics);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
QList<ClangStaticAnalyzerRunControl::AnalyzeUnit> unitsToAnalyze();
|
||||||
void analyzeNextFile();
|
void analyzeNextFile();
|
||||||
ClangStaticAnalyzerRunner *createRunner();
|
ClangStaticAnalyzerRunner *createRunner();
|
||||||
|
|
||||||
@@ -68,6 +69,7 @@ private:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
const CppTools::ProjectInfo m_projectInfo;
|
const CppTools::ProjectInfo m_projectInfo;
|
||||||
|
const QString m_toolchainType;
|
||||||
|
|
||||||
QString m_clangExecutable;
|
QString m_clangExecutable;
|
||||||
QString m_clangLogFileDir;
|
QString m_clangLogFileDir;
|
||||||
|
|||||||
@@ -61,7 +61,8 @@ bool ClangStaticAnalyzerRunControlFactory::canRun(RunConfiguration *runConfigura
|
|||||||
QTC_ASSERT(kit, return false);
|
QTC_ASSERT(kit, return false);
|
||||||
ToolChain *toolChain = ToolChainKitInformation::toolChain(kit);
|
ToolChain *toolChain = ToolChainKitInformation::toolChain(kit);
|
||||||
return toolChain && (toolChain->type() == QLatin1String("clang")
|
return toolChain && (toolChain->type() == QLatin1String("clang")
|
||||||
|| toolChain->type() == QLatin1String("gcc"));
|
|| toolChain->type() == QLatin1String("gcc")
|
||||||
|
|| toolChain->type() == QLatin1String("msvc"));
|
||||||
}
|
}
|
||||||
|
|
||||||
RunControl *ClangStaticAnalyzerRunControlFactory::create(RunConfiguration *runConfiguration,
|
RunControl *ClangStaticAnalyzerRunControlFactory::create(RunConfiguration *runConfiguration,
|
||||||
|
|||||||
@@ -50,7 +50,7 @@ static QStringList constructCommandLineArguments(const QString &filePath,
|
|||||||
<< logFile
|
<< logFile
|
||||||
;
|
;
|
||||||
arguments += options;
|
arguments += options;
|
||||||
arguments << filePath;
|
arguments << QDir::toNativeSeparators(filePath);
|
||||||
return arguments;
|
return arguments;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -73,6 +73,7 @@ ClangStaticAnalyzerRunner::ClangStaticAnalyzerRunner(const QString &clangExecuta
|
|||||||
QTC_CHECK(!m_clangLogFileDir.isEmpty());
|
QTC_CHECK(!m_clangLogFileDir.isEmpty());
|
||||||
|
|
||||||
m_process.setProcessChannelMode(QProcess::MergedChannels);
|
m_process.setProcessChannelMode(QProcess::MergedChannels);
|
||||||
|
m_process.setWorkingDirectory(m_clangLogFileDir); // Current clang-cl puts log file into working dir.
|
||||||
connect(&m_process, &QProcess::started,
|
connect(&m_process, &QProcess::started,
|
||||||
this, &ClangStaticAnalyzerRunner::onProcessStarted);
|
this, &ClangStaticAnalyzerRunner::onProcessStarted);
|
||||||
connect(&m_process, static_cast<void (QProcess::*)(int, QProcess::ExitStatus)>(&QProcess::finished),
|
connect(&m_process, static_cast<void (QProcess::*)(int, QProcess::ExitStatus)>(&QProcess::finished),
|
||||||
@@ -122,7 +123,7 @@ void ClangStaticAnalyzerRunner::onProcessFinished(int exitCode, QProcess::ExitSt
|
|||||||
{
|
{
|
||||||
if (exitStatus == QProcess::NormalExit) {
|
if (exitStatus == QProcess::NormalExit) {
|
||||||
if (exitCode == 0)
|
if (exitCode == 0)
|
||||||
emit finishedWithSuccess(m_logFile);
|
emit finishedWithSuccess(actualLogFile());
|
||||||
else
|
else
|
||||||
emit finishedWithFailure(finishedWithBadExitCode(exitCode), processCommandlineAndOutput());
|
emit finishedWithFailure(finishedWithBadExitCode(exitCode), processCommandlineAndOutput());
|
||||||
} else { // == QProcess::CrashExit
|
} else { // == QProcess::CrashExit
|
||||||
@@ -169,5 +170,15 @@ QString ClangStaticAnalyzerRunner::processCommandlineAndOutput() const
|
|||||||
QString::fromLocal8Bit(m_processOutput));
|
QString::fromLocal8Bit(m_processOutput));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QString ClangStaticAnalyzerRunner::actualLogFile() const
|
||||||
|
{
|
||||||
|
if (QFileInfo(m_logFile).size() == 0) {
|
||||||
|
// Current clang-cl ignores -o, always putting the log file into the working directory.
|
||||||
|
return m_clangLogFileDir + QLatin1Char('/') + QFileInfo(m_filePath).completeBaseName()
|
||||||
|
+ QLatin1String(".plist");
|
||||||
|
}
|
||||||
|
return m_logFile;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace Internal
|
} // namespace Internal
|
||||||
} // namespace ClangStaticAnalyzer
|
} // namespace ClangStaticAnalyzer
|
||||||
|
|||||||
@@ -60,6 +60,7 @@ private:
|
|||||||
|
|
||||||
QString createLogFile(const QString &filePath) const;
|
QString createLogFile(const QString &filePath) const;
|
||||||
QString processCommandlineAndOutput() const;
|
QString processCommandlineAndOutput() const;
|
||||||
|
QString actualLogFile() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QString m_clangExecutable;
|
QString m_clangExecutable;
|
||||||
|
|||||||
@@ -37,9 +37,12 @@ static bool isFileExecutable(const QString &executablePath)
|
|||||||
namespace ClangStaticAnalyzer {
|
namespace ClangStaticAnalyzer {
|
||||||
namespace Internal {
|
namespace Internal {
|
||||||
|
|
||||||
QString clangExecutableFromSettings(bool *isValid)
|
QString clangExecutableFromSettings(const QString &toolchainType, bool *isValid)
|
||||||
{
|
{
|
||||||
return clangExecutable(ClangStaticAnalyzerSettings::instance()->clangExecutable(), isValid);
|
QString exeFromSettings = ClangStaticAnalyzerSettings::instance()->clangExecutable();
|
||||||
|
if (toolchainType == QLatin1String("msvc"))
|
||||||
|
exeFromSettings.replace(QLatin1String("clang.exe"), QLatin1String("clang-cl.exe"));
|
||||||
|
return clangExecutable(exeFromSettings, isValid);
|
||||||
}
|
}
|
||||||
|
|
||||||
QString clangExecutable(const QString &fileNameOrPath, bool *isValid)
|
QString clangExecutable(const QString &fileNameOrPath, bool *isValid)
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ namespace Internal {
|
|||||||
class Location;
|
class Location;
|
||||||
|
|
||||||
QString clangExecutable(const QString &fileNameOrPath, bool *isValid);
|
QString clangExecutable(const QString &fileNameOrPath, bool *isValid);
|
||||||
QString clangExecutableFromSettings(bool *isValid);
|
QString clangExecutableFromSettings(const QString &toolchainType, bool *isValid);
|
||||||
|
|
||||||
QString createFullLocationString(const ClangStaticAnalyzer::Internal::Location &location);
|
QString createFullLocationString(const ClangStaticAnalyzer::Internal::Location &location);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user