// file : odb/semantics/elements.cxx // copyright : Copyright (c) 2009-2015 Code Synthesis Tools CC // license : GNU GPL v3; see accompanying LICENSE file #include #include #include #include #include #include using namespace std; namespace semantics { // access // static char const* access_str[] = {"public", "protected", "private"}; char const* access:: string () const { return access_str[value_]; } // // node:: node (path const& file, size_t line, size_t column, tree tn) : tree_node_ (tn), loc_ (file, line, column) { } node:: node () : loc_ (0) { // GCC plugin machinery #define's abort as a macro. // // std::abort (); abort (); } // nameable // bool nameable:: in_scope (scope_type& s) { for (scope_type* p (&scope ());; p = &p->scope_ ()) { //@@ Need to handle namespace extensions. // if (p == &s) return true; if (p->global_scope ()) break; } return false; } 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_ (scope_entry const* prev) const { scope_entry scope (this, prev); // Nameable is fq-anonymous if all the paths to the global scope // have at least one anonymous link. // if (defined_ != 0 || !named_.empty ()) { if (named ().global_scope ()) return false; if (defined_ != 0) { nameable const& s (defined_->scope ()); if (!scope.find (&s) && !s.fq_anonymous_ (&scope)) return false; } for (names_list::const_iterator i (named_.begin ()), e (named_.end ()); i != e; ++i) { nameable const& s ((*i)->scope ()); if (!scope.find (&s) && !s.fq_anonymous_ (&scope)) return false; } } // If we can get a literal name for this type node, 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)); gcc_tree_code_type tc (TREE_CODE (s)); if (tc == TYPE_DECL) s = TREE_TYPE (s); else if (tc == NAMESPACE_DECL) { // "Unwind" any inline namespaces since they are not in // semantic grapth. // while (s != global_namespace) { tree prev (CP_DECL_CONTEXT (s)); if (!is_associated_namespace (prev, s)) break; s = prev; } } if (nameable* n = dynamic_cast (unit ().find (s))) return scope.find (n) || n->fq_anonymous_ (&scope); } else return false; // Assume this is a derived type (e.g., pointer). } return true; } bool nameable:: fq_anonymous (names* hint) const { 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_string_lexer l; l.start (n); string r, t; bool punc (false); bool scoped (false); // Names returned by GCC's type_as_string() (on which this function // is called) include inline namespaces (e.g., std::__cxx11::string). // So, besides fully-qualifying names, this function also needs to get // rid of those. The idea is to resolve names as we lex them, skipping // inline namespaces and stopping once we reach something other than a // namespace. // tree ns (global_namespace); tree id; for (cpp_ttype tt = l.next (t, &id); tt != CPP_EOF; tt = l.next (t, &id)) { if (punc && tt > CPP_LAST_PUNCTUATOR) r += ' '; punc = false; tree new_ns (global_namespace); // By default, revert to global. switch (static_cast (tt)) { case CPP_LESS: { r += "< "; break; } case CPP_GREATER: { r += " >"; break; } case CPP_COMMA: { r += ", "; break; } case CPP_NAME: { // Check if this is a namespace and, if so, whether it is // inline. // if (ns != 0) { new_ns = lookup_qualified_name (ns, id, false, false); if (new_ns == error_mark_node || TREE_CODE (new_ns) != NAMESPACE_DECL) new_ns = 0; // Not a namespace, stop resolving. else { // Check if this is an inline namespace and skip it if so. // if (is_associated_namespace (ns, new_ns)) { // Skip also the following scope operator. Strictly speaking // there could be none (i.e., this is a name of an inline // namespace) but we only use this function to print names // of anonymous types. // assert (l.next (t) == CPP_SCOPE); continue; } } } else new_ns = 0; // Keep it disabled until we hit a new 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; } case CPP_SCOPE: { new_ns = ns; // Don't change the namespace. // Fall through. } default: { r += t; break; } } scoped = (tt == CPP_SCOPE); ns = new_ns; } 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 { return fq_name_ (0); } string nameable:: fq_name_ (scope_entry const* prev) const { // @@ Doing this once and caching the result is probably a // good idea. // scope_entry scope (this, prev); if (named_p () && named ().global_scope ()) return ""; if (defined_ != 0) { nameable const& s (defined_->scope ()); if (!scope.find (&s) && !s.fq_anonymous_ (&scope)) return s.fq_name_ (&scope) + "::" + name (); } for (names_list::const_iterator i (named_.begin ()), e (named_.end ()); i != e; ++i) { nameable const& s ((*i)->scope ()); if (!scope.find (&s) && !s.fq_anonymous_ (&scope)) return s.fq_name_ (&scope) + "::" + name (); } 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 { if (hint != 0 || defined_ != 0) { names& n (hint ? *hint : *defined_); if (n.global_scope ()) return ""; 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 // scope::names_iterator_pair scope:: find (string const& name) const { names_map::const_iterator i (names_map_.find (name)); if (i == names_map_.end ()) return names_iterator_pair (names_.end (), names_.end ()); else return names_iterator_pair (i->second.begin (), i->second.end ()); } scope::names_iterator scope:: find (names& e) { list_iterator_map::iterator i (iterator_map_.find (&e)); return i != iterator_map_.end () ? i->second : names_.end (); } static bool is_base (type_id const& b, compiler::type_info const& d) { using compiler::type_info; for (type_info::base_iterator i (d.begin_base ()); i != d.end_base (); ++i) { type_info const& ti (i->type_info ()); if (b == ti.type_id () || is_base (b, ti)) return true; } return false; } names* scope:: lookup (string const& name, type_id const& ti, unsigned int flags, bool* hidden) const { names_iterator_pair p (find (name)); names* r (0); for (names_const_iterator i (p.first); i != p.second; ++i) { type_id const& xti (typeid (i->named ())); // If types are equal, then we found a match. Also check if ti is // a base type of xti. // if (xti == ti || is_base (ti, compiler::lookup (xti))) { if (r != 0) { // If both are namespaces, then the one is just an extension // of the other. // if (!(r->named ().is_a () && i->named ().is_a ())) throw ambiguous (*r, *i); } else r = &*i; } } if (r != 0) return r; // If we found a name but the types didn't match, then bail out // unless we want hidden names. // if (p.first != p.second) { if (hidden != 0) *hidden = true; if ((flags & include_hidden) == 0) return 0; } // Look in the outer scope unless requested not to or if this is // the global scope. // if ((flags & exclude_outer) == 0 && !global_scope ()) return scope ().lookup (name, ti, flags, hidden); return 0; } void scope:: add_edge_left (names& e) { names_list::iterator i (names_.insert (names_.end (), &e)); iterator_map_[&e] = i; names_map_[e.name ()].push_back (&e); } void scope:: add_edge_left (names& e, names_iterator after) { names_list::iterator i; if (after.base () == names_.end ()) i = names_.insert (names_.begin (), &e); else { names_list::iterator j (after.base ()); i = names_.insert (++j, &e); } iterator_map_[&e] = i; names_map_[e.name ()].push_back (&e); } // type info // namespace { struct init { init () { using compiler::type_info; // node // insert (type_info (typeid (node))); // edge // insert (type_info (typeid (edge))); // names // { type_info ti (typeid (names)); ti.add_base (typeid (edge)); insert (ti); } // declares // { type_info ti (typeid (declares)); ti.add_base (typeid (names)); insert (ti); } // defines // { type_info ti (typeid (defines)); ti.add_base (typeid (declares)); insert (ti); } // typedefs // { type_info ti (typeid (typedefs)); ti.add_base (typeid (declares)); insert (ti); } // nameable // { type_info ti (typeid (nameable)); ti.add_base (typeid (node)); insert (ti); } // scope // { type_info ti (typeid (scope)); ti.add_base (typeid (nameable)); insert (ti); } // type // { type_info ti (typeid (type)); ti.add_base (typeid (nameable)); insert (ti); } // belongs // { type_info ti (typeid (belongs)); ti.add_base (typeid (edge)); insert (ti); } // instance // { type_info ti (typeid (instance)); ti.add_base (typeid (node)); insert (ti); } // data_member // { type_info ti (typeid (data_member)); ti.add_base (typeid (nameable)); ti.add_base (typeid (instance)); insert (ti); } // unsupported_type // { type_info ti (typeid (unsupported_type)); ti.add_base (typeid (type)); insert (ti); } } } init_; } }