diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index d4bd2cf6e4..2590f7345b 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -21,7 +21,7 @@ add_unit_test( system_tests ) add_unit_test( time_tests ) add_unit_test( varint_tests ) -add_test( NAME toolchain_tests COMMAND ${CMAKE_BINARY_DIR}/tools/toolchain-tester/toolchain-tester ${CMAKE_SOURCE_DIR}/tests/toolchain --cdt ${CMAKE_BINARY_DIR}/bin ) +add_test( NAME toolchain_tests COMMAND ${CMAKE_BINARY_DIR}/tools/toolchain-tester/toolchain-tester ${CMAKE_SOURCE_DIR}/tests/toolchain --cdt ${CMAKE_BINARY_DIR}/bin --verbose ) set_property(TEST toolchain_tests PROPERTY LABELS toolchain_tests) configure_file(${CMAKE_CURRENT_SOURCE_DIR}/unit/version_tests.sh ${CMAKE_BINARY_DIR}/tests/unit/version_tests.sh COPYONLY) diff --git a/tests/toolchain/abigen-pass/exclude_from_abi.hpp b/tests/toolchain/abigen-pass/exclude_from_abi.hpp new file mode 100644 index 0000000000..3b90f866ac --- /dev/null +++ b/tests/toolchain/abigen-pass/exclude_from_abi.hpp @@ -0,0 +1,50 @@ +#pragma once + +#include +#include +#include +#include + + + +struct [[eosio::table]] out_of_class { + uint64_t id; + uint64_t primary_key() const { return id; } +}; +typedef eosio::multi_index<"mi.config55"_n, out_of_class> out_of_class_index; +using uout_of_class_index = eosio::multi_index<"mi.config551"_n, out_of_class>; + +typedef eosio::singleton<"smpl.conf55"_n, eosio::name> smpl_config55; +typedef eosio::singleton<"config55"_n, out_of_class> config55; +typedef smpl_config55 smpl_config551; +typedef config55 config551; +using smpl_conf551 = eosio::singleton<"smpl.conf551"_n, eosio::name>; +using config552 = eosio::singleton<"config552"_n, out_of_class>; +using smpl_conf552 = smpl_conf551; +using config553 = config551; + +class [[eosio::contract("singleton_contract_simple2")]] singleton_contract_simple2 : public eosio::contract { + public: + using eosio::contract::contract; + + [[eosio::action]] + void whatever() {}; + + struct [[eosio::table]] inside_class { + uint64_t id; + uint64_t primary_key() const { return id; } + }; + typedef eosio::singleton<"smpl.conf552"_n, eosio::name> smpl_conf552; + typedef eosio::singleton<"config552"_n, inside_class> config552; + typedef smpl_conf552 smpl_conf553; + typedef config552 config553; + using smpl_conf554 = eosio::singleton<"smpl.conf554"_n, eosio::name>; + using config554 = eosio::singleton<"config554"_n, inside_class>; + using smpl_conf555 = smpl_conf554; + using config555 = config554; + + + + typedef eosio::multi_index<"mi.config553"_n, inside_class> inside_class_index; + using uinside_class_index = eosio::multi_index<"mi.config554"_n, inside_class>; +}; diff --git a/tests/toolchain/abigen-pass/singleton_contract.abi b/tests/toolchain/abigen-pass/singleton_contract.abi index 4c6e9853a5..6cdc4a8c72 100644 --- a/tests/toolchain/abigen-pass/singleton_contract.abi +++ b/tests/toolchain/abigen-pass/singleton_contract.abi @@ -37,6 +37,27 @@ "index_type": "i64", "key_names": [], "key_types": [] + }, + { + "name": "config55", + "type": "out_of_class", + "index_type": "i64", + "key_names": [], + "key_types": [] + }, + { + "name": "smpl.conf5", + "type": "name", + "index_type": "i64", + "key_names": [], + "key_types": [] + }, + { + "name": "smpl.config", + "type": "name", + "index_type": "i64", + "key_names": [], + "key_types": [] } ], "ricardian_clauses": [], diff --git a/tests/toolchain/abigen-pass/singleton_contract.cpp b/tests/toolchain/abigen-pass/singleton_contract.cpp index 89831854c9..f1999c27bc 100644 --- a/tests/toolchain/abigen-pass/singleton_contract.cpp +++ b/tests/toolchain/abigen-pass/singleton_contract.cpp @@ -2,9 +2,27 @@ #include #include #include + +#include "exclude_from_abi.hpp" using namespace eosio; - + +struct [[eosio::table]] out_of_class2 { + uint64_t id; + uint64_t primary_key() const { return id; } +}; +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>; + +typedef eosio::singleton<"smpl.conf5"_n, eosio::name> smpl_config5; +typedef eosio::singleton<"config5"_n, out_of_class2> config5; +typedef smpl_config5 smpl_config51; +typedef config5 config51; +using smpl_conf51 = eosio::singleton<"smpl.conf51"_n, eosio::name>; +using config52 = eosio::singleton<"config52"_n, out_of_class2>; +using smpl_conf52 = smpl_conf51; +using config53 = config51; + class [[eosio::contract("singleton_contract")]] singleton_contract : public contract { public: using contract::contract; @@ -17,5 +35,8 @@ class [[eosio::contract("singleton_contract")]] singleton_contract : public cont uint64_t x; }; - typedef eosio::singleton<"config"_n, tbl_config> config; + typedef eosio::singleton<"config"_n, tbl_config> config; + typedef eosio::singleton<"smpl.config"_n, name> smpl_config; + using smpl_config2 = smpl_config5; + typedef config551 config2; //from exclude_from_abi.hpp }; diff --git a/tests/toolchain/abigen-pass/singleton_contract_simple.abi b/tests/toolchain/abigen-pass/singleton_contract_simple.abi deleted file mode 100644 index 8600eb2f76..0000000000 --- a/tests/toolchain/abigen-pass/singleton_contract_simple.abi +++ /dev/null @@ -1,31 +0,0 @@ -{ - "____comment": "This file was generated with eosio-abigen. DO NOT EDIT ", - "version": "eosio::abi/1.2", - "types": [], - "structs": [ - { - "name": "whatever", - "base": "", - "fields": [] - } - ], - "actions": [ - { - "name": "whatever", - "type": "whatever", - "ricardian_contract": "" - } - ], - "tables": [ - { - "name": "smpl.config", - "type": "name", - "index_type": "i64", - "key_names": [], - "key_types": [] - } - ], - "ricardian_clauses": [], - "variants": [], - "action_results": [] -} diff --git a/tests/toolchain/abigen-pass/singleton_contract_simple.cpp b/tests/toolchain/abigen-pass/singleton_contract_simple.cpp deleted file mode 100644 index 2afdc7c332..0000000000 --- a/tests/toolchain/abigen-pass/singleton_contract_simple.cpp +++ /dev/null @@ -1,16 +0,0 @@ -#include -#include -#include -#include - -using namespace eosio; - -class [[eosio::contract("singleton_contract_simple")]] singleton_contract_simple : public contract { - public: - using contract::contract; - - [[eosio::action]] - void whatever() {}; - - typedef eosio::singleton<"smpl.config"_n, name> config; -}; diff --git a/tests/toolchain/abigen-pass/singleton_contract_simple.json b/tests/toolchain/abigen-pass/singleton_contract_simple.json deleted file mode 100644 index 0bf81acc1e..0000000000 --- a/tests/toolchain/abigen-pass/singleton_contract_simple.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "tests" : [ - { - "expected" : { - "abi-file" : "singleton_contract_simple.abi" - } - } - ] - } - \ No newline at end of file diff --git a/tools/include/eosio/abigen.hpp b/tools/include/eosio/abigen.hpp index 479c9fec73..9d83babcd2 100644 --- a/tools/include/eosio/abigen.hpp +++ b/tools/include/eosio/abigen.hpp @@ -755,6 +755,7 @@ namespace eosio { namespace cdt { private: bool has_added_clauses = false; abigen& ag = abigen::get(); + const clang::CXXRecordDecl* contract_class = NULL; public: explicit eosio_abigen_visitor(CompilerInstance *CI) { @@ -799,10 +800,66 @@ 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; + if (decl1 == decl2) + return true; + + // checking if declaration is a typedef or using + if (const clang::TypedefNameDecl* typedef_decl = llvm::dyn_cast(decl1)) { + if (const auto* cur_type = typedef_decl->getUnderlyingType().getTypePtrOrNull()) { + if (decl2 == cur_type->getAsCXXRecordDecl()) { + return true; + } + } + } + + return false; + } + + 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"); + return false; + } + } + + for (const clang::Decl* cur_decl : contract_class->decls()) { + if (is_same_type(cur_decl, decl)) + return true; + } + + return false; + } + 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) { + 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); } @@ -826,7 +883,6 @@ namespace eosio { namespace cdt { auto& f_mgr = src_mgr.getFileManager(); auto main_fe = f_mgr.getFile(main_file); if (main_fe) { - auto fid = src_mgr.getOrCreateFileID(f_mgr.getFile(main_file), SrcMgr::CharacteristicKind::C_User); visitor->TraverseDecl(Context.getTranslationUnitDecl()); } } diff --git a/tools/include/eosio/error_emitter.hpp b/tools/include/eosio/error_emitter.hpp index 70e4157b3e..0b2de429dd 100644 --- a/tools/include/eosio/error_emitter.hpp +++ b/tools/include/eosio/error_emitter.hpp @@ -61,6 +61,8 @@ namespace eosio { namespace cdt { #define CDT_ERROR(e, l, s) \ get_error_emitter().emit_error(l, get_error_emitter().diags.get(e), s); -#define CDT_INTERNAL_ERROR(s) \ - std::cerr << s << "\n"; \ - throw internal_error_ex; +#define CDT_INTERNAL_ERROR(s) \ + do { \ + std::cerr << s << "\n"; \ + throw internal_error_ex; \ + } while (false) diff --git a/tools/include/eosio/gen.hpp b/tools/include/eosio/gen.hpp index 8e2494d428..3637e74fea 100644 --- a/tools/include/eosio/gen.hpp +++ b/tools/include/eosio/gen.hpp @@ -155,7 +155,7 @@ struct generation_utils { inline void set_contract_name( const std::string& cn ) { contract_name = cn; } - inline std::string get_contract_name()const { return contract_name; } + inline const std::string& get_contract_name()const { return contract_name; } static inline std::string get_parsed_contract_name() { return parsed_contract_name; } inline void set_resource_dirs( const std::vector& rd ) { llvm::SmallString<128> cwd; @@ -274,30 +274,30 @@ struct generation_utils { } static inline bool is_eosio_contract( const clang::CXXMethodDecl* decl, const std::string& cn ) { - std::string name = ""; + llvm::StringRef name; if (decl->isEosioContract()) name = decl->getEosioContractAttr()->getName(); else if (decl->getParent()->isEosioContract()) name = decl->getParent()->getEosioContractAttr()->getName(); if (name.empty()) { - name = decl->getParent()->getName().str(); + name = decl->getParent()->getName(); } - parsed_contract_name = name; + parsed_contract_name = name.str(); return cn == parsed_contract_name; } static inline bool is_eosio_contract( const clang::CXXRecordDecl* decl, const std::string& cn ) { - std::string name = ""; + llvm::StringRef name; auto pd = llvm::dyn_cast(decl->getParent()); if (decl->isEosioContract()) { - auto nm = decl->getEosioContractAttr()->getName().str(); - name = nm.empty() ? decl->getName().str() : nm; + auto nm = decl->getEosioContractAttr()->getName(); + name = nm.empty() ? decl->getName() : nm; } else if (pd && pd->isEosioContract()) { - auto nm = pd->getEosioContractAttr()->getName().str(); - name = nm.empty() ? pd->getName().str() : nm; + auto nm = pd->getEosioContractAttr()->getName(); + name = nm.empty() ? pd->getName() : nm; } - parsed_contract_name = name; + parsed_contract_name = name.str(); return cn == parsed_contract_name; }