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