From 6f3506215ba336264fa83a2b177774f9584e5146 Mon Sep 17 00:00:00 2001 From: Dodji Seketeli Date: Mon, 10 Feb 2014 15:42:19 +0100 Subject: [PATCH] Support diffing entities of different kinds. * include/abg-comparison.h (class distinct_diff): Declare new type. (compute_diff_for_distinct_kinds): Declare new function. * src/abg-comparison.cc (distinct_diff::{distinct_diff, first, second, entities_are_of_distinct_kinds, length, report}): Define new member functions. (compute_diff_for_distinct_kinds, try_to_diff_distinct_kinds): Define new function. (compute_diff_for_types, compute_diff_for_decls): Support diffing entities of different kinds. Signed-off-by: Dodji Seketeli --- include/abg-comparison.h | 46 +++++++++++ src/abg-comparison.cc | 159 +++++++++++++++++++++++++++++++++++++-- 2 files changed, 197 insertions(+), 8 deletions(-) diff --git a/include/abg-comparison.h b/include/abg-comparison.h index 9308a43c..832632f6 100644 --- a/include/abg-comparison.h +++ b/include/abg-comparison.h @@ -294,6 +294,52 @@ compute_diff(const type_base_sptr, const type_base_sptr, diff_context_sptr ctxt); +class distinct_diff; + +/// Convenience typedef for a shared pointer to distinct_types_diff +typedef shared_ptr distinct_diff_sptr; + +/// An abstraction of a diff between entities that are of a different +/// kind (disctinct). +class distinct_diff : public diff +{ + struct priv; + typedef shared_ptr priv_sptr; + priv_sptr priv_; + +protected: + distinct_diff(decl_base_sptr first, + decl_base_sptr second, + diff_context_sptr ctxt = diff_context_sptr()); +public: + + const decl_base_sptr + first() const; + + const decl_base_sptr + second() const; + + virtual unsigned + length() const; + + virtual void + report(ostream& out, const string& indent = "") const; + + static bool + entities_are_of_distinct_kinds(decl_base_sptr first, + decl_base_sptr second); + + friend distinct_diff_sptr + compute_diff_for_distinct_kinds(const decl_base_sptr first, + const decl_base_sptr second, + diff_context_sptr ctxt); +};// end class distinct_types_diff + +distinct_diff_sptr +compute_diff_for_distinct_kinds(const decl_base_sptr, + const decl_base_sptr, + diff_context_sptr ctxt); + class var_diff; /// Convenience typedef for a shared pointer to var_diff. diff --git a/src/abg-comparison.cc b/src/abg-comparison.cc index aba383bc..f5e364ff 100644 --- a/src/abg-comparison.cc +++ b/src/abg-comparison.cc @@ -142,6 +142,124 @@ diff_context::add_diff(decl_base_sptr first, diff_sptr d) {priv_->decls_diff_map[std::make_pair(first, second)] = d;} +/// + +/// The private data structure for @ref distinct_diff. +struct distinct_diff::priv +{ +};// end struct distinct_diff + +/// Constructor for @ref distinct_diff. +/// +/// Note that the two entities considered for the diff (and passed in +/// parameter) must be of different kinds. +/// +/// @param first the first entity to consider for the diff. +/// +/// @param second the second entity to consider for the diff. +/// +/// @param ctxt the context of the diff. +distinct_diff::distinct_diff(decl_base_sptr first, + decl_base_sptr second, + diff_context_sptr ctxt) + : diff(first, second, ctxt), + priv_(new priv) +{assert(entities_are_of_distinct_kinds(first, second));} + +/// Getter for the first subject of the diff. +/// +/// @return the first subject of the diff. +const decl_base_sptr +distinct_diff::first() const +{return first_subject();} + +/// Getter for the second subject of the diff. +/// +/// @return the second subject of the diff. +const decl_base_sptr +distinct_diff::second() const +{return second_subject();} + +/// Test if the two arguments are of different kind. +/// +/// @param first the first argument to test for similarity in kind. +/// +/// @param second the second argument to test for similarity in kind. +/// +/// @return true iff the two arguments are of different kind. +bool +distinct_diff::entities_are_of_distinct_kinds(decl_base_sptr first, + decl_base_sptr second) +{ + if (!!first != !!second) + return true; + if (first == second) + return true; + + return typeid(*first.get()) != typeid(*second.get()); +} + +/// @return 1 if the two subjects of the diff are different, 0 +/// otherwise. +unsigned +distinct_diff::length() const +{ + if (first() == second()) + return 0; + return 1; +} + +/// Emit a report about the current diff instance. +/// +/// @param out the output stream to send the diff report to. +/// +/// @param indent the indentation string to use in the report. +void +distinct_diff::report(ostream& out, const string& indent) const +{ + if (length() == 0) + return; + + decl_base_sptr f = first(), s = second(); + + string f_repr = f ? f->get_pretty_representation() : "'void'"; + string s_repr = s ? s->get_pretty_representation() : "'void'"; + + out << indent << "entity changed from " << f_repr << " to " << s_repr << "\n"; +} + +/// Try to diff entities that are of distinct kinds. +/// +/// @param first the first entity to consider for the diff. +/// +/// @param second the second entity to consider for the diff. +/// +/// @param ctxt the context of the diff. +/// +/// @return a non-null diff if a diff object could be built, null +/// otherwise. +distinct_diff_sptr +compute_diff_for_distinct_kinds(const decl_base_sptr first, + const decl_base_sptr second, + diff_context_sptr ctxt) +{ + if (!distinct_diff::entities_are_of_distinct_kinds(first, second)) + return distinct_diff_sptr(); + + if (diff_sptr dif = ctxt->has_diff_for(first, second)) + { + distinct_diff_sptr d = dynamic_pointer_cast(dif); + assert(d); + return d; + } + distinct_diff_sptr result(new distinct_diff(first, second, ctxt)); + + ctxt->add_diff(first, second, result); + return result; +} + +/// + /// Try to compute a diff on two instances of DiffType representation. /// /// The function template performs the diff if and only if the decl @@ -214,6 +332,22 @@ try_to_diff(const decl_base_sptr first, return diff_sptr(); } +/// Try to diff entities that are of distinct kinds. +/// +/// @param first the first entity to consider for the diff. +/// +/// @param second the second entity to consider for the diff. +/// +/// @param ctxt the context of the diff. +/// +/// @return a non-null diff if a diff object could be built, null +/// otherwise. +static diff_sptr +try_to_diff_distinct_kinds(const decl_base_sptr first, + const decl_base_sptr second, + diff_context_sptr ctxt) +{return compute_diff_for_distinct_kinds(first, second, ctxt);} + /// Compute the difference between two types. /// /// The function considers every possible types known to libabigail @@ -238,13 +372,19 @@ compute_diff_for_types(const decl_base_sptr first, { diff_sptr d; - ((d = try_to_diff(first, second, ctxt)) - ||(d = try_to_diff(first, second, ctxt)) - ||(d = try_to_diff(first, second,ctxt)) - ||(d = try_to_diff(first, second, ctxt)) - ||(d = try_to_diff(first, second, ctxt)) - ||(d = try_to_diff(first, second, ctxt)) - ||(d = try_to_diff(first, second, ctxt))); + const decl_base_sptr f = get_type_declaration(as_non_member_type(first)); + const decl_base_sptr s = get_type_declaration(as_non_member_type(second)); + + ((d = try_to_diff_distinct_kinds(f, s, ctxt)) + ||(d = try_to_diff(f, s, ctxt)) + ||(d = try_to_diff(f, s, ctxt)) + ||(d = try_to_diff(f, s,ctxt)) + ||(d = try_to_diff(f, s, ctxt)) + ||(d = try_to_diff(f, s, ctxt)) + ||(d = try_to_diff(f, s, ctxt)) + ||(d = try_to_diff(f, s, ctxt))); + + assert(d); return d; } @@ -307,9 +447,12 @@ compute_diff_for_decls(const decl_base_sptr first, diff_sptr d; - ((d = try_to_diff(first, second, ctxt)) + ((d = try_to_diff_distinct_kinds(first, second, ctxt)) + || (d = try_to_diff(first, second, ctxt)) || (d = try_to_diff(first, second, ctxt))); + assert(d); + return d; }