#include "clang/AST/DeclTemplate.h"
#include "clang/AST/DeclarationName.h"
#include "clang/AST/GlobalDecl.h"
#include "clang/AST/Mangle.h"
#include "clang/AST/QualTypeNames.h"
#include <stdio.h>
#include <memory>
namespace clang {
namespace TypeName {
static NestedNameSpecifier *createNestedNameSpecifier(
const ASTContext &Ctx,
const NamespaceDecl *Namesp,
bool WithGlobalNsPrefix);
static NestedNameSpecifier *createNestedNameSpecifier(
const ASTContext &Ctx, const TypeDecl *TD,
bool FullyQualify, bool WithGlobalNsPrefix);
static NestedNameSpecifier *createNestedNameSpecifierForScopeOf(
const ASTContext &Ctx, const Decl *decl,
bool FullyQualified, bool WithGlobalNsPrefix);
static NestedNameSpecifier *getFullyQualifiedNestedNameSpecifier(
const ASTContext &Ctx, NestedNameSpecifier *scope, bool WithGlobalNsPrefix);
static bool getFullyQualifiedTemplateName(const ASTContext &Ctx,
TemplateName &TName,
bool WithGlobalNsPrefix) {
bool Changed = false;
NestedNameSpecifier *NNS = nullptr;
TemplateDecl *ArgTDecl = TName.getAsTemplateDecl();
assert(ArgTDecl != nullptr);
QualifiedTemplateName *QTName = TName.getAsQualifiedTemplateName();
if (QTName && !QTName->hasTemplateKeyword()) {
NNS = QTName->getQualifier();
NestedNameSpecifier *QNNS = getFullyQualifiedNestedNameSpecifier(
Ctx, NNS, WithGlobalNsPrefix);
if (QNNS != NNS) {
Changed = true;
NNS = QNNS;
} else {
NNS = nullptr;
}
} else {
NNS = createNestedNameSpecifierForScopeOf(
Ctx, ArgTDecl, true, WithGlobalNsPrefix);
}
if (NNS) {
TemplateName UnderlyingTN(ArgTDecl);
if (UsingShadowDecl *USD = TName.getAsUsingShadowDecl())
UnderlyingTN = TemplateName(USD);
TName =
Ctx.getQualifiedTemplateName(NNS,
false, UnderlyingTN);
Changed = true;
}
return Changed;
}
static bool getFullyQualifiedTemplateArgument(const ASTContext &Ctx,
TemplateArgument &Arg,
bool WithGlobalNsPrefix) {
bool Changed = false;
if (Arg.getKind() == TemplateArgument::Template) {
TemplateName TName = Arg.getAsTemplate();
Changed = getFullyQualifiedTemplateName(Ctx, TName, WithGlobalNsPrefix);
if (Changed) {
Arg = TemplateArgument(TName);
}
} else if (Arg.getKind() == TemplateArgument::Type) {
QualType SubTy = Arg.getAsType();
QualType QTFQ = getFullyQualifiedType(SubTy, Ctx, WithGlobalNsPrefix);
if (QTFQ != SubTy) {
Arg = TemplateArgument(QTFQ);
Changed = true;
}
}
return Changed;
}
static const Type *getFullyQualifiedTemplateType(const ASTContext &Ctx,
const Type *TypePtr,
bool WithGlobalNsPrefix) {
assert(!isa<DependentTemplateSpecializationType>(TypePtr));
if (const auto *TST = dyn_cast<const TemplateSpecializationType>(TypePtr)) {
bool MightHaveChanged = false;
SmallVector<TemplateArgument, 4> FQArgs;
for (TemplateSpecializationType::iterator I = TST->begin(), E = TST->end();
I != E; ++I) {
TemplateArgument Arg(*I);
MightHaveChanged |= getFullyQualifiedTemplateArgument(
Ctx, Arg, WithGlobalNsPrefix);
FQArgs.push_back(Arg);
}
if (MightHaveChanged) {
QualType QT = Ctx.getTemplateSpecializationType(
TST->getTemplateName(), FQArgs,
TST->getCanonicalTypeInternal());
return QT.getTypePtr();
}
} else if (const auto *TSTRecord = dyn_cast<const RecordType>(TypePtr)) {
if (const auto *TSTDecl =
dyn_cast<ClassTemplateSpecializationDecl>(TSTRecord->getDecl())) {
const TemplateArgumentList &TemplateArgs = TSTDecl->getTemplateArgs();
bool MightHaveChanged = false;
SmallVector<TemplateArgument, 4> FQArgs;
for (unsigned int I = 0, E = TemplateArgs.size(); I != E; ++I) {
TemplateArgument Arg(TemplateArgs[I]);
MightHaveChanged |= getFullyQualifiedTemplateArgument(
Ctx, Arg, WithGlobalNsPrefix);
FQArgs.push_back(Arg);
}
if (MightHaveChanged) {
TemplateName TN(TSTDecl->getSpecializedTemplate());
QualType QT = Ctx.getTemplateSpecializationType(
TN, FQArgs,
TSTRecord->getCanonicalTypeInternal());
return QT.getTypePtr();
}
}
}
return TypePtr;
}
static NestedNameSpecifier *createOuterNNS(const ASTContext &Ctx, const Decl *D,
bool FullyQualify,
bool WithGlobalNsPrefix) {
const DeclContext *DC = D->getDeclContext();
if (const auto *NS = dyn_cast<NamespaceDecl>(DC)) {
while (NS && NS->isInline()) {
NS = dyn_cast<NamespaceDecl>(NS->getDeclContext());
}
if (NS && NS->getDeclName()) {
return createNestedNameSpecifier(Ctx, NS, WithGlobalNsPrefix);
}
return nullptr; } else if (const auto *TD = dyn_cast<TagDecl>(DC)) {
return createNestedNameSpecifier(Ctx, TD, FullyQualify, WithGlobalNsPrefix);
} else if (const auto *TDD = dyn_cast<TypedefNameDecl>(DC)) {
return createNestedNameSpecifier(
Ctx, TDD, FullyQualify, WithGlobalNsPrefix);
} else if (WithGlobalNsPrefix && DC->isTranslationUnit()) {
return NestedNameSpecifier::GlobalSpecifier(Ctx);
}
return nullptr; }
static NestedNameSpecifier *getFullyQualifiedNestedNameSpecifier(
const ASTContext &Ctx, NestedNameSpecifier *Scope,
bool WithGlobalNsPrefix) {
switch (Scope->getKind()) {
case NestedNameSpecifier::Global:
return Scope;
case NestedNameSpecifier::Namespace:
return TypeName::createNestedNameSpecifier(
Ctx, Scope->getAsNamespace(), WithGlobalNsPrefix);
case NestedNameSpecifier::NamespaceAlias:
return TypeName::createNestedNameSpecifier(
Ctx,
Scope->getAsNamespaceAlias()->getNamespace()->getCanonicalDecl(),
WithGlobalNsPrefix);
case NestedNameSpecifier::Identifier:
return getFullyQualifiedNestedNameSpecifier(
Ctx, Scope->getPrefix(), WithGlobalNsPrefix);
case NestedNameSpecifier::Super:
case NestedNameSpecifier::TypeSpec:
case NestedNameSpecifier::TypeSpecWithTemplate: {
const Type *Type = Scope->getAsType();
const TagDecl *TD = nullptr;
if (const TagType *TagDeclType = Type->getAs<TagType>()) {
TD = TagDeclType->getDecl();
} else {
TD = Type->getAsCXXRecordDecl();
}
if (TD) {
return TypeName::createNestedNameSpecifier(Ctx, TD,
true ,
WithGlobalNsPrefix);
} else if (const auto *TDD = dyn_cast<TypedefType>(Type)) {
return TypeName::createNestedNameSpecifier(Ctx, TDD->getDecl(),
true ,
WithGlobalNsPrefix);
}
return Scope;
}
}
llvm_unreachable("bad NNS kind");
}
static NestedNameSpecifier *createNestedNameSpecifierForScopeOf(
const ASTContext &Ctx, const Decl *Decl,
bool FullyQualified, bool WithGlobalNsPrefix) {
assert(Decl);
const DeclContext *DC = Decl->getDeclContext()->getRedeclContext();
const auto *Outer = dyn_cast_or_null<NamedDecl>(DC);
const auto *OuterNS = dyn_cast_or_null<NamespaceDecl>(DC);
if (Outer && !(OuterNS && OuterNS->isAnonymousNamespace())) {
if (const auto *CxxDecl = dyn_cast<CXXRecordDecl>(DC)) {
if (ClassTemplateDecl *ClassTempl =
CxxDecl->getDescribedClassTemplate()) {
if (ClassTempl->spec_begin() != ClassTempl->spec_end()) {
Decl = *(ClassTempl->spec_begin());
Outer = dyn_cast<NamedDecl>(Decl);
OuterNS = dyn_cast<NamespaceDecl>(Decl);
}
}
}
if (OuterNS) {
return createNestedNameSpecifier(Ctx, OuterNS, WithGlobalNsPrefix);
} else if (const auto *TD = dyn_cast<TagDecl>(Outer)) {
return createNestedNameSpecifier(
Ctx, TD, FullyQualified, WithGlobalNsPrefix);
} else if (isa<TranslationUnitDecl>(Outer)) {
return nullptr;
} else {
return nullptr;
}
} else if (WithGlobalNsPrefix && DC->isTranslationUnit()) {
return NestedNameSpecifier::GlobalSpecifier(Ctx);
}
return nullptr;
}
static NestedNameSpecifier *createNestedNameSpecifierForScopeOf(
const ASTContext &Ctx, const Type *TypePtr,
bool FullyQualified, bool WithGlobalNsPrefix) {
if (!TypePtr) return nullptr;
Decl *Decl = nullptr;
if (const auto *TDT = dyn_cast<TypedefType>(TypePtr)) {
Decl = TDT->getDecl();
} else if (const auto *TagDeclType = dyn_cast<TagType>(TypePtr)) {
Decl = TagDeclType->getDecl();
} else if (const auto *TST = dyn_cast<TemplateSpecializationType>(TypePtr)) {
Decl = TST->getTemplateName().getAsTemplateDecl();
} else {
Decl = TypePtr->getAsCXXRecordDecl();
}
if (!Decl) return nullptr;
return createNestedNameSpecifierForScopeOf(
Ctx, Decl, FullyQualified, WithGlobalNsPrefix);
}
NestedNameSpecifier *createNestedNameSpecifier(const ASTContext &Ctx,
const NamespaceDecl *Namespace,
bool WithGlobalNsPrefix) {
while (Namespace && Namespace->isInline()) {
Namespace = dyn_cast<NamespaceDecl>(Namespace->getDeclContext());
}
if (!Namespace) return nullptr;
bool FullyQualified = true; return NestedNameSpecifier::Create(
Ctx,
createOuterNNS(Ctx, Namespace, FullyQualified, WithGlobalNsPrefix),
Namespace);
}
NestedNameSpecifier *createNestedNameSpecifier(const ASTContext &Ctx,
const TypeDecl *TD,
bool FullyQualify,
bool WithGlobalNsPrefix) {
const Type *TypePtr = TD->getTypeForDecl();
if (isa<const TemplateSpecializationType>(TypePtr) ||
isa<const RecordType>(TypePtr)) {
TypePtr = getFullyQualifiedTemplateType(Ctx, TypePtr, WithGlobalNsPrefix);
}
return NestedNameSpecifier::Create(
Ctx, createOuterNNS(Ctx, TD, FullyQualify, WithGlobalNsPrefix),
false , TypePtr);
}
QualType getFullyQualifiedType(QualType QT, const ASTContext &Ctx,
bool WithGlobalNsPrefix) {
if (isa<PointerType>(QT.getTypePtr())) {
Qualifiers Quals = QT.getQualifiers();
QT = getFullyQualifiedType(QT->getPointeeType(), Ctx, WithGlobalNsPrefix);
QT = Ctx.getPointerType(QT);
QT = Ctx.getQualifiedType(QT, Quals);
return QT;
}
if (auto *MPT = dyn_cast<MemberPointerType>(QT.getTypePtr())) {
Qualifiers Quals = QT.getQualifiers();
QT = getFullyQualifiedType(QT->getPointeeType(), Ctx, WithGlobalNsPrefix);
QualType Class = getFullyQualifiedType(QualType(MPT->getClass(), 0), Ctx,
WithGlobalNsPrefix);
QT = Ctx.getMemberPointerType(QT, Class.getTypePtr());
QT = Ctx.getQualifiedType(QT, Quals);
return QT;
}
if (isa<ReferenceType>(QT.getTypePtr())) {
bool IsLValueRefTy = isa<LValueReferenceType>(QT.getTypePtr());
Qualifiers Quals = QT.getQualifiers();
QT = getFullyQualifiedType(QT->getPointeeType(), Ctx, WithGlobalNsPrefix);
if (IsLValueRefTy)
QT = Ctx.getLValueReferenceType(QT);
else
QT = Ctx.getRValueReferenceType(QT);
QT = Ctx.getQualifiedType(QT, Quals);
return QT;
}
if (isa<UsingType>(QT.getTypePtr())) {
return getFullyQualifiedType(QT.getSingleStepDesugaredType(Ctx), Ctx,
WithGlobalNsPrefix);
}
while (isa<SubstTemplateTypeParmType>(QT.getTypePtr())) {
Qualifiers Quals = QT.getQualifiers();
QT = cast<SubstTemplateTypeParmType>(QT.getTypePtr())->desugar();
QT = Ctx.getQualifiedType(QT, Quals);
}
NestedNameSpecifier *Prefix = nullptr;
Qualifiers PrefixQualifiers = QT.getLocalQualifiers();
QT = QualType(QT.getTypePtr(), 0);
ElaboratedTypeKeyword Keyword = ETK_None;
if (const auto *ETypeInput = dyn_cast<ElaboratedType>(QT.getTypePtr())) {
QT = ETypeInput->getNamedType();
assert(!QT.hasLocalQualifiers());
Keyword = ETypeInput->getKeyword();
}
Prefix = createNestedNameSpecifierForScopeOf(Ctx, QT.getTypePtr(),
true ,
WithGlobalNsPrefix);
if (isa<const TemplateSpecializationType>(QT.getTypePtr()) ||
isa<const RecordType>(QT.getTypePtr())) {
const Type *TypePtr = getFullyQualifiedTemplateType(
Ctx, QT.getTypePtr(), WithGlobalNsPrefix);
QT = QualType(TypePtr, 0);
}
if (Prefix || Keyword != ETK_None) {
QT = Ctx.getElaboratedType(Keyword, Prefix, QT);
}
QT = Ctx.getQualifiedType(QT, PrefixQualifiers);
return QT;
}
std::string getFullyQualifiedName(QualType QT,
const ASTContext &Ctx,
const PrintingPolicy &Policy,
bool WithGlobalNsPrefix) {
QualType FQQT = getFullyQualifiedType(QT, Ctx, WithGlobalNsPrefix);
return FQQT.getAsString(Policy);
}
} }