From 5ff5211a2570e0e894f53bfedb1f1102bde4d58c Mon Sep 17 00:00:00 2001 From: Nikolai Kosjar <nikolai.kosjar@theqtcompany.com> Date: Mon, 11 Apr 2016 11:53:50 +0200 Subject: [PATCH] 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 daf08d8702905335e3fc63c629f917e99715b915 Clang Static Analyzer: Workaround analyzing MSVC2015 projects with clang 3.8.0 Change-Id: I9d34abdbe2c83fe271eadd8d051caad43aca6772 Reviewed-by: Christian Kandeler <christian.kandeler@theqtcompany.com> --- src/plugins/clangcodemodel/clangutils.cpp | 2 + .../clangstaticanalyzerruncontrol.cpp | 82 +++++++++++++------ .../cpptools/compileroptionsbuilder.cpp | 80 ++++++++++++++++-- src/plugins/cpptools/compileroptionsbuilder.h | 2 + 4 files changed, 132 insertions(+), 34 deletions(-) diff --git a/src/plugins/clangcodemodel/clangutils.cpp b/src/plugins/clangcodemodel/clangutils.cpp index 39eeeb31878..7c5c5494935 100644 --- a/src/plugins/clangcodemodel/clangutils.cpp +++ b/src/plugins/clangcodemodel/clangutils.cpp @@ -99,6 +99,8 @@ public: optionsBuilder.addHeaderPathOptions(); optionsBuilder.addProjectConfigFileInclude(); + optionsBuilder.addMsvcCompatibilityVersion(); + optionsBuilder.addExtraOptions(); return optionsBuilder.options(); diff --git a/src/plugins/clangstaticanalyzer/clangstaticanalyzerruncontrol.cpp b/src/plugins/clangstaticanalyzer/clangstaticanalyzerruncontrol.cpp index 5a9fcdbbd31..1b2ace47379 100644 --- a/src/plugins/clangstaticanalyzer/clangstaticanalyzerruncontrol.cpp +++ b/src/plugins/clangstaticanalyzer/clangstaticanalyzerruncontrol.cpp @@ -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; diff --git a/src/plugins/cpptools/compileroptionsbuilder.cpp b/src/plugins/cpptools/compileroptionsbuilder.cpp index b520babef13..6de6a44d5dc 100644 --- a/src/plugins/cpptools/compileroptionsbuilder.cpp +++ b/src/plugins/cpptools/compileroptionsbuilder.cpp @@ -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"); diff --git a/src/plugins/cpptools/compileroptionsbuilder.h b/src/plugins/cpptools/compileroptionsbuilder.h index c259c8cf4dc..e2c38f02258 100644 --- a/src/plugins/cpptools/compileroptionsbuilder.h +++ b/src/plugins/cpptools/compileroptionsbuilder.h @@ -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; -- GitLab