From 5e5341266851e4f2984c472186b099e7be025988 Mon Sep 17 00:00:00 2001 From: Vipul Cariappa Date: Tue, 2 Sep 2025 15:20:26 +0200 Subject: [PATCH] [WIP] APIs to enable TypeHints in cppyy --- include/CppInterOp/CppInterOp.h | 21 +++- lib/CppInterOp/CppInterOp.cpp | 108 +++++++++++++++++- .../CppInterOp/FunctionReflectionTest.cpp | 4 +- 3 files changed, 125 insertions(+), 8 deletions(-) diff --git a/include/CppInterOp/CppInterOp.h b/include/CppInterOp/CppInterOp.h index 79cffad12..0954127a2 100644 --- a/include/CppInterOp/CppInterOp.h +++ b/include/CppInterOp/CppInterOp.h @@ -301,7 +301,10 @@ CPPINTEROP_API size_t SizeOf(TCppScope_t scope); /// Checks if it is a "built-in" or a "complex" type. CPPINTEROP_API bool IsBuiltin(TCppType_t type); -/// Checks if it is a templated class. +/// Checks if it is a template class. +CPPINTEROP_API bool IsTemplateClass(TCppScope_t handle); + +/// Checks if it is a template. CPPINTEROP_API bool IsTemplate(TCppScope_t handle); /// Checks if it is a class template specialization class. @@ -373,6 +376,8 @@ CPPINTEROP_API bool IsVariable(TCppScope_t scope); /// namespace, variable, or a function). CPPINTEROP_API std::string GetName(TCppScope_t klass); +CPPINTEROP_API std::string GetDocString(TCppScope_t scope); + /// This is similar to GetName() function, but besides /// the name, it also gets the template arguments. CPPINTEROP_API std::string GetCompleteName(TCppScope_t klass); @@ -437,6 +442,12 @@ CPPINTEROP_API bool IsSubclass(TCppScope_t derived, TCppScope_t base); CPPINTEROP_API int64_t GetBaseClassOffset(TCppScope_t derived, TCppScope_t base); +CPPINTEROP_API void GetDatamembersInNamespace(TCppScope_t ns, std::vector& members); +CPPINTEROP_API void GetFunctionsInNamespace(TCppScope_t ns, std::vector& members); +CPPINTEROP_API void GetClassInNamespace(TCppScope_t ns, std::vector& members); +CPPINTEROP_API void GetTemplatedClassInNamespace(TCppScope_t ns, std::vector& members); +CPPINTEROP_API void GetTemplatedFunctionsInNamespace(TCppScope_t ns, std::vector& members); + /// Sets a list of all the Methods that are in the Class that is /// supplied as a parameter. ///\param[in] klass - Pointer to the scope/class under which the methods have @@ -490,6 +501,8 @@ CPPINTEROP_API std::string GetFunctionSignature(TCppFunction_t func); ///\returns if a function was marked as \c =delete. CPPINTEROP_API bool IsFunctionDeleted(TCppConstFunction_t function); +CPPINTEROP_API bool IsTemplateInstantiationOrSpecialization(TCppScope_t scope); + CPPINTEROP_API bool IsTemplatedFunction(TCppFunction_t func); /// This function performs a lookup to check if there is a @@ -670,6 +683,12 @@ CPPINTEROP_API bool IsConstMethod(TCppFunction_t method); CPPINTEROP_API std::string GetFunctionArgDefault(TCppFunction_t func, TCppIndex_t param_index); +///\returns the size of template arguments +CPPINTEROP_API TCppIndex_t GetTemplateNumArgs(TCppScope_t scope); + +///\returns the template argument name of template as string. +CPPINTEROP_API std::string GetTemplateArgName(TCppScope_t scope, TCppIndex_t param_index); + ///\returns the argument name of function as string. CPPINTEROP_API std::string GetFunctionArgName(TCppFunction_t func, TCppIndex_t param_index); diff --git a/lib/CppInterOp/CppInterOp.cpp b/lib/CppInterOp/CppInterOp.cpp index 3a5a345f4..0706ce5ed 100755 --- a/lib/CppInterOp/CppInterOp.cpp +++ b/lib/CppInterOp/CppInterOp.cpp @@ -12,6 +12,7 @@ #include "Compatibility.h" #include "clang/AST/Attrs.inc" +#include "clang/AST/Comment.h" #include "clang/AST/CXXInheritance.h" #include "clang/AST/Decl.h" #include "clang/AST/DeclAccessPair.h" @@ -380,6 +381,11 @@ bool IsBuiltin(TCppType_t type) { return llvm::StringRef(Ty.getAsString()).contains("complex"); } +bool IsTemplateClass(TCppScope_t handle) { + auto* D = (clang::Decl*)handle; + return llvm::isa_and_nonnull(D); +} + bool IsTemplate(TCppScope_t handle) { auto* D = (clang::Decl*)handle; return llvm::isa_and_nonnull(D); @@ -546,6 +552,15 @@ bool IsVariable(TCppScope_t scope) { return llvm::isa_and_nonnull(D); } +std::string GetDocString(TCppScope_t scope) { + auto *D = static_cast(scope); + auto &AST = getASTContext(); + const clang::RawComment *Comment = AST.getRawCommentForAnyRedecl(D); + if (!Comment) + return ""; + return Comment->getFormattedText(AST.getSourceManager(), AST.getDiagnostics()); +} + std::string GetName(TCppType_t klass) { auto* D = (clang::NamedDecl*)klass; @@ -877,6 +892,51 @@ int64_t GetBaseClassOffset(TCppScope_t derived, TCppScope_t base) { return ComputeBaseOffset(getSema().getASTContext(), DCXXRD, Paths.front()); } +template +static void GetNamespaceDecls(TCppScope_t ns, + std::vector& members) { + if (!ns) + return; + + auto* D = (clang::Decl*)ns; + + if (!D || !isa(D)) + return; + + auto* NSD = dyn_cast(D)->getMostRecentDecl(); + while (NSD) { + for (Decl* DI : NSD->decls()) { + if (auto* MD = dyn_cast(DI)) + members.push_back(MD); + else if (auto* USD = dyn_cast(DI)) { + if (auto *MD = dyn_cast(USD->getTargetDecl())) + members.push_back(MD); + } + } + NSD = NSD->getPreviousDecl(); + } +} + +void GetDatamembersInNamespace(TCppScope_t ns, std::vector& members) { + GetNamespaceDecls(ns, members); +} + +void GetFunctionsInNamespace(TCppScope_t ns, std::vector& members) { + GetNamespaceDecls(ns, members); +} + +void GetClassInNamespace(TCppScope_t ns, std::vector& members) { + GetNamespaceDecls(ns, members); +} + +void GetTemplatedClassInNamespace(TCppScope_t ns, std::vector& members) { + GetNamespaceDecls(ns, members); +} + +void GetTemplatedFunctionsInNamespace(TCppScope_t ns, std::vector& members) { + GetNamespaceDecls(ns, members); +} + template static void GetClassDecls(TCppScope_t klass, std::vector& methods) { @@ -888,6 +948,10 @@ static void GetClassDecls(TCppScope_t klass, if (auto* TD = dyn_cast(D)) D = GetScopeFromType(TD->getUnderlyingType()); + if (auto *CTD = llvm::dyn_cast_or_null(D)) { + D = CTD->getTemplatedDecl(); + } + if (!D || !isa(D)) return; @@ -1011,7 +1075,7 @@ TCppType_t GetFunctionReturnType(TCppFunction_t func) { QualType Type = FD->getReturnType(); if (Type->isUndeducedAutoType()) { bool needInstantiation = false; - if (IsTemplatedFunction(FD) && !FD->isDefined()) + if (IsTemplateInstantiationOrSpecialization(FD) && !FD->isDefined()) needInstantiation = true; if (auto* MD = llvm::dyn_cast(FD)) { if (IsTemplateSpecialization(MD->getParent())) @@ -1055,8 +1119,10 @@ TCppIndex_t GetFunctionRequiredArgs(TCppConstFunction_t func) { } TCppType_t GetFunctionArgType(TCppFunction_t func, TCppIndex_t iarg) { - auto* D = (clang::Decl*)func; - + auto* D = static_cast(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); @@ -1122,7 +1188,12 @@ bool IsFunctionDeleted(TCppConstFunction_t function) { bool IsTemplatedFunction(TCppFunction_t func) { auto* D = (Decl*)func; - return IsTemplatedFunction(D) || IsTemplateInstantiationOrSpecialization(D); + return IsTemplatedFunction(D) /*|| IsTemplateInstantiationOrSpecialization(D)*/; +} + +bool IsTemplateInstantiationOrSpecialization(TCppScope_t scope) { + auto *D = static_cast(scope); + return IsTemplateInstantiationOrSpecialization(D); } // FIXME: This lookup is broken, and should no longer be used in favour of @@ -1334,6 +1405,9 @@ bool IsDestructor(TCppConstFunction_t method) { bool IsStaticMethod(TCppConstFunction_t method) { const auto* D = static_cast(method); + if (auto *FTD = llvm::dyn_cast_or_null(D)) { + D = FTD->getTemplatedDecl(); + } if (auto* CXXMD = llvm::dyn_cast_or_null(D)) { return CXXMD->isStatic(); } @@ -1404,6 +1478,9 @@ bool IsVirtualMethod(TCppFunction_t method) { void GetDatamembers(TCppScope_t scope, std::vector& datamembers) { auto* D = (Decl*)scope; + if (auto *CTD = llvm::dyn_cast_or_null(D)) { + D = CTD->getTemplatedDecl(); + } if (auto* CXXRD = llvm::dyn_cast_or_null(D)) { getSema().ForceDeclarationOfImplicitMembers(CXXRD); @@ -1497,7 +1574,7 @@ TCppType_t GetVariableType(TCppScope_t var) { QualType QT = DD->getType(); // Check if the type is a typedef type - if (QT->isTypedefNameType()) { + if (QT->isTypedefNameType() || QT->getAs()) { return QT.getAsOpaquePtr(); } @@ -1758,6 +1835,8 @@ TCppType_t GetCanonicalType(TCppType_t type) { if (!type) return 0; QualType QT = QualType::getFromOpaquePtr(type); + if (QT->getAs()) + return type; return QT.getCanonicalType().getAsOpaquePtr(); } @@ -3841,6 +3920,25 @@ bool IsConstMethod(TCppFunction_t method) { return false; } +TCppIndex_t GetTemplateNumArgs(TCppScope_t scope) { + auto *D = static_cast(scope); + if (auto *TD = llvm::dyn_cast(D)) { + auto *TPL = TD->getTemplateParameters(); + return TPL->size(); + } + return -1; +} + +std::string GetTemplateArgName(TCppScope_t scope, TCppIndex_t param_index) { + auto *D = static_cast(scope); + if (auto *TD = llvm::dyn_cast(D)) { + auto *TPL = TD->getTemplateParameters(); + NamedDecl *ND = TPL->getParam(param_index); + return ND->getNameAsString(); + } + return ""; +} + std::string GetFunctionArgName(TCppFunction_t func, TCppIndex_t param_index) { auto* D = (clang::Decl*)func; clang::ParmVarDecl* PI = nullptr; diff --git a/unittests/CppInterOp/FunctionReflectionTest.cpp b/unittests/CppInterOp/FunctionReflectionTest.cpp index 96dd45477..b9119b8e8 100644 --- a/unittests/CppInterOp/FunctionReflectionTest.cpp +++ b/unittests/CppInterOp/FunctionReflectionTest.cpp @@ -929,7 +929,7 @@ TYPED_TEST(CppInterOpTest, FunctionReflectionTestInstantiateVariadicFunction) { C.IntTy.getAsOpaquePtr()}; auto Instance1 = Cpp::InstantiateTemplate(Decls[1], args1.data(), /*type_size*/ args1.size()); - EXPECT_TRUE(Cpp::IsTemplatedFunction(Instance1)); + EXPECT_TRUE(Cpp::IsTemplateInstantiationOrSpecialization(Instance1)); EXPECT_EQ(Cpp::GetFunctionSignature(Instance1), "template<> void VariadicFn<>(double args, int args)"); @@ -952,7 +952,7 @@ TYPED_TEST(CppInterOpTest, FunctionReflectionTestInstantiateVariadicFunction) { // instantiate VariadicFnExtended auto Instance2 = Cpp::InstantiateTemplate(Decls[2], args2.data(), args2.size(), true); - EXPECT_TRUE(Cpp::IsTemplatedFunction(Instance2)); + EXPECT_TRUE(Cpp::IsTemplateInstantiationOrSpecialization(Instance2)); FunctionDecl* FD2 = cast((Decl*)Instance2); FunctionDecl* FnTD2 = FD2->getTemplateInstantiationPattern();