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