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 @@ -39,8 +39,12 @@ /// Adds a file-to-string mapping from \p ID to \p CanonicalPath. void addMapping(FileEntryRef Header, llvm::StringRef CanonicalPath); - /// Returns the overridden include for symbol with \p QualifiedName, or "". - llvm::StringRef mapSymbol(llvm::StringRef QualifiedName) const; + /// Returns the overridden include for a qualified symbol with, or "". + /// \p Scope and \p Name concatenation forms the fully qualified name. + /// \p Scope is the qualifier with the trailing "::" (e.g. "std::") or empty + /// (for global namespace). + llvm::StringRef mapSymbol(llvm::StringRef Scope, llvm::StringRef Name, + const LangOptions &L) const; /// Returns the overridden include for files in \p Header, or "". llvm::StringRef mapHeader(FileEntryRef Header) const; @@ -61,9 +65,6 @@ /// A map from a suffix (one or components of a path) to a canonical path. /// Used only for mapping standard headers. const llvm::StringMap *StdSuffixHeaderMapping = nullptr; - /// A map from fully qualified symbol names to header names. - /// Used only for mapping standard symbols. - const llvm::StringMap *StdSymbolMapping = nullptr; }; /// Returns a CommentHandler that parses pragma comment on include files to 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 @@ -10,6 +10,7 @@ #include "Headers.h" #include "clang/Basic/FileEntry.h" #include "clang/Tooling/Inclusions/HeaderAnalysis.h" +#include "clang/Tooling/Inclusions/StandardLibrary.h" #include "llvm/ADT/StringRef.h" #include "llvm/Support/FileSystem/UniqueID.h" #include "llvm/Support/Path.h" @@ -700,8 +701,26 @@ return ""; } -llvm::StringRef CanonicalIncludes::mapSymbol(llvm::StringRef QName) const { - return StdSymbolMapping ? StdSymbolMapping->lookup(QName) : ""; +llvm::StringRef CanonicalIncludes::mapSymbol(llvm::StringRef Scope, + llvm::StringRef Name, + const LangOptions &L) const { + tooling::stdlib::Lang Lang; + if (L.CPlusPlus) + Lang = tooling::stdlib::Lang::CXX; + else if (L.C11) + Lang = tooling::stdlib::Lang::C; + else + return ""; + // FIXME: remove the following special cases when the tooling stdlib supports + // them. + // There are two std::move()s, this is by far the most common. + if (Scope == "std::" && Name == "move") + return ""; + if (Scope == "std::" && Name == "size_t") + return ""; + if (auto StdSym = tooling::stdlib::Symbol::named(Scope, Name, Lang)) + return StdSym->header().name(); + return ""; } std::unique_ptr @@ -732,28 +751,6 @@ } void CanonicalIncludes::addSystemHeadersMapping(const LangOptions &Language) { - if (Language.CPlusPlus) { - static const auto *Symbols = new llvm::StringMap({ -#define SYMBOL(Name, NameSpace, Header) {#NameSpace #Name, #Header}, -#include "clang/Tooling/Inclusions/StdSymbolMap.inc" - // There are two std::move()s, this is by far the most common. - SYMBOL(move, std::, ) - // There are multiple headers for size_t, pick one. - SYMBOL(size_t, std::, ) -#undef SYMBOL - }); - StdSymbolMapping = Symbols; - } else if (Language.C11) { - static const auto *CSymbols = new llvm::StringMap({ -#define SYMBOL(Name, NameSpace, Header) {#Name, #Header}, -#include "clang/Tooling/Inclusions/CSymbolMap.inc" - // There are multiple headers for size_t, pick one. - SYMBOL(size_t, None, ) -#undef SYMBOL - }); - StdSymbolMapping = CSymbols; - } - // FIXME: remove the std header mapping once we support ambiguous symbols, now // it serves as a fallback to disambiguate: // - symbols with multiple headers (e.g. std::move) diff --git a/clang-tools-extra/clangd/index/StdLib.cpp b/clang-tools-extra/clangd/index/StdLib.cpp --- a/clang-tools-extra/clangd/index/StdLib.cpp +++ b/clang-tools-extra/clangd/index/StdLib.cpp @@ -22,6 +22,7 @@ #include "clang/Basic/LangOptions.h" #include "clang/Frontend/CompilerInvocation.h" #include "clang/Lex/PreprocessorOptions.h" +#include "clang/Tooling/Inclusions/StandardLibrary.h" #include "llvm/ADT/IntrusiveRefCntPtr.h" #include "llvm/ADT/StringRef.h" #include "llvm/Support/MemoryBuffer.h" @@ -67,7 +68,7 @@ } std::string buildUmbrella(llvm::StringLiteral Mandatory, - std::vector Headers) { + llvm::ArrayRef Headers) { std::string Result; llvm::raw_string_ostream OS(Result); @@ -80,13 +81,11 @@ "#endif\n", Mandatory); - llvm::sort(Headers); - auto Last = std::unique(Headers.begin(), Headers.end()); - for (auto Header = Headers.begin(); Header != Last; ++Header) { + for (auto Header : Headers) { OS << llvm::formatv("#if __has_include({0})\n" "#include {0}\n" "#endif\n", - *Header); + Header); } OS.flush(); return Result; @@ -102,20 +101,14 @@ Lang L = langFromOpts(LO); switch (L) { case CXX: - static std::string *UmbrellaCXX = - new std::string(buildUmbrella(mandatoryHeader(L), { -#define SYMBOL(Name, NameSpace, Header) #Header, -#include "clang/Tooling/Inclusions/StdSymbolMap.inc" -#undef SYMBOL - })); + static std::string *UmbrellaCXX = new std::string(buildUmbrella( + mandatoryHeader(L), + tooling::stdlib::Header::all(tooling::stdlib::Lang::CXX))); return *UmbrellaCXX; case C: - static std::string *UmbrellaC = - new std::string(buildUmbrella(mandatoryHeader(L), { -#define SYMBOL(Name, NameSpace, Header) #Header, -#include "clang/Tooling/Inclusions/CSymbolMap.inc" -#undef SYMBOL - })); + static std::string *UmbrellaC = new std::string( + buildUmbrella(mandatoryHeader(L), + tooling::stdlib::Header::all(tooling::stdlib::Lang::C))); return *UmbrellaC; } llvm_unreachable("invalid Lang in langFromOpts"); @@ -141,13 +134,10 @@ static auto &StandardHeaders = *[] { auto *Set = new llvm::DenseSet(); - for (llvm::StringRef Header : { -#define SYMBOL(Name, NameSpace, Header) #Header, -#include "clang/Tooling/Inclusions/CSymbolMap.inc" -#include "clang/Tooling/Inclusions/StdSymbolMap.inc" -#undef SYMBOL - }) - Set->insert(Header); + for (auto Header : tooling::stdlib::Header::all(tooling::stdlib::Lang::CXX)) + Set->insert(Header.name()); + for (auto Header : tooling::stdlib::Header::all(tooling::stdlib::Lang::C)) + Set->insert(Header.name()); return Set; }(); diff --git a/clang-tools-extra/clangd/index/SymbolCollector.cpp b/clang-tools-extra/clangd/index/SymbolCollector.cpp --- a/clang-tools-extra/clangd/index/SymbolCollector.cpp +++ b/clang-tools-extra/clangd/index/SymbolCollector.cpp @@ -829,20 +829,18 @@ llvm::DenseMap FileToContainsImportsOrObjC; // Fill in IncludeHeaders. // We delay this until end of TU so header guards are all resolved. - llvm::SmallString<128> QName; for (const auto &[SID, FID] : IncludeFiles) { if (const Symbol *S = Symbols.find(SID)) { llvm::StringRef IncludeHeader; // Look for an overridden include header for this symbol specifically. if (Opts.Includes) { - QName = S->Scope; - QName.append(S->Name); - IncludeHeader = Opts.Includes->mapSymbol(QName); + IncludeHeader = + Opts.Includes->mapSymbol(S->Scope, S->Name, ASTCtx->getLangOpts()); if (!IncludeHeader.empty()) { if (IncludeHeader.front() != '"' && IncludeHeader.front() != '<') IncludeHeader = HeaderFileURIs->toURI(IncludeHeader); - else if (IncludeHeader == "" && QName == "std::move" && - S->Signature.contains(',')) + else if (IncludeHeader == "" && S->Scope == "std::" && + S->Name == "move" && S->Signature.contains(',')) IncludeHeader = ""; } } 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 @@ -36,8 +36,8 @@ Language.C11 = true; CI.addSystemHeadersMapping(Language); // Usual standard library symbols are mapped correctly. - EXPECT_EQ("", CI.mapSymbol("printf")); - EXPECT_EQ("", CI.mapSymbol("unknown_symbol")); + EXPECT_EQ("", CI.mapSymbol("", "printf", Language)); + EXPECT_EQ("", CI.mapSymbol("", "unknown_symbol", Language)); } TEST(CanonicalIncludesTest, CXXStandardLibrary) { @@ -47,14 +47,14 @@ CI.addSystemHeadersMapping(Language); // Usual standard library symbols are mapped correctly. - EXPECT_EQ("", CI.mapSymbol("std::vector")); - EXPECT_EQ("", CI.mapSymbol("std::printf")); + EXPECT_EQ("", CI.mapSymbol("std::", "vector", Language)); + EXPECT_EQ("", CI.mapSymbol("std::", "printf", Language)); // std::move is ambiguous, currently always mapped to - EXPECT_EQ("", CI.mapSymbol("std::move")); + EXPECT_EQ("", CI.mapSymbol("std::", "move", Language)); // Unknown std symbols aren't mapped. - EXPECT_EQ("", CI.mapSymbol("std::notathing")); + EXPECT_EQ("", CI.mapSymbol("std::", "notathing", Language)); // iosfwd declares some symbols it doesn't own. - EXPECT_EQ("", CI.mapSymbol("std::ostream")); + EXPECT_EQ("", CI.mapSymbol("std::", "ostream", Language)); // And (for now) we assume it owns the others. auto InMemFS = llvm::makeIntrusiveRefCnt(); FileManager Files(FileSystemOptions(), InMemFS);