xref: /freebsd/contrib/llvm-project/clang/lib/Tooling/Inclusions/Stdlib/StandardLibrary.cpp (revision 7ef62cebc2f965b0f640263e179276928885e33d)
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