diff --git a/lib/CppInterOp/CppInterOp.cpp b/lib/CppInterOp/CppInterOp.cpp index 7bd53811e..627417ef3 100644 --- a/lib/CppInterOp/CppInterOp.cpp +++ b/lib/CppInterOp/CppInterOp.cpp @@ -36,6 +36,7 @@ #include "clang/AST/DeclAccessPair.h" #include "clang/AST/DeclBase.h" #include "clang/AST/DeclCXX.h" +#include "clang/AST/DeclTemplate.h" #include "clang/AST/DeclarationName.h" #include "clang/AST/Expr.h" #include "clang/AST/ExprCXX.h" @@ -1616,6 +1617,9 @@ TCppType_t GetFunctionArgType(TCppFunction_t func, TCppIndex_t iarg) { INTEROP_TRACE(func, iarg); auto* D = (clang::Decl*)func; + if (auto* FTD = llvm::dyn_cast_or_null(D)) + D = FTD->getTemplatedDecl(); + if (auto* FD = llvm::dyn_cast_or_null(D)) { if (iarg < FD->getNumParams()) { auto* PVD = FD->getParamDecl(iarg); @@ -1626,6 +1630,12 @@ TCppType_t GetFunctionArgType(TCppFunction_t func, TCppIndex_t iarg) { return INTEROP_RETURN(nullptr); } +bool IsTemplateParmType(TCppType_t typ) { + INTEROP_TRACE(typ); + clang::QualType QT = clang::QualType::getFromOpaquePtr(typ); + return INTEROP_RETURN(QT->isTemplateTypeParmType()); +} + std::string GetFunctionSignature(TCppFunction_t func) { INTEROP_TRACE(func); if (!func) @@ -1873,8 +1883,10 @@ bool CheckMethodAccess(TCppFunction_t method, AccessSpecifier AS) { bool IsMethod(TCppConstFunction_t method) { INTEROP_TRACE(method); - return INTEROP_RETURN( - dyn_cast_or_null(static_cast(method))); + const auto* D = static_cast(method); + if (const auto* FTD = dyn_cast_or_null(D)) + D = FTD->getTemplatedDecl(); + return INTEROP_RETURN(dyn_cast_or_null(D)); } bool IsPublicMethod(TCppFunction_t method) { diff --git a/lib/CppInterOp/CppInterOp.td b/lib/CppInterOp/CppInterOp.td index 5c00d24b5..4dc8d9111 100644 --- a/lib/CppInterOp/CppInterOp.td +++ b/lib/CppInterOp/CppInterOp.td @@ -1375,6 +1375,14 @@ This function parses and instantiates a template function.}]; let Args = [Arg<"const char*", "function_template">]; } +def IsTemplateParmType : CppInterOpAPI { + let Doc = "Checks if the given type is a template parameter type."; + let ReturnType = "bool"; + let Args = [ + Arg<"TCppType_t", "typ"> + ]; +} + def IsFunction : CppInterOpAPI { let Doc = "Checks if the scope is a function."; let ReturnType = "bool"; diff --git a/unittests/CppInterOp/FunctionReflectionTest.cpp b/unittests/CppInterOp/FunctionReflectionTest.cpp index d22813ae0..0ff605047 100644 --- a/unittests/CppInterOp/FunctionReflectionTest.cpp +++ b/unittests/CppInterOp/FunctionReflectionTest.cpp @@ -570,6 +570,8 @@ TYPED_TEST(CPPINTEROP_TEST_MODE, FunctionReflection_GetFunctionArgType) { void f1(int i, double d, long l, char ch) {} void f2(const int i, double d[], long *l, char ch[4]) {} int a; + + template void f3(T t, const T& r, int i) {} )"; GetAllTopLevelDecls(code, Decls); @@ -577,11 +579,47 @@ TYPED_TEST(CPPINTEROP_TEST_MODE, FunctionReflection_GetFunctionArgType) { EXPECT_EQ(Cpp::GetTypeAsString(Cpp::GetFunctionArgType(Decls[0], 1)), "double"); EXPECT_EQ(Cpp::GetTypeAsString(Cpp::GetFunctionArgType(Decls[0], 2)), "long"); EXPECT_EQ(Cpp::GetTypeAsString(Cpp::GetFunctionArgType(Decls[0], 3)), "char"); + EXPECT_EQ(Cpp::GetFunctionArgType(Decls[0], 4), nullptr); + EXPECT_EQ(Cpp::GetTypeAsString(Cpp::GetFunctionArgType(Decls[1], 0)), "const int"); EXPECT_EQ(Cpp::GetTypeAsString(Cpp::GetFunctionArgType(Decls[1], 1)), "double[]"); EXPECT_EQ(Cpp::GetTypeAsString(Cpp::GetFunctionArgType(Decls[1], 2)), "long *"); EXPECT_EQ(Cpp::GetTypeAsString(Cpp::GetFunctionArgType(Decls[1], 3)), "char[4]"); + EXPECT_EQ(Cpp::GetTypeAsString(Cpp::GetFunctionArgType(Decls[2], 0)), "NULL TYPE"); + + EXPECT_TRUE(Cpp::IsTemplatedFunction(Decls[3])); + EXPECT_EQ(Cpp::GetTypeAsString(Cpp::GetFunctionArgType(Decls[3], 0)), "T"); + EXPECT_EQ(Cpp::GetTypeAsString(Cpp::GetFunctionArgType(Decls[3], 1)), + "const T &"); + EXPECT_EQ(Cpp::GetTypeAsString(Cpp::GetFunctionArgType(Decls[3], 2)), "int"); +} + +TYPED_TEST(CPPINTEROP_TEST_MODE, FunctionReflection_IsMethod) { + std::vector Decls, SubDecls; + std::string code = R"( + void f1() {} + + template void f2(T t) {} + + class MyClass { + void m1() {} + + template + void m2(T t) {} + }; + )"; + + GetAllTopLevelDecls(code, Decls); + GetAllSubDecls(Decls[2], SubDecls); + + EXPECT_FALSE(Cpp::IsMethod(Decls[0])); + EXPECT_FALSE(Cpp::IsMethod(Decls[1])); + EXPECT_FALSE(Cpp::IsMethod(SubDecls[0])); + EXPECT_TRUE(Cpp::IsMethod(SubDecls[1])); + EXPECT_TRUE(Cpp::IsTemplatedFunction(SubDecls[2])); + EXPECT_TRUE(Cpp::IsMethod(SubDecls[2])); + EXPECT_FALSE(Cpp::IsMethod(nullptr)); } TYPED_TEST(CPPINTEROP_TEST_MODE, FunctionReflection_FunctionTypes) { diff --git a/unittests/CppInterOp/TypeReflectionTest.cpp b/unittests/CppInterOp/TypeReflectionTest.cpp index 6df0a6c6f..89f43784b 100644 --- a/unittests/CppInterOp/TypeReflectionTest.cpp +++ b/unittests/CppInterOp/TypeReflectionTest.cpp @@ -578,6 +578,20 @@ TYPED_TEST(CPPINTEROP_TEST_MODE, TypeReflection_IsPODType) { EXPECT_FALSE(Cpp::IsPODType(0)); } +TYPED_TEST(CPPINTEROP_TEST_MODE, TypeReflection_IsTemplateParmType) { + std::vector Decls; + + std::string code = R"( + template void f(T t, const T& r, int i) {} + )"; + + GetAllTopLevelDecls(code, Decls); + + EXPECT_TRUE(Cpp::IsTemplateParmType(Cpp::GetFunctionArgType(Decls[0], 0))); + EXPECT_FALSE(Cpp::IsTemplateParmType(Cpp::GetFunctionArgType(Decls[0], 1))); + EXPECT_FALSE(Cpp::IsTemplateParmType(Cpp::GetFunctionArgType(Decls[0], 2))); +} + TYPED_TEST(CPPINTEROP_TEST_MODE, TypeReflection_IsSmartPtrType) { #if CLANG_VERSION_MAJOR == 20 && defined(CPPINTEROP_USE_CLING) && defined(_WIN32) GTEST_SKIP() << "Test fails with Cling on Windows";