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
38using namespace clang;
39
40static int compareInt(unsigned A, unsigned B) {
41 return (A < B ? -1 : (A > B ? 1 : 0));
42}
43
44int 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
111static 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
130void 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
204namespace clang {
205
206raw_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
214bool 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
227std::string DeclarationName::getAsString() const {
228 std::string Result;
229 llvm::raw_string_ostream OS(Result);
230 OS << *this;
231 return Result;
232}
233
234void *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
253void 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
276LLVM_DUMP_METHOD void DeclarationName::dump() const {
277 llvm::errs() << *this << '\n';
278}
279
280DeclarationNameTable::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
286DeclarationName
287DeclarationNameTable::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
302DeclarationName 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
318DeclarationName 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
334DeclarationName
335DeclarationNameTable::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
350DeclarationName
351DeclarationNameTable::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
365DeclarationName
366DeclarationNameTable::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
379DeclarationNameLoc::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
405bool 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
428bool 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
451std::string DeclarationNameInfo::getAsString() const {
452 std::string Result;
453 llvm::raw_string_ostream OS(Result);
454 OS << *this;
455 return Result;
456}
457
458raw_ostream &clang::operator<<(raw_ostream &OS, DeclarationNameInfo DNInfo) {
459 LangOptions LO;
460 DNInfo.printName(OS, Policy: PrintingPolicy(LangOptions()));
461 return OS;
462}
463
464void 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
496SourceLocation 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

Provided by KDAB

Privacy Policy
Improve your Profiling and Debugging skills
Find out more

source code of clang/lib/AST/DeclarationName.cpp