diff options
author | Boris Kolpackov <boris@codesynthesis.com> | 2012-10-25 10:35:36 +0200 |
---|---|---|
committer | Boris Kolpackov <boris@codesynthesis.com> | 2012-10-25 10:35:36 +0200 |
commit | d1ad30f7a517e69bc87d1347224f1c9ab38493b3 (patch) | |
tree | 95189ae91fcce6366f0a121f67b483f3c1b962e7 /odb/relational | |
parent | 7fc555e53f0a03c93fe31ad9850b1e5d885c44f6 (diff) |
Static multi-database support
Add new options (--multi-database, --default-database). Generate common
code to -odb.?xx files and database-specific to -odb-<db>.?xx.
Diffstat (limited to 'odb/relational')
-rw-r--r-- | odb/relational/common.hxx | 2 | ||||
-rw-r--r-- | odb/relational/header.cxx | 274 | ||||
-rw-r--r-- | odb/relational/header.hxx | 3 | ||||
-rw-r--r-- | odb/relational/inline.hxx | 180 | ||||
-rw-r--r-- | odb/relational/processor.cxx | 1102 | ||||
-rw-r--r-- | odb/relational/source.cxx | 4 | ||||
-rw-r--r-- | odb/relational/validator.cxx | 296 |
7 files changed, 351 insertions, 1510 deletions
diff --git a/odb/relational/common.hxx b/odb/relational/common.hxx index 26e8197..b951d15 100644 --- a/odb/relational/common.hxx +++ b/odb/relational/common.hxx @@ -336,7 +336,7 @@ namespace relational static B* create (B const& prototype) { - database db (context::current ().options.database ()); + database db (context::current ().options.database ()[0]); if (map_ != 0) { diff --git a/odb/relational/header.cxx b/odb/relational/header.cxx index c6fc9a5..1295106 100644 --- a/odb/relational/header.cxx +++ b/odb/relational/header.cxx @@ -13,15 +13,14 @@ traverse_object (type& c) using semantics::data_member; data_member* id (id_member (c)); - bool auto_id (id ? id->count ("auto") : false); - bool base_id (id ? &id->scope () != &c : false); // Comes from base. + bool auto_id (id && auto_ (*id)); + bool base_id (id && &id->scope () != &c); // Comes from base. data_member* optimistic (context::optimistic (c)); type* poly_root (polymorphic (c)); bool poly (poly_root != 0); bool poly_derived (poly && poly_root != &c); - type* poly_base (poly_derived ? &polymorphic_base (c) : 0); data_member* discriminator (poly ? context::discriminator (*poly_root) : 0); bool abst (abstract (c)); @@ -33,196 +32,6 @@ traverse_object (type& c) os << "// " << class_name (c) << endl << "//" << endl; - // class_traits - // - os << "template <>" << endl - << "struct class_traits< " << type << " >" - << "{" - << "static const class_kind kind = class_object;" - << "};"; - - // object_traits - // - os << "template <>" << endl - << "class access::object_traits< " << type << " >" - << "{" - << "public:" << endl; - - // object_type & pointer_type - // - os << "typedef " << type << " object_type;" - << "typedef " << c.get<string> ("object-pointer") << " pointer_type;" - << "typedef odb::pointer_traits<pointer_type> pointer_traits;" - << endl; - - // polymorphic, root_type, base_type, etc. - // - os << "static const bool polymorphic = " << (poly ? "true" : "false") << ";" - << endl; - - if (poly) - { - os << "typedef " << class_fq_name (*poly_root) << " root_type;"; - - if (poly_derived) - { - os << "typedef " << class_fq_name (*poly_base) << " base_type;" - << "typedef object_traits<root_type>::discriminator_type " << - "discriminator_type;" - << "typedef polymorphic_concrete_info<root_type> info_type;"; - - if (abst) - os << "typedef polymorphic_abstract_info<root_type> " << - "abstract_info_type;"; - - // Calculate our hierarchy depth (number of classes). - // - size_t depth (polymorphic_depth (c)); - - os << endl - << "static const std::size_t depth = " << depth << "UL;"; - } - else - { - semantics::names* hint; - semantics::type& t (utype (*discriminator, hint)); - - os << "typedef " << t.fq_name (hint) << " discriminator_type;" - << "typedef polymorphic_map<object_type> map_type;" - << "typedef polymorphic_concrete_info<object_type> info_type;"; - - if (abst) - os << "typedef polymorphic_abstract_info<object_type> " << - "abstract_info_type;"; - - os << endl - << "static const std::size_t depth = 1UL;"; - } - - os << endl; - } - - // id_type, version_type, etc. - // - if (id != 0) - { - if (base_id) - { - semantics::class_& b ( - dynamic_cast<semantics::class_&> (id->scope ())); - string const& type (class_fq_name (b)); - - os << "typedef object_traits< " << type << " >::id_type id_type;"; - - if (optimistic != 0) - os << "typedef object_traits< " << type << " >::version_type " << - "version_type;"; - - os << endl; - - if (poly_derived) - os << "static const bool auto_id = false;"; - else - os << "static const bool auto_id = object_traits< " << type << - " >::auto_id;"; - } - else - { - { - semantics::names* hint; - semantics::type& t (utype (*id, hint)); - os << "typedef " << t.fq_name (hint) << " id_type;"; - } - - if (optimistic != 0) - { - semantics::names* hint; - semantics::type& t (utype (*optimistic, hint)); - os << "typedef " << t.fq_name (hint) << " version_type;"; - } - - os << endl - << "static const bool auto_id = " << (auto_id ? "true;" : "false;"); - } - - os << endl; - } - else if (!reuse_abst) - { - // Object without id. - // - os << "typedef void id_type;" - << endl - << "static const bool auto_id = false;" - << endl; - } - - // abstract - // - os << "static const bool abstract = " << (abst ? "true" : "false") << ";" - << endl; - - // id () - // - if (id != 0 || !reuse_abst) - { - // We want to generate a dummy void id() accessor even if this - // object has no id to help us in the runtime. This way we can - // write generic code that will work for both void and non-void - // ids. - // - os << "static id_type" << endl - << "id (const object_type&);" - << endl; - } - - if (!reuse_abst) - { - // Cache traits typedefs. - // - if (id == 0) - { - os << "typedef" << endl - << "no_id_pointer_cache_traits<pointer_type>" << endl - << "pointer_cache_traits;" - << endl - << "typedef" << endl - << "no_id_reference_cache_traits<object_type>" << endl - << "reference_cache_traits;" - << endl; - } - else - { - char const* p (session (c) ? "odb::" : "no_op_"); - - if (poly_derived) - { - os << "typedef" << endl - << p << "pointer_cache_traits<" << - "object_traits<root_type>::pointer_type>" << endl - << "pointer_cache_traits;" - << endl - << "typedef" << endl - << p << "reference_cache_traits<root_type>" << endl - << "reference_cache_traits;" - << endl; - } - else - { - os << "typedef" << endl - << p << "pointer_cache_traits<pointer_type>" << endl - << "pointer_cache_traits;" - << endl - << "typedef" << endl - << p << "reference_cache_traits<object_type>" << endl - << "reference_cache_traits;" - << endl; - } - } - } - - os << "};"; - // pointer_query_columns & query_columns // if (options.generate_query ()) @@ -584,16 +393,6 @@ traverse_object (type& c) // Functions (concrete). // - // callback () - // - os << "static void" << endl - << "callback (database&, object_type&, callback_event);" - << endl; - - os << "static void" << endl - << "callback (database&, const object_type&, callback_event);" - << endl; - // persist () // os << "static void" << endl @@ -814,13 +613,17 @@ traverse_object (type& c) // // Note that it is not generated for reuse-abstract classes. // - os << "template <>" << endl - << "class access::object_traits_impl< " << type << ", " << - "id_default >:" << endl - << " public access::object_traits_impl< " << type << ", " << - "id_" << db << " >" - << "{" - << "};"; + if (options.default_database_specified () && + options.default_database () == db) + { + os << "template <>" << endl + << "class access::object_traits_impl< " << type << ", " << + "id_default >:" << endl + << " public access::object_traits_impl< " << type << ", " << + "id_" << db << " >" + << "{" + << "};"; + } } void relational::header::class1:: @@ -831,28 +634,6 @@ traverse_view (type& c) os << "// " << class_name (c) << endl << "//" << endl; - // class_traits - // - os << "template <>" << endl - << "struct class_traits< " << type << " >" - << "{" - << "static const class_kind kind = class_view;" - << "};"; - - // view_traits - // - os << "template <>" << endl - << "class access::view_traits< " << type << " >" - << "{" - << "public:" << endl; - - // view_type & pointer_type - // - os << "typedef " << type << " view_type;" - << "typedef " << c.get<string> ("object-pointer") << " pointer_type;"; - - os << "};"; - // view_traits_impl // os << "template <>" << endl @@ -933,12 +714,6 @@ traverse_view (type& c) // Functions. // - // callback () - // - os << "static void" << endl - << "callback (database&, view_type&, callback_event);" - << endl; - // query () // if (!options.omit_unprepared ()) @@ -963,12 +738,17 @@ traverse_view (type& c) // view_traits_impl< , id_default> // - os << "template <>" << endl - << "class access::view_traits_impl< " << type << ", id_default >:" << endl - << " public access::view_traits_impl< " << type << ", " << - "id_" << db << " >" - << "{" - << "};"; + if (options.default_database_specified () && + options.default_database () == db) + { + os << "template <>" << endl + << "class access::view_traits_impl< " << type << ", " << + "id_default >:" << endl + << " public access::view_traits_impl< " << type << ", " << + "id_" << db << " >" + << "{" + << "};"; + } } void relational::header::class1:: @@ -980,12 +760,6 @@ traverse_composite (type& c) << "//" << endl; os << "template <>" << endl - << "struct class_traits< " << type << " >" - << "{" - << "static const class_kind kind = class_composite;" - << "};"; - - os << "template <>" << endl << "class access::composite_value_traits< " << type << ", " << "id_" << db << " >" << "{" diff --git a/odb/relational/header.hxx b/odb/relational/header.hxx index 75cee16..c0e1e89 100644 --- a/odb/relational/header.hxx +++ b/odb/relational/header.hxx @@ -1233,8 +1233,7 @@ namespace relational virtual void generate () { - os << "#include <odb/details/buffer.hxx>" << endl - << "#include <odb/details/unused.hxx>" << endl; + os << "#include <odb/details/buffer.hxx>" << endl; if (options.generate_query ()) os << "#include <odb/details/shared-ptr.hxx>" << endl; diff --git a/odb/relational/inline.hxx b/odb/relational/inline.hxx index 7e70ab1..466e348 100644 --- a/odb/relational/inline.hxx +++ b/odb/relational/inline.hxx @@ -14,68 +14,6 @@ namespace relational namespace inline_ { // - // - struct callback_calls: traversal::class_, virtual context - { - typedef callback_calls base; - - callback_calls () - { - *this >> inherits_ >> *this; - } - - callback_calls (callback_calls const&) - : root_context (), //@@ -Wextra - context () - { - *this >> inherits_ >> *this; - } - - virtual void - traverse (type& c, bool constant) - { - const_ = constant; - traverse (c); - } - - virtual void - traverse (type& c) - { - bool obj (object (c)); - - // Ignore transient bases. - // - if (!(obj || view (c))) - return; - - if (c.count ("callback")) - { - string name (c.get<string> ("callback")); - - // In case of the const instance, we only generate the call if - // there is a const callback. - // - string const& type (class_fq_name (c)); - - if (const_) - { - if (c.count ("callback-const")) - os << "static_cast< const " << type << "& > (x)." << - name << " (e, db);"; - } - else - os << "static_cast< " << type << "& > (x)." << name << " (e, db);"; - } - else if (obj) - inherits (c); - } - - protected: - bool const_; - traversal::inherits inherits_; - }; - - // // get/set null (composite value only) // @@ -211,7 +149,7 @@ namespace relational if (object (c)) traverse_object (c); - if (view (c)) + else if (view (c)) traverse_view (c); else if (composite (c)) traverse_composite (c); @@ -228,11 +166,11 @@ namespace relational traverse_object (type& c) { semantics::data_member* id (id_member (c)); - bool base_id (id ? &id->scope () != &c : false); // Comes from base. + bool base_id (id && &id->scope () != &c); // Comes from base. semantics::data_member* optimistic (context::optimistic (c)); - // Base class the contains the object id and version for optimistic + // Base class that contains the object id and version for optimistic // concurrency. // type* base ( @@ -246,47 +184,13 @@ namespace relational bool reuse_abst (abst && !poly); string const& type (class_fq_name (c)); - string traits ("access::object_traits< " + type + " >"); - string traits_impl ("access::object_traits_impl< " + type + - ", id_" + db.string () + " >"); + string traits ("access::object_traits_impl< " + type + ", id_" + + db.string () + " >"); os << "// " << class_name (c) << endl << "//" << endl << endl; - // id (object_type) - // - if (id != 0 || !reuse_abst) - { - os << "inline" << endl - << traits << "::id_type" << endl - << traits << "::" << endl - << "id (const object_type&" << (id != 0 ? " o" : "") << ")" - << "{"; - - if (id != 0) - { - if (base_id) - os << "return object_traits< " << class_fq_name (*base) << - " >::id (o);"; - else - { - // Get the id using the accessor expression. If this is not - // a synthesized expression, then output its location for - // easier error tracking. - // - member_access& ma (id->get<member_access> ("get")); - - if (!ma.synthesized) - os << "// From " << location_string (ma.loc, true) << endl; - - os << "return " << ma.translate ("o") << ";"; - } - } - - os << "}"; - } - object_extra (c); if (id != 0 && base_id) @@ -298,8 +202,8 @@ namespace relational if (options.generate_query ()) { os << "inline" << endl - << traits_impl << "::id_type" << endl - << traits_impl << "::" << endl + << traits << "::id_type" << endl + << traits << "::" << endl << "id (const image_type& i)" << "{" << "return object_traits_impl< " << class_fq_name (*base) << @@ -312,8 +216,8 @@ namespace relational if (optimistic != 0) { os << "inline" << endl - << traits_impl << "::version_type" << endl - << traits_impl << "::" << endl + << traits << "::version_type" << endl + << traits << "::" << endl << "version (const image_type& i)" << "{" << "return object_traits_impl< " << class_fq_name (*base) << @@ -325,7 +229,7 @@ namespace relational // bind (id_image_type) // os << "inline" << endl - << "void " << traits_impl << "::" << endl + << "void " << traits << "::" << endl << "bind (" << bind_vector << " b, id_image_type& i" << (optimistic != 0 ? ", bool bv" : "") << ")" << "{" @@ -334,7 +238,7 @@ namespace relational << "}"; os << "inline" << endl - << "void " << traits_impl << "::" << endl + << "void " << traits << "::" << endl << "init (id_image_type& i, const id_type& id" << (optimistic != 0 ? ", const version_type* v" : "") << ")" << "{" @@ -350,7 +254,7 @@ namespace relational // check_version // os << "inline" << endl - << "bool " << traits_impl << "::" << endl + << "bool " << traits << "::" << endl << "check_version (const std::size_t* v, const image_type& i)" << "{" << "return "; @@ -370,7 +274,7 @@ namespace relational // update_version // os << "inline" << endl - << "void " << traits_impl << "::" << endl + << "void " << traits << "::" << endl << "update_version (std::size_t* v, const image_type& i, " << db << "::binding* b)" << "{"; @@ -394,7 +298,6 @@ namespace relational os << "}"; } - // // The rest does not apply to reuse-abstract objects. // if (reuse_abst) @@ -405,7 +308,7 @@ namespace relational if (id != 0 && !poly && optimistic == 0) { os << "inline" << endl - << "void " << traits_impl << "::" << endl + << "void " << traits << "::" << endl << "erase (database& db, const object_type& obj)" << "{" << "callback (db, obj, callback_event::pre_erase);" @@ -414,37 +317,12 @@ namespace relational << "}"; } - // callback () - // - os << "inline" << endl - << "void " << traits_impl << "::" << endl - << "callback (database& db, object_type& x, callback_event e)" - << endl - << "{" - << "ODB_POTENTIALLY_UNUSED (db);" - << "ODB_POTENTIALLY_UNUSED (x);" - << "ODB_POTENTIALLY_UNUSED (e);" - << endl; - callback_calls_->traverse (c, false); - os << "}"; - - os << "inline" << endl - << "void " << traits_impl << "::" << endl - << "callback (database& db, const object_type& x, callback_event e)" - << "{" - << "ODB_POTENTIALLY_UNUSED (db);" - << "ODB_POTENTIALLY_UNUSED (x);" - << "ODB_POTENTIALLY_UNUSED (e);" - << endl; - callback_calls_->traverse (c, true); - os << "}"; - // load_() // if (id != 0 && !(poly_derived || has_a (c, test_container))) { os << "inline" << endl - << "void " << traits_impl << "::" << endl + << "void " << traits << "::" << endl << "load_ ("; if (poly && !poly_derived) @@ -462,8 +340,8 @@ namespace relational // root_image () // os << "inline" << endl - << traits_impl << "::root_traits::image_type&" << endl - << traits_impl << "::" << endl + << traits << "::root_traits::image_type&" << endl + << traits << "::" << endl << "root_image (image_type& i)" << "{"; @@ -477,8 +355,8 @@ namespace relational // clone_image () // os << "inline" << endl - << traits_impl << "::image_type*" << endl - << traits_impl << "::" << endl + << traits << "::image_type*" << endl + << traits << "::" << endl << "clone_image (const image_type& i)" << "{"; @@ -496,7 +374,7 @@ namespace relational // copy_image () // os << "inline" << endl - << "void " << traits_impl << "::" << endl + << "void " << traits << "::" << endl << "copy_image (image_type& d, const image_type& s)" << "{"; @@ -513,7 +391,7 @@ namespace relational // free_image () // os << "inline" << endl - << "void " << traits_impl << "::" << endl + << "void " << traits << "::" << endl << "free_image (image_type* i)" << "{"; @@ -542,20 +420,6 @@ namespace relational << endl; view_extra (c); - - // callback () - // - os << "inline" << endl - << "void " << traits << "::" << endl - << "callback (database& db, view_type& x, callback_event e)" - << endl - << "{" - << "ODB_POTENTIALLY_UNUSED (db);" - << "ODB_POTENTIALLY_UNUSED (x);" - << "ODB_POTENTIALLY_UNUSED (e);" - << endl; - callback_calls_->traverse (c, false); - os << "}"; } virtual void @@ -604,8 +468,6 @@ namespace relational } private: - instance<callback_calls> callback_calls_; - instance<null_base> get_null_base_; traversal::inherits get_null_base_inherits_; instance<null_member> get_null_member_; diff --git a/odb/relational/processor.cxx b/odb/relational/processor.cxx index f000858..5100739 100644 --- a/odb/relational/processor.cxx +++ b/odb/relational/processor.cxx @@ -305,497 +305,14 @@ namespace relational throw operation_failed (); } - process_access (m, "get"); - process_access (m, "set"); - process_index (m); - } - - // - // Process member access expressions. - // - - enum found_type - { - found_none, - found_some, // Found something but keep looking for a better one. - found_best - }; - - // Check if a function is a suitable accessor for this member. - // - found_type - check_accessor (semantics::data_member& m, - tree f, - string const& n, - member_access& ma, - bool strict) - { - // Must be const. - // - if (!DECL_CONST_MEMFUNC_P (f)) - return found_none; - - // Accessor is a function with no arguments (other than 'this'). - // - if (DECL_CHAIN (DECL_ARGUMENTS (f)) != NULL_TREE) - return found_none; - - // Note that to get the return type we have to use - // TREE_TYPE(TREE_TYPE()) and not DECL_RESULT, as - // suggested in the documentation. - // - tree r (TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (f)))); - int tc (TREE_CODE (r)); - - // In the strict mode make sure the function returns for non-array - // types a value or a (const) reference to the member type and for - // array types a (const) pointer to element type. In the lax mode - // we just check that the return value is not void. - // - if (strict) - { - semantics::type& t (utype (m)); - semantics::array* ar (dynamic_cast<semantics::array*> (&t)); - - if (ar != 0 && tc != POINTER_TYPE) - return found_none; - - tree bt (ar != 0 || tc == REFERENCE_TYPE ? TREE_TYPE (r) : r); - tree bt_mv (TYPE_MAIN_VARIANT (bt)); - - if ((ar != 0 ? ar->base_type () : t).tree_node () != bt_mv) - return found_none; - } - else if (r == void_type_node) - return found_none; - - cxx_tokens& e (ma.expr); - e.push_back (cxx_token (0, CPP_KEYWORD, "this")); - e.push_back (cxx_token (0, CPP_DOT)); - e.push_back (cxx_token (0, CPP_NAME, n)); - e.push_back (cxx_token (0, CPP_OPEN_PAREN, n)); - e.push_back (cxx_token (0, CPP_CLOSE_PAREN, n)); - - // See if it returns by value. - // - ma.by_value = (tc != REFERENCE_TYPE && tc != POINTER_TYPE); - - return found_best; - } - - // Check if a function is a suitable modifier for this member. - // - found_type - check_modifier (semantics::data_member& m, - tree f, - string const& n, - member_access& ma, - bool strict) - { - tree a (DECL_ARGUMENTS (f)); - a = DECL_CHAIN (a); // Skip this. - - // For a modifier, it can either be a function that returns a non- - // const reference (or non-const pointer, in case the member is an - // array) or a by-value modifier that sets a new value. If both are - // available, we prefer the former for efficiency. - // - cxx_tokens& e (ma.expr); - semantics::type& t (utype (m)); - semantics::array* ar (dynamic_cast<semantics::array*> (&t)); - - if (a == NULL_TREE) + if (m.count ("polymorphic-ref")) { - // Note that to get the return type we have to use - // TREE_TYPE(TREE_TYPE()) and not DECL_RESULT, as - // suggested in the documentation. - // - tree r (TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (f)))); - int tc (TREE_CODE (r)); - - // By-reference modifier. Should return a reference or a pointer. - // - if (tc != (ar != 0 ? POINTER_TYPE : REFERENCE_TYPE)) - return found_none; - - // The base type should not be const and, in strict mode, should - // match the member type. - // - tree bt (TREE_TYPE (r)); - - if (CP_TYPE_CONST_P (bt)) - return found_none; - - tree bt_mv (TYPE_MAIN_VARIANT (bt)); - - if (strict && (ar != 0 ? ar->base_type () : t).tree_node () != bt_mv) - return found_none; - - e.clear (); // Could contain by value modifier. - e.push_back (cxx_token (0, CPP_KEYWORD, "this")); - e.push_back (cxx_token (0, CPP_DOT)); - e.push_back (cxx_token (0, CPP_NAME, n)); - e.push_back (cxx_token (0, CPP_OPEN_PAREN, n)); - e.push_back (cxx_token (0, CPP_CLOSE_PAREN, n)); - - return found_best; + m.set ("not-null", true); + m.set ("deferred", false); + m.set ("on-delete", sema_rel::foreign_key::cascade); } - // Otherwise look for a by value modifier, which is a function - // with a single argument. - // - else if (DECL_CHAIN (a) == NULL_TREE) - { - // In the lax mode any function with a single argument works - // for us. And we don't care what it returns. - // - if (strict) - { - // In the strict mode make sure the argument matches the - // member. This is exactly the same logic as in accessor - // with regards to arrays, references, etc. - // - tree at (TREE_TYPE (a)); - int tc (TREE_CODE (at)); - - if (ar != 0 && tc != POINTER_TYPE) - return found_none; - - tree bt (ar != 0 || tc == REFERENCE_TYPE ? TREE_TYPE (at) : at); - tree bt_mv (TYPE_MAIN_VARIANT (bt)); - - if ((ar != 0 ? ar->base_type () : t).tree_node () != bt_mv) - return found_none; - } - - if (e.empty ()) - { - e.push_back (cxx_token (0, CPP_KEYWORD, "this")); - e.push_back (cxx_token (0, CPP_DOT)); - e.push_back (cxx_token (0, CPP_NAME, n)); - e.push_back (cxx_token (0, CPP_OPEN_PAREN, n)); - e.push_back (cxx_token (0, CPP_QUERY)); - e.push_back (cxx_token (0, CPP_CLOSE_PAREN, n)); - - // Continue searching in case there is version that returns a - // non-const reference which we prefer for efficiency. - // - return found_some; - } - else - return found_none; // We didn't find anything better. - } - - return found_none; - } - - void - process_access (semantics::data_member& m, std::string const& k) - { - bool virt (m.count ("virtual")); - - // Ignore certain special virtual members. - // - if (virt && (m.count ("polymorphic-ref") || m.count ("discriminator"))) - return; - - char const* kind (k == "get" ? "accessor" : "modifier"); - semantics::class_& c (dynamic_cast<semantics::class_&> (m.scope ())); - - // If we don't have an access expression, try to come up with - // one. - // - if (!m.count (k)) - { - found_type found (found_none); - semantics::access const& a (m.named ().access ()); - member_access& ma (m.set (k, member_access (m.location (), true))); - - // If this member is not virtual and is either public or if we - // are a friend of this class, then go for the member directly. - // - if (!virt && (a == semantics::access::public_ || - c.get<bool> ("friend"))) - { - ma.expr.push_back (cxx_token (0, CPP_KEYWORD, "this")); - ma.expr.push_back (cxx_token (0, CPP_DOT)); - ma.expr.push_back (cxx_token (0, CPP_NAME, m.name ())); - found = found_best; - } - - // Otherwise, try to find a suitable accessor/modifier. - // - - // First try the original name. If that doesn't produce anything, - // then try the public name. - // - bool t (k == "get" - ? options.accessor_regex_trace () - : options.modifier_regex_trace ()); - regex_mapping const& re ( - k == "get" ? accessor_regex : modifier_regex); - - for (unsigned short j (0); found != found_best && j != 2; ++j) - { - string b (j == 0 ? m.name () : public_name (m, false)); - - // Skip the second pass if original and public names are the same. - // - if (j == 1 && b == m.name ()) - continue; - - if (t) - cerr << kind << (j == 0 ? " original" : " public") - << " name '" << b << "'" << endl; - - for (regex_mapping::const_iterator i (re.begin ()); - found != found_best && i != re.end (); - ++i) - { - if (t) - cerr << "try: '" << i->regex () << "' : "; - - if (!i->match (b)) - { - if (t) - cerr << '-' << endl; - continue; - } - - string n (i->replace (b)); - - if (t) - cerr << "'" << n << "' : "; - - tree decl ( - lookup_qualified_name ( - c.tree_node (), get_identifier (n.c_str ()), false, false)); - - if (decl == error_mark_node || TREE_CODE (decl) != BASELINK) - { - if (t) - cerr << '-' << endl; - continue; - } - - // OVL_* macros work for both FUNCTION_DECL and OVERLOAD. - // - for (tree o (BASELINK_FUNCTIONS (decl)); - o != 0; - o = OVL_NEXT (o)) - { - tree f (OVL_CURRENT (o)); - - // We are only interested in public non-static member - // functions. Note that TREE_PUBLIC() returns something - // other than what we need. - // - if (!DECL_NONSTATIC_MEMBER_FUNCTION_P (f) || - TREE_PRIVATE (f) || TREE_PROTECTED (f)) - continue; - - found_type r (k == "get" - ? check_accessor (m, f, n, ma, true) - : check_modifier (m, f, n, ma, true)); - - if (r != found_none) - { - // Update the location of the access expression to point - // to this function. - // - ma.loc = location (DECL_SOURCE_LOCATION (f)); - found = r; - } - } - - if (t) - cerr << (found != found_none ? '+' : '-') << endl; - } - } - - // If that didn't work then the generated code won't be able - // to access this member. - // - if (found == found_none) - { - location const& l (m.location ()); - - if (virt) - { - error (l) << "no suitable " << kind << " function could be " - << "automatically found for virtual data member '" - << m.name () << "'" << endl; - - info (l) << "use '#pragma db " << k << "' to explicitly " - << "specify the " << kind << " function or " - << "expression" << endl; - } - else - { - error (l) << "data member '" << m.name () << "' is " - << a.string () << " and no suitable " << kind - << " function could be automatically found" << endl; - info (l) << "consider making class 'odb::access' a friend of " - << "class '" << class_name (c) << "'" << endl; - - info (l) << "or use '#pragma db " << k << "' to explicitly " - << "specify the " << kind << " function or " - << "expression" << endl; - } - - throw operation_failed (); - } - } - - member_access& ma (m.get<member_access> (k)); - cxx_tokens& e (ma.expr); - - // If it is just a name, resolve it and convert to an appropriate - // expression. - // - if (e.size () == 1 && e.back ().type == CPP_NAME) - { - string n (e.back ().literal); - e.clear (); - - tree decl ( - lookup_qualified_name ( - c.tree_node (), get_identifier (n.c_str ()), false, false)); - - if (decl == error_mark_node) - { - error (ma.loc) << "unable to resolve data member or function " - << "name '" << n << "'" << endl; - throw operation_failed (); - } - - switch (TREE_CODE (decl)) - { - case FIELD_DECL: - { - e.push_back (cxx_token (0, CPP_KEYWORD, "this")); - e.push_back (cxx_token (0, CPP_DOT)); - e.push_back (cxx_token (0, CPP_NAME, n)); - break; - } - case BASELINK: - { - // OVL_* macros work for both FUNCTION_DECL and OVERLOAD. - // - for (tree o (BASELINK_FUNCTIONS (decl)); - o != 0; - o = OVL_NEXT (o)) - { - tree f (OVL_CURRENT (o)); - - // We are only interested in non-static member functions. - // - if (!DECL_NONSTATIC_MEMBER_FUNCTION_P (f)) - continue; - - if ((k == "get" - ? check_accessor (m, f, n, ma, false) - : check_modifier (m, f, n, ma, false)) == found_best) - break; - } - - if (e.empty ()) - { - error (ma.loc) << "unable to find suitable " << kind - << " function '" << n << "'" << endl; - throw operation_failed (); - } - break; - } - default: - { - error (ma.loc) << "name '" << n << "' does not refer to a data " - << "member or function" << endl; - throw operation_failed (); - } - } - } - - // If there is no 'this' keyword, then add it as a prefix. - // - { - bool t (false); - for (cxx_tokens::iterator i (e.begin ()); i != e.end (); ++i) - { - if (i->type == CPP_KEYWORD && i->literal == "this") - { - t = true; - break; - } - } - - if (!t) - { - e.insert (e.begin (), cxx_token (0, CPP_DOT)); - e.insert (e.begin (), cxx_token (0, CPP_KEYWORD, "this")); - } - } - - // Check that there is no placeholder in the accessor expression. - // - if (k == "get" && ma.placeholder ()) - { - error (ma.loc) << "(?) placeholder in the accessor expression" - << endl; - throw operation_failed (); - } - - // Check that the member type is default-constructible if we - // have a by value modifier. - // - if (k == "set" && ma.placeholder ()) - { - semantics::class_* c (dynamic_cast<semantics::class_*> (&utype (m))); - - // Assume all other types are default-constructible. - // - if (c != 0) - { - // If this type is a class template instantiation, then make - // sure it is instantiated. While types used in real members - // will be instantiated, this is not necessarily the case for - // virtual members. Without the instantiation we won't be able - // to detect whether the type has the default ctor. - // - // It would have been cleaner to do it in post_process_pragmas() - // but there we don't yet know whether we need the default ctor. - // And it is a good idea not to require instantiability unless - // we really need it. - // - tree type (c->tree_node ()); - - if (!COMPLETE_TYPE_P (type) && - CLASSTYPE_TEMPLATE_INSTANTIATION (type)) - { - // Reset input location so that we get nice diagnostics in - // case of an error. Use the location of the virtual pragma. - // - location_t loc (m.get<location_t> ("virtual-location")); - input_location = loc; - - if (instantiate_class_template (type) == error_mark_node || - errorcount != 0 || - !COMPLETE_TYPE_P (type)) - { - error (loc) << "unable to instantiate virtual data member " << - "type" << endl; - throw operation_failed (); - } - } - - if (!c->default_ctor ()) - { - error (ma.loc) << "modifier expression requires member type " << - "to be default-constructible" << endl; - throw operation_failed (); - } - } - } + process_index (m); } // Convert index/unique specifiers to the index entry in the object. @@ -2351,44 +1868,7 @@ namespace relational struct class_: traversal::class_, context { class_ () - : std_string_ (0), std_string_hint_ (0), access_ (0) { - // Resolve the std::string type node. - // - using semantics::scope; - - for (scope::names_iterator_pair ip (unit.find ("std")); - ip.first != ip.second; ++ip.first) - { - if (scope* ns = dynamic_cast<scope*> (&ip.first->named ())) - { - scope::names_iterator_pair jp (ns->find ("string")); - - if (jp.first != jp.second) - { - std_string_ = dynamic_cast<semantics::type*> ( - &jp.first->named ()); - std_string_hint_ = &*jp.first; - break; - } - } - } - - assert (std_string_ != 0); // No std::string? - - // Resolve odb::access, if any. - // - tree odb = lookup_qualified_name ( - global_namespace, get_identifier ("odb"), false, false); - - if (odb != error_mark_node) - { - access_ = lookup_qualified_name ( - odb, get_identifier ("access"), true, false); - - access_ = (access_ != error_mark_node ? TREE_TYPE (access_) : 0); - } - *this >> member_names_ >> member_; } @@ -2400,28 +1880,12 @@ namespace relational if (k == class_other) return; - // Check if odb::access is a friend of this class. - // - c.set ("friend", access_ != 0 && is_friend (c.tree_node (), access_)); - - // Assign pointer. - // - if (k == class_object || k == class_view) - assign_pointer (c); - - // Do some additional pre-processing. - // - if (k == class_object) - traverse_object_pre (c); - names (c); - // Do some additional post-processing. - // if (k == class_object) - traverse_object_post (c); + traverse_object (c); else if (k == class_view) - traverse_view_post (c); + traverse_view (c); } // @@ -2429,149 +1893,7 @@ namespace relational // virtual void - traverse_object_pre (type& c) - { - semantics::class_* poly_root (polymorphic (c)); - - // Determine whether it is a session object. - // - if (!c.count ("session")) - { - // If this is a derived class in a polymorphic hierarchy, - // then it should have the same session value as the root. - // - if (poly_root != 0 && poly_root != &c) - c.set ("session", session (*poly_root)); - else - { - // See if any of the namespaces containing this class specify - // the session value. - // - bool found (false); - for (semantics::scope* s (&c.scope ());; s = &s->scope_ ()) - { - using semantics::namespace_; - - namespace_* ns (dynamic_cast<namespace_*> (s)); - - if (ns == 0) - continue; // Some other scope. - - if (ns->extension ()) - ns = &ns->original (); - - if (ns->count ("session")) - { - c.set ("session", ns->get<bool> ("session")); - found = true; - break; - } - - if (ns->global_scope ()) - break; - } - - // If still not found, then use the default value. - // - if (!found) - c.set ("session", options.generate_session ()); - } - } - - if (session (c)) - features.session_object = true; - - if (poly_root != 0) - { - using namespace semantics; - - semantics::data_member& idm (*id_member (*poly_root)); - - if (poly_root != &c) - { - // If we are a derived class in the polymorphic persistent - // class hierarchy, then add a synthesized virtual pointer - // member that points back to the root. - // - path const& f (idm.file ()); - size_t l (idm.line ()), col (idm.column ()); - - semantics::data_member& m ( - unit.new_node<semantics::data_member> (f, l, col, tree (0))); - m.set ("virtual", true); - - // Make it the first member in the class. - // - node_position<type, scope::names_iterator> np (c, c.names_end ()); - unit.new_edge<semantics::names> ( - np, m, idm.name (), access::public_); - - // Use the raw pointer as this member's type. - // - if (!poly_root->pointed_p ()) - { - // Create the pointer type in the graph. The pointer node - // in GCC seems to always be present, even if not explicitly - // used in the translation unit. - // - tree t (poly_root->tree_node ()); - tree ptr (TYPE_POINTER_TO (t)); - assert (ptr != 0); - ptr = TYPE_MAIN_VARIANT (ptr); - pointer& p (unit.new_node<pointer> (f, l, col, ptr)); - unit.insert (ptr, p); - unit.new_edge<points> (p, *poly_root); - assert (poly_root->pointed_p ()); - } - - unit.new_edge<belongs> (m, poly_root->pointed ().pointer ()); - - m.set ("not-null", true); - m.set ("deferred", false); - m.set ("on-delete", sema_rel::foreign_key::cascade); - - // Mark it as a special kind of id. - // - m.set ("id", true); - m.set ("polymorphic-ref", true); - } - else - { - // If we are a root of the polymorphic persistent class hierarchy, - // then add a synthesized virtual member for the discriminator. - // Use the location of the polymorphic pragma as the location of - // this member. - // - location_t loc (c.get<location_t> ("polymorphic-location")); - semantics::data_member& m ( - unit.new_node<semantics::data_member> ( - path (LOCATION_FILE (loc)), - LOCATION_LINE (loc), - LOCATION_COLUMN (loc), - tree (0))); - m.set ("virtual", true); - - // Insert it after the id member (or first if this id comes - // from reuse-base). - // - node_position<type, scope::names_iterator> np ( - c, c.find (idm.named ())); - unit.new_edge<semantics::names> ( - np, m, "typeid_", access::public_); - - belongs& edge (unit.new_edge<belongs> (m, *std_string_)); - edge.hint (*std_string_hint_); - - m.set ("readonly", true); - m.set ("discriminator", true); - - c.set ("discriminator", &m); - } - } - } - - virtual void - traverse_object_post (type& c) + traverse_object (type& c) { // Process indexes. Here we need to do two things: resolve member // names to member paths and assign names to unnamed indexes. We @@ -2767,7 +2089,7 @@ namespace relational typedef vector<relationship> relationships; virtual void - traverse_view_post (type& c) + traverse_view (type& c) { bool has_q (c.count ("query")); bool has_o (c.count ("objects")); @@ -3154,417 +2476,11 @@ namespace relational view_object& pointee_; }; - void - assign_pointer (type& c) - { - location_t loc (0); // Pragma location, or 0 if not used. - - try - { - string ptr; - string const& type (class_fq_name (c)); - - tree decl (0); // Resolved template node. - string decl_name; // User-provided template name. - tree resolve_scope (0); // Scope in which we resolve names. - - class_pointer const* cp (0); - bool cp_template (false); - - if (c.count ("pointer")) - { - cp = &c.get<class_pointer> ("pointer"); - } - // If we are a derived type in polymorphic hierarchy, then use - // our root's pointer type by default. - // - else if (semantics::class_* r = polymorphic (c)) - { - if (&c != r && r->count ("pointer-template")) - cp = r->get<class_pointer const*> ("pointer-template"); - } - - if (cp != 0) - { - string const& p (cp->name); - - if (p == "*") - { - ptr = type + "*"; - cp_template = true; - } - else if (p[p.size () - 1] == '*') - ptr = p; - else if (p.find ('<') != string::npos) - { - // Template-id. - // - ptr = p; - decl_name.assign (p, 0, p.find ('<')); - } - else - { - // This is not a template-id. Resolve it and see if it is a - // template or a type. - // - decl = resolve_name (p, cp->scope, true); - int tc (TREE_CODE (decl)); - - if (tc == TYPE_DECL) - { - ptr = p; - - // This can be a typedef'ed alias for a TR1 template-id. - // - if (tree ti = TYPE_TEMPLATE_INFO (TREE_TYPE (decl))) - { - decl = TI_TEMPLATE (ti); // DECL_TEMPLATE - - // Get to the most general template declaration. - // - while (DECL_TEMPLATE_INFO (decl)) - decl = DECL_TI_TEMPLATE (decl); - } - else - decl = 0; // Not a template. - } - else if (tc == TEMPLATE_DECL && DECL_CLASS_TEMPLATE_P (decl)) - { - ptr = p + "< " + type + " >"; - decl_name = p; - cp_template = true; - } - else - { - error (cp->loc) - << "name '" << p << "' specified with db pragma pointer " - << "does not name a type or a template" << endl; - - throw operation_failed (); - } - } - - // Resolve scope is the scope of the pragma. - // - resolve_scope = cp->scope; - loc = cp->loc; - } - else - { - // See if any of the namespaces containing this class specify - // a pointer. - // - for (semantics::scope* s (&c.scope ());; s = &s->scope_ ()) - { - using semantics::namespace_; - - namespace_* ns (dynamic_cast<namespace_*> (s)); - - if (ns == 0) - continue; // Some other scope. - - if (ns->extension ()) - ns = &ns->original (); - - if (!ns->count ("pointer")) - { - if (ns->global_scope ()) - break; - else - continue; - } - - cp = &ns->get<class_pointer> ("pointer"); - string const& p (cp->name); - - // Namespace-specified pointer can only be '*' or are template. - // - if (p == "*") - ptr = type + "*"; - else if (p[p.size () - 1] == '*') - { - error (cp->loc) - << "name '" << p << "' specified with db pragma pointer " - << "at namespace level cannot be a raw pointer" << endl; - } - else if (p.find ('<') != string::npos) - { - error (cp->loc) - << "name '" << p << "' specified with db pragma pointer " - << "at namespace level cannot be a template-id" << endl; - } - else - { - // Resolve this name and make sure it is a template. - // - decl = resolve_name (p, cp->scope, true); - int tc (TREE_CODE (decl)); - - if (tc == TEMPLATE_DECL && DECL_CLASS_TEMPLATE_P (decl)) - { - ptr = p + "< " + type + " >"; - decl_name = p; - } - else - { - error (cp->loc) - << "name '" << p << "' specified with db pragma pointer " - << "does not name a template" << endl; - } - } - - if (ptr.empty ()) - throw operation_failed (); - - cp_template = true; - - // Resolve scope is the scope of the pragma. - // - resolve_scope = cp->scope; - loc = cp->loc; - break; - } - - // Use the default pointer. - // - if (ptr.empty ()) - { - string const& p (options.default_pointer ()); - - if (p == "*") - ptr = type + "*"; - else - { - ptr = p + "< " + type + " >"; - decl_name = p; - } - - // Resolve scope is the scope of the class. - // - resolve_scope = c.scope ().tree_node (); - } - } - - // If this class is a root of a polymorphic hierarchy, then cache - // the pointer template so that we can use it for derived classes. - // - if (cp != 0 && cp_template && polymorphic (c) == &c) - c.set ("pointer-template", cp); - - // Check if we are using TR1. - // - if (decl != 0 || !decl_name.empty ()) - { - bool& tr1 (features.tr1_pointer); - bool& boost (features.boost_pointer); - - // First check the user-supplied name. - // - tr1 = tr1 - || decl_name.compare (0, 8, "std::tr1") == 0 - || decl_name.compare (0, 10, "::std::tr1") == 0; - - // If there was no match, also resolve the name since it can be - // a using-declaration for a TR1 template. - // - if (!tr1) - { - if (decl == 0) - decl = resolve_name (decl_name, resolve_scope, false); - - if (TREE_CODE (decl) != TEMPLATE_DECL || ! - DECL_CLASS_TEMPLATE_P (decl)) - { - // This is only checked for the --default-pointer option. - // - error (c.file (), c.line (), c.column ()) - << "name '" << decl_name << "' specified with the " - << "--default-pointer option does not name a class " - << "template" << endl; - - throw operation_failed (); - } - - string n (decl_as_string (decl, TFF_PLAIN_IDENTIFIER)); - - // In case of a boost TR1 implementation, we cannot distinguish - // between the boost:: and std::tr1:: usage since the latter is - // just a using-declaration for the former. - // - tr1 = tr1 - || n.compare (0, 8, "std::tr1") == 0 - || n.compare (0, 10, "::std::tr1") == 0; - - boost = boost - || n.compare (0, 17, "boost::shared_ptr") == 0 - || n.compare (0, 19, "::boost::shared_ptr") == 0; - } - } - - // Fully-qualify all the unqualified components of the name. - // - try - { - lex_.start (ptr); - ptr.clear (); - - string t; - bool punc (false); - bool scoped (false); - - for (cpp_ttype tt (lex_.next (t)); - tt != CPP_EOF; - tt = lex_.next (t)) - { - if (punc && tt > CPP_LAST_PUNCTUATOR) - ptr += ' '; - - punc = false; - - switch (static_cast<unsigned> (tt)) - { - case CPP_LESS: - { - ptr += "< "; - break; - } - case CPP_GREATER: - { - ptr += " >"; - break; - } - case CPP_COMMA: - { - ptr += ", "; - break; - } - case CPP_NAME: - { - // If the name was not preceeded with '::', look it - // up in the pragmas's scope and add the qualifer. - // - if (!scoped) - { - tree decl (resolve_name (t, resolve_scope, false)); - tree scope (CP_DECL_CONTEXT (decl)); - - if (scope != global_namespace) - { - ptr += "::"; - ptr += decl_as_string (scope, TFF_PLAIN_IDENTIFIER); - } - - ptr += "::"; - } - - ptr += t; - punc = true; - break; - } - case CPP_KEYWORD: - case CPP_NUMBER: - { - ptr += t; - punc = true; - break; - } - default: - { - ptr += t; - break; - } - } - - scoped = (tt == CPP_SCOPE); - } - } - catch (cxx_lexer::invalid_input const&) - { - throw operation_failed (); - } - - c.set ("object-pointer", ptr); - } - catch (invalid_name const& ex) - { - if (loc != 0) - error (loc) - << "name '" << ex.name () << "' specified with db pragma " - << "pointer is invalid" << endl; - else - error (c.file (), c.line (), c.column ()) - << "name '" << ex.name () << "' specified with the " - << "--default-pointer option is invalid" << endl; - - - throw operation_failed (); - } - catch (unable_to_resolve const& ex) - { - if (loc != 0) - error (loc) - << "unable to resolve name '" << ex.name () << "' specified " - << "with db pragma pointer" << endl; - else - error (c.file (), c.line (), c.column ()) - << "unable to resolve name '" << ex.name () << "' specified " - << "with the --default-pointer option" << endl; - - throw operation_failed (); - } - } - - private: - struct invalid_name - { - invalid_name (string const& n): name_ (n) {} - - string const& - name () const {return name_;} - - private: - string name_; - }; - - typedef lookup::unable_to_resolve unable_to_resolve; - - tree - resolve_name (string const& qn, tree scope, bool is_type) - { - try - { - string tl; - tree tn; - cpp_ttype tt, ptt; - - nlex_.start (qn); - tt = nlex_.next (tl, &tn); - - string name; - return lookup::resolve_scoped_name ( - nlex_, tt, tl, tn, ptt, scope, name, is_type); - } - catch (cxx_lexer::invalid_input const&) - { - throw invalid_name (qn); - } - catch (lookup::invalid_name const&) - { - throw invalid_name (qn); - } - } - private: cxx_string_lexer lex_; - cxx_string_lexer nlex_; // Nested lexer. data_member member_; traversal::names member_names_; - - semantics::type* std_string_; - semantics::names* std_string_hint_; - - tree access_; // odb::access node. }; } diff --git a/odb/relational/source.cxx b/odb/relational/source.cxx index 4d56655..7516801 100644 --- a/odb/relational/source.cxx +++ b/odb/relational/source.cxx @@ -18,8 +18,8 @@ traverse_object (type& c) using semantics::data_member; data_member* id (id_member (c)); - bool auto_id (id ? id->count ("auto") : false); - bool base_id (id ? &id->scope () != &c : false); // Comes from base. + bool auto_id (id && auto_ (*id)); + bool base_id (id && &id->scope () != &c); // Comes from base. member_access* id_ma (id ? &id->get<member_access> ("get") : 0); bool has_ptr (has_a (c, test_pointer)); diff --git a/odb/relational/validator.cxx b/odb/relational/validator.cxx index 1269406..9d14571 100644 --- a/odb/relational/validator.cxx +++ b/odb/relational/validator.cxx @@ -21,11 +21,228 @@ namespace relational // Pass 2. // + struct data_member2: traversal::data_member, context + { + data_member2 (bool& valid) + : valid_ (valid) + { + } + + virtual void + traverse (type& m) + { + if (transient (m)) + return; + + if (null (m)) + { + if (semantics::class_* c = composite_wrapper (utype (m))) + { + if (has_a (*c, test_container)) + { + os << m.file () << ":" << m.line () << ":" << m.column () << ":" + << " error: composite member containing containers cannot " + << "be null" << endl; + + os << c->file () << ":" << c->line () << ":" << c->column () + << ": info: composite value type is defined here" << endl; + + valid_ = false; + } + } + } + } + + bool& valid_; + }; + + struct object_no_id_members: object_members_base + { + object_no_id_members (bool& valid) + : object_members_base (false, false, true), valid_ (valid), dm_ (0) + { + } + + virtual void + traverse_pointer (semantics::data_member& m, semantics::class_&) + { + if (inverse (m)) + { + semantics::data_member& dm (dm_ != 0 ? *dm_ : m); + + os << dm.file () << ":" << dm.line () << ":" << dm.column () << ":" + << " error: inverse object pointer member '" << member_prefix_ + << m.name () << "' in an object without an object id" << endl; + + valid_ = false; + } + } + + virtual void + traverse_container (semantics::data_member& m, semantics::type&) + { + semantics::data_member& dm (dm_ != 0 ? *dm_ : m); + + os << dm.file () << ":" << dm.line () << ":" << dm.column () << ":" + << " error: container member '" << member_prefix_ << m.name () + << "' in an object without an object id" << endl; + + valid_ = false; + } + + virtual void + traverse_composite (semantics::data_member* m, semantics::class_& c) + { + semantics::data_member* old_dm (dm_); + + if (dm_ == 0) + dm_ = m; + + object_members_base::traverse_composite (m, c); + + dm_ = old_dm; + } + + private: + bool& valid_; + semantics::data_member* dm_; // Direct object data member. + }; + + struct composite_id_members: object_members_base + { + composite_id_members (bool& valid) + : object_members_base (false, false, true), valid_ (valid), dm_ (0) + { + } + + virtual void + traverse_pointer (semantics::data_member& m, semantics::class_&) + { + semantics::data_member& dm (dm_ != 0 ? *dm_ : m); + + os << dm.file () << ":" << dm.line () << ":" << dm.column () << ":" + << " error: object pointer member '" << member_prefix_ << m.name () + << "' in a composite value type that is used as an object id" + << endl; + + valid_ = false; + } + + virtual void + traverse_simple (semantics::data_member& m) + { + if (readonly (member_path_, member_scope_)) + { + semantics::data_member& dm (dm_ != 0 ? *dm_ : m); + + os << dm.file () << ":" << dm.line () << ":" << dm.column () << ":" + << " error: readonly member '" << member_prefix_ << m.name () + << "' in a composite value type that is used as an object id" + << endl; + + valid_ = false; + } + } + + virtual void + traverse_container (semantics::data_member& m, semantics::type&) + { + semantics::data_member& dm (dm_ != 0 ? *dm_ : m); + + os << dm.file () << ":" << dm.line () << ":" << dm.column () << ":" + << " error: container member '" << member_prefix_ << m.name () + << "' in a composite value type that is used as an object id" + << endl; + + valid_ = false; + } + + virtual void + traverse_composite (semantics::data_member* m, semantics::class_& c) + { + semantics::data_member* old_dm (dm_); + + if (dm_ == 0) + dm_ = m; + + object_members_base::traverse_composite (m, c); + + dm_ = old_dm; + } + + private: + bool& valid_; + semantics::data_member* dm_; // Direct composite member. + }; + + struct view_members: object_members_base + { + view_members (bool& valid) + : object_members_base (false, false, true), valid_ (valid), dm_ (0) + { + } + + virtual void + traverse_simple (semantics::data_member& m) + { + if (object_pointer (utype (m))) + { + semantics::data_member& dm (dm_ != 0 ? *dm_ : m); + + os << dm.file () << ":" << dm.line () << ":" << dm.column () << ":" + << " error: view data member '" << member_prefix_ << m.name () + << "' is an object pointer" << endl; + + os << dm.file () << ":" << dm.line () << ":" << dm.column () << ":" + << ": info: views cannot contain object pointers" << endl; + + valid_ = false; + } + } + + virtual void + traverse_container (semantics::data_member& m, semantics::type&) + { + semantics::data_member& dm (dm_ != 0 ? *dm_ : m); + + os << dm.file () << ":" << dm.line () << ":" << dm.column () << ":" + << " error: view data member '" << member_prefix_ << m.name () + << "' is a container" << endl; + + os << dm.file () << ":" << dm.line () << ":" << dm.column () << ":" + << ": info: views cannot contain containers" << endl; + + valid_ = false; + } + + virtual void + traverse_composite (semantics::data_member* m, semantics::class_& c) + { + semantics::data_member* old_dm (dm_); + + if (dm_ == 0) + dm_ = m; + + object_members_base::traverse_composite (m, c); + + dm_ = old_dm; + } + + private: + bool& valid_; + semantics::data_member* dm_; // Direct view data member. + }; + struct class2: traversal::class_, context { class2 (bool& valid) - : valid_ (valid) + : valid_ (valid), + data_member_ (valid), + object_no_id_members_ (valid), + composite_id_members_ (valid), + view_members_ (valid) { + *this >> data_member_names_ >> data_member_; } virtual void @@ -56,6 +273,66 @@ namespace relational virtual void traverse_object (type& c) { + semantics::data_member* id (id_member (c)); + + if (id != 0) + { + if (semantics::class_* cm = composite_wrapper (utype (*id))) + { + // Composite id cannot be auto. + // + if (auto_ (*id)) + { + os << id->file () << ":" << id->line () << ":" << id->column () + << ": error: composite id cannot be automatically assigned" + << endl; + + valid_ = false; + } + + // Make sure we don't have any containers or pointers in this + // composite value type. + // + if (valid_) + { + composite_id_members_.traverse (*cm); + + if (!valid_) + os << id->file () << ":" << id->line () << ":" << id->column () + << ": info: composite id is defined here" << endl; + } + + // Check that the composite value type is default-constructible. + // + if (!cm->default_ctor ()) + { + os << cm->file () << ":" << cm->line () << ":" << cm->column () + << ": error: composite value type that is used as object id " + << "is not default-constructible" << endl; + + os << cm->file () << ":" << cm->line () << ":" << cm->column () + << ": info: provide default constructor for this value type" + << endl; + + os << id->file () << ":" << id->line () << ":" << id->column () + << ": info: composite id is defined here" << endl; + + valid_ = false; + } + } + } + else + { + if (!abstract (c)) + { + // Make sure we don't have any containers or inverse pointers. + // + object_no_id_members_.traverse (c); + } + } + + names (c); + // Validate indexes. // { @@ -90,17 +367,30 @@ namespace relational } virtual void - traverse_view (type&) + traverse_view (type& c) { + // Make sure we don't have any containers or object pointers. + // + view_members_.traverse (c); + + names (c); } virtual void - traverse_composite (type&) + traverse_composite (type& c) { + names (c); } public: bool& valid_; + + data_member2 data_member_; + traversal::names data_member_names_; + + object_no_id_members object_no_id_members_; + composite_id_members composite_id_members_; + view_members view_members_; }; } |