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