// 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:: 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)); if (TREE_CODE (s) == TYPE_DECL) s = TREE_TYPE (s); 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); for (cpp_ttype tt = l.next (t); tt != CPP_EOF; tt = l.next (t)) { if (punc && tt > CPP_LAST_PUNCTUATOR) r += ' '; 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 { 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_; } }