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