the global variables that were added (defined) to
*second-shared-library*.
+ * ``--non-reachable-types|-t``
+
+ Analyze and emit change reports for all the types of the binary,
+ including those that are not reachable from global functions and
+ variables.
+
+ This option might incur some serious performance degradation as
+ the number of types analyzed can be huge. However, if paired with
+ the ``--headers-dir{1,2}`` options, the additional non-reachable
+ types analyzed are restricted to those defined in public headers
+ files, thus hopefully making the performance hit acceptable.
+
+ Also, using this option alongside suppression specifications (by
+ also using the ``--suppressions`` option) might help keep the number of
+ analyzed types (and the potential performance degradation) in
+ control.
+
+ Note that without this option, only types that are reachable from
+ global functions and variables are analyzed, so the tool detects
+ and reports changes on these reachable types only.
+
* ``--no-added-syms``
In the resulting report about the differences between
$
+ * ``--non-reachable-types|-t``
+
+ Analyze and emit change reports for all the types of the binary,
+ including those that are not reachable from global functions and
+ variables.
+
+ This option might incur some serious performance degradation as
+ the number of types analyzed can be huge. However, if paired with
+ the ``--devel-pkg{1,2}`` options, the additional non-reachable
+ types analyzed are restricted to those defined in the public
+ headers files carried by the referenced development packages, thus
+ hopefully making the performance hit acceptable.
+
+ Also, using this option alongside suppression specifications (by
+ also using the ``--suppressions`` option) might help keep the number of
+ analyzed types (and the potential performance degradation) in
+ control.
+
+ Note that without this option, only types that are reachable from
+ global functions and variables are analyzed, so the tool detects
+ and reports changes on these reachable types only.
+
* ``--redundant``
In the diff reports, do display redundant changes. A redundant
/// value is a @ref decl_base_sptr.
typedef unordered_map<string, decl_base_sptr> string_decl_base_sptr_map;
+/// Convenience typedef for a map which key is a string and which
+/// value is a @ref type_base_sptr.
+typedef unordered_map<string, type_base_sptr> string_type_base_sptr_map;
+
/// Convenience typedef for a map which key is an unsigned integer and
/// which value is a @ref decl_base_sptr
typedef unordered_map<unsigned, decl_base_sptr> unsigned_decl_base_sptr_map;
void
show_added_symbols_unreferenced_by_debug_info(bool f);
+ void show_unreachable_types(bool f);
+
+ bool show_unreachable_types();
+
bool
show_impacted_interfaces() const;
const string_elf_symbol_map&
added_unrefed_variable_symbols() const;
+ const string_type_base_sptr_map&
+ deleted_unreachable_types() const;
+
+ const vector<type_base_sptr>&
+ deleted_unreachable_types_sorted() const;
+
+ const string_type_base_sptr_map&
+ added_unreachable_types() const;
+
+ const vector<type_base_sptr>&
+ added_unreachable_types_sorted() const;
+
+ const string_diff_sptr_map&
+ changed_unreachable_types() const;
+
+ const vector<diff_sptr>&
+ changed_unreachable_types_sorted() const;
+
const diff_context_sptr
context() const;
friend void
apply_suppressions(const corpus_diff* diff_tree);
+ friend void
+ maybe_report_unreachable_type_changes(const corpus_diff& d,
+ const corpus_diff::diff_stats &s,
+ const string& indent,
+ ostream& out);
+
friend class default_reporter;
friend class leaf_reporter;
}; // end class corpus_diff
size_t num_leaf_var_changes_filtered_out() const;
void num_leaf_var_changes_filtered_out(size_t);
size_t net_num_leaf_var_changes() const;
+
+ size_t num_added_unreachable_types() const;
+ void num_added_unreachable_types(size_t);
+
+ size_t num_added_unreachable_types_filtered_out() const;
+ void num_added_unreachable_types_filtered_out(size_t);
+ size_t net_num_added_unreachable_types() const;
+
+ size_t num_removed_unreachable_types() const;
+ void num_removed_unreachable_types(size_t);
+
+ size_t num_removed_unreachable_types_filtered_out() const;
+ void num_removed_unreachable_types_filtered_out(size_t);
+ size_t net_num_removed_unreachable_types() const;
+
+ size_t num_changed_unreachable_types() const;
+ void num_changed_unreachable_types(size_t);
+
+ size_t num_changed_unreachable_types_filtered_out() const;
+ void num_changed_unreachable_types_filtered_out(size_t);
+ size_t net_num_changed_unreachable_types() const;
+
}; // end class corpus_diff::diff_stats
/// The base class for the node visitors. These are the types used to
const type_maps&
get_type_per_loc_map() const;
+ virtual bool
+ recording_types_reachable_from_public_interface_supported();
+
+ void
+ record_type_as_reachable_from_public_interfaces(const type_base&);
+
+ bool
+ type_is_reachable_from_public_interfaces(const type_base&) const;
+
+ const vector<type_base_wptr>&
+ get_types_not_reachable_from_public_interfaces() const;
+
const corpus_group*
get_group() const;
virtual const elf_symbols&
get_unreferenced_variable_symbols() const;
+ unordered_set<interned_string, hash_interned_string>*
+ get_public_types_pretty_representations();
+
+ virtual bool
+ recording_types_reachable_from_public_interface_supported();
+
bool
operator==(const corpus_group&) const;
}; // end class corpus_group
return *first == *second;
}
+ /// This equality operator compares pointers by comparing the
+ /// pointed-to objects.
+ ///
+ /// @param first the first comparison argument.
+ ///
+ /// @param second the second comparison argument.
+ ///
+ /// @return true if the objects pointed to by the pointers are
+ /// equal, false otherwise.
template<typename T>
bool
operator()(const shared_ptr<T> first,
const shared_ptr<T> second) const
{return operator()(first.get(), second.get());}
-};
+
+ /// This equality operator compares pointers by comparing the
+ /// pointed-to objects.
+ ///
+ /// @param first the first comparison argument.
+ ///
+ /// @param second the second comparison argument.
+ ///
+ /// @return true if the objects pointed to by the pointers are
+ /// equal, false otherwise.
+ template<typename T>
+ bool
+ operator()(const weak_ptr<T> first,
+ const weak_ptr<T> second) const
+ {return operator()(shared_ptr<T>(first), shared_ptr<T>(second));}
+}; // end struct deep_ptr_eq_functor
/// Find the end of the furthest reaching d-path on diagonal k, for
/// two sequences. In the paper This is referred to as "the basic
bool
is_member_type(const type_base_sptr&);
+bool
+is_user_defined_type(const type_base*);
+
+bool
+is_user_defined_type(const type_base_sptr&);
+
void
remove_decl_from_scope(decl_base_sptr);
/// Convenience typedef for a vector of @ref suppression_sptr
typedef vector<suppression_sptr> suppressions_type;
-} // end namespace comparison
+} // end namespace suppr
void
dump(const decl_base_sptr, std::ostream&);
///
/// For instance, the type_maps contains a map of string to basic
/// type, a map of string to class type, a map of string to union
-/// types, etc.
+/// types, etc. The key of a map entry is the pretty representation
+/// of the type, and the value of the map entry is the type.
class type_maps
{
struct priv;
const istring_type_base_wptrs_map_type&
function_types() const;
+
+ const vector<type_base_wptr>&
+ get_types_sorted_by_name() const;
}; // end class type_maps;
/// This is the abstraction of the set of relevant artefacts (types,
void
set_is_anonymous(bool);
+ bool
+ get_is_artificial() const;
+
+ void
+ set_is_artificial(bool);
+
bool
get_has_anonymous_parent() const;
bool
operator==(const decl_base_sptr&, const decl_base_sptr&);
+bool
+operator!=(const decl_base_sptr&, const decl_base_sptr&);
+
bool
operator==(const type_base_sptr&, const type_base_sptr&);
void
set_index(unsigned i);
- bool
- get_artificial() const;
-
- void
- set_artificial(bool f);
-
bool
get_variadic_marker() const;
add_read_context_suppressions(read_context& ctxt,
const suppr::suppressions_type& supprs);
+void
+consider_types_not_reachable_from_public_interfaces(read_context& ctxt,
+ bool flag);
}//end xml_reader
}//end namespace abigail
bool show_redundant_changes_;
bool show_syms_unreferenced_by_di_;
bool show_added_syms_unreferenced_by_di_;
+ bool show_unreachable_types_;
bool show_impacted_interfaces_;
bool dump_diff_tree_;
show_redundant_changes_(true),
show_syms_unreferenced_by_di_(true),
show_added_syms_unreferenced_by_di_(true),
+ show_unreachable_types_(false),
show_impacted_interfaces_(true),
dump_diff_tree_()
{}
/// A comparison functor for instances of @ref diff.
struct diff_comp
{
+ /// Lexicographically compare two diff nodes.
+ ///
+ /// Compare the pretty representation of the first subjects of two
+ /// diff nodes.
+ ///
+ /// @return true iff @p l is less than @p r.
bool
operator()(const diff& l, diff& r) const
{
- return (get_name(l.first_subject()) < get_name(r.first_subject()));
+ return (get_pretty_representation(l.first_subject(), true)
+ <
+ get_pretty_representation(r.first_subject(), true));
}
+ /// Lexicographically compare two diff nodes.
+ ///
+ /// Compare the pretty representation of the first subjects of two
+ /// diff nodes.
+ ///
+ /// @return true iff @p l is less than @p r.
bool
operator()(const diff* l, diff* r) const
{return operator()(*l, *r);}
+ /// Lexicographically compare two diff nodes.
+ ///
+ /// Compare the pretty representation of the first subjects of two
+ /// diff nodes.
+ ///
+ /// @return true iff @p l is less than @p r.
bool
operator()(const diff_sptr l, diff_sptr r) const
{return operator()(l.get(), r.get());}
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_;
+ edit_script unreachable_types_edit_script_;
+ string_type_base_sptr_map deleted_unreachable_types_;
+ vector<type_base_sptr> deleted_unreachable_types_sorted_;
+ string_type_base_sptr_map suppressed_deleted_unreachable_types_;
+ string_type_base_sptr_map added_unreachable_types_;
+ vector<type_base_sptr> added_unreachable_types_sorted_;
+ string_type_base_sptr_map suppressed_added_unreachable_types_;
+ string_diff_sptr_map changed_unreachable_types_;
+ mutable vector<diff_sptr> changed_unreachable_types_sorted_;
diff_maps leaf_diffs_;
/// Default constructor of corpus_diff::priv.
ensure_lookup_tables_populated();
void
- apply_suppressions_to_added_removed_fns_vars();
+ apply_supprs_to_added_removed_fns_vars_unreachable_types();
bool
deleted_function_is_suppressed(const function_decl* fn) const;
bool
added_variable_is_suppressed(const var_decl* var) const;
+ bool
+ added_unreachable_type_is_suppressed(const type_base *t)const ;
+
+ bool
+ deleted_unreachable_type_is_suppressed(const type_base *t)const ;
+
bool
deleted_unrefed_fn_sym_is_suppressed(const elf_symbol*) const;
void count_leaf_type_changes(size_t &num_type_changes,
size_t &num_type_changes_filtered);
+ void count_unreachable_types(size_t &num_added_unreachable_types,
+ size_t &num_removed_unreachable_types,
+ size_t &num_changed_unreachable_types,
+ size_t &num_filtered_added_unreachable_types,
+ size_t &num_filtered_removed_unreachable_types,
+ size_t &num_filtered_changed_unreachable_types);
+
+ const vector<diff_sptr>&
+ changed_unreachable_types_sorted() const;
+
void
apply_filters_and_compute_diff_stats(corpus_diff::diff_stats&);
size_t num_leaf_func_changes_filtered_out;
size_t num_leaf_var_changes;
size_t num_leaf_var_changes_filtered_out;
+ size_t num_added_unreachable_types;
+ size_t num_added_unreachable_types_filtered_out;
+ size_t num_removed_unreachable_types;
+ size_t num_removed_unreachable_types_filtered_out;
+ size_t num_changed_unreachable_types;
+ size_t num_changed_unreachable_types_filtered_out;
priv(diff_context_sptr ctxt)
: ctxt_(ctxt),
num_leaf_func_changes(),
num_leaf_func_changes_filtered_out(),
num_leaf_var_changes(),
- num_leaf_var_changes_filtered_out()
+ num_leaf_var_changes_filtered_out(),
+ num_added_unreachable_types(),
+ num_added_unreachable_types_filtered_out(),
+ num_removed_unreachable_types(),
+ num_removed_unreachable_types_filtered_out(),
+ num_changed_unreachable_types(),
+ num_changed_unreachable_types_filtered_out()
{}
diff_context_sptr
vector<function_decl*>& sorted);
void
+sort_string_type_base_sptr_map(string_type_base_sptr_map& map,
+ vector<type_base_sptr>& sorted);
+void
sort_string_function_decl_diff_sptr_map
(const string_function_decl_diff_sptr_map& map,
function_decl_diff_sptrs_type& sorted);
++i)
sorted.push_back(i->second);
- // TODO: finish this.
parm_comp comp;
std::sort(sorted.begin(), sorted.end(), comp);
}
std::sort(sorted.begin(), sorted.end(), comp);
}
+/// Sort a map of string to type_base_sptr entities.
+///
+/// The entries are sorted based on the lexicographic order of the
+/// pretty representation of the type_sptr_sptr. The sorted result is
+/// put in a vector of type_base_sptr.
+///
+/// @param map the map to sort.
+///
+/// @param sorted the resulting vector of type_base_sptr
+/// lexicographically sorted using their pretty representation.
+void
+sort_string_type_base_sptr_map(string_type_base_sptr_map& map,
+ vector<type_base_sptr>& sorted)
+{
+ for (string_type_base_sptr_map::const_iterator i = map.begin();
+ i != map.end();
+ ++i)
+ sorted.push_back(i->second);
+
+ type_or_decl_base_comp comp;
+ std::sort(sorted.begin(), sorted.end(), comp);
+}
+
/// Return the first underlying type that is not a qualified type.
/// @param t the qualified type to consider.
///
diff_context::show_added_symbols_unreferenced_by_debug_info(bool f)
{priv_->show_added_syms_unreferenced_by_di_ = f;}
+/// Setter for the flag that indicates if changes on types unreachable
+/// from global functions and variables are to be reported.
+///
+/// @param f if true, then changes on types unreachable from global
+/// functions and variables are to be reported.
+void
+diff_context::show_unreachable_types(bool f)
+{priv_->show_unreachable_types_ = f;}
+
+/// Getter for the flag that indicates if changes on types unreachable
+/// from global functions and variables are to be reported.
+///
+/// @return true iff changes on types unreachable from global
+/// functions and variables are to be reported.
+bool
+diff_context::show_unreachable_types()
+{return priv_->show_unreachable_types_;}
+
/// Getter of the flag that indicates if the leaf reporter should
/// display a summary of the interfaces impacted by a given leaf
/// change or not.
///
/// @param dif the new diff node to insert into the @ref diff_maps.
///
+/// @param impacted_iface the interface (global function or variable)
+/// currently being analysed that led to analysing the diff node @p
+/// dif. In other words, this is the interface impacted by the diff
+/// node @p dif. Note that this can be nil in cases where we are
+/// directly analysing changes to a type that is not reachable from
+/// any global function or variable.
+///
/// @return true iff the diff node could be added to the current
/// instance of @ref diff_maps.
bool
else
ABG_ASSERT_NOT_REACHED;
- // Update the map that associate the interface that is impacted by
- // this diff, to this diff node.
+ // Update the map that associates this diff node to the set of
+ // interfaces it impacts.
- diff_artifact_set_map_type::iterator i =
- priv_->impacted_artifacts_map_.find(dif);
-
- if (i == priv_->impacted_artifacts_map_.end())
+ if (impacted_iface)
{
- artifact_sptr_set_type set;
- set.insert(impacted_iface);
- priv_->impacted_artifacts_map_[dif] = set;
+ diff_artifact_set_map_type::iterator i =
+ priv_->impacted_artifacts_map_.find(dif);
+
+ if (i == priv_->impacted_artifacts_map_.end())
+ {
+ artifact_sptr_set_type set;
+ set.insert(impacted_iface);
+ priv_->impacted_artifacts_map_[dif] = set;
+ }
+ else
+ i->second.insert(impacted_iface);
}
- else
- i->second.insert(impacted_iface);
return true;
}
corpus_diff::diff_stats::num_leaf_var_changes(size_t n)
{priv_->num_leaf_var_changes = n;}
+/// Getter of the number of added types that are unreachable from the
+/// public interface of the ABI corpus.
+///
+/// Public interface means the set of defined and publicly exported
+/// functions and variables of the ABI corpus.
+///
+/// @return the number of added types that are unreachable from the
+/// public interface of the ABI corpus.
+size_t
+corpus_diff::diff_stats::num_added_unreachable_types() const
+{return priv_->num_added_unreachable_types;}
+
+/// Setter of the number of added types that are unreachable from the
+/// public interface (global functions or variables) of the ABI
+/// corpus.
+///
+/// Public interface means the set of defined and publicly exported
+/// functions and variables of the ABI corpus.
+///
+/// @param n the new number of added types that are unreachable from
+/// the public interface of the ABI corpus.
+void
+corpus_diff::diff_stats::num_added_unreachable_types(size_t n)
+{priv_->num_added_unreachable_types = n;}
+
+/// Getter of the number of added types that are unreachable from
+/// public interfaces and that are filtered out by suppression
+/// specifications.
+///
+/// @return the number of added types that are unreachable from public
+/// interfaces and that are filtered out by suppression
+/// specifications.
+size_t
+corpus_diff::diff_stats::num_added_unreachable_types_filtered_out() const
+{return priv_->num_added_unreachable_types_filtered_out;}
+
+/// Setter of the number of added types that are unreachable from
+/// public interfaces and that are filtered out by suppression
+/// specifications.
+///
+/// @param n the new number of added types that are unreachable from
+/// public interfaces and that are filtered out by suppression
+/// specifications.
+void
+corpus_diff::diff_stats::num_added_unreachable_types_filtered_out(size_t n)
+{priv_->num_added_unreachable_types_filtered_out = n;}
+
+/// Getter of the number of added types that are unreachable from
+/// public interfaces and that are *NOT* filtered out by suppression
+/// specifications.
+///
+/// @return the number of added types that are unreachable from public
+/// interfaces and that are *NOT* filtered out by suppression
+/// specifications.
+size_t
+corpus_diff::diff_stats::net_num_added_unreachable_types() const
+{
+ ABG_ASSERT(num_added_unreachable_types()
+ >=
+ num_added_unreachable_types_filtered_out());
+
+ return (num_added_unreachable_types()
+ -
+ num_added_unreachable_types_filtered_out());
+}
+
+/// Getter of the number of removed types that are unreachable from
+/// the public interface of the ABI corpus.
+///
+/// Public interface means the set of defined and publicly exported
+/// functions and variables of the ABI corpus.
+///
+/// @return the number of removed types that are unreachable from
+/// the public interface of the ABI corpus.
+size_t
+corpus_diff::diff_stats::num_removed_unreachable_types() const
+{return priv_->num_removed_unreachable_types;}
+
+/// Setter of the number of removed types that are unreachable from
+/// the public interface of the ABI corpus.
+///
+/// Public interface means the set of defined and publicly exported
+/// functions and variables of the ABI corpus.
+///
+///@param n the new number of removed types that are unreachable from
+/// the public interface of the ABI corpus.
+void
+corpus_diff::diff_stats::num_removed_unreachable_types(size_t n)
+{priv_->num_removed_unreachable_types = n;}
+
+/// Getter of the number of removed types that are not reachable from
+/// public interfaces and that have been filtered out by suppression
+/// specifications.
+///
+/// @return the number of removed types that are not reachable from
+/// public interfaces and that have been filtered out by suppression
+/// specifications.
+size_t
+corpus_diff::diff_stats::num_removed_unreachable_types_filtered_out() const
+{return priv_->num_removed_unreachable_types_filtered_out;}
+
+/// Setter of the number of removed types that are not reachable from
+/// public interfaces and that have been filtered out by suppression
+/// specifications.
+///
+/// @param n the new number of removed types that are not reachable
+/// from public interfaces and that have been filtered out by
+/// suppression specifications.
+void
+corpus_diff::diff_stats::num_removed_unreachable_types_filtered_out(size_t n)
+{priv_->num_removed_unreachable_types_filtered_out = n;}
+
+/// Getter of the number of removed types that are not reachable from
+/// public interfaces and that have *NOT* been filtered out by
+/// suppression specifications.
+///
+/// @return the number of removed types that are not reachable from
+/// public interfaces and that have *NOT* been filtered out by
+/// suppression specifications.
+size_t
+corpus_diff::diff_stats::net_num_removed_unreachable_types() const
+{
+ ABG_ASSERT(num_removed_unreachable_types()
+ >=
+ num_removed_unreachable_types_filtered_out());
+
+ return (num_removed_unreachable_types()
+ -
+ num_removed_unreachable_types_filtered_out());
+}
+
+/// Getter of the number of changed types that are unreachable from
+/// the public interface of the ABI corpus.
+///
+/// Public interface means the set of defined and publicly exported
+/// functions and variables of the ABI corpus.
+///
+/// @return the number of changed types that are unreachable from the
+/// public interface of the ABI corpus.
+size_t
+corpus_diff::diff_stats::num_changed_unreachable_types() const
+{return priv_->num_changed_unreachable_types;}
+
+/// Setter of the number of changed types that are unreachable from
+/// the public interface of the ABI corpus.
+///
+/// Public interface means the set of defined and publicly exported
+/// functions and variables of the ABI corpus.
+///
+///@param n the new number of changed types that are unreachable from
+/// the public interface of the ABI corpus.
+void
+corpus_diff::diff_stats::num_changed_unreachable_types(size_t n)
+{priv_->num_changed_unreachable_types = n;}
+
+/// Getter of the number of changed types that are unreachable from
+/// public interfaces and that have been filtered out by suppression
+/// specifications.
+///
+/// @return the number of changed types that are unreachable from
+/// public interfaces and that have been filtered out by suppression
+/// specifications.
+size_t
+corpus_diff::diff_stats::num_changed_unreachable_types_filtered_out() const
+{return priv_->num_changed_unreachable_types_filtered_out;}
+
+/// Setter of the number of changed types that are unreachable from
+/// public interfaces and that have been filtered out by suppression
+/// specifications.
+///
+/// @param n the new number of changed types that are unreachable from
+/// public interfaces and that have been filtered out by suppression
+/// specifications.
+void
+corpus_diff::diff_stats::num_changed_unreachable_types_filtered_out(size_t n)
+{priv_->num_changed_unreachable_types_filtered_out = n;}
+
+/// Getter of the number of changed types that are unreachable from
+/// public interfaces and that have *NOT* been filtered out by
+/// suppression specifications.
+///
+/// @return the number of changed types that are unreachable from
+/// public interfaces and that have *NOT* been filtered out by
+/// suppression specifications.
+size_t
+corpus_diff::diff_stats::net_num_changed_unreachable_types() const
+{
+ ABG_ASSERT(num_changed_unreachable_types()
+ >=
+ num_changed_unreachable_types_filtered_out());
+
+ return (num_changed_unreachable_types()
+ -
+ num_changed_unreachable_types_filtered_out());
+}
+
/// Getter for the number of leaf variable changes diff nodes that
/// have been filtered out.
///
size_t
corpus_diff::diff_stats::net_num_leaf_var_changes() const
{return num_leaf_var_changes() - num_leaf_var_changes_filtered_out();}
-// <corpus stuff>
+
+
+// <corpus_diff stuff>
/// Getter of the context associated with this corpus.
///
}
}
}
+
+ // Handle the unreachable_types_edit_script_
+ {
+ edit_script& e = unreachable_types_edit_script_;
+
+ // Populate the map of deleted unreachable types from the
+ // deletions of the edit script.
+ for (vector<deletion>::const_iterator it = e.deletions().begin();
+ it != e.deletions().end();
+ ++it)
+ {
+ unsigned i = it->index();
+ type_base_sptr t
+ (first_->get_types_not_reachable_from_public_interfaces()[i]);
+
+ if (!is_user_defined_type(t))
+ continue;
+
+ string repr = abigail::ir::get_pretty_representation(t, true);
+ deleted_unreachable_types_[repr] = t;
+ }
+
+ // Populate the map of added and change unreachable types from the
+ // insertions of the edit script.
+ for (vector<insertion>::const_iterator it = e.insertions().begin();
+ it != e.insertions().end();
+ ++it)
+ {
+ for (vector<unsigned>::const_iterator iit =
+ it->inserted_indexes().begin();
+ iit != it->inserted_indexes().end();
+ ++iit)
+ {
+ unsigned i = *iit;
+ type_base_sptr t
+ (second_->get_types_not_reachable_from_public_interfaces()[i]);
+
+ if (!is_user_defined_type(t))
+ continue;
+
+ string repr = abigail::ir::get_pretty_representation(t, true);
+
+ // Let's see if the inserted type we are looking at was
+ // reported as deleted as well.
+ //
+ // If it's been deleted and a different version of it has
+ // now been added, it means it's been *changed*. In that
+ // case we'll compute the diff of that change and store it
+ // in the map of changed unreachable types.
+ //
+ // Otherwise, it means the type's been added so we'll add
+ // it to the set of added unreachable types.
+
+ string_type_base_sptr_map::const_iterator j =
+ deleted_unreachable_types_.find(repr);
+ if (j != deleted_unreachable_types_.end())
+ {
+ // So there was another type of the same pretty
+ // representation which was reported as deleted.
+ // Let's see if they are different or not ...
+ decl_base_sptr old_type = is_decl(j->second);
+ decl_base_sptr new_type = is_decl(t);
+ if (old_type != new_type)
+ {
+ // The previously added type is different from this
+ // one that is added. That means the initial type
+ // was changed. Let's compute its diff and store it
+ // as a changed type.
+ diff_sptr d = compute_diff(old_type, new_type, ctxt);
+ ABG_ASSERT(d->has_changes());
+ changed_unreachable_types_[repr]= d;
+ }
+
+ // In any case, the type was both deleted and added,
+ // so we cannot have it marked as being deleted. So
+ // let's remove it from the deleted types.
+ deleted_unreachable_types_.erase(j);
+ }
+ else
+ // The type wasn't previously reported as deleted, so
+ // it's really added.
+ added_unreachable_types_[repr] = t;
+ }
+ }
+ }
}
/// Test if a change reports about a given @ref function_decl that is
return var_suppr->suppresses_variable(var, k, ctxt);
}
-/// Apply the suppression specifications for this corpus diff to the
-/// set of added and removed functions and variables.
+/// Apply suppression specifications for this corpus diff to the set
+/// of added/removed functions/variables, as well as to types not
+/// reachable from global functions/variables.
void
-corpus_diff::priv::apply_suppressions_to_added_removed_fns_vars()
+corpus_diff::priv::apply_supprs_to_added_removed_fns_vars_unreachable_types()
{
diff_context_sptr ctxt = get_context();
if (type_suppr->suppresses_type(c, ctxt))
suppressed_deleted_fns_[e->first] = e->second;
}
+
+ // Apply this type suppression to deleted types
+ // non-reachable from a public interface.
+ for (string_type_base_sptr_map::const_iterator e =
+ deleted_unreachable_types_.begin();
+ e != deleted_unreachable_types_.end();
+ ++e)
+ if (type_suppr->suppresses_type(e->second, ctxt))
+ suppressed_deleted_unreachable_types_[e->first] = e->second;
+
+ // Apply this type suppression to added types
+ // non-reachable from a public interface.
+ for (string_type_base_sptr_map::const_iterator e =
+ added_unreachable_types_.begin();
+ e != added_unreachable_types_.end();
+ ++e)
+ if (type_suppr->suppresses_type(e->second, ctxt))
+ suppressed_added_unreachable_types_[e->first] = e->second;
}
// Added/Deleted variables
else if (variable_suppression_sptr var_suppr =
return (i != suppressed_deleted_fns_.end());
}
+/// Test if an added type that is unreachable from public interface
+/// has been suppressed by a suppression specification.
+///
+/// @param t the added unreachable type to be considered.
+///
+/// @return true iff @p t has been suppressed by a suppression
+/// specification.
+bool
+corpus_diff::priv::added_unreachable_type_is_suppressed(const type_base *t)const
+{
+ if (!t)
+ return false;
+
+ string repr = abigail::ir::get_pretty_representation(t, /*internal=*/true);
+ string_type_base_sptr_map::const_iterator i =
+ suppressed_added_unreachable_types_.find(repr);
+ if (i == suppressed_added_unreachable_types_.end())
+ return false;
+
+ return true;
+}
+
+/// Test if a deleted type that is unreachable from public interface
+/// has been suppressed by a suppression specification.
+///
+/// @param t the deleted unreachable type to be considered.
+///
+/// @return true iff @p t has been suppressed by a suppression
+/// specification.
+bool
+corpus_diff::priv::deleted_unreachable_type_is_suppressed(const type_base *t) const
+{
+ if (!t)
+ return false;
+
+ string repr = abigail::ir::get_pretty_representation(t, /*internal=*/true);
+ string_type_base_sptr_map::const_iterator i =
+ suppressed_deleted_unreachable_types_.find(repr);
+ if (i == suppressed_deleted_unreachable_types_.end())
+ return false;
+
+ return true;
+}
+
/// Test if the change reports for a give given added function has
/// been deleted.
///
num_changes, num_filtered);
}
+/// Count the number of types not reachable from the interface (i.e,
+/// not reachable from global functions or variables).
+///
+/// @param num_added this is set to the number of added types not
+/// reachable from the interface.
+///
+/// @param num_deleted this is set to the number of deleted types not
+/// reachable from the interface.
+///
+/// @param num_changed this is set to the number of changed types not
+/// reachable from the interface.
+///
+/// @param num_filtered_added this is set to the number of added types
+/// not reachable from the interface and that have been filtered out
+/// by suppression specifications.
+///
+/// @param num_filtered_deleted this is set to the number of deleted
+/// types not reachable from the interface and that have been filtered
+/// out by suppression specifications.
+///
+/// @param num_filtered_changed this is set to the number of changed
+/// types not reachable from the interface and that have been filtered
+/// out by suppression specifications.
+void
+corpus_diff::priv::count_unreachable_types(size_t &num_added,
+ size_t &num_deleted,
+ size_t &num_changed,
+ size_t &num_filtered_added,
+ size_t &num_filtered_deleted,
+ size_t &num_filtered_changed)
+{
+ num_added = added_unreachable_types_.size();
+ num_deleted = deleted_unreachable_types_.size();
+ num_changed = changed_unreachable_types_.size();
+ num_filtered_added = suppressed_added_unreachable_types_.size();
+ num_filtered_deleted = suppressed_deleted_unreachable_types_.size();
+
+ for (vector<diff_sptr>::const_iterator i =
+ changed_unreachable_types_sorted().begin();
+ i != changed_unreachable_types_sorted().end();
+ ++i)
+ if (!(*i)->to_be_reported())
+ ++num_filtered_changed;
+}
+
+/// Get the sorted vector of diff nodes representing changed
+/// unreachable types.
+///
+/// Upon the first invocation of this method, if the vector is empty,
+/// this function gets the diff nodes representing changed
+/// unreachable, sort them, and return the sorted vector.
+///
+/// @return the sorted vector of diff nodes representing changed
+/// unreachable types.
+const vector<diff_sptr>&
+corpus_diff::priv::changed_unreachable_types_sorted() const
+{
+if (changed_unreachable_types_sorted_.empty())
+ if (!changed_unreachable_types_.empty())
+ sort_string_diff_sptr_map(changed_unreachable_types_,
+ changed_unreachable_types_sorted_);
+
+ return changed_unreachable_types_sorted_;
+}
+
/// Compute the diff stats.
///
/// To know the number of functions that got filtered out, this
/// 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_removed_func_filtered_out(suppressed_deleted_fns_.size());
ctxt->maybe_apply_filters(diff);
}
+ // walk the changed unreachable types to apply categorization
+ // filters
+ for (diff_sptrs_type::const_iterator i =
+ changed_unreachable_types_sorted().begin();
+ i != changed_unreachable_types_sorted().end();
+ ++i)
+ {
+ diff_sptr diff = *i;
+ ctxt->maybe_apply_filters(diff);
+ }
+
categorize_redundant_changed_sub_nodes();
// Walk the changed function diff nodes to count the number of
stat.num_leaf_changes(num_changes);
stat.num_leaf_changes_filtered_out(num_filtered);
}
+
+ // Walk the unreachable types to count them
+ {
+ size_t num_added_unreachable_types = 0,
+ num_changed_unreachable_types = 0,
+ num_deleted_unreachable_types = 0,
+ num_added_unreachable_types_filtered = 0,
+ num_changed_unreachable_types_filtered = 0,
+ num_deleted_unreachable_types_filtered = 0;
+
+ count_unreachable_types(num_added_unreachable_types,
+ num_deleted_unreachable_types,
+ num_changed_unreachable_types,
+ num_added_unreachable_types_filtered,
+ num_deleted_unreachable_types_filtered,
+ num_changed_unreachable_types_filtered);
+
+ stat.num_added_unreachable_types(num_added_unreachable_types);
+ stat.num_removed_unreachable_types(num_deleted_unreachable_types);
+ stat.num_changed_unreachable_types(num_changed_unreachable_types);
+ stat.num_added_unreachable_types_filtered_out
+ (num_added_unreachable_types_filtered);
+ stat.num_removed_unreachable_types_filtered_out
+ (num_deleted_unreachable_types_filtered);
+ stat.num_changed_unreachable_types_filtered_out
+ (num_changed_unreachable_types_filtered);
+ }
}
/// Emit the summary of the functions & variables that got
out << "\n";
}
+ // Show statistics about types not reachable from global
+ // functions/variables.
+ if (ctxt->show_unreachable_types())
+ {
+ size_t total_nb_variable_changes =
+ s.num_removed_unreachable_types()
+ + s.num_changed_unreachable_types()
+ + s.num_added_unreachable_types();
+
+ // Show summary of unreachable types
+ out << indent << "Unreachable types summary: "
+ << s.net_num_removed_unreachable_types()
+ << " removed";
+ if (s.num_removed_unreachable_types_filtered_out())
+ out << " (" << s.num_removed_unreachable_types_filtered_out()
+ << " filtered out)";
+ out << ", ";
+
+ out << s.net_num_changed_unreachable_types()
+ << " changed";
+ if (s.num_changed_unreachable_types_filtered_out())
+ out << " (" << s.num_changed_unreachable_types_filtered_out()
+ << " filtered out)";
+ out << ", ";
+
+ out << s.net_num_added_unreachable_types()
+ << " added";
+ if (s.num_added_unreachable_types_filtered_out())
+ out << " (" << s.num_added_unreachable_types_filtered_out()
+ << " filtered out)";
+ if (total_nb_variable_changes <= 1)
+ out << " type";
+ else
+ out << " types";
+ out << "\n";
+ }
+
if (ctxt->show_symbols_unreferenced_by_debug_info()
&& (s.num_func_syms_removed()
|| s.num_func_syms_added()
diff_sptr diff = *i;
categorize_redundancy(diff);
}
+
+ for (diff_sptrs_type::const_iterator i =
+ changed_unreachable_types_sorted().begin();
+ i!= changed_unreachable_types_sorted().end();
+ ++i)
+ {
+ diff_sptr diff = *i;
+ categorize_redundancy(diff);
+ }
}
/// Walk the changed functions and variables diff nodes and clear the
print_diff_tree(d, *ctxt->error_output_stream());
}
}
+
+ if (!changed_unreachable_types_sorted().empty())
+ {
+ *ctxt->error_output_stream() << "\nchanged unreachable "
+ "types diff tree: \n\n";
+ for (vector<diff_sptr>::const_iterator i =
+ changed_unreachable_types_sorted().begin();
+ i != changed_unreachable_types_sorted().end();
+ ++i)
+ {
+ diff_sptr d = *i;
+ print_diff_tree(d, *ctxt->error_output_stream());
+ }
+ }
}
/// Populate the vector of children node of the @ref corpus_diff type.
corpus_diff::added_unrefed_variable_symbols() const
{return priv_->added_unrefed_var_syms_;}
+/// Getter for a map of deleted types that are not reachable from
+/// global functions/variables.
+///
+/// @return a map that associates pretty representation of deleted
+/// unreachable types and said types.
+const string_type_base_sptr_map&
+corpus_diff::deleted_unreachable_types() const
+{return priv_->deleted_unreachable_types_;}
+
+/// Getter of a sorted vector of deleted types that are not reachable
+/// from global functions/variables.
+///
+/// @return a sorted vector of deleted types that are not reachable
+/// from global functions/variables. The types are lexicographically
+/// sorted by considering their pretty representation.
+const vector<type_base_sptr>&
+corpus_diff::deleted_unreachable_types_sorted() const
+{
+ if (priv_->deleted_unreachable_types_sorted_.empty())
+ if (!priv_->deleted_unreachable_types_.empty())
+ sort_string_type_base_sptr_map(priv_->deleted_unreachable_types_,
+ priv_->deleted_unreachable_types_sorted_);
+
+ return priv_->deleted_unreachable_types_sorted_;
+}
+
+/// Getter for a map of added types that are not reachable from global
+/// functions/variables.
+///
+/// @return a map that associates pretty representation of added
+/// unreachable types and said types.
+const string_type_base_sptr_map&
+corpus_diff::added_unreachable_types() const
+{return priv_->added_unreachable_types_;}
+
+/// Getter of a sorted vector of added types that are not reachable
+/// from global functions/variables.
+///
+/// @return a sorted vector of added types that are not reachable from
+/// global functions/variables. The types are lexicographically
+/// sorted by considering their pretty representation.
+const vector<type_base_sptr>&
+corpus_diff::added_unreachable_types_sorted() const
+{
+ if (priv_->added_unreachable_types_sorted_.empty())
+ if (!priv_->added_unreachable_types_.empty())
+ sort_string_type_base_sptr_map(priv_->added_unreachable_types_,
+ priv_->added_unreachable_types_sorted_);
+
+ return priv_->added_unreachable_types_sorted_;
+}
+
+/// Getter for a map of changed types that are not reachable from
+/// global functions/variables.
+///
+/// @return a map that associates pretty representation of changed
+/// unreachable types and said types.
+const string_diff_sptr_map&
+corpus_diff::changed_unreachable_types() const
+{return priv_->changed_unreachable_types_;}
+
+/// Getter of a sorted vector of changed types that are not reachable
+/// from global functions/variables.
+///
+/// @return a sorted vector of changed types that are not reachable
+/// from global functions/variables. The diffs are lexicographically
+/// sorted by considering their pretty representation.
+const vector<diff_sptr>&
+corpus_diff::changed_unreachable_types_sorted() const
+{return priv_->changed_unreachable_types_sorted();}
+
/// Getter of the diff context of this diff
///
/// @return the diff context for this diff.
}
return priv_->pretty_representation_;
}
-/// Return true iff the current diff node carries a change.
+/// Return true iff the current @ref corpus_diff node carries a
+/// change.
///
/// @return true iff the current diff node carries a change.
bool
|| priv_->added_unrefed_fn_syms_.size()
|| priv_->deleted_unrefed_fn_syms_.size()
|| priv_->added_unrefed_var_syms_.size()
- || priv_->deleted_unrefed_var_syms_.size());
+ || priv_->deleted_unrefed_var_syms_.size()
+ || priv_->deleted_unreachable_types_.size()
+ || priv_->added_unreachable_types_.size()
+ || priv_->changed_unreachable_types_.size());
}
/// Test if the current instance of @ref corpus_diff carries changes
&& stats.net_num_func_changed() != 0)
|| stats.net_num_vars_removed() != 0
|| stats.net_num_removed_func_syms() != 0
- || stats.net_num_removed_var_syms() != 0);
+ || stats.net_num_removed_var_syms() != 0
+ || stats.net_num_removed_unreachable_types() != 0
+ || stats.net_num_changed_unreachable_types() != 0);
}
/// Test if the current instance of @ref corpus_diff carries subtype
apply_filters_and_suppressions_before_reporting();
return (stats.net_num_func_changed() != 0
- || stats.net_num_vars_changed() != 0);
+ || stats.net_num_vars_changed() != 0
+ || stats.net_num_removed_unreachable_types() != 0
+ || stats.net_num_changed_unreachable_types() != 0);
}
/// Test if the current instance of @ref corpus_diff carries changes
|| stats.net_num_vars_added()
|| stats.net_num_added_var_syms()
|| stats.net_num_vars_removed()
- || stats.net_num_removed_var_syms());
+ || stats.net_num_removed_var_syms()
+ || stats.net_num_added_unreachable_types()
+ || stats.net_num_removed_unreachable_types()
+ || stats.net_num_changed_unreachable_types());
}
/// Apply the different filters that are registered to be applied to
/// This is called when the visitor visits a diff node.
///
/// It basically tests if the diff node being visited is a leaf diff
- /// node - that is, if contains local changes. If it does, then the
+ /// node - that is, it contains local changes. If it does, then the
/// node is added to the set of maps that hold leaf diffs in the
/// current corpus_diff.
///
+ /// Note that only leaf nodes that are reachable from public
+ /// interfaces (global functions or variables) are collected by this
+ /// visitor.
+ ///
/// @param d the diff node being visited.
virtual void
visit_begin(diff *d)
diff_context_sptr ctxt = d->context();
const corpus_diff *corpus_diff_node = ctxt->get_corpus_diff().get();
ABG_ASSERT(corpus_diff_node);
- type_or_decl_base_sptr iface =
- get_current_topmost_iface_diff()->first_subject();
- // So this is diff node carries a leaf change. Let's add it
- // to the set of of leaf diffs of corpus_diff_node.
- const_cast<corpus_diff*>(corpus_diff_node)->
- get_leaf_diffs().insert_diff_node(d, iface);
+
+ if (diff *iface_diff = get_current_topmost_iface_diff())
+ {
+ type_or_decl_base_sptr iface = iface_diff->first_subject();
+ // So this diff node carries a leaf change. Let's add it
+ // to the set of of leaf diffs of corpus_diff_node.
+ const_cast<corpus_diff*>(corpus_diff_node)->
+ get_leaf_diffs().insert_diff_node(d, iface);
+ }
}
}
}; // end struct leaf_diff_node_marker_visitor
v.set_current_topmost_iface_diff(0);
+ // Traverse the changed unreachable type diffs. These diffs are on
+ // types that are not reachable from global functions or variables.
+ for (vector<diff_sptr>::const_iterator i =
+ changed_unreachable_types_sorted().begin();
+ i != changed_unreachable_types_sorted().end();
+ ++i)
+ {
+ if (diff_sptr d = *i)
+ {
+ const diff_context_sptr &ctxt = context();
+ if (ctxt->visiting_a_node_twice_is_forbidden_per_interface())
+ ctxt->forget_visited_diffs();
+
+ if (!d->traverse(v))
+ {
+ v.visit_end(this);
+ return false;
+ }
+ }
+ }
+
v.visit_end(this);
return true;
}
typedef corpus::variables::const_iterator vars_it_type;
typedef elf_symbols::const_iterator symbols_it_type;
typedef diff_utils::deep_ptr_eq_functor eq_type;
+ typedef vector<type_base_wptr>::const_iterator type_base_wptr_it_type;
ABG_ASSERT(f && s);
r->priv_->architectures_equal_ =
f->get_architecture_name() == s->get_architecture_name();
+ // Compute the diff of publicly defined and exported functions
diff_utils::compute_diff<fns_it_type, eq_type>(f->get_functions().begin(),
f->get_functions().end(),
s->get_functions().begin(),
s->get_functions().end(),
r->priv_->fns_edit_script_);
+ // Compute the diff of publicly defined and exported variables.
diff_utils::compute_diff<vars_it_type, eq_type>
(f->get_variables().begin(), f->get_variables().end(),
s->get_variables().begin(), s->get_variables().end(),
r->priv_->vars_edit_script_);
+ // Compute the diff of function elf symbols not referenced by debug
+ // info.
diff_utils::compute_diff<symbols_it_type, eq_type>
(f->get_unreferenced_function_symbols().begin(),
f->get_unreferenced_function_symbols().end(),
s->get_unreferenced_function_symbols().end(),
r->priv_->unrefed_fn_syms_edit_script_);
+ // Compute the diff of variable elf symbols not referenced by debug
+ // info.
diff_utils::compute_diff<symbols_it_type, eq_type>
(f->get_unreferenced_variable_symbols().begin(),
f->get_unreferenced_variable_symbols().end(),
s->get_unreferenced_variable_symbols().end(),
r->priv_->unrefed_var_syms_edit_script_);
+ if (ctxt->show_unreachable_types())
+ // Compute the diff of types not reachable from public functions
+ // or global variables that are exported.
+ diff_utils::compute_diff<type_base_wptr_it_type, eq_type>
+ (f->get_types_not_reachable_from_public_interfaces().begin(),
+ f->get_types_not_reachable_from_public_interfaces().end(),
+ s->get_types_not_reachable_from_public_interfaces().begin(),
+ s->get_types_not_reachable_from_public_interfaces().end(),
+ r->priv_->unreachable_types_edit_script_);
+
r->priv_->ensure_lookup_tables_populated();
return r;
apply_suppressions(diff_sptr diff_tree)
{apply_suppressions(diff_tree.get());}
-/// Walk a diff tree and appply the suppressions carried by the
-/// context. If the suppression applies to a given node than
+/// Walk a @ref corpus_diff tree and appply the suppressions carried
+/// by the context. If the suppression applies to a given node then
/// categorize the node into the SUPPRESSED_CATEGORY category and
/// propagate that categorization.
///
const_cast<corpus_diff*>(diff_tree)->traverse(v);
diff_tree->context()->forbid_visiting_a_node_twice(s);
- // ... then also visit the set added and removed functions,
- // variables, and symbols
- diff_tree->priv_->apply_suppressions_to_added_removed_fns_vars();
+ // ... then also visit the set of added and removed functions,
+ // variables, symbols, and types not reachable from global
+ // functions and variables.
+ diff_tree->priv_->
+ apply_supprs_to_added_removed_fns_vars_unreachable_types();
}
}
// the type maps of each translation unit.
type_maps types_;
type_maps type_per_loc_map_;
+ mutable vector<type_base_wptr> types_not_reachable_from_pub_ifaces_;
+ unordered_set<interned_string, hash_interned_string> *pub_type_pretty_reprs_;
private:
priv();
: env(e),
group(),
origin_(ARTIFICIAL_ORIGIN),
- path(p)
+ path(p),
+ pub_type_pretty_reprs_()
{}
void
const type_maps&
get_types() const;
+
+ unordered_set<interned_string, hash_interned_string>*
+ get_public_types_pretty_representations();
+
+ ~priv();
}; // end struct corpus::priv
void
corpus::priv::get_types() const
{return types_;}
+/// Getter of the set of pretty representation of types that are
+/// reachable from public interfaces (global functions and variables).
+///
+/// @return the set of pretty representation of types that are
+/// reachable from public interfaces (global functions and variables).
+unordered_set<interned_string, hash_interned_string>*
+corpus::priv::get_public_types_pretty_representations()
+{
+ if (group)
+ return group->get_public_types_pretty_representations();
+
+ if (pub_type_pretty_reprs_ == 0)
+ pub_type_pretty_reprs_ =
+ new unordered_set<interned_string, hash_interned_string>;
+ return pub_type_pretty_reprs_;
+}
+
+/// Destructor of the @ref corpus::priv type.
+corpus::priv::~priv()
+{
+ delete pub_type_pretty_reprs_;
+}
+
/// Record a canonical type which has been computed for the current
/// corpus.
///
corpus::get_type_per_loc_map() const
{return priv_->type_per_loc_map_;}
+/// Test if the recording of reachable types (and thus, indirectly,
+/// the recording of non-reachable types) is activated for the
+/// current @ref corpus.
+///
+/// @return true iff the recording of reachable types is activated for
+/// the current @ref corpus.
+bool
+corpus::recording_types_reachable_from_public_interface_supported()
+{
+ return (priv_->get_public_types_pretty_representations()
+ && !priv_->get_public_types_pretty_representations()->empty());
+}
+
+/// Record a type as being reachable from public interfaces (global
+/// functions and variables).
+///
+/// @param t the type to record as reachable.
+void
+corpus::record_type_as_reachable_from_public_interfaces(const type_base& t)
+{
+ string repr = get_pretty_representation(&t, /*internal=*/true);
+ interned_string s = t.get_environment()->intern(repr);
+ priv_->get_public_types_pretty_representations()->insert(s);
+}
+
+/// Test if a type is reachable from public interfaces (global
+/// functions and variables).
+///
+/// For a type to be considered reachable from public interfaces, it
+/// must have been previously marked as such by calling
+/// corpus::record_type_as_reachable_from_public_interfaces.
+///
+/// @param t the type to test for.
+///
+/// @return true iff @p t is reachable from public interfaces.
+bool
+corpus::type_is_reachable_from_public_interfaces(const type_base& t) const
+{
+ string repr = get_pretty_representation(&t, /*internal=*/true);
+ interned_string s = t.get_environment()->intern(repr);
+
+ return (priv_->get_public_types_pretty_representations()->find(s)
+ != priv_->get_public_types_pretty_representations()->end());
+}
+
+/// Getter ofa a sorted vector of the types that are *NOT* reachable
+/// from public interfaces.
+///
+/// Note that for this to be non-empty, the libabigail reader that
+/// analyzed the input (be it a binary or an abixml file) must have be
+/// configured to load types that are not reachable from public
+/// interfaces.
+///
+/// @return a reference to a vector of sorted types NON reachable from
+/// public interfaces.
+const vector<type_base_wptr>&
+corpus::get_types_not_reachable_from_public_interfaces() const
+{
+ if (priv_->types_not_reachable_from_pub_ifaces_.empty())
+ {
+ const type_maps& types = get_types();
+ for (vector<type_base_wptr>::const_iterator it =
+ types.get_types_sorted_by_name().begin();
+ it != types.get_types_sorted_by_name().end();
+ ++it)
+ {
+ type_base_sptr t(*it);
+ if (!type_is_reachable_from_public_interfaces(*t))
+ priv_->types_not_reachable_from_pub_ifaces_.push_back(t);
+ }
+ }
+
+ return priv_->types_not_reachable_from_pub_ifaces_;
+}
+
/// Get the maps that associate a location string to a certain kind of
/// type.
///
unordered_map<string, elf_symbol_sptr> unrefed_var_symbol_map;
elf_symbols unrefed_var_symbols;
bool unrefed_var_symbols_built;
+ unordered_set<interned_string, hash_interned_string> pub_type_pretty_reprs_;
priv()
: unrefed_fun_symbols_built(),
return priv_->unrefed_var_symbols;
}
+/// Getter of a pointer to the set of types reachable from public
+/// interfaces of a given corpus group.
+unordered_set<interned_string, hash_interned_string>*
+corpus_group::get_public_types_pretty_representations()
+{return &priv_->pub_type_pretty_reprs_;}
+
+/// Test if the recording of reachable types (and thus, indirectly,
+/// the recording of non-reachable types) is activated for the
+/// current @ref corpus_group.
+///
+/// @return true iff the recording of reachable types is activated for
+/// the current @ref corpus_group.
+bool
+corpus_group::recording_types_reachable_from_public_interface_supported()
+{return !get_public_types_pretty_representations()->empty();}
+
// </corpus_group stuff>
}// end namespace ir
out << '\n';
}
+ // Report added/removed/changed types not reacheable from public
+ // interfaces.
+
+ maybe_report_unreachable_type_changes(d, s, indent, out);
+
d.priv_->maybe_dump_diff_tree();
}
while (dwarf_siblingof(&child, &child) == 0);
}
+ bool is_artificial = die_is_artificial(die);
+
// DWARF up to version 4 (at least) doesn't seem to carry the
// underlying type, so let's create an artificial one here, which
// sole purpose is to be passed to the constructor of the
ABG_ASSERT(t);
result.reset(new enum_type_decl(name, loc, t, enms, linkage_name));
result->set_is_anonymous(enum_is_anonymous);
+ result->set_is_artificial(is_artificial);
ctxt.associate_die_to_type(die, result, where_offset);
return result;
}
first_parm = f->get_parameters()[0];
bool is_artificial =
- first_parm && first_parm->get_artificial();;
+ first_parm && first_parm->get_is_artificial();;
pointer_type_def_sptr this_ptr_type;
type_base_sptr other_klass;
uint64_t size = 0;
die_size_in_bits(die, size);
+ bool is_artificial = die_is_artificial(die);
Dwarf_Die child;
bool has_child = (dwarf_child(die, &child) == 0);
if (size)
result->set_size_in_bits(size);
+ result->set_is_artificial(is_artificial);
+
ctxt.associate_die_to_type(die, result, where_offset);
ctxt.maybe_schedule_declaration_only_class_for_resolution(result);
uint64_t size = 0;
die_size_in_bits(die, size);
+ bool is_artificial = die_is_artificial(die);
if (union_type)
{
result->set_is_declaration_only(false);
}
+ result->set_is_artificial(is_artificial);
+
ctxt.associate_die_to_type(die, result, where_offset);
// TODO: maybe schedule declaration-only union for result like we do
if ((result = ctxt.lookup_decl_from_die_offset(dwarf_dieoffset(die),
source_of_die)))
- return result;
+ {
+ if (ctxt.load_all_types())
+ if (called_from_public_decl)
+ if (type_base_sptr t = is_type(result))
+ if (corpus *abi_corpus = scope->get_corpus())
+ abi_corpus->record_type_as_reachable_from_public_interfaces(*t);
+
+ return result;
+ }
switch (tag)
{
ctxt.associate_die_to_decl(die, is_decl(result), where_offset,
/*associate_by_repr=*/false);
+ if (result)
+ if (ctxt.load_all_types())
+ if (called_from_public_decl)
+ if (type_base_sptr t = is_type(result))
+ if (corpus *abi_corpus = scope->get_corpus())
+ abi_corpus->record_type_as_reachable_from_public_interfaces(*t);
+
return result;
}
mutable istring_type_base_wptrs_map_type array_types_;
mutable istring_type_base_wptrs_map_type subrange_types_;
mutable istring_type_base_wptrs_map_type function_types_;
+ mutable vector<type_base_wptr> sorted_types_;
}; // end struct type_maps::priv
type_maps::type_maps()
type_maps::function_types()
{return priv_->function_types_;}
+/// A comparison functor to compare/sort types based on their pretty
+/// representations.
+struct type_name_comp
+{
+ /// Comparison operator for two instances of @ref type_base.
+ ///
+ /// This compares the two types by lexicographically comparing their
+ /// pretty representation.
+ ///
+ /// @param l the left-most type to compare.
+ ///
+ /// @param r the right-most type to compare.
+ ///
+ /// @return true iff @p l < @p r.
+ bool
+ operator()(type_base *l, type_base *r) const
+ {
+ if (l == 0 && r == 0)
+ return false;
+
+ string l_repr = get_pretty_representation(l);
+ string r_repr = get_pretty_representation(r);
+ return l_repr < r_repr;
+ }
+
+ /// Comparison operator for two instances of @ref type_base.
+ ///
+ /// This compares the two types by lexicographically comparing their
+ /// pretty representation.
+ ///
+ /// @param l the left-most type to compare.
+ ///
+ /// @param r the right-most type to compare.
+ ///
+ /// @return true iff @p l < @p r.
+ bool
+ operator()(const type_base_sptr &l, const type_base_sptr &r) const
+ {return operator()(l.get(), r.get());}
+
+ /// Comparison operator for two instances of @ref type_base.
+ ///
+ /// This compares the two types by lexicographically comparing their
+ /// pretty representation.
+ ///
+ /// @param l the left-most type to compare.
+ ///
+ /// @param r the right-most type to compare.
+ ///
+ /// @return true iff @p l < @p r.
+ bool
+ operator()(const type_base_wptr &l, const type_base_wptr &r) const
+ {return operator()(type_base_sptr(l), type_base_sptr(r));}
+}; // end struct type_name_comp
+
+/// Getter of all types types sorted by their pretty representation.
+///
+/// @return a sorted vector of all types sorted by their pretty
+/// representation.
+const vector<type_base_wptr>&
+type_maps::get_types_sorted_by_name() const
+{
+ if (priv_->sorted_types_.empty())
+ {
+ istring_type_base_wptrs_map_type::const_iterator i;
+ vector<type_base_wptr>::const_iterator j;
+
+ for (i = basic_types().begin(); i != basic_types().end(); ++i)
+ for (j = i->second.begin(); j != i->second.end(); ++j)
+ priv_->sorted_types_.push_back(*j);
+
+ for (i = class_types().begin(); i != class_types().end(); ++i)
+ for (j = i->second.begin(); j != i->second.end(); ++j)
+ priv_->sorted_types_.push_back(*j);
+
+ for (i = union_types().begin(); i != union_types().end(); ++i)
+ for (j = i->second.begin(); j != i->second.end(); ++j)
+ priv_->sorted_types_.push_back(*j);
+
+ for (i = enum_types().begin(); i != enum_types().end(); ++i)
+ for (j = i->second.begin(); j != i->second.end(); ++j)
+ priv_->sorted_types_.push_back(*j);
+
+ for (i = typedef_types().begin(); i != typedef_types().end(); ++i)
+ for (j = i->second.begin(); j != i->second.end(); ++j)
+ priv_->sorted_types_.push_back(*j);
+
+ type_name_comp comp;
+ sort(priv_->sorted_types_.begin(), priv_->sorted_types_.end(), comp);
+ }
+
+ return priv_->sorted_types_;
+}
+
// </type_maps stuff>
// <translation_unit stuff>
{
bool in_pub_sym_tab_;
bool is_anonymous_;
+ bool is_artificial_;
bool has_anonymous_parent_;
location location_;
context_rel *context_;
priv()
: in_pub_sym_tab_(false),
is_anonymous_(true),
+ is_artificial_(false),
has_anonymous_parent_(false),
context_(),
visibility_(VISIBILITY_DEFAULT)
decl_base::set_is_anonymous(bool f)
{priv_->is_anonymous_ = f;}
+/// Getter of the flag that says if the declaration is artificial.
+///
+/// Being artificial means the parameter was not explicitely
+/// mentionned in the source code, but was rather artificially created
+/// by the compiler.
+///
+/// @return true iff the declaration is artificial.
+bool
+decl_base::get_is_artificial() const
+{return priv_->is_artificial_;}
+
+/// Setter of the flag that says if the declaration is artificial.
+///
+/// Being artificial means the parameter was not explicitely
+/// mentionned in the source code, but was rather artificially created
+/// by the compiler.
+///
+/// @param f the new value of the flag that says if the declaration is
+/// artificial.
+void
+decl_base::set_is_artificial(bool f)
+{priv_->is_artificial_ = f;}
+
/// Get the "has_anonymous_parent" flag of the current declaration.
///
/// Having an anoymous parent means having a anonymous parent scope
}
/// Turn equality of shared_ptr of decl_base into a deep equality;
-/// that is, make it compare the pointed to objects too.
+/// that is, make it compare the pointed to objects, not just the
+/// pointers.
///
/// @param l the shared_ptr of decl_base on left-hand-side of the
/// equality.
return *l == *r;
}
+/// Inequality operator of shared_ptr of @ref decl_base.
+///
+/// This is a deep equality operator, that is, it compares the
+/// pointed-to objects, rather than just the pointers.
+///
+/// @param l the left-hand-side operand.
+///
+/// @param r the right-hand-side operand.
+///
+/// @return true iff @p l is different from @p r.
+bool
+operator!=(const decl_base_sptr& l, const decl_base_sptr& r)
+{return !operator==(l, r);}
+
/// Turn equality of shared_ptr of type_base into a deep equality;
/// that is, make it compare the pointed to objects too.
///
return is_member_decl(d);
}
+/// Test if a type is user-defined.
+///
+/// A type is considered user-defined if it's a
+/// struct/class/union/enum that is *NOT* artificial.
+///
+/// @param t the type to consider.
+///
+/// @return true iff the type @p t is user-defined.
+bool
+is_user_defined_type(const type_base* t)
+{
+ if (t == 0)
+ return false;
+
+ t = peel_qualified_or_typedef_type(t);
+ decl_base *d = is_decl(t);
+
+ if ((is_class_or_union_type(t) || is_enum_type(t))
+ && d && !d->get_is_artificial())
+ return true;
+
+ return false;
+}
+
+/// Test if a type is user-defined.
+///
+/// A type is considered user-defined if it's a
+/// struct/class/union/enum.
+///
+///
+/// @param t the type to consider.
+///
+/// @return true iff the type @p t is user-defined.
+bool
+is_user_defined_type(const type_base_sptr& t)
+{return is_user_defined_type(t.get());}
+
/// Gets the access specifier for a class member.
///
/// @param d the declaration of the class member to consider. Note
p->get_name(),
p->get_location(),
p->get_variadic_marker(),
- p->get_artificial()));
+ p->get_is_artificial()));
parm.push_back(stripped);
}
type_base_sptr p = strip_typedef(ty->get_return_type());
p->get_name(),
p->get_location(),
p->get_variadic_marker(),
- p->get_artificial()));
+ p->get_is_artificial()));
parm.push_back(stripped);
}
type_base_sptr p = strip_typedef(ty->get_return_type());
(*i)->get_name(),
(*i)->get_location(),
(*i)->get_variadic_marker(),
- (*i)->get_artificial()));
+ (*i)->get_is_artificial()));
parms.push_back(parm);
}
i < priv_->parms_.size();
++i, ++j)
{
- if (i == 0 && priv_->parms_[i]->get_artificial())
+ if (i == 0 && priv_->parms_[i]->get_is_artificial())
// If the first parameter is artificial, then it certainly
// means that this is a member function, and the first
// parameter is the implicit this pointer. In that case, set
i < priv_->parms_.size();
++i, ++j)
{
- if (i == 0 && priv_->parms_[i]->get_artificial())
+ if (i == 0 && priv_->parms_[i]->get_is_artificial())
// If the first parameter is artificial, then it certainly
// means that this is a member function, and the first
// parameter is the implicit this pointer. In that case, set
type_base_wptr type_;
unsigned index_;
bool variadic_marker_;
- bool artificial_;
priv()
: index_(),
- variadic_marker_(),
- artificial_()
+ variadic_marker_()
{}
priv(type_base_sptr type,
unsigned index,
- bool variadic_marker,
- bool artificial)
+ bool variadic_marker)
: type_(type),
index_(index),
- variadic_marker_(variadic_marker),
- artificial_(artificial)
+ variadic_marker_(variadic_marker)
{}
};// end struct function_decl::parameter::priv
: type_or_decl_base(type->get_environment(),
FUNCTION_PARAMETER_DECL | ABSTRACT_DECL_BASE),
decl_base(type->get_environment(), name, loc),
- priv_(new priv(type, index, is_variadic, /*is_artificial=*/false))
+ priv_(new priv(type, index, is_variadic))
{
runtime_type_instance(this);
}
: type_or_decl_base(type->get_environment(),
FUNCTION_PARAMETER_DECL | ABSTRACT_DECL_BASE),
decl_base(type->get_environment(), name, loc),
- priv_(new priv(type, index, is_variadic, is_artificial))
+ priv_(new priv(type, index, is_variadic))
{
runtime_type_instance(this);
+ set_is_artificial(is_artificial);
}
function_decl::parameter::parameter(const type_base_sptr type,
: type_or_decl_base(type->get_environment(),
FUNCTION_PARAMETER_DECL | ABSTRACT_DECL_BASE),
decl_base(type->get_environment(), name, loc),
- priv_(new priv(type, 0, is_variadic, is_artificial))
+ priv_(new priv(type, 0, is_variadic))
{
runtime_type_instance(this);
+ set_is_artificial(is_artificial);
}
function_decl::parameter::parameter(const type_base_sptr type,
: type_or_decl_base(type->get_environment(),
FUNCTION_PARAMETER_DECL | ABSTRACT_DECL_BASE),
decl_base(type->get_environment(), "", location()),
- priv_(new priv(type, index, variad, /*is_artificial=*/false))
+ priv_(new priv(type, index, variad))
{
runtime_type_instance(this);
}
function_decl::parameter::set_index(unsigned i)
{priv_->index_ = i;}
-/// Test if the parameter is artificial.
-///
-/// Being artificial means the parameter was not explicitely
-/// mentionned in the source code, but was rather artificially
-/// created by the compiler.
-///
-/// @return true if the parameter is artificial, false otherwise.
-bool
-function_decl::parameter::get_artificial() const
-{return priv_->artificial_;}
bool
function_decl::parameter::get_variadic_marker() const
{return priv_->variadic_marker_;}
-/// Getter for the artificial-ness of the parameter.
-///
-/// Being artificial means the parameter was not explicitely
-/// mentionned in the source code, but was rather artificially
-/// created by the compiler.
-///
-/// @param f set to true if the parameter is artificial.
-void
-function_decl::parameter::set_artificial(bool f)
-{priv_->artificial_ = f;}
-
/// Compares two instances of @ref function_decl::parameter.
///
/// If the two intances are different, set a bitfield to give some
// Now show the changed types.
const diff_maps& leaf_diffs = d.get_leaf_diffs();
report_type_changes_from_diff_maps(*this, leaf_diffs, out, indent);
+
+ // Report added/removed/changed types not reacheable from public
+ // interfaces.
+ maybe_report_unreachable_type_changes(d, s, indent, out);
}
} // end namespace comparison
} // end namespace abigail
#endif //WITH_ZIP_ARCHIVE
static bool read_is_declaration_only(xmlNodePtr, bool&);
+static bool read_is_artificial(xmlNodePtr, bool&);
+static bool read_tracking_non_reachable_types(xmlNodePtr, bool&);
+static bool read_is_non_reachable_type(xmlNodePtr, bool&);
class read_context;
corpus_group_sptr m_corpus_group;
corpus::exported_decls_builder* m_exported_decls_builder;
suppr::suppressions_type m_supprs;
+ bool m_tracking_non_reachable_types;
read_context();
: m_env(env),
m_reader(reader),
m_corp_node(),
- m_exported_decls_builder()
+ m_exported_decls_builder(),
+ m_tracking_non_reachable_types()
{}
+ /// Getter for the flag that tells us if we are tracking types that
+ /// are not reachable from global functions and variables.
+ ///
+ /// @return true iff we are tracking types that are not reachable
+ /// from global functions and variables.
+ bool
+ tracking_non_reachable_types() const
+ {return m_tracking_non_reachable_types;}
+
+ /// Setter for the flag that tells us if we are tracking types that
+ /// are not reachable from global functions and variables.
+ ///
+ /// @param f the new value of the flag.
+ /// from global functions and variables.
+ void
+ tracking_non_reachable_types(bool f)
+ {m_tracking_non_reachable_types = f;}
+
/// Getter of the path to the ABI file.
///
/// @return the path to the native xml abi file.
ctxt.get_suppressions().push_back(*i);
}
+/// Configure the @ref read_context so that types not reachable from
+/// public interface are taken into account when the abixml file is
+/// read.
+///
+/// @param ctxt the @read_context to consider.
+///
+/// @param flag if yes, then types not reachable from public interface
+/// are taken into account when the abixml file is read.
+void
+consider_types_not_reachable_from_public_interfaces(read_context& ctxt,
+ bool flag)
+{ctxt.tracking_non_reachable_types(flag);}
+
/// Parse the input XML document containing an ABI corpus, represented
/// by an 'abi-corpus' element node, associated to the current
/// context.
}
while (is_ok);
+ if (ctxt.tracking_non_reachable_types())
+ {
+ bool is_tracking_non_reachable_types = false;
+ read_tracking_non_reachable_types(node, is_tracking_non_reachable_types);
+
+ ABG_ASSERT
+ (corp.recording_types_reachable_from_public_interface_supported()
+ == is_tracking_non_reachable_types);
+ }
+
+
ctxt.perform_late_type_canonicalizing();
ctxt.get_environment()->canonicalization_is_done(true);
add_to_current_scope))
|| (decl = handle_class_tdecl(ctxt, node,
add_to_current_scope)));
+
+ // If the user wants us to track non-reachable types, then read the
+ // 'is-non-reachable-type' attribute on type elements and record
+ // reachable types accordingly.
+ if (ctxt.tracking_non_reachable_types())
+ {
+ if (type_base_sptr t = is_type(decl))
+ {
+ corpus_sptr abi = ctxt.get_corpus();
+ ABG_ASSERT(abi);
+ bool is_non_reachable_type = false;
+ read_is_non_reachable_type(node, is_non_reachable_type);
+ if (!is_non_reachable_type)
+ abi->record_type_as_reachable_from_public_interfaces(*t);
+ }
+ }
+
return decl;
}
/// @param node the xml node to consider.
///
/// @param is_decl_only is set to true iff the "is-declaration-only" attribute
-/// is present and set to "yes"
+/// is present and set to "yes".
///
/// @return true iff the is_decl_only attribute was set.
static bool
read_is_declaration_only(xmlNodePtr node, bool& is_decl_only)
{
- if (xml_char_sptr s = XML_NODE_GET_ATTRIBUTE(node, "is-declaration-only"))
- {
- string str = CHAR_STR(s);
- if (str == "yes")
- is_decl_only = true;
- else
- is_decl_only = false;
- return true;
- }
- return false;
+ if (xml_char_sptr s = XML_NODE_GET_ATTRIBUTE(node, "is-declaration-only"))
+ {
+ string str = CHAR_STR(s);
+ if (str == "yes")
+ is_decl_only = true;
+ else
+ is_decl_only = false;
+ return true;
+ }
+ return false;
+}
+
+/// Read the "is-artificial" attribute of the current XML node.
+///
+/// @param node the XML node to consider.
+///
+/// @param is_artificial this output parameter is set to true iff the
+/// "is-artificial" parameter is present and set to 'yes'.
+///
+/// @return true iff the "is-artificial" parameter was present on the
+/// XML node.
+static bool
+read_is_artificial(xmlNodePtr node, bool& is_artificial)
+{
+ if (xml_char_sptr s = XML_NODE_GET_ATTRIBUTE(node, "is-artificial"))
+ {
+ string is_artificial_str = CHAR_STR(s) ? CHAR_STR(s) : "";
+ is_artificial = (is_artificial_str == "yes") ? true : false;
+ return true;
+ }
+ return false;
+}
+
+/// Read the 'tracking-non-reachable-types' attribute on the current
+/// XML element.
+///
+/// @param node the current XML element.
+///
+/// @param tracking_non_reachable_types output parameter. This is set
+/// to true iff the 'tracking-non-reachable-types' attribute is
+/// present on the current XML node and set to 'yes'. In that case,
+/// the function returns true.
+///
+/// @return true iff the 'tracking-non-reachable-types' attribute is
+/// present on the current XML node and set to 'yes'.
+static bool
+read_tracking_non_reachable_types(xmlNodePtr node,
+ bool& tracking_non_reachable_types)
+{
+ if (xml_char_sptr s =
+ XML_NODE_GET_ATTRIBUTE(node, "tracking-non-reachable-types"))
+ {
+ string tracking_non_reachable_types_str = CHAR_STR(s) ? CHAR_STR(s) : "";
+ tracking_non_reachable_types =
+ (tracking_non_reachable_types_str == "yes")
+ ? true
+ : false;
+ return true;
+ }
+ return false;
+}
+
+/// Read the 'is-non-reachable' attribute on the current XML element.
+///
+/// @param node the current XML element.
+///
+/// @param is_non_reachable_type output parameter. This is set to true
+/// iff the 'is-non-reachable' attribute is present on the current XML
+/// element with a value se to 'yes'.
+///
+/// @return true iff the 'is-non-reachable' attribute is present on
+/// the current XML element with a value se to 'yes'.
+static bool
+read_is_non_reachable_type(xmlNodePtr node, bool& is_non_reachable_type)
+{
+ if (xml_char_sptr s =
+ XML_NODE_GET_ATTRIBUTE(node, "is-non-reachable"))
+ {
+ string is_non_reachable_type_str = CHAR_STR(s) ? CHAR_STR(s) : "";
+ is_non_reachable_type =
+ (is_non_reachable_type_str == "yes")
+ ? true
+ : false;
+ return true;
+ }
+ return false;
}
/// Read the "is-virtual" attribute of the current xml node.
}
bool is_artificial = false;
- string is_artificial_str;
- if (xml_char_sptr s =
- xml::build_sptr(xmlGetProp(node, BAD_CAST("is-artificial"))))
- {
- is_artificial_str = CHAR_STR(s) ? CHAR_STR(s) : "";
- is_artificial = (is_artificial_str == "yes") ? true : false;
- }
+ read_is_artificial(node, is_artificial);
string type_id;
if (xml_char_sptr a = xml::build_sptr(xmlGetProp(node, BAD_CAST("type-id"))))
bool is_anonymous = false;
read_is_anonymous(node, is_anonymous);
+ bool is_artificial = false;
+ read_is_artificial(node, is_artificial);
+
string id;
if (xml_char_sptr s = XML_NODE_GET_ATTRIBUTE(node, "id"))
id = CHAR_STR(s);
underlying_type,
enums, linkage_name));
t->set_is_anonymous(is_anonymous);
+ t->set_is_artificial(is_artificial);
if (ctxt.push_and_key_type_decl(t, id, add_to_current_scope))
{
ctxt.map_xml_node_to_decl(node, t);
decl_base::visibility vis = decl_base::VISIBILITY_NONE;
read_visibility(node, vis);
+ bool is_artificial = false;
+ read_is_artificial(node, is_artificial);
+
string id;
if (xml_char_sptr s = XML_NODE_GET_ATTRIBUTE(node, "id"))
id = CHAR_STR(s);
decl->set_is_anonymous(is_anonymous);
}
+ decl->set_is_artificial(is_artificial);
+
string def_id;
bool is_def_of_decl = false;
if (xml_char_sptr s = XML_NODE_GET_ATTRIBUTE(node, "def-of-decl-id"))
decl_base::visibility vis = decl_base::VISIBILITY_NONE;
read_visibility(node, vis);
+ bool is_artificial = false;
+ read_is_artificial(node, is_artificial);
+
string id;
if (xml_char_sptr s = XML_NODE_GET_ATTRIBUTE(node, "id"))
id = CHAR_STR(s);
decl->set_is_anonymous(is_anonymous);
}
+ decl->set_is_artificial(is_artificial);
+
string def_id;
bool is_def_of_decl = false;
if (xml_char_sptr s = XML_NODE_GET_ATTRIBUTE(node, "def-of-decl-id"))
|| (t = build_union_decl_if_not_suppressed(ctxt, node,
add_to_current_scope)));
+ if (ctxt.tracking_non_reachable_types() && t)
+ {
+ corpus_sptr abi = ctxt.get_corpus();
+ ABG_ASSERT(abi);
+ bool is_non_reachable_type = false;
+ read_is_non_reachable_type(node, is_non_reachable_type);
+ if (!is_non_reachable_type)
+ abi->record_type_as_reachable_from_public_interfaces(*t);
+ }
+
return t;
}
out << ", aliases " << aliases;
}
+/// Report changes about types that are not reachable from global
+/// functions and variables, in a given @param corpus_diff.
+///
+/// @param d the corpus_diff to consider.
+///
+/// @param s the statistics of the changes, after filters and
+/// suppressions are reported. This is typically what is returned by
+/// corpus_diff::apply_filters_and_suppressions_before_reporting().
+///
+/// @param indent the indendation string (usually a string of white
+/// spaces) to use for indentation during the reporting.
+///
+/// @param out the output stream to emit the report to.
+void
+maybe_report_unreachable_type_changes(const corpus_diff& d,
+ const corpus_diff::diff_stats &s,
+ const string& indent,
+ ostream& out)
+{
+ const unsigned large_num = 100;
+ const diff_context_sptr& ctxt = d.context();
+
+ if (!(ctxt->show_unreachable_types()
+ && (!d.priv_->deleted_unreachable_types_.empty()
+ || !d.priv_->added_unreachable_types_.empty()
+ || !d.priv_->changed_unreachable_types_.empty())))
+ // The user either doesn't want us to show changes about
+ // unreachable types or there are not such changes.
+ return;
+
+ // Handle removed unreachable types.
+ if (s.net_num_removed_unreachable_types() == 1)
+ out << indent
+ << "1 removed type unreachable from any public interface:\n\n";
+ else if (s.net_num_removed_unreachable_types() > 1)
+ out << indent
+ << s.net_num_removed_unreachable_types()
+ << " removed types unreachable from any public interface:\n\n";
+
+ vector<type_base_sptr> sorted_removed_unreachable_types;
+ sort_string_type_base_sptr_map(d.priv_->deleted_unreachable_types_,
+ sorted_removed_unreachable_types);
+ bool emitted = false;
+ for (vector<type_base_sptr>::const_iterator i =
+ sorted_removed_unreachable_types.begin();
+ i != sorted_removed_unreachable_types.end();
+ ++i)
+ {
+ if (d.priv_->deleted_unreachable_type_is_suppressed((*i).get()))
+ continue;
+
+ out << indent << " ";
+ if (s.num_removed_unreachable_types() > large_num)
+ out << "[D] ";
+ out << get_pretty_representation(*i);
+ report_loc_info(*i, *ctxt, out);
+ out << "\n";
+ emitted = true;
+ }
+ if (emitted)
+ {
+ out << "\n";
+ emitted = false;
+ }
+
+ // Handle changed unreachable types!
+ if (s.net_num_changed_unreachable_types() == 1)
+ out << indent
+ << "1 changed type unreachable from any public interface:\n\n";
+ else if (s.net_num_changed_unreachable_types() > 1)
+ out << indent
+ << s.net_num_changed_unreachable_types()
+ << " changed types unreachable from any public interface:\n\n";
+
+ diff_sptrs_type sorted_diff_sptrs;
+ sort_string_diff_sptr_map(d.priv_->changed_unreachable_types_,
+ sorted_diff_sptrs);
+ emitted = true;
+ for (diff_sptrs_type::const_iterator i = sorted_diff_sptrs.begin();
+ i != sorted_diff_sptrs.end();
+ ++i)
+ {
+ diff_sptr diff = *i;
+ if (!diff || !diff->to_be_reported())
+ continue;
+
+ string repr = diff->first_subject()->get_pretty_representation();
+
+ out << " ";
+
+ if (sorted_diff_sptrs.size() > large_num)
+ out << "[C] ";
+
+ out << "'" << repr << "' changed:\n";
+ diff->report(out, indent + " ");
+ out << "\n";
+ emitted = true;
+ }
+ if (emitted)
+ {
+ out << "\n";
+ emitted = false;
+ }
+
+ // Handle added unreachable types.
+ if (s.net_num_added_unreachable_types() == 1)
+ out << indent
+ << "1 added type unreachable from any public interface:\n\n";
+ else if (s.net_num_added_unreachable_types() > 1)
+ out << indent
+ << s.net_num_added_unreachable_types()
+ << " added types unreachable from any public interface:\n\n";
+
+ vector<type_base_sptr> sorted_added_unreachable_types;
+ sort_string_type_base_sptr_map(d.priv_->added_unreachable_types_,
+ sorted_added_unreachable_types);
+ emitted = false;
+ for (vector<type_base_sptr>::const_iterator i =
+ sorted_added_unreachable_types.begin();
+ i != sorted_added_unreachable_types.end();
+ ++i)
+ {
+ if (d.priv_->added_unreachable_type_is_suppressed((*i).get()))
+ continue;
+
+ out << indent << " ";
+ if (s.num_added_unreachable_types() > large_num)
+ out << "[A] ";
+ out << "'" << get_pretty_representation(*i) << "'";
+ report_loc_info(*i, *ctxt, out);
+ out << "\n";
+ emitted = true;
+ }
+ if (emitted)
+ {
+ out << "\n";
+ emitted = false;
+ }
+}
+
/// If a given diff node impacts some public interfaces, then report
-/// about those impacted interfaces on standard output.
+/// about those impacted interfaces on a given output stream.
///
/// @param d the diff node to get the impacted interfaces for.
///
const elf_symbol& symbol,
const string_elf_symbols_map_type& sym_map);
+void
+maybe_report_unreachable_type_changes(const corpus_diff& d,
+ const corpus_diff::diff_stats &s,
+ const string& indent,
+ ostream& out);
+
void
maybe_report_interfaces_impacted_by_diff(const diff *d,
ostream &out,
static void write_location(const decl_base_sptr&, write_context&);
static bool write_visibility(const decl_base_sptr&, ostream&);
static bool write_binding(const decl_base_sptr&, ostream&);
+static bool write_is_artificial(const decl_base_sptr&, ostream&);
+static bool write_is_non_reachable(const type_base_sptr&, ostream&);
+static bool write_tracking_non_reachable_types(const corpus_sptr&, ostream&);
static void write_array_size_and_alignment(const array_type_def_sptr,
ostream&);
static void write_size_and_alignment(const type_base_sptr, ostream&);
o << "variadic parameter";
else
{
- if (parm->get_artificial())
+ if (parm->get_is_artificial())
{
if (parm->get_index() == 0)
o << "implicit ";
return true;
}
+/// Write the "is-artificial" attribute of the @ref decl.
+///
+/// @param decl the declaration to consider.
+///
+/// @param o the output stream to emit the "is-artificial" attribute
+/// to.
+///
+/// @return true iff the "is-artificial" attribute was emitted.
+static bool
+write_is_artificial(const decl_base_sptr& decl, ostream& o)
+{
+ if (!decl)
+ return false;
+
+ if (decl->get_is_artificial())
+ o << " is-artificial='yes'";
+
+ return true;
+}
+
+/// Write the 'is-non-reachable' attribute if a given type we are
+/// looking at is not reachable from global functions and variables
+/// and if the user asked us to track that information.
+///
+/// @param t the type to consider.
+///
+/// @param o the output stream to write the 'is-non-reachable'
+/// attribute to.
+static bool
+write_is_non_reachable(const type_base_sptr& t, ostream& o)
+{
+ if (!t)
+ return false;
+
+ corpus* c = t->get_corpus();
+ if (!c)
+ return false;
+
+ if (!c->recording_types_reachable_from_public_interface_supported()
+ || c->type_is_reachable_from_public_interfaces(*t))
+ return false;
+
+ o << " is-non-reachable='yes'";
+
+ return true;
+}
+
+/// Write the 'tracking-non-reachable-types' attribute if for a given
+/// corpus, the user wants us to track non-reachable types.
+///
+/// @param corpus the ABI corpus to consider.
+///
+/// @param o the output parameter to write the
+/// 'tracking-non-reachable-types' attribute to.
+static bool
+write_tracking_non_reachable_types(const corpus_sptr& corpus,
+ ostream& o)
+{
+ corpus_group* group = corpus->get_group();
+ if (!group)
+ if (corpus->recording_types_reachable_from_public_interface_supported())
+ {
+ o << " tracking-non-reachable-types='yes'";
+ return true;
+ }
+
+ return false;
+}
+
/// Serialize the size and alignment attributes of a given type.
///
/// @param decl the type to consider.
o << "<enum-decl name='" << xml::escape_xml_string(decl->get_name()) << "'";
write_is_anonymous(decl, o);
+ write_is_artificial(decl, o);
+ write_is_non_reachable(is_type(decl), o);
if (!decl->get_linkage_name().empty())
o << " linkage-name='" << decl->get_linkage_name() << "'";
if (!(*pi)->get_name().empty())
o << " name='" << (*pi)->get_name() << "'";
}
- if ((*pi)->get_artificial())
- o << " is-artificial='yes'";
+ write_is_artificial(*pi, o);
write_location((*pi)->get_location(), ctxt);
o << "/>\n";
}
o << " name='" << name << "'";
}
}
- if ((*pi)->get_artificial())
- o << " is-artificial='yes'";
+ write_is_artificial(*pi, o);
o << "/>\n";
}
write_is_anonymous(decl, o);
+ write_is_artificial(decl, o);
+
+ write_is_non_reachable(is_type(decl), o);
+
write_naming_typedef(decl, ctxt);
write_visibility(decl, o);
write_visibility(decl, o);
+ write_is_artificial(decl, o);
+
+ write_is_non_reachable(is_type(decl), o);
+
write_location(decl, ctxt);
write_class_or_union_is_declaration_only(decl, o);
if (!corpus->get_soname().empty())
out << " soname='" << corpus->get_soname()<< "'";
+ write_tracking_non_reachable_types(corpus, out);
+
if (corpus->is_empty())
{
out << "/>\n";
if (!group->get_architecture_name().empty() && ctxt.get_write_architecture())
out << " architecture='" << group->get_architecture_name()<< "'";
+ write_tracking_non_reachable_types(group, out);
+
if (group->is_empty())
{
out << "/>\n";
test-diff-suppr/test46-PR25128-base.xml \
test-diff-suppr/test46-PR25128-new.xml \
test-diff-suppr/test46-PR25128-report-1.txt \
+test-diff-suppr/test47-non-reachable-types-report-1.txt \
+test-diff-suppr/test47-non-reachable-types-report-2.txt \
+test-diff-suppr/test47-non-reachable-types-report-3.txt \
+test-diff-suppr/test47-non-reachable-types-report-4.txt \
+test-diff-suppr/test47-non-reachable-types-report-5.txt \
+test-diff-suppr/test47-non-reachable-types-report-6.txt \
+test-diff-suppr/test47-non-reachable-types-report-7.txt \
+test-diff-suppr/test47-non-reachable-types-report-8.txt \
+test-diff-suppr/test47-non-reachable-types-report-9.txt \
+test-diff-suppr/test47-non-reachable-types-suppr-1.txt \
+test-diff-suppr/test47-non-reachable-types-suppr-2.txt \
+test-diff-suppr/test47-non-reachable-types-suppr-3.txt \
+test-diff-suppr/test47-non-reachable-types-suppr-4.txt \
+test-diff-suppr/test47-non-reachable-types-suppr-5.txt \
+test-diff-suppr/test47-non-reachable-types-v0.c \
+test-diff-suppr/test47-non-reachable-types-v0.o \
+test-diff-suppr/test47-non-reachable-types-v1.c \
+test-diff-suppr/test47-non-reachable-types-v1.o \
+test-diff-suppr/test47-non-reachable-types-v0.o.alltypes.abixml \
+test-diff-suppr/test47-non-reachable-types-v1.o.alltypes.abixml \
+test-diff-suppr/test47-non-reachable-types-report-10.txt \
\
test-diff-dwarf-abixml/test0-pr19026-libvtkIOSQL-6.1.so.1 \
test-diff-dwarf-abixml/test0-pr19026-libvtkIOSQL-6.1.so.1.abi \
test-diff-pkg/PR24410-old/poppler-qt5-debuginfo-0.73.0-4.fc30.x86_64.rpm \
test-diff-pkg/PR24410-old/poppler-qt5-devel-0.73.0-4.fc30.x86_64.rpm \
test-diff-pkg/PR24410-report-0.txt \
+test-diff-pkg/PR24690/PR24690-report-0.txt \
+test-diff-pkg/PR24690/flatpak-debuginfo-1.2.4-3.fc30.x86_64.rpm \
+test-diff-pkg/PR24690/flatpak-debuginfo-1.4.0-1.fc30.x86_64.rpm \
+test-diff-pkg/PR24690/flatpak-devel-1.2.4-3.fc30.x86_64.rpm \
+test-diff-pkg/PR24690/flatpak-devel-1.4.0-1.fc30.x86_64.rpm \
+test-diff-pkg/PR24690/flatpak-libs-1.2.4-3.fc30.x86_64.rpm \
+test-diff-pkg/PR24690/flatpak-libs-1.4.0-1.fc30.x86_64.rpm \
+test-diff-pkg/PR24690/flatpak-libs-debuginfo-1.2.4-3.fc30.x86_64.rpm \
+test-diff-pkg/PR24690/flatpak-libs-debuginfo-1.4.0-1.fc30.x86_64.rpm \
\
test-fedabipkgdiff/dbus-glib-0.104-3.fc23.x86_64.rpm \
test-fedabipkgdiff/dbus-glib-debuginfo-0.104-3.fc23.x86_64.rpm \
5 changed types:
- 'const s0' changed:
- in unqualified underlying type 'class s0':
- type size changed from 192 to 256 (in bits)
- 1 member function insertion:
- 'method virtual int s0::foo(int, char) const', virtual at voffset 2/2
+ 'class s0' changed:
+ type size changed from 192 to 256 (in bits)
+ 1 member function insertion:
+ 'method virtual int s0::foo(int, char) const', virtual at voffset 2/2
- 1 data member deletion:
- 'char s0::m1', at offset 96 (in bits)
+ 1 data member deletion:
+ 'char s0::m1', at offset 96 (in bits)
- 1 data member insertion:
- 'double s0::m01', at offset 128 (in bits)
- 2 data member changes:
- type of 'int s0::m0' changed:
- type name changed from 'int' to 'char'
- type size changed from 32 to 8 (in bits)
- type alignement changed from 32 to 8
+ 1 data member insertion:
+ 'double s0::m01', at offset 128 (in bits)
+ 2 data member changes:
+ type of 'int s0::m0' changed:
+ type name changed from 'int' to 'char'
+ type size changed from 32 to 8 (in bits)
+ type alignement changed from 32 to 8
- 'unsigned int s0::m2' offset changed from 128 to 192 (in bits) (by +64 bits)
+ 'unsigned int s0::m2' offset changed from 128 to 192 (in bits) (by +64 bits)
+ 'const s0' changed:
+ unqualified underlying type 'class s0' changed, as reported earlier
'const s0*' changed:
in pointed to type 'const s0':
unqualified underlying type 'class s0' changed, as reported earlier
- 'class s0' changed:
- details were reported earlier
's0&' changed:
referenced type 'class s0' changed, as reported earlier
's0*' changed:
--- /dev/null
+================ changes of 'libflatpak.so.0.10204.0'===============
+ Functions changes summary: 0 Removed, 0 Changed (16 filtered out), 16 Added functions
+ Variables changes summary: 0 Removed, 0 Changed, 0 Added variable
+ Unreachable types summary: 3 removed (2 filtered out), 1 changed (15 filtered out), 3 added (1 filtered out) types
+
+ 16 Added functions:
+
+ 'function gboolean flatpak_installation_add_remote(FlatpakInstallation*, FlatpakRemote*, gboolean, GCancellable*, GError**)' {flatpak_installation_add_remote}
+ 'function FlatpakRemoteRef* flatpak_installation_fetch_remote_ref_sync_full(FlatpakInstallation*, const char*, FlatpakRefKind, const char*, const char*, const char*, FlatpakQueryFlags, GCancellable*, GError**)' {flatpak_installation_fetch_remote_ref_sync_full}
+ 'function GPtrArray* flatpak_installation_list_remote_refs_sync_full(FlatpakInstallation*, const char*, FlatpakQueryFlags, GCancellable*, GError**)' {flatpak_installation_list_remote_refs_sync_full}
+ 'function GType flatpak_query_flags_get_type()' {flatpak_query_flags_get_type}
+ 'function char* flatpak_remote_get_comment(FlatpakRemote*)' {flatpak_remote_get_comment}
+ 'function char* flatpak_remote_get_description(FlatpakRemote*)' {flatpak_remote_get_description}
+ 'function char* flatpak_remote_get_filter(FlatpakRemote*)' {flatpak_remote_get_filter}
+ 'function char* flatpak_remote_get_homepage(FlatpakRemote*)' {flatpak_remote_get_homepage}
+ 'function char* flatpak_remote_get_icon(FlatpakRemote*)' {flatpak_remote_get_icon}
+ 'function FlatpakRemote* flatpak_remote_new_from_file(const char*, GBytes*, GError**)' {flatpak_remote_new_from_file}
+ 'function void flatpak_remote_set_comment(FlatpakRemote*, const char*)' {flatpak_remote_set_comment}
+ 'function void flatpak_remote_set_description(FlatpakRemote*, const char*)' {flatpak_remote_set_description}
+ 'function void flatpak_remote_set_filter(FlatpakRemote*, const char*)' {flatpak_remote_set_filter}
+ 'function void flatpak_remote_set_homepage(FlatpakRemote*, const char*)' {flatpak_remote_set_homepage}
+ 'function void flatpak_remote_set_icon(FlatpakRemote*, const char*)' {flatpak_remote_set_icon}
+ 'function gboolean flatpak_transaction_add_rebase(FlatpakTransaction*, const char*, const char*, const char**, const char**, GError**)' {flatpak_transaction_add_rebase}
+
+ 3 removed types unreachable from any public interface:
+
+ struct _GUnixFDList at gunixfdlist.h:58:1
+ typedef GUnixFDList at giotypes.h:549:1
+ typedef GUnixFDListPrivate at gunixfdlist.h:41:1
+
+ 1 changed type unreachable from any public interface:
+
+ 'struct _FlatpakTransactionClass' changed:
+ type size changed from 2176 to 2240 (in bits)
+ 1 data member insertion:
+ 'typedef gboolean (FlatpakTransaction*, const char*, const char*, const char*, const char*, const char**)* _FlatpakTransactionClass::end_of_lifed_with_rebase', at offset 1408 (in bits) at flatpak-transaction.h:117:1
+ 4 data member changes (3 filtered):
+ 'typedef gboolean (FlatpakTransaction*)* _FlatpakTransactionClass::ready' offset changed from 1408 to 1472 (in bits) (by +64 bits)
+ 'typedef gboolean (FlatpakTransaction*, typedef FlatpakTransactionRemoteReason, const char*, const char*, const char*)* _FlatpakTransactionClass::add_new_remote' offset changed from 1472 to 1536 (in bits) (by +64 bits)
+ 'typedef gboolean (FlatpakTransaction*, GCancellable*, GError**)* _FlatpakTransactionClass::run' offset changed from 1536 to 1600 (in bits) (by +64 bits)
+ 'gpointer _FlatpakTransactionClass::padding[9]' offset changed from 1600 to 1664 (in bits) (by +64 bits)
+
+
+ 3 added types unreachable from any public interface:
+
+ 'struct gpgme_data_cbs' at gpgme-64.h:1139:1
+ 'typedef GSubprocess' at giotypes.h:642:1
+ 'typedef OstreeRepoResolveRevExtFlags' at ostree-repo.h:473:1
+
+================ end of changes of 'libflatpak.so.0.10204.0'===============
+
--- /dev/null
+Functions changes summary: 0 Removed, 0 Changed, 0 Added function
+Variables changes summary: 0 Removed, 0 Changed, 0 Added variable
+Unreachable types summary: 1 removed, 1 changed, 1 added types
+
+1 removed type unreachable from any public interface:
+
+ struct unreachable_struct1 at test-v0.c:6:1
+
+1 changed type unreachable from any public interface:
+
+ 'struct unreachable_struct2' changed:
+ type size changed from 32 to 64 (in bits)
+ 1 data member insertion:
+ 'char unreachable_struct2::m2', at offset 32 (in bits) at test-v1.c:9:1
+
+
+1 added type unreachable from any public interface:
+
+ 'struct unreachable_struct3' at test-v1.c:12:1
+
--- /dev/null
+Functions changes summary: 0 Removed, 0 Changed, 0 Added function
+Variables changes summary: 0 Removed, 0 Changed, 0 Added variable
+Unreachable types summary: 0 removed (1 filtered out), 1 changed, 1 added types
+
+1 changed type unreachable from any public interface:
+
+ 'struct unreachable_struct2' changed:
+ type size changed from 32 to 64 (in bits)
+ 1 data member insertion:
+ 'char unreachable_struct2::m2', at offset 32 (in bits) at test-v1.c:9:1
+
+
+1 added type unreachable from any public interface:
+
+ 'struct unreachable_struct3' at test-v1.c:12:1
+
--- /dev/null
+Functions changes summary: 0 Removed, 0 Changed, 0 Added function
+Variables changes summary: 0 Removed, 0 Changed, 0 Added variable
+Unreachable types summary: 1 removed, 0 changed (1 filtered out), 1 added types
+
+1 removed type unreachable from any public interface:
+
+ struct unreachable_struct1 at test-v0.c:6:1
+
+
+1 added type unreachable from any public interface:
+
+ 'struct unreachable_struct3' at test-v1.c:12:1
+
--- /dev/null
+Functions changes summary: 0 Removed, 0 Changed, 0 Added function
+Variables changes summary: 0 Removed, 0 Changed, 0 Added variable
+Unreachable types summary: 1 removed, 1 changed, 0 added (1 filtered out) types
+
+1 removed type unreachable from any public interface:
+
+ struct unreachable_struct1 at test-v0.c:6:1
+
+1 changed type unreachable from any public interface:
+
+ 'struct unreachable_struct2' changed:
+ type size changed from 32 to 64 (in bits)
+ 1 data member insertion:
+ 'char unreachable_struct2::m2', at offset 32 (in bits) at test-v1.c:9:1
+
+
--- /dev/null
+Functions changes summary: 0 Removed, 0 Changed, 0 Added function
+Variables changes summary: 0 Removed, 0 Changed, 0 Added variable
+Unreachable types summary: 0 removed (1 filtered out), 0 changed (1 filtered out), 0 added (1 filtered out) types
+
+
--- /dev/null
+Leaf changes summary: 0 artifact changed
+Changed leaf types summary: 0 leaf type changed
+Removed/Changed/Added functions summary: 0 Removed, 0 Changed, 0 Added function
+Removed/Changed/Added variables summary: 0 Removed, 0 Changed, 0 Added variable
+Unreachable types summary: 1 removed, 1 changed, 1 added types
+
+1 removed type unreachable from any public interface:
+
+ struct unreachable_struct1 at test-v0.c:6:1
+
+1 changed type unreachable from any public interface:
+
+ 'struct unreachable_struct2' changed:
+ type size changed from 32 to 64 (in bits)
+ 1 data member insertion:
+ 'char unreachable_struct2::m2', at offset 32 (in bits) at test-v1.c:9:1
+
+
+1 added type unreachable from any public interface:
+
+ 'struct unreachable_struct3' at test-v1.c:12:1
+
--- /dev/null
+Leaf changes summary: 0 artifact changed
+Changed leaf types summary: 0 leaf type changed
+Removed/Changed/Added functions summary: 0 Removed, 0 Changed, 0 Added function
+Removed/Changed/Added variables summary: 0 Removed, 0 Changed, 0 Added variable
+Unreachable types summary: 0 removed (1 filtered out), 0 changed (1 filtered out), 0 added (1 filtered out) types
+
+
--- /dev/null
+[suppress_type]
+ name = unreachable_struct1
+
--- /dev/null
+[suppress_type]
+ name = unreachable_struct2
+
--- /dev/null
+[suppress_type]
+ name = unreachable_struct3
+
--- /dev/null
+[suppress_type]
+ name_regexp = unreachable_struct.
--- /dev/null
+[suppress_type]
+ name_regexp = unreachable_struct.
+ drop = true
+
--- /dev/null
+struct reachable_struct1
+{
+ int m0;
+};
+
+struct unreachable_struct1
+{
+ int m1;
+};
+
+struct unreachable_struct2
+{
+ int m1;
+};
+
+void foo(struct reachable_struct1* __attribute__((unused)) s)
+{
+}
+
+static void private_func()
+{
+ struct unreachable_struct1 s1;
+ s1.m1 = 0;
+
+ struct unreachable_struct2 s0;
+ s0.m1 = 0;
+
+}
--- /dev/null
+<abi-corpus path='test-v0.o' architecture='elf-amd-x86_64' tracking-non-reachable-types='yes'>
+ <elf-function-symbols>
+ <elf-symbol name='foo' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
+ </elf-function-symbols>
+ <abi-instr version='1.0' address-size='64' path='test-v0.c' comp-dir-path='/home/dodji/git/libabigail/compare-all-types/prtests/PR24690' language='LANG_C89'>
+ <type-decl name='int' size-in-bits='32' id='type-id-1'/>
+ <type-decl name='void' id='type-id-2'/>
+ <class-decl name='reachable_struct1' size-in-bits='32' is-struct='yes' visibility='default' filepath='/home/dodji/git/libabigail/compare-all-types/prtests/PR24690/test-v0.c' line='1' column='1' id='type-id-3'>
+ <data-member access='public' layout-offset-in-bits='0'>
+ <var-decl name='m0' type-id='type-id-1' visibility='default' filepath='/home/dodji/git/libabigail/compare-all-types/prtests/PR24690/test-v0.c' line='3' column='1'/>
+ </data-member>
+ </class-decl>
+ <class-decl name='unreachable_struct1' size-in-bits='32' is-struct='yes' is-non-reachable='yes' visibility='default' filepath='/home/dodji/git/libabigail/compare-all-types/prtests/PR24690/test-v0.c' line='6' column='1' id='type-id-4'>
+ <data-member access='public' layout-offset-in-bits='0'>
+ <var-decl name='m1' type-id='type-id-1' visibility='default' filepath='/home/dodji/git/libabigail/compare-all-types/prtests/PR24690/test-v0.c' line='8' column='1'/>
+ </data-member>
+ </class-decl>
+ <class-decl name='unreachable_struct2' size-in-bits='32' is-struct='yes' is-non-reachable='yes' visibility='default' filepath='/home/dodji/git/libabigail/compare-all-types/prtests/PR24690/test-v0.c' line='11' column='1' id='type-id-5'>
+ <data-member access='public' layout-offset-in-bits='0'>
+ <var-decl name='m1' type-id='type-id-1' visibility='default' filepath='/home/dodji/git/libabigail/compare-all-types/prtests/PR24690/test-v0.c' line='13' column='1'/>
+ </data-member>
+ </class-decl>
+ <pointer-type-def type-id='type-id-3' size-in-bits='64' id='type-id-6'/>
+ <function-decl name='foo' mangled-name='foo' filepath='/home/dodji/git/libabigail/compare-all-types/prtests/PR24690/test-v0.c' line='16' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='foo'>
+ <parameter type-id='type-id-6' name='s' filepath='/home/dodji/git/libabigail/compare-all-types/prtests/PR24690/test-v0.c' line='16' column='1'/>
+ <return type-id='type-id-2'/>
+ </function-decl>
+ </abi-instr>
+</abi-corpus>
--- /dev/null
+struct reachable_struct1
+{
+ int m0;
+};
+
+struct unreachable_struct2
+{
+ int m1;
+ char m2;
+};
+
+struct unreachable_struct3
+{
+ int m1;
+};
+
+void foo(struct reachable_struct1* __attribute__((unused)) s)
+{
+}
+
+static void private_func()
+{
+ struct unreachable_struct2 s0;
+ s0.m1 = 0;
+ struct unreachable_struct3 s1;
+ s1.m1 = 0;
+}
--- /dev/null
+<abi-corpus path='test-v1.o' architecture='elf-amd-x86_64' tracking-non-reachable-types='yes'>
+ <elf-function-symbols>
+ <elf-symbol name='foo' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
+ </elf-function-symbols>
+ <abi-instr version='1.0' address-size='64' path='test-v1.c' comp-dir-path='/home/dodji/git/libabigail/compare-all-types/prtests/PR24690' language='LANG_C89'>
+ <type-decl name='char' size-in-bits='8' id='type-id-1'/>
+ <type-decl name='int' size-in-bits='32' id='type-id-2'/>
+ <type-decl name='void' id='type-id-3'/>
+ <class-decl name='reachable_struct1' size-in-bits='32' is-struct='yes' visibility='default' filepath='/home/dodji/git/libabigail/compare-all-types/prtests/PR24690/test-v1.c' line='1' column='1' id='type-id-4'>
+ <data-member access='public' layout-offset-in-bits='0'>
+ <var-decl name='m0' type-id='type-id-2' visibility='default' filepath='/home/dodji/git/libabigail/compare-all-types/prtests/PR24690/test-v1.c' line='3' column='1'/>
+ </data-member>
+ </class-decl>
+ <class-decl name='unreachable_struct2' size-in-bits='64' is-struct='yes' is-non-reachable='yes' visibility='default' filepath='/home/dodji/git/libabigail/compare-all-types/prtests/PR24690/test-v1.c' line='6' column='1' id='type-id-5'>
+ <data-member access='public' layout-offset-in-bits='0'>
+ <var-decl name='m1' type-id='type-id-2' visibility='default' filepath='/home/dodji/git/libabigail/compare-all-types/prtests/PR24690/test-v1.c' line='8' column='1'/>
+ </data-member>
+ <data-member access='public' layout-offset-in-bits='32'>
+ <var-decl name='m2' type-id='type-id-1' visibility='default' filepath='/home/dodji/git/libabigail/compare-all-types/prtests/PR24690/test-v1.c' line='9' column='1'/>
+ </data-member>
+ </class-decl>
+ <class-decl name='unreachable_struct3' size-in-bits='32' is-struct='yes' is-non-reachable='yes' visibility='default' filepath='/home/dodji/git/libabigail/compare-all-types/prtests/PR24690/test-v1.c' line='12' column='1' id='type-id-6'>
+ <data-member access='public' layout-offset-in-bits='0'>
+ <var-decl name='m1' type-id='type-id-2' visibility='default' filepath='/home/dodji/git/libabigail/compare-all-types/prtests/PR24690/test-v1.c' line='14' column='1'/>
+ </data-member>
+ </class-decl>
+ <pointer-type-def type-id='type-id-4' size-in-bits='64' id='type-id-7'/>
+ <function-decl name='foo' mangled-name='foo' filepath='/home/dodji/git/libabigail/compare-all-types/prtests/PR24690/test-v1.c' line='17' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='foo'>
+ <parameter type-id='type-id-7' name='s' filepath='/home/dodji/git/libabigail/compare-all-types/prtests/PR24690/test-v1.c' line='17' column='1'/>
+ <return type-id='type-id-3'/>
+ </function-decl>
+ </abi-instr>
+</abi-corpus>
"data/test-diff-pkg/PR24410-report-0.txt",
"output/test-diff-pkg/PR24410-report-0.txt"
},
+ {
+ "data/test-diff-pkg/PR24690/flatpak-libs-1.2.4-3.fc30.x86_64.rpm",
+ "data/test-diff-pkg/PR24690/flatpak-libs-1.4.0-1.fc30.x86_64.rpm",
+ "--non-reachable-types",
+ "",
+ "data/test-diff-pkg/PR24690/flatpak-debuginfo-1.2.4-3.fc30.x86_64.rpm, "
+ "data/test-diff-pkg/PR24690/flatpak-libs-debuginfo-1.2.4-3.fc30.x86_64.rpm",
+ "data/test-diff-pkg/PR24690/flatpak-debuginfo-1.4.0-1.fc30.x86_64.rpm, "
+ "data/test-diff-pkg/PR24690/flatpak-libs-debuginfo-1.4.0-1.fc30.x86_64.rpm",
+ "data/test-diff-pkg/PR24690/flatpak-devel-1.2.4-3.fc30.x86_64.rpm",
+ "data/test-diff-pkg/PR24690/flatpak-devel-1.4.0-1.fc30.x86_64.rpm",
+ "data/test-diff-pkg/PR24690/PR24690-report-0.txt",
+ "output/test-diff-pkg/PR24690/PR24690-report-0.txt"
+ },
#endif //WITH_RPM
#ifdef WITH_DEB
"data/test-diff-suppr/test46-PR25128-report-1.txt",
"output/test-diff-suppr/test46-PR25128-report-1.txt"
},
+ {
+ "data/test-diff-suppr/test47-non-reachable-types-v0.o",
+ "data/test-diff-suppr/test47-non-reachable-types-v1.o",
+ "",
+ "",
+ "",
+ "--no-default-suppression --non-reachable-types",
+ "data/test-diff-suppr/test47-non-reachable-types-report-1.txt",
+ "output/test-diff-suppr/test47-non-reachable-types-report-1.txt"
+ },
+ {
+ "data/test-diff-suppr/test47-non-reachable-types-v0.o",
+ "data/test-diff-suppr/test47-non-reachable-types-v1.o",
+ "",
+ "",
+ "data/test-diff-suppr/test47-non-reachable-types-suppr-1.txt",
+ "--no-default-suppression --non-reachable-types",
+ "data/test-diff-suppr/test47-non-reachable-types-report-2.txt",
+ "output/test-diff-suppr/test47-non-reachable-types-report-2.txt"
+ },
+ {
+ "data/test-diff-suppr/test47-non-reachable-types-v0.o",
+ "data/test-diff-suppr/test47-non-reachable-types-v1.o",
+ "",
+ "",
+ "data/test-diff-suppr/test47-non-reachable-types-suppr-2.txt",
+ "--no-default-suppression --non-reachable-types",
+ "data/test-diff-suppr/test47-non-reachable-types-report-3.txt",
+ "output/test-diff-suppr/test47-non-reachable-types-report-3.txt"
+ },
+ {
+ "data/test-diff-suppr/test47-non-reachable-types-v0.o",
+ "data/test-diff-suppr/test47-non-reachable-types-v1.o",
+ "",
+ "",
+ "data/test-diff-suppr/test47-non-reachable-types-suppr-3.txt",
+ "--no-default-suppression --non-reachable-types",
+ "data/test-diff-suppr/test47-non-reachable-types-report-4.txt",
+ "output/test-diff-suppr/test47-non-reachable-types-report-4.txt"
+ },
+ {
+ "data/test-diff-suppr/test47-non-reachable-types-v0.o",
+ "data/test-diff-suppr/test47-non-reachable-types-v1.o",
+ "",
+ "",
+ "data/test-diff-suppr/test47-non-reachable-types-suppr-4.txt",
+ "--no-default-suppression --non-reachable-types",
+ "data/test-diff-suppr/test47-non-reachable-types-report-5.txt",
+ "output/test-diff-suppr/test47-non-reachable-types-report-5.txt"
+ },
+ {
+ "data/test-diff-suppr/test47-non-reachable-types-v0.o",
+ "data/test-diff-suppr/test47-non-reachable-types-v1.o",
+ "",
+ "",
+ "data/test-diff-suppr/test47-non-reachable-types-suppr-5.txt",
+ "--no-default-suppression --non-reachable-types",
+ "data/test-diff-suppr/test47-non-reachable-types-report-6.txt",
+ "output/test-diff-suppr/test47-non-reachable-types-report-6.txt"
+ },
+ {
+ "data/test-diff-suppr/test47-non-reachable-types-v0.o",
+ "data/test-diff-suppr/test47-non-reachable-types-v1.o",
+ "",
+ "",
+ "",
+ "--no-default-suppression --non-reachable-types --leaf-changes-only",
+ "data/test-diff-suppr/test47-non-reachable-types-report-7.txt",
+ "output/test-diff-suppr/test47-non-reachable-types-report-7.txt"
+ },
+ {
+ "data/test-diff-suppr/test47-non-reachable-types-v0.o",
+ "data/test-diff-suppr/test47-non-reachable-types-v1.o",
+ "",
+ "",
+ "data/test-diff-suppr/test47-non-reachable-types-suppr-4.txt",
+ "--no-default-suppression --non-reachable-types --leaf-changes-only",
+ "data/test-diff-suppr/test47-non-reachable-types-report-8.txt",
+ "output/test-diff-suppr/test47-non-reachable-types-report-8.txt"
+ },
+ {
+ "data/test-diff-suppr/test47-non-reachable-types-v0.o",
+ "data/test-diff-suppr/test47-non-reachable-types-v1.o",
+ "",
+ "",
+ "data/test-diff-suppr/test47-non-reachable-types-suppr-5.txt",
+ "--no-default-suppression --non-reachable-types --leaf-changes-only",
+ "data/test-diff-suppr/test47-non-reachable-types-report-9.txt",
+ "output/test-diff-suppr/test47-non-reachable-types-report-9.txt"
+ },
+ {
+ "data/test-diff-suppr/test47-non-reachable-types-v0.o.alltypes.abixml",
+ "data/test-diff-suppr/test47-non-reachable-types-v1.o.alltypes.abixml",
+ "",
+ "",
+ "",
+ "--no-default-suppression --non-reachable-types",
+ "data/test-diff-suppr/test47-non-reachable-types-report-1.txt",
+ "output/test-diff-suppr/test47-non-reachable-types-report-1.txt"
+ },
+ {
+ "data/test-diff-suppr/test47-non-reachable-types-v0.o.alltypes.abixml",
+ "data/test-diff-suppr/test47-non-reachable-types-v1.o.alltypes.abixml",
+ "",
+ "",
+ "",
+ "--no-default-suppression",
+ "data/test-diff-suppr/test47-non-reachable-types-report-10.txt",
+ "output/test-diff-suppr/test47-non-reachable-types-report-10.txt"
+ },
// This should be the last entry
{NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}
};
bool show_changed_vars;
bool show_added_vars;
bool show_all_vars;
+ bool show_all_types;
bool show_linkage_names;
bool show_locs;
bool show_harmful_changes;
show_changed_vars(),
show_added_vars(),
show_all_vars(true),
+ show_all_types(false),
show_linkage_names(true),
show_locs(true),
show_harmful_changes(true),
<< " --deleted-vars display deleted global public variables\n"
<< " --changed-vars display changed global public variables\n"
<< " --added-vars display added global public variables\n"
+ << " --non-reachable-types|-t consider types non reachable"
+ " from public interfaces\n"
<< " --no-added-syms do not display added functions or variables\n"
<< " --no-linkage-name do not display linkage names of "
"added/removed/changed\n"
opts.show_all_fns = false;
opts.show_all_vars = false;
}
+ else if (!strcmp(argv[i], "--non-reachable-types")
+ || !strcmp(argv[i], "-t"))
+ opts.show_all_types = true;
else if (!strcmp(argv[i], "--no-added-syms"))
{
opts.show_added_syms = false;
(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_unreachable_types(opts.show_all_types);
ctxt->show_impacted_interfaces(opts.show_impacted_interfaces);
if (!opts.show_harmless_changes)
add_read_context_suppressions(read_ctxt, supprs);
}
+/// Configure the abigail::xml_reacher::read_context based on the
+/// relevant command-line options.
+///
+/// @param ctxt the read context to configure.
+///
+/// @param opts the command-line options to configure @p ctxt from.
+static void
+set_native_xml_reader_options(abigail::xml_reader::read_context& ctxt,
+ const options& opts)
+{
+ consider_types_not_reachable_from_public_interfaces(ctxt,
+ opts.show_all_types);
+}
+
/// Set the regex patterns describing the functions to drop from the
/// symbol table of a given corpus.
///
t1 = abigail::xml_reader::read_translation_unit_from_file(opts.file1,
env.get());
break;
- case abigail::tools_utils::FILE_TYPE_ELF:
+ case abigail::tools_utils::FILE_TYPE_ELF: // fall through
case abigail::tools_utils::FILE_TYPE_AR:
{
abigail::dwarf_reader::read_context_sptr ctxt =
abigail::dwarf_reader::create_read_context
- (opts.file1, opts.prepared_di_root_paths1, env.get(),
- /*readalltypes*/false, opts.linux_kernel_mode);
+ (opts.file1, opts.prepared_di_root_paths1,
+ env.get(), /*readalltypes=*/opts.show_all_types,
+ opts.linux_kernel_mode);
assert(ctxt);
abigail::dwarf_reader::set_show_stats(*ctxt, opts.show_stats);
env.get());
assert(ctxt);
set_suppressions(*ctxt, opts);
+ set_native_xml_reader_options(*ctxt, opts);
c1 = abigail::xml_reader::read_corpus_from_input(*ctxt);
if (!c1)
return handle_error(c1_status, /*ctxt=*/0,
env.get());
assert(ctxt);
set_suppressions(*ctxt, opts);
+ set_native_xml_reader_options(*ctxt, opts);
g1 = abigail::xml_reader::read_corpus_group_from_input(*ctxt);
if (!g1)
return handle_error(c1_status, /*ctxt=*/0,
t2 = abigail::xml_reader::read_translation_unit_from_file(opts.file2,
env.get());
break;
- case abigail::tools_utils::FILE_TYPE_ELF:
+ case abigail::tools_utils::FILE_TYPE_ELF: // Fall through
case abigail::tools_utils::FILE_TYPE_AR:
{
abigail::dwarf_reader::read_context_sptr ctxt =
abigail::dwarf_reader::create_read_context
- (opts.file2, opts.prepared_di_root_paths2, env.get(),
- /*readalltypes=*/false, opts.linux_kernel_mode);
+ (opts.file2, opts.prepared_di_root_paths2,
+ env.get(), /*readalltypes=*/opts.show_all_types,
+ opts.linux_kernel_mode);
assert(ctxt);
abigail::dwarf_reader::set_show_stats(*ctxt, opts.show_stats);
abigail::dwarf_reader::set_do_log(*ctxt, opts.do_log);
env.get());
assert(ctxt);
set_suppressions(*ctxt, opts);
+ set_native_xml_reader_options(*ctxt, opts);
c2 = abigail::xml_reader::read_corpus_from_input(*ctxt);
if (!c2)
return handle_error(c2_status, /*ctxt=*/0, argv[0], opts);
env.get());
assert(ctxt);
set_suppressions(*ctxt, opts);
+ set_native_xml_reader_options(*ctxt, opts);
g2 = abigail::xml_reader::read_corpus_group_from_input(*ctxt);
if (!g2)
return handle_error(c2_status, /*ctxt=*/0, argv[0], opts);
bool compare_dso_only;
bool compare_private_dsos;
bool leaf_changes_only;
+ bool show_all_types;
bool show_hexadecimal_values;
bool show_offsets_sizes_in_bits;
bool show_impacted_interfaces;
compare_dso_only(),
compare_private_dsos(),
leaf_changes_only(),
+ show_all_types(),
show_hexadecimal_values(),
show_offsets_sizes_in_bits(true),
show_impacted_interfaces(),
"interfaces impacted by ABI changes\n"
<< " --full-impact|-f when comparing kernel packages, show the "
"full impact analysis report rather than the default leaf changes reports\n"
+ << " --non-reachable-types|-t consider types non reachable"
+ " from public interfaces\n"
<< " --no-linkage-name do not display linkage names of "
"added/removed/changed\n"
<< " --redundant display redundant changes\n"
ctxt->show_redundant_changes(opts.show_redundant_changes);
ctxt->show_leaf_changes_only(opts.leaf_changes_only);
ctxt->show_impacted_interfaces(opts.show_impacted_interfaces);
+ ctxt->show_unreachable_types(opts.show_all_types);
ctxt->show_hex_values(opts.show_hexadecimal_values);
ctxt->show_offsets_sizes_in_bits(opts.show_offsets_sizes_in_bits);
ctxt->show_relative_offset_changes(opts.show_relative_offset_changes);
corpus_sptr corpus1;
{
- read_context_sptr c = create_read_context(elf1.path, di_dirs1, env.get(),
- /*load_all_types=*/false);
+ read_context_sptr c =
+ create_read_context(elf1.path, di_dirs1, env.get(),
+ /*load_all_types=*/opts.show_all_types);
add_read_context_suppressions(*c, priv_types_supprs1);
if (!opts.kabi_suppressions.empty())
add_read_context_suppressions(*c, opts.kabi_suppressions);
corpus_sptr corpus2;
{
- read_context_sptr c = create_read_context(elf2.path, di_dirs2, env.get(),
- /*load_all_types=*/false);
+ read_context_sptr c =
+ create_read_context(elf2.path, di_dirs2, env.get(),
+ /*load_all_types=*/opts.show_all_types);
add_read_context_suppressions(*c, priv_types_supprs2);
if (!opts.kabi_suppressions.empty())
else if (!strcmp(argv[i], "--impacted-interfaces")
||!strcmp(argv[i], "-i"))
opts.show_impacted_interfaces = true;
+ else if (!strcmp(argv[i], "--non-reachable-types")
+ ||!strcmp(argv[i], "-t"))
+ opts.show_all_types = true;
else if (!strcmp(argv[i], "--full-impact")
||!strcmp(argv[i], "-f"))
opts.show_full_impact_report = true;