Skip to content

Commit

Permalink
Add interfaces enabling template function logic (#215)
Browse files Browse the repository at this point in the history
  • Loading branch information
aaronj0 authored Apr 12, 2024
1 parent 8dd6b87 commit 1e4b64f
Show file tree
Hide file tree
Showing 4 changed files with 235 additions and 50 deletions.
66 changes: 58 additions & 8 deletions include/clang/Interpreter/CppInterOp.h
Original file line number Diff line number Diff line change
Expand Up @@ -246,7 +246,7 @@ namespace Cpp {
/// passed as a parameter, and if the parent is not passed,
/// then global scope will be assumed.
CPPINTEROP_API TCppScope_t GetScope(const std::string& name,
TCppScope_t parent = 0);
TCppScope_t parent = nullptr);

/// When the namespace is known, then the parent doesn't need
/// to be specified. This will probably be phased-out in
Expand Down Expand Up @@ -284,9 +284,22 @@ namespace Cpp {
CPPINTEROP_API int64_t GetBaseClassOffset(TCppScope_t derived,
TCppScope_t base);

/// Gets a list of all the Methods that are in the Class that is
/// Sets a list of all the Methods that are in the Class that is
/// supplied as a parameter.
CPPINTEROP_API std::vector<TCppFunction_t> GetClassMethods(TCppScope_t klass);
///\param[in] klass - Pointer to the scope/class under which the methods have
/// to be retrieved
///\param[out] methods - Vector of methods in the class
CPPINTEROP_API void GetClassMethods(TCppScope_t klass,
std::vector<TCppFunction_t>& methods);

/// Template function pointer list to add proxies for un-instantiated/
/// non-overloaded templated methods
///\param[in] klass - Pointer to the scope/class under which the methods have
/// to be retrieved
///\param[out] methods - Vector of methods in the class
CPPINTEROP_API void
GetFunctionTemplatedDecls(TCppScope_t klass,
std::vector<TCppFunction_t>& methods);

///\returns if a class has a default constructor.
CPPINTEROP_API bool HasDefaultConstructor(TCppScope_t scope);
Expand Down Expand Up @@ -329,7 +342,17 @@ namespace Cpp {
/// This function performs a lookup to check if there is a
/// templated function of that type.
CPPINTEROP_API bool ExistsFunctionTemplate(const std::string& name,
TCppScope_t parent = 0);
TCppScope_t parent = nullptr);

/// Sets a list of all the Templated Methods that are in the Class that is
/// supplied as a parameter.
///\param[in] name - method name
///\param[in] parent - Pointer to the scope/class under which the methods have
/// to be retrieved
///\param[out] funcs - vector of function pointers matching the name
CPPINTEROP_API void
GetClassTemplatedMethods(const std::string& name, TCppScope_t parent,
std::vector<TCppFunction_t>& funcs);

/// Checks if the provided parameter is a method.
CPPINTEROP_API bool IsMethod(TCppConstFunction_t method);
Expand Down Expand Up @@ -535,11 +558,24 @@ namespace Cpp {
: m_Type(type), m_IntegralValue(integral_value) {}
};
/// Builds a template instantiation for a given templated declaration.
CPPINTEROP_API TCppScope_t InstantiateTemplate(TCppScope_t tmpl,
TemplateArgInfo* template_args,
size_t template_args_size);
/// Offers a single interface for instantiation of class, function and
/// variable templates
///
///\param[in] tmpl - Uninstantiated template class/function
///\param[in] template_args - Pointer to vector of template arguments stored
/// in the \c TemplateArgInfo struct
///\param[in] template_args_size - Size of the vector of template arguments
/// passed as \c template_args
///
///\returns Instantiated templated class/function/variable pointer
CPPINTEROP_API TCppScope_t
InstantiateTemplate(TCppScope_t tmpl, const TemplateArgInfo* template_args,
size_t template_args_size);

/// Returns the class template instantiation arguments of \c templ_instance.
/// Sets the class template instantiation arguments of \c templ_instance.
///
///\param[in] templ_instance - Pointer to the template instance
///\param[out] args - Vector of instantiation arguments
CPPINTEROP_API void
GetClassTemplateInstantiationArgs(TCppScope_t templ_instance,
std::vector<TemplateArgInfo>& args);
Expand All @@ -550,6 +586,20 @@ namespace Cpp {
CPPINTEROP_API TCppFunction_t
InstantiateTemplateFunctionFromString(const char* function_template);

/// Finds best template match based on explicit template parameters and
/// argument types
///
///\param[in] candidates - Vector of suitable candidates that come under the
/// parent scope and have the same name (obtained using
/// GetClassTemplatedMethods)
///\param[in] explicit_types - set of expicitly instantiated template types
///\param[in] arg_types - set of argument types
///\returns Instantiated function pointer
CPPINTEROP_API TCppFunction_t
BestTemplateFunctionMatch(const std::vector<TCppFunction_t>& candidates,
const std::vector<TemplateArgInfo>& explicit_types,
const std::vector<TemplateArgInfo>& arg_types);

CPPINTEROP_API std::vector<std::string> GetAllCppNames(TCppScope_t scope);

CPPINTEROP_API void DumpScope(TCppScope_t scope);
Expand Down
136 changes: 103 additions & 33 deletions lib/Interpreter/CppInterOp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -719,39 +719,46 @@ namespace Cpp {
return ComputeBaseOffset(getSema().getASTContext(), DCXXRD, Paths.front());
}

// FIXME: We should make the std::vector<TCppFunction_t> an out parameter to
// avoid copies.
std::vector<TCppFunction_t> GetClassMethods(TCppScope_t klass)
{

template <typename DeclType>
static void GetClassDecls(TCppScope_t klass,
std::vector<TCppFunction_t>& methods) {
if (!klass)
return {};
return;

auto *D = (clang::Decl *) klass;
auto* D = (clang::Decl*)klass;

if (auto *TD = dyn_cast<TypedefNameDecl>(D))
if (auto* TD = dyn_cast<TypedefNameDecl>(D))
D = GetScopeFromType(TD->getUnderlyingType());

std::vector<TCppFunction_t> methods;
if (auto *CXXRD = dyn_cast_or_null<CXXRecordDecl>(D)) {
getSema().ForceDeclarationOfImplicitMembers(CXXRD);
for (Decl* DI : CXXRD->decls()) {
if (auto* MD = dyn_cast<CXXMethodDecl>(DI))
if (!D || !isa<CXXRecordDecl>(D))
return;

auto* CXXRD = dyn_cast<CXXRecordDecl>(D);
getSema().ForceDeclarationOfImplicitMembers(CXXRD);
for (Decl* DI : CXXRD->decls()) {
if (auto* MD = dyn_cast<DeclType>(DI))
methods.push_back(MD);
else if (auto* USD = dyn_cast<UsingShadowDecl>(DI))
if (auto* MD = dyn_cast<DeclType>(USD->getTargetDecl()))
methods.push_back(MD);
else if (auto* USD = dyn_cast<UsingShadowDecl>(DI))
if (auto* MD = dyn_cast<CXXMethodDecl>(USD->getTargetDecl()))
methods.push_back(MD);
}
}
return methods;
}

void GetClassMethods(TCppScope_t klass,
std::vector<TCppFunction_t>& methods) {
GetClassDecls<CXXMethodDecl>(klass, methods);
}

void GetFunctionTemplatedDecls(TCppScope_t klass,
std::vector<TCppFunction_t>& methods) {
GetClassDecls<FunctionTemplateDecl>(klass, methods);
}

bool HasDefaultConstructor(TCppScope_t scope) {
auto *D = (clang::Decl *) scope;

if (auto *CXXRD = llvm::dyn_cast_or_null<CXXRecordDecl>(D)) {
if (auto* CXXRD = llvm::dyn_cast_or_null<CXXRecordDecl>(D))
return CXXRD->hasDefaultConstructor();
}

return false;
}
Expand Down Expand Up @@ -818,21 +825,19 @@ namespace Cpp {
TCppType_t GetFunctionReturnType(TCppFunction_t func)
{
auto *D = (clang::Decl *) func;
if (auto *FD = llvm::dyn_cast_or_null<clang::FunctionDecl>(D)) {
return FD->getReturnType().getAsOpaquePtr();
}
if (auto* FD = llvm::dyn_cast_or_null<clang::FunctionDecl>(D))
return FD->getReturnType().getAsOpaquePtr();

if (auto* FD = llvm::dyn_cast_or_null<clang::FunctionTemplateDecl>(D)) {
return (FD->getTemplatedDecl())->getReturnType().getAsOpaquePtr();
}
if (auto* FD = llvm::dyn_cast_or_null<clang::FunctionTemplateDecl>(D))
return (FD->getTemplatedDecl())->getReturnType().getAsOpaquePtr();

return 0;
}

TCppIndex_t GetFunctionNumArgs(TCppFunction_t func)
{
auto *D = (clang::Decl *) func;
if (auto *FD = llvm::dyn_cast_or_null<FunctionDecl>(D))
if (auto* FD = llvm::dyn_cast_or_null<FunctionDecl>(D))
return FD->getNumParams();

if (auto* FD = llvm::dyn_cast_or_null<clang::FunctionTemplateDecl>(D))
Expand All @@ -844,9 +849,8 @@ namespace Cpp {
TCppIndex_t GetFunctionRequiredArgs(TCppConstFunction_t func)
{
auto *D = (const clang::Decl *) func;
if (auto *FD = llvm::dyn_cast_or_null<FunctionDecl> (D)) {
if (auto* FD = llvm::dyn_cast_or_null<FunctionDecl>(D))
return FD->getMinRequiredArguments();
}

if (auto* FD = llvm::dyn_cast_or_null<clang::FunctionTemplateDecl>(D))
return (FD->getTemplatedDecl())->getMinRequiredArguments();
Expand All @@ -868,8 +872,7 @@ namespace Cpp {
return 0;
}

std::string GetFunctionSignature(TCppFunction_t func)
{
std::string GetFunctionSignature(TCppFunction_t func) {
if (!func)
return "<unknown>";

Expand All @@ -886,6 +889,7 @@ namespace Cpp {
SS.flush();
return Signature;
}

return "<unknown>";
}

Expand Down Expand Up @@ -925,7 +929,7 @@ namespace Cpp {
{
DeclContext *Within = 0;
if (parent) {
auto *D = (Decl *)parent;
auto* D = (Decl*)parent;
Within = llvm::dyn_cast<DeclContext>(D);
}

Expand All @@ -941,6 +945,72 @@ namespace Cpp {
return true;
}

void GetClassTemplatedMethods(const std::string& name, TCppScope_t parent,
std::vector<TCppFunction_t>& funcs) {

auto* D = (Decl*)parent;

if (!parent || name.empty())
return;

D = GetUnderlyingScope(D);

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();

for (auto* Found : R)
if (llvm::isa<FunctionTemplateDecl>(Found))
funcs.push_back(Found);
}

TCppFunction_t
BestTemplateFunctionMatch(const std::vector<TCppFunction_t>& candidates,
const std::vector<TemplateArgInfo>& explicit_types,
const std::vector<TemplateArgInfo>& arg_types) {

for (const auto& candidate : candidates) {
auto* TFD = (FunctionTemplateDecl*)candidate;
clang::TemplateParameterList* tpl = TFD->getTemplateParameters();

// template parameter size does not match
if (tpl->size() < explicit_types.size())
continue;

// right now uninstantiated functions give template typenames instead of
// actual types. We make this match solely based on count

const FunctionDecl* func = TFD->getTemplatedDecl();
if (func->getNumParams() != arg_types.size())
continue;

// FIXME : 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?
instantiated = InstantiateTemplate(candidate, explicit_types.data(),
explicit_types.size());
if (instantiated)
return instantiated;
}
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)
Expand Down Expand Up @@ -2836,7 +2906,7 @@ namespace Cpp {
}

TCppScope_t InstantiateTemplate(TCppScope_t tmpl,
TemplateArgInfo* template_args,
const TemplateArgInfo* template_args,
size_t template_args_size) {
ASTContext &C = getASTContext();

Expand Down
Loading

0 comments on commit 1e4b64f

Please sign in to comment.