106f32e7eSjoerg //===------- QualTypeNames.cpp - Generate Complete QualType Names ---------===//
206f32e7eSjoerg //
306f32e7eSjoerg // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
406f32e7eSjoerg // See https://llvm.org/LICENSE.txt for license information.
506f32e7eSjoerg // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
606f32e7eSjoerg //
706f32e7eSjoerg //===----------------------------------------------------------------------===//
806f32e7eSjoerg
906f32e7eSjoerg #include "clang/AST/DeclTemplate.h"
1006f32e7eSjoerg #include "clang/AST/DeclarationName.h"
1106f32e7eSjoerg #include "clang/AST/GlobalDecl.h"
1206f32e7eSjoerg #include "clang/AST/Mangle.h"
1306f32e7eSjoerg #include "clang/AST/QualTypeNames.h"
1406f32e7eSjoerg
1506f32e7eSjoerg #include <stdio.h>
1606f32e7eSjoerg #include <memory>
1706f32e7eSjoerg
1806f32e7eSjoerg namespace clang {
1906f32e7eSjoerg
2006f32e7eSjoerg namespace TypeName {
2106f32e7eSjoerg
2206f32e7eSjoerg /// Create a NestedNameSpecifier for Namesp and its enclosing
2306f32e7eSjoerg /// scopes.
2406f32e7eSjoerg ///
2506f32e7eSjoerg /// \param[in] Ctx - the AST Context to be used.
2606f32e7eSjoerg /// \param[in] Namesp - the NamespaceDecl for which a NestedNameSpecifier
2706f32e7eSjoerg /// is requested.
2806f32e7eSjoerg /// \param[in] WithGlobalNsPrefix - Indicate whether the global namespace
2906f32e7eSjoerg /// specifier "::" should be prepended or not.
3006f32e7eSjoerg static NestedNameSpecifier *createNestedNameSpecifier(
3106f32e7eSjoerg const ASTContext &Ctx,
3206f32e7eSjoerg const NamespaceDecl *Namesp,
3306f32e7eSjoerg bool WithGlobalNsPrefix);
3406f32e7eSjoerg
3506f32e7eSjoerg /// Create a NestedNameSpecifier for TagDecl and its enclosing
3606f32e7eSjoerg /// scopes.
3706f32e7eSjoerg ///
3806f32e7eSjoerg /// \param[in] Ctx - the AST Context to be used.
3906f32e7eSjoerg /// \param[in] TD - the TagDecl for which a NestedNameSpecifier is
4006f32e7eSjoerg /// requested.
4106f32e7eSjoerg /// \param[in] FullyQualify - Convert all template arguments into fully
4206f32e7eSjoerg /// qualified names.
4306f32e7eSjoerg /// \param[in] WithGlobalNsPrefix - Indicate whether the global namespace
4406f32e7eSjoerg /// specifier "::" should be prepended or not.
4506f32e7eSjoerg static NestedNameSpecifier *createNestedNameSpecifier(
4606f32e7eSjoerg const ASTContext &Ctx, const TypeDecl *TD,
4706f32e7eSjoerg bool FullyQualify, bool WithGlobalNsPrefix);
4806f32e7eSjoerg
4906f32e7eSjoerg static NestedNameSpecifier *createNestedNameSpecifierForScopeOf(
5006f32e7eSjoerg const ASTContext &Ctx, const Decl *decl,
5106f32e7eSjoerg bool FullyQualified, bool WithGlobalNsPrefix);
5206f32e7eSjoerg
5306f32e7eSjoerg static NestedNameSpecifier *getFullyQualifiedNestedNameSpecifier(
5406f32e7eSjoerg const ASTContext &Ctx, NestedNameSpecifier *scope, bool WithGlobalNsPrefix);
5506f32e7eSjoerg
getFullyQualifiedTemplateName(const ASTContext & Ctx,TemplateName & TName,bool WithGlobalNsPrefix)5606f32e7eSjoerg static bool getFullyQualifiedTemplateName(const ASTContext &Ctx,
5706f32e7eSjoerg TemplateName &TName,
5806f32e7eSjoerg bool WithGlobalNsPrefix) {
5906f32e7eSjoerg bool Changed = false;
6006f32e7eSjoerg NestedNameSpecifier *NNS = nullptr;
6106f32e7eSjoerg
6206f32e7eSjoerg TemplateDecl *ArgTDecl = TName.getAsTemplateDecl();
6306f32e7eSjoerg // ArgTDecl won't be NULL because we asserted that this isn't a
6406f32e7eSjoerg // dependent context very early in the call chain.
6506f32e7eSjoerg assert(ArgTDecl != nullptr);
6606f32e7eSjoerg QualifiedTemplateName *QTName = TName.getAsQualifiedTemplateName();
6706f32e7eSjoerg
6806f32e7eSjoerg if (QTName && !QTName->hasTemplateKeyword()) {
6906f32e7eSjoerg NNS = QTName->getQualifier();
7006f32e7eSjoerg NestedNameSpecifier *QNNS = getFullyQualifiedNestedNameSpecifier(
7106f32e7eSjoerg Ctx, NNS, WithGlobalNsPrefix);
7206f32e7eSjoerg if (QNNS != NNS) {
7306f32e7eSjoerg Changed = true;
7406f32e7eSjoerg NNS = QNNS;
7506f32e7eSjoerg } else {
7606f32e7eSjoerg NNS = nullptr;
7706f32e7eSjoerg }
7806f32e7eSjoerg } else {
7906f32e7eSjoerg NNS = createNestedNameSpecifierForScopeOf(
8006f32e7eSjoerg Ctx, ArgTDecl, true, WithGlobalNsPrefix);
8106f32e7eSjoerg }
8206f32e7eSjoerg if (NNS) {
8306f32e7eSjoerg TName = Ctx.getQualifiedTemplateName(NNS,
8406f32e7eSjoerg /*TemplateKeyword=*/false, ArgTDecl);
8506f32e7eSjoerg Changed = true;
8606f32e7eSjoerg }
8706f32e7eSjoerg return Changed;
8806f32e7eSjoerg }
8906f32e7eSjoerg
getFullyQualifiedTemplateArgument(const ASTContext & Ctx,TemplateArgument & Arg,bool WithGlobalNsPrefix)9006f32e7eSjoerg static bool getFullyQualifiedTemplateArgument(const ASTContext &Ctx,
9106f32e7eSjoerg TemplateArgument &Arg,
9206f32e7eSjoerg bool WithGlobalNsPrefix) {
9306f32e7eSjoerg bool Changed = false;
9406f32e7eSjoerg
9506f32e7eSjoerg // Note: we do not handle TemplateArgument::Expression, to replace it
9606f32e7eSjoerg // we need the information for the template instance decl.
9706f32e7eSjoerg
9806f32e7eSjoerg if (Arg.getKind() == TemplateArgument::Template) {
9906f32e7eSjoerg TemplateName TName = Arg.getAsTemplate();
10006f32e7eSjoerg Changed = getFullyQualifiedTemplateName(Ctx, TName, WithGlobalNsPrefix);
10106f32e7eSjoerg if (Changed) {
10206f32e7eSjoerg Arg = TemplateArgument(TName);
10306f32e7eSjoerg }
10406f32e7eSjoerg } else if (Arg.getKind() == TemplateArgument::Type) {
10506f32e7eSjoerg QualType SubTy = Arg.getAsType();
10606f32e7eSjoerg // Check if the type needs more desugaring and recurse.
10706f32e7eSjoerg QualType QTFQ = getFullyQualifiedType(SubTy, Ctx, WithGlobalNsPrefix);
10806f32e7eSjoerg if (QTFQ != SubTy) {
10906f32e7eSjoerg Arg = TemplateArgument(QTFQ);
11006f32e7eSjoerg Changed = true;
11106f32e7eSjoerg }
11206f32e7eSjoerg }
11306f32e7eSjoerg return Changed;
11406f32e7eSjoerg }
11506f32e7eSjoerg
getFullyQualifiedTemplateType(const ASTContext & Ctx,const Type * TypePtr,bool WithGlobalNsPrefix)11606f32e7eSjoerg static const Type *getFullyQualifiedTemplateType(const ASTContext &Ctx,
11706f32e7eSjoerg const Type *TypePtr,
11806f32e7eSjoerg bool WithGlobalNsPrefix) {
11906f32e7eSjoerg // DependentTemplateTypes exist within template declarations and
12006f32e7eSjoerg // definitions. Therefore we shouldn't encounter them at the end of
12106f32e7eSjoerg // a translation unit. If we do, the caller has made an error.
12206f32e7eSjoerg assert(!isa<DependentTemplateSpecializationType>(TypePtr));
12306f32e7eSjoerg // In case of template specializations, iterate over the arguments
12406f32e7eSjoerg // and fully qualify them as well.
12506f32e7eSjoerg if (const auto *TST = dyn_cast<const TemplateSpecializationType>(TypePtr)) {
12606f32e7eSjoerg bool MightHaveChanged = false;
12706f32e7eSjoerg SmallVector<TemplateArgument, 4> FQArgs;
12806f32e7eSjoerg for (TemplateSpecializationType::iterator I = TST->begin(), E = TST->end();
12906f32e7eSjoerg I != E; ++I) {
13006f32e7eSjoerg // Cheap to copy and potentially modified by
13106f32e7eSjoerg // getFullyQualifedTemplateArgument.
13206f32e7eSjoerg TemplateArgument Arg(*I);
13306f32e7eSjoerg MightHaveChanged |= getFullyQualifiedTemplateArgument(
13406f32e7eSjoerg Ctx, Arg, WithGlobalNsPrefix);
13506f32e7eSjoerg FQArgs.push_back(Arg);
13606f32e7eSjoerg }
13706f32e7eSjoerg
13806f32e7eSjoerg // If a fully qualified arg is different from the unqualified arg,
13906f32e7eSjoerg // allocate new type in the AST.
14006f32e7eSjoerg if (MightHaveChanged) {
14106f32e7eSjoerg QualType QT = Ctx.getTemplateSpecializationType(
14206f32e7eSjoerg TST->getTemplateName(), FQArgs,
14306f32e7eSjoerg TST->getCanonicalTypeInternal());
14406f32e7eSjoerg // getTemplateSpecializationType returns a fully qualified
14506f32e7eSjoerg // version of the specialization itself, so no need to qualify
14606f32e7eSjoerg // it.
14706f32e7eSjoerg return QT.getTypePtr();
14806f32e7eSjoerg }
14906f32e7eSjoerg } else if (const auto *TSTRecord = dyn_cast<const RecordType>(TypePtr)) {
15006f32e7eSjoerg // We are asked to fully qualify and we have a Record Type,
15106f32e7eSjoerg // which can point to a template instantiation with no sugar in any of
15206f32e7eSjoerg // its template argument, however we still need to fully qualify them.
15306f32e7eSjoerg
15406f32e7eSjoerg if (const auto *TSTDecl =
15506f32e7eSjoerg dyn_cast<ClassTemplateSpecializationDecl>(TSTRecord->getDecl())) {
15606f32e7eSjoerg const TemplateArgumentList &TemplateArgs = TSTDecl->getTemplateArgs();
15706f32e7eSjoerg
15806f32e7eSjoerg bool MightHaveChanged = false;
15906f32e7eSjoerg SmallVector<TemplateArgument, 4> FQArgs;
16006f32e7eSjoerg for (unsigned int I = 0, E = TemplateArgs.size(); I != E; ++I) {
16106f32e7eSjoerg // cheap to copy and potentially modified by
16206f32e7eSjoerg // getFullyQualifedTemplateArgument
16306f32e7eSjoerg TemplateArgument Arg(TemplateArgs[I]);
16406f32e7eSjoerg MightHaveChanged |= getFullyQualifiedTemplateArgument(
16506f32e7eSjoerg Ctx, Arg, WithGlobalNsPrefix);
16606f32e7eSjoerg FQArgs.push_back(Arg);
16706f32e7eSjoerg }
16806f32e7eSjoerg
16906f32e7eSjoerg // If a fully qualified arg is different from the unqualified arg,
17006f32e7eSjoerg // allocate new type in the AST.
17106f32e7eSjoerg if (MightHaveChanged) {
17206f32e7eSjoerg TemplateName TN(TSTDecl->getSpecializedTemplate());
17306f32e7eSjoerg QualType QT = Ctx.getTemplateSpecializationType(
17406f32e7eSjoerg TN, FQArgs,
17506f32e7eSjoerg TSTRecord->getCanonicalTypeInternal());
17606f32e7eSjoerg // getTemplateSpecializationType returns a fully qualified
17706f32e7eSjoerg // version of the specialization itself, so no need to qualify
17806f32e7eSjoerg // it.
17906f32e7eSjoerg return QT.getTypePtr();
18006f32e7eSjoerg }
18106f32e7eSjoerg }
18206f32e7eSjoerg }
18306f32e7eSjoerg return TypePtr;
18406f32e7eSjoerg }
18506f32e7eSjoerg
createOuterNNS(const ASTContext & Ctx,const Decl * D,bool FullyQualify,bool WithGlobalNsPrefix)18606f32e7eSjoerg static NestedNameSpecifier *createOuterNNS(const ASTContext &Ctx, const Decl *D,
18706f32e7eSjoerg bool FullyQualify,
18806f32e7eSjoerg bool WithGlobalNsPrefix) {
18906f32e7eSjoerg const DeclContext *DC = D->getDeclContext();
19006f32e7eSjoerg if (const auto *NS = dyn_cast<NamespaceDecl>(DC)) {
19106f32e7eSjoerg while (NS && NS->isInline()) {
19206f32e7eSjoerg // Ignore inline namespace;
19306f32e7eSjoerg NS = dyn_cast<NamespaceDecl>(NS->getDeclContext());
19406f32e7eSjoerg }
195*13fbcb42Sjoerg if (NS && NS->getDeclName()) {
19606f32e7eSjoerg return createNestedNameSpecifier(Ctx, NS, WithGlobalNsPrefix);
19706f32e7eSjoerg }
19806f32e7eSjoerg return nullptr; // no starting '::', no anonymous
19906f32e7eSjoerg } else if (const auto *TD = dyn_cast<TagDecl>(DC)) {
20006f32e7eSjoerg return createNestedNameSpecifier(Ctx, TD, FullyQualify, WithGlobalNsPrefix);
20106f32e7eSjoerg } else if (const auto *TDD = dyn_cast<TypedefNameDecl>(DC)) {
20206f32e7eSjoerg return createNestedNameSpecifier(
20306f32e7eSjoerg Ctx, TDD, FullyQualify, WithGlobalNsPrefix);
20406f32e7eSjoerg } else if (WithGlobalNsPrefix && DC->isTranslationUnit()) {
20506f32e7eSjoerg return NestedNameSpecifier::GlobalSpecifier(Ctx);
20606f32e7eSjoerg }
20706f32e7eSjoerg return nullptr; // no starting '::' if |WithGlobalNsPrefix| is false
20806f32e7eSjoerg }
20906f32e7eSjoerg
21006f32e7eSjoerg /// Return a fully qualified version of this name specifier.
getFullyQualifiedNestedNameSpecifier(const ASTContext & Ctx,NestedNameSpecifier * Scope,bool WithGlobalNsPrefix)21106f32e7eSjoerg static NestedNameSpecifier *getFullyQualifiedNestedNameSpecifier(
21206f32e7eSjoerg const ASTContext &Ctx, NestedNameSpecifier *Scope,
21306f32e7eSjoerg bool WithGlobalNsPrefix) {
21406f32e7eSjoerg switch (Scope->getKind()) {
21506f32e7eSjoerg case NestedNameSpecifier::Global:
21606f32e7eSjoerg // Already fully qualified
21706f32e7eSjoerg return Scope;
21806f32e7eSjoerg case NestedNameSpecifier::Namespace:
21906f32e7eSjoerg return TypeName::createNestedNameSpecifier(
22006f32e7eSjoerg Ctx, Scope->getAsNamespace(), WithGlobalNsPrefix);
22106f32e7eSjoerg case NestedNameSpecifier::NamespaceAlias:
22206f32e7eSjoerg // Namespace aliases are only valid for the duration of the
22306f32e7eSjoerg // scope where they were introduced, and therefore are often
22406f32e7eSjoerg // invalid at the end of the TU. So use the namespace name more
22506f32e7eSjoerg // likely to be valid at the end of the TU.
22606f32e7eSjoerg return TypeName::createNestedNameSpecifier(
22706f32e7eSjoerg Ctx,
22806f32e7eSjoerg Scope->getAsNamespaceAlias()->getNamespace()->getCanonicalDecl(),
22906f32e7eSjoerg WithGlobalNsPrefix);
23006f32e7eSjoerg case NestedNameSpecifier::Identifier:
23106f32e7eSjoerg // A function or some other construct that makes it un-namable
23206f32e7eSjoerg // at the end of the TU. Skip the current component of the name,
23306f32e7eSjoerg // but use the name of it's prefix.
23406f32e7eSjoerg return getFullyQualifiedNestedNameSpecifier(
23506f32e7eSjoerg Ctx, Scope->getPrefix(), WithGlobalNsPrefix);
23606f32e7eSjoerg case NestedNameSpecifier::Super:
23706f32e7eSjoerg case NestedNameSpecifier::TypeSpec:
23806f32e7eSjoerg case NestedNameSpecifier::TypeSpecWithTemplate: {
23906f32e7eSjoerg const Type *Type = Scope->getAsType();
24006f32e7eSjoerg // Find decl context.
24106f32e7eSjoerg const TagDecl *TD = nullptr;
24206f32e7eSjoerg if (const TagType *TagDeclType = Type->getAs<TagType>()) {
24306f32e7eSjoerg TD = TagDeclType->getDecl();
24406f32e7eSjoerg } else {
24506f32e7eSjoerg TD = Type->getAsCXXRecordDecl();
24606f32e7eSjoerg }
24706f32e7eSjoerg if (TD) {
24806f32e7eSjoerg return TypeName::createNestedNameSpecifier(Ctx, TD,
24906f32e7eSjoerg true /*FullyQualified*/,
25006f32e7eSjoerg WithGlobalNsPrefix);
25106f32e7eSjoerg } else if (const auto *TDD = dyn_cast<TypedefType>(Type)) {
25206f32e7eSjoerg return TypeName::createNestedNameSpecifier(Ctx, TDD->getDecl(),
25306f32e7eSjoerg true /*FullyQualified*/,
25406f32e7eSjoerg WithGlobalNsPrefix);
25506f32e7eSjoerg }
25606f32e7eSjoerg return Scope;
25706f32e7eSjoerg }
25806f32e7eSjoerg }
25906f32e7eSjoerg llvm_unreachable("bad NNS kind");
26006f32e7eSjoerg }
26106f32e7eSjoerg
26206f32e7eSjoerg /// Create a nested name specifier for the declaring context of
26306f32e7eSjoerg /// the type.
createNestedNameSpecifierForScopeOf(const ASTContext & Ctx,const Decl * Decl,bool FullyQualified,bool WithGlobalNsPrefix)26406f32e7eSjoerg static NestedNameSpecifier *createNestedNameSpecifierForScopeOf(
26506f32e7eSjoerg const ASTContext &Ctx, const Decl *Decl,
26606f32e7eSjoerg bool FullyQualified, bool WithGlobalNsPrefix) {
26706f32e7eSjoerg assert(Decl);
26806f32e7eSjoerg
26906f32e7eSjoerg const DeclContext *DC = Decl->getDeclContext()->getRedeclContext();
27006f32e7eSjoerg const auto *Outer = dyn_cast_or_null<NamedDecl>(DC);
27106f32e7eSjoerg const auto *OuterNS = dyn_cast_or_null<NamespaceDecl>(DC);
27206f32e7eSjoerg if (Outer && !(OuterNS && OuterNS->isAnonymousNamespace())) {
27306f32e7eSjoerg if (const auto *CxxDecl = dyn_cast<CXXRecordDecl>(DC)) {
27406f32e7eSjoerg if (ClassTemplateDecl *ClassTempl =
27506f32e7eSjoerg CxxDecl->getDescribedClassTemplate()) {
27606f32e7eSjoerg // We are in the case of a type(def) that was declared in a
27706f32e7eSjoerg // class template but is *not* type dependent. In clang, it
27806f32e7eSjoerg // gets attached to the class template declaration rather than
27906f32e7eSjoerg // any specific class template instantiation. This result in
28006f32e7eSjoerg // 'odd' fully qualified typename:
28106f32e7eSjoerg //
28206f32e7eSjoerg // vector<_Tp,_Alloc>::size_type
28306f32e7eSjoerg //
28406f32e7eSjoerg // Make the situation is 'useable' but looking a bit odd by
28506f32e7eSjoerg // picking a random instance as the declaring context.
28606f32e7eSjoerg if (ClassTempl->spec_begin() != ClassTempl->spec_end()) {
28706f32e7eSjoerg Decl = *(ClassTempl->spec_begin());
28806f32e7eSjoerg Outer = dyn_cast<NamedDecl>(Decl);
28906f32e7eSjoerg OuterNS = dyn_cast<NamespaceDecl>(Decl);
29006f32e7eSjoerg }
29106f32e7eSjoerg }
29206f32e7eSjoerg }
29306f32e7eSjoerg
29406f32e7eSjoerg if (OuterNS) {
29506f32e7eSjoerg return createNestedNameSpecifier(Ctx, OuterNS, WithGlobalNsPrefix);
29606f32e7eSjoerg } else if (const auto *TD = dyn_cast<TagDecl>(Outer)) {
29706f32e7eSjoerg return createNestedNameSpecifier(
29806f32e7eSjoerg Ctx, TD, FullyQualified, WithGlobalNsPrefix);
29906f32e7eSjoerg } else if (dyn_cast<TranslationUnitDecl>(Outer)) {
30006f32e7eSjoerg // Context is the TU. Nothing needs to be done.
30106f32e7eSjoerg return nullptr;
30206f32e7eSjoerg } else {
30306f32e7eSjoerg // Decl's context was neither the TU, a namespace, nor a
30406f32e7eSjoerg // TagDecl, which means it is a type local to a scope, and not
30506f32e7eSjoerg // accessible at the end of the TU.
30606f32e7eSjoerg return nullptr;
30706f32e7eSjoerg }
30806f32e7eSjoerg } else if (WithGlobalNsPrefix && DC->isTranslationUnit()) {
30906f32e7eSjoerg return NestedNameSpecifier::GlobalSpecifier(Ctx);
31006f32e7eSjoerg }
31106f32e7eSjoerg return nullptr;
31206f32e7eSjoerg }
31306f32e7eSjoerg
31406f32e7eSjoerg /// Create a nested name specifier for the declaring context of
31506f32e7eSjoerg /// the type.
createNestedNameSpecifierForScopeOf(const ASTContext & Ctx,const Type * TypePtr,bool FullyQualified,bool WithGlobalNsPrefix)31606f32e7eSjoerg static NestedNameSpecifier *createNestedNameSpecifierForScopeOf(
31706f32e7eSjoerg const ASTContext &Ctx, const Type *TypePtr,
31806f32e7eSjoerg bool FullyQualified, bool WithGlobalNsPrefix) {
31906f32e7eSjoerg if (!TypePtr) return nullptr;
32006f32e7eSjoerg
32106f32e7eSjoerg Decl *Decl = nullptr;
32206f32e7eSjoerg // There are probably other cases ...
32306f32e7eSjoerg if (const auto *TDT = dyn_cast<TypedefType>(TypePtr)) {
32406f32e7eSjoerg Decl = TDT->getDecl();
32506f32e7eSjoerg } else if (const auto *TagDeclType = dyn_cast<TagType>(TypePtr)) {
32606f32e7eSjoerg Decl = TagDeclType->getDecl();
32706f32e7eSjoerg } else if (const auto *TST = dyn_cast<TemplateSpecializationType>(TypePtr)) {
32806f32e7eSjoerg Decl = TST->getTemplateName().getAsTemplateDecl();
32906f32e7eSjoerg } else {
33006f32e7eSjoerg Decl = TypePtr->getAsCXXRecordDecl();
33106f32e7eSjoerg }
33206f32e7eSjoerg
33306f32e7eSjoerg if (!Decl) return nullptr;
33406f32e7eSjoerg
33506f32e7eSjoerg return createNestedNameSpecifierForScopeOf(
33606f32e7eSjoerg Ctx, Decl, FullyQualified, WithGlobalNsPrefix);
33706f32e7eSjoerg }
33806f32e7eSjoerg
createNestedNameSpecifier(const ASTContext & Ctx,const NamespaceDecl * Namespace,bool WithGlobalNsPrefix)33906f32e7eSjoerg NestedNameSpecifier *createNestedNameSpecifier(const ASTContext &Ctx,
34006f32e7eSjoerg const NamespaceDecl *Namespace,
34106f32e7eSjoerg bool WithGlobalNsPrefix) {
34206f32e7eSjoerg while (Namespace && Namespace->isInline()) {
34306f32e7eSjoerg // Ignore inline namespace;
34406f32e7eSjoerg Namespace = dyn_cast<NamespaceDecl>(Namespace->getDeclContext());
34506f32e7eSjoerg }
34606f32e7eSjoerg if (!Namespace) return nullptr;
34706f32e7eSjoerg
34806f32e7eSjoerg bool FullyQualified = true; // doesn't matter, DeclContexts are namespaces
34906f32e7eSjoerg return NestedNameSpecifier::Create(
35006f32e7eSjoerg Ctx,
35106f32e7eSjoerg createOuterNNS(Ctx, Namespace, FullyQualified, WithGlobalNsPrefix),
35206f32e7eSjoerg Namespace);
35306f32e7eSjoerg }
35406f32e7eSjoerg
createNestedNameSpecifier(const ASTContext & Ctx,const TypeDecl * TD,bool FullyQualify,bool WithGlobalNsPrefix)35506f32e7eSjoerg NestedNameSpecifier *createNestedNameSpecifier(const ASTContext &Ctx,
35606f32e7eSjoerg const TypeDecl *TD,
35706f32e7eSjoerg bool FullyQualify,
35806f32e7eSjoerg bool WithGlobalNsPrefix) {
35906f32e7eSjoerg return NestedNameSpecifier::Create(
36006f32e7eSjoerg Ctx,
36106f32e7eSjoerg createOuterNNS(Ctx, TD, FullyQualify, WithGlobalNsPrefix),
36206f32e7eSjoerg false /*No TemplateKeyword*/,
36306f32e7eSjoerg TD->getTypeForDecl());
36406f32e7eSjoerg }
36506f32e7eSjoerg
36606f32e7eSjoerg /// Return the fully qualified type, including fully-qualified
36706f32e7eSjoerg /// versions of any template parameters.
getFullyQualifiedType(QualType QT,const ASTContext & Ctx,bool WithGlobalNsPrefix)36806f32e7eSjoerg QualType getFullyQualifiedType(QualType QT, const ASTContext &Ctx,
36906f32e7eSjoerg bool WithGlobalNsPrefix) {
37006f32e7eSjoerg // In case of myType* we need to strip the pointer first, fully
37106f32e7eSjoerg // qualify and attach the pointer once again.
37206f32e7eSjoerg if (isa<PointerType>(QT.getTypePtr())) {
37306f32e7eSjoerg // Get the qualifiers.
37406f32e7eSjoerg Qualifiers Quals = QT.getQualifiers();
37506f32e7eSjoerg QT = getFullyQualifiedType(QT->getPointeeType(), Ctx, WithGlobalNsPrefix);
37606f32e7eSjoerg QT = Ctx.getPointerType(QT);
37706f32e7eSjoerg // Add back the qualifiers.
37806f32e7eSjoerg QT = Ctx.getQualifiedType(QT, Quals);
37906f32e7eSjoerg return QT;
38006f32e7eSjoerg }
38106f32e7eSjoerg
38206f32e7eSjoerg if (auto *MPT = dyn_cast<MemberPointerType>(QT.getTypePtr())) {
38306f32e7eSjoerg // Get the qualifiers.
38406f32e7eSjoerg Qualifiers Quals = QT.getQualifiers();
38506f32e7eSjoerg // Fully qualify the pointee and class types.
38606f32e7eSjoerg QT = getFullyQualifiedType(QT->getPointeeType(), Ctx, WithGlobalNsPrefix);
38706f32e7eSjoerg QualType Class = getFullyQualifiedType(QualType(MPT->getClass(), 0), Ctx,
38806f32e7eSjoerg WithGlobalNsPrefix);
38906f32e7eSjoerg QT = Ctx.getMemberPointerType(QT, Class.getTypePtr());
39006f32e7eSjoerg // Add back the qualifiers.
39106f32e7eSjoerg QT = Ctx.getQualifiedType(QT, Quals);
39206f32e7eSjoerg return QT;
39306f32e7eSjoerg }
39406f32e7eSjoerg
39506f32e7eSjoerg // In case of myType& we need to strip the reference first, fully
39606f32e7eSjoerg // qualify and attach the reference once again.
39706f32e7eSjoerg if (isa<ReferenceType>(QT.getTypePtr())) {
39806f32e7eSjoerg // Get the qualifiers.
39906f32e7eSjoerg bool IsLValueRefTy = isa<LValueReferenceType>(QT.getTypePtr());
40006f32e7eSjoerg Qualifiers Quals = QT.getQualifiers();
40106f32e7eSjoerg QT = getFullyQualifiedType(QT->getPointeeType(), Ctx, WithGlobalNsPrefix);
40206f32e7eSjoerg // Add the r- or l-value reference type back to the fully
40306f32e7eSjoerg // qualified one.
40406f32e7eSjoerg if (IsLValueRefTy)
40506f32e7eSjoerg QT = Ctx.getLValueReferenceType(QT);
40606f32e7eSjoerg else
40706f32e7eSjoerg QT = Ctx.getRValueReferenceType(QT);
40806f32e7eSjoerg // Add back the qualifiers.
40906f32e7eSjoerg QT = Ctx.getQualifiedType(QT, Quals);
41006f32e7eSjoerg return QT;
41106f32e7eSjoerg }
41206f32e7eSjoerg
41306f32e7eSjoerg // Remove the part of the type related to the type being a template
41406f32e7eSjoerg // parameter (we won't report it as part of the 'type name' and it
41506f32e7eSjoerg // is actually make the code below to be more complex (to handle
41606f32e7eSjoerg // those)
41706f32e7eSjoerg while (isa<SubstTemplateTypeParmType>(QT.getTypePtr())) {
41806f32e7eSjoerg // Get the qualifiers.
41906f32e7eSjoerg Qualifiers Quals = QT.getQualifiers();
42006f32e7eSjoerg
42106f32e7eSjoerg QT = cast<SubstTemplateTypeParmType>(QT.getTypePtr())->desugar();
42206f32e7eSjoerg
42306f32e7eSjoerg // Add back the qualifiers.
42406f32e7eSjoerg QT = Ctx.getQualifiedType(QT, Quals);
42506f32e7eSjoerg }
42606f32e7eSjoerg
42706f32e7eSjoerg NestedNameSpecifier *Prefix = nullptr;
42806f32e7eSjoerg // Local qualifiers are attached to the QualType outside of the
42906f32e7eSjoerg // elaborated type. Retrieve them before descending into the
43006f32e7eSjoerg // elaborated type.
43106f32e7eSjoerg Qualifiers PrefixQualifiers = QT.getLocalQualifiers();
43206f32e7eSjoerg QT = QualType(QT.getTypePtr(), 0);
43306f32e7eSjoerg ElaboratedTypeKeyword Keyword = ETK_None;
43406f32e7eSjoerg if (const auto *ETypeInput = dyn_cast<ElaboratedType>(QT.getTypePtr())) {
43506f32e7eSjoerg QT = ETypeInput->getNamedType();
43606f32e7eSjoerg assert(!QT.hasLocalQualifiers());
43706f32e7eSjoerg Keyword = ETypeInput->getKeyword();
43806f32e7eSjoerg }
43906f32e7eSjoerg // Create a nested name specifier if needed.
44006f32e7eSjoerg Prefix = createNestedNameSpecifierForScopeOf(Ctx, QT.getTypePtr(),
44106f32e7eSjoerg true /*FullyQualified*/,
44206f32e7eSjoerg WithGlobalNsPrefix);
44306f32e7eSjoerg
44406f32e7eSjoerg // In case of template specializations iterate over the arguments and
44506f32e7eSjoerg // fully qualify them as well.
44606f32e7eSjoerg if (isa<const TemplateSpecializationType>(QT.getTypePtr()) ||
44706f32e7eSjoerg isa<const RecordType>(QT.getTypePtr())) {
44806f32e7eSjoerg // We are asked to fully qualify and we have a Record Type (which
44906f32e7eSjoerg // may point to a template specialization) or Template
45006f32e7eSjoerg // Specialization Type. We need to fully qualify their arguments.
45106f32e7eSjoerg
45206f32e7eSjoerg const Type *TypePtr = getFullyQualifiedTemplateType(
45306f32e7eSjoerg Ctx, QT.getTypePtr(), WithGlobalNsPrefix);
45406f32e7eSjoerg QT = QualType(TypePtr, 0);
45506f32e7eSjoerg }
45606f32e7eSjoerg if (Prefix || Keyword != ETK_None) {
45706f32e7eSjoerg QT = Ctx.getElaboratedType(Keyword, Prefix, QT);
45806f32e7eSjoerg }
45906f32e7eSjoerg QT = Ctx.getQualifiedType(QT, PrefixQualifiers);
46006f32e7eSjoerg return QT;
46106f32e7eSjoerg }
46206f32e7eSjoerg
getFullyQualifiedName(QualType QT,const ASTContext & Ctx,const PrintingPolicy & Policy,bool WithGlobalNsPrefix)46306f32e7eSjoerg std::string getFullyQualifiedName(QualType QT,
46406f32e7eSjoerg const ASTContext &Ctx,
46506f32e7eSjoerg const PrintingPolicy &Policy,
46606f32e7eSjoerg bool WithGlobalNsPrefix) {
46706f32e7eSjoerg QualType FQQT = getFullyQualifiedType(QT, Ctx, WithGlobalNsPrefix);
46806f32e7eSjoerg return FQQT.getAsString(Policy);
46906f32e7eSjoerg }
47006f32e7eSjoerg
47106f32e7eSjoerg } // end namespace TypeName
47206f32e7eSjoerg } // end namespace clang
473