// RUN: cat %s | %cling | FileCheck %s // The test verifies the expected behavior in cling::utils::Transform class, // which is supposed to provide different transformation of AST nodes and types. #include "cling/Interpreter/Interpreter.h" #include "cling/Interpreter/LookupHelper.h" #include "cling/Utils/AST.h" #include "clang/AST/Type.h" #include "clang/AST/ASTContext.h" #include "llvm/ADT/SmallSet.h" #include "clang/Sema/Sema.h" .rawInput 1 #include #include typedef double Double32_t; typedef int Int_t; typedef long Long_t; typedef Int_t* IntPtr_t; typedef Int_t& IntRef_t; template class A {}; template class B {}; template class C {}; typedef C >, Double32_t > CTD; typedef C >, Double32_t > CTDConst; template , typename alloc = std::allocator > > class cmap { key fKey; const value fValue; alloc fAlloc; }; // : public std::map { template class mypair { public: key fKey; value fValue; }; #include namespace Details { class Impl {}; } // To insure instantiation. // typedef std::pair > details_pairs; 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; const int typeN =1; typedef ArrayType FArray; typedef int IntNS_t; } // Anonymous namespace namespace { class InsideAnonymous { }; } using namespace std; class Embedded_objects { public: enum Eenum { kEnumConst=16 }; 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; const Eenum m_enum; typedef vector vecint2; vecint2::iterator m_iter2; }; namespace NS1 { namespace NS2 { namespace NS3 { class Point {}; class Inner3 { public: Point p1; NS3::Point p2; ::NS1::NS2::NS3::Point p3; }; } } } .rawInput 0 const cling::LookupHelper& lookup = gCling->getLookupHelper(); const clang::ASTContext& Ctx = gCling->getSema().getASTContext(); cling::utils::Transform::Config transConfig; transConfig.m_toSkip.insert(lookup.findType("Double32_t").getTypePtr()); using namespace std; transConfig.m_toSkip.insert(lookup.findType("string").getTypePtr()); transConfig.m_toSkip.insert(lookup.findType("std::string").getTypePtr()); const clang::Type* t = 0; const clang::TypedefType *td = 0; clang::QualType QT; using namespace cling::utils; // Test the behavior on a simple class lookup.findScope("Details::Impl", &t); QT = clang::QualType(t, 0); //QT.getAsString().c_str() Transform::GetPartiallyDesugaredType(Ctx, QT, transConfig).getAsString().c_str() // CHECK: (const char *) "Details::Impl" // Test the behavior for a class inside an anonymous namespace lookup.findScope("InsideAnonymous", &t); QT = clang::QualType(t, 0); //QT.getAsString().c_str()c Transform::GetPartiallyDesugaredType(Ctx, QT, transConfig).getAsString().c_str() // CHECK: (const char *) "class ::InsideAnonymous" // The above result is not quite want we want, so the client must using // the following: // The scope suppression is required for getting rid of the anonymous part of the name of a class defined in an anonymous namespace. // This gives us more control vs not using the clang::ElaboratedType and relying on the Policy.SuppressUnwrittenScope which would // strip both the anonymous and the inline namespace names (and we probably do not want the later to be suppressed). clang::PrintingPolicy Policy(Ctx.getPrintingPolicy()); Policy.SuppressTagKeyword = true; // Never get the class or struct keyword Policy.SuppressScope = true; // Force the scope to be coming from a clang::ElaboratedType. std::string name; Transform::GetPartiallyDesugaredType(Ctx, QT, transConfig).getAsStringInternal(name,Policy); name.c_str() // CHECK: (const char *) "InsideAnonymous" // Test desugaring pointers types: QT = lookup.findType("Int_t*"); Transform::GetPartiallyDesugaredType(Ctx, QT, transConfig).getAsString().c_str() // CHECK:(const char *) "int *" QT = lookup.findType("const IntPtr_t*"); Transform::GetPartiallyDesugaredType(Ctx, QT, transConfig).getAsString().c_str() // CHECK:(const char *) "int *const *" // Test desugaring reference (both r- or l- value) types: QT = lookup.findType("const IntPtr_t&"); Transform::GetPartiallyDesugaredType(Ctx, QT, transConfig).getAsString().c_str() // CHECK:(const char *) "int *const &" //TODO: QT = lookup.findType("IntPtr_t[32]"); // To do: findType does not return the const below: // Test desugaring reference (both r- or l- value) types: //QT = lookup.findType("const IntRef_t"); //Transform::GetPartiallyDesugaredType(Ctx, QT, transConfig).getAsString().c_str() // should print:(const char *) "int &const" // Test desugaring reference (both r- or l- value) types: QT = lookup.findType("IntRef_t"); Transform::GetPartiallyDesugaredType(Ctx, QT, transConfig).getAsString().c_str() // CHECK:(const char *) "int &" //Desugar template parameters: lookup.findScope("A >", &t); QT = clang::QualType(t, 0); Transform::GetPartiallyDesugaredType(Ctx, QT, transConfig).getAsString().c_str() // CHECK:(const char *) "A >" lookup.findScope("A >", &t); QT = clang::QualType(t, 0); Transform::GetPartiallyDesugaredType(Ctx, QT, transConfig).getAsString().c_str() // CHECK:(const char *) "A >" lookup.findScope("CTD", &t); QT = clang::QualType(t, 0); Transform::GetPartiallyDesugaredType(Ctx, QT, transConfig).getAsString().c_str() // CHECK: (const char *) "C >, Double32_t>" lookup.findScope("CTDConst", &t); QT = clang::QualType(t, 0); Transform::GetPartiallyDesugaredType(Ctx, QT, transConfig).getAsString().c_str() // CHECK: (const char *) "C >, Double32_t>" lookup.findScope("std::pair", &t); QT = clang::QualType(t, 0); Transform::GetPartiallyDesugaredType(Ctx, QT, transConfig).getAsString().c_str() // CHECK: (const char *) "std::pair" lookup.findScope("NS::Array >", &t); QT = clang::QualType(t, 0); Transform::GetPartiallyDesugaredType(Ctx, QT, transConfig).getAsString().c_str() // CHECK: (const char *) "NS::Array >" lookup.findScope("NS::Array >", &t); QT = clang::QualType(t, 0); Transform::GetPartiallyDesugaredType(Ctx, QT, transConfig).getAsString().c_str() // CHECK: (const char *) "NS::Array >" lookup.findScope("NS::Container::Content", &t); QT = clang::QualType(t, 0); Transform::GetPartiallyDesugaredType(Ctx, QT, transConfig).getAsString().c_str() // CHECK: (const char *) "NS::Container::Content" QT = lookup.findType("NS::Container::Value_t"); Transform::GetPartiallyDesugaredType(Ctx, QT, transConfig).getAsString().c_str() // CHECK: (const char *) "long" lookup.findScope("NS::Container::Content_t", &t); QT = clang::QualType(t, 0); Transform::GetPartiallyDesugaredType(Ctx, QT, transConfig).getAsString().c_str() // CHECK: (const char *) "NS::Container::Content" lookup.findScope("NS::Container::Impl_t", &t); QT = clang::QualType(t, 0); Transform::GetPartiallyDesugaredType(Ctx, QT, transConfig).getAsString().c_str() // CHECK: (const char *) "Details::Impl" lookup.findScope("NS::Container::Content", &t); QT = clang::QualType(t, 0); Transform::GetPartiallyDesugaredType(Ctx, QT, transConfig).getAsString().c_str() // CHECK: (const char *) "NS::Container::Content" QT = lookup.findType("NS::Container::Value_t"); Transform::GetPartiallyDesugaredType(Ctx, QT, transConfig).getAsString().c_str() // CHECK: (const char *) "double" // Really we would want it to say Double32_t but oh well. lookup.findScope("NS::Container::Content_t", &t); QT = clang::QualType(t, 0); Transform::GetPartiallyDesugaredType(Ctx, QT, transConfig).getAsString().c_str() // CHECK: (const char *) "NS::Container::Content" lookup.findScope("NS::Container::Impl_t", &t); QT = clang::QualType(t, 0); Transform::GetPartiallyDesugaredType(Ctx, QT, transConfig).getAsString().c_str() // CHECK: (const char *) "Details::Impl" lookup.findScope("NS::TDataPointF", &t); QT = clang::QualType(t, 0); Transform::GetPartiallyDesugaredType(Ctx, QT, transConfig).getAsString().c_str() // CHECK: (const char *) "NS::TDataPoint" lookup.findScope("NS::TDataPointD32", &t); QT = clang::QualType(t, 0); Transform::GetPartiallyDesugaredType(Ctx, QT, transConfig).getAsString().c_str() // CHECK: (const char *) "NS::TDataPoint" lookup.findScope("NS::ArrayType", &t); QT = clang::QualType(t, 0); Transform::GetPartiallyDesugaredType(Ctx, QT, transConfig).getAsString().c_str() // CHECK: (const char *) "NS::ArrayType" lookup.findScope("NS::FArray", &t); QT = clang::QualType(t, 0); Transform::GetPartiallyDesugaredType(Ctx, QT, transConfig).getAsString().c_str() // CHECK: (const char *) "NS::ArrayType" QT = lookup.findType("const NS::IntNS_t"); Transform::GetPartiallyDesugaredType(Ctx, QT, transConfig).getAsString().c_str() // CHECK: (const char *) "const int" lookup.findScope("vector::value_type", &t); QT = clang::QualType(t, 0); Transform::GetPartiallyDesugaredType(Ctx, QT, transConfig).getAsString().c_str() // CHECK: (const char *) "Details::Impl" lookup.findScope("vector::iterator", &t); QT = clang::QualType(t, 0); Transform::GetPartiallyDesugaredType(Ctx, QT, transConfig).getAsString().c_str() // CHECK: (const char *) "std::vector::iterator" lookup.findScope("vector::const_iterator", &t); QT = clang::QualType(t, 0); td = QT->getAs(); clang::TypedefNameDecl *tdDecl = td->getDecl(); QT = Ctx.getTypedefType(tdDecl); Transform::GetPartiallyDesugaredType(Ctx, QT, transConfig, true).getAsString().c_str() // CHECK: (const char *) "std::vector >::const_iterator" 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(); name.clear(); Transform::GetPartiallyDesugaredType(Ctx,vdType,transConfig).getAsStringInternal(name,Policy); std::cout << name.c_str() << std::endl; } ++iter; } } } // CHECK: Embedded_objects::EmbeddedClasses // CHECK: Embedded_objects::EmbeddedClasses::Embedded1 // CHECK: Embedded_objects::EmbeddedClasses::Embedded2 // CHECK: Embedded_objects::EmbeddedClasses::Embedded3 // CHECK: Embedded_objects::EmbeddedClasses::Embedded4 // CHECK: Embedded_objects::EmbeddedClasses::Embedded5 // CHECK: Embedded_objects::EmbeddedClasses::Embedded6 // CHECK: std::vector::iterator // CHECK: const Embedded_objects::Eenum // CHECK: std::vector::iterator // In the partial desugaring add support for the case where we have a type // that point to an already completely desugared template instantiation in // which case the type is a RecordDecl rather than a TemplateInstantationType decl = lookup.findScope("std::pair >",&t); QT = clang::QualType(t, 0); std::cout << Transform::GetPartiallyDesugaredType(Ctx, QT, transConfig).getAsString().c_str() << std::endl; // CHECK: std::pair > if (const clang::RecordDecl *rdecl = llvm::dyn_cast_or_null(decl)) { clang::RecordDecl::field_iterator field_iter = rdecl->field_begin(); // For some reason we can not call field_end: // cling: root/interpreter/llvm/src/tools/clang/lib/CodeGen/CGCall.cpp:1839: void checkArgMatches(llvm::Value*, unsigned int&, llvm::FunctionType*): Assertion `Elt->getType() == FTy->getParamType(ArgNo)' failed. // so just 'guess' the size int i = 0; while( i < 2 ) { name.clear(); clang::QualType fdType = field_iter->getType(); Transform::GetPartiallyDesugaredType(Ctx,fdType,transConfig).getAsStringInternal(name,Policy); std::cout << name.c_str() << std::endl; ++field_iter; ++i; } } // CHECK: Details::Impl // CHECK: std::vector > decl=lookup.findScope("NS1::NS2::NS3::Inner3",&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(); name.clear(); Transform::GetPartiallyDesugaredType(Ctx,vdType,transConfig).getAsStringInternal(name,Policy); std::cout << name.c_str() << std::endl; } ++iter; } } } // CHECK: NS1::NS2::NS3::Point // CHECK: NS1::NS2::NS3::Point // CHECK: NS1::NS2::NS3::Point decl = lookup.findScope("cmap",&t); QT = clang::QualType(t, 0); std::cout << Transform::GetPartiallyDesugaredType(Ctx, QT, transConfig).getAsString().c_str() << std::endl; if (const clang::RecordDecl *rdecl = llvm::dyn_cast_or_null(decl)) { QT = clang::QualType(rdecl->getTypeForDecl(), 0); std::cout << Transform::GetPartiallyDesugaredType(Ctx, QT, transConfig).getAsString().c_str() << std::endl; clang::RecordDecl::field_iterator field_iter = rdecl->field_begin(); // For some reason we can not call field_end: // cling: root/interpreter/llvm/src/tools/clang/lib/CodeGen/CGCall.cpp:1839: void checkArgMatches(llvm::Value*, unsigned int&, llvm::FunctionType*): Assertion `Elt->getType() == FTy->getParamType(ArgNo)' failed. // so just 'guess' the size int i = 0; while( i < 2 ) { name.clear(); clang::QualType fdType = field_iter->getType(); Transform::GetPartiallyDesugaredType(Ctx,fdType,transConfig).getAsStringInternal(name,Policy); std::cout << name.c_str() << std::endl; ++field_iter; ++i; } } // CHECK: cmap // CHECK: cmap, std::allocator > > // CHECK: volatile int // CHECK: const volatile int