Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Enable template features #215

Merged
merged 8 commits into from
Apr 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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.
aaronj0 marked this conversation as resolved.
Show resolved Hide resolved
///\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>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We do not need a template, we can take a DeclKind as a parameter.

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;
aaronj0 marked this conversation as resolved.
Show resolved Hide resolved

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;
aaronj0 marked this conversation as resolved.
Show resolved Hide resolved
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;
aaronj0 marked this conversation as resolved.
Show resolved Hide resolved

if (!parent || name.empty())
aaronj0 marked this conversation as resolved.
Show resolved Hide resolved
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
Loading