Commit 5ff5211a authored by Nikolai Kosjar's avatar Nikolai Kosjar

Clang: Set -fms-compatibility-version explicitly

Infer the version from the _MSC_FULL_VER macro, so it cannot get out of sync
with that.

Adapt the analyzer to do the same.

Based on

  commit daf08d87
  Clang Static Analyzer: Workaround analyzing MSVC2015 projects with clang 3.8.0

Change-Id: I9d34abdbe2c83fe271eadd8d051caad43aca6772
Reviewed-by: default avatarChristian Kandeler <christian.kandeler@theqtcompany.com>
parent b0959ee6
......@@ -99,6 +99,8 @@ public:
optionsBuilder.addHeaderPathOptions();
optionsBuilder.addProjectConfigFileInclude();
optionsBuilder.addMsvcCompatibilityVersion();
optionsBuilder.addExtraOptions();
return optionsBuilder.options();
......
......@@ -142,14 +142,6 @@ QStringList inputAndOutputArgumentsRemoved(const QString &inputFile, const QStri
return newArguments;
}
static void appendMsCompatibility2015OptionForMsvc2015(QStringList *arguments, bool isMsvc2015)
{
QTC_ASSERT(arguments, return);
if (isMsvc2015)
arguments->append(QLatin1String("-fms-compatibility-version=19"));
}
static QStringList languageFeatureMacros()
{
// Collected with:
......@@ -198,19 +190,6 @@ static void undefineCppLanguageFeatureMacrosForMsvc2015(QStringList *arguments,
}
}
static QStringList tweakedArguments(const QString &filePath,
const QStringList &arguments,
const ExtraToolChainInfo &extraParams)
{
QStringList newArguments = inputAndOutputArgumentsRemoved(filePath, arguments);
prependWordWidthArgumentIfNotIncluded(&newArguments, extraParams.wordWidth);
prependTargetTripleIfNotIncludedAndNotEmpty(&newArguments, extraParams.targetTriple);
appendMsCompatibility2015OptionForMsvc2015(&newArguments, extraParams.isMsvc2015);
undefineCppLanguageFeatureMacrosForMsvc2015(&newArguments, extraParams.isMsvc2015);
return newArguments;
}
static QString createLanguageOptionMsvc(ProjectFile::Kind fileKind)
{
switch (fileKind) {
......@@ -252,6 +231,7 @@ public:
optionsBuilder.addToolchainAndProjectDefines();
optionsBuilder.addHeaderPathOptions();
optionsBuilder.addMsvcCompatibilityVersion();
if (type == ProjectExplorer::Constants::MSVC_TOOLCHAIN_TYPEID)
optionsBuilder.add(QLatin1String("/EHsc")); // clang-cl does not understand exceptions
......@@ -260,19 +240,18 @@ public:
QStringList options = optionsBuilder.options();
prependWordWidthArgumentIfNotIncluded(&options, extraParams.wordWidth);
appendMsCompatibility2015OptionForMsvc2015(&options, extraParams.isMsvc2015);
undefineCppLanguageFeatureMacrosForMsvc2015(&options, extraParams.isMsvc2015);
return options;
}
private:
ClangStaticAnalyzerOptionsBuilder(const CppTools::ProjectPart &projectPart)
: CompilerOptionsBuilder(projectPart)
, m_isMsvcToolchain(m_projectPart.toolchainType == ProjectExplorer::Constants::MSVC_TOOLCHAIN_TYPEID)
{
}
private:
void addTargetTriple() override
{
// For MSVC toolchains we use clang-cl.exe, so there is nothing to do here since
......@@ -315,7 +294,31 @@ private:
bool m_isMsvcToolchain;
};
static QStringList createMsCompatibilityVersionOption(const ProjectPart &projectPart)
{
ClangStaticAnalyzerOptionsBuilder optionsBuilder(projectPart);
optionsBuilder.addMsvcCompatibilityVersion();
const QStringList option = optionsBuilder.options();
return option;
}
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);
newArguments.append(createMsCompatibilityVersionOption(projectPart));
undefineCppLanguageFeatureMacrosForMsvc2015(&newArguments, extraParams.isMsvc2015);
return newArguments;
}
static AnalyzeUnits unitsToAnalyzeFromCompilerCallData(
const QHash<QString, ProjectPart::Ptr> &projectFileToProjectPart,
const ProjectInfo::CompilerCallData &compilerCallData,
const ExtraToolChainInfo &extraParams)
{
......@@ -324,13 +327,20 @@ static AnalyzeUnits unitsToAnalyzeFromCompilerCallData(
AnalyzeUnits unitsToAnalyze;
foreach (const ProjectInfo::CompilerCallGroup &compilerCallGroup, compilerCallData) {
const ProjectPart::Ptr projectPart
= projectFileToProjectPart.value(compilerCallGroup.groupId);
QTC_ASSERT(projectPart, continue);
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) {
const QStringList arguments = tweakedArguments(file, options, extraParams);
const QStringList arguments = tweakedArguments(*projectPart,
file,
options,
extraParams);
unitsToAnalyze << AnalyzeUnit(file, arguments);
}
}
......@@ -367,16 +377,34 @@ static AnalyzeUnits unitsToAnalyzeFromProjectParts(const QList<ProjectPart::Ptr>
return unitsToAnalyze;
}
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;
}
AnalyzeUnits ClangStaticAnalyzerRunControl::sortedUnitsToAnalyze()
{
QTC_ASSERT(m_projectInfo.isValid(), return AnalyzeUnits());
AnalyzeUnits units;
const ProjectInfo::CompilerCallData compilerCallData = m_projectInfo.compilerCallData();
if (compilerCallData.isEmpty())
if (compilerCallData.isEmpty()) {
units = unitsToAnalyzeFromProjectParts(m_projectInfo.projectParts(), m_extraToolChainInfo);
else
units = unitsToAnalyzeFromCompilerCallData(compilerCallData, m_extraToolChainInfo);
} else {
const QHash<QString, ProjectPart::Ptr> projectFileToProjectPart
= generateProjectFileToProjectPartMapping(m_projectInfo.projectParts());
units = unitsToAnalyzeFromCompilerCallData(projectFileToProjectPart,
compilerCallData,
m_extraToolChainInfo);
}
Utils::sort(units, [](const AnalyzeUnit &a1, const AnalyzeUnit &a2) -> bool {
return a1.file < a2.file;
......
......@@ -44,16 +44,39 @@ void CompilerOptionsBuilder::add(const QString &option)
m_options.append(option);
}
QString CompilerOptionsBuilder::defineLineToDefineOption(const QByteArray &defineLine)
struct Macro {
static Macro fromDefineDirective(const QByteArray &defineDirective);
QByteArray toDefineOption(const QByteArray &option) const;
QByteArray name;
QByteArray value;
};
Macro Macro::fromDefineDirective(const QByteArray &defineDirective)
{
QByteArray str = defineLine.mid(8);
int spaceIdx = str.indexOf(' ');
const QString option = defineOption();
const QByteArray str = defineDirective.mid(8);
const int spaceIdx = str.indexOf(' ');
const bool hasValue = spaceIdx != -1;
QString arg = option + QLatin1String(str.left(hasValue ? spaceIdx : str.size()) + '=');
Macro macro;
macro.name = str.left(hasValue ? spaceIdx : str.size());
if (hasValue)
arg += QLatin1String(str.mid(spaceIdx + 1));
return arg;
macro.value = str.mid(spaceIdx + 1);
return macro;
}
QByteArray Macro::toDefineOption(const QByteArray &option) const
{
QByteArray result;
result.append(option);
result.append(name);
result.append('=');
if (!value.isEmpty())
result.append(value);
return result;
}
void CompilerOptionsBuilder::addDefine(const QByteArray &defineLine)
......@@ -225,11 +248,54 @@ void CompilerOptionsBuilder::addOptionsForLanguage(bool checkForBorlandExtension
m_options.append(opts);
}
static QByteArray toMsCompatibilityVersionFormat(const QByteArray &mscFullVer)
{
return mscFullVer.left(2)
+ QByteArray(".")
+ mscFullVer.mid(2, 2);
}
static QByteArray msCompatibilityVersionFromDefines(const QByteArray &defineDirectives)
{
foreach (QByteArray defineDirective, defineDirectives.split('\n')) {
if (defineDirective.isEmpty())
continue;
const Macro macro = Macro::fromDefineDirective(defineDirective);
if (macro.name == "_MSC_FULL_VER")
return toMsCompatibilityVersionFormat(macro.value);
}
return QByteArray();
}
void CompilerOptionsBuilder::addMsvcCompatibilityVersion()
{
if (m_projectPart.toolchainType == ProjectExplorer::Constants::MSVC_TOOLCHAIN_TYPEID) {
const QByteArray defines = m_projectPart.toolchainDefines + m_projectPart.projectDefines;
const QByteArray msvcVersion = msCompatibilityVersionFromDefines(defines);
if (!msvcVersion.isEmpty()) {
const QString option = QLatin1String("-fms-compatibility-version=")
+ QLatin1String(msvcVersion);
m_options.append(option);
}
}
}
QString CompilerOptionsBuilder::includeOption() const
{
return QLatin1String("-I");
}
QString CompilerOptionsBuilder::defineLineToDefineOption(const QByteArray &defineLine)
{
const Macro macro = Macro::fromDefineDirective(defineLine);
const QByteArray option = macro.toDefineOption(defineOption().toLatin1());
return QString::fromLatin1(option);
}
QString CompilerOptionsBuilder::defineOption() const
{
return QLatin1String("-D");
......
......@@ -51,6 +51,8 @@ public:
virtual void addLanguageOption(ProjectFile::Kind fileKind);
virtual void addOptionsForLanguage(bool checkForBorlandExtensions = true);
void addMsvcCompatibilityVersion();
protected:
virtual bool excludeDefineLine(const QByteArray &defineLine) const;
virtual bool excludeHeaderPath(const QString &headerPath) const;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment