/Users/buildslave/jenkins/workspace/coverage/llvm-project/clang/lib/AST/NestedNameSpecifier.cpp
Line | Count | Source (jump to first uncovered line) |
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 | 18.4M | const NestedNameSpecifier &Mockup) { |
43 | 18.4M | llvm::FoldingSetNodeID ID; |
44 | 18.4M | Mockup.Profile(ID); |
45 | | |
46 | 18.4M | void *InsertPos = nullptr; |
47 | 18.4M | NestedNameSpecifier *NNS |
48 | 18.4M | = Context.NestedNameSpecifiers.FindNodeOrInsertPos(ID, InsertPos); |
49 | 18.4M | if (!NNS) { |
50 | 7.62M | NNS = |
51 | 7.62M | new (Context, alignof(NestedNameSpecifier)) NestedNameSpecifier(Mockup); |
52 | 7.62M | Context.NestedNameSpecifiers.InsertNode(NNS, InsertPos); |
53 | 7.62M | } |
54 | | |
55 | 18.4M | return NNS; |
56 | 18.4M | } |
57 | | |
58 | | NestedNameSpecifier * |
59 | | NestedNameSpecifier::Create(const ASTContext &Context, |
60 | 293k | NestedNameSpecifier *Prefix, IdentifierInfo *II) { |
61 | 293k | assert(II && "Identifier cannot be NULL"); |
62 | 0 | assert((!Prefix || Prefix->isDependent()) && "Prefix must be dependent"); |
63 | | |
64 | 0 | NestedNameSpecifier Mockup; |
65 | 293k | Mockup.Prefix.setPointer(Prefix); |
66 | 293k | Mockup.Prefix.setInt(StoredIdentifier); |
67 | 293k | Mockup.Specifier = II; |
68 | 293k | return FindOrInsert(Context, Mockup); |
69 | 293k | } |
70 | | |
71 | | NestedNameSpecifier * |
72 | | NestedNameSpecifier::Create(const ASTContext &Context, |
73 | | NestedNameSpecifier *Prefix, |
74 | 1.88M | const NamespaceDecl *NS) { |
75 | 1.88M | assert(NS && "Namespace cannot be NULL"); |
76 | 0 | assert((!Prefix || |
77 | 1.88M | (Prefix->getAsType() == nullptr && |
78 | 1.88M | Prefix->getAsIdentifier() == nullptr)) && |
79 | 1.88M | "Broken nested name specifier"); |
80 | 0 | NestedNameSpecifier Mockup; |
81 | 1.88M | Mockup.Prefix.setPointer(Prefix); |
82 | 1.88M | Mockup.Prefix.setInt(StoredDecl); |
83 | 1.88M | Mockup.Specifier = const_cast<NamespaceDecl *>(NS); |
84 | 1.88M | return FindOrInsert(Context, Mockup); |
85 | 1.88M | } |
86 | | |
87 | | NestedNameSpecifier * |
88 | | NestedNameSpecifier::Create(const ASTContext &Context, |
89 | | NestedNameSpecifier *Prefix, |
90 | 247 | NamespaceAliasDecl *Alias) { |
91 | 247 | assert(Alias && "Namespace alias cannot be NULL"); |
92 | 0 | assert((!Prefix || |
93 | 247 | (Prefix->getAsType() == nullptr && |
94 | 247 | Prefix->getAsIdentifier() == nullptr)) && |
95 | 247 | "Broken nested name specifier"); |
96 | 0 | NestedNameSpecifier Mockup; |
97 | 247 | Mockup.Prefix.setPointer(Prefix); |
98 | 247 | Mockup.Prefix.setInt(StoredDecl); |
99 | 247 | Mockup.Specifier = Alias; |
100 | 247 | return FindOrInsert(Context, Mockup); |
101 | 247 | } |
102 | | |
103 | | NestedNameSpecifier * |
104 | | NestedNameSpecifier::Create(const ASTContext &Context, |
105 | | NestedNameSpecifier *Prefix, |
106 | 16.2M | bool Template, const Type *T) { |
107 | 16.2M | assert(T && "Type cannot be NULL"); |
108 | 0 | NestedNameSpecifier Mockup; |
109 | 16.2M | Mockup.Prefix.setPointer(Prefix); |
110 | 16.2M | Mockup.Prefix.setInt(Template? StoredTypeSpecWithTemplate24.3k : StoredTypeSpec16.2M ); |
111 | 16.2M | Mockup.Specifier = const_cast<Type*>(T); |
112 | 16.2M | return FindOrInsert(Context, Mockup); |
113 | 16.2M | } |
114 | | |
115 | | NestedNameSpecifier * |
116 | 0 | NestedNameSpecifier::Create(const ASTContext &Context, IdentifierInfo *II) { |
117 | 0 | assert(II && "Identifier cannot be NULL"); |
118 | 0 | NestedNameSpecifier Mockup; |
119 | 0 | Mockup.Prefix.setPointer(nullptr); |
120 | 0 | Mockup.Prefix.setInt(StoredIdentifier); |
121 | 0 | Mockup.Specifier = II; |
122 | 0 | return FindOrInsert(Context, Mockup); |
123 | 0 | } |
124 | | |
125 | | NestedNameSpecifier * |
126 | 338k | NestedNameSpecifier::GlobalSpecifier(const ASTContext &Context) { |
127 | 338k | if (!Context.GlobalNestedNameSpecifier) |
128 | 4.64k | Context.GlobalNestedNameSpecifier = |
129 | 4.64k | new (Context, alignof(NestedNameSpecifier)) NestedNameSpecifier(); |
130 | 338k | return Context.GlobalNestedNameSpecifier; |
131 | 338k | } |
132 | | |
133 | | NestedNameSpecifier * |
134 | | NestedNameSpecifier::SuperSpecifier(const ASTContext &Context, |
135 | 58 | CXXRecordDecl *RD) { |
136 | 58 | NestedNameSpecifier Mockup; |
137 | 58 | Mockup.Prefix.setPointer(nullptr); |
138 | 58 | Mockup.Prefix.setInt(StoredDecl); |
139 | 58 | Mockup.Specifier = RD; |
140 | 58 | return FindOrInsert(Context, Mockup); |
141 | 58 | } |
142 | | |
143 | 184M | NestedNameSpecifier::SpecifierKind NestedNameSpecifier::getKind() const { |
144 | 184M | if (!Specifier) |
145 | 5.87M | return Global; |
146 | | |
147 | 179M | switch (Prefix.getInt()) { |
148 | 854k | case StoredIdentifier: |
149 | 854k | return Identifier; |
150 | | |
151 | 33.3M | case StoredDecl: { |
152 | 33.3M | NamedDecl *ND = static_cast<NamedDecl *>(Specifier); |
153 | 33.3M | if (isa<CXXRecordDecl>(ND)) |
154 | 1.60k | return Super; |
155 | 33.3M | return isa<NamespaceDecl>(ND) ? Namespace33.3M : NamespaceAlias6.93k ; |
156 | 33.3M | } |
157 | | |
158 | 144M | case StoredTypeSpec: |
159 | 144M | return TypeSpec; |
160 | | |
161 | 41.8k | case StoredTypeSpecWithTemplate: |
162 | 41.8k | return TypeSpecWithTemplate; |
163 | 179M | } |
164 | | |
165 | 0 | llvm_unreachable("Invalid NNS Kind!"); |
166 | 0 | } |
167 | | |
168 | | /// Retrieve the namespace stored in this nested name specifier. |
169 | 3.78M | NamespaceDecl *NestedNameSpecifier::getAsNamespace() const { |
170 | 3.78M | if (Prefix.getInt() == StoredDecl) |
171 | 3.78M | return dyn_cast<NamespaceDecl>(static_cast<NamedDecl *>(Specifier)); |
172 | | |
173 | 6.69k | return nullptr; |
174 | 3.78M | } |
175 | | |
176 | | /// Retrieve the namespace alias stored in this nested name specifier. |
177 | 7.48k | NamespaceAliasDecl *NestedNameSpecifier::getAsNamespaceAlias() const { |
178 | 7.48k | if (Prefix.getInt() == StoredDecl) |
179 | 844 | return dyn_cast<NamespaceAliasDecl>(static_cast<NamedDecl *>(Specifier)); |
180 | | |
181 | 6.63k | return nullptr; |
182 | 7.48k | } |
183 | | |
184 | | /// Retrieve the record declaration stored in this nested name specifier. |
185 | 134k | CXXRecordDecl *NestedNameSpecifier::getAsRecordDecl() const { |
186 | 134k | switch (Prefix.getInt()) { |
187 | 0 | case StoredIdentifier: |
188 | 0 | return nullptr; |
189 | | |
190 | 119 | case StoredDecl: |
191 | 119 | return dyn_cast<CXXRecordDecl>(static_cast<NamedDecl *>(Specifier)); |
192 | | |
193 | 134k | case StoredTypeSpec: |
194 | 134k | case StoredTypeSpecWithTemplate: |
195 | 134k | return getAsType()->getAsCXXRecordDecl(); |
196 | 134k | } |
197 | | |
198 | 0 | llvm_unreachable("Invalid NNS Kind!"); |
199 | 0 | } |
200 | | |
201 | 37.2M | NestedNameSpecifierDependence NestedNameSpecifier::getDependence() const { |
202 | 37.2M | switch (getKind()) { |
203 | 315k | case Identifier: { |
204 | | // Identifier specifiers always represent dependent types |
205 | 315k | auto F = NestedNameSpecifierDependence::Dependent | |
206 | 315k | NestedNameSpecifierDependence::Instantiation; |
207 | | // Prefix can contain unexpanded template parameters. |
208 | 315k | if (getPrefix()) |
209 | 315k | return F | getPrefix()->getDependence(); |
210 | 355 | return F; |
211 | 315k | } |
212 | | |
213 | 4.48M | case Namespace: |
214 | 4.48M | case NamespaceAlias: |
215 | 5.94M | case Global: |
216 | 5.94M | return NestedNameSpecifierDependence::None; |
217 | | |
218 | 337 | case Super: { |
219 | 337 | CXXRecordDecl *RD = static_cast<CXXRecordDecl *>(Specifier); |
220 | 337 | for (const auto &Base : RD->bases()) |
221 | 345 | if (Base.getType()->isDependentType()) |
222 | | // FIXME: must also be instantiation-dependent. |
223 | 192 | return NestedNameSpecifierDependence::Dependent; |
224 | 145 | return NestedNameSpecifierDependence::None; |
225 | 337 | } |
226 | | |
227 | 30.9M | case TypeSpec: |
228 | 31.0M | case TypeSpecWithTemplate: |
229 | 31.0M | return toNestedNameSpecifierDependendence(getAsType()->getDependence()); |
230 | 37.2M | } |
231 | 0 | llvm_unreachable("Invalid NNS Kind!"); |
232 | 0 | } |
233 | | |
234 | 26.2M | bool NestedNameSpecifier::isDependent() const { |
235 | 26.2M | return getDependence() & NestedNameSpecifierDependence::Dependent; |
236 | 26.2M | } |
237 | | |
238 | 11.4k | bool NestedNameSpecifier::isInstantiationDependent() const { |
239 | 11.4k | return getDependence() & NestedNameSpecifierDependence::Instantiation; |
240 | 11.4k | } |
241 | | |
242 | 494k | bool NestedNameSpecifier::containsUnexpandedParameterPack() const { |
243 | 494k | return getDependence() & NestedNameSpecifierDependence::UnexpandedPack; |
244 | 494k | } |
245 | | |
246 | 188 | bool NestedNameSpecifier::containsErrors() const { |
247 | 188 | return getDependence() & NestedNameSpecifierDependence::Error; |
248 | 188 | } |
249 | | |
250 | | /// Print this nested name specifier to the given output |
251 | | /// stream. |
252 | | void NestedNameSpecifier::print(raw_ostream &OS, const PrintingPolicy &Policy, |
253 | 152k | bool ResolveTemplateArguments) const { |
254 | 152k | if (getPrefix()) |
255 | 19.7k | getPrefix()->print(OS, Policy); |
256 | | |
257 | 152k | switch (getKind()) { |
258 | 17 | case Identifier: |
259 | 17 | OS << getAsIdentifier()->getName(); |
260 | 17 | break; |
261 | | |
262 | 21.3k | case Namespace: |
263 | 21.3k | if (getAsNamespace()->isAnonymousNamespace()) |
264 | 0 | return; |
265 | | |
266 | 21.3k | OS << getAsNamespace()->getName(); |
267 | 21.3k | break; |
268 | | |
269 | 16 | case NamespaceAlias: |
270 | 16 | OS << getAsNamespaceAlias()->getName(); |
271 | 16 | break; |
272 | | |
273 | 451 | case Global: |
274 | 451 | break; |
275 | | |
276 | 16 | case Super: |
277 | 16 | OS << "__super"; |
278 | 16 | break; |
279 | | |
280 | 0 | case TypeSpecWithTemplate: |
281 | 0 | OS << "template "; |
282 | | // Fall through to print the type. |
283 | 0 | LLVM_FALLTHROUGH; |
284 | |
|
285 | 130k | case TypeSpec: { |
286 | 130k | const auto *Record = |
287 | 130k | dyn_cast_or_null<ClassTemplateSpecializationDecl>(getAsRecordDecl()); |
288 | 130k | if (ResolveTemplateArguments && Record124k ) { |
289 | | // Print the type trait with resolved template parameters. |
290 | 106k | Record->printName(OS); |
291 | 106k | printTemplateArgumentList( |
292 | 106k | OS, Record->getTemplateArgs().asArray(), Policy, |
293 | 106k | Record->getSpecializedTemplate()->getTemplateParameters()); |
294 | 106k | break; |
295 | 106k | } |
296 | 23.8k | const Type *T = getAsType(); |
297 | | |
298 | 23.8k | PrintingPolicy InnerPolicy(Policy); |
299 | 23.8k | 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 | 23.8k | assert(!isa<ElaboratedType>(T) && |
309 | 23.8k | "Elaborated type in nested-name-specifier"); |
310 | 23.8k | if (const TemplateSpecializationType *SpecType |
311 | 23.8k | = dyn_cast<TemplateSpecializationType>(T)) { |
312 | | // Print the template name without its corresponding |
313 | | // nested-name-specifier. |
314 | 16.3k | SpecType->getTemplateName().print(OS, InnerPolicy, |
315 | 16.3k | TemplateName::Qualified::None); |
316 | | |
317 | | // Print the template argument list. |
318 | 16.3k | printTemplateArgumentList(OS, SpecType->template_arguments(), |
319 | 16.3k | InnerPolicy); |
320 | 16.3k | } else if (const auto *7.50k DepSpecType7.50k = |
321 | 7.50k | dyn_cast<DependentTemplateSpecializationType>(T)) { |
322 | | // Print the template name without its corresponding |
323 | | // nested-name-specifier. |
324 | 0 | OS << DepSpecType->getIdentifier()->getName(); |
325 | | // Print the template argument list. |
326 | 0 | printTemplateArgumentList(OS, DepSpecType->template_arguments(), |
327 | 0 | InnerPolicy); |
328 | 7.50k | } else { |
329 | | // Print the type normally |
330 | 7.50k | QualType(T, 0).print(OS, InnerPolicy); |
331 | 7.50k | } |
332 | 23.8k | break; |
333 | 130k | } |
334 | 152k | } |
335 | | |
336 | 152k | OS << "::"; |
337 | 152k | } |
338 | | |
339 | 0 | LLVM_DUMP_METHOD void NestedNameSpecifier::dump(const LangOptions &LO) const { |
340 | 0 | dump(llvm::errs(), LO); |
341 | 0 | } |
342 | | |
343 | 0 | LLVM_DUMP_METHOD void NestedNameSpecifier::dump() const { dump(llvm::errs()); } |
344 | | |
345 | 0 | LLVM_DUMP_METHOD void NestedNameSpecifier::dump(llvm::raw_ostream &OS) const { |
346 | 0 | LangOptions LO; |
347 | 0 | dump(OS, LO); |
348 | 0 | } |
349 | | |
350 | | LLVM_DUMP_METHOD void NestedNameSpecifier::dump(llvm::raw_ostream &OS, |
351 | 0 | const LangOptions &LO) const { |
352 | 0 | print(OS, PrintingPolicy(LO)); |
353 | 0 | } |
354 | | |
355 | | unsigned |
356 | 17.2M | NestedNameSpecifierLoc::getLocalDataLength(NestedNameSpecifier *Qualifier) { |
357 | 17.2M | assert(Qualifier && "Expected a non-NULL qualifier"); |
358 | | |
359 | | // Location of the trailing '::'. |
360 | 0 | unsigned Length = sizeof(SourceLocation::UIntTy); |
361 | | |
362 | 17.2M | switch (Qualifier->getKind()) { |
363 | 170k | case NestedNameSpecifier::Global: |
364 | | // Nothing more to add. |
365 | 170k | break; |
366 | | |
367 | 78.9k | case NestedNameSpecifier::Identifier: |
368 | 4.49M | case NestedNameSpecifier::Namespace: |
369 | 4.49M | case NestedNameSpecifier::NamespaceAlias: |
370 | 4.49M | case NestedNameSpecifier::Super: |
371 | | // The location of the identifier or namespace name. |
372 | 4.49M | Length += sizeof(SourceLocation::UIntTy); |
373 | 4.49M | break; |
374 | | |
375 | 4.48k | case NestedNameSpecifier::TypeSpecWithTemplate: |
376 | 12.5M | case NestedNameSpecifier::TypeSpec: |
377 | | // The "void*" that points at the TypeLoc data. |
378 | | // Note: the 'template' keyword is part of the TypeLoc. |
379 | 12.5M | Length += sizeof(void *); |
380 | 12.5M | break; |
381 | 17.2M | } |
382 | | |
383 | 17.2M | return Length; |
384 | 17.2M | } |
385 | | |
386 | | unsigned |
387 | 116M | NestedNameSpecifierLoc::getDataLength(NestedNameSpecifier *Qualifier) { |
388 | 116M | unsigned Length = 0; |
389 | 133M | for (; Qualifier; Qualifier = Qualifier->getPrefix()17.2M ) |
390 | 17.2M | Length += getLocalDataLength(Qualifier); |
391 | 116M | return Length; |
392 | 116M | } |
393 | | |
394 | | /// Load a (possibly unaligned) source location from a given address |
395 | | /// and offset. |
396 | 116M | static SourceLocation LoadSourceLocation(void *Data, unsigned Offset) { |
397 | 116M | SourceLocation::UIntTy Raw; |
398 | 116M | memcpy(&Raw, static_cast<char *>(Data) + Offset, sizeof(Raw)); |
399 | 116M | return SourceLocation::getFromRawEncoding(Raw); |
400 | 116M | } |
401 | | |
402 | | /// Load a (possibly unaligned) pointer from a given address and |
403 | | /// offset. |
404 | 78.7M | static void *LoadPointer(void *Data, unsigned Offset) { |
405 | 78.7M | void *Result; |
406 | 78.7M | memcpy(&Result, static_cast<char *>(Data) + Offset, sizeof(void*)); |
407 | 78.7M | return Result; |
408 | 78.7M | } |
409 | | |
410 | 44.1M | SourceRange NestedNameSpecifierLoc::getSourceRange() const { |
411 | 44.1M | if (!Qualifier) |
412 | 189k | return SourceRange(); |
413 | | |
414 | 43.9M | NestedNameSpecifierLoc First = *this; |
415 | 45.9M | while (NestedNameSpecifierLoc Prefix = First.getPrefix()) |
416 | 2.00M | First = Prefix; |
417 | | |
418 | 43.9M | return SourceRange(First.getLocalSourceRange().getBegin(), |
419 | 43.9M | getLocalSourceRange().getEnd()); |
420 | 44.1M | } |
421 | | |
422 | 96.7M | SourceRange NestedNameSpecifierLoc::getLocalSourceRange() const { |
423 | 96.7M | if (!Qualifier) |
424 | 0 | return SourceRange(); |
425 | | |
426 | 96.7M | unsigned Offset = getDataLength(Qualifier->getPrefix()); |
427 | 96.7M | switch (Qualifier->getKind()) { |
428 | 3.15M | case NestedNameSpecifier::Global: |
429 | 3.15M | return LoadSourceLocation(Data, Offset); |
430 | | |
431 | 240k | case NestedNameSpecifier::Identifier: |
432 | 20.1M | case NestedNameSpecifier::Namespace: |
433 | 20.1M | case NestedNameSpecifier::NamespaceAlias: |
434 | 20.1M | case NestedNameSpecifier::Super: |
435 | 20.1M | return SourceRange( |
436 | 20.1M | LoadSourceLocation(Data, Offset), |
437 | 20.1M | LoadSourceLocation(Data, Offset + sizeof(SourceLocation::UIntTy))); |
438 | | |
439 | 8.15k | case NestedNameSpecifier::TypeSpecWithTemplate: |
440 | 73.4M | case NestedNameSpecifier::TypeSpec: { |
441 | | // The "void*" that points at the TypeLoc data. |
442 | | // Note: the 'template' keyword is part of the TypeLoc. |
443 | 73.4M | void *TypeData = LoadPointer(Data, Offset); |
444 | 73.4M | TypeLoc TL(Qualifier->getAsType(), TypeData); |
445 | 73.4M | return SourceRange(TL.getBeginLoc(), |
446 | 73.4M | LoadSourceLocation(Data, Offset + sizeof(void*))); |
447 | 8.15k | } |
448 | 96.7M | } |
449 | | |
450 | 0 | llvm_unreachable("Invalid NNS Kind!"); |
451 | 0 | } |
452 | | |
453 | 5.26M | TypeLoc NestedNameSpecifierLoc::getTypeLoc() const { |
454 | 5.26M | if (Qualifier->getKind() != NestedNameSpecifier::TypeSpec && |
455 | 5.26M | Qualifier->getKind() != NestedNameSpecifier::TypeSpecWithTemplate3.17k ) |
456 | 105 | return TypeLoc(); |
457 | | |
458 | | // The "void*" that points at the TypeLoc data. |
459 | 5.26M | unsigned Offset = getDataLength(Qualifier->getPrefix()); |
460 | 5.26M | void *TypeData = LoadPointer(Data, Offset); |
461 | 5.26M | return TypeLoc(Qualifier->getAsType(), TypeData); |
462 | 5.26M | } |
463 | | |
464 | | static void Append(char *Start, char *End, char *&Buffer, unsigned &BufferSize, |
465 | 21.6M | unsigned &BufferCapacity) { |
466 | 21.6M | if (Start == End) |
467 | 14 | return; |
468 | | |
469 | 21.6M | if (BufferSize + (End - Start) > BufferCapacity) { |
470 | | // Reallocate the buffer. |
471 | 11.1M | unsigned NewCapacity = std::max( |
472 | 11.1M | (unsigned)(BufferCapacity ? BufferCapacity * 2331k : sizeof(void *) * 210.7M ), |
473 | 11.1M | (unsigned)(BufferSize + (End - Start))); |
474 | 11.1M | if (!BufferCapacity) { |
475 | 10.7M | char *NewBuffer = static_cast<char *>(llvm::safe_malloc(NewCapacity)); |
476 | 10.7M | if (Buffer) |
477 | 10 | memcpy(NewBuffer, Buffer, BufferSize); |
478 | 10.7M | Buffer = NewBuffer; |
479 | 10.7M | } else { |
480 | 331k | Buffer = static_cast<char *>(llvm::safe_realloc(Buffer, NewCapacity)); |
481 | 331k | } |
482 | 11.1M | BufferCapacity = NewCapacity; |
483 | 11.1M | } |
484 | 21.6M | assert(Buffer && Start && End && End > Start && "Illegal memory buffer copy"); |
485 | 0 | memcpy(Buffer + BufferSize, Start, End - Start); |
486 | 21.6M | BufferSize += End - Start; |
487 | 21.6M | } |
488 | | |
489 | | /// Save a source location to the given buffer. |
490 | | static void SaveSourceLocation(SourceLocation Loc, char *&Buffer, |
491 | 12.5M | unsigned &BufferSize, unsigned &BufferCapacity) { |
492 | 12.5M | SourceLocation::UIntTy Raw = Loc.getRawEncoding(); |
493 | 12.5M | Append(reinterpret_cast<char *>(&Raw), |
494 | 12.5M | reinterpret_cast<char *>(&Raw) + sizeof(Raw), Buffer, BufferSize, |
495 | 12.5M | BufferCapacity); |
496 | 12.5M | } |
497 | | |
498 | | /// Save a pointer to the given buffer. |
499 | | static void SavePointer(void *Ptr, char *&Buffer, unsigned &BufferSize, |
500 | 8.89M | unsigned &BufferCapacity) { |
501 | 8.89M | Append(reinterpret_cast<char *>(&Ptr), |
502 | 8.89M | reinterpret_cast<char *>(&Ptr) + sizeof(void *), |
503 | 8.89M | Buffer, BufferSize, BufferCapacity); |
504 | 8.89M | } |
505 | | |
506 | | NestedNameSpecifierLocBuilder:: |
507 | | NestedNameSpecifierLocBuilder(const NestedNameSpecifierLocBuilder &Other) |
508 | 11.9M | : Representation(Other.Representation) { |
509 | 11.9M | if (!Other.Buffer) |
510 | 11.9M | return; |
511 | | |
512 | 36.8k | if (Other.BufferCapacity == 0) { |
513 | | // Shallow copy is okay. |
514 | 27.6k | Buffer = Other.Buffer; |
515 | 27.6k | BufferSize = Other.BufferSize; |
516 | 27.6k | return; |
517 | 27.6k | } |
518 | | |
519 | | // Deep copy |
520 | 9.27k | Append(Other.Buffer, Other.Buffer + Other.BufferSize, Buffer, BufferSize, |
521 | 9.27k | BufferCapacity); |
522 | 9.27k | } |
523 | | |
524 | | NestedNameSpecifierLocBuilder & |
525 | | NestedNameSpecifierLocBuilder:: |
526 | 2.14M | operator=(const NestedNameSpecifierLocBuilder &Other) { |
527 | 2.14M | Representation = Other.Representation; |
528 | | |
529 | 2.14M | if (Buffer && Other.Buffer39 && BufferCapacity >= Other.BufferSize39 ) { |
530 | | // Re-use our storage. |
531 | 26 | BufferSize = Other.BufferSize; |
532 | 26 | memcpy(Buffer, Other.Buffer, BufferSize); |
533 | 26 | return *this; |
534 | 26 | } |
535 | | |
536 | | // Free our storage, if we have any. |
537 | 2.14M | if (BufferCapacity) { |
538 | 0 | free(Buffer); |
539 | 0 | BufferCapacity = 0; |
540 | 0 | } |
541 | | |
542 | 2.14M | if (!Other.Buffer) { |
543 | | // Empty. |
544 | 1.73M | Buffer = nullptr; |
545 | 1.73M | BufferSize = 0; |
546 | 1.73M | return *this; |
547 | 1.73M | } |
548 | | |
549 | 416k | if (Other.BufferCapacity == 0) { |
550 | | // Shallow copy is okay. |
551 | 163k | Buffer = Other.Buffer; |
552 | 163k | BufferSize = Other.BufferSize; |
553 | 163k | return *this; |
554 | 163k | } |
555 | | |
556 | | // Deep copy. |
557 | 252k | BufferSize = 0; |
558 | 252k | Append(Other.Buffer, Other.Buffer + Other.BufferSize, Buffer, BufferSize, |
559 | 252k | BufferCapacity); |
560 | 252k | return *this; |
561 | 416k | } |
562 | | |
563 | | void NestedNameSpecifierLocBuilder::Extend(ASTContext &Context, |
564 | | SourceLocation TemplateKWLoc, |
565 | | TypeLoc TL, |
566 | 7.78M | SourceLocation ColonColonLoc) { |
567 | 7.78M | Representation = NestedNameSpecifier::Create(Context, Representation, |
568 | 7.78M | TemplateKWLoc.isValid(), |
569 | 7.78M | TL.getTypePtr()); |
570 | | |
571 | | // Push source-location info into the buffer. |
572 | 7.78M | SavePointer(TL.getOpaqueData(), Buffer, BufferSize, BufferCapacity); |
573 | 7.78M | SaveSourceLocation(ColonColonLoc, Buffer, BufferSize, BufferCapacity); |
574 | 7.78M | } |
575 | | |
576 | | void NestedNameSpecifierLocBuilder::Extend(ASTContext &Context, |
577 | | IdentifierInfo *Identifier, |
578 | | SourceLocation IdentifierLoc, |
579 | 63.0k | SourceLocation ColonColonLoc) { |
580 | 63.0k | Representation = NestedNameSpecifier::Create(Context, Representation, |
581 | 63.0k | Identifier); |
582 | | |
583 | | // Push source-location info into the buffer. |
584 | 63.0k | SaveSourceLocation(IdentifierLoc, Buffer, BufferSize, BufferCapacity); |
585 | 63.0k | SaveSourceLocation(ColonColonLoc, Buffer, BufferSize, BufferCapacity); |
586 | 63.0k | } |
587 | | |
588 | | void NestedNameSpecifierLocBuilder::Extend(ASTContext &Context, |
589 | | NamespaceDecl *Namespace, |
590 | | SourceLocation NamespaceLoc, |
591 | 1.55M | SourceLocation ColonColonLoc) { |
592 | 1.55M | Representation = NestedNameSpecifier::Create(Context, Representation, |
593 | 1.55M | Namespace); |
594 | | |
595 | | // Push source-location info into the buffer. |
596 | 1.55M | SaveSourceLocation(NamespaceLoc, Buffer, BufferSize, BufferCapacity); |
597 | 1.55M | SaveSourceLocation(ColonColonLoc, Buffer, BufferSize, BufferCapacity); |
598 | 1.55M | } |
599 | | |
600 | | void NestedNameSpecifierLocBuilder::Extend(ASTContext &Context, |
601 | | NamespaceAliasDecl *Alias, |
602 | | SourceLocation AliasLoc, |
603 | 243 | SourceLocation ColonColonLoc) { |
604 | 243 | Representation = NestedNameSpecifier::Create(Context, Representation, Alias); |
605 | | |
606 | | // Push source-location info into the buffer. |
607 | 243 | SaveSourceLocation(AliasLoc, Buffer, BufferSize, BufferCapacity); |
608 | 243 | SaveSourceLocation(ColonColonLoc, Buffer, BufferSize, BufferCapacity); |
609 | 243 | } |
610 | | |
611 | | void NestedNameSpecifierLocBuilder::MakeGlobal(ASTContext &Context, |
612 | 320k | SourceLocation ColonColonLoc) { |
613 | 320k | assert(!Representation && "Already have a nested-name-specifier!?"); |
614 | 0 | Representation = NestedNameSpecifier::GlobalSpecifier(Context); |
615 | | |
616 | | // Push source-location info into the buffer. |
617 | 320k | SaveSourceLocation(ColonColonLoc, Buffer, BufferSize, BufferCapacity); |
618 | 320k | } |
619 | | |
620 | | void NestedNameSpecifierLocBuilder::MakeSuper(ASTContext &Context, |
621 | | CXXRecordDecl *RD, |
622 | | SourceLocation SuperLoc, |
623 | 58 | SourceLocation ColonColonLoc) { |
624 | 58 | Representation = NestedNameSpecifier::SuperSpecifier(Context, RD); |
625 | | |
626 | | // Push source-location info into the buffer. |
627 | 58 | SaveSourceLocation(SuperLoc, Buffer, BufferSize, BufferCapacity); |
628 | 58 | SaveSourceLocation(ColonColonLoc, Buffer, BufferSize, BufferCapacity); |
629 | 58 | } |
630 | | |
631 | | void NestedNameSpecifierLocBuilder::MakeTrivial(ASTContext &Context, |
632 | | NestedNameSpecifier *Qualifier, |
633 | 1.14M | SourceRange R) { |
634 | 1.14M | Representation = Qualifier; |
635 | | |
636 | | // Construct bogus (but well-formed) source information for the |
637 | | // nested-name-specifier. |
638 | 1.14M | BufferSize = 0; |
639 | 1.14M | SmallVector<NestedNameSpecifier *, 4> Stack; |
640 | 2.28M | for (NestedNameSpecifier *NNS = Qualifier; NNS; NNS = NNS->getPrefix()1.14M ) |
641 | 1.14M | Stack.push_back(NNS); |
642 | 2.28M | while (!Stack.empty()) { |
643 | 1.14M | NestedNameSpecifier *NNS = Stack.pop_back_val(); |
644 | 1.14M | switch (NNS->getKind()) { |
645 | 772 | case NestedNameSpecifier::Identifier: |
646 | 32.5k | case NestedNameSpecifier::Namespace: |
647 | 32.5k | case NestedNameSpecifier::NamespaceAlias: |
648 | 32.5k | SaveSourceLocation(R.getBegin(), Buffer, BufferSize, BufferCapacity); |
649 | 32.5k | break; |
650 | | |
651 | 1.10M | case NestedNameSpecifier::TypeSpec: |
652 | 1.10M | case NestedNameSpecifier::TypeSpecWithTemplate: { |
653 | 1.10M | TypeSourceInfo *TSInfo |
654 | 1.10M | = Context.getTrivialTypeSourceInfo(QualType(NNS->getAsType(), 0), |
655 | 1.10M | R.getBegin()); |
656 | 1.10M | SavePointer(TSInfo->getTypeLoc().getOpaqueData(), Buffer, BufferSize, |
657 | 1.10M | BufferCapacity); |
658 | 1.10M | break; |
659 | 1.10M | } |
660 | | |
661 | 40 | case NestedNameSpecifier::Global: |
662 | 40 | case NestedNameSpecifier::Super: |
663 | 40 | break; |
664 | 1.14M | } |
665 | | |
666 | | // Save the location of the '::'. |
667 | 1.14M | SaveSourceLocation(Stack.empty()? R.getEnd()1.13M : R.getBegin()7.42k , |
668 | 1.14M | Buffer, BufferSize, BufferCapacity); |
669 | 1.14M | } |
670 | 1.14M | } |
671 | | |
672 | 10.5M | void NestedNameSpecifierLocBuilder::Adopt(NestedNameSpecifierLoc Other) { |
673 | 10.5M | if (BufferCapacity) |
674 | 196k | free(Buffer); |
675 | | |
676 | 10.5M | if (!Other) { |
677 | 0 | Representation = nullptr; |
678 | 0 | BufferSize = 0; |
679 | 0 | return; |
680 | 0 | } |
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 | 10.5M | Representation = Other.getNestedNameSpecifier(); |
686 | 10.5M | Buffer = static_cast<char *>(Other.getOpaqueData()); |
687 | 10.5M | BufferSize = Other.getDataLength(); |
688 | 10.5M | BufferCapacity = 0; |
689 | 10.5M | } |
690 | | |
691 | | NestedNameSpecifierLoc |
692 | 17.9M | NestedNameSpecifierLocBuilder::getWithLocInContext(ASTContext &Context) const { |
693 | 17.9M | if (!Representation) |
694 | 5.83M | 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 | 12.1M | if (BufferCapacity == 0) |
699 | 3.78M | 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 | 8.36M | void *Mem = Context.Allocate(BufferSize, alignof(void *)); |
705 | 8.36M | memcpy(Mem, Buffer, BufferSize); |
706 | 8.36M | return NestedNameSpecifierLoc(Representation, Mem); |
707 | 12.1M | } |