mirror of
git://sourceware.org/git/libabigail.git
synced 2025-02-20 15:56:57 +00:00
Initial implementation of a --leaf-changes-only option to abidiff
This patch allows abidiff to take the --leaf-changes-only option and then to display only the changes that are local to any given type. That means the reporting agent won't follow pointers when displaying changes. That gives less context to the ABI change reports but then they are less cluttered. To do this, the patch introduces a new reporting agent to libabigail: abigail::comparison::leaf_reporter. When given a graph of diff nodes, this agent only reports about the leaf (local) changes. That is, it will *NOT* follow pointers, references, underlying types of qualified and typedef types and things like that. It will just report about changes that are local to a given type. This reporting agent is then used (in lieu of the default abigail::comparison::default_reporter agent) when the --leaf-changes-only option is provided by the user on the command line of abidiff. Note that abidiff also takes the --impacted-interfaces option to so that the leaf reporter shows the set of interfaces impacted by each leaf change. * doc/manuals/abidiff.rst: Add documentation the new --leaf-changes-only and --impacted-interfaces options. * src/abg-leaf-reporter.cc: New file. * src/Makefile.am: Add the new src/abg-leaf-reporter.cc file to source distribution. * include/abg-fwd.h (get_var_size_in_bits) (function_decl_is_less_than): Declare new functions. (get_name): Add new overload for type_or_decl_base*. * include/abg-ir.h (struct type_or_decl_hash, type_or_decl_equal) (type_or_decl_base_comp): Define new types. (artifact_sptr_set_type, artifact_ptr_set_type): Define new typedefs. * include/abg-comp-filter.h: Update copyright year. (has_basic_type_name_change): Add new function declaration. * src/abg-comp-filter.cc (decl_name_changed): Take a type_or_decl_base rather than just a decl. Add an overload for diff*. (has_basic_type_name_change): Define new function. * include/abg-comparison.h: Update copyright year. (string_diff_ptr_map): Define this new typedef. (class diff_maps): Define this new class. (diff_context::{set_corpora}): Remove this member function. (diff_context::{set_corpus_diff, get_corpus_diff, show_leaf_changes_only, show_impacted_interfaces, forbid_visiting_a_node_twice_per_interface}): Declare these new member functions. (diff_node_visitor::priv_): Add a new pimpl data member. (diff_node_visitor::{diff_node_visitor, get_visiting_kind, set_visiting_kind}): Turn these into out-of-line member functions. (diff_node_visitor::{set,get}_current_topmost_iface_diff): Add new member functions. (class {scope_diff, function_type_diff, corpus_diff}): Add class leaf_reporter as a friend. (corpus_diff::mark_leaf_diff_nodes, get_leaf_diffs): Declare new member functions. (diff::{visiting_a_node_twice_is_forbidden_per_interface, parent_interface_node}): Define new member functions. (is_diff_of_basic_type): Return a type_decl_diff* rather than just a bool. (is_enum_diff, is_array_diff, is_function_type, is_typedef_diff) (is_corpus_diff): Declare new functions. (corpus_diff::diff_stats::{num_leaf_changes, num_leaf_changes_filtered_out, net_num_leaf_changes}): Add new member functions. (is_distinct_diff): Declare new function. * include/abg-reporter.h: Forward-declare "class diff_maps". (reporter_base::diff_to_be_reported): Declare a new virtual member function. (reporter_base::{report_local_typedef_changes, report_local_reference_type_changes, report_local_function_type_changes}): Declare new member functions. (class leaf_reporter): Define new type. * src/abg-comparison-priv.h (struct diff_hash, diff_equal): Define new types. (diff_artifact_set_map_type): Define new typedef. (diff_context::priv::{first_corpus_, second_corpus_}): Remove these data members. (diff_context::priv::{corpus_diff_, leaf_changes_only_, reset_visited_diffs_for_each_interface_, show_impacted_interfaces_}): Add new data members. (diff_context::priv::priv): Adjust. (corpus_diff::priv::{leaf_diffs_, parent_interface_}): Add new data member. (corpus_diff::diff_stats::priv::{num_leaf_changes, num_leaf_changes_filtered_out}): Add new data members. (corpus_diff::priv::count_leaf_changes): Define new member function. (sort_artifacts_set, get_fn_decl_or_var_decl_diff_ancestor) (is_diff_of_global_decls): Declare new functions. (function_comp::operator()): Factorize this out into the new function abigail::ir::function_decl_is_less_than. * src/abg-ir.cc (get_var_size_in_bits) (function_decl_is_less_than): Define new functions. (get_name): Define new overload for type_or_decl_base*. * src/abg-comparison.cc (is_enum_diff, is_typedef_diff) (is_array_diff, is_function_type_diff, is_corpus_diff) (is_distinct_diff, sort_artifacts_set, is_diff_of_global_decls): Define new functions. (is_union_diff): Fix comment. (diff_context::forbid_visiting_a_node_twice_per_interface): Define new member functions. (diff_context::set_corpus_diff, get_corpus_diff) (diff_context::show_leaf_changes_only) (diff_context::visiting_a_node_twice_is_forbidden_per_interface) (diff_context::show_impacted_interfaces): Define new member functions. (diff_context::get_reporter): Create the reporter that matches what diff_context::show_leaf_changes_only says. (diff_node_visitor::priv): Define a new type. (diff_node_visitor::{diff_node_visitor, get_visiting_kind, set_visiting_kind, or_visiting_kind, set_current_topmost_iface_diff, get_current_topmost_iface_diff}): Define new out-of-line member functions. (struct diff_maps::priv): Define new type. (diff_maps::{diff_maps, get_type_decl_diff_map, get_type_decl_diff_map, get_enum_diff_map, get_class_diff_map, get_union_diff_map, get_typedef_diff_map, get_array_diff_map, get_function_type_diff_map, get_function_decl_diff_map, get_var_decl_diff_map, get_reference_diff_map, get_fn_parm_diff_map, get_distinct_diff_map, insert_diff_node, lookup_impacted_interfaces}): Define member functions. (corpus_diff::{mark_leaf_diff_nodes, get_leaf_diffs}): Define new member functions. (struct leaf_diff_node_marker_visitor): Define new type. (corpus_diff::apply_filters_and_suppressions_before_reporting): Mark diff nodes in here. (corpus_diff::traverse): Appropriately set the current topmost interface into the visitor before visiting a diff node. (compute_diff): In the overload for corpus_sptr, adjust to reflect that we are now storing the corpus_diff in the diff context. (is_diff_of_basic_type): Return a type_decl_diff*, not just a bool. (corpus_diff::priv::count_leaf_changes): Define a new member function. (corpus_diff::diff_stats::{num_leaf_changes, num_leaf_changes_filtered_out, net_num_leaf_changes}): Define new member functions. (corpus_diff::priv::apply_filters_and_compute_diff_stats): Use the new corpus_diff::priv::count_leaf_changes to compute the number of leaf changes. (corpus_diff::priv::emit_diff_stats): Emit the report about leaf type changes when necessary. * src/abg-reporter-priv.h (report_mem_header): Declare new overload. (maybe_show_relative_offset_change,): Pass the var_diff_sptr parameter by const reference. (represent): Pass the var_diff_sptr parameter by const reference and take a new "local-only" flag. (maybe_show_relative_size_change) (maybe_report_interfaces_impacted_by_diff): Declare new functions. * src/abg-default-reporter.cc: Adjust copyright year. (default_reporter::{report_local_typedef_changes, report_local_qualified_type_changes, report_local_reference_type_changes, report_local_function_type_changes}): Define new member functions. (default_reporter::report): Adjust. Add an overload for function_type_diff&. In the overload for qualified_type_diff, if the name of the underlying type changed, do not detail the changes any further. In the overload for function_decl_diff, Adjust to use the new diff_context::get_{first, second}_corpus member function. In the overload for enum_diff, call the new maybe_report_interfaces_impacted_by_diff that is advertised below. * src/abg-reporter-priv.cc (represent): Adjust the overload for var_diff_sptr. (report_mem_header): Define new overload. (maybe_show_relative_size_change) (maybe_report_interfaces_impacted_by_diff): Define new functions. (reporter_base::diff_to_be_reported): Define new member function. (maybe_show_relative_offset_change): Pass the var_diff_sptr parameter by const reference. (represent): In the overload for var_diff_sptr, pass the var_diff_sptr parameter by reference. Take a 'local_only' flag. Iisplay type changes only if we are not displaying "local changes only". Display size changes of data members too, when in "local-only" mode. * src/abg-suppression.cc (sonames_of_binaries_match) (names_of_binaries_match): Adjust. * tools/abidiff.cc (options::{leaf_changes_only, show_impacted_interfaces}): Add new data members. (display_usage): Emit usage string for the new --leaf-changes-only and --impacted-interfaces options. (parse_command_line): Parse the new --leaf-changes-only and the --impacted-interfaces options. (set_diff_context_from_opts): Set the 'show-leaf-changes' and the 'show-impacted-interfaces' flags. * tests/data/test-diff-filter/libtest42-leaf-report-v{0,1}.so: New test input. * tests/data/test-diff-filter/test42-leaf-report-output-0.txt: New test reference output. * tests/data/test-diff-filter/test42-leaf-report-v{0,1}.cc: Source code of the new test inputs. * tests/test-diff-filter.cc (in_out_specs): Use the new test inputs above in this harness. * tests/data/test-diff-suppr/libtest35-leaf-v0.so: New test input. * tests/data/test-diff-suppr/test35-leaf-report-0.txt: New test reference output. * tests/data/test-diff-suppr/test35-leaf-v{0,1}.cc: Source code of the new test inputs. * tests/data/test-diff-suppr/test35-leaf.suppr: Suppression specification to use for the test35 test. * tests/data/test-diff-suppr/libtest36-leaf-v0.so: New test input. * tests/data/test-diff-suppr/libtest36-leaf-v1.so: Likewise. * tests/data/test-diff-suppr/test36-leaf-report-0.txt: New reference test output. * tests/data/test-diff-suppr/test36-leaf-v0.cc: Source code of test input above. * tests/data/test-diff-suppr/test36-leaf-v1.cc: Likewise. * tests/test-diff-suppr.cc (in_out_specs): Use the new test inputs above in this harness. * tests/data/Makefile.am: Add the new test inputs above to source distribution. Signed-off-by: Dodji Seketeli <dodji@redhat.com>
This commit is contained in:
parent
3824d8f3c2
commit
108a6074a5
@ -330,6 +330,68 @@ Options
|
||||
|
||||
Do not emit the path attribute for the ABI corpus.
|
||||
|
||||
* ``--leaf-changes-only|-l`` only show leaf changes, so don't show
|
||||
impact analysis report.
|
||||
|
||||
The typical output of abidiff when comparing two binaries looks
|
||||
like this ::
|
||||
|
||||
$ abidiff libtest-v0.so libtest-v1.so
|
||||
Functions changes summary: 0 Removed, 1 Changed, 0 Added function
|
||||
Variables changes summary: 0 Removed, 0 Changed, 0 Added variable
|
||||
|
||||
1 function with some indirect sub-type change:
|
||||
|
||||
[C]'function void fn(C&)' at test-v1.cc:13:1 has some indirect sub-type changes:
|
||||
parameter 1 of type 'C&' has sub-type changes:
|
||||
in referenced type 'struct C' at test-v1.cc:7:1:
|
||||
type size hasn't changed
|
||||
1 data member change:
|
||||
type of 'leaf* C::m0' changed:
|
||||
in pointed to type 'struct leaf' at test-v1.cc:1:1:
|
||||
type size changed from 32 to 64 bits
|
||||
1 data member insertion:
|
||||
'char leaf::m1', at offset 32 (in bits) at test-v1.cc:4:1
|
||||
|
||||
$
|
||||
|
||||
So in that example the report emits information about how the data
|
||||
member insertion change of "struct leaf" is reachable from
|
||||
function "void fn(C&)". In other words, the report not only shows
|
||||
the data member change on "struct leaf", but it also shows the
|
||||
impact of that change on the function "void fn(C&)".
|
||||
|
||||
In abidiff parlance, the change on "struct leaf" is called a leaf
|
||||
change. So the ``--leaf-changes-only --impacted-interfaces``
|
||||
options show, well, only the leaf change. And it goes like this:
|
||||
::
|
||||
|
||||
$ abidiff -l libtest-v0.so libtest-v1.so
|
||||
'struct leaf' changed:
|
||||
type size changed from 32 to 64 bits
|
||||
1 data member insertion:
|
||||
'char leaf::m1', at offset 32 (in bits) at test-v1.cc:4:1
|
||||
|
||||
one impacted interface:
|
||||
function void fn(C&)
|
||||
$
|
||||
|
||||
Note how the report ends by showing the list of interfaces
|
||||
impacted by the leaf change.
|
||||
|
||||
Now if you don't want to see that list of impacted interfaces,
|
||||
then you can just avoid using the ``--impacted-interface`` option.
|
||||
You can learn about that option below, in any case.
|
||||
|
||||
|
||||
* ``--impacted-interfaces``
|
||||
|
||||
When showing leaf changes, this option instructs abidiff to show
|
||||
the list of impacted interfaces. This option is thus to be used
|
||||
in addition the ``--leaf-changes-only`` option, otherwise, it's
|
||||
ignored.
|
||||
|
||||
|
||||
* ``--dump-diff-tree``
|
||||
|
||||
After the diff report, emit a textual representation of the diff
|
||||
|
@ -1,6 +1,6 @@
|
||||
// -*- Mode: C++ -*-
|
||||
//
|
||||
// Copyright (C) 2013-2016 Red Hat, Inc.
|
||||
// Copyright (C) 2013-2017 Red Hat, Inc.
|
||||
//
|
||||
// This file is part of the GNU Application Binary Interface Generic
|
||||
// Analysis and Instrumentation Library (libabigail). This library is
|
||||
@ -49,6 +49,9 @@ bool
|
||||
has_class_decl_only_def_change(const class_or_union_sptr& first,
|
||||
const class_or_union_sptr& second);
|
||||
|
||||
bool
|
||||
has_basic_type_name_change(const diff *);
|
||||
|
||||
struct filter_base;
|
||||
/// Convenience typedef for a shared pointer to filter_base
|
||||
typedef shared_ptr<filter_base> filter_base_sptr;
|
||||
|
@ -1,6 +1,6 @@
|
||||
// -*- Mode: C++ -*-
|
||||
//
|
||||
// Copyright (C) 2013-2016 Red Hat, Inc.
|
||||
// Copyright (C) 2013-2017 Red Hat, Inc.
|
||||
//
|
||||
// This file is part of the GNU Application Binary Interface Generic
|
||||
// Analysis and Instrumentation Library (libabigail). This library is
|
||||
@ -182,6 +182,10 @@ typedef unordered_map<string,
|
||||
/// of the map is the qualified name of the changed type.
|
||||
typedef unordered_map<string, diff_sptr> string_diff_sptr_map;
|
||||
|
||||
/// Convenience typedef for a map which value is a diff*. The key of
|
||||
/// the map is the qualified name of the changed type.
|
||||
typedef unordered_map<string, diff*> string_diff_ptr_map;
|
||||
|
||||
/// Convenience typedef for a map whose key is a string and whose
|
||||
/// value is a changed variable of type @ref var_diff_sptr.
|
||||
typedef unordered_map<string,
|
||||
@ -423,6 +427,99 @@ operator<<(ostream& o, diff_category);
|
||||
|
||||
class corpus_diff;
|
||||
|
||||
/// This type contains maps. Each map associates a type name to a
|
||||
/// diff of that type. Not all kinds of diffs are present; only those
|
||||
/// that carry leaf changes are, for now.
|
||||
class diff_maps
|
||||
{
|
||||
struct priv;
|
||||
typedef shared_ptr<priv> priv_sptr;
|
||||
priv_sptr priv_;
|
||||
|
||||
public:
|
||||
|
||||
diff_maps();
|
||||
|
||||
const string_diff_ptr_map&
|
||||
get_type_decl_diff_map() const;
|
||||
|
||||
string_diff_ptr_map&
|
||||
get_type_decl_diff_map();
|
||||
|
||||
const string_diff_ptr_map&
|
||||
get_enum_diff_map() const;
|
||||
|
||||
string_diff_ptr_map&
|
||||
get_enum_diff_map();
|
||||
|
||||
const string_diff_ptr_map&
|
||||
get_class_diff_map() const;
|
||||
|
||||
string_diff_ptr_map&
|
||||
get_class_diff_map();
|
||||
|
||||
const string_diff_ptr_map&
|
||||
get_union_diff_map() const;
|
||||
|
||||
string_diff_ptr_map&
|
||||
get_union_diff_map();
|
||||
|
||||
const string_diff_ptr_map&
|
||||
get_typedef_diff_map() const;
|
||||
|
||||
string_diff_ptr_map&
|
||||
get_typedef_diff_map();
|
||||
|
||||
const string_diff_ptr_map&
|
||||
get_array_diff_map() const;
|
||||
|
||||
string_diff_ptr_map&
|
||||
get_array_diff_map();
|
||||
|
||||
const string_diff_ptr_map&
|
||||
get_reference_diff_map() const;
|
||||
|
||||
string_diff_ptr_map&
|
||||
get_reference_diff_map();
|
||||
|
||||
const string_diff_ptr_map&
|
||||
get_fn_parm_diff_map() const;
|
||||
|
||||
string_diff_ptr_map&
|
||||
get_fn_parm_diff_map();
|
||||
|
||||
const string_diff_ptr_map&
|
||||
get_function_type_diff_map() const;
|
||||
|
||||
string_diff_ptr_map&
|
||||
get_function_type_diff_map();
|
||||
|
||||
const string_diff_ptr_map&
|
||||
get_function_decl_diff_map() const;
|
||||
|
||||
string_diff_ptr_map&
|
||||
get_function_decl_diff_map();
|
||||
|
||||
const string_diff_ptr_map&
|
||||
get_var_decl_diff_map() const;
|
||||
|
||||
string_diff_ptr_map&
|
||||
get_var_decl_diff_map();
|
||||
|
||||
const string_diff_ptr_map&
|
||||
get_distinct_diff_map() const;
|
||||
|
||||
string_diff_ptr_map&
|
||||
get_distinct_diff_map();
|
||||
|
||||
bool
|
||||
insert_diff_node(const diff *d,
|
||||
const type_or_decl_base_sptr& impacted_iface);
|
||||
|
||||
artifact_sptr_set_type*
|
||||
lookup_impacted_interfaces(const diff *d) const;
|
||||
}; // end class diff_maps
|
||||
|
||||
/// A convenience typedef for a shared pointer to @ref corpus_diff.
|
||||
typedef shared_ptr<corpus_diff> corpus_diff_sptr;
|
||||
|
||||
@ -473,13 +570,15 @@ public:
|
||||
diff_context();
|
||||
|
||||
void
|
||||
set_corpora(const corpus_sptr corp1,
|
||||
const corpus_sptr corp2);
|
||||
set_corpus_diff(const corpus_diff_sptr&);
|
||||
|
||||
const corpus_sptr
|
||||
const corpus_diff_sptr&
|
||||
get_corpus_diff() const;
|
||||
|
||||
corpus_sptr
|
||||
get_first_corpus() const;
|
||||
|
||||
const corpus_sptr
|
||||
corpus_sptr
|
||||
get_second_corpus() const;
|
||||
|
||||
reporter_base_sptr
|
||||
@ -528,6 +627,12 @@ public:
|
||||
bool
|
||||
visiting_a_node_twice_is_forbidden() const;
|
||||
|
||||
void
|
||||
forbid_visiting_a_node_twice_per_interface(bool);
|
||||
|
||||
bool
|
||||
visiting_a_node_twice_is_forbidden_per_interface() const;
|
||||
|
||||
diff_category
|
||||
get_allowed_category() const;
|
||||
|
||||
@ -561,6 +666,12 @@ public:
|
||||
void
|
||||
add_suppressions(const suppr::suppressions_type& supprs);
|
||||
|
||||
void
|
||||
show_leaf_changes_only(bool f);
|
||||
|
||||
bool
|
||||
show_leaf_changes_only() const;
|
||||
|
||||
void
|
||||
show_relative_offset_changes(bool f);
|
||||
|
||||
@ -651,6 +762,12 @@ public:
|
||||
void
|
||||
show_added_symbols_unreferenced_by_debug_info(bool f);
|
||||
|
||||
bool
|
||||
show_impacted_interfaces() const;
|
||||
|
||||
void
|
||||
show_impacted_interfaces(bool f);
|
||||
|
||||
void
|
||||
default_output_stream(ostream*);
|
||||
|
||||
@ -1717,6 +1834,7 @@ public:
|
||||
chain_into_hierarchy();
|
||||
|
||||
friend class default_reporter;
|
||||
friend class leaf_reporter;
|
||||
};// end class scope_diff
|
||||
|
||||
scope_diff_sptr
|
||||
@ -1851,6 +1969,7 @@ public:
|
||||
chain_into_hierarchy();
|
||||
|
||||
friend class default_reporter;
|
||||
friend class leaf_reporter;
|
||||
};// end class function_type_diff
|
||||
|
||||
function_type_diff_sptr
|
||||
@ -2174,6 +2293,15 @@ public:
|
||||
const diff_stats&
|
||||
apply_filters_and_suppressions_before_reporting();
|
||||
|
||||
void
|
||||
mark_leaf_diff_nodes();
|
||||
|
||||
diff_maps&
|
||||
get_leaf_diffs();
|
||||
|
||||
const diff_maps&
|
||||
get_leaf_diffs() const;
|
||||
|
||||
virtual void
|
||||
report(ostream& out, const string& indent = "") const;
|
||||
|
||||
@ -2192,6 +2320,7 @@ public:
|
||||
apply_suppressions(const corpus_diff* diff_tree);
|
||||
|
||||
friend class default_reporter;
|
||||
friend class leaf_reporter;
|
||||
}; // end class corpus_diff
|
||||
|
||||
corpus_diff_sptr
|
||||
@ -2302,6 +2431,14 @@ public:
|
||||
|
||||
size_t net_num_removed_var_syms() const;
|
||||
size_t net_num_added_var_syms() const;
|
||||
|
||||
size_t num_leaf_changes() const;
|
||||
void num_leaf_changes(size_t);
|
||||
|
||||
size_t num_leaf_changes_filtered_out() const;
|
||||
void num_leaf_changes_filtered_out(size_t);
|
||||
|
||||
size_t net_num_leaf_changes() const;
|
||||
}; // end class corpus_diff::diff_stats
|
||||
|
||||
/// The base class for the node visitors. These are the types used to
|
||||
@ -2309,50 +2446,30 @@ public:
|
||||
class diff_node_visitor : public node_visitor_base
|
||||
{
|
||||
protected:
|
||||
visiting_kind visiting_kind_;
|
||||
struct priv;
|
||||
typedef shared_ptr<priv> priv_sptr;
|
||||
priv_sptr priv_;
|
||||
|
||||
public:
|
||||
|
||||
/// Default constructor of the @ref diff_node_visitor type.
|
||||
diff_node_visitor()
|
||||
: visiting_kind_()
|
||||
{}
|
||||
diff_node_visitor();
|
||||
|
||||
/// Constructor of the @ref diff_node_visitor type.
|
||||
///
|
||||
/// @param k how the visiting has to be performed.
|
||||
diff_node_visitor(visiting_kind k)
|
||||
: visiting_kind_(k)
|
||||
{}
|
||||
diff_node_visitor(visiting_kind k);
|
||||
|
||||
/// Getter for the visiting policy of the traversing code while
|
||||
/// invoking this visitor.
|
||||
///
|
||||
/// @return the visiting policy used by the traversing code when
|
||||
/// invoking this visitor.
|
||||
visiting_kind
|
||||
get_visiting_kind() const
|
||||
{return visiting_kind_;}
|
||||
get_visiting_kind() const;
|
||||
|
||||
/// Setter for the visiting policy of the traversing code while
|
||||
/// invoking this visitor.
|
||||
///
|
||||
/// @param v a bit map representing the new visiting policy used by
|
||||
/// the traversing code when invoking this visitor.
|
||||
void
|
||||
set_visiting_kind(visiting_kind v)
|
||||
{visiting_kind_ = v;}
|
||||
set_visiting_kind(visiting_kind v);
|
||||
|
||||
/// Setter for the visiting policy of the traversing code while
|
||||
/// invoking this visitor. This one makes a logical or between the
|
||||
/// current policy and the bitmap given in argument and assigns the
|
||||
/// current policy to the result.
|
||||
///
|
||||
/// @param v a bitmap representing the visiting policy to or with
|
||||
/// the current policy.
|
||||
void
|
||||
or_visiting_kind(visiting_kind v)
|
||||
{visiting_kind_ = visiting_kind_ | v;}
|
||||
or_visiting_kind(visiting_kind v);
|
||||
|
||||
void
|
||||
set_current_topmost_iface_diff(diff*);
|
||||
|
||||
diff*
|
||||
get_current_topmost_iface_diff() const;
|
||||
|
||||
virtual void
|
||||
visit_begin(diff*);
|
||||
@ -2496,18 +2613,30 @@ is_type_diff(const diff* diff);
|
||||
const decl_diff_base*
|
||||
is_decl_diff(const diff* diff);
|
||||
|
||||
bool
|
||||
const type_decl_diff*
|
||||
is_diff_of_basic_type(const diff* diff);
|
||||
|
||||
bool
|
||||
has_basic_type_change_only(const diff* diff);
|
||||
|
||||
const enum_diff*
|
||||
is_enum_diff(const diff *diff);
|
||||
|
||||
const class_diff*
|
||||
is_class_diff(const diff* diff);
|
||||
|
||||
const union_diff*
|
||||
is_union_diff(const diff* diff);
|
||||
|
||||
const array_diff*
|
||||
is_array_diff(const diff* diff);
|
||||
|
||||
const function_type_diff*
|
||||
is_function_type_diff(const diff* diff);
|
||||
|
||||
const typedef_diff*
|
||||
is_typedef_diff(const diff *diff);
|
||||
|
||||
const var_diff*
|
||||
is_var_diff(const diff* diff);
|
||||
|
||||
@ -2529,12 +2658,18 @@ is_fn_parm_diff(const diff* diff);
|
||||
const base_diff*
|
||||
is_base_diff(const diff* diff);
|
||||
|
||||
const distinct_diff*
|
||||
is_distinct_diff(const diff *diff);
|
||||
|
||||
bool
|
||||
is_child_node_of_function_parm_diff(const diff* diff);
|
||||
|
||||
bool
|
||||
is_child_node_of_base_diff(const diff* diff);
|
||||
|
||||
const corpus_diff*
|
||||
is_corpus_diff(const diff* diff);
|
||||
|
||||
}// end namespace comparison
|
||||
|
||||
}// end namespace abigail
|
||||
|
@ -604,6 +604,9 @@ get_data_member_offset(const var_decl_sptr);
|
||||
uint64_t
|
||||
get_data_member_offset(const decl_base_sptr);
|
||||
|
||||
uint64_t
|
||||
get_var_size_in_bits(const var_decl_sptr&);
|
||||
|
||||
void
|
||||
set_data_member_is_laid_out(var_decl_sptr, bool);
|
||||
|
||||
@ -729,6 +732,9 @@ peel_typedef_pointer_or_reference_type(const type_base_sptr);
|
||||
type_base*
|
||||
peel_typedef_pointer_or_reference_type(const type_base*);
|
||||
|
||||
string
|
||||
get_name(const type_or_decl_base*, bool qualified = true);
|
||||
|
||||
string
|
||||
get_name(const type_or_decl_base_sptr&,
|
||||
bool qualified = true);
|
||||
@ -1173,6 +1179,10 @@ hash_type_or_decl(const type_or_decl_base *);
|
||||
|
||||
size_t
|
||||
hash_type_or_decl(const type_or_decl_base_sptr &);
|
||||
|
||||
bool
|
||||
function_decl_is_less_than(const function_decl&f, const function_decl &s);
|
||||
|
||||
} // end namespace ir
|
||||
|
||||
using namespace abigail::ir;
|
||||
|
126
include/abg-ir.h
126
include/abg-ir.h
@ -321,6 +321,90 @@ struct ir_traversable_base : public traversable_base
|
||||
traverse(ir_node_visitor& v);
|
||||
}; // end class ir_traversable_base
|
||||
|
||||
/// The hashing functor for using instances of @ref type_or_decl_base
|
||||
/// as values in a hash map or set.
|
||||
struct type_or_decl_hash
|
||||
{
|
||||
|
||||
/// Function-call Operator to hash the string representation of an
|
||||
/// ABI artifact.
|
||||
///
|
||||
/// @param artifact the ABI artifact to hash.
|
||||
///
|
||||
/// @return the hash value of the string representation of @p
|
||||
/// artifact.
|
||||
size_t
|
||||
operator()(const type_or_decl_base *artifact) const
|
||||
{
|
||||
string repr = get_pretty_representation(artifact);
|
||||
std::tr1::hash<string> do_hash;
|
||||
return do_hash(repr);
|
||||
}
|
||||
|
||||
/// Function-call Operator to hash the string representation of an
|
||||
/// ABI artifact.
|
||||
///
|
||||
/// @param artifact the ABI artifact to hash.
|
||||
///
|
||||
/// @return the hash value of the string representation of @p
|
||||
/// artifact.
|
||||
size_t
|
||||
operator()(const type_or_decl_base_sptr& artifact) const
|
||||
{return operator()(artifact.get());}
|
||||
}; // end struct type_or_decl_hash
|
||||
|
||||
/// The comparison functor for using instances of @ref
|
||||
/// type_or_decl_base as values in a hash map or set.
|
||||
struct type_or_decl_equal
|
||||
{
|
||||
|
||||
/// The function-call operator to compare the string representations
|
||||
/// of two ABI artifacts.
|
||||
///
|
||||
/// @param l the left hand side ABI artifact operand of the
|
||||
/// comparison.
|
||||
///
|
||||
/// @param r the right hand side ABI artifact operand of the
|
||||
/// comparison.
|
||||
///
|
||||
/// @return true iff the string representation of @p l equals the one
|
||||
/// of @p r.
|
||||
bool
|
||||
operator()(const type_or_decl_base *l, const type_or_decl_base *r) const
|
||||
{
|
||||
string repr1 = get_pretty_representation(l);
|
||||
string repr2 = get_pretty_representation(r);
|
||||
|
||||
return repr1 == repr2;
|
||||
}
|
||||
|
||||
/// The function-call operator to compare the string representations
|
||||
/// of two ABI artifacts.
|
||||
///
|
||||
/// @param l the left hand side ABI artifact operand of the
|
||||
/// comparison.
|
||||
///
|
||||
/// @param r the right hand side ABI artifact operand of the
|
||||
/// comparison.
|
||||
///
|
||||
/// @return true iff the string representation of @p l equals the one
|
||||
/// of @p r.
|
||||
bool
|
||||
operator()(const type_or_decl_base_sptr &l,
|
||||
const type_or_decl_base_sptr &r) const
|
||||
{return operator()(l.get(), r.get());}
|
||||
}; // end type_or_decl_equal
|
||||
|
||||
/// A convenience typedef for a hash set of type_or_decl_base_sptr
|
||||
typedef unordered_set<type_or_decl_base_sptr,
|
||||
type_or_decl_hash,
|
||||
type_or_decl_equal> artifact_sptr_set_type;
|
||||
|
||||
/// A convenience typedef for a hash set of const type_or_decl_base*
|
||||
typedef unordered_set<const type_or_decl_base*,
|
||||
type_or_decl_hash,
|
||||
type_or_decl_equal> artifact_ptr_set_type;
|
||||
|
||||
/// A convenience typedef for a map which key is a string and which
|
||||
/// value is a @ref type_base_wptr.
|
||||
typedef unordered_map<string, type_base_wptr> string_type_base_wptr_map_type;
|
||||
@ -2492,6 +2576,48 @@ equals(const function_decl::parameter&,
|
||||
const function_decl::parameter&,
|
||||
change_kind*);
|
||||
|
||||
/// A comparison functor to compare pointer to instances of @ref
|
||||
/// type_or_decl_base.
|
||||
struct type_or_decl_base_comp
|
||||
{
|
||||
/// Comparison operator for ABI artifacts.
|
||||
///
|
||||
/// @param f the first ABI artifact to consider for the comparison.
|
||||
///
|
||||
/// @param s the second ABI artifact to consider for the comparison.
|
||||
///
|
||||
/// @return true iff @p f is lexicographically less than than @p s.
|
||||
bool
|
||||
operator()(const type_or_decl_base *f,
|
||||
const type_or_decl_base *s)
|
||||
{
|
||||
function_decl *f_fn = is_function_decl(f), *s_fn = is_function_decl(s);
|
||||
if (f_fn && s_fn)
|
||||
return function_decl_is_less_than(*f_fn, *s_fn);
|
||||
|
||||
var_decl *f_var = is_var_decl(f), *s_var = is_var_decl(s);
|
||||
if (f_var && s_var)
|
||||
return get_name(f_var) < get_name(s_var);
|
||||
|
||||
string l_repr = get_pretty_representation(f),
|
||||
r_repr = get_pretty_representation(s);
|
||||
|
||||
return l_repr < r_repr;
|
||||
}
|
||||
|
||||
/// Comparison operator for ABI artifacts.
|
||||
///
|
||||
/// @param f the first ABI artifact to consider for the comparison.
|
||||
///
|
||||
/// @param s the second ABI artifact to consider for the comparison.
|
||||
///
|
||||
/// @return true iff @p f is lexicographically less than than @p s.
|
||||
bool
|
||||
operator()(const type_or_decl_base_sptr& f,
|
||||
const type_or_decl_base_sptr& s)
|
||||
{return operator()(f.get(), s.get());}
|
||||
}; // end struct type_or_decl_base_comp
|
||||
|
||||
/// Abstraction of a function parameter.
|
||||
class function_decl::parameter : public decl_base
|
||||
{
|
||||
|
@ -52,7 +52,7 @@ class function_decl_diff;
|
||||
class var_diff;
|
||||
class translation_unit_diff;
|
||||
class corpus_diff;
|
||||
|
||||
class diff_maps;
|
||||
class reporter_base;
|
||||
|
||||
/// A convenience typedef for a shared pointer to a @ref
|
||||
@ -64,6 +64,8 @@ class reporter_base
|
||||
{
|
||||
public:
|
||||
|
||||
virtual bool diff_to_be_reported(const diff *d) const;
|
||||
|
||||
virtual void
|
||||
report(const type_decl_diff& d, ostream& out,
|
||||
const string& indent = "") const = 0;
|
||||
@ -159,10 +161,20 @@ public:
|
||||
report(const enum_diff& d, ostream& out,
|
||||
const string& indent = "") const;
|
||||
|
||||
bool
|
||||
report_local_typedef_changes(const typedef_diff &d,
|
||||
ostream& out,
|
||||
const string& indent) const;
|
||||
|
||||
virtual void
|
||||
report(const typedef_diff& d, ostream& out,
|
||||
const string& indent = "") const;
|
||||
|
||||
bool
|
||||
report_local_qualified_type_changes(const qualified_type_diff& d,
|
||||
ostream& out,
|
||||
const string& indent) const;
|
||||
|
||||
virtual void
|
||||
report(const qualified_type_diff& d, ostream& out,
|
||||
const string& indent = "") const;
|
||||
@ -170,6 +182,11 @@ public:
|
||||
virtual void
|
||||
report(const pointer_diff& d, ostream& out, const string& indent = "") const;
|
||||
|
||||
void
|
||||
report_local_reference_type_changes(const reference_diff& d,
|
||||
ostream& out,
|
||||
const string& indent) const;
|
||||
|
||||
virtual void
|
||||
report(const reference_diff& d, ostream& out,
|
||||
const string& indent = "") const;
|
||||
@ -178,6 +195,11 @@ public:
|
||||
report(const fn_parm_diff& d, ostream& out,
|
||||
const string& indent = "") const;
|
||||
|
||||
void
|
||||
report_local_function_type_changes(const function_type_diff& d,
|
||||
ostream& out,
|
||||
const string& indent) const;
|
||||
|
||||
virtual void
|
||||
report(const function_type_diff& d, ostream& out,
|
||||
const string& indent = "") const;
|
||||
@ -220,6 +242,77 @@ public:
|
||||
const string& indent = "") const;
|
||||
}; // end class default_reporter
|
||||
|
||||
/// A reporter that only reports leaf changes
|
||||
class leaf_reporter : public default_reporter
|
||||
{
|
||||
public:
|
||||
|
||||
virtual bool diff_to_be_reported(const diff *d) const;
|
||||
|
||||
void
|
||||
report_changes_from_diff_maps(const diff_maps&,
|
||||
ostream& out,
|
||||
const string& indent) const;
|
||||
|
||||
virtual void
|
||||
report(const typedef_diff& d, ostream& out,
|
||||
const string& indent = "") const;
|
||||
|
||||
virtual void
|
||||
report(const qualified_type_diff& d, ostream& out,
|
||||
const string& indent = "") const;
|
||||
|
||||
virtual void
|
||||
report(const pointer_diff& d, ostream& out,
|
||||
const string& indent = "") const;
|
||||
|
||||
virtual void
|
||||
report(const reference_diff& d, ostream& out,
|
||||
const string& indent = "") const;
|
||||
|
||||
virtual void
|
||||
report(const fn_parm_diff& d, ostream& out,
|
||||
const string& indent = "") const;
|
||||
|
||||
virtual void
|
||||
report(const function_type_diff& d, ostream& out,
|
||||
const string& indent = "") const;
|
||||
|
||||
virtual void
|
||||
report(const array_diff& d, ostream& out, const string& indent = "") const;
|
||||
|
||||
virtual void
|
||||
report(const scope_diff& d, ostream& out, const string& indent = "") const;
|
||||
|
||||
virtual void
|
||||
report(const class_or_union_diff& d, ostream& out,
|
||||
const string& indent = "") const;
|
||||
|
||||
virtual void
|
||||
report(const class_diff& d, ostream& out, const string& indent = "") const;
|
||||
|
||||
virtual void
|
||||
report(const union_diff& d, ostream& out, const string& indent = "") const;
|
||||
|
||||
virtual void
|
||||
report(const distinct_diff& d, ostream& out, const string& indent = "") const;
|
||||
|
||||
virtual void
|
||||
report(const function_decl_diff& d, ostream& out,
|
||||
const string& indent = "") const;
|
||||
|
||||
virtual void
|
||||
report(const var_diff& d, ostream& out, const string& indent = "") const;
|
||||
|
||||
virtual void
|
||||
report(const translation_unit_diff& d, ostream& out,
|
||||
const string& indent = "") const;
|
||||
|
||||
virtual void
|
||||
report(const corpus_diff& d, ostream& out,
|
||||
const string& indent = "") const;
|
||||
}; // end class leaf_reporter
|
||||
|
||||
} // end namespace comparison
|
||||
} // end namespace abigail
|
||||
|
||||
|
@ -26,6 +26,7 @@ abg-comparison-priv.h \
|
||||
abg-reporter-priv.h \
|
||||
abg-reporter-priv.cc \
|
||||
abg-default-reporter.cc \
|
||||
abg-leaf-reporter.cc \
|
||||
abg-suppression-priv.h \
|
||||
abg-suppression.cc \
|
||||
abg-comp-filter.cc \
|
||||
|
@ -362,10 +362,18 @@ is_compatible_change(const decl_base_sptr& d1, const decl_base_sptr& d2)
|
||||
///
|
||||
/// @return true if d1 and d2 have different names.
|
||||
static bool
|
||||
decl_name_changed(const decl_base_sptr& d1, const decl_base_sptr& d2)
|
||||
decl_name_changed(const type_or_decl_base* a1, const type_or_decl_base *a2)
|
||||
{
|
||||
string d1_name, d2_name;
|
||||
|
||||
const decl_base *d1 = dynamic_cast<const decl_base*>(a1);
|
||||
if (d1 == 0)
|
||||
return false;
|
||||
|
||||
const decl_base *d2 = dynamic_cast<const decl_base*>(a2);
|
||||
if (d2 == 0)
|
||||
return false;
|
||||
|
||||
if (d1)
|
||||
d1_name = d1->get_qualified_name();
|
||||
if (d2)
|
||||
@ -374,6 +382,29 @@ decl_name_changed(const decl_base_sptr& d1, const decl_base_sptr& d2)
|
||||
return d1_name != d2_name;
|
||||
}
|
||||
|
||||
/// Test if two decls have different names.
|
||||
///
|
||||
/// @param d1 the first declaration to consider.
|
||||
///
|
||||
/// @param d2 the second declaration to consider.
|
||||
///
|
||||
/// @return true if d1 and d2 have different names.
|
||||
static bool
|
||||
decl_name_changed(const type_or_decl_base_sptr& d1,
|
||||
const type_or_decl_base_sptr& d2)
|
||||
{return decl_name_changed(d1.get(), d2.get());}
|
||||
|
||||
/// Test if a diff nodes carries a changes in which two decls have
|
||||
/// different names.
|
||||
///
|
||||
/// @param d the diff node to consider.
|
||||
///
|
||||
/// @return true iff d carries a changes in which two decls have
|
||||
/// different names.
|
||||
static bool
|
||||
decl_name_changed(const diff *d)
|
||||
{return decl_name_changed(d->first_subject(), d->second_subject());}
|
||||
|
||||
/// Test if two decls represents a harmless name change.
|
||||
///
|
||||
/// For now, a harmless name change is a name change for a typedef,
|
||||
@ -776,6 +807,20 @@ has_class_decl_only_def_change(const diff *diff)
|
||||
return has_class_decl_only_def_change(f, s);
|
||||
}
|
||||
|
||||
/// Test if a diff node carries a basic type name change.
|
||||
///
|
||||
/// @param d the diff node to consider.
|
||||
///
|
||||
/// @return true iff the diff node carries a basic type name change.
|
||||
bool
|
||||
has_basic_type_name_change(const diff *d)
|
||||
{
|
||||
if (const type_decl_diff *dif = is_diff_of_basic_type(d))
|
||||
if (decl_name_changed(dif))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// Test if an enum_diff carries an enumerator insertion.
|
||||
///
|
||||
|
@ -91,6 +91,94 @@ typedef unordered_map<types_or_decls_type, diff_sptr,
|
||||
types_or_decls_hash, types_or_decls_equal>
|
||||
types_or_decls_diff_map_type;
|
||||
|
||||
/// A hashing functor for using @ref diff_sptr and @ref diff* in a
|
||||
/// hash map or set.
|
||||
struct diff_hash
|
||||
{
|
||||
/// The function-call operator to hash a @ref diff node.
|
||||
///
|
||||
/// @param d the @ref diff node to hash.
|
||||
///
|
||||
/// @return the hash value of @p d.
|
||||
size_t
|
||||
operator()(const diff_sptr& d) const
|
||||
{return operator()(*d);}
|
||||
|
||||
/// The function-call operator to hash a @ref diff node.
|
||||
///
|
||||
/// @param d the @ref diff node to hash.
|
||||
///
|
||||
/// @return the hash value of @p d.
|
||||
size_t
|
||||
operator()(const diff *d) const
|
||||
{return operator()(*d);}
|
||||
|
||||
/// The function-call operator to hash a @ref diff node.
|
||||
///
|
||||
/// @param d the @ref diff node to hash.
|
||||
///
|
||||
/// @return the hash value of @p d.
|
||||
size_t
|
||||
operator()(const diff& d) const
|
||||
{
|
||||
diff* canonical_diff = d.get_canonical_diff();
|
||||
assert(canonical_diff);
|
||||
return reinterpret_cast<size_t>(canonical_diff);
|
||||
}
|
||||
}; // end struct diff_hash
|
||||
|
||||
/// A comparison functor for using @ref diff_sptr and @ref diff* in a
|
||||
/// hash map or set.
|
||||
struct diff_equal
|
||||
{
|
||||
/// The function-call operator to compare two @ref diff nodes.
|
||||
///
|
||||
/// @param d1 the first diff node involved in the comparison.
|
||||
///
|
||||
/// @param d2 the second diff node involved in the comparison.
|
||||
///
|
||||
/// @return true iff @p d1 equals @p d2.
|
||||
bool
|
||||
operator()(const diff* d1, const diff* d2) const
|
||||
{return operator()(*d1, *d2);}
|
||||
|
||||
/// The function-call operator to compare two @ref diff nodes.
|
||||
///
|
||||
/// @param d1 the first diff node involved in the comparison.
|
||||
///
|
||||
/// @param d2 the second diff node involved in the comparison.
|
||||
///
|
||||
/// @return true iff @p d1 equals @p d2.
|
||||
bool
|
||||
operator()(const diff_sptr& d1, const diff_sptr& d2) const
|
||||
{return operator()(*d1, *d2);}
|
||||
|
||||
/// The function-call operator to compare two @ref diff nodes.
|
||||
///
|
||||
/// @param d1 the first diff node involved in the comparison.
|
||||
///
|
||||
/// @param d2 the second diff node involved in the comparison.
|
||||
///
|
||||
/// @return true iff @p d1 equals @p d2.
|
||||
bool
|
||||
operator()(const diff& d1, const diff& d2) const
|
||||
{
|
||||
diff* canonical_diff1 = d1.get_canonical_diff();
|
||||
assert(canonical_diff1);
|
||||
|
||||
diff *canonical_diff2 = d2.get_canonical_diff();
|
||||
assert(canonical_diff2);
|
||||
|
||||
return canonical_diff1 == canonical_diff2;
|
||||
}
|
||||
}; // end struct diff_equal
|
||||
|
||||
/// A convenience typedef for an unordered_map which key is a @ref
|
||||
/// diff* and which value is a @ref artifact_sptr_set_type.
|
||||
typedef unordered_map<const diff*, artifact_sptr_set_type,
|
||||
diff_hash, diff_equal>
|
||||
diff_artifact_set_map_type;
|
||||
|
||||
/// The private member (pimpl) for @ref diff_context.
|
||||
struct diff_context::priv
|
||||
{
|
||||
@ -105,11 +193,12 @@ struct diff_context::priv
|
||||
// This is the last visited diff node, per class of equivalence.
|
||||
// It's set during the redundant diff node marking process.
|
||||
pointer_map last_visited_diff_node_;
|
||||
corpus_sptr first_corpus_;
|
||||
corpus_sptr second_corpus_;
|
||||
corpus_diff_sptr corpus_diff_;
|
||||
ostream* default_output_stream_;
|
||||
ostream* error_output_stream_;
|
||||
bool leaf_changes_only_;
|
||||
bool forbid_visiting_a_node_twice_;
|
||||
bool reset_visited_diffs_for_each_interface_;
|
||||
bool show_relative_offset_changes_;
|
||||
bool show_stats_only_;
|
||||
bool show_soname_change_;
|
||||
@ -125,14 +214,17 @@ struct diff_context::priv
|
||||
bool show_redundant_changes_;
|
||||
bool show_syms_unreferenced_by_di_;
|
||||
bool show_added_syms_unreferenced_by_di_;
|
||||
bool show_impacted_interfaces_;
|
||||
bool dump_diff_tree_;
|
||||
|
||||
priv()
|
||||
: allowed_category_(EVERYTHING_CATEGORY),
|
||||
reporter_(new default_reporter),
|
||||
reporter_(),
|
||||
default_output_stream_(),
|
||||
error_output_stream_(),
|
||||
leaf_changes_only_(),
|
||||
forbid_visiting_a_node_twice_(true),
|
||||
reset_visited_diffs_for_each_interface_(),
|
||||
show_relative_offset_changes_(true),
|
||||
show_stats_only_(false),
|
||||
show_soname_change_(true),
|
||||
@ -148,6 +240,7 @@ struct diff_context::priv
|
||||
show_redundant_changes_(true),
|
||||
show_syms_unreferenced_by_di_(true),
|
||||
show_added_syms_unreferenced_by_di_(true),
|
||||
show_impacted_interfaces_(true),
|
||||
dump_diff_tree_()
|
||||
{}
|
||||
};// end struct diff_context::priv
|
||||
@ -167,6 +260,7 @@ struct diff::priv
|
||||
type_or_decl_base_sptr second_subject_;
|
||||
vector<diff*> children_;
|
||||
diff* parent_;
|
||||
diff* parent_interface_;
|
||||
diff* canonical_diff_;
|
||||
diff_context_wptr ctxt_;
|
||||
diff_category local_category_;
|
||||
@ -190,6 +284,7 @@ public:
|
||||
first_subject_(first_subject),
|
||||
second_subject_(second_subject),
|
||||
parent_(),
|
||||
parent_interface_(),
|
||||
canonical_diff_(),
|
||||
ctxt_(ctxt),
|
||||
local_category_(category),
|
||||
@ -888,6 +983,7 @@ struct corpus_diff::priv
|
||||
string_elf_symbol_map suppressed_added_unrefed_var_syms_;
|
||||
string_elf_symbol_map deleted_unrefed_var_syms_;
|
||||
string_elf_symbol_map suppressed_deleted_unrefed_var_syms_;
|
||||
diff_maps leaf_diffs_;
|
||||
|
||||
/// Default constructor of corpus_diff::priv.
|
||||
priv()
|
||||
@ -953,6 +1049,8 @@ struct corpus_diff::priv
|
||||
bool
|
||||
added_unrefed_var_sym_is_suppressed(const elf_symbol*) const;
|
||||
|
||||
void count_leaf_changes(size_t &, size_t&);
|
||||
|
||||
void
|
||||
apply_filters_and_compute_diff_stats(corpus_diff::diff_stats&);
|
||||
|
||||
@ -985,31 +1083,7 @@ struct function_comp
|
||||
/// @return true iff @p f is less than @p s.
|
||||
bool
|
||||
operator()(const function_decl& f, const function_decl& s)
|
||||
{
|
||||
string fr = f.get_pretty_representation_of_declarator(),
|
||||
sr = s.get_pretty_representation_of_declarator();
|
||||
|
||||
if (fr != sr)
|
||||
return fr < sr;
|
||||
|
||||
fr = f.get_pretty_representation(),
|
||||
sr = s.get_pretty_representation();
|
||||
|
||||
if (fr != sr)
|
||||
return fr < sr;
|
||||
|
||||
if (f.get_symbol())
|
||||
fr = f.get_symbol()->get_id_string();
|
||||
else if (!f.get_linkage_name().empty())
|
||||
fr = f.get_linkage_name();
|
||||
|
||||
if (s.get_symbol())
|
||||
sr = s.get_symbol()->get_id_string();
|
||||
else if (!s.get_linkage_name().empty())
|
||||
sr = s.get_linkage_name();
|
||||
|
||||
return fr < sr;
|
||||
}
|
||||
{return abigail::ir::function_decl_is_less_than(f, s);}
|
||||
|
||||
/// The actual "less than" operator for instances of @ref
|
||||
/// function_decl. It returns true if the first @ref function_decl
|
||||
@ -1145,6 +1219,8 @@ struct corpus_diff::diff_stats::priv
|
||||
size_t num_removed_var_syms_filtered_out;
|
||||
size_t num_var_syms_added;
|
||||
size_t num_added_var_syms_filtered_out;
|
||||
size_t num_leaf_changes;
|
||||
size_t num_leaf_changes_filtered_out;
|
||||
|
||||
priv(diff_context_sptr ctxt)
|
||||
: ctxt_(ctxt),
|
||||
@ -1244,9 +1320,19 @@ void
|
||||
sort_string_parm_map(const string_parm_map& map,
|
||||
vector<function_decl::parameter_sptr>& sorted);
|
||||
|
||||
void
|
||||
sort_artifacts_set(const artifact_sptr_set_type& set,
|
||||
vector<type_or_decl_base_sptr>& sorted);
|
||||
|
||||
type_base_sptr
|
||||
get_leaf_type(qualified_type_def_sptr t);
|
||||
|
||||
diff*
|
||||
get_fn_decl_or_var_decl_diff_ancestor(const diff *);
|
||||
|
||||
bool
|
||||
is_diff_of_global_decls(const diff*);
|
||||
|
||||
} // end namespace comparison
|
||||
|
||||
} // namespace abigail
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,6 +1,6 @@
|
||||
// -*- Mode: C++ -*-
|
||||
//
|
||||
// Copyright (C) 2013-2017 Red Hat, Inc.
|
||||
// Copyright (C) 2017 Red Hat, Inc.
|
||||
//
|
||||
// This file is part of the GNU Application Binary Interface Generic
|
||||
// Analysis and Instrumentation Library (libabigail). This library is
|
||||
@ -181,6 +181,51 @@ default_reporter::report(const enum_diff& d, ostream& out,
|
||||
}
|
||||
out << "\n\n";
|
||||
}
|
||||
|
||||
if (d.context()->show_leaf_changes_only())
|
||||
maybe_report_interfaces_impacted_by_diff(&d, out, indent,
|
||||
/*new_line_prefix=*/false);
|
||||
}
|
||||
|
||||
/// For a @ref typedef_diff node, report the changes that are local.
|
||||
///
|
||||
/// @param d the @ref typedef_diff node to consider.
|
||||
///
|
||||
/// @param out the output stream to report to.
|
||||
///
|
||||
/// @param indent the white space string to use for indentation.
|
||||
///
|
||||
/// @return true iff the caller needs to emit a newline to the output
|
||||
/// stream before emitting anything else.
|
||||
bool
|
||||
default_reporter::report_local_typedef_changes(const typedef_diff &d,
|
||||
ostream& out,
|
||||
const string& indent) const
|
||||
{
|
||||
if (!d.to_be_reported())
|
||||
return false;
|
||||
|
||||
bool emit_nl = false;
|
||||
typedef_decl_sptr f = d.first_typedef_decl(), s = d.second_typedef_decl();
|
||||
|
||||
maybe_report_diff_for_member(f, s, d.context(), out, indent);
|
||||
|
||||
if (filtering::has_harmless_name_change(f, s)
|
||||
&& ((d.context()->get_allowed_category()
|
||||
& HARMLESS_DECL_NAME_CHANGE_CATEGORY)
|
||||
||
|
||||
d.context()->show_leaf_changes_only()))
|
||||
{
|
||||
out << indent << "typedef name changed from "
|
||||
<< f->get_qualified_name()
|
||||
<< " to "
|
||||
<< s->get_qualified_name();
|
||||
report_loc_info(s, *d.context(), out);
|
||||
out << "\n";
|
||||
emit_nl = true;
|
||||
}
|
||||
|
||||
return emit_nl;
|
||||
}
|
||||
|
||||
/// Reports the difference between the two subjects of the diff in a
|
||||
@ -192,31 +237,17 @@ default_reporter::report(const enum_diff& d, ostream& out,
|
||||
///
|
||||
/// @param indent the indentation string to use.
|
||||
void
|
||||
default_reporter::report(const typedef_diff& d, ostream& out,
|
||||
default_reporter::report(const typedef_diff& d,
|
||||
ostream& out,
|
||||
const string& indent) const
|
||||
{
|
||||
if (!d.to_be_reported())
|
||||
return;
|
||||
|
||||
bool emit_nl = false;
|
||||
typedef_decl_sptr f = d.first_typedef_decl(), s = d.second_typedef_decl();
|
||||
|
||||
RETURN_IF_BEING_REPORTED_OR_WAS_REPORTED_EARLIER(f, s);
|
||||
|
||||
maybe_report_diff_for_member(f, s, d.context(), out, indent);
|
||||
|
||||
if (filtering::has_harmless_name_change(f, s)
|
||||
&& (d.context()->get_allowed_category()
|
||||
& HARMLESS_DECL_NAME_CHANGE_CATEGORY))
|
||||
{
|
||||
out << indent << "typedef name changed from "
|
||||
<< f->get_qualified_name()
|
||||
<< " to "
|
||||
<< s->get_qualified_name();
|
||||
report_loc_info(s, *d.context(), out);
|
||||
out << "\n";
|
||||
emit_nl = true;
|
||||
}
|
||||
bool emit_nl = report_local_typedef_changes(d, out, indent);
|
||||
|
||||
diff_sptr dif = d.underlying_type_diff();
|
||||
if (dif && dif->to_be_reported())
|
||||
@ -235,6 +266,36 @@ default_reporter::report(const typedef_diff& d, ostream& out,
|
||||
out << "\n";
|
||||
}
|
||||
|
||||
/// For a @ref qualified_type_diff node, report the changes that are
|
||||
/// local.
|
||||
///
|
||||
/// @param d the @ref qualified_type_diff node to consider.
|
||||
///
|
||||
/// @param out the output stream to emit the report to.
|
||||
///
|
||||
/// @param indent the white string to use for indentation.
|
||||
///
|
||||
/// @return true iff a local change has been emitted. In this case,
|
||||
/// the local change is a name change.
|
||||
bool
|
||||
default_reporter::report_local_qualified_type_changes(const qualified_type_diff& d,
|
||||
ostream& out,
|
||||
const string& indent) const
|
||||
{
|
||||
if (!d.to_be_reported())
|
||||
return false;
|
||||
|
||||
string fname = d.first_qualified_type()->get_pretty_representation(),
|
||||
sname = d.second_qualified_type()->get_pretty_representation();
|
||||
|
||||
if (fname != sname)
|
||||
{
|
||||
out << indent << "'" << fname << "' changed to '" << sname << "'\n";
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/// Report a @ref qualified_type_diff in a serialized form.
|
||||
///
|
||||
/// @param d the @ref qualified_type_diff node to consider.
|
||||
@ -249,17 +310,14 @@ default_reporter::report(const qualified_type_diff& d, ostream& out,
|
||||
if (!d.to_be_reported())
|
||||
return;
|
||||
|
||||
string fname = d.first_qualified_type()->get_pretty_representation(),
|
||||
sname = d.second_qualified_type()->get_pretty_representation();
|
||||
|
||||
RETURN_IF_BEING_REPORTED_OR_WAS_REPORTED_EARLIER(d.first_qualified_type(),
|
||||
d.second_qualified_type());
|
||||
|
||||
if (fname != sname)
|
||||
{
|
||||
out << indent << "'" << fname << "' changed to '" << sname << "'\n";
|
||||
return;
|
||||
}
|
||||
if (report_local_qualified_type_changes(d, out, indent))
|
||||
// The local change was emitted and it's a name change. If the
|
||||
// type name changed, the it means the type changed altogether.
|
||||
// It makes a little sense to detail the changes in extenso here.
|
||||
return;
|
||||
|
||||
diff_sptr dif = d.leaf_underlying_type_diff();
|
||||
assert(dif);
|
||||
@ -305,16 +363,18 @@ default_reporter::report(const pointer_diff& d, ostream& out,
|
||||
}
|
||||
}
|
||||
|
||||
/// Report a @ref reference_diff in a serialized form.
|
||||
/// For a @reference_diff node, report the local changes carried by
|
||||
/// the diff node.
|
||||
///
|
||||
/// @param d the @ref reference_diff node to consider.
|
||||
/// @param d the @reference_diff node to consider.
|
||||
///
|
||||
/// @param out the output stream to serialize the dif to.
|
||||
/// @param out the output stream to report to.
|
||||
///
|
||||
/// @param indent the string to use for indenting the report.
|
||||
/// @param indent the white space indentation to use in the report.
|
||||
void
|
||||
default_reporter::report(const reference_diff& d, ostream& out,
|
||||
const string& indent) const
|
||||
default_reporter::report_local_reference_type_changes(const reference_diff& d,
|
||||
ostream& out,
|
||||
const string& indent) const
|
||||
{
|
||||
if (!d.to_be_reported())
|
||||
return;
|
||||
@ -340,6 +400,23 @@ default_reporter::report(const reference_diff& d, ostream& out,
|
||||
<< s_repr
|
||||
<< "'\n";
|
||||
}
|
||||
}
|
||||
|
||||
/// Report a @ref reference_diff in a serialized form.
|
||||
///
|
||||
/// @param d the @ref reference_diff node to consider.
|
||||
///
|
||||
/// @param out the output stream to serialize the dif to.
|
||||
///
|
||||
/// @param indent the string to use for indenting the report.
|
||||
void
|
||||
default_reporter::report(const reference_diff& d, ostream& out,
|
||||
const string& indent) const
|
||||
{
|
||||
if (!d.to_be_reported())
|
||||
return;
|
||||
|
||||
report_local_reference_type_changes(d, out, indent);
|
||||
|
||||
if (diff_sptr dif = d.underlying_type_diff())
|
||||
{
|
||||
@ -394,16 +471,19 @@ default_reporter::report(const fn_parm_diff& d, ostream& out,
|
||||
}
|
||||
}
|
||||
|
||||
/// Build and emit a textual report about a @ref function_type_diff.
|
||||
/// For a @ref function_type_diff node, report the local changes
|
||||
/// carried by the diff node.
|
||||
///
|
||||
/// @param d the @ref function_type_diff to consider.
|
||||
/// @param d the @ref function_type_diff node to consider.
|
||||
///
|
||||
/// @param out the output stream.
|
||||
/// @param out the output stream to report to.
|
||||
///
|
||||
/// @param indent the indentation string to use.
|
||||
/// @param indent the white space indentation string to use.
|
||||
void
|
||||
default_reporter::report(const function_type_diff& d, ostream& out,
|
||||
const string& indent) const
|
||||
default_reporter::report_local_function_type_changes(const function_type_diff& d,
|
||||
ostream& out,
|
||||
const string& indent) const
|
||||
|
||||
{
|
||||
if (!d.to_be_reported())
|
||||
return;
|
||||
@ -412,8 +492,6 @@ default_reporter::report(const function_type_diff& d, ostream& out,
|
||||
function_type_sptr sft = d.second_function_type();
|
||||
|
||||
diff_context_sptr ctxt = d.context();
|
||||
corpus_sptr fc = ctxt->get_first_corpus();
|
||||
corpus_sptr sc = ctxt->get_second_corpus();
|
||||
|
||||
// Report about the size of the function address
|
||||
if (fft->get_size_in_bits() != sft->get_size_in_bits())
|
||||
@ -436,41 +514,9 @@ default_reporter::report(const function_type_diff& d, ostream& out,
|
||||
<< " bits\n";
|
||||
}
|
||||
|
||||
// Report about return type differences.
|
||||
if (d.priv_->return_type_diff_
|
||||
&& d.priv_->return_type_diff_->to_be_reported())
|
||||
{
|
||||
out << indent << "return type changed:\n";
|
||||
d.priv_->return_type_diff_->report(out, indent + " ");
|
||||
}
|
||||
|
||||
// Hmmh, the above was quick. Now report about function parameters;
|
||||
// this shouldn't be as straightforward.
|
||||
//
|
||||
// Report about the parameter types that have changed sub-types.
|
||||
for (vector<fn_parm_diff_sptr>::const_iterator i =
|
||||
d.priv_->sorted_subtype_changed_parms_.begin();
|
||||
i != d.priv_->sorted_subtype_changed_parms_.end();
|
||||
++i)
|
||||
{
|
||||
diff_sptr dif = *i;
|
||||
if (dif && dif->to_be_reported())
|
||||
dif->report(out, indent);
|
||||
}
|
||||
|
||||
// Report about parameters that have changed, while staying
|
||||
// compatible -- otherwise they would have changed the mangled name
|
||||
// of the function and the function would have been reported as
|
||||
// removed.
|
||||
for (vector<fn_parm_diff_sptr>::const_iterator i =
|
||||
d.priv_->sorted_changed_parms_by_id_.begin();
|
||||
i != d.priv_->sorted_changed_parms_by_id_.end();
|
||||
++i)
|
||||
{
|
||||
diff_sptr dif = *i;
|
||||
if (dif && dif->to_be_reported())
|
||||
dif->report(out, indent);
|
||||
}
|
||||
|
||||
// Report about the parameters that got removed.
|
||||
bool emitted = false;
|
||||
@ -504,6 +550,50 @@ default_reporter::report(const function_type_diff& d, ostream& out,
|
||||
out << "\n";
|
||||
}
|
||||
|
||||
/// Build and emit a textual report about a @ref function_type_diff.
|
||||
///
|
||||
/// @param d the @ref function_type_diff to consider.
|
||||
///
|
||||
/// @param out the output stream.
|
||||
///
|
||||
/// @param indent the indentation string to use.
|
||||
void
|
||||
default_reporter::report(const function_type_diff& d, ostream& out,
|
||||
const string& indent) const
|
||||
{
|
||||
if (!d.to_be_reported())
|
||||
return;
|
||||
|
||||
function_type_sptr fft = d.first_function_type();
|
||||
function_type_sptr sft = d.second_function_type();
|
||||
|
||||
diff_context_sptr ctxt = d.context();
|
||||
corpus_sptr fc = ctxt->get_first_corpus();
|
||||
corpus_sptr sc = ctxt->get_second_corpus();
|
||||
|
||||
// Report about return type differences.
|
||||
if (d.priv_->return_type_diff_
|
||||
&& d.priv_->return_type_diff_->to_be_reported())
|
||||
{
|
||||
out << indent << "return type changed:\n";
|
||||
d.priv_->return_type_diff_->report(out, indent + " ");
|
||||
}
|
||||
|
||||
// Report about the parameter types that have changed sub-types.
|
||||
for (vector<fn_parm_diff_sptr>::const_iterator i =
|
||||
d.priv_->sorted_subtype_changed_parms_.begin();
|
||||
i != d.priv_->sorted_subtype_changed_parms_.end();
|
||||
++i)
|
||||
{
|
||||
diff_sptr dif = *i;
|
||||
if (dif && dif->to_be_reported())
|
||||
dif->report(out, indent);
|
||||
}
|
||||
|
||||
report_local_function_type_changes(d, out, indent);
|
||||
|
||||
}
|
||||
|
||||
/// Report a @ref array_diff in a serialized form.
|
||||
///
|
||||
/// @param d the @ref array_diff to consider.
|
||||
@ -1352,7 +1442,7 @@ default_reporter::report(const distinct_diff& d, ostream& out,
|
||||
type_base_sptr fs = strip_typedef(is_type(f)),
|
||||
ss = strip_typedef(is_type(s));
|
||||
|
||||
if (diff_sptr diff = d.compatible_child_diff())
|
||||
if (diff)
|
||||
diff->report(out, indent + " ");
|
||||
else
|
||||
if (report_size_and_alignment_changes(f, s, d.context(), out, indent,
|
||||
@ -1386,6 +1476,7 @@ default_reporter::report(const function_decl_diff& d, ostream& out,
|
||||
corpus_sptr fc = ctxt->get_first_corpus();
|
||||
corpus_sptr sc = ctxt->get_second_corpus();
|
||||
|
||||
|
||||
string qn1 = ff->get_qualified_name(), qn2 = sf->get_qualified_name(),
|
||||
linkage_names1, linkage_names2;
|
||||
elf_symbol_sptr s1 = ff->get_symbol(), s2 = sf->get_symbol();
|
||||
|
@ -3800,6 +3800,20 @@ uint64_t
|
||||
get_data_member_offset(const decl_base_sptr d)
|
||||
{return get_data_member_offset(dynamic_pointer_cast<var_decl>(d));}
|
||||
|
||||
/// Get the size of a given variable.
|
||||
///
|
||||
/// @param v the variable to consider.
|
||||
///
|
||||
/// @return the size of variable @p v.
|
||||
uint64_t
|
||||
get_var_size_in_bits(const var_decl_sptr& v)
|
||||
{
|
||||
type_base_sptr t = v->get_type();
|
||||
assert(t);
|
||||
|
||||
return t->get_size_in_bits();
|
||||
}
|
||||
|
||||
/// Set a flag saying if a data member is laid out.
|
||||
///
|
||||
/// @param m the data member to consider.
|
||||
@ -5278,13 +5292,15 @@ get_string_representation_of_cv_quals(const qualified_type_def::CV cv_quals)
|
||||
///
|
||||
/// @return the name of @p tod.
|
||||
string
|
||||
get_name(const type_or_decl_base_sptr& tod, bool qualified)
|
||||
get_name(const type_or_decl_base *tod, bool qualified)
|
||||
{
|
||||
string result;
|
||||
|
||||
if (type_base_sptr t = dynamic_pointer_cast<type_base>(tod))
|
||||
type_or_decl_base* a = const_cast<type_or_decl_base*>(tod);
|
||||
|
||||
if (type_base* t = dynamic_cast<type_base*>(a))
|
||||
result = get_type_name(t, qualified);
|
||||
else if (decl_base_sptr d = dynamic_pointer_cast<decl_base>(tod))
|
||||
else if (decl_base *d = dynamic_cast<decl_base*>(a))
|
||||
{
|
||||
if (qualified)
|
||||
result = d->get_qualified_name();
|
||||
@ -5298,6 +5314,19 @@ get_name(const type_or_decl_base_sptr& tod, bool qualified)
|
||||
return result;
|
||||
}
|
||||
|
||||
/// Build and return a copy of the name of an ABI artifact that is
|
||||
/// either a type of a decl.
|
||||
///
|
||||
/// @param tod the ABI artifact to get the name for.
|
||||
///
|
||||
/// @param qualified if yes, return the qualified name of @p tod;
|
||||
/// otherwise, return the non-qualified name;
|
||||
///
|
||||
/// @return the name of @p tod.
|
||||
string
|
||||
get_name(const type_or_decl_base_sptr& tod, bool qualified)
|
||||
{return get_name(tod.get(), qualified);}
|
||||
|
||||
/// Build and return a qualified name from a name and its scope.
|
||||
///
|
||||
/// The name is supposed to be for an entity that is part of the
|
||||
@ -19584,6 +19613,44 @@ size_t
|
||||
hash_type_or_decl(const type_or_decl_base_sptr& tod)
|
||||
{return hash_type_or_decl(tod.get());}
|
||||
|
||||
/// Test if the pretty representation of a given @ref function_decl is
|
||||
/// lexicographically less then the pretty representation of another
|
||||
/// @ref function_decl.
|
||||
///
|
||||
/// @param f the first @ref function_decl to consider for comparison.
|
||||
///
|
||||
/// @param s the second @ref function_decl to consider for comparison.
|
||||
///
|
||||
/// @return true iff the pretty representation of @p f is
|
||||
/// lexicographically less than the pretty representation of @p s.
|
||||
bool
|
||||
function_decl_is_less_than(const function_decl &f, const function_decl &s)
|
||||
{
|
||||
string fr = f.get_pretty_representation_of_declarator(),
|
||||
sr = s.get_pretty_representation_of_declarator();
|
||||
|
||||
if (fr != sr)
|
||||
return fr < sr;
|
||||
|
||||
fr = f.get_pretty_representation(),
|
||||
sr = s.get_pretty_representation();
|
||||
|
||||
if (fr != sr)
|
||||
return fr < sr;
|
||||
|
||||
if (f.get_symbol())
|
||||
fr = f.get_symbol()->get_id_string();
|
||||
else if (!f.get_linkage_name().empty())
|
||||
fr = f.get_linkage_name();
|
||||
|
||||
if (s.get_symbol())
|
||||
sr = s.get_symbol()->get_id_string();
|
||||
else if (!s.get_linkage_name().empty())
|
||||
sr = s.get_linkage_name();
|
||||
|
||||
return fr < sr;
|
||||
}
|
||||
|
||||
bool
|
||||
ir_traversable_base::traverse(ir_node_visitor&)
|
||||
{return true;}
|
||||
|
1107
src/abg-leaf-reporter.cc
Normal file
1107
src/abg-leaf-reporter.cc
Normal file
File diff suppressed because it is too large
Load Diff
@ -127,7 +127,7 @@ represent_data_member(var_decl_sptr d,
|
||||
///
|
||||
/// @param out the output stream to emit the string to.
|
||||
void
|
||||
maybe_show_relative_offset_change(var_diff_sptr diff,
|
||||
maybe_show_relative_offset_change(const var_diff_sptr &diff,
|
||||
diff_context& ctxt,
|
||||
ostream& out)
|
||||
{
|
||||
@ -158,6 +158,56 @@ maybe_show_relative_offset_change(var_diff_sptr diff,
|
||||
out << " (by " << sign << change << " bits)";
|
||||
}
|
||||
|
||||
/// If a given @ref var_diff node carries a hange in which the size of
|
||||
/// the variable actually changed, then emit a string (to an output
|
||||
/// stream) that represents that size change.
|
||||
///
|
||||
/// For instance, if the size of the variable increased by 32 bits
|
||||
/// then the string emitted is going to be "by +32 bits".
|
||||
///
|
||||
/// If, on the other hand, the size of the variable decreased by 64
|
||||
/// bits then the string emitted is going to be "by -64 bits".
|
||||
///
|
||||
/// This function is a sub-routine used by the reporting system.
|
||||
///
|
||||
/// @param diff the diff node that potentially carries the variable
|
||||
/// change.
|
||||
///
|
||||
/// @param ctxt the context in which the diff is being reported.
|
||||
///
|
||||
/// @param out the output stream to emit the string to.
|
||||
void
|
||||
maybe_show_relative_size_change(const var_diff_sptr &diff,
|
||||
diff_context& ctxt,
|
||||
ostream& out)
|
||||
{
|
||||
if (!ctxt.show_relative_offset_changes())
|
||||
return;
|
||||
|
||||
var_decl_sptr o = diff->first_var();
|
||||
var_decl_sptr n = diff->second_var();
|
||||
|
||||
uint64_t first_size = get_var_size_in_bits(o),
|
||||
second_size = get_var_size_in_bits(n);
|
||||
|
||||
string sign;
|
||||
uint64_t change = 0;
|
||||
if (first_size < second_size)
|
||||
{
|
||||
sign = "+";
|
||||
change = second_size - first_size;
|
||||
}
|
||||
else if (first_size > second_size)
|
||||
{
|
||||
sign = "-";
|
||||
change = first_size - second_size;
|
||||
}
|
||||
else
|
||||
return;
|
||||
|
||||
out << " (by " << sign << change << " bits)";
|
||||
}
|
||||
|
||||
/// Represent the changes carried by an instance of @ref var_diff that
|
||||
/// represent a difference between two class data members.
|
||||
///
|
||||
@ -165,16 +215,19 @@ maybe_show_relative_offset_change(var_diff_sptr diff,
|
||||
///
|
||||
/// @param ctxt the diff context to use.
|
||||
///
|
||||
/// @param local_only if true, only display local changes.
|
||||
///
|
||||
/// @param out the output stream to send the representation to.
|
||||
///
|
||||
/// @param indent the indentation string to use for the change report.
|
||||
void
|
||||
represent(var_diff_sptr diff,
|
||||
represent(const var_diff_sptr &diff,
|
||||
diff_context_sptr ctxt,
|
||||
ostream& out,
|
||||
const string& indent)
|
||||
const string& indent,
|
||||
bool local_only)
|
||||
{
|
||||
if (!diff->to_be_reported())
|
||||
if (!ctxt->get_reporter()->diff_to_be_reported(diff.get()))
|
||||
return;
|
||||
|
||||
var_decl_sptr o = diff->first_var();
|
||||
@ -186,21 +239,22 @@ represent(var_diff_sptr diff,
|
||||
string name2 = n->get_qualified_name();
|
||||
string pretty_representation = o->get_pretty_representation();
|
||||
|
||||
if (diff_sptr d = diff->type_diff())
|
||||
{
|
||||
if (d->to_be_reported())
|
||||
{
|
||||
out << indent
|
||||
<< "type of '" << pretty_representation << "' changed:\n";
|
||||
if (d->currently_reporting())
|
||||
out << indent << " details are being reported\n";
|
||||
else if (d->reported_once())
|
||||
out << indent << " details were reported earlier\n";
|
||||
else
|
||||
d->report(out, indent + " ");
|
||||
begin_with_and = true;
|
||||
}
|
||||
}
|
||||
if (!local_only)
|
||||
if (diff_sptr d = diff->type_diff())
|
||||
{
|
||||
if (ctxt->get_reporter()->diff_to_be_reported(d.get()))
|
||||
{
|
||||
out << indent
|
||||
<< "type of '" << pretty_representation << "' changed:\n";
|
||||
if (d->currently_reporting())
|
||||
out << indent << " details are being reported\n";
|
||||
else if (d->reported_once())
|
||||
out << indent << " details were reported earlier\n";
|
||||
else
|
||||
d->report(out, indent + " ");
|
||||
begin_with_and = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (name1 != name2)
|
||||
{
|
||||
@ -240,27 +294,50 @@ represent(var_diff_sptr diff,
|
||||
out << "now becomes laid out";
|
||||
emitted = true;
|
||||
}
|
||||
if ((ctxt->get_allowed_category() & SIZE_OR_OFFSET_CHANGE_CATEGORY)
|
||||
&& (get_data_member_offset(o)
|
||||
!= get_data_member_offset(n)))
|
||||
if ((ctxt->get_allowed_category() & SIZE_OR_OFFSET_CHANGE_CATEGORY))
|
||||
{
|
||||
if (begin_with_and)
|
||||
if (get_data_member_offset(o) != get_data_member_offset(n))
|
||||
{
|
||||
out << indent << "and ";
|
||||
begin_with_and = false;
|
||||
if (begin_with_and)
|
||||
{
|
||||
out << indent << "and ";
|
||||
begin_with_and = false;
|
||||
}
|
||||
else if (!emitted)
|
||||
out << indent << "'" << pretty_representation << "' ";
|
||||
else
|
||||
out << ", ";
|
||||
out << "offset changed from "
|
||||
<< get_data_member_offset(o)
|
||||
<< " to " << get_data_member_offset(n)
|
||||
<< " (in bits)";
|
||||
|
||||
maybe_show_relative_offset_change(diff, *ctxt, out);
|
||||
|
||||
emitted = true;
|
||||
}
|
||||
else if (!emitted)
|
||||
out << indent << "'" << pretty_representation << "' ";
|
||||
else
|
||||
out << ", ";
|
||||
out << "offset changed from "
|
||||
<< get_data_member_offset(o)
|
||||
<< " to " << get_data_member_offset(n)
|
||||
<< " (in bits)";
|
||||
if (// If we are not displaying only local changes, we must
|
||||
// have indicated the type size change already.
|
||||
local_only
|
||||
&& (get_var_size_in_bits(o) != get_var_size_in_bits(n)))
|
||||
{
|
||||
if (begin_with_and)
|
||||
{
|
||||
out << indent << "and ";
|
||||
begin_with_and = false;
|
||||
}
|
||||
else if (!emitted)
|
||||
out << indent << "'" << pretty_representation << "' ";
|
||||
else
|
||||
out << ", ";
|
||||
|
||||
maybe_show_relative_offset_change(diff, *ctxt, out);
|
||||
|
||||
emitted = true;
|
||||
out << "size changed from "
|
||||
<< get_var_size_in_bits(o)
|
||||
<< " to " << get_var_size_in_bits(n)
|
||||
<< " (in bits)";
|
||||
maybe_show_relative_size_change(diff, *ctxt, out);
|
||||
emitted = true;
|
||||
}
|
||||
}
|
||||
if (o->get_binding() != n->get_binding())
|
||||
{
|
||||
@ -566,6 +643,8 @@ report_name_size_and_alignment_changes(decl_base_sptr first,
|
||||
/// @param number the number of insertion/deletion to refer to in the
|
||||
/// header.
|
||||
///
|
||||
/// @param num_filtered the number of filtered changes.
|
||||
///
|
||||
/// @param k the kind of diff (insertion/deletion/change) we want the
|
||||
/// head to introduce.
|
||||
///
|
||||
@ -616,6 +695,45 @@ report_mem_header(ostream& out,
|
||||
out << colon_or_semi_colon << '\n';
|
||||
}
|
||||
|
||||
/// Output the header preceding the the report for
|
||||
/// insertion/deletion/change of a part of a class. This is a
|
||||
/// subroutine of class_diff::report.
|
||||
///
|
||||
/// @param out the output stream to output the report to.
|
||||
///
|
||||
/// @param k the kind of diff (insertion/deletion/change) we want the
|
||||
/// head to introduce.
|
||||
///
|
||||
/// @param section_name the name of the sub-part of the class to
|
||||
/// report about.
|
||||
///
|
||||
/// @param indent the string to use as indentation prefix in the
|
||||
/// header.
|
||||
void
|
||||
report_mem_header(ostream& out,
|
||||
diff_kind k,
|
||||
const string& section_name,
|
||||
const string& indent)
|
||||
{
|
||||
string change;
|
||||
|
||||
switch (k)
|
||||
{
|
||||
case del_kind:
|
||||
change = "deletions";
|
||||
break;
|
||||
case ins_kind:
|
||||
change = "insertions";
|
||||
break;
|
||||
case subtype_change_kind:
|
||||
case change_kind:
|
||||
change = "changes";
|
||||
break;
|
||||
}
|
||||
|
||||
out << indent << "there are " << section_name << " " << change << ":\n";
|
||||
}
|
||||
|
||||
/// Report the differences in access specifiers and static-ness for
|
||||
/// class members.
|
||||
///
|
||||
@ -813,5 +931,89 @@ show_linkage_name_and_aliases(ostream& out,
|
||||
out << ", aliases " << aliases;
|
||||
}
|
||||
|
||||
/// If a given diff node impacts some public interfaces, then report
|
||||
/// about those impacted interfaces on standard output.
|
||||
///
|
||||
/// @param d the diff node to get the impacted interfaces for.
|
||||
///
|
||||
/// @param out the output stream to report to.
|
||||
///
|
||||
/// @param indent the white space string to use for indentation.
|
||||
///
|
||||
/// @param new_line_prefix if set to true, it means there is going to
|
||||
/// be a new line emitted before the report.
|
||||
void
|
||||
maybe_report_interfaces_impacted_by_diff(const diff *d,
|
||||
ostream &out,
|
||||
const string &indent,
|
||||
bool new_line_prefix)
|
||||
{
|
||||
const diff_context_sptr &ctxt = d->context();
|
||||
const corpus_diff_sptr &corp_diff = ctxt->get_corpus_diff();
|
||||
if (!corp_diff)
|
||||
return;
|
||||
|
||||
if (!ctxt->show_impacted_interfaces())
|
||||
return;
|
||||
|
||||
const diff_maps &maps = corp_diff->get_leaf_diffs();
|
||||
artifact_sptr_set_type* impacted_artifacts =
|
||||
maps.lookup_impacted_interfaces(d);
|
||||
if (impacted_artifacts == 0)
|
||||
return;
|
||||
|
||||
if (impacted_artifacts->empty())
|
||||
return;
|
||||
|
||||
vector<type_or_decl_base_sptr> sorted_impacted_interfaces;
|
||||
sort_artifacts_set(*impacted_artifacts, sorted_impacted_interfaces);
|
||||
|
||||
if (new_line_prefix)
|
||||
out << '\n';
|
||||
|
||||
size_t num_impacted_interfaces = impacted_artifacts->size();
|
||||
if (num_impacted_interfaces == 1)
|
||||
out << indent << "one impacted interface:\n";
|
||||
else
|
||||
out << indent << num_impacted_interfaces << " impacted interfaces:\n";
|
||||
|
||||
string cur_indent = indent + " ";
|
||||
vector<type_or_decl_base_sptr>::const_iterator it;
|
||||
for (it = sorted_impacted_interfaces.begin();
|
||||
it != sorted_impacted_interfaces.end();
|
||||
++it)
|
||||
{
|
||||
if (it != sorted_impacted_interfaces.begin())
|
||||
out << '\n';
|
||||
out << cur_indent << get_pretty_representation(*it);
|
||||
}
|
||||
}
|
||||
|
||||
/// If a given diff node impacts some public interfaces, then report
|
||||
/// about those impacted interfaces on standard output.
|
||||
///
|
||||
/// @param d the diff node to get the impacted interfaces for.
|
||||
///
|
||||
/// @param out the output stream to report to.
|
||||
///
|
||||
/// @param indent the white space string to use for indentation.
|
||||
///
|
||||
/// @param new_line_prefix if set to true, it means there is going to
|
||||
/// be a new line emitted before the report.
|
||||
void
|
||||
maybe_report_interfaces_impacted_by_diff(const diff_sptr &d,
|
||||
ostream &out,
|
||||
const string &indent)
|
||||
{return maybe_report_interfaces_impacted_by_diff(d.get(), out, indent);}
|
||||
|
||||
/// Tests if the diff node is to be reported.
|
||||
///
|
||||
/// @param p the diff to consider.
|
||||
///
|
||||
/// @return true iff the diff is to be reported.
|
||||
bool
|
||||
reporter_base::diff_to_be_reported(const diff *d) const
|
||||
{return d && d->to_be_reported();}
|
||||
|
||||
} // namespace comparison
|
||||
} // end namespace abigail
|
||||
|
@ -35,7 +35,7 @@
|
||||
/// @param S1 the first diff subject to take in account.
|
||||
///
|
||||
/// @param S2 the second diff subject to take in account.
|
||||
#define RETURN_IF_BEING_REPORTED_OR_WAS_REPORTED_EARLIER(S1, S2) \
|
||||
#define RETURN_IF_BEING_REPORTED_OR_WAS_REPORTED_EARLIER(S1, S2) \
|
||||
do { \
|
||||
if (diff_context_sptr ctxt = d.context()) \
|
||||
if (diff_sptr _diff_ = ctxt->get_canonical_diff_for(S1, S2)) \
|
||||
@ -45,7 +45,7 @@
|
||||
out << indent << "details are being reported\n"; \
|
||||
else \
|
||||
out << indent << "details were reported earlier\n"; \
|
||||
return ; \
|
||||
return; \
|
||||
} \
|
||||
} while (false)
|
||||
|
||||
@ -119,15 +119,21 @@ represent_data_member(var_decl_sptr d,
|
||||
ostream& out);
|
||||
|
||||
void
|
||||
maybe_show_relative_offset_change(var_diff_sptr diff,
|
||||
maybe_show_relative_offset_change(const var_diff_sptr &diff,
|
||||
diff_context& ctxt,
|
||||
ostream& out);
|
||||
|
||||
void
|
||||
represent(var_diff_sptr diff,
|
||||
maybe_show_relative_size_change(const var_diff_sptr &diff,
|
||||
diff_context& ctxt,
|
||||
ostream& out);
|
||||
|
||||
void
|
||||
represent(const var_diff_sptr &diff,
|
||||
diff_context_sptr ctxt,
|
||||
ostream& out,
|
||||
const string& indent = "");
|
||||
const string& indent = "",
|
||||
bool local_only = false);
|
||||
|
||||
bool
|
||||
report_size_and_alignment_changes(type_or_decl_base_sptr first,
|
||||
@ -160,6 +166,12 @@ enum diff_kind
|
||||
change_kind
|
||||
};
|
||||
|
||||
void
|
||||
report_mem_header(ostream& out,
|
||||
diff_kind k,
|
||||
const string& section_name,
|
||||
const string& indent);
|
||||
|
||||
void
|
||||
report_mem_header(ostream& out,
|
||||
size_t number,
|
||||
@ -187,6 +199,18 @@ show_linkage_name_and_aliases(ostream& out,
|
||||
const elf_symbol& symbol,
|
||||
const string_elf_symbols_map_type& sym_map);
|
||||
|
||||
void
|
||||
maybe_report_interfaces_impacted_by_diff(const diff *d,
|
||||
ostream &out,
|
||||
const string &indent,
|
||||
bool new_line_prefix = true);
|
||||
|
||||
void
|
||||
maybe_report_interfaces_impacted_by_diff(const diff_sptr &d,
|
||||
ostream &out,
|
||||
const string &indent,
|
||||
bool new_line_prefix = false);
|
||||
|
||||
} // end namespace comparison
|
||||
} // end namespace abigail
|
||||
|
||||
|
@ -248,8 +248,8 @@ sonames_of_binaries_match(const suppression_base& suppr,
|
||||
const diff_context& ctxt)
|
||||
{
|
||||
// Check if the sonames of the binaries match
|
||||
string first_soname = ctxt.get_first_corpus()->get_soname(),
|
||||
second_soname = ctxt.get_second_corpus()->get_soname();
|
||||
string first_soname = ctxt.get_corpus_diff()->first_corpus()->get_soname(),
|
||||
second_soname = ctxt.get_corpus_diff()->second_corpus()->get_soname();
|
||||
|
||||
if (!suppr.priv_->matches_soname(first_soname)
|
||||
&& !suppr.priv_->matches_soname(second_soname))
|
||||
@ -275,8 +275,8 @@ names_of_binaries_match(const suppression_base& suppr,
|
||||
const diff_context &ctxt)
|
||||
{
|
||||
// Check if the file names of the binaries match
|
||||
string first_binary_path = ctxt.get_first_corpus()->get_path(),
|
||||
second_binary_path = ctxt.get_second_corpus()->get_path();
|
||||
string first_binary_path = ctxt.get_corpus_diff()->first_corpus()->get_path(),
|
||||
second_binary_path = ctxt.get_corpus_diff()->second_corpus()->get_path();
|
||||
|
||||
if (!suppr.priv_->matches_binary_name(first_binary_path)
|
||||
&& !suppr.priv_->matches_binary_name(second_binary_path))
|
||||
|
@ -635,6 +635,11 @@ test-diff-filter/test40-v1.cc \
|
||||
test-diff-filter/test41-PR21486-abg-writer.gcc.o \
|
||||
test-diff-filter/test41-PR21486-abg-writer.llvm.o \
|
||||
test-diff-filter/test41-report-0.txt \
|
||||
test-diff-filter/libtest42-leaf-report-v0.so \
|
||||
test-diff-filter/libtest42-leaf-report-v1.so \
|
||||
test-diff-filter/test42-leaf-report-output-0.txt \
|
||||
test-diff-filter/test42-leaf-report-v0.cc \
|
||||
test-diff-filter/test42-leaf-report-v1.cc \
|
||||
\
|
||||
test-diff-suppr/test0-type-suppr-v0.cc \
|
||||
test-diff-suppr/test0-type-suppr-v1.cc \
|
||||
@ -1086,6 +1091,17 @@ test-diff-suppr/test34-pub-include-dir-v1/test34-pub-include-v1.h \
|
||||
test-diff-suppr/test34-report-0.txt \
|
||||
test-diff-suppr/test34-v0.c \
|
||||
test-diff-suppr/test34-v1.c \
|
||||
test-diff-suppr/libtest35-leaf-v0.so \
|
||||
test-diff-suppr/libtest35-leaf-v1.so \
|
||||
test-diff-suppr/test35-leaf-report-0.txt \
|
||||
test-diff-suppr/test35-leaf-v0.cc \
|
||||
test-diff-suppr/test35-leaf-v1.cc \
|
||||
test-diff-suppr/test35-leaf.suppr \
|
||||
test-diff-suppr/libtest36-leaf-v0.so \
|
||||
test-diff-suppr/libtest36-leaf-v1.so \
|
||||
test-diff-suppr/test36-leaf-report-0.txt \
|
||||
test-diff-suppr/test36-leaf-v0.cc \
|
||||
test-diff-suppr/test36-leaf-v1.cc \
|
||||
\
|
||||
test-diff-dwarf-abixml/test0-pr19026-libvtkIOSQL-6.1.so.1 \
|
||||
test-diff-dwarf-abixml/test0-pr19026-libvtkIOSQL-6.1.so.1.abi \
|
||||
|
BIN
tests/data/test-diff-filter/libtest42-leaf-report-v0.so
Executable file
BIN
tests/data/test-diff-filter/libtest42-leaf-report-v0.so
Executable file
Binary file not shown.
BIN
tests/data/test-diff-filter/libtest42-leaf-report-v1.so
Executable file
BIN
tests/data/test-diff-filter/libtest42-leaf-report-v1.so
Executable file
Binary file not shown.
11
tests/data/test-diff-filter/test42-leaf-report-output-0.txt
Normal file
11
tests/data/test-diff-filter/test42-leaf-report-output-0.txt
Normal file
@ -0,0 +1,11 @@
|
||||
Leaf changes summary: 1 artifact changed
|
||||
Added/removed functions summary: 0 Removed, 0 Added function
|
||||
Added/removed variables summary: 0 Removed, 0 Added variable
|
||||
|
||||
'struct leaf' changed:
|
||||
type size changed from 32 to 64 bits
|
||||
1 data member insertion:
|
||||
'char leaf::m1', at offset 32 (in bits) at test42-leaf-report-v1.cc:7:1
|
||||
|
||||
one impacted interface:
|
||||
function void fn(C&)
|
16
tests/data/test-diff-filter/test42-leaf-report-v0.cc
Normal file
16
tests/data/test-diff-filter/test42-leaf-report-v0.cc
Normal file
@ -0,0 +1,16 @@
|
||||
// Compile this with:
|
||||
// g++ -shared -g -o libtest42-leaf-report-v0.so test42-leaf-report-v0.cc
|
||||
|
||||
struct leaf
|
||||
{
|
||||
int m0;
|
||||
};
|
||||
|
||||
struct C
|
||||
{
|
||||
leaf *m0;
|
||||
};
|
||||
|
||||
void
|
||||
fn(C&)
|
||||
{}
|
17
tests/data/test-diff-filter/test42-leaf-report-v1.cc
Normal file
17
tests/data/test-diff-filter/test42-leaf-report-v1.cc
Normal file
@ -0,0 +1,17 @@
|
||||
// Compile this with:
|
||||
// g++ -shared -g -o libtest42-leaf-report-v1.so test42-leaf-report-v1.cc
|
||||
|
||||
struct leaf
|
||||
{
|
||||
int m0;
|
||||
char m1;
|
||||
};
|
||||
|
||||
struct C
|
||||
{
|
||||
leaf *m0;
|
||||
};
|
||||
|
||||
void
|
||||
fn(C&)
|
||||
{}
|
BIN
tests/data/test-diff-suppr/libtest35-leaf-v0.so
Executable file
BIN
tests/data/test-diff-suppr/libtest35-leaf-v0.so
Executable file
Binary file not shown.
BIN
tests/data/test-diff-suppr/libtest35-leaf-v1.so
Executable file
BIN
tests/data/test-diff-suppr/libtest35-leaf-v1.so
Executable file
Binary file not shown.
BIN
tests/data/test-diff-suppr/libtest36-leaf-v0.so
Executable file
BIN
tests/data/test-diff-suppr/libtest36-leaf-v0.so
Executable file
Binary file not shown.
BIN
tests/data/test-diff-suppr/libtest36-leaf-v1.so
Executable file
BIN
tests/data/test-diff-suppr/libtest36-leaf-v1.so
Executable file
Binary file not shown.
11
tests/data/test-diff-suppr/test35-leaf-report-0.txt
Normal file
11
tests/data/test-diff-suppr/test35-leaf-report-0.txt
Normal file
@ -0,0 +1,11 @@
|
||||
Leaf changes summary: 1 artifact changed (1 filtered out)
|
||||
Added/removed functions summary: 0 Removed, 0 Added function
|
||||
Added/removed variables summary: 0 Removed, 0 Added variable
|
||||
|
||||
'struct leaf' changed:
|
||||
type size changed from 32 to 64 bits
|
||||
1 data member insertion:
|
||||
'char leaf::m1', at offset 32 (in bits) at test35-leaf-v1.cc:8:1
|
||||
|
||||
one impacted interface:
|
||||
function void fn(C&)
|
23
tests/data/test-diff-suppr/test35-leaf-v0.cc
Normal file
23
tests/data/test-diff-suppr/test35-leaf-v0.cc
Normal file
@ -0,0 +1,23 @@
|
||||
// Compile this with:
|
||||
//
|
||||
// g++ -shared -g -o libtest35-leaf-v0.so test35-leaf-v0.cc
|
||||
|
||||
struct leaf
|
||||
{
|
||||
int m0;
|
||||
};
|
||||
|
||||
struct leaf_to_filter
|
||||
{
|
||||
int member0;
|
||||
};
|
||||
|
||||
struct C
|
||||
{
|
||||
leaf *m0;
|
||||
leaf_to_filter *m1;
|
||||
};
|
||||
|
||||
void
|
||||
fn(C&)
|
||||
{}
|
25
tests/data/test-diff-suppr/test35-leaf-v1.cc
Normal file
25
tests/data/test-diff-suppr/test35-leaf-v1.cc
Normal file
@ -0,0 +1,25 @@
|
||||
// Compile this with:
|
||||
//
|
||||
// g++ -shared -g -o libtest35-leaf-v1.so test35-leaf-v1.cc
|
||||
|
||||
struct leaf
|
||||
{
|
||||
int m0;
|
||||
char m1;
|
||||
};
|
||||
|
||||
struct leaf_to_filter
|
||||
{
|
||||
int member0;
|
||||
int added;
|
||||
};
|
||||
|
||||
struct C
|
||||
{
|
||||
leaf *m0;
|
||||
leaf_to_filter *m1;
|
||||
};
|
||||
|
||||
void
|
||||
fn(C&)
|
||||
{}
|
8
tests/data/test-diff-suppr/test35-leaf.suppr
Normal file
8
tests/data/test-diff-suppr/test35-leaf.suppr
Normal file
@ -0,0 +1,8 @@
|
||||
[suppress_type]
|
||||
|
||||
# Suppress the type that had a data member inserted after the data
|
||||
# member named 'member0'. That would be the type named
|
||||
# leaf_to_filter.
|
||||
|
||||
name_regexp = *.
|
||||
has_data_member_inserted_between = {offset_after(member0), end}
|
25
tests/data/test-diff-suppr/test36-leaf-report-0.txt
Normal file
25
tests/data/test-diff-suppr/test36-leaf-report-0.txt
Normal file
@ -0,0 +1,25 @@
|
||||
Leaf changes summary: 2 artifacts changed
|
||||
Added/removed functions summary: 0 Removed, 0 Added function
|
||||
Added/removed variables summary: 0 Removed, 0 Added variable
|
||||
|
||||
'struct leaf2' changed:
|
||||
type size changed from 64 to 96 bits
|
||||
there are data member changes:
|
||||
'leaf1 leaf2::member0' size changed from 32 to 64 (in bits) (by +32 bits)
|
||||
'char leaf2::member1' offset changed from 32 to 64 (in bits) (by +32 bits)
|
||||
|
||||
3 impacted interfaces:
|
||||
function void interface1(struct_type*)
|
||||
function void interface2(struct_type&)
|
||||
function void interface3(struct_type**)
|
||||
|
||||
|
||||
'struct leaf1' changed:
|
||||
type size changed from 32 to 64 bits
|
||||
1 data member insertion:
|
||||
'char leaf1::m1', at offset 32 (in bits) at test36-leaf-v1.cc:7:1
|
||||
|
||||
3 impacted interfaces:
|
||||
function void interface1(struct_type*)
|
||||
function void interface2(struct_type&)
|
||||
function void interface3(struct_type**)
|
30
tests/data/test-diff-suppr/test36-leaf-v0.cc
Normal file
30
tests/data/test-diff-suppr/test36-leaf-v0.cc
Normal file
@ -0,0 +1,30 @@
|
||||
// Compile this with:
|
||||
// g++ -g -shared -o libtest36-leaf-v0.so test36-leaf-v0.cc
|
||||
|
||||
struct leaf1
|
||||
{
|
||||
int m0;
|
||||
}; // end struct leaf1
|
||||
|
||||
struct leaf2
|
||||
{
|
||||
leaf1 member0;
|
||||
char member1;
|
||||
}; // end struct leaf2
|
||||
|
||||
struct struct_type
|
||||
{
|
||||
leaf2* m0;
|
||||
};
|
||||
|
||||
void
|
||||
interface1(struct_type*)
|
||||
{}
|
||||
|
||||
void
|
||||
interface2(struct_type&)
|
||||
{}
|
||||
|
||||
void
|
||||
interface3(struct_type**)
|
||||
{}
|
31
tests/data/test-diff-suppr/test36-leaf-v1.cc
Normal file
31
tests/data/test-diff-suppr/test36-leaf-v1.cc
Normal file
@ -0,0 +1,31 @@
|
||||
// Compile this with:
|
||||
// g++ -g -shared -o libtest36-leaf-v1.so test36-leaf-v1.cc
|
||||
|
||||
struct leaf1
|
||||
{
|
||||
int m0;
|
||||
char m1;
|
||||
}; // end struct leaf1
|
||||
|
||||
struct leaf2
|
||||
{
|
||||
leaf1 member0;
|
||||
char member1;
|
||||
}; // end struct leaf2
|
||||
|
||||
struct struct_type
|
||||
{
|
||||
leaf2* m0;
|
||||
};
|
||||
|
||||
void
|
||||
interface1(struct_type*)
|
||||
{}
|
||||
|
||||
void
|
||||
interface2(struct_type&)
|
||||
{}
|
||||
|
||||
void
|
||||
interface3(struct_type**)
|
||||
{}
|
@ -478,6 +478,13 @@ InOutSpec in_out_specs[] =
|
||||
"data/test-diff-filter/test41-report-0.txt",
|
||||
"output/test-diff-filter/test41-report-0.txt",
|
||||
},
|
||||
{
|
||||
"data/test-diff-filter/libtest42-leaf-report-v0.so",
|
||||
"data/test-diff-filter/libtest42-leaf-report-v1.so",
|
||||
"--no-default-suppression --leaf-changes-only --impacted-interfaces",
|
||||
"data/test-diff-filter/test42-leaf-report-output-0.txt",
|
||||
"output/test-diff-filter/test42-leaf-report-output-0.txt",
|
||||
},
|
||||
// This should be the last entry
|
||||
{NULL, NULL, NULL, NULL, NULL}
|
||||
};
|
||||
|
@ -1,6 +1,6 @@
|
||||
// -*- Mode: C++ -*-
|
||||
//
|
||||
// Copyright (C) 2013-2016 Red Hat, Inc.
|
||||
// Copyright (C) 2013-2017 Red Hat, Inc.
|
||||
//
|
||||
// This file is part of the GNU Application Binary Interface Generic
|
||||
// Analysis and Instrumentation Library (libabigail). This library is
|
||||
@ -1678,6 +1678,26 @@ InOutSpec in_out_specs[] =
|
||||
"data/test-diff-suppr/test34-report-0.txt",
|
||||
"output/test-diff-suppr/test34-report-0.txt"
|
||||
},
|
||||
{
|
||||
"data/test-diff-suppr/libtest35-leaf-v0.so",
|
||||
"data/test-diff-suppr/libtest35-leaf-v1.so",
|
||||
"",
|
||||
"",
|
||||
"data/test-diff-suppr/test35-leaf.suppr",
|
||||
"--no-default-suppression --leaf-changes-only --impacted-interfaces",
|
||||
"data/test-diff-suppr/test35-leaf-report-0.txt",
|
||||
"output/test-diff-suppr/test35-leaf-report-0.txt"
|
||||
},
|
||||
{
|
||||
"data/test-diff-suppr/libtest36-leaf-v0.so",
|
||||
"data/test-diff-suppr/libtest36-leaf-v1.so",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"--no-default-suppression --leaf-changes-only --impacted-interfaces",
|
||||
"data/test-diff-suppr/test36-leaf-report-0.txt",
|
||||
"output/test-diff-suppr/test36-leaf-report-0.txt"
|
||||
},
|
||||
// This should be the last entry
|
||||
{NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}
|
||||
};
|
||||
|
@ -85,6 +85,7 @@ struct options
|
||||
bool no_default_supprs;
|
||||
bool no_arch;
|
||||
bool no_corpus;
|
||||
bool leaf_changes_only;
|
||||
bool show_relative_offset_changes;
|
||||
bool show_stats_only;
|
||||
bool show_symtabs;
|
||||
@ -103,6 +104,7 @@ struct options
|
||||
bool show_harmless_changes;
|
||||
bool show_redundant_changes;
|
||||
bool show_symbols_not_referenced_by_debug_info;
|
||||
bool show_impacted_interfaces;
|
||||
bool dump_diff_tree;
|
||||
bool show_stats;
|
||||
bool do_log;
|
||||
@ -118,6 +120,7 @@ struct options
|
||||
no_default_supprs(),
|
||||
no_arch(),
|
||||
no_corpus(),
|
||||
leaf_changes_only(),
|
||||
show_relative_offset_changes(true),
|
||||
show_stats_only(),
|
||||
show_symtabs(),
|
||||
@ -136,6 +139,7 @@ struct options
|
||||
show_harmless_changes(),
|
||||
show_redundant_changes(),
|
||||
show_symbols_not_referenced_by_debug_info(true),
|
||||
show_impacted_interfaces(),
|
||||
dump_diff_tree(),
|
||||
show_stats(),
|
||||
do_log()
|
||||
@ -166,6 +170,8 @@ display_usage(const string& prog_name, ostream& out)
|
||||
"default suppression specification\n"
|
||||
<< " --no-architecture do not take architecture in account\n"
|
||||
<< " --no-corpus-path do not take the path to the corpora into account\n"
|
||||
<< " --leaf-changes-only|-l only show leaf changes, "
|
||||
"so no change impact analysis\n"
|
||||
<< " --deleted-fns display deleted public functions\n"
|
||||
<< " --changed-fns display changed public functions\n"
|
||||
<< " --added-fns display added public functions\n"
|
||||
@ -192,6 +198,8 @@ display_usage(const string& prog_name, ostream& out)
|
||||
<< " --redundant display redundant changes\n"
|
||||
<< " --no-redundant do not display redundant changes "
|
||||
"(this is the default)\n"
|
||||
<< " --impacted-interfaces do not display interfaces impacted"
|
||||
" by leaf changes\n"
|
||||
<< " --dump-diff-tree emit a debug dump of the internal diff tree to "
|
||||
"the error output stream\n"
|
||||
<< " --stats show statistics about various internal stuff\n"
|
||||
@ -321,6 +329,9 @@ parse_command_line(int argc, char* argv[], options& opts)
|
||||
opts.no_arch = true;
|
||||
else if (!strcmp(argv[i], "--no-corpus-path"))
|
||||
opts.no_corpus = true;
|
||||
else if (!strcmp(argv[i], "--leaf-changes-only")
|
||||
||!strcmp(argv[i], "-l"))
|
||||
opts.leaf_changes_only = true;
|
||||
else if (!strcmp(argv[i], "--deleted-fns"))
|
||||
{
|
||||
opts.show_deleted_fns = true;
|
||||
@ -484,6 +495,8 @@ parse_command_line(int argc, char* argv[], options& opts)
|
||||
opts.show_redundant_changes = true;
|
||||
else if (!strcmp(argv[i], "--no-redundant"))
|
||||
opts.show_redundant_changes = false;
|
||||
else if (!strcmp(argv[i], "--impacted-interfaces"))
|
||||
opts.show_impacted_interfaces = true;
|
||||
else if (!strcmp(argv[i], "--dump-diff-tree"))
|
||||
opts.dump_diff_tree = true;
|
||||
else if (!strcmp(argv[i], "--stats"))
|
||||
@ -577,6 +590,7 @@ set_diff_context_from_opts(diff_context_sptr ctxt,
|
||||
{
|
||||
ctxt->default_output_stream(&cout);
|
||||
ctxt->error_output_stream(&cerr);
|
||||
ctxt->show_leaf_changes_only(opts.leaf_changes_only);
|
||||
ctxt->show_relative_offset_changes(opts.show_relative_offset_changes);
|
||||
ctxt->show_stats_only(opts.show_stats_only);
|
||||
ctxt->show_deleted_fns(opts.show_all_fns || opts.show_deleted_fns);
|
||||
@ -592,6 +606,7 @@ set_diff_context_from_opts(diff_context_sptr ctxt,
|
||||
(opts.show_symbols_not_referenced_by_debug_info);
|
||||
ctxt->show_added_symbols_unreferenced_by_debug_info
|
||||
(opts.show_symbols_not_referenced_by_debug_info && opts.show_added_syms);
|
||||
ctxt->show_impacted_interfaces(opts.show_impacted_interfaces);
|
||||
|
||||
if (!opts.show_harmless_changes)
|
||||
ctxt->switch_categories_off(get_default_harmless_categories_bitmap());
|
||||
|
Loading…
Reference in New Issue
Block a user