From 93f6a186aa64edd45e71d1a45464e3b9a496bb7d Mon Sep 17 00:00:00 2001 From: Dmytro Sydorchenko Date: Mon, 18 Sep 2023 22:43:57 -0400 Subject: [PATCH 1/2] improve abi generation --- .../abigen-pass/singleton_contract.abi | 17 ++++ .../abigen-pass/singleton_contract.cpp | 6 ++ tools/include/eosio/abigen.hpp | 91 ++++++++++++------- 3 files changed, 81 insertions(+), 33 deletions(-) diff --git a/tests/toolchain/abigen-pass/singleton_contract.abi b/tests/toolchain/abigen-pass/singleton_contract.abi index 6cdc4a8c72..86c6fe4927 100644 --- a/tests/toolchain/abigen-pass/singleton_contract.abi +++ b/tests/toolchain/abigen-pass/singleton_contract.abi @@ -3,6 +3,16 @@ "version": "eosio::abi/1.2", "types": [], "structs": [ + { + "name": "out_of_class3", + "base": "", + "fields": [ + { + "name": "id", + "type": "uint64" + } + ] + }, { "name": "tbl_config", "base": "", @@ -45,6 +55,13 @@ "key_names": [], "key_types": [] }, + { + "name": "mi.config52", + "type": "out_of_class3", + "index_type": "i64", + "key_names": [], + "key_types": [] + }, { "name": "smpl.conf5", "type": "name", diff --git a/tests/toolchain/abigen-pass/singleton_contract.cpp b/tests/toolchain/abigen-pass/singleton_contract.cpp index f1999c27bc..0a0c96c9bc 100644 --- a/tests/toolchain/abigen-pass/singleton_contract.cpp +++ b/tests/toolchain/abigen-pass/singleton_contract.cpp @@ -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; diff --git a/tools/include/eosio/abigen.hpp b/tools/include/eosio/abigen.hpp index 9d83babcd2..2dc4317e37 100644 --- a/tools/include/eosio/abigen.hpp +++ b/tools/include/eosio/abigen.hpp @@ -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>& clauses ) { @@ -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(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; @@ -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()) { @@ -858,16 +835,60 @@ namespace eosio { namespace cdt { virtual bool VisitDecl(clang::Decl* decl) { if (const auto* d = dyn_cast(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); + } } } return true; } + void set_contract_class(const CXXRecordDecl* decl) { + contract_class = decl; + } }; + class contract_class_finder : public RecursiveASTVisitor { + 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; + } + bool contract_found() const { + return contract_class != nullptr; + } + const clang::CXXRecordDecl* get_contract() const { + return contract_class; + } + }; class eosio_abigen_consumer : public ASTConsumer { private: eosio_abigen_visitor *visitor; @@ -883,6 +904,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()); } } From d6721b2d66274c65bfa29998f91b9b1a3f42be7a Mon Sep 17 00:00:00 2001 From: Dmytro Sydorchenko Date: Tue, 19 Sep 2023 00:00:38 -0400 Subject: [PATCH 2/2] fixing integration tests --- tests/toolchain/abigen-pass/singleton_contract.abi | 10 ++++++++++ tools/include/eosio/abigen.hpp | 8 +++++--- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/tests/toolchain/abigen-pass/singleton_contract.abi b/tests/toolchain/abigen-pass/singleton_contract.abi index 86c6fe4927..4adaedf6d8 100644 --- a/tests/toolchain/abigen-pass/singleton_contract.abi +++ b/tests/toolchain/abigen-pass/singleton_contract.abi @@ -3,6 +3,16 @@ "version": "eosio::abi/1.2", "types": [], "structs": [ + { + "name": "out_of_class", + "base": "", + "fields": [ + { + "name": "id", + "type": "uint64" + } + ] + }, { "name": "out_of_class3", "base": "", diff --git a/tools/include/eosio/abigen.hpp b/tools/include/eosio/abigen.hpp index 2dc4317e37..5836b04dcf 100644 --- a/tools/include/eosio/abigen.hpp +++ b/tools/include/eosio/abigen.hpp @@ -841,12 +841,14 @@ namespace eosio { namespace cdt { 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; } - void set_contract_class(const CXXRecordDecl* decl) { + inline void set_contract_class(const CXXRecordDecl* decl) { contract_class = decl; } }; @@ -882,10 +884,10 @@ namespace eosio { namespace cdt { return true; } - bool contract_found() const { + inline bool contract_found() const { return contract_class != nullptr; } - const clang::CXXRecordDecl* get_contract() const { + inline const clang::CXXRecordDecl* get_contract() const { return contract_class; } };