1 //===--- StandardLibrary.cpp ------------------------------------*- C++ -*-===//
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
7 //===----------------------------------------------------------------------===//
9 #include "clang/Tooling/Inclusions/StandardLibrary.h"
10 #include "clang/AST/Decl.h"
11 #include "clang/Basic/LangOptions.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"
24 // Symbol name -> Symbol::ID, within a namespace.
25 using NSSymbolMap
= llvm::DenseMap
<llvm::StringRef
, unsigned>;
27 // A Mapping per language.
28 struct SymbolHeaderMapping
{
29 llvm::StringRef
*HeaderNames
= nullptr;
30 // Header name => Header::ID
31 llvm::DenseMap
<llvm::StringRef
, unsigned> *HeaderIDs
;
33 unsigned SymbolCount
= 0;
34 // Symbol::ID => symbol qualified_name/name/scope
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
);
44 } *SymbolNames
= nullptr;
45 // Symbol name -> Symbol::ID, within a namespace.
46 llvm::DenseMap
<llvm::StringRef
, NSSymbolMap
*> *NamespaceSymbols
= nullptr;
47 // Symbol::ID => Header::ID
48 llvm::SmallVector
<unsigned> *SymbolHeaderIDs
= nullptr;
51 static SymbolHeaderMapping
52 *LanguageMappings
[static_cast<unsigned>(Lang::LastValue
) + 1];
53 static const SymbolHeaderMapping
*getMappingPerLang(Lang L
) {
54 return LanguageMappings
[static_cast<unsigned>(L
)];
57 static int countSymbols(Lang Language
) {
58 ArrayRef
<const char*> Symbols
;
59 #define SYMBOL(Name, NS, Header) #NS #Name,
62 static constexpr const char *CSymbols
[] = {
63 #include "CSymbolMap.inc"
69 static constexpr const char *CXXSymbols
[] = {
70 #include "StdSpecialSymbolMap.inc"
71 #include "StdSymbolMap.inc"
72 #include "StdTsSymbolMap.inc"
79 return llvm::DenseSet
<StringRef
>(Symbols
.begin(), Symbols
.end()).size();
82 static int initialize(Lang Language
) {
83 SymbolHeaderMapping
*Mapping
= new SymbolHeaderMapping();
84 LanguageMappings
[static_cast<unsigned>(Language
)] = Mapping
;
86 unsigned SymCount
= countSymbols(Language
);
87 Mapping
->SymbolCount
= SymCount
;
88 Mapping
->SymbolNames
=
89 new std::remove_reference_t
<decltype(*Mapping
->SymbolNames
)>[SymCount
];
90 Mapping
->SymbolHeaderIDs
= new std::remove_reference_t
<
91 decltype(*Mapping
->SymbolHeaderIDs
)>[SymCount
];
92 Mapping
->NamespaceSymbols
=
93 new std::remove_reference_t
<decltype(*Mapping
->NamespaceSymbols
)>;
95 new std::remove_reference_t
<decltype(*Mapping
->HeaderIDs
)>;
96 auto AddNS
= [&](llvm::StringRef NS
) -> NSSymbolMap
& {
97 auto R
= Mapping
->NamespaceSymbols
->try_emplace(NS
, nullptr);
99 R
.first
->second
= new NSSymbolMap();
100 return *R
.first
->second
;
103 auto AddHeader
= [&](llvm::StringRef Header
) -> unsigned {
104 return Mapping
->HeaderIDs
->try_emplace(Header
, Mapping
->HeaderIDs
->size())
108 auto Add
= [&, SymIndex(-1)](llvm::StringRef QName
, unsigned NSLen
,
109 llvm::StringRef HeaderName
) mutable {
110 // Correct "Nonefoo" => foo.
111 // FIXME: get rid of "None" from the generated mapping files.
112 if (QName
.take_front(NSLen
) == "None") {
113 QName
= QName
.drop_front(NSLen
);
118 Mapping
->SymbolNames
[SymIndex
].qualifiedName() == QName
) {
119 // Not a new symbol, use the same index.
120 assert(llvm::none_of(llvm::ArrayRef(Mapping
->SymbolNames
, SymIndex
),
121 [&QName
](const SymbolHeaderMapping::SymbolName
&S
) {
122 return S
.qualifiedName() == QName
;
124 "The symbol has been added before, make sure entries in the .inc "
125 "file are grouped by symbol name!");
127 // First symbol or new symbol, increment next available index.
130 Mapping
->SymbolNames
[SymIndex
] = {
131 QName
.data(), NSLen
, static_cast<unsigned int>(QName
.size() - NSLen
)};
132 if (!HeaderName
.empty())
133 Mapping
->SymbolHeaderIDs
[SymIndex
].push_back(AddHeader(HeaderName
));
135 NSSymbolMap
&NSSymbols
= AddNS(QName
.take_front(NSLen
));
136 NSSymbols
.try_emplace(QName
.drop_front(NSLen
), SymIndex
);
142 const char *HeaderName
;
144 #define SYMBOL(Name, NS, Header) {#NS #Name, StringRef(#NS).size(), #Header},
147 static constexpr Symbol CSymbols
[] = {
148 #include "CSymbolMap.inc"
150 for (const Symbol
&S
: CSymbols
)
151 Add(S
.QName
, S
.NSLen
, S
.HeaderName
);
155 static constexpr Symbol CXXSymbols
[] = {
156 #include "StdSpecialSymbolMap.inc"
157 #include "StdSymbolMap.inc"
158 #include "StdTsSymbolMap.inc"
160 for (const Symbol
&S
: CXXSymbols
)
161 Add(S
.QName
, S
.NSLen
, S
.HeaderName
);
167 Mapping
->HeaderNames
= new llvm::StringRef
[Mapping
->HeaderIDs
->size()];
168 for (const auto &E
: *Mapping
->HeaderIDs
)
169 Mapping
->HeaderNames
[E
.second
] = E
.first
;
174 static void ensureInitialized() {
175 static int Dummy
= []() {
176 for (unsigned L
= 0; L
<= static_cast<unsigned>(Lang::LastValue
); ++L
)
177 initialize(static_cast<Lang
>(L
));
183 std::vector
<Header
> Header::all(Lang L
) {
185 std::vector
<Header
> Result
;
186 const auto *Mapping
= getMappingPerLang(L
);
187 Result
.reserve(Mapping
->HeaderIDs
->size());
188 for (unsigned I
= 0, E
= Mapping
->HeaderIDs
->size(); I
< E
; ++I
)
189 Result
.push_back(Header(I
, L
));
192 std::optional
<Header
> Header::named(llvm::StringRef Name
, Lang L
) {
194 const auto *Mapping
= getMappingPerLang(L
);
195 auto It
= Mapping
->HeaderIDs
->find(Name
);
196 if (It
== Mapping
->HeaderIDs
->end())
198 return Header(It
->second
, L
);
200 llvm::StringRef
Header::name() const {
201 return getMappingPerLang(Language
)->HeaderNames
[ID
];
204 std::vector
<Symbol
> Symbol::all(Lang L
) {
206 std::vector
<Symbol
> Result
;
207 const auto *Mapping
= getMappingPerLang(L
);
208 Result
.reserve(Mapping
->SymbolCount
);
209 for (unsigned I
= 0, E
= Mapping
->SymbolCount
; I
< E
; ++I
)
210 Result
.push_back(Symbol(I
, L
));
213 llvm::StringRef
Symbol::scope() const {
214 return getMappingPerLang(Language
)->SymbolNames
[ID
].scope();
216 llvm::StringRef
Symbol::name() const {
217 return getMappingPerLang(Language
)->SymbolNames
[ID
].name();
219 llvm::StringRef
Symbol::qualifiedName() const {
220 return getMappingPerLang(Language
)->SymbolNames
[ID
].qualifiedName();
222 std::optional
<Symbol
> Symbol::named(llvm::StringRef Scope
, llvm::StringRef Name
,
226 if (NSSymbolMap
*NSSymbols
=
227 getMappingPerLang(L
)->NamespaceSymbols
->lookup(Scope
)) {
228 auto It
= NSSymbols
->find(Name
);
229 if (It
!= NSSymbols
->end())
230 return Symbol(It
->second
, L
);
234 std::optional
<Header
> Symbol::header() const {
235 const auto& Headers
= getMappingPerLang(Language
)->SymbolHeaderIDs
[ID
];
238 return Header(Headers
.front(), Language
);
240 llvm::SmallVector
<Header
> Symbol::headers() const {
241 llvm::SmallVector
<Header
> Results
;
242 for (auto HeaderID
: getMappingPerLang(Language
)->SymbolHeaderIDs
[ID
])
243 Results
.emplace_back(Header(HeaderID
, Language
));
247 Recognizer::Recognizer() { ensureInitialized(); }
249 NSSymbolMap
*Recognizer::namespaceSymbols(const DeclContext
*DC
, Lang L
) {
250 if (DC
->isTranslationUnit()) // global scope.
251 return getMappingPerLang(L
)->NamespaceSymbols
->lookup("");
253 auto It
= NamespaceCache
.find(DC
);
254 if (It
!= NamespaceCache
.end())
256 const NamespaceDecl
*D
= llvm::cast
<NamespaceDecl
>(DC
);
257 NSSymbolMap
*Result
= [&]() -> NSSymbolMap
* {
258 if (D
->isAnonymousNamespace())
260 // Print the namespace and its parents ommitting inline scopes.
262 for (const auto *ND
= D
; ND
;
263 ND
= llvm::dyn_cast_or_null
<NamespaceDecl
>(ND
->getParent()))
264 if (!ND
->isInlineNamespace() && !ND
->isAnonymousNamespace())
265 Scope
= ND
->getName().str() + "::" + Scope
;
266 return getMappingPerLang(L
)->NamespaceSymbols
->lookup(Scope
);
268 NamespaceCache
.try_emplace(D
, Result
);
272 std::optional
<Symbol
> Recognizer::operator()(const Decl
*D
) {
274 if (D
->getLangOpts().CPlusPlus
)
276 else if (D
->getLangOpts().C99
)
279 return std::nullopt
; // not a supported language.
281 // If D is std::vector::iterator, `vector` is the outer symbol to look up.
282 // We keep all the candidate DCs as some may turn out to be anon enums.
283 // Do this resolution lazily as we may turn out not to have a std namespace.
284 llvm::SmallVector
<const DeclContext
*> IntermediateDecl
;
285 const DeclContext
*DC
= D
->getDeclContext();
286 if (!DC
) // The passed D is a TranslationUnitDecl!
288 while (!DC
->isNamespace() && !DC
->isTranslationUnit()) {
289 if (NamedDecl::classofKind(DC
->getDeclKind()))
290 IntermediateDecl
.push_back(DC
);
291 DC
= DC
->getParent();
293 NSSymbolMap
*Symbols
= namespaceSymbols(DC
, L
);
297 llvm::StringRef Name
= [&]() -> llvm::StringRef
{
298 for (const auto *SymDC
: llvm::reverse(IntermediateDecl
)) {
299 DeclarationName N
= cast
<NamedDecl
>(SymDC
)->getDeclName();
300 if (const auto *II
= N
.getAsIdentifierInfo())
301 return II
->getName();
303 return ""; // e.g. operator<: give up
305 if (const auto *ND
= llvm::dyn_cast
<NamedDecl
>(D
))
306 if (const auto *II
= ND
->getIdentifier())
307 return II
->getName();
313 auto It
= Symbols
->find(Name
);
314 if (It
== Symbols
->end())
316 return Symbol(It
->second
, L
);
319 } // namespace stdlib
320 } // namespace tooling