Initial support of class templates

* src/abg-ir.cc (class_template_decl::class_template_decl)
	(class_template_decl::set_pattern)
	(class_template_decl::operator==)
	(class_template_decl::~class_template_decl)
	(class_template_decl_hash::operator())
	(class_tmpl_shared_ptr_hash::operator()): New definitions.
	* src/abg-ir.h (class class_template_decl, struct
	class_tmpl_shared_ptr_hash, struct class_tmpl_shared_ptr_hash):
	New declarations.
	* src/abg-reader.cc (read_context::const_class_tmpl_map_it): New
	typedef.
	(read_context::get_fn_tmpl_decl): Fix comment.
	(read_context::{get_class_tmpl_decl,key_class_tmpl_decl})
	(build_class_template_decl, handle_class_template_decl): New
	definitions.
	(read_context::m_class_tmpl_map): New member.
	(handle_element): Support "class-template-decl" xml elements
	nodes.
	(build_class_decl): Add missing bits to comment.
	(build_function_template_decl): Fix spacing.
	* src/abg-writer.cc (class_tmpl_shared_ptr_map): New typedef.
	(write_context::m_class_tmpl_map): New member.
	(write_context::get_id_for_class_tmpl, write_class_template_decl):
	New definitions.
	(write_template_parameters): Factorize this this out from ...
	(write_function_template_decl): ... here.
	(write_decl): Support writing instances of class_template_decl.
	Fix spacing.
	* tests/data/test-read-write/test15.xml: New test input.
	* tests/Makefile.am: Add the new test15.xml input to the
	distribution.
	* tests/test-read-write.cc (in_out_specs): Add the new test15.xml
	test to the list of serialized output to be de-serialized and
	serialized back.
This commit is contained in:
Dodji Seketeli 2013-05-02 15:25:04 +02:00 committed by Dodji Seketeli
parent 9b14a86ac4
commit c50b9dbb55
7 changed files with 402 additions and 27 deletions

View File

@ -1680,4 +1680,66 @@ function_template_decl::~function_template_decl()
{
}
// </function_template>
// <class template>
class_template_decl::class_template_decl(shared_ptr<class_decl> pattern,
location locus,
visibility vis)
: decl_base(pattern->get_name(), locus,
pattern->get_name(), vis),
scope_decl(pattern->get_name(), locus)
{set_pattern(pattern);}
void
class_template_decl::set_pattern(shared_ptr<class_decl> p)
{
m_pattern = p;
add_decl_to_scope(p, this);
set_name(p->get_name());
}
bool
class_template_decl::operator==(const class_template_decl& o) const
{
if (!(static_cast<template_decl>(*this) == o
&& static_cast<scope_decl>(*this) == o
&& !!get_pattern() == !!o.get_pattern()))
return false;
return (*get_pattern() == *o.get_pattern());
}
class_template_decl::~class_template_decl()
{
}
size_t
class_template_decl_hash::operator()(const class_template_decl& t) const
{
hash<string> hash_string;
decl_base_hash hash_decl_base;
template_decl_hash hash_template_decl;
class_decl_hash hash_class_decl;
size_t v = hash_string(typeid(t).name());
v = hashing::combine_hashes(v, hash_decl_base(t));
v = hashing::combine_hashes(v, hash_template_decl(t));
if (t.get_pattern())
v = hashing::combine_hashes(v, hash_class_decl(*t.get_pattern()));
return v;
}
size_t
class_tmpl_shared_ptr_hash::operator()
(const shared_ptr<class_template_decl> t) const
{
class_template_decl_hash hash_class_tmpl_decl;
if (t)
return hash_class_tmpl_decl(*t);
return 0;
}
// </class template>
}//end namespace abigail

View File

@ -51,6 +51,7 @@ using namespace std::rel_ops; // Pull in relational operators so that
class decl_base;
class scope_decl;
class global_scope;
class class_decl;
class translation_unit;
void add_decl_to_scope(shared_ptr<decl_base>,
@ -1166,18 +1167,76 @@ private:
binding m_binding;
};//end class function_template_decl
/// Hash functor for
/// Hashing functor for pointer to a function template.
struct fn_tmpl_shared_ptr_hash
{
size_t
operator()(const shared_ptr<function_template_decl>) const;
};//end struct fn_tmpl_shared_ptr_hash
/// Hash functor for function templates
struct function_template_decl_hash
{
size_t
operator()(const function_template_decl&) const;
};// end struct function_template_decl_hash
struct fn_tmpl_shared_ptr_hash
/// Abstract a class template.
class class_template_decl : public template_decl, public scope_decl
{
// Forbidden
class_template_decl();
public:
class_template_decl(location locus,
visibility vis = VISIBILITY_DEFAULT)
: decl_base("", locus, "", vis),
scope_decl("", locus)
{}
/// Constructor for the class_template_decl type.
///
/// \param the pattern of the class template. This must NOT be a
/// null pointer. If you really this to be null, please use the
/// constructor above instead.
///
/// \param the source location of the declaration of the type.
///
/// \param the visibility of the instances of class instantiated
/// from this template.
class_template_decl(shared_ptr<class_decl> pattern,
location locus,
visibility vis = VISIBILITY_DEFAULT);
virtual bool
operator==(const class_template_decl&) const;
void
set_pattern(shared_ptr<class_decl> p);
shared_ptr<class_decl>
get_pattern() const
{return m_pattern;}
virtual ~class_template_decl();
private:
shared_ptr<class_decl> m_pattern;
};// end class class_template_decl
struct class_template_decl_hash
{
size_t
operator()(const shared_ptr<function_template_decl>) const;
};//end struct fn_tmpl_shared_ptr_hash
operator()(const class_template_decl&) const;
};// end struct class_template_decl_hash
struct class_tmpl_shared_ptr_hash
{
size_t
operator()(const shared_ptr<class_template_decl>) const;
};// end struct class_tmpl_shared_ptr_hash
/// Abstracts a class declaration.
class class_decl : public scope_type_decl

View File

@ -73,6 +73,10 @@ public:
shared_ptr<function_template_decl> >::const_iterator
const_fn_tmpl_map_it;
typedef unordered_map<string,
shared_ptr<class_template_decl> >::const_iterator
const_class_tmpl_map_it;
read_context(xml::reader_sptr reader)
: m_depth(0),
m_reader(reader)
@ -115,9 +119,10 @@ public:
}
/// Return the function template that is identified by a unique ID.
/// Note that a function template to be indentified by #id, the
/// function key_fn_tmpl_decl must have been previously called
/// with that function template and with #id.
///
/// Note that for a function template to be identified by #id, the
/// function key_fn_tmpl_decl must have been previously called with
/// that function template and with #id.
///
/// \param id the ID to consider.
///
@ -133,6 +138,25 @@ public:
return i->second;
}
/// Return the class template that is identified by a unique ID.
///
/// Note that for a class template to be identified by #id, the
/// function key_class_tmpl_decl must have been previously called
/// with that class template and with #id.
///
/// \param id the ID to consider.
///
/// \return the class template identified by #id, or a null pointer
/// if no class template has ever been associated with #id before.
shared_ptr<class_template_decl>
get_class_tmpl_decl(const string& id) const
{
const_class_tmpl_map_it i = m_class_tmpl_map.find(id);
if (i == m_class_tmpl_map.end())
return shared_ptr<class_template_decl>();
return i->second;
}
/// Return the current lexical scope. For this function to return a
/// sane result, the path to the current decl element (starting from the
/// root element) must be up to date. It is updated by a call to
@ -239,6 +263,29 @@ public:
return true;
}
/// Associate an ID to a class template.
///
/// \param class_tmpl_decl the class template to consider.
///
/// \param id the ID to associate to the class template.
///
/// \return true upon successful completion, false otherwise. Note
/// that the function returns false if an ID was previously
/// associated to the class template.
bool
key_class_tmpl_decl(shared_ptr<class_template_decl> class_tmpl_decl,
const string& id)
{
assert(class_tmpl_decl);
const_class_tmpl_map_it i = m_class_tmpl_map.find(id);
if (i != m_class_tmpl_map.end())
return false;
m_class_tmpl_map[id] = class_tmpl_decl;
return true;
}
/// This function must be called on each decl that is created during
/// the parsing. It adds the decl to the current scope, and updates
/// the state of the parsing context accordingly.
@ -335,6 +382,7 @@ private:
int m_depth;
unordered_map<string, shared_ptr<type_base> > m_types_map;
unordered_map<string, shared_ptr<function_template_decl> > m_fn_tmpl_map;
unordered_map<string, shared_ptr<class_template_decl> > m_class_tmpl_map;
xml::reader_sptr m_reader;
stack<shared_ptr<decl_base> > m_decls_stack;
};//end class read_context
@ -380,6 +428,8 @@ static shared_ptr<class_decl>
build_class_decl(read_context&, const xmlNodePtr, bool);
static shared_ptr<function_template_decl>
build_function_template_decl(read_context&, const xmlNodePtr, bool);
static shared_ptr<class_template_decl>
build_class_template_decl(read_context&, const xmlNodePtr, bool);
static shared_ptr<template_type_parameter>
build_template_type_parameter(read_context&, const xmlNodePtr, unsigned, bool);
static shared_ptr<tmpl_parm_type_composition>
@ -416,6 +466,8 @@ static bool handle_var_decl(read_context&);
static bool handle_function_decl(read_context&);
static bool handle_class_decl(read_context&);
static bool handle_function_template_decl(read_context&);
static bool handle_class_template_decl(read_context&);
bool
read_file(const string& file_path,
translation_unit& tu)
@ -619,6 +671,9 @@ handle_element(read_context& ctxt)
if (xmlStrEqual(XML_READER_GET_NODE_NAME(reader).get(),
BAD_CAST("function-template-decl")))
return handle_function_template_decl(ctxt);
if (xmlStrEqual(XML_READER_GET_NODE_NAME(reader).get(),
BAD_CAST("class-template-decl")))
return handle_class_template_decl(ctxt);
return false;
}
@ -1487,6 +1542,9 @@ build_typedef_decl(read_context& ctxt,
///
/// \param node the xml node to build the class_decl from.
///
/// \param update_depth_info whether to update the depth info carried
/// by the parsing context.
///
/// \return a pointer to class_decl upon successful completion, a null
/// pointer otherwise.
static shared_ptr<class_decl>
@ -1727,7 +1785,7 @@ build_function_template_decl(read_context& ctxt,
ctxt.push_decl_to_current_scope(fn_tmpl_decl, node, update_depth_info);
unsigned parm_index = 0;
for (xmlNodePtr n = node->children; n ; n = n->next)
for (xmlNodePtr n = node->children; n; n = n->next)
{
if (n->type != XML_ELEMENT_NODE)
continue;
@ -1749,6 +1807,75 @@ build_function_template_decl(read_context& ctxt,
return fn_tmpl_decl;
}
/// Build an intance of #class_template_decl, from a
/// 'class-template-decl' xml element node.
///
/// \param ctxt the context of the parsing.
///
/// \param node the xml node to parse from.
///
/// \param update_depth_info this must be set to false, if we reached
/// this xml node by calling the xmlTextReaderRead function. In that
/// case, build_class_decl doesn't have to update the depth
/// information that is maintained in the context of the parsing.
/// Otherwise if this node if just a child grand child of a node that
/// we reached using xmlTextReaderRead, of if it wasn't reached via
/// xmlTextReaderRead at all,then the argument to this parameter
/// should be true. In that case this function will update the depth
/// information that is maintained by in the context of the parsing.
///
/// \return the newly built function_template_decl upon successful
/// completion, a null pointer otherwise.
static shared_ptr<class_template_decl>
build_class_template_decl(read_context& ctxt,
const xmlNodePtr node,
bool update_depth_info)
{
shared_ptr<class_template_decl> nil, result;
if (!xmlStrEqual(node->name, BAD_CAST("class-template-decl")))
return nil;
string id;
if (xml_char_sptr s = XML_NODE_GET_ATTRIBUTE(node, "id"))
id = CHAR_STR(s);
if (id.empty() || ctxt.get_class_tmpl_decl(id))
return nil;
location loc;
read_location(ctxt, node, loc);
decl_base::visibility vis = decl_base::VISIBILITY_NONE;
read_visibility(node, vis);
shared_ptr<class_template_decl> class_tmpl
(new class_template_decl(loc, vis));
ctxt.push_decl_to_current_scope(class_tmpl, node, update_depth_info);
unsigned parm_index = 0;
for (xmlNodePtr n = node->children; n; n = n->next)
{
if (n->type != XML_ELEMENT_NODE)
continue;
if (shared_ptr<template_parameter> parm=
build_template_parameter(ctxt, n, parm_index,
/*update_depth_info=*/true))
{
class_tmpl->add_template_parameter(parm);
++parm_index;
}
else if (shared_ptr<class_decl> c =
build_class_decl(ctxt, n, /*update_depth_info=*/true))
class_tmpl->set_pattern(c);
}
ctxt.key_class_tmpl_decl(class_tmpl, id);
return class_tmpl;
}
/// Build a template_type_parameter from a 'template-type-parameter'
/// xml element node.
///
@ -2514,5 +2641,28 @@ handle_function_template_decl(read_context& ctxt)
return is_ok;
}
/// Parse a 'class-template-decl' xml element.
///
/// \param ctxt the context of the parsing.
///
/// \return true upon successful completion, false otherwise.
static bool
handle_class_template_decl(read_context& ctxt)
{
xml::reader_sptr r = ctxt.get_reader();
if (!r)
return false;
xmlNodePtr node = xmlTextReaderExpand(r.get());
if (!node)
return false;
bool is_ok = build_class_template_decl(ctxt, node,
/*update_depth_info=*/false);
xmlTextReaderNext(r.get());
return is_ok;
}
}//end namespace reader
}//end namespace abigail

View File

@ -92,6 +92,11 @@ typedef unordered_map<shared_ptr<type_base>,
typedef unordered_map<shared_ptr<function_template_decl>,
string,
fn_tmpl_shared_ptr_hash> fn_tmpl_shared_ptr_map;
typedef unordered_map<shared_ptr<class_template_decl>,
string,
class_tmpl_shared_ptr_hash> class_tmpl_shared_ptr_map;
class write_context
{
write_context();
@ -156,12 +161,26 @@ public:
return m_fn_tmpl_id_map[f];
}
string
get_id_for_class_tmpl(shared_ptr<class_template_decl> c)
{
class_tmpl_shared_ptr_map::const_iterator it = m_class_tmpl_id_map.find(c);
if (it == m_class_tmpl_id_map.end())
{
string id = get_id_manager().get_id_with_prefix("class-tmpl-id-");
m_class_tmpl_id_map[c] = id;
return id;
}
return m_class_tmpl_id_map[c];
}
private:
id_manager m_id_manager;
config m_config;
ostream& m_ostream;
type_shared_ptr_map m_type_id_map;
fn_tmpl_shared_ptr_map m_fn_tmpl_id_map;
class_tmpl_shared_ptr_map m_class_tmpl_id_map;
};//end write_context
static bool write_translation_unit(const translation_unit&,
@ -207,9 +226,14 @@ static bool write_tmpl_parm_type_composition
(const shared_ptr<tmpl_parm_type_composition>, write_context&, unsigned);
static bool write_template_parameter(const shared_ptr<template_parameter>,
write_context&, unsigned);
static void write_template_parameters(const shared_ptr<template_decl>,
write_context&, unsigned);
static bool write_function_template_decl
(const shared_ptr<function_template_decl>,
write_context&, unsigned);
static bool write_class_template_decl
(const shared_ptr<class_template_decl>,
write_context&, unsigned);
static void do_indent(ostream&, unsigned);
static void do_indent_to_level(write_context&, unsigned, unsigned);
static unsigned get_indent_to_level(write_context&, unsigned, unsigned);
@ -532,21 +556,19 @@ write_decl(const shared_ptr<decl_base> decl,
|| write_pointer_type_def(dynamic_pointer_cast<pointer_type_def>(decl),
ctxt, indent)
|| write_reference_type_def(dynamic_pointer_cast
<reference_type_def>(decl),
ctxt, indent)
<reference_type_def>(decl), ctxt, indent)
|| write_enum_type_decl(dynamic_pointer_cast<enum_type_decl>(decl),
ctxt, indent)
|| write_typedef_decl(dynamic_pointer_cast<typedef_decl>(decl),
ctxt, indent)
|| write_var_decl(dynamic_pointer_cast<var_decl>(decl),
ctxt, indent)
|| write_var_decl(dynamic_pointer_cast<var_decl>(decl), ctxt, indent)
|| write_function_decl(dynamic_pointer_cast<function_decl>(decl),
ctxt, indent)
|| write_class_decl(dynamic_pointer_cast<class_decl>(decl),
ctxt, indent)
|| write_class_decl(dynamic_pointer_cast<class_decl>(decl), ctxt, indent)
|| (write_function_template_decl
(dynamic_pointer_cast<function_template_decl>(decl),
ctxt, indent)))
(dynamic_pointer_cast<function_template_decl>(decl), ctxt, indent))
|| (write_class_template_decl
(dynamic_pointer_cast<class_template_decl>(decl), ctxt, indent)))
return true;
return false;
@ -1305,6 +1327,29 @@ write_template_parameter(const shared_ptr<template_parameter> decl,
return true;
}
/// Serialize the template parameters of the a given template.
///
/// \param tmpl the template for which to emit the template parameters.
static void
write_template_parameters(const shared_ptr<template_decl> tmpl,
write_context& ctxt, unsigned indent)
{
if (!tmpl)
return;
ostream &o = ctxt.get_ostream();
unsigned nb_spaces = get_indent_to_level(ctxt, indent, 1);
for (list<shared_ptr<template_parameter> >::const_iterator p =
tmpl->get_template_parameters().begin();
p != tmpl->get_template_parameters().end();
++p)
{
write_template_parameter(*p, ctxt, nb_spaces);
o << "\n";
}
}
/// Serialize an instance of function_template_decl.
///
/// \param decl the instance to serialize.
@ -1333,24 +1378,61 @@ write_function_template_decl(const shared_ptr<function_template_decl> decl,
o << ">\n";
unsigned nb_spaces = get_indent_to_level(ctxt, indent, 1);
for (list<shared_ptr<template_parameter> >::const_iterator p =
decl->get_template_parameters().begin();
p != decl->get_template_parameters().end();
++p)
{
write_template_parameter(*p, ctxt, nb_spaces);
o << "\n";
}
write_template_parameters(decl, ctxt, indent);
write_function_decl(decl->get_pattern(), ctxt, nb_spaces);
write_function_decl(decl->get_pattern(), ctxt,
get_indent_to_level(ctxt, indent, 1));
o << "\n";
do_indent_to_level(ctxt, indent, 0);
o << "</function-template-decl>";
return true;
}
/// Serialize an instance of class_template_decl
///
/// \param decl a pointer to the instance of class_template_decl to serialize.
///
/// \param ctxt the context of the serializtion.
///
/// \param indent the initial number of white space to use for
/// indentation.
///
/// \return true upon successful completion, false otherwise.
static bool
write_class_template_decl (const shared_ptr<class_template_decl> decl,
write_context& ctxt, unsigned indent)
{
if (!decl)
return false;
ostream& o = ctxt.get_ostream();
do_indent_to_level(ctxt,indent, 0);
o << "<class-template-decl id='" << ctxt.get_id_for_class_tmpl(decl) << "'";
write_location(decl, o);
write_visibility(decl, o);
o << ">\n";
write_template_parameters(decl, ctxt, indent);
write_class_decl(decl->get_pattern(), ctxt,
get_indent_to_level(ctxt, indent, 1));
o << "\n";
do_indent_to_level(ctxt, indent, 0);
o << "</class-template-decl>";
return true;
}
}//end namespace writer
}//end namespace abigail

View File

@ -34,4 +34,5 @@ $(h)/data/test-read-write/test10.xml \
$(h)/data/test-read-write/test11.xml \
$(h)/data/test-read-write/test12.xml \
$(h)/data/test-read-write/test13.xml \
$(h)/data/test-read-write/test14.xml
$(h)/data/test-read-write/test14.xml \
$(h)/data/test-read-write/test15.xml

View File

@ -0,0 +1,17 @@
<abi-instr version='1.0'>
<type-decl name='int' size-in-bits='32' alignment-in-bits='32' id='type-id-1'/>
<class-template-decl id='class-tmpl-id-2'>
<template-type-parameter id='type-id-3' name='T'/>
<class-decl name='C' visibility='default' id='type-id-4'>
<member-type access='public'>
<typedef-decl name='TINT' type-id='type-id-1' id='type-id-5'/>
</member-type>
<data-member access='private'>
<var-decl name='m_first' type-id='type-id-3'/>
</data-member>
<data-member access='private'>
<var-decl name='m_second' type-id='type-id-5'/>
</data-member>
</class-decl>
</class-template-decl>
</abi-instr>

View File

@ -107,6 +107,10 @@ InOutSpec in_out_specs[] =
"data/test-read-write/test14.xml",
"output/test-read-write/test14.xml"
},
{
"data/test-read-write/test15.xml",
"output/test-read-write/test15.xml"
},
// This should be the last entry.
{NULL, NULL}
};