aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2011-07-19 13:42:18 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2011-07-19 13:42:18 +0200
commit73c98a67ef4ed605cf69e0d212934c4dc1f3eb8e (patch)
tree8645cd8d06f218ff5d945b1b3b94a58a127753c4
parent12d0d9bbd0f5b7295c50fd5b223e538afe1abbf7 (diff)
New design for NULL semantics
Now, instead of being specified as part of the SQL type with the type pragma, there are separate null and not_null pragmas. The not_null pragma was used to control NULL-ness of object pointers. Now the two pragmas are used consistently for object pointers and simple values (and in the future will work for composite values and containers).
-rw-r--r--odb/context.cxx64
-rw-r--r--odb/context.hxx43
-rw-r--r--odb/pragma.cxx40
-rw-r--r--odb/relational/mysql/context.cxx10
-rw-r--r--odb/relational/mysql/context.hxx5
-rw-r--r--odb/relational/mysql/schema.cxx18
-rw-r--r--odb/relational/mysql/source.cxx4
-rw-r--r--odb/relational/pgsql/context.cxx12
-rw-r--r--odb/relational/pgsql/context.hxx5
-rw-r--r--odb/relational/pgsql/source.cxx4
-rw-r--r--odb/relational/schema.hxx8
-rw-r--r--odb/relational/sqlite/context.cxx12
-rw-r--r--odb/relational/sqlite/context.hxx6
-rw-r--r--odb/relational/sqlite/source.cxx4
-rw-r--r--odb/relational/type-processor.cxx93
-rw-r--r--odb/validator.cxx83
16 files changed, 282 insertions, 129 deletions
diff --git a/odb/context.cxx b/odb/context.cxx
index 04761f8..520caea 100644
--- a/odb/context.cxx
+++ b/odb/context.cxx
@@ -145,6 +145,47 @@ context ()
context* context::current_;
+bool context::
+null (semantics::data_member& m)
+{
+ semantics::type& t (m.type ());
+
+ // By default pointers can be null.
+ //
+ if (object_pointer (t))
+ return m.count ("null") ||
+ (!m.count ("not-null") &&
+ (t.count ("null") || !t.count ("not-null")));
+ else
+ // Everything else by default is not null.
+ //
+ return m.count ("null") ||
+ (!m.count ("not-null") && t.count ("null"));
+}
+
+bool context::
+null (semantics::data_member& m, string const& kp)
+{
+ if (kp.empty ())
+ return null (m);
+
+ semantics::type& c (m.type ());
+ semantics::type& t (member_type (m, kp));
+
+ if (object_pointer (t))
+ return m.count (kp + "-null") ||
+ (!m.count (kp + "-not-null") &&
+ (c.count (kp + "-null") ||
+ (!c.count (kp + "-not-null") &&
+ (t.count ("null") || !t.count ("not-null")))));
+ else
+ return m.count (kp + "-null") ||
+ (!m.count (kp + "-not-null") &&
+ (c.count (kp + "-null") ||
+ (!c.count (kp + "-not-null") &&
+ t.count ("null"))));
+}
+
string context::
upcase (string const& s)
{
@@ -192,7 +233,7 @@ comp_value_ (semantics::class_& c)
{
bool r (true);
- //@@ This is bad. Did I add new value pragmas and forgot to
+ //@@ This is bad. Did we add new value pragmas and forgot to
// account for them here?
//
r = r && c.count ("value");
@@ -206,7 +247,10 @@ comp_value_ (semantics::class_& c)
r = r && !c.count ("index-column");
r = r && !c.count ("key-column");
r = r && !c.count ("id-column");
+ r = r && !c.count ("null");
r = r && !c.count ("not-null");
+ r = r && !c.count ("value-null");
+ r = r && !c.count ("value-not-null");
r = r && !c.count ("unordered");
c.set ("composite-value", r);
@@ -269,10 +313,7 @@ column_type (semantics::data_member& m, string const& kp)
}
string context::
-database_type_impl (semantics::type& t,
- semantics::names* hint,
- semantics::context& ctx,
- column_type_flags f)
+database_type_impl (semantics::type& t, semantics::names* hint, bool id)
{
type_map_type::const_iterator end (data_->type_map_.end ()), i (end);
@@ -293,16 +334,9 @@ database_type_impl (semantics::type& t,
i = data_->type_map_.find (t.fq_name ());
if (i != end)
- {
- string r (ctx.count ("id") ? i->second.id_type : i->second.type);
-
- if ((f & ctf_default_null) == 0)
- r += " NOT NULL";
-
- return r;
- }
-
- return string ();
+ return id ? i->second.id_type : i->second.type;
+ else
+ return string ();
}
static string
diff --git a/odb/context.hxx b/odb/context.hxx
index 54f6832..a256866 100644
--- a/odb/context.hxx
+++ b/odb/context.hxx
@@ -123,6 +123,12 @@ public:
return c.abstract () || c.count ("abstract");
}
+ bool
+ null (semantics::data_member&);
+
+ bool
+ null (semantics::data_member&, string const& key_prefix);
+
// Database names and types.
//
public:
@@ -225,23 +231,6 @@ public:
return pointer_kind (p) == pk_weak;
}
- bool
- null_pointer (semantics::data_member& m)
- {
- return !(m.count ("not-null") || m.type ().count ("not-null"));
- }
-
- bool
- null_pointer (semantics::data_member& m, string const& key_prefix)
- {
- if (key_prefix.empty ())
- return null_pointer (m);
-
- return !(m.count (key_prefix + "-not-null") ||
- m.type ().count ("not-null") ||
- member_type (m, key_prefix).count ("not-null"));
- }
-
semantics::data_member*
inverse (semantics::data_member& m)
{
@@ -441,33 +430,19 @@ public:
// Per-database customizable functionality.
//
protected:
- typedef unsigned short column_type_flags;
-
- static column_type_flags const ctf_none = 0;
-
- // Default type should be NULL-able.
- //
- static column_type_flags const ctf_default_null = 0x01;
-
// Return empty string if there is no mapping.
//
string
- database_type (semantics::type& t,
- semantics::names* hint,
- semantics::context& c,
- column_type_flags f)
+ database_type (semantics::type& t, semantics::names* hint, bool id)
{
- return current ().database_type_impl (t, hint, c, f);
+ return current ().database_type_impl (t, hint, id);
}
// The default implementation uses the type map (populated by the database-
// specific context implementation) to come up with a mapping.
//
virtual string
- database_type_impl (semantics::type&,
- semantics::names*,
- semantics::context&,
- column_type_flags);
+ database_type_impl (semantics::type&, semantics::names*, bool);
public:
typedef context root_context;
diff --git a/odb/pragma.cxx b/odb/pragma.cxx
index 3b8d222..8408489 100644
--- a/odb/pragma.cxx
+++ b/odb/pragma.cxx
@@ -198,9 +198,13 @@ check_decl_type (tree d, string const& name, string const& p, location_t l)
return false;
}
}
- else if (p == "not_null")
+ else if (p == "null" ||
+ p == "not_null" ||
+ p == "value_null" ||
+ p == "value_not_null")
{
- // Not_null can be used for both members and types (container or pointer).
+ // Null pragmas can be used for both members and types (values,
+ // containers, and pointers).
//
if (tc != FIELD_DECL && !TYPE_P (d))
{
@@ -518,9 +522,15 @@ handle_pragma (cpp_reader* reader,
tt = pragma_lex (&t);
}
- else if (p == "not_null")
+ else if (p == "null" ||
+ p == "not_null" ||
+ p == "value_null" ||
+ p == "value_not_null")
{
+ // null
// not_null
+ // value_null
+ // value_not_null
//
// Make sure we've got the correct declaration type.
@@ -766,7 +776,10 @@ handle_pragma_qualifier (cpp_reader* reader, string const& p)
p == "index_type" ||
p == "key_type" ||
p == "table" ||
+ p == "null" ||
p == "not_null" ||
+ p == "value_null" ||
+ p == "value_not_null" ||
p == "inverse" ||
p == "unordered" ||
p == "transient")
@@ -903,12 +916,30 @@ handle_pragma_db_table (cpp_reader* reader)
}
extern "C" void
+handle_pragma_db_null (cpp_reader* reader)
+{
+ handle_pragma_qualifier (reader, "null");
+}
+
+extern "C" void
handle_pragma_db_not_null (cpp_reader* reader)
{
handle_pragma_qualifier (reader, "not_null");
}
extern "C" void
+handle_pragma_db_value_null (cpp_reader* reader)
+{
+ handle_pragma_qualifier (reader, "value_null");
+}
+
+extern "C" void
+handle_pragma_db_value_not_null (cpp_reader* reader)
+{
+ handle_pragma_qualifier (reader, "value_not_null");
+}
+
+extern "C" void
handle_pragma_db_inverse (cpp_reader* reader)
{
handle_pragma_qualifier (reader, "inverse");
@@ -945,7 +976,10 @@ register_odb_pragmas (void*, void*)
c_register_pragma_with_expansion ("db", "index_type", handle_pragma_db_itype);
c_register_pragma_with_expansion ("db", "key_type", handle_pragma_db_ktype);
c_register_pragma_with_expansion ("db", "table", handle_pragma_db_table);
+ c_register_pragma_with_expansion ("db", "null", handle_pragma_db_null);
c_register_pragma_with_expansion ("db", "not_null", handle_pragma_db_not_null);
+ c_register_pragma_with_expansion ("db", "value_null", handle_pragma_db_value_null);
+ c_register_pragma_with_expansion ("db", "value_not_null", handle_pragma_db_value_not_null);
c_register_pragma_with_expansion ("db", "inverse", handle_pragma_db_inverse);
c_register_pragma_with_expansion ("db", "unordered", handle_pragma_db_unordered);
c_register_pragma_with_expansion ("db", "transient", handle_pragma_db_transient);
diff --git a/odb/relational/mysql/context.cxx b/odb/relational/mysql/context.cxx
index e9446c2..431470a 100644
--- a/odb/relational/mysql/context.cxx
+++ b/odb/relational/mysql/context.cxx
@@ -234,12 +234,9 @@ namespace relational
}
string context::
- database_type_impl (semantics::type& t,
- semantics::names* hint,
- semantics::context& ctx,
- column_type_flags f)
+ database_type_impl (semantics::type& t, semantics::names* hint, bool id)
{
- string r (base_context::database_type_impl (t, hint, ctx, f));
+ string r (base_context::database_type_impl (t, hint, id));
if (!r.empty ())
return r;
@@ -290,9 +287,6 @@ namespace relational
if (e->unsigned_ ())
r += " UNSIGNED";
}
-
- if ((f & ctf_default_null) == 0)
- r += " NOT NULL";
}
return r;
diff --git a/odb/relational/mysql/context.hxx b/odb/relational/mysql/context.hxx
index 019b878..00ebe57 100644
--- a/odb/relational/mysql/context.hxx
+++ b/odb/relational/mysql/context.hxx
@@ -97,10 +97,7 @@ namespace relational
protected:
virtual string
- database_type_impl (semantics::type&,
- semantics::names*,
- semantics::context&,
- column_type_flags);
+ database_type_impl (semantics::type&, semantics::names*, bool);
public:
virtual
diff --git a/odb/relational/mysql/schema.cxx b/odb/relational/mysql/schema.cxx
index 0b44c53..3848c75 100644
--- a/odb/relational/mysql/schema.cxx
+++ b/odb/relational/mysql/schema.cxx
@@ -37,11 +37,27 @@ namespace relational
}
};
- struct object_columns: relational::object_columns
+ struct object_columns: relational::object_columns, context
{
object_columns (base const& x): base (x) {}
virtual void
+ null (semantics::data_member& m)
+ {
+ if (!context::null (m, prefix_))
+ os << " NOT NULL";
+ else
+ {
+ // MySQL TIMESTAMP is by default NOT NULL. If we want it
+ // to contain NULL values, we need to explicitly declare
+ // the column as NULL.
+ //
+ if (column_sql_type (m, prefix_).type == sql_type::TIMESTAMP)
+ os << " NULL";
+ }
+ }
+
+ virtual void
constraints (semantics::data_member& m)
{
base::constraints (m);
diff --git a/odb/relational/mysql/source.cxx b/odb/relational/mysql/source.cxx
index 17bffdc..d3b4129 100644
--- a/odb/relational/mysql/source.cxx
+++ b/odb/relational/mysql/source.cxx
@@ -588,7 +588,7 @@ namespace relational
{
os << "}";
- if (!null_pointer (mi.m, key_prefix_))
+ if (!null (mi.m, key_prefix_))
os << "else" << endl
<< "throw null_pointer ();";
}
@@ -786,7 +786,7 @@ namespace relational
<< endl
<< "if (i." << mi.var << "null)" << endl;
- if (null_pointer (mi.m, key_prefix_))
+ if (null (mi.m, key_prefix_))
os << member << " = ptr_traits::pointer_type ();";
else
os << "throw null_pointer ();";
diff --git a/odb/relational/pgsql/context.cxx b/odb/relational/pgsql/context.cxx
index 5a6b158..6c6c5a0 100644
--- a/odb/relational/pgsql/context.cxx
+++ b/odb/relational/pgsql/context.cxx
@@ -211,12 +211,9 @@ namespace relational
}
string context::
- database_type_impl (semantics::type& t,
- semantics::names* hint,
- semantics::context& ctx,
- column_type_flags f)
+ database_type_impl (semantics::type& t, semantics::names* hint, bool id)
{
- string r (base_context::database_type_impl (t, hint, ctx, f));
+ string r (base_context::database_type_impl (t, hint, id));
if (!r.empty ())
return r;
@@ -224,13 +221,8 @@ namespace relational
using semantics::enum_;
if (t.is_a<semantics::enum_> ())
- {
r = "INTEGER";
- if ((f & ctf_default_null) == 0)
- r += " NOT NULL";
- }
-
return r;
}
diff --git a/odb/relational/pgsql/context.hxx b/odb/relational/pgsql/context.hxx
index 66d9318..a4fbc00 100644
--- a/odb/relational/pgsql/context.hxx
+++ b/odb/relational/pgsql/context.hxx
@@ -85,10 +85,7 @@ namespace relational
protected:
virtual string
- database_type_impl (semantics::type& t,
- semantics::names* hint,
- semantics::context& ctx,
- column_type_flags f);
+ database_type_impl (semantics::type& t, semantics::names* hint, bool);
public:
virtual
diff --git a/odb/relational/pgsql/source.cxx b/odb/relational/pgsql/source.cxx
index 0ed6890..3b7664d 100644
--- a/odb/relational/pgsql/source.cxx
+++ b/odb/relational/pgsql/source.cxx
@@ -502,7 +502,7 @@ namespace relational
{
os << "}";
- if (!null_pointer (mi.m, key_prefix_))
+ if (!null (mi.m, key_prefix_))
os << "else" << endl
<< "throw null_pointer ();";
}
@@ -674,7 +674,7 @@ namespace relational
<< endl
<< "if (i." << mi.var << "null)" << endl;
- if (null_pointer (mi.m, key_prefix_))
+ if (null (mi.m, key_prefix_))
os << member << " = ptr_traits::pointer_type ();";
else
os << "throw null_pointer ();";
diff --git a/odb/relational/schema.hxx b/odb/relational/schema.hxx
index b9243df..9d64276 100644
--- a/odb/relational/schema.hxx
+++ b/odb/relational/schema.hxx
@@ -189,6 +189,7 @@ namespace relational
os << " " << quote_id (name) << " ";
type (m);
+ null (m);
constraints (m);
reference (m);
@@ -202,6 +203,13 @@ namespace relational
}
virtual void
+ null (semantics::data_member& m)
+ {
+ if (!context::null (m, prefix_))
+ os << " NOT NULL";
+ }
+
+ virtual void
constraints (semantics::data_member& m)
{
if (m.count ("id"))
diff --git a/odb/relational/sqlite/context.cxx b/odb/relational/sqlite/context.cxx
index b026822..4d00621 100644
--- a/odb/relational/sqlite/context.cxx
+++ b/odb/relational/sqlite/context.cxx
@@ -197,12 +197,9 @@ namespace relational
}
string context::
- database_type_impl (semantics::type& t,
- semantics::names* hint,
- semantics::context& ctx,
- column_type_flags f)
+ database_type_impl (semantics::type& t, semantics::names* hint, bool id)
{
- string r (base_context::database_type_impl (t, hint, ctx, f));
+ string r (base_context::database_type_impl (t, hint, id));
if (!r.empty ())
return r;
@@ -210,13 +207,8 @@ namespace relational
using semantics::enum_;
if (t.is_a<semantics::enum_> ())
- {
r = "INTEGER";
- if ((f & ctf_default_null) == 0)
- r += " NOT NULL";
- }
-
return r;
}
diff --git a/odb/relational/sqlite/context.hxx b/odb/relational/sqlite/context.hxx
index c625069..b5c3d85 100644
--- a/odb/relational/sqlite/context.hxx
+++ b/odb/relational/sqlite/context.hxx
@@ -49,10 +49,8 @@ namespace relational
protected:
virtual string
- database_type_impl (semantics::type&,
- semantics::names*,
- semantics::context&,
- column_type_flags);
+ database_type_impl (semantics::type&, semantics::names*, bool);
+
public:
virtual
~context ();
diff --git a/odb/relational/sqlite/source.cxx b/odb/relational/sqlite/source.cxx
index 35a3246..6a99fc8 100644
--- a/odb/relational/sqlite/source.cxx
+++ b/odb/relational/sqlite/source.cxx
@@ -321,7 +321,7 @@ namespace relational
{
os << "}";
- if (!null_pointer (mi.m, key_prefix_))
+ if (!null (mi.m, key_prefix_))
os << "else" << endl
<< "throw null_pointer ();";
}
@@ -437,7 +437,7 @@ namespace relational
<< endl
<< "if (i." << mi.var << "null)" << endl;
- if (null_pointer (mi.m, key_prefix_))
+ if (null (mi.m, key_prefix_))
os << member << " = ptr_traits::pointer_type ();";
else
os << "throw null_pointer ();";
diff --git a/odb/relational/type-processor.cxx b/odb/relational/type-processor.cxx
index f7b0b2a..0f1c1d2 100644
--- a/odb/relational/type-processor.cxx
+++ b/odb/relational/type-processor.cxx
@@ -131,14 +131,7 @@ namespace relational
type = idt.get<string> ("type");
if (type.empty ())
- {
- column_type_flags f (ctf_none);
-
- if (null_pointer (m))
- f |= ctf_default_null;
-
- type = database_type (idt, id.belongs ().hint (), id, f);
- }
+ type = database_type (idt, id.belongs ().hint (), true);
}
else
{
@@ -149,12 +142,22 @@ namespace relational
type = t.get<string> ("type");
if (type.empty ())
- type = database_type (t, m.belongs ().hint (), m, ctf_none);
+ type = database_type (t, m.belongs ().hint (), m.count ("id"));
}
if (!type.empty ())
{
m.set ("column-type", type);
+
+ // Issue a warning if we are relaxing null-ness.
+ //
+ if (m.count ("null") && m.type ().count ("not-null"))
+ {
+ os << m.file () << ":" << m.line () << ":" << m.column () << ":"
+ << " warning: data member declared null while its type is "
+ << "declared not null" << endl;
+ }
+
return;
}
@@ -221,14 +224,7 @@ namespace relational
type = idt.get<string> ("type");
if (type.empty ())
- {
- column_type_flags f (ctf_none);
-
- if (null_pointer (m, prefix))
- f |= ctf_default_null;
-
- type = database_type (idt, id.belongs ().hint (), id, f);
- }
+ type = database_type (idt, id.belongs ().hint (), true);
}
else
{
@@ -236,7 +232,7 @@ namespace relational
type = t.get<string> ("type");
if (type.empty ())
- type = database_type (t, hint, m, ctf_none);
+ type = database_type (t, hint, false);
}
if (!type.empty ())
@@ -366,6 +362,10 @@ namespace relational
t.set ("container-kind", ck);
+ // Mark id column as not null.
+ //
+ t.set ("id-not-null", string ());
+
// Get the value type.
//
try
@@ -404,6 +404,33 @@ namespace relational
t.set ("value-tree-type", vt);
t.set ("value-tree-hint", vh);
+ // If we have a set container, automatically mark the value
+ // column as not null. If we already have an explicit null for
+ // this column, issue an error.
+ //
+ if (ck == ck_set)
+ {
+ if (t.count ("value-null"))
+ {
+ os << t.file () << ":" << t.line () << ":" << t.column () << ":"
+ << " error: set container cannot contain null values" << endl;
+
+ throw generation_failed ();
+ }
+ else
+ t.set ("value-not-null", string ());
+ }
+
+ // 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)
@@ -443,6 +470,7 @@ namespace relational
t.set ("index-tree-type", it);
t.set ("index-tree-hint", ih);
+ t.set ("index-not-null", string ());
}
// Get the key type for maps.
@@ -484,6 +512,7 @@ namespace relational
t.set ("key-tree-type", kt);
t.set ("key-tree-hint", kh);
+ t.set ("key-not-null", string ());
}
}
@@ -507,6 +536,28 @@ namespace relational
if (ck == ck_ordered && m.count ("value-inverse"))
m.set ("unordered", string ()); // Keep compatible with pragma.
+ // Issue an error if we have a null column in a set container.
+ // This can only happen if the value is declared as null in
+ // the member.
+ //
+ if (ck == ck_set && m.count ("value-null"))
+ {
+ os << m.file () << ":" << m.line () << ":" << m.column () << ":"
+ << " error: set container cannot contain null values" << endl;
+
+ throw generation_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")))
+ {
+ os << m.file () << ":" << m.line () << ":" << m.column () << ":"
+ << " warning: container value declared null while the container "
+ << "type or value type declares it as not null" << endl;
+ }
+
return true;
}
@@ -729,12 +780,6 @@ namespace relational
throw generation_failed ();
}
- if (m.count ("not-null") && !kp.empty ())
- {
- m.remove ("not-null");
- m.set (kp + "-not-null", string ()); // Keep compatible with pragma.
- }
-
// See if this is the inverse side of a bidirectional relationship.
// If so, then resolve the member and cache it in the context.
//
diff --git a/odb/validator.cxx b/odb/validator.cxx
index 487d69a..b07f5cd 100644
--- a/odb/validator.cxx
+++ b/odb/validator.cxx
@@ -15,6 +15,29 @@ using namespace std;
namespace
{
+ // Resolve null overrides.
+ //
+ static void
+ override_null (semantics::node& n, string const& prefix = "")
+ {
+ string p (prefix.empty () ? prefix : prefix + '-');
+
+ if (n.count (p + "null") && n.count (p + "not-null"))
+ {
+ if (n.get<location_t> (p + "null-loc") <
+ n.get<location_t> (p + "not-null-loc"))
+ {
+ n.remove (p + "null");
+ n.remove (p + "null-loc");
+ }
+ else
+ {
+ n.remove (p + "not-null");
+ n.remove (p + "not-null-loc");
+ }
+ }
+ }
+
struct data_member: traversal::data_member
{
data_member (bool& valid)
@@ -42,6 +65,11 @@ namespace
valid_ = false;
}
+
+ // Resolve null overrides.
+ //
+ override_null (m);
+ override_null (m, "value");
}
bool& valid_;
@@ -119,22 +147,44 @@ namespace
//
//
+ struct value_type: traversal::type
+ {
+ value_type (bool& valid): valid_ (valid) {}
+
+ virtual void
+ traverse (semantics::type& t)
+ {
+ // Resolve null overrides.
+ //
+ override_null (t);
+ override_null (t, "value");
+ }
+
+ bool& valid_;
+ };
+
+ //
+ //
struct class_: traversal::class_
{
- class_ (bool& valid, semantics::unit& unit)
- : valid_ (valid), unit_ (unit), member_ (valid)
+ class_ (bool& valid, semantics::unit& unit, value_type& vt)
+ : valid_ (valid), unit_ (unit), vt_ (vt), member_ (valid)
{
*this >> names_ >> member_;
}
-
virtual void
traverse (type& c)
{
if (c.count ("object"))
traverse_object (c);
- else if (context::comp_value (c))
- traverse_value (c);
+ else
+ {
+ if (context::comp_value (c))
+ traverse_value (c);
+
+ vt_.dispatch (c);
+ }
}
virtual void
@@ -234,8 +284,23 @@ namespace
}
}
else
+ {
c.set ("id-member", id);
+ // Automatically mark the id member as not null. If we already have
+ // an explicit null pragma for this member, issue an error.
+ //
+ if (id->count ("null"))
+ {
+ cerr << id->file () << ":" << id->line () << ":" << id->column ()
+ << ": error: object id member cannot be null" << endl;
+
+ valid_ = false;
+ }
+ else
+ id->set ("not-null", string ());
+ }
+
// Check members.
//
member_.count_ = 0;
@@ -317,6 +382,7 @@ namespace
bool& valid_;
semantics::unit& unit_;
+ value_type& vt_;
data_member member_;
traversal::names names_;
@@ -332,16 +398,21 @@ validate (options const&,
traversal::unit unit;
traversal::defines unit_defines;
+ traversal::declares unit_declares;
traversal::namespace_ ns;
- class_ c (valid, u);
+ value_type vt (valid);
+ class_ c (valid, u, vt);
unit >> unit_defines >> ns;
unit_defines >> c;
+ unit >> unit_declares >> vt;
traversal::defines ns_defines;
+ traversal::declares ns_declares;
ns >> ns_defines >> ns;
ns_defines >> c;
+ ns >> ns_declares >> vt;
unit.dispatch (u);