@@ -243,13 +243,11 @@ namespace eosio { namespace cdt {
243
243
ctables.insert (t);
244
244
}
245
245
246
- void add_table ( uint64_t name, const clang::CXXRecordDecl* decl, bool force=false ) {
247
- if (force || decl->isEosioTable () && abigen::is_eosio_contract (decl, get_contract_name ())) {
248
- abi_table t;
249
- t.type = decl->getNameAsString ();
250
- t.name = name_to_string (name);
251
- _abi.tables .insert (t);
252
- }
246
+ void add_table ( uint64_t name, const clang::CXXRecordDecl* decl ) {
247
+ abi_table t;
248
+ t.type = decl->getNameAsString ();
249
+ t.name = name_to_string (name);
250
+ _abi.tables .insert (t);
253
251
}
254
252
255
253
void add_clauses ( const std::vector<std::pair<std::string, std::string>>& clauses ) {
@@ -755,6 +753,7 @@ namespace eosio { namespace cdt {
755
753
private:
756
754
bool has_added_clauses = false ;
757
755
abigen& ag = abigen::get();
756
+ const clang::CXXRecordDecl* contract_class = NULL ;
758
757
759
758
public:
760
759
explicit eosio_abigen_visitor (CompilerInstance *CI) {
@@ -799,18 +798,99 @@ namespace eosio { namespace cdt {
799
798
}
800
799
return true ;
801
800
}
801
+
802
+ bool is_same_type (const clang::Decl* decl1, const clang::CXXRecordDecl* decl2) const {
803
+ if (!decl1 || !decl2)
804
+ return false ;
805
+ if (decl1 == decl2)
806
+ return true ;
807
+
808
+ // checking if declaration is a typedef or using
809
+ if (const clang::TypedefNameDecl* typedef_decl = llvm::dyn_cast<clang::TypedefNameDecl>(decl1)) {
810
+ if (const auto * cur_type = typedef_decl->getUnderlyingType ().getTypePtrOrNull ()) {
811
+ if (decl2 == cur_type->getAsCXXRecordDecl ()) {
812
+ return true ;
813
+ }
814
+ }
815
+ }
816
+
817
+ return false ;
818
+ }
819
+
820
+ bool defined_in_contract (const clang::ClassTemplateSpecializationDecl* decl) {
821
+
822
+ if (!contract_class) {
823
+ // currently this is unreachable as we do not traverse non-main file translation units
824
+ CDT_WARN (" codegen_warning" , decl->getLocation (), " contract class not found: " + ag.get_contract_name ());
825
+ return false ;
826
+ }
827
+
828
+ for (const clang::Decl* cur_decl : contract_class->decls ()) {
829
+ if (is_same_type (cur_decl, decl))
830
+ return true ;
831
+ }
832
+
833
+ return false ;
834
+ }
835
+
802
836
virtual bool VisitDecl (clang::Decl* decl) {
803
837
if (const auto * d = dyn_cast<clang::ClassTemplateSpecializationDecl>(decl)) {
804
- bool is_singleton = d->getName () == " singleton" ;
805
- if (d->getName () == " multi_index" || is_singleton) {
806
- ag.add_table (d->getTemplateArgs ()[0 ].getAsIntegral ().getExtValue (),
807
- d->getTemplateArgs ()[1 ].getAsType ().getTypePtr ()->getAsCXXRecordDecl (), is_singleton);
838
+ if (d->getName () == " multi_index" || d->getName () == " singleton" ) {
839
+ // second template parameter is table type
840
+ const auto * table_type = d->getTemplateArgs ()[1 ].getAsType ().getTypePtr ()->getAsCXXRecordDecl ();
841
+ if ((table_type->isEosioTable () && ag.is_eosio_contract (table_type, ag.get_contract_name ())) || defined_in_contract (d)) {
842
+ // first parameter is table name
843
+ ag.add_table (d->getTemplateArgs ()[0 ].getAsIntegral ().getExtValue (), table_type);
844
+ if (table_type->isEosioTable ())
845
+ ag.add_struct (table_type);
846
+ }
808
847
}
809
848
}
810
849
return true ;
811
850
}
851
+ inline void set_contract_class (const CXXRecordDecl* decl) {
852
+ contract_class = decl;
853
+ }
812
854
};
855
+ class contract_class_finder : public RecursiveASTVisitor <contract_class_finder> {
856
+ private:
857
+ abigen& ag = abigen::get();
858
+ const clang::CXXRecordDecl* contract_class = nullptr ;
859
+ public:
860
+ virtual bool VisitCXXRecordDecl (clang::CXXRecordDecl* cxx_decl) {
861
+ if (cxx_decl->isEosioContract ()) {
862
+ bool is_eosio_contract = false ;
863
+ // on this point it could be just an attribute so let's check base classes
864
+ for (const auto & base : cxx_decl->bases ()) {
865
+ if (const clang::Type *base_type = base.getType ().getTypePtrOrNull ()) {
866
+ if (const auto * cur_cxx_decl = base_type->getAsCXXRecordDecl ()) {
867
+ if (cur_cxx_decl->getQualifiedNameAsString () == " eosio::contract" ) {
868
+ is_eosio_contract = true ;
869
+ break ;
870
+ }
871
+ }
872
+ }
873
+ }
874
+ if (!is_eosio_contract)
875
+ return true ;
876
+
877
+ auto attr_name = cxx_decl->getEosioContractAttr ()->getName ();
878
+ auto name = attr_name.empty () ? cxx_decl->getName () : attr_name;
879
+ if (name == llvm::StringRef (ag.get_contract_name ())) {
880
+ contract_class = cxx_decl;
881
+ return false ;
882
+ }
883
+ }
813
884
885
+ return true ;
886
+ }
887
+ inline bool contract_found () const {
888
+ return contract_class != nullptr ;
889
+ }
890
+ inline const clang::CXXRecordDecl* get_contract () const {
891
+ return contract_class;
892
+ }
893
+ };
814
894
class eosio_abigen_consumer : public ASTConsumer {
815
895
private:
816
896
eosio_abigen_visitor *visitor;
@@ -826,7 +906,10 @@ namespace eosio { namespace cdt {
826
906
auto & f_mgr = src_mgr.getFileManager ();
827
907
auto main_fe = f_mgr.getFile (main_file);
828
908
if (main_fe) {
829
- auto fid = src_mgr.getOrCreateFileID (f_mgr.getFile (main_file), SrcMgr::CharacteristicKind::C_User);
909
+ contract_class_finder cf;
910
+ cf.TraverseDecl (Context.getTranslationUnitDecl ());
911
+ if (cf.contract_found ())
912
+ visitor->set_contract_class (cf.get_contract ());
830
913
visitor->TraverseDecl (Context.getTranslationUnitDecl ());
831
914
}
832
915
}
0 commit comments