mirror of
git://sourceware.org/git/libabigail.git
synced 2024-12-16 15:04:46 +00:00
Take filtering in account in diff stats & better categorizing
* include/abg-comparison.h (diff_category::ACCESS_CHANGE_CATEGORY): Renamed ACCESS_CHANGED_CATEGORY into this. (diff_category::SIZE_OR_OFFSET_CHANGE_CATEGORY): Renamed SIZE_CHANGED_CATEGORY into this. Changed its semantics to incorporate offset changes as well. * src/abg-comparison.cc (struct noop_deleter): Move this up. (represent): Do not report filtered out data members. (report_mem_header): Add a new num_filtered parameter to take filtered-out members in account in members report headers. Adjust. (class_diff::priv::{count_filtered_bases, count_filtered_data_members, count_filtered_member_functions}): New member functions. When a member is filtered, do not report it all. ({enum_diff, class_diff}::report): Adjust. Take filtered members into account in headers. (corpus_diff::priv::apply_filters_and_compute_diff_stats): New member function. (corpus_diff::priv::emit_diff_stats): Renamed emit_corpus_diff_stats into this. Change it to take the stats in parameter. (corpus_diff::report): Adjust to re-use the above. Filter varibles as well. Take the filtered functions & variables in account in the stats. Do not report filtered-out functions & variables at all. * src/abg-comp-filter.cc (type_size_changed, access_changed) (data_member_offset_changed): New predicates. ({harmless, harmful}_filter::visit): Adjust to use the new predicates above. Update the harmful variant for the new SIZE_OR_OFFSET_CHANGE_CATEGORY category. * tools/bidiff.cc (set_diff_context_from_opts): Adjust for the categories name changes. * tests/data/test-diff-filter/test0-report.txt: New test input. * tests/data/test-diff-filter/test0-v0.cc: Likewise. * tests/data/test-diff-filter/test0-v0.o: Likewise. * tests/data/test-diff-filter/test0-v1.cc: Likewise. * tests/data/test-diff-filter/test0-v1.o: Likewise. * tests/test-diff-filter.cc: New test harness. * tests/Makefile.am: Add the new test files above to the distribution. Signed-off-by: Dodji Seketeli <dodji@redhat.com>
This commit is contained in:
parent
e55a7e3397
commit
67e6971005
@ -207,10 +207,11 @@ enum diff_category
|
||||
/// This means the diff node (or at least one of its descendant
|
||||
/// nodes) carries access related changes, e.g, a private member
|
||||
/// that becomes public.
|
||||
ACCESS_CHANGED_CATEGORY = 1,
|
||||
ACCESS_CHANGE_CATEGORY = 1,
|
||||
/// This means the diff node (or at least one of its descendant
|
||||
/// nodes) carries a change that modifies the size of a type.
|
||||
SIZE_CHANGED_CATEGORY = 1 << 1,
|
||||
/// nodes) carries a change that modifies the size of a type or an
|
||||
/// offset of a type member.
|
||||
SIZE_OR_OFFSET_CHANGE_CATEGORY = 1 << 1,
|
||||
|
||||
/// A special enumerator that is the logical 'or' all the
|
||||
/// enumerators above.
|
||||
@ -218,8 +219,8 @@ enum diff_category
|
||||
/// This one must stay the last enumerator. Please update it each
|
||||
/// time you add a new enumerator above.
|
||||
EVERYTHING_CATEGORY =
|
||||
ACCESS_CHANGED_CATEGORY
|
||||
| SIZE_CHANGED_CATEGORY
|
||||
ACCESS_CHANGE_CATEGORY
|
||||
| SIZE_OR_OFFSET_CHANGE_CATEGORY
|
||||
};
|
||||
|
||||
diff_category
|
||||
@ -817,7 +818,7 @@ public:
|
||||
enum_diff_sptr
|
||||
compute_diff(const enum_type_decl_sptr,
|
||||
const enum_type_decl_sptr,
|
||||
diff_context_sptr ctxt);
|
||||
diff_context_sptr);
|
||||
|
||||
class class_diff;
|
||||
|
||||
|
@ -34,6 +34,8 @@ namespace comparison
|
||||
namespace filtering
|
||||
{
|
||||
|
||||
using std::tr1::dynamic_pointer_cast;
|
||||
|
||||
/// Walk and categorize the nodes of a diff sub-tree.
|
||||
///
|
||||
/// @param filter the filter invoked on each node of the walked
|
||||
@ -57,6 +59,80 @@ void
|
||||
apply_filter(filter_base_sptr filter, diff_sptr d)
|
||||
{apply_filter(*filter, d);}
|
||||
|
||||
/// Tests if the size of a given type changed.
|
||||
///
|
||||
/// @param f the declaration of the first version of the type to
|
||||
/// consider.
|
||||
///
|
||||
/// @param s the declaration of the second version of the type to
|
||||
/// consider.
|
||||
///
|
||||
/// @return true if the type size changed, false otherwise.
|
||||
static bool
|
||||
type_size_changed(decl_base_sptr f, decl_base_sptr s)
|
||||
{
|
||||
type_base_sptr t0 = is_type(f), t1 = is_type(s);
|
||||
if (!t0 || !t1)
|
||||
return false;
|
||||
|
||||
if (t0->get_size_in_bits() != t1->get_size_in_bits())
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// Tests if the access specifiers for a member declaration changed.
|
||||
///
|
||||
/// @param f the declaration for the first version of the member
|
||||
/// declaration to consider.
|
||||
///
|
||||
/// @param s the declaration for the second version of the member
|
||||
/// delcaration to consider.
|
||||
///
|
||||
/// @return true iff the access specifier changed.
|
||||
static bool
|
||||
access_changed(decl_base_sptr f, decl_base_sptr s)
|
||||
{
|
||||
if (!is_member_decl(f)
|
||||
&& !is_member_decl(s))
|
||||
return false;
|
||||
|
||||
access_specifier fa = get_member_access_specifier(f),
|
||||
sa = get_member_access_specifier(s);
|
||||
|
||||
if (sa != fa)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// Tests if the offset of a given data member changed.
|
||||
///
|
||||
/// @param f the declaration for the first version of the data member to
|
||||
/// consider.
|
||||
///
|
||||
/// @param s the declaration for the second version of the data member
|
||||
/// to consider.
|
||||
///
|
||||
/// @return true iff the offset of the data member changed.
|
||||
static bool
|
||||
data_member_offset_changed(decl_base_sptr f, decl_base_sptr s)
|
||||
{
|
||||
if (!is_member_decl(f)
|
||||
&& !is_member_decl(s))
|
||||
return false;
|
||||
|
||||
var_decl_sptr v0 = dynamic_pointer_cast<var_decl>(f),
|
||||
v1 = dynamic_pointer_cast<var_decl>(s);
|
||||
if (!v0 || !v1)
|
||||
return false;
|
||||
|
||||
if (get_data_member_offset(v0) != get_data_member_offset(v1))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// The visiting code of the harmless_filter.
|
||||
///
|
||||
/// @param d the diff node being visited.
|
||||
@ -74,15 +150,8 @@ harmless_filter::visit(diff* d, bool pre)
|
||||
decl_base_sptr f = d->first_subject(),
|
||||
s = d->second_subject();
|
||||
|
||||
if (!is_member_decl(f)
|
||||
&& !is_member_decl(s))
|
||||
return true;
|
||||
|
||||
access_specifier fa = get_member_access_specifier(f),
|
||||
sa = get_member_access_specifier(s);
|
||||
|
||||
if (sa != fa)
|
||||
d->add_to_category(ACCESS_CHANGED_CATEGORY);
|
||||
if (access_changed(f, s))
|
||||
d->add_to_category(ACCESS_CHANGE_CATEGORY);
|
||||
// Add non-virtual member function deletions and changes due to
|
||||
// details that are being reported or got reported earlier.
|
||||
}
|
||||
@ -90,7 +159,7 @@ harmless_filter::visit(diff* d, bool pre)
|
||||
// Propagate the categorization to the parent nodes.
|
||||
if (d->get_parent())
|
||||
d->get_parent()->add_to_category(d->get_category()
|
||||
& ACCESS_CHANGED_CATEGORY);
|
||||
& ACCESS_CHANGE_CATEGORY);
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -111,23 +180,16 @@ harmful_filter::visit(diff* d, bool pre)
|
||||
{
|
||||
decl_base_sptr f = d->first_subject(),
|
||||
s = d->second_subject();
|
||||
bool size_changed = false;
|
||||
type_base_sptr tf, ts;
|
||||
|
||||
if (is_type(f) && is_type(s))
|
||||
{
|
||||
tf= is_type(f), ts = is_type(s);
|
||||
if (tf->get_size_in_bits() != ts->get_size_in_bits())
|
||||
size_changed = true;
|
||||
}
|
||||
|
||||
if (size_changed)
|
||||
d->add_to_category(SIZE_CHANGED_CATEGORY);
|
||||
if (type_size_changed(f, s)
|
||||
|| data_member_offset_changed(f, s))
|
||||
d->add_to_category(SIZE_OR_OFFSET_CHANGE_CATEGORY);
|
||||
}
|
||||
|
||||
// Propagate the categorization to the parent nodes.
|
||||
if (d->get_parent())
|
||||
d->get_parent()->add_to_category(d->get_category() & SIZE_CHANGED_CATEGORY);
|
||||
d->get_parent()->add_to_category(d->get_category()
|
||||
& SIZE_OR_OFFSET_CHANGE_CATEGORY);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -37,6 +37,16 @@ using std::vector;
|
||||
using std::tr1::dynamic_pointer_cast;
|
||||
using std::tr1::static_pointer_cast;
|
||||
|
||||
/// A deleter for shared pointers that ... doesn't delete the object
|
||||
/// managed by the shared pointer.
|
||||
struct noop_deleter
|
||||
{
|
||||
template<typename T>
|
||||
void
|
||||
operator()(T*)
|
||||
{}
|
||||
};
|
||||
|
||||
/// Convenience typedef for a pair of decls.
|
||||
typedef std::pair<const decl_base_sptr, const decl_base_sptr> decls_type;
|
||||
|
||||
@ -902,6 +912,10 @@ represent(var_decl_sptr o,
|
||||
ostream& out,
|
||||
const string& indent = "")
|
||||
{
|
||||
diff_sptr diff = compute_diff_for_decls(o, n, ctxt);
|
||||
if (!diff->to_be_reported())
|
||||
return;
|
||||
|
||||
bool emitted = false;
|
||||
string name = o->get_qualified_name();
|
||||
string name2 = n->get_qualified_name();
|
||||
@ -1093,11 +1107,16 @@ enum diff_kind
|
||||
/// header.
|
||||
static void
|
||||
report_mem_header(ostream& out,
|
||||
int number,
|
||||
size_t number,
|
||||
size_t num_filtered,
|
||||
diff_kind k,
|
||||
const string& section_name,
|
||||
const string& indent)
|
||||
{
|
||||
size_t net_number = number;
|
||||
if (k == change_kind)
|
||||
net_number = number - num_filtered;
|
||||
|
||||
string change;
|
||||
switch (k)
|
||||
{
|
||||
@ -1111,13 +1130,18 @@ report_mem_header(ostream& out,
|
||||
change = (number > 1) ? "changes" : "change";
|
||||
}
|
||||
|
||||
if (number == 0)
|
||||
out << indent << "no " << section_name << " " << change << "\n";
|
||||
else if (number == 1)
|
||||
out << indent << "1 " << section_name << " " << change << ":\n";
|
||||
if (net_number == 0)
|
||||
out << indent << "no " << section_name << " " << change;
|
||||
else if (net_number == 1)
|
||||
out << indent << "1 " << section_name << " " << change;
|
||||
else
|
||||
out << indent << number << " " << section_name
|
||||
<< " " << change << ":\n";
|
||||
out << indent << net_number << " " << section_name
|
||||
<< " " << change;
|
||||
|
||||
if (k == change_kind
|
||||
&& num_filtered)
|
||||
out << ", (" << num_filtered << " filtered)";
|
||||
out << ":\n";
|
||||
}
|
||||
|
||||
// <pointer_type_def stuff>
|
||||
@ -2040,7 +2064,7 @@ enum_diff::report(ostream& out, const string& indent) const
|
||||
|
||||
if (numdels)
|
||||
{
|
||||
report_mem_header(out, numdels, del_kind, "enumerator", indent);
|
||||
report_mem_header(out, numdels, 0, del_kind, "enumerator", indent);
|
||||
for (string_enumerator_map::const_iterator i =
|
||||
deleted_enumerators().begin();
|
||||
i != deleted_enumerators().end();
|
||||
@ -2062,7 +2086,7 @@ enum_diff::report(ostream& out, const string& indent) const
|
||||
}
|
||||
if (numins)
|
||||
{
|
||||
report_mem_header(out, numins, ins_kind, "enumerator", indent);
|
||||
report_mem_header(out, numins, 0, ins_kind, "enumerator", indent);
|
||||
for (string_enumerator_map::const_iterator i =
|
||||
inserted_enumerators().begin();
|
||||
i != inserted_enumerators().end();
|
||||
@ -2084,7 +2108,7 @@ enum_diff::report(ostream& out, const string& indent) const
|
||||
}
|
||||
if (numchanges)
|
||||
{
|
||||
report_mem_header(out, numchanges, change_kind, "enumerator", indent);
|
||||
report_mem_header(out, numchanges, 0, change_kind, "enumerator", indent);
|
||||
for (string_changed_enumerator_map::const_iterator i =
|
||||
changed_enumerators().begin();
|
||||
i != changed_enumerators().end();
|
||||
@ -2203,6 +2227,16 @@ struct class_diff::priv
|
||||
|
||||
decl_base_sptr
|
||||
member_class_tmpl_has_changed(decl_base_sptr) const;
|
||||
|
||||
size_t
|
||||
count_filtered_bases(const diff_context_sptr&);
|
||||
|
||||
size_t
|
||||
count_filtered_data_members(const diff_context_sptr&);
|
||||
|
||||
size_t
|
||||
count_filtered_member_functions(const diff_context_sptr&);
|
||||
|
||||
};//end struct class_diff::priv
|
||||
|
||||
/// Clear the lookup tables useful for reporting.
|
||||
@ -2576,6 +2610,87 @@ class_diff::priv::member_class_tmpl_has_changed(decl_base_sptr d) const
|
||||
: it->second.second);
|
||||
}
|
||||
|
||||
/// Count the number of bases classes whose changes got filtered out.
|
||||
///
|
||||
/// @param ctxt the context to use to determine the filtering settings
|
||||
/// from the user.
|
||||
///
|
||||
/// @return the number of bases classes whose changes got filtered
|
||||
/// out.
|
||||
size_t
|
||||
class_diff::priv::count_filtered_bases(const diff_context_sptr& ctxt)
|
||||
{
|
||||
size_t num_filtered = 0;
|
||||
for (string_changed_base_map::const_iterator i = changed_bases_.begin();
|
||||
i != changed_bases_.end();
|
||||
++i)
|
||||
{
|
||||
class_decl::base_spec_sptr o =
|
||||
dynamic_pointer_cast<class_decl::base_spec>(i->second.first);
|
||||
class_decl::base_spec_sptr n =
|
||||
dynamic_pointer_cast<class_decl::base_spec>(i->second.second);
|
||||
diff_sptr diff = compute_diff(o, n, ctxt);
|
||||
ctxt->maybe_apply_filters(diff);
|
||||
if (diff->is_filtered_out())
|
||||
++num_filtered;
|
||||
}
|
||||
return num_filtered;
|
||||
}
|
||||
|
||||
/// Count the number of data members whose changes got filtered out.
|
||||
///
|
||||
/// @param ctxt the diff context to use to get the filtering settings
|
||||
/// from the user.
|
||||
///
|
||||
/// @return the number of data members whose changes got filtered out.
|
||||
size_t
|
||||
class_diff::priv::count_filtered_data_members(const diff_context_sptr& ctxt)
|
||||
{
|
||||
size_t num_filtered= 0;
|
||||
for (string_changed_type_or_decl_map::const_iterator i =
|
||||
changed_data_members_.begin();
|
||||
i != changed_data_members_.end();
|
||||
++i)
|
||||
{
|
||||
var_decl_sptr o =
|
||||
dynamic_pointer_cast<var_decl>(i->second.first);
|
||||
var_decl_sptr n =
|
||||
dynamic_pointer_cast<var_decl>(i->second.second);
|
||||
diff_sptr diff = compute_diff_for_decls(o, n, ctxt);
|
||||
ctxt->maybe_apply_filters(diff);
|
||||
if (diff->is_filtered_out())
|
||||
++num_filtered;
|
||||
}
|
||||
return num_filtered;
|
||||
}
|
||||
|
||||
/// Count the number of member functions whose changes got filtered
|
||||
/// out.
|
||||
///
|
||||
/// @param ctxt the diff context to use to get the filtering settings
|
||||
/// from the user.
|
||||
///
|
||||
/// @return the number of member functions whose changes got filtered
|
||||
/// out.
|
||||
size_t
|
||||
class_diff::priv::count_filtered_member_functions(const diff_context_sptr& ctxt)
|
||||
{
|
||||
size_t num_filtered = 0;
|
||||
for (string_changed_member_function_sptr_map::const_iterator i =
|
||||
changed_member_functions_.begin();
|
||||
i != changed_member_functions_.end();
|
||||
++i)
|
||||
{
|
||||
class_decl::method_decl_sptr f = i->second.first;
|
||||
class_decl::method_decl_sptr s = i->second.second;
|
||||
diff_sptr diff = compute_diff_for_decls(f, s, ctxt);
|
||||
ctxt->maybe_apply_filters(diff);
|
||||
if (diff->is_filtered_out())
|
||||
++num_filtered;
|
||||
}
|
||||
return num_filtered;
|
||||
}
|
||||
|
||||
/// Constructor of class_diff
|
||||
///
|
||||
/// @param first_scope the first class of the diff.
|
||||
@ -2721,11 +2836,11 @@ class_diff::report(ostream& out, const string& indent) const
|
||||
{
|
||||
// Report deletions.
|
||||
int numdels = priv_->deleted_bases_.size();
|
||||
int numchanges = priv_->changed_bases_.size();
|
||||
size_t numchanges = priv_->changed_bases_.size();
|
||||
|
||||
if (numdels)
|
||||
{
|
||||
report_mem_header(out, numdels, del_kind,
|
||||
report_mem_header(out, numdels, 0, del_kind,
|
||||
"base class", indent);
|
||||
|
||||
for (string_base_sptr_map::const_iterator i
|
||||
@ -2745,10 +2860,12 @@ class_diff::report(ostream& out, const string& indent) const
|
||||
}
|
||||
out << "\n\n";
|
||||
}
|
||||
|
||||
// Report changes.
|
||||
size_t num_filtered = priv_->count_filtered_bases(context());
|
||||
if (numchanges)
|
||||
{
|
||||
report_mem_header(out, numchanges, change_kind,
|
||||
report_mem_header(out, numchanges, num_filtered, change_kind,
|
||||
"base class", indent);
|
||||
for (string_changed_base_map::const_iterator it =
|
||||
priv_->changed_bases_.begin();
|
||||
@ -2772,7 +2889,7 @@ class_diff::report(ostream& out, const string& indent) const
|
||||
int numins = priv_->inserted_bases_.size();
|
||||
if (numins)
|
||||
{
|
||||
report_mem_header(out, numins, ins_kind,
|
||||
report_mem_header(out, numins, 0, ins_kind,
|
||||
"base class", indent);
|
||||
|
||||
bool emitted = false;
|
||||
@ -2800,7 +2917,7 @@ class_diff::report(ostream& out, const string& indent) const
|
||||
// report deletions
|
||||
if (numdels)
|
||||
{
|
||||
report_mem_header(out, numdels, del_kind,
|
||||
report_mem_header(out, numdels, 0, del_kind,
|
||||
"member type", indent);
|
||||
|
||||
for (string_decl_base_sptr_map::const_iterator i =
|
||||
@ -2820,7 +2937,7 @@ class_diff::report(ostream& out, const string& indent) const
|
||||
// report changes
|
||||
if (numchanges)
|
||||
{
|
||||
report_mem_header(out, numchanges, change_kind,
|
||||
report_mem_header(out, numchanges, 0, change_kind,
|
||||
"member type", indent);
|
||||
|
||||
for (string_changed_type_or_decl_map::const_iterator it =
|
||||
@ -2846,7 +2963,7 @@ class_diff::report(ostream& out, const string& indent) const
|
||||
|
||||
if (numins)
|
||||
{
|
||||
report_mem_header(out, numins, ins_kind,
|
||||
report_mem_header(out, numins, 0, ins_kind,
|
||||
"member type", indent);
|
||||
|
||||
bool emitted = false;
|
||||
@ -2883,11 +3000,9 @@ class_diff::report(ostream& out, const string& indent) const
|
||||
{
|
||||
// report deletions
|
||||
int numdels = priv_->deleted_data_members_.size();
|
||||
int numchanges = priv_->changed_data_members_.size();
|
||||
|
||||
if (numdels)
|
||||
{
|
||||
report_mem_header(out, numdels, del_kind,
|
||||
report_mem_header(out, numdels, 0, del_kind,
|
||||
"data member", indent);
|
||||
bool emitted = false;
|
||||
for (string_decl_base_sptr_map::const_iterator i =
|
||||
@ -2907,10 +3022,12 @@ class_diff::report(ostream& out, const string& indent) const
|
||||
}
|
||||
|
||||
// report change
|
||||
size_t numchanges = priv_->changed_data_members_.size();
|
||||
size_t num_filtered = priv_->count_filtered_data_members(context());
|
||||
if (numchanges)
|
||||
{
|
||||
report_mem_header(out, numchanges, change_kind,
|
||||
"data member", indent);
|
||||
report_mem_header(out, numchanges, num_filtered,
|
||||
change_kind, "data member", indent);
|
||||
|
||||
for (string_changed_type_or_decl_map::const_iterator it =
|
||||
priv_->changed_data_members_.begin();
|
||||
@ -2930,7 +3047,7 @@ class_diff::report(ostream& out, const string& indent) const
|
||||
int numins = priv_->inserted_data_members_.size();
|
||||
if (numins)
|
||||
{
|
||||
report_mem_header(out, numins, ins_kind,
|
||||
report_mem_header(out, numins, 0, ins_kind,
|
||||
"data member", indent);
|
||||
bool emitted = false;
|
||||
for (string_decl_base_sptr_map::const_iterator i =
|
||||
@ -2958,7 +3075,7 @@ class_diff::report(ostream& out, const string& indent) const
|
||||
// report deletions
|
||||
int numdels = priv_->deleted_member_functions_.size();
|
||||
if (numdels)
|
||||
report_mem_header(out, numdels, del_kind,
|
||||
report_mem_header(out, numdels, 0, del_kind,
|
||||
"member function", indent);
|
||||
for (string_member_function_sptr_map::const_iterator i =
|
||||
priv_->deleted_member_functions_.begin();
|
||||
@ -2977,7 +3094,7 @@ class_diff::report(ostream& out, const string& indent) const
|
||||
// report insertions;
|
||||
int numins = priv_->inserted_member_functions_.size();
|
||||
if (numins)
|
||||
report_mem_header(out, numins, ins_kind,
|
||||
report_mem_header(out, numins, 0, ins_kind,
|
||||
"member function", indent);
|
||||
bool emitted = false;
|
||||
for (string_member_function_sptr_map::const_iterator i =
|
||||
@ -2997,8 +3114,9 @@ class_diff::report(ostream& out, const string& indent) const
|
||||
|
||||
// report function sub-types changes
|
||||
int numchanges = priv_->changed_member_functions_.size();
|
||||
size_t num_filtered = priv_->count_filtered_member_functions(context());
|
||||
if (numchanges)
|
||||
report_mem_header(out, numchanges, change_kind,
|
||||
report_mem_header(out, numchanges, num_filtered, change_kind,
|
||||
"member function", indent);
|
||||
for (string_changed_member_function_sptr_map::const_iterator i =
|
||||
priv_->changed_member_functions_.begin();
|
||||
@ -3008,21 +3126,13 @@ class_diff::report(ostream& out, const string& indent) const
|
||||
class_decl::method_decl_sptr f = i->second.first;
|
||||
class_decl::method_decl_sptr s = i->second.second;
|
||||
diff_sptr diff = compute_diff_for_decls(f, s, context());
|
||||
if (!diff)
|
||||
if (!diff || !diff->to_be_reported())
|
||||
continue;
|
||||
|
||||
string repr = f->get_pretty_representation();
|
||||
if (i !=priv_->changed_member_functions_.begin())
|
||||
out << "\n";
|
||||
if (!diff->to_be_reported())
|
||||
{
|
||||
out << indent << " " << repr
|
||||
<< " has some filtered out sub-type changes\n";
|
||||
continue;
|
||||
}
|
||||
|
||||
out << indent << " '"
|
||||
<< repr << "' has some sub-type changes:\n";
|
||||
out << indent << " '" << repr << "' has some sub-type changes:\n";
|
||||
diff->report(out, indent + " ");
|
||||
emitted = true;
|
||||
}
|
||||
@ -3036,7 +3146,7 @@ class_diff::report(ostream& out, const string& indent) const
|
||||
// report deletions
|
||||
int numdels = e.num_deletions();
|
||||
if (numdels)
|
||||
report_mem_header(out, numdels, del_kind,
|
||||
report_mem_header(out, numdels, 0, del_kind,
|
||||
"member function template", indent);
|
||||
for (vector<deletion>::const_iterator i = e.deletions().begin();
|
||||
i != e.deletions().end();
|
||||
@ -3056,7 +3166,7 @@ class_diff::report(ostream& out, const string& indent) const
|
||||
// report insertions
|
||||
int numins = e.num_insertions();
|
||||
if (numins)
|
||||
report_mem_header(out, numins, ins_kind,
|
||||
report_mem_header(out, numins, 0, ins_kind,
|
||||
"member function template", indent);
|
||||
bool emitted = false;
|
||||
for (vector<insertion>::const_iterator i = e.insertions().begin();
|
||||
@ -3089,7 +3199,7 @@ class_diff::report(ostream& out, const string& indent) const
|
||||
// report deletions
|
||||
int numdels = e.num_deletions();
|
||||
if (numdels)
|
||||
report_mem_header(out, numdels, del_kind,
|
||||
report_mem_header(out, numdels, 0, del_kind,
|
||||
"member class template", indent);
|
||||
for (vector<deletion>::const_iterator i = e.deletions().begin();
|
||||
i != e.deletions().end();
|
||||
@ -3109,7 +3219,7 @@ class_diff::report(ostream& out, const string& indent) const
|
||||
// report insertions
|
||||
int numins = e.num_insertions();
|
||||
if (numins)
|
||||
report_mem_header(out, numins, ins_kind,
|
||||
report_mem_header(out, numins, 0, ins_kind,
|
||||
"member class template", indent);
|
||||
bool emitted = false;
|
||||
for (vector<insertion>::const_iterator i = e.insertions().begin();
|
||||
@ -4890,7 +5000,7 @@ compute_diff(const translation_unit_sptr first,
|
||||
// <corpus stuff>
|
||||
struct corpus_diff::priv
|
||||
{
|
||||
diff_context_sptr ctxt_;
|
||||
diff_context_sptr ctxt_;
|
||||
corpus_sptr first_;
|
||||
corpus_sptr second_;
|
||||
edit_script fns_edit_script_;
|
||||
@ -4911,8 +5021,36 @@ struct corpus_diff::priv
|
||||
void
|
||||
ensure_lookup_tables_populated();
|
||||
|
||||
struct diff_stats
|
||||
{
|
||||
size_t num_func_removed;
|
||||
size_t num_func_added;
|
||||
size_t num_func_changed;
|
||||
size_t num_func_filtered_out;
|
||||
size_t num_vars_removed;
|
||||
size_t num_vars_added;
|
||||
size_t num_vars_changed;
|
||||
size_t num_vars_filtered_out;
|
||||
|
||||
diff_stats()
|
||||
: num_func_removed(0),
|
||||
num_func_added(0),
|
||||
num_func_changed(0),
|
||||
num_func_filtered_out(0),
|
||||
num_vars_removed(0),
|
||||
num_vars_added(0),
|
||||
num_vars_changed(0),
|
||||
num_vars_filtered_out(0)
|
||||
{}
|
||||
};
|
||||
|
||||
void
|
||||
emit_corpus_diff_stats(ostream& out, const string& indent);
|
||||
apply_filters_and_compute_diff_stats(diff_stats&);
|
||||
|
||||
void
|
||||
emit_diff_stats(diff_stats& stats,
|
||||
ostream& out,
|
||||
const string& indent);
|
||||
}; // end corpus::priv
|
||||
|
||||
/// Tests if the lookup tables are empty.
|
||||
@ -5049,6 +5187,60 @@ corpus_diff::priv::ensure_lookup_tables_populated()
|
||||
}
|
||||
}
|
||||
|
||||
/// Compute the diff stats.
|
||||
///
|
||||
/// To know the number of functions that got filtered out, this
|
||||
/// function applies the categorizing filters to the diff sub-trees of
|
||||
/// each function changes diff, prior to calculating the stats.
|
||||
///
|
||||
/// @param num_removed the number of removed functions.
|
||||
///
|
||||
/// @param num_added the number of added functions.
|
||||
///
|
||||
/// @param num_changed the number of changed functions.
|
||||
///
|
||||
/// @param num_filtered_out the number of changed functions that are
|
||||
/// got filtered out from the report
|
||||
void
|
||||
corpus_diff::priv::apply_filters_and_compute_diff_stats(diff_stats& stat)
|
||||
|
||||
{
|
||||
stat.num_func_removed = deleted_fns_.size();
|
||||
stat.num_func_added = added_fns_.size();
|
||||
stat.num_func_changed = changed_fns_.size();
|
||||
|
||||
stat.num_vars_removed = deleted_vars_.size();
|
||||
stat.num_vars_added = added_vars_.size();
|
||||
stat.num_vars_changed = changed_vars_.size();
|
||||
|
||||
// Calculate number of filtered functions & variables.
|
||||
diff_sptr diff;
|
||||
for (string_changed_function_ptr_map::const_iterator i =
|
||||
changed_fns_.begin();
|
||||
i != changed_fns_.end();
|
||||
++i)
|
||||
{
|
||||
function_decl_sptr f(i->second.first, noop_deleter());
|
||||
function_decl_sptr s(i->second.second, noop_deleter());
|
||||
diff = compute_diff_for_decls(f, s, ctxt_);
|
||||
ctxt_->maybe_apply_filters(diff);
|
||||
if (diff->is_filtered_out())
|
||||
++stat.num_func_filtered_out;
|
||||
}
|
||||
|
||||
for (string_changed_var_ptr_map::const_iterator i = changed_vars_.begin();
|
||||
i != changed_vars_.end();
|
||||
++i)
|
||||
{
|
||||
var_decl_sptr f(i->second.first, noop_deleter());
|
||||
var_decl_sptr s(i->second.second, noop_deleter());
|
||||
diff = compute_diff_for_decls(f, s, ctxt_);
|
||||
ctxt_->maybe_apply_filters(diff);
|
||||
if (diff->is_filtered_out())
|
||||
++stat.num_vars_filtered_out;
|
||||
}
|
||||
}
|
||||
|
||||
/// Emit the summary of the functions & variables that got
|
||||
/// removed/changed/added.
|
||||
///
|
||||
@ -5056,37 +5248,38 @@ corpus_diff::priv::ensure_lookup_tables_populated()
|
||||
///
|
||||
/// @param indent the indentation string to use in the summary.
|
||||
void
|
||||
corpus_diff::priv::emit_corpus_diff_stats(ostream& out, const string& indent)
|
||||
corpus_diff::priv::emit_diff_stats(diff_stats& s,
|
||||
ostream& out,
|
||||
const string& indent)
|
||||
{
|
||||
unsigned total = 0, num_removed = 0, num_added = 0, num_changed = 0;
|
||||
|
||||
/// Report added/removed/changed functions.
|
||||
num_removed = deleted_fns_.size();
|
||||
num_added = added_fns_.size();
|
||||
num_changed = changed_fns_.size();
|
||||
total = num_removed + num_added + num_changed;
|
||||
size_t total = s.num_func_removed + s.num_func_added +
|
||||
s.num_func_changed - s.num_func_filtered_out;
|
||||
|
||||
// function changes summary
|
||||
out << indent << "Functions changes summary: ";
|
||||
out << num_removed << " Removed, ";
|
||||
out << num_changed << " Changed, ";
|
||||
out << num_added << " Added ";
|
||||
out << s.num_func_removed << " Removed, ";
|
||||
out << s.num_func_changed - s.num_func_filtered_out << " Changed";
|
||||
if (s.num_func_filtered_out)
|
||||
out << " (" << s.num_func_filtered_out << " filtered out)";
|
||||
out << ", ";
|
||||
out << s.num_func_added << " Added ";
|
||||
if (total <= 1)
|
||||
out << "function\n";
|
||||
else
|
||||
out << "functions\n";
|
||||
|
||||
// Report added/removed/changed variables.
|
||||
num_removed = deleted_vars_.size();
|
||||
num_added = added_vars_.size();
|
||||
num_changed = changed_vars_.size();
|
||||
total = num_removed + num_added + num_changed;
|
||||
total = s.num_vars_removed + s.num_vars_added +
|
||||
s.num_vars_changed - s.num_vars_filtered_out;
|
||||
|
||||
// variables changes summary
|
||||
out << indent << "Variables changes summary: ";
|
||||
out << num_removed << " Removed, ";
|
||||
out << num_changed << " Changed, ";
|
||||
out << num_added << " Added ";
|
||||
out << s.num_vars_removed << " Removed, ";
|
||||
out << s.num_vars_changed - s.num_vars_filtered_out<< " Changed";
|
||||
if (s.num_vars_filtered_out)
|
||||
out << " (" << s.num_vars_filtered_out << " filtered out)";
|
||||
out << ", ";
|
||||
out << s.num_vars_added << " Added ";
|
||||
if (total <= 1)
|
||||
out << "variable\n";
|
||||
else
|
||||
@ -5171,16 +5364,6 @@ corpus_diff::length() const
|
||||
- priv_->changed_fns_.size());
|
||||
}
|
||||
|
||||
/// A deleter for shared pointers that ... doesn't delete the object
|
||||
/// managed by the shared pointer.
|
||||
struct noop_deleter
|
||||
{
|
||||
template<typename T>
|
||||
void
|
||||
operator()(T*)
|
||||
{}
|
||||
};
|
||||
|
||||
/// Report the diff in a serialized form.
|
||||
///
|
||||
/// @param out the stream to serialize the diff to.
|
||||
@ -5190,28 +5373,26 @@ struct noop_deleter
|
||||
void
|
||||
corpus_diff::report(ostream& out, const string& indent) const
|
||||
{
|
||||
unsigned total = 0, num_removed = 0, num_added = 0, num_changed = 0;
|
||||
unsigned removed = 0, added = 0;
|
||||
size_t total = 0, removed = 0, added = 0;
|
||||
priv::diff_stats s;
|
||||
|
||||
/// Report added/removed/changed functions.
|
||||
num_removed = priv_->deleted_fns_.size();
|
||||
num_added = priv_->added_fns_.size();
|
||||
num_changed = priv_->changed_fns_.size();
|
||||
total = num_removed + num_added + num_changed;
|
||||
priv_->apply_filters_and_compute_diff_stats(s);
|
||||
total = s.num_func_removed + s.num_func_added +
|
||||
s.num_func_changed - s.num_func_filtered_out;
|
||||
const unsigned large_num = 100;
|
||||
|
||||
priv_->emit_corpus_diff_stats(out, indent);
|
||||
priv_->emit_diff_stats(s, out, indent);
|
||||
if (context()->show_stats_only())
|
||||
return;
|
||||
out << "\n";
|
||||
|
||||
|
||||
if (context()->show_deleted_fns())
|
||||
{
|
||||
if (num_removed == 1)
|
||||
if (s.num_func_removed == 1)
|
||||
out << indent << "1 Removed function:\n\n";
|
||||
else if (num_removed > 1)
|
||||
out << indent << num_removed << " Removed functions:\n\n";
|
||||
else if (s.num_func_removed > 1)
|
||||
out << indent << s.num_func_removed << " Removed functions:\n\n";
|
||||
|
||||
for (string_function_ptr_map::const_iterator i =
|
||||
priv_->deleted_fns_.begin();
|
||||
@ -5232,6 +5413,7 @@ corpus_diff::report(ostream& out, const string& indent) const
|
||||
|
||||
if (context()->show_changed_fns())
|
||||
{
|
||||
size_t num_changed = s.num_func_changed - s.num_func_filtered_out;
|
||||
if (num_changed == 1)
|
||||
out << indent << "1 function with some indirect sub-type change:\n\n";
|
||||
else if (num_changed > 1)
|
||||
@ -5250,7 +5432,6 @@ corpus_diff::report(ostream& out, const string& indent) const
|
||||
if (!diff)
|
||||
continue;
|
||||
|
||||
context()->maybe_apply_filters(diff);
|
||||
if (diff->to_be_reported())
|
||||
{
|
||||
out << indent << " [C]'"
|
||||
@ -5258,23 +5439,16 @@ corpus_diff::report(ostream& out, const string& indent) const
|
||||
<< "' has some indirect sub-type changes:\n";
|
||||
diff->report(out, indent + " ");
|
||||
}
|
||||
else if (diff->is_filtered_out())
|
||||
{
|
||||
out << indent << " [C]{F}'"
|
||||
<< i->second.first->get_pretty_representation()
|
||||
<< "' has some filtered out sub-type changes\n";
|
||||
}
|
||||
}
|
||||
if (priv_->changed_fns_.size())
|
||||
out << "\n";
|
||||
out << "\n";
|
||||
}
|
||||
|
||||
if (context()->show_added_fns())
|
||||
{
|
||||
if (num_added == 1)
|
||||
if (s.num_func_added == 1)
|
||||
out << indent << "1 Added function:\n";
|
||||
else if (num_added > 1)
|
||||
out << indent << num_added
|
||||
else if (s.num_func_added > 1)
|
||||
out << indent << s.num_func_added
|
||||
<< " Added functions:\n\n";
|
||||
for (string_function_ptr_map::const_iterator i =
|
||||
priv_->added_fns_.begin();
|
||||
@ -5295,17 +5469,15 @@ corpus_diff::report(ostream& out, const string& indent) const
|
||||
}
|
||||
|
||||
// Report added/removed/changed variables.
|
||||
num_removed = priv_->deleted_vars_.size();
|
||||
num_added = priv_->added_vars_.size();
|
||||
num_changed = priv_->changed_vars_.size();
|
||||
total = num_removed + num_added + num_changed;
|
||||
total = s.num_vars_removed + s.num_vars_added +
|
||||
s.num_vars_changed - s.num_vars_filtered_out;
|
||||
|
||||
if (context()->show_deleted_vars())
|
||||
{
|
||||
if (num_removed == 1)
|
||||
if (s.num_vars_removed == 1)
|
||||
out << indent << "1 Deleted variable:\n";
|
||||
else if (num_removed > 1)
|
||||
out << indent << num_removed
|
||||
else if (s.num_vars_removed > 1)
|
||||
out << indent << s.num_vars_removed
|
||||
<< " Deleted variables:\n\n";
|
||||
string n;
|
||||
for (string_var_ptr_map::const_iterator i =
|
||||
@ -5331,6 +5503,7 @@ corpus_diff::report(ostream& out, const string& indent) const
|
||||
|
||||
if (context()->show_changed_vars())
|
||||
{
|
||||
size_t num_changed = s.num_vars_changed - s.num_vars_filtered_out;
|
||||
if (num_changed == 1)
|
||||
out << indent << "1 Changed variable:\n";
|
||||
else if (num_changed > 1)
|
||||
@ -5342,42 +5515,39 @@ corpus_diff::report(ostream& out, const string& indent) const
|
||||
i != priv_->changed_vars_.end();
|
||||
++i)
|
||||
{
|
||||
if (!i->second.first->get_mangled_name().empty())
|
||||
n1 =
|
||||
demangle_cplus_mangled_name(i->second.first->get_mangled_name());
|
||||
else
|
||||
n1 = i->second.first->get_pretty_representation();
|
||||
var_decl_sptr f(i->second.first, noop_deleter());
|
||||
var_decl_sptr s(i->second.second, noop_deleter());
|
||||
diff_sptr diff = compute_diff_for_decls(f, s, context());
|
||||
if (!diff || !diff->to_be_reported())
|
||||
continue;
|
||||
|
||||
if (!i->second.second->get_mangled_name().empty())
|
||||
n2 =
|
||||
demangle_cplus_mangled_name(i->second.second->get_mangled_name());
|
||||
if (!f->get_mangled_name().empty())
|
||||
n1 = demangle_cplus_mangled_name(f->get_mangled_name());
|
||||
else
|
||||
n2 = i->second.second->get_pretty_representation();
|
||||
n1 = f->get_pretty_representation();
|
||||
|
||||
if (!s->get_mangled_name().empty())
|
||||
n2 = demangle_cplus_mangled_name(s->get_mangled_name());
|
||||
else
|
||||
n2 = s->get_pretty_representation();
|
||||
|
||||
out << indent << " '"
|
||||
<< n1
|
||||
<< "' was changed to '"
|
||||
<< n2
|
||||
<< "':\n";
|
||||
{
|
||||
var_decl_sptr f(i->second.first, noop_deleter());
|
||||
var_decl_sptr s(i->second.second, noop_deleter());
|
||||
|
||||
diff_sptr diff = compute_diff_for_decls(f, s, context());
|
||||
if (diff)
|
||||
diff->report(out, indent + " ");
|
||||
}
|
||||
diff->report(out, indent + " ");
|
||||
}
|
||||
if (priv_->changed_vars_.size())
|
||||
if (num_changed)
|
||||
out << "\n";
|
||||
}
|
||||
|
||||
if (context()->show_added_vars())
|
||||
{
|
||||
if (num_added == 1)
|
||||
if (s.num_vars_added == 1)
|
||||
out << indent << "1 Added variable:\n";
|
||||
else if (num_added > 1)
|
||||
out << indent << num_added
|
||||
else if (s.num_vars_added > 1)
|
||||
out << indent << s.num_vars_added
|
||||
<< " Added variables:\n";
|
||||
string n;
|
||||
for (string_var_ptr_map::const_iterator i =
|
||||
|
@ -7,6 +7,7 @@ runtestreaddwarf \
|
||||
runtestcorediff \
|
||||
runtestbidiff \
|
||||
runtestdiffdwarf \
|
||||
runtestdifffilter \
|
||||
runtestsvg \
|
||||
runtestdot
|
||||
|
||||
@ -43,6 +44,9 @@ runtestbidiff_LDADD = libtestutils.la $(top_builddir)/src/libabigail.la
|
||||
runtestdiffdwarf_SOURCES = $(h)/test-diff-dwarf.cc
|
||||
runtestdiffdwarf_LDADD = libtestutils.la $(top_builddir)/src/libabigail.la
|
||||
|
||||
runtestdifffilter_SOURCES = $(h)/test-diff-filter.cc
|
||||
runtestdifffilter_LDADD = libtestutils.la $(top_builddir)/src/libabigail.la
|
||||
|
||||
runtestsvg_SOURCES=$(h)/test-svg.cc
|
||||
runtestsvg_LDADD=$(top_builddir)/src/libabigail.la
|
||||
|
||||
@ -124,7 +128,14 @@ data/test-read-dwarf/test0.abi \
|
||||
data/test-read-dwarf/test0.cc \
|
||||
data/test-read-dwarf/test1 \
|
||||
data/test-read-dwarf/test1.abi \
|
||||
data/test-read-dwarf/test1.cc
|
||||
data/test-read-dwarf/test1.cc \
|
||||
\
|
||||
data/test-diff-filter/test0-v0.cc \
|
||||
data/test-diff-filter/test0-v1.cc \
|
||||
data/test-diff-filter/test0-v0.o \
|
||||
data/test-diff-filter/test0-v1.o \
|
||||
data/test-diff-filter/test0-report.txt
|
||||
|
||||
|
||||
clean-local: clean-local-check
|
||||
.PHONY: clean-local-check
|
||||
|
32
tests/data/test-diff-filter/test0-report.txt
Normal file
32
tests/data/test-diff-filter/test0-report.txt
Normal file
@ -0,0 +1,32 @@
|
||||
Functions changes summary: 0 Removed, 1 Changed (2 filtered out), 1 Added functions
|
||||
Variables changes summary: 0 Removed, 0 Changed, 0 Added variable
|
||||
|
||||
1 function with some indirect sub-type change:
|
||||
|
||||
[C]'function void foo(const S0&, S1*)' has some indirect sub-type changes:
|
||||
parameter 0 of type 'const S0&' changed:
|
||||
in unqualified underlying type 'S0&':
|
||||
in referenced type 'class S0':
|
||||
size changed from 96 to 128 bits
|
||||
1 base class change:
|
||||
'class B0S0' changed:
|
||||
size changed from 64 to 96 bits
|
||||
1 data member change:
|
||||
'char B0S0::m1' offset changed from 32 to 64
|
||||
|
||||
1 data member insertion:
|
||||
'unsigned int B0S0::m2', at offset 32 (in bits)
|
||||
|
||||
|
||||
1 data member change:
|
||||
'int S0::m0' offset changed from 64 to 96, access changed from 'private' to 'protected'
|
||||
|
||||
1 member function insertion:
|
||||
'method int S0::get_member0()'
|
||||
no member function change, (1 filtered):
|
||||
|
||||
|
||||
1 Added function:
|
||||
'method int S0::get_member0()
|
||||
|
||||
|
50
tests/data/test-diff-filter/test0-v0.cc
Normal file
50
tests/data/test-diff-filter/test0-v0.cc
Normal file
@ -0,0 +1,50 @@
|
||||
class B0S0
|
||||
{
|
||||
int m0;
|
||||
char m1;
|
||||
|
||||
public:
|
||||
void
|
||||
member0() const
|
||||
{}
|
||||
|
||||
static void
|
||||
static_member0();
|
||||
};
|
||||
|
||||
void
|
||||
B0S0::static_member0()
|
||||
{
|
||||
}
|
||||
|
||||
class B0S1
|
||||
{
|
||||
int m0;
|
||||
|
||||
public:
|
||||
B0S1()
|
||||
{}
|
||||
};
|
||||
|
||||
class S0 : public B0S0
|
||||
{
|
||||
int m0;
|
||||
void
|
||||
member0() const
|
||||
{}
|
||||
};
|
||||
|
||||
class S1 : public B0S1
|
||||
{
|
||||
int m0;
|
||||
void member0()
|
||||
{}
|
||||
};
|
||||
|
||||
void
|
||||
foo(S0&, S1*)
|
||||
{}
|
||||
|
||||
void
|
||||
bar(S1&)
|
||||
{}
|
BIN
tests/data/test-diff-filter/test0-v0.o
Normal file
BIN
tests/data/test-diff-filter/test0-v0.o
Normal file
Binary file not shown.
60
tests/data/test-diff-filter/test0-v1.cc
Normal file
60
tests/data/test-diff-filter/test0-v1.cc
Normal file
@ -0,0 +1,60 @@
|
||||
class B0S0
|
||||
{
|
||||
int m0;
|
||||
unsigned m2;
|
||||
char m1;
|
||||
|
||||
public:
|
||||
void
|
||||
member0() const
|
||||
{}
|
||||
|
||||
static void
|
||||
static_member0();
|
||||
};
|
||||
|
||||
void
|
||||
B0S0::static_member0()
|
||||
{
|
||||
}
|
||||
|
||||
class B0S1
|
||||
{
|
||||
int m0;
|
||||
|
||||
public:
|
||||
B0S1()
|
||||
{}
|
||||
};
|
||||
|
||||
class S0 : public B0S0
|
||||
{
|
||||
protected:
|
||||
int m0;
|
||||
|
||||
public:
|
||||
void
|
||||
member0() const
|
||||
{}
|
||||
|
||||
int
|
||||
get_member0() const
|
||||
{return m0;}
|
||||
};
|
||||
|
||||
class S1 : public B0S1
|
||||
{
|
||||
int m0;
|
||||
|
||||
public:
|
||||
void member0()
|
||||
{}
|
||||
};
|
||||
|
||||
void
|
||||
foo(S0&, S1*)
|
||||
{}
|
||||
|
||||
void
|
||||
bar(S1&)
|
||||
{}
|
BIN
tests/data/test-diff-filter/test0-v1.o
Normal file
BIN
tests/data/test-diff-filter/test0-v1.o
Normal file
Binary file not shown.
118
tests/test-diff-filter.cc
Normal file
118
tests/test-diff-filter.cc
Normal file
@ -0,0 +1,118 @@
|
||||
// -*- 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/>.
|
||||
|
||||
// Author: Dodji Seketeli
|
||||
|
||||
/// @file
|
||||
///
|
||||
/// This program runs a diff between input ELF files containing DWARF
|
||||
/// debugging information and compares the resulting report with a
|
||||
/// reference report. If the resulting report is different from the
|
||||
/// reference report, the test has failed. Note that the comparison
|
||||
/// is done using the bidiff command line comparison tool.
|
||||
///
|
||||
/// The set of input files and reference reports to consider should be
|
||||
/// present in the source distribution.
|
||||
|
||||
#include <string>
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <cstdlib>
|
||||
#include "abg-tools-utils.h"
|
||||
#include "test-utils.h"
|
||||
|
||||
using std::string;
|
||||
using std::cerr;
|
||||
|
||||
/// This is an aggregate that specifies where a test shall get its
|
||||
/// input from and where it shall write its ouput to.
|
||||
struct InOutSpec
|
||||
{
|
||||
const char* in_elfv0_path;
|
||||
const char* in_elfv1_path;
|
||||
const char* bidiff_options;
|
||||
const char* in_report_path;
|
||||
const char* out_report_path;
|
||||
}; // end struct InOutSpec;
|
||||
|
||||
InOutSpec in_out_specs[] =
|
||||
{
|
||||
{
|
||||
"data/test-diff-filter/test0-v0.o",
|
||||
"data/test-diff-filter/test0-v1.o",
|
||||
"--no-harmless",
|
||||
"data/test-diff-filter/test0-report.txt",
|
||||
"output/test-diff-filter/test0-report.txt",
|
||||
},
|
||||
// This should be the last entry
|
||||
{NULL, NULL, NULL, NULL, NULL}
|
||||
};
|
||||
|
||||
int
|
||||
main()
|
||||
{
|
||||
using abigail::tests::get_src_dir;
|
||||
using abigail::tests::get_build_dir;
|
||||
using abigail::tools::ensure_parent_dir_created;
|
||||
|
||||
bool is_ok = true;
|
||||
string in_elfv0_path, in_elfv1_path,
|
||||
bidiff_options, bidiff, cmd,
|
||||
ref_diff_report_path, out_diff_report_path;
|
||||
|
||||
for (InOutSpec* s = in_out_specs; s->in_elfv0_path; ++s)
|
||||
{
|
||||
in_elfv0_path = get_src_dir() + "/tests/" + s->in_elfv0_path;
|
||||
in_elfv1_path = get_src_dir() + "/tests/" + s->in_elfv1_path;
|
||||
bidiff_options = s->bidiff_options;
|
||||
ref_diff_report_path = get_src_dir() + "/tests/" + s->in_report_path;
|
||||
out_diff_report_path = get_build_dir() + "/tests/" + s->out_report_path;
|
||||
|
||||
if (!ensure_parent_dir_created(out_diff_report_path))
|
||||
{
|
||||
cerr << "could not create parent directory for "
|
||||
<< out_diff_report_path;
|
||||
is_ok = false;
|
||||
continue;
|
||||
}
|
||||
|
||||
bidiff = get_build_dir() + "/tools/bidiff";
|
||||
bidiff += " " + bidiff_options;
|
||||
|
||||
cmd = bidiff + " " + in_elfv0_path + " " + in_elfv1_path;
|
||||
cmd += " > " + out_diff_report_path;
|
||||
|
||||
bool bidiff_ok = true;
|
||||
if (system(cmd.c_str()))
|
||||
bidiff_ok = false;
|
||||
|
||||
if (bidiff_ok)
|
||||
{
|
||||
cmd = "diff -u " + ref_diff_report_path
|
||||
+ " " + out_diff_report_path;
|
||||
if (system(cmd.c_str()))
|
||||
is_ok = false;
|
||||
}
|
||||
else
|
||||
is_ok = false;
|
||||
}
|
||||
|
||||
return !is_ok;
|
||||
}
|
@ -293,9 +293,9 @@ set_diff_context_from_opts(diff_context_sptr ctxt,
|
||||
ctxt->show_added_vars(opts.show_all_vars || opts.show_added_vars);
|
||||
|
||||
if (!opts.show_harmless_changes)
|
||||
ctxt->switch_categories_off(abigail::comparison::ACCESS_CHANGED_CATEGORY);
|
||||
ctxt->switch_categories_off(abigail::comparison::ACCESS_CHANGE_CATEGORY);
|
||||
if (!opts.show_harmful_changes)
|
||||
ctxt->switch_categories_off(abigail::comparison::SIZE_CHANGED_CATEGORY);
|
||||
ctxt->switch_categories_off(abigail::comparison::SIZE_OR_OFFSET_CHANGE_CATEGORY);
|
||||
}
|
||||
|
||||
/// Set the regex patterns describing the functions to drop from the
|
||||
|
Loading…
Reference in New Issue
Block a user