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

improve abi generation #226

Merged
merged 2 commits into from
Sep 22, 2023
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
27 changes: 27 additions & 0 deletions tests/toolchain/abigen-pass/singleton_contract.abi
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,26 @@
"version": "eosio::abi/1.2",
"types": [],
"structs": [
{
"name": "out_of_class",
"base": "",
"fields": [
{
"name": "id",
"type": "uint64"
}
]
},
{
"name": "out_of_class3",
"base": "",
"fields": [
{
"name": "id",
"type": "uint64"
}
]
},
{
"name": "tbl_config",
"base": "",
Expand Down Expand Up @@ -45,6 +65,13 @@
"key_names": [],
"key_types": []
},
{
"name": "mi.config52",
"type": "out_of_class3",
"index_type": "i64",
"key_names": [],
"key_types": []
},
{
"name": "smpl.conf5",
"type": "name",
Expand Down
6 changes: 6 additions & 0 deletions tests/toolchain/abigen-pass/singleton_contract.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,12 @@ struct [[eosio::table]] out_of_class2 {
typedef eosio::multi_index<"mi.config5"_n, out_of_class2> out_of_class_index51;
using uout_of_class_index51 = eosio::multi_index<"mi.config51"_n, out_of_class2>;

struct [[eosio::table, eosio::contract("singleton_contract")]] out_of_class3 {
uint64_t id;
uint64_t primary_key() const { return id; }
};
typedef eosio::multi_index<"mi.config52"_n, out_of_class3> out_of_class_index52;

typedef eosio::singleton<"smpl.conf5"_n, eosio::name> smpl_config5;
typedef eosio::singleton<"config5"_n, out_of_class2> config5;
typedef smpl_config5 smpl_config51;
Expand Down
93 changes: 60 additions & 33 deletions tools/include/eosio/abigen.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -243,13 +243,11 @@ namespace eosio { namespace cdt {
ctables.insert(t);
}

void add_table( uint64_t name, const clang::CXXRecordDecl* decl, bool force=false ) {
if (force || decl->isEosioTable() && abigen::is_eosio_contract(decl, get_contract_name())) {
abi_table t;
t.type = decl->getNameAsString();
t.name = name_to_string(name);
_abi.tables.insert(t);
}
void add_table( uint64_t name, const clang::CXXRecordDecl* decl ) {
abi_table t;
t.type = decl->getNameAsString();
t.name = name_to_string(name);
_abi.tables.insert(t);
}

void add_clauses( const std::vector<std::pair<std::string, std::string>>& clauses ) {
Expand Down Expand Up @@ -801,24 +799,6 @@ namespace eosio { namespace cdt {
return true;
}

const clang::CXXRecordDecl* find_contract_class(const clang::ASTContext &ctx) const {
const auto* translation_unit = ctx.getTranslationUnitDecl();
// scanning entire translation unit to find contract class
for (const clang::Decl* cur_decl : translation_unit->decls()) {
if (const auto* cxx_decl = llvm::dyn_cast<clang::CXXRecordDecl>(cur_decl)) {

if (cxx_decl->isEosioContract()) {
auto attr_name = cxx_decl->getEosioContractAttr()->getName();
auto name = attr_name.empty() ? cxx_decl->getName() : attr_name;
if (name == llvm::StringRef(ag.get_contract_name()))
return cxx_decl;
}
}
}

return nullptr;
}

bool is_same_type(const clang::Decl* decl1, const clang::CXXRecordDecl* decl2) const {
if (!decl1 || !decl2)
return false;
Expand All @@ -840,12 +820,9 @@ namespace eosio { namespace cdt {
bool defined_in_contract(const clang::ClassTemplateSpecializationDecl* decl) {

if (!contract_class) {
contract_class = find_contract_class(decl->getASTContext());
if (!contract_class) {
// currently this is unreachable as we do not traverse non-main file translation units
CDT_WARN("codegen_warning", decl->getLocation(), "contract class not found");
CDT_WARN("codegen_warning", decl->getLocation(), "contract class not found: " + ag.get_contract_name());
return false;
}
}

for (const clang::Decl* cur_decl : contract_class->decls()) {
Expand All @@ -858,16 +835,62 @@ namespace eosio { namespace cdt {

virtual bool VisitDecl(clang::Decl* decl) {
if (const auto* d = dyn_cast<clang::ClassTemplateSpecializationDecl>(decl)) {
bool is_singleton = d->getName() == "singleton";
if ((d->getName() == "multi_index" || is_singleton) && defined_in_contract(d)) {
ag.add_table(d->getTemplateArgs()[0].getAsIntegral().getExtValue(),
d->getTemplateArgs()[1].getAsType().getTypePtr()->getAsCXXRecordDecl(), is_singleton);
if (d->getName() == "multi_index" || d->getName() == "singleton") {
// second template parameter is table type
const auto* table_type = d->getTemplateArgs()[1].getAsType().getTypePtr()->getAsCXXRecordDecl();
if ((table_type->isEosioTable() && ag.is_eosio_contract(table_type, ag.get_contract_name())) || defined_in_contract(d)) {
// first parameter is table name
ag.add_table(d->getTemplateArgs()[0].getAsIntegral().getExtValue(), table_type);
if (table_type->isEosioTable())
ag.add_struct(table_type);
}
}
}
return true;
}
inline void set_contract_class(const CXXRecordDecl* decl) {
contract_class = decl;
}
};
class contract_class_finder : public RecursiveASTVisitor<contract_class_finder> {
private:
abigen& ag = abigen::get();
const clang::CXXRecordDecl* contract_class = nullptr;
public:
virtual bool VisitCXXRecordDecl(clang::CXXRecordDecl* cxx_decl) {
if (cxx_decl->isEosioContract()) {
bool is_eosio_contract = false;
// on this point it could be just an attribute so let's check base classes
for (const auto& base : cxx_decl->bases()) {
if (const clang::Type *base_type = base.getType().getTypePtrOrNull()) {
if (const auto* cur_cxx_decl = base_type->getAsCXXRecordDecl()) {
if (cur_cxx_decl->getQualifiedNameAsString() == "eosio::contract") {
is_eosio_contract = true;
break;
}
}
}
}
if (!is_eosio_contract)
return true;

auto attr_name = cxx_decl->getEosioContractAttr()->getName();
auto name = attr_name.empty() ? cxx_decl->getName() : attr_name;
if (name == llvm::StringRef(ag.get_contract_name())) {
contract_class = cxx_decl;
return false;
}
}

return true;
}
inline bool contract_found() const {
return contract_class != nullptr;
}
inline const clang::CXXRecordDecl* get_contract() const {
return contract_class;
}
};
class eosio_abigen_consumer : public ASTConsumer {
private:
eosio_abigen_visitor *visitor;
Expand All @@ -883,6 +906,10 @@ namespace eosio { namespace cdt {
auto& f_mgr = src_mgr.getFileManager();
auto main_fe = f_mgr.getFile(main_file);
if (main_fe) {
contract_class_finder cf;
cf.TraverseDecl(Context.getTranslationUnitDecl());
if (cf.contract_found())
visitor->set_contract_class(cf.get_contract());
visitor->TraverseDecl(Context.getTranslationUnitDecl());
}
}
Expand Down