diff --git a/clang-tools-extra/clangd/ParsedAST.cpp b/clang-tools-extra/clangd/ParsedAST.cpp --- a/clang-tools-extra/clangd/ParsedAST.cpp +++ b/clang-tools-extra/clangd/ParsedAST.cpp @@ -368,7 +368,7 @@ if (Preamble) CanonIncludes = Preamble->CanonIncludes; else - addSystemHeadersMapping(&CanonIncludes, Clang->getLangOpts()); + CanonIncludes.addSystemHeadersMapping(Clang->getLangOpts()); std::unique_ptr IWYUHandler = collectIWYUHeaderMaps(&CanonIncludes); Clang->getPreprocessor().addCommentHandler(IWYUHandler.get()); diff --git a/clang-tools-extra/clangd/Preamble.cpp b/clang-tools-extra/clangd/Preamble.cpp --- a/clang-tools-extra/clangd/Preamble.cpp +++ b/clang-tools-extra/clangd/Preamble.cpp @@ -78,7 +78,7 @@ } void BeforeExecute(CompilerInstance &CI) override { - addSystemHeadersMapping(&CanonIncludes, CI.getLangOpts()); + CanonIncludes.addSystemHeadersMapping(CI.getLangOpts()); SourceMgr = &CI.getSourceManager(); } diff --git a/clang-tools-extra/clangd/index/CanonicalIncludes.h b/clang-tools-extra/clangd/index/CanonicalIncludes.h --- a/clang-tools-extra/clangd/index/CanonicalIncludes.h +++ b/clang-tools-extra/clangd/index/CanonicalIncludes.h @@ -55,6 +55,16 @@ llvm::StringRef mapHeader(llvm::StringRef Header, llvm::StringRef QualifiedName) const; + /// Adds mapping for system headers and some special symbols (e.g. STL symbols + /// in need to be mapped individually). Approximately, the following + /// system headers are handled: + /// - C++ standard library e.g. bits/basic_string.h$ -> + /// - Posix library e.g. bits/pthreadtypes.h$ -> + /// - Compiler extensions, e.g. include/avx512bwintrin.h$ -> + /// The mapping is hardcoded and hand-maintained, so it might not cover all + /// headers. + void addSystemHeadersMapping(const LangOptions &Language); + private: /// A map from full include path to a canonical path. llvm::StringMap FullPathMapping; @@ -65,6 +75,8 @@ int MaxSuffixComponents = 0; /// A map from fully qualified symbol names to header names. llvm::StringMap SymbolMapping; + /// Precomputed mapping of std symbols. Ignored when null. + const CanonicalIncludes *SystemSymbols = nullptr; }; /// Returns a CommentHandler that parses pragma comment on include files to @@ -76,16 +88,6 @@ std::unique_ptr collectIWYUHeaderMaps(CanonicalIncludes *Includes); -/// Adds mapping for system headers and some special symbols (e.g. STL symbols -/// in need to be mapped individually). Approximately, the following -/// system headers are handled: -/// - C++ standard library e.g. bits/basic_string.h$ -> -/// - Posix library e.g. bits/pthreadtypes.h$ -> -/// - Compiler extensions, e.g. include/avx512bwintrin.h$ -> -/// The mapping is hardcoded and hand-maintained, so it might not cover all -/// headers. -void addSystemHeadersMapping(CanonicalIncludes *Includes, - const LangOptions &Language); } // namespace clangd } // namespace clang diff --git a/clang-tools-extra/clangd/index/CanonicalIncludes.cpp b/clang-tools-extra/clangd/index/CanonicalIncludes.cpp --- a/clang-tools-extra/clangd/index/CanonicalIncludes.cpp +++ b/clang-tools-extra/clangd/index/CanonicalIncludes.cpp @@ -8,9 +8,12 @@ #include "CanonicalIncludes.h" #include "Headers.h" +#include "clang/Basic/LangOptions.h" #include "clang/Driver/Types.h" +#include "llvm/Support/ErrorHandling.h" #include "llvm/Support/Path.h" #include +#include namespace clang { namespace clangd { @@ -40,6 +43,12 @@ CanonicalIncludes::mapHeader(llvm::StringRef Header, llvm::StringRef QualifiedName) const { assert(!Header.empty()); + // Prefer a mapping from the system symbols. + if (SystemSymbols) { + auto Result = SystemSymbols->mapHeader(Header, QualifiedName); + if (Result != Header) + return Result; + } auto SE = SymbolMapping.find(QualifiedName); if (SE != SymbolMapping.end()) return SE->second; @@ -86,24 +95,41 @@ return std::make_unique(Includes); } -void addSystemHeadersMapping(CanonicalIncludes *Includes, - const LangOptions &Language) { +namespace { +enum class SymbolsFlavour { Cpp, C11, Other }; + +SymbolsFlavour symbolsFlavour(const LangOptions &Language) { + if (Language.CPlusPlus) + return SymbolsFlavour::Cpp; + if (Language.C11) + return SymbolsFlavour::C11; + return SymbolsFlavour::Other; +} + +std::unique_ptr +buildStandardSymbolMapping(SymbolsFlavour Language) { + auto Includes = std::make_unique(); static constexpr std::pair SymbolMap[] = { -#define SYMBOL(Name, NameSpace, Header) { #NameSpace#Name, #Header }, - #include "StdSymbolMap.inc" +#define SYMBOL(Name, NameSpace, Header) {#NameSpace #Name, #Header}, +#include "StdSymbolMap.inc" #undef SYMBOL }; static constexpr std::pair CSymbolMap[] = { -#define SYMBOL(Name, NameSpace, Header) { #Name, #Header }, - #include "CSymbolMap.inc" +#define SYMBOL(Name, NameSpace, Header) {#Name, #Header}, +#include "CSymbolMap.inc" #undef SYMBOL }; - if (Language.CPlusPlus) { + switch (Language) { + case SymbolsFlavour::Cpp: for (const auto &Pair : SymbolMap) Includes->addSymbolMapping(Pair.first, Pair.second); - } else if (Language.C11) { + break; + case SymbolsFlavour::C11: for (const auto &Pair : CSymbolMap) Includes->addSymbolMapping(Pair.first, Pair.second); + break; + case SymbolsFlavour::Other: + break; } // FIXME: remove the std header mapping once we support ambiguous symbols, now // it serves as a fallback to disambiguate: @@ -763,6 +789,32 @@ }; for (const auto &Pair : SystemHeaderMap) Includes->addPathSuffixMapping(Pair.first, Pair.second); + return Includes; +} + +const CanonicalIncludes &getStandardSymbolMapping(const LangOptions &Opts) { + static const CanonicalIncludes *ForCpp = + buildStandardSymbolMapping(SymbolsFlavour::Cpp).release(); + static const CanonicalIncludes *ForC11 = + buildStandardSymbolMapping(SymbolsFlavour::C11).release(); + static const CanonicalIncludes *ForOther = + buildStandardSymbolMapping(SymbolsFlavour::Other).release(); + + switch (symbolsFlavour(Opts)) { + case SymbolsFlavour::Cpp: + return *ForCpp; + case SymbolsFlavour::C11: + return *ForC11; + case SymbolsFlavour::Other: + return *ForOther; + } + llvm_unreachable("unhandled SymbolFlavour"); +} +} // namespace + +void CanonicalIncludes::addSystemHeadersMapping(const LangOptions &Language) { + assert(SystemSymbols == nullptr && "resetting the system headers mapping"); + SystemSymbols = &getStandardSymbolMapping(Language); } } // namespace clangd diff --git a/clang-tools-extra/clangd/index/IndexAction.cpp b/clang-tools-extra/clangd/index/IndexAction.cpp --- a/clang-tools-extra/clangd/index/IndexAction.cpp +++ b/clang-tools-extra/clangd/index/IndexAction.cpp @@ -140,7 +140,7 @@ std::unique_ptr CreateASTConsumer(CompilerInstance &CI, llvm::StringRef InFile) override { CI.getPreprocessor().addCommentHandler(PragmaHandler.get()); - addSystemHeadersMapping(Includes.get(), CI.getLangOpts()); + Includes->addSystemHeadersMapping(CI.getLangOpts()); if (IncludeGraphCallback != nullptr) CI.getPreprocessor().addPPCallbacks( std::make_unique(CI.getSourceManager(), IG)); diff --git a/clang-tools-extra/clangd/unittests/CanonicalIncludesTests.cpp b/clang-tools-extra/clangd/unittests/CanonicalIncludesTests.cpp --- a/clang-tools-extra/clangd/unittests/CanonicalIncludesTests.cpp +++ b/clang-tools-extra/clangd/unittests/CanonicalIncludesTests.cpp @@ -17,7 +17,7 @@ CanonicalIncludes CI; auto Language = LangOptions(); Language.C11 = true; - addSystemHeadersMapping(&CI, Language); + CI.addSystemHeadersMapping(Language); // Usual standard library symbols are mapped correctly. EXPECT_EQ("", CI.mapHeader("path/stdio.h", "printf")); } @@ -26,7 +26,7 @@ CanonicalIncludes CI; auto Language = LangOptions(); Language.CPlusPlus = true; - addSystemHeadersMapping(&CI, Language); + CI.addSystemHeadersMapping(Language); // Usual standard library symbols are mapped correctly. EXPECT_EQ("", CI.mapHeader("path/vector.h", "std::vector")); diff --git a/clang-tools-extra/clangd/unittests/SymbolCollectorTests.cpp b/clang-tools-extra/clangd/unittests/SymbolCollectorTests.cpp --- a/clang-tools-extra/clangd/unittests/SymbolCollectorTests.cpp +++ b/clang-tools-extra/clangd/unittests/SymbolCollectorTests.cpp @@ -973,7 +973,7 @@ CanonicalIncludes Includes; auto Language = LangOptions(); Language.CPlusPlus = true; - addSystemHeadersMapping(&Includes, Language); + Includes.addSystemHeadersMapping(Language); CollectorOpts.Includes = &Includes; runSymbolCollector("namespace std { class string {}; }", /*Main=*/""); EXPECT_THAT(Symbols,