Implement a translation unit traversal API

* include/libabigail/abg-ir.h (struct ir_node_visitor, struct
	traversable): New interfaces.
	(translation_unit, scope_decl, type_decl, qualified_type_def)
	(pointer_type_def, reference_type_def, enum_type_decl)
	(typedef_decl, var_decl, function_decl, data_member)
	(member_function, member_function_template)
	(member_class_template): Implement the traversable interface,
	overload the traversable::traverse pure virtual function.
	* src/abg-ir.cc ({translation_unit, scope_decl, type_decl,
	namespace_decl, qualified_type_def, pointer_type_def,
	reference_type_def, enum_type_decl, typedef_decl, var_decl,
	function_decl, class_decl::member_function, class_decl,
	class_decl::data_member, class_decl::member_function_template,
	class_decl::member_class_template, function_template_decl,
	class_template_decl, }::traverse): Implement traversal.
	(ir_node_visitor::visit): New method, overloaded for the types
	above, which implement the traversable interface.
	* tests/test-walker.cc: New test case program to showcase how to
	use the new traversal API.
	* tests/makefile.am: Add test-walker.cc to the build system.
This commit is contained in:
Dodji Seketeli 2013-07-20 12:30:04 +02:00
parent e9be65956c
commit 95ec67b143
4 changed files with 543 additions and 15 deletions

View File

@ -150,10 +150,29 @@ public:
unsigned& column) const;
};
class ir_node_visitor;
/// The Base interface implemented by types which instances are
/// visited during the traversal of translation unit nodes.
struct traversable
{
/// This virtual pure method is implemented by any single type which
/// instance is going to be visited during the traversal of
/// translation unit nodes.
///
/// The method visits a given node and, for scopes, visits their
/// member nodes. Visiting a node means calling the
/// ir_node_visitor::visit method with the node passed as an
/// argument.
///
/// \param v the visitor used during the t
virtual void traverse(ir_node_visitor& v) = 0;
};
/// This is the abstraction of the set of relevant artefacts (types,
/// variable declarations, functions, templates, etc) bundled together
/// into a translation unit.
class translation_unit
class translation_unit : public virtual traversable
{
// Forbidden
translation_unit();
@ -179,6 +198,9 @@ public:
bool
is_empty() const;
void
traverse(ir_node_visitor&);
private:
std::string m_path;
location_manager m_loc_mgr;
@ -277,7 +299,7 @@ private:
/// \brief A declaration that introduces a scope.
class scope_decl : public virtual decl_base
class scope_decl : public virtual decl_base, public virtual traversable
{
scope_decl();
@ -312,6 +334,9 @@ public:
is_empty() const
{return get_member_decls().empty();}
void
traverse(ir_node_visitor&);
virtual ~scope_decl();
friend void
@ -438,7 +463,9 @@ struct type_shared_ptr_equal
};//end struct type_shared_ptr_equal
/// A basic type declaration that introduces no scope.
class type_decl : public virtual decl_base, public virtual type_base
class type_decl : public virtual decl_base,
public virtual type_base,
public virtual traversable
{
// Forbidden.
type_decl();
@ -455,6 +482,9 @@ public:
virtual bool
operator==(const type_decl&) const;
void
traverse(ir_node_visitor&);
virtual ~type_decl();
};// class type_decl
@ -504,11 +534,16 @@ public:
virtual bool
operator==(const namespace_decl&) const;
void
traverse(ir_node_visitor&);
virtual ~namespace_decl();
};//end class namespace_decl
/// The abstraction of a qualified type.
class qualified_type_def : public virtual type_base, public virtual decl_base
class qualified_type_def : public virtual type_base,
public virtual decl_base,
public virtual traversable
{
// Forbidden.
@ -540,6 +575,9 @@ public:
const shared_ptr<type_base>
get_underlying_type() const;
void
traverse(ir_node_visitor&);
virtual ~qualified_type_def();
private:
@ -559,7 +597,8 @@ struct qualified_type_def_hash
/// The abstraction of a pointer type.
class pointer_type_def : public virtual type_base,
public virtual decl_base
public virtual decl_base,
public virtual traversable
{
// Forbidden.
pointer_type_def();
@ -577,6 +616,9 @@ public:
shared_ptr<type_base>
get_pointed_to_type() const;
void
traverse(ir_node_visitor&);
virtual ~pointer_type_def();
private:
@ -592,7 +634,8 @@ struct pointer_type_def_hash
/// Abstracts a reference type.
class reference_type_def : public virtual type_base,
public virtual decl_base
public virtual decl_base,
public virtual traversable
{
// Forbidden.
reference_type_def();
@ -613,6 +656,9 @@ public:
bool
is_lvalue() const;
void
traverse(ir_node_visitor&);
virtual ~reference_type_def();
private:
@ -629,7 +675,8 @@ struct reference_type_def_hash
/// Abstracts a declaration for an enum type.
class enum_type_decl: public virtual type_base,
public virtual decl_base
public virtual decl_base,
public virtual traversable
{
// Forbidden
enum_type_decl();
@ -693,6 +740,9 @@ public:
virtual bool
operator==(const enum_type_decl&) const;
void
traverse(ir_node_visitor&);
virtual ~enum_type_decl();
private:
@ -710,7 +760,8 @@ struct enum_type_decl_hash
/// The abstraction of a typedef declaration.
class typedef_decl: public virtual type_base,
public virtual decl_base
public virtual decl_base,
public virtual traversable
{
// Forbidden
typedef_decl();
@ -729,6 +780,9 @@ public:
shared_ptr<type_base>
get_underlying_type() const;
void
traverse(ir_node_visitor&);
virtual ~typedef_decl();
private:
@ -744,7 +798,7 @@ struct typedef_decl_hash
};// end struct typedef_decl_hash
/// Abstracts a variable declaration.
class var_decl : public virtual decl_base
class var_decl : public virtual decl_base, public virtual traversable
{
// Forbidden
var_decl();
@ -773,6 +827,9 @@ public:
set_binding(binding b)
{m_binding = b;}
void
traverse(ir_node_visitor&);
virtual ~var_decl();
private:
@ -791,7 +848,8 @@ struct var_decl_hash
class function_type;
/// Abstraction for a function declaration.
class function_decl: public virtual decl_base
class function_decl: public virtual decl_base,
public virtual traversable
{
public:
@ -929,6 +987,9 @@ public:
{return (!get_parameters().empty()
&& get_parameters().back()->get_variadic_marker());}
void
traverse(ir_node_visitor&);
virtual ~function_decl();
protected:
@ -1357,6 +1418,9 @@ public:
get_binding() const
{return m_binding;}
void
traverse(ir_node_visitor&);
virtual ~function_template_decl();
private:
@ -1416,6 +1480,8 @@ public:
get_pattern() const
{return m_pattern;}
void
traverse(ir_node_visitor&);
virtual ~class_template_decl();
@ -1591,7 +1657,9 @@ public:
};// end struct base_spec_hash
/// Abstract a data member declaration in a class declaration.
class data_member : public var_decl, public member
class data_member : public var_decl,
public member,
public virtual traversable
{
// Forbidden
data_member();
@ -1632,6 +1700,9 @@ public:
&& static_cast<member>(*this) == other);
}
void
traverse(ir_node_visitor&);
virtual ~data_member();
private:
@ -1702,7 +1773,9 @@ public:
};//end class method_decl;
/// Abstracts a member function declaration in a class declaration.
class member_function : public method_decl, public member
class member_function : public method_decl,
public member,
public virtual traversable
{
// Forbidden
member_function();
@ -1797,6 +1870,11 @@ public:
&& static_cast<function_decl>(*this) == o);
}
/// This implements the traversable::traverse pure virtual
/// function.
void
traverse(ir_node_visitor&);
private:
size_t m_vtable_offset_in_bits;
bool m_is_constructor;
@ -1812,7 +1890,8 @@ public:
};// end struct member_function_hash
/// Abstract a member function template.
class member_function_template : public member
class member_function_template : public member,
public virtual traversable
{
// Forbiden
member_function_template();
@ -1848,6 +1927,9 @@ public:
bool
operator==(const member_function_template& o) const;
void
traverse(ir_node_visitor&);
private:
bool m_is_constructor;
bool m_is_const;
@ -1861,7 +1943,7 @@ public:
};// end struct member_function_template_hash
/// Abstracts a member class template template
class member_class_template : public member
class member_class_template : public member, public virtual traversable
{
// Forbidden
member_class_template();
@ -1884,6 +1966,9 @@ public:
bool
operator==(const member_class_template& o) const;
void
traverse(ir_node_visitor&);
private:
shared_ptr<class_template_decl> m_class_tmpl;
};// end class member_class_template
@ -1994,6 +2079,9 @@ public:
virtual bool
operator==(const class_decl&) const;
void
traverse(ir_node_visitor&);
virtual ~class_decl();
private:
@ -2015,5 +2103,36 @@ struct class_decl_hash
};//end struct class_decl_hash
/// The base class for the visitor type hierarchy used for traversing
/// a translation unit.
///
/// Client code willing to get notified for a certain kind of node
/// during the IR traversal might want to define a visitor class that
/// inherit #ir_node_visitor, overload the ir_node_visitor::visit
/// method of its choice, and provide and implementation for it. That
/// new visitor class would then be passed to e.g,
/// translation_unit::traverse or to the #traverse method of any type
/// where the traversal is supposed to start from.
struct ir_node_visitor
{
virtual void visit(scope_decl&);
virtual void visit(type_decl&);
virtual void visit(namespace_decl&);
virtual void visit(qualified_type_def&);
virtual void visit(pointer_type_def&);
virtual void visit(reference_type_def&);
virtual void visit(enum_type_decl&);
virtual void visit(typedef_decl&);
virtual void visit(var_decl&);
virtual void visit(function_decl&);
virtual void visit(function_template_decl&);
virtual void visit(class_template_decl&);
virtual void visit(class_decl&);
virtual void visit(class_decl::data_member&);
virtual void visit(class_decl::member_function&);
virtual void visit(class_decl::member_function_template&);
virtual void visit(class_decl::member_class_template&);
};
} // end namespace abigail
#endif // __ABG_IR_H__

View File

@ -208,6 +208,17 @@ translation_unit::is_empty() const
return get_global_scope()->is_empty();
}
/// This implements the traversable::traverse pure virtual
/// function.
///
/// \param v the visitor used on the member nodes of the translation
/// unit during the traversal.
void
translation_unit::traverse(ir_node_visitor& v)
{
get_global_scope()->traverse(v);
}
// <Decl definition>
decl_base::decl_base(const std::string& name,
@ -324,6 +335,27 @@ scope_decl::operator==(const scope_decl& other) const
return true;
}
/// This implements the traversable::traverse pure virtual
/// function.
///
/// \param v the visitor used on the current instance of scope_decl
/// and on its member nodes.
void
scope_decl::traverse(ir_node_visitor &v)
{
v.visit(*this);
std::list<shared_ptr<decl_base> >::const_iterator i;
for (i = get_member_decls().begin();
i != get_member_decls ().end();
++i)
{
shared_ptr<traversable> t = dynamic_pointer_cast<traversable>(*i);
if (t)
t->traverse (v);
}
}
scope_decl::~scope_decl()
{
}
@ -611,6 +643,16 @@ type_decl::operator==(const type_decl& other) const
&& static_cast<type_base>(*this) == other);
}
/// This implements the traversable::traverse pure virtual
/// function.
///
/// \param v the visitor used on the current instance.
void
type_decl::traverse(ir_node_visitor& v)
{
v.visit(*this);
}
type_decl::~type_decl()
{
}
@ -708,6 +750,27 @@ namespace_decl::operator==(const namespace_decl& other) const
return (static_cast<scope_decl>(*this) == other);
}
/// This implements the traversable::traverse pure virtual
/// function.
///
/// \param v the visitor used on the current instance and on its
/// member nodes.
void
namespace_decl::traverse(ir_node_visitor& v)
{
v.visit(*this);
std::list<shared_ptr<decl_base> >::const_iterator i;
for (i = get_member_decls().begin();
i != get_member_decls ().end();
++i)
{
shared_ptr<traversable> t = dynamic_pointer_cast<traversable>(*i);
if (t)
t->traverse (v);
}
}
namespace_decl::~namespace_decl()
{
}
@ -754,6 +817,16 @@ qualified_type_def::operator==(const qualified_type_def& other) const
return *get_underlying_type() == *other.get_underlying_type();
}
/// This implements the traversable::traverse pure virtual
/// function.
///
/// \param v the visitor used on the current instance.
void
qualified_type_def::traverse(ir_node_visitor& v)
{
v.visit(*this);
}
/// The destructor of the qualified type
qualified_type_def::~qualified_type_def()
{
@ -889,6 +962,16 @@ pointer_type_def::get_pointed_to_type() const
return m_pointed_to_type;
}
/// This implements the traversable::traverse pure virtual
/// function.
///
/// \param v the visitor used on the current instance.
void
pointer_type_def::traverse(ir_node_visitor& v)
{
v.visit(*this);
}
pointer_type_def::~pointer_type_def()
{
}
@ -948,6 +1031,16 @@ reference_type_def::is_lvalue() const
return m_is_lvalue;
}
/// This implements the traversable::traverse pure virtual
/// function.
///
/// \param v the visitor used on the current instance.
void
reference_type_def::traverse(ir_node_visitor& v)
{
v.visit(*this);
}
reference_type_def::~reference_type_def()
{
}
@ -1010,6 +1103,16 @@ enum_type_decl::get_enumerators() const
return m_enumerators;
}
/// This implements the traversable::traverse pure virtual
/// function.
///
/// \param v the visitor used on the current instance.
void
enum_type_decl::traverse(ir_node_visitor &v)
{
v.visit(*this);
}
/// Destructor for the enum type declaration.
enum_type_decl::~enum_type_decl()
{
@ -1103,6 +1206,16 @@ typedef_decl::get_underlying_type() const
return m_underlying_type;
}
/// This implements the traversable::traverse pure virtual
/// function.
///
/// \param v the visitor used on the current instance.
void
typedef_decl::traverse(ir_node_visitor& v)
{
v.visit(*this);
}
/// Destructor of the typedef_decl.
typedef_decl::~typedef_decl()
{
@ -1147,6 +1260,16 @@ var_decl::operator==(const var_decl& other) const
&& *get_type() == *other.get_type());
}
/// This implements the traversable::traverse pure virtual
/// function.
///
/// \param v the visitor used on the current instance.
void
var_decl::traverse(ir_node_visitor& v)
{
v.visit(*this);
}
var_decl::~var_decl()
{
}
@ -1567,6 +1690,16 @@ function_decl_hash::operator()(const function_decl& t) const
return v;
}
/// This implements the traversable::traverse pure virtual
/// function.
///
/// \param v the visitor used on the current instance.
void
function_decl::traverse(ir_node_visitor& v)
{
v.visit(*this);
}
function_decl::~function_decl()
{
}
@ -1981,6 +2114,16 @@ class_decl::member_function::member_function
{
}
/// This implements the traversable::traverse pure virtual
/// function.
///
/// \param v the visitor used on the current instance.
void
class_decl::member_function::traverse(ir_node_visitor& v)
{
v.visit(*this);
}
/// Add a member function to the current instance of class_decl.
///
/// \param m the member function to add.
@ -2117,6 +2260,63 @@ class_decl::operator==(const class_decl& o) const
return true;
}
/// This implements the traversable::traverse pure virtual
/// function.
///
/// \param v the visitor used on the current instance and on its members.
void
class_decl::traverse(ir_node_visitor& v)
{
v.visit(*this);
for (member_types_type::const_iterator i = get_member_types().begin();
i != get_member_types().end();
++i)
{
shared_ptr<traversable> t = dynamic_pointer_cast<traversable>(*i);
if (t)
t->traverse(v);
}
for (member_function_templates_type::const_iterator i =
get_member_function_templates().begin();
i != get_member_function_templates().end();
++i)
{
shared_ptr<traversable> t = dynamic_pointer_cast<traversable>(*i);
if (t)
t->traverse(v);
}
for (member_class_templates_type::const_iterator i =
get_member_class_templates().begin();
i != get_member_class_templates().end();
++i)
{
shared_ptr<traversable> t = dynamic_pointer_cast<traversable>(*i);
if (t)
t->traverse(v);
}
for (data_members_type::const_iterator i = get_data_members().begin();
i != get_data_members().end();
++i)
{
shared_ptr<traversable> t = dynamic_pointer_cast<traversable>(*i);
if (t)
t->traverse(v);
}
for (member_functions_type::const_iterator i= get_member_functions().begin();
i != get_member_functions().end();
++i)
{
shared_ptr<traversable> t = dynamic_pointer_cast<traversable>(*i);
if (t)
t->traverse(v);
}
}
class_decl::~class_decl()
{
}
@ -2215,6 +2415,16 @@ class_decl::data_member::data_member(const std::string& name,
{
}
/// This implements the traversable::traverse pure virtual
/// function.
///
/// \param v the visitor used on the current instance.
void
class_decl::data_member::traverse(ir_node_visitor& v)
{
v.visit(*this);
}
/// Destructor for instances of class_decl::data_member.
class_decl::data_member::~data_member()
{
@ -2276,6 +2486,18 @@ class_decl::member_function_template::operator==
return true;
}
/// This implements the traversable::traverse pure virtual
/// function.
///
/// \param v the visitor used on the current instance and on its
/// underlying function template.
void
class_decl::member_function_template::traverse(ir_node_visitor& v)
{
v.visit(*this);
as_function_template_decl()->traverse(v);
}
/// Hashing function for instances of class_decl::member_function_template_hash.
///
/// \param t the instance of class_decl::member_function_template to hash.
@ -2310,6 +2532,18 @@ class_decl::member_class_template::operator==
return true;
}
/// This implements the traversable::traverse pure virtual
/// function.
///
/// \param v the visitor used on the current instance and on the class
/// pattern of the template.
void
class_decl::member_class_template::traverse(ir_node_visitor& v)
{
v.visit(*this);
as_class_template_decl()->get_pattern()->traverse(v);
}
size_t
class_decl::member_class_template_hash::operator()
(member_class_template& t) const
@ -2621,6 +2855,18 @@ fn_tmpl_shared_ptr_hash::operator()
return 0;
}
/// This implements the traversable::traverse pure virtual
/// function.
///
/// \param v the visitor used on the current instance and on the
/// function pattern of the template.
void
function_template_decl::traverse(ir_node_visitor&v)
{
v.visit(*this);
get_pattern()->traverse(v);
}
function_template_decl::~function_template_decl()
{
}
@ -2654,6 +2900,21 @@ class_template_decl::operator==(const class_template_decl& o) const
return (*get_pattern() == *o.get_pattern());
}
/// This implements the traversable::traverse pure virtual
/// function.
///
/// \param v the visitor used on the current instance and on the class
/// pattern of the template.
void
class_template_decl::traverse(ir_node_visitor&v)
{
v.visit(*this);
shared_ptr<class_decl> pattern = get_pattern();
if (pattern)
pattern->traverse(v);
}
class_template_decl::~class_template_decl()
{
}
@ -2686,5 +2947,89 @@ class_tmpl_shared_ptr_hash::operator()
return 0;
}
void
ir_node_visitor::visit(scope_decl&)
{
}
void
ir_node_visitor::visit(type_decl&)
{
}
void
ir_node_visitor::visit(namespace_decl&)
{
}
void
ir_node_visitor::visit(qualified_type_def&)
{
}
void
ir_node_visitor::visit(pointer_type_def&)
{
}
void
ir_node_visitor::visit(reference_type_def&)
{
}
void
ir_node_visitor::visit(enum_type_decl&)
{
}
void
ir_node_visitor::visit(typedef_decl&)
{
}
void
ir_node_visitor::visit(var_decl&){
}
void
ir_node_visitor::visit(function_decl&)
{
}
void
ir_node_visitor::visit(function_template_decl&)
{
}
void
ir_node_visitor::visit(class_template_decl&)
{
}
void
ir_node_visitor::visit(class_decl&)
{
}
void
ir_node_visitor::visit(class_decl::data_member&)
{
}
void
ir_node_visitor::visit(class_decl::member_function&)
{
}
void
ir_node_visitor::visit(class_decl::member_function_template&)
{
}
void
ir_node_visitor::visit(class_decl::member_class_template&)
{
}
// </class template>
}//end namespace abigail

View File

@ -3,7 +3,7 @@ runtestreadwrite \
runtestsvg \
runtestdot
noinst_PROGRAMS= $(TESTS)
noinst_PROGRAMS= $(TESTS) testwalker
noinst_LTLIBRARIES = libtestutils.la
@ -24,6 +24,9 @@ runtestsvg_LDADD=$(top_builddir)/src/libabigail.la
runtestdot_SOURCES=test-dot.cc
runtestdot_LDADD=$(top_builddir)/src/libabigail.la
testwalker_SOURCES=test-walker.cc
testwalker_LDADD=$(top_builddir)/src/libabigail.la
AM_CPPFLAGS=-I${top_srcdir}/include/libabigail -I${top_builddir}/include/libabigail
AM_CXXFLAGS="-std=gnu++11"

61
tests/test-walker.cc Normal file
View File

@ -0,0 +1,61 @@
// -*- Mode: C++ -*-
//
// Copyright (C) 2013 Red Hat, Inc.
//
// This file is part of the GNU Application Binary Interface Generic
// Analysis and Instrumentation Library (libabigail). This library is
// free software; you can redistribute it and/or modify it under the
// terms of the GNU Lesser General Public License as published by the
// Free Software Foundation; either version 3, or (at your option) any
// later version.
// This library is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Lesser Public License for more details.
// You should have received a copy of the GNU Lesser General Public
// License along with this program; see the file COPYING-LGPLV3. If
// not, see <http://www.gnu.org/licenses/>.
#include <string>
#include <fstream>
#include <iostream>
#include <cstdlib>
#include "test-utils.h"
#include "abg-reader.h"
using std::string;
using std::ofstream;
using std::cerr;
using std::cout;
struct name_printing_visitor : public abigail::ir_node_visitor
{
void
visit(abigail::class_decl& klass)
{cout << "class name: " << klass.get_name() << "\n";}
void
visit(abigail::namespace_decl& ns)
{cout << "namespace name: " << ns.get_name() << "\n";}
};
int
main(int argc, char **argv)
{
if (argc < 2)
return 0;
string file_name = argv[1];
abigail::translation_unit tu(file_name);
if (!abigail::reader::read_file(file_name, tu))
{
cerr << "failed to read " << file_name << "\n";
return 1;
}
name_printing_visitor v;
tu.traverse(v);
}