From 823026b58211a4166de06ac243d978dcb9930271 Mon Sep 17 00:00:00 2001 From: Karen Arutyunov Date: Mon, 22 Jan 2024 15:58:08 +0300 Subject: Turn odb repository into muti-package repository Also remove the autoconf/make-based build system. --- odb/processor.cxx | 3255 ----------------------------------------------------- 1 file changed, 3255 deletions(-) delete mode 100644 odb/processor.cxx (limited to 'odb/processor.cxx') diff --git a/odb/processor.cxx b/odb/processor.cxx deleted file mode 100644 index d48baa7..0000000 --- a/odb/processor.cxx +++ /dev/null @@ -1,3255 +0,0 @@ -// file : odb/processor.cxx -// license : GNU GPL v3; see accompanying LICENSE file - -#include - -#include -#include // std::find - -#include -#include -#include -#include -#include -#include - -#include - -using namespace std; - -namespace -{ - // Find name hint for this type decl. - // - static semantics::names* - find_hint (semantics::unit& u, tree decl) - { - semantics::names* r (0); - - for (tree ot (DECL_ORIGINAL_TYPE (decl)); - ot != 0; - ot = decl ? DECL_ORIGINAL_TYPE (decl) : 0) - { - if ((r = u.find_hint (ot))) - break; - - decl = TYPE_NAME (ot); - } - - return r; - } - - // Indirect (dynamic) context values. - // - static semantics::type* - id_tree_type (semantics::names*& hint) - { - context& c (context::current ()); - data_member_path& id (*context::id_member (*c.top_object)); - return &c.utype (id, hint); - } - - struct data_member: traversal::data_member, context - { - virtual void - traverse (semantics::data_member& m) - { - if (transient (m)) - return; - - semantics::names* hint; - semantics::type& t (utype (m, hint)); - - // See if this member is a section. - // - if (t.fq_name () == "::odb::section") - { - using semantics::class_; - - class_& c (dynamic_cast (m.scope ())); - class_* poly_root (polymorphic (c)); - semantics::data_member* opt (optimistic (c)); - - // If we have sections in a polymorphic optimistic hierarchy, - // then the version member should be in the root. - // - if (poly_root == &c && opt != 0 && &opt->scope () != &c) - { - error (m.location ()) << "version must be a direct data member " << - "of a class that contains sections" << endl; - info (opt->location ()) << "version member is declared here" << endl; - throw operation_failed (); - } - - process_user_section (m, c); - - // We don't need a modifier but the accessor should be by-reference. - // - process_access (m, "get"); - - member_access& ma (m.get ("get")); - if (ma.by_value) - { - error (ma.loc) << "accessor returning a value cannot be used " - << "for a section" << endl; - info (ma.loc) << "accessor returning a const reference is required" - << endl; - info (m.location ()) << "data member is defined here" << endl; - throw operation_failed (); - } - - // Mark this member as transient since we don't store it in the - // database. - // - m.set ("transient", true); - - features.section = true; - return; - } - else - { - process_access (m, "get"); - process_access (m, "set"); - } - - // See if this member belongs to a section. - // - if (m.count ("section-member") != 0) - process_section_member (m); - - // We don't need to do any further processing for common if we - // are generating static multi-database code. - // - if (multi_static && options.database ()[0] == database::common) - return; - - // Handle wrappers. - // - semantics::type* wt (0), *qwt (0); - semantics::names* whint (0); - if (process_wrapper (t)) - { - qwt = t.get ("wrapper-type"); - whint = t.get ("wrapper-hint"); - wt = &utype (*qwt, whint); - } - - // If the type is const and the member is not id, version, or - // inverse, then mark it as readonly. In case of a wrapper, - // both the wrapper type and the wrapped type must be const. - // To see why, consider these possibilities: - // - // unique_ptr - can modify by setting a new pointer - // const unique_ptr - can modify by changing the pointed-to value - // - if (const_member (m) && !(id (m) || version (m) || m.count ("inverse"))) - { - if (qwt == 0 || const_type (*qwt)) - m.set ("readonly", true); - } - - process_points_to (m); - - if (composite_wrapper (t)) - return; - - // Process object pointer. The resulting column will be a simple - // or composite value. - // - if (process_object_pointer (m, t)) - return; - - // Before checking if this is a container, check if this member - // or its type were deduced to be a simple value based on the - // pragmas. This is necessary because a container member (e.g., - // vector) can be "overridden" into a simple value (e.g., - // BLOB) with a pragma. - // - if (m.count ("simple") || - t.count ("simple") || - (wt != 0 && wt->count ("simple"))) - return; - - process_container (m, (wt != 0 ? *wt : t)); - } - - // - // 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 (FUNCTION_FIRST_USER_PARMTYPE (f) != void_list_node) - 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)))); - gcc_tree_code_type 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 (&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)); - e.push_back (cxx_token (0, CPP_CLOSE_PAREN)); - - // 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 (FUNCTION_FIRST_USER_PARMTYPE (f)); - - // 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 (&t)); - - if (a == void_list_node) - { - // 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)))); - gcc_tree_code_type 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)); - e.push_back (cxx_token (0, CPP_CLOSE_PAREN)); - - return found_best; - } - // Otherwise look for a by value modifier, which is a function - // with a single argument. - // - else if (TREE_CHAIN (a) == void_list_node) - { - // 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_VALUE (a)); - gcc_tree_code_type 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)); - e.push_back (cxx_token (0, CPP_QUERY)); - e.push_back (cxx_token (0, CPP_CLOSE_PAREN)); - - // 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 (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 (), kind, 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 ("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. - // -#if BUILDING_GCC_MAJOR >= 8 - for (ovl_iterator i (BASELINK_FUNCTIONS (decl)); i; ++i) -#else - for (tree o (BASELINK_FUNCTIONS (decl)); o != 0; o = OVL_NEXT (o)) -#endif - { -#if BUILDING_GCC_MAJOR >= 8 - tree f (*i); -#else - tree f (OVL_CURRENT (o)); -#endif - // 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 (real_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 (k)); - - if (ma.empty ()) - return; - - 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. - // -#if BUILDING_GCC_MAJOR >= 8 - for (ovl_iterator i (BASELINK_FUNCTIONS (decl)); i; ++i) -#else - for (tree o (BASELINK_FUNCTIONS (decl)); o != 0; o = OVL_NEXT (o)) -#endif - { -#if BUILDING_GCC_MAJOR >= 8 - tree f (*i); -#else - tree f (OVL_CURRENT (o)); -#endif - // 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 (&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 ("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 section. - // - - user_section& - process_user_section (semantics::data_member& m, semantics::class_& c) - { - user_sections& uss (c.get ("user-sections")); - - user_section::load_type l ( - m.get ("section-load", user_section::load_eager)); - - user_section::update_type u ( - m.get ("section-update", user_section::update_always)); - - if (l == user_section::load_eager && u == user_section::update_always) - { - location const& l (m.location ()); - - error (l) << "eager-loaded, always-updated section is pointless" - << endl; - - info (l) << "use '#pragma db load' and/or '#pragma db update' to " - "specify an alternative loading and/or updating strategy" << endl; - - info (l) << "or remove the section altogether" << endl; - - throw operation_failed (); - } - - size_t n (uss.count (user_sections::count_total | - user_sections::count_all | - user_sections::count_special_version)); - user_section us (m, c, n, l, u); - - // We may already have seen this section (e.g., forward reference - // from a member of this section). - // - user_sections::iterator i (find (uss.begin (), uss.end (), us)); - - if (i != uss.end ()) - return *i; - - // If we are adding a new section to an optimistic class with - // version in a base, make sure the base is sectionable. - // - semantics::data_member* opt (optimistic (c)); - if (opt != 0 && &opt->scope () != &c) - { - semantics::class_* poly_root (polymorphic (c)); - semantics::node* base (poly_root ? poly_root : &opt->scope ()); - - if (!base->count ("sectionable")) - { - error (m.location ()) << "adding new section to a derived class " << - "in an optimistic hierarchy requires sectionable base class" << - endl; - - info (base->location ()) << "use '#pragma db object sectionable' " << - "to make the base class of this hierarchy sectionable" << endl; - - throw operation_failed (); - } - } - - uss.push_back (us); - return uss.back (); - } - - void - process_section_member (semantics::data_member& m) - { - using semantics::class_; - using semantics::data_member; - - string name (m.get ("section-member")); - location_t loc (m.get ("section-member-location")); - class_& c (dynamic_cast (m.scope ())); - - class_* poly_root (polymorphic (c)); - bool poly_derived (poly_root != 0 && poly_root != &c); - - try - { - data_member& us (c.lookup (name, class_::include_hidden)); - - // Make sure we are referencing a section. - // - if (utype (us).fq_name () != "::odb::section") - { - error (loc) << "data member '" << name << "' in '#pragma db " << - "section' is not of the odb::section type" << endl; - throw operation_failed (); - } - - // If the section is in the base, handle polymorphic inheritance. - // - class_& b (dynamic_cast (us.scope ())); - user_section* s (0); - - if (&c != &b && poly_derived) - { - user_sections& uss (c.get ("user-sections")); - - // This is a section override. See if we have already handled - // this section. - // - for (user_sections::iterator i (uss.begin ()); - s == 0 && i != uss.end (); - ++i) - { - if (i->member == &us) - s = &*i; - } - - // Otherwise, find and copy the nearest override in the base. - // The result should be a chain of overrides leading all the - // way to the original section. - // - if (s == 0) - { - for (class_* b (&polymorphic_base (c));; - b = &polymorphic_base (*b)) - { - user_sections& buss (b->get ("user-sections")); - - for (user_sections::iterator i (buss.begin ()); - s == 0 && i != buss.end (); - ++i) - { - if (i->member == &us) - { - uss.push_back (*i); - uss.back ().object = &c; - uss.back ().base = &*i; - s = &uss.back (); - } - } - - if (s != 0) - break; - - assert (b != poly_root); // We should have found it by now. - } - } - } - else - s = &process_user_section (us, c); - - // Mark the member as added/deleted if the section is added/deleted. - // Also check that the version ordering is correct. - // - if (unsigned long long sav = added (*s->member)) - { - location_t sl (s->member->get ("added-location")); - - if (unsigned long long mav = added (m)) - { - location_t ml (m.get ("added-location")); - - if (mav < sav) - { - error (ml) << "member addition version is less than the " << - "section addition version" << endl; - info (sl) << "section addition version is specified here" << - endl; - throw operation_failed (); - } - - if (mav == sav) - { - error (ml) << "member addition version is the same as " << - "section addition version" << endl; - info (sl) << "section addition version is specified here" << - endl; - info (ml) << "delete this pragma" << endl; - throw operation_failed (); - } - } - else - { - m.set ("added", sav); - m.set ("added-location", sl); - } - } - - if (unsigned long long sdv = deleted (*s->member)) - { - location_t sl (s->member->get ("deleted-location")); - - if (unsigned long long mdv = deleted (m)) - { - location_t ml (m.get ("deleted-location")); - - if (mdv > sdv) - { - error (ml) << "member deletion version is greater than the " << - "section deletion version" << endl; - info (sl) << "section deletion version is specified here" << - endl; - throw operation_failed (); - } - - if (mdv == sdv) - { - error (ml) << "member deletion version is the same as " << - "section deletion version" << endl; - info (sl) << "section deletion version is specified here" << - endl; - info (ml) << "delete this pragma" << endl; - throw operation_failed (); - } - } - else - { - m.set ("deleted", sdv); - m.set ("deleted-location", sl); - } - } - - // Insert as object_section. - // - m.set ("section", static_cast (s)); - } - catch (semantics::unresolved const& e) - { - if (e.type_mismatch) - error (loc) << "name '" << name << "' in '#pragma db section' " << - "does not refer to a data member" << endl; - else - error (loc) << "unable to resolve data member '" << name << "' " << - "specified with '#pragma db section'" << endl; - - throw operation_failed (); - } - catch (semantics::ambiguous const& e) - { - error (loc) << "data member name '" << name << "' specified " << - "with '#pragma db section' is ambiguous" << endl; - - info (e.first.named ().location ()) << "could resolve to this " << - "data member" << endl; - - info (e.second.named ().location ()) << "or could resolve to " << - "this data member" << endl; - - throw operation_failed (); - } - } - - // - // Process wrapper. - // - - bool - process_wrapper (semantics::type& t) - { - if (t.count ("wrapper")) - return t.get ("wrapper"); - - // Check this type with wrapper_traits. - // - tree inst (instantiate_template (wrapper_traits_, t.tree_node ())); - - if (inst == 0) - { - t.set ("wrapper", false); - return false; - } - - // @@ This points to the primary template, not the specialization. - // - tree decl (TYPE_NAME (inst)); - - string f (DECL_SOURCE_FILE (decl)); - size_t l (DECL_SOURCE_LINE (decl)); - size_t c (DECL_SOURCE_COLUMN (decl)); - - // Get the wrapped type. - // - try - { - tree decl ( - lookup_qualified_name ( - inst, get_identifier ("wrapped_type"), true, false)); - - if (decl == error_mark_node || TREE_CODE (decl) != TYPE_DECL) - throw operation_failed (); - - // The wrapped_type alias is a typedef in an instantiation - // that we just instantiated dynamically. As a result there - // is no semantic graph edges corresponding to this typedef - // since we haven't parsed it yet (unless it was instantiated - // explicitly by the user; see below). So to get the tree node - // that can actually be resolved to the graph node, we use - // the source type of this typedef. - // - tree type (DECL_ORIGINAL_TYPE (decl)); - - bool qc (CP_TYPE_CONST_P (type)); - bool qv (CP_TYPE_VOLATILE_P (type)); - bool qr (CP_TYPE_RESTRICT_P (type)); - - type = TYPE_MAIN_VARIANT (type); - semantics::type* wt ( - dynamic_cast (unit.find (type))); - - // Object pointers and wrappers often use the same smart - // pointers so check if the wrapped type is an object. - // - if (object (*wt)) - { - t.set ("wrapper", false); - return false; - } - - if (qc || qv || qr) - { - for (semantics::type::qualified_iterator i (wt->qualified_begin ()); - i != wt->qualified_end (); ++i) - { - semantics::qualifier& q (i->qualifier ()); - - if (q.const_ () == qc && - q.volatile_ () == qv && - q.restrict_ () == qr) - { - wt = &q; - break; - } - } - } - - // Find the hint. - // - // If we can't find any, then try to fallback to the wrapped_type - // alias inside wrapper_traits. This requires an explicit - // wrapper_traits instantiation (see above). - // - semantics::names* wh (find_hint (unit, decl)); - - if (wh == nullptr) - wh = unit.find_hint (TREE_TYPE (decl)); - - t.set ("wrapper-type", wt); - t.set ("wrapper-hint", wh); - } - catch (operation_failed const&) - { - os << f << ":" << l << ":" << c << ": error: " - << "wrapper_traits specialization does not define the " - << "wrapped_type type" << endl; - throw; - } - - // Get the null_handler flag. - // - bool null_handler (false); - - try - { - tree nh ( - lookup_qualified_name ( - inst, get_identifier ("null_handler"), false, false)); - - if (nh == error_mark_node || TREE_CODE (nh) != VAR_DECL) - throw operation_failed (); - - // Instantiate this decalaration so that we can get its value. - // - if (DECL_TEMPLATE_INSTANTIATION (nh) && - !DECL_TEMPLATE_INSTANTIATED (nh) && - !DECL_EXPLICIT_INSTANTIATION (nh)) - instantiate_decl (nh, false, false); - - tree init (DECL_INITIAL (nh)); - - if (init == error_mark_node || TREE_CODE (init) != INTEGER_CST) - throw operation_failed (); - - null_handler = static_cast (integer_value (init)); - t.set ("wrapper-null-handler", null_handler); - } - catch (operation_failed const&) - { - os << f << ":" << l << ":" << c << ": error: " - << "wrapper_traits specialization does not define the " - << "null_handler constant" << endl; - throw; - } - - // Get the null_default flag. - // - if (null_handler) - { - try - { - tree nh ( - lookup_qualified_name ( - inst, get_identifier ("null_default"), false, false)); - - if (nh == error_mark_node || TREE_CODE (nh) != VAR_DECL) - throw operation_failed (); - - // Instantiate this decalaration so that we can get its value. - // - if (DECL_TEMPLATE_INSTANTIATION (nh) && - !DECL_TEMPLATE_INSTANTIATED (nh) && - !DECL_EXPLICIT_INSTANTIATION (nh)) - instantiate_decl (nh, false, false); - - tree init (DECL_INITIAL (nh)); - - if (init == error_mark_node || TREE_CODE (init) != INTEGER_CST) - throw operation_failed (); - - t.set ("wrapper-null-default", - static_cast (integer_value (init))); - } - catch (operation_failed const&) - { - os << f << ":" << l << ":" << c << ": error: " - << "wrapper_traits specialization does not define the " - << "null_default constant" << endl; - throw; - } - } - - // Check if the wrapper is a TR1 template instantiation. - // - if (tree ti = TYPE_TEMPLATE_INFO (t.tree_node ())) - { - tree decl (TI_TEMPLATE (ti)); // DECL_TEMPLATE - - // Get to the most general template declaration. - // - while (DECL_TEMPLATE_INFO (decl)) - decl = DECL_TI_TEMPLATE (decl); - - bool& tr1 (features.tr1_pointer); - bool& boost (features.boost_pointer); - - 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; - } - - t.set ("wrapper", true); - return true; - } - - // - // Process object pointer. - // - - semantics::class_* - process_object_pointer (semantics::data_member& m, - semantics::type& t, - string const& kp = string ()) - { - using semantics::class_; - using semantics::data_member; - - class_* c (0); - - // The overall idea is as follows: try to instantiate the pointer - // traits class template. If we are successeful, then get the - // element type and see if it is an object. - // - if (t.count ("element-type")) - c = t.get ("element-type"); - else - { - tree inst (instantiate_template (pointer_traits_, t.tree_node ())); - - if (inst == 0) - return 0; - - // @@ This points to the primary template, not the specialization. - // - tree decl (TYPE_NAME (inst)); - - string fl (DECL_SOURCE_FILE (decl)); - size_t ln (DECL_SOURCE_LINE (decl)); - size_t cl (DECL_SOURCE_COLUMN (decl)); - - // Get the element type. - // - tree tn (0); - try - { - tree decl ( - lookup_qualified_name ( - inst, get_identifier ("element_type"), true, false)); - - if (decl == error_mark_node || TREE_CODE (decl) != TYPE_DECL) - throw operation_failed (); - - tn = TYPE_MAIN_VARIANT (TREE_TYPE (decl)); - - // Check if the pointer is a TR1 template instantiation. - // - if (tree ti = TYPE_TEMPLATE_INFO (t.tree_node ())) - { - decl = TI_TEMPLATE (ti); // DECL_TEMPLATE - - // Get to the most general template declaration. - // - while (DECL_TEMPLATE_INFO (decl)) - decl = DECL_TI_TEMPLATE (decl); - - bool& tr1 (features.tr1_pointer); - bool& boost (features.boost_pointer); - - 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; - } - } - catch (operation_failed const&) - { - os << fl << ":" << ln << ":" << cl << ": error: pointer_traits " - << "specialization does not define the 'element_type' type" - << endl; - throw; - } - - c = dynamic_cast (unit.find (tn)); - - if (c == 0 || !object (*c)) - return 0; - - t.set ("element-type", c); - - // Determine the pointer kind. - // - try - { - tree kind ( - lookup_qualified_name ( - inst, get_identifier ("kind"), false, false)); - - if (kind == error_mark_node || TREE_CODE (kind) != VAR_DECL) - throw operation_failed (); - - // Instantiate this decalaration so that we can get its value. - // - if (DECL_TEMPLATE_INSTANTIATION (kind) && - !DECL_TEMPLATE_INSTANTIATED (kind) && - !DECL_EXPLICIT_INSTANTIATION (kind)) - instantiate_decl (kind, false, false); - - tree init (DECL_INITIAL (kind)); - - if (init == error_mark_node || TREE_CODE (init) != INTEGER_CST) - throw operation_failed (); - - pointer_kind_type pk = static_cast ( - integer_value (init)); - t.set ("pointer-kind", pk); - } - catch (operation_failed const&) - { - os << fl << ":" << ln << ":" << cl << ": error: pointer_traits " - << "specialization does not define the 'kind' constant" << endl; - throw; - } - - // Get the lazy flag. - // - try - { - tree lazy ( - lookup_qualified_name ( - inst, get_identifier ("lazy"), false, false)); - - if (lazy == error_mark_node || TREE_CODE (lazy) != VAR_DECL) - throw operation_failed (); - - // Instantiate this decalaration so that we can get its value. - // - if (DECL_TEMPLATE_INSTANTIATION (lazy) && - !DECL_TEMPLATE_INSTANTIATED (lazy) && - !DECL_EXPLICIT_INSTANTIATION (lazy)) - instantiate_decl (lazy, false, false); - - tree init (DECL_INITIAL (lazy)); - - if (init == error_mark_node || TREE_CODE (init) != INTEGER_CST) - throw operation_failed (); - - t.set ("pointer-lazy", static_cast (integer_value (init))); - } - catch (operation_failed const&) - { - os << fl << ":" << ln << ":" << cl << ": error: pointer_traits " - << "specialization does not define the 'kind' constant" << endl; - throw; - } - } - - // See if this is the inverse side of a bidirectional relationship. - // If so, then resolve the member path and cache it in the context. - // - if (m.count ("inverse")) - { - string name (m.get ("inverse")); - location_t l (m.get ("inverse-location")); - data_member_path mp (resolve_data_members (*c, name, l, lex_)); - - { - string tl; - data_member& m (*mp.back ()); - - if (container (m) && lex_.next (tl) != CPP_EOF) - { - error (l) << "unexpect name after container member " << - m.name () << " in '#pragma db inverse'" << endl; - throw operation_failed (); - } - } - - // Validate each member. - // - for (data_member_path::iterator i (mp.begin ()); i != mp.end (); ++i) - { - data_member& im (**i); - const string& n (im.name ()); - - if (im.count ("transient")) - { - error (l) << "data member '" << n << "' specified with " << - "'#pragma db inverse' is transient" << endl; - info (im.location ()) << "data member '" << n << "' is " << - "defined here" << endl; - throw operation_failed (); - } - - if (im.count ("inverse") || im.count ("value-inverse")) - { - error (l) << "data member '" << n << "' specified with " << - "'#pragma db inverse' is itself inverse" << endl; - info (im.location ()) << "data member '" << n << "' is " << - "defined here" << endl; - throw operation_failed (); - } - } - - // @@ Would be good to check that the other end is actually - // an object pointer/points_to and points to the correct - // object. But the other class may not have been processed - // yet. Need to do in validator, pass 2. - // - m.remove ("inverse"); - m.set (kp + (kp.empty () ? "": "-") + "inverse", mp); - } - - return c; - } - - // - // Process points-to pragma. - // - - void - process_points_to (semantics::data_member& m, - string const& /*kp*/ = string ()) - { - if (!m.count ("points-to")) - return; - - using semantics::class_; - - tree t (m.get ("points-to")); - location_t l (m.get ("points-to-location")); - - class_* c (dynamic_cast (unit.find (t))); - - if (c == 0 || !object (*c)) - { - error (l) << "name specified with '#pragma db points_to' does " - << "not refer to an object" << endl; - throw operation_failed (); - } - - m.remove ("points-to"); - m.set (/*kp + (kp.empty () ? "": "-") + */"points-to", c); - } - - // - // Process container. - // - - void - process_container_value (semantics::type& t, - semantics::data_member& m, - string const& prefix, - bool obj_ptr) - { - if (composite_wrapper (t)) - return; - - if (obj_ptr) - process_object_pointer (m, t, prefix); - } - - bool - process_container (semantics::data_member& m, semantics::type& t) - { - // The overall idea is as follows: try to instantiate the container - // traits class template. If we are successeful, then this is a - // container type and we can extract the various information from - // the instantiation. Otherwise, this is not a container. - // - location ml (m.location ()); - - container_kind_type ck; - bool smart; - semantics::type* vt (0); - semantics::type* it (0); - semantics::type* kt (0); - - semantics::names* vh (0); - semantics::names* ih (0); - semantics::names* kh (0); - - if (t.count ("container-kind")) - { - ck = t.get ("container-kind"); - smart = t.get ("container-smart"); - - vt = &utype (m, vh, "value"); - - if (ck == ck_ordered) - it = &utype (m, ih, "index"); - - if (ck == ck_map || ck == ck_multimap) - kt = &utype (m, kh, "key"); - } - else - { - tree inst (instantiate_template (container_traits_, t.tree_node ())); - - if (inst == 0) - return false; - - // @@ This points to the primary template, not the specialization. - // - tree decl (TYPE_NAME (inst)); - - string f (DECL_SOURCE_FILE (decl)); - size_t l (DECL_SOURCE_LINE (decl)); - size_t c (DECL_SOURCE_COLUMN (decl)); - - // Determine the container kind. - // - try - { - tree decl ( - lookup_qualified_name ( - inst, get_identifier ("kind"), false, false)); - - if (decl == error_mark_node || TREE_CODE (decl) != VAR_DECL) - throw operation_failed (); - - // Instantiate this decalaration so that we can get its value. - // - if (DECL_TEMPLATE_INSTANTIATION (decl) && - !DECL_TEMPLATE_INSTANTIATED (decl) && - !DECL_EXPLICIT_INSTANTIATION (decl)) - instantiate_decl (decl, false, false); - - tree init (DECL_INITIAL (decl)); - - if (init == error_mark_node || TREE_CODE (init) != INTEGER_CST) - throw operation_failed (); - - ck = static_cast (integer_value (init)); - } - catch (operation_failed const&) - { - os << f << ":" << l << ":" << c << ": error: " - << "container_traits specialization does not define the " - << "container kind constant" << endl; - - throw; - } - - t.set ("container-kind", ck); - - // See if it is a smart container. - // - try - { - tree decl ( - lookup_qualified_name ( - inst, get_identifier ("smart"), false, false)); - - if (decl == error_mark_node || TREE_CODE (decl) != VAR_DECL) - throw operation_failed (); - - // Instantiate this decalaration so that we can get its value. - // - if (DECL_TEMPLATE_INSTANTIATION (decl) && - !DECL_TEMPLATE_INSTANTIATED (decl) && - !DECL_EXPLICIT_INSTANTIATION (decl)) - instantiate_decl (decl, false, false); - - tree init (DECL_INITIAL (decl)); - - if (init == error_mark_node || TREE_CODE (init) != INTEGER_CST) - throw operation_failed (); - - smart = static_cast (integer_value (init)); - } - catch (operation_failed const&) - { - os << f << ":" << l << ":" << c << ": error: " - << "container_traits specialization does not define the " - << "'smart' constant" << endl; - throw; - } - - // For now we only support ordered smart containers. - // - if (smart && ck != ck_ordered) - { - os << f << ":" << l << ":" << c << ": error: only ordered smart " << - "containers are currently supported" << endl; - throw operation_failed (); - } - - t.set ("container-smart", smart); - - // Mark id column as not null. - // - t.set ("id-not-null", true); - - // Get the value type. - // - { - tree decl (lookup_qualified_name ( - inst, get_identifier ("value_type"), true, false)); - - if (decl == error_mark_node || TREE_CODE (decl) != TYPE_DECL) - { - os << f << ":" << l << ":" << c << ": error: " - << "container_traits specialization does not define the " - << "value_type type" << endl; - - throw operation_failed (); - } - - tree type (TYPE_MAIN_VARIANT (TREE_TYPE (decl))); - - if (semantics::node* n = unit.find (type)) - vt = &dynamic_cast (*n); - else - { - error (ml) << "container value type is not instantiated" << endl; - info (ml) << "use typedef/using to instantiate" << endl; - throw operation_failed (); - } - - // Find the hint. - // - vh = find_hint (unit, decl); - } - - - t.set ("value-tree-type", vt); - t.set ("value-tree-hint", vh); - vt = &utype (m, vh, "value"); // Map. - - // Issue a warning if we are relaxing null-ness in the container - // type. - // - if (t.count ("value-null") && vt->count ("not-null")) - { - os << t.file () << ":" << t.line () << ":" << t.column () << ":" - << " warning: container value declared null while its type " - << "is declared not null" << endl; - } - - // Get the index type for ordered containers. - // - if (ck == ck_ordered) - { - tree decl ( - lookup_qualified_name ( - inst, get_identifier ("index_type"), true, false)); - - if (decl == error_mark_node || TREE_CODE (decl) != TYPE_DECL) - { - os << f << ":" << l << ":" << c << ": error: " - << "container_traits specialization does not define the " - << "index_type type" << endl; - throw operation_failed (); - } - - tree type (TYPE_MAIN_VARIANT (TREE_TYPE (decl))); - - if (semantics::node* n = unit.find (type)) - it = &dynamic_cast (*n); - else - { - error (ml) << "container index type is not instantiated" << endl; - info (ml) << "use typedef/using to instantiate" << endl; - throw operation_failed (); - } - - // Find the hint. - // - ih = find_hint (unit, decl); - - t.set ("index-not-null", true); - t.set ("index-tree-type", it); - t.set ("index-tree-hint", ih); - it = &utype (m, ih, "index"); // Map. - } - - // Get the key type for maps. - // - if (ck == ck_map || ck == ck_multimap) - { - tree decl ( - lookup_qualified_name ( - inst, get_identifier ("key_type"), true, false)); - - if (decl == error_mark_node || TREE_CODE (decl) != TYPE_DECL) - { - os << f << ":" << l << ":" << c << ": error: " - << "container_traits specialization does not define the " - << "key_type type" << endl; - throw operation_failed (); - } - - tree type (TYPE_MAIN_VARIANT (TREE_TYPE (decl))); - - if (semantics::node* n = unit.find (type)) - kt = &dynamic_cast (*n); - else - { - error (ml) << "container key type is not instantiated" << endl; - info (ml) << "use typedef/using to instantiate" << endl; - throw operation_failed (); - } - - // Find the hint. - // - kh = find_hint (unit, decl); - - t.set ("key-tree-type", kt); - t.set ("key-tree-hint", kh); - kt = &utype (m, kh, "key"); // Map. - - // Issue a warning if we are relaxing null-ness in the container - // type. - // - if (t.count ("key-null") && kt->count ("not-null")) - { - os << t.file () << ":" << t.line () << ":" << t.column () << ":" - << " warning: container key declared null while its type " - << "is declared not null" << endl; - } - } - - // Determine if container value/index/key types are wrappers. - // - process_wrapper (*vt); - - if (it != 0) - process_wrapper (*it); - - if (kt != 0) - process_wrapper (*kt); - - // Check if we are versioned. For now we are not allowing for - // soft-add/delete in container keys (might be used in WHERE, - // primary key). - // - { - semantics::class_* comp (0); - switch (ck) - { - case ck_ordered: - { - comp = composite_wrapper (*vt); - break; - } - case ck_map: - case ck_multimap: - { - comp = composite_wrapper (*kt); - if (comp == 0 || column_count (*comp).soft == 0) - { - comp = composite_wrapper (*vt); - break; - } - - error (ml) << "map key type cannot have soft-added/deleted " << - "data members" << endl; - info (kt->location ()) << "key type is defined here" << endl; - throw operation_failed (); - } - case ck_set: - case ck_multiset: - { - comp = composite_wrapper (*vt); - if (comp == 0 || column_count (*comp).soft == 0) - { - comp = 0; - break; - } - - error (ml) << "set value type cannot have soft-added/deleted " << - "data members" << endl; - info (vt->location ()) << "value type is defined here" << endl; - throw operation_failed (); - } - } - - if (force_versioned || (comp != 0 && column_count (*comp).soft != 0)) - t.set ("versioned", true); - } - } - - // Process member data. - // - m.set ("id-tree-type", &id_tree_type); - - // Has to be first to handle inverse. - // - process_container_value (*vt, m, "value", true); - - if (it != 0) - process_container_value (*it, m, "index", false); - - if (kt != 0) - process_container_value (*kt, m, "key", true); - - // A map cannot be an inverse container. - // - if (m.count ("value-inverse") && (ck == ck_map || ck == ck_multimap)) - { - os << m.file () << ":" << m.line () << ":" << m.column () << ":" - << " error: inverse container cannot be a map" << endl; - throw operation_failed (); - } - - // If this is an inverse side of a bidirectional object relationship - // and it is an ordered container, mark it as unordred since there is - // no concept of order in this construct. - // - if (ck == ck_ordered && m.count ("value-inverse")) - m.set ("unordered", true); - - // Issue an error if we have a non-inverse smart unordered container. - // - if (smart && ck == ck_ordered && unordered (m) && - !m.count ("value-inverse")) - { - error (ml) << "smart ordered container cannot be unordered" << endl; - throw operation_failed (); - } - - // Issue a warning if we are relaxing null-ness in the member. - // - if (m.count ("value-null") && - (t.count ("value-not-null") || vt->count ("not-null"))) - { - warn (ml) << "container value declared null while the container " - << "type or value type declares it as not null" << endl; - } - - if (ck == ck_map || ck == ck_multimap) - { - if (m.count ("key-null") && - (t.count ("key-not-null") || kt->count ("not-null"))) - { - warn (ml) << "container key declared null while the container " - << "type or key type declares it as not null" << endl; - } - } - - return true; - } - - // - // Implementation details (c-tor, helpers). - // - - data_member () - { - // Find the odb namespace. - // - tree odb = lookup_qualified_name ( - global_namespace, get_identifier ("odb"), false, false); - - if (odb == error_mark_node) - { - os << unit.file () << ": error: unable to resolve odb namespace" - << endl; - - throw operation_failed (); - } - - // Find wrapper traits. - // - wrapper_traits_ = lookup_qualified_name ( - odb, get_identifier ("wrapper_traits"), true, false); - - if (wrapper_traits_ == error_mark_node || - !DECL_CLASS_TEMPLATE_P (wrapper_traits_)) - { - os << unit.file () << ": error: unable to resolve wrapper_traits " - << "in the odb namespace" << endl; - - throw operation_failed (); - } - - // Find pointer traits. - // - pointer_traits_ = lookup_qualified_name ( - odb, get_identifier ("pointer_traits"), true, false); - - if (pointer_traits_ == error_mark_node || - !DECL_CLASS_TEMPLATE_P (pointer_traits_)) - { - os << unit.file () << ": error: unable to resolve pointer_traits " - << "in the odb namespace" << endl; - - throw operation_failed (); - } - - // Find the access class. - // - tree access = lookup_qualified_name ( - odb, get_identifier ("access"), true, false); - - if (access == error_mark_node) - { - os << unit.file () << ": error: unable to resolve access class" - << "in the odb namespace" << endl; - - throw operation_failed (); - } - - access = TREE_TYPE (access); - - // Find container_traits. - // - container_traits_ = lookup_qualified_name ( - access, get_identifier ("container_traits"), true, false); - - if (container_traits_ == error_mark_node || - !DECL_CLASS_TEMPLATE_P (container_traits_)) - { - os << unit.file () << ": error: unable to resolve container_traits " - << "in the odb namespace" << endl; - - throw operation_failed (); - } - } - - static tree - instantiate_template (tree t, tree arg) - { - tree args (make_tree_vec (1)); - TREE_VEC_ELT (args, 0) = arg; - - // This step should succeed regardles of whether there is a - // specialization for this type. - // - tree inst ( - lookup_template_class (t, args, 0, 0, 0, tf_warning_or_error)); - - if (inst == error_mark_node) - { - // Diagnostics has already been issued by lookup_template_class. - // - throw operation_failed (); - } - - inst = TYPE_MAIN_VARIANT (inst); - - // The instantiation may already be complete if it matches a - // (complete) specialization or was used before. - // - if (!COMPLETE_TYPE_P (inst)) - inst = instantiate_class_template (inst); - - // If we cannot instantiate this type, assume there is no suitable - // specialization for it. - // - if (inst == error_mark_node || !COMPLETE_TYPE_P (inst)) - return 0; - - return inst; - } - - private: - tree wrapper_traits_; - tree pointer_traits_; - tree container_traits_; - - cxx_string_lexer lex_; - }; - - struct view_data_member: traversal::data_member, context - { - view_data_member (semantics::class_& c) - : view_ (c), - amap_ (c.get ("alias-map")), - omap_ (c.get ("object-map")) {} - - virtual void - traverse (semantics::data_member& m) - { - using semantics::data_member; - - if (transient (m)) - return; - - semantics::type& t (utype (m)); - - if (semantics::class_* c = object_pointer (t)) - { - location const& l (m.location ()); - - if (lazy_pointer (t)) - { - error (l) << "lazy object pointer in view" << endl; - throw operation_failed (); - } - - // Find the corresponding associated object. First see if this - // data member name matches any aliases. - // - view_alias_map::iterator i (amap_.find (m.name ())); - - if (i == amap_.end ()) - i = amap_.find (public_name (m, false)); - - view_object* vo (0); - - if (i != amap_.end ()) - { - vo = i->second; - - if (vo->obj != c) // @@ Poly base/derived difference? - { - error (l) << "different pointed-to and associated objects" << endl; - info (vo->loc) << "associated object is defined here" << endl; - throw operation_failed (); - } - } - else - { - // If there is no alias match, try the object type. - // - view_object_map::iterator i (omap_.find (c)); - - if (i == omap_.end ()) - { - error (l) << "unable to find associated object for object " - << "pointer" << endl; - info (l) << "use associated object alias as this data member " - << "name" << endl; - throw operation_failed (); - } - - vo = i->second; - } - - if (vo->ptr != 0) - { - location const& l2 (vo->ptr->location ()); - - error (l) << "associated object is already loaded via another " - << "object pointer" << endl; - info (l2) << "the other data member is defined here" << endl; - info (l2) << "use associated object alias as this data member " - << "name to load a different object" << endl; - - throw operation_failed (); - } - - vo->ptr = &m; - m.set ("view-object", vo); - } - } - - private: - semantics::class_& view_; - view_alias_map& amap_; - view_object_map& omap_; - }; - - // Figure out the "summary" added/deleted version for a composite - // value type. - // - struct summary_version: object_members_base - { - summary_version (): av (0), dv (0), a_ (true), d_ (true) {} - - virtual void - traverse_simple (semantics::data_member&) - { - if (a_) - { - if (unsigned long long v = added (member_path_)) - { - if (av == 0 || av < v) - av = v; - } - else - { - av = 0; - a_ = false; - } - } - - if (d_) - { - if (unsigned long long v = deleted (member_path_)) - { - if (dv == 0 || dv > v) - dv = v; - } - else - { - dv = 0; - d_ = false; - } - } - } - - public: - unsigned long long av; - unsigned long long dv; - - bool a_; - bool d_; - }; - - struct class_: traversal::class_, context - { - class_ () - : typedefs_ (true), - std_string_ (0), - std_string_hint_ (0), - access_ (0) - { - *this >> defines_ >> *this; - *this >> typedefs_ >> *this; - - member_names_ >> member_; - - // 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 (&ip.first->named ())) - { - scope::names_iterator_pair jp (ns->find ("string")); - - if (jp.first != jp.second) - { - std_string_ = dynamic_cast ( - &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); - } - } - - virtual void - traverse (type& c) - { - class_kind_type k (class_kind (c)); - - if (k == class_other) - return; - - names (c); // Process nested classes. - - // 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); - - if (k == class_object) - traverse_object_pre (c); - else if (k == class_view) - traverse_view_pre (c); - - names (c, member_names_); - - if (k == class_object) - traverse_object_post (c); - else if (k == class_view) - traverse_view_post (c); - else if (k == class_composite) - traverse_composite_post (c); - } - - // - // Object. - // - - virtual void - traverse_object_pre (type& c) - { - using semantics::class_; - using semantics::data_member; - - class_* poly_root (polymorphic (c)); - - // Sections. - // - user_sections& uss (c.set ("user-sections", user_sections (c))); - - // Copy sections from reuse bases. For polymorphic classes, sections - // are overridden. - // - if (poly_root == 0 || poly_root == &c) - { - for (type::inherits_iterator i (c.inherits_begin ()); - i != c.inherits_end (); ++i) - { - type& b (i->base ()); - - if (object (b)) - { - user_sections& buss (b.get ("user-sections")); - - for (user_sections::iterator j (buss.begin ()); - j != buss.end (); - ++j) - { - // Don't copy the special version update section. - // - if (j->special == user_section::special_version) - continue; - - uss.push_back (*j); - uss.back ().object = &c; - uss.back ().base = &*j; - } - } - } - } - - // 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 (&class_scope (c));; s = &s->scope_ ()) - { - using semantics::namespace_; - - namespace_* ns (dynamic_cast (s)); - - if (ns == 0) // Some other scope. - { - if (!s->named_p ()) - break; - - continue; - } - - if (ns->extension ()) - ns = &ns->original (); - - if (ns->count ("session")) - { - c.set ("session", ns->get ("session")); - found = true; - break; - } - - if (ns->global_scope ()) // Note: namespaces always named. - 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; - using semantics::data_member; - - data_member_path& id (*id_member (*poly_root)); - data_member* idm (id.front ()); - - 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. - // - semantics::class_& base (polymorphic_base (c)); - - if (&base != poly_root) - idm = &dynamic_cast (base.names_begin ()->named ()); - - path const& f (idm->file ()); - size_t l (idm->line ()), col (idm->column ()); - - semantics::data_member& m ( - unit.new_node (f, l, col, tree (0))); - m.set ("virtual", true); - - // Make it the first member in the class. This is important: - // we rely on the corrensponding foreign key to be first. - // - node_position np (c, c.names_end ()); - unit.new_edge ( - np, m, idm->name (), access::public_); - - // Use the raw pointer as this member's type. - // - if (!base.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 (base.tree_node ()); - tree ptr (TYPE_POINTER_TO (t)); - assert (ptr != 0); - ptr = TYPE_MAIN_VARIANT (ptr); - pointer& p (unit.new_node (f, l, col, ptr)); - unit.insert (ptr, p); - unit.new_edge (p, base); - assert (base.pointed_p ()); - } - - unit.new_edge (m, base.pointed ().pointer ()); - - // Mark it as a special kind of id. - // - m.set ("id", string ()); - m.set ("polymorphic-ref", true); - - // Make sure we also use the same column name as the root. - // - if (composite_wrapper (utype (id))) - m.set ("column", table_column (column_prefix (id, true).prefix)); - else - m.set ("column", table_column (column_name (id))); - } - 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 ("polymorphic-location")); - semantics::data_member& m ( - unit.new_node ( - 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 np ( - c, c.find (idm->named ())); - unit.new_edge ( - np, m, "typeid_", access::public_); - - belongs& edge (unit.new_edge (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) - { - semantics::class_* poly_root (polymorphic (c)); - bool poly_derived (poly_root != 0 && poly_root != &c); - - semantics::data_member* opt (optimistic (c)); - - // Figure out if we are versioned. We are versioned if we have - // soft-added/deleted columns ourselves or our poly-base is - // versioned. - // - if (force_versioned || - column_count (c).soft != 0 || - (poly_derived && polymorphic_base (c).count ("versioned"))) - c.set ("versioned", true); - - // Sections. - // - user_sections& uss (c.get ("user-sections")); - - // See if we need to add a special fake section for version update. - // - if (c.count ("sectionable")) - { - uss.push_back ( - user_section (*opt, - c, - uss.count (user_sections::count_total | - user_sections::count_all | - user_sections::count_special_version), - user_section::load_lazy, - user_section::update_manual, - user_section::special_version)); - - // If we are a root of a polymorphic hierarchy and the version is in - // a reuse-base, then we need to make sure that base is sectionable - // and derive from its special version update section. - // - semantics::node& opt_base (opt->scope ()); - if (poly_root == &c && &opt_base != &c) - { - if (!opt_base.count ("sectionable")) - { - location_t l (c.get ("sectionable-location")); - - error (l) << "reuse base class of a sectionable polymorphic " << - "root class must be sectionable" << endl; - - info (opt_base.location ()) << "use '#pragma db object " << - "sectionable' to make the base class of this hierarchy " << - "sectionable" << endl; - - throw operation_failed (); - } - - uss.back ().base = - &opt_base.get ("user-sections").back (); - } - } - - // Calculate column counts for sections. - // - for (user_sections::iterator i (uss.begin ()); i != uss.end (); ++i) - { - column_count_type cc (column_count (c, &*i)); - i->total = cc.total; - i->inverse = cc.inverse; - i->readonly = cc.readonly; - - // Figure out if we are versioned. We are versioned if we have - // soft-added/deleted columns ourselves or our poly-base is - // versioned. - // - if (force_versioned || cc.soft != 0 || - (poly_derived && i->base != 0 && i->base->versioned)) - i->versioned = true; - - if (size_t n = has_a (c, test_container, &*i)) - { - i->containers = true; - i->versioned_containers = - n != has_a (c, - test_container | - exclude_deleted | exclude_added | exclude_versioned, - &*i); - - if ((n = has_a (c, test_readwrite_container, &*i))) - { - i->readwrite_containers = true; - i->readwrite_versioned_containers = - n != has_a (c, - test_readwrite_container | - exclude_deleted | exclude_added | exclude_versioned, - &*i); - } - } - } - } - - // - // View. - // - - virtual void - traverse_view_pre (type& c) - { - // Resolve referenced objects from tree nodes to semantic graph - // nodes. Also populate maps and compute counts. - // - view_alias_map& amap (c.set ("alias-map", view_alias_map ())); - view_object_map& omap (c.set ("object-map", view_object_map ())); - - size_t& obj_count (c.set ("object-count", size_t (0))); - size_t& tbl_count (c.set ("table-count", size_t (0))); - - if (c.count ("objects")) - { - using semantics::class_; - - view_objects& objs (c.get ("objects")); - - for (view_objects::iterator i (objs.begin ()); i != objs.end (); ++i) - { - if (i->kind != view_object::object) - { - tbl_count++; - continue; - } - else - obj_count++; - - tree n (TYPE_MAIN_VARIANT (i->obj_node)); - - if (TREE_CODE (n) != RECORD_TYPE) - { - error (i->loc) << "name '" << i->obj_name << "' in db pragma " << - "object does not name a class" << endl; - - throw operation_failed (); - } - - class_& o (dynamic_cast (*unit.find (n))); - - if (!object (o)) - { - error (i->loc) << "name '" << i->obj_name << "' in db pragma " << - "object does not name a persistent class" << endl; - - info (o.location ()) << "class '" << i->obj_name << "' is " << - "defined here" << endl; - - throw operation_failed (); - } - - i->obj = &o; - i->ptr = 0; // Nothing yet. - - if (i->alias.empty ()) - { - if (!omap.insert (view_object_map::value_type (&o, &*i)).second) - { - error (i->loc) << "persistent class '" << i->obj_name << - "' is used in the view more than once" << endl; - - error (omap[&o]->loc) << "previously used here" << endl; - - info (i->loc) << "use the alias clause to assign it a " << - "different name" << endl; - - throw operation_failed (); - } - - // Also add the bases of a polymorphic object. - // - class_* poly_root (polymorphic (o)); - - if (poly_root != 0 && poly_root != &o) - { - for (class_* b (&polymorphic_base (o));; - b = &polymorphic_base (*b)) - { - if (!omap.insert (view_object_map::value_type (b, &*i)).second) - { - error (i->loc) << "base class '" << class_name (*b) << - "' is used in the view more than once" << endl; - - error (omap[b]->loc) << "previously used here" << endl; - - info (i->loc) << "use the alias clause to assign it a " << - "different name" << endl; - - throw operation_failed (); - } - - if (b == poly_root) - break; - } - } - } - else - { - if (!amap.insert ( - view_alias_map::value_type (i->alias, &*i)).second) - { - error (i->loc) << "alias '" << i->alias << "' is used in " << - "the view more than once" << endl; - - throw operation_failed (); - } - } - } - } - } - - virtual void - traverse_view_post (type& c) - { - // Handle data members. - // - { - view_data_member t (c); - traversal::names n (t); - names (c, n); - } - - // Figure out if we are versioned. Forced versioning is handled - // in relational/processing. - // - if (column_count (c).soft != 0) - c.set ("versioned", true); - } - - // - // Composite. - // - - virtual void - traverse_composite_post (type& c) - { - // Figure out if we are versioned. - // - if (force_versioned || column_count (c).soft != 0) - { - c.set ("versioned", true); - - // See if we are "summarily" added/deleted, that is, all the - // columns are added/deleted. Note: this does not include - // containers. - // - summary_version sv; - sv.traverse (c); - - // Note: there are no locations. - // - if (sv.av != 0) - c.set ("added", sv.av); - - if (sv.dv != 0) - c.set ("deleted", sv.dv); - } - } - - // - // Assign object/view pointer. - // - - void - assign_pointer (type& c) - { - location_t loc (0); // Pragma location, or 0 if not used. - - try - { - bool raw; - 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 ("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 ("pointer-template"); - } - - if (cp != 0) - { - string const& p (cp->name); - - if (p == "*") - { - raw = true; - ptr = type + "*"; - cp_template = true; - } - else if (p[p.size () - 1] == '*') - { - raw = true; - ptr = p; - } - else if (p.find ('<') != string::npos) - { - // Template-id. - // - raw = false; // Fair to assume not raw, though technically can be. - 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); - gcc_tree_code_type tc (TREE_CODE (decl)); - - if (tc == TYPE_DECL) - { - raw = (TREE_CODE (TREE_TYPE (decl)) == POINTER_TYPE); - 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)) - { - raw = false; - 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 (&class_scope (c));; s = &s->scope_ ()) - { - using semantics::namespace_; - - namespace_* ns (dynamic_cast (s)); - - if (ns == 0) // Some other scope. - { - if (!s->named_p ()) - break; - - continue; - } - - if (ns->extension ()) - ns = &ns->original (); - - if (!ns->count ("pointer")) - { - if (ns->global_scope ()) // Note: namespace always named. - break; - else - continue; - } - - cp = &ns->get ("pointer"); - string const& p (cp->name); - - // Namespace-specified pointer can only be '*' or are template. - // - if (p == "*") - { - raw = true; - 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); - gcc_tree_code_type tc (TREE_CODE (decl)); - - if (tc == TEMPLATE_DECL && DECL_CLASS_TEMPLATE_P (decl)) - { - raw = false; - 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 == "*") - { - raw = true; - ptr = type + "*"; - } - else - { - raw = false; - ptr = p + "< " + type + " >"; - decl_name = p; - } - - // Resolve scope is the scope of the class. - // - resolve_scope = class_scope (c).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 (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 this is an inline namespace, skip it until we get - // to the non-inline one. - // - while (scope != global_namespace) - { - tree prev (CP_DECL_CONTEXT (scope)); - -#if BUILDING_GCC_MAJOR >= 8 - if (!is_nested_namespace (prev, scope, true)) -#else - if (!is_associated_namespace (prev, scope)) -#endif - break; - - scope = prev; - } - - 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); - c.set ("object-pointer-raw", raw); - } - 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: - traversal::defines defines_; - typedefs typedefs_; - - data_member member_; - traversal::names member_names_; - - cxx_string_lexer lex_; - cxx_string_lexer nlex_; // Nested lexer. - - semantics::type* std_string_; - semantics::names* std_string_hint_; - - tree access_; // odb::access node. - }; - - static bool - check_to_from (const cxx_tokens& ex, const char* c, location_t l) - { - // Make sure we have one and only one placeholder (?). - // - bool r (false), m (true); - - for (cxx_tokens::const_iterator i (ex.begin ()), e (ex.end ()); i != e;) - { - if (i->type == CPP_OPEN_PAREN) - { - if (++i != e && i->type == CPP_QUERY) - { - if (++i != e && i->type == CPP_CLOSE_PAREN) - { - if (r) - m = false; // Multiple (?), can't move. - else - r = true; - } - } - } - else - ++i; - } - - if (!r) - { - error (l) << "no '(?)' expression in the '" << c << "' clause " - << "of db pragma map" << endl; - - throw operation_failed (); - } - - return m; - } -} - -static void -process1 (semantics::unit& u) -{ - // Process custom C++ type mapping. - // - - // Create an empty list if we don't have one. This makes the - // rest of the code simpler. - // - if (!u.count ("custom-cxx-types")) - u.set ("custom-cxx-types", custom_cxx_types ()); - - custom_cxx_types & cts (u.get ("custom-cxx-types")); - - for (custom_cxx_types::iterator i (cts.begin ()); i != cts.end (); ++i) - { - custom_cxx_type& ct (*i); - - // type - // - if (ct.type_node == 0) - { - error (ct.loc) << "'type' clause expected in db pragma map" << endl; - throw operation_failed (); - } - - ct.type = dynamic_cast ( - u.find (TYPE_MAIN_VARIANT (ct.type_node))); - ct.type_hint = u.find_hint (ct.type_node); - - // as - // - if (ct.as_node == 0) - { - error (ct.loc) << "'as' clause expected in db pragma map" << endl; - throw operation_failed (); - } - - ct.as = dynamic_cast ( - u.find (TYPE_MAIN_VARIANT (ct.as_node))); - ct.as_hint = u.find_hint (ct.as_node); - - // to - // - { - cxx_tokens& e (ct.to); - - if (e.empty ()) - { - e.push_back (cxx_token (0, CPP_OPEN_PAREN)); - e.push_back (cxx_token (0, CPP_QUERY)); - e.push_back (cxx_token (0, CPP_CLOSE_PAREN)); - ct.to_move = true; - } - else - ct.to_move = check_to_from (e, "to", ct.loc); - } - - // from - // - { - cxx_tokens& e (ct.from); - - if (e.empty ()) - { - e.push_back (cxx_token (0, CPP_OPEN_PAREN)); - e.push_back (cxx_token (0, CPP_QUERY)); - e.push_back (cxx_token (0, CPP_CLOSE_PAREN)); - ct.from_move = true; - } - else - ct.from_move = check_to_from (e, "from", ct.loc); - } - - // Resolve mapping scope. - // - semantics::scope* s (dynamic_cast (u.find (ct.scope))); - if (s == 0) - { - error (ct.loc) << "unable to resolve db pragma map scope" << endl; - throw operation_failed (); - } - - if (semantics::namespace_* ns = dynamic_cast (s)) - { - if (ns->extension ()) - s = &ns->original (); - } - - // Enter into the map. - // - if (!s->count ("custom-cxx-type-map")) - s->set ("custom-cxx-type-map", custom_cxx_type_map ()); - - s->get ("custom-cxx-type-map")[ct.type] = &ct; - } -} - -static void -process2 (options const& ops, features& f, semantics::unit& u) -{ - unique_ptr ctx (create_context (cerr, u, ops, f, 0)); - - // Common processing. - // - { - traversal::unit unit; - traversal::defines unit_defines; - typedefs unit_typedefs (true); - traversal::namespace_ ns; - class_ c; - - unit >> unit_defines >> ns; - unit_defines >> c; - unit >> unit_typedefs >> c; - - traversal::defines ns_defines; - typedefs ns_typedefs (true); - - ns >> ns_defines >> ns; - ns_defines >> c; - ns >> ns_typedefs >> c; - - unit.dispatch (ctx->unit); - } - - // Database-specific processing. - // - switch (ops.database ()[0]) - { - case database::common: - { - break; - } - case database::mssql: - case database::mysql: - case database::oracle: - case database::pgsql: - case database::sqlite: - { - relational::process (); - break; - } - } -} - -void -process (options const& ops, - features& f, - semantics::unit& u, - semantics::path const&, - unsigned short pass) -{ - try - { - if (pass == 1) - process1 (u); - else if (pass == 2) - process2 (ops, f, u); - } - catch (operation_failed const&) - { - // Processing failed. Diagnostics has already been issued. - // - throw processor_failed (); - } -} -- cgit v1.1