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