1d1f13c54SKadir Cetinkaya //===--- StandardLibrary.cpp ------------------------------------*- C++ -*-===// 2d1f13c54SKadir Cetinkaya // 3d1f13c54SKadir Cetinkaya // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4d1f13c54SKadir Cetinkaya // See https://llvm.org/LICENSE.txt for license information. 5d1f13c54SKadir Cetinkaya // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6d1f13c54SKadir Cetinkaya // 7d1f13c54SKadir Cetinkaya //===----------------------------------------------------------------------===// 8d1f13c54SKadir Cetinkaya 9d1f13c54SKadir Cetinkaya #include "clang/Tooling/Inclusions/StandardLibrary.h" 10d03ee70dSSam McCall #include "clang/AST/Decl.h" 111285172cSViktoriia Bakalova #include "clang/Basic/LangOptions.h" 121ab62d9dSHaojian Wu #include "llvm/ADT/ArrayRef.h" 131ab62d9dSHaojian Wu #include "llvm/ADT/DenseSet.h" 141ab62d9dSHaojian Wu #include "llvm/ADT/STLExtras.h" 15d1f13c54SKadir Cetinkaya #include "llvm/ADT/StringRef.h" 16d1f13c54SKadir Cetinkaya #include "llvm/Support/Casting.h" 175a623c2aSKadir Cetinkaya #include <optional> 18d1f13c54SKadir Cetinkaya 19d1f13c54SKadir Cetinkaya namespace clang { 20d1f13c54SKadir Cetinkaya namespace tooling { 21d1f13c54SKadir Cetinkaya namespace stdlib { 22d1f13c54SKadir Cetinkaya 231285172cSViktoriia Bakalova namespace { 241285172cSViktoriia Bakalova // Symbol name -> Symbol::ID, within a namespace. 251285172cSViktoriia Bakalova using NSSymbolMap = llvm::DenseMap<llvm::StringRef, unsigned>; 26e1aaa314SSam McCall 271285172cSViktoriia Bakalova // A Mapping per language. 281285172cSViktoriia Bakalova struct SymbolHeaderMapping { 291285172cSViktoriia Bakalova llvm::StringRef *HeaderNames = nullptr; 301285172cSViktoriia Bakalova // Header name => Header::ID 311285172cSViktoriia Bakalova llvm::DenseMap<llvm::StringRef, unsigned> *HeaderIDs; 321285172cSViktoriia Bakalova 331285172cSViktoriia Bakalova unsigned SymbolCount = 0; 34e1aaa314SSam McCall // Symbol::ID => symbol qualified_name/name/scope 351285172cSViktoriia Bakalova struct SymbolName { 36e1aaa314SSam McCall const char *Data; // std::vector 37e1aaa314SSam McCall unsigned ScopeLen; // ~~~~~ 38e1aaa314SSam McCall unsigned NameLen; // ~~~~~~ 39d46d44e3SHaojian Wu StringRef scope() const { return StringRef(Data, ScopeLen); } 40d46d44e3SHaojian Wu StringRef name() const { return StringRef(Data + ScopeLen, NameLen); } 41d46d44e3SHaojian Wu StringRef qualifiedName() const { 42d46d44e3SHaojian Wu return StringRef(Data, ScopeLen + NameLen); 43d46d44e3SHaojian Wu } 441285172cSViktoriia Bakalova } *SymbolNames = nullptr; 45e1aaa314SSam McCall // Symbol name -> Symbol::ID, within a namespace. 461285172cSViktoriia Bakalova llvm::DenseMap<llvm::StringRef, NSSymbolMap *> *NamespaceSymbols = nullptr; 47e1aaa314SSam McCall // Symbol::ID => Header::ID 481ab62d9dSHaojian Wu llvm::SmallVector<unsigned> *SymbolHeaderIDs = nullptr; 491285172cSViktoriia Bakalova }; 501285172cSViktoriia Bakalova } // namespace 511285172cSViktoriia Bakalova static SymbolHeaderMapping 521285172cSViktoriia Bakalova *LanguageMappings[static_cast<unsigned>(Lang::LastValue) + 1]; 531285172cSViktoriia Bakalova static const SymbolHeaderMapping *getMappingPerLang(Lang L) { 541285172cSViktoriia Bakalova return LanguageMappings[static_cast<unsigned>(L)]; 551285172cSViktoriia Bakalova } 56d1f13c54SKadir Cetinkaya 571285172cSViktoriia Bakalova static int countSymbols(Lang Language) { 584674e303SBenjamin Kramer ArrayRef<const char *> Symbols; 594674e303SBenjamin Kramer #define SYMBOL(Name, NS, Header) #NS #Name, 601285172cSViktoriia Bakalova switch (Language) { 6124f068b0SBenjamin Kramer case Lang::C: { 624674e303SBenjamin Kramer static constexpr const char *CSymbols[] = { 63756c2056Skadir çetinkaya #include "CSpecialSymbolMap.inc" 64c751264aSHaojian Wu #include "CSymbolMap.inc" 654674e303SBenjamin Kramer }; 664674e303SBenjamin Kramer Symbols = CSymbols; 671285172cSViktoriia Bakalova break; 6824f068b0SBenjamin Kramer } 6924f068b0SBenjamin Kramer case Lang::CXX: { 704674e303SBenjamin Kramer static constexpr const char *CXXSymbols[] = { 7111dcd885SHaojian Wu #include "StdSpecialSymbolMap.inc" 72d4021ed3SYounan Zhang #include "StdSymbolMap.inc" 73d4021ed3SYounan Zhang #include "StdTsSymbolMap.inc" 744674e303SBenjamin Kramer }; 754674e303SBenjamin Kramer Symbols = CXXSymbols; 761285172cSViktoriia Bakalova break; 771285172cSViktoriia Bakalova } 7824f068b0SBenjamin Kramer } 79d1f13c54SKadir Cetinkaya #undef SYMBOL 804674e303SBenjamin Kramer return llvm::DenseSet<StringRef>(Symbols.begin(), Symbols.end()).size(); 811285172cSViktoriia Bakalova } 82d1f13c54SKadir Cetinkaya 831285172cSViktoriia Bakalova static int initialize(Lang Language) { 841285172cSViktoriia Bakalova SymbolHeaderMapping *Mapping = new SymbolHeaderMapping(); 851285172cSViktoriia Bakalova LanguageMappings[static_cast<unsigned>(Language)] = Mapping; 861285172cSViktoriia Bakalova 871285172cSViktoriia Bakalova unsigned SymCount = countSymbols(Language); 881285172cSViktoriia Bakalova Mapping->SymbolCount = SymCount; 891285172cSViktoriia Bakalova Mapping->SymbolNames = 901285172cSViktoriia Bakalova new std::remove_reference_t<decltype(*Mapping->SymbolNames)>[SymCount]; 911285172cSViktoriia Bakalova Mapping->SymbolHeaderIDs = new std::remove_reference_t< 921285172cSViktoriia Bakalova decltype(*Mapping->SymbolHeaderIDs)>[SymCount]; 931285172cSViktoriia Bakalova Mapping->NamespaceSymbols = 941285172cSViktoriia Bakalova new std::remove_reference_t<decltype(*Mapping->NamespaceSymbols)>; 951285172cSViktoriia Bakalova Mapping->HeaderIDs = 961285172cSViktoriia Bakalova new std::remove_reference_t<decltype(*Mapping->HeaderIDs)>; 97d1f13c54SKadir Cetinkaya auto AddNS = [&](llvm::StringRef NS) -> NSSymbolMap & { 981285172cSViktoriia Bakalova auto R = Mapping->NamespaceSymbols->try_emplace(NS, nullptr); 99d1f13c54SKadir Cetinkaya if (R.second) 100d1f13c54SKadir Cetinkaya R.first->second = new NSSymbolMap(); 101d1f13c54SKadir Cetinkaya return *R.first->second; 102d1f13c54SKadir Cetinkaya }; 103d1f13c54SKadir Cetinkaya 104d1f13c54SKadir Cetinkaya auto AddHeader = [&](llvm::StringRef Header) -> unsigned { 1051285172cSViktoriia Bakalova return Mapping->HeaderIDs->try_emplace(Header, Mapping->HeaderIDs->size()) 1061285172cSViktoriia Bakalova .first->second; 107d1f13c54SKadir Cetinkaya }; 108d1f13c54SKadir Cetinkaya 1091ab62d9dSHaojian Wu auto Add = [&, SymIndex(-1)](llvm::StringRef QName, unsigned NSLen, 110d1f13c54SKadir Cetinkaya llvm::StringRef HeaderName) mutable { 111e1aaa314SSam McCall // Correct "Nonefoo" => foo. 112e1aaa314SSam McCall // FIXME: get rid of "None" from the generated mapping files. 113e1aaa314SSam McCall if (QName.take_front(NSLen) == "None") { 114e1aaa314SSam McCall QName = QName.drop_front(NSLen); 115e1aaa314SSam McCall NSLen = 0; 116e1aaa314SSam McCall } 117d1f13c54SKadir Cetinkaya 118*c0ce44e8SVadim D. if (SymIndex > 0) { 1191ab62d9dSHaojian Wu assert(llvm::none_of(llvm::ArrayRef(Mapping->SymbolNames, SymIndex), 1201ab62d9dSHaojian Wu [&QName](const SymbolHeaderMapping::SymbolName &S) { 1211ab62d9dSHaojian Wu return S.qualifiedName() == QName; 1221ab62d9dSHaojian Wu }) && 1231ab62d9dSHaojian Wu "The symbol has been added before, make sure entries in the .inc " 1241ab62d9dSHaojian Wu "file are grouped by symbol name!"); 125*c0ce44e8SVadim D. } 126*c0ce44e8SVadim D. if (SymIndex < 0 || 127*c0ce44e8SVadim D. Mapping->SymbolNames[SymIndex].qualifiedName() != QName) { 1281ab62d9dSHaojian Wu // First symbol or new symbol, increment next available index. 1291ab62d9dSHaojian Wu ++SymIndex; 130*c0ce44e8SVadim D. } // Else use the same index. 1311285172cSViktoriia Bakalova Mapping->SymbolNames[SymIndex] = { 1321285172cSViktoriia Bakalova QName.data(), NSLen, static_cast<unsigned int>(QName.size() - NSLen)}; 1335a623c2aSKadir Cetinkaya if (!HeaderName.empty()) 1341ab62d9dSHaojian Wu Mapping->SymbolHeaderIDs[SymIndex].push_back(AddHeader(HeaderName)); 135d1f13c54SKadir Cetinkaya 136e1aaa314SSam McCall NSSymbolMap &NSSymbols = AddNS(QName.take_front(NSLen)); 137e1aaa314SSam McCall NSSymbols.try_emplace(QName.drop_front(NSLen), SymIndex); 138d1f13c54SKadir Cetinkaya }; 1394674e303SBenjamin Kramer 1404674e303SBenjamin Kramer struct Symbol { 1414674e303SBenjamin Kramer const char *QName; 1424674e303SBenjamin Kramer unsigned NSLen; 1434674e303SBenjamin Kramer const char *HeaderName; 1444674e303SBenjamin Kramer }; 145764c3afdSKrzysztof Parzyszek #define SYMBOL(Name, NS, Header) \ 146764c3afdSKrzysztof Parzyszek {#NS #Name, static_cast<decltype(Symbol::NSLen)>(StringRef(#NS).size()), \ 147764c3afdSKrzysztof Parzyszek #Header}, 1481285172cSViktoriia Bakalova switch (Language) { 14924f068b0SBenjamin Kramer case Lang::C: { 1504674e303SBenjamin Kramer static constexpr Symbol CSymbols[] = { 151756c2056Skadir çetinkaya #include "CSpecialSymbolMap.inc" 152c751264aSHaojian Wu #include "CSymbolMap.inc" 1534674e303SBenjamin Kramer }; 1544674e303SBenjamin Kramer for (const Symbol &S : CSymbols) 1554674e303SBenjamin Kramer Add(S.QName, S.NSLen, S.HeaderName); 1561285172cSViktoriia Bakalova break; 15724f068b0SBenjamin Kramer } 15824f068b0SBenjamin Kramer case Lang::CXX: { 1594674e303SBenjamin Kramer static constexpr Symbol CXXSymbols[] = { 16011dcd885SHaojian Wu #include "StdSpecialSymbolMap.inc" 161d4021ed3SYounan Zhang #include "StdSymbolMap.inc" 162d4021ed3SYounan Zhang #include "StdTsSymbolMap.inc" 1634674e303SBenjamin Kramer }; 1644674e303SBenjamin Kramer for (const Symbol &S : CXXSymbols) 1654674e303SBenjamin Kramer Add(S.QName, S.NSLen, S.HeaderName); 1661285172cSViktoriia Bakalova break; 1671285172cSViktoriia Bakalova } 16824f068b0SBenjamin Kramer } 169d1f13c54SKadir Cetinkaya #undef SYMBOL 170d1f13c54SKadir Cetinkaya 1711285172cSViktoriia Bakalova Mapping->HeaderNames = new llvm::StringRef[Mapping->HeaderIDs->size()]; 1721285172cSViktoriia Bakalova for (const auto &E : *Mapping->HeaderIDs) 1731285172cSViktoriia Bakalova Mapping->HeaderNames[E.second] = E.first; 174d1f13c54SKadir Cetinkaya 175d1f13c54SKadir Cetinkaya return 0; 176d1f13c54SKadir Cetinkaya } 177d1f13c54SKadir Cetinkaya 178d1f13c54SKadir Cetinkaya static void ensureInitialized() { 1791285172cSViktoriia Bakalova static int Dummy = []() { 1801285172cSViktoriia Bakalova for (unsigned L = 0; L <= static_cast<unsigned>(Lang::LastValue); ++L) 1811285172cSViktoriia Bakalova initialize(static_cast<Lang>(L)); 1821285172cSViktoriia Bakalova return 0; 1831285172cSViktoriia Bakalova }(); 184d1f13c54SKadir Cetinkaya (void)Dummy; 185d1f13c54SKadir Cetinkaya } 186d1f13c54SKadir Cetinkaya 1871285172cSViktoriia Bakalova std::vector<Header> Header::all(Lang L) { 1880bf58458SHaojian Wu ensureInitialized(); 189e1aaa314SSam McCall std::vector<Header> Result; 1901285172cSViktoriia Bakalova const auto *Mapping = getMappingPerLang(L); 1911285172cSViktoriia Bakalova Result.reserve(Mapping->HeaderIDs->size()); 1921285172cSViktoriia Bakalova for (unsigned I = 0, E = Mapping->HeaderIDs->size(); I < E; ++I) 1931285172cSViktoriia Bakalova Result.push_back(Header(I, L)); 194e1aaa314SSam McCall return Result; 195e1aaa314SSam McCall } 1961285172cSViktoriia Bakalova std::optional<Header> Header::named(llvm::StringRef Name, Lang L) { 197d1f13c54SKadir Cetinkaya ensureInitialized(); 1981285172cSViktoriia Bakalova const auto *Mapping = getMappingPerLang(L); 1991285172cSViktoriia Bakalova auto It = Mapping->HeaderIDs->find(Name); 2001285172cSViktoriia Bakalova if (It == Mapping->HeaderIDs->end()) 2015891420eSKazu Hirata return std::nullopt; 2021285172cSViktoriia Bakalova return Header(It->second, L); 203d1f13c54SKadir Cetinkaya } 2041285172cSViktoriia Bakalova llvm::StringRef Header::name() const { 2051285172cSViktoriia Bakalova return getMappingPerLang(Language)->HeaderNames[ID]; 2061285172cSViktoriia Bakalova } 207e1aaa314SSam McCall 2081285172cSViktoriia Bakalova std::vector<Symbol> Symbol::all(Lang L) { 2090bf58458SHaojian Wu ensureInitialized(); 210e1aaa314SSam McCall std::vector<Symbol> Result; 2111285172cSViktoriia Bakalova const auto *Mapping = getMappingPerLang(L); 2121285172cSViktoriia Bakalova Result.reserve(Mapping->SymbolCount); 2131285172cSViktoriia Bakalova for (unsigned I = 0, E = Mapping->SymbolCount; I < E; ++I) 2141285172cSViktoriia Bakalova Result.push_back(Symbol(I, L)); 215e1aaa314SSam McCall return Result; 216e1aaa314SSam McCall } 217e1aaa314SSam McCall llvm::StringRef Symbol::scope() const { 218d46d44e3SHaojian Wu return getMappingPerLang(Language)->SymbolNames[ID].scope(); 219e1aaa314SSam McCall } 220e1aaa314SSam McCall llvm::StringRef Symbol::name() const { 221d46d44e3SHaojian Wu return getMappingPerLang(Language)->SymbolNames[ID].name(); 222e1aaa314SSam McCall } 223d46d44e3SHaojian Wu llvm::StringRef Symbol::qualifiedName() const { 224d46d44e3SHaojian Wu return getMappingPerLang(Language)->SymbolNames[ID].qualifiedName(); 225e1aaa314SSam McCall } 2261285172cSViktoriia Bakalova std::optional<Symbol> Symbol::named(llvm::StringRef Scope, llvm::StringRef Name, 2271285172cSViktoriia Bakalova Lang L) { 228d1f13c54SKadir Cetinkaya ensureInitialized(); 2291285172cSViktoriia Bakalova 2301285172cSViktoriia Bakalova if (NSSymbolMap *NSSymbols = 2311285172cSViktoriia Bakalova getMappingPerLang(L)->NamespaceSymbols->lookup(Scope)) { 232d1f13c54SKadir Cetinkaya auto It = NSSymbols->find(Name); 233d1f13c54SKadir Cetinkaya if (It != NSSymbols->end()) 2341285172cSViktoriia Bakalova return Symbol(It->second, L); 235d1f13c54SKadir Cetinkaya } 2365891420eSKazu Hirata return std::nullopt; 237d1f13c54SKadir Cetinkaya } 2385a623c2aSKadir Cetinkaya std::optional<Header> Symbol::header() const { 2395a623c2aSKadir Cetinkaya const auto& Headers = getMappingPerLang(Language)->SymbolHeaderIDs[ID]; 2405a623c2aSKadir Cetinkaya if (Headers.empty()) 2415a623c2aSKadir Cetinkaya return std::nullopt; 2425a623c2aSKadir Cetinkaya return Header(Headers.front(), Language); 2431285172cSViktoriia Bakalova } 244d1f13c54SKadir Cetinkaya llvm::SmallVector<Header> Symbol::headers() const { 2451ab62d9dSHaojian Wu llvm::SmallVector<Header> Results; 2461ab62d9dSHaojian Wu for (auto HeaderID : getMappingPerLang(Language)->SymbolHeaderIDs[ID]) 2471ab62d9dSHaojian Wu Results.emplace_back(Header(HeaderID, Language)); 2481ab62d9dSHaojian Wu return Results; 249d1f13c54SKadir Cetinkaya } 250d1f13c54SKadir Cetinkaya 251d1f13c54SKadir Cetinkaya Recognizer::Recognizer() { ensureInitialized(); } 252d1f13c54SKadir Cetinkaya 253c812ab73SHaojian Wu NSSymbolMap *Recognizer::namespaceSymbols(const DeclContext *DC, Lang L) { 254c812ab73SHaojian Wu if (DC->isTranslationUnit()) // global scope. 255c812ab73SHaojian Wu return getMappingPerLang(L)->NamespaceSymbols->lookup(""); 2561285172cSViktoriia Bakalova 257c812ab73SHaojian Wu auto It = NamespaceCache.find(DC); 258d1f13c54SKadir Cetinkaya if (It != NamespaceCache.end()) 259d1f13c54SKadir Cetinkaya return It->second; 260c812ab73SHaojian Wu const NamespaceDecl *D = llvm::cast<NamespaceDecl>(DC); 261d1f13c54SKadir Cetinkaya NSSymbolMap *Result = [&]() -> NSSymbolMap * { 2621285172cSViktoriia Bakalova if (D->isAnonymousNamespace()) 263d1f13c54SKadir Cetinkaya return nullptr; 264d1f13c54SKadir Cetinkaya // Print the namespace and its parents ommitting inline scopes. 265d1f13c54SKadir Cetinkaya std::string Scope; 266d1f13c54SKadir Cetinkaya for (const auto *ND = D; ND; 267d1f13c54SKadir Cetinkaya ND = llvm::dyn_cast_or_null<NamespaceDecl>(ND->getParent())) 268d1f13c54SKadir Cetinkaya if (!ND->isInlineNamespace() && !ND->isAnonymousNamespace()) 269d1f13c54SKadir Cetinkaya Scope = ND->getName().str() + "::" + Scope; 270c812ab73SHaojian Wu return getMappingPerLang(L)->NamespaceSymbols->lookup(Scope); 271d1f13c54SKadir Cetinkaya }(); 272d1f13c54SKadir Cetinkaya NamespaceCache.try_emplace(D, Result); 273d1f13c54SKadir Cetinkaya return Result; 274d1f13c54SKadir Cetinkaya } 275d1f13c54SKadir Cetinkaya 27667b72a28SHaojian Wu std::optional<Symbol> Recognizer::operator()(const Decl *D) { 277c812ab73SHaojian Wu Lang L; 278e93cbd18SHaojian Wu if (D->getLangOpts().CPlusPlus) 279c812ab73SHaojian Wu L = Lang::CXX; 280e93cbd18SHaojian Wu else if (D->getLangOpts().C99) 281c812ab73SHaojian Wu L = Lang::C; 282e93cbd18SHaojian Wu else 283c812ab73SHaojian Wu return std::nullopt; // not a supported language. 284c812ab73SHaojian Wu 285d1f13c54SKadir Cetinkaya // If D is std::vector::iterator, `vector` is the outer symbol to look up. 286d1f13c54SKadir Cetinkaya // We keep all the candidate DCs as some may turn out to be anon enums. 287d1f13c54SKadir Cetinkaya // Do this resolution lazily as we may turn out not to have a std namespace. 288d1f13c54SKadir Cetinkaya llvm::SmallVector<const DeclContext *> IntermediateDecl; 289d1f13c54SKadir Cetinkaya const DeclContext *DC = D->getDeclContext(); 290c812ab73SHaojian Wu if (!DC) // The passed D is a TranslationUnitDecl! 291c812ab73SHaojian Wu return std::nullopt; 292c812ab73SHaojian Wu while (!DC->isNamespace() && !DC->isTranslationUnit()) { 293d1f13c54SKadir Cetinkaya if (NamedDecl::classofKind(DC->getDeclKind())) 294d1f13c54SKadir Cetinkaya IntermediateDecl.push_back(DC); 295d1f13c54SKadir Cetinkaya DC = DC->getParent(); 296d1f13c54SKadir Cetinkaya } 297c812ab73SHaojian Wu NSSymbolMap *Symbols = namespaceSymbols(DC, L); 298d1f13c54SKadir Cetinkaya if (!Symbols) 2995891420eSKazu Hirata return std::nullopt; 300d1f13c54SKadir Cetinkaya 301d1f13c54SKadir Cetinkaya llvm::StringRef Name = [&]() -> llvm::StringRef { 302d1f13c54SKadir Cetinkaya for (const auto *SymDC : llvm::reverse(IntermediateDecl)) { 303d1f13c54SKadir Cetinkaya DeclarationName N = cast<NamedDecl>(SymDC)->getDeclName(); 304d1f13c54SKadir Cetinkaya if (const auto *II = N.getAsIdentifierInfo()) 305d1f13c54SKadir Cetinkaya return II->getName(); 306d1f13c54SKadir Cetinkaya if (!N.isEmpty()) 307d1f13c54SKadir Cetinkaya return ""; // e.g. operator<: give up 308d1f13c54SKadir Cetinkaya } 309d1f13c54SKadir Cetinkaya if (const auto *ND = llvm::dyn_cast<NamedDecl>(D)) 310d1f13c54SKadir Cetinkaya if (const auto *II = ND->getIdentifier()) 311d1f13c54SKadir Cetinkaya return II->getName(); 312d1f13c54SKadir Cetinkaya return ""; 313d1f13c54SKadir Cetinkaya }(); 314d1f13c54SKadir Cetinkaya if (Name.empty()) 3155891420eSKazu Hirata return std::nullopt; 316d1f13c54SKadir Cetinkaya 317d1f13c54SKadir Cetinkaya auto It = Symbols->find(Name); 318d1f13c54SKadir Cetinkaya if (It == Symbols->end()) 3195891420eSKazu Hirata return std::nullopt; 320c812ab73SHaojian Wu return Symbol(It->second, L); 321d1f13c54SKadir Cetinkaya } 322d1f13c54SKadir Cetinkaya 323d1f13c54SKadir Cetinkaya } // namespace stdlib 324d1f13c54SKadir Cetinkaya } // namespace tooling 325d1f13c54SKadir Cetinkaya } // namespace clang 326