1cc3cf58cSIlya Biryukov //===------- QualTypeNames.cpp - Generate Complete QualType Names ---------===//
2cc3cf58cSIlya Biryukov //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6cc3cf58cSIlya Biryukov //
7cc3cf58cSIlya Biryukov //===----------------------------------------------------------------------===//
8cc3cf58cSIlya Biryukov
9cc3cf58cSIlya Biryukov #include "clang/AST/DeclTemplate.h"
10cc3cf58cSIlya Biryukov #include "clang/AST/DeclarationName.h"
11cc3cf58cSIlya Biryukov #include "clang/AST/GlobalDecl.h"
12cc3cf58cSIlya Biryukov #include "clang/AST/Mangle.h"
13cc3cf58cSIlya Biryukov #include "clang/AST/QualTypeNames.h"
14cc3cf58cSIlya Biryukov
15cc3cf58cSIlya Biryukov #include <stdio.h>
16cc3cf58cSIlya Biryukov #include <memory>
17cc3cf58cSIlya Biryukov
18cc3cf58cSIlya Biryukov namespace clang {
19cc3cf58cSIlya Biryukov
20cc3cf58cSIlya Biryukov namespace TypeName {
21cc3cf58cSIlya Biryukov
229fc8faf9SAdrian Prantl /// Create a NestedNameSpecifier for Namesp and its enclosing
23cc3cf58cSIlya Biryukov /// scopes.
24cc3cf58cSIlya Biryukov ///
25cc3cf58cSIlya Biryukov /// \param[in] Ctx - the AST Context to be used.
26cc3cf58cSIlya Biryukov /// \param[in] Namesp - the NamespaceDecl for which a NestedNameSpecifier
27cc3cf58cSIlya Biryukov /// is requested.
28cc3cf58cSIlya Biryukov /// \param[in] WithGlobalNsPrefix - Indicate whether the global namespace
29cc3cf58cSIlya Biryukov /// specifier "::" should be prepended or not.
30cc3cf58cSIlya Biryukov static NestedNameSpecifier *createNestedNameSpecifier(
31cc3cf58cSIlya Biryukov const ASTContext &Ctx,
32cc3cf58cSIlya Biryukov const NamespaceDecl *Namesp,
33cc3cf58cSIlya Biryukov bool WithGlobalNsPrefix);
34cc3cf58cSIlya Biryukov
359fc8faf9SAdrian Prantl /// Create a NestedNameSpecifier for TagDecl and its enclosing
36cc3cf58cSIlya Biryukov /// scopes.
37cc3cf58cSIlya Biryukov ///
38cc3cf58cSIlya Biryukov /// \param[in] Ctx - the AST Context to be used.
39cc3cf58cSIlya Biryukov /// \param[in] TD - the TagDecl for which a NestedNameSpecifier is
40cc3cf58cSIlya Biryukov /// requested.
41cc3cf58cSIlya Biryukov /// \param[in] FullyQualify - Convert all template arguments into fully
42cc3cf58cSIlya Biryukov /// qualified names.
43cc3cf58cSIlya Biryukov /// \param[in] WithGlobalNsPrefix - Indicate whether the global namespace
44cc3cf58cSIlya Biryukov /// specifier "::" should be prepended or not.
45cc3cf58cSIlya Biryukov static NestedNameSpecifier *createNestedNameSpecifier(
46cc3cf58cSIlya Biryukov const ASTContext &Ctx, const TypeDecl *TD,
47cc3cf58cSIlya Biryukov bool FullyQualify, bool WithGlobalNsPrefix);
48cc3cf58cSIlya Biryukov
49cc3cf58cSIlya Biryukov static NestedNameSpecifier *createNestedNameSpecifierForScopeOf(
50cc3cf58cSIlya Biryukov const ASTContext &Ctx, const Decl *decl,
51cc3cf58cSIlya Biryukov bool FullyQualified, bool WithGlobalNsPrefix);
52cc3cf58cSIlya Biryukov
53cc3cf58cSIlya Biryukov static NestedNameSpecifier *getFullyQualifiedNestedNameSpecifier(
54cc3cf58cSIlya Biryukov const ASTContext &Ctx, NestedNameSpecifier *scope, bool WithGlobalNsPrefix);
55cc3cf58cSIlya Biryukov
getFullyQualifiedTemplateName(const ASTContext & Ctx,TemplateName & TName,bool WithGlobalNsPrefix)56cc3cf58cSIlya Biryukov static bool getFullyQualifiedTemplateName(const ASTContext &Ctx,
57cc3cf58cSIlya Biryukov TemplateName &TName,
58cc3cf58cSIlya Biryukov bool WithGlobalNsPrefix) {
59cc3cf58cSIlya Biryukov bool Changed = false;
60cc3cf58cSIlya Biryukov NestedNameSpecifier *NNS = nullptr;
61cc3cf58cSIlya Biryukov
62cc3cf58cSIlya Biryukov TemplateDecl *ArgTDecl = TName.getAsTemplateDecl();
63cc3cf58cSIlya Biryukov // ArgTDecl won't be NULL because we asserted that this isn't a
64cc3cf58cSIlya Biryukov // dependent context very early in the call chain.
65cc3cf58cSIlya Biryukov assert(ArgTDecl != nullptr);
66cc3cf58cSIlya Biryukov QualifiedTemplateName *QTName = TName.getAsQualifiedTemplateName();
67cc3cf58cSIlya Biryukov
68cc3cf58cSIlya Biryukov if (QTName && !QTName->hasTemplateKeyword()) {
69cc3cf58cSIlya Biryukov NNS = QTName->getQualifier();
70cc3cf58cSIlya Biryukov NestedNameSpecifier *QNNS = getFullyQualifiedNestedNameSpecifier(
71cc3cf58cSIlya Biryukov Ctx, NNS, WithGlobalNsPrefix);
72cc3cf58cSIlya Biryukov if (QNNS != NNS) {
73cc3cf58cSIlya Biryukov Changed = true;
74cc3cf58cSIlya Biryukov NNS = QNNS;
75cc3cf58cSIlya Biryukov } else {
76cc3cf58cSIlya Biryukov NNS = nullptr;
77cc3cf58cSIlya Biryukov }
78cc3cf58cSIlya Biryukov } else {
79cc3cf58cSIlya Biryukov NNS = createNestedNameSpecifierForScopeOf(
80cc3cf58cSIlya Biryukov Ctx, ArgTDecl, true, WithGlobalNsPrefix);
81cc3cf58cSIlya Biryukov }
82cc3cf58cSIlya Biryukov if (NNS) {
831234b1c6SHaojian Wu TemplateName UnderlyingTN(ArgTDecl);
841234b1c6SHaojian Wu if (UsingShadowDecl *USD = TName.getAsUsingShadowDecl())
851234b1c6SHaojian Wu UnderlyingTN = TemplateName(USD);
861234b1c6SHaojian Wu TName =
871234b1c6SHaojian Wu Ctx.getQualifiedTemplateName(NNS,
881234b1c6SHaojian Wu /*TemplateKeyword=*/false, UnderlyingTN);
89cc3cf58cSIlya Biryukov Changed = true;
90cc3cf58cSIlya Biryukov }
91cc3cf58cSIlya Biryukov return Changed;
92cc3cf58cSIlya Biryukov }
93cc3cf58cSIlya Biryukov
getFullyQualifiedTemplateArgument(const ASTContext & Ctx,TemplateArgument & Arg,bool WithGlobalNsPrefix)94cc3cf58cSIlya Biryukov static bool getFullyQualifiedTemplateArgument(const ASTContext &Ctx,
95cc3cf58cSIlya Biryukov TemplateArgument &Arg,
96cc3cf58cSIlya Biryukov bool WithGlobalNsPrefix) {
97cc3cf58cSIlya Biryukov bool Changed = false;
98cc3cf58cSIlya Biryukov
99cc3cf58cSIlya Biryukov // Note: we do not handle TemplateArgument::Expression, to replace it
100cc3cf58cSIlya Biryukov // we need the information for the template instance decl.
101cc3cf58cSIlya Biryukov
102cc3cf58cSIlya Biryukov if (Arg.getKind() == TemplateArgument::Template) {
103cc3cf58cSIlya Biryukov TemplateName TName = Arg.getAsTemplate();
104cc3cf58cSIlya Biryukov Changed = getFullyQualifiedTemplateName(Ctx, TName, WithGlobalNsPrefix);
105cc3cf58cSIlya Biryukov if (Changed) {
106cc3cf58cSIlya Biryukov Arg = TemplateArgument(TName);
107cc3cf58cSIlya Biryukov }
108cc3cf58cSIlya Biryukov } else if (Arg.getKind() == TemplateArgument::Type) {
109cc3cf58cSIlya Biryukov QualType SubTy = Arg.getAsType();
110cc3cf58cSIlya Biryukov // Check if the type needs more desugaring and recurse.
111cc3cf58cSIlya Biryukov QualType QTFQ = getFullyQualifiedType(SubTy, Ctx, WithGlobalNsPrefix);
112cc3cf58cSIlya Biryukov if (QTFQ != SubTy) {
113cc3cf58cSIlya Biryukov Arg = TemplateArgument(QTFQ);
114cc3cf58cSIlya Biryukov Changed = true;
115cc3cf58cSIlya Biryukov }
116cc3cf58cSIlya Biryukov }
117cc3cf58cSIlya Biryukov return Changed;
118cc3cf58cSIlya Biryukov }
119cc3cf58cSIlya Biryukov
getFullyQualifiedTemplateType(const ASTContext & Ctx,const Type * TypePtr,bool WithGlobalNsPrefix)120cc3cf58cSIlya Biryukov static const Type *getFullyQualifiedTemplateType(const ASTContext &Ctx,
121cc3cf58cSIlya Biryukov const Type *TypePtr,
122cc3cf58cSIlya Biryukov bool WithGlobalNsPrefix) {
123cc3cf58cSIlya Biryukov // DependentTemplateTypes exist within template declarations and
124cc3cf58cSIlya Biryukov // definitions. Therefore we shouldn't encounter them at the end of
125cc3cf58cSIlya Biryukov // a translation unit. If we do, the caller has made an error.
126cc3cf58cSIlya Biryukov assert(!isa<DependentTemplateSpecializationType>(TypePtr));
127cc3cf58cSIlya Biryukov // In case of template specializations, iterate over the arguments
128cc3cf58cSIlya Biryukov // and fully qualify them as well.
129cc3cf58cSIlya Biryukov if (const auto *TST = dyn_cast<const TemplateSpecializationType>(TypePtr)) {
130cc3cf58cSIlya Biryukov bool MightHaveChanged = false;
131cc3cf58cSIlya Biryukov SmallVector<TemplateArgument, 4> FQArgs;
132cc3cf58cSIlya Biryukov for (TemplateSpecializationType::iterator I = TST->begin(), E = TST->end();
133cc3cf58cSIlya Biryukov I != E; ++I) {
134cc3cf58cSIlya Biryukov // Cheap to copy and potentially modified by
135cc3cf58cSIlya Biryukov // getFullyQualifedTemplateArgument.
136cc3cf58cSIlya Biryukov TemplateArgument Arg(*I);
137cc3cf58cSIlya Biryukov MightHaveChanged |= getFullyQualifiedTemplateArgument(
138cc3cf58cSIlya Biryukov Ctx, Arg, WithGlobalNsPrefix);
139cc3cf58cSIlya Biryukov FQArgs.push_back(Arg);
140cc3cf58cSIlya Biryukov }
141cc3cf58cSIlya Biryukov
142cc3cf58cSIlya Biryukov // If a fully qualified arg is different from the unqualified arg,
143cc3cf58cSIlya Biryukov // allocate new type in the AST.
144cc3cf58cSIlya Biryukov if (MightHaveChanged) {
145cc3cf58cSIlya Biryukov QualType QT = Ctx.getTemplateSpecializationType(
146cc3cf58cSIlya Biryukov TST->getTemplateName(), FQArgs,
147cc3cf58cSIlya Biryukov TST->getCanonicalTypeInternal());
148cc3cf58cSIlya Biryukov // getTemplateSpecializationType returns a fully qualified
149cc3cf58cSIlya Biryukov // version of the specialization itself, so no need to qualify
150cc3cf58cSIlya Biryukov // it.
151cc3cf58cSIlya Biryukov return QT.getTypePtr();
152cc3cf58cSIlya Biryukov }
153cc3cf58cSIlya Biryukov } else if (const auto *TSTRecord = dyn_cast<const RecordType>(TypePtr)) {
154cc3cf58cSIlya Biryukov // We are asked to fully qualify and we have a Record Type,
155cc3cf58cSIlya Biryukov // which can point to a template instantiation with no sugar in any of
156cc3cf58cSIlya Biryukov // its template argument, however we still need to fully qualify them.
157cc3cf58cSIlya Biryukov
158cc3cf58cSIlya Biryukov if (const auto *TSTDecl =
159cc3cf58cSIlya Biryukov dyn_cast<ClassTemplateSpecializationDecl>(TSTRecord->getDecl())) {
160cc3cf58cSIlya Biryukov const TemplateArgumentList &TemplateArgs = TSTDecl->getTemplateArgs();
161cc3cf58cSIlya Biryukov
162cc3cf58cSIlya Biryukov bool MightHaveChanged = false;
163cc3cf58cSIlya Biryukov SmallVector<TemplateArgument, 4> FQArgs;
164cc3cf58cSIlya Biryukov for (unsigned int I = 0, E = TemplateArgs.size(); I != E; ++I) {
165cc3cf58cSIlya Biryukov // cheap to copy and potentially modified by
166cc3cf58cSIlya Biryukov // getFullyQualifedTemplateArgument
167cc3cf58cSIlya Biryukov TemplateArgument Arg(TemplateArgs[I]);
168cc3cf58cSIlya Biryukov MightHaveChanged |= getFullyQualifiedTemplateArgument(
169cc3cf58cSIlya Biryukov Ctx, Arg, WithGlobalNsPrefix);
170cc3cf58cSIlya Biryukov FQArgs.push_back(Arg);
171cc3cf58cSIlya Biryukov }
172cc3cf58cSIlya Biryukov
173cc3cf58cSIlya Biryukov // If a fully qualified arg is different from the unqualified arg,
174cc3cf58cSIlya Biryukov // allocate new type in the AST.
175cc3cf58cSIlya Biryukov if (MightHaveChanged) {
176cc3cf58cSIlya Biryukov TemplateName TN(TSTDecl->getSpecializedTemplate());
177cc3cf58cSIlya Biryukov QualType QT = Ctx.getTemplateSpecializationType(
178cc3cf58cSIlya Biryukov TN, FQArgs,
179cc3cf58cSIlya Biryukov TSTRecord->getCanonicalTypeInternal());
180cc3cf58cSIlya Biryukov // getTemplateSpecializationType returns a fully qualified
181cc3cf58cSIlya Biryukov // version of the specialization itself, so no need to qualify
182cc3cf58cSIlya Biryukov // it.
183cc3cf58cSIlya Biryukov return QT.getTypePtr();
184cc3cf58cSIlya Biryukov }
185cc3cf58cSIlya Biryukov }
186cc3cf58cSIlya Biryukov }
187cc3cf58cSIlya Biryukov return TypePtr;
188cc3cf58cSIlya Biryukov }
189cc3cf58cSIlya Biryukov
createOuterNNS(const ASTContext & Ctx,const Decl * D,bool FullyQualify,bool WithGlobalNsPrefix)190cc3cf58cSIlya Biryukov static NestedNameSpecifier *createOuterNNS(const ASTContext &Ctx, const Decl *D,
191cc3cf58cSIlya Biryukov bool FullyQualify,
192cc3cf58cSIlya Biryukov bool WithGlobalNsPrefix) {
193cc3cf58cSIlya Biryukov const DeclContext *DC = D->getDeclContext();
194cc3cf58cSIlya Biryukov if (const auto *NS = dyn_cast<NamespaceDecl>(DC)) {
195cc3cf58cSIlya Biryukov while (NS && NS->isInline()) {
196cc3cf58cSIlya Biryukov // Ignore inline namespace;
197cc3cf58cSIlya Biryukov NS = dyn_cast<NamespaceDecl>(NS->getDeclContext());
198cc3cf58cSIlya Biryukov }
199128f39daSAlexey Bader if (NS && NS->getDeclName()) {
200cc3cf58cSIlya Biryukov return createNestedNameSpecifier(Ctx, NS, WithGlobalNsPrefix);
201cc3cf58cSIlya Biryukov }
202cc3cf58cSIlya Biryukov return nullptr; // no starting '::', no anonymous
203cc3cf58cSIlya Biryukov } else if (const auto *TD = dyn_cast<TagDecl>(DC)) {
204cc3cf58cSIlya Biryukov return createNestedNameSpecifier(Ctx, TD, FullyQualify, WithGlobalNsPrefix);
205cc3cf58cSIlya Biryukov } else if (const auto *TDD = dyn_cast<TypedefNameDecl>(DC)) {
206cc3cf58cSIlya Biryukov return createNestedNameSpecifier(
207cc3cf58cSIlya Biryukov Ctx, TDD, FullyQualify, WithGlobalNsPrefix);
208cc3cf58cSIlya Biryukov } else if (WithGlobalNsPrefix && DC->isTranslationUnit()) {
209cc3cf58cSIlya Biryukov return NestedNameSpecifier::GlobalSpecifier(Ctx);
210cc3cf58cSIlya Biryukov }
211cc3cf58cSIlya Biryukov return nullptr; // no starting '::' if |WithGlobalNsPrefix| is false
212cc3cf58cSIlya Biryukov }
213cc3cf58cSIlya Biryukov
2149fc8faf9SAdrian Prantl /// Return a fully qualified version of this name specifier.
getFullyQualifiedNestedNameSpecifier(const ASTContext & Ctx,NestedNameSpecifier * Scope,bool WithGlobalNsPrefix)215cc3cf58cSIlya Biryukov static NestedNameSpecifier *getFullyQualifiedNestedNameSpecifier(
216cc3cf58cSIlya Biryukov const ASTContext &Ctx, NestedNameSpecifier *Scope,
217cc3cf58cSIlya Biryukov bool WithGlobalNsPrefix) {
218cc3cf58cSIlya Biryukov switch (Scope->getKind()) {
219cc3cf58cSIlya Biryukov case NestedNameSpecifier::Global:
220cc3cf58cSIlya Biryukov // Already fully qualified
221cc3cf58cSIlya Biryukov return Scope;
222cc3cf58cSIlya Biryukov case NestedNameSpecifier::Namespace:
223cc3cf58cSIlya Biryukov return TypeName::createNestedNameSpecifier(
224cc3cf58cSIlya Biryukov Ctx, Scope->getAsNamespace(), WithGlobalNsPrefix);
225cc3cf58cSIlya Biryukov case NestedNameSpecifier::NamespaceAlias:
226cc3cf58cSIlya Biryukov // Namespace aliases are only valid for the duration of the
227cc3cf58cSIlya Biryukov // scope where they were introduced, and therefore are often
228cc3cf58cSIlya Biryukov // invalid at the end of the TU. So use the namespace name more
229cc3cf58cSIlya Biryukov // likely to be valid at the end of the TU.
230cc3cf58cSIlya Biryukov return TypeName::createNestedNameSpecifier(
231cc3cf58cSIlya Biryukov Ctx,
232cc3cf58cSIlya Biryukov Scope->getAsNamespaceAlias()->getNamespace()->getCanonicalDecl(),
233cc3cf58cSIlya Biryukov WithGlobalNsPrefix);
234cc3cf58cSIlya Biryukov case NestedNameSpecifier::Identifier:
235cc3cf58cSIlya Biryukov // A function or some other construct that makes it un-namable
236cc3cf58cSIlya Biryukov // at the end of the TU. Skip the current component of the name,
237cc3cf58cSIlya Biryukov // but use the name of it's prefix.
238cc3cf58cSIlya Biryukov return getFullyQualifiedNestedNameSpecifier(
239cc3cf58cSIlya Biryukov Ctx, Scope->getPrefix(), WithGlobalNsPrefix);
240cc3cf58cSIlya Biryukov case NestedNameSpecifier::Super:
241cc3cf58cSIlya Biryukov case NestedNameSpecifier::TypeSpec:
242cc3cf58cSIlya Biryukov case NestedNameSpecifier::TypeSpecWithTemplate: {
243cc3cf58cSIlya Biryukov const Type *Type = Scope->getAsType();
244cc3cf58cSIlya Biryukov // Find decl context.
245cc3cf58cSIlya Biryukov const TagDecl *TD = nullptr;
246cc3cf58cSIlya Biryukov if (const TagType *TagDeclType = Type->getAs<TagType>()) {
247cc3cf58cSIlya Biryukov TD = TagDeclType->getDecl();
248cc3cf58cSIlya Biryukov } else {
249cc3cf58cSIlya Biryukov TD = Type->getAsCXXRecordDecl();
250cc3cf58cSIlya Biryukov }
251cc3cf58cSIlya Biryukov if (TD) {
252cc3cf58cSIlya Biryukov return TypeName::createNestedNameSpecifier(Ctx, TD,
253cc3cf58cSIlya Biryukov true /*FullyQualified*/,
254cc3cf58cSIlya Biryukov WithGlobalNsPrefix);
255cc3cf58cSIlya Biryukov } else if (const auto *TDD = dyn_cast<TypedefType>(Type)) {
256cc3cf58cSIlya Biryukov return TypeName::createNestedNameSpecifier(Ctx, TDD->getDecl(),
257cc3cf58cSIlya Biryukov true /*FullyQualified*/,
258cc3cf58cSIlya Biryukov WithGlobalNsPrefix);
259cc3cf58cSIlya Biryukov }
260cc3cf58cSIlya Biryukov return Scope;
261cc3cf58cSIlya Biryukov }
262cc3cf58cSIlya Biryukov }
263cc3cf58cSIlya Biryukov llvm_unreachable("bad NNS kind");
264cc3cf58cSIlya Biryukov }
265cc3cf58cSIlya Biryukov
2669fc8faf9SAdrian Prantl /// Create a nested name specifier for the declaring context of
267cc3cf58cSIlya Biryukov /// the type.
createNestedNameSpecifierForScopeOf(const ASTContext & Ctx,const Decl * Decl,bool FullyQualified,bool WithGlobalNsPrefix)268cc3cf58cSIlya Biryukov static NestedNameSpecifier *createNestedNameSpecifierForScopeOf(
269cc3cf58cSIlya Biryukov const ASTContext &Ctx, const Decl *Decl,
270cc3cf58cSIlya Biryukov bool FullyQualified, bool WithGlobalNsPrefix) {
271cc3cf58cSIlya Biryukov assert(Decl);
272cc3cf58cSIlya Biryukov
273cc3cf58cSIlya Biryukov const DeclContext *DC = Decl->getDeclContext()->getRedeclContext();
274cc3cf58cSIlya Biryukov const auto *Outer = dyn_cast_or_null<NamedDecl>(DC);
275cc3cf58cSIlya Biryukov const auto *OuterNS = dyn_cast_or_null<NamespaceDecl>(DC);
276cc3cf58cSIlya Biryukov if (Outer && !(OuterNS && OuterNS->isAnonymousNamespace())) {
277cc3cf58cSIlya Biryukov if (const auto *CxxDecl = dyn_cast<CXXRecordDecl>(DC)) {
278cc3cf58cSIlya Biryukov if (ClassTemplateDecl *ClassTempl =
279cc3cf58cSIlya Biryukov CxxDecl->getDescribedClassTemplate()) {
280cc3cf58cSIlya Biryukov // We are in the case of a type(def) that was declared in a
281cc3cf58cSIlya Biryukov // class template but is *not* type dependent. In clang, it
282cc3cf58cSIlya Biryukov // gets attached to the class template declaration rather than
283cc3cf58cSIlya Biryukov // any specific class template instantiation. This result in
284cc3cf58cSIlya Biryukov // 'odd' fully qualified typename:
285cc3cf58cSIlya Biryukov //
286cc3cf58cSIlya Biryukov // vector<_Tp,_Alloc>::size_type
287cc3cf58cSIlya Biryukov //
288cc3cf58cSIlya Biryukov // Make the situation is 'useable' but looking a bit odd by
289cc3cf58cSIlya Biryukov // picking a random instance as the declaring context.
290cc3cf58cSIlya Biryukov if (ClassTempl->spec_begin() != ClassTempl->spec_end()) {
291cc3cf58cSIlya Biryukov Decl = *(ClassTempl->spec_begin());
292cc3cf58cSIlya Biryukov Outer = dyn_cast<NamedDecl>(Decl);
293cc3cf58cSIlya Biryukov OuterNS = dyn_cast<NamespaceDecl>(Decl);
294cc3cf58cSIlya Biryukov }
295cc3cf58cSIlya Biryukov }
296cc3cf58cSIlya Biryukov }
297cc3cf58cSIlya Biryukov
298cc3cf58cSIlya Biryukov if (OuterNS) {
299cc3cf58cSIlya Biryukov return createNestedNameSpecifier(Ctx, OuterNS, WithGlobalNsPrefix);
300cc3cf58cSIlya Biryukov } else if (const auto *TD = dyn_cast<TagDecl>(Outer)) {
301cc3cf58cSIlya Biryukov return createNestedNameSpecifier(
302cc3cf58cSIlya Biryukov Ctx, TD, FullyQualified, WithGlobalNsPrefix);
303d0ac215dSKazu Hirata } else if (isa<TranslationUnitDecl>(Outer)) {
304cc3cf58cSIlya Biryukov // Context is the TU. Nothing needs to be done.
305cc3cf58cSIlya Biryukov return nullptr;
306cc3cf58cSIlya Biryukov } else {
307cc3cf58cSIlya Biryukov // Decl's context was neither the TU, a namespace, nor a
308cc3cf58cSIlya Biryukov // TagDecl, which means it is a type local to a scope, and not
309cc3cf58cSIlya Biryukov // accessible at the end of the TU.
310cc3cf58cSIlya Biryukov return nullptr;
311cc3cf58cSIlya Biryukov }
312cc3cf58cSIlya Biryukov } else if (WithGlobalNsPrefix && DC->isTranslationUnit()) {
313cc3cf58cSIlya Biryukov return NestedNameSpecifier::GlobalSpecifier(Ctx);
314cc3cf58cSIlya Biryukov }
315cc3cf58cSIlya Biryukov return nullptr;
316cc3cf58cSIlya Biryukov }
317cc3cf58cSIlya Biryukov
3189fc8faf9SAdrian Prantl /// Create a nested name specifier for the declaring context of
319cc3cf58cSIlya Biryukov /// the type.
createNestedNameSpecifierForScopeOf(const ASTContext & Ctx,const Type * TypePtr,bool FullyQualified,bool WithGlobalNsPrefix)320cc3cf58cSIlya Biryukov static NestedNameSpecifier *createNestedNameSpecifierForScopeOf(
321cc3cf58cSIlya Biryukov const ASTContext &Ctx, const Type *TypePtr,
322cc3cf58cSIlya Biryukov bool FullyQualified, bool WithGlobalNsPrefix) {
323cc3cf58cSIlya Biryukov if (!TypePtr) return nullptr;
324cc3cf58cSIlya Biryukov
325cc3cf58cSIlya Biryukov Decl *Decl = nullptr;
326cc3cf58cSIlya Biryukov // There are probably other cases ...
327cc3cf58cSIlya Biryukov if (const auto *TDT = dyn_cast<TypedefType>(TypePtr)) {
328cc3cf58cSIlya Biryukov Decl = TDT->getDecl();
329cc3cf58cSIlya Biryukov } else if (const auto *TagDeclType = dyn_cast<TagType>(TypePtr)) {
330cc3cf58cSIlya Biryukov Decl = TagDeclType->getDecl();
331cc3cf58cSIlya Biryukov } else if (const auto *TST = dyn_cast<TemplateSpecializationType>(TypePtr)) {
332cc3cf58cSIlya Biryukov Decl = TST->getTemplateName().getAsTemplateDecl();
333cc3cf58cSIlya Biryukov } else {
334cc3cf58cSIlya Biryukov Decl = TypePtr->getAsCXXRecordDecl();
335cc3cf58cSIlya Biryukov }
336cc3cf58cSIlya Biryukov
337cc3cf58cSIlya Biryukov if (!Decl) return nullptr;
338cc3cf58cSIlya Biryukov
339cc3cf58cSIlya Biryukov return createNestedNameSpecifierForScopeOf(
340cc3cf58cSIlya Biryukov Ctx, Decl, FullyQualified, WithGlobalNsPrefix);
341cc3cf58cSIlya Biryukov }
342cc3cf58cSIlya Biryukov
createNestedNameSpecifier(const ASTContext & Ctx,const NamespaceDecl * Namespace,bool WithGlobalNsPrefix)343cc3cf58cSIlya Biryukov NestedNameSpecifier *createNestedNameSpecifier(const ASTContext &Ctx,
344cc3cf58cSIlya Biryukov const NamespaceDecl *Namespace,
345cc3cf58cSIlya Biryukov bool WithGlobalNsPrefix) {
346cc3cf58cSIlya Biryukov while (Namespace && Namespace->isInline()) {
347cc3cf58cSIlya Biryukov // Ignore inline namespace;
348cc3cf58cSIlya Biryukov Namespace = dyn_cast<NamespaceDecl>(Namespace->getDeclContext());
349cc3cf58cSIlya Biryukov }
350cc3cf58cSIlya Biryukov if (!Namespace) return nullptr;
351cc3cf58cSIlya Biryukov
352cc3cf58cSIlya Biryukov bool FullyQualified = true; // doesn't matter, DeclContexts are namespaces
353cc3cf58cSIlya Biryukov return NestedNameSpecifier::Create(
354cc3cf58cSIlya Biryukov Ctx,
355cc3cf58cSIlya Biryukov createOuterNNS(Ctx, Namespace, FullyQualified, WithGlobalNsPrefix),
356cc3cf58cSIlya Biryukov Namespace);
357cc3cf58cSIlya Biryukov }
358cc3cf58cSIlya Biryukov
createNestedNameSpecifier(const ASTContext & Ctx,const TypeDecl * TD,bool FullyQualify,bool WithGlobalNsPrefix)359cc3cf58cSIlya Biryukov NestedNameSpecifier *createNestedNameSpecifier(const ASTContext &Ctx,
360cc3cf58cSIlya Biryukov const TypeDecl *TD,
361cc3cf58cSIlya Biryukov bool FullyQualify,
362cc3cf58cSIlya Biryukov bool WithGlobalNsPrefix) {
3633e55f550SVictor Kuznetsov const Type *TypePtr = TD->getTypeForDecl();
3643e55f550SVictor Kuznetsov if (isa<const TemplateSpecializationType>(TypePtr) ||
3653e55f550SVictor Kuznetsov isa<const RecordType>(TypePtr)) {
3663e55f550SVictor Kuznetsov // We are asked to fully qualify and we have a Record Type (which
3673e55f550SVictor Kuznetsov // may point to a template specialization) or Template
3683e55f550SVictor Kuznetsov // Specialization Type. We need to fully qualify their arguments.
3693e55f550SVictor Kuznetsov
3703e55f550SVictor Kuznetsov TypePtr = getFullyQualifiedTemplateType(Ctx, TypePtr, WithGlobalNsPrefix);
3713e55f550SVictor Kuznetsov }
3723e55f550SVictor Kuznetsov
373cc3cf58cSIlya Biryukov return NestedNameSpecifier::Create(
3743e55f550SVictor Kuznetsov Ctx, createOuterNNS(Ctx, TD, FullyQualify, WithGlobalNsPrefix),
3753e55f550SVictor Kuznetsov false /*No TemplateKeyword*/, TypePtr);
376cc3cf58cSIlya Biryukov }
377cc3cf58cSIlya Biryukov
3789fc8faf9SAdrian Prantl /// Return the fully qualified type, including fully-qualified
379cc3cf58cSIlya Biryukov /// versions of any template parameters.
getFullyQualifiedType(QualType QT,const ASTContext & Ctx,bool WithGlobalNsPrefix)380cc3cf58cSIlya Biryukov QualType getFullyQualifiedType(QualType QT, const ASTContext &Ctx,
381cc3cf58cSIlya Biryukov bool WithGlobalNsPrefix) {
382cc3cf58cSIlya Biryukov // In case of myType* we need to strip the pointer first, fully
383cc3cf58cSIlya Biryukov // qualify and attach the pointer once again.
384cc3cf58cSIlya Biryukov if (isa<PointerType>(QT.getTypePtr())) {
385cc3cf58cSIlya Biryukov // Get the qualifiers.
386cc3cf58cSIlya Biryukov Qualifiers Quals = QT.getQualifiers();
387cc3cf58cSIlya Biryukov QT = getFullyQualifiedType(QT->getPointeeType(), Ctx, WithGlobalNsPrefix);
388cc3cf58cSIlya Biryukov QT = Ctx.getPointerType(QT);
389cc3cf58cSIlya Biryukov // Add back the qualifiers.
390cc3cf58cSIlya Biryukov QT = Ctx.getQualifiedType(QT, Quals);
391cc3cf58cSIlya Biryukov return QT;
392cc3cf58cSIlya Biryukov }
393cc3cf58cSIlya Biryukov
394a65ec7eeSBenjamin Kramer if (auto *MPT = dyn_cast<MemberPointerType>(QT.getTypePtr())) {
395a65ec7eeSBenjamin Kramer // Get the qualifiers.
396a65ec7eeSBenjamin Kramer Qualifiers Quals = QT.getQualifiers();
397a65ec7eeSBenjamin Kramer // Fully qualify the pointee and class types.
398a65ec7eeSBenjamin Kramer QT = getFullyQualifiedType(QT->getPointeeType(), Ctx, WithGlobalNsPrefix);
399a65ec7eeSBenjamin Kramer QualType Class = getFullyQualifiedType(QualType(MPT->getClass(), 0), Ctx,
400a65ec7eeSBenjamin Kramer WithGlobalNsPrefix);
401a65ec7eeSBenjamin Kramer QT = Ctx.getMemberPointerType(QT, Class.getTypePtr());
402a65ec7eeSBenjamin Kramer // Add back the qualifiers.
403a65ec7eeSBenjamin Kramer QT = Ctx.getQualifiedType(QT, Quals);
404a65ec7eeSBenjamin Kramer return QT;
405a65ec7eeSBenjamin Kramer }
406a65ec7eeSBenjamin Kramer
407cc3cf58cSIlya Biryukov // In case of myType& we need to strip the reference first, fully
408cc3cf58cSIlya Biryukov // qualify and attach the reference once again.
409cc3cf58cSIlya Biryukov if (isa<ReferenceType>(QT.getTypePtr())) {
410cc3cf58cSIlya Biryukov // Get the qualifiers.
411cc3cf58cSIlya Biryukov bool IsLValueRefTy = isa<LValueReferenceType>(QT.getTypePtr());
412cc3cf58cSIlya Biryukov Qualifiers Quals = QT.getQualifiers();
413cc3cf58cSIlya Biryukov QT = getFullyQualifiedType(QT->getPointeeType(), Ctx, WithGlobalNsPrefix);
414cc3cf58cSIlya Biryukov // Add the r- or l-value reference type back to the fully
415cc3cf58cSIlya Biryukov // qualified one.
416cc3cf58cSIlya Biryukov if (IsLValueRefTy)
417cc3cf58cSIlya Biryukov QT = Ctx.getLValueReferenceType(QT);
418cc3cf58cSIlya Biryukov else
419cc3cf58cSIlya Biryukov QT = Ctx.getRValueReferenceType(QT);
420cc3cf58cSIlya Biryukov // Add back the qualifiers.
421cc3cf58cSIlya Biryukov QT = Ctx.getQualifiedType(QT, Quals);
422cc3cf58cSIlya Biryukov return QT;
423cc3cf58cSIlya Biryukov }
424cc3cf58cSIlya Biryukov
425*888673b6SJonas Devlieghere // We don't consider the alias introduced by `using a::X` as a new type.
426*888673b6SJonas Devlieghere // The qualified name is still a::X.
427*888673b6SJonas Devlieghere if (isa<UsingType>(QT.getTypePtr())) {
428*888673b6SJonas Devlieghere return getFullyQualifiedType(QT.getSingleStepDesugaredType(Ctx), Ctx,
429*888673b6SJonas Devlieghere WithGlobalNsPrefix);
430*888673b6SJonas Devlieghere }
431*888673b6SJonas Devlieghere
432cc3cf58cSIlya Biryukov // Remove the part of the type related to the type being a template
433cc3cf58cSIlya Biryukov // parameter (we won't report it as part of the 'type name' and it
434cc3cf58cSIlya Biryukov // is actually make the code below to be more complex (to handle
435cc3cf58cSIlya Biryukov // those)
436cc3cf58cSIlya Biryukov while (isa<SubstTemplateTypeParmType>(QT.getTypePtr())) {
437cc3cf58cSIlya Biryukov // Get the qualifiers.
438cc3cf58cSIlya Biryukov Qualifiers Quals = QT.getQualifiers();
439cc3cf58cSIlya Biryukov
440294016b8SCraig Topper QT = cast<SubstTemplateTypeParmType>(QT.getTypePtr())->desugar();
441cc3cf58cSIlya Biryukov
442cc3cf58cSIlya Biryukov // Add back the qualifiers.
443cc3cf58cSIlya Biryukov QT = Ctx.getQualifiedType(QT, Quals);
444cc3cf58cSIlya Biryukov }
445cc3cf58cSIlya Biryukov
446cc3cf58cSIlya Biryukov NestedNameSpecifier *Prefix = nullptr;
447cc3cf58cSIlya Biryukov // Local qualifiers are attached to the QualType outside of the
448cc3cf58cSIlya Biryukov // elaborated type. Retrieve them before descending into the
449cc3cf58cSIlya Biryukov // elaborated type.
450cc3cf58cSIlya Biryukov Qualifiers PrefixQualifiers = QT.getLocalQualifiers();
451cc3cf58cSIlya Biryukov QT = QualType(QT.getTypePtr(), 0);
452cc3cf58cSIlya Biryukov ElaboratedTypeKeyword Keyword = ETK_None;
453cc3cf58cSIlya Biryukov if (const auto *ETypeInput = dyn_cast<ElaboratedType>(QT.getTypePtr())) {
454cc3cf58cSIlya Biryukov QT = ETypeInput->getNamedType();
455cc3cf58cSIlya Biryukov assert(!QT.hasLocalQualifiers());
456cc3cf58cSIlya Biryukov Keyword = ETypeInput->getKeyword();
457cc3cf58cSIlya Biryukov }
458cc3cf58cSIlya Biryukov // Create a nested name specifier if needed.
459cc3cf58cSIlya Biryukov Prefix = createNestedNameSpecifierForScopeOf(Ctx, QT.getTypePtr(),
460cc3cf58cSIlya Biryukov true /*FullyQualified*/,
461cc3cf58cSIlya Biryukov WithGlobalNsPrefix);
462cc3cf58cSIlya Biryukov
463cc3cf58cSIlya Biryukov // In case of template specializations iterate over the arguments and
464cc3cf58cSIlya Biryukov // fully qualify them as well.
465cc3cf58cSIlya Biryukov if (isa<const TemplateSpecializationType>(QT.getTypePtr()) ||
466cc3cf58cSIlya Biryukov isa<const RecordType>(QT.getTypePtr())) {
467cc3cf58cSIlya Biryukov // We are asked to fully qualify and we have a Record Type (which
468cc3cf58cSIlya Biryukov // may point to a template specialization) or Template
469cc3cf58cSIlya Biryukov // Specialization Type. We need to fully qualify their arguments.
470cc3cf58cSIlya Biryukov
471cc3cf58cSIlya Biryukov const Type *TypePtr = getFullyQualifiedTemplateType(
472cc3cf58cSIlya Biryukov Ctx, QT.getTypePtr(), WithGlobalNsPrefix);
473cc3cf58cSIlya Biryukov QT = QualType(TypePtr, 0);
474cc3cf58cSIlya Biryukov }
475cc3cf58cSIlya Biryukov if (Prefix || Keyword != ETK_None) {
476cc3cf58cSIlya Biryukov QT = Ctx.getElaboratedType(Keyword, Prefix, QT);
477cc3cf58cSIlya Biryukov }
478cc3cf58cSIlya Biryukov QT = Ctx.getQualifiedType(QT, PrefixQualifiers);
479cc3cf58cSIlya Biryukov return QT;
480cc3cf58cSIlya Biryukov }
481cc3cf58cSIlya Biryukov
getFullyQualifiedName(QualType QT,const ASTContext & Ctx,const PrintingPolicy & Policy,bool WithGlobalNsPrefix)482cc3cf58cSIlya Biryukov std::string getFullyQualifiedName(QualType QT,
483cc3cf58cSIlya Biryukov const ASTContext &Ctx,
48458910646SSterling Augustine const PrintingPolicy &Policy,
485cc3cf58cSIlya Biryukov bool WithGlobalNsPrefix) {
486cc3cf58cSIlya Biryukov QualType FQQT = getFullyQualifiedType(QT, Ctx, WithGlobalNsPrefix);
487cc3cf58cSIlya Biryukov return FQQT.getAsString(Policy);
488cc3cf58cSIlya Biryukov }
489cc3cf58cSIlya Biryukov
490cc3cf58cSIlya Biryukov } // end namespace TypeName
491cc3cf58cSIlya Biryukov } // end namespace clang
492