diff --git a/src/plugins/clangcodemodel/clangutils.cpp b/src/plugins/clangcodemodel/clangutils.cpp index 8f11758ac4d..725042488b5 100644 --- a/src/plugins/clangcodemodel/clangutils.cpp +++ b/src/plugins/clangcodemodel/clangutils.cpp @@ -83,44 +83,17 @@ QStringList createClangOptions(const ProjectPart::Ptr &pPart, const QString &fil return createClangOptions(pPart, fileKind); } -static QString creatorResourcePath() -{ -#ifndef UNIT_TESTS - return Core::ICore::resourcePath(); -#else - return QString(); -#endif -} - -static QString clangIncludeDirectory(const QString &clangVersion, - const QString &clangResourceDirectory) -{ -#ifndef UNIT_TESTS - return Core::ICore::clangIncludeDirectory(clangVersion, clangResourceDirectory); -#else - return QString(); -#endif -} - class LibClangOptionsBuilder final : public CompilerOptionsBuilder { public: LibClangOptionsBuilder(const ProjectPart &projectPart) - : CompilerOptionsBuilder(projectPart) - , m_clangVersion(CLANG_VERSION) - , m_clangResourceDirectory(CLANG_RESOURCE_DIR) + : CompilerOptionsBuilder(projectPart, + UseSystemHeader::No, + QString(CLANG_VERSION), + QString(CLANG_RESOURCE_DIR)) { } - void addPredefinedHeaderPathsOptions() final - { - CompilerOptionsBuilder::addPredefinedHeaderPathsOptions(); - add("-nostdinc"); - add("-nostdlibinc"); - addClangIncludeFolder(); - addWrappedQtHeadersIncludePath(); - } - void addToolchainAndProjectMacros() final { addMacros({ProjectExplorer::Macro("Q_CREATOR_RUN", "1")}); @@ -138,28 +111,6 @@ public: } private: - void addClangIncludeFolder() - { - QTC_CHECK(!m_clangVersion.isEmpty()); - add("-I"); - add(clangIncludeDirectory(m_clangVersion, m_clangResourceDirectory)); - } - - void addWrappedQtHeadersIncludePath() - { - static const QString resourcePath = creatorResourcePath(); - static QString wrappedQtHeadersPath = resourcePath + "/cplusplus/wrappedQtHeaders"; - QTC_ASSERT(QDir(wrappedQtHeadersPath).exists(), return;); - - if (m_projectPart.qtVersion != CppTools::ProjectPart::NoQt) { - const QString wrappedQtCoreHeaderPath = wrappedQtHeadersPath + "/QtCore"; - add(includeDirOptionForPath(wrappedQtHeadersPath)); - add(QDir::toNativeSeparators(wrappedQtHeadersPath)); - add(includeDirOptionForPath(wrappedQtHeadersPath)); - add(QDir::toNativeSeparators(wrappedQtCoreHeaderPath)); - } - } - void addDummyUiHeaderOnDiskIncludePath() { const QString path = ModelManagerSupportClang::instance()->dummyUiHeaderOnDiskDirPath(); @@ -168,9 +119,6 @@ private: add(QDir::toNativeSeparators(path)); } } - - QString m_clangVersion; - QString m_clangResourceDirectory; }; /** diff --git a/src/plugins/clangtools/clangtoolruncontrol.cpp b/src/plugins/clangtools/clangtoolruncontrol.cpp index e824d7a0c08..92e225bc5b9 100644 --- a/src/plugins/clangtools/clangtoolruncontrol.cpp +++ b/src/plugins/clangtools/clangtoolruncontrol.cpp @@ -191,7 +191,10 @@ static AnalyzeUnits toAnalyzeUnits(const FileInfos &fileInfos) AnalyzeUnits unitsToAnalyze; const CompilerOptionsBuilder::PchUsage pchUsage = CppTools::getPchUsage(); for (const FileInfo &fileInfo : fileInfos) { - CompilerOptionsBuilder optionsBuilder(*fileInfo.projectPart); + CompilerOptionsBuilder optionsBuilder(*fileInfo.projectPart, + CppTools::UseSystemHeader::No, + QString(CLANG_VERSION), + QString(CLANG_RESOURCE_DIR)); QStringList arguments = extraClangToolsPrependOptions(); arguments.append(optionsBuilder.build(fileInfo.kind, pchUsage)); arguments.append(extraClangToolsAppendOptions()); diff --git a/src/plugins/cpptools/compileroptionsbuilder.cpp b/src/plugins/cpptools/compileroptionsbuilder.cpp index 8a1434cce96..d63aaa0951f 100644 --- a/src/plugins/cpptools/compileroptionsbuilder.cpp +++ b/src/plugins/cpptools/compileroptionsbuilder.cpp @@ -25,6 +25,8 @@ #include "compileroptionsbuilder.h" +#include "cppmodelmanager.h" + #include #include @@ -40,9 +42,13 @@ namespace CppTools { CompilerOptionsBuilder::CompilerOptionsBuilder(const ProjectPart &projectPart, - UseSystemHeader useSystemHeader) - : m_projectPart(projectPart), - m_useSystemHeader(useSystemHeader) + UseSystemHeader useSystemHeader, + QString clangVersion, + QString clangResourceDirectory) + : m_projectPart(projectPart) + , m_useSystemHeader(useSystemHeader) + , m_clangVersion(clangVersion) + , m_clangResourceDirectory(clangResourceDirectory) { } @@ -69,7 +75,7 @@ QStringList CompilerOptionsBuilder::build(CppTools::ProjectFile::Kind fileKind, undefineCppLanguageFeatureMacrosForMsvc2015(); addDefineFunctionMacrosMsvc(); - addPredefinedHeaderPathsOptions(); + addGlobalUndef(); addPrecompiledHeaderOptions(pchUsage); addHeaderPathOptions(); addProjectConfigFileInclude(); @@ -78,6 +84,8 @@ QStringList CompilerOptionsBuilder::build(CppTools::ProjectFile::Kind fileKind, addExtraOptions(); + insertPredefinedHeaderPathsOptions(); + return options(); } @@ -509,7 +517,107 @@ bool CompilerOptionsBuilder::excludeHeaderPath(const QString &headerPath) const return clangIncludeDir.match(headerPath).hasMatch(); } -void CompilerOptionsBuilder::addPredefinedHeaderPathsOptions() +static QString creatorResourcePath() +{ +#ifndef UNIT_TESTS + return Core::ICore::resourcePath(); +#else + return QString(); +#endif +} + +static QString clangIncludeDirectory(const QString &clangVersion, + const QString &clangResourceDirectory) +{ +#ifndef UNIT_TESTS + return Core::ICore::clangIncludeDirectory(clangVersion, clangResourceDirectory); +#else + return QString(); +#endif +} + +static int lastIncludeIndex(const QStringList &options, const QRegularExpression &includePathRegEx) +{ + int index = options.lastIndexOf(includePathRegEx); + + while (index > 0 && options[index - 1] != "-I" && options[index - 1] != "-isystem") + index = options.lastIndexOf(includePathRegEx, index - 1); + + if (index == 0) + index = -1; + + return index; +} + +static int includeIndexForResourceDirectory(const QStringList &options) +{ + // include/c++/{version}, include/c++/v1 and include/g++ + const int cppIncludeIndex = lastIncludeIndex( + options, + QRegularExpression("\\A.*[\\/\\\\]include[\\/\\\\].*(g\\+\\+.*\\z|c\\+\\+[\\/\\\\](v1\\z|\\d+.*\\z))")); + + if (cppIncludeIndex > 0) + return cppIncludeIndex + 1; + + return -1; +} + +void CompilerOptionsBuilder::insertPredefinedHeaderPathsOptions() +{ + if (m_clangVersion.isEmpty()) + return; + + QStringList wrappedQtHeaders; + addWrappedQtHeadersIncludePath(wrappedQtHeaders); + + QStringList predefinedOptions; + predefinedOptions.append("-nostdinc"); + predefinedOptions.append("-nostdlibinc"); + addClangIncludeFolder(predefinedOptions); + + const int index = m_options.indexOf(QRegularExpression("\\A-I.*\\z")); + if (index < 0) { + m_options.append(wrappedQtHeaders); + m_options.append(predefinedOptions); + return; + } + + int includeIndexForResourceDir = includeIndexForResourceDirectory(m_options); + if (includeIndexForResourceDir < index) + includeIndexForResourceDir = index; + + m_options = m_options.mid(0, index) + + wrappedQtHeaders + + m_options.mid(index, includeIndexForResourceDir - index) + + predefinedOptions + + m_options.mid(includeIndexForResourceDir); +} + +void CompilerOptionsBuilder::addClangIncludeFolder(QStringList &list) +{ + QTC_CHECK(!m_clangVersion.isEmpty()); + const QString clangIncludeDir = clangIncludeDirectory(m_clangVersion, m_clangResourceDirectory); + + list.append(includeDirOptionForPath(clangIncludeDir)); + list.append(clangIncludeDir); +} + +void CompilerOptionsBuilder::addWrappedQtHeadersIncludePath(QStringList &list) +{ + static const QString resourcePath = creatorResourcePath(); + static QString wrappedQtHeadersPath = resourcePath + "/cplusplus/wrappedQtHeaders"; + QTC_ASSERT(QDir(wrappedQtHeadersPath).exists(), return;); + + if (m_projectPart.qtVersion != CppTools::ProjectPart::NoQt) { + const QString wrappedQtCoreHeaderPath = wrappedQtHeadersPath + "/QtCore"; + list.append(includeDirOptionForPath(wrappedQtHeadersPath)); + list.append(QDir::toNativeSeparators(wrappedQtHeadersPath)); + list.append(includeDirOptionForPath(wrappedQtHeadersPath)); + list.append(QDir::toNativeSeparators(wrappedQtCoreHeaderPath)); + } +} + +void CompilerOptionsBuilder::addGlobalUndef() { // In case of MSVC we need builtin clang defines to correctly handle clang includes if (m_projectPart.toolchainType != ProjectExplorer::Constants::MSVC_TOOLCHAIN_TYPEID) diff --git a/src/plugins/cpptools/compileroptionsbuilder.h b/src/plugins/cpptools/compileroptionsbuilder.h index 75241dd0231..4c85427cf41 100644 --- a/src/plugins/cpptools/compileroptionsbuilder.h +++ b/src/plugins/cpptools/compileroptionsbuilder.h @@ -46,13 +46,15 @@ public: }; CompilerOptionsBuilder(const ProjectPart &projectPart, - UseSystemHeader useSystemHeader = UseSystemHeader::No); + UseSystemHeader useSystemHeader = UseSystemHeader::No, + QString clangVersion = QString(), + QString clangResourceDirectory = QString()); virtual ~CompilerOptionsBuilder() {} virtual void addTargetTriple(); virtual void addExtraCodeModelFlags(); virtual void enableExceptions(); - virtual void addPredefinedHeaderPathsOptions(); + virtual void insertPredefinedHeaderPathsOptions(); virtual void addOptionsForLanguage(bool checkForBorlandExtensions = true); virtual void updateLanguageOption(ProjectFile::Kind fileKind); @@ -68,6 +70,7 @@ public: // Add options based on project part void addWordWidth(); + void addGlobalUndef(); void addHeaderPathOptions(); void addPrecompiledHeaderOptions(PchUsage pchUsage); virtual void addToolchainAndProjectMacros(); @@ -95,8 +98,14 @@ private: QByteArray toDefineOption(const ProjectExplorer::Macro ¯o) const; QString defineDirectiveToDefineOption(const ProjectExplorer::Macro &marco) const; + void addClangIncludeFolder(QStringList &list); + void addWrappedQtHeadersIncludePath(QStringList &list); + QStringList m_options; UseSystemHeader m_useSystemHeader; + + QString m_clangVersion; + QString m_clangResourceDirectory; }; } // namespace CppTools