106f32e7eSjoerg //===------- QualTypeNames.cpp - Generate Complete QualType Names ---------===//
206f32e7eSjoerg //
306f32e7eSjoerg // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
406f32e7eSjoerg // See https://llvm.org/LICENSE.txt for license information.
506f32e7eSjoerg // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
606f32e7eSjoerg //
706f32e7eSjoerg //===----------------------------------------------------------------------===//
806f32e7eSjoerg 
906f32e7eSjoerg #include "clang/AST/DeclTemplate.h"
1006f32e7eSjoerg #include "clang/AST/DeclarationName.h"
1106f32e7eSjoerg #include "clang/AST/GlobalDecl.h"
1206f32e7eSjoerg #include "clang/AST/Mangle.h"
1306f32e7eSjoerg #include "clang/AST/QualTypeNames.h"
1406f32e7eSjoerg 
1506f32e7eSjoerg #include <stdio.h>
1606f32e7eSjoerg #include <memory>
1706f32e7eSjoerg 
1806f32e7eSjoerg namespace clang {
1906f32e7eSjoerg 
2006f32e7eSjoerg namespace TypeName {
2106f32e7eSjoerg 
2206f32e7eSjoerg /// Create a NestedNameSpecifier for Namesp and its enclosing
2306f32e7eSjoerg /// scopes.
2406f32e7eSjoerg ///
2506f32e7eSjoerg /// \param[in] Ctx - the AST Context to be used.
2606f32e7eSjoerg /// \param[in] Namesp - the NamespaceDecl for which a NestedNameSpecifier
2706f32e7eSjoerg /// is requested.
2806f32e7eSjoerg /// \param[in] WithGlobalNsPrefix - Indicate whether the global namespace
2906f32e7eSjoerg /// specifier "::" should be prepended or not.
3006f32e7eSjoerg static NestedNameSpecifier *createNestedNameSpecifier(
3106f32e7eSjoerg     const ASTContext &Ctx,
3206f32e7eSjoerg     const NamespaceDecl *Namesp,
3306f32e7eSjoerg     bool WithGlobalNsPrefix);
3406f32e7eSjoerg 
3506f32e7eSjoerg /// Create a NestedNameSpecifier for TagDecl and its enclosing
3606f32e7eSjoerg /// scopes.
3706f32e7eSjoerg ///
3806f32e7eSjoerg /// \param[in] Ctx - the AST Context to be used.
3906f32e7eSjoerg /// \param[in] TD - the TagDecl for which a NestedNameSpecifier is
4006f32e7eSjoerg /// requested.
4106f32e7eSjoerg /// \param[in] FullyQualify - Convert all template arguments into fully
4206f32e7eSjoerg /// qualified names.
4306f32e7eSjoerg /// \param[in] WithGlobalNsPrefix - Indicate whether the global namespace
4406f32e7eSjoerg /// specifier "::" should be prepended or not.
4506f32e7eSjoerg static NestedNameSpecifier *createNestedNameSpecifier(
4606f32e7eSjoerg     const ASTContext &Ctx, const TypeDecl *TD,
4706f32e7eSjoerg     bool FullyQualify, bool WithGlobalNsPrefix);
4806f32e7eSjoerg 
4906f32e7eSjoerg static NestedNameSpecifier *createNestedNameSpecifierForScopeOf(
5006f32e7eSjoerg     const ASTContext &Ctx, const Decl *decl,
5106f32e7eSjoerg     bool FullyQualified, bool WithGlobalNsPrefix);
5206f32e7eSjoerg 
5306f32e7eSjoerg static NestedNameSpecifier *getFullyQualifiedNestedNameSpecifier(
5406f32e7eSjoerg     const ASTContext &Ctx, NestedNameSpecifier *scope, bool WithGlobalNsPrefix);
5506f32e7eSjoerg 
getFullyQualifiedTemplateName(const ASTContext & Ctx,TemplateName & TName,bool WithGlobalNsPrefix)5606f32e7eSjoerg static bool getFullyQualifiedTemplateName(const ASTContext &Ctx,
5706f32e7eSjoerg                                           TemplateName &TName,
5806f32e7eSjoerg                                           bool WithGlobalNsPrefix) {
5906f32e7eSjoerg   bool Changed = false;
6006f32e7eSjoerg   NestedNameSpecifier *NNS = nullptr;
6106f32e7eSjoerg 
6206f32e7eSjoerg   TemplateDecl *ArgTDecl = TName.getAsTemplateDecl();
6306f32e7eSjoerg   // ArgTDecl won't be NULL because we asserted that this isn't a
6406f32e7eSjoerg   // dependent context very early in the call chain.
6506f32e7eSjoerg   assert(ArgTDecl != nullptr);
6606f32e7eSjoerg   QualifiedTemplateName *QTName = TName.getAsQualifiedTemplateName();
6706f32e7eSjoerg 
6806f32e7eSjoerg   if (QTName && !QTName->hasTemplateKeyword()) {
6906f32e7eSjoerg     NNS = QTName->getQualifier();
7006f32e7eSjoerg     NestedNameSpecifier *QNNS = getFullyQualifiedNestedNameSpecifier(
7106f32e7eSjoerg         Ctx, NNS, WithGlobalNsPrefix);
7206f32e7eSjoerg     if (QNNS != NNS) {
7306f32e7eSjoerg       Changed = true;
7406f32e7eSjoerg       NNS = QNNS;
7506f32e7eSjoerg     } else {
7606f32e7eSjoerg       NNS = nullptr;
7706f32e7eSjoerg     }
7806f32e7eSjoerg   } else {
7906f32e7eSjoerg     NNS = createNestedNameSpecifierForScopeOf(
8006f32e7eSjoerg         Ctx, ArgTDecl, true, WithGlobalNsPrefix);
8106f32e7eSjoerg   }
8206f32e7eSjoerg   if (NNS) {
8306f32e7eSjoerg     TName = Ctx.getQualifiedTemplateName(NNS,
8406f32e7eSjoerg                                          /*TemplateKeyword=*/false, ArgTDecl);
8506f32e7eSjoerg     Changed = true;
8606f32e7eSjoerg   }
8706f32e7eSjoerg   return Changed;
8806f32e7eSjoerg }
8906f32e7eSjoerg 
getFullyQualifiedTemplateArgument(const ASTContext & Ctx,TemplateArgument & Arg,bool WithGlobalNsPrefix)9006f32e7eSjoerg static bool getFullyQualifiedTemplateArgument(const ASTContext &Ctx,
9106f32e7eSjoerg                                               TemplateArgument &Arg,
9206f32e7eSjoerg                                               bool WithGlobalNsPrefix) {
9306f32e7eSjoerg   bool Changed = false;
9406f32e7eSjoerg 
9506f32e7eSjoerg   // Note: we do not handle TemplateArgument::Expression, to replace it
9606f32e7eSjoerg   // we need the information for the template instance decl.
9706f32e7eSjoerg 
9806f32e7eSjoerg   if (Arg.getKind() == TemplateArgument::Template) {
9906f32e7eSjoerg     TemplateName TName = Arg.getAsTemplate();
10006f32e7eSjoerg     Changed = getFullyQualifiedTemplateName(Ctx, TName, WithGlobalNsPrefix);
10106f32e7eSjoerg     if (Changed) {
10206f32e7eSjoerg       Arg = TemplateArgument(TName);
10306f32e7eSjoerg     }
10406f32e7eSjoerg   } else if (Arg.getKind() == TemplateArgument::Type) {
10506f32e7eSjoerg     QualType SubTy = Arg.getAsType();
10606f32e7eSjoerg     // Check if the type needs more desugaring and recurse.
10706f32e7eSjoerg     QualType QTFQ = getFullyQualifiedType(SubTy, Ctx, WithGlobalNsPrefix);
10806f32e7eSjoerg     if (QTFQ != SubTy) {
10906f32e7eSjoerg       Arg = TemplateArgument(QTFQ);
11006f32e7eSjoerg       Changed = true;
11106f32e7eSjoerg     }
11206f32e7eSjoerg   }
11306f32e7eSjoerg   return Changed;
11406f32e7eSjoerg }
11506f32e7eSjoerg 
getFullyQualifiedTemplateType(const ASTContext & Ctx,const Type * TypePtr,bool WithGlobalNsPrefix)11606f32e7eSjoerg static const Type *getFullyQualifiedTemplateType(const ASTContext &Ctx,
11706f32e7eSjoerg                                                  const Type *TypePtr,
11806f32e7eSjoerg                                                  bool WithGlobalNsPrefix) {
11906f32e7eSjoerg   // DependentTemplateTypes exist within template declarations and
12006f32e7eSjoerg   // definitions. Therefore we shouldn't encounter them at the end of
12106f32e7eSjoerg   // a translation unit. If we do, the caller has made an error.
12206f32e7eSjoerg   assert(!isa<DependentTemplateSpecializationType>(TypePtr));
12306f32e7eSjoerg   // In case of template specializations, iterate over the arguments
12406f32e7eSjoerg   // and fully qualify them as well.
12506f32e7eSjoerg   if (const auto *TST = dyn_cast<const TemplateSpecializationType>(TypePtr)) {
12606f32e7eSjoerg     bool MightHaveChanged = false;
12706f32e7eSjoerg     SmallVector<TemplateArgument, 4> FQArgs;
12806f32e7eSjoerg     for (TemplateSpecializationType::iterator I = TST->begin(), E = TST->end();
12906f32e7eSjoerg          I != E; ++I) {
13006f32e7eSjoerg       // Cheap to copy and potentially modified by
13106f32e7eSjoerg       // getFullyQualifedTemplateArgument.
13206f32e7eSjoerg       TemplateArgument Arg(*I);
13306f32e7eSjoerg       MightHaveChanged |= getFullyQualifiedTemplateArgument(
13406f32e7eSjoerg           Ctx, Arg, WithGlobalNsPrefix);
13506f32e7eSjoerg       FQArgs.push_back(Arg);
13606f32e7eSjoerg     }
13706f32e7eSjoerg 
13806f32e7eSjoerg     // If a fully qualified arg is different from the unqualified arg,
13906f32e7eSjoerg     // allocate new type in the AST.
14006f32e7eSjoerg     if (MightHaveChanged) {
14106f32e7eSjoerg       QualType QT = Ctx.getTemplateSpecializationType(
14206f32e7eSjoerg           TST->getTemplateName(), FQArgs,
14306f32e7eSjoerg           TST->getCanonicalTypeInternal());
14406f32e7eSjoerg       // getTemplateSpecializationType returns a fully qualified
14506f32e7eSjoerg       // version of the specialization itself, so no need to qualify
14606f32e7eSjoerg       // it.
14706f32e7eSjoerg       return QT.getTypePtr();
14806f32e7eSjoerg     }
14906f32e7eSjoerg   } else if (const auto *TSTRecord = dyn_cast<const RecordType>(TypePtr)) {
15006f32e7eSjoerg     // We are asked to fully qualify and we have a Record Type,
15106f32e7eSjoerg     // which can point to a template instantiation with no sugar in any of
15206f32e7eSjoerg     // its template argument, however we still need to fully qualify them.
15306f32e7eSjoerg 
15406f32e7eSjoerg     if (const auto *TSTDecl =
15506f32e7eSjoerg         dyn_cast<ClassTemplateSpecializationDecl>(TSTRecord->getDecl())) {
15606f32e7eSjoerg       const TemplateArgumentList &TemplateArgs = TSTDecl->getTemplateArgs();
15706f32e7eSjoerg 
15806f32e7eSjoerg       bool MightHaveChanged = false;
15906f32e7eSjoerg       SmallVector<TemplateArgument, 4> FQArgs;
16006f32e7eSjoerg       for (unsigned int I = 0, E = TemplateArgs.size(); I != E; ++I) {
16106f32e7eSjoerg         // cheap to copy and potentially modified by
16206f32e7eSjoerg         // getFullyQualifedTemplateArgument
16306f32e7eSjoerg         TemplateArgument Arg(TemplateArgs[I]);
16406f32e7eSjoerg         MightHaveChanged |= getFullyQualifiedTemplateArgument(
16506f32e7eSjoerg             Ctx, Arg, WithGlobalNsPrefix);
16606f32e7eSjoerg         FQArgs.push_back(Arg);
16706f32e7eSjoerg       }
16806f32e7eSjoerg 
16906f32e7eSjoerg       // If a fully qualified arg is different from the unqualified arg,
17006f32e7eSjoerg       // allocate new type in the AST.
17106f32e7eSjoerg       if (MightHaveChanged) {
17206f32e7eSjoerg         TemplateName TN(TSTDecl->getSpecializedTemplate());
17306f32e7eSjoerg         QualType QT = Ctx.getTemplateSpecializationType(
17406f32e7eSjoerg             TN, FQArgs,
17506f32e7eSjoerg             TSTRecord->getCanonicalTypeInternal());
17606f32e7eSjoerg         // getTemplateSpecializationType returns a fully qualified
17706f32e7eSjoerg         // version of the specialization itself, so no need to qualify
17806f32e7eSjoerg         // it.
17906f32e7eSjoerg         return QT.getTypePtr();
18006f32e7eSjoerg       }
18106f32e7eSjoerg     }
18206f32e7eSjoerg   }
18306f32e7eSjoerg   return TypePtr;
18406f32e7eSjoerg }
18506f32e7eSjoerg 
createOuterNNS(const ASTContext & Ctx,const Decl * D,bool FullyQualify,bool WithGlobalNsPrefix)18606f32e7eSjoerg static NestedNameSpecifier *createOuterNNS(const ASTContext &Ctx, const Decl *D,
18706f32e7eSjoerg                                            bool FullyQualify,
18806f32e7eSjoerg                                            bool WithGlobalNsPrefix) {
18906f32e7eSjoerg   const DeclContext *DC = D->getDeclContext();
19006f32e7eSjoerg   if (const auto *NS = dyn_cast<NamespaceDecl>(DC)) {
19106f32e7eSjoerg     while (NS && NS->isInline()) {
19206f32e7eSjoerg       // Ignore inline namespace;
19306f32e7eSjoerg       NS = dyn_cast<NamespaceDecl>(NS->getDeclContext());
19406f32e7eSjoerg     }
195*13fbcb42Sjoerg     if (NS && NS->getDeclName()) {
19606f32e7eSjoerg       return createNestedNameSpecifier(Ctx, NS, WithGlobalNsPrefix);
19706f32e7eSjoerg     }
19806f32e7eSjoerg     return nullptr;  // no starting '::', no anonymous
19906f32e7eSjoerg   } else if (const auto *TD = dyn_cast<TagDecl>(DC)) {
20006f32e7eSjoerg     return createNestedNameSpecifier(Ctx, TD, FullyQualify, WithGlobalNsPrefix);
20106f32e7eSjoerg   } else if (const auto *TDD = dyn_cast<TypedefNameDecl>(DC)) {
20206f32e7eSjoerg     return createNestedNameSpecifier(
20306f32e7eSjoerg         Ctx, TDD, FullyQualify, WithGlobalNsPrefix);
20406f32e7eSjoerg   } else if (WithGlobalNsPrefix && DC->isTranslationUnit()) {
20506f32e7eSjoerg     return NestedNameSpecifier::GlobalSpecifier(Ctx);
20606f32e7eSjoerg   }
20706f32e7eSjoerg   return nullptr;  // no starting '::' if |WithGlobalNsPrefix| is false
20806f32e7eSjoerg }
20906f32e7eSjoerg 
21006f32e7eSjoerg /// Return a fully qualified version of this name specifier.
getFullyQualifiedNestedNameSpecifier(const ASTContext & Ctx,NestedNameSpecifier * Scope,bool WithGlobalNsPrefix)21106f32e7eSjoerg static NestedNameSpecifier *getFullyQualifiedNestedNameSpecifier(
21206f32e7eSjoerg     const ASTContext &Ctx, NestedNameSpecifier *Scope,
21306f32e7eSjoerg     bool WithGlobalNsPrefix) {
21406f32e7eSjoerg   switch (Scope->getKind()) {
21506f32e7eSjoerg     case NestedNameSpecifier::Global:
21606f32e7eSjoerg       // Already fully qualified
21706f32e7eSjoerg       return Scope;
21806f32e7eSjoerg     case NestedNameSpecifier::Namespace:
21906f32e7eSjoerg       return TypeName::createNestedNameSpecifier(
22006f32e7eSjoerg           Ctx, Scope->getAsNamespace(), WithGlobalNsPrefix);
22106f32e7eSjoerg     case NestedNameSpecifier::NamespaceAlias:
22206f32e7eSjoerg       // Namespace aliases are only valid for the duration of the
22306f32e7eSjoerg       // scope where they were introduced, and therefore are often
22406f32e7eSjoerg       // invalid at the end of the TU.  So use the namespace name more
22506f32e7eSjoerg       // likely to be valid at the end of the TU.
22606f32e7eSjoerg       return TypeName::createNestedNameSpecifier(
22706f32e7eSjoerg           Ctx,
22806f32e7eSjoerg           Scope->getAsNamespaceAlias()->getNamespace()->getCanonicalDecl(),
22906f32e7eSjoerg           WithGlobalNsPrefix);
23006f32e7eSjoerg     case NestedNameSpecifier::Identifier:
23106f32e7eSjoerg       // A function or some other construct that makes it un-namable
23206f32e7eSjoerg       // at the end of the TU. Skip the current component of the name,
23306f32e7eSjoerg       // but use the name of it's prefix.
23406f32e7eSjoerg       return getFullyQualifiedNestedNameSpecifier(
23506f32e7eSjoerg           Ctx, Scope->getPrefix(), WithGlobalNsPrefix);
23606f32e7eSjoerg     case NestedNameSpecifier::Super:
23706f32e7eSjoerg     case NestedNameSpecifier::TypeSpec:
23806f32e7eSjoerg     case NestedNameSpecifier::TypeSpecWithTemplate: {
23906f32e7eSjoerg       const Type *Type = Scope->getAsType();
24006f32e7eSjoerg       // Find decl context.
24106f32e7eSjoerg       const TagDecl *TD = nullptr;
24206f32e7eSjoerg       if (const TagType *TagDeclType = Type->getAs<TagType>()) {
24306f32e7eSjoerg         TD = TagDeclType->getDecl();
24406f32e7eSjoerg       } else {
24506f32e7eSjoerg         TD = Type->getAsCXXRecordDecl();
24606f32e7eSjoerg       }
24706f32e7eSjoerg       if (TD) {
24806f32e7eSjoerg         return TypeName::createNestedNameSpecifier(Ctx, TD,
24906f32e7eSjoerg                                                    true /*FullyQualified*/,
25006f32e7eSjoerg                                                    WithGlobalNsPrefix);
25106f32e7eSjoerg       } else if (const auto *TDD = dyn_cast<TypedefType>(Type)) {
25206f32e7eSjoerg         return TypeName::createNestedNameSpecifier(Ctx, TDD->getDecl(),
25306f32e7eSjoerg                                                    true /*FullyQualified*/,
25406f32e7eSjoerg                                                    WithGlobalNsPrefix);
25506f32e7eSjoerg       }
25606f32e7eSjoerg       return Scope;
25706f32e7eSjoerg     }
25806f32e7eSjoerg   }
25906f32e7eSjoerg   llvm_unreachable("bad NNS kind");
26006f32e7eSjoerg }
26106f32e7eSjoerg 
26206f32e7eSjoerg /// Create a nested name specifier for the declaring context of
26306f32e7eSjoerg /// the type.
createNestedNameSpecifierForScopeOf(const ASTContext & Ctx,const Decl * Decl,bool FullyQualified,bool WithGlobalNsPrefix)26406f32e7eSjoerg static NestedNameSpecifier *createNestedNameSpecifierForScopeOf(
26506f32e7eSjoerg     const ASTContext &Ctx, const Decl *Decl,
26606f32e7eSjoerg     bool FullyQualified, bool WithGlobalNsPrefix) {
26706f32e7eSjoerg   assert(Decl);
26806f32e7eSjoerg 
26906f32e7eSjoerg   const DeclContext *DC = Decl->getDeclContext()->getRedeclContext();
27006f32e7eSjoerg   const auto *Outer = dyn_cast_or_null<NamedDecl>(DC);
27106f32e7eSjoerg   const auto *OuterNS = dyn_cast_or_null<NamespaceDecl>(DC);
27206f32e7eSjoerg   if (Outer && !(OuterNS && OuterNS->isAnonymousNamespace())) {
27306f32e7eSjoerg     if (const auto *CxxDecl = dyn_cast<CXXRecordDecl>(DC)) {
27406f32e7eSjoerg       if (ClassTemplateDecl *ClassTempl =
27506f32e7eSjoerg               CxxDecl->getDescribedClassTemplate()) {
27606f32e7eSjoerg         // We are in the case of a type(def) that was declared in a
27706f32e7eSjoerg         // class template but is *not* type dependent.  In clang, it
27806f32e7eSjoerg         // gets attached to the class template declaration rather than
27906f32e7eSjoerg         // any specific class template instantiation.  This result in
28006f32e7eSjoerg         // 'odd' fully qualified typename:
28106f32e7eSjoerg         //
28206f32e7eSjoerg         //    vector<_Tp,_Alloc>::size_type
28306f32e7eSjoerg         //
28406f32e7eSjoerg         // Make the situation is 'useable' but looking a bit odd by
28506f32e7eSjoerg         // picking a random instance as the declaring context.
28606f32e7eSjoerg         if (ClassTempl->spec_begin() != ClassTempl->spec_end()) {
28706f32e7eSjoerg           Decl = *(ClassTempl->spec_begin());
28806f32e7eSjoerg           Outer = dyn_cast<NamedDecl>(Decl);
28906f32e7eSjoerg           OuterNS = dyn_cast<NamespaceDecl>(Decl);
29006f32e7eSjoerg         }
29106f32e7eSjoerg       }
29206f32e7eSjoerg     }
29306f32e7eSjoerg 
29406f32e7eSjoerg     if (OuterNS) {
29506f32e7eSjoerg       return createNestedNameSpecifier(Ctx, OuterNS, WithGlobalNsPrefix);
29606f32e7eSjoerg     } else if (const auto *TD = dyn_cast<TagDecl>(Outer)) {
29706f32e7eSjoerg       return createNestedNameSpecifier(
29806f32e7eSjoerg           Ctx, TD, FullyQualified, WithGlobalNsPrefix);
29906f32e7eSjoerg     } else if (dyn_cast<TranslationUnitDecl>(Outer)) {
30006f32e7eSjoerg       // Context is the TU. Nothing needs to be done.
30106f32e7eSjoerg       return nullptr;
30206f32e7eSjoerg     } else {
30306f32e7eSjoerg       // Decl's context was neither the TU, a namespace, nor a
30406f32e7eSjoerg       // TagDecl, which means it is a type local to a scope, and not
30506f32e7eSjoerg       // accessible at the end of the TU.
30606f32e7eSjoerg       return nullptr;
30706f32e7eSjoerg     }
30806f32e7eSjoerg   } else if (WithGlobalNsPrefix && DC->isTranslationUnit()) {
30906f32e7eSjoerg     return NestedNameSpecifier::GlobalSpecifier(Ctx);
31006f32e7eSjoerg   }
31106f32e7eSjoerg   return nullptr;
31206f32e7eSjoerg }
31306f32e7eSjoerg 
31406f32e7eSjoerg /// Create a nested name specifier for the declaring context of
31506f32e7eSjoerg /// the type.
createNestedNameSpecifierForScopeOf(const ASTContext & Ctx,const Type * TypePtr,bool FullyQualified,bool WithGlobalNsPrefix)31606f32e7eSjoerg static NestedNameSpecifier *createNestedNameSpecifierForScopeOf(
31706f32e7eSjoerg     const ASTContext &Ctx, const Type *TypePtr,
31806f32e7eSjoerg     bool FullyQualified, bool WithGlobalNsPrefix) {
31906f32e7eSjoerg   if (!TypePtr) return nullptr;
32006f32e7eSjoerg 
32106f32e7eSjoerg   Decl *Decl = nullptr;
32206f32e7eSjoerg   // There are probably other cases ...
32306f32e7eSjoerg   if (const auto *TDT = dyn_cast<TypedefType>(TypePtr)) {
32406f32e7eSjoerg     Decl = TDT->getDecl();
32506f32e7eSjoerg   } else if (const auto *TagDeclType = dyn_cast<TagType>(TypePtr)) {
32606f32e7eSjoerg     Decl = TagDeclType->getDecl();
32706f32e7eSjoerg   } else if (const auto *TST = dyn_cast<TemplateSpecializationType>(TypePtr)) {
32806f32e7eSjoerg     Decl = TST->getTemplateName().getAsTemplateDecl();
32906f32e7eSjoerg   } else {
33006f32e7eSjoerg     Decl = TypePtr->getAsCXXRecordDecl();
33106f32e7eSjoerg   }
33206f32e7eSjoerg 
33306f32e7eSjoerg   if (!Decl) return nullptr;
33406f32e7eSjoerg 
33506f32e7eSjoerg   return createNestedNameSpecifierForScopeOf(
33606f32e7eSjoerg       Ctx, Decl, FullyQualified, WithGlobalNsPrefix);
33706f32e7eSjoerg }
33806f32e7eSjoerg 
createNestedNameSpecifier(const ASTContext & Ctx,const NamespaceDecl * Namespace,bool WithGlobalNsPrefix)33906f32e7eSjoerg NestedNameSpecifier *createNestedNameSpecifier(const ASTContext &Ctx,
34006f32e7eSjoerg                                                const NamespaceDecl *Namespace,
34106f32e7eSjoerg                                                bool WithGlobalNsPrefix) {
34206f32e7eSjoerg   while (Namespace && Namespace->isInline()) {
34306f32e7eSjoerg     // Ignore inline namespace;
34406f32e7eSjoerg     Namespace = dyn_cast<NamespaceDecl>(Namespace->getDeclContext());
34506f32e7eSjoerg   }
34606f32e7eSjoerg   if (!Namespace) return nullptr;
34706f32e7eSjoerg 
34806f32e7eSjoerg   bool FullyQualified = true;  // doesn't matter, DeclContexts are namespaces
34906f32e7eSjoerg   return NestedNameSpecifier::Create(
35006f32e7eSjoerg       Ctx,
35106f32e7eSjoerg       createOuterNNS(Ctx, Namespace, FullyQualified, WithGlobalNsPrefix),
35206f32e7eSjoerg       Namespace);
35306f32e7eSjoerg }
35406f32e7eSjoerg 
createNestedNameSpecifier(const ASTContext & Ctx,const TypeDecl * TD,bool FullyQualify,bool WithGlobalNsPrefix)35506f32e7eSjoerg NestedNameSpecifier *createNestedNameSpecifier(const ASTContext &Ctx,
35606f32e7eSjoerg                                                const TypeDecl *TD,
35706f32e7eSjoerg                                                bool FullyQualify,
35806f32e7eSjoerg                                                bool WithGlobalNsPrefix) {
35906f32e7eSjoerg   return NestedNameSpecifier::Create(
36006f32e7eSjoerg       Ctx,
36106f32e7eSjoerg       createOuterNNS(Ctx, TD, FullyQualify, WithGlobalNsPrefix),
36206f32e7eSjoerg       false /*No TemplateKeyword*/,
36306f32e7eSjoerg       TD->getTypeForDecl());
36406f32e7eSjoerg }
36506f32e7eSjoerg 
36606f32e7eSjoerg /// Return the fully qualified type, including fully-qualified
36706f32e7eSjoerg /// versions of any template parameters.
getFullyQualifiedType(QualType QT,const ASTContext & Ctx,bool WithGlobalNsPrefix)36806f32e7eSjoerg QualType getFullyQualifiedType(QualType QT, const ASTContext &Ctx,
36906f32e7eSjoerg                                bool WithGlobalNsPrefix) {
37006f32e7eSjoerg   // In case of myType* we need to strip the pointer first, fully
37106f32e7eSjoerg   // qualify and attach the pointer once again.
37206f32e7eSjoerg   if (isa<PointerType>(QT.getTypePtr())) {
37306f32e7eSjoerg     // Get the qualifiers.
37406f32e7eSjoerg     Qualifiers Quals = QT.getQualifiers();
37506f32e7eSjoerg     QT = getFullyQualifiedType(QT->getPointeeType(), Ctx, WithGlobalNsPrefix);
37606f32e7eSjoerg     QT = Ctx.getPointerType(QT);
37706f32e7eSjoerg     // Add back the qualifiers.
37806f32e7eSjoerg     QT = Ctx.getQualifiedType(QT, Quals);
37906f32e7eSjoerg     return QT;
38006f32e7eSjoerg   }
38106f32e7eSjoerg 
38206f32e7eSjoerg   if (auto *MPT = dyn_cast<MemberPointerType>(QT.getTypePtr())) {
38306f32e7eSjoerg     // Get the qualifiers.
38406f32e7eSjoerg     Qualifiers Quals = QT.getQualifiers();
38506f32e7eSjoerg     // Fully qualify the pointee and class types.
38606f32e7eSjoerg     QT = getFullyQualifiedType(QT->getPointeeType(), Ctx, WithGlobalNsPrefix);
38706f32e7eSjoerg     QualType Class = getFullyQualifiedType(QualType(MPT->getClass(), 0), Ctx,
38806f32e7eSjoerg                                            WithGlobalNsPrefix);
38906f32e7eSjoerg     QT = Ctx.getMemberPointerType(QT, Class.getTypePtr());
39006f32e7eSjoerg     // Add back the qualifiers.
39106f32e7eSjoerg     QT = Ctx.getQualifiedType(QT, Quals);
39206f32e7eSjoerg     return QT;
39306f32e7eSjoerg   }
39406f32e7eSjoerg 
39506f32e7eSjoerg   // In case of myType& we need to strip the reference first, fully
39606f32e7eSjoerg   // qualify and attach the reference once again.
39706f32e7eSjoerg   if (isa<ReferenceType>(QT.getTypePtr())) {
39806f32e7eSjoerg     // Get the qualifiers.
39906f32e7eSjoerg     bool IsLValueRefTy = isa<LValueReferenceType>(QT.getTypePtr());
40006f32e7eSjoerg     Qualifiers Quals = QT.getQualifiers();
40106f32e7eSjoerg     QT = getFullyQualifiedType(QT->getPointeeType(), Ctx, WithGlobalNsPrefix);
40206f32e7eSjoerg     // Add the r- or l-value reference type back to the fully
40306f32e7eSjoerg     // qualified one.
40406f32e7eSjoerg     if (IsLValueRefTy)
40506f32e7eSjoerg       QT = Ctx.getLValueReferenceType(QT);
40606f32e7eSjoerg     else
40706f32e7eSjoerg       QT = Ctx.getRValueReferenceType(QT);
40806f32e7eSjoerg     // Add back the qualifiers.
40906f32e7eSjoerg     QT = Ctx.getQualifiedType(QT, Quals);
41006f32e7eSjoerg     return QT;
41106f32e7eSjoerg   }
41206f32e7eSjoerg 
41306f32e7eSjoerg   // Remove the part of the type related to the type being a template
41406f32e7eSjoerg   // parameter (we won't report it as part of the 'type name' and it
41506f32e7eSjoerg   // is actually make the code below to be more complex (to handle
41606f32e7eSjoerg   // those)
41706f32e7eSjoerg   while (isa<SubstTemplateTypeParmType>(QT.getTypePtr())) {
41806f32e7eSjoerg     // Get the qualifiers.
41906f32e7eSjoerg     Qualifiers Quals = QT.getQualifiers();
42006f32e7eSjoerg 
42106f32e7eSjoerg     QT = cast<SubstTemplateTypeParmType>(QT.getTypePtr())->desugar();
42206f32e7eSjoerg 
42306f32e7eSjoerg     // Add back the qualifiers.
42406f32e7eSjoerg     QT = Ctx.getQualifiedType(QT, Quals);
42506f32e7eSjoerg   }
42606f32e7eSjoerg 
42706f32e7eSjoerg   NestedNameSpecifier *Prefix = nullptr;
42806f32e7eSjoerg   // Local qualifiers are attached to the QualType outside of the
42906f32e7eSjoerg   // elaborated type.  Retrieve them before descending into the
43006f32e7eSjoerg   // elaborated type.
43106f32e7eSjoerg   Qualifiers PrefixQualifiers = QT.getLocalQualifiers();
43206f32e7eSjoerg   QT = QualType(QT.getTypePtr(), 0);
43306f32e7eSjoerg   ElaboratedTypeKeyword Keyword = ETK_None;
43406f32e7eSjoerg   if (const auto *ETypeInput = dyn_cast<ElaboratedType>(QT.getTypePtr())) {
43506f32e7eSjoerg     QT = ETypeInput->getNamedType();
43606f32e7eSjoerg     assert(!QT.hasLocalQualifiers());
43706f32e7eSjoerg     Keyword = ETypeInput->getKeyword();
43806f32e7eSjoerg   }
43906f32e7eSjoerg   // Create a nested name specifier if needed.
44006f32e7eSjoerg   Prefix = createNestedNameSpecifierForScopeOf(Ctx, QT.getTypePtr(),
44106f32e7eSjoerg                                                true /*FullyQualified*/,
44206f32e7eSjoerg                                                WithGlobalNsPrefix);
44306f32e7eSjoerg 
44406f32e7eSjoerg   // In case of template specializations iterate over the arguments and
44506f32e7eSjoerg   // fully qualify them as well.
44606f32e7eSjoerg   if (isa<const TemplateSpecializationType>(QT.getTypePtr()) ||
44706f32e7eSjoerg       isa<const RecordType>(QT.getTypePtr())) {
44806f32e7eSjoerg     // We are asked to fully qualify and we have a Record Type (which
44906f32e7eSjoerg     // may point to a template specialization) or Template
45006f32e7eSjoerg     // Specialization Type. We need to fully qualify their arguments.
45106f32e7eSjoerg 
45206f32e7eSjoerg     const Type *TypePtr = getFullyQualifiedTemplateType(
45306f32e7eSjoerg         Ctx, QT.getTypePtr(), WithGlobalNsPrefix);
45406f32e7eSjoerg     QT = QualType(TypePtr, 0);
45506f32e7eSjoerg   }
45606f32e7eSjoerg   if (Prefix || Keyword != ETK_None) {
45706f32e7eSjoerg     QT = Ctx.getElaboratedType(Keyword, Prefix, QT);
45806f32e7eSjoerg   }
45906f32e7eSjoerg   QT = Ctx.getQualifiedType(QT, PrefixQualifiers);
46006f32e7eSjoerg   return QT;
46106f32e7eSjoerg }
46206f32e7eSjoerg 
getFullyQualifiedName(QualType QT,const ASTContext & Ctx,const PrintingPolicy & Policy,bool WithGlobalNsPrefix)46306f32e7eSjoerg std::string getFullyQualifiedName(QualType QT,
46406f32e7eSjoerg                                   const ASTContext &Ctx,
46506f32e7eSjoerg                                   const PrintingPolicy &Policy,
46606f32e7eSjoerg                                   bool WithGlobalNsPrefix) {
46706f32e7eSjoerg   QualType FQQT = getFullyQualifiedType(QT, Ctx, WithGlobalNsPrefix);
46806f32e7eSjoerg   return FQQT.getAsString(Policy);
46906f32e7eSjoerg }
47006f32e7eSjoerg 
47106f32e7eSjoerg }  // end namespace TypeName
47206f32e7eSjoerg }  // end namespace clang
473