saugustine updated this revision to Diff 44245. saugustine marked 4 inline comments as done. saugustine added a comment.
- Update docs. Handle keywords and anonymous namespaces. http://reviews.llvm.org/D15861 Files: include/clang/Tooling/Core/QualTypeNames.h lib/Tooling/Core/CMakeLists.txt lib/Tooling/Core/QualTypeNames.cpp unittests/Tooling/CMakeLists.txt unittests/Tooling/QualTypeNamesTest.cpp
Index: unittests/Tooling/QualTypeNamesTest.cpp =================================================================== --- /dev/null +++ unittests/Tooling/QualTypeNamesTest.cpp @@ -0,0 +1,135 @@ +//===- unittest/Tooling/QualTypeNameTest.cpp ------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "clang/Tooling/Core/QualTypeNames.h" +#include "TestVisitor.h" +using namespace clang; + +namespace { +struct TypeNameVisitor : TestVisitor<TypeNameVisitor> { + llvm::StringMap<std::string> ExpectedQualTypeNames; + + // ValueDecls are the least-derived decl with both a qualtype and a + // name. + bool traverseDecl(Decl *D) { + return true; // Always continue + } + + bool VisitValueDecl(const ValueDecl *VD) { + std::string ExpectedName = + ExpectedQualTypeNames.lookup(VD->getNameAsString()); + if (ExpectedName != "") { + std::string ActualName = + TypeName::getFullyQualifiedName(VD->getType(), *Context); + if (ExpectedName != ActualName) { + // A custom message makes it much easier to see what declaration + // failed compared to EXPECT_EQ. + EXPECT_TRUE(false) << "Typename::getFullyQualifiedName failed for " + << VD->getQualifiedNameAsString() << std::endl + << " Actual: " << ActualName << std::endl + << " Exepcted: " << ExpectedName; + } + } + return true; + } +}; + +TEST(QualTypeNameTest, getFullyQualifiedName) { + TypeNameVisitor Visitor; + // Simple case to test the test framework itself. + Visitor.ExpectedQualTypeNames["CheckInt"] = "int"; + + // Keeping the names of the variables whose types we check unique + // within the entire test--regardless of their own scope--makes it + // easier to diagnose test failures. + + // Simple namespace qualifier + Visitor.ExpectedQualTypeNames["CheckA"] = "A::B::Class0"; + // Lookup up the enclosing scopes, then down another one. (These + // appear as elaborated type in the AST. In that case--even if + // policy.SuppressScope = 0--qual_type.getAsString(policy) only + // gives the name as it appears in the source, not the full name. + Visitor.ExpectedQualTypeNames["CheckB"] = "A::B::C::Class1"; + // Template parameter expansion. + Visitor.ExpectedQualTypeNames["CheckC"] = + "A::B::Template0<A::B::C::MyInt, A::B::AnotherClass>"; + // Recursive template parameter expansion. + Visitor.ExpectedQualTypeNames["CheckD"] = + "A::B::Template0<A::B::Template1<A::B::C::MyInt, A::B::AnotherClass>, " + "A::B::Template0<int, long> >"; + // Variadic Template expansion. + Visitor.ExpectedQualTypeNames["CheckE"] = + "A::Variadic<int, A::B::Template0<int, char>, " + "A::B::Template1<int, long>, A::B::C::MyInt>"; + // Using declarations should be fully expanded. + Visitor.ExpectedQualTypeNames["CheckF"] = "A::B::Class0"; + // Elements found within "using namespace foo;" should be fully + // expanded. + Visitor.ExpectedQualTypeNames["CheckG"] = "A::B::C::MyInt"; + // Type inside function + Visitor.ExpectedQualTypeNames["CheckH"] = "struct X"; + // Anonymous Namespaces + Visitor.ExpectedQualTypeNames["CheckI"] = "aClass"; + // Keyword inclusion with namespaces + Visitor.ExpectedQualTypeNames["CheckJ"] = "struct A::aStruct"; + Visitor.runOver( + "int CheckInt;\n" + "namespace A {\n" + " namespace B {\n" + " class Class0 { };\n" + " namespace C {\n" + " typedef int MyInt;" + " }\n" + " template<class X, class Y> class Template0;" + " template<class X, class Y> class Template1;" + " typedef B::Class0 AnotherClass;\n" + " void Function1(Template0<C::MyInt,\n" + " AnotherClass> CheckC);\n" + " void Function2(Template0<Template1<C::MyInt, AnotherClass>,\n" + " Template0<int, long> > CheckD);\n" + " }\n" + "template<typename... Values> class Variadic {};\n" + "Variadic<int, B::Template0<int, char>, " + " B::Template1<int, long>, " + " B::C::MyInt > CheckE;\n" + "}\n" + "using A::B::Class0;\n" + "void Function(Class0 CheckF);\n" + "using namespace A::B::C;\n" + "void Function(MyInt CheckG);\n" + "void f() {\n" + " struct X {} CheckH;\n" + "}\n" + "namespace {\n" + " class aClass {};\n" + " aClass CheckI;\n" + "}\n" + "namespace A {\n" + " struct aStruct {} CheckJ;\n" + "}\n"); + + TypeNameVisitor Complex; + Complex.ExpectedQualTypeNames["CheckTX"] = "B::TX"; + Complex.runOver( + "namespace A {" + " struct X {};" + "}" + "using A::X;" + "namespace fake_std {" + " template<class... Types > class tuple {};" + "}" + "namespace B {" + " using fake_std::tuple;" + " typedef tuple<X> TX;" + " TX CheckTX;" + " struct A { typedef int X; };" + "}"); +} + +} // end anonymous namespace Index: unittests/Tooling/CMakeLists.txt =================================================================== --- unittests/Tooling/CMakeLists.txt +++ unittests/Tooling/CMakeLists.txt @@ -17,6 +17,7 @@ RewriterTest.cpp RefactoringCallbacksTest.cpp ReplacementsYamlTest.cpp + QualTypeNamesTest.cpp ) target_link_libraries(ToolingTests Index: lib/Tooling/Core/QualTypeNames.cpp =================================================================== --- /dev/null +++ lib/Tooling/Core/QualTypeNames.cpp @@ -0,0 +1,407 @@ +//===------- QualTypeNames.cpp - Generate Complete QualType Names ---------===// +// +// The LLVM Compiler Infrastructure +// +//===----------------------------------------------------------------------===// +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "clang/Tooling/Core/QualTypeNames.h" +#include "clang/AST/ASTContext.h" +#include "clang/AST/DeclTemplate.h" +#include "clang/AST/DeclarationName.h" +#include "clang/AST/GlobalDecl.h" +#include "clang/AST/Mangle.h" +#include "clang/Sema/Lookup.h" +#include "clang/Sema/Sema.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/StringRef.h" + +#include <stdio.h> +#include <memory> + +namespace clang { + +static NestedNameSpecifier *createNestedNameSpecifierForScopeOf( + const ASTContext &Ctx, const Decl *decl, bool FullyQualified); + +static NestedNameSpecifier *getFullyQualifiedNameSpecifier( + const ASTContext &Ctx, NestedNameSpecifier *scope); + +static bool getFullyQualifiedTemplateName(const ASTContext &Ctx, + TemplateName &TName) { + bool Changed = false; + NestedNameSpecifier *NNS = nullptr; + + TemplateDecl *ArgTDecl = TName.getAsTemplateDecl(); + QualifiedTemplateName *QTName = TName.getAsQualifiedTemplateName(); + + if (QTName && !QTName->hasTemplateKeyword()) { + NNS = QTName->getQualifier(); + NestedNameSpecifier *QNNS = getFullyQualifiedNameSpecifier(Ctx, NNS); + if (QNNS != NNS) { + Changed = true; + NNS = QNNS; + } else { + NNS = nullptr; + } + } else { + NNS = createNestedNameSpecifierForScopeOf(Ctx, ArgTDecl, true); + } + if (NNS) { + TName = Ctx.getQualifiedTemplateName(NNS, + /*TemplateKeyword=*/false, ArgTDecl); + Changed = true; + } + return Changed; +} + +static bool getFullyQualifiedTemplateArgument(const ASTContext &Ctx, + TemplateArgument &Arg) { + bool Changed = false; + + // Note: we do not handle TemplateArgument::Expression, to replace it + // we need the information for the template instance decl. + + if (Arg.getKind() == TemplateArgument::Template) { + TemplateName TName = Arg.getAsTemplate(); + Changed = getFullyQualifiedTemplateName(Ctx, TName); + if (Changed) { + Arg = TemplateArgument(TName); + } + } else if (Arg.getKind() == TemplateArgument::Type) { + QualType SubTy = Arg.getAsType(); + // Check if the type needs more desugaring and recurse. + QualType QTFQ = TypeName::getFullyQualifiedType(SubTy, Ctx); + if (QTFQ != SubTy) { + Arg = TemplateArgument(QTFQ); + Changed = true; + } + } + return Changed; +} + +static const Type *getFullyQualifiedLocalType(const ASTContext &Ctx, + const Type *TypePtr) { + // We really just want to handle the template parameter if any .... + // In case of template specializations iterate over the arguments and + // fully qualify them as well. + if (const TemplateSpecializationType *TST = + llvm::dyn_cast<const TemplateSpecializationType>(TypePtr)) { + bool MightHaveChanged = false; + llvm::SmallVector<TemplateArgument, 4> DesArgs; + for (TemplateSpecializationType::iterator I = TST->begin(), E = TST->end(); + I != E; ++I) { + // cheap to copy and potentially modified by + // getFullyQualifedTemplateArgument + TemplateArgument Arg(*I); + MightHaveChanged |= getFullyQualifiedTemplateArgument(Ctx, Arg); + DesArgs.push_back(Arg); + } + + // If desugaring happened allocate new type in the AST. + if (MightHaveChanged) { + QualType QT = Ctx.getTemplateSpecializationType( + TST->getTemplateName(), DesArgs.data(), DesArgs.size(), + TST->getCanonicalTypeInternal()); + return QT.getTypePtr(); + } + } else if (const RecordType *TSTRecord = + llvm::dyn_cast<const RecordType>(TypePtr)) { + // We are asked to fully qualify and we have a Record Type, + // which can point to a template instantiation with no sugar in any of + // its template argument, however we still need to fully qualify them. + + if (const ClassTemplateSpecializationDecl *TSTDecl = + llvm::dyn_cast<ClassTemplateSpecializationDecl>( + TSTRecord->getDecl())) { + const TemplateArgumentList &TemplateArgs = TSTDecl->getTemplateArgs(); + + bool MightHaveChanged = false; + llvm::SmallVector<TemplateArgument, 4> DesArgs; + for (unsigned int I = 0, E = TemplateArgs.size(); I != E; ++I) { + // cheap to copy and potentially modified by + // getFullyQualifedTemplateArgument + TemplateArgument Arg(TemplateArgs[I]); + MightHaveChanged |= getFullyQualifiedTemplateArgument(Ctx, Arg); + DesArgs.push_back(Arg); + } + + // If desugaring happened allocate new type in the AST. + if (MightHaveChanged) { + TemplateName TN(TSTDecl->getSpecializedTemplate()); + QualType QT = Ctx.getTemplateSpecializationType( + TN, DesArgs.data(), DesArgs.size(), + TSTRecord->getCanonicalTypeInternal()); + return QT.getTypePtr(); + } + } + } + return TypePtr; +} + +static NestedNameSpecifier *createOuterNNS(const ASTContext &Ctx, const Decl *D, + bool FullyQualify) { + const DeclContext *DC = D->getDeclContext(); + if (const NamespaceDecl *NS = dyn_cast<NamespaceDecl>(DC)) { + while (NS && NS->isInline()) { + // Ignore inline namespace; + NS = dyn_cast_or_null<NamespaceDecl>(NS->getDeclContext()); + } + if (NS->getDeclName()) return TypeName::createNestedNameSpecifier(Ctx, NS); + return nullptr; // no starting '::', no anonymous + } else if (const TagDecl *TD = dyn_cast<TagDecl>(DC)) { + return TypeName::createNestedNameSpecifier(Ctx, TD, FullyQualify); + } else if (const TypedefNameDecl *TDD = dyn_cast<TypedefNameDecl>(DC)) { + return TypeName::createNestedNameSpecifier(Ctx, TDD, FullyQualify); + } + return nullptr; // no starting '::' +} + +static NestedNameSpecifier *getFullyQualifiedNameSpecifier( + const ASTContext &Ctx, NestedNameSpecifier *Scope) { + // Return a fully qualified version of this name specifier + switch (Scope->getKind()) { + case NestedNameSpecifier::Global: + // Already fully qualified + return Scope; + case NestedNameSpecifier::Namespace: + return TypeName::createNestedNameSpecifier(Ctx, Scope->getAsNamespace()); + case NestedNameSpecifier::NamespaceAlias: + return TypeName::createNestedNameSpecifier( + Ctx, Scope->getAsNamespaceAlias()->getNamespace()->getCanonicalDecl()); + case NestedNameSpecifier::Identifier: + // A function or some other construct that makes it un-namable + // at the end of the TU. FIXME: How to report this? + return Scope; + case NestedNameSpecifier::Super: + case NestedNameSpecifier::TypeSpec: + case NestedNameSpecifier::TypeSpecWithTemplate: { + const Type *Type = Scope->getAsType(); + // Find decl context. + const TagDecl *TD = nullptr; + if (const TagType *TagDeclType = dyn_cast<TagType>(Type)) { + TD = TagDeclType->getDecl(); + } else { + TD = Type->getAsCXXRecordDecl(); + } + if (TD) { + return TypeName::createNestedNameSpecifier(Ctx, TD, + true /*FullyQualified*/); + } else if (const TypedefType *TDD = dyn_cast<TypedefType>(Type)) { + return TypeName::createNestedNameSpecifier(Ctx, TDD->getDecl(), + true /*FullyQualified*/); + } + return Scope; + } + } +} + +static NestedNameSpecifier *createNestedNameSpecifierForScopeOf( + const ASTContext &Ctx, const Decl *Decl, bool FullyQualified) { + // Create a nested name specifier for the declaring context of the type. + + assert(Decl); + + const NamedDecl *Outer = + llvm::dyn_cast_or_null<NamedDecl>(Decl->getDeclContext()); + const NamespaceDecl *OuterNS = + llvm::dyn_cast_or_null<NamespaceDecl>(Decl->getDeclContext()); + if (Outer && !(OuterNS && OuterNS->isAnonymousNamespace())) { + if (const CXXRecordDecl *CxxDecl = + llvm::dyn_cast<CXXRecordDecl>(Decl->getDeclContext())) { + if (ClassTemplateDecl *ClassTempl = + CxxDecl->getDescribedClassTemplate()) { + // We are in the case of a type(def) that was declared in a + // class template but is *not* type dependent. In clang, it + // gets attached to the class template declaration rather than + // any specific class template instantiation. This result in + // 'odd' fully qualified typename: + // + // vector<_Tp,_Alloc>::size_type + // + // Make the situation is 'useable' but looking a bit odd by + // picking a random instance as the declaring context. + if (ClassTempl->spec_begin() != ClassTempl->spec_end()) { + Decl = *(ClassTempl->spec_begin()); + Outer = llvm::dyn_cast<NamedDecl>(Decl); + OuterNS = llvm::dyn_cast<NamespaceDecl>(Decl); + } + } + } + + if (OuterNS) { + return TypeName::createNestedNameSpecifier(Ctx, OuterNS); + } else if (const TagDecl *TD = llvm::dyn_cast<TagDecl>(Outer)) { + return TypeName::createNestedNameSpecifier(Ctx, TD, FullyQualified); + } else { + // Decl's context wasn't a namespace or a TagDecl, which means + // it is a type local to a scope, and not accessible at the end + // of the TU. FIXME: How to report this? + return nullptr; + } + } + return nullptr; +} + +static NestedNameSpecifier *createNestedNameSpecifierForScopeOf( + const ASTContext &Ctx, const Type *TypePtr, bool FullyQualified) { + // Create a nested name specifier for the declaring context of the type. + + if (!TypePtr) return nullptr; + + Decl *Decl = nullptr; + if (const TypedefType *TDT = llvm::dyn_cast<TypedefType>(TypePtr)) { + Decl = TDT->getDecl(); + } else { + // There are probably other cases ... + if (const TagType *TagDeclType = llvm::dyn_cast<TagType>(TypePtr)) + Decl = TagDeclType->getDecl(); + else + Decl = TypePtr->getAsCXXRecordDecl(); + } + + if (!Decl) return nullptr; + + return createNestedNameSpecifierForScopeOf(Ctx, Decl, FullyQualified); +} + +NestedNameSpecifier *TypeName::createNestedNameSpecifier( + const ASTContext &Ctx, const NamespaceDecl *Namespace) { + while (Namespace && Namespace->isInline()) { + // Ignore inline namespace; + Namespace = dyn_cast_or_null<NamespaceDecl>(Namespace->getDeclContext()); + } + if (!Namespace) return nullptr; + + bool FullyQualified = true; // doesn't matter, DeclContexts are namespaces + return NestedNameSpecifier::Create( + Ctx, createOuterNNS(Ctx, Namespace, FullyQualified), Namespace); +} + +NestedNameSpecifier *TypeName::createNestedNameSpecifier( + const ASTContext &Ctx, const TypedefNameDecl *TD, bool FullyQualify) { + return NestedNameSpecifier::Create(Ctx, createOuterNNS(Ctx, TD, FullyQualify), + true /*Template*/, TD->getTypeForDecl()); +} + +NestedNameSpecifier *TypeName::createNestedNameSpecifier(const ASTContext &Ctx, + const TagDecl *TD, + bool FullyQualify) { + const Type *Ty = Ctx.getTypeDeclType(TD).getTypePtr(); + if (FullyQualify) Ty = getFullyQualifiedLocalType(Ctx, Ty); + return NestedNameSpecifier::Create(Ctx, createOuterNNS(Ctx, TD, FullyQualify), + false /* template keyword wanted */, Ty); +} + +QualType TypeName::getFullyQualifiedType(QualType QT, const ASTContext &Ctx) { + // Return the fully qualified type, including for any template + // parameters. + + // In case of myType* we need to strip the pointer first, fully + // qualify and attach the pointer once again. + if (llvm::isa<PointerType>(QT.getTypePtr())) { + // Get the qualifiers. + Qualifiers Quals = QT.getQualifiers(); + QT = getFullyQualifiedType(QT->getPointeeType(), Ctx); + QT = Ctx.getPointerType(QT); + // Add back the qualifiers. + QT = Ctx.getQualifiedType(QT, Quals); + return QT; + } + + // In case of myType& we need to strip the reference first, fully + // qualify and attach the reference once again. + if (llvm::isa<ReferenceType>(QT.getTypePtr())) { + // Get the qualifiers. + bool IsLValueRefTy = llvm::isa<LValueReferenceType>(QT.getTypePtr()); + Qualifiers Quals = QT.getQualifiers(); + QT = getFullyQualifiedType(QT->getPointeeType(), Ctx); + // Add the r- or l-value reference type back to the fully + // qualified one. + if (IsLValueRefTy) + QT = Ctx.getLValueReferenceType(QT); + else + QT = Ctx.getRValueReferenceType(QT); + // Add back the qualifiers. + QT = Ctx.getQualifiedType(QT, Quals); + return QT; + } + + // Remove the part of the type related to the type being a template + // parameter (we won't report it as part of the 'type name' and it + // is actually make the code below to be more complex (to handle + // those) + while (isa<SubstTemplateTypeParmType>(QT.getTypePtr())) { + // Get the qualifiers. + Qualifiers Quals = QT.getQualifiers(); + + QT = dyn_cast<SubstTemplateTypeParmType>(QT.getTypePtr())->desugar(); + + // Add back the qualifiers. + QT = Ctx.getQualifiedType(QT, Quals); + } + + NestedNameSpecifier *Prefix = nullptr; + Qualifiers PrefixQualifiers; + ElaboratedTypeKeyword Keyword = ETK_None; + if (const ElaboratedType *ETypeInput = + llvm::dyn_cast<ElaboratedType>(QT.getTypePtr())) { + QT = ETypeInput->getNamedType(); + Keyword = ETypeInput->getKeyword(); + } + // Create a nested name specifier if needed (i.e. if the decl context + // is not the global scope. + Prefix = createNestedNameSpecifierForScopeOf(Ctx, QT.getTypePtr(), + true /*FullyQualified*/); + + // move the qualifiers on the outer type (avoid 'std::const string'!) + if (Prefix) { + PrefixQualifiers = QT.getLocalQualifiers(); + QT = QualType(QT.getTypePtr(), 0); + } + + // In case of template specializations iterate over the arguments and + // fully qualify them as well. + if (llvm::isa<const TemplateSpecializationType>(QT.getTypePtr())) { + Qualifiers Quals = QT.getLocalQualifiers(); + const Type *TypePtr = getFullyQualifiedLocalType(Ctx, QT.getTypePtr()); + QT = Ctx.getQualifiedType(TypePtr, Quals); + + } else if (llvm::isa<const RecordType>(QT.getTypePtr())) { + // We are asked to fully qualify and we have a Record Type, + // which can point to a template instantiation with no sugar in any of + // its template argument, however we still need to fully qualify them. + + Qualifiers Quals = QT.getLocalQualifiers(); + const Type *TypePtr = getFullyQualifiedLocalType(Ctx, QT.getTypePtr()); + QT = Ctx.getQualifiedType(TypePtr, Quals); + } + if (Prefix || Keyword != ETK_None) { + QT = Ctx.getElaboratedType(Keyword, Prefix, QT); + QT = Ctx.getQualifiedType(QT, PrefixQualifiers); + } + return QT; +} + +std::string TypeName::getFullyQualifiedName(QualType QT, + const ASTContext &Ctx) { + PrintingPolicy Policy(Ctx.getPrintingPolicy()); + Policy.SuppressScope = false; + Policy.AnonymousTagLocations = false; + Policy.PolishForDeclaration = true; + Policy.SuppressUnwrittenScope = true; + return getFullyQualifiedName(QT, Ctx, Policy); +} + +std::string TypeName::getFullyQualifiedName(QualType QT, + const ASTContext &Ctx, + const PrintingPolicy& Policy) { + QualType FQQT = getFullyQualifiedType(QT, Ctx); + return FQQT.getAsString(Policy); +} + +} // end namespace clang Index: lib/Tooling/Core/CMakeLists.txt =================================================================== --- lib/Tooling/Core/CMakeLists.txt +++ lib/Tooling/Core/CMakeLists.txt @@ -3,6 +3,7 @@ add_clang_library(clangToolingCore Lookup.cpp Replacement.cpp + QualTypeNames.cpp LINK_LIBS clangAST Index: include/clang/Tooling/Core/QualTypeNames.h =================================================================== --- /dev/null +++ include/clang/Tooling/Core/QualTypeNames.h @@ -0,0 +1,143 @@ +//===--- QualTypeNames.h - Generate Complete QualType Names ----*- C++ -*-===// +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +// ===----------------------------------------------------------------------===// +// +// \file +// Functionality to generate the fully-qualified names of QualTypes, +// including recursively expanding any subtypes and template +// parameters. +// +// More precisely: Generates a name that can be used to name the same +// type if used at the end of the current translation unit--with +// certain limitations. See below. +// +// This code desugars names only very minimally, so in this code: +// +// namespace A { +// struct X {}; +// } +// using A::X; +// namespace B { +// using std::tuple; +// typedef tuple<X> TX; +// TX t; +// } +// +// B::t's type is reported as "B::TX", rather than std::tuple<A::X>. +// +// Also, this code replaces types found via using declarations with +// their more qualified name, so for the code: +// +// using std::tuple; +// tuple<int> TInt; +// +// TInt's type will be named, "std::tuple<int>". +// +// Limitations: +// +// Some types have ambiguous names at the end of a translation unit, +// are not namable at all there, or are special cases in other ways. +// +// 1) Types with only local scope will have their local names: +// +// void foo() { +// struct LocalType {} LocalVar; +// } +// +// LocalVar's type will be named, "struct LocalType", without any +// qualification. +// +// 2) Types that have been shadowed are reported normally, but a +// client using that name at the end of the translation unit will be +// refering to a different type. +// +// ===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_TOOLING_CORE_QUALTYPENAMES_H +#define LLVM_CLANG_TOOLING_CORE_QUALTYPENAMES_H + +#include "clang/AST/PrettyPrinter.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/SmallSet.h" +#include "llvm/ADT/StringRef.h" + +namespace clang { +class ASTContext; +class NamespaceDecl; +class NestedNameSpecifier; +class QualType; +class TagDecl; +class Type; +class TypedefNameDecl; + +namespace TypeName { +/// \brief Generates a QualType that can be used to name the same type +/// if used at the end of the current translation unit. This ignores +/// issues such as type shadowing. + +/// \param[in] QT - the type for which the fully qualified type will be +/// returned. +/// \param[in] Ctx - the ASTContext to be used. +QualType getFullyQualifiedType(QualType QT, const ASTContext &Ctx); + +/// \brief Get the fully qualified name for a type using a policy most +/// useful for referring to a type at the end of a translation +/// unit. This includes full qualification of all template parameters +/// etc. +/// +/// \param[in] QT - the type for which the fully qualified name will be +/// returned. +/// \param[in] Ctx - the ASTContext to be used. +std::string getFullyQualifiedName(QualType QT, + const ASTContext &Ctx); + +/// \brief Get the fully qualified name for a type using the given +/// printing policy. This includes full qualification of all template +/// parameters etc. +/// +/// \param[in] QT - the type for which the fully qualified name will be +/// returned. +/// \param[in] Ctx - the ASTContext to be used. +/// \param[in] Policy - the PrintingPolicy to be used. +std::string getFullyQualifiedName(QualType QT, + const ASTContext &Ctx, + const PrintingPolicy& Policy); + +/// \brief Create a NestedNameSpecifier for Namesp and its enclosing +/// scopes. +/// +/// \param[in] Ctx - the AST Context to be used. +/// \param[in] Namesp - the NamespaceDecl for which a NestedNameSpecifier +/// is requested. +NestedNameSpecifier *createNestedNameSpecifier( + const ASTContext &Ctx, const NamespaceDecl *Namesp); + +/// \brief Create a NestedNameSpecifier for TagDecl and its enclosing +/// scopes. +/// +/// \param[in] Ctx - the AST Context to be used. +/// \param[in] TD - the TagDecl for which a NestedNameSpecifier is +/// requested. +/// \param[in] FullyQualify - Convert all template arguments into fully +/// qualified names. +NestedNameSpecifier *createNestedNameSpecifier( + const ASTContext &Ctx, const TagDecl *TD, bool FullyQualify); + +/// \brief Create a NestedNameSpecifier for TypedefDecl and its enclosing +/// scopes. +/// +/// \param[in] Ctx - the AST Context to be used. +/// \param[in] TD - the TypedefDecl for which a NestedNameSpecifier is +/// requested. +/// \param[in] FullyQualify - Convert all template arguments (of possible +/// parent scopes) into fully qualified names. +NestedNameSpecifier *createNestedNameSpecifier( + const ASTContext &Ctx, const TypedefNameDecl *TD, + bool FullyQualify); + +} // end namespace TypeName +} // end namespace clang +#endif // LLVM_CLANG_TOOLING_CORE_QUALTYPENAMES_H
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits