"Fossies" - the Fresh Open Source Software Archive

Member "cfe-9.0.0.src/lib/AST/QualTypeNames.cpp" (15 Mar 2019, 18893 Bytes) of package /linux/misc/cfe-9.0.0.src.tar.xz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. See also the latest Fossies "Diffs" side-by-side code changes report for "QualTypeNames.cpp": 8.0.1_vs_9.0.0.

    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->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