aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--odb/context.cxx29
-rw-r--r--odb/context.hxx26
-rw-r--r--odb/location.hxx2
-rw-r--r--odb/options.cli78
-rw-r--r--odb/parser.cxx2
-rw-r--r--odb/pragma.cxx2
-rw-r--r--odb/relational/inline.hxx2
-rw-r--r--odb/relational/processor.cxx433
-rw-r--r--odb/relational/source.cxx56
-rw-r--r--odb/relational/source.hxx47
10 files changed, 519 insertions, 158 deletions
diff --git a/odb/context.cxx b/odb/context.cxx
index 8a80030..6b59033 100644
--- a/odb/context.cxx
+++ b/odb/context.cxx
@@ -439,6 +439,8 @@ context (ostream& os_,
db (options.database ()),
keyword_set (data_->keyword_set_),
include_regex (data_->include_regex_),
+ accessor_regex (data_->accessor_regex_),
+ modifier_regex (data_->modifier_regex_),
embedded_schema (ops.generate_schema () &&
ops.schema_format ().count (schema_format::embedded)),
separate_schema (ops.generate_schema () &&
@@ -455,6 +457,27 @@ context (ostream& os_,
for (strings::const_iterator i (ops.include_regex ().begin ());
i != ops.include_regex ().end (); ++i)
data_->include_regex_.push_back (regexsub (*i));
+
+ // Common accessor/modifier naming variants. Try the user-supplied and
+ // more specific ones first.
+ //
+ for (strings::const_iterator i (ops.accessor_regex ().begin ());
+ i != ops.accessor_regex ().end (); ++i)
+ data_->accessor_regex_.push_back (regexsub (*i));
+
+ data_->accessor_regex_.push_back (regexsub ("/(.+)/get_$1/")); // get_foo
+ data_->accessor_regex_.push_back (regexsub ("/(.+)/get\\u$1/")); // getFoo
+ data_->accessor_regex_.push_back (regexsub ("/(.+)/get$1/")); // getfoo
+ data_->accessor_regex_.push_back (regexsub ("/(.+)/$1/")); // foo
+
+ for (strings::const_iterator i (ops.modifier_regex ().begin ());
+ i != ops.modifier_regex ().end (); ++i)
+ data_->modifier_regex_.push_back (regexsub (*i));
+
+ data_->modifier_regex_.push_back (regexsub ("/(.+)/set_$1/")); // set_foo
+ data_->modifier_regex_.push_back (regexsub ("/(.+)/set\\u$1/")); // setFoo
+ data_->modifier_regex_.push_back (regexsub ("/(.+)/set$1/")); // setfoo
+ data_->modifier_regex_.push_back (regexsub ("/(.+)/$1/")); // foo
}
context::
@@ -467,6 +490,8 @@ context ()
db (current ().db),
keyword_set (current ().keyword_set),
include_regex (current ().include_regex),
+ accessor_regex (current ().accessor_regex),
+ modifier_regex (current ().modifier_regex),
embedded_schema (current ().embedded_schema),
separate_schema (current ().separate_schema),
top_object (current ().top_object),
@@ -1542,9 +1567,9 @@ public_name_db (semantics::data_member& m) const
}
string context::
-public_name (semantics::data_member& m) const
+public_name (semantics::data_member& m, bool e) const
{
- return escape (public_name_impl (m));
+ return e ? escape (public_name_impl (m)) : public_name_impl (m);
}
string context::
diff --git a/odb/context.hxx b/odb/context.hxx
index 5d8c339..a24edee 100644
--- a/odb/context.hxx
+++ b/odb/context.hxx
@@ -22,6 +22,7 @@
#include <odb/options.hxx>
#include <odb/features.hxx>
+#include <odb/location.hxx>
#include <odb/cxx-token.hxx>
#include <odb/semantics.hxx>
#include <odb/semantics/relational/name.hxx>
@@ -221,18 +222,29 @@ struct column_expr: std::vector<column_expr_part>
//
struct member_access
{
- member_access (location_t l): loc (l), by_value (false) {}
+ member_access (const location& l, bool s)
+ : loc (l), synthesized (s), by_value (false) {}
// Return true of we have the (?) placeholder.
//
bool
placeholder () const;
+ // Return true if this is a synthesized expression that goes
+ // directly for the member.
+ //
+ bool
+ direct () const
+ {
+ return synthesized && expr.size () == 3; // this.member
+ }
+
std::string
translate (std::string const& obj,
std::string const& val = std::string ()) const;
- location_t loc; // If zero, then this is a synthesized expression.
+ location loc;
+ bool synthesized; // If true, then this is a synthesized expression.
cxx_tokens expr;
bool by_value; // True if accessor returns by value. False doesn't
// necessarily mean that it is by reference.
@@ -653,11 +665,11 @@ public:
// C++ names.
//
public:
- // Cleaned-up and escaped member name that can be used in public C++
- // interfaces.
+ // Cleaned-up and potentially escaped member name that can be used
+ // in public C++ interfaces.
//
string
- public_name (semantics::data_member&) const;
+ public_name (semantics::data_member&, bool escape = true) const;
// "Flatten" fully-qualified C++ name by replacing '::' with '_'
// and removing leading '::', if any.
@@ -930,6 +942,8 @@ protected:
type_map_type type_map_;
regex_mapping include_regex_;
+ regex_mapping accessor_regex_;
+ regex_mapping modifier_regex_;
};
typedef cutl::shared_ptr<data> data_ptr;
@@ -947,6 +961,8 @@ public:
keyword_set_type const& keyword_set;
regex_mapping const& include_regex;
+ regex_mapping const& accessor_regex;
+ regex_mapping const& modifier_regex;
bool embedded_schema;
bool separate_schema;
diff --git a/odb/location.hxx b/odb/location.hxx
index a9cc6ad..658cd1b 100644
--- a/odb/location.hxx
+++ b/odb/location.hxx
@@ -12,9 +12,7 @@
struct location
{
- explicit
location (location_t);
-
location (cutl::fs::path const& f, std::size_t l, std::size_t c)
: file (f), line (l), column (c)
{
diff --git a/odb/options.cli b/odb/options.cli
index d205039..8705283 100644
--- a/odb/options.cli
+++ b/odb/options.cli
@@ -408,6 +408,84 @@ class options
option)."
};
+ // Accessor/modifier options.
+ //
+ std::vector<std::string> --accessor-regex
+ {
+ "<regex>",
+ "Add <regex> to the list of regular expressions used to transform
+ data member names to function names when searching for a suitable
+ accessor function. The argument to this option is a Perl-like regular
+ expression in the form \c{\b{/}\i{pattern}\b{/}\i{replacement}\b{/}}.
+ Any character can be used as a delimiter instead of \cb{/} and the
+ delimiter can be escaped inside \ci{pattern} and \ci{replacement}
+ with a backslash (\cb{\\}). You can specify multiple regular
+ expressions by repeating this option.
+
+ All the regular expressions are tried in the order specified and
+ the first expression that produces a suitable accessor function is
+ used. Each expression is tried twice: first with the actual member
+ name and then with the member's \i{public name} which is obtained by
+ removing the common member name decorations, such as leading and
+ trailing underscores, the \cb{m_} prefix, etc. The ODB compiler also
+ includes a number of built-in expressions for commonly used accessor
+ names, such as \cb{get_foo}, \cb{getFoo}, \cb{getfoo}, and just
+ \cb{foo}. The built-in expressions are tried last.
+
+ As an example, the following expression transforms data members with
+ public names in the form \cb{foo} to accessor names in the form
+ \cb{GetFoo}:
+
+ \cb{/(.+)/Get\\u$1/}
+
+ See also the REGEX AND SHELL QUOTING section below."
+ };
+
+ bool --accessor-regex-trace
+ {
+ "Trace the process of applying regular expressions specified with the
+ \cb{--accessor-regex} option. Use this option to find out why your
+ regular expressions don't do what you expected them to do."
+ };
+
+ std::vector<std::string> --modifier-regex
+ {
+ "<regex>",
+ "Add <regex> to the list of regular expressions used to transform
+ data member names to function names when searching for a suitable
+ modifier function. The argument to this option is a Perl-like regular
+ expression in the form \c{\b{/}\i{pattern}\b{/}\i{replacement}\b{/}}.
+ Any character can be used as a delimiter instead of \cb{/} and the
+ delimiter can be escaped inside \ci{pattern} and \ci{replacement}
+ with a backslash (\cb{\\}). You can specify multiple regular
+ expressions by repeating this option.
+
+ All the regular expressions are tried in the order specified and
+ the first expression that produces a suitable modifier function is
+ used. Each expression is tried twice: first with the actual member
+ name and then with the member's \i{public name} which is obtained by
+ removing the common member name decorations, such as leading and
+ trailing underscores, the \cb{m_} prefix, etc. The ODB compiler also
+ includes a number of built-in expressions for commonly used modifier
+ names, such as \cb{set_foo}, \cb{setFoo}, \cb{setfoo}, and just
+ \cb{foo}. The built-in expressions are tried last.
+
+ As an example, the following expression transforms data members with
+ public names in the form \cb{foo} to modifier names in the form
+ \cb{SetFoo}:
+
+ \cb{/(.+)/Set\\u$1/}
+
+ See also the REGEX AND SHELL QUOTING section below."
+ };
+
+ bool --modifier-regex-trace
+ {
+ "Trace the process of applying regular expressions specified with the
+ \cb{--modifier-regex} option. Use this option to find out why your
+ regular expressions don't do what you expected them to do."
+ };
+
// Include options.
//
bool --include-with-brackets
diff --git a/odb/parser.cxx b/odb/parser.cxx
index 9a19440..c5456d6 100644
--- a/odb/parser.cxx
+++ b/odb/parser.cxx
@@ -141,6 +141,8 @@ private:
access
decl_access (tree decl)
{
+ // Note that TREE_PUBLIC() returns something other than what we need.
+ //
if (TREE_PRIVATE (decl))
return access::private_;
diff --git a/odb/pragma.cxx b/odb/pragma.cxx
index d440f82..6fea747 100644
--- a/odb/pragma.cxx
+++ b/odb/pragma.cxx
@@ -887,7 +887,7 @@ handle_pragma (cxx_lexer& l,
tt = l.next (tl, &tn);
- val = member_access (loc);
+ val = member_access (loc, false);
if (!parse_expression (l, tt, tl, tn, val.value<member_access> ().expr, p))
return; // Diagnostics has already been issued.
diff --git a/odb/relational/inline.hxx b/odb/relational/inline.hxx
index 2642809..ff97874 100644
--- a/odb/relational/inline.hxx
+++ b/odb/relational/inline.hxx
@@ -275,7 +275,7 @@ namespace relational
//
member_access& ma (id->get<member_access> ("get"));
- if (ma.loc != 0)
+ if (!ma.synthesized)
os << "// From " << location_string (ma.loc, true) << endl;
os << "return " << ma.translate ("o") << ";";
diff --git a/odb/relational/processor.cxx b/odb/relational/processor.cxx
index 7e2bf53..edafeac 100644
--- a/odb/relational/processor.cxx
+++ b/odb/relational/processor.cxx
@@ -310,30 +310,326 @@ namespace relational
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)
+ {
+ // 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;
+ }
+ // 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)
{
- // If we don't have an access expression, synthesize one which
- // goes directly for the member. Zero location indicates it is
- // a synthesized one.
+ 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))
{
- member_access& ma (m.set (k, member_access (0)));
- 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 ()));
- return;
+ 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 public or if we are a friend of this
+ // class, then go for the member directly.
+ //
+ if (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 ());
+
+ 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" << endl;
+
+ throw operation_failed ();
+ }
}
- semantics::type& t (utype (m));
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 it is just a name, resolve it and convert to an appropriate
+ // expression.
//
if (e.size () == 1 && e.back ().type == CPP_NAME)
{
@@ -342,10 +638,7 @@ namespace relational
tree decl (
lookup_qualified_name (
- m.scope ().tree_node (),
- get_identifier (n.c_str ()),
- false,
- false));
+ c.tree_node (), get_identifier (n.c_str ()), false, false));
if (decl == error_mark_node)
{
@@ -378,90 +671,15 @@ namespace relational
if (!DECL_NONSTATIC_MEMBER_FUNCTION_P (f))
continue;
- // Note that we have to use TREE_TYPE(TREE_TYPE()) and
- // not DECL_RESULT, as suggested by the documentation.
- //
- tree r (TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (f))));
- tree a (DECL_ARGUMENTS (f));
- a = DECL_CHAIN (a); // Skip this.
-
- if (k == "get")
- {
- // For an accessor, look for a function with a non-void
- // return value and no arguments (other than 'this').
- //
- if (r != void_type_node && a == NULL_TREE)
- {
- 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.
- //
- int tc (TREE_CODE (r));
- ma.by_value = (tc != REFERENCE_TYPE && tc != POINTER_TYPE);
- break;
- }
- }
- else
- {
- // 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 proper modifier
- // that sets a new value. If both are available, we
- // prefer the former for efficiency.
- //
- semantics::array* ar (dynamic_cast<semantics::array*> (&t));
- int tc (TREE_CODE (r));
-
- if (a == NULL_TREE &&
- ((ar == 0 && tc == REFERENCE_TYPE) ||
- (ar != 0 && tc == POINTER_TYPE)))
- {
- tree bt (TREE_TYPE (r)); // Base type.
- tree bt_mv (TYPE_MAIN_VARIANT (bt));
-
- if (!CP_TYPE_CONST_P (bt) &&
- ((ar == 0 && bt_mv == t.tree_node ()) ||
- (ar != 0 && bt_mv == ar->base_type ().tree_node ())))
- {
- e.clear (); // Could contain proper 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));
- break;
- }
- }
-
- // Any function with a single argument works for us.
- // And we don't care what it returns.
- //
- if (a != NULL_TREE && DECL_CHAIN (a) == NULL_TREE)
- {
- 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).
- }
- }
+ 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 "
- << (k == "get" ? "accessor" : "modifier")
+ error (ma.loc) << "unable to find suitable " << kind
<< " function '" << n << "'" << endl;
throw operation_failed ();
}
@@ -506,13 +724,13 @@ namespace relational
}
// Check that the member type is default-constructible if we
- // have a placeholder in the modifier.
+ // have a by value modifier.
//
if (k == "set" && ma.placeholder ())
{
// Assume all other types are default-constructible.
//
- semantics::class_* c (dynamic_cast<semantics::class_*> (&t));
+ semantics::class_* c (dynamic_cast<semantics::class_*> (&utype (m)));
if (c != 0 && !c->default_ctor ())
{
@@ -2031,7 +2249,7 @@ namespace relational
struct class_: traversal::class_, context
{
class_ ()
- : std_string_ (0), std_string_hint_ (0)
+ : std_string_ (0), std_string_hint_ (0), access_ (0)
{
// Resolve the std::string type node.
//
@@ -2056,6 +2274,19 @@ namespace relational
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_;
}
@@ -2067,6 +2298,10 @@ 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)
@@ -3226,6 +3461,8 @@ namespace relational
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 e525089..1289b9d 100644
--- a/odb/relational/source.cxx
+++ b/odb/relational/source.cxx
@@ -945,7 +945,7 @@ traverse_object (type& c)
{
member_access& ma (id->get<member_access> ("set"));
- if (ma.loc != 0)
+ if (!ma.synthesized)
os << "// From " << location_string (ma.loc, true) << endl;
if (ma.placeholder ())
@@ -953,11 +953,11 @@ traverse_object (type& c)
<< endl;
else
{
- // If this member is const and we have a synthesized access, then
- // cast away constness. Otherwise, we assume that the user-provided
- // expression handles this.
+ // If this member is const and we have a synthesized direct access,
+ // then cast away constness. Otherwise, we assume that the user-
+ // provided expression handles this.
//
- bool cast (ma.loc == 0 && const_type (id->type ()));
+ bool cast (ma.direct () && const_type (id->type ()));
if (cast)
os << "const_cast< id_type& > (" << endl;
@@ -979,7 +979,7 @@ traverse_object (type& c)
//
string obj (auto_id ? "obj" : "const_cast< object_type& > (obj)");
- if (opt_ma_set->loc != 0)
+ if (!opt_ma_set->synthesized)
os << "// From " << location_string (opt_ma_set->loc, true) << endl;
if (opt_ma_set->placeholder ())
@@ -987,11 +987,11 @@ traverse_object (type& c)
<< endl;
else
{
- // If this member is const and we have a synthesized access, then
- // cast away constness. Otherwise, we assume that the user-provided
- // expression handles this.
+ // If this member is const and we have a synthesized direct access,
+ // then cast away constness. Otherwise, we assume that the user-
+ // provided expression handles this.
//
- bool cast (opt_ma_set->loc == 0 && const_type (opt->type ()));
+ bool cast (opt_ma_set->direct () && const_type (opt->type ()));
if (cast)
os << "const_cast< version_type& > (" << endl;
@@ -1020,7 +1020,7 @@ traverse_object (type& c)
os << "id_image_type& i (sts.id_image ());";
- if (id_ma->loc != 0)
+ if (!id_ma->synthesized)
os << "// From " << location_string (id_ma->loc, true) << endl;
os << "init (i, " << id_ma->translate ("obj") << ");"
@@ -1153,7 +1153,7 @@ traverse_object (type& c)
os << "{"
<< "id_image_type& i (sts.id_image ());";
- if (id_ma->loc != 0)
+ if (!id_ma->synthesized)
os << "// From " << location_string (id_ma->loc, true) << endl;
os << "init (i, " << id_ma->translate ("obj") << ");"
@@ -1216,7 +1216,7 @@ traverse_object (type& c)
// exists in the database. Use the discriminator_() call for
// that.
//
- if (id_ma->loc != 0)
+ if (!id_ma->synthesized)
os << "// From " << location_string (id_ma->loc, true) << endl;
os << "root_traits::discriminator_ (sts.root_statements (), " <<
@@ -1238,7 +1238,7 @@ traverse_object (type& c)
//
if (opt != 0)
{
- if (opt_ma_get->loc != 0)
+ if (!opt_ma_get->synthesized)
os << "// From " << location_string (opt_ma_get->loc, true) << endl;
os << "const version_type& v (" << endl
@@ -1247,7 +1247,7 @@ traverse_object (type& c)
os << "id_image_type& i (sts.id_image ());";
- if (id_ma->loc != 0)
+ if (!id_ma->synthesized)
os << "// From " << location_string (id_ma->loc, true) << endl;
os << "init (i, " << id_ma->translate ("obj");
@@ -1334,7 +1334,7 @@ traverse_object (type& c)
<< "conn.statement_cache ().find_object<object_type> ());"
<< endl;
- if (id_ma->loc != 0)
+ if (!id_ma->synthesized)
os << "// From " << location_string (id_ma->loc, true) << endl;
os << "const id_type& id (" << endl
@@ -1398,12 +1398,12 @@ traverse_object (type& c)
//
string obj ("const_cast< object_type& > (obj)");
- if (opt_ma_set->loc != 0)
+ if (!opt_ma_set->synthesized)
os << "// From " << location_string (opt_ma_set->loc, true) << endl;
if (opt_ma_set->placeholder ())
{
- if (opt_ma_get->loc != 0)
+ if (!opt_ma_get->synthesized)
os << "// From " << location_string (opt_ma_get->loc, true) <<
endl;
@@ -1413,11 +1413,11 @@ traverse_object (type& c)
}
else
{
- // If this member is const and we have a synthesized access, then
- // cast away constness. Otherwise, we assume that the user-provided
- // expression handles this.
+ // If this member is const and we have a synthesized direct access,
+ // then cast away constness. Otherwise, we assume that the user-
+ // provided expression handles this.
//
- bool cast (opt_ma_set->loc == 0 && const_type (opt->type ()));
+ bool cast (opt_ma_set->direct () && const_type (opt->type ()));
if (cast)
os << "const_cast< version_type& > (" << endl;
@@ -1644,7 +1644,7 @@ traverse_object (type& c)
if (!abst || straight_containers)
{
- if (id_ma->loc != 0)
+ if (!id_ma->synthesized)
os << "// From " << location_string (id_ma->loc, true) << endl;
os << "const id_type& id (" << endl
@@ -1663,7 +1663,7 @@ traverse_object (type& c)
os << "if (top)"
<< "{";
- if (opt_ma_get->loc != 0)
+ if (!opt_ma_get->synthesized)
os << "// From " << location_string (opt_ma_get->loc, true) << endl;
os << "const version_type& v (" << endl
@@ -1721,7 +1721,7 @@ traverse_object (type& c)
<< "root_traits::discriminator_ (" << rsts << ", id, 0, &v);"
<< endl;
- if (opt_ma_get->loc != 0)
+ if (!opt_ma_get->synthesized)
os << "// From " << location_string (opt_ma_get->loc, true) << endl;
os << "if (v != " << opt_ma_get->translate ("obj") << ")" << endl
@@ -1755,7 +1755,7 @@ traverse_object (type& c)
os << "sts.find_statement ().free_result ();"
<< endl;
- if (opt_ma_get->loc != 0)
+ if (!opt_ma_get->synthesized)
os << "// From " << location_string (opt_ma_get->loc, true) << endl;
os << "if (version (sts.image ()) != " <<
@@ -2148,7 +2148,7 @@ traverse_object (type& c)
<< "statements_type::auto_lock l (" << rsts << ");"
<< endl;
- if (id_ma->loc != 0)
+ if (!id_ma->synthesized)
os << "// From " << location_string (id_ma->loc, true) << endl;
os << "const id_type& id (" << endl
@@ -2170,7 +2170,7 @@ traverse_object (type& c)
if (opt != 0)
{
- if (opt_ma_get->loc != 0)
+ if (!opt_ma_get->synthesized)
os << "// From " << location_string (opt_ma_get->loc, true) << endl;
os << "if (" << (poly_derived ? "root_traits::" : "") << "version (" <<
diff --git a/odb/relational/source.hxx b/odb/relational/source.hxx
index 38bb80f..21ab776 100644
--- a/odb/relational/source.hxx
+++ b/odb/relational/source.hxx
@@ -1201,7 +1201,7 @@ namespace relational
// If this is not a synthesized expression, then output
// its location for easier error tracking.
//
- if (ma.loc != 0)
+ if (!ma.synthesized)
os << "// From " << location_string (ma.loc, true) << endl;
// Use the original type to form the const reference.
@@ -1512,7 +1512,7 @@ namespace relational
// If this is not a synthesized expression, then output
// its location for easier error tracking.
//
- if (ma.loc != 0)
+ if (!ma.synthesized)
os << "// From " << location_string (ma.loc, true) << endl;
// See if we are modifying via a reference or proper modifier.
@@ -1526,17 +1526,18 @@ namespace relational
//
os << member_ref_type (mi.m, false, "v") << " (" << endl;
- // If this member is const and we have a synthesized access,
- // then cast away constness. Otherwise, we assume that the
- // user-provided expression handles this.
+ // If this member is const and we have a synthesized direct
+ // access, then cast away constness. Otherwise, we assume
+ // that the user-provided expression handles this.
//
- if (mi.cq && ma.loc == 0)
+ bool cast (mi.cq && ma.direct ());
+ if (cast)
os << "const_cast< " << member_ref_type (mi.m, false) <<
" > (" << endl;
os << ma.translate ("o");
- if (mi.cq && ma.loc == 0)
+ if (cast)
os << ")";
os << ");"
@@ -1678,7 +1679,7 @@ namespace relational
// If this is not a synthesized expression, then output its
// location for easier error tracking.
//
- if (ma.loc != 0)
+ if (!ma.synthesized)
os << "// From " << location_string (ma.loc, true) << endl;
os << ma.translate ("o", "v") << ";";
@@ -2999,24 +3000,26 @@ namespace relational
string old_f (from_);
obj_prefix_.clear ();
- // If this member is const and we have a synthesized access,
- // then cast away constness. Otherwise, we assume that the
- // user-provided expression handles this.
+ // If this member is const and we have a synthesized direct
+ // access, then cast away constness. Otherwise, we assume
+ // that the user-provided expression handles this.
//
- if (call_ == load_call && ma.loc == 0 && const_type (m->type ()))
+ bool cast (
+ call_ == load_call && ma.direct () && const_type (m->type ()));
+ if (cast)
obj_prefix_ = "const_cast< " + member_ref_type (*m, false) +
" > (\n";
obj_prefix_ += ma.translate (old_op);
- if (call_ == load_call && ma.loc == 0 && const_type (m->type ()))
+ if (cast)
obj_prefix_ += ")";
// If this is not a synthesized expression, then store its
// location which we will output later for easier error
// tracking.
//
- if (ma.loc != 0)
+ if (!ma.synthesized)
from_ += "// From " + location_string (ma.loc, true) + "\n";
// If this is a wrapped composite value, then we need to "unwrap" it.
@@ -3091,7 +3094,7 @@ namespace relational
// If this is not a synthesized expression, then output its
// location for easier error tracking.
//
- if (ma.loc != 0)
+ if (!ma.synthesized)
os << "// From " << location_string (ma.loc, true) << endl;
// See if we are modifying via a reference or proper modifier.
@@ -3103,17 +3106,19 @@ namespace relational
{
os << member_ref_type (m, call_ != load_call, "v") << " (" << endl;
- // If this member is const and we have a synthesized access,
- // then cast away constness. Otherwise, we assume that the
- // user-provided expression handles this.
+ // If this member is const and we have a synthesized direct
+ // access, then cast away constness. Otherwise, we assume
+ // that the user-provided expression handles this.
//
- if (call_ == load_call && ma.loc == 0 && const_type (m.type ()))
+ bool cast (
+ call_ == load_call && ma.direct () && const_type (m.type ()));
+ if (cast)
os << "const_cast< " << member_ref_type (m, false) <<
" > (" << endl;
os << ma.translate (obj_prefix_);
- if (call_ == load_call && ma.loc == 0 && const_type (m.type ()))
+ if (cast)
os << ")";
os << ");"
@@ -3182,7 +3187,7 @@ namespace relational
// If this is not a synthesized expression, then output its
// location for easier error tracking.
//
- if (ma.loc != 0)
+ if (!ma.synthesized)
os << "// From " << location_string (ma.loc, true) << endl;
os << ma.translate (obj_prefix_, "v") << ";";