blob: a17abde7773033cdfeb49f5d00d33f3ca62ff4d2 [file] [log] [blame]
Douglas Gregor2e1cd422008-11-17 14:58:09 +00001//===-- DeclarationName.cpp - Declaration names implementation --*- C++ -*-===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
10// This file implements the DeclarationName and DeclarationNameTable
11// classes.
12//
13//===----------------------------------------------------------------------===//
14#include "clang/AST/DeclarationName.h"
Douglas Gregor10bd3682008-11-17 22:58:34 +000015#include "clang/AST/Type.h"
16#include "clang/AST/Decl.h"
Douglas Gregor2e1cd422008-11-17 14:58:09 +000017#include "clang/Basic/IdentifierTable.h"
Douglas Gregor370187c2009-04-22 21:45:53 +000018#include "llvm/ADT/DenseMap.h"
Douglas Gregor2e1cd422008-11-17 14:58:09 +000019#include "llvm/ADT/FoldingSet.h"
Douglas Gregor2e1cd422008-11-17 14:58:09 +000020using namespace clang;
21
22namespace clang {
23/// CXXSpecialName - Records the type associated with one of the
24/// "special" kinds of declaration names in C++, e.g., constructors,
25/// destructors, and conversion functions.
26class CXXSpecialName
27 : public DeclarationNameExtra, public llvm::FoldingSetNode {
28public:
Douglas Gregor2def4832008-11-17 20:34:05 +000029 /// Type - The type associated with this declaration name.
Douglas Gregor2e1cd422008-11-17 14:58:09 +000030 QualType Type;
31
Douglas Gregor2def4832008-11-17 20:34:05 +000032 /// FETokenInfo - Extra information associated with this declaration
33 /// name that can be used by the front end.
34 void *FETokenInfo;
35
Douglas Gregor2e1cd422008-11-17 14:58:09 +000036 void Profile(llvm::FoldingSetNodeID &ID) {
37 ID.AddInteger(ExtraKindOrNumArgs);
38 ID.AddPointer(Type.getAsOpaquePtr());
39 }
40};
41
Douglas Gregore94ca9e42008-11-18 14:39:36 +000042/// CXXOperatorIdName - Contains extra information for the name of an
43/// overloaded operator in C++, such as "operator+.
44class CXXOperatorIdName : public DeclarationNameExtra {
45public:
46 /// FETokenInfo - Extra information associated with this operator
47 /// name that can be used by the front end.
48 void *FETokenInfo;
49};
50
Douglas Gregor2e1cd422008-11-17 14:58:09 +000051bool operator<(DeclarationName LHS, DeclarationName RHS) {
52 if (IdentifierInfo *LhsId = LHS.getAsIdentifierInfo())
53 if (IdentifierInfo *RhsId = RHS.getAsIdentifierInfo())
54 return strcmp(LhsId->getName(), RhsId->getName()) < 0;
55
56 return LHS.getAsOpaqueInteger() < RHS.getAsOpaqueInteger();
57}
58
59} // end namespace clang
60
61DeclarationName::DeclarationName(Selector Sel) {
Douglas Gregor319ac892009-04-23 22:29:11 +000062 if (!Sel.getAsOpaquePtr()) {
63 Ptr = StoredObjCZeroArgSelector;
64 return;
65 }
66
Douglas Gregor2e1cd422008-11-17 14:58:09 +000067 switch (Sel.getNumArgs()) {
68 case 0:
69 Ptr = reinterpret_cast<uintptr_t>(Sel.getAsIdentifierInfo());
Ted Kremenek3eb8dd72009-03-14 00:27:40 +000070 assert((Ptr & PtrMask) == 0 && "Improperly aligned IdentifierInfo");
Douglas Gregor2e1cd422008-11-17 14:58:09 +000071 Ptr |= StoredObjCZeroArgSelector;
72 break;
73
74 case 1:
75 Ptr = reinterpret_cast<uintptr_t>(Sel.getAsIdentifierInfo());
Ted Kremenek3eb8dd72009-03-14 00:27:40 +000076 assert((Ptr & PtrMask) == 0 && "Improperly aligned IdentifierInfo");
Douglas Gregor2e1cd422008-11-17 14:58:09 +000077 Ptr |= StoredObjCOneArgSelector;
78 break;
79
80 default:
81 Ptr = Sel.InfoPtr & ~Selector::ArgFlags;
Ted Kremenek3eb8dd72009-03-14 00:27:40 +000082 assert((Ptr & PtrMask) == 0 && "Improperly aligned MultiKeywordSelector");
Douglas Gregore94ca9e42008-11-18 14:39:36 +000083 Ptr |= StoredDeclarationNameExtra;
Douglas Gregor2e1cd422008-11-17 14:58:09 +000084 break;
85 }
86}
87
88DeclarationName::NameKind DeclarationName::getNameKind() const {
89 switch (getStoredNameKind()) {
90 case StoredIdentifier: return Identifier;
91 case StoredObjCZeroArgSelector: return ObjCZeroArgSelector;
92 case StoredObjCOneArgSelector: return ObjCOneArgSelector;
93
Douglas Gregore94ca9e42008-11-18 14:39:36 +000094 case StoredDeclarationNameExtra:
Douglas Gregor2e1cd422008-11-17 14:58:09 +000095 switch (getExtra()->ExtraKindOrNumArgs) {
96 case DeclarationNameExtra::CXXConstructor:
97 return CXXConstructorName;
98
99 case DeclarationNameExtra::CXXDestructor:
100 return CXXDestructorName;
101
102 case DeclarationNameExtra::CXXConversionFunction:
103 return CXXConversionFunctionName;
104
Douglas Gregor2a3009a2009-02-03 19:21:40 +0000105 case DeclarationNameExtra::CXXUsingDirective:
106 return CXXUsingDirective;
107
Douglas Gregor2e1cd422008-11-17 14:58:09 +0000108 default:
Douglas Gregore94ca9e42008-11-18 14:39:36 +0000109 // Check if we have one of the CXXOperator* enumeration values.
110 if (getExtra()->ExtraKindOrNumArgs <
Douglas Gregor2a3009a2009-02-03 19:21:40 +0000111 DeclarationNameExtra::CXXUsingDirective)
Douglas Gregore94ca9e42008-11-18 14:39:36 +0000112 return CXXOperatorName;
113
Douglas Gregor2e1cd422008-11-17 14:58:09 +0000114 return ObjCMultiArgSelector;
115 }
116 break;
117 }
118
119 // Can't actually get here.
Chris Lattnerac8d75f2009-03-21 06:40:50 +0000120 assert(0 && "This should be unreachable!");
Douglas Gregor2e1cd422008-11-17 14:58:09 +0000121 return Identifier;
122}
123
Douglas Gregor10bd3682008-11-17 22:58:34 +0000124std::string DeclarationName::getAsString() const {
125 switch (getNameKind()) {
126 case Identifier:
127 if (const IdentifierInfo *II = getAsIdentifierInfo())
128 return II->getName();
129 return "";
130
131 case ObjCZeroArgSelector:
132 case ObjCOneArgSelector:
133 case ObjCMultiArgSelector:
Chris Lattner077bf5e2008-11-24 03:33:13 +0000134 return getObjCSelector().getAsString();
Douglas Gregor10bd3682008-11-17 22:58:34 +0000135
136 case CXXConstructorName: {
137 QualType ClassType = getCXXNameType();
138 if (const RecordType *ClassRec = ClassType->getAsRecordType())
Chris Lattner39f34e92008-11-24 04:00:27 +0000139 return ClassRec->getDecl()->getNameAsString();
Douglas Gregor10bd3682008-11-17 22:58:34 +0000140 return ClassType.getAsString();
141 }
142
143 case CXXDestructorName: {
144 std::string Result = "~";
145 QualType Type = getCXXNameType();
146 if (const RecordType *Rec = Type->getAsRecordType())
Chris Lattner39f34e92008-11-24 04:00:27 +0000147 Result += Rec->getDecl()->getNameAsString();
Douglas Gregor10bd3682008-11-17 22:58:34 +0000148 else
149 Result += Type.getAsString();
150 return Result;
151 }
152
Douglas Gregore94ca9e42008-11-18 14:39:36 +0000153 case CXXOperatorName: {
154 static const char *OperatorNames[NUM_OVERLOADED_OPERATORS] = {
155 0,
156#define OVERLOADED_OPERATOR(Name,Spelling,Token,Unary,Binary,MemberOnly) \
157 Spelling,
158#include "clang/Basic/OperatorKinds.def"
159 };
160 const char *OpName = OperatorNames[getCXXOverloadedOperator()];
161 assert(OpName && "not an overloaded operator");
162
163 std::string Result = "operator";
164 if (OpName[0] >= 'a' && OpName[0] <= 'z')
165 Result += ' ';
166 Result += OpName;
167 return Result;
168 }
169
Douglas Gregor10bd3682008-11-17 22:58:34 +0000170 case CXXConversionFunctionName: {
171 std::string Result = "operator ";
172 QualType Type = getCXXNameType();
173 if (const RecordType *Rec = Type->getAsRecordType())
Chris Lattner39f34e92008-11-24 04:00:27 +0000174 Result += Rec->getDecl()->getNameAsString();
Douglas Gregor10bd3682008-11-17 22:58:34 +0000175 else
176 Result += Type.getAsString();
177 return Result;
178 }
Douglas Gregor2a3009a2009-02-03 19:21:40 +0000179 case CXXUsingDirective:
180 return "<using-directive>";
Douglas Gregor10bd3682008-11-17 22:58:34 +0000181 }
182
183 assert(false && "Unexpected declaration name kind");
184 return "";
185}
186
Douglas Gregor2e1cd422008-11-17 14:58:09 +0000187QualType DeclarationName::getCXXNameType() const {
188 if (CXXSpecialName *CXXName = getAsCXXSpecialName())
189 return CXXName->Type;
190 else
191 return QualType();
192}
193
Douglas Gregore94ca9e42008-11-18 14:39:36 +0000194OverloadedOperatorKind DeclarationName::getCXXOverloadedOperator() const {
195 if (CXXOperatorIdName *CXXOp = getAsCXXOperatorIdName()) {
196 unsigned value
197 = CXXOp->ExtraKindOrNumArgs - DeclarationNameExtra::CXXConversionFunction;
198 return static_cast<OverloadedOperatorKind>(value);
199 } else {
200 return OO_None;
201 }
202}
203
Douglas Gregor2e1cd422008-11-17 14:58:09 +0000204Selector DeclarationName::getObjCSelector() const {
205 switch (getNameKind()) {
206 case ObjCZeroArgSelector:
207 return Selector(reinterpret_cast<IdentifierInfo *>(Ptr & ~PtrMask), 0);
208
209 case ObjCOneArgSelector:
210 return Selector(reinterpret_cast<IdentifierInfo *>(Ptr & ~PtrMask), 1);
211
212 case ObjCMultiArgSelector:
213 return Selector(reinterpret_cast<MultiKeywordSelector *>(Ptr & ~PtrMask));
214
215 default:
216 break;
217 }
218
219 return Selector();
220}
221
Douglas Gregor2def4832008-11-17 20:34:05 +0000222void *DeclarationName::getFETokenInfoAsVoid() const {
223 switch (getNameKind()) {
224 case Identifier:
225 return getAsIdentifierInfo()->getFETokenInfo<void>();
226
227 case CXXConstructorName:
228 case CXXDestructorName:
229 case CXXConversionFunctionName:
230 return getAsCXXSpecialName()->FETokenInfo;
231
Douglas Gregore94ca9e42008-11-18 14:39:36 +0000232 case CXXOperatorName:
233 return getAsCXXOperatorIdName()->FETokenInfo;
234
Douglas Gregor2def4832008-11-17 20:34:05 +0000235 default:
236 assert(false && "Declaration name has no FETokenInfo");
237 }
238 return 0;
239}
240
241void DeclarationName::setFETokenInfo(void *T) {
242 switch (getNameKind()) {
243 case Identifier:
244 getAsIdentifierInfo()->setFETokenInfo(T);
245 break;
246
247 case CXXConstructorName:
248 case CXXDestructorName:
249 case CXXConversionFunctionName:
250 getAsCXXSpecialName()->FETokenInfo = T;
251 break;
252
Douglas Gregore94ca9e42008-11-18 14:39:36 +0000253 case CXXOperatorName:
254 getAsCXXOperatorIdName()->FETokenInfo = T;
255 break;
256
Douglas Gregor2def4832008-11-17 20:34:05 +0000257 default:
258 assert(false && "Declaration name has no FETokenInfo");
259 }
260}
261
Douglas Gregor2a3009a2009-02-03 19:21:40 +0000262DeclarationName DeclarationName::getUsingDirectiveName() {
263 // Single instance of DeclarationNameExtra for using-directive
264 static DeclarationNameExtra UDirExtra =
265 { DeclarationNameExtra::CXXUsingDirective };
266
267 uintptr_t Ptr = reinterpret_cast<uintptr_t>(&UDirExtra);
268 Ptr |= StoredDeclarationNameExtra;
269
270 return DeclarationName(Ptr);
271}
272
Douglas Gregor2e1cd422008-11-17 14:58:09 +0000273DeclarationNameTable::DeclarationNameTable() {
274 CXXSpecialNamesImpl = new llvm::FoldingSet<CXXSpecialName>;
Douglas Gregore94ca9e42008-11-18 14:39:36 +0000275
276 // Initialize the overloaded operator names.
277 CXXOperatorNames = new CXXOperatorIdName[NUM_OVERLOADED_OPERATORS];
278 for (unsigned Op = 0; Op < NUM_OVERLOADED_OPERATORS; ++Op) {
279 CXXOperatorNames[Op].ExtraKindOrNumArgs
280 = Op + DeclarationNameExtra::CXXConversionFunction;
281 CXXOperatorNames[Op].FETokenInfo = 0;
282 }
Douglas Gregor2e1cd422008-11-17 14:58:09 +0000283}
284
285DeclarationNameTable::~DeclarationNameTable() {
Nuno Lopes6d34ae52008-12-14 17:27:25 +0000286 llvm::FoldingSet<CXXSpecialName> *set =
287 static_cast<llvm::FoldingSet<CXXSpecialName>*>(CXXSpecialNamesImpl);
Nuno Lopesf9d1e4b2008-12-14 21:53:25 +0000288 llvm::FoldingSetIterator<CXXSpecialName> I = set->begin(), E = set->end();
Nuno Lopes6d34ae52008-12-14 17:27:25 +0000289
Nuno Lopesf9d1e4b2008-12-14 21:53:25 +0000290 while (I != E) {
291 CXXSpecialName *n = &*I++;
292 delete n;
Nuno Lopes6d34ae52008-12-14 17:27:25 +0000293 }
294
295 delete set;
Douglas Gregore94ca9e42008-11-18 14:39:36 +0000296 delete [] CXXOperatorNames;
Douglas Gregor2e1cd422008-11-17 14:58:09 +0000297}
298
299DeclarationName
300DeclarationNameTable::getCXXSpecialName(DeclarationName::NameKind Kind,
301 QualType Ty) {
302 assert(Kind >= DeclarationName::CXXConstructorName &&
303 Kind <= DeclarationName::CXXConversionFunctionName &&
304 "Kind must be a C++ special name kind");
Douglas Gregor49f25ec2009-05-15 21:18:27 +0000305 assert(Ty->isCanonical() &&
306 "Can only build C++ special names from canonical types");
Douglas Gregor2e1cd422008-11-17 14:58:09 +0000307 llvm::FoldingSet<CXXSpecialName> *SpecialNames
308 = static_cast<llvm::FoldingSet<CXXSpecialName>*>(CXXSpecialNamesImpl);
309
310 DeclarationNameExtra::ExtraKind EKind;
311 switch (Kind) {
312 case DeclarationName::CXXConstructorName:
313 EKind = DeclarationNameExtra::CXXConstructor;
Chris Lattnerd603eaa2009-02-16 22:33:34 +0000314 assert(Ty.getCVRQualifiers() == 0 &&"Constructor type must be unqualified");
Douglas Gregor2e1cd422008-11-17 14:58:09 +0000315 break;
316 case DeclarationName::CXXDestructorName:
317 EKind = DeclarationNameExtra::CXXDestructor;
Douglas Gregore63ef482009-01-13 00:11:19 +0000318 assert(Ty.getCVRQualifiers() == 0 && "Destructor type must be unqualified");
Douglas Gregor2e1cd422008-11-17 14:58:09 +0000319 break;
320 case DeclarationName::CXXConversionFunctionName:
321 EKind = DeclarationNameExtra::CXXConversionFunction;
322 break;
323 default:
324 return DeclarationName();
325 }
326
327 // Unique selector, to guarantee there is one per name.
328 llvm::FoldingSetNodeID ID;
329 ID.AddInteger(EKind);
330 ID.AddPointer(Ty.getAsOpaquePtr());
331
332 void *InsertPos = 0;
333 if (CXXSpecialName *Name = SpecialNames->FindNodeOrInsertPos(ID, InsertPos))
334 return DeclarationName(Name);
335
336 CXXSpecialName *SpecialName = new CXXSpecialName;
337 SpecialName->ExtraKindOrNumArgs = EKind;
338 SpecialName->Type = Ty;
Douglas Gregor2def4832008-11-17 20:34:05 +0000339 SpecialName->FETokenInfo = 0;
Douglas Gregor2e1cd422008-11-17 14:58:09 +0000340
341 SpecialNames->InsertNode(SpecialName, InsertPos);
342 return DeclarationName(SpecialName);
343}
344
Douglas Gregore94ca9e42008-11-18 14:39:36 +0000345DeclarationName
346DeclarationNameTable::getCXXOperatorName(OverloadedOperatorKind Op) {
347 return DeclarationName(&CXXOperatorNames[(unsigned)Op]);
348}
349
Douglas Gregor44b43212008-12-11 16:49:14 +0000350unsigned
351llvm::DenseMapInfo<clang::DeclarationName>::
352getHashValue(clang::DeclarationName N) {
353 return DenseMapInfo<void*>::getHashValue(N.getAsOpaquePtr());
354}
355