Support reading namespaces

* include/abg-fwd.h (get_global_scope): Return a const
	global_scope.  Add a new overload that takes a naked pointer as
	parm.
	(insert_decl_into_scope, get_top_most_scope_under): Declare new
	entry points.
	* include/abg-ir.h (class decl_base, class scope_decl): Add
	insert_decl_into_scope as a friend of these classes.
	(scope_decl::{insert_decl_into_scope, find_iterator_for_member}):
	Declare new member.
	(scope_decl::get_member_decls): New non-const overload.
	* src/abg-dwarf-reader.cc (build_translation_unit): Remove the
	"recurse" parameter.  Adjust the call to build_ir_node_from_die to
	read just public decls that are at namespace scope.  Anything else
	should be dropped unless it's needed to emitting the public
	namespace-level decls.
	(build_namespace_decl_and_add_to_ir)
	(canonicalize_and_insert_type_into_ir): Define new static
	functions.
	(build_corpus): Adjust ad build_translation_unit doesn't have the
	"recurse" parameter anymore.
	(canonicalize_and_add_type_to_ir): Make this static.  Fix
	comments.
	(build_ir_node_from_die): Take a new "only_public_decl"
	parameter. For DW_TAG_base_type case, use the new
	canonicalize_and_insert_type_into_ir to insert the type at the
	right place in the global scope making sure it is seen before the
	current scope.  For pointer, references and qualified types, use
	canonicalize_and_insert_type_into_ir to add the type at the same
	scope as its underlying type.  Handle DW_TAG_{namespace,module}
	using the new build_namespace_decl_and_add_to_ir function.  Add
	some vertical spaces and some assertions.
	* src/abg-ir.cc (scope_decl::add_member_decl): Use scope_decl_sptr
	typedef.
	(scope_decl::{insert_member_decl,find_iterator_for_member}):
	Define new methods.
	(insert_decl_into_scope, get_top_most_scope_under): Define new
	functions.
	(get_global_scope): Constify the return type.
	(get_translation_unit): Adjust as get_global_scope now returns a
	const.
	* src/abg-reader.cc (get_translation_unit): Likewise.

Signed-off-by: Dodji Seketeli <dodji@redhat.com>
This commit is contained in:
Dodji Seketeli 2013-12-12 15:40:52 +01:00
parent f918fdb0f9
commit 643b02fd6a
5 changed files with 413 additions and 46 deletions

View File

@ -60,6 +60,7 @@ namespace abigail
// Inject some types.
using std::tr1::shared_ptr;
using std::string;
using std::vector;
// Pull in relational operators.
using namespace std::rel_ops;
@ -112,7 +113,7 @@ add_decl_to_scope(shared_ptr<decl_base>, scope_decl*);
void
add_decl_to_scope (shared_ptr<decl_base>, shared_ptr<scope_decl>);
global_scope*
const global_scope*
get_global_scope(const shared_ptr<decl_base>);
translation_unit*
@ -160,11 +161,18 @@ add_decl_to_scope(shared_ptr<decl_base>, scope_decl*);
void
add_decl_to_scope(shared_ptr<decl_base>, shared_ptr<scope_decl>);
global_scope*
get_global_scope(decl_base* decl);
void
insert_decl_into_scope(shared_ptr<decl_base>,
vector<shared_ptr<decl_base> >::iterator,
scope_decl*);
global_scope*
get_global_scope(const shared_ptr<decl_base>);
void
insert_decl_into_scope(shared_ptr<decl_base>,
vector<shared_ptr<decl_base> >::iterator,
shared_ptr<scope_decl>);
const global_scope*
get_global_scope(const decl_base* decl);
translation_unit*
get_translation_unit(decl_base* decl);
@ -178,6 +186,18 @@ get_type_name(const shared_ptr<type_base>);
shared_ptr<decl_base>
get_type_declaration(const shared_ptr<type_base>);
const scope_decl*
get_top_most_scope_under(const decl_base*,
const scope_decl*);
const scope_decl*
get_top_most_scope_under(const shared_ptr<decl_base>,
const scope_decl*);
const scope_decl*
get_top_most_scope_under(const shared_ptr<decl_base>,
const shared_ptr<scope_decl>);
void
dump(const shared_ptr<decl_base>, std::ostream&);

View File

@ -265,6 +265,12 @@ public:
friend void
add_decl_to_scope(shared_ptr<decl_base> dcl, scope_decl* scpe);
friend void
insert_decl_into_scope(shared_ptr<decl_base>,
vector<shared_ptr<decl_base> >::iterator,
scope_decl*);
friend class class_decl;
};// end class decl_base
@ -300,6 +306,10 @@ protected:
virtual void
add_member_decl(const decl_base_sptr member);
virtual void
insert_member_decl(const decl_base_sptr member,
declarations::iterator before);
public:
scope_decl(const std::string& name, location locus,
visibility vis = VISIBILITY_DEFAULT)
@ -316,14 +326,24 @@ public:
get_member_decls() const
{return members_;}
const scopes&
get_member_scopes() const
declarations&
get_member_decls()
{return members_;}
scopes&
get_member_scopes()
{return member_scopes_;}
bool
is_empty() const
{return get_member_decls().empty();}
bool
find_iterator_for_member(const decl_base*, declarations::iterator&);
bool
find_iterator_for_member(const decl_base_sptr, declarations::iterator&);
void
traverse(ir_node_visitor&);
@ -331,6 +351,11 @@ public:
friend void
add_decl_to_scope(shared_ptr<decl_base> dcl, scope_decl* scpe);
friend void
insert_decl_into_scope(decl_base_sptr decl,
scope_decl::declarations::iterator before,
scope_decl* scope);
};//end class scope_decl
/// Convenience typedef for shared pointer on @ref global_scope.

View File

@ -206,7 +206,8 @@ public:
static decl_base_sptr
build_ir_node_from_die(read_context& ctxt,
Dwarf_Die* die);
Dwarf_Die* die,
bool only_public_decl = false);
/// Constructor for a default Dwfl handle that knows how to load debug
/// info from a library or executable elf file.
@ -472,7 +473,9 @@ is_public_decl(Dwarf_Die* die)
}
/// Given a DW_TAG_compile_unit, build and return the corresponding
/// abigail::translation_unit ir node.
/// abigail::translation_unit ir node. Note that this function
/// recursively reads the children dies of the current DIE and
/// populates the resulting translation unit.
///
/// @param ctxt the read_context to use.
///
@ -489,8 +492,7 @@ is_public_decl(Dwarf_Die* die)
static translation_unit_sptr
build_translation_unit(read_context& ctxt,
Dwarf_Die* die,
char address_size,
bool recurse = false)
char address_size)
{
translation_unit_sptr result;
@ -505,17 +507,64 @@ build_translation_unit(read_context& ctxt,
ctxt.current_translation_unit(result);
Dwarf_Die child;
if (!recurse
|| (dwarf_child(die, &child) != 0))
if (dwarf_child(die, &child) != 0)
return result;
do
build_ir_node_from_die(ctxt, &child);
build_ir_node_from_die(ctxt, &child, /*only_public_decl=*/true);
while (dwarf_siblingof(&child, &child) == 0);
return result;
}
/// Build a @ref namespace_decl out of a DW_TAG_namespace or
/// DW_TAG_module (for fortran) DIE.
///
/// Note that this function connects the DW_TAG_namespace to the IR
/// being currently created, reads the children of the DIE and
/// connects them to the IR as well.
///
/// @param ctxt the read context to use.
///
/// @param die the DIE to read from. Must be either DW_TAG_namespace
/// or DW_TAG_module.
///
/// @return the resulting @ref nampespace_decl or NULL if it couldn't
/// be created.
static namespace_decl_sptr
build_namespace_decl_and_add_to_ir(read_context& ctxt,
Dwarf_Die* die)
{
namespace_decl_sptr result;
if (!die)
return result;
unsigned tag = dwarf_tag(die);
if (tag != DW_TAG_namespace && tag != DW_TAG_module)
return result;
string name, mangled_name;
location loc;
die_loc_and_name(ctxt, die, loc, name, mangled_name);
result.reset(new namespace_decl(name, loc));
add_decl_to_scope(result, ctxt.current_scope());
Dwarf_Die child;
if (dwarf_child(die, &child) != 0)
return result;
ctxt.scope_stack().push(result);
do
build_ir_node_from_die(ctxt, &child, /*only_public_decl=*/true);
while (dwarf_siblingof(&child, &child) == 0);
ctxt.scope_stack().pop();
return result;
}
/// Build a @ref type_decl out of a DW_TAG_base_type DIE.
///
/// @param ctxt the read context to use.
@ -885,23 +934,24 @@ build_corpus(read_context& ctxt)
// Build a translation_unit IR node from cu; note that cu must
// be a DW_TAG_compile_unit die.
translation_unit_sptr ir_node =
build_translation_unit(ctxt, &cu, address_size, /*recurse=*/true);
build_translation_unit(ctxt, &cu, address_size);
assert(ir_node);
}
return ctxt.current_corpus();
}
/// Canonicalize a type and add it to the current IR being built, if
/// necessary.
/// necessary. The canonicalized type is appended to the children IR
/// nodes of a given scope.
///
/// @param type_declaration the declaration of the type to
/// canonicalize.
///
/// @param type_scope the scope into which the canonicalized type
/// needs to be added to.
/// @param type_scope the scope into which the canonicalized type is
/// to be added.
///
/// @return the resulting canonicalized type.
decl_base_sptr
static decl_base_sptr
canonicalize_and_add_type_to_ir(decl_base_sptr type_declaration,
scope_decl* type_scope)
{
@ -938,7 +988,7 @@ canonicalize_and_add_type_to_ir(decl_base_sptr type_declaration,
/// canonicalize.
///
/// @param type_scope the scope into which the canonicalized type
/// needs to be added to.
/// needs to be added.
///
/// @return the resulting canonicalized type.
decl_base_sptr
@ -946,17 +996,124 @@ canonicalize_and_add_type_to_ir(decl_base_sptr type_declaration,
scope_decl_sptr type_scope)
{return canonicalize_and_add_type_to_ir(type_declaration, type_scope.get());}
/// Canonicalize a given type and insert it into the children of a
/// given scope right before a given child.
///
/// @param type_declaration the declaration of the type to canonicalize.
///
/// @param before an iterator pointing to an IR node that is a child
/// of the scope under wich the canonicalized type is to be inserted.
/// The canonicalized type is to be inserted right before that
/// iterator.
static decl_base_sptr
canonicalize_and_insert_type_into_ir(decl_base_sptr type_declaration,
scope_decl::declarations::iterator before,
scope_decl* type_scope)
{
if (!type_declaration)
return type_declaration;
translation_unit* tu = get_translation_unit(type_scope);
assert(tu);
/// TODO: maybe change the interfance of
/// translation_unit::canonicalize_type to include the final
/// qualified name of the type (i.e, one that includes the qualified
/// name of type_scope), to handle two user defined types that might
/// be same, but at different scopes. In that case, the two types
/// should be considered different by
/// translation_unit::canonicalize_type.
decl_base_sptr result = tu->canonicalize_type(type_declaration);
assert(result);
if (result->get_scope())
// This type is the same as a type that was already added to the
// IR tree. Do not add a new one. Just re-use the previous one.
;
else
insert_decl_into_scope(result, before, type_scope);
return result;
}
/// Canonicalize a type and insert it into the current IR. The
/// canonicalized type is to be inserted before the current scope C
/// and under a given scope S. If C and S are equal the the
/// canonicalized type is just appended to the current scope.
///
/// @param ctxt the read context to consider.
///
/// @param type_decl the declaration of the type to canonicalize.
///
/// @param scope the scope under which the canonicalized type is to be
/// added. This must be a scope that is higher or equal to the
/// current scope.
///
/// @return the declaration of the canonicalized type.
static decl_base_sptr
canonicalize_and_insert_type_into_ir_under_scope(read_context& ctxt,
decl_base_sptr type_decl,
scope_decl* scope)
{
decl_base_sptr result;
const scope_decl* ns_under_scope =
get_top_most_scope_under(ctxt.current_scope(), scope);
if (ns_under_scope == scope)
result =
canonicalize_and_add_type_to_ir(type_decl, scope);
else
{
scope_decl::declarations::iterator it;
assert(scope->find_iterator_for_member(ns_under_scope,
it));
result =
canonicalize_and_insert_type_into_ir(type_decl, it, scope);
}
return result;
}
/// Canonicalize a type and insert it into the current IR. The
/// canonicalized type is to be inserted before the current scope C
/// and under a given scope S. If C and S are equal the the
/// canonicalized type is just appended to the current scope.
///
/// @param ctxt the read context to consider.
///
/// @param type_decl the declaration of the type to canonicalize.
///
/// @param scope the scope under which the canonicalized type is to be
/// added. This must be a scope that is higher or equal to the
/// current scope.
///
/// @return the declaration of the canonicalized type.
static decl_base_sptr
canonicalize_and_insert_type_into_ir_under_scope(read_context& ctxt,
decl_base_sptr type_decl,
scope_decl_sptr scope)
{return canonicalize_and_insert_type_into_ir_under_scope(ctxt, type_decl,
scope.get());}
/// Build an IR node from a given DIE and add the node to the current
/// IR being build and held in the read_context.
/// IR being build and held in the read_context. Doing that is called
/// "emitting an IR node for the DIE".
///
/// @param ctxt the read context.
///
/// @parm die the DIE to consider.
///
/// @param only_public_decl if yes, only namespace-level declarations
/// that are public are emitted. The types needed to emit these
/// public declaration are emitted too, and added to the IR at a point
/// that is before the point of emitting the decl.
///
/// @return the resulting IR node.
static decl_base_sptr
build_ir_node_from_die(read_context& ctxt,
Dwarf_Die* die)
Dwarf_Die* die,
bool only_public_decl)
{
decl_base_sptr result;
@ -968,6 +1125,16 @@ build_ir_node_from_die(read_context& ctxt,
return it->second;
int tag = dwarf_tag(die);
if (only_public_decl == true)
{
if (!(tag == DW_TAG_namespace
|| tag == DW_TAG_module
|| tag == DW_TAG_subprogram
|| tag == DW_TAG_variable))
return result;
}
switch (tag)
{
// Type DIEs we intent to support someday, maybe.
@ -975,9 +1142,10 @@ build_ir_node_from_die(read_context& ctxt,
if((result = build_type_decl(ctxt, die)))
{
translation_unit_sptr tu = ctxt.current_translation_unit();
result =
canonicalize_and_add_type_to_ir(result,
tu->get_global_scope());
global_scope_sptr gscope = tu->get_global_scope();
result = canonicalize_and_insert_type_into_ir_under_scope(ctxt,
result,
gscope);
}
break;
@ -991,10 +1159,11 @@ build_ir_node_from_die(read_context& ctxt,
case DW_TAG_pointer_type:
{
pointer_type_def_sptr p = build_pointer_type_def(ctxt, die);
decl_base_sptr underlying_type =
decl_base_sptr utype =
get_type_declaration(p->get_pointed_to_type());
result =
canonicalize_and_add_type_to_ir(p, underlying_type->get_scope());
canonicalize_and_insert_type_into_ir_under_scope(ctxt, p,
utype->get_scope());
}
break;
@ -1002,10 +1171,11 @@ build_ir_node_from_die(read_context& ctxt,
case DW_TAG_rvalue_reference_type:
{
reference_type_def_sptr r = build_reference_type(ctxt, die);
decl_base_sptr underlying_type =
decl_base_sptr utype =
get_type_declaration(r->get_pointed_to_type());
result =
canonicalize_and_add_type_to_ir(r, underlying_type->get_scope());
canonicalize_and_insert_type_into_ir_under_scope(ctxt, r,
utype->get_scope());
}
break;
@ -1015,10 +1185,11 @@ build_ir_node_from_die(read_context& ctxt,
qualified_type_def_sptr q = build_qualified_type(ctxt, die);
if (q)
{
decl_base_sptr underlying_type =
decl_base_sptr t =
get_type_declaration(q->get_underlying_type());
result =
canonicalize_and_add_type_to_ir(q, underlying_type->get_scope());
canonicalize_and_insert_type_into_ir_under_scope(ctxt, q,
t->get_scope());
}
}
break;
@ -1069,17 +1240,26 @@ build_ir_node_from_die(read_context& ctxt,
break;
case DW_TAG_namespace:
case DW_TAG_module:
result = build_namespace_decl_and_add_to_ir(ctxt, die);
break;
case DW_TAG_variable:
if ((result = build_var_decl(ctxt, die)))
add_decl_to_scope(result, ctxt.current_scope());
break;
case DW_TAG_subprogram:
if ((result = build_function_decl(ctxt, die)))
add_decl_to_scope(result, ctxt.current_scope());
break;
case DW_TAG_formal_parameter:
// We should not read this case as it should have been dealt
// with by build_function_decl above.
abort();
break;
case DW_TAG_constant:
break;
case DW_TAG_enumerator:
@ -1098,7 +1278,6 @@ build_ir_node_from_die(read_context& ctxt,
case DW_TAG_common_inclusion:
case DW_TAG_inheritance:
case DW_TAG_inlined_subroutine:
case DW_TAG_module:
case DW_TAG_with_stmt:
case DW_TAG_access_declaration:
case DW_TAG_catch_block:

View File

@ -513,7 +513,25 @@ scope_decl::add_member_decl(const shared_ptr<decl_base> member)
{
members_.push_back(member);
if (shared_ptr<scope_decl> m = dynamic_pointer_cast<scope_decl>(member))
if (scope_decl_sptr m = dynamic_pointer_cast<scope_decl>(member))
member_scopes_.push_back(m);
}
/// Insert a member decl to this scope, right before an element
/// pointed to by a given iterator. Note that user code should not
/// use this, but rather use insert_decl_into_scope.
///
/// @param member the new member decl to add to this scope.
///
/// @param before an interator pointing to the element before which
/// the new member should be inserted.
void
scope_decl::insert_member_decl(const decl_base_sptr member,
declarations::iterator before)
{
members_.insert(before, member);
if (scope_decl_sptr m = dynamic_pointer_cast<scope_decl>(member))
member_scopes_.push_back(m);
}
@ -549,6 +567,46 @@ scope_decl::operator==(const decl_base& o) const
return true;
}
/// Find a member of the current scope and return an iterator on it.
///
/// @param decl the scope member to find.
///
/// @param i the iterator to set to the member @ref decl. This is set
/// iff the function returns true.
///
/// @return true if the member decl was found, false otherwise.
bool
scope_decl::find_iterator_for_member(const decl_base* decl,
declarations::iterator& i)
{
if (!decl)
return false;
for (declarations::iterator it = get_member_decls().begin();
it != get_member_decls().end();
++it)
if (**it == *decl)
{
i = it;
return true;
}
return false;
}
/// Find a member of the current scope and return an iterator on it.
///
/// @param decl the scope member to find.
///
/// @param i the iterator to set to the member @ref decl. This is set
/// iff the function returns true.
///
/// @return true if the member decl was found, false otherwise.
bool
scope_decl::find_iterator_for_member(const decl_base_sptr decl,
declarations::iterator& i)
{return find_iterator_for_member(decl.get(), i);}
/// This implements the traversable_base::traverse pure virtual
/// function.
///
@ -600,16 +658,52 @@ void
add_decl_to_scope(shared_ptr<decl_base> decl, shared_ptr<scope_decl> scope)
{add_decl_to_scope(decl, scope.get());}
/// Return the global scope as seen by a given declaration.
/// Inserts a declaration into a given scope, before a given IR child
/// node of the scope.
///
/// @param decl the declaration to insert into the scope.
///
/// @param before an iterator pointing to the child IR node before
/// which to insert the declaration.
///
/// @param scope the scope into which to insert the declaration.
void
insert_decl_into_scope(decl_base_sptr decl,
scope_decl::declarations::iterator before,
scope_decl* scope)
{
if (scope && decl && !decl->get_scope())
{
scope->insert_member_decl(decl, before);
decl->set_scope(scope);
}
}
/// Inserts a declaration into a given scope, before a given IR child
/// node of the scope.
///
/// @param decl the declaration to insert into the scope.
///
/// @param before an iterator pointing to the child IR node before
/// which to insert the declaration.
///
/// @param scope the scope into which to insert the declaration.
void
insert_decl_into_scope(decl_base_sptr decl,
scope_decl::declarations::iterator before,
scope_decl_sptr scope)
{insert_decl_into_scope(decl, before, scope.get());}
/// return the global scope as seen by a given declaration.
///
/// @param decl the declaration to consider.
///
/// @return the global scope of the decl, or a null pointer if the
/// decl is not yet added to a translation_unit.
global_scope*
get_global_scope(decl_base* decl)
const global_scope*
get_global_scope(const decl_base* decl)
{
if (global_scope* s = dynamic_cast<global_scope*>(decl))
if (const global_scope* s = dynamic_cast<const global_scope*>(decl))
return s;
scope_decl* scope = decl->get_scope();
@ -625,19 +719,68 @@ get_global_scope(decl_base* decl)
///
/// @return the global scope of the decl, or a null pointer if the
/// decl is not yet added to a translation_unit.
global_scope*
const global_scope*
get_global_scope(const shared_ptr<decl_base> decl)
{return get_global_scope(decl.get());}
/// Return the a scope S containing a given declaration and that is
/// right under a given scope P.
///
/// @param decl the decl for which to find a scope.
///
/// @param scope the scope under which the resulting scope must be.
///
/// @return the resulting scope.
const scope_decl*
get_top_most_scope_under(const decl_base* decl,
const scope_decl* scope)
{
if (shared_ptr<global_scope> s = dynamic_pointer_cast<global_scope>(decl))
return s.get();
if (!decl)
return 0;
scope_decl* scope = decl->get_scope();
while (scope && !dynamic_cast<global_scope*>(scope))
scope = scope->get_scope();
if (scope == 0)
return get_global_scope(decl);
return scope ? dynamic_cast<global_scope*> (scope) : 0;
const scope_decl* s = dynamic_cast<const scope_decl*>(decl);
if (!s)
s = decl->get_scope();
while (!is_global_scope(s) && s->get_scope() != scope)
s = s->get_scope();
if (is_global_scope(s))
assert(is_global_scope(scope));
assert(s);
return s;
}
/// Return the a scope S containing a given declaration and that is
/// right under a given scope P.
///
/// @param decl the decl for which to find a scope.
///
/// @param scope the scope under which the resulting scope must be.
///
/// @return the resulting scope.
const scope_decl*
get_top_most_scope_under(const decl_base_sptr decl,
const scope_decl* scope)
{return get_top_most_scope_under(decl.get(), scope);}
/// Return the a scope S containing a given declaration and that is
/// right under a given scope P.
///
/// @param decl the decl for which to find a scope.
///
/// @param scope the scope under which the resulting scope must be.
///
/// @return the resulting scope.
const scope_decl*
get_top_most_scope_under(const decl_base_sptr decl,
const scope_decl_sptr scope)
{return get_top_most_scope_under(decl, scope.get());}
/// Get the name of a given type and return a copy of it.
///
/// @return a copy of the type name if the type has a name, or the
@ -667,7 +810,7 @@ get_type_declaration(const type_base_sptr t)
translation_unit*
get_translation_unit(decl_base* decl)
{
global_scope* global = get_global_scope(decl);
const global_scope* global = get_global_scope(decl);
if (global)
return global->get_translation_unit();

View File

@ -187,7 +187,7 @@ public:
translation_unit*
get_translation_unit()
{
global_scope* global = 0;
const global_scope* global = 0;
if (shared_ptr<decl_base> d = get_cur_decl ())
global = get_global_scope(d);