From 7dff3249f7ef6f8675e0c0fcbe3109d50f4c1b1d Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Sun, 28 Nov 2010 17:51:23 +0200 Subject: Add support for literal names (template-id, derived type declarator) --- odb/semantics/elements.cxx | 216 ++++++++++++++++++++++++++++++++++++++++----- odb/semantics/elements.hxx | 75 +++++++++++++++- odb/semantics/unit.cxx | 1 + odb/semantics/unit.hxx | 28 ++++-- odb/validator.cxx | 7 +- 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 + #include + +#include + #include +#include 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 (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 (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 ""; + + // @@ 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 ""; + tree n (tree_node ()); + + if (!TYPE_P (n)) + return ""; + + 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 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 (*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 (file, line, column); + T& r (graph_.new_node (file, line, column)); + r.unit (*this); + return r; } template T& new_node (path const& file, size_t line, size_t column, A0 const& a0) { - return graph_.new_node (file, line, column, a0); + T& r (graph_.new_node (file, line, column, a0)); + r.unit (*this); + return r; } template @@ -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 (file, line, column, a0, a1); + T& r (graph_.new_node (file, line, column, a0, a1)); + r.unit (*this); + return r; } template @@ -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 (file, line, column, a0, a1, a2); + T& r (graph_.new_node (file, line, column, a0, a1, a2)); + r.unit (*this); + return r; } template @@ -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 (file, line, column, a0, a1, a2, a3); + T& r (graph_.new_node (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 (tn); + T& r (graph_.new_node (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 () ? "" : b.fq_name ()); + string name (b.fq_name ()); cerr << c.file () << ":" << c.line () << ":" << c.column () << ":" << " error: base class '" << name << "' is not a " -- cgit v1.1