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