diff --git a/src/abg-ir.cc b/src/abg-ir.cc index 03ccc1d5..396de06c 100644 --- a/src/abg-ir.cc +++ b/src/abg-ir.cc @@ -4,7 +4,6 @@ #include #include #include - #include "abg-ir.h" using std::string; @@ -159,6 +158,20 @@ decl_base::decl_base(const decl_base& d) m_context = d.m_context; } +/// Return true iff the two decls have the same name. +/// +/// This function doesn't test if the scopes of the the two decls are +/// equal. +bool +decl_base::operator==(const decl_base& other) const +{ + // Runtime types must be equal. + if (typeid(*this) != typeid(other)) + return false; + + return get_name() == other.get_name(); +} + decl_base::~decl_base() { } @@ -184,6 +197,34 @@ scope_decl::scope_decl(location l) { } +/// Return true iff both scopes have the same names and have the same +/// member decls. +/// +/// This function doesn't check for equality of the scopes of its +/// arguments. +bool +scope_decl::operator==(const scope_decl& other) const +{ + // Runtime types must be equal. + if (typeid(*this) != typeid(other)) + return false; + + if (static_cast(*this) != static_cast(other)) + return false; + + std::list >::const_iterator i, j; + for (i = get_member_decls().begin(), j = other.get_member_decls().begin(); + i != get_member_decls().end() && j != other.get_member_decls().end(); + ++i, ++j) + if (**i != **j) + return false; + + if (i != get_member_decls().end() || j != other.get_member_decls().end()) + return false; + + return true; +} + /// Add a member decl to this scope. Note that user code should not /// use this, but rather use #add_decl_to_scope. /// @@ -229,6 +270,20 @@ type_base::type_base(size_t s = 8, size_t a = 8) { } +/// Return true iff both type declarations are equal. +/// +/// Note that this doesn't test if the scopes of both types are equal. +bool +type_base::operator==(const type_base& other) const +{ + // Runtime types must be equal. + if (typeid(*this) != typeid(other)) + return false; + + return (get_size_in_bits() == other.get_size_in_bits() + && get_alignment_in_bits() == other.get_alignment_in_bits()); +} + void type_base::set_size_in_bits(size_t s) { @@ -270,6 +325,20 @@ type_decl::type_decl(const std::string& name, { } +/// Return true if both types equals. +/// +/// Note that this does not check the scopes of any of the types. +bool +type_decl::operator==(const type_decl& other) const +{ + // Runtime types must be equal. + if (typeid(*this) != typeid(other)) + return false; + + return (static_cast(*this) == other + && static_cast(*this) == other); +} + type_decl::~type_decl() { } @@ -287,6 +356,21 @@ scope_type_decl::scope_type_decl(const std::string& name, { } +/// Return true iff both scope types are equal. +/// +/// Note that this function does not consider the scope of the scope +/// types themselves. +bool +scope_type_decl::operator==(const scope_type_decl& other) const +{ + // Runtime types must be equal. + if (typeid(*this) != typeid(other)) + return false; + + return (static_cast(*this) == other + && static_cast(*this) == other); +} + scope_type_decl::~scope_type_decl() { } @@ -300,6 +384,20 @@ namespace_decl::namespace_decl(const std::string& name, { } +/// Return true iff both namespaces and their members are equal. +/// +/// Note that this function does not check if the scope of these +/// namespaces are equal. +bool +namespace_decl::operator==(const namespace_decl& other) const +{ + // Runtime types must be equal. + if (typeid(*this) != typeid(other)) + return false; + + return (static_cast(*this) == other); +} + namespace_decl::~namespace_decl() { } @@ -331,6 +429,24 @@ qualified_type_def::qualified_type_def(shared_ptr type, set_name(get_name() + dynamic_pointer_cast(type)->get_name()); } +/// Return true iff both qualified types are equal. +/// +/// Note that this function does not check for equality of the scopes. +bool +qualified_type_def::operator==(const qualified_type_def& other) const +{ + // Runtime types must be equal. + if (typeid(*this) != typeid(other) + || get_cv_quals() != other.get_cv_quals() + || get_underlying_type() != other.get_underlying_type()) + return false; + + if (shared_ptr u = get_underlying_type()) + return (*u == *other.get_underlying_type()); + + return true; +} + /// The destructor of the qualified type qualified_type_def::~qualified_type_def() { @@ -383,4 +499,43 @@ dynamic_type_hash::operator()(const type_base* t) const // Poor man's fallback case. return type_base_hash()(*t); } + +pointer_type_def::pointer_type_def(shared_ptr& pointed_to, + size_t size_in_bits, + size_t align_in_bits, + location locus) + : type_base(size_in_bits, align_in_bits), + decl_base("", locus), + m_pointed_to_type(pointed_to) +{ +} + +/// Return true iff both instances of pointer_type_def are equal. +/// +/// Note that this function does not check for the scopes of the this +/// types. +bool +pointer_type_def::operator==(const pointer_type_def& other) const +{ + // Runtime types must be equal. + if (typeid(*this) != typeid(other) + || get_pointed_to_type() != other.get_pointed_to_type()) + return false; + + if (shared_ptr c = get_pointed_to_type()) + return *c == *other.get_pointed_to_type(); + + return true; +} + +shared_ptr +pointer_type_def::get_pointed_to_type() const +{ + return m_pointed_to_type; +} + +pointer_type_def::~pointer_type_def() +{ +} + }//end namespace abigail diff --git a/src/abg-ir.h b/src/abg-ir.h index 1d44fa8f..bca2e2de 100644 --- a/src/abg-ir.h +++ b/src/abg-ir.h @@ -9,7 +9,7 @@ #include #include #include - +#include // for std::rel_ops, at least. #include "abg-hash.h" using std::tr1::shared_ptr; @@ -19,6 +19,10 @@ using std::string; // Our real stuff namespace abigail { + +using namespace std::rel_ops; // Pull in relational operators so that + // we don't have to define them all here. + /// \brief The source location of a token. /// /// This represents the location of a token coming from a given ABI @@ -50,6 +54,14 @@ public: return !!m_value; } + bool + operator==(const location other) const + {return m_value == other.m_value;} + + bool + operator<(const location other) const + {return m_value < other.m_value;} + friend class location_manager; private: @@ -99,8 +111,14 @@ public: decl_base(const std::string& name, location locus); + decl_base(location); + decl_base(const decl_base&); + + virtual bool + operator==(const decl_base&) const; + virtual ~decl_base(); location @@ -153,8 +171,12 @@ class scope_decl : public decl_base public: scope_decl(const std::string& name, location locus); + scope_decl(location); + virtual bool + operator==(const scope_decl&) const; + const std::list >& get_member_decls() const; @@ -198,6 +220,10 @@ class type_base public: type_base(size_t s, size_t a); + + virtual bool + operator==(const type_base&) const; + virtual ~type_base(); void @@ -253,6 +279,24 @@ struct type_shared_ptr_hash } };//end struct type_shared_ptr_hash +/// A predicate for deep equality of instances of +/// shared_ptr +struct type_shared_ptr_equal +{ + bool + operator()(const shared_ptrl, + const shared_ptrr) const + { + if (l != r) + return false; + + if (l) + return *l == *r; + + return true; + } +};//end struct type_shared_ptr_equal + /// A basic type declaration that introduces no scope. class type_decl : public decl_base, public type_base { @@ -266,6 +310,9 @@ public: size_t alignment_in_bits, location locus); + virtual bool + operator==(const type_decl&) const; + virtual ~type_decl(); };// class type_decl @@ -297,6 +344,9 @@ public: size_t alignment_in_bits, location locus); + virtual bool + operator==(const scope_type_decl&) const; + virtual ~scope_type_decl(); }; @@ -324,6 +374,9 @@ public: namespace_decl(const std::string& name, location locus); + virtual bool + operator==(const namespace_decl&) const; + virtual ~namespace_decl(); };//end class namespace_decl @@ -331,6 +384,8 @@ public: class qualified_type_def : public type_base, public decl_base { + // Forbidden. + qualified_type_def(); public: /// Bit field values representing the cv qualifiers of the /// underlying type. @@ -345,6 +400,9 @@ public: CV quals, location locus); + virtual bool + operator==(const qualified_type_def&) const; + char get_cv_quals() const; @@ -378,5 +436,30 @@ struct qualified_type_def_hash } };//end struct qualified_type_def_hash +/// The abstraction of a pointer type. +class pointer_type_def : public type_base, public decl_base +{ + // Forbidden. + pointer_type_def(); + +public: + + pointer_type_def(shared_ptr& pointed_to_type, + size_t size_in_bits, + size_t alignment_in_bits, + location locus); + + virtual bool + operator==(const pointer_type_def&) const; + + shared_ptr + get_pointed_to_type() const; + + virtual ~pointer_type_def(); + +private: + shared_ptr m_pointed_to_type; +};//end class pointer_type_def + } // end namespace abigail #endif // __ABL_IR_H__ diff --git a/src/abg-reader.cc b/src/abg-reader.cc index e3300dfc..cf62474a 100644 --- a/src/abg-reader.cc +++ b/src/abg-reader.cc @@ -140,14 +140,15 @@ private: stack > m_decls_stack; };//end class read_context -static void update_read_context(read_context&); -static int advance_cursor(read_context&); -static bool read_input(read_context&, abi_corpus&); -static bool read_location(read_context&, abi_corpus& , location&); -static bool handle_element(read_context&, abi_corpus&); -static bool handle_type_decl(read_context&, abi_corpus&); -static bool handle_namespace_decl(read_context&, abi_corpus&); -static bool handle_qualified_type_decl(read_context&, abi_corpus&); +static void update_read_context(read_context&); +static int advance_cursor(read_context&); +static bool read_input(read_context&, abi_corpus&); +static bool read_location(read_context&, abi_corpus& , location&); +static bool handle_element(read_context&, abi_corpus&); +static bool handle_type_decl(read_context&, abi_corpus&); +static bool handle_namespace_decl(read_context&, abi_corpus&); +static bool handle_qualified_type_decl(read_context&, abi_corpus&); +static bool handle_pointer_type_def(read_context&, abi_corpus&); bool read_file(const string& file_path, @@ -212,7 +213,7 @@ advance_cursor(read_context& ctxt) /// /// \param corpus the result of the parsing. /// -/// \return true upon successufl parsing, false otherwise. +/// \return true upon successful parsing, false otherwise. static bool read_input(read_context& ctxt, abi_corpus& corpus) @@ -276,6 +277,9 @@ handle_element(read_context& ctxt, if (xmlStrEqual (XML_READER_GET_NODE_NAME(reader).get(), BAD_CAST("qualified-type-def"))) return handle_qualified_type_decl(ctxt, corpus); + if (xmlStrEqual (XML_READER_GET_NODE_NAME(reader).get(), + BAD_CAST("pointer-type-def"))) + return handle_pointer_type_def(ctxt, corpus); return false; } @@ -411,7 +415,7 @@ handle_namespace_decl(read_context& ctxt, abi_corpus& corpus) return true; } -/// Parse qualified-type-def xml element +/// Parse a qualified-type-def xml element. /// /// \param ctxt the parsing context. /// @@ -480,5 +484,61 @@ handle_qualified_type_decl(read_context& ctxt, abi_corpus& corpus) return true; } + +/// Parse a pointer-type-decl element. +/// +/// \param ctxt the context of the parsing. +/// +/// \param corpus the ABI Corpus to augment with the result of the +/// parsing. +/// +/// \return true upon successful completion, false otherwise. +static bool +handle_pointer_type_def(read_context& ctxt, abi_corpus& corpus) +{ + xml::reader_sptr r = ctxt.get_reader(); + if (!r) + return false; + + string type_id; + if (xml_char_sptr s = XML_READER_GET_ATTRIBUTE(r, "type-id")) + type_id = CHAR_STR(s); + + shared_ptr pointed_to_type = ctxt.get_type_decl(type_id); + if (!pointed_to_type) + return false; + + size_t size_in_bits = 0, alignment_in_bits = 0; + if (xml_char_sptr s = XML_READER_GET_ATTRIBUTE(r, "size-in-bits")) + size_in_bits = atoi(CHAR_STR(s)); + if (xml_char_sptr s = XML_READER_GET_ATTRIBUTE(r, "alignment-in-bits")) + alignment_in_bits = atoi(CHAR_STR(s)); + + string id; + if (xml_char_sptr s = XML_READER_GET_ATTRIBUTE(r, "id")) + id = CHAR_STR(s); + if (id.empty() || ctxt.get_type_decl(id)) + return false; + + location loc; + read_location(ctxt, corpus, loc); + + shared_ptr decl = + shared_ptr (new pointer_type_def(pointed_to_type, + size_in_bits, + alignment_in_bits, + loc)); + add_decl_to_scope(decl, ctxt.get_cur_scope()); + + if (!decl->get_scope()) + corpus.add(decl); + + ctxt.push_decl(decl); + + ctxt.add_type_decl(id, dynamic_pointer_cast(decl)); + + return true; +} + }//end namespace reader }//end namespace abigail diff --git a/src/abg-writer.cc b/src/abg-writer.cc index ae04b8c9..994da042 100644 --- a/src/abg-writer.cc +++ b/src/abg-writer.cc @@ -9,6 +9,7 @@ using std::tr1::shared_ptr; using std::tr1::dynamic_pointer_cast; +using std::tr1::static_pointer_cast; using std::ostream; using std::ostringstream; using std::list; @@ -61,7 +62,8 @@ private: typedef unordered_map, string, - type_shared_ptr_hash> type_shared_ptr_map; + type_shared_ptr_hash, + type_shared_ptr_equal> type_shared_ptr_map; class write_context { write_context(); @@ -138,7 +140,11 @@ static bool write_qualified_type_def(const shared_ptr, const abi_corpus&, write_context&, unsigned); -void do_indent(ostream&, unsigned); +static bool write_pointer_type_def(const shared_ptr, + const abi_corpus&, + write_context&, + unsigned); +static void do_indent(ostream&, unsigned); /// Emit #nb_whitespaces white spaces into the output stream #o. void @@ -215,13 +221,14 @@ write_decl(const shared_ptr decl, unsigned indent) { if (write_type_decl(dynamic_pointer_cast (decl), - corpus, ctxt, indent)) - return true; - if (write_namespace_decl(dynamic_pointer_cast(decl), - corpus, ctxt, indent)) - return true; - if (write_qualified_type_def(dynamic_pointer_cast(decl), - corpus, ctxt, indent)) + corpus, ctxt, indent) + || write_namespace_decl(dynamic_pointer_cast(decl), + corpus, ctxt, indent) + || write_qualified_type_def (dynamic_pointer_cast + (decl), + corpus, ctxt, indent) + || write_pointer_type_def(dynamic_pointer_cast(decl), + corpus, ctxt, indent)) return true; return false; @@ -400,7 +407,7 @@ write_qualified_type_def(const shared_ptr decl, if (decl->get_cv_quals() & qualified_type_def::CV_VOLATILE) o << " volatile='yes'"; - write_decl_location(dynamic_pointer_cast(decl), corpus, o); + write_decl_location(static_pointer_cast(decl), corpus, o); o<< " id='" << ctxt.get_id_for_type(decl) @@ -411,5 +418,45 @@ write_qualified_type_def(const shared_ptr decl, return true; } +/// Serialize a pointer to an instance of pointer_type_def. +/// +/// \param decl the pointer_type_def to serialize. +/// +/// \param corpus the ABI corpus it belongs to. +/// +/// \param ctxt the context of the serialization. +/// +/// \param indent the number of indentation white spaces to use. +/// +/// \return true upon succesful completion, false otherwise. +static bool +write_pointer_type_def(const shared_ptr decl, + const abi_corpus& corpus, + write_context& ctxt, + unsigned indent) +{ + if (!decl) + return false; + + ostream &o = ctxt.get_ostream(); + + do_indent(o, indent); + + o << "get_size_in_bits()) + o << " size-in-bits='" << s << "'"; + if (size_t s = decl->get_alignment_in_bits()) + o << " alignment-in-bits='" << s << "'"; + + o << " id='" << ctxt.get_id_for_type(decl) << "'"; + + write_decl_location(static_pointer_cast(decl), corpus, o); + o << "/>"; + + return true; +} }//end namespace writer }//end namespace abigail diff --git a/tests/Makefile.am b/tests/Makefile.am index 5a3a067c..91d19ac9 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -23,4 +23,5 @@ EXTRA_DIST= \ $(h)/data/test-read-write/test0.xml \ $(h)/data/test-read-write/test1.xml \ $(h)/data/test-read-write/test2.xml \ -$(h)/data/test-read-write/test3.xml +$(h)/data/test-read-write/test3.xml \ +$(h)/data/test-read-write/test4.xml diff --git a/tests/data/test-read-write/test4.xml b/tests/data/test-read-write/test4.xml new file mode 100644 index 00000000..1e74e780 --- /dev/null +++ b/tests/data/test-read-write/test4.xml @@ -0,0 +1,4 @@ + + + + diff --git a/tests/test-read-write.cc b/tests/test-read-write.cc index 8a6d34b8..24b7edfa 100644 --- a/tests/test-read-write.cc +++ b/tests/test-read-write.cc @@ -40,6 +40,10 @@ InOutSpec in_out_specs[] = "data/test-read-write/test3.xml", "output/test-read-write/test3.xml" }, + { + "data/test-read-write/test4.xml", + "output/test-read-write/test4.xml" + }, // This should be the last entry. {NULL, NULL}