brintos

brintos / llvm-project-archived public Read only

0
0
Text · 19.6 KiB · 1918416 Raw
506 lines · cpp
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-exception6//7//===----------------------------------------------------------------------===//8 9#include "clang/AST/QualTypeNames.h"10#include "clang/AST/DeclTemplate.h"11#include "clang/AST/DeclarationName.h"12#include "clang/AST/Mangle.h"13#include "clang/AST/Type.h"14 15namespace clang {16 17namespace TypeName {18 19/// Create a NestedNameSpecifier for Namesp and its enclosing20/// scopes.21///22/// \param[in] Ctx - the AST Context to be used.23/// \param[in] Namesp - the NamespaceDecl for which a NestedNameSpecifier24/// is requested.25/// \param[in] WithGlobalNsPrefix - Indicate whether the global namespace26/// specifier "::" should be prepended or not.27static NestedNameSpecifier28createNestedNameSpecifier(const ASTContext &Ctx, const NamespaceDecl *Namesp,29                          bool WithGlobalNsPrefix);30 31/// Create a NestedNameSpecifier for TagDecl and its enclosing32/// scopes.33///34/// \param[in] Ctx - the AST Context to be used.35/// \param[in] TD - the TagDecl for which a NestedNameSpecifier is36/// requested.37/// \param[in] FullyQualify - Convert all template arguments into fully38/// qualified names.39/// \param[in] WithGlobalNsPrefix - Indicate whether the global namespace40/// specifier "::" should be prepended or not.41static NestedNameSpecifier createNestedNameSpecifier(const ASTContext &Ctx,42                                                     const TypeDecl *TD,43                                                     bool FullyQualify,44                                                     bool WithGlobalNsPrefix);45 46static NestedNameSpecifier47createNestedNameSpecifierForScopeOf(const ASTContext &Ctx, const Decl *decl,48                                    bool FullyQualified,49                                    bool WithGlobalNsPrefix);50 51static NestedNameSpecifier getFullyQualifiedNestedNameSpecifier(52    const ASTContext &Ctx, NestedNameSpecifier NNS, bool WithGlobalNsPrefix);53 54static bool getFullyQualifiedTemplateName(const ASTContext &Ctx,55                                          TemplateName &TName,56                                          bool WithGlobalNsPrefix) {57  bool Changed = false;58  NestedNameSpecifier NNS = std::nullopt;59 60  TemplateDecl *ArgTDecl = TName.getAsTemplateDecl();61  if (!ArgTDecl) // ArgTDecl can be null in dependent contexts.62    return false;63 64  QualifiedTemplateName *QTName = TName.getAsQualifiedTemplateName();65 66  if (QTName &&67      !QTName->hasTemplateKeyword() &&68      (NNS = QTName->getQualifier())) {69    NestedNameSpecifier QNNS =70        getFullyQualifiedNestedNameSpecifier(Ctx, NNS, WithGlobalNsPrefix);71    if (QNNS != NNS) {72      Changed = true;73      NNS = QNNS;74    } else {75      NNS = std::nullopt;76    }77  } else {78    NNS = createNestedNameSpecifierForScopeOf(79        Ctx, ArgTDecl, true, WithGlobalNsPrefix);80  }81  if (NNS) {82    TemplateName UnderlyingTN(ArgTDecl);83    if (UsingShadowDecl *USD = TName.getAsUsingShadowDecl())84      UnderlyingTN = TemplateName(USD);85    TName =86        Ctx.getQualifiedTemplateName(NNS,87                                     /*TemplateKeyword=*/false, UnderlyingTN);88    Changed = true;89  }90  return Changed;91}92 93static bool getFullyQualifiedTemplateArgument(const ASTContext &Ctx,94                                              TemplateArgument &Arg,95                                              bool WithGlobalNsPrefix) {96  bool Changed = false;97 98  // Note: we do not handle TemplateArgument::Expression, to replace it99  // we need the information for the template instance decl.100 101  if (Arg.getKind() == TemplateArgument::Template) {102    TemplateName TName = Arg.getAsTemplate();103    Changed = getFullyQualifiedTemplateName(Ctx, TName, WithGlobalNsPrefix);104    if (Changed) {105      Arg = TemplateArgument(TName);106    }107  } else if (Arg.getKind() == TemplateArgument::Type) {108    QualType SubTy = Arg.getAsType();109    // Check if the type needs more desugaring and recurse.110    QualType QTFQ = getFullyQualifiedType(SubTy, Ctx, WithGlobalNsPrefix);111    if (QTFQ != SubTy) {112      Arg = TemplateArgument(QTFQ);113      Changed = true;114    }115  }116  return Changed;117}118 119static const Type *getFullyQualifiedTemplateType(const ASTContext &Ctx,120                                                 const TagType *TSTRecord,121                                                 ElaboratedTypeKeyword Keyword,122                                                 NestedNameSpecifier Qualifier,123                                                 bool WithGlobalNsPrefix) {124  // We are asked to fully qualify and we have a Record Type,125  // which can point to a template instantiation with no sugar in any of126  // its template argument, however we still need to fully qualify them.127 128  const auto *TD = TSTRecord->getDecl();129  const auto *TSTDecl = dyn_cast<ClassTemplateSpecializationDecl>(TD);130  if (!TSTDecl)131    return Ctx.getTagType(Keyword, Qualifier, TD, /*OwnsTag=*/false)132        .getTypePtr();133 134  const TemplateArgumentList &TemplateArgs = TSTDecl->getTemplateArgs();135 136  bool MightHaveChanged = false;137  SmallVector<TemplateArgument, 4> FQArgs;138  for (unsigned int I = 0, E = TemplateArgs.size(); I != E; ++I) {139    // cheap to copy and potentially modified by140    // getFullyQualifedTemplateArgument141    TemplateArgument Arg(TemplateArgs[I]);142    MightHaveChanged |=143        getFullyQualifiedTemplateArgument(Ctx, Arg, WithGlobalNsPrefix);144    FQArgs.push_back(Arg);145  }146 147  if (!MightHaveChanged)148    return Ctx.getTagType(Keyword, Qualifier, TD, /*OwnsTag=*/false)149        .getTypePtr();150  // If a fully qualified arg is different from the unqualified arg,151  // allocate new type in the AST.152  TemplateName TN = Ctx.getQualifiedTemplateName(153      Qualifier, /*TemplateKeyword=*/false,154      TemplateName(TSTDecl->getSpecializedTemplate()));155  QualType QT = Ctx.getTemplateSpecializationType(156      Keyword, TN, FQArgs,157      /*CanonicalArgs=*/{}, TSTRecord->getCanonicalTypeInternal());158  // getTemplateSpecializationType returns a fully qualified159  // version of the specialization itself, so no need to qualify160  // it.161  return QT.getTypePtr();162}163 164static const Type *165getFullyQualifiedTemplateType(const ASTContext &Ctx,166                              const TemplateSpecializationType *TST,167                              bool WithGlobalNsPrefix) {168  TemplateName TName = TST->getTemplateName();169  bool MightHaveChanged =170      getFullyQualifiedTemplateName(Ctx, TName, WithGlobalNsPrefix);171  SmallVector<TemplateArgument, 4> FQArgs;172  // Cheap to copy and potentially modified by173  // getFullyQualifedTemplateArgument.174  for (TemplateArgument Arg : TST->template_arguments()) {175    MightHaveChanged |=176        getFullyQualifiedTemplateArgument(Ctx, Arg, WithGlobalNsPrefix);177    FQArgs.push_back(Arg);178  }179 180  if (!MightHaveChanged)181    return TST;182 183  QualType NewQT =184      Ctx.getTemplateSpecializationType(TST->getKeyword(), TName, FQArgs,185                                        /*CanonicalArgs=*/{}, TST->desugar());186  // getTemplateSpecializationType returns a fully qualified187  // version of the specialization itself, so no need to qualify188  // it.189  return NewQT.getTypePtr();190}191 192static NestedNameSpecifier createOuterNNS(const ASTContext &Ctx, const Decl *D,193                                          bool FullyQualify,194                                          bool WithGlobalNsPrefix) {195  const DeclContext *DC = D->getDeclContext();196  if (const auto *NS = dyn_cast<NamespaceDecl>(DC)) {197    while (NS && NS->isInline()) {198      // Ignore inline namespace;199      NS = dyn_cast<NamespaceDecl>(NS->getDeclContext());200    }201    if (NS && NS->getDeclName()) {202      return createNestedNameSpecifier(Ctx, NS, WithGlobalNsPrefix);203    }204    return std::nullopt; // no starting '::', no anonymous205  }206  if (const auto *TD = dyn_cast<TagDecl>(DC))207    return createNestedNameSpecifier(Ctx, TD, FullyQualify, WithGlobalNsPrefix);208  if (const auto *TDD = dyn_cast<TypedefNameDecl>(DC))209    return createNestedNameSpecifier(Ctx, TDD, FullyQualify,210                                     WithGlobalNsPrefix);211  if (WithGlobalNsPrefix && DC->isTranslationUnit())212    return NestedNameSpecifier::getGlobal();213  return std::nullopt; // no starting '::' if |WithGlobalNsPrefix| is false214}215 216/// Return a fully qualified version of this name specifier.217static NestedNameSpecifier getFullyQualifiedNestedNameSpecifier(218    const ASTContext &Ctx, NestedNameSpecifier Scope, bool WithGlobalNsPrefix) {219  switch (Scope.getKind()) {220  case NestedNameSpecifier::Kind::Null:221    llvm_unreachable("can't fully qualify the empty nested name specifier");222  case NestedNameSpecifier::Kind::Global:223  case NestedNameSpecifier::Kind::MicrosoftSuper:224    // Already fully qualified225    return Scope;226  case NestedNameSpecifier::Kind::Namespace:227    return TypeName::createNestedNameSpecifier(228        Ctx, Scope.getAsNamespaceAndPrefix().Namespace->getNamespace(),229        WithGlobalNsPrefix);230  case NestedNameSpecifier::Kind::Type: {231    const Type *Type = Scope.getAsType();232    // Find decl context.233    const TypeDecl *TD;234    if (const TagType *TagDeclType = Type->getAs<TagType>())235      TD = TagDeclType->getDecl();236    else if (const auto *D = dyn_cast<TypedefType>(Type))237      TD = D->getDecl();238    else239      return Scope;240    return TypeName::createNestedNameSpecifier(Ctx, TD, /*FullyQualify=*/true,241                                               WithGlobalNsPrefix);242  }243  }244  llvm_unreachable("bad NNS kind");245}246 247/// Create a nested name specifier for the declaring context of248/// the type.249static NestedNameSpecifier250createNestedNameSpecifierForScopeOf(const ASTContext &Ctx, const Decl *Decl,251                                    bool FullyQualified,252                                    bool WithGlobalNsPrefix) {253  assert(Decl);254 255  // Some declaration cannot be qualified.256  if (Decl->isTemplateParameter())257    return std::nullopt;258  const DeclContext *DC = Decl->getDeclContext()->getRedeclContext();259  const auto *Outer = dyn_cast<NamedDecl>(DC);260  const auto *OuterNS = dyn_cast<NamespaceDecl>(DC);261  if (OuterNS && OuterNS->isAnonymousNamespace())262    OuterNS = dyn_cast<NamespaceDecl>(OuterNS->getParent());263  if (Outer) {264    if (const auto *CxxDecl = dyn_cast<CXXRecordDecl>(DC)) {265      if (ClassTemplateDecl *ClassTempl =266              CxxDecl->getDescribedClassTemplate()) {267        // We are in the case of a type(def) that was declared in a268        // class template but is *not* type dependent.  In clang, it269        // gets attached to the class template declaration rather than270        // any specific class template instantiation.  This result in271        // 'odd' fully qualified typename:272        //273        //    vector<_Tp,_Alloc>::size_type274        //275        // Make the situation is 'useable' but looking a bit odd by276        // picking a random instance as the declaring context.277        if (!ClassTempl->specializations().empty()) {278          Decl = *(ClassTempl->spec_begin());279          Outer = dyn_cast<NamedDecl>(Decl);280          OuterNS = dyn_cast<NamespaceDecl>(Decl);281        }282      }283    }284 285    if (OuterNS) {286      return createNestedNameSpecifier(Ctx, OuterNS, WithGlobalNsPrefix);287    } else if (const auto *TD = dyn_cast<TagDecl>(Outer)) {288      return createNestedNameSpecifier(289          Ctx, TD, FullyQualified, WithGlobalNsPrefix);290    } else if (isa<TranslationUnitDecl>(Outer)) {291      // Context is the TU. Nothing needs to be done.292      return std::nullopt;293    } else {294      // Decl's context was neither the TU, a namespace, nor a295      // TagDecl, which means it is a type local to a scope, and not296      // accessible at the end of the TU.297      return std::nullopt;298    }299  } else if (WithGlobalNsPrefix && DC->isTranslationUnit()) {300    return NestedNameSpecifier::getGlobal();301  }302  return std::nullopt;303}304 305/// Create a nested name specifier for the declaring context of306/// the type.307static NestedNameSpecifier308createNestedNameSpecifierForScopeOf(const ASTContext &Ctx, const Type *TypePtr,309                                    bool FullyQualified,310                                    bool WithGlobalNsPrefix) {311  if (!TypePtr)312    return std::nullopt;313 314  Decl *Decl = nullptr;315  // There are probably other cases ...316  if (const auto *TDT = dyn_cast<TypedefType>(TypePtr)) {317    Decl = TDT->getDecl();318  } else if (const auto *TagDeclType = dyn_cast<TagType>(TypePtr)) {319    Decl = TagDeclType->getDecl();320  } else if (const auto *TST = dyn_cast<TemplateSpecializationType>(TypePtr)) {321    Decl = TST->getTemplateName().getAsTemplateDecl();322  } else {323    Decl = TypePtr->getAsCXXRecordDecl();324  }325 326  if (!Decl)327    return std::nullopt;328 329  return createNestedNameSpecifierForScopeOf(330      Ctx, Decl, FullyQualified, WithGlobalNsPrefix);331}332 333static NestedNameSpecifier334createNestedNameSpecifier(const ASTContext &Ctx, const NamespaceDecl *Namespace,335                          bool WithGlobalNsPrefix) {336  while (Namespace && Namespace->isInline()) {337    // Ignore inline namespace;338    Namespace = dyn_cast<NamespaceDecl>(Namespace->getDeclContext());339  }340  if (!Namespace)341    return std::nullopt;342 343  bool FullyQualify = true; // doesn't matter, DeclContexts are namespaces344  return NestedNameSpecifier(345      Ctx, Namespace,346      createOuterNNS(Ctx, Namespace, FullyQualify, WithGlobalNsPrefix));347}348 349NestedNameSpecifier createNestedNameSpecifier(const ASTContext &Ctx,350                                              const TypeDecl *TD,351                                              bool FullyQualify,352                                              bool WithGlobalNsPrefix) {353  const Type *TypePtr = Ctx.getTypeDeclType(TD).getTypePtr();354  if (auto *RD = dyn_cast<TagType>(TypePtr)) {355    // We are asked to fully qualify and we have a Record Type (which356    // may point to a template specialization) or Template357    // Specialization Type. We need to fully qualify their arguments.358    TypePtr = getFullyQualifiedTemplateType(359        Ctx, RD, ElaboratedTypeKeyword::None,360        createOuterNNS(Ctx, TD, FullyQualify, WithGlobalNsPrefix),361        WithGlobalNsPrefix);362  } else if (auto *TST = dyn_cast<TemplateSpecializationType>(TypePtr)) {363    TypePtr = getFullyQualifiedTemplateType(Ctx, TST, WithGlobalNsPrefix);364  }365  return NestedNameSpecifier(TypePtr);366}367 368/// Return the fully qualified type, including fully-qualified369/// versions of any template parameters.370QualType getFullyQualifiedType(QualType QT, const ASTContext &Ctx,371                               bool WithGlobalNsPrefix) {372  // In case of myType* we need to strip the pointer first, fully373  // qualify and attach the pointer once again.374  if (isa<PointerType>(QT.getTypePtr())) {375    // Get the qualifiers.376    Qualifiers Quals = QT.getQualifiers();377    QT = getFullyQualifiedType(QT->getPointeeType(), Ctx, WithGlobalNsPrefix);378    QT = Ctx.getPointerType(QT);379    // Add back the qualifiers.380    QT = Ctx.getQualifiedType(QT, Quals);381    return QT;382  }383 384  if (auto *MPT = dyn_cast<MemberPointerType>(QT.getTypePtr())) {385    // Get the qualifiers.386    Qualifiers Quals = QT.getQualifiers();387    // Fully qualify the pointee and class types.388    QT = getFullyQualifiedType(QT->getPointeeType(), Ctx, WithGlobalNsPrefix);389    NestedNameSpecifier Qualifier = getFullyQualifiedNestedNameSpecifier(390        Ctx, MPT->getQualifier(), WithGlobalNsPrefix);391    QT = Ctx.getMemberPointerType(QT, Qualifier,392                                  MPT->getMostRecentCXXRecordDecl());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, fully399  // 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 fully406    // qualified one.407    if (IsLValueRefTy)408      QT = Ctx.getLValueReferenceType(QT);409    else410      QT = Ctx.getRValueReferenceType(QT);411    // Add back the qualifiers.412    QT = Ctx.getQualifiedType(QT, Quals);413    return QT;414  }415 416  // Handle types with attributes such as `unique_ptr<int> _Nonnull`.417  if (auto *AT = dyn_cast<AttributedType>(QT.getTypePtr())) {418    QualType NewModified =419        getFullyQualifiedType(AT->getModifiedType(), Ctx, WithGlobalNsPrefix);420    QualType NewEquivalent =421        getFullyQualifiedType(AT->getEquivalentType(), Ctx, WithGlobalNsPrefix);422    Qualifiers Qualifiers = QT.getLocalQualifiers();423    return Ctx.getQualifiedType(424        Ctx.getAttributedType(AT->getAttrKind(), NewModified, NewEquivalent),425        Qualifiers);426  }427 428  // Remove the part of the type related to the type being a template429  // parameter (we won't report it as part of the 'type name' and it430  // is actually make the code below to be more complex (to handle431  // those)432  while (isa<SubstTemplateTypeParmType>(QT.getTypePtr())) {433    // Get the qualifiers.434    Qualifiers Quals = QT.getQualifiers();435 436    QT = cast<SubstTemplateTypeParmType>(QT.getTypePtr())->desugar();437 438    // Add back the qualifiers.439    QT = Ctx.getQualifiedType(QT, Quals);440  }441 442  if (const auto *TST =443          dyn_cast<const TemplateSpecializationType>(QT.getTypePtr())) {444 445    const Type *T = getFullyQualifiedTemplateType(Ctx, TST, WithGlobalNsPrefix);446    if (T == TST)447      return QT;448    return Ctx.getQualifiedType(T, QT.getQualifiers());449  }450 451  // Local qualifiers are attached to the QualType outside of the452  // elaborated type.  Retrieve them before descending into the453  // elaborated type.454  Qualifiers PrefixQualifiers = QT.getLocalQualifiers();455  QT = QualType(QT.getTypePtr(), 0);456 457  // We don't consider the alias introduced by `using a::X` as a new type.458  // The qualified name is still a::X.459  if (const auto *UT = QT->getAs<UsingType>()) {460    QT = Ctx.getQualifiedType(UT->desugar(), PrefixQualifiers);461    return getFullyQualifiedType(QT, Ctx, WithGlobalNsPrefix);462  }463 464  // Create a nested name specifier if needed.465  NestedNameSpecifier Prefix = createNestedNameSpecifierForScopeOf(466      Ctx, QT.getTypePtr(), true /*FullyQualified*/, WithGlobalNsPrefix);467 468  // In case of template specializations iterate over the arguments and469  // fully qualify them as well.470  if (const auto *TT = dyn_cast<TagType>(QT.getTypePtr())) {471    // We are asked to fully qualify and we have a Record Type (which472    // may point to a template specialization) or Template473    // Specialization Type. We need to fully qualify their arguments.474 475    const Type *TypePtr = getFullyQualifiedTemplateType(476        Ctx, TT, TT->getKeyword(), Prefix, WithGlobalNsPrefix);477    QT = QualType(TypePtr, 0);478  } else if (const auto *TT = dyn_cast<TypedefType>(QT.getTypePtr())) {479    QT = Ctx.getTypedefType(480        TT->getKeyword(), Prefix, TT->getDecl(),481        getFullyQualifiedType(TT->desugar(), Ctx, WithGlobalNsPrefix));482  } else {483    assert(!Prefix && "Unhandled type node");484  }485  QT = Ctx.getQualifiedType(QT, PrefixQualifiers);486  return QT;487}488 489std::string getFullyQualifiedName(QualType QT,490                                  const ASTContext &Ctx,491                                  const PrintingPolicy &Policy,492                                  bool WithGlobalNsPrefix) {493  QualType FQQT = getFullyQualifiedType(QT, Ctx, WithGlobalNsPrefix);494  return FQQT.getAsString(Policy);495}496 497NestedNameSpecifier getFullyQualifiedDeclaredContext(const ASTContext &Ctx,498                                                     const Decl *Decl,499                                                     bool WithGlobalNsPrefix) {500  return createNestedNameSpecifierForScopeOf(Ctx, Decl, /*FullyQualified=*/true,501                                             WithGlobalNsPrefix);502}503 504}  // end namespace TypeName505}  // end namespace clang506