diff --git a/include/clang/Interpreter/CppInterOp.h b/include/clang/Interpreter/CppInterOp.h index 4392950b2..2ea87903b 100644 --- a/include/clang/Interpreter/CppInterOp.h +++ b/include/clang/Interpreter/CppInterOp.h @@ -288,6 +288,9 @@ namespace Cpp { /// supplied as a parameter. CPPINTEROP_API std::vector GetClassMethods(TCppScope_t klass); + ///\returns Template function pointer list to add proxies for un-instantiated/non-overloaded templated methods + std::vector GetTemplatedFuncs(TCppScope_t klass); + ///\returns if a class has a default constructor. CPPINTEROP_API bool HasDefaultConstructor(TCppScope_t scope); @@ -330,6 +333,15 @@ namespace Cpp { /// templated function of that type. CPPINTEROP_API bool ExistsFunctionTemplate(const std::string& name, TCppScope_t parent = 0); + + CPPINTEROP_API std::vector GetTemplatedMethods(const std::string& name, + TCppScope_t parent = 0, const std::string& filter = ""); + + CPPINTEROP_API TCppIndex_t GetNumTemplatedMethods(TCppScope_t scope, bool accept_namespace); + + CPPINTEROP_API std::string GetTemplatedMethodName(TCppScope_t scope, TCppIndex_t imeth); + + /// Checks if the provided parameter is a method. CPPINTEROP_API bool IsMethod(TCppConstFunction_t method); @@ -534,9 +546,10 @@ namespace Cpp { TemplateArgInfo(TCppScope_t type, const char* integral_value = nullptr) : m_Type(type), m_IntegralValue(integral_value) {} }; + /// Builds a template instantiation for a given templated declaration. CPPINTEROP_API TCppScope_t - InstantiateClassTemplate(TCppScope_t tmpl, TemplateArgInfo* template_args, - size_t template_args_size); + InstantiateTemplate(TCppScope_t tmpl, TemplateArgInfo* template_args, + size_t template_args_size); /// Returns the class template instantiation arguments of \c templ_instance. CPPINTEROP_API void @@ -549,6 +562,10 @@ namespace Cpp { CPPINTEROP_API TCppFunction_t InstantiateTemplateFunctionFromString(const char* function_template); + // Find best template match based on explicit template parameters and arg types + CPPINTEROP_API TCppFunction_t BestTemplateFunctionMatch(std::vector candidates, + std::vector explicit_types, std::vector arg_types); + CPPINTEROP_API std::vector GetAllCppNames(TCppScope_t scope); CPPINTEROP_API void DumpScope(TCppScope_t scope); diff --git a/lib/Interpreter/CppInterOp.cpp b/lib/Interpreter/CppInterOp.cpp index 578f3882f..bcfa5810d 100644 --- a/lib/Interpreter/CppInterOp.cpp +++ b/lib/Interpreter/CppInterOp.cpp @@ -24,6 +24,7 @@ #include "clang/Frontend/CompilerInstance.h" #include "clang/Sema/Lookup.h" #include "clang/Sema/Sema.h" +#include "clang/Sema/TemplateDeduction.h" #include "llvm/ADT/StringRef.h" #include "llvm/Support/Casting.h" @@ -745,6 +746,33 @@ namespace Cpp { return methods; } + // FIXME: We should make the std::vector an out parameter to + // avoid copies. + std::vector GetTemplatedFuncs(TCppScope_t klass) + { + + if (!klass) + return {}; + + auto *D = (clang::Decl *) klass; + + if (auto *TD = dyn_cast(D)) + D = GetScopeFromType(TD->getUnderlyingType()); + + std::vector methods; + if (auto *CXXRD = dyn_cast_or_null(D)) { + getSema().ForceDeclarationOfImplicitMembers(CXXRD); + for (Decl* DI : CXXRD->decls()) { + if (auto* MD = dyn_cast(DI)) + methods.push_back(MD); + else if (auto* USD = dyn_cast(DI)) + if (auto* MD = dyn_cast(USD->getTargetDecl())) + methods.push_back(MD); + } + } + return methods; + } + bool HasDefaultConstructor(TCppScope_t scope) { auto *D = (clang::Decl *) scope; @@ -821,6 +849,10 @@ namespace Cpp { return FD->getReturnType().getAsOpaquePtr(); } + else if (auto *FD = llvm::dyn_cast_or_null(D)) { + return (FD->getTemplatedDecl())->getReturnType().getAsOpaquePtr(); + } + return 0; } @@ -830,6 +862,10 @@ namespace Cpp { if (auto *FD = llvm::dyn_cast_or_null(D)) { return FD->getNumParams(); } + + else if (auto *FD = llvm::dyn_cast_or_null(D)) { + return (FD->getTemplatedDecl())->getNumParams(); + } return 0; } @@ -839,6 +875,10 @@ namespace Cpp { if (auto *FD = llvm::dyn_cast_or_null (D)) { return FD->getMinRequiredArguments(); } + + else if (auto *FD = llvm::dyn_cast_or_null(D)) { + return (FD->getTemplatedDecl())->getMinRequiredArguments(); + } return 0; } @@ -857,7 +897,7 @@ namespace Cpp { } std::string GetFunctionSignature(TCppFunction_t func) - { + { // FIXME : Doesn't work for template functions as it does in cling if (!func) return ""; @@ -874,6 +914,19 @@ namespace Cpp { SS.flush(); return Signature; } + + // FIXME: else if (auto *FD = llvm::dyn_cast(D)) { + // std::string Signature; + // raw_string_ostream SS(Signature); + // PrintingPolicy Policy = getASTContext().getPrintingPolicy(); + // // Skip printing the body + // Policy.TerseOutput = true; + // Policy.FullyQualifiedName = true; + // Policy.SuppressDefaultTemplateArgs = false; + // FD->print(SS, Policy); + // SS.flush(); + // return Signature; + // } return ""; } @@ -930,6 +983,118 @@ namespace Cpp { return true; } + std::vector GetTemplatedMethods(const std::string& name, + TCppScope_t parent, const std::string& filter) + { + + auto *D = (Decl *) parent; + + if (!parent || name.empty()) + return {}; + + D = GetUnderlyingScope(D); + + std::vector funcs; + llvm::StringRef Name(name); + auto &S = getSema(); + DeclarationName DName = &getASTContext().Idents.get(name); + clang::LookupResult R(S, + DName, + SourceLocation(), + Sema::LookupOrdinaryName, + Sema::ForVisibleRedeclaration); + + Cpp_utils::Lookup::Named(&S, R, Decl::castToDeclContext(D)); + + if (R.empty()) return {}; + + R.resolveKind(); + TCppFunction_t best_match; + + for (auto *Found : R){ + if (llvm::isa(Found)) funcs.push_back(Found); + } + + if(!funcs.empty()) return funcs; + + return {}; + } + + TCppIndex_t GetNumTemplatedMethods(TCppScope_t scope, bool accept_namespace) + { + if (!accept_namespace && IsNamespace(scope)) + return (TCppIndex_t)0; // Enforce lazy + + std::vector mc = GetTemplatedFuncs(scope); + TCppIndex_t res = 0; + + for (auto method : mc) { + res += IsTemplatedFunction(method) ? 1 : 0; + } + return res; + } + + std::string GetTemplatedMethodName(TCppScope_t scope, TCppIndex_t imeth) + { + std::vector mc = GetTemplatedFuncs(scope); + auto *D = (FunctionTemplateDecl *) mc[imeth]; + + return D->getNameAsString(); + } + + TCppFunction_t BestTemplateFunctionMatch(std::vector candidates, + std::vector explicit_types, std::vector arg_types) + { + + int k = 1; + for (const auto& candidate : candidates) { + auto *TFD = (FunctionTemplateDecl *)candidate; + clang::TemplateParameterList* tpl = TFD->getTemplateParameters(); + + if(tpl->size() < explicit_types.size()) + { + //template parameter size does not match + ++k; + continue; + } + + else{ + // right now if the function has not been instantiated these will give types like "A" or "B" that can take any types + // We make this match solely based on count + + const FunctionDecl* func = TFD->getTemplatedDecl(); + const auto& params = func->parameters(); + + // Check if number of function parameters match + if (func->getNumParams() != arg_types.size()) { + ++k; + continue; + } + + else{ + // TODO : first score based on the type similarity before forcing instantiation + // try instantiating + TCppFunction_t instantiated = InstantiateTemplate(candidate, arg_types.data(), arg_types.size()); + if (instantiated) return instantiated; + + // Force the instantiation with template params in case of no args + // maybe steer instantiation better with arg set returned from TemplateProxy? + else { + instantiated = InstantiateTemplate(candidate, explicit_types.data(), explicit_types.size()); + if (instantiated) return instantiated; + + else { + k++; + continue; + + } + } + } + } + } + return nullptr; + } + // Gets the AccessSpecifier of the function and checks if it is equal to // the provided AccessSpecifier. bool CheckMethodAccess(TCppFunction_t method, AccessSpecifier AS) @@ -2768,18 +2933,36 @@ namespace Cpp { return getInterp().toString(type, obj); } - static QualType InstantiateTemplate(TemplateDecl* ClassDecl, - TemplateArgumentListInfo& TLI, Sema &S) { - // This will instantiate tape type and return it. - SourceLocation noLoc; - QualType TT = S.CheckTemplateIdType(TemplateName(ClassDecl), noLoc, TLI); - + static Decl* InstantiateTemplate(TemplateDecl* TemplateD, + TemplateArgumentListInfo& TLI, Sema& S) { // This is not right but we don't have a lot of options to choose from as a // template instantiation requires a valid source location. SourceLocation fakeLoc = GetValidSLoc(S); + if (auto* FunctionTemplate = dyn_cast(TemplateD)) { + FunctionDecl* Specialization = nullptr; + clang::sema::TemplateDeductionInfo Info(fakeLoc); + if (Sema::TemplateDeductionResult Result = S.DeduceTemplateArguments( + FunctionTemplate, &TLI, Specialization, Info, + /*IsAddressOfFunction*/ true)) { + // FIXME: Diagnose what happened. + (void)Result; + } + return Specialization; + } else if (auto* VarTemplate = dyn_cast(TemplateD)) { + DeclResult R = S.CheckVarTemplateId(VarTemplate, fakeLoc, fakeLoc, TLI); + if (R.isInvalid()) { + // FIXME: Diagnose + } + return R.get(); + } + + // This will instantiate tape type and return it. + SourceLocation noLoc; + QualType TT = S.CheckTemplateIdType(TemplateName(TemplateD), noLoc, TLI); + // Perhaps we can extract this into a new interface. S.RequireCompleteType(fakeLoc, TT, diag::err_tentative_def_incomplete_type); - return TT; + return GetScopeFromType(TT); // ASTContext &C = S.getASTContext(); // // Get clad namespace and its identifier clad::. @@ -2792,21 +2975,21 @@ namespace Cpp { // return C.getElaboratedType(ETK_None, NS, TT); } - static QualType InstantiateTemplate(TemplateDecl* ClassDecl, - ArrayRef TemplateArgs, - Sema &S) { + static Decl* InstantiateTemplate(TemplateDecl* TemplateD, + ArrayRef TemplateArgs, + Sema& S) { // Create a list of template arguments. TemplateArgumentListInfo TLI{}; for (auto TA : TemplateArgs) TLI.addArgument(S.getTrivialTemplateArgumentLoc(TA,QualType(), SourceLocation())); - return InstantiateTemplate(ClassDecl, TLI, S); + return InstantiateTemplate(TemplateD, TLI, S); } - TCppScope_t InstantiateClassTemplate(TCppScope_t tmpl, - TemplateArgInfo* template_args, - size_t template_args_size) { + TCppScope_t InstantiateTemplate(TCppScope_t tmpl, + TemplateArgInfo* template_args, + size_t template_args_size) { ASTContext &C = getASTContext(); llvm::SmallVector TemplateArgs; @@ -2830,8 +3013,7 @@ namespace Cpp { #ifdef USE_CLING cling::Interpreter::PushTransactionRAII RAII(&getInterp()); #endif - QualType Instance = InstantiateTemplate(TmplD, TemplateArgs, getSema()); - return GetScopeFromType(Instance); + return InstantiateTemplate(TmplD, TemplateArgs, getSema()); } void GetClassTemplateInstantiationArgs(TCppScope_t templ_instance, @@ -2975,8 +3157,14 @@ namespace Cpp { std::string GetFunctionArgDefault(TCppFunction_t func, TCppIndex_t param_index) { auto *D = (clang::Decl *)func; - auto *FD = llvm::dyn_cast_or_null(D); - auto PI = FD->getParamDecl(param_index); + clang::ParmVarDecl *PI; + + if (auto *FD = llvm::dyn_cast_or_null(D)) { + PI = FD->getParamDecl(param_index); + } + else if (auto *FD = llvm::dyn_cast_or_null(D)) { + PI = (FD->getTemplatedDecl())->getParamDecl(param_index); + } if (PI->hasDefaultArg()) { @@ -3017,8 +3205,14 @@ namespace Cpp { std::string GetFunctionArgName(TCppFunction_t func, TCppIndex_t param_index) { auto *D = (clang::Decl *)func; - auto *FD = llvm::cast(D); - auto PI = FD->getParamDecl(param_index); + clang::ParmVarDecl *PI; + + if (auto *FD = llvm::dyn_cast_or_null(D)) { + PI = FD->getParamDecl(param_index); + } + else if (auto *FD = llvm::dyn_cast_or_null(D)) { + PI = (FD->getTemplatedDecl())->getParamDecl(param_index); + } return PI->getNameAsString(); }