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 ++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 193 insertions(+), 23 deletions(-) (limited to 'odb/semantics/elements.cxx') 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 -- cgit v1.1