From c90e0f7b3ab78b4df877db5f45b87b3af91db5ab Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Fri, 2 Apr 2010 19:38:00 +0200 Subject: Move parser into a separate set of files --- odb/makefile | 1 + odb/parser.cxx | 1636 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ odb/parser.hxx | 148 +++++ odb/plugin.cxx | 1697 +------------------------------------------------------- 4 files changed, 1791 insertions(+), 1691 deletions(-) create mode 100644 odb/parser.cxx create mode 100644 odb/parser.hxx (limited to 'odb') diff --git a/odb/makefile b/odb/makefile index b7c9209..12c4a74 100644 --- a/odb/makefile +++ b/odb/makefile @@ -10,6 +10,7 @@ include $(dir $(lastword $(MAKEFILE_LIST)))../build/bootstrap.make cxx_ptun := \ context.cxx \ generator.cxx \ +parser.cxx \ plugin.cxx \ pragma.cxx \ source.cxx diff --git a/odb/parser.cxx b/odb/parser.cxx new file mode 100644 index 0000000..bdeb19a --- /dev/null +++ b/odb/parser.cxx @@ -0,0 +1,1636 @@ +// file : odb/parser.cxx +// author : Boris Kolpackov +// copyright : Copyright (c) 2009-2010 Code Synthesis Tools CC +// license : GNU GPL v2; see accompanying LICENSE file + +#include // Keep it first. + +#include +#include +#include + +#include +#include + +using namespace std; +using namespace semantics; + +bool parser::tree_decl:: +operator< (tree_decl const& y) const +{ + location_t xloc (decl ? DECL_SOURCE_LOCATION (decl) : prag->loc); + location_t yloc (y.decl ? DECL_SOURCE_LOCATION (y.decl) : y.prag->loc); + + if (xloc != yloc) + return xloc < yloc; + + size_t xl (LOCATION_LINE (xloc)); + size_t yl (LOCATION_LINE (yloc)); + + if (xl != yl) + return xl < yl; + + size_t xc (LOCATION_COLUMN (xloc)); + size_t yc (LOCATION_COLUMN (yloc)); + + if (xc != yc) + return xc < yc; + + return false; +} + +// +// Function templates. +// + +template +void parser:: +define_fund (tree t) +{ + t = TYPE_MAIN_VARIANT (t); + char const* name (IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (t)))); + + T& node (unit_->new_fund_node (t)); + unit_->new_edge (*scope_, node, name); + unit_->insert (t, node); +} + +template +T& parser:: +emit_class (tree c, path const& file, size_t line, size_t clmn, bool stub) +{ + c = TYPE_MAIN_VARIANT (c); + + // See if there is a stub already for this type. + // + T* c_node (0); + + if (node* n = unit_->find (c)) + { + c_node = &dynamic_cast (*n); + } + else + { + c_node = &unit_->new_node (file, line, clmn, c); + unit_->insert (c, *c_node); + } + + if (stub || !COMPLETE_TYPE_P (c)) + return *c_node; + + // Traverse base information. + // + tree bis (TYPE_BINFO (c)); + size_t n (bis ? BINFO_N_BASE_BINFOS (bis) : 0); + + for (size_t i (0); i < n; i++) + { + tree bi (BINFO_BASE_BINFO (bis, i)); + access a (access::public_); + + if (BINFO_BASE_ACCESSES (bis)) + { + tree ac (BINFO_BASE_ACCESS (bis, i)); + + if (ac == NULL_TREE || ac == access_public_node) + { + a = access::public_; + } + else if (ac == access_protected_node) + { + a = access::protected_; + } + else + { + assert (ac == access_private_node); + a = access::private_; + } + } + + bool virt (BINFO_VIRTUAL_P (bi)); + tree base (TYPE_MAIN_VARIANT (BINFO_TYPE (bi))); + + tree base_decl (TYPE_NAME (base)); // Typedef decl for this base. + + // Find the corresponding graph node. If we cannot find one then + // the base is a template instantiation since an ordinary class + // has to be defined (complete) in order to be a base. + // + class_* b_node (0); + string name; + + if (node* n = unit_->find (base)) + { + b_node = &dynamic_cast (*n); + + if (trace) + name = IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (base))); + } + else + { + b_node = &dynamic_cast (emit_type (base, file, line, clmn)); + + if (trace) + name = emit_type_name (base); + } + + unit_->new_edge (*c_node, *b_node, a, virt); + + if (trace) + ts << "\t" << a.string () << (virt ? " virtual" : "") << " base " + << name << " (" << static_cast (b_node) << ")" << endl; + } + + // Collect member declarations so that we can traverse them in + // the source code order. + // + decl_set decls; + + for (tree d (TYPE_FIELDS (c)); d != NULL_TREE ; d = TREE_CHAIN (d)) + { + switch (TREE_CODE (d)) + { + case TYPE_DECL: + { + if (!DECL_SELF_REFERENCE_P (d)) + decls.insert (d); + break; + } + case TEMPLATE_DECL: + { + if (DECL_CLASS_TEMPLATE_P (d)) + decls.insert (d); + break; + } + case FIELD_DECL: + { + if (!DECL_ARTIFICIAL (d)) + decls.insert (d); + break; + } + } + } + + // Add location pragmas if any. + // + { + loc_pragmas::const_iterator i (loc_pragmas_.find (c)); + + if (i != loc_pragmas_.end ()) + decls.insert (i->second.begin (), i->second.end ()); + } + + scope* prev_scope (scope_); + scope_ = c_node; + + for (decl_set::const_iterator b (decls.begin ()), i (b), e (decls.end ()); + i != e; ++i) + { + // Skip pragmas. + // + if (i->prag) + continue; + + tree d (i->decl); + + switch (TREE_CODE (d)) + { + case TYPE_DECL: + { + type* n (emit_type_decl (d)); + + // If this is a named class-type definition, then handle + // the pragmas. + // + if (n != 0) + process_pragmas (n->tree_node (), *n, n->name (), b, i, e); + + break; + } + case TEMPLATE_DECL: + { + emit_template_decl (d); + break; + } + case FIELD_DECL: + { + // If this is a bit-field then TREE_TYPE may be a modified type + // with lesser precision. In this case, DECL_BIT_FIELD_TYPE + // will be the type that was original specified. Use that type + // for now. Furthermore, bitfields can be anonymous, which we + // ignore. + // + // + bool bf (DECL_C_BIT_FIELD (d)); + + if (bf && DECL_NAME (d) == 0) + break; + + tree t (bf ? DECL_BIT_FIELD_TYPE (d) : TREE_TYPE (d)); + + char const* name (IDENTIFIER_POINTER (DECL_NAME (d))); + + path file (DECL_SOURCE_FILE (d)); + size_t line (DECL_SOURCE_LINE (d)); + size_t clmn (DECL_SOURCE_COLUMN (d)); + + access a (decl_access (d)); + + type& type_node (emit_type (t, file, line, clmn)); + data_member& member_node ( + unit_->new_node (file, line, clmn)); + + unit_->new_edge (member_node, type_node); + unit_->new_edge (*c_node, member_node, name, a); + + if (trace) + { + string type_name (emit_type_name (t)); + + ts << "\t" << a.string () << " data member " << type_name + << " (" << &type_node << ") " << name << " at " + << file << ":" << line << endl; + } + + // Process pragmas that may be associated with this field. + // + process_pragmas (d, member_node, name, b, i, e); + + break; + } + } + } + + // Diagnose any position pragmas that haven't been associated. + // + diagnose_unassoc_pragmas (decls); + + scope_ = prev_scope; + return *c_node; +} + +template +T& parser:: +emit_union (tree u, path const& file, size_t line, size_t clmn, bool stub) +{ + u = TYPE_MAIN_VARIANT (u); + + // See if there is a stub already for this type. + // + T* u_node (0); + + if (node* n = unit_->find (u)) + { + u_node = &dynamic_cast (*n); + } + else + { + u_node = &unit_->new_node (file, line, clmn, u); + unit_->insert (u, *u_node); + } + + if (stub || !COMPLETE_TYPE_P (u)) + return *u_node; + + // Collect member declarations so that we can traverse them in + // the source code order. + // + decl_set decls; + + for (tree d (TYPE_FIELDS (u)); d != NULL_TREE ; d = TREE_CHAIN (d)) + { + switch (TREE_CODE (d)) + { + case TYPE_DECL: + { + if (!DECL_SELF_REFERENCE_P (d)) + decls.insert (d); + break; + } + case TEMPLATE_DECL: + { + if (DECL_CLASS_TEMPLATE_P (d)) + decls.insert (d); + break; + } + case FIELD_DECL: + { + if (!DECL_ARTIFICIAL (d)) + decls.insert (d); + break; + } + } + } + + // Add location pragmas if any. + // + { + loc_pragmas::const_iterator i (loc_pragmas_.find (u)); + + if (i != loc_pragmas_.end ()) + decls.insert (i->second.begin (), i->second.end ()); + } + + scope* prev_scope (scope_); + scope_ = u_node; + + for (decl_set::const_iterator b (decls.begin ()), i (b), e (decls.end ()); + i != e; ++i) + { + // Skip pragmas. + // + if (i->prag) + continue; + + tree d (i->decl); + + switch (TREE_CODE (d)) + { + case TYPE_DECL: + { + type* n (emit_type_decl (d)); + + // If this is a named class-type definition, then handle + // the pragmas. + // + if (n != 0) + process_pragmas (n->tree_node (), *n, n->name (), b, i, e); + + break; + } + case TEMPLATE_DECL: + { + emit_template_decl (d); + break; + } + case FIELD_DECL: + { + tree t (TREE_TYPE (d)); + char const* name (IDENTIFIER_POINTER (DECL_NAME (d))); + + path file (DECL_SOURCE_FILE (d)); + size_t line (DECL_SOURCE_LINE (d)); + size_t clmn (DECL_SOURCE_COLUMN (d)); + + access a (decl_access (d)); + + type& type_node (emit_type (t, file, line, clmn)); + data_member& member_node ( + unit_->new_node (file, line, clmn)); + + unit_->new_edge (member_node, type_node); + unit_->new_edge (*u_node, member_node, name, a); + + if (trace) + { + string type_name (emit_type_name (t)); + + ts << "\t" << a.string () << " union member " << type_name + << " (" << &type_node << ") " << name << " at " + << file << ":" << line << endl; + } + + // Process pragmas that may be associated with this field. + // + process_pragmas (d, member_node, name, b, i, e); + + break; + } + } + } + + // Diagnose any position pragmas that haven't been associated. + // + diagnose_unassoc_pragmas (decls); + + scope_ = prev_scope; + return *u_node; +} + +// +// Functions. +// + +parser:: +parser (options const& ops, + loc_pragmas const& lp, + decl_pragmas const& dp) + : ops_ (ops), + loc_pragmas_ (lp), + decl_pragmas_ (dp), + trace (ops.trace ()), + ts (cerr) +{ +} + +auto_ptr parser:: +parse (tree global_scope, path const& main_file) +{ + auto_ptr u (new unit (main_file)); + unit_ = u.get (); + scope_ = unit_; + error_ = 0; + + // Define fundamental types. + // + define_fund (void_type_node); + define_fund (boolean_type_node); + define_fund (char_type_node); + define_fund (wchar_type_node); + define_fund (signed_char_type_node); + define_fund (unsigned_char_type_node); + define_fund (short_integer_type_node); + define_fund (short_unsigned_type_node); + define_fund (integer_type_node); + define_fund (unsigned_type_node); + define_fund (long_integer_type_node); + define_fund (long_unsigned_type_node); + define_fund (long_long_integer_type_node); + define_fund (long_long_unsigned_type_node); + define_fund (float_type_node); + define_fund (double_type_node); + define_fund (long_double_type_node); + + // First collect all the declarations we are interested in + // in the line-decl map so that they appear in the source + // code order. + // + collect (global_scope); + + // Add namespace-level location pragmas if any. + // + { + loc_pragmas::const_iterator i (loc_pragmas_.find (global_namespace)); + + if (i != loc_pragmas_.end ()) + decls_.insert (i->second.begin (), i->second.end ()); + } + + // Construct the semantic graph. + // + emit (); + + if (error_ > 0) + throw failed (); + + return u; +} + +void parser:: +collect (tree ns) +{ + cp_binding_level* level = NAMESPACE_LEVEL (ns); + tree decl = level->names; + + // Collect declarations. + // + for (; decl != NULL_TREE; decl = TREE_CHAIN (decl)) + { + if (DECL_IS_BUILTIN (decl)) + continue; + + switch (TREE_CODE (decl)) + { + case TYPE_DECL: + { + if (DECL_NAME (decl) != NULL_TREE) + decls_.insert (decl); + + break; + } + case TEMPLATE_DECL: + { + if (DECL_CLASS_TEMPLATE_P (decl)) + decls_.insert (decl); + break; + } + } + } + + // Traverse namespaces. + // + for(decl = level->namespaces; decl != NULL_TREE; decl = TREE_CHAIN (decl)) + { + // !DECL_NAMESPACE_STD_P (decl) + + if (!DECL_IS_BUILTIN (decl)) + { + if (trace) + { + tree dn (DECL_NAME (decl)); + char const* name (dn ? IDENTIFIER_POINTER (dn) : ""); + + ts << "namespace " << name << " at " + << DECL_SOURCE_FILE (decl) << ":" + << DECL_SOURCE_LINE (decl) << endl; + } + + collect (decl); + } + } +} + +void parser:: +emit () +{ + for (decl_set::const_iterator b (decls_.begin ()), i (b), + e (decls_.end ()); i != e; ++i) + { + // Skip pragmas. + // + if (i->prag) + continue; + + tree decl (i->decl); + + // Get this declaration's namespace and unwind our scope until + // we find a common prefix of namespaces. + // + string pfx; + string ns (fq_scope (decl)); + + for (pfx = scope_->fq_name (); !pfx.empty (); pfx = scope_->fq_name ()) + { + if (ns.compare (0, pfx.size (), pfx) == 0) + break; + + scope_ = &scope_->scope_ (); + } + + // Build the rest of the namespace hierarchy for this declaration. + // + if (ns != pfx) + { + path f (DECL_SOURCE_FILE (decl)); + size_t l (DECL_SOURCE_LINE (decl)); + size_t c (DECL_SOURCE_COLUMN (decl)); + + for (size_t b (pfx.size () + 2), e (ns.find ("::", b)); + b != string::npos;) + { + string n (ns, b, e == string::npos ? e : e - b); + + if (trace) + ts << "creating namespace " << n << " for " + << DECL_SOURCE_FILE (decl) << ":" + << DECL_SOURCE_LINE (decl) << endl; + + // Use the declarations's file, line, and column as an + // approximation for this namespace origin. + // + namespace_& node (unit_->new_node (f, l, c)); + unit_->new_edge (*scope_, node, n); + scope_ = &node; + + if (e == string::npos) + b = e; + else + { + b = e + 2; + e = ns.find ("::", b); + } + } + } + + switch (TREE_CODE (decl)) + { + case TYPE_DECL: + { + type* n (emit_type_decl (decl)); + + // If this is a named class-type definition, then handle + // the pragmas. + // + if (n != 0) + process_pragmas (n->tree_node (), *n, n->name (), b, i, e); + + break; + } + case TEMPLATE_DECL: + { + emit_template_decl (decl); + break; + } + } + } + + // Diagnose any position pragmas that haven't been associated. + // + diagnose_unassoc_pragmas (decls_); +} + +type* parser:: +emit_type_decl (tree decl) +{ + tree t (TREE_TYPE (decl)); + int tc (TREE_CODE (t)); + + tree decl_name (DECL_NAME (decl)); + char const* name (IDENTIFIER_POINTER (decl_name)); + + + if (DECL_ARTIFICIAL (decl) && + (tc == RECORD_TYPE || tc == UNION_TYPE || tc == ENUMERAL_TYPE)) + { + // If we have an anonymous class typedef, use the user- + // supplied name instead of the synthesized one. ARM + // says that in typedef struct {} S; S becomes struct's + // name. + // + if (ANON_AGGRNAME_P (decl_name)) + { + tree d (TYPE_NAME (t)); + + if (d != NULL_TREE && + !DECL_ARTIFICIAL (d) && + DECL_NAME (d) != NULL_TREE && + !ANON_AGGRNAME_P (DECL_NAME (d))) + { + decl = d; + decl_name = DECL_NAME (decl); + name = IDENTIFIER_POINTER (decl_name); + } + else + { + // This type has only the synthesized name which means that + // it is either typedef'ed as a derived type or it is used + // to declare a varibale or similar. The first case will be + // covered by the typedef handling code below. The second + // case will be covere by emit_type(). + // + return 0; + } + } + + path file (DECL_SOURCE_FILE (decl)); + size_t line (DECL_SOURCE_LINE (decl)); + size_t clmn (DECL_SOURCE_COLUMN (decl)); + + type* node (0); + + // Pointers to member functions are represented as record + // types. Detect and handle this case. + // + if (TYPE_PTRMEMFUNC_P (t)) + { + t = TYPE_MAIN_VARIANT (t); + node = &unit_->new_node ( + file, line, clmn, t, "pointer_to_member_function_type"); + unit_->insert (t, *node); + } + else + { + + if (trace) + ts << "start " << tree_code_name[tc] << " " << name << " at " + << DECL_SOURCE_FILE (decl) << ":" + << DECL_SOURCE_LINE (decl) << endl; + + switch (tc) + { + case RECORD_TYPE: + { + node = &emit_class (t, file, line, clmn); + break; + } + case UNION_TYPE: + { + node = &emit_union (t, file, line, clmn); + break; + } + case ENUMERAL_TYPE: + { + node = &emit_enum (t, file, line, clmn); + break; + } + } + + if (trace) + ts << "end " << tree_code_name[tc] << " " << name + << " (" << node << ") at " + << DECL_SOURCE_FILE (decl) << ":" + << DECL_SOURCE_LINE (decl) << endl; + } + + if (COMPLETE_TYPE_P (t)) + unit_->new_edge (*scope_, *node, name); + else + unit_->new_edge (*scope_, *node, name); + + return node; + } + else + { + // Normal typedef. We need to detect and ignore the anonymous + // class typedef case described above since we already used + // this name to define the class. + // + int tc (TREE_CODE (t)); + + if ((tc == RECORD_TYPE || tc == UNION_TYPE || tc == ENUMERAL_TYPE) && + TYPE_NAME (TYPE_MAIN_VARIANT (t)) == decl) + return 0; + + path f (DECL_SOURCE_FILE (decl)); + size_t l (DECL_SOURCE_LINE (decl)); + size_t c (DECL_SOURCE_COLUMN (decl)); + + type& node (emit_type (t, f, l, c)); + unit_->new_edge (*scope_, node, name); + + if (trace) + { + string s (emit_type_name (t, false)); + + ts << "typedef " << s << " (" << &node << ") -> " << name << " at " + << DECL_SOURCE_FILE (decl) << ":" + << DECL_SOURCE_LINE (decl) << endl; + } + + return 0; + } +} + +void parser:: +emit_template_decl (tree decl) +{ + // Currently we only handle class/union templates. + // + tree t (TREE_TYPE (DECL_TEMPLATE_RESULT (decl))); + int tc (TREE_CODE (t)); + + if (trace) + { + ts << tree_code_name[tc] << " template (" << decl << ") " + << IDENTIFIER_POINTER (DECL_NAME (decl)) << " (" << t << ") at " + << DECL_SOURCE_FILE (decl) << ":" + << DECL_SOURCE_LINE (decl) << endl; + + ts << "specializations:" << endl; + + for (tree s (DECL_TEMPLATE_SPECIALIZATIONS (decl)); + s != NULL_TREE; s = TREE_CHAIN (s)) + { + tree t (TREE_TYPE (s)); + tree d (TYPE_NAME (t)); + + ts << "\tspecialization" << t << " at " + << DECL_SOURCE_FILE (d) << ":" + << DECL_SOURCE_LINE (d) << endl; + } + + ts << "instantiations:" << endl; + + for (tree i (DECL_TEMPLATE_INSTANTIATIONS (decl)); + i != NULL_TREE; i = TREE_CHAIN (i)) + { + tree t (TREE_VALUE (i)); + tree d (TYPE_NAME (t)); + + ts << "\tinstantiation" << t << " at " + << DECL_SOURCE_FILE (d) << ":" + << DECL_SOURCE_LINE (d) << endl; + } + } + + char const* name (IDENTIFIER_POINTER (DECL_NAME (decl))); + + if (trace) + ts << "start " << tree_code_name[tc] << " template " << name << " at " + << DECL_SOURCE_FILE (decl) << ":" + << DECL_SOURCE_LINE (decl) << endl; + + type_template* t_node (0); + + if (tc == RECORD_TYPE) + t_node = &emit_class_template (decl); + else + t_node = &emit_union_template (decl); + + if (COMPLETE_TYPE_P (t)) + unit_->new_edge (*scope_, *t_node, name); + else + unit_->new_edge (*scope_, *t_node, name); + + if (trace) + ts << "end " << tree_code_name[tc] << " template " << name + << " (" << t_node << ") at " + << DECL_SOURCE_FILE (decl) << ":" + << DECL_SOURCE_LINE (decl) << endl; +} + +class_template& parser:: +emit_class_template (tree t, bool stub) +{ + // See if there is a stub already for this template. + // + class_template* ct_node (0); + + if (node* n = unit_->find (t)) + { + ct_node = &dynamic_cast (*n); + } + else + { + path f (DECL_SOURCE_FILE (t)); + size_t l (DECL_SOURCE_LINE (t)); + size_t c (DECL_SOURCE_COLUMN (t)); + + ct_node = &unit_->new_node (f, l, c); + unit_->insert (t, *ct_node); + } + + tree c (TREE_TYPE (DECL_TEMPLATE_RESULT (t))); + + if (stub || !COMPLETE_TYPE_P (c)) + return *ct_node; + + // Collect member declarations so that we can traverse them in + // the source code order. For now we are only interested in + // nested class template declarations. + // + decl_set decls; + + for (tree d (TYPE_FIELDS (c)); d != NULL_TREE ; d = TREE_CHAIN (d)) + { + switch (TREE_CODE (d)) + { + case TEMPLATE_DECL: + { + if (DECL_CLASS_TEMPLATE_P (d)) + decls.insert (d); + break; + } + } + } + + scope* prev_scope (scope_); + scope_ = ct_node; + + for (decl_set::const_iterator i (decls.begin ()), e (decls.end ()); + i != e; ++i) + { + // Skip pragmas. + // + if (i->prag) + continue; + + tree d (i->decl); + + switch (TREE_CODE (d)) + { + case TEMPLATE_DECL: + { + emit_template_decl (d); + break; + } + } + } + + // Diagnose any position pragmas that haven't been associated. + // + diagnose_unassoc_pragmas (decls); + + scope_ = prev_scope; + return *ct_node; +} + +union_template& parser:: +emit_union_template (tree t, bool stub) +{ + // See if there is a stub already for this template. + // + union_template* ut_node (0); + + if (node* n = unit_->find (t)) + { + ut_node = &dynamic_cast (*n); + } + else + { + path f (DECL_SOURCE_FILE (t)); + size_t l (DECL_SOURCE_LINE (t)); + size_t c (DECL_SOURCE_COLUMN (t)); + + ut_node = &unit_->new_node (f, l, c); + unit_->insert (t, *ut_node); + } + + tree u (TREE_TYPE (DECL_TEMPLATE_RESULT (t))); + + if (stub || !COMPLETE_TYPE_P (u)) + return *ut_node; + + // Collect member declarations so that we can traverse them in + // the source code order. For now we are only interested in + // nested class template declarations. + // + decl_set decls; + + for (tree d (TYPE_FIELDS (u)); d != NULL_TREE ; d = TREE_CHAIN (d)) + { + switch (TREE_CODE (d)) + { + case TEMPLATE_DECL: + { + if (DECL_CLASS_TEMPLATE_P (d)) + decls.insert (d); + break; + } + } + } + + scope* prev_scope (scope_); + scope_ = ut_node; + + for (decl_set::const_iterator i (decls.begin ()), e (decls.end ()); + i != e; ++i) + { + // Skip pragmas. + // + if (i->prag) + continue; + + tree d (i->decl); + + switch (TREE_CODE (d)) + { + case TEMPLATE_DECL: + { + emit_template_decl (d); + break; + } + } + } + + // Diagnose any position pragmas that haven't been associated. + // + diagnose_unassoc_pragmas (decls); + + scope_ = prev_scope; + return *ut_node; +} + +enum_& parser:: +emit_enum (tree e, path const& file, size_t line, size_t clmn, bool stub) +{ + e = TYPE_MAIN_VARIANT (e); + + // See if there is a stub already for this type. + // + enum_* e_node (0); + + if (node* n = unit_->find (e)) + { + e_node = &dynamic_cast (*n); + } + else + { + e_node = &unit_->new_node (file, line, clmn, e); + unit_->insert (e, *e_node); + } + + if (stub || !COMPLETE_TYPE_P (e)) + return *e_node; + + // Traverse enumerators. + // + for (tree er (TYPE_VALUES (e)); er != NULL_TREE ; er = TREE_CHAIN (er)) + { + char const* name (IDENTIFIER_POINTER (TREE_PURPOSE (er))); + + // There doesn't seem to be a way to get the proper position for + // each enumerator. + // + enumerator& er_node = unit_->new_node (file, line, clmn); + unit_->new_edge (*e_node, er_node); + + if (trace) + ts << "\tenumerator " << name << " at " << file << ":" << line << endl; + } + + return *e_node; +} + +type& parser:: +emit_type (tree t, + path const& file, + size_t line, + size_t clmn) +{ + tree mv (TYPE_MAIN_VARIANT (t)); + + if (trace) + { + ts << tree_code_name[TREE_CODE (t)] << " " << t + << " main " << mv << endl; + + for (tree v (TYPE_MAIN_VARIANT (t)); v != 0; v = TYPE_NEXT_VARIANT (v)) + ts << "\tvariant " << v << endl; + } + + node* n (unit_->find (mv)); + + type& r (n != 0 + ? dynamic_cast (*n) + : create_type (t, file, line, clmn)); + + if (trace && n != 0) + ts << "found node " << &r << " for type " << mv << endl; + + if (cp_type_quals (t) == TYPE_UNQUALIFIED) + return r; + + // See if this type already has this variant. + // + bool qc (CP_TYPE_CONST_P (t)); + bool qv (CP_TYPE_VOLATILE_P (t)); + bool qr (CP_TYPE_RESTRICT_P (t)); + + for (type::qualified_iterator i (r.qualified_begin ()); + i != r.qualified_end (); ++i) + { + qualifier& q (i->qualifier ()); + + if (q.const_ () == qc && q.volatile_ () == qv && q.restrict_ () == qr) + { + if (trace) + ts << "found qualifier variant " << &q << endl; + + return q; + } + } + + // No such variant yet. Create a new one. Qualified types are not + // unique in the tree so don't add this node to the map. + // + qualifier& q (unit_->new_node (file, line, clmn, t, qc, qv, qr)); + unit_->new_edge (q, r); + return q; +} + +type& parser:: +create_type (tree t, + path const& file, + size_t line, + size_t clmn) +{ + type* r (0); + int tc (TREE_CODE (t)); + + switch (tc) + { + // + // User-defined types. + // + case RECORD_TYPE: + case UNION_TYPE: + { + tree ti (TYPE_TEMPLATE_INFO (t)); + + if (ti == NULL_TREE) + { + // Ordinary class. There are two situations which can lead + // here. First is when we have an anonymous class that is + // part of the declaration, for example: + // + // typedef const struct {...} s; + // + // The second situation is a named class definition which + // we haven't parsed yet. In this case we are going to + // create a "stub" class node which will be processed and + // filled in later. + // + t = TYPE_MAIN_VARIANT (t); + + // Pointers to member functions are represented as record + // types. Detect and handle this case. + // + if (TYPE_PTRMEMFUNC_P (t)) + { + r = &unit_->new_node ( + file, line, clmn, t, "pointer_to_member_function_type"); + unit_->insert (t, *r); + } + else + { + tree d (TYPE_NAME (t)); + + if (trace) + ts << "start anon/stub " << tree_code_name[tc] << " at " + << file << ":" << line << endl; + + if (d == NULL_TREE || ANON_AGGRNAME_P (DECL_NAME (d))) + { + if (tc == RECORD_TYPE) + r = &emit_class (t, file, line, clmn); + else + r = &emit_union (t, file, line, clmn); + } + else + { + // Use the "defining" declaration's file, line, and column + // information to create the stub. + // + path f (DECL_SOURCE_FILE (d)); + size_t l (DECL_SOURCE_LINE (d)); + size_t c (DECL_SOURCE_COLUMN (d)); + + if (tc == RECORD_TYPE) + r = &emit_class (t, f, l, c, true); + else + r = &emit_union (t, f, l, c, true); + } + + if (trace) + ts << "end anon/stub " << tree_code_name[tc] << " (" << r << ")" + << " at " << file << ":" << line << endl; + } + } + else + { + // Template instantiation. + // + t = TYPE_MAIN_VARIANT (t); + tree decl (TI_TEMPLATE (ti)); // DECL_TEMPLATE + + // Get to the most general template declaration. + // + while (DECL_TEMPLATE_INFO (decl)) + decl = DECL_TI_TEMPLATE (decl); + + type_template* t_node (0); + + // Find the template node or create a stub if none exist. + // + if (node* n = unit_->find (decl)) + t_node = &dynamic_cast (*n); + else + { + if (trace) + ts << "start stub " << tree_code_name[tc] << " template for (" + << decl << ") at " << file << ":" << line << endl; + + if (tc == RECORD_TYPE) + t_node = &emit_class_template (decl, true); + else + t_node = &emit_union_template (decl, true); + + if (trace) + ts << "end stub " << tree_code_name[tc] << " template (" + << t_node << ") at " << file << ":" << line << endl; + } + + if (trace) + ts << "start " << tree_code_name[tc] << " instantiation (" + << t << ") for template (" << t_node << ")" + << " at " << file << ":" << line << endl; + + type_instantiation* i_node (0); + + if (tc == RECORD_TYPE) + i_node = &emit_class (t, file, line, clmn); + else + i_node = &emit_union (t, file, line, clmn); + + if (trace) + ts << "end " << tree_code_name[tc] << " instantiation (" + << static_cast (i_node) << ")" + << " at " << file << ":" << line << endl; + + unit_->new_edge (*i_node, *t_node); + r = i_node; + } + + break; + } + case ENUMERAL_TYPE: + { + // The same logic as in the "ordinary class" case above + // applies here. + // + + t = TYPE_MAIN_VARIANT (t); + tree d (TYPE_NAME (t)); + + if (trace) + ts << "start anon/stub " << tree_code_name[tc] << " at " + << file << ":" << line << endl; + + if (d == NULL_TREE || ANON_AGGRNAME_P (DECL_NAME (d))) + { + r = &emit_enum (t, file, line, clmn); + } + else + { + // Use the "defining" declaration's file, line, and column + // information to create the stub. + // + path f (DECL_SOURCE_FILE (d)); + size_t l (DECL_SOURCE_LINE (d)); + size_t c (DECL_SOURCE_COLUMN (d)); + + r = &emit_enum (t, f, l, c, true); + } + + if (trace) + ts << "end anon/stub " << tree_code_name[tc] << " (" << r << ")" + << " at " << file << ":" << line << endl; + + break; + } + + // + // Derived types. + // + + case ARRAY_TYPE: + { + unsigned long long size (0); + + if (tree index = TYPE_DOMAIN (t)) + { + tree max (TYPE_MAX_VALUE (index)); + + if (TREE_CODE (max) == INTEGER_CST) + { + HOST_WIDE_INT hwl (TREE_INT_CST_LOW (max)); + HOST_WIDE_INT hwh (TREE_INT_CST_HIGH (max)); + + // The docs say that TYPE_DOMAIN will be NULL if the + // array doesn't specify bounds. In reality, both + // low and high parts are set to HOST_WIDE_INT_MAX. + // + if (hwl != ~HOST_WIDE_INT (0) && hwh != ~HOST_WIDE_INT (0)) + { + unsigned long long l (hwl); + unsigned long long h (hwh); + unsigned short width (HOST_BITS_PER_WIDE_INT); + + size = (h << width) + l + 1; + } + } + else + { + cerr << file << ':' << line << ':' << clmn << ": error: " + << " non-integer array index " + << tree_code_name[TREE_CODE (max)]; + + throw failed (); + } + } + + type& bt (emit_type (TREE_TYPE (t), file, line, clmn)); + t = TYPE_MAIN_VARIANT (t); + array& a (unit_->new_node (file, line, clmn, t, size)); + unit_->insert (t, a); + unit_->new_edge (a, bt); + r = &a; + break; + } + case REFERENCE_TYPE: + { + type& bt (emit_type (TREE_TYPE (t), file, line, clmn)); + t = TYPE_MAIN_VARIANT (t); + reference& ref (unit_->new_node (file, line, clmn, t)); + unit_->insert (t, ref); + unit_->new_edge (ref, bt); + r = &ref; + break; + } + case POINTER_TYPE: + { + if (!TYPE_PTRMEM_P (t)) + { + type& bt (emit_type (TREE_TYPE (t), file, line, clmn)); + t = TYPE_MAIN_VARIANT (t); + pointer& p (unit_->new_node (file, line, clmn, t)); + unit_->insert (t, p); + unit_->new_edge (p, bt); + r = &p; + } + else + { + t = TYPE_MAIN_VARIANT (t); + r = &unit_->new_node ( + file, line, clmn, t, "pointer_to_data_member_type"); + unit_->insert (t, *r); + + if (trace) + ts << "unsupported pointer_to_data_member_type (" << r << ")" + << " at " << file << ":" << line << endl; + } + break; + } + default: + { + t = TYPE_MAIN_VARIANT (t); + r = &unit_->new_node ( + file, line, clmn, t, tree_code_name[tc]); + unit_->insert (t, *r); + + if (trace) + ts << "unsupported " << tree_code_name[tc] << " (" << r << ")" + << " at " << file << ":" << line << endl; + + break; + } + } + + return *r; +} + +string parser:: +emit_type_name (tree type, bool direct) +{ + // First see if there is a "direct" name for this type. + // + if (direct) + { + if (tree decl = TYPE_NAME (type)) + { + tree t (TREE_TYPE (decl)); + + if (same_type_p (type, t)) + return IDENTIFIER_POINTER (DECL_NAME (decl)); + } + } + + string r; + + if (CP_TYPE_CONST_P (type)) + r += " const"; + + if (CP_TYPE_VOLATILE_P (type)) + r += " volatile"; + + if (CP_TYPE_RESTRICT_P (type)) + r += " __restrict"; + + int tc (TREE_CODE (type)); + + switch (tc) + { + // + // User-defined types. + // + + case RECORD_TYPE: + case UNION_TYPE: + { + tree ti (TYPE_TEMPLATE_INFO (type)); + + if (ti == NULL_TREE) + { + // Ordinary class. + // + type = TYPE_MAIN_VARIANT (type); + + // Pointers to member functions are represented as record + // types and don't have names, not even the synthesized ones. + // + if (TYPE_PTRMEMFUNC_P (type)) + r = "" + r; + else + { + tree name (TYPE_NAME (type)); + r = IDENTIFIER_POINTER (DECL_NAME (name)) + r; + } + } + else + { + // Template instantiation. + // + tree decl (TI_TEMPLATE (ti)); // DECL_TEMPLATE + string id (IDENTIFIER_POINTER (DECL_NAME (decl))); + + id += '<'; + + tree args (INNERMOST_TEMPLATE_ARGS (TI_ARGS (ti))); + + int n (TREE_VEC_LENGTH (args)); + + for (size_t i (0), n (TREE_VEC_LENGTH (args)); i < n ; ++i) + { + tree a (TREE_VEC_ELT (args, i)); + + if (i != 0) + id += ", "; + + // Assume type-only arguments. + // + id += emit_type_name (a); + } + + id += '>'; + + r = id + r; + } + + break; + } + + case ENUMERAL_TYPE: + { + type = TYPE_MAIN_VARIANT (type); + tree decl (TYPE_NAME (type)); + r = IDENTIFIER_POINTER (DECL_NAME (decl)) + r; + break; + } + + // + // Derived types. + // + + case ARRAY_TYPE: + { + unsigned long long size (0); + + if (tree index = TYPE_DOMAIN (type)) + { + tree max (TYPE_MAX_VALUE (index)); + + if (TREE_CODE (max) == INTEGER_CST) + { + HOST_WIDE_INT hwl (TREE_INT_CST_LOW (max)); + HOST_WIDE_INT hwh (TREE_INT_CST_HIGH (max)); + + if (hwl != ~HOST_WIDE_INT (0) && hwh != ~HOST_WIDE_INT (0)) + { + unsigned long long l (hwl); + unsigned long long h (hwh); + unsigned short width (HOST_BITS_PER_WIDE_INT); + + size = (h << width) + l + 1; + } + } + else + { + // Non-integer array index which we do not support. The + // error has been/will be issued in emit_type. + // + } + } + + tree t (TREE_TYPE (type)); + + if (size != 0) + { + ostringstream ostr; + ostr << size; + r = emit_type_name (t) + "[" + ostr.str () + "]" + r; + } + else + r = emit_type_name (t) + "[]" + r; + + break; + } + case REFERENCE_TYPE: + { + tree t (TREE_TYPE (type)); + r = emit_type_name (t) + "&" + r; + break; + } + case POINTER_TYPE: + { + if (!TYPE_PTRMEM_P (type)) + { + tree t (TREE_TYPE (type)); + r = emit_type_name (t) + "*" + r; + } + else + r = ""; + + break; + } + + // + // Fundamental types. + // + + case VOID_TYPE: + case REAL_TYPE: + case BOOLEAN_TYPE: + case INTEGER_TYPE: + { + type = TYPE_MAIN_VARIANT (type); + tree decl (TYPE_NAME (type)); + r = IDENTIFIER_POINTER (DECL_NAME (decl)) + r; + break; + } + default: + { + r = "<" + string (tree_code_name[tc]) + ">"; + break; + } + } + + return r; +} + +void parser:: +process_pragmas (tree t, + node& node, + string const& name, + decl_set::const_iterator begin, + decl_set::const_iterator cur, + decl_set::const_iterator end) +{ + // First process the position pragmas by iterating backwards + // until we get to the preceding non-pragma declaration. + // + pragma_set prags; + + if (cur != begin) + { + decl_set::const_iterator i (cur); + for (--i; i != begin && i->prag != 0; --i) ; + + // We may stop at pragma if j == b. + // + if (i->prag == 0) + ++i; + + for (; i != cur; ++i) + { + assert (!i->assoc); + + if (check_decl_type (t, name, i->prag->name, i->prag->loc)) + prags.insert (*i->prag); + else + error_++; + + i->assoc = true; // Mark this pragma as associated. + } + } + + // Now see if there are any identifier pragmas for this decl. + // By doing this after handling the position pragmas we ensure + // correct overriding. + // + { + decl_pragmas::const_iterator i (decl_pragmas_.find (t)); + + if (i != decl_pragmas_.end ()) + prags.insert (i->second.begin (), i->second.end ()); + } + + // Finally, copy the resulting pragma set to context. + // + for (pragma_set::iterator i (prags.begin ()); i != prags.end (); ++i) + { + if (trace) + ts << "\t\t pragma " << i->name << " (" << i->value << ")" + << endl; + + node.set (i->name, i->value); + } +} + +void parser:: +diagnose_unassoc_pragmas (decl_set const& decls) +{ + for (decl_set::const_iterator i (decls.begin ()), e (decls.end ()); + i != e; ++i) + { + if (i->prag && !i->assoc) + { + pragma const& p (*i->prag); + error_at (p.loc, "odb pragma %qs is not associated with a declaration", + p.name.c_str ()); + error_++; + } + } +} + +string parser:: +fq_scope (tree decl) +{ + string s, tmp; + + for (tree scope (CP_DECL_CONTEXT (decl)); + scope != global_namespace; + scope = CP_DECL_CONTEXT (scope)) + { + tree n = DECL_NAME (scope); + + tmp = "::"; + tmp += (n != NULL_TREE ? IDENTIFIER_POINTER (n) : ""); + tmp += s; + s.swap (tmp); + } + + return s; +} + +parser::access parser:: +decl_access (tree decl) +{ + if (TREE_PRIVATE (decl)) + return access::private_; + + if (TREE_PROTECTED (decl)) + return access::protected_; + + return access::public_; +} diff --git a/odb/parser.hxx b/odb/parser.hxx new file mode 100644 index 0000000..128abb5 --- /dev/null +++ b/odb/parser.hxx @@ -0,0 +1,148 @@ +// file : odb/parser.hxx +// author : Boris Kolpackov +// copyright : Copyright (c) 2009-2010 Code Synthesis Tools CC +// license : GNU GPL v2; see accompanying LICENSE file + +#ifndef ODB_PARSER_HXX +#define ODB_PARSER_HXX + +#include + +#include +#include +#include // std::auto_ptr +#include + +#include +#include +#include + +class parser +{ +public: + class failed {}; + + parser (options const& ops, loc_pragmas const&, decl_pragmas const&); + + std::auto_ptr + parse (tree global_scope, semantics::path const& main_file); + +private: + typedef semantics::path path; + typedef semantics::access access; + + // Extended GGC tree declaration that is either a tree node or a + // pragma. If this declaration is a pragma, then the assoc flag + // indicated whether this pragma has been associated with a + // declaration. + // + struct tree_decl + { + tree decl; + pragma const* prag; + mutable bool assoc; // Allow modification via std::set iterator. + + tree_decl (tree d): decl (d), prag (0) {} + tree_decl (pragma const& p): decl (0), prag (&p), assoc (false) {} + + bool + operator< (tree_decl const& y) const; + }; + + typedef std::multiset decl_set; + +private: + void + collect (tree ns); + + void + emit (); + + // Emit a type declaration. This is either a named class-type definition/ + // declaration or a typedef. In the former case the function returns the + // newly created type node. In the latter case it returns 0. + // + semantics::type* + emit_type_decl (tree); + + // Emit a template declaration. + // + void + emit_template_decl (tree); + + semantics::class_template& + emit_class_template (tree, bool stub = false); + + semantics::union_template& + emit_union_template (tree, bool stub = false); + + template + T& + emit_class (tree, path const& f, size_t l, size_t c, bool stub = false); + + template + T& + emit_union (tree, path const& f, size_t l, size_t c, bool stub = false); + + semantics::enum_& + emit_enum (tree, path const& f, size_t l, size_t c, bool stub = false); + + // Create new or find existing semantic graph type. + // + semantics::type& + emit_type (tree, path const& f, size_t l, size_t c); + + semantics::type& + create_type (tree, path const& f, size_t l, size_t c); + + std::string + emit_type_name (tree, bool direct = true); + + + // Pragma handling. + // + void + process_pragmas (tree, + semantics::node&, + std::string const& name, + decl_set::const_iterator begin, + decl_set::const_iterator cur, + decl_set::const_iterator end); + + void + diagnose_unassoc_pragmas (decl_set const&); + + // Return declaration's fully-qualified scope name (e.g., ::foo::bar). + // + std::string + fq_scope (tree); + + // Return declaration's access. + // + access + decl_access (tree); + + // + // + template + void + define_fund (tree); + +private: + options const& ops_; + loc_pragmas const& loc_pragmas_; + decl_pragmas const& decl_pragmas_; + + bool trace; + std::ostream& ts; + + semantics::unit* unit_; + semantics::scope* scope_; + + std::size_t error_; + + decl_set decls_; +}; + + +#endif // ODB_PARSER_HXX diff --git a/odb/plugin.cxx b/odb/plugin.cxx index 98d12d8..eef51b9 100644 --- a/odb/plugin.cxx +++ b/odb/plugin.cxx @@ -5,1706 +5,21 @@ #include // Keep it first. -#include -#include -#include #include // std::auto_ptr -#include -#include +#include +#include #include #include +#include #include -#include #include +#include using namespace std; using namespace semantics; int plugin_is_GPL_compatible; - -class parser -{ -public: - class failed {}; - - parser (options const& ops, - loc_pragmas const& lp, - decl_pragmas const& dp) - : ops_ (ops), - loc_pragmas_ (lp), - decl_pragmas_ (dp), - trace (ops.trace ()), - ts (cerr) - { - } - - auto_ptr - parse (tree global_scope, path const& main_file) - { - auto_ptr u (new unit (main_file)); - unit_ = u.get (); - scope_ = unit_; - error_ = 0; - - // Define fundamental types. - // - define_fund (void_type_node); - define_fund (boolean_type_node); - define_fund (char_type_node); - define_fund (wchar_type_node); - define_fund (signed_char_type_node); - define_fund (unsigned_char_type_node); - define_fund (short_integer_type_node); - define_fund (short_unsigned_type_node); - define_fund (integer_type_node); - define_fund (unsigned_type_node); - define_fund (long_integer_type_node); - define_fund (long_unsigned_type_node); - define_fund (long_long_integer_type_node); - define_fund (long_long_unsigned_type_node); - define_fund (float_type_node); - define_fund (double_type_node); - define_fund (long_double_type_node); - - // First collect all the declarations we are interested in - // in the line-decl map so that they appear in the source - // code order. - // - collect (global_scope); - - // Add namespace-level location pragmas if any. - // - { - loc_pragmas::const_iterator i (loc_pragmas_.find (global_namespace)); - - if (i != loc_pragmas_.end ()) - decls_.insert (i->second.begin (), i->second.end ()); - } - - // Construct the semantic graph. - // - emit (); - - if (error_ > 0) - throw failed (); - - return u; - } - -private: - typedef semantics::access access; - - // Extended GGC tree declaration that is either a tree node or a - // pragma. If this declaration is a pragma, then the assoc flag - // indicated whether this pragma has been associated with a - // declaration. - // - struct tree_decl - { - tree decl; - pragma const* prag; - mutable bool assoc; // Allow modification via std::set iterator. - - tree_decl (tree d): decl (d), prag (0) {} - tree_decl (pragma const& p): decl (0), prag (&p), assoc (false) {} - - bool - operator< (tree_decl const& y) const - { - location_t xloc (decl ? DECL_SOURCE_LOCATION (decl) : prag->loc); - location_t yloc (y.decl ? DECL_SOURCE_LOCATION (y.decl) : y.prag->loc); - - if (xloc != yloc) - return xloc < yloc; - - size_t xl (LOCATION_LINE (xloc)); - size_t yl (LOCATION_LINE (yloc)); - - if (xl != yl) - return xl < yl; - - size_t xc (LOCATION_COLUMN (xloc)); - size_t yc (LOCATION_COLUMN (yloc)); - - if (xc != yc) - return xc < yc; - - return false; - } - }; - - typedef std::multiset decl_set; - -private: - void - collect (tree ns) - { - cp_binding_level* level = NAMESPACE_LEVEL (ns); - tree decl = level->names; - - // Collect declarations. - // - for (; decl != NULL_TREE; decl = TREE_CHAIN (decl)) - { - if (DECL_IS_BUILTIN (decl)) - continue; - - switch (TREE_CODE (decl)) - { - case TYPE_DECL: - { - if (DECL_NAME (decl) != NULL_TREE) - decls_.insert (decl); - - break; - } - case TEMPLATE_DECL: - { - if (DECL_CLASS_TEMPLATE_P (decl)) - decls_.insert (decl); - break; - } - } - } - - // Traverse namespaces. - // - for(decl = level->namespaces; decl != NULL_TREE; decl = TREE_CHAIN (decl)) - { - // !DECL_NAMESPACE_STD_P (decl) - - if (!DECL_IS_BUILTIN (decl)) - { - if (trace) - { - tree dn (DECL_NAME (decl)); - char const* name (dn ? IDENTIFIER_POINTER (dn) : ""); - - ts << "namespace " << name << " at " - << DECL_SOURCE_FILE (decl) << ":" - << DECL_SOURCE_LINE (decl) << endl; - } - - collect (decl); - } - } - } - - void - emit () - { - for (decl_set::const_iterator b (decls_.begin ()), i (b), - e (decls_.end ()); i != e; ++i) - { - // Skip pragmas. - // - if (i->prag) - continue; - - tree decl (i->decl); - - // Get this declaration's namespace and unwind our scope until - // we find a common prefix of namespaces. - // - string pfx; - string ns (fq_scope (decl)); - - for (pfx = scope_->fq_name (); !pfx.empty (); pfx = scope_->fq_name ()) - { - if (ns.compare (0, pfx.size (), pfx) == 0) - break; - - scope_ = &scope_->scope_ (); - } - - // Build the rest of the namespace hierarchy for this declaration. - // - if (ns != pfx) - { - path f (DECL_SOURCE_FILE (decl)); - size_t l (DECL_SOURCE_LINE (decl)); - size_t c (DECL_SOURCE_COLUMN (decl)); - - for (size_t b (pfx.size () + 2), e (ns.find ("::", b)); - b != string::npos;) - { - string n (ns, b, e == string::npos ? e : e - b); - - if (trace) - ts << "creating namespace " << n << " for " - << DECL_SOURCE_FILE (decl) << ":" - << DECL_SOURCE_LINE (decl) << endl; - - // Use the declarations's file, line, and column as an - // approximation for this namespace origin. - // - namespace_& node (unit_->new_node (f, l, c)); - unit_->new_edge (*scope_, node, n); - scope_ = &node; - - if (e == string::npos) - b = e; - else - { - b = e + 2; - e = ns.find ("::", b); - } - } - } - - switch (TREE_CODE (decl)) - { - case TYPE_DECL: - { - type* n (emit_type_decl (decl)); - - // If this is a named class-type definition, then handle - // the pragmas. - // - if (n != 0) - process_pragmas (n->tree_node (), *n, n->name (), b, i, e); - - break; - } - case TEMPLATE_DECL: - { - emit_template_decl (decl); - break; - } - } - } - - // Diagnose any position pragmas that haven't been associated. - // - diagnose_unassoc_pragmas (decls_); - } - - // Emit a type declaration. This is either a named class-type definition/ - // declaration or a typedef. In the former case the function returns the - // newly created type node. In the latter case it returns 0. - // - type* - emit_type_decl (tree decl) - { - tree t (TREE_TYPE (decl)); - int tc (TREE_CODE (t)); - - tree decl_name (DECL_NAME (decl)); - char const* name (IDENTIFIER_POINTER (decl_name)); - - - if (DECL_ARTIFICIAL (decl) && - (tc == RECORD_TYPE || tc == UNION_TYPE || tc == ENUMERAL_TYPE)) - { - // If we have an anonymous class typedef, use the user- - // supplied name instead of the synthesized one. ARM - // says that in typedef struct {} S; S becomes struct's - // name. - // - if (ANON_AGGRNAME_P (decl_name)) - { - tree d (TYPE_NAME (t)); - - if (d != NULL_TREE && - !DECL_ARTIFICIAL (d) && - DECL_NAME (d) != NULL_TREE && - !ANON_AGGRNAME_P (DECL_NAME (d))) - { - decl = d; - decl_name = DECL_NAME (decl); - name = IDENTIFIER_POINTER (decl_name); - } - else - { - // This type has only the synthesized name which means that - // it is either typedef'ed as a derived type or it is used - // to declare a varibale or similar. The first case will be - // covered by the typedef handling code below. The second - // case will be covere by emit_type(). - // - return 0; - } - } - - path file (DECL_SOURCE_FILE (decl)); - size_t line (DECL_SOURCE_LINE (decl)); - size_t clmn (DECL_SOURCE_COLUMN (decl)); - - type* node (0); - - // Pointers to member functions are represented as record - // types. Detect and handle this case. - // - if (TYPE_PTRMEMFUNC_P (t)) - { - t = TYPE_MAIN_VARIANT (t); - node = &unit_->new_node ( - file, line, clmn, t, "pointer_to_member_function_type"); - unit_->insert (t, *node); - } - else - { - - if (trace) - ts << "start " << tree_code_name[tc] << " " << name << " at " - << DECL_SOURCE_FILE (decl) << ":" - << DECL_SOURCE_LINE (decl) << endl; - - switch (tc) - { - case RECORD_TYPE: - { - node = &emit_class (t, file, line, clmn); - break; - } - case UNION_TYPE: - { - node = &emit_union (t, file, line, clmn); - break; - } - case ENUMERAL_TYPE: - { - node = &emit_enum (t, file, line, clmn); - break; - } - } - - if (trace) - ts << "end " << tree_code_name[tc] << " " << name - << " (" << node << ") at " - << DECL_SOURCE_FILE (decl) << ":" - << DECL_SOURCE_LINE (decl) << endl; - } - - if (COMPLETE_TYPE_P (t)) - unit_->new_edge (*scope_, *node, name); - else - unit_->new_edge (*scope_, *node, name); - - return node; - } - else - { - // Normal typedef. We need to detect and ignore the anonymous - // class typedef case described above since we already used - // this name to define the class. - // - int tc (TREE_CODE (t)); - - if ((tc == RECORD_TYPE || tc == UNION_TYPE || tc == ENUMERAL_TYPE) && - TYPE_NAME (TYPE_MAIN_VARIANT (t)) == decl) - return 0; - - path f (DECL_SOURCE_FILE (decl)); - size_t l (DECL_SOURCE_LINE (decl)); - size_t c (DECL_SOURCE_COLUMN (decl)); - - type& node (emit_type (t, f, l, c)); - unit_->new_edge (*scope_, node, name); - - if (trace) - { - string s (emit_type_name (t, false)); - - ts << "typedef " << s << " (" << &node << ") -> " << name << " at " - << DECL_SOURCE_FILE (decl) << ":" - << DECL_SOURCE_LINE (decl) << endl; - } - - return 0; - } - } - - // Emit a template declaration. - // - void - emit_template_decl (tree decl) - { - // Currently we only handle class/union templates. - // - tree t (TREE_TYPE (DECL_TEMPLATE_RESULT (decl))); - int tc (TREE_CODE (t)); - - if (trace) - { - ts << tree_code_name[tc] << " template (" << decl << ") " - << IDENTIFIER_POINTER (DECL_NAME (decl)) << " (" << t << ") at " - << DECL_SOURCE_FILE (decl) << ":" - << DECL_SOURCE_LINE (decl) << endl; - - ts << "specializations:" << endl; - - for (tree s (DECL_TEMPLATE_SPECIALIZATIONS (decl)); - s != NULL_TREE; s = TREE_CHAIN (s)) - { - tree t (TREE_TYPE (s)); - tree d (TYPE_NAME (t)); - - ts << "\tspecialization" << t << " at " - << DECL_SOURCE_FILE (d) << ":" - << DECL_SOURCE_LINE (d) << endl; - } - - ts << "instantiations:" << endl; - - for (tree i (DECL_TEMPLATE_INSTANTIATIONS (decl)); - i != NULL_TREE; i = TREE_CHAIN (i)) - { - tree t (TREE_VALUE (i)); - tree d (TYPE_NAME (t)); - - ts << "\tinstantiation" << t << " at " - << DECL_SOURCE_FILE (d) << ":" - << DECL_SOURCE_LINE (d) << endl; - } - } - - char const* name (IDENTIFIER_POINTER (DECL_NAME (decl))); - - if (trace) - ts << "start " << tree_code_name[tc] << " template " << name << " at " - << DECL_SOURCE_FILE (decl) << ":" - << DECL_SOURCE_LINE (decl) << endl; - - type_template* t_node (0); - - if (tc == RECORD_TYPE) - t_node = &emit_class_template (decl); - else - t_node = &emit_union_template (decl); - - if (COMPLETE_TYPE_P (t)) - unit_->new_edge (*scope_, *t_node, name); - else - unit_->new_edge (*scope_, *t_node, name); - - if (trace) - ts << "end " << tree_code_name[tc] << " template " << name - << " (" << t_node << ") at " - << DECL_SOURCE_FILE (decl) << ":" - << DECL_SOURCE_LINE (decl) << endl; - } - - class_template& - emit_class_template (tree t, bool stub = false) - { - // See if there is a stub already for this template. - // - class_template* ct_node (0); - - if (node* n = unit_->find (t)) - { - ct_node = &dynamic_cast (*n); - } - else - { - path f (DECL_SOURCE_FILE (t)); - size_t l (DECL_SOURCE_LINE (t)); - size_t c (DECL_SOURCE_COLUMN (t)); - - ct_node = &unit_->new_node (f, l, c); - unit_->insert (t, *ct_node); - } - - tree c (TREE_TYPE (DECL_TEMPLATE_RESULT (t))); - - if (stub || !COMPLETE_TYPE_P (c)) - return *ct_node; - - // Collect member declarations so that we can traverse them in - // the source code order. For now we are only interested in - // nested class template declarations. - // - decl_set decls; - - for (tree d (TYPE_FIELDS (c)); d != NULL_TREE ; d = TREE_CHAIN (d)) - { - switch (TREE_CODE (d)) - { - case TEMPLATE_DECL: - { - if (DECL_CLASS_TEMPLATE_P (d)) - decls.insert (d); - break; - } - } - } - - scope* prev_scope (scope_); - scope_ = ct_node; - - for (decl_set::const_iterator i (decls.begin ()), e (decls.end ()); - i != e; ++i) - { - // Skip pragmas. - // - if (i->prag) - continue; - - tree d (i->decl); - - switch (TREE_CODE (d)) - { - case TEMPLATE_DECL: - { - emit_template_decl (d); - break; - } - } - } - - // Diagnose any position pragmas that haven't been associated. - // - diagnose_unassoc_pragmas (decls); - - scope_ = prev_scope; - return *ct_node; - } - - union_template& - emit_union_template (tree t, bool stub = false) - { - // See if there is a stub already for this template. - // - union_template* ut_node (0); - - if (node* n = unit_->find (t)) - { - ut_node = &dynamic_cast (*n); - } - else - { - path f (DECL_SOURCE_FILE (t)); - size_t l (DECL_SOURCE_LINE (t)); - size_t c (DECL_SOURCE_COLUMN (t)); - - ut_node = &unit_->new_node (f, l, c); - unit_->insert (t, *ut_node); - } - - tree u (TREE_TYPE (DECL_TEMPLATE_RESULT (t))); - - if (stub || !COMPLETE_TYPE_P (u)) - return *ut_node; - - // Collect member declarations so that we can traverse them in - // the source code order. For now we are only interested in - // nested class template declarations. - // - decl_set decls; - - for (tree d (TYPE_FIELDS (u)); d != NULL_TREE ; d = TREE_CHAIN (d)) - { - switch (TREE_CODE (d)) - { - case TEMPLATE_DECL: - { - if (DECL_CLASS_TEMPLATE_P (d)) - decls.insert (d); - break; - } - } - } - - scope* prev_scope (scope_); - scope_ = ut_node; - - for (decl_set::const_iterator i (decls.begin ()), e (decls.end ()); - i != e; ++i) - { - // Skip pragmas. - // - if (i->prag) - continue; - - tree d (i->decl); - - switch (TREE_CODE (d)) - { - case TEMPLATE_DECL: - { - emit_template_decl (d); - break; - } - } - } - - // Diagnose any position pragmas that haven't been associated. - // - diagnose_unassoc_pragmas (decls); - - scope_ = prev_scope; - return *ut_node; - } - - template - T& - emit_class (tree c, - path const& file, - size_t line, - size_t clmn, - bool stub = false) - { - c = TYPE_MAIN_VARIANT (c); - - // See if there is a stub already for this type. - // - T* c_node (0); - - if (node* n = unit_->find (c)) - { - c_node = &dynamic_cast (*n); - } - else - { - c_node = &unit_->new_node (file, line, clmn, c); - unit_->insert (c, *c_node); - } - - if (stub || !COMPLETE_TYPE_P (c)) - return *c_node; - - // Traverse base information. - // - tree bis (TYPE_BINFO (c)); - size_t n (bis ? BINFO_N_BASE_BINFOS (bis) : 0); - - for (size_t i (0); i < n; i++) - { - tree bi (BINFO_BASE_BINFO (bis, i)); - access a (access::public_); - - if (BINFO_BASE_ACCESSES (bis)) - { - tree ac (BINFO_BASE_ACCESS (bis, i)); - - if (ac == NULL_TREE || ac == access_public_node) - { - a = access::public_; - } - else if (ac == access_protected_node) - { - a = access::protected_; - } - else - { - assert (ac == access_private_node); - a = access::private_; - } - } - - bool virt (BINFO_VIRTUAL_P (bi)); - tree base (TYPE_MAIN_VARIANT (BINFO_TYPE (bi))); - - tree base_decl (TYPE_NAME (base)); // Typedef decl for this base. - - // Find the corresponding graph node. If we cannot find one then - // the base is a template instantiation since an ordinary class - // has to be defined (complete) in order to be a base. - // - class_* b_node (0); - string name; - - if (node* n = unit_->find (base)) - { - b_node = &dynamic_cast (*n); - - if (trace) - name = IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (base))); - } - else - { - b_node = &dynamic_cast (emit_type (base, file, line, clmn)); - - if (trace) - name = emit_type_name (base); - } - - unit_->new_edge (*c_node, *b_node, a, virt); - - if (trace) - ts << "\t" << a.string () << (virt ? " virtual" : "") << " base " - << name << " (" << static_cast (b_node) << ")" << endl; - } - - // Collect member declarations so that we can traverse them in - // the source code order. - // - decl_set decls; - - for (tree d (TYPE_FIELDS (c)); d != NULL_TREE ; d = TREE_CHAIN (d)) - { - switch (TREE_CODE (d)) - { - case TYPE_DECL: - { - if (!DECL_SELF_REFERENCE_P (d)) - decls.insert (d); - break; - } - case TEMPLATE_DECL: - { - if (DECL_CLASS_TEMPLATE_P (d)) - decls.insert (d); - break; - } - case FIELD_DECL: - { - if (!DECL_ARTIFICIAL (d)) - decls.insert (d); - break; - } - } - } - - // Add location pragmas if any. - // - { - loc_pragmas::const_iterator i (loc_pragmas_.find (c)); - - if (i != loc_pragmas_.end ()) - decls.insert (i->second.begin (), i->second.end ()); - } - - scope* prev_scope (scope_); - scope_ = c_node; - - for (decl_set::const_iterator b (decls.begin ()), i (b), e (decls.end ()); - i != e; ++i) - { - // Skip pragmas. - // - if (i->prag) - continue; - - tree d (i->decl); - - switch (TREE_CODE (d)) - { - case TYPE_DECL: - { - type* n (emit_type_decl (d)); - - // If this is a named class-type definition, then handle - // the pragmas. - // - if (n != 0) - process_pragmas (n->tree_node (), *n, n->name (), b, i, e); - - break; - } - case TEMPLATE_DECL: - { - emit_template_decl (d); - break; - } - case FIELD_DECL: - { - // If this is a bit-field then TREE_TYPE may be a modified type - // with lesser precision. In this case, DECL_BIT_FIELD_TYPE - // will be the type that was original specified. Use that type - // for now. Furthermore, bitfields can be anonymous, which we - // ignore. - // - // - bool bf (DECL_C_BIT_FIELD (d)); - - if (bf && DECL_NAME (d) == 0) - break; - - tree t (bf ? DECL_BIT_FIELD_TYPE (d) : TREE_TYPE (d)); - - char const* name (IDENTIFIER_POINTER (DECL_NAME (d))); - - path file (DECL_SOURCE_FILE (d)); - size_t line (DECL_SOURCE_LINE (d)); - size_t clmn (DECL_SOURCE_COLUMN (d)); - - access a (decl_access (d)); - - type& type_node (emit_type (t, file, line, clmn)); - data_member& member_node ( - unit_->new_node (file, line, clmn)); - - unit_->new_edge (member_node, type_node); - unit_->new_edge (*c_node, member_node, name, a); - - if (trace) - { - string type_name (emit_type_name (t)); - - ts << "\t" << a.string () << " data member " << type_name - << " (" << &type_node << ") " << name << " at " - << file << ":" << line << endl; - } - - // Process pragmas that may be associated with this field. - // - process_pragmas (d, member_node, name, b, i, e); - - break; - } - } - } - - // Diagnose any position pragmas that haven't been associated. - // - diagnose_unassoc_pragmas (decls); - - scope_ = prev_scope; - return *c_node; - } - - template - T& - emit_union (tree u, - path const& file, - size_t line, - size_t clmn, - bool stub = false) - { - u = TYPE_MAIN_VARIANT (u); - - // See if there is a stub already for this type. - // - T* u_node (0); - - if (node* n = unit_->find (u)) - { - u_node = &dynamic_cast (*n); - } - else - { - u_node = &unit_->new_node (file, line, clmn, u); - unit_->insert (u, *u_node); - } - - if (stub || !COMPLETE_TYPE_P (u)) - return *u_node; - - // Collect member declarations so that we can traverse them in - // the source code order. - // - decl_set decls; - - for (tree d (TYPE_FIELDS (u)); d != NULL_TREE ; d = TREE_CHAIN (d)) - { - switch (TREE_CODE (d)) - { - case TYPE_DECL: - { - if (!DECL_SELF_REFERENCE_P (d)) - decls.insert (d); - break; - } - case TEMPLATE_DECL: - { - if (DECL_CLASS_TEMPLATE_P (d)) - decls.insert (d); - break; - } - case FIELD_DECL: - { - if (!DECL_ARTIFICIAL (d)) - decls.insert (d); - break; - } - } - } - - // Add location pragmas if any. - // - { - loc_pragmas::const_iterator i (loc_pragmas_.find (u)); - - if (i != loc_pragmas_.end ()) - decls.insert (i->second.begin (), i->second.end ()); - } - - scope* prev_scope (scope_); - scope_ = u_node; - - for (decl_set::const_iterator b (decls.begin ()), i (b), e (decls.end ()); - i != e; ++i) - { - // Skip pragmas. - // - if (i->prag) - continue; - - tree d (i->decl); - - switch (TREE_CODE (d)) - { - case TYPE_DECL: - { - type* n (emit_type_decl (d)); - - // If this is a named class-type definition, then handle - // the pragmas. - // - if (n != 0) - process_pragmas (n->tree_node (), *n, n->name (), b, i, e); - - break; - } - case TEMPLATE_DECL: - { - emit_template_decl (d); - break; - } - case FIELD_DECL: - { - tree t (TREE_TYPE (d)); - char const* name (IDENTIFIER_POINTER (DECL_NAME (d))); - - path file (DECL_SOURCE_FILE (d)); - size_t line (DECL_SOURCE_LINE (d)); - size_t clmn (DECL_SOURCE_COLUMN (d)); - - access a (decl_access (d)); - - type& type_node (emit_type (t, file, line, clmn)); - data_member& member_node ( - unit_->new_node (file, line, clmn)); - - unit_->new_edge (member_node, type_node); - unit_->new_edge (*u_node, member_node, name, a); - - if (trace) - { - string type_name (emit_type_name (t)); - - ts << "\t" << a.string () << " union member " << type_name - << " (" << &type_node << ") " << name << " at " - << file << ":" << line << endl; - } - - // Process pragmas that may be associated with this field. - // - process_pragmas (d, member_node, name, b, i, e); - - break; - } - } - } - - // Diagnose any position pragmas that haven't been associated. - // - diagnose_unassoc_pragmas (decls); - - scope_ = prev_scope; - return *u_node; - } - - enum_& - emit_enum (tree e, - path const& file, - size_t line, - size_t clmn, - bool stub = false) - { - e = TYPE_MAIN_VARIANT (e); - - // See if there is a stub already for this type. - // - enum_* e_node (0); - - if (node* n = unit_->find (e)) - { - e_node = &dynamic_cast (*n); - } - else - { - e_node = &unit_->new_node (file, line, clmn, e); - unit_->insert (e, *e_node); - } - - if (stub || !COMPLETE_TYPE_P (e)) - return *e_node; - - // Traverse enumerators. - // - for (tree er (TYPE_VALUES (e)); er != NULL_TREE ; er = TREE_CHAIN (er)) - { - char const* name (IDENTIFIER_POINTER (TREE_PURPOSE (er))); - - // There doesn't seem to be a way to get the proper position for - // each enumerator. - // - enumerator& er_node = unit_->new_node (file, line, clmn); - unit_->new_edge (*e_node, er_node); - - if (trace) - ts << "\tenumerator " << name << " at " << file << ":" << line << endl; - } - - return *e_node; - } - - // Create new or find existing semantic graph type. - // - type& - emit_type (tree t, - path const& file, - size_t line, - size_t clmn) - { - tree mv (TYPE_MAIN_VARIANT (t)); - - if (trace) - { - ts << tree_code_name[TREE_CODE (t)] << " " << t - << " main " << mv << endl; - - for (tree v (TYPE_MAIN_VARIANT (t)); v != 0; v = TYPE_NEXT_VARIANT (v)) - ts << "\tvariant " << v << endl; - } - - node* n (unit_->find (mv)); - - type& r (n != 0 - ? dynamic_cast (*n) - : create_type (t, file, line, clmn)); - - if (trace && n != 0) - ts << "found node " << &r << " for type " << mv << endl; - - if (cp_type_quals (t) == TYPE_UNQUALIFIED) - return r; - - // See if this type already has this variant. - // - bool qc (CP_TYPE_CONST_P (t)); - bool qv (CP_TYPE_VOLATILE_P (t)); - bool qr (CP_TYPE_RESTRICT_P (t)); - - for (type::qualified_iterator i (r.qualified_begin ()); - i != r.qualified_end (); ++i) - { - qualifier& q (i->qualifier ()); - - if (q.const_ () == qc && q.volatile_ () == qv && q.restrict_ () == qr) - { - if (trace) - ts << "found qualifier variant " << &q << endl; - - return q; - } - } - - // No such variant yet. Create a new one. Qualified types are not - // unique in the tree so don't add this node to the map. - // - qualifier& q (unit_->new_node (file, line, clmn, t, qc, qv, qr)); - unit_->new_edge (q, r); - return q; - } - - type& - create_type (tree t, - path const& file, - size_t line, - size_t clmn) - { - type* r (0); - int tc (TREE_CODE (t)); - - switch (tc) - { - // - // User-defined types. - // - case RECORD_TYPE: - case UNION_TYPE: - { - tree ti (TYPE_TEMPLATE_INFO (t)); - - if (ti == NULL_TREE) - { - // Ordinary class. There are two situations which can lead - // here. First is when we have an anonymous class that is - // part of the declaration, for example: - // - // typedef const struct {...} s; - // - // The second situation is a named class definition which - // we haven't parsed yet. In this case we are going to - // create a "stub" class node which will be processed and - // filled in later. - // - t = TYPE_MAIN_VARIANT (t); - - // Pointers to member functions are represented as record - // types. Detect and handle this case. - // - if (TYPE_PTRMEMFUNC_P (t)) - { - r = &unit_->new_node ( - file, line, clmn, t, "pointer_to_member_function_type"); - unit_->insert (t, *r); - } - else - { - tree d (TYPE_NAME (t)); - - if (trace) - ts << "start anon/stub " << tree_code_name[tc] << " at " - << file << ":" << line << endl; - - if (d == NULL_TREE || ANON_AGGRNAME_P (DECL_NAME (d))) - { - if (tc == RECORD_TYPE) - r = &emit_class (t, file, line, clmn); - else - r = &emit_union (t, file, line, clmn); - } - else - { - // Use the "defining" declaration's file, line, and column - // information to create the stub. - // - path f (DECL_SOURCE_FILE (d)); - size_t l (DECL_SOURCE_LINE (d)); - size_t c (DECL_SOURCE_COLUMN (d)); - - if (tc == RECORD_TYPE) - r = &emit_class (t, f, l, c, true); - else - r = &emit_union (t, f, l, c, true); - } - - if (trace) - ts << "end anon/stub " << tree_code_name[tc] << " (" << r << ")" - << " at " << file << ":" << line << endl; - } - } - else - { - // Template instantiation. - // - t = TYPE_MAIN_VARIANT (t); - tree decl (TI_TEMPLATE (ti)); // DECL_TEMPLATE - - // Get to the most general template declaration. - // - while (DECL_TEMPLATE_INFO (decl)) - decl = DECL_TI_TEMPLATE (decl); - - type_template* t_node (0); - - // Find the template node or create a stub if none exist. - // - if (node* n = unit_->find (decl)) - t_node = &dynamic_cast (*n); - else - { - if (trace) - ts << "start stub " << tree_code_name[tc] << " template for (" - << decl << ") at " << file << ":" << line << endl; - - if (tc == RECORD_TYPE) - t_node = &emit_class_template (decl, true); - else - t_node = &emit_union_template (decl, true); - - if (trace) - ts << "end stub " << tree_code_name[tc] << " template (" - << t_node << ") at " << file << ":" << line << endl; - } - - if (trace) - ts << "start " << tree_code_name[tc] << " instantiation (" - << t << ") for template (" << t_node << ")" - << " at " << file << ":" << line << endl; - - type_instantiation* i_node (0); - - if (tc == RECORD_TYPE) - i_node = &emit_class (t, file, line, clmn); - else - i_node = &emit_union (t, file, line, clmn); - - if (trace) - ts << "end " << tree_code_name[tc] << " instantiation (" - << static_cast (i_node) << ")" - << " at " << file << ":" << line << endl; - - unit_->new_edge (*i_node, *t_node); - r = i_node; - } - - break; - } - case ENUMERAL_TYPE: - { - // The same logic as in the "ordinary class" case above - // applies here. - // - - t = TYPE_MAIN_VARIANT (t); - tree d (TYPE_NAME (t)); - - if (trace) - ts << "start anon/stub " << tree_code_name[tc] << " at " - << file << ":" << line << endl; - - if (d == NULL_TREE || ANON_AGGRNAME_P (DECL_NAME (d))) - { - r = &emit_enum (t, file, line, clmn); - } - else - { - // Use the "defining" declaration's file, line, and column - // information to create the stub. - // - path f (DECL_SOURCE_FILE (d)); - size_t l (DECL_SOURCE_LINE (d)); - size_t c (DECL_SOURCE_COLUMN (d)); - - r = &emit_enum (t, f, l, c, true); - } - - if (trace) - ts << "end anon/stub " << tree_code_name[tc] << " (" << r << ")" - << " at " << file << ":" << line << endl; - - break; - } - - // - // Derived types. - // - - case ARRAY_TYPE: - { - unsigned long long size (0); - - if (tree index = TYPE_DOMAIN (t)) - { - tree max (TYPE_MAX_VALUE (index)); - - if (TREE_CODE (max) == INTEGER_CST) - { - HOST_WIDE_INT hwl (TREE_INT_CST_LOW (max)); - HOST_WIDE_INT hwh (TREE_INT_CST_HIGH (max)); - - // The docs say that TYPE_DOMAIN will be NULL if the - // array doesn't specify bounds. In reality, both - // low and high parts are set to HOST_WIDE_INT_MAX. - // - if (hwl != ~HOST_WIDE_INT (0) && hwh != ~HOST_WIDE_INT (0)) - { - unsigned long long l (hwl); - unsigned long long h (hwh); - unsigned short width (HOST_BITS_PER_WIDE_INT); - - size = (h << width) + l + 1; - } - } - else - { - cerr << file << ':' << line << ':' << clmn << ": error: " - << " non-integer array index " - << tree_code_name[TREE_CODE (max)]; - - throw failed (); - } - } - - type& bt (emit_type (TREE_TYPE (t), file, line, clmn)); - t = TYPE_MAIN_VARIANT (t); - array& a (unit_->new_node (file, line, clmn, t, size)); - unit_->insert (t, a); - unit_->new_edge (a, bt); - r = &a; - break; - } - case REFERENCE_TYPE: - { - type& bt (emit_type (TREE_TYPE (t), file, line, clmn)); - t = TYPE_MAIN_VARIANT (t); - reference& ref (unit_->new_node (file, line, clmn, t)); - unit_->insert (t, ref); - unit_->new_edge (ref, bt); - r = &ref; - break; - } - case POINTER_TYPE: - { - if (!TYPE_PTRMEM_P (t)) - { - type& bt (emit_type (TREE_TYPE (t), file, line, clmn)); - t = TYPE_MAIN_VARIANT (t); - pointer& p (unit_->new_node (file, line, clmn, t)); - unit_->insert (t, p); - unit_->new_edge (p, bt); - r = &p; - } - else - { - t = TYPE_MAIN_VARIANT (t); - r = &unit_->new_node ( - file, line, clmn, t, "pointer_to_data_member_type"); - unit_->insert (t, *r); - - if (trace) - ts << "unsupported pointer_to_data_member_type (" << r << ")" - << " at " << file << ":" << line << endl; - } - break; - } - default: - { - t = TYPE_MAIN_VARIANT (t); - r = &unit_->new_node ( - file, line, clmn, t, tree_code_name[tc]); - unit_->insert (t, *r); - - if (trace) - ts << "unsupported " << tree_code_name[tc] << " (" << r << ")" - << " at " << file << ":" << line << endl; - - break; - } - } - - return *r; - } - - string - emit_type_name (tree type, bool direct = true) - { - // First see if there is a "direct" name for this type. - // - if (direct) - { - if (tree decl = TYPE_NAME (type)) - { - tree t (TREE_TYPE (decl)); - - if (same_type_p (type, t)) - return IDENTIFIER_POINTER (DECL_NAME (decl)); - } - } - - string r; - - if (CP_TYPE_CONST_P (type)) - r += " const"; - - if (CP_TYPE_VOLATILE_P (type)) - r += " volatile"; - - if (CP_TYPE_RESTRICT_P (type)) - r += " __restrict"; - - int tc (TREE_CODE (type)); - - switch (tc) - { - // - // User-defined types. - // - - case RECORD_TYPE: - case UNION_TYPE: - { - tree ti (TYPE_TEMPLATE_INFO (type)); - - if (ti == NULL_TREE) - { - // Ordinary class. - // - type = TYPE_MAIN_VARIANT (type); - - // Pointers to member functions are represented as record - // types and don't have names, not even the synthesized ones. - // - if (TYPE_PTRMEMFUNC_P (type)) - r = "" + r; - else - { - tree name (TYPE_NAME (type)); - r = IDENTIFIER_POINTER (DECL_NAME (name)) + r; - } - } - else - { - // Template instantiation. - // - tree decl (TI_TEMPLATE (ti)); // DECL_TEMPLATE - string id (IDENTIFIER_POINTER (DECL_NAME (decl))); - - id += '<'; - - tree args (INNERMOST_TEMPLATE_ARGS (TI_ARGS (ti))); - - int n (TREE_VEC_LENGTH (args)); - - for (size_t i (0), n (TREE_VEC_LENGTH (args)); i < n ; ++i) - { - tree a (TREE_VEC_ELT (args, i)); - - if (i != 0) - id += ", "; - - // Assume type-only arguments. - // - id += emit_type_name (a); - } - - id += '>'; - - r = id + r; - } - - break; - } - - case ENUMERAL_TYPE: - { - type = TYPE_MAIN_VARIANT (type); - tree decl (TYPE_NAME (type)); - r = IDENTIFIER_POINTER (DECL_NAME (decl)) + r; - break; - } - - // - // Derived types. - // - - case ARRAY_TYPE: - { - unsigned long long size (0); - - if (tree index = TYPE_DOMAIN (type)) - { - tree max (TYPE_MAX_VALUE (index)); - - if (TREE_CODE (max) == INTEGER_CST) - { - HOST_WIDE_INT hwl (TREE_INT_CST_LOW (max)); - HOST_WIDE_INT hwh (TREE_INT_CST_HIGH (max)); - - if (hwl != ~HOST_WIDE_INT (0) && hwh != ~HOST_WIDE_INT (0)) - { - unsigned long long l (hwl); - unsigned long long h (hwh); - unsigned short width (HOST_BITS_PER_WIDE_INT); - - size = (h << width) + l + 1; - } - } - else - { - // Non-integer array index which we do not support. The - // error has been/will be issued in emit_type. - // - } - } - - tree t (TREE_TYPE (type)); - - if (size != 0) - { - ostringstream ostr; - ostr << size; - r = emit_type_name (t) + "[" + ostr.str () + "]" + r; - } - else - r = emit_type_name (t) + "[]" + r; - - break; - } - case REFERENCE_TYPE: - { - tree t (TREE_TYPE (type)); - r = emit_type_name (t) + "&" + r; - break; - } - case POINTER_TYPE: - { - if (!TYPE_PTRMEM_P (type)) - { - tree t (TREE_TYPE (type)); - r = emit_type_name (t) + "*" + r; - } - else - r = ""; - - break; - } - - // - // Fundamental types. - // - - case VOID_TYPE: - case REAL_TYPE: - case BOOLEAN_TYPE: - case INTEGER_TYPE: - { - type = TYPE_MAIN_VARIANT (type); - tree decl (TYPE_NAME (type)); - r = IDENTIFIER_POINTER (DECL_NAME (decl)) + r; - break; - } - default: - { - r = "<" + string (tree_code_name[tc]) + ">"; - break; - } - } - - return r; - } - - void - process_pragmas (tree t, - node& node, - string const& name, - decl_set::const_iterator begin, - decl_set::const_iterator cur, - decl_set::const_iterator end) - { - // First process the position pragmas by iterating backwards - // until we get to the preceding non-pragma declaration. - // - pragma_set prags; - - if (cur != begin) - { - decl_set::const_iterator i (cur); - for (--i; i != begin && i->prag != 0; --i) ; - - // We may stop at pragma if j == b. - // - if (i->prag == 0) - ++i; - - for (; i != cur; ++i) - { - assert (!i->assoc); - - if (check_decl_type (t, name, i->prag->name, i->prag->loc)) - prags.insert (*i->prag); - else - error_++; - - i->assoc = true; // Mark this pragma as associated. - } - } - - // Now see if there are any identifier pragmas for this decl. - // By doing this after handling the position pragmas we ensure - // correct overriding. - // - { - decl_pragmas::const_iterator i (decl_pragmas_.find (t)); - - if (i != decl_pragmas_.end ()) - prags.insert (i->second.begin (), i->second.end ()); - } - - // Finally, copy the resulting pragma set to context. - // - for (pragma_set::iterator i (prags.begin ()); i != prags.end (); ++i) - { - if (trace) - ts << "\t\t pragma " << i->name << " (" << i->value << ")" - << endl; - - node.set (i->name, i->value); - } - } - - void - diagnose_unassoc_pragmas (decl_set const& decls) - { - for (decl_set::const_iterator i (decls.begin ()), e (decls.end ()); - i != e; ++i) - { - if (i->prag && !i->assoc) - { - pragma const& p (*i->prag); - error_at (p.loc, "odb pragma %qs is not associated with a declaration", - p.name.c_str ()); - error_++; - } - } - } - - // Return declaration's fully-qualified scope name (e.g., ::foo::bar). - // - string - fq_scope (tree decl) - { - string s, tmp; - - for (tree scope (CP_DECL_CONTEXT (decl)); - scope != global_namespace; - scope = CP_DECL_CONTEXT (scope)) - { - tree n = DECL_NAME (scope); - - tmp = "::"; - tmp += (n != NULL_TREE ? IDENTIFIER_POINTER (n) : ""); - tmp += s; - s.swap (tmp); - } - - return s; - } - - // Return access for decl. - // - access - decl_access (tree decl) - { - if (TREE_PRIVATE (decl)) - return access::private_; - - if (TREE_PROTECTED (decl)) - return access::protected_; - - return access::public_; - } - - // - // - template - void - define_fund (tree t) - { - t = TYPE_MAIN_VARIANT (t); - char const* name (IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (t)))); - - T& node (unit_->new_fund_node (t)); - unit_->new_edge (*scope_, node, name); - unit_->insert (t, node); - } - -private: - options const& ops_; - loc_pragmas const& loc_pragmas_; - decl_pragmas const& decl_pragmas_; - - bool trace; - ostream& ts; - - unit* unit_; - scope* scope_; - - size_t error_; - - decl_set decls_; - - typedef std::map fund_type_map; - fund_type_map fund_types_; -}; - auto_ptr options_; extern "C" void @@ -1744,8 +59,8 @@ gate_callback (void* gcc_data, void*) } extern "C" int -plugin_init (struct plugin_name_args *plugin_info, - struct plugin_gcc_version *version) +plugin_init (struct plugin_name_args* plugin_info, + struct plugin_gcc_version* version) { int r (0); -- cgit v1.1