diff --git a/lib/Utils/AST.cpp b/lib/Utils/AST.cpp index 828dd66c..c3f28113 100644 --- a/lib/Utils/AST.cpp +++ b/lib/Utils/AST.cpp @@ -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(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(cl->getDeclContext()); + if (outer && outer->getName().size()) { + NestedNameSpecifier *outerNNS; + if (cl->getDeclContext()->isNamespace()) { + outerNNS = CreateNestedNameSpecifier(Ctx, + llvm::dyn_cast(outer)); + } else { + outerNNS = CreateNestedNameSpecifier(Ctx, + llvm::dyn_cast(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& TypesToSkip); + + static + NestedNameSpecifier* SelectPrefix(const ASTContext& Ctx, + const ElaboratedType *etype, + NestedNameSpecifier *original_prefix, + const llvm::SmallSet& 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(scope_type); + if (typedeftype) { + decl = typedeftype->getDecl(); + } else { + // There are probably other cases ... + const TagType* tagdecltype = + llvm::dyn_cast_or_null(scope_type); + if (tagdecltype) { + decl = tagdecltype->getDecl(); + } else { + decl = scope_type->getAsCXXRecordDecl(); + } + } + if (decl) { + NamedDecl* outer + = llvm::dyn_cast_or_null(decl->getDeclContext()); + NamespaceDecl* outer_ns + = llvm::dyn_cast_or_null(decl->getDeclContext()); + if (outer + && !(outer_ns && outer_ns->isAnonymousNamespace()) + && outer->getName().size() ) { + if (decl->getDeclContext()->isNamespace()) { + outer_scope = CreateNestedNameSpecifier(Ctx, + llvm::dyn_cast(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(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(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(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(cl->getDeclContext()); - if (outer && outer->getName().size()) { - NestedNameSpecifier *outerNNS; - if (cl->getDeclContext()->isNamespace()) { - outerNNS = CreateNestedNameSpecifier(Ctx, - llvm::dyn_cast(outer)); - } else { - outerNNS = CreateNestedNameSpecifier(Ctx, - llvm::dyn_cast(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& TypesToSkip) { @@ -426,58 +538,12 @@ namespace utils { const ElaboratedType* etype = llvm::dyn_cast(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 diff --git a/test/Utils/Transform.C b/test/Utils/Transform.C index ccb8a634..24aad3f4 100644 --- a/test/Utils/Transform.C +++ b/test/Utils/Transform.C @@ -13,6 +13,9 @@ .rawInput 1 +#include +#include + typedef double Double32_t; typedef int Int_t; typedef long Long_t; @@ -28,32 +31,59 @@ typedef C >, Double32_t > CTDConst; #include namespace Details { - class Impl {}; + class Impl {}; } namespace NS { - template class ArrayType {}; - template class Array {}; - - template class Container { - public: - class Content {}; - typedef T Value_t; - typedef Content Content_t; - typedef ::Details::Impl Impl_t; - }; - - template class TDataPoint {}; - typedef TDataPoint TDataPointF; - typedef TDataPoint TDataPointD32; + template class ArrayType {}; + template class Array {}; + + template class Container { + public: + class Content {}; + typedef T Value_t; + typedef Content Content_t; + typedef ::Details::Impl Impl_t; + }; + + template class TDataPoint {}; + typedef TDataPoint TDataPointF; + typedef TDataPoint 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 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" + +const clang::Decl*decl=lookup.findScope("Embedded_objects",&t); +if (decl) { + const clang::CXXRecordDecl *cxxdecl + = llvm::dyn_cast(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(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::iterator + +