1 //===--- StandardLibrary.cpp ------------------------------------*- C++ -*-===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #include "clang/Tooling/Inclusions/StandardLibrary.h" 10 #include "clang/AST/Decl.h" 11 #include "llvm/ADT/StringRef.h" 12 #include "llvm/Support/Casting.h" 13 14 namespace clang { 15 namespace tooling { 16 namespace stdlib { 17 18 static llvm::StringRef *HeaderNames; 19 static std::pair<llvm::StringRef, llvm::StringRef> *SymbolNames; 20 static unsigned *SymbolHeaderIDs; 21 static llvm::DenseMap<llvm::StringRef, unsigned> *HeaderIDs; 22 // Maps symbol name -> Symbol::ID, within a namespace. 23 using NSSymbolMap = llvm::DenseMap<llvm::StringRef, unsigned>; 24 static llvm::DenseMap<llvm::StringRef, NSSymbolMap *> *NamespaceSymbols; 25 26 static int initialize() { 27 unsigned SymCount = 0; 28 #define SYMBOL(Name, NS, Header) ++SymCount; 29 #include "clang/Tooling/Inclusions/CSymbolMap.inc" 30 #include "clang/Tooling/Inclusions/StdSymbolMap.inc" 31 #undef SYMBOL 32 SymbolNames = new std::remove_reference_t<decltype(*SymbolNames)>[SymCount]; 33 SymbolHeaderIDs = 34 new std::remove_reference_t<decltype(*SymbolHeaderIDs)>[SymCount]; 35 NamespaceSymbols = new std::remove_reference_t<decltype(*NamespaceSymbols)>; 36 HeaderIDs = new std::remove_reference_t<decltype(*HeaderIDs)>; 37 38 auto AddNS = [&](llvm::StringRef NS) -> NSSymbolMap & { 39 auto R = NamespaceSymbols->try_emplace(NS, nullptr); 40 if (R.second) 41 R.first->second = new NSSymbolMap(); 42 return *R.first->second; 43 }; 44 45 auto AddHeader = [&](llvm::StringRef Header) -> unsigned { 46 return HeaderIDs->try_emplace(Header, HeaderIDs->size()).first->second; 47 }; 48 49 auto Add = [&, SymIndex(0)](llvm::StringRef Name, llvm::StringRef NS, 50 llvm::StringRef HeaderName) mutable { 51 if (NS == "None") 52 NS = ""; 53 54 SymbolNames[SymIndex] = {NS, Name}; 55 SymbolHeaderIDs[SymIndex] = AddHeader(HeaderName); 56 57 NSSymbolMap &NSSymbols = AddNS(NS); 58 NSSymbols.try_emplace(Name, SymIndex); 59 60 ++SymIndex; 61 }; 62 #define SYMBOL(Name, NS, Header) Add(#Name, #NS, #Header); 63 #include "clang/Tooling/Inclusions/CSymbolMap.inc" 64 #include "clang/Tooling/Inclusions/StdSymbolMap.inc" 65 #undef SYMBOL 66 67 HeaderNames = new llvm::StringRef[HeaderIDs->size()]; 68 for (const auto &E : *HeaderIDs) 69 HeaderNames[E.second] = E.first; 70 71 return 0; 72 } 73 74 static void ensureInitialized() { 75 static int Dummy = initialize(); 76 (void)Dummy; 77 } 78 79 std::optional<Header> Header::named(llvm::StringRef Name) { 80 ensureInitialized(); 81 auto It = HeaderIDs->find(Name); 82 if (It == HeaderIDs->end()) 83 return std::nullopt; 84 return Header(It->second); 85 } 86 llvm::StringRef Header::name() const { return HeaderNames[ID]; } 87 llvm::StringRef Symbol::scope() const { return SymbolNames[ID].first; } 88 llvm::StringRef Symbol::name() const { return SymbolNames[ID].second; } 89 std::optional<Symbol> Symbol::named(llvm::StringRef Scope, 90 llvm::StringRef Name) { 91 ensureInitialized(); 92 if (NSSymbolMap *NSSymbols = NamespaceSymbols->lookup(Scope)) { 93 auto It = NSSymbols->find(Name); 94 if (It != NSSymbols->end()) 95 return Symbol(It->second); 96 } 97 return std::nullopt; 98 } 99 Header Symbol::header() const { return Header(SymbolHeaderIDs[ID]); } 100 llvm::SmallVector<Header> Symbol::headers() const { 101 return {header()}; // FIXME: multiple in case of ambiguity 102 } 103 104 Recognizer::Recognizer() { ensureInitialized(); } 105 106 NSSymbolMap *Recognizer::namespaceSymbols(const NamespaceDecl *D) { 107 auto It = NamespaceCache.find(D); 108 if (It != NamespaceCache.end()) 109 return It->second; 110 111 NSSymbolMap *Result = [&]() -> NSSymbolMap * { 112 if (D && D->isAnonymousNamespace()) 113 return nullptr; 114 // Print the namespace and its parents ommitting inline scopes. 115 std::string Scope; 116 for (const auto *ND = D; ND; 117 ND = llvm::dyn_cast_or_null<NamespaceDecl>(ND->getParent())) 118 if (!ND->isInlineNamespace() && !ND->isAnonymousNamespace()) 119 Scope = ND->getName().str() + "::" + Scope; 120 return NamespaceSymbols->lookup(Scope); 121 }(); 122 NamespaceCache.try_emplace(D, Result); 123 return Result; 124 } 125 126 std::optional<Symbol> Recognizer::operator()(const Decl *D) { 127 // If D is std::vector::iterator, `vector` is the outer symbol to look up. 128 // We keep all the candidate DCs as some may turn out to be anon enums. 129 // Do this resolution lazily as we may turn out not to have a std namespace. 130 llvm::SmallVector<const DeclContext *> IntermediateDecl; 131 const DeclContext *DC = D->getDeclContext(); 132 while (DC && !DC->isNamespace()) { 133 if (NamedDecl::classofKind(DC->getDeclKind())) 134 IntermediateDecl.push_back(DC); 135 DC = DC->getParent(); 136 } 137 NSSymbolMap *Symbols = namespaceSymbols(cast_or_null<NamespaceDecl>(DC)); 138 if (!Symbols) 139 return std::nullopt; 140 141 llvm::StringRef Name = [&]() -> llvm::StringRef { 142 for (const auto *SymDC : llvm::reverse(IntermediateDecl)) { 143 DeclarationName N = cast<NamedDecl>(SymDC)->getDeclName(); 144 if (const auto *II = N.getAsIdentifierInfo()) 145 return II->getName(); 146 if (!N.isEmpty()) 147 return ""; // e.g. operator<: give up 148 } 149 if (const auto *ND = llvm::dyn_cast<NamedDecl>(D)) 150 if (const auto *II = ND->getIdentifier()) 151 return II->getName(); 152 return ""; 153 }(); 154 if (Name.empty()) 155 return std::nullopt; 156 157 auto It = Symbols->find(Name); 158 if (It == Symbols->end()) 159 return std::nullopt; 160 return Symbol(It->second); 161 } 162 163 } // namespace stdlib 164 } // namespace tooling 165 } // namespace clang 166