In the GetPartiallyDesugaredType, properly handle the case where the input is partially qualified (input: B::C and the ouput needs to be A::B::C ; i.e. properly handle ElaboratedType as input). Also properly strip the typedef from any of the scopes (A::vecint::iterator -> std::vector<int>::iterator). Add the corresponding test

git-svn-id: http://root.cern.ch/svn/root/trunk@47958 27541ba8-7e3a-0410-8455-c3a389f83636
This commit is contained in:
Philippe Canal 2012-12-11 08:26:00 +00:00
parent cbc0713c9e
commit d267a7e10e
2 changed files with 234 additions and 109 deletions

View File

@ -109,6 +109,111 @@ namespace utils {
return IntegerLiteral::Create(C, Addr, C.UnsignedLongTy, SourceLocation());
}
static
NestedNameSpecifier* CreateNestedNameSpecifier(const ASTContext& Ctx,
NamespaceDecl* cl) {
NamespaceDecl* outer
= llvm::dyn_cast_or_null<NamespaceDecl>(cl->getDeclContext());
if (outer && outer->getName().size()) {
NestedNameSpecifier* outerNNS = CreateNestedNameSpecifier(Ctx,outer);
return NestedNameSpecifier::Create(Ctx,outerNNS,
cl);
} else {
return NestedNameSpecifier::Create(Ctx,
0, /* no starting '::'*/
cl);
}
}
static
NestedNameSpecifier* CreateNestedNameSpecifier(const ASTContext& Ctx,
TagDecl *cl) {
NamedDecl* outer = llvm::dyn_cast_or_null<NamedDecl>(cl->getDeclContext());
if (outer && outer->getName().size()) {
NestedNameSpecifier *outerNNS;
if (cl->getDeclContext()->isNamespace()) {
outerNNS = CreateNestedNameSpecifier(Ctx,
llvm::dyn_cast<NamespaceDecl>(outer));
} else {
outerNNS = CreateNestedNameSpecifier(Ctx,
llvm::dyn_cast<TagDecl>(outer));
}
return NestedNameSpecifier::Create(Ctx,outerNNS,
false /* template keyword wanted */,
Ctx.getTypeDeclType(cl).getTypePtr());
} else {
return NestedNameSpecifier::Create(Ctx,
0, /* no starting '::'*/
false /* template keyword wanted */,
Ctx.getTypeDeclType(cl).getTypePtr());
}
}
static
NestedNameSpecifier* GetPartiallyDesugaredNNS(const ASTContext& Ctx,
NestedNameSpecifier* scope,
const llvm::SmallSet<const Type*, 4>& TypesToSkip);
static
NestedNameSpecifier* SelectPrefix(const ASTContext& Ctx,
const ElaboratedType *etype,
NestedNameSpecifier *original_prefix,
const llvm::SmallSet<const Type*,4>& TypesToSkip) {
// We have to also desugar the prefix.
NestedNameSpecifier* prefix = etype->getQualifier();
if (original_prefix) {
// We had a scope prefix as input, let see if it is still
// the same as the scope of the result and if it is, then
// we use it.
const clang::Type *newtype = prefix->getAsType();
if (newtype) {
// Deal with a class
const clang::Type *oldtype = original_prefix->getAsType();
if (oldtype &&
// NOTE: Should we compare the RecordDecl instead?
oldtype->getAsCXXRecordDecl() == newtype->getAsCXXRecordDecl())
{
// This is the same type, use the original prefix as a starting
// point.
prefix = GetPartiallyDesugaredNNS(Ctx,original_prefix,TypesToSkip);
} else {
prefix = GetPartiallyDesugaredNNS(Ctx,prefix,TypesToSkip);
}
} else {
// Deal with namespace. This is mostly about dealing with
// namespace aliases (i.e. keeping the one the user used).
const NamespaceDecl *new_ns = prefix->getAsNamespace();
if (new_ns) {
new_ns = new_ns->getCanonicalDecl();
}
else if (NamespaceAliasDecl *alias = prefix->getAsNamespaceAlias())
{
new_ns = alias->getNamespace()->getCanonicalDecl();
}
if (new_ns) {
const NamespaceDecl *old_ns = original_prefix->getAsNamespace();
if (old_ns) {
old_ns = old_ns->getCanonicalDecl();
}
else if (NamespaceAliasDecl *alias =
original_prefix->getAsNamespaceAlias())
{
old_ns = alias->getNamespace()->getCanonicalDecl();
}
if (old_ns == new_ns) {
// This is the same namespace, use the original prefix
// as a starting point.
prefix = original_prefix;
}
}
}
}
return prefix;
}
static
NestedNameSpecifier* GetPartiallyDesugaredNNS(const ASTContext& Ctx,
NestedNameSpecifier* scope,
@ -121,6 +226,45 @@ namespace utils {
NestedNameSpecifier* outer_scope = scope->getPrefix();
if (outer_scope) {
outer_scope = GetPartiallyDesugaredNNS(Ctx, outer_scope, TypesToSkip);
} else {
// Create one if needed.
Decl *decl = 0;
const TypedefType* typedeftype =
llvm::dyn_cast_or_null<clang::TypedefType>(scope_type);
if (typedeftype) {
decl = typedeftype->getDecl();
} else {
// There are probably other cases ...
const TagType* tagdecltype =
llvm::dyn_cast_or_null<clang::TagType>(scope_type);
if (tagdecltype) {
decl = tagdecltype->getDecl();
} else {
decl = scope_type->getAsCXXRecordDecl();
}
}
if (decl) {
NamedDecl* outer
= llvm::dyn_cast_or_null<NamedDecl>(decl->getDeclContext());
NamespaceDecl* outer_ns
= llvm::dyn_cast_or_null<NamespaceDecl>(decl->getDeclContext());
if (outer
&& !(outer_ns && outer_ns->isAnonymousNamespace())
&& outer->getName().size() ) {
if (decl->getDeclContext()->isNamespace()) {
outer_scope = CreateNestedNameSpecifier(Ctx,
llvm::dyn_cast<NamespaceDecl>(outer));
} else {
// We should only create the nested name specifier
// if the outer scope is really a TagDecl.
// It could also be a CXXMethod for example.
TagDecl *tdecl = llvm::dyn_cast<TagDecl>(outer);
if (tdecl) {
outer_scope = CreateNestedNameSpecifier(Ctx,tdecl);
}
}
}
}
}
QualType desugared =
@ -128,6 +272,16 @@ namespace utils {
QualType(scope_type,0),
TypesToSkip,
/*fullyQualify=*/false);
const ElaboratedType* etype
= llvm::dyn_cast<ElaboratedType>(desugared.getTypePtr());
if (etype) {
// The desugarding returned an elaborated type even-though we
// did not request it (/*fullyQualify=*/false), so we must have been
// looking a typedef pointing at a (or another) scope.
outer_scope = SelectPrefix(Ctx,etype,outer_scope,TypesToSkip);
desugared = etype->getNamedType();
}
// NOTE: Should check whether the type has changed or not.
return NestedNameSpecifier::Create(Ctx,outer_scope,
false /* template keyword wanted */,
@ -136,48 +290,6 @@ namespace utils {
return scope;
}
static
NestedNameSpecifier* CreateNestedNameSpecifier(const ASTContext& Ctx,
NamespaceDecl* cl) {
NamespaceDecl* outer
= llvm::dyn_cast_or_null<NamespaceDecl>(cl->getDeclContext());
if (outer && outer->getName().size()) {
NestedNameSpecifier* outerNNS = CreateNestedNameSpecifier(Ctx,outer);
return NestedNameSpecifier::Create(Ctx,outerNNS,
cl);
} else {
return NestedNameSpecifier::Create(Ctx,
0, /* no starting '::'*/
cl);
}
}
static
NestedNameSpecifier* CreateNestedNameSpecifier(const ASTContext& Ctx,
TagDecl *cl) {
NamedDecl* outer = llvm::dyn_cast_or_null<NamedDecl>(cl->getDeclContext());
if (outer && outer->getName().size()) {
NestedNameSpecifier *outerNNS;
if (cl->getDeclContext()->isNamespace()) {
outerNNS = CreateNestedNameSpecifier(Ctx,
llvm::dyn_cast<NamespaceDecl>(outer));
} else {
outerNNS = CreateNestedNameSpecifier(Ctx,
llvm::dyn_cast<TagDecl>(outer));
}
return NestedNameSpecifier::Create(Ctx,outerNNS,
false /* template keyword wanted */,
Ctx.getTypeDeclType(cl).getTypePtr());
} else {
return NestedNameSpecifier::Create(Ctx,
0, /* no starting '::'*/
false /* template keyword wanted */,
Ctx.getTypeDeclType(cl).getTypePtr());
}
}
static bool ShouldKeepTypedef(QualType QT,
const llvm::SmallSet<const Type*, 4>& TypesToSkip)
{
@ -426,58 +538,12 @@ namespace utils {
const ElaboratedType* etype
= llvm::dyn_cast<ElaboratedType>(QT.getTypePtr());
if (etype) {
// We have to also desugar the prefix.
prefix = etype->getQualifier();
if (original_prefix) {
// We had a scope prefix as input, let see if it is still
// the same as the scope of the result and if it is, then
// we use it.
const clang::Type *newtype = prefix->getAsType();
if (newtype) {
// Deal with a class
const clang::Type *oldtype = original_prefix->getAsType();
if (oldtype &&
// NOTE: Should we compare the RecordDecl instead?
oldtype->getAsCXXRecordDecl() == newtype->getAsCXXRecordDecl())
{
// This is the same type, use the original prefix as a starting
// point.
prefix = GetPartiallyDesugaredNNS(Ctx,original_prefix,TypesToSkip);
} else {
prefix = GetPartiallyDesugaredNNS(Ctx,prefix,TypesToSkip);
}
} else {
// Deal with namespace. This is mostly about dealing with
// namespace aliases (i.e. keeping the one the user used).
const NamespaceDecl *new_ns = prefix->getAsNamespace();
if (new_ns) {
new_ns = new_ns->getCanonicalDecl();
}
else if (NamespaceAliasDecl *alias = prefix->getAsNamespaceAlias())
{
new_ns = alias->getNamespace()->getCanonicalDecl();
}
if (new_ns) {
const NamespaceDecl *old_ns = original_prefix->getAsNamespace();
if (old_ns) {
old_ns = old_ns->getCanonicalDecl();
}
else if (NamespaceAliasDecl *alias =
original_prefix->getAsNamespaceAlias())
{
old_ns = alias->getNamespace()->getCanonicalDecl();
}
if (old_ns == new_ns) {
// This is the same namespace, use the original prefix
// as a starting point.
prefix = original_prefix;
}
}
}
}
prefix = SelectPrefix(Ctx,etype,original_prefix,TypesToSkip);
prefix_qualifiers.addQualifiers(QT.getLocalQualifiers());
QT = QualType(etype->getNamedType().getTypePtr(),0);
} else if (fullyQualify) {
// Let's check whether this type should have been an elaborated type.
// in which case we want to add it ... but we can't really preserve

View File

@ -13,6 +13,9 @@
.rawInput 1
#include <vector>
#include <iostream>
typedef double Double32_t;
typedef int Int_t;
typedef long Long_t;
@ -28,32 +31,59 @@ typedef C<A<B<const Double32_t, const Int_t> >, Double32_t > CTDConst;
#include <string>
namespace Details {
class Impl {};
class Impl {};
}
namespace NS {
template <typename T, int size = 0> class ArrayType {};
template <typename T> class Array {};
template <typename T> class Container {
public:
class Content {};
typedef T Value_t;
typedef Content Content_t;
typedef ::Details::Impl Impl_t;
};
template <typename T> class TDataPoint {};
typedef TDataPoint<float> TDataPointF;
typedef TDataPoint<Double32_t> TDataPointD32;
template <typename T, int size = 0> class ArrayType {};
template <typename T> class Array {};
template <typename T> class Container {
public:
class Content {};
typedef T Value_t;
typedef Content Content_t;
typedef ::Details::Impl Impl_t;
};
template <typename T> class TDataPoint {};
typedef TDataPoint<float> TDataPointF;
typedef TDataPoint<Double32_t> TDataPointD32;
}
// Anonymous namespace
namespace {
class InsideAnonymous {
};
class InsideAnonymous {
};
}
class Embedded_objects {
public:
class EmbeddedClasses;
typedef EmbeddedClasses EmbeddedTypedef;
class EmbeddedClasses {
public:
class Embedded1 {};
class Embedded2 {};
class Embedded3 {};
class Embedded4 {};
class Embedded5 {};
class Embedded6 {};
};
EmbeddedClasses m_embedded;
EmbeddedClasses::Embedded1 m_emb1;
EmbeddedClasses::Embedded2 m_emb2;
EmbeddedClasses::Embedded3 m_emb3;
EmbeddedTypedef::Embedded4 m_emb4;
Embedded_objects::EmbeddedClasses::Embedded5 m_emb5;
Embedded_objects::EmbeddedTypedef::Embedded6 m_emb6;
typedef std::vector<int> vecint;
vecint::iterator m_iter;
};
.rawInput 0
const cling::LookupHelper& lookup = gCling->getLookupHelper();
@ -64,6 +94,7 @@ skip.insert(lookup.findType("Double32_t").getTypePtr());
const clang::Type* t = 0;
clang::QualType QT;
using namespace cling::utils;
using namespace std;
// Test the behavior on a simple class
lookup.findScope("Details::Impl", &t);
@ -202,3 +233,31 @@ lookup.findScope("NS::TDataPointD32", &t);
QT = clang::QualType(t, 0);
Transform::GetPartiallyDesugaredType(Ctx, QT, skip).getAsString().c_str()
// CHECK: (const char *) "NS::TDataPoint<Double32_t>"
const clang::Decl*decl=lookup.findScope("Embedded_objects",&t);
if (decl) {
const clang::CXXRecordDecl *cxxdecl
= llvm::dyn_cast<clang::CXXRecordDecl>(decl);
if (cxxdecl) {
clang::DeclContext::decl_iterator iter = cxxdecl->decls_begin();
while ( *iter ) {
const clang::Decl *mdecl = *iter;
if (const clang::ValueDecl *vd = llvm::dyn_cast<clang::ValueDecl>(mdecl)) {
clang::QualType vdType = vd->getType();
std::cout << cling::utils::Transform::GetPartiallyDesugaredType(Ctx,vdType,skip).
getAsString().c_str() << std::endl;
}
++iter;
}
}
}
// CHECK: class Embedded_objects::EmbeddedClasses
// CHECK: class Embedded_objects::class EmbeddedClasses::Embedded1
// CHECK: class Embedded_objects::class EmbeddedClasses::Embedded2
// CHECK: class Embedded_objects::class EmbeddedClasses::Embedded3
// CHECK: class Embedded_objects::class EmbeddedClasses::Embedded4
// CHECK: class Embedded_objects::class EmbeddedClasses::Embedded5
// CHECK: class Embedded_objects::class EmbeddedClasses::Embedded6
// CHECK: std::vector<int>::iterator