diff --git a/include/clang/Interpreter/CppInterOp.h b/include/clang/Interpreter/CppInterOp.h index eb5eb5564..c301711d2 100644 --- a/include/clang/Interpreter/CppInterOp.h +++ b/include/clang/Interpreter/CppInterOp.h @@ -185,6 +185,9 @@ namespace Cpp { ///\returns the version string information of the library. CPPINTEROP_API std::string GetVersion(); + ///\returns the demangled representation of the given mangled_name + CPPINTEROP_API std::string Demangle(const std::string& mangled_name); + /// Enables or disables the debugging printouts on stderr. /// Debugging output can be enabled also by the environment variable /// CPPINTEROP_EXTRA_INTERPRETER_ARGS. For example, @@ -207,6 +210,10 @@ namespace Cpp { /// Checks if the scope is a class or not. CPPINTEROP_API bool IsClass(TCppScope_t scope); + /// Checks if the klass polymorphic. + /// which means that the class contains or inherits a virtual function + CPPINTEROP_API bool IsClassPolymorphic(TCppScope_t klass); + // See TClingClassInfo::IsLoaded /// Checks if the class definition is present, or not. Performs a /// template instantiation if necessary. diff --git a/lib/Interpreter/CppInterOp.cpp b/lib/Interpreter/CppInterOp.cpp index 56480082e..34908d88a 100644 --- a/lib/Interpreter/CppInterOp.cpp +++ b/lib/Interpreter/CppInterOp.cpp @@ -31,6 +31,7 @@ #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringRef.h" +#include "llvm/Demangle/Demangle.h" #include "llvm/Support/Casting.h" #include "llvm/Support/Debug.h" #include "llvm/Support/raw_os_ostream.h" @@ -155,6 +156,25 @@ namespace Cpp { return fullVersion + "[" + clang::getClangFullVersion() + "])\n"; } + std::string Demangle(const std::string& mangled_name) { +#if CLANG_VERSION_MAJOR > 16 +#ifdef _WIN32 + std::string demangle = microsoftDemangle(mangled_name, nullptr, nullptr); +#else + std::string demangle = itaniumDemangle(mangled_name); +#endif +#else +#ifdef _WIN32 + std::string demangle = microsoftDemangle(mangled_name.c_str(), nullptr, + nullptr, nullptr, nullptr); +#else + std::string demangle = + itaniumDemangle(mangled_name.c_str(), nullptr, nullptr, nullptr); +#endif +#endif + return demangle; + } + void EnableDebugOutput(bool value/* =true*/) { llvm::DebugFlag = value; } @@ -188,6 +208,14 @@ namespace Cpp { return isa(D); } + bool IsClassPolymorphic(TCppScope_t klass) { + Decl* D = static_cast(klass); + if (auto* CXXRD = llvm::dyn_cast(D)) + if (auto* CXXRDD = CXXRD->getDefinition()) + return CXXRDD->isPolymorphic(); + return false; + } + static SourceLocation GetValidSLoc(Sema& semaRef) { auto& SM = semaRef.getSourceManager(); return SM.getLocForStartOfFile(SM.getMainFileID()); diff --git a/unittests/CppInterOp/ScopeReflectionTest.cpp b/unittests/CppInterOp/ScopeReflectionTest.cpp index 88cd133fa..76ebf4d44 100644 --- a/unittests/CppInterOp/ScopeReflectionTest.cpp +++ b/unittests/CppInterOp/ScopeReflectionTest.cpp @@ -8,15 +8,51 @@ #include "clang/Frontend/CompilerInstance.h" #include "clang/Sema/Sema.h" -#include "clang/AST/DeclBase.h" #include "clang/AST/ASTDumper.h" +#include "clang/AST/Decl.h" +#include "clang/AST/DeclBase.h" +#include "clang/AST/GlobalDecl.h" + +#include "llvm/Support/Valgrind.h" #include "gtest/gtest.h" +#include + using namespace TestUtils; using namespace llvm; using namespace clang; +TEST(ScopeReflectionTest, Demangle) { + if (llvm::sys::RunningOnValgrind()) + GTEST_SKIP() << "XFAIL due to Valgrind report"; + + std::string code = R"( + int add(int x, int y) { return x + y; } + int add(double x, double y) { return x + y; } + )"; + + std::vector Decls; + GetAllTopLevelDecls(code, Decls); + EXPECT_EQ(Decls.size(), 2); + + auto Add_int = clang::GlobalDecl(static_cast(Decls[0])); + auto Add_double = clang::GlobalDecl(static_cast(Decls[1])); + + std::string mangled_add_int; + std::string mangled_add_double; + compat::maybeMangleDeclName(Add_int, mangled_add_int); + compat::maybeMangleDeclName(Add_double, mangled_add_double); + + std::string demangled_add_int = Cpp::Demangle(mangled_add_int); + std::string demangled_add_double = Cpp::Demangle(mangled_add_double); + + EXPECT_NE(demangled_add_int.find(Cpp::GetQualifiedCompleteName(Decls[0])), + std::string::npos); + EXPECT_NE(demangled_add_double.find(Cpp::GetQualifiedCompleteName(Decls[1])), + std::string::npos); +} + TEST(ScopeReflectionTest, IsAggregate) { std::vector Decls; std::string code = R"( @@ -59,6 +95,28 @@ TEST(ScopeReflectionTest, IsClass) { EXPECT_FALSE(Cpp::IsClass(Decls[2])); } +TEST(ScopeReflectionTest, IsClassPolymorphic) { + std::vector Decls; + GetAllTopLevelDecls(R"( + namespace N {} + + class C{}; + + class C2 { + public: + virtual ~C2() {} + }; + + int I; + )", + Decls); + + EXPECT_FALSE(Cpp::IsClassPolymorphic(Decls[0])); + EXPECT_FALSE(Cpp::IsClassPolymorphic(Decls[1])); + EXPECT_TRUE(Cpp::IsClassPolymorphic(Decls[2])); + EXPECT_FALSE(Cpp::IsClassPolymorphic(Decls[3])); +} + TEST(ScopeReflectionTest, IsComplete) { std::vector Decls; std::string code = R"(