// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // -*- Mode: C++ -*- // // Copyright (C) 2017-2022 Red Hat, Inc. // // Author: Dodji Seketeli /// @file /// /// The private data and functions of the @ref abigail::ir::comparison types. /// /// Interfaces declared/defined in this file are to be used by parts /// of libabigail but *NOT* by clients of libabigail. /// #ifndef __ABG_COMPARISON_PRIV_H__ #define __ABG_COMPARISON_PRIV_H__ #include "abg-internal.h" // #include #include ABG_BEGIN_EXPORT_DECLARATIONS #include "abg-hash.h" #include "abg-suppression.h" #include "abg-comparison.h" #include "abg-comp-filter.h" #include "abg-sptr-utils.h" #include "abg-tools-utils.h" ABG_END_EXPORT_DECLARATIONS // namespace abigail { namespace comparison { using std::unordered_set; using namespace abigail::suppr; // Inject types from outside in here. using std::vector; using std::dynamic_pointer_cast; using std::static_pointer_cast; using abigail::sptr_utils::noop_deleter; /// Convenience typedef for a pair of decls or types. typedef std::pair types_or_decls_type; /// A hashing functor for @ref types_or_decls_type. struct types_or_decls_hash { size_t operator()(const types_or_decls_type& d) const { size_t h1 = hash_type_or_decl(d.first); size_t h2 = hash_type_or_decl(d.second); return hashing::combine_hashes(h1, h2); } }; /// An equality functor for @ref types_or_decls_type. struct types_or_decls_equal { bool operator()(const types_or_decls_type &d1, const types_or_decls_type &d2) const {return d1.first == d2.first && d1.second == d2.second;} }; /// A convenience typedef for a map of @ref types_or_decls_type and /// diff_sptr. typedef unordered_map types_or_decls_diff_map_type; /// A hashing functor for using @ref diff_sptr and @ref diff* in a /// hash map or set. struct diff_hash { /// The function-call operator to hash a @ref diff node. /// /// @param d the @ref diff node to hash. /// /// @return the hash value of @p d. size_t operator()(const diff_sptr& d) const {return operator()(*d);} /// The function-call operator to hash a @ref diff node. /// /// @param d the @ref diff node to hash. /// /// @return the hash value of @p d. size_t operator()(const diff *d) const {return operator()(*d);} /// The function-call operator to hash a @ref diff node. /// /// @param d the @ref diff node to hash. /// /// @return the hash value of @p d. size_t operator()(const diff& d) const { diff* canonical_diff = d.get_canonical_diff(); ABG_ASSERT(canonical_diff); return reinterpret_cast(canonical_diff); } }; // end struct diff_hash /// A comparison functor for using @ref diff_sptr and @ref diff* in a /// hash map or set. struct diff_equal { /// The function-call operator to compare two @ref diff nodes. /// /// @param d1 the first diff node involved in the comparison. /// /// @param d2 the second diff node involved in the comparison. /// /// @return true iff @p d1 equals @p d2. bool operator()(const diff* d1, const diff* d2) const {return operator()(*d1, *d2);} /// The function-call operator to compare two @ref diff nodes. /// /// @param d1 the first diff node involved in the comparison. /// /// @param d2 the second diff node involved in the comparison. /// /// @return true iff @p d1 equals @p d2. bool operator()(const diff_sptr& d1, const diff_sptr& d2) const {return operator()(*d1, *d2);} /// The function-call operator to compare two @ref diff nodes. /// /// @param d1 the first diff node involved in the comparison. /// /// @param d2 the second diff node involved in the comparison. /// /// @return true iff @p d1 equals @p d2. bool operator()(const diff& d1, const diff& d2) const { diff* canonical_diff1 = d1.get_canonical_diff(); ABG_ASSERT(canonical_diff1); diff *canonical_diff2 = d2.get_canonical_diff(); ABG_ASSERT(canonical_diff2); return canonical_diff1 == canonical_diff2; } }; // end struct diff_equal /// A convenience typedef for an unordered_map which key is a @ref /// diff* and which value is a @ref artifact_sptr_set_type. typedef unordered_map diff_artifact_set_map_type; /// The private member (pimpl) for @ref diff_context. struct diff_context::priv { diff_category allowed_category_; reporter_base_sptr reporter_; types_or_decls_diff_map_type types_or_decls_diff_map; unordered_diff_sptr_set live_diffs_; vector canonical_diffs; vector filters_; suppressions_type suppressions_; pointer_map visited_diff_nodes_; corpus_diff_sptr corpus_diff_; ostream* default_output_stream_; ostream* error_output_stream_; bool leaf_changes_only_; bool forbid_visiting_a_node_twice_; bool reset_visited_diffs_for_each_interface_; bool hex_values_; bool show_offsets_sizes_in_bits_; bool show_relative_offset_changes_; bool show_stats_only_; bool show_soname_change_; bool show_architecture_change_; bool show_deleted_fns_; bool show_changed_fns_; bool show_added_fns_; bool show_deleted_vars_; bool show_changed_vars_; bool show_added_vars_; bool show_linkage_names_; bool show_locs_; 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_; priv() : allowed_category_(EVERYTHING_CATEGORY), reporter_(), default_output_stream_(), error_output_stream_(), leaf_changes_only_(), forbid_visiting_a_node_twice_(true), reset_visited_diffs_for_each_interface_(), hex_values_(), show_offsets_sizes_in_bits_(true), show_relative_offset_changes_(true), show_stats_only_(false), show_soname_change_(true), show_architecture_change_(true), show_deleted_fns_(true), show_changed_fns_(true), show_added_fns_(true), show_deleted_vars_(true), show_changed_vars_(true), show_added_vars_(true), show_linkage_names_(false), show_locs_(true), 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_() {} };// end struct diff_context::priv struct type_diff_base::priv { public: friend class type_diff_base; }; // end class type_diff_base /// Private data for the @ref diff type. The details of generic view /// of the diff node are expressed here. struct diff::priv { bool finished_; bool traversing_; type_or_decl_base_sptr first_subject_; type_or_decl_base_sptr second_subject_; vector children_; diff* parent_; diff* parent_interface_; diff* canonical_diff_; diff_context_wptr ctxt_; diff_category local_category_; diff_category category_; mutable bool reported_once_; mutable bool currently_reporting_; mutable string pretty_representation_; priv(); public: priv(type_or_decl_base_sptr first_subject, type_or_decl_base_sptr second_subject, diff_context_sptr ctxt, diff_category category, bool reported_once, bool currently_reporting) : finished_(), traversing_(), first_subject_(first_subject), second_subject_(second_subject), parent_(), parent_interface_(), canonical_diff_(), ctxt_(ctxt), local_category_(category), category_(category), reported_once_(reported_once), currently_reporting_(currently_reporting) {} /// Getter of the diff context associated with this diff. /// /// @returnt a smart pointer to the diff context. diff_context_sptr get_context() const {return ctxt_.lock();} /// Check if a given categorization of a diff node should make it be /// filtered out. /// /// @param category the categorization to take into account. bool is_filtered_out(diff_category category) { diff_context_sptr ctxt = get_context(); if (!ctxt) return false; if (ctxt->get_allowed_category() == EVERYTHING_CATEGORY) return false; /// We don't want to display nodes suppressed by a user-provided /// suppression specification or by a "private type" suppression /// specification. if (category & (SUPPRESSED_CATEGORY | PRIVATE_TYPE_CATEGORY)) return true; // We don't want to display redundant diff nodes, when the user // asked to avoid seeing redundant diff nodes. if (!ctxt->show_redundant_changes() && (category & REDUNDANT_CATEGORY)) return true; if (category == NO_CHANGE_CATEGORY) return false; // Ignore the REDUNDANT_CATEGORY bit when comparing allowed // categories and the current set of categories. return !((category & ~REDUNDANT_CATEGORY) & (ctxt->get_allowed_category() & ~REDUNDANT_CATEGORY)); } };// end class diff::priv /// A functor to compare two instances of @ref diff_sptr. struct diff_less_than_functor { /// An operator that takes two instances of @ref diff_sptr returns /// true if its first operand compares less than its second operand. /// /// @param l the first operand to consider. /// /// @param r the second operand to consider. /// /// @return true if @p l compares less than @p r. bool operator()(const diff* l, const diff* r) const { if (!l || !r || !l->first_subject() || !r->first_subject()) return false; string l_qn = get_name(l->first_subject()); string r_qn = get_name(r->first_subject()); return l_qn < r_qn; } /// An operator that takes two instances of @ref diff_sptr returns /// true if its first operand compares less than its second operand. /// /// @param l the first operand to consider. /// /// @param r the second operand to consider. /// /// @return true if @p l compares less than @p r. bool operator()(const diff_sptr& l, const diff_sptr& r) const {return operator()(l.get(), r.get());} }; // end struct diff_less_than_functor struct decl_diff_base::priv { public: friend class decl_diff_base; };//end class priv /// The private data structure for @ref distinct_diff. struct distinct_diff::priv { diff_sptr compatible_child_diff; };// end struct distinct_diff /// The internal type for the impl idiom implementation of @ref /// var_diff. struct var_diff::priv { diff_wptr type_diff_; };//end struct var_diff /// The internal type for the impl idiom implementation of @ref /// pointer_diff. struct pointer_diff::priv { diff_sptr underlying_type_diff_; priv(diff_sptr ud) : underlying_type_diff_(ud) {} };//end struct pointer_diff::priv struct array_diff::priv { /// The diff between the two array element types. diff_sptr element_type_diff_; priv(diff_sptr element_type_diff) : element_type_diff_(element_type_diff) {} };//end struct array_diff::priv struct reference_diff::priv { diff_sptr underlying_type_diff_; priv(diff_sptr underlying) : underlying_type_diff_(underlying) {} };//end struct reference_diff::priv struct qualified_type_diff::priv { diff_sptr underlying_type_diff; mutable diff_sptr leaf_underlying_type_diff; priv(diff_sptr underlying) : underlying_type_diff(underlying) {} };// end struct qualified_type_diff::priv struct enum_diff::priv { diff_sptr underlying_type_diff_; edit_script enumerators_changes_; string_enumerator_map deleted_enumerators_; string_enumerator_map inserted_enumerators_; string_changed_enumerator_map changed_enumerators_; priv(diff_sptr underlying) : underlying_type_diff_(underlying) {} };//end struct enum_diff::priv /// A functor to compare two enumerators based on their value. This /// implements the "less than" operator. struct enumerator_value_comp { bool operator()(const enum_type_decl::enumerator& f, const enum_type_decl::enumerator& s) const {return f.get_value() < s.get_value();} };//end struct enumerator_value_comp /// A functor to compare two changed enumerators, based on their /// initial value. struct changed_enumerator_comp { bool operator()(const changed_enumerator& f, const changed_enumerator& s) const {return f.first.get_value() < s.first.get_value();} };// end struct changed_enumerator_comp. /// The type of private data of @ref class_or_union_diff. struct class_or_union_diff::priv { edit_script member_types_changes_; edit_script data_members_changes_; edit_script member_fns_changes_; edit_script member_fn_tmpls_changes_; edit_script member_class_tmpls_changes_; string_decl_base_sptr_map deleted_member_types_; string_decl_base_sptr_map inserted_member_types_; string_diff_sptr_map changed_member_types_; diff_sptrs_type sorted_changed_member_types_; string_decl_base_sptr_map deleted_data_members_; unsigned_decl_base_sptr_map deleted_dm_by_offset_; string_decl_base_sptr_map inserted_data_members_; unsigned_decl_base_sptr_map inserted_dm_by_offset_; // This map contains the data member which sub-type changed. string_var_diff_sptr_map subtype_changed_dm_; var_diff_sptrs_type sorted_subtype_changed_dm_; // This one contains the list of data members changes that can be // represented as a data member foo that got removed from offset N, // and a data member bar that got inserted at offset N; IOW, this // can be translated as data member foo that got changed into data // member bar at offset N. unsigned_var_diff_sptr_map changed_dm_; var_diff_sptrs_type sorted_changed_dm_; // This is a data structure to represent data members that have been // replaced by anonymous data members. It's a map that associates // the name of the data member to the anonymous data member that // replaced it. string_decl_base_sptr_map dms_replaced_by_adms_; mutable changed_var_sptrs_type dms_replaced_by_adms_ordered_; string_member_function_sptr_map deleted_member_functions_; class_or_union::member_functions sorted_deleted_member_functions_; string_member_function_sptr_map inserted_member_functions_; class_or_union::member_functions sorted_inserted_member_functions_; string_function_decl_diff_sptr_map changed_member_functions_; function_decl_diff_sptrs_type sorted_changed_member_functions_; string_decl_base_sptr_map deleted_member_class_tmpls_; string_decl_base_sptr_map inserted_member_class_tmpls_; string_diff_sptr_map changed_member_class_tmpls_; diff_sptrs_type sorted_changed_member_class_tmpls_; type_or_decl_base_sptr member_type_has_changed(decl_base_sptr) const; decl_base_sptr subtype_changed_dm(decl_base_sptr) const; decl_base_sptr member_class_tmpl_has_changed(decl_base_sptr) const; size_t get_deleted_non_static_data_members_number() const; size_t get_inserted_non_static_data_members_number() const; size_t count_filtered_subtype_changed_dm(bool local_only = false); size_t count_filtered_changed_dm(bool local_only = false); size_t count_filtered_changed_mem_fns(const diff_context_sptr&); size_t count_filtered_inserted_mem_fns(const diff_context_sptr&); size_t count_filtered_deleted_mem_fns(const diff_context_sptr&); priv() {} }; // end struct class_or_union_diff::priv /// A comparison functor to compare two data members based on their /// offset. struct data_member_comp { /// Compare two data members. /// /// First look at their offset and then their name. /// /// @parm first_dm the first data member to consider. /// /// @param second_dm the second data member to consider. bool compare_data_members(const var_decl_sptr& first_dm, const var_decl_sptr& second_dm) const { ABG_ASSERT(first_dm); ABG_ASSERT(second_dm); size_t first_offset = get_data_member_offset(first_dm); size_t second_offset = get_data_member_offset(second_dm); // The data member at the smallest offset comes first. if (first_offset != second_offset) return first_offset < second_offset; string first_dm_name = first_dm->get_name(); string second_dm_name = second_dm->get_name(); // But in case the two data members are at the same offset, then // sort them lexicographically. return first_dm_name < second_dm_name; } /// Compare two data members. /// /// First look at their offset and then their name. /// /// @parm first_dm the first data member to consider. /// /// @param second_dm the second data member to consider. bool operator()(const decl_base_sptr& f, const decl_base_sptr& s) const { var_decl_sptr first_dm = is_data_member(f); var_decl_sptr second_dm = is_data_member(s); return compare_data_members(first_dm, second_dm); } /// Compare two data members. /// /// First look at their offset and then their name. /// /// @parm first_dm the first data member to consider. /// /// @param second_dm the second data member to consider. bool operator()(const changed_var_sptr& f, const changed_var_sptr& s) const { var_decl_sptr first_dm = is_data_member(is_decl(f.first)); var_decl_sptr second_dm = is_data_member(is_decl(s.first)); return compare_data_members(first_dm, second_dm); } };//end struct data_member_comp /// The type of the private data (pimpl sub-object) of the @ref /// class_diff type. struct class_diff::priv { edit_script base_changes_; string_base_sptr_map deleted_bases_; class_decl::base_specs sorted_deleted_bases_; string_base_sptr_map inserted_bases_; class_decl::base_specs sorted_inserted_bases_; string_base_diff_sptr_map changed_bases_; base_diff_sptrs_type sorted_changed_bases_; vector moved_bases_; class_decl::base_spec_sptr base_has_changed(class_decl::base_spec_sptr) const; size_t count_filtered_bases(); priv() {} };//end struct class_diff::priv /// A functor to compare instances of @ref class_decl::base_spec. struct base_spec_comp { bool operator()(const class_decl::base_spec&l, const class_decl::base_spec&r) { string str1 = l.get_pretty_representation(); string str2 = r.get_pretty_representation(); return str1 < str2; } bool operator()(const class_decl::base_spec_sptr&l, const class_decl::base_spec_sptr&r) {return operator()(*l, *r);} }; // end base_spec_comp /// A comparison function for instances of @ref base_diff. struct base_diff_comp { bool operator()(const base_diff& l, const base_diff& r) const { class_decl::base_spec_sptr f = l.first_base(), s = r.first_base(); if (f->get_offset_in_bits() >= 0 && s->get_offset_in_bits() >= 0) return f->get_offset_in_bits() < s->get_offset_in_bits(); else return (f->get_base_class()->get_pretty_representation() < s->get_base_class()->get_pretty_representation()); } bool operator()(const base_diff* l, const base_diff* r) const {return operator()(*l, *r);} bool operator()(const base_diff_sptr l, const base_diff_sptr r) const {return operator()(l.get(), r.get());} }; // end struct base_diff_comp /// A comparison functor to compare two instances of @ref var_diff /// that represent changed data members based on the offset of the /// initial data members, or if equal, based on their qualified name. /// If equal again, then the offset and qualified name of the new data /// members are considered. struct data_member_diff_comp { /// @param f the first change to data member to take into account /// /// @param s the second change to data member to take into account. /// /// @return true iff f is before s. bool operator()(const var_diff_sptr f, const var_diff_sptr s) const { var_decl_sptr first_dm = f->first_var(); var_decl_sptr second_dm = s->first_var(); ABG_ASSERT(is_data_member(first_dm)); ABG_ASSERT(is_data_member(second_dm)); size_t off1 = get_data_member_offset(first_dm); size_t off2 = get_data_member_offset(second_dm); if (off1 != off2) return off1 < off2; // The two offsets of the initial data members are the same. So // lets compare the qualified name of these initial data members. string name1 = first_dm->get_qualified_name(); string name2 = second_dm->get_qualified_name(); if (name1 != name2) return name1 < name2; // The offsets and the qualified names of the initial data members // are the same. Let's now compare the offsets of the *new* data // members. first_dm = f->second_var(); second_dm = s->second_var(); ABG_ASSERT(is_data_member(first_dm)); ABG_ASSERT(is_data_member(second_dm)); off1 = get_data_member_offset(first_dm); off2 = get_data_member_offset(second_dm); if (off1 != off2) return off1 < off2; // The offsets of the new data members are the same, dang! Let's // compare the qualified names of these new data members then. name1 = first_dm->get_qualified_name(); name2 = second_dm->get_qualified_name(); return name1 < name2; } }; // end struct var_diff_comp /// A comparison functor for instances of @ref function_decl_diff that /// represent changes between two virtual member functions. struct virtual_member_function_diff_comp { bool operator()(const function_decl_diff& l, const function_decl_diff& r) const { ABG_ASSERT(get_member_function_is_virtual(l.first_function_decl())); ABG_ASSERT(get_member_function_is_virtual(r.first_function_decl())); return (get_member_function_vtable_offset(l.first_function_decl()) < get_member_function_vtable_offset(r.first_function_decl())); } bool operator()(const function_decl_diff* l, const function_decl_diff* r) {return operator()(*l, *r);} bool operator()(const function_decl_diff_sptr l, const function_decl_diff_sptr r) {return operator()(l.get(), r.get());} }; // end struct virtual_member_function_diff_comp struct base_diff::priv { class_diff_sptr underlying_class_diff_; priv(class_diff_sptr underlying) : underlying_class_diff_(underlying) {} }; // end struct base_diff::priv struct scope_diff::priv { // The edit script built by the function compute_diff. edit_script member_changes_; // Below are the useful lookup tables. // // If you add a new lookup table, please update member functions // clear_lookup_tables, lookup_tables_empty and // ensure_lookup_tables_built. // The deleted/inserted types/decls. These basically map what is // inside the member_changes_ data member. Note that for instance, // a given type T might be deleted from the first scope and added to // the second scope again; this means that the type was *changed*. string_decl_base_sptr_map deleted_types_; string_decl_base_sptr_map deleted_decls_; string_decl_base_sptr_map inserted_types_; string_decl_base_sptr_map inserted_decls_; // The changed types/decls lookup tables. // // These lookup tables are populated from the lookup tables above. // // Note that the value stored in each of these tables is a pair // containing the old decl/type and the new one. That way it is // easy to run a diff between the old decl/type and the new one. // // A changed type/decl is one that has been deleted from the first // scope and that has been inserted into the second scope. string_diff_sptr_map changed_types_; diff_sptrs_type sorted_changed_types_; string_diff_sptr_map changed_decls_; diff_sptrs_type sorted_changed_decls_; // The removed types/decls lookup tables. // // A removed type/decl is one that has been deleted from the first // scope and that has *NOT* been inserted into it again. string_decl_base_sptr_map removed_types_; string_decl_base_sptr_map removed_decls_; // The added types/decls lookup tables. // // An added type/decl is one that has been inserted to the first // scope but that has not been deleted from it. string_decl_base_sptr_map added_types_; string_decl_base_sptr_map added_decls_; };//end struct scope_diff::priv /// 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_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());} }; // end struct diff_comp; struct fn_parm_diff::priv { mutable diff_sptr type_diff; }; // end struct fn_parm_diff::priv struct function_type_diff::priv { diff_sptr return_type_diff_; edit_script parm_changes_; // useful lookup tables. string_parm_map deleted_parms_; vector sorted_deleted_parms_; string_parm_map added_parms_; vector sorted_added_parms_; // This map contains parameters sub-type changes that don't change // the name of the type of the parameter. string_fn_parm_diff_sptr_map subtype_changed_parms_; vector sorted_subtype_changed_parms_; // This map contains parameter type changes that actually change the // name of the type of the parameter, but in a compatible way; // otherwise, the mangling of the function would have changed (in // c++ at least). unsigned_fn_parm_diff_sptr_map changed_parms_by_id_; vector sorted_changed_parms_by_id_; unsigned_parm_map deleted_parms_by_id_; unsigned_parm_map added_parms_by_id_; priv() {} }; // end struct function_type_diff::priv struct function_decl_diff::priv { function_type_diff_sptr type_diff_; priv() {} };// end struct function_decl_diff::priv /// A comparison functor to compare two instances of @ref fn_parm_diff /// based on their indexes. struct fn_parm_diff_comp { /// @param f the first diff /// /// @param s the second diff /// /// @return true if the index of @p f is less than the index of @p /// s. bool operator()(const fn_parm_diff& f, const fn_parm_diff& s) {return f.first_parameter()->get_index() < s.first_parameter()->get_index();} bool operator()(const fn_parm_diff_sptr& f, const fn_parm_diff_sptr& s) {return operator()(*f, *s);} }; // end struct fn_parm_diff_comp /// Functor that compares two function parameters for the purpose of /// sorting them. struct parm_comp { /// Returns true iff the index of the first parameter is smaller /// than the of the second parameter. /// /// @param l the first parameter to compare. /// /// @param r the second parameter to compare. /// /// @return true iff the index of the first parameter is smaller /// than the of the second parameter. bool operator()(const function_decl::parameter& l, const function_decl::parameter& r) {return l.get_index() < r.get_index();} /// Returns true iff the index of the first parameter is smaller /// than the of the second parameter. /// /// @param l the first parameter to compare. /// /// @param r the second parameter to compare. /// /// @return true iff the index of the first parameter is smaller /// than the of the second parameter. bool operator()(const function_decl::parameter_sptr& l, const function_decl::parameter_sptr& r) {return operator()(*l, *r);} }; // end struct parm_comp /// A functor to compare instances of @ref var_decl base on their /// qualified names. struct var_comp { bool operator() (const var_decl& l, const var_decl& r) const { string name1 = l.get_qualified_name(), name2 = r.get_qualified_name(); return name1 < name2; } bool operator() (const var_decl* l, const var_decl* r) const {return operator()(*l, *r);} };// end struct var_comp /// A functor to compare instances of @ref elf_symbol base on their /// names. struct elf_symbol_comp { bool operator()(const elf_symbol& l, const elf_symbol& r) { string name1 = l.get_id_string(), name2 = r.get_id_string(); return name1 < name2; } bool operator()(const elf_symbol* l, const elf_symbol* r) {return operator()(*l, *r);} bool operator()(const elf_symbol_sptr& l, const elf_symbol_sptr& r) {return operator()(l.get(), r.get());} }; //end struct elf_symbol_comp struct typedef_diff::priv { diff_sptr underlying_type_diff_; priv(const diff_sptr underlying_type_diff) : underlying_type_diff_(underlying_type_diff) {} };//end struct typedef_diff::priv struct translation_unit_diff::priv { translation_unit_sptr first_; translation_unit_sptr second_; priv(translation_unit_sptr f, translation_unit_sptr s) : first_(f), second_(s) {} };//end struct translation_unit_diff::priv struct corpus_diff::priv { bool finished_; string pretty_representation_; vector children_; corpus_sptr first_; corpus_sptr second_; diff_context_wptr ctxt_; corpus_diff::diff_stats_sptr diff_stats_; bool sonames_equal_; bool architectures_equal_; edit_script fns_edit_script_; edit_script vars_edit_script_; edit_script unrefed_fn_syms_edit_script_; edit_script unrefed_var_syms_edit_script_; string_function_ptr_map deleted_fns_; string_function_ptr_map suppressed_deleted_fns_; string_function_ptr_map added_fns_; string_function_ptr_map suppressed_added_fns_; string_function_decl_diff_sptr_map changed_fns_map_; function_decl_diff_sptrs_type changed_fns_; string_var_ptr_map deleted_vars_; string_var_ptr_map suppressed_deleted_vars_; string_var_ptr_map added_vars_; string_var_ptr_map suppressed_added_vars_; string_var_diff_sptr_map changed_vars_map_; var_diff_sptrs_type sorted_changed_vars_; string_elf_symbol_map added_unrefed_fn_syms_; string_elf_symbol_map suppressed_added_unrefed_fn_syms_; string_elf_symbol_map deleted_unrefed_fn_syms_; string_elf_symbol_map suppressed_deleted_unrefed_fn_syms_; string_elf_symbol_map added_unrefed_var_syms_; 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 deleted_unreachable_types_sorted_; string_type_base_sptr_map suppressed_deleted_unreachable_types_; string_type_base_sptr_map added_unreachable_types_; vector added_unreachable_types_sorted_; string_type_base_sptr_map suppressed_added_unreachable_types_; string_diff_sptr_map changed_unreachable_types_; mutable vector changed_unreachable_types_sorted_; diff_maps leaf_diffs_; /// Default constructor of corpus_diff::priv. priv() : finished_(false), sonames_equal_(false), architectures_equal_(false) {} /// Constructor of corpus_diff::priv. /// /// @param first the first corpus of this diff. /// /// @param second the second corpus of this diff. /// /// @param ctxt the context of the diff. priv(corpus_sptr first, corpus_sptr second, diff_context_sptr ctxt) : finished_(false), first_(first), second_(second), ctxt_(ctxt), sonames_equal_(false), architectures_equal_(false) {} diff_context_sptr get_context(); bool lookup_tables_empty() const; void clear_lookup_tables(); void ensure_lookup_tables_populated(); void apply_supprs_to_added_removed_fns_vars_unreachable_types(); bool deleted_function_is_suppressed(const function_decl* fn) const; bool added_function_is_suppressed(const function_decl* fn) const; bool deleted_variable_is_suppressed(const var_decl* var) 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; bool added_unrefed_fn_sym_is_suppressed(const elf_symbol*) const; bool deleted_unrefed_var_sym_is_suppressed(const elf_symbol*) const; bool added_unrefed_var_sym_is_suppressed(const elf_symbol*) const; void count_leaf_changes(size_t &num_changes, size_t &num_filtered); void count_leaf_type_changes(size_t &num_type_changes, size_t &num_type_changes_filtered); void count_unreachable_types(size_t &num_added, size_t &num_removed, size_t &num_changed, size_t &num_filtered_added, size_t &num_filtered_removed, size_t &num_filtered_changed); const vector& changed_unreachable_types_sorted() const; void apply_filters_and_compute_diff_stats(corpus_diff::diff_stats&); void emit_diff_stats(const diff_stats& stats, ostream& out, const string& indent); void categorize_redundant_changed_sub_nodes(); void clear_redundancy_categorization(); void maybe_dump_diff_tree(); }; // end corpus::priv /// "Less than" functor to compare instances of @ref function_decl. struct function_comp { /// The actual "less than" operator for instances of @ref /// function_decl. It returns true if the first @ref function_decl /// is lest than the second one. /// /// @param f the first @ref function_decl to take in account. /// /// @param s the second @ref function_decl to take in account. /// /// @return true iff @p f is less than @p s. bool operator()(const function_decl& f, const function_decl& s) {return abigail::ir::function_decl_is_less_than(f, s);} /// The actual "less than" operator for instances of @ref /// function_decl. It returns true if the first @ref function_decl /// is lest than the second one. /// /// @param f the first @ref function_decl to take in account. /// /// @param s the second @ref function_decl to take in account. /// /// @return true iff @p f is less than @p s. bool operator()(const function_decl* f, const function_decl* s) {return operator()(*f, *s);} /// The actual "less than" operator for instances of @ref /// function_decl. It returns true if the first @ref function_decl /// is lest than the second one. /// /// @param f the first @ref function_decl to take in account. /// /// @param s the second @ref function_decl to take in account. /// /// @return true iff @p f is less than @p s. bool operator()(const function_decl_sptr f, const function_decl_sptr s) {return operator()(f.get(), s.get());} }; // end function_comp /// A "Less Than" functor to compare instance of @ref /// function_decl_diff. struct function_decl_diff_comp { /// The actual less than operator. /// /// It returns true if the first @ref function_decl_diff is less /// than the second one. /// /// param first the first @ref function_decl_diff to consider. /// /// @param second the second @ref function_decl_diff to consider. /// /// @return true iff @p first is less than @p second. bool operator()(const function_decl_diff& first, const function_decl_diff& second) { function_decl_sptr f = first.first_function_decl(), s = second.first_function_decl(); string fr = f->get_qualified_name(), sr = s->get_qualified_name(); if (fr == sr) { if (f->get_symbol()) fr = f->get_symbol()->get_id_string(); else if (!f->get_linkage_name().empty()) fr = f->get_linkage_name(); else fr = f->get_pretty_representation(); if (s->get_symbol()) sr = s->get_symbol()->get_id_string(); else if (!s->get_linkage_name().empty()) sr = s->get_linkage_name(); else sr = s->get_pretty_representation(); } return (fr.compare(sr) < 0); } /// The actual less than operator. /// /// It returns true if the first @ref function_decl_diff_sptr is /// less than the second one. /// /// param first the first @ref function_decl_diff_sptr to consider. /// /// @param second the second @ref function_decl_diff_sptr to /// consider. /// /// @return true iff @p first is less than @p second. bool operator()(const function_decl_diff_sptr first, const function_decl_diff_sptr second) {return operator()(*first, *second);} }; // end struct function_decl_diff_comp /// Functor to sort instances of @ref var_diff_sptr struct var_diff_sptr_comp { /// Return true if the first argument is less than the second one. /// /// @param f the first argument to consider. /// /// @param s the second argument to consider. /// /// @return true if @p f is less than @p s. bool operator()(const var_diff_sptr f, const var_diff_sptr s) { return (f->first_var()->get_qualified_name() < s->first_var()->get_qualified_name()); } }; // end struct var_diff_sptr_comp /// The type of the private data of corpus_diff::diff_stats. struct corpus_diff::diff_stats::priv { friend class corpus_diff::diff_stats; diff_context_wptr ctxt_; size_t num_func_removed; size_t num_removed_func_filtered_out; size_t num_func_added; size_t num_added_func_filtered_out; size_t num_func_changed; size_t num_changed_func_filtered_out; size_t num_func_with_virt_offset_changes; size_t num_vars_removed; size_t num_removed_vars_filtered_out; size_t num_vars_added; size_t num_added_vars_filtered_out; size_t num_vars_changed; size_t num_changed_vars_filtered_out; size_t num_func_syms_removed; size_t num_removed_func_syms_filtered_out; size_t num_func_syms_added; size_t num_added_func_syms_filtered_out; size_t num_var_syms_removed; size_t num_removed_var_syms_filtered_out; size_t num_var_syms_added; size_t num_added_var_syms_filtered_out; size_t num_leaf_changes; size_t num_leaf_changes_filtered_out; size_t num_leaf_type_changes; size_t num_leaf_type_changes_filtered_out; size_t num_leaf_func_changes; 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_func_removed(), num_removed_func_filtered_out(), num_func_added(), num_added_func_filtered_out(), num_func_changed(), num_changed_func_filtered_out(), num_func_with_virt_offset_changes(), num_vars_removed(), num_removed_vars_filtered_out(), num_vars_added(), num_added_vars_filtered_out(), num_vars_changed(), num_changed_vars_filtered_out(), num_func_syms_removed(), num_removed_func_syms_filtered_out(), num_func_syms_added(), num_added_func_syms_filtered_out(), num_var_syms_removed(), num_removed_var_syms_filtered_out(), num_var_syms_added(), num_added_var_syms_filtered_out(), num_leaf_changes(), num_leaf_changes_filtered_out(), num_leaf_type_changes(), num_leaf_type_changes_filtered_out(), num_leaf_func_changes(), num_leaf_func_changes_filtered_out(), num_leaf_var_changes(), 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 ctxt() {return ctxt_.lock();} }; // end class corpus_diff::diff_stats::priv void sort_enumerators(const string_enumerator_map& enumerators_map, enum_type_decl::enumerators& sorted); void sort_changed_enumerators(const string_changed_enumerator_map& enumerators_map, changed_enumerators_type& sorted); void sort_data_members(const string_decl_base_sptr_map &data_members, vector& sorted); void sort_changed_data_members(changed_var_sptrs_type& input); void sort_string_function_ptr_map(const string_function_ptr_map& map, vector& sorted); void sort_string_member_function_sptr_map(const string_member_function_sptr_map& map, class_or_union::member_functions& sorted); void sort_string_type_base_sptr_map(string_type_base_sptr_map& map, vector& sorted); void sort_string_function_decl_diff_sptr_map (const string_function_decl_diff_sptr_map& map, function_decl_diff_sptrs_type& sorted); void sort_string_var_diff_sptr_map(const string_var_diff_sptr_map& map, var_diff_sptrs_type& sorted); void sort_string_elf_symbol_map(const string_elf_symbol_map& map, vector& sorted); void sort_string_var_ptr_map(const string_var_ptr_map& map, vector& sorted); void sort_string_data_member_diff_sptr_map(const string_var_diff_sptr_map& map, var_diff_sptrs_type& sorted); void sort_unsigned_data_member_diff_sptr_map(const unsigned_var_diff_sptr_map map, var_diff_sptrs_type& sorted); void sort_string_virtual_member_function_diff_sptr_map (const string_function_decl_diff_sptr_map& map, function_decl_diff_sptrs_type& sorted); void sort_string_diff_sptr_map(const string_diff_sptr_map& map, diff_sptrs_type& sorted); void sort_string_diff_ptr_map(const string_diff_ptr_map& map, diff_ptrs_type& sorted); void sort_string_base_diff_sptr_map(const string_base_diff_sptr_map& map, base_diff_sptrs_type& sorted); void sort_string_base_sptr_map(const string_base_sptr_map& m, class_decl::base_specs& sorted); void sort_string_fn_parm_diff_sptr_map(const unsigned_fn_parm_diff_sptr_map& map, vector& sorted); void sort_string_fn_parm_diff_sptr_map(const string_fn_parm_diff_sptr_map& map, vector& sorted); void sort_string_parm_map(const string_parm_map& map, vector& sorted); void sort_artifacts_set(const artifact_sptr_set_type& set, vector& sorted); type_base_sptr get_leaf_type(qualified_type_def_sptr t); diff* get_fn_decl_or_var_decl_diff_ancestor(const diff *); bool is_diff_of_global_decls(const diff*); } // end namespace comparison } // namespace abigail #endif // __ABG_COMPARISON_PRIV_H__