1 | //===- NestedNameSpecifier.cpp - C++ nested name specifiers ---------------===// |
---|---|
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 defines the NestedNameSpecifier class, which represents |
10 | // a C++ nested-name-specifier. |
11 | // |
12 | //===----------------------------------------------------------------------===// |
13 | |
14 | #include "clang/AST/NestedNameSpecifier.h" |
15 | #include "clang/AST/ASTContext.h" |
16 | #include "clang/AST/Decl.h" |
17 | #include "clang/AST/DeclCXX.h" |
18 | #include "clang/AST/DeclTemplate.h" |
19 | #include "clang/AST/DependenceFlags.h" |
20 | #include "clang/AST/PrettyPrinter.h" |
21 | #include "clang/AST/TemplateName.h" |
22 | #include "clang/AST/Type.h" |
23 | #include "clang/AST/TypeLoc.h" |
24 | #include "clang/Basic/LLVM.h" |
25 | #include "clang/Basic/LangOptions.h" |
26 | #include "clang/Basic/SourceLocation.h" |
27 | #include "llvm/ADT/FoldingSet.h" |
28 | #include "llvm/Support/Compiler.h" |
29 | #include "llvm/Support/ErrorHandling.h" |
30 | #include "llvm/Support/raw_ostream.h" |
31 | #include <algorithm> |
32 | #include <cassert> |
33 | #include <cstdlib> |
34 | #include <cstring> |
35 | |
36 | using namespace clang; |
37 | |
38 | NestedNameSpecifier * |
39 | NestedNameSpecifier::FindOrInsert(const ASTContext &Context, |
40 | const NestedNameSpecifier &Mockup) { |
41 | llvm::FoldingSetNodeID ID; |
42 | Mockup.Profile(ID); |
43 | |
44 | void *InsertPos = nullptr; |
45 | NestedNameSpecifier *NNS |
46 | = Context.NestedNameSpecifiers.FindNodeOrInsertPos(ID, InsertPos); |
47 | if (!NNS) { |
48 | NNS = |
49 | new (Context, alignof(NestedNameSpecifier)) NestedNameSpecifier(Mockup); |
50 | Context.NestedNameSpecifiers.InsertNode(N: NNS, InsertPos); |
51 | } |
52 | |
53 | return NNS; |
54 | } |
55 | |
56 | NestedNameSpecifier *NestedNameSpecifier::Create(const ASTContext &Context, |
57 | NestedNameSpecifier *Prefix, |
58 | const IdentifierInfo *II) { |
59 | assert(II && "Identifier cannot be NULL"); |
60 | assert((!Prefix || Prefix->isDependent()) && "Prefix must be dependent"); |
61 | |
62 | NestedNameSpecifier Mockup; |
63 | Mockup.Prefix.setPointer(Prefix); |
64 | Mockup.Prefix.setInt(StoredIdentifier); |
65 | Mockup.Specifier = const_cast<IdentifierInfo *>(II); |
66 | return FindOrInsert(Context, Mockup); |
67 | } |
68 | |
69 | NestedNameSpecifier * |
70 | NestedNameSpecifier::Create(const ASTContext &Context, |
71 | NestedNameSpecifier *Prefix, |
72 | const NamespaceDecl *NS) { |
73 | assert(NS && "Namespace cannot be NULL"); |
74 | assert((!Prefix || |
75 | (Prefix->getAsType() == nullptr && |
76 | Prefix->getAsIdentifier() == nullptr)) && |
77 | "Broken nested name specifier"); |
78 | NestedNameSpecifier Mockup; |
79 | Mockup.Prefix.setPointer(Prefix); |
80 | Mockup.Prefix.setInt(StoredDecl); |
81 | Mockup.Specifier = const_cast<NamespaceDecl *>(NS); |
82 | return FindOrInsert(Context, Mockup); |
83 | } |
84 | |
85 | NestedNameSpecifier * |
86 | NestedNameSpecifier::Create(const ASTContext &Context, |
87 | NestedNameSpecifier *Prefix, |
88 | const NamespaceAliasDecl *Alias) { |
89 | assert(Alias && "Namespace alias cannot be NULL"); |
90 | assert((!Prefix || |
91 | (Prefix->getAsType() == nullptr && |
92 | Prefix->getAsIdentifier() == nullptr)) && |
93 | "Broken nested name specifier"); |
94 | NestedNameSpecifier Mockup; |
95 | Mockup.Prefix.setPointer(Prefix); |
96 | Mockup.Prefix.setInt(StoredDecl); |
97 | Mockup.Specifier = const_cast<NamespaceAliasDecl *>(Alias); |
98 | return FindOrInsert(Context, Mockup); |
99 | } |
100 | |
101 | NestedNameSpecifier *NestedNameSpecifier::Create(const ASTContext &Context, |
102 | NestedNameSpecifier *Prefix, |
103 | const Type *T) { |
104 | assert(T && "Type cannot be NULL"); |
105 | NestedNameSpecifier Mockup; |
106 | Mockup.Prefix.setPointer(Prefix); |
107 | Mockup.Prefix.setInt(StoredTypeSpec); |
108 | Mockup.Specifier = const_cast<Type*>(T); |
109 | return FindOrInsert(Context, Mockup); |
110 | } |
111 | |
112 | NestedNameSpecifier *NestedNameSpecifier::Create(const ASTContext &Context, |
113 | const IdentifierInfo *II) { |
114 | assert(II && "Identifier cannot be NULL"); |
115 | NestedNameSpecifier Mockup; |
116 | Mockup.Prefix.setPointer(nullptr); |
117 | Mockup.Prefix.setInt(StoredIdentifier); |
118 | Mockup.Specifier = const_cast<IdentifierInfo *>(II); |
119 | return FindOrInsert(Context, Mockup); |
120 | } |
121 | |
122 | NestedNameSpecifier * |
123 | NestedNameSpecifier::GlobalSpecifier(const ASTContext &Context) { |
124 | if (!Context.GlobalNestedNameSpecifier) |
125 | Context.GlobalNestedNameSpecifier = |
126 | new (Context, alignof(NestedNameSpecifier)) NestedNameSpecifier(); |
127 | return Context.GlobalNestedNameSpecifier; |
128 | } |
129 | |
130 | NestedNameSpecifier * |
131 | NestedNameSpecifier::SuperSpecifier(const ASTContext &Context, |
132 | CXXRecordDecl *RD) { |
133 | NestedNameSpecifier Mockup; |
134 | Mockup.Prefix.setPointer(nullptr); |
135 | Mockup.Prefix.setInt(StoredDecl); |
136 | Mockup.Specifier = RD; |
137 | return FindOrInsert(Context, Mockup); |
138 | } |
139 | |
140 | NestedNameSpecifier::SpecifierKind NestedNameSpecifier::getKind() const { |
141 | if (!Specifier) |
142 | return Global; |
143 | |
144 | switch (Prefix.getInt()) { |
145 | case StoredIdentifier: |
146 | return Identifier; |
147 | |
148 | case StoredDecl: { |
149 | NamedDecl *ND = static_cast<NamedDecl *>(Specifier); |
150 | if (isa<CXXRecordDecl>(Val: ND)) |
151 | return Super; |
152 | return isa<NamespaceDecl>(Val: ND) ? Namespace : NamespaceAlias; |
153 | } |
154 | |
155 | case StoredTypeSpec: |
156 | return TypeSpec; |
157 | } |
158 | |
159 | llvm_unreachable("Invalid NNS Kind!"); |
160 | } |
161 | |
162 | /// Retrieve the namespace stored in this nested name specifier. |
163 | NamespaceDecl *NestedNameSpecifier::getAsNamespace() const { |
164 | if (Prefix.getInt() == StoredDecl) |
165 | return dyn_cast<NamespaceDecl>(Val: static_cast<NamedDecl *>(Specifier)); |
166 | |
167 | return nullptr; |
168 | } |
169 | |
170 | /// Retrieve the namespace alias stored in this nested name specifier. |
171 | NamespaceAliasDecl *NestedNameSpecifier::getAsNamespaceAlias() const { |
172 | if (Prefix.getInt() == StoredDecl) |
173 | return dyn_cast<NamespaceAliasDecl>(Val: static_cast<NamedDecl *>(Specifier)); |
174 | |
175 | return nullptr; |
176 | } |
177 | |
178 | /// Retrieve the record declaration stored in this nested name specifier. |
179 | CXXRecordDecl *NestedNameSpecifier::getAsRecordDecl() const { |
180 | switch (Prefix.getInt()) { |
181 | case StoredIdentifier: |
182 | return nullptr; |
183 | |
184 | case StoredDecl: |
185 | return dyn_cast<CXXRecordDecl>(Val: static_cast<NamedDecl *>(Specifier)); |
186 | |
187 | case StoredTypeSpec: |
188 | return getAsType()->getAsCXXRecordDecl(); |
189 | } |
190 | |
191 | llvm_unreachable("Invalid NNS Kind!"); |
192 | } |
193 | |
194 | NestedNameSpecifierDependence NestedNameSpecifier::getDependence() const { |
195 | switch (getKind()) { |
196 | case Identifier: { |
197 | // Identifier specifiers always represent dependent types |
198 | auto F = NestedNameSpecifierDependence::Dependent | |
199 | NestedNameSpecifierDependence::Instantiation; |
200 | // Prefix can contain unexpanded template parameters. |
201 | if (getPrefix()) |
202 | return F | getPrefix()->getDependence(); |
203 | return F; |
204 | } |
205 | |
206 | case Namespace: |
207 | case NamespaceAlias: |
208 | case Global: |
209 | return NestedNameSpecifierDependence::None; |
210 | |
211 | case Super: { |
212 | CXXRecordDecl *RD = static_cast<CXXRecordDecl *>(Specifier); |
213 | for (const auto &Base : RD->bases()) |
214 | if (Base.getType()->isDependentType()) |
215 | // FIXME: must also be instantiation-dependent. |
216 | return NestedNameSpecifierDependence::Dependent; |
217 | return NestedNameSpecifierDependence::None; |
218 | } |
219 | |
220 | case TypeSpec: { |
221 | NestedNameSpecifierDependence Dep = |
222 | toNestedNameSpecifierDependendence(D: getAsType()->getDependence()); |
223 | if (NestedNameSpecifier *Prefix = getPrefix()) |
224 | Dep |= |
225 | Prefix->getDependence() & ~NestedNameSpecifierDependence::Dependent; |
226 | return Dep; |
227 | } |
228 | } |
229 | llvm_unreachable("Invalid NNS Kind!"); |
230 | } |
231 | |
232 | bool NestedNameSpecifier::isDependent() const { |
233 | return getDependence() & NestedNameSpecifierDependence::Dependent; |
234 | } |
235 | |
236 | bool NestedNameSpecifier::isInstantiationDependent() const { |
237 | return getDependence() & NestedNameSpecifierDependence::Instantiation; |
238 | } |
239 | |
240 | bool NestedNameSpecifier::containsUnexpandedParameterPack() const { |
241 | return getDependence() & NestedNameSpecifierDependence::UnexpandedPack; |
242 | } |
243 | |
244 | bool NestedNameSpecifier::containsErrors() const { |
245 | return getDependence() & NestedNameSpecifierDependence::Error; |
246 | } |
247 | |
248 | const Type * |
249 | NestedNameSpecifier::translateToType(const ASTContext &Context) const { |
250 | NestedNameSpecifier *Prefix = getPrefix(); |
251 | switch (getKind()) { |
252 | case SpecifierKind::Identifier: |
253 | return Context |
254 | .getDependentNameType(Keyword: ElaboratedTypeKeyword::None, NNS: Prefix, |
255 | Name: getAsIdentifier()) |
256 | .getTypePtr(); |
257 | case SpecifierKind::TypeSpec: { |
258 | const Type *T = getAsType(); |
259 | switch (T->getTypeClass()) { |
260 | case Type::DependentTemplateSpecialization: { |
261 | const auto *DT = cast<DependentTemplateSpecializationType>(Val: T); |
262 | const DependentTemplateStorage &DTN = DT->getDependentTemplateName(); |
263 | return Context |
264 | .getDependentTemplateSpecializationType( |
265 | Keyword: ElaboratedTypeKeyword::None, |
266 | Name: {Prefix, DTN.getName(), DTN.hasTemplateKeyword()}, |
267 | Args: DT->template_arguments()) |
268 | .getTypePtr(); |
269 | } |
270 | case Type::Record: |
271 | case Type::TemplateSpecialization: |
272 | case Type::Using: |
273 | case Type::Enum: |
274 | case Type::Typedef: |
275 | case Type::UnresolvedUsing: |
276 | return Context |
277 | .getElaboratedType(Keyword: ElaboratedTypeKeyword::None, NNS: Prefix, |
278 | NamedType: QualType(T, 0)) |
279 | .getTypePtr(); |
280 | default: |
281 | assert(Prefix == nullptr && "unexpected type with elaboration"); |
282 | return T; |
283 | } |
284 | } |
285 | case SpecifierKind::Global: |
286 | case SpecifierKind::Namespace: |
287 | case SpecifierKind::NamespaceAlias: |
288 | case SpecifierKind::Super: |
289 | // These are not representable as types. |
290 | return nullptr; |
291 | } |
292 | llvm_unreachable("Unhandled SpecifierKind enum"); |
293 | } |
294 | |
295 | /// Print this nested name specifier to the given output |
296 | /// stream. |
297 | void NestedNameSpecifier::print(raw_ostream &OS, const PrintingPolicy &Policy, |
298 | bool ResolveTemplateArguments, |
299 | bool PrintFinalScopeResOp) const { |
300 | if (getPrefix()) |
301 | getPrefix()->print(OS, Policy); |
302 | |
303 | switch (getKind()) { |
304 | case Identifier: |
305 | OS << getAsIdentifier()->getName(); |
306 | break; |
307 | |
308 | case Namespace: |
309 | if (getAsNamespace()->isAnonymousNamespace()) |
310 | return; |
311 | |
312 | OS << getAsNamespace()->getName(); |
313 | break; |
314 | |
315 | case NamespaceAlias: |
316 | OS << getAsNamespaceAlias()->getName(); |
317 | break; |
318 | |
319 | case Global: |
320 | OS << "::"; |
321 | return; |
322 | |
323 | case Super: |
324 | OS << "__super"; |
325 | break; |
326 | |
327 | case TypeSpec: { |
328 | PrintingPolicy InnerPolicy(Policy); |
329 | InnerPolicy.SuppressScope = true; |
330 | InnerPolicy.SuppressTagKeyword = true; |
331 | QualType(getAsType(), 0).print(OS, Policy: InnerPolicy); |
332 | break; |
333 | } |
334 | } |
335 | |
336 | if (PrintFinalScopeResOp) |
337 | OS << "::"; |
338 | } |
339 | |
340 | LLVM_DUMP_METHOD void NestedNameSpecifier::dump(const LangOptions &LO) const { |
341 | dump(OS&: llvm::errs(), LO); |
342 | } |
343 | |
344 | LLVM_DUMP_METHOD void NestedNameSpecifier::dump() const { dump(OS&: llvm::errs()); } |
345 | |
346 | LLVM_DUMP_METHOD void NestedNameSpecifier::dump(llvm::raw_ostream &OS) const { |
347 | LangOptions LO; |
348 | dump(OS, LO); |
349 | } |
350 | |
351 | LLVM_DUMP_METHOD void NestedNameSpecifier::dump(llvm::raw_ostream &OS, |
352 | const LangOptions &LO) const { |
353 | print(OS, Policy: PrintingPolicy(LO)); |
354 | } |
355 | |
356 | unsigned |
357 | NestedNameSpecifierLoc::getLocalDataLength(NestedNameSpecifier *Qualifier) { |
358 | assert(Qualifier && "Expected a non-NULL qualifier"); |
359 | |
360 | // Location of the trailing '::'. |
361 | unsigned Length = sizeof(SourceLocation::UIntTy); |
362 | |
363 | switch (Qualifier->getKind()) { |
364 | case NestedNameSpecifier::Global: |
365 | // Nothing more to add. |
366 | break; |
367 | |
368 | case NestedNameSpecifier::Identifier: |
369 | case NestedNameSpecifier::Namespace: |
370 | case NestedNameSpecifier::NamespaceAlias: |
371 | case NestedNameSpecifier::Super: |
372 | // The location of the identifier or namespace name. |
373 | Length += sizeof(SourceLocation::UIntTy); |
374 | break; |
375 | |
376 | case NestedNameSpecifier::TypeSpec: |
377 | // The "void*" that points at the TypeLoc data. |
378 | // Note: the 'template' keyword is part of the TypeLoc. |
379 | Length += sizeof(void *); |
380 | break; |
381 | } |
382 | |
383 | return Length; |
384 | } |
385 | |
386 | unsigned |
387 | NestedNameSpecifierLoc::getDataLength(NestedNameSpecifier *Qualifier) { |
388 | unsigned Length = 0; |
389 | for (; Qualifier; Qualifier = Qualifier->getPrefix()) |
390 | Length += getLocalDataLength(Qualifier); |
391 | return Length; |
392 | } |
393 | |
394 | /// Load a (possibly unaligned) source location from a given address |
395 | /// and offset. |
396 | static SourceLocation LoadSourceLocation(void *Data, unsigned Offset) { |
397 | SourceLocation::UIntTy Raw; |
398 | memcpy(dest: &Raw, src: static_cast<char *>(Data) + Offset, n: sizeof(Raw)); |
399 | return SourceLocation::getFromRawEncoding(Encoding: Raw); |
400 | } |
401 | |
402 | /// Load a (possibly unaligned) pointer from a given address and |
403 | /// offset. |
404 | static void *LoadPointer(void *Data, unsigned Offset) { |
405 | void *Result; |
406 | memcpy(dest: &Result, src: static_cast<char *>(Data) + Offset, n: sizeof(void*)); |
407 | return Result; |
408 | } |
409 | |
410 | SourceRange NestedNameSpecifierLoc::getLocalSourceRange() const { |
411 | if (!Qualifier) |
412 | return SourceRange(); |
413 | |
414 | unsigned Offset = getDataLength(Qualifier: Qualifier->getPrefix()); |
415 | switch (Qualifier->getKind()) { |
416 | case NestedNameSpecifier::Global: |
417 | return LoadSourceLocation(Data, Offset); |
418 | |
419 | case NestedNameSpecifier::Identifier: |
420 | case NestedNameSpecifier::Namespace: |
421 | case NestedNameSpecifier::NamespaceAlias: |
422 | case NestedNameSpecifier::Super: |
423 | return SourceRange( |
424 | LoadSourceLocation(Data, Offset), |
425 | LoadSourceLocation(Data, Offset: Offset + sizeof(SourceLocation::UIntTy))); |
426 | |
427 | case NestedNameSpecifier::TypeSpec: { |
428 | // The "void*" that points at the TypeLoc data. |
429 | // Note: the 'template' keyword is part of the TypeLoc. |
430 | void *TypeData = LoadPointer(Data, Offset); |
431 | TypeLoc TL(Qualifier->getAsType(), TypeData); |
432 | return SourceRange(TL.getBeginLoc(), |
433 | LoadSourceLocation(Data, Offset: Offset + sizeof(void*))); |
434 | } |
435 | } |
436 | |
437 | llvm_unreachable("Invalid NNS Kind!"); |
438 | } |
439 | |
440 | TypeLoc NestedNameSpecifierLoc::getTypeLoc() const { |
441 | if (Qualifier->getKind() != NestedNameSpecifier::TypeSpec) |
442 | return TypeLoc(); |
443 | |
444 | // The "void*" that points at the TypeLoc data. |
445 | unsigned Offset = getDataLength(Qualifier: Qualifier->getPrefix()); |
446 | void *TypeData = LoadPointer(Data, Offset); |
447 | return TypeLoc(Qualifier->getAsType(), TypeData); |
448 | } |
449 | |
450 | static void Append(char *Start, char *End, char *&Buffer, unsigned &BufferSize, |
451 | unsigned &BufferCapacity) { |
452 | if (Start == End) |
453 | return; |
454 | |
455 | if (BufferSize + (End - Start) > BufferCapacity) { |
456 | // Reallocate the buffer. |
457 | unsigned NewCapacity = std::max( |
458 | a: (unsigned)(BufferCapacity ? BufferCapacity * 2 : sizeof(void *) * 2), |
459 | b: (unsigned)(BufferSize + (End - Start))); |
460 | if (!BufferCapacity) { |
461 | char *NewBuffer = static_cast<char *>(llvm::safe_malloc(Sz: NewCapacity)); |
462 | if (Buffer) |
463 | memcpy(dest: NewBuffer, src: Buffer, n: BufferSize); |
464 | Buffer = NewBuffer; |
465 | } else { |
466 | Buffer = static_cast<char *>(llvm::safe_realloc(Ptr: Buffer, Sz: NewCapacity)); |
467 | } |
468 | BufferCapacity = NewCapacity; |
469 | } |
470 | assert(Buffer && Start && End && End > Start && "Illegal memory buffer copy"); |
471 | memcpy(dest: Buffer + BufferSize, src: Start, n: End - Start); |
472 | BufferSize += End - Start; |
473 | } |
474 | |
475 | /// Save a source location to the given buffer. |
476 | static void SaveSourceLocation(SourceLocation Loc, char *&Buffer, |
477 | unsigned &BufferSize, unsigned &BufferCapacity) { |
478 | SourceLocation::UIntTy Raw = Loc.getRawEncoding(); |
479 | Append(Start: reinterpret_cast<char *>(&Raw), |
480 | End: reinterpret_cast<char *>(&Raw) + sizeof(Raw), Buffer, BufferSize, |
481 | BufferCapacity); |
482 | } |
483 | |
484 | /// Save a pointer to the given buffer. |
485 | static void SavePointer(void *Ptr, char *&Buffer, unsigned &BufferSize, |
486 | unsigned &BufferCapacity) { |
487 | Append(Start: reinterpret_cast<char *>(&Ptr), |
488 | End: reinterpret_cast<char *>(&Ptr) + sizeof(void *), |
489 | Buffer, BufferSize, BufferCapacity); |
490 | } |
491 | |
492 | NestedNameSpecifierLocBuilder:: |
493 | NestedNameSpecifierLocBuilder(const NestedNameSpecifierLocBuilder &Other) |
494 | : Representation(Other.Representation) { |
495 | if (!Other.Buffer) |
496 | return; |
497 | |
498 | if (Other.BufferCapacity == 0) { |
499 | // Shallow copy is okay. |
500 | Buffer = Other.Buffer; |
501 | BufferSize = Other.BufferSize; |
502 | return; |
503 | } |
504 | |
505 | // Deep copy |
506 | Append(Start: Other.Buffer, End: Other.Buffer + Other.BufferSize, Buffer, BufferSize, |
507 | BufferCapacity); |
508 | } |
509 | |
510 | NestedNameSpecifierLocBuilder & |
511 | NestedNameSpecifierLocBuilder:: |
512 | operator=(const NestedNameSpecifierLocBuilder &Other) { |
513 | Representation = Other.Representation; |
514 | |
515 | if (Buffer && Other.Buffer && BufferCapacity >= Other.BufferSize) { |
516 | // Re-use our storage. |
517 | BufferSize = Other.BufferSize; |
518 | memcpy(dest: Buffer, src: Other.Buffer, n: BufferSize); |
519 | return *this; |
520 | } |
521 | |
522 | // Free our storage, if we have any. |
523 | if (BufferCapacity) { |
524 | free(ptr: Buffer); |
525 | BufferCapacity = 0; |
526 | } |
527 | |
528 | if (!Other.Buffer) { |
529 | // Empty. |
530 | Buffer = nullptr; |
531 | BufferSize = 0; |
532 | return *this; |
533 | } |
534 | |
535 | if (Other.BufferCapacity == 0) { |
536 | // Shallow copy is okay. |
537 | Buffer = Other.Buffer; |
538 | BufferSize = Other.BufferSize; |
539 | return *this; |
540 | } |
541 | |
542 | // Deep copy. |
543 | BufferSize = 0; |
544 | Append(Start: Other.Buffer, End: Other.Buffer + Other.BufferSize, Buffer, BufferSize, |
545 | BufferCapacity); |
546 | return *this; |
547 | } |
548 | |
549 | void NestedNameSpecifierLocBuilder::Extend(ASTContext &Context, TypeLoc TL, |
550 | SourceLocation ColonColonLoc) { |
551 | Representation = |
552 | NestedNameSpecifier::Create(Context, Prefix: Representation, T: TL.getTypePtr()); |
553 | |
554 | // Push source-location info into the buffer. |
555 | SavePointer(Ptr: TL.getOpaqueData(), Buffer, BufferSize, BufferCapacity); |
556 | SaveSourceLocation(Loc: ColonColonLoc, Buffer, BufferSize, BufferCapacity); |
557 | } |
558 | |
559 | void NestedNameSpecifierLocBuilder::Extend(ASTContext &Context, |
560 | IdentifierInfo *Identifier, |
561 | SourceLocation IdentifierLoc, |
562 | SourceLocation ColonColonLoc) { |
563 | Representation = NestedNameSpecifier::Create(Context, Prefix: Representation, |
564 | II: Identifier); |
565 | |
566 | // Push source-location info into the buffer. |
567 | SaveSourceLocation(Loc: IdentifierLoc, Buffer, BufferSize, BufferCapacity); |
568 | SaveSourceLocation(Loc: ColonColonLoc, Buffer, BufferSize, BufferCapacity); |
569 | } |
570 | |
571 | void NestedNameSpecifierLocBuilder::Extend(ASTContext &Context, |
572 | NamespaceDecl *Namespace, |
573 | SourceLocation NamespaceLoc, |
574 | SourceLocation ColonColonLoc) { |
575 | Representation = NestedNameSpecifier::Create(Context, Prefix: Representation, |
576 | NS: Namespace); |
577 | |
578 | // Push source-location info into the buffer. |
579 | SaveSourceLocation(Loc: NamespaceLoc, Buffer, BufferSize, BufferCapacity); |
580 | SaveSourceLocation(Loc: ColonColonLoc, Buffer, BufferSize, BufferCapacity); |
581 | } |
582 | |
583 | void NestedNameSpecifierLocBuilder::Extend(ASTContext &Context, |
584 | NamespaceAliasDecl *Alias, |
585 | SourceLocation AliasLoc, |
586 | SourceLocation ColonColonLoc) { |
587 | Representation = NestedNameSpecifier::Create(Context, Prefix: Representation, Alias); |
588 | |
589 | // Push source-location info into the buffer. |
590 | SaveSourceLocation(Loc: AliasLoc, Buffer, BufferSize, BufferCapacity); |
591 | SaveSourceLocation(Loc: ColonColonLoc, Buffer, BufferSize, BufferCapacity); |
592 | } |
593 | |
594 | void NestedNameSpecifierLocBuilder::MakeGlobal(ASTContext &Context, |
595 | SourceLocation ColonColonLoc) { |
596 | assert(!Representation && "Already have a nested-name-specifier!?"); |
597 | Representation = NestedNameSpecifier::GlobalSpecifier(Context); |
598 | |
599 | // Push source-location info into the buffer. |
600 | SaveSourceLocation(Loc: ColonColonLoc, Buffer, BufferSize, BufferCapacity); |
601 | } |
602 | |
603 | void NestedNameSpecifierLocBuilder::MakeSuper(ASTContext &Context, |
604 | CXXRecordDecl *RD, |
605 | SourceLocation SuperLoc, |
606 | SourceLocation ColonColonLoc) { |
607 | Representation = NestedNameSpecifier::SuperSpecifier(Context, RD); |
608 | |
609 | // Push source-location info into the buffer. |
610 | SaveSourceLocation(Loc: SuperLoc, Buffer, BufferSize, BufferCapacity); |
611 | SaveSourceLocation(Loc: ColonColonLoc, Buffer, BufferSize, BufferCapacity); |
612 | } |
613 | |
614 | void NestedNameSpecifierLocBuilder::MakeTrivial(ASTContext &Context, |
615 | NestedNameSpecifier *Qualifier, |
616 | SourceRange R) { |
617 | Representation = Qualifier; |
618 | |
619 | // Construct bogus (but well-formed) source information for the |
620 | // nested-name-specifier. |
621 | BufferSize = 0; |
622 | SmallVector<NestedNameSpecifier *, 4> Stack; |
623 | for (NestedNameSpecifier *NNS = Qualifier; NNS; NNS = NNS->getPrefix()) |
624 | Stack.push_back(Elt: NNS); |
625 | while (!Stack.empty()) { |
626 | NestedNameSpecifier *NNS = Stack.pop_back_val(); |
627 | switch (NNS->getKind()) { |
628 | case NestedNameSpecifier::Identifier: |
629 | case NestedNameSpecifier::Namespace: |
630 | case NestedNameSpecifier::NamespaceAlias: |
631 | SaveSourceLocation(Loc: R.getBegin(), Buffer, BufferSize, BufferCapacity); |
632 | break; |
633 | |
634 | case NestedNameSpecifier::TypeSpec: { |
635 | TypeSourceInfo *TSInfo |
636 | = Context.getTrivialTypeSourceInfo(T: QualType(NNS->getAsType(), 0), |
637 | Loc: R.getBegin()); |
638 | SavePointer(Ptr: TSInfo->getTypeLoc().getOpaqueData(), Buffer, BufferSize, |
639 | BufferCapacity); |
640 | break; |
641 | } |
642 | |
643 | case NestedNameSpecifier::Global: |
644 | case NestedNameSpecifier::Super: |
645 | break; |
646 | } |
647 | |
648 | // Save the location of the '::'. |
649 | SaveSourceLocation(Loc: Stack.empty()? R.getEnd() : R.getBegin(), |
650 | Buffer, BufferSize, BufferCapacity); |
651 | } |
652 | } |
653 | |
654 | void NestedNameSpecifierLocBuilder::Adopt(NestedNameSpecifierLoc Other) { |
655 | if (BufferCapacity) |
656 | free(ptr: Buffer); |
657 | |
658 | if (!Other) { |
659 | Representation = nullptr; |
660 | BufferSize = 0; |
661 | return; |
662 | } |
663 | |
664 | // Rather than copying the data (which is wasteful), "adopt" the |
665 | // pointer (which points into the ASTContext) but set the capacity to zero to |
666 | // indicate that we don't own it. |
667 | Representation = Other.getNestedNameSpecifier(); |
668 | Buffer = static_cast<char *>(Other.getOpaqueData()); |
669 | BufferSize = Other.getDataLength(); |
670 | BufferCapacity = 0; |
671 | } |
672 | |
673 | NestedNameSpecifierLoc |
674 | NestedNameSpecifierLocBuilder::getWithLocInContext(ASTContext &Context) const { |
675 | if (!Representation) |
676 | return NestedNameSpecifierLoc(); |
677 | |
678 | // If we adopted our data pointer from elsewhere in the AST context, there's |
679 | // no need to copy the memory. |
680 | if (BufferCapacity == 0) |
681 | return NestedNameSpecifierLoc(Representation, Buffer); |
682 | |
683 | // FIXME: After copying the source-location information, should we free |
684 | // our (temporary) buffer and adopt the ASTContext-allocated memory? |
685 | // Doing so would optimize repeated calls to getWithLocInContext(). |
686 | void *Mem = Context.Allocate(Size: BufferSize, Align: alignof(void *)); |
687 | memcpy(dest: Mem, src: Buffer, n: BufferSize); |
688 | return NestedNameSpecifierLoc(Representation, Mem); |
689 | } |
690 |
Definitions
- FindOrInsert
- Create
- Create
- Create
- Create
- Create
- GlobalSpecifier
- SuperSpecifier
- getKind
- getAsNamespace
- getAsNamespaceAlias
- getAsRecordDecl
- getDependence
- isDependent
- isInstantiationDependent
- containsUnexpandedParameterPack
- containsErrors
- translateToType
- dump
- dump
- dump
- dump
- getLocalDataLength
- getDataLength
- LoadSourceLocation
- LoadPointer
- getLocalSourceRange
- getTypeLoc
- Append
- SaveSourceLocation
- SavePointer
- NestedNameSpecifierLocBuilder
- operator=
- Extend
- Extend
- Extend
- Extend
- MakeGlobal
- MakeSuper
- MakeTrivial
- Adopt
Improve your Profiling and Debugging skills
Find out more