clang 18.0.0git
StandardLibrary.cpp
Go to the documentation of this file.
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
10#include "clang/AST/Decl.h"
12#include "llvm/ADT/ArrayRef.h"
13#include "llvm/ADT/DenseSet.h"
14#include "llvm/ADT/STLExtras.h"
15#include "llvm/ADT/StringRef.h"
16#include "llvm/Support/Casting.h"
17#include <optional>
18
19namespace clang {
20namespace tooling {
21namespace stdlib {
22
23namespace {
24// Symbol name -> Symbol::ID, within a namespace.
25using NSSymbolMap = llvm::DenseMap<llvm::StringRef, unsigned>;
26
27// A Mapping per language.
28struct SymbolHeaderMapping {
29 llvm::StringRef *HeaderNames = nullptr;
30 // Header name => Header::ID
31 llvm::DenseMap<llvm::StringRef, unsigned> *HeaderIDs;
32
33 unsigned SymbolCount = 0;
34 // Symbol::ID => symbol qualified_name/name/scope
35 struct SymbolName {
36 const char *Data; // std::vector
37 unsigned ScopeLen; // ~~~~~
38 unsigned NameLen; // ~~~~~~
39 StringRef scope() const { return StringRef(Data, ScopeLen); }
40 StringRef name() const { return StringRef(Data + ScopeLen, NameLen); }
41 StringRef qualifiedName() const {
42 return StringRef(Data, ScopeLen + NameLen);
43 }
44 } *SymbolNames = nullptr;
45 // Symbol name -> Symbol::ID, within a namespace.
46 llvm::DenseMap<llvm::StringRef, NSSymbolMap *> *NamespaceSymbols = nullptr;
47 // Symbol::ID => Header::ID
49};
50} // namespace
51static SymbolHeaderMapping
52 *LanguageMappings[static_cast<unsigned>(Lang::LastValue) + 1];
53static const SymbolHeaderMapping *getMappingPerLang(Lang L) {
54 return LanguageMappings[static_cast<unsigned>(L)];
55}
56
59#define SYMBOL(Name, NS, Header) Set.insert(#NS #Name);
60 switch (Language) {
61 case Lang::C:
62#include "CSymbolMap.inc"
63 break;
64 case Lang::CXX:
66#include "StdSymbolMap.inc"
67#include "StdTsSymbolMap.inc"
68 break;
69 }
70#undef SYMBOL
71 return Set.size();
72}
73
75 SymbolHeaderMapping *Mapping = new SymbolHeaderMapping();
76 LanguageMappings[static_cast<unsigned>(Language)] = Mapping;
77
78 unsigned SymCount = countSymbols(Language);
79 Mapping->SymbolCount = SymCount;
80 Mapping->SymbolNames =
81 new std::remove_reference_t<decltype(*Mapping->SymbolNames)>[SymCount];
82 Mapping->SymbolHeaderIDs = new std::remove_reference_t<
83 decltype(*Mapping->SymbolHeaderIDs)>[SymCount];
84 Mapping->NamespaceSymbols =
85 new std::remove_reference_t<decltype(*Mapping->NamespaceSymbols)>;
86 Mapping->HeaderIDs =
87 new std::remove_reference_t<decltype(*Mapping->HeaderIDs)>;
88 auto AddNS = [&](llvm::StringRef NS) -> NSSymbolMap & {
89 auto R = Mapping->NamespaceSymbols->try_emplace(NS, nullptr);
90 if (R.second)
91 R.first->second = new NSSymbolMap();
92 return *R.first->second;
93 };
94
95 auto AddHeader = [&](llvm::StringRef Header) -> unsigned {
96 return Mapping->HeaderIDs->try_emplace(Header, Mapping->HeaderIDs->size())
97 .first->second;
98 };
99
100 auto Add = [&, SymIndex(-1)](llvm::StringRef QName, unsigned NSLen,
101 llvm::StringRef HeaderName) mutable {
102 // Correct "Nonefoo" => foo.
103 // FIXME: get rid of "None" from the generated mapping files.
104 if (QName.take_front(NSLen) == "None") {
105 QName = QName.drop_front(NSLen);
106 NSLen = 0;
107 }
108
109 if (SymIndex >= 0 &&
110 Mapping->SymbolNames[SymIndex].qualifiedName() == QName) {
111 // Not a new symbol, use the same index.
112 assert(llvm::none_of(llvm::ArrayRef(Mapping->SymbolNames, SymIndex),
113 [&QName](const SymbolHeaderMapping::SymbolName &S) {
114 return S.qualifiedName() == QName;
115 }) &&
116 "The symbol has been added before, make sure entries in the .inc "
117 "file are grouped by symbol name!");
118 } else {
119 // First symbol or new symbol, increment next available index.
120 ++SymIndex;
121 }
122 Mapping->SymbolNames[SymIndex] = {
123 QName.data(), NSLen, static_cast<unsigned int>(QName.size() - NSLen)};
124 if (!HeaderName.empty())
125 Mapping->SymbolHeaderIDs[SymIndex].push_back(AddHeader(HeaderName));
126
127 NSSymbolMap &NSSymbols = AddNS(QName.take_front(NSLen));
128 NSSymbols.try_emplace(QName.drop_front(NSLen), SymIndex);
129 };
130#define SYMBOL(Name, NS, Header) Add(#NS #Name, strlen(#NS), #Header);
131 switch (Language) {
132 case Lang::C:
133#include "CSymbolMap.inc"
134 break;
135 case Lang::CXX:
137#include "StdSymbolMap.inc"
138#include "StdTsSymbolMap.inc"
139 break;
140 }
141#undef SYMBOL
142
143 Mapping->HeaderNames = new llvm::StringRef[Mapping->HeaderIDs->size()];
144 for (const auto &E : *Mapping->HeaderIDs)
145 Mapping->HeaderNames[E.second] = E.first;
146
147 return 0;
148}
149
150static void ensureInitialized() {
151 static int Dummy = []() {
152 for (unsigned L = 0; L <= static_cast<unsigned>(Lang::LastValue); ++L)
153 initialize(static_cast<Lang>(L));
154 return 0;
155 }();
156 (void)Dummy;
157}
158
159std::vector<Header> Header::all(Lang L) {
161 std::vector<Header> Result;
162 const auto *Mapping = getMappingPerLang(L);
163 Result.reserve(Mapping->HeaderIDs->size());
164 for (unsigned I = 0, E = Mapping->HeaderIDs->size(); I < E; ++I)
165 Result.push_back(Header(I, L));
166 return Result;
167}
168std::optional<Header> Header::named(llvm::StringRef Name, Lang L) {
170 const auto *Mapping = getMappingPerLang(L);
171 auto It = Mapping->HeaderIDs->find(Name);
172 if (It == Mapping->HeaderIDs->end())
173 return std::nullopt;
174 return Header(It->second, L);
175}
176llvm::StringRef Header::name() const {
177 return getMappingPerLang(Language)->HeaderNames[ID];
178}
179
180std::vector<Symbol> Symbol::all(Lang L) {
182 std::vector<Symbol> Result;
183 const auto *Mapping = getMappingPerLang(L);
184 Result.reserve(Mapping->SymbolCount);
185 for (unsigned I = 0, E = Mapping->SymbolCount; I < E; ++I)
186 Result.push_back(Symbol(I, L));
187 return Result;
188}
189llvm::StringRef Symbol::scope() const {
190 return getMappingPerLang(Language)->SymbolNames[ID].scope();
191}
192llvm::StringRef Symbol::name() const {
193 return getMappingPerLang(Language)->SymbolNames[ID].name();
194}
195llvm::StringRef Symbol::qualifiedName() const {
196 return getMappingPerLang(Language)->SymbolNames[ID].qualifiedName();
197}
198std::optional<Symbol> Symbol::named(llvm::StringRef Scope, llvm::StringRef Name,
199 Lang L) {
201
202 if (NSSymbolMap *NSSymbols =
204 auto It = NSSymbols->find(Name);
205 if (It != NSSymbols->end())
206 return Symbol(It->second, L);
207 }
208 return std::nullopt;
209}
210std::optional<Header> Symbol::header() const {
211 const auto& Headers = getMappingPerLang(Language)->SymbolHeaderIDs[ID];
212 if (Headers.empty())
213 return std::nullopt;
214 return Header(Headers.front(), Language);
215}
218 for (auto HeaderID : getMappingPerLang(Language)->SymbolHeaderIDs[ID])
219 Results.emplace_back(Header(HeaderID, Language));
220 return Results;
221}
222
224
225NSSymbolMap *Recognizer::namespaceSymbols(const DeclContext *DC, Lang L) {
226 if (DC->isTranslationUnit()) // global scope.
227 return getMappingPerLang(L)->NamespaceSymbols->lookup("");
228
229 auto It = NamespaceCache.find(DC);
230 if (It != NamespaceCache.end())
231 return It->second;
232 const NamespaceDecl *D = llvm::cast<NamespaceDecl>(DC);
233 NSSymbolMap *Result = [&]() -> NSSymbolMap * {
234 if (D->isAnonymousNamespace())
235 return nullptr;
236 // Print the namespace and its parents ommitting inline scopes.
237 std::string Scope;
238 for (const auto *ND = D; ND;
239 ND = llvm::dyn_cast_or_null<NamespaceDecl>(ND->getParent()))
240 if (!ND->isInlineNamespace() && !ND->isAnonymousNamespace())
241 Scope = ND->getName().str() + "::" + Scope;
242 return getMappingPerLang(L)->NamespaceSymbols->lookup(Scope);
243 }();
244 NamespaceCache.try_emplace(D, Result);
245 return Result;
246}
247
248std::optional<Symbol> Recognizer::operator()(const Decl *D) {
249 Lang L;
250 if (D->getLangOpts().CPlusPlus)
251 L = Lang::CXX;
252 else if (D->getLangOpts().C99)
253 L = Lang::C;
254 else
255 return std::nullopt; // not a supported language.
256
257 // If D is std::vector::iterator, `vector` is the outer symbol to look up.
258 // We keep all the candidate DCs as some may turn out to be anon enums.
259 // Do this resolution lazily as we may turn out not to have a std namespace.
261 const DeclContext *DC = D->getDeclContext();
262 if (!DC) // The passed D is a TranslationUnitDecl!
263 return std::nullopt;
264 while (!DC->isNamespace() && !DC->isTranslationUnit()) {
266 IntermediateDecl.push_back(DC);
267 DC = DC->getParent();
268 }
269 NSSymbolMap *Symbols = namespaceSymbols(DC, L);
270 if (!Symbols)
271 return std::nullopt;
272
273 llvm::StringRef Name = [&]() -> llvm::StringRef {
274 for (const auto *SymDC : llvm::reverse(IntermediateDecl)) {
275 DeclarationName N = cast<NamedDecl>(SymDC)->getDeclName();
276 if (const auto *II = N.getAsIdentifierInfo())
277 return II->getName();
278 if (!N.isEmpty())
279 return ""; // e.g. operator<: give up
280 }
281 if (const auto *ND = llvm::dyn_cast<NamedDecl>(D))
282 if (const auto *II = ND->getIdentifier())
283 return II->getName();
284 return "";
285 }();
286 if (Name.empty())
287 return std::nullopt;
288
289 auto It = Symbols->find(Name);
290 if (It == Symbols->end())
291 return std::nullopt;
292 return Symbol(It->second, L);
293}
294
295} // namespace stdlib
296} // namespace tooling
297} // namespace clang
Defines the clang::LangOptions interface.
unsigned NameLen
struct clang::tooling::stdlib::@1848::SymbolHeaderMapping::SymbolName * SymbolNames
llvm::DenseMap< llvm::StringRef, NSSymbolMap * > * NamespaceSymbols
llvm::StringRef * HeaderNames
const char * Data
unsigned ScopeLen
llvm::SmallVector< unsigned > * SymbolHeaderIDs
llvm::DenseMap< llvm::StringRef, unsigned > * HeaderIDs
unsigned SymbolCount
Provides an interface for querying information about C and C++ Standard Library headers and symbols.
DeclContext - This is used only as base class of specific decl types that can act as declaration cont...
Definition: DeclBase.h:1409
DeclContext * getParent()
getParent - Returns the containing DeclContext.
Definition: DeclBase.h:1951
bool isNamespace() const
Definition: DeclBase.h:2035
bool isTranslationUnit() const
Definition: DeclBase.h:2026
Decl::Kind getDeclKind() const
Definition: DeclBase.h:1944
Decl - This represents one declaration (or definition), e.g.
Definition: DeclBase.h:83
DeclContext * getDeclContext()
Definition: DeclBase.h:441
const LangOptions & getLangOpts() const LLVM_READONLY
Helper to get the language options from the ASTContext.
Definition: DeclBase.cpp:435
The name of a declaration.
IdentifierInfo * getAsIdentifierInfo() const
Retrieve the IdentifierInfo * stored in this declaration name, or null if this declaration name isn't...
bool isEmpty() const
Evaluates true when this declaration name is empty.
static bool classofKind(Kind K)
Definition: Decl.h:483
Represent a C++ namespace.
Definition: Decl.h:544
bool isAnonymousNamespace() const
Returns true if this is an anonymous namespace declaration.
Definition: Decl.h:602
Scope - A scope is a transient data structure that is used while parsing the program.
Definition: Scope.h:41
static std::optional< Header > named(llvm::StringRef Name, Lang Language=Lang::CXX)
static std::vector< Header > all(Lang L=Lang::CXX)
llvm::StringRef name() const
std::optional< Symbol > operator()(const Decl *D)
static std::optional< Symbol > named(llvm::StringRef Scope, llvm::StringRef Name, Lang Language=Lang::CXX)
Scope should have the trailing "::", for example: named("std::chrono::", "system_clock")
llvm::StringRef name() const
llvm::StringRef scope() const
llvm::SmallVector< Header > headers() const
llvm::StringRef qualifiedName() const
static std::vector< Symbol > all(Lang L=Lang::CXX)
std::optional< Header > header() const
static int countSymbols(Lang Language)
static int initialize(Lang Language)
static const SymbolHeaderMapping * getMappingPerLang(Lang L)
static SymbolHeaderMapping * LanguageMappings[static_cast< unsigned >(Lang::LastValue)+1]
static void ensureInitialized()
RangeSelector name(std::string ID)
Given a node with a "name", (like NamedDecl, DeclRefExpr, CxxCtorInitializer, and TypeLoc) selects th...
Language
The language for the input, used to select and validate the language standard and possible actions.
Definition: LangStandard.h:23
@ Result
The result type of a method or function.