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