diff --git a/clang/include/clang/Tooling/Inclusions/StandardLibrary.h b/clang/include/clang/Tooling/Inclusions/StandardLibrary.h --- a/clang/include/clang/Tooling/Inclusions/StandardLibrary.h +++ b/clang/include/clang/Tooling/Inclusions/StandardLibrary.h @@ -30,6 +30,7 @@ namespace stdlib { class Symbol; +enum class Lang { C = 0, CXX, LastValue = CXX }; // A standard library header, such as // Lightweight class, in fact just an index into a table. @@ -38,7 +39,8 @@ class Header { public: // Name should contain the angle brackets, e.g. "". - static std::optional
named(llvm::StringRef Name); + static std::optional
named(llvm::StringRef Name, + Lang Language = Lang::CXX); friend llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const Header &H) { return OS << H.name(); @@ -46,8 +48,10 @@ llvm::StringRef name() const; private: - Header(unsigned ID) : ID(ID) {} + Header(unsigned ID, Lang Language = Lang::CXX) : ID(ID), Language(Language) {} unsigned ID; + Lang Language; + friend Symbol; friend llvm::DenseMapInfo
; friend bool operator==(const Header &L, const Header &R) { @@ -65,8 +69,8 @@ public: /// \p Scope should have the trailing "::", for example: /// named("std::chrono::", "system_clock") - static std::optional named(llvm::StringRef Scope, - llvm::StringRef Name); + static std::optional + named(llvm::StringRef Scope, llvm::StringRef Name, Lang Language = Lang::CXX); friend llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const Symbol &S) { return OS << S.scope() << S.name(); @@ -79,8 +83,9 @@ llvm::SmallVector
headers() const; private: - Symbol(unsigned ID) : ID(ID) {} + Symbol(unsigned ID, Lang Language = Lang::CXX) : ID(ID), Language(Language) {} unsigned ID; + clang::tooling::stdlib::Lang Language; friend class Recognizer; friend llvm::DenseMapInfo; friend bool operator==(const Symbol &L, const Symbol &R) { @@ -99,7 +104,8 @@ private: using NSSymbolMap = llvm::DenseMap; - NSSymbolMap *namespaceSymbols(const NamespaceDecl *D); + NSSymbolMap *namespaceSymbols(const NamespaceDecl *D, + Lang Language = Lang::CXX); llvm::DenseMap NamespaceCache; }; diff --git a/clang/lib/Tooling/Inclusions/Stdlib/StandardLibrary.cpp b/clang/lib/Tooling/Inclusions/Stdlib/StandardLibrary.cpp --- a/clang/lib/Tooling/Inclusions/Stdlib/StandardLibrary.cpp +++ b/clang/lib/Tooling/Inclusions/Stdlib/StandardLibrary.cpp @@ -8,42 +8,69 @@ #include "clang/Tooling/Inclusions/StandardLibrary.h" #include "clang/AST/Decl.h" +#include "clang/Basic/LangOptions.h" #include "llvm/ADT/StringRef.h" #include "llvm/Support/Casting.h" +#include "llvm/Support/raw_ostream.h" namespace clang { namespace tooling { namespace stdlib { -static llvm::StringRef *HeaderNames; -static std::pair *SymbolNames; -static unsigned *SymbolHeaderIDs; -static llvm::DenseMap *HeaderIDs; +Lang &operator++(Lang &Language) { + Language = static_cast(static_cast(Language) + 1); + return Language; +} + // Maps symbol name -> Symbol::ID, within a namespace. using NSSymbolMap = llvm::DenseMap; -static llvm::DenseMap *NamespaceSymbols; -static int initialize() { +struct SymbolHeaderMapping { + llvm::StringRef *HeaderNames; + std::pair *SymbolNames; + unsigned *SymbolHeaderIDs; + llvm::DenseMap HeaderIDs; + llvm::DenseMap NamespaceSymbols; +}; + +static SymbolHeaderMapping + *LanguageMappings[static_cast(Lang::LastValue) + 1]; + +static int countSymbols(Lang Language) { unsigned SymCount = 0; #define SYMBOL(Name, NS, Header) ++SymCount; + switch (Language) { + case Lang::C: #include "clang/Tooling/Inclusions/CSymbolMap.inc" + break; + case Lang::CXX: #include "clang/Tooling/Inclusions/StdSymbolMap.inc" + break; + } #undef SYMBOL - SymbolNames = new std::remove_reference_t[SymCount]; - SymbolHeaderIDs = - new std::remove_reference_t[SymCount]; - NamespaceSymbols = new std::remove_reference_t; - HeaderIDs = new std::remove_reference_t; + return SymCount; +} + +static void initialize(Lang Language) { + SymbolHeaderMapping *Mapping = new SymbolHeaderMapping(); + LanguageMappings[static_cast(Language)] = Mapping; + + unsigned SymCount = countSymbols(Language); + Mapping->SymbolNames = + new std::remove_reference_tSymbolNames)>[SymCount]; + Mapping->SymbolHeaderIDs = new std::remove_reference_t< + decltype(*Mapping->SymbolHeaderIDs)>[SymCount]; auto AddNS = [&](llvm::StringRef NS) -> NSSymbolMap & { - auto R = NamespaceSymbols->try_emplace(NS, nullptr); + auto R = Mapping->NamespaceSymbols.try_emplace(NS, nullptr); if (R.second) R.first->second = new NSSymbolMap(); return *R.first->second; }; auto AddHeader = [&](llvm::StringRef Header) -> unsigned { - return HeaderIDs->try_emplace(Header, HeaderIDs->size()).first->second; + return Mapping->HeaderIDs.try_emplace(Header, Mapping->HeaderIDs.size()) + .first->second; }; auto Add = [&, SymIndex(0)](llvm::StringRef Name, llvm::StringRef NS, @@ -51,8 +78,8 @@ if (NS == "None") NS = ""; - SymbolNames[SymIndex] = {NS, Name}; - SymbolHeaderIDs[SymIndex] = AddHeader(HeaderName); + Mapping->SymbolNames[SymIndex] = {NS, Name}; + Mapping->SymbolHeaderIDs[SymIndex] = AddHeader(HeaderName); NSSymbolMap &NSSymbols = AddNS(NS); NSSymbols.try_emplace(Name, SymIndex); @@ -60,14 +87,24 @@ ++SymIndex; }; #define SYMBOL(Name, NS, Header) Add(#Name, #NS, #Header); + switch (Language) { + case Lang::C: #include "clang/Tooling/Inclusions/CSymbolMap.inc" + break; + case Lang::CXX: #include "clang/Tooling/Inclusions/StdSymbolMap.inc" + break; + } #undef SYMBOL - HeaderNames = new llvm::StringRef[HeaderIDs->size()]; - for (const auto &E : *HeaderIDs) - HeaderNames[E.second] = E.first; + Mapping->HeaderNames = new llvm::StringRef[Mapping->HeaderIDs.size()]; + for (const auto &E : Mapping->HeaderIDs) + Mapping->HeaderNames[E.second] = E.first; +} +static int initialize() { + for (Lang i = Lang::C; i <= Lang::LastValue; ++i) + initialize(i); return 0; } @@ -76,38 +113,63 @@ (void)Dummy; } -std::optional
Header::named(llvm::StringRef Name) { +std::optional
Header::named(llvm::StringRef Name, Lang Language) { ensureInitialized(); - auto It = HeaderIDs->find(Name); - if (It == HeaderIDs->end()) + SymbolHeaderMapping *Mapping = + LanguageMappings[static_cast(Language)]; + auto It = Mapping->HeaderIDs.find(Name); + if (It == Mapping->HeaderIDs.end()) return std::nullopt; - return Header(It->second); + return Header(It->second, Language); +} + +llvm::StringRef Header::name() const { + SymbolHeaderMapping *Mapping = + LanguageMappings[static_cast(Language)]; + return Mapping->HeaderNames[ID]; +} +llvm::StringRef Symbol::scope() const { + SymbolHeaderMapping *Mapping = + LanguageMappings[static_cast(Language)]; + return Mapping->SymbolNames[ID].first; } -llvm::StringRef Header::name() const { return HeaderNames[ID]; } -llvm::StringRef Symbol::scope() const { return SymbolNames[ID].first; } -llvm::StringRef Symbol::name() const { return SymbolNames[ID].second; } -std::optional Symbol::named(llvm::StringRef Scope, - llvm::StringRef Name) { +llvm::StringRef Symbol::name() const { + SymbolHeaderMapping *Mapping = + LanguageMappings[static_cast(Language)]; + return Mapping->SymbolNames[ID].second; +} +std::optional Symbol::named(llvm::StringRef Scope, llvm::StringRef Name, + Lang Language) { ensureInitialized(); - if (NSSymbolMap *NSSymbols = NamespaceSymbols->lookup(Scope)) { + SymbolHeaderMapping *Mapping = + LanguageMappings[static_cast(Language)]; + if (NSSymbolMap *NSSymbols = Mapping->NamespaceSymbols.lookup(Scope)) { auto It = NSSymbols->find(Name); if (It != NSSymbols->end()) - return Symbol(It->second); + return Symbol(It->second, Language); } return std::nullopt; } -Header Symbol::header() const { return Header(SymbolHeaderIDs[ID]); } +Header Symbol::header() const { + SymbolHeaderMapping *Mapping = + LanguageMappings[static_cast(Language)]; + return Header(Mapping->SymbolHeaderIDs[ID], Language); +} llvm::SmallVector
Symbol::headers() const { return {header()}; // FIXME: multiple in case of ambiguity } Recognizer::Recognizer() { ensureInitialized(); } -NSSymbolMap *Recognizer::namespaceSymbols(const NamespaceDecl *D) { +NSSymbolMap *Recognizer::namespaceSymbols(const NamespaceDecl *D, + Lang Language) { auto It = NamespaceCache.find(D); if (It != NamespaceCache.end()) return It->second; + SymbolHeaderMapping *Mapping = + LanguageMappings[static_cast(Language)]; + NSSymbolMap *Result = [&]() -> NSSymbolMap * { if (D && D->isAnonymousNamespace()) return nullptr; @@ -117,13 +179,18 @@ ND = llvm::dyn_cast_or_null(ND->getParent())) if (!ND->isInlineNamespace() && !ND->isAnonymousNamespace()) Scope = ND->getName().str() + "::" + Scope; - return NamespaceSymbols->lookup(Scope); + return Mapping->NamespaceSymbols.lookup(Scope); }(); NamespaceCache.try_emplace(D, Result); return Result; } std::optional Recognizer::operator()(const Decl *D) { + Lang RecognizerLang = Lang::C; + if (D->getLangOpts().CPlusPlus) { + RecognizerLang = Lang::CXX; + } + // If D is std::vector::iterator, `vector` is the outer symbol to look up. // We keep all the candidate DCs as some may turn out to be anon enums. // Do this resolution lazily as we may turn out not to have a std namespace. @@ -134,7 +201,8 @@ IntermediateDecl.push_back(DC); DC = DC->getParent(); } - NSSymbolMap *Symbols = namespaceSymbols(cast_or_null(DC)); + NSSymbolMap *Symbols = + namespaceSymbols(cast_or_null(DC), RecognizerLang); if (!Symbols) return std::nullopt; diff --git a/clang/unittests/Tooling/StandardLibraryTest.cpp b/clang/unittests/Tooling/StandardLibraryTest.cpp --- a/clang/unittests/Tooling/StandardLibraryTest.cpp +++ b/clang/unittests/Tooling/StandardLibraryTest.cpp @@ -38,14 +38,28 @@ EXPECT_EQ(llvm::to_string(*VectorH), ""); EXPECT_FALSE(stdlib::Header::named("HeadersTests.cpp")); + EXPECT_TRUE(stdlib::Header::named("", stdlib::Lang::CXX)); + EXPECT_FALSE(stdlib::Header::named("", stdlib::Lang::C)); + auto Vector = stdlib::Symbol::named("std::", "vector"); EXPECT_TRUE(Vector); EXPECT_EQ(llvm::to_string(*Vector), "std::vector"); EXPECT_FALSE(stdlib::Symbol::named("std::", "dongle")); EXPECT_FALSE(stdlib::Symbol::named("clang::", "ASTContext")); + EXPECT_TRUE(stdlib::Symbol::named("std::", "vector", stdlib::Lang::CXX)); + EXPECT_FALSE(stdlib::Symbol::named("std::", "vector", stdlib::Lang::C)); + EXPECT_EQ(Vector->header(), *VectorH); EXPECT_THAT(Vector->headers(), ElementsAre(*VectorH)); + + EXPECT_FALSE(stdlib::Header::named("")); + EXPECT_FALSE(stdlib::Header::named("", stdlib::Lang::CXX)); + EXPECT_TRUE(stdlib::Header::named("", stdlib::Lang::C)); + + EXPECT_FALSE(stdlib::Symbol::named("", "int16_t")); + EXPECT_FALSE(stdlib::Symbol::named("", "int16_t", stdlib::Lang::CXX)); + EXPECT_TRUE(stdlib::Symbol::named("", "int16_t", stdlib::Lang::C)); } TEST(StdlibTest, Recognizer) { @@ -96,10 +110,14 @@ EXPECT_EQ(Recognizer(&VectorNonstd), std::nullopt); EXPECT_EQ(Recognizer(Vec), stdlib::Symbol::named("std::", "vector")); + EXPECT_EQ(Recognizer(Vec), + stdlib::Symbol::named("std::", "vector", stdlib::Lang::CXX)); EXPECT_EQ(Recognizer(Nest), stdlib::Symbol::named("std::", "vector")); EXPECT_EQ(Recognizer(Clock), stdlib::Symbol::named("std::chrono::", "system_clock")); EXPECT_EQ(Recognizer(CDivT), stdlib::Symbol::named("", "div_t")); + EXPECT_EQ(Recognizer(CDivT), + stdlib::Symbol::named("", "div_t", stdlib::Lang::C)); EXPECT_EQ(Recognizer(Sec), std::nullopt); }