1 | //===- DeclarationName.cpp - Declaration names implementation -------------===// |
---|---|
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 | // This file implements the DeclarationName and DeclarationNameTable |
10 | // classes. |
11 | // |
12 | //===----------------------------------------------------------------------===// |
13 | |
14 | #include "clang/AST/DeclarationName.h" |
15 | #include "clang/AST/ASTContext.h" |
16 | #include "clang/AST/Decl.h" |
17 | #include "clang/AST/DeclBase.h" |
18 | #include "clang/AST/DeclCXX.h" |
19 | #include "clang/AST/DeclTemplate.h" |
20 | #include "clang/AST/OpenMPClause.h" |
21 | #include "clang/AST/PrettyPrinter.h" |
22 | #include "clang/AST/Type.h" |
23 | #include "clang/AST/TypeLoc.h" |
24 | #include "clang/AST/TypeOrdering.h" |
25 | #include "clang/Basic/IdentifierTable.h" |
26 | #include "clang/Basic/LLVM.h" |
27 | #include "clang/Basic/LangOptions.h" |
28 | #include "clang/Basic/OperatorKinds.h" |
29 | #include "clang/Basic/SourceLocation.h" |
30 | #include "llvm/ADT/FoldingSet.h" |
31 | #include "llvm/Support/Compiler.h" |
32 | #include "llvm/Support/ErrorHandling.h" |
33 | #include "llvm/Support/raw_ostream.h" |
34 | #include <algorithm> |
35 | #include <cassert> |
36 | #include <string> |
37 | |
38 | using namespace clang; |
39 | |
40 | static int compareInt(unsigned A, unsigned B) { |
41 | return (A < B ? -1 : (A > B ? 1 : 0)); |
42 | } |
43 | |
44 | int DeclarationName::compare(DeclarationName LHS, DeclarationName RHS) { |
45 | if (LHS.getNameKind() != RHS.getNameKind()) |
46 | return (LHS.getNameKind() < RHS.getNameKind() ? -1 : 1); |
47 | |
48 | switch (LHS.getNameKind()) { |
49 | case DeclarationName::Identifier: { |
50 | IdentifierInfo *LII = LHS.castAsIdentifierInfo(); |
51 | IdentifierInfo *RII = RHS.castAsIdentifierInfo(); |
52 | if (!LII) |
53 | return RII ? -1 : 0; |
54 | if (!RII) |
55 | return 1; |
56 | |
57 | return LII->getName().compare(RHS: RII->getName()); |
58 | } |
59 | |
60 | case DeclarationName::ObjCZeroArgSelector: |
61 | case DeclarationName::ObjCOneArgSelector: |
62 | case DeclarationName::ObjCMultiArgSelector: { |
63 | Selector LHSSelector = LHS.getObjCSelector(); |
64 | Selector RHSSelector = RHS.getObjCSelector(); |
65 | // getNumArgs for ZeroArgSelector returns 0, but we still need to compare. |
66 | if (LHS.getNameKind() == DeclarationName::ObjCZeroArgSelector && |
67 | RHS.getNameKind() == DeclarationName::ObjCZeroArgSelector) { |
68 | return LHSSelector.getAsIdentifierInfo()->getName().compare( |
69 | RHS: RHSSelector.getAsIdentifierInfo()->getName()); |
70 | } |
71 | unsigned LN = LHSSelector.getNumArgs(), RN = RHSSelector.getNumArgs(); |
72 | for (unsigned I = 0, N = std::min(a: LN, b: RN); I != N; ++I) { |
73 | if (int Compare = LHSSelector.getNameForSlot(argIndex: I).compare( |
74 | RHS: RHSSelector.getNameForSlot(argIndex: I))) |
75 | return Compare; |
76 | } |
77 | |
78 | return compareInt(A: LN, B: RN); |
79 | } |
80 | |
81 | case DeclarationName::CXXConstructorName: |
82 | case DeclarationName::CXXDestructorName: |
83 | case DeclarationName::CXXConversionFunctionName: |
84 | if (QualTypeOrdering()(LHS.getCXXNameType(), RHS.getCXXNameType())) |
85 | return -1; |
86 | if (QualTypeOrdering()(RHS.getCXXNameType(), LHS.getCXXNameType())) |
87 | return 1; |
88 | return 0; |
89 | |
90 | case DeclarationName::CXXDeductionGuideName: |
91 | // We never want to compare deduction guide names for templates from |
92 | // different scopes, so just compare the template-name. |
93 | return compare(LHS: LHS.getCXXDeductionGuideTemplate()->getDeclName(), |
94 | RHS: RHS.getCXXDeductionGuideTemplate()->getDeclName()); |
95 | |
96 | case DeclarationName::CXXOperatorName: |
97 | return compareInt(A: LHS.getCXXOverloadedOperator(), |
98 | B: RHS.getCXXOverloadedOperator()); |
99 | |
100 | case DeclarationName::CXXLiteralOperatorName: |
101 | return LHS.getCXXLiteralIdentifier()->getName().compare( |
102 | RHS: RHS.getCXXLiteralIdentifier()->getName()); |
103 | |
104 | case DeclarationName::CXXUsingDirective: |
105 | return 0; |
106 | } |
107 | |
108 | llvm_unreachable("Invalid DeclarationName Kind!"); |
109 | } |
110 | |
111 | static void printCXXConstructorDestructorName(QualType ClassType, |
112 | raw_ostream &OS, |
113 | PrintingPolicy Policy) { |
114 | // We know we're printing C++ here. Ensure we print types properly. |
115 | Policy.adjustForCPlusPlus(); |
116 | |
117 | if (const RecordType *ClassRec = ClassType->getAs<RecordType>()) { |
118 | ClassRec->getDecl()->printName(OS, Policy); |
119 | return; |
120 | } |
121 | if (Policy.SuppressTemplateArgsInCXXConstructors) { |
122 | if (auto *InjTy = ClassType->getAs<InjectedClassNameType>()) { |
123 | InjTy->getDecl()->printName(OS, Policy); |
124 | return; |
125 | } |
126 | } |
127 | ClassType.print(OS, Policy); |
128 | } |
129 | |
130 | void DeclarationName::print(raw_ostream &OS, |
131 | const PrintingPolicy &Policy) const { |
132 | switch (getNameKind()) { |
133 | case DeclarationName::Identifier: |
134 | if (const IdentifierInfo *II = getAsIdentifierInfo()) { |
135 | StringRef Name = II->getName(); |
136 | // If this is a mangled OpenMP variant name we strip off the mangling for |
137 | // printing. It should not be visible to the user at all. |
138 | if (II->isMangledOpenMPVariantName()) { |
139 | std::pair<StringRef, StringRef> NameContextPair = |
140 | Name.split(Separator: getOpenMPVariantManglingSeparatorStr()); |
141 | OS << NameContextPair.first << "[" |
142 | << OMPTraitInfo(NameContextPair.second) << "]"; |
143 | } else { |
144 | OS << Name; |
145 | } |
146 | } |
147 | return; |
148 | |
149 | case DeclarationName::ObjCZeroArgSelector: |
150 | case DeclarationName::ObjCOneArgSelector: |
151 | case DeclarationName::ObjCMultiArgSelector: |
152 | getObjCSelector().print(OS); |
153 | return; |
154 | |
155 | case DeclarationName::CXXConstructorName: |
156 | return printCXXConstructorDestructorName(ClassType: getCXXNameType(), OS, Policy); |
157 | |
158 | case DeclarationName::CXXDestructorName: |
159 | OS << '~'; |
160 | return printCXXConstructorDestructorName(ClassType: getCXXNameType(), OS, Policy); |
161 | |
162 | case DeclarationName::CXXDeductionGuideName: |
163 | OS << "<deduction guide for "; |
164 | getCXXDeductionGuideTemplate()->getDeclName().print(OS, Policy); |
165 | OS << '>'; |
166 | return; |
167 | |
168 | case DeclarationName::CXXOperatorName: { |
169 | const char *OpName = getOperatorSpelling(Operator: getCXXOverloadedOperator()); |
170 | assert(OpName && "not an overloaded operator"); |
171 | |
172 | OS << "operator"; |
173 | if (OpName[0] >= 'a' && OpName[0] <= 'z') |
174 | OS << ' '; |
175 | OS << OpName; |
176 | return; |
177 | } |
178 | |
179 | case DeclarationName::CXXLiteralOperatorName: |
180 | OS << "operator\"\""<< getCXXLiteralIdentifier()->getName(); |
181 | return; |
182 | |
183 | case DeclarationName::CXXConversionFunctionName: { |
184 | OS << "operator "; |
185 | QualType Type = getCXXNameType(); |
186 | if (const RecordType *Rec = Type->getAs<RecordType>()) { |
187 | OS << *Rec->getDecl(); |
188 | return; |
189 | } |
190 | // We know we're printing C++ here, ensure we print 'bool' properly. |
191 | PrintingPolicy CXXPolicy = Policy; |
192 | CXXPolicy.adjustForCPlusPlus(); |
193 | Type.print(OS, Policy: CXXPolicy); |
194 | return; |
195 | } |
196 | case DeclarationName::CXXUsingDirective: |
197 | OS << "<using-directive>"; |
198 | return; |
199 | } |
200 | |
201 | llvm_unreachable("Unexpected declaration name kind"); |
202 | } |
203 | |
204 | namespace clang { |
205 | |
206 | raw_ostream &operator<<(raw_ostream &OS, DeclarationName N) { |
207 | LangOptions LO; |
208 | N.print(OS, Policy: PrintingPolicy(LO)); |
209 | return OS; |
210 | } |
211 | |
212 | } // namespace clang |
213 | |
214 | bool DeclarationName::isDependentName() const { |
215 | QualType T = getCXXNameType(); |
216 | if (!T.isNull() && T->isDependentType()) |
217 | return true; |
218 | |
219 | // A class-scope deduction guide in a dependent context has a dependent name. |
220 | auto *TD = getCXXDeductionGuideTemplate(); |
221 | if (TD && TD->getDeclContext()->isDependentContext()) |
222 | return true; |
223 | |
224 | return false; |
225 | } |
226 | |
227 | std::string DeclarationName::getAsString() const { |
228 | std::string Result; |
229 | llvm::raw_string_ostream OS(Result); |
230 | OS << *this; |
231 | return Result; |
232 | } |
233 | |
234 | void *DeclarationName::getFETokenInfoSlow() const { |
235 | switch (getNameKind()) { |
236 | case Identifier: |
237 | llvm_unreachable("case Identifier already handled by getFETokenInfo!"); |
238 | case CXXConstructorName: |
239 | case CXXDestructorName: |
240 | case CXXConversionFunctionName: |
241 | return castAsCXXSpecialNameExtra()->FETokenInfo; |
242 | case CXXOperatorName: |
243 | return castAsCXXOperatorIdName()->FETokenInfo; |
244 | case CXXDeductionGuideName: |
245 | return castAsCXXDeductionGuideNameExtra()->FETokenInfo; |
246 | case CXXLiteralOperatorName: |
247 | return castAsCXXLiteralOperatorIdName()->FETokenInfo; |
248 | default: |
249 | llvm_unreachable("DeclarationName has no FETokenInfo!"); |
250 | } |
251 | } |
252 | |
253 | void DeclarationName::setFETokenInfoSlow(void *T) { |
254 | switch (getNameKind()) { |
255 | case Identifier: |
256 | llvm_unreachable("case Identifier already handled by setFETokenInfo!"); |
257 | case CXXConstructorName: |
258 | case CXXDestructorName: |
259 | case CXXConversionFunctionName: |
260 | castAsCXXSpecialNameExtra()->FETokenInfo = T; |
261 | break; |
262 | case CXXOperatorName: |
263 | castAsCXXOperatorIdName()->FETokenInfo = T; |
264 | break; |
265 | case CXXDeductionGuideName: |
266 | castAsCXXDeductionGuideNameExtra()->FETokenInfo = T; |
267 | break; |
268 | case CXXLiteralOperatorName: |
269 | castAsCXXLiteralOperatorIdName()->FETokenInfo = T; |
270 | break; |
271 | default: |
272 | llvm_unreachable("DeclarationName has no FETokenInfo!"); |
273 | } |
274 | } |
275 | |
276 | LLVM_DUMP_METHOD void DeclarationName::dump() const { |
277 | llvm::errs() << *this << '\n'; |
278 | } |
279 | |
280 | DeclarationNameTable::DeclarationNameTable(const ASTContext &C) : Ctx(C) { |
281 | // Initialize the overloaded operator names. |
282 | for (unsigned Op = 0; Op < NUM_OVERLOADED_OPERATORS; ++Op) |
283 | CXXOperatorNames[Op].Kind = static_cast<OverloadedOperatorKind>(Op); |
284 | } |
285 | |
286 | DeclarationName |
287 | DeclarationNameTable::getCXXDeductionGuideName(TemplateDecl *Template) { |
288 | Template = cast<TemplateDecl>(Template->getCanonicalDecl()); |
289 | |
290 | llvm::FoldingSetNodeID ID; |
291 | ID.AddPointer(Ptr: Template); |
292 | |
293 | void *InsertPos = nullptr; |
294 | if (auto *Name = CXXDeductionGuideNames.FindNodeOrInsertPos(ID, InsertPos)) |
295 | return DeclarationName(Name); |
296 | |
297 | auto *Name = new (Ctx) detail::CXXDeductionGuideNameExtra(Template); |
298 | CXXDeductionGuideNames.InsertNode(N: Name, InsertPos); |
299 | return DeclarationName(Name); |
300 | } |
301 | |
302 | DeclarationName DeclarationNameTable::getCXXConstructorName(CanQualType Ty) { |
303 | // The type of constructors is unqualified. |
304 | Ty = Ty.getUnqualifiedType(); |
305 | // Do we already have this C++ constructor name ? |
306 | llvm::FoldingSetNodeID ID; |
307 | ID.AddPointer(Ptr: Ty.getAsOpaquePtr()); |
308 | void *InsertPos = nullptr; |
309 | if (auto *Name = CXXConstructorNames.FindNodeOrInsertPos(ID, InsertPos)) |
310 | return {Name, DeclarationName::StoredCXXConstructorName}; |
311 | |
312 | // We have to create it. |
313 | auto *SpecialName = new (Ctx) detail::CXXSpecialNameExtra(Ty); |
314 | CXXConstructorNames.InsertNode(N: SpecialName, InsertPos); |
315 | return {SpecialName, DeclarationName::StoredCXXConstructorName}; |
316 | } |
317 | |
318 | DeclarationName DeclarationNameTable::getCXXDestructorName(CanQualType Ty) { |
319 | // The type of destructors is unqualified. |
320 | Ty = Ty.getUnqualifiedType(); |
321 | // Do we already have this C++ destructor name ? |
322 | llvm::FoldingSetNodeID ID; |
323 | ID.AddPointer(Ptr: Ty.getAsOpaquePtr()); |
324 | void *InsertPos = nullptr; |
325 | if (auto *Name = CXXDestructorNames.FindNodeOrInsertPos(ID, InsertPos)) |
326 | return {Name, DeclarationName::StoredCXXDestructorName}; |
327 | |
328 | // We have to create it. |
329 | auto *SpecialName = new (Ctx) detail::CXXSpecialNameExtra(Ty); |
330 | CXXDestructorNames.InsertNode(N: SpecialName, InsertPos); |
331 | return {SpecialName, DeclarationName::StoredCXXDestructorName}; |
332 | } |
333 | |
334 | DeclarationName |
335 | DeclarationNameTable::getCXXConversionFunctionName(CanQualType Ty) { |
336 | // Do we already have this C++ conversion function name ? |
337 | llvm::FoldingSetNodeID ID; |
338 | ID.AddPointer(Ptr: Ty.getAsOpaquePtr()); |
339 | void *InsertPos = nullptr; |
340 | if (auto *Name = |
341 | CXXConversionFunctionNames.FindNodeOrInsertPos(ID, InsertPos)) |
342 | return {Name, DeclarationName::StoredCXXConversionFunctionName}; |
343 | |
344 | // We have to create it. |
345 | auto *SpecialName = new (Ctx) detail::CXXSpecialNameExtra(Ty); |
346 | CXXConversionFunctionNames.InsertNode(N: SpecialName, InsertPos); |
347 | return {SpecialName, DeclarationName::StoredCXXConversionFunctionName}; |
348 | } |
349 | |
350 | DeclarationName |
351 | DeclarationNameTable::getCXXSpecialName(DeclarationName::NameKind Kind, |
352 | CanQualType Ty) { |
353 | switch (Kind) { |
354 | case DeclarationName::CXXConstructorName: |
355 | return getCXXConstructorName(Ty); |
356 | case DeclarationName::CXXDestructorName: |
357 | return getCXXDestructorName(Ty); |
358 | case DeclarationName::CXXConversionFunctionName: |
359 | return getCXXConversionFunctionName(Ty); |
360 | default: |
361 | llvm_unreachable("Invalid kind in getCXXSpecialName!"); |
362 | } |
363 | } |
364 | |
365 | DeclarationName |
366 | DeclarationNameTable::getCXXLiteralOperatorName(const IdentifierInfo *II) { |
367 | llvm::FoldingSetNodeID ID; |
368 | ID.AddPointer(Ptr: II); |
369 | |
370 | void *InsertPos = nullptr; |
371 | if (auto *Name = CXXLiteralOperatorNames.FindNodeOrInsertPos(ID, InsertPos)) |
372 | return DeclarationName(Name); |
373 | |
374 | auto *LiteralName = new (Ctx) detail::CXXLiteralOperatorIdName(II); |
375 | CXXLiteralOperatorNames.InsertNode(N: LiteralName, InsertPos); |
376 | return DeclarationName(LiteralName); |
377 | } |
378 | |
379 | DeclarationNameLoc::DeclarationNameLoc(DeclarationName Name) { |
380 | switch (Name.getNameKind()) { |
381 | case DeclarationName::Identifier: |
382 | case DeclarationName::CXXDeductionGuideName: |
383 | break; |
384 | case DeclarationName::CXXConstructorName: |
385 | case DeclarationName::CXXDestructorName: |
386 | case DeclarationName::CXXConversionFunctionName: |
387 | setNamedTypeLoc(nullptr); |
388 | break; |
389 | case DeclarationName::CXXOperatorName: |
390 | setCXXOperatorNameRange(SourceRange()); |
391 | break; |
392 | case DeclarationName::CXXLiteralOperatorName: |
393 | setCXXLiteralOperatorNameLoc(SourceLocation()); |
394 | break; |
395 | case DeclarationName::ObjCZeroArgSelector: |
396 | case DeclarationName::ObjCOneArgSelector: |
397 | case DeclarationName::ObjCMultiArgSelector: |
398 | // FIXME: ? |
399 | break; |
400 | case DeclarationName::CXXUsingDirective: |
401 | break; |
402 | } |
403 | } |
404 | |
405 | bool DeclarationNameInfo::containsUnexpandedParameterPack() const { |
406 | switch (Name.getNameKind()) { |
407 | case DeclarationName::Identifier: |
408 | case DeclarationName::ObjCZeroArgSelector: |
409 | case DeclarationName::ObjCOneArgSelector: |
410 | case DeclarationName::ObjCMultiArgSelector: |
411 | case DeclarationName::CXXOperatorName: |
412 | case DeclarationName::CXXLiteralOperatorName: |
413 | case DeclarationName::CXXUsingDirective: |
414 | case DeclarationName::CXXDeductionGuideName: |
415 | return false; |
416 | |
417 | case DeclarationName::CXXConstructorName: |
418 | case DeclarationName::CXXDestructorName: |
419 | case DeclarationName::CXXConversionFunctionName: |
420 | if (TypeSourceInfo *TInfo = LocInfo.getNamedTypeInfo()) |
421 | return TInfo->getType()->containsUnexpandedParameterPack(); |
422 | |
423 | return Name.getCXXNameType()->containsUnexpandedParameterPack(); |
424 | } |
425 | llvm_unreachable("All name kinds handled."); |
426 | } |
427 | |
428 | bool DeclarationNameInfo::isInstantiationDependent() const { |
429 | switch (Name.getNameKind()) { |
430 | case DeclarationName::Identifier: |
431 | case DeclarationName::ObjCZeroArgSelector: |
432 | case DeclarationName::ObjCOneArgSelector: |
433 | case DeclarationName::ObjCMultiArgSelector: |
434 | case DeclarationName::CXXOperatorName: |
435 | case DeclarationName::CXXLiteralOperatorName: |
436 | case DeclarationName::CXXUsingDirective: |
437 | case DeclarationName::CXXDeductionGuideName: |
438 | return false; |
439 | |
440 | case DeclarationName::CXXConstructorName: |
441 | case DeclarationName::CXXDestructorName: |
442 | case DeclarationName::CXXConversionFunctionName: |
443 | if (TypeSourceInfo *TInfo = LocInfo.getNamedTypeInfo()) |
444 | return TInfo->getType()->isInstantiationDependentType(); |
445 | |
446 | return Name.getCXXNameType()->isInstantiationDependentType(); |
447 | } |
448 | llvm_unreachable("All name kinds handled."); |
449 | } |
450 | |
451 | std::string DeclarationNameInfo::getAsString() const { |
452 | std::string Result; |
453 | llvm::raw_string_ostream OS(Result); |
454 | OS << *this; |
455 | return Result; |
456 | } |
457 | |
458 | raw_ostream &clang::operator<<(raw_ostream &OS, DeclarationNameInfo DNInfo) { |
459 | LangOptions LO; |
460 | DNInfo.printName(OS, Policy: PrintingPolicy(LangOptions())); |
461 | return OS; |
462 | } |
463 | |
464 | void DeclarationNameInfo::printName(raw_ostream &OS, PrintingPolicy Policy) const { |
465 | switch (Name.getNameKind()) { |
466 | case DeclarationName::Identifier: |
467 | case DeclarationName::ObjCZeroArgSelector: |
468 | case DeclarationName::ObjCOneArgSelector: |
469 | case DeclarationName::ObjCMultiArgSelector: |
470 | case DeclarationName::CXXOperatorName: |
471 | case DeclarationName::CXXLiteralOperatorName: |
472 | case DeclarationName::CXXUsingDirective: |
473 | case DeclarationName::CXXDeductionGuideName: |
474 | Name.print(OS, Policy); |
475 | return; |
476 | |
477 | case DeclarationName::CXXConstructorName: |
478 | case DeclarationName::CXXDestructorName: |
479 | case DeclarationName::CXXConversionFunctionName: |
480 | if (TypeSourceInfo *TInfo = LocInfo.getNamedTypeInfo()) { |
481 | if (Name.getNameKind() == DeclarationName::CXXDestructorName) |
482 | OS << '~'; |
483 | else if (Name.getNameKind() == DeclarationName::CXXConversionFunctionName) |
484 | OS << "operator "; |
485 | LangOptions LO; |
486 | Policy.adjustForCPlusPlus(); |
487 | Policy.SuppressScope = true; |
488 | OS << TInfo->getType().getAsString(Policy); |
489 | } else |
490 | Name.print(OS, Policy); |
491 | return; |
492 | } |
493 | llvm_unreachable("Unexpected declaration name kind"); |
494 | } |
495 | |
496 | SourceLocation DeclarationNameInfo::getEndLocPrivate() const { |
497 | switch (Name.getNameKind()) { |
498 | case DeclarationName::Identifier: |
499 | case DeclarationName::CXXDeductionGuideName: |
500 | return NameLoc; |
501 | |
502 | case DeclarationName::CXXOperatorName: |
503 | return LocInfo.getCXXOperatorNameEndLoc(); |
504 | |
505 | case DeclarationName::CXXLiteralOperatorName: |
506 | return LocInfo.getCXXLiteralOperatorNameLoc(); |
507 | |
508 | case DeclarationName::CXXConstructorName: |
509 | case DeclarationName::CXXDestructorName: |
510 | case DeclarationName::CXXConversionFunctionName: |
511 | if (TypeSourceInfo *TInfo = LocInfo.getNamedTypeInfo()) |
512 | return TInfo->getTypeLoc().getEndLoc(); |
513 | else |
514 | return NameLoc; |
515 | |
516 | // DNInfo work in progress: FIXME. |
517 | case DeclarationName::ObjCZeroArgSelector: |
518 | case DeclarationName::ObjCOneArgSelector: |
519 | case DeclarationName::ObjCMultiArgSelector: |
520 | case DeclarationName::CXXUsingDirective: |
521 | return NameLoc; |
522 | } |
523 | llvm_unreachable("Unexpected declaration name kind"); |
524 | } |
525 |
Definitions
- compareInt
- compare
- printCXXConstructorDestructorName
- operator<<
- isDependentName
- getAsString
- getFETokenInfoSlow
- setFETokenInfoSlow
- dump
- DeclarationNameTable
- getCXXDeductionGuideName
- getCXXConstructorName
- getCXXDestructorName
- getCXXConversionFunctionName
- getCXXSpecialName
- getCXXLiteralOperatorName
- DeclarationNameLoc
- containsUnexpandedParameterPack
- isInstantiationDependent
- getAsString
- operator<<
- printName
Improve your Profiling and Debugging skills
Find out more