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:
parent
cbc0713c9e
commit
d267a7e10e
@ -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
|
||||
|
@ -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
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user