1326941Sdim//===------- QualTypeNames.cpp - Generate Complete QualType Names ---------===// 2326941Sdim// 3353358Sdim// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4353358Sdim// See https://llvm.org/LICENSE.txt for license information. 5353358Sdim// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6326941Sdim// 7326941Sdim//===----------------------------------------------------------------------===// 8326941Sdim 9326941Sdim#include "clang/AST/DeclTemplate.h" 10326941Sdim#include "clang/AST/DeclarationName.h" 11326941Sdim#include "clang/AST/GlobalDecl.h" 12326941Sdim#include "clang/AST/Mangle.h" 13326941Sdim#include "clang/AST/QualTypeNames.h" 14326941Sdim 15326941Sdim#include <stdio.h> 16326941Sdim#include <memory> 17326941Sdim 18326941Sdimnamespace clang { 19326941Sdim 20326941Sdimnamespace TypeName { 21326941Sdim 22341825Sdim/// Create a NestedNameSpecifier for Namesp and its enclosing 23326941Sdim/// scopes. 24326941Sdim/// 25326941Sdim/// \param[in] Ctx - the AST Context to be used. 26326941Sdim/// \param[in] Namesp - the NamespaceDecl for which a NestedNameSpecifier 27326941Sdim/// is requested. 28326941Sdim/// \param[in] WithGlobalNsPrefix - Indicate whether the global namespace 29326941Sdim/// specifier "::" should be prepended or not. 30326941Sdimstatic NestedNameSpecifier *createNestedNameSpecifier( 31326941Sdim const ASTContext &Ctx, 32326941Sdim const NamespaceDecl *Namesp, 33326941Sdim bool WithGlobalNsPrefix); 34326941Sdim 35341825Sdim/// Create a NestedNameSpecifier for TagDecl and its enclosing 36326941Sdim/// scopes. 37326941Sdim/// 38326941Sdim/// \param[in] Ctx - the AST Context to be used. 39326941Sdim/// \param[in] TD - the TagDecl for which a NestedNameSpecifier is 40326941Sdim/// requested. 41326941Sdim/// \param[in] FullyQualify - Convert all template arguments into fully 42326941Sdim/// qualified names. 43326941Sdim/// \param[in] WithGlobalNsPrefix - Indicate whether the global namespace 44326941Sdim/// specifier "::" should be prepended or not. 45326941Sdimstatic NestedNameSpecifier *createNestedNameSpecifier( 46326941Sdim const ASTContext &Ctx, const TypeDecl *TD, 47326941Sdim bool FullyQualify, bool WithGlobalNsPrefix); 48326941Sdim 49326941Sdimstatic NestedNameSpecifier *createNestedNameSpecifierForScopeOf( 50326941Sdim const ASTContext &Ctx, const Decl *decl, 51326941Sdim bool FullyQualified, bool WithGlobalNsPrefix); 52326941Sdim 53326941Sdimstatic NestedNameSpecifier *getFullyQualifiedNestedNameSpecifier( 54326941Sdim const ASTContext &Ctx, NestedNameSpecifier *scope, bool WithGlobalNsPrefix); 55326941Sdim 56326941Sdimstatic bool getFullyQualifiedTemplateName(const ASTContext &Ctx, 57326941Sdim TemplateName &TName, 58326941Sdim bool WithGlobalNsPrefix) { 59326941Sdim bool Changed = false; 60326941Sdim NestedNameSpecifier *NNS = nullptr; 61326941Sdim 62326941Sdim TemplateDecl *ArgTDecl = TName.getAsTemplateDecl(); 63326941Sdim // ArgTDecl won't be NULL because we asserted that this isn't a 64326941Sdim // dependent context very early in the call chain. 65326941Sdim assert(ArgTDecl != nullptr); 66326941Sdim QualifiedTemplateName *QTName = TName.getAsQualifiedTemplateName(); 67326941Sdim 68326941Sdim if (QTName && !QTName->hasTemplateKeyword()) { 69326941Sdim NNS = QTName->getQualifier(); 70326941Sdim NestedNameSpecifier *QNNS = getFullyQualifiedNestedNameSpecifier( 71326941Sdim Ctx, NNS, WithGlobalNsPrefix); 72326941Sdim if (QNNS != NNS) { 73326941Sdim Changed = true; 74326941Sdim NNS = QNNS; 75326941Sdim } else { 76326941Sdim NNS = nullptr; 77326941Sdim } 78326941Sdim } else { 79326941Sdim NNS = createNestedNameSpecifierForScopeOf( 80326941Sdim Ctx, ArgTDecl, true, WithGlobalNsPrefix); 81326941Sdim } 82326941Sdim if (NNS) { 83326941Sdim TName = Ctx.getQualifiedTemplateName(NNS, 84326941Sdim /*TemplateKeyword=*/false, ArgTDecl); 85326941Sdim Changed = true; 86326941Sdim } 87326941Sdim return Changed; 88326941Sdim} 89326941Sdim 90326941Sdimstatic bool getFullyQualifiedTemplateArgument(const ASTContext &Ctx, 91326941Sdim TemplateArgument &Arg, 92326941Sdim bool WithGlobalNsPrefix) { 93326941Sdim bool Changed = false; 94326941Sdim 95326941Sdim // Note: we do not handle TemplateArgument::Expression, to replace it 96326941Sdim // we need the information for the template instance decl. 97326941Sdim 98326941Sdim if (Arg.getKind() == TemplateArgument::Template) { 99326941Sdim TemplateName TName = Arg.getAsTemplate(); 100326941Sdim Changed = getFullyQualifiedTemplateName(Ctx, TName, WithGlobalNsPrefix); 101326941Sdim if (Changed) { 102326941Sdim Arg = TemplateArgument(TName); 103326941Sdim } 104326941Sdim } else if (Arg.getKind() == TemplateArgument::Type) { 105326941Sdim QualType SubTy = Arg.getAsType(); 106326941Sdim // Check if the type needs more desugaring and recurse. 107326941Sdim QualType QTFQ = getFullyQualifiedType(SubTy, Ctx, WithGlobalNsPrefix); 108326941Sdim if (QTFQ != SubTy) { 109326941Sdim Arg = TemplateArgument(QTFQ); 110326941Sdim Changed = true; 111326941Sdim } 112326941Sdim } 113326941Sdim return Changed; 114326941Sdim} 115326941Sdim 116326941Sdimstatic const Type *getFullyQualifiedTemplateType(const ASTContext &Ctx, 117326941Sdim const Type *TypePtr, 118326941Sdim bool WithGlobalNsPrefix) { 119326941Sdim // DependentTemplateTypes exist within template declarations and 120326941Sdim // definitions. Therefore we shouldn't encounter them at the end of 121326941Sdim // a translation unit. If we do, the caller has made an error. 122326941Sdim assert(!isa<DependentTemplateSpecializationType>(TypePtr)); 123326941Sdim // In case of template specializations, iterate over the arguments 124326941Sdim // and fully qualify them as well. 125326941Sdim if (const auto *TST = dyn_cast<const TemplateSpecializationType>(TypePtr)) { 126326941Sdim bool MightHaveChanged = false; 127326941Sdim SmallVector<TemplateArgument, 4> FQArgs; 128326941Sdim for (TemplateSpecializationType::iterator I = TST->begin(), E = TST->end(); 129326941Sdim I != E; ++I) { 130326941Sdim // Cheap to copy and potentially modified by 131326941Sdim // getFullyQualifedTemplateArgument. 132326941Sdim TemplateArgument Arg(*I); 133326941Sdim MightHaveChanged |= getFullyQualifiedTemplateArgument( 134326941Sdim Ctx, Arg, WithGlobalNsPrefix); 135326941Sdim FQArgs.push_back(Arg); 136326941Sdim } 137326941Sdim 138326941Sdim // If a fully qualified arg is different from the unqualified arg, 139326941Sdim // allocate new type in the AST. 140326941Sdim if (MightHaveChanged) { 141326941Sdim QualType QT = Ctx.getTemplateSpecializationType( 142326941Sdim TST->getTemplateName(), FQArgs, 143326941Sdim TST->getCanonicalTypeInternal()); 144326941Sdim // getTemplateSpecializationType returns a fully qualified 145326941Sdim // version of the specialization itself, so no need to qualify 146326941Sdim // it. 147326941Sdim return QT.getTypePtr(); 148326941Sdim } 149326941Sdim } else if (const auto *TSTRecord = dyn_cast<const RecordType>(TypePtr)) { 150326941Sdim // We are asked to fully qualify and we have a Record Type, 151326941Sdim // which can point to a template instantiation with no sugar in any of 152326941Sdim // its template argument, however we still need to fully qualify them. 153326941Sdim 154326941Sdim if (const auto *TSTDecl = 155326941Sdim dyn_cast<ClassTemplateSpecializationDecl>(TSTRecord->getDecl())) { 156326941Sdim const TemplateArgumentList &TemplateArgs = TSTDecl->getTemplateArgs(); 157326941Sdim 158326941Sdim bool MightHaveChanged = false; 159326941Sdim SmallVector<TemplateArgument, 4> FQArgs; 160326941Sdim for (unsigned int I = 0, E = TemplateArgs.size(); I != E; ++I) { 161326941Sdim // cheap to copy and potentially modified by 162326941Sdim // getFullyQualifedTemplateArgument 163326941Sdim TemplateArgument Arg(TemplateArgs[I]); 164326941Sdim MightHaveChanged |= getFullyQualifiedTemplateArgument( 165326941Sdim Ctx, Arg, WithGlobalNsPrefix); 166326941Sdim FQArgs.push_back(Arg); 167326941Sdim } 168326941Sdim 169326941Sdim // If a fully qualified arg is different from the unqualified arg, 170326941Sdim // allocate new type in the AST. 171326941Sdim if (MightHaveChanged) { 172326941Sdim TemplateName TN(TSTDecl->getSpecializedTemplate()); 173326941Sdim QualType QT = Ctx.getTemplateSpecializationType( 174326941Sdim TN, FQArgs, 175326941Sdim TSTRecord->getCanonicalTypeInternal()); 176326941Sdim // getTemplateSpecializationType returns a fully qualified 177326941Sdim // version of the specialization itself, so no need to qualify 178326941Sdim // it. 179326941Sdim return QT.getTypePtr(); 180326941Sdim } 181326941Sdim } 182326941Sdim } 183326941Sdim return TypePtr; 184326941Sdim} 185326941Sdim 186326941Sdimstatic NestedNameSpecifier *createOuterNNS(const ASTContext &Ctx, const Decl *D, 187326941Sdim bool FullyQualify, 188326941Sdim bool WithGlobalNsPrefix) { 189326941Sdim const DeclContext *DC = D->getDeclContext(); 190326941Sdim if (const auto *NS = dyn_cast<NamespaceDecl>(DC)) { 191326941Sdim while (NS && NS->isInline()) { 192326941Sdim // Ignore inline namespace; 193326941Sdim NS = dyn_cast<NamespaceDecl>(NS->getDeclContext()); 194326941Sdim } 195360784Sdim if (NS && NS->getDeclName()) { 196326941Sdim return createNestedNameSpecifier(Ctx, NS, WithGlobalNsPrefix); 197326941Sdim } 198326941Sdim return nullptr; // no starting '::', no anonymous 199326941Sdim } else if (const auto *TD = dyn_cast<TagDecl>(DC)) { 200326941Sdim return createNestedNameSpecifier(Ctx, TD, FullyQualify, WithGlobalNsPrefix); 201326941Sdim } else if (const auto *TDD = dyn_cast<TypedefNameDecl>(DC)) { 202326941Sdim return createNestedNameSpecifier( 203326941Sdim Ctx, TDD, FullyQualify, WithGlobalNsPrefix); 204326941Sdim } else if (WithGlobalNsPrefix && DC->isTranslationUnit()) { 205326941Sdim return NestedNameSpecifier::GlobalSpecifier(Ctx); 206326941Sdim } 207326941Sdim return nullptr; // no starting '::' if |WithGlobalNsPrefix| is false 208326941Sdim} 209326941Sdim 210341825Sdim/// Return a fully qualified version of this name specifier. 211326941Sdimstatic NestedNameSpecifier *getFullyQualifiedNestedNameSpecifier( 212326941Sdim const ASTContext &Ctx, NestedNameSpecifier *Scope, 213326941Sdim bool WithGlobalNsPrefix) { 214326941Sdim switch (Scope->getKind()) { 215326941Sdim case NestedNameSpecifier::Global: 216326941Sdim // Already fully qualified 217326941Sdim return Scope; 218326941Sdim case NestedNameSpecifier::Namespace: 219326941Sdim return TypeName::createNestedNameSpecifier( 220326941Sdim Ctx, Scope->getAsNamespace(), WithGlobalNsPrefix); 221326941Sdim case NestedNameSpecifier::NamespaceAlias: 222326941Sdim // Namespace aliases are only valid for the duration of the 223326941Sdim // scope where they were introduced, and therefore are often 224326941Sdim // invalid at the end of the TU. So use the namespace name more 225326941Sdim // likely to be valid at the end of the TU. 226326941Sdim return TypeName::createNestedNameSpecifier( 227326941Sdim Ctx, 228326941Sdim Scope->getAsNamespaceAlias()->getNamespace()->getCanonicalDecl(), 229326941Sdim WithGlobalNsPrefix); 230326941Sdim case NestedNameSpecifier::Identifier: 231326941Sdim // A function or some other construct that makes it un-namable 232326941Sdim // at the end of the TU. Skip the current component of the name, 233326941Sdim // but use the name of it's prefix. 234326941Sdim return getFullyQualifiedNestedNameSpecifier( 235326941Sdim Ctx, Scope->getPrefix(), WithGlobalNsPrefix); 236326941Sdim case NestedNameSpecifier::Super: 237326941Sdim case NestedNameSpecifier::TypeSpec: 238326941Sdim case NestedNameSpecifier::TypeSpecWithTemplate: { 239326941Sdim const Type *Type = Scope->getAsType(); 240326941Sdim // Find decl context. 241326941Sdim const TagDecl *TD = nullptr; 242326941Sdim if (const TagType *TagDeclType = Type->getAs<TagType>()) { 243326941Sdim TD = TagDeclType->getDecl(); 244326941Sdim } else { 245326941Sdim TD = Type->getAsCXXRecordDecl(); 246326941Sdim } 247326941Sdim if (TD) { 248326941Sdim return TypeName::createNestedNameSpecifier(Ctx, TD, 249326941Sdim true /*FullyQualified*/, 250326941Sdim WithGlobalNsPrefix); 251326941Sdim } else if (const auto *TDD = dyn_cast<TypedefType>(Type)) { 252326941Sdim return TypeName::createNestedNameSpecifier(Ctx, TDD->getDecl(), 253326941Sdim true /*FullyQualified*/, 254326941Sdim WithGlobalNsPrefix); 255326941Sdim } 256326941Sdim return Scope; 257326941Sdim } 258326941Sdim } 259326941Sdim llvm_unreachable("bad NNS kind"); 260326941Sdim} 261326941Sdim 262341825Sdim/// Create a nested name specifier for the declaring context of 263326941Sdim/// the type. 264326941Sdimstatic NestedNameSpecifier *createNestedNameSpecifierForScopeOf( 265326941Sdim const ASTContext &Ctx, const Decl *Decl, 266326941Sdim bool FullyQualified, bool WithGlobalNsPrefix) { 267326941Sdim assert(Decl); 268326941Sdim 269326941Sdim const DeclContext *DC = Decl->getDeclContext()->getRedeclContext(); 270326941Sdim const auto *Outer = dyn_cast_or_null<NamedDecl>(DC); 271326941Sdim const auto *OuterNS = dyn_cast_or_null<NamespaceDecl>(DC); 272326941Sdim if (Outer && !(OuterNS && OuterNS->isAnonymousNamespace())) { 273326941Sdim if (const auto *CxxDecl = dyn_cast<CXXRecordDecl>(DC)) { 274326941Sdim if (ClassTemplateDecl *ClassTempl = 275326941Sdim CxxDecl->getDescribedClassTemplate()) { 276326941Sdim // We are in the case of a type(def) that was declared in a 277326941Sdim // class template but is *not* type dependent. In clang, it 278326941Sdim // gets attached to the class template declaration rather than 279326941Sdim // any specific class template instantiation. This result in 280326941Sdim // 'odd' fully qualified typename: 281326941Sdim // 282326941Sdim // vector<_Tp,_Alloc>::size_type 283326941Sdim // 284326941Sdim // Make the situation is 'useable' but looking a bit odd by 285326941Sdim // picking a random instance as the declaring context. 286326941Sdim if (ClassTempl->spec_begin() != ClassTempl->spec_end()) { 287326941Sdim Decl = *(ClassTempl->spec_begin()); 288326941Sdim Outer = dyn_cast<NamedDecl>(Decl); 289326941Sdim OuterNS = dyn_cast<NamespaceDecl>(Decl); 290326941Sdim } 291326941Sdim } 292326941Sdim } 293326941Sdim 294326941Sdim if (OuterNS) { 295326941Sdim return createNestedNameSpecifier(Ctx, OuterNS, WithGlobalNsPrefix); 296326941Sdim } else if (const auto *TD = dyn_cast<TagDecl>(Outer)) { 297326941Sdim return createNestedNameSpecifier( 298326941Sdim Ctx, TD, FullyQualified, WithGlobalNsPrefix); 299326941Sdim } else if (dyn_cast<TranslationUnitDecl>(Outer)) { 300326941Sdim // Context is the TU. Nothing needs to be done. 301326941Sdim return nullptr; 302326941Sdim } else { 303326941Sdim // Decl's context was neither the TU, a namespace, nor a 304326941Sdim // TagDecl, which means it is a type local to a scope, and not 305326941Sdim // accessible at the end of the TU. 306326941Sdim return nullptr; 307326941Sdim } 308326941Sdim } else if (WithGlobalNsPrefix && DC->isTranslationUnit()) { 309326941Sdim return NestedNameSpecifier::GlobalSpecifier(Ctx); 310326941Sdim } 311326941Sdim return nullptr; 312326941Sdim} 313326941Sdim 314341825Sdim/// Create a nested name specifier for the declaring context of 315326941Sdim/// the type. 316326941Sdimstatic NestedNameSpecifier *createNestedNameSpecifierForScopeOf( 317326941Sdim const ASTContext &Ctx, const Type *TypePtr, 318326941Sdim bool FullyQualified, bool WithGlobalNsPrefix) { 319326941Sdim if (!TypePtr) return nullptr; 320326941Sdim 321326941Sdim Decl *Decl = nullptr; 322326941Sdim // There are probably other cases ... 323326941Sdim if (const auto *TDT = dyn_cast<TypedefType>(TypePtr)) { 324326941Sdim Decl = TDT->getDecl(); 325326941Sdim } else if (const auto *TagDeclType = dyn_cast<TagType>(TypePtr)) { 326326941Sdim Decl = TagDeclType->getDecl(); 327326941Sdim } else if (const auto *TST = dyn_cast<TemplateSpecializationType>(TypePtr)) { 328326941Sdim Decl = TST->getTemplateName().getAsTemplateDecl(); 329326941Sdim } else { 330326941Sdim Decl = TypePtr->getAsCXXRecordDecl(); 331326941Sdim } 332326941Sdim 333326941Sdim if (!Decl) return nullptr; 334326941Sdim 335326941Sdim return createNestedNameSpecifierForScopeOf( 336326941Sdim Ctx, Decl, FullyQualified, WithGlobalNsPrefix); 337326941Sdim} 338326941Sdim 339326941SdimNestedNameSpecifier *createNestedNameSpecifier(const ASTContext &Ctx, 340326941Sdim const NamespaceDecl *Namespace, 341326941Sdim bool WithGlobalNsPrefix) { 342326941Sdim while (Namespace && Namespace->isInline()) { 343326941Sdim // Ignore inline namespace; 344326941Sdim Namespace = dyn_cast<NamespaceDecl>(Namespace->getDeclContext()); 345326941Sdim } 346326941Sdim if (!Namespace) return nullptr; 347326941Sdim 348326941Sdim bool FullyQualified = true; // doesn't matter, DeclContexts are namespaces 349326941Sdim return NestedNameSpecifier::Create( 350326941Sdim Ctx, 351326941Sdim createOuterNNS(Ctx, Namespace, FullyQualified, WithGlobalNsPrefix), 352326941Sdim Namespace); 353326941Sdim} 354326941Sdim 355326941SdimNestedNameSpecifier *createNestedNameSpecifier(const ASTContext &Ctx, 356326941Sdim const TypeDecl *TD, 357326941Sdim bool FullyQualify, 358326941Sdim bool WithGlobalNsPrefix) { 359326941Sdim return NestedNameSpecifier::Create( 360326941Sdim Ctx, 361326941Sdim createOuterNNS(Ctx, TD, FullyQualify, WithGlobalNsPrefix), 362326941Sdim false /*No TemplateKeyword*/, 363326941Sdim TD->getTypeForDecl()); 364326941Sdim} 365326941Sdim 366341825Sdim/// Return the fully qualified type, including fully-qualified 367326941Sdim/// versions of any template parameters. 368326941SdimQualType getFullyQualifiedType(QualType QT, const ASTContext &Ctx, 369326941Sdim bool WithGlobalNsPrefix) { 370326941Sdim // In case of myType* we need to strip the pointer first, fully 371326941Sdim // qualify and attach the pointer once again. 372326941Sdim if (isa<PointerType>(QT.getTypePtr())) { 373326941Sdim // Get the qualifiers. 374326941Sdim Qualifiers Quals = QT.getQualifiers(); 375326941Sdim QT = getFullyQualifiedType(QT->getPointeeType(), Ctx, WithGlobalNsPrefix); 376326941Sdim QT = Ctx.getPointerType(QT); 377326941Sdim // Add back the qualifiers. 378326941Sdim QT = Ctx.getQualifiedType(QT, Quals); 379326941Sdim return QT; 380326941Sdim } 381326941Sdim 382353358Sdim if (auto *MPT = dyn_cast<MemberPointerType>(QT.getTypePtr())) { 383353358Sdim // Get the qualifiers. 384353358Sdim Qualifiers Quals = QT.getQualifiers(); 385353358Sdim // Fully qualify the pointee and class types. 386353358Sdim QT = getFullyQualifiedType(QT->getPointeeType(), Ctx, WithGlobalNsPrefix); 387353358Sdim QualType Class = getFullyQualifiedType(QualType(MPT->getClass(), 0), Ctx, 388353358Sdim WithGlobalNsPrefix); 389353358Sdim QT = Ctx.getMemberPointerType(QT, Class.getTypePtr()); 390353358Sdim // Add back the qualifiers. 391353358Sdim QT = Ctx.getQualifiedType(QT, Quals); 392353358Sdim return QT; 393353358Sdim } 394353358Sdim 395326941Sdim // In case of myType& we need to strip the reference first, fully 396326941Sdim // qualify and attach the reference once again. 397326941Sdim if (isa<ReferenceType>(QT.getTypePtr())) { 398326941Sdim // Get the qualifiers. 399326941Sdim bool IsLValueRefTy = isa<LValueReferenceType>(QT.getTypePtr()); 400326941Sdim Qualifiers Quals = QT.getQualifiers(); 401326941Sdim QT = getFullyQualifiedType(QT->getPointeeType(), Ctx, WithGlobalNsPrefix); 402326941Sdim // Add the r- or l-value reference type back to the fully 403326941Sdim // qualified one. 404326941Sdim if (IsLValueRefTy) 405326941Sdim QT = Ctx.getLValueReferenceType(QT); 406326941Sdim else 407326941Sdim QT = Ctx.getRValueReferenceType(QT); 408326941Sdim // Add back the qualifiers. 409326941Sdim QT = Ctx.getQualifiedType(QT, Quals); 410326941Sdim return QT; 411326941Sdim } 412326941Sdim 413326941Sdim // Remove the part of the type related to the type being a template 414326941Sdim // parameter (we won't report it as part of the 'type name' and it 415326941Sdim // is actually make the code below to be more complex (to handle 416326941Sdim // those) 417326941Sdim while (isa<SubstTemplateTypeParmType>(QT.getTypePtr())) { 418326941Sdim // Get the qualifiers. 419326941Sdim Qualifiers Quals = QT.getQualifiers(); 420326941Sdim 421341825Sdim QT = cast<SubstTemplateTypeParmType>(QT.getTypePtr())->desugar(); 422326941Sdim 423326941Sdim // Add back the qualifiers. 424326941Sdim QT = Ctx.getQualifiedType(QT, Quals); 425326941Sdim } 426326941Sdim 427326941Sdim NestedNameSpecifier *Prefix = nullptr; 428326941Sdim // Local qualifiers are attached to the QualType outside of the 429326941Sdim // elaborated type. Retrieve them before descending into the 430326941Sdim // elaborated type. 431326941Sdim Qualifiers PrefixQualifiers = QT.getLocalQualifiers(); 432326941Sdim QT = QualType(QT.getTypePtr(), 0); 433326941Sdim ElaboratedTypeKeyword Keyword = ETK_None; 434326941Sdim if (const auto *ETypeInput = dyn_cast<ElaboratedType>(QT.getTypePtr())) { 435326941Sdim QT = ETypeInput->getNamedType(); 436326941Sdim assert(!QT.hasLocalQualifiers()); 437326941Sdim Keyword = ETypeInput->getKeyword(); 438326941Sdim } 439326941Sdim // Create a nested name specifier if needed. 440326941Sdim Prefix = createNestedNameSpecifierForScopeOf(Ctx, QT.getTypePtr(), 441326941Sdim true /*FullyQualified*/, 442326941Sdim WithGlobalNsPrefix); 443326941Sdim 444326941Sdim // In case of template specializations iterate over the arguments and 445326941Sdim // fully qualify them as well. 446326941Sdim if (isa<const TemplateSpecializationType>(QT.getTypePtr()) || 447326941Sdim isa<const RecordType>(QT.getTypePtr())) { 448326941Sdim // We are asked to fully qualify and we have a Record Type (which 449326941Sdim // may point to a template specialization) or Template 450326941Sdim // Specialization Type. We need to fully qualify their arguments. 451326941Sdim 452326941Sdim const Type *TypePtr = getFullyQualifiedTemplateType( 453326941Sdim Ctx, QT.getTypePtr(), WithGlobalNsPrefix); 454326941Sdim QT = QualType(TypePtr, 0); 455326941Sdim } 456326941Sdim if (Prefix || Keyword != ETK_None) { 457326941Sdim QT = Ctx.getElaboratedType(Keyword, Prefix, QT); 458326941Sdim } 459326941Sdim QT = Ctx.getQualifiedType(QT, PrefixQualifiers); 460326941Sdim return QT; 461326941Sdim} 462326941Sdim 463326941Sdimstd::string getFullyQualifiedName(QualType QT, 464326941Sdim const ASTContext &Ctx, 465341825Sdim const PrintingPolicy &Policy, 466326941Sdim bool WithGlobalNsPrefix) { 467326941Sdim QualType FQQT = getFullyQualifiedType(QT, Ctx, WithGlobalNsPrefix); 468326941Sdim return FQQT.getAsString(Policy); 469326941Sdim} 470326941Sdim 471326941Sdim} // end namespace TypeName 472326941Sdim} // end namespace clang 473