Skip to content

Commit 0056647

Browse files
authored
Merge pull request #201 from AntelopeIO/extend-abi-non-contract
Redesign abi generation for multi_index and singleton
2 parents b5d71e2 + b2386d9 commit 0056647

10 files changed

+168
-75
lines changed

tests/CMakeLists.txt

+1-1
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ add_unit_test( system_tests )
2121
add_unit_test( time_tests )
2222
add_unit_test( varint_tests )
2323

24-
add_test( NAME toolchain_tests COMMAND ${CMAKE_BINARY_DIR}/tools/toolchain-tester/toolchain-tester ${CMAKE_SOURCE_DIR}/tests/toolchain --cdt ${CMAKE_BINARY_DIR}/bin )
24+
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 )
2525
set_property(TEST toolchain_tests PROPERTY LABELS toolchain_tests)
2626

2727
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/unit/version_tests.sh ${CMAKE_BINARY_DIR}/tests/unit/version_tests.sh COPYONLY)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
#pragma once
2+
3+
#include <eosio/eosio.hpp>
4+
#include <eosio/name.hpp>
5+
#include <eosio/singleton.hpp>
6+
#include <eosio/multi_index.hpp>
7+
8+
9+
10+
struct [[eosio::table]] out_of_class {
11+
uint64_t id;
12+
uint64_t primary_key() const { return id; }
13+
};
14+
typedef eosio::multi_index<"mi.config55"_n, out_of_class> out_of_class_index;
15+
using uout_of_class_index = eosio::multi_index<"mi.config551"_n, out_of_class>;
16+
17+
typedef eosio::singleton<"smpl.conf55"_n, eosio::name> smpl_config55;
18+
typedef eosio::singleton<"config55"_n, out_of_class> config55;
19+
typedef smpl_config55 smpl_config551;
20+
typedef config55 config551;
21+
using smpl_conf551 = eosio::singleton<"smpl.conf551"_n, eosio::name>;
22+
using config552 = eosio::singleton<"config552"_n, out_of_class>;
23+
using smpl_conf552 = smpl_conf551;
24+
using config553 = config551;
25+
26+
class [[eosio::contract("singleton_contract_simple2")]] singleton_contract_simple2 : public eosio::contract {
27+
public:
28+
using eosio::contract::contract;
29+
30+
[[eosio::action]]
31+
void whatever() {};
32+
33+
struct [[eosio::table]] inside_class {
34+
uint64_t id;
35+
uint64_t primary_key() const { return id; }
36+
};
37+
typedef eosio::singleton<"smpl.conf552"_n, eosio::name> smpl_conf552;
38+
typedef eosio::singleton<"config552"_n, inside_class> config552;
39+
typedef smpl_conf552 smpl_conf553;
40+
typedef config552 config553;
41+
using smpl_conf554 = eosio::singleton<"smpl.conf554"_n, eosio::name>;
42+
using config554 = eosio::singleton<"config554"_n, inside_class>;
43+
using smpl_conf555 = smpl_conf554;
44+
using config555 = config554;
45+
46+
47+
48+
typedef eosio::multi_index<"mi.config553"_n, inside_class> inside_class_index;
49+
using uinside_class_index = eosio::multi_index<"mi.config554"_n, inside_class>;
50+
};

tests/toolchain/abigen-pass/singleton_contract.abi

+21
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,27 @@
3737
"index_type": "i64",
3838
"key_names": [],
3939
"key_types": []
40+
},
41+
{
42+
"name": "config55",
43+
"type": "out_of_class",
44+
"index_type": "i64",
45+
"key_names": [],
46+
"key_types": []
47+
},
48+
{
49+
"name": "smpl.conf5",
50+
"type": "name",
51+
"index_type": "i64",
52+
"key_names": [],
53+
"key_types": []
54+
},
55+
{
56+
"name": "smpl.config",
57+
"type": "name",
58+
"index_type": "i64",
59+
"key_names": [],
60+
"key_types": []
4061
}
4162
],
4263
"ricardian_clauses": [],

tests/toolchain/abigen-pass/singleton_contract.cpp

+23-2
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,27 @@
22
#include <eosio/eosio.hpp>
33
#include <eosio/name.hpp>
44
#include <eosio/singleton.hpp>
5+
6+
#include "exclude_from_abi.hpp"
57

68
using namespace eosio;
7-
9+
10+
struct [[eosio::table]] out_of_class2 {
11+
uint64_t id;
12+
uint64_t primary_key() const { return id; }
13+
};
14+
typedef eosio::multi_index<"mi.config5"_n, out_of_class2> out_of_class_index51;
15+
using uout_of_class_index51 = eosio::multi_index<"mi.config51"_n, out_of_class2>;
16+
17+
typedef eosio::singleton<"smpl.conf5"_n, eosio::name> smpl_config5;
18+
typedef eosio::singleton<"config5"_n, out_of_class2> config5;
19+
typedef smpl_config5 smpl_config51;
20+
typedef config5 config51;
21+
using smpl_conf51 = eosio::singleton<"smpl.conf51"_n, eosio::name>;
22+
using config52 = eosio::singleton<"config52"_n, out_of_class2>;
23+
using smpl_conf52 = smpl_conf51;
24+
using config53 = config51;
25+
826
class [[eosio::contract("singleton_contract")]] singleton_contract : public contract {
927
public:
1028
using contract::contract;
@@ -17,5 +35,8 @@ class [[eosio::contract("singleton_contract")]] singleton_contract : public cont
1735
uint64_t x;
1836
};
1937

20-
typedef eosio::singleton<"config"_n, tbl_config> config;
38+
typedef eosio::singleton<"config"_n, tbl_config> config;
39+
typedef eosio::singleton<"smpl.config"_n, name> smpl_config;
40+
using smpl_config2 = smpl_config5;
41+
typedef config551 config2; //from exclude_from_abi.hpp
2142
};

tests/toolchain/abigen-pass/singleton_contract_simple.abi

-31
This file was deleted.

tests/toolchain/abigen-pass/singleton_contract_simple.cpp

-16
This file was deleted.

tests/toolchain/abigen-pass/singleton_contract_simple.json

-10
This file was deleted.

tools/include/eosio/abigen.hpp

+58-2
Original file line numberDiff line numberDiff line change
@@ -755,6 +755,7 @@ namespace eosio { namespace cdt {
755755
private:
756756
bool has_added_clauses = false;
757757
abigen& ag = abigen::get();
758+
const clang::CXXRecordDecl* contract_class = NULL;
758759

759760
public:
760761
explicit eosio_abigen_visitor(CompilerInstance *CI) {
@@ -799,10 +800,66 @@ namespace eosio { namespace cdt {
799800
}
800801
return true;
801802
}
803+
804+
const clang::CXXRecordDecl* find_contract_class(const clang::ASTContext &ctx) const {
805+
const auto* translation_unit = ctx.getTranslationUnitDecl();
806+
// scanning entire translation unit to find contract class
807+
for (const clang::Decl* cur_decl : translation_unit->decls()) {
808+
if (const auto* cxx_decl = llvm::dyn_cast<clang::CXXRecordDecl>(cur_decl)) {
809+
810+
if (cxx_decl->isEosioContract()) {
811+
auto attr_name = cxx_decl->getEosioContractAttr()->getName();
812+
auto name = attr_name.empty() ? cxx_decl->getName() : attr_name;
813+
if (name == llvm::StringRef(ag.get_contract_name()))
814+
return cxx_decl;
815+
}
816+
}
817+
}
818+
819+
return nullptr;
820+
}
821+
822+
bool is_same_type(const clang::Decl* decl1, const clang::CXXRecordDecl* decl2) const {
823+
if (!decl1 || !decl2)
824+
return false;
825+
if (decl1 == decl2)
826+
return true;
827+
828+
// checking if declaration is a typedef or using
829+
if (const clang::TypedefNameDecl* typedef_decl = llvm::dyn_cast<clang::TypedefNameDecl>(decl1)) {
830+
if (const auto* cur_type = typedef_decl->getUnderlyingType().getTypePtrOrNull()) {
831+
if (decl2 == cur_type->getAsCXXRecordDecl()) {
832+
return true;
833+
}
834+
}
835+
}
836+
837+
return false;
838+
}
839+
840+
bool defined_in_contract(const clang::ClassTemplateSpecializationDecl* decl) {
841+
842+
if (!contract_class) {
843+
contract_class = find_contract_class(decl->getASTContext());
844+
if (!contract_class) {
845+
// currently this is unreachable as we do not traverse non-main file translation units
846+
CDT_WARN("codegen_warning", decl->getLocation(), "contract class not found");
847+
return false;
848+
}
849+
}
850+
851+
for (const clang::Decl* cur_decl : contract_class->decls()) {
852+
if (is_same_type(cur_decl, decl))
853+
return true;
854+
}
855+
856+
return false;
857+
}
858+
802859
virtual bool VisitDecl(clang::Decl* decl) {
803860
if (const auto* d = dyn_cast<clang::ClassTemplateSpecializationDecl>(decl)) {
804861
bool is_singleton = d->getName() == "singleton";
805-
if (d->getName() == "multi_index" || is_singleton) {
862+
if ((d->getName() == "multi_index" || is_singleton) && defined_in_contract(d)) {
806863
ag.add_table(d->getTemplateArgs()[0].getAsIntegral().getExtValue(),
807864
d->getTemplateArgs()[1].getAsType().getTypePtr()->getAsCXXRecordDecl(), is_singleton);
808865
}
@@ -826,7 +883,6 @@ namespace eosio { namespace cdt {
826883
auto& f_mgr = src_mgr.getFileManager();
827884
auto main_fe = f_mgr.getFile(main_file);
828885
if (main_fe) {
829-
auto fid = src_mgr.getOrCreateFileID(f_mgr.getFile(main_file), SrcMgr::CharacteristicKind::C_User);
830886
visitor->TraverseDecl(Context.getTranslationUnitDecl());
831887
}
832888
}

tools/include/eosio/error_emitter.hpp

+5-3
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,8 @@ namespace eosio { namespace cdt {
6161
#define CDT_ERROR(e, l, s) \
6262
get_error_emitter().emit_error(l, get_error_emitter().diags.get(e), s);
6363

64-
#define CDT_INTERNAL_ERROR(s) \
65-
std::cerr << s << "\n"; \
66-
throw internal_error_ex;
64+
#define CDT_INTERNAL_ERROR(s) \
65+
do { \
66+
std::cerr << s << "\n"; \
67+
throw internal_error_ex; \
68+
} while (false)

tools/include/eosio/gen.hpp

+10-10
Original file line numberDiff line numberDiff line change
@@ -155,7 +155,7 @@ struct generation_utils {
155155

156156

157157
inline void set_contract_name( const std::string& cn ) { contract_name = cn; }
158-
inline std::string get_contract_name()const { return contract_name; }
158+
inline const std::string& get_contract_name()const { return contract_name; }
159159
static inline std::string get_parsed_contract_name() { return parsed_contract_name; }
160160
inline void set_resource_dirs( const std::vector<std::string>& rd ) {
161161
llvm::SmallString<128> cwd;
@@ -274,30 +274,30 @@ struct generation_utils {
274274
}
275275

276276
static inline bool is_eosio_contract( const clang::CXXMethodDecl* decl, const std::string& cn ) {
277-
std::string name = "";
277+
llvm::StringRef name;
278278
if (decl->isEosioContract())
279279
name = decl->getEosioContractAttr()->getName();
280280
else if (decl->getParent()->isEosioContract())
281281
name = decl->getParent()->getEosioContractAttr()->getName();
282282
if (name.empty()) {
283-
name = decl->getParent()->getName().str();
283+
name = decl->getParent()->getName();
284284
}
285-
parsed_contract_name = name;
285+
parsed_contract_name = name.str();
286286
return cn == parsed_contract_name;
287287
}
288288

289289
static inline bool is_eosio_contract( const clang::CXXRecordDecl* decl, const std::string& cn ) {
290-
std::string name = "";
290+
llvm::StringRef name;
291291
auto pd = llvm::dyn_cast<clang::CXXRecordDecl>(decl->getParent());
292292
if (decl->isEosioContract()) {
293-
auto nm = decl->getEosioContractAttr()->getName().str();
294-
name = nm.empty() ? decl->getName().str() : nm;
293+
auto nm = decl->getEosioContractAttr()->getName();
294+
name = nm.empty() ? decl->getName() : nm;
295295
}
296296
else if (pd && pd->isEosioContract()) {
297-
auto nm = pd->getEosioContractAttr()->getName().str();
298-
name = nm.empty() ? pd->getName().str() : nm;
297+
auto nm = pd->getEosioContractAttr()->getName();
298+
name = nm.empty() ? pd->getName() : nm;
299299
}
300-
parsed_contract_name = name;
300+
parsed_contract_name = name.str();
301301
return cn == parsed_contract_name;
302302
}
303303

0 commit comments

Comments
 (0)