aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2010-11-28 17:51:23 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2010-11-28 17:51:23 +0200
commit7dff3249f7ef6f8675e0c0fcbe3109d50f4c1b1d (patch)
tree8596735f193cc4a377e97cf63af1a0a6c40d5bbf
parentc6a2b0f125c70f521daf820d014ff07b4fe8af3b (diff)
Add support for literal names (template-id, derived type declarator)
-rw-r--r--odb/semantics/elements.cxx216
-rw-r--r--odb/semantics/elements.hxx75
-rw-r--r--odb/semantics/unit.cxx1
-rw-r--r--odb/semantics/unit.hxx28
-rw-r--r--odb/validator.cxx7
5 files changed, 289 insertions, 38 deletions
diff --git a/odb/semantics/elements.cxx b/odb/semantics/elements.cxx
index 728b1b5..a1a63cd 100644
--- a/odb/semantics/elements.cxx
+++ b/odb/semantics/elements.cxx
@@ -3,8 +3,14 @@
// copyright : Copyright (c) 2009-2010 Code Synthesis Tools CC
// license : GNU GPL v3; see accompanying LICENSE file
+#include <odb/gcc.hxx>
+
#include <cutl/compiler/type-info.hxx>
+
+#include <odb/cxx-lexer.hxx>
+
#include <odb/semantics/elements.hxx>
+#include <odb/semantics/unit.hxx>
namespace semantics
{
@@ -40,25 +46,72 @@ namespace semantics
//
bool nameable::
+ anonymous_ () const
+ {
+ tree n (tree_node ());
+
+ if (TYPE_P (n))
+ {
+ tree name (0);
+
+ if (tree decl = TYPE_NAME (n))
+ name = DECL_NAME (decl);
+
+ return name != 0 && ANON_AGGRNAME_P (name);
+ }
+
+ return true;
+ }
+
+ bool nameable::
fq_anonymous () const
{
// Nameable is fq-anonymous if all the paths to the global scope
// have at least one anonymous link.
//
- if (anonymous ())
- return true;
-
- if (named ().global_scope ())
- return false;
+ if (defined_ != 0 || !named_.empty ())
+ {
+ if (named ().global_scope ())
+ return false;
- if (defined_ != 0 && !defined_->scope ().fq_anonymous ())
- return false;
+ if (defined_ != 0 && !defined_->scope ().fq_anonymous ())
+ return false;
- for (names_list::const_iterator i (named_.begin ()), e (named_.end ());
- i != e; ++i)
+ for (names_list::const_iterator i (named_.begin ()), e (named_.end ());
+ i != e; ++i)
+ {
+ if (!(*i)->scope ().fq_anonymous ())
+ return false;
+ }
+ }
+ else
{
- if (!(*i)->scope ().fq_anonymous ())
- return false;
+ // If we can get a literal name for this type, then it is not
+ // anonymous as long as its scope is not anonymous.
+ //
+ tree type (tree_node ());
+
+ if (TYPE_P (type))
+ {
+ tree name (0);
+
+ if (tree decl = TYPE_NAME (type))
+ {
+ name = DECL_NAME (decl);
+ if (name != 0 && ANON_AGGRNAME_P (name))
+ return true;
+
+ tree s (CP_DECL_CONTEXT (decl));
+
+ if (TREE_CODE (s) == TYPE_DECL)
+ s = TREE_TYPE (s);
+
+ if (nameable* n = dynamic_cast<nameable*> (unit ().find (s)))
+ return n->fq_anonymous ();
+ }
+ else
+ return false; // Assume this is a derived type (e.g., pointer).
+ }
}
return true;
@@ -67,21 +120,115 @@ namespace semantics
bool nameable::
fq_anonymous (names* hint) const
{
- if (hint == 0 && defined_ == 0)
- return true;
+ if (hint != 0 || defined_ != 0)
+ {
+ names& n (hint ? *hint : *defined_);
+
+ if (n.global_scope ())
+ return false;
+
+ return n.scope ().fq_anonymous ();
+ }
+ else
+ return fq_anonymous ();
+ }
+
+ static string
+ qualify_names (string const& n, bool qualify_first)
+ {
+ // @@ Creating a lexer for each call is a bad idea. Need
+ // to cache it somewhere.
+ //
+ cxx_lexer l;
+ l.start (n);
- names& n (hint ? *hint : *defined_);
+ string r, t;
+ bool punc (false);
+ bool scoped (false);
- if (n.global_scope ())
- return false;
+ for (cpp_ttype tt = l.next (t); tt != CPP_EOF; tt = l.next (t))
+ {
+ if (punc && tt > CPP_LAST_PUNCTUATOR)
+ r += ' ';
- return n.scope ().fq_anonymous ();
+ punc = false;
+
+ switch (static_cast<unsigned> (tt))
+ {
+ case CPP_LESS:
+ {
+ r += "< ";
+ break;
+ }
+ case CPP_GREATER:
+ {
+ r += " >";
+ break;
+ }
+ case CPP_COMMA:
+ {
+ r += ", ";
+ break;
+ }
+ case CPP_NAME:
+ {
+ // If the name was not preceeded with '::', qualify it.
+ //
+ if (!scoped)
+ {
+ if (!qualify_first)
+ qualify_first = true;
+ else
+ r += "::";
+ }
+
+ r += t;
+ punc = true;
+ break;
+ }
+ case CPP_KEYWORD:
+ case CPP_NUMBER:
+ {
+ r += t;
+ punc = true;
+ break;
+ }
+ default:
+ {
+ r += t;
+ break;
+ }
+ }
+
+ scoped = (tt == CPP_SCOPE);
+ }
+
+ return r;
+ }
+
+ string nameable::
+ name_ () const
+ {
+ tree n (tree_node ());
+
+ if (!TYPE_P (n))
+ return "<anonymous>";
+
+ // @@ Doing this once and caching the result is probably a
+ // good idea.
+ //
+ return qualify_names (
+ type_as_string (n, TFF_PLAIN_IDENTIFIER | TFF_UNQUALIFIED_NAME), false);
}
string nameable::
fq_name () const
{
- if (named ().global_scope ())
+ // @@ Doing this once and caching the result is probably a
+ // good idea.
+ //
+
+ if (named_p () && named ().global_scope ())
return "";
if (defined_ != 0 && !defined_->scope ().fq_anonymous ())
@@ -94,18 +241,41 @@ namespace semantics
return (*i)->scope ().fq_name () + "::" + name ();
}
- return "<anonymous>";
+ tree n (tree_node ());
+
+ if (!TYPE_P (n))
+ return "<anonymous>";
+
+ return qualify_names (type_as_string (n, TFF_PLAIN_IDENTIFIER), true);
}
string nameable::
fq_name (names* hint) const
{
- names& n (hint ? *hint : *defined_);
+ if (hint != 0 || defined_ != 0)
+ {
+ names& n (hint ? *hint : *defined_);
- if (n.global_scope ())
- return "";
+ if (n.global_scope ())
+ return "";
- return n.scope ().fq_name () + "::" + n.name ();
+ return n.scope ().fq_name () + "::" + n.name ();
+ }
+ else
+ {
+ // Since there was no hint, prefer the literal name over the names
+ // edges.
+ //
+ tree n (tree_node ());
+
+ if (TYPE_P (n))
+ return qualify_names (type_as_string (n, TFF_PLAIN_IDENTIFIER), true);
+
+ // Last resort is to call the other version of fq_name which will
+ // check the names edges.
+ //
+ return fq_name ();
+ }
}
// scope
diff --git a/odb/semantics/elements.hxx b/odb/semantics/elements.hxx
index 2e8908e..dfc5840 100644
--- a/odb/semantics/elements.hxx
+++ b/odb/semantics/elements.hxx
@@ -66,6 +66,7 @@ namespace semantics
//
class node;
class edge;
+ class unit;
//
//
@@ -142,8 +143,33 @@ namespace semantics
//
node ();
+ protected:
+ typedef semantics::unit unit_type;
+
+ unit_type const&
+ unit () const
+ {
+ return *unit_;
+ }
+
+ unit_type&
+ unit ()
+ {
+ return *unit_;
+ }
+
+ private:
+ friend class semantics::unit;
+
+ void
+ unit (unit_type& u)
+ {
+ unit_ = &u;
+ }
+
private:
tree tree_node_;
+ unit_type* unit_;
path file_;
size_t line_;
@@ -269,34 +295,68 @@ namespace semantics
public:
typedef semantics::scope scope_type;
+ // Return true if this type is unnamed and no literal name, such as
+ // template-id or derived type declarator, can be used instead.
+ //
bool
anonymous () const
{
- return defined_ == 0 && named_.empty ();
+ if (defined_ != 0 || !named_.empty ())
+ return false;
+
+ return anonymous_ ();
}
+ // Return true if the node itself or any of the scopes up to the
+ // global scope is anonymous. For a named class nested in an unnamed
+ // class, anonymous() will return false and fq_anonymous() will
+ // return true.
+ //
bool
fq_anonymous () const;
- // If hint is 0, use the defines edge.
+ // As above but use the hint to select the first outer scope. If
+ // hint is 0, use the defines edge.
//
bool
fq_anonymous (names* hint) const;
+ // Return the node's unqualifed name. If the node has a name, then
+ // return it, preferring the defines edge. Otherwise, return a
+ // literal name, e.g., template-id or a derived type declarator.
+ // Finally, if the type is anonymous, return <anonymous> string.
+ //
string
name () const
{
- return named ().name ();
+ if (defined_ != 0)
+ return defined_->name ();
+
+ if (!named_.empty ())
+ return named_[0]->name ();
+
+ return name_ ();
}
+ // Return the node's fully-qualifed name.
+ //
virtual string
fq_name () const;
- // If hint is 0, use the defines edge.
+ // As above but use the hint to select the first outer scope. If hint
+ // is 0, use the defines edge.
//
virtual string
fq_name (names* hint) const;
+ // Return true if the type is named.
+ //
+ bool
+ named_p () const
+ {
+ return defined_ != 0 || !named_.empty ();
+ }
+
scope_type&
scope () const
{
@@ -331,6 +391,13 @@ namespace semantics
using node::add_edge_right;
private:
+ bool
+ anonymous_ () const;
+
+ string
+ name_ () const;
+
+ private:
defines* defined_;
names_list named_;
};
diff --git a/odb/semantics/unit.cxx b/odb/semantics/unit.cxx
index 56d4f87..a64e0d0 100644
--- a/odb/semantics/unit.cxx
+++ b/odb/semantics/unit.cxx
@@ -18,6 +18,7 @@ namespace semantics
// namespace name ("").
//
new_edge<global_names> (*this, *this);
+ node::unit (*this);
}
// type info
diff --git a/odb/semantics/unit.hxx b/odb/semantics/unit.hxx
index e12f181..0dd6033 100644
--- a/odb/semantics/unit.hxx
+++ b/odb/semantics/unit.hxx
@@ -18,6 +18,10 @@ namespace semantics
public:
unit (path const&);
+ private:
+ unit (unit const&);
+ unit& operator= (unit const&);
+
// Mapping from tree nodes to semantic graph nodes.
//
public:
@@ -39,14 +43,18 @@ namespace semantics
T&
new_node (path const& file, size_t line, size_t column)
{
- return graph_.new_node<T> (file, line, column);
+ T& r (graph_.new_node<T> (file, line, column));
+ r.unit (*this);
+ return r;
}
template <typename T, typename A0>
T&
new_node (path const& file, size_t line, size_t column, A0 const& a0)
{
- return graph_.new_node<T> (file, line, column, a0);
+ T& r (graph_.new_node<T> (file, line, column, a0));
+ r.unit (*this);
+ return r;
}
template <typename T, typename A0, typename A1>
@@ -54,7 +62,9 @@ namespace semantics
new_node (path const& file, size_t line, size_t column,
A0 const& a0, A1 const& a1)
{
- return graph_.new_node<T> (file, line, column, a0, a1);
+ T& r (graph_.new_node<T> (file, line, column, a0, a1));
+ r.unit (*this);
+ return r;
}
template <typename T, typename A0, typename A1, typename A2>
@@ -62,7 +72,9 @@ namespace semantics
new_node (path const& file, size_t line, size_t column,
A0 const& a0, A1 const& a1, A2 const& a2)
{
- return graph_.new_node<T> (file, line, column, a0, a1, a2);
+ T& r (graph_.new_node<T> (file, line, column, a0, a1, a2));
+ r.unit (*this);
+ return r;
}
template <typename T, typename A0, typename A1, typename A2, typename A3>
@@ -70,7 +82,9 @@ namespace semantics
new_node (path const& file, size_t line, size_t column,
A0 const& a0, A1 const& a1, A2 const& a2, A3 const& a3)
{
- return graph_.new_node<T> (file, line, column, a0, a1, a2, a3);
+ T& r (graph_.new_node<T> (file, line, column, a0, a1, a2, a3));
+ r.unit (*this);
+ return r;
}
// For fundamental types.
@@ -79,7 +93,9 @@ namespace semantics
T&
new_fund_node (tree tn)
{
- return graph_.new_node<T> (tn);
+ T& r (graph_.new_node<T> (tn));
+ r.unit (*this);
+ return r;
}
protected:
diff --git a/odb/validator.cxx b/odb/validator.cxx
index ee1c4dc..73c8f90 100644
--- a/odb/validator.cxx
+++ b/odb/validator.cxx
@@ -32,9 +32,6 @@ namespace
if (type.fq_anonymous (b.hint ()))
{
- // Can be a template-id (which we should handle eventually) or an
- // anonymous type in member declaration (e.g., struct {...} m_;).
- //
cerr << m.file () << ":" << m.line () << ":" << m.column () << ":"
<< " error: unnamed type in data member declaration" << endl;
@@ -132,9 +129,9 @@ namespace
if (!context::comp_value (b))
{
- // @@ Should we use hint here? Need template printer.
+ // @@ Should we use hint here?
//
- string name (b.fq_anonymous () ? "<anonymous>" : b.fq_name ());
+ string name (b.fq_name ());
cerr << c.file () << ":" << c.line () << ":" << c.column () << ":"
<< " error: base class '" << name << "' is not a "