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:
Christian Kandeler
2015-01-23 15:25:45 +01:00
parent 6aad65375b
commit 0aa20dd26d
8 changed files with 56 additions and 24 deletions

View File

@@ -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\",

View File

@@ -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,19 +90,30 @@ 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 += QLatin1String("-fPIC"); // TODO: Remove? 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?
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;
}); });

View 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;

View File

@@ -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,

View File

@@ -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

View File

@@ -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;

View File

@@ -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)

View File

@@ -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);