3 // Copyright (C) 2013-2019 Red Hat, Inc.
5 // This file is part of the GNU Application Binary Interface Generic
6 // Analysis and Instrumentation Library (libabigail). This library is
7 // free software; you can redistribute it and/or modify it under the
8 // terms of the GNU Lesser General Public License as published by the
9 // Free Software Foundation; either version 3, or (at your option) any
12 // This library is distributed in the hope that it will be useful, but
13 // WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 // General Lesser Public License for more details.
17 // You should have received a copy of the GNU Lesser General Public
18 // License along with this program; see the file COPYING-LGPLV3. If
19 // not, see <http://www.gnu.org/licenses/>.
21 // Author: Dodji Seketeli
25 /// This contains the implementation of the comparison engine of
33 #include "abg-comparison-priv.h"
34 #include "abg-reporter-priv.h"
44 ///@defgroup DiffNode Internal Representation of the comparison engine
47 /// @brief How changes are represented in libabigail's comparison engine.
51 /// The internal representation of the comparison engine is basically
52 /// a graph of @ref instances of @ref diff node. We refer to these
53 /// just as <em>diff nodes</em>. A diff node represents a change
54 /// between two ABI artifacts represented by instances of types of the
55 /// abigail::ir namespace. These two artifacts that are being
56 /// compared are called the <em>subjects of the diff</em>.
58 /// The types of that IR are in the abigail::comparison namespace.
60 ///@par comparing diff nodes
62 /// Comparing two instances of @ref diff nodes amounts to comparing
63 /// the subject of the diff. In other words, two @ref diff nodes are
64 /// equal if and only if their subjects are equal. Thus, two @ref
65 /// diff nodes can have different memory addresses and yet be equal.
67 ///@par diff reporting and context
69 /// A diff node can be serialized to an output stream to express, in
70 /// a human-readable textual form, the different changes that exist
71 /// between its two subjects. This is done by invoking the
72 /// diff::report() method. That reporting is controlled by several
73 /// parameters that are conceptually part of the context of the diff.
74 /// That context is materialized by an instance of the @ref
75 /// diff_context type.
77 /// Please note that the role of the instance(s) of @ref diff_context
78 /// is boreader than just controlling the reporting of @ref diff
79 /// nodes. Basically, a @ref diff node itself is created following
80 /// behaviours that are controlled by a particular instance of
81 /// diff_context. A diff node is created in a particular diff
82 /// context, so to speak.
88 ///@defgroup CanonicalDiff Canonical diff tree nodes
91 /// @brief How equivalent diff nodes are quickly spotted.
93 /// @par Equivalence of diff nodes.
95 /// Each @ref diff node has a property named <em>Canonical Diff
96 /// Node</em>. If \c D is a diff node, the canonical diff node of @c
97 /// D, noted @c C(D) is a particular diff node that is equal to @c D.
98 /// Thus, a fast way to compare two @ref diff node is to perform a
99 /// pointer comparison of their canonical diff nodes.
101 /// A set of equivalent @ref diff nodes is a set of diff nodes that
102 /// all have the same canonical node. All the nodes of that set are
105 /// A canonical node is registereded for a given diff node by invoking
106 /// the method diff_context::initialize_canonical_diff().
108 /// Please note that the diff_context holds all the canonical diffs
109 /// that got registered through it. Thus, the life time of all of
110 /// canonical diff objects is the same as the life time of the @ref
111 /// diff_context they relate to.
116 // -----------------------------------------
117 // <private functions re-usable elsewhere>
118 // -----------------------------------------
119 /// Sort a map of enumerators by their value.
121 /// @param enumerators_map the map to sort.
123 /// @param sorted the resulting vector of sorted enumerators.
125 sort_enumerators(const string_enumerator_map& enumerators_map,
126 enum_type_decl::enumerators& sorted)
128 for (string_enumerator_map::const_iterator i = enumerators_map.begin();
129 i != enumerators_map.end();
131 sorted.push_back(i->second);
132 enumerator_value_comp comp;
133 std::sort(sorted.begin(), sorted.end(), comp);
136 /// Sort a map of changed enumerators.
138 /// @param enumerators_map the map to sort.
140 ///@param output parameter. The resulting sorted enumerators.
142 sort_changed_enumerators(const string_changed_enumerator_map& enumerators_map,
143 changed_enumerators_type& sorted)
145 for (string_changed_enumerator_map::const_iterator i =
146 enumerators_map.begin();
147 i != enumerators_map.end();
149 sorted.push_back(i->second);
151 changed_enumerator_comp comp;
152 std::sort(sorted.begin(), sorted.end(), comp);
155 /// Sort a map of data members by the offset of their initial value.
157 /// @param data_members the map of changed data members to sort.
159 /// @param sorted the resulting vector of sorted changed data members.
161 sort_data_members(const string_decl_base_sptr_map &data_members,
162 vector<decl_base_sptr>& sorted)
164 sorted.reserve(data_members.size());
165 for (string_decl_base_sptr_map::const_iterator i = data_members.begin();
166 i != data_members.end();
168 sorted.push_back(i->second);
170 data_member_comp comp;
171 std::sort(sorted.begin(), sorted.end(), comp);
174 /// Sort a an instance of @ref string_function_ptr_map map and stuff
175 /// a resulting sorted vector of pointers to function_decl.
177 /// @param map the map to sort.
179 /// @param sorted the resulting sorted vector.
181 sort_string_function_ptr_map(const string_function_ptr_map& map,
182 vector<function_decl*>& sorted)
184 sorted.reserve(map.size());
185 for (string_function_ptr_map::const_iterator i = map.begin();
188 sorted.push_back(i->second);
191 std::sort(sorted.begin(), sorted.end(), comp);
194 /// Sort the values of a @ref string_function_decl_diff_sptr_map map
195 /// and store the result in a vector of @ref function_decl_diff_sptr
198 /// @param map the map whose values to store.
200 /// @param sorted the vector of function_decl_diff_sptr to store the
201 /// result of the sort into.
203 sort_string_function_decl_diff_sptr_map
204 (const string_function_decl_diff_sptr_map& map,
205 function_decl_diff_sptrs_type& sorted)
207 sorted.reserve(map.size());
208 for (string_function_decl_diff_sptr_map::const_iterator i = map.begin();
211 sorted.push_back(i->second);
212 function_decl_diff_comp comp;
213 std::sort(sorted.begin(), sorted.end(), comp);
216 /// Sort of an instance of @ref string_var_diff_sptr_map map.
218 /// @param map the input map to sort.
220 /// @param sorted the ouptut sorted vector of @ref var_diff_sptr.
221 /// It's populated with the sorted content.
223 sort_string_var_diff_sptr_map(const string_var_diff_sptr_map& map,
224 var_diff_sptrs_type& sorted)
226 sorted.reserve(map.size());
227 for (string_var_diff_sptr_map::const_iterator i = map.begin();
230 sorted.push_back(i->second);
232 var_diff_sptr_comp comp;
233 std::sort(sorted.begin(), sorted.end(), comp);
236 /// Sort a map of string -> pointer to @ref elf_symbol.
238 /// The result is a vector of @ref elf_symbol_sptr sorted by the
239 /// name of the symbol.
241 /// @param map the map to sort.
243 /// @param sorted out parameter; the sorted vector of @ref
246 sort_string_elf_symbol_map(const string_elf_symbol_map& map,
247 vector<elf_symbol_sptr>& sorted)
249 for (string_elf_symbol_map::const_iterator i = map.begin();
252 sorted.push_back(i->second);
254 elf_symbol_comp comp;
255 std::sort(sorted.begin(), sorted.end(), comp);
258 /// Sort a map of string -> pointer to @ref var_decl.
260 /// The result is a vector of var_decl* sorted by the qualified name
261 /// of the variables.
263 /// @param map the map to sort.
265 /// @param sorted out parameter; the sorted vector of @ref var_decl.
267 sort_string_var_ptr_map(const string_var_ptr_map& map,
268 vector<var_decl*>& sorted)
270 for (string_var_ptr_map::const_iterator i = map.begin();
273 sorted.push_back(i->second);
276 std::sort(sorted.begin(), sorted.end(), comp);
279 /// Sort the values of a string_var_diff_sptr_map and store the result
280 /// in a vector of var_diff_sptr.
282 /// @param map the map of changed data members to sort.
284 /// @param sorted the resulting vector of var_diff_sptr.
286 sort_string_data_member_diff_sptr_map(const string_var_diff_sptr_map& map,
287 var_diff_sptrs_type& sorted)
289 sorted.reserve(map.size());
290 for (string_var_diff_sptr_map::const_iterator i = map.begin();
293 sorted.push_back(i->second);
294 data_member_diff_comp comp;
295 std::sort(sorted.begin(), sorted.end(), comp);
298 /// Sort the values of a unsigned_var_diff_sptr_map map and store the
299 /// result into a vector of var_diff_sptr.
301 /// @param map the map of changed data members to sort.
303 /// @param sorted the resulting vector of sorted var_diff_sptr.
305 sort_unsigned_data_member_diff_sptr_map(const unsigned_var_diff_sptr_map map,
306 var_diff_sptrs_type& sorted)
308 sorted.reserve(map.size());
309 for (unsigned_var_diff_sptr_map::const_iterator i = map.begin();
312 sorted.push_back(i->second);
313 data_member_diff_comp comp;
314 std::sort(sorted.begin(), sorted.end(), comp);
317 /// Sort an map of string -> virtual member function into a vector of
318 /// virtual member functions. The virtual member functions are sorted
319 /// by increasing order of their virtual index.
321 /// @param map the input map.
323 /// @param sorted the resulting sorted vector of virtual function
326 sort_string_virtual_member_function_diff_sptr_map
327 (const string_function_decl_diff_sptr_map& map,
328 function_decl_diff_sptrs_type& sorted)
330 sorted.reserve(map.size());
331 for (string_function_decl_diff_sptr_map::const_iterator i = map.begin();
334 sorted.push_back(i->second);
336 virtual_member_function_diff_comp comp;
337 sort(sorted.begin(), sorted.end(), comp);
340 /// Sort a map ofg string -> @ref diff_sptr into a vector of @ref
341 /// diff_sptr. The diff_sptr are sorted lexicographically wrt
342 /// qualified names of their first subjects.
344 /// @param map the map to sort.
346 /// @param sorted the resulting sorted vector.
348 sort_string_diff_sptr_map(const string_diff_sptr_map& map,
349 diff_sptrs_type& sorted)
351 sorted.reserve(map.size());
352 for (string_diff_sptr_map::const_iterator i = map.begin();
355 sorted.push_back(i->second);
358 sort(sorted.begin(), sorted.end(), comp);
361 /// Sort a map ofg string -> @ref diff* into a vector of @ref
362 /// diff_ptr. The diff_ptr are sorted lexicographically wrt
363 /// qualified names of their first subjects.
365 /// @param map the map to sort.
367 /// @param sorted the resulting sorted vector.
369 sort_string_diff_ptr_map(const string_diff_ptr_map& map,
370 diff_ptrs_type& sorted)
372 sorted.reserve(map.size());
373 for (string_diff_ptr_map::const_iterator i = map.begin();
376 sorted.push_back(i->second);
379 sort(sorted.begin(), sorted.end(), comp);
382 /// Sort a map of string -> base_diff_sptr into a sorted vector of
383 /// base_diff_sptr. The base_diff_sptr are sorted by increasing value
384 /// of their offset in their containing type.
386 /// @param map the input map to sort.
388 /// @param sorted the resulting sorted vector.
390 sort_string_base_diff_sptr_map(const string_base_diff_sptr_map& map,
391 base_diff_sptrs_type& sorted)
393 for (string_base_diff_sptr_map::const_iterator i = map.begin();
396 sorted.push_back(i->second);
398 sort(sorted.begin(), sorted.end(), comp);
401 /// Lexicographically sort base specifications found
402 /// in instances of string_base_sptr_map.
404 sort_string_base_sptr_map(const string_base_sptr_map& m,
405 class_decl::base_specs& sorted)
407 for (string_base_sptr_map::const_iterator i = m.begin();
410 sorted.push_back(i->second);
413 std::sort(sorted.begin(), sorted.end(), comp);
416 /// Sort a map of @ref fn_parm_diff by the indexes of the function
419 /// @param map the map to sort.
421 /// @param sorted the resulting sorted vector of changed function
424 sort_string_fn_parm_diff_sptr_map(const unsigned_fn_parm_diff_sptr_map& map,
425 vector<fn_parm_diff_sptr>& sorted)
427 sorted.reserve(map.size());
428 for (unsigned_fn_parm_diff_sptr_map::const_iterator i = map.begin();
431 sorted.push_back(i->second);
433 fn_parm_diff_comp comp;
434 std::sort(sorted.begin(), sorted.end(), comp);
437 /// Sort a map of changed function parameters by the indexes of the
438 /// function parameters.
440 /// @param map the map to sort.
442 /// @param sorted the resulting sorted vector of instances of @ref
443 /// fn_parm_diff_sptr
445 sort_string_fn_parm_diff_sptr_map(const string_fn_parm_diff_sptr_map& map,
446 vector<fn_parm_diff_sptr>& sorted)
448 sorted.reserve(map.size());
449 for (string_fn_parm_diff_sptr_map::const_iterator i = map.begin();
452 sorted.push_back(i->second);
454 fn_parm_diff_comp comp;
455 std::sort(sorted.begin(), sorted.end(), comp);
458 /// Sort a map of string -> function parameters.
460 /// @param map the map to sort.
462 /// @param sorted the resulting sorted vector of
463 /// @ref vector<function_decl::parameter_sptr>
465 sort_string_parm_map(const string_parm_map& map,
466 vector<function_decl::parameter_sptr>& sorted)
468 for (string_parm_map::const_iterator i = map.begin();
471 sorted.push_back(i->second);
473 // TODO: finish this.
475 std::sort(sorted.begin(), sorted.end(), comp);
478 /// Sort the set of ABI artifacts contained in a @ref
479 /// artifact_sptr_set_type.
481 /// @param set the set of ABI artifacts to sort.
483 /// @param output parameter the vector containing the sorted ABI
486 sort_artifacts_set(const artifact_sptr_set_type& set,
487 vector<type_or_decl_base_sptr>& sorted)
490 for (artifact_sptr_set_type::const_iterator it = set.begin();
493 sorted.push_back(*it);
495 type_or_decl_base_comp comp;
496 std::sort(sorted.begin(), sorted.end(), comp);
499 /// Return the first underlying type that is not a qualified type.
500 /// @param t the qualified type to consider.
502 /// @return the first underlying type that is not a qualified type, or
503 /// NULL if t is NULL.
505 get_leaf_type(qualified_type_def_sptr t)
508 return type_base_sptr();
510 type_base_sptr ut = t->get_underlying_type();
511 qualified_type_def_sptr qut = dynamic_pointer_cast<qualified_type_def>(ut);
515 return get_leaf_type(qut);
518 /// Tests if a given diff node is to represent the changes between two
521 /// @param d the diff node to consider.
523 /// @return true iff @p d represents the changes between two global
526 is_diff_of_global_decls(const diff* d)
533 type_or_decl_base_sptr first = d->first_subject();
536 type_or_decl_base_sptr second = d->first_subject();
539 if (decl_base_sptr decl = is_decl(first))
540 if (is_at_global_scope(decl))
541 if ((decl = is_decl(second)))
542 if (is_at_global_scope(decl))
548 // -----------------------------------------
549 // </private functions re-usable elsewhere>
550 // -----------------------------------------
552 /// The overloaded or operator for @ref visiting_kind.
554 operator|(visiting_kind l, visiting_kind r)
555 {return static_cast<visiting_kind>(static_cast<unsigned>(l)
556 | static_cast<unsigned>(r));}
558 /// The overloaded and operator for @ref visiting_kind.
560 operator&(visiting_kind l, visiting_kind r)
562 return static_cast<visiting_kind>(static_cast<unsigned>(l)
563 & static_cast<unsigned>(r));
566 /// The overloaded 'bit inversion' operator for @ref visiting_kind.
568 operator~(visiting_kind l)
569 {return static_cast<visiting_kind>(~static_cast<unsigned>(l));}
571 /// Test if a diff node is about differences between types.
573 /// @param diff the diff node to test.
575 /// @return a pointer to the actual type_diff_base* that @p diff
576 /// extends, iff it is about differences between types.
577 const type_diff_base*
578 is_type_diff(const diff* diff)
579 {return dynamic_cast<const type_diff_base*>(diff);}
581 /// Test if a diff node is about differences between declarations.
583 /// @param diff the diff node to test.
585 /// @return a pointer to the actual decl_diff_base @p diff extends,
586 /// iff it is about differences between declarations.
587 const decl_diff_base*
588 is_decl_diff(const diff* diff)
589 {return dynamic_cast<const decl_diff_base*>(diff);}
591 /// Test if a diff node is a @ref class_diff node.
593 /// @param diff the diff node to consider.
595 /// @return a non-nil pointer to a @ref class_diff iff @p diff is a
596 /// @ref class_diff node.
598 is_class_diff(const diff* diff)
599 {return dynamic_cast<const class_diff*>(diff);}
601 /// Test if a diff node is a @ref enum_diff node.
603 /// @param diff the diff node to consider.
605 /// @return a non-nil pointer to ad @ref enum_diff node iff @p diff is
606 /// a @ref enum_diff node.
608 is_enum_diff(const diff *diff)
609 {return dynamic_cast<const enum_diff*>(diff);}
611 /// Test if a diff node is a @ref union_diff node.
613 /// @param diff the diff node to consider.
615 /// @return a non-nil pointer to a @ref union_diff iff @p diff is a
616 /// @ref union_diff node.
618 is_union_diff(const diff* diff)
619 {return dynamic_cast<const union_diff*>(diff);}
621 /// Test if a diff node is a @ref class_or_union_diff node.
623 /// @param d the diff node to consider.
625 /// @return a non-nil pointer to the @ref class_or_union_diff denoted
626 /// by @p d iff @p d is a @ref class_or_union_diff.
627 const class_or_union_diff*
628 is_class_or_union_diff(const diff* d)
629 {return dynamic_cast<const class_or_union_diff*>(d);}
631 /// Test if a diff node is a @ref class_or_union_diff between two
632 /// anonymous classes or unions.
634 /// @param d the diff node to consider.
636 /// @return a non-nil pointer to the @ref class_or_union_diff iff @p
637 /// denoted by @p d iff @p is pointer to an anonymous class or union
639 const class_or_union_diff*
640 is_anonymous_class_or_union_diff(const diff* d)
642 if (const class_or_union_diff *dif = is_class_or_union_diff(d))
643 if (dif->first_class_or_union()->get_is_anonymous())
648 /// Test if a diff node is a @ref typedef_diff node.
650 /// @param diff the diff node to consider.
652 /// @return a non-nil pointer to a @ref typedef_diff iff @p diff is a
653 /// @ref typedef_diff node.
655 is_typedef_diff(const diff *diff)
656 {return dynamic_cast<const typedef_diff*>(diff);}
658 /// Test if a diff node is a @ref array_diff node.
660 /// @param diff the diff node to consider.
662 /// @return a non-nil pointer to a @ref array_diff iff @p diff is a
663 /// @ref array_diff node.
665 is_array_diff(const diff* diff)
666 {return dynamic_cast<const array_diff*>(diff);}
668 /// Test if a diff node is a @ref function_type_diff node.
670 /// @param diff the diff node to consider.
672 /// @return a non-nil pointer to a @ref function_type_diff iff @p diff is a
673 /// @ref function_type_diff node.
674 const function_type_diff*
675 is_function_type_diff(const diff* diff)
676 {return dynamic_cast<const function_type_diff*>(diff);}
678 /// Test if a given diff node carries a function type change with
681 /// @param diff the diff node to consider.
683 /// @return a non-nil pointer to a @ref function_type_diff iff @p diff
684 /// is a function_type_diff node that carries a local change.
685 const function_type_diff*
686 is_function_type_diff_with_local_changes(const diff* diff)
688 if (const function_type_diff* d = is_function_type_diff(diff))
689 if (d->has_local_changes())
695 /// Test if a diff node is about differences between variables.
697 /// @param diff the diff node to test.
699 /// @return a pointer to the actual var_diff that @p diff is a type
700 /// of, iff it is about differences between variables.
702 is_var_diff(const diff* diff)
704 const var_diff* d = dynamic_cast<const var_diff*>(diff);
706 ABG_ASSERT(is_decl_diff(diff));
710 /// Test if a diff node is about differences between functions.
712 /// @param diff the diff node to test.
714 /// @return a pointer to the actual var_diff that @p diff is a type
715 /// of, iff it is about differences between variables.
716 const function_decl_diff*
717 is_function_decl_diff(const diff* diff)
719 const function_decl_diff *d = dynamic_cast<const function_decl_diff*>(diff);
721 ABG_ASSERT(is_decl_diff(diff));
725 /// Test if a diff node is about differences between two pointers.
727 /// @param diff the diff node to consider.
729 /// @return the @p diff converted into an instance of @ref
730 /// pointer_diff iff @p diff is about differences between two
733 is_pointer_diff(const diff* diff)
734 {return dynamic_cast<const pointer_diff*>(diff);}
736 /// Test if a diff node is about differences between two references.
738 /// @param diff the diff node to consider.
740 /// @return the @p diff converted into an instance of @ref
741 /// reference_diff iff @p diff is about differences between two
743 const reference_diff*
744 is_reference_diff(const diff* diff)
745 {return dynamic_cast<const reference_diff*>(diff);}
747 /// Test if a diff node is about differences between two qualified
750 /// @param diff the diff node to consider.
752 /// @return @p diff converted into an instance of @ref
753 /// qualified_type_diff iff @p diff is about differences between two
755 const qualified_type_diff*
756 is_qualified_type_diff(const diff* diff)
757 {return dynamic_cast<const qualified_type_diff*>(diff);}
759 /// Test if a diff node is either a reference diff node or a pointer
760 /// diff node. Note that this function also works on diffs of
761 /// typedefs of reference or pointer.
763 /// @param diff the diff node to test.
765 /// @return true iff @p diff is either reference diff node or a
766 /// pointer diff node.
768 is_reference_or_pointer_diff(const diff* diff)
770 diff = peel_typedef_diff(diff);
771 return is_reference_diff(diff) || is_pointer_diff(diff);
774 /// Test if a diff node is a reference or pointer diff node to a
775 /// change that is neither basic type change nor distinct type change.
777 /// Note that this function also works on diffs of typedefs of
778 /// reference or pointer.
780 /// @param diff the diff node to consider.
782 /// @return true iff @p diff is a eference or pointer diff node to a
783 /// change that is neither basic type change nor distinct type change.
785 is_reference_or_ptr_diff_to_non_basic_nor_distinct_types(const diff* diff)
787 diff = peel_typedef_diff(diff);
788 if (const reference_diff* d = is_reference_diff(diff))
790 diff = peel_reference_diff(d);
791 if (is_diff_of_basic_type(diff) || is_distinct_diff(diff))
795 else if (const pointer_diff *d = is_pointer_diff(diff))
797 diff = peel_pointer_diff(d);
798 if (is_diff_of_basic_type(diff) || is_distinct_diff(diff))
806 /// Test if a diff node is about differences between two function
809 /// @param diff the diff node to consider.
811 /// @return the @p diff converted into an instance of @ref
812 /// reference_diff iff @p diff is about differences between two
813 /// function parameters.
815 is_fn_parm_diff(const diff* diff)
816 {return dynamic_cast<const fn_parm_diff*>(diff);}
818 /// Test if a diff node is about differences between two base class
821 /// @param diff the diff node to consider.
823 /// @return the @p diff converted into an instance of @ref base_diff
824 /// iff @p diff is about differences between two base class
827 is_base_diff(const diff* diff)
828 {return dynamic_cast<const base_diff*>(diff);}
830 /// Test if a diff node is about differences between two diff nodes of
833 /// @param diff the diff node to consider.
835 /// @return the @p diff converted into an instance of @ref
836 /// distintc_diff iff @p diff is about differences between two diff
837 /// nodes of different kinds.
839 is_distinct_diff(const diff *diff)
840 {return dynamic_cast<const distinct_diff*>(diff);}
842 /// Test if a diff node is a @ref corpus_diff node.
844 /// @param diff the diff node to consider.
846 /// @return a non-nil pointer to a @ref corpus_diff iff @p diff is a
847 /// @ref corpus_diff node.
849 is_corpus_diff(const diff* diff)
850 {return dynamic_cast<const corpus_diff*>(diff);}
852 /// Test if a diff node is a child node of a function parameter diff node.
854 /// @param diff the diff node to test.
856 /// @return true iff @p diff is a child node of a function parameter
859 is_child_node_of_function_parm_diff(const diff* diff)
860 {return diff && is_fn_parm_diff(diff->parent_node());}
862 /// Test if a diff node is a child node of a base diff node.
864 /// @param diff the diff node to test.
866 /// @return true iff @p diff is a child node of a base diff node.
868 is_child_node_of_base_diff(const diff* diff)
869 {return diff && is_base_diff(diff->parent_node());}
871 /// Test if the current diff node has an ancestor node that has been
874 /// This function detects cycles when walking through the "parent"
877 /// @param diff the diff node to take into account.
879 /// @param ancestor this is a hash map of the pointers of the parents
880 /// that are visited. It's used to detect cycles while visiting
881 /// parents of this diff tree node.
883 /// @return true iff the current diff node has an ancestor node that
884 /// has been filtered out.
886 diff_has_ancestor_filtered_out(const diff* d,
887 unordered_map<size_t, bool>& ancestors)
889 if (!d || !d->parent_node())
891 if (d->parent_node()->is_filtered_out())
894 const diff* parent = d->parent_node();
895 unordered_map<size_t, bool>::const_iterator i =
896 ancestors.find(reinterpret_cast<size_t>(parent));
897 if (i != ancestors.end())
898 // We've just detected a cycle in the path made of the parents
899 // that we are visiting.
901 ancestors[reinterpret_cast<size_t>(parent)] = true;
903 return diff_has_ancestor_filtered_out(parent, ancestors);
906 /// Test if the current diff node has an ancestor node that has been
909 /// @param diff the diff node to take into account.
911 /// @return true iff the current diff node has an ancestor node that
912 /// has been filtered out.
914 diff_has_ancestor_filtered_out(const diff* diff)
916 unordered_map<size_t, bool> ancestors_trace;
917 return diff_has_ancestor_filtered_out(diff, ancestors_trace);
920 /// The default traverse function.
924 diff_traversable_base::traverse(diff_node_visitor&)
927 diff_context::diff_context()
928 : priv_(new diff_context::priv)
930 // Setup all the diff output filters we have.
931 filtering::filter_base_sptr f;
933 f.reset(new filtering::harmless_harmful_filter);
936 // f.reset(new filtering::harmless_filter);
937 // add_diff_filter(f);
939 // f.reset(new filtering::harmful_filter);
940 // add_diff_filter(f);
943 /// Set the corpus diff relevant to this context.
945 /// @param d the corpus_diff we are interested in.
947 diff_context::set_corpus_diff(const corpus_diff_sptr& d)
948 {priv_->corpus_diff_ = d;}
950 /// Get the corpus diff for the current context.
952 /// @return the corpus diff of this context.
953 const corpus_diff_sptr&
954 diff_context::get_corpus_diff() const
955 {return priv_->corpus_diff_;}
957 /// Getter for the first corpus of the corpus diff of the current context.
959 /// @return the first corpus of the corpus diff of the current
960 /// context, if no corpus diff is associated to the context.
962 diff_context::get_first_corpus() const
964 if (priv_->corpus_diff_)
965 return priv_->corpus_diff_->first_corpus();
966 return corpus_sptr();
969 /// Getter for the second corpus of the corpus diff of the current
972 /// @return the second corpus of the corpus diff of the current
973 /// context, if no corpus diff is associated to the context.
975 diff_context::get_second_corpus() const
977 if (priv_->corpus_diff_)
978 return priv_->corpus_diff_->second_corpus();
979 return corpus_sptr();
982 /// Getter of the reporter to be used in this context.
984 /// @return the reporter to be used in this context.
986 diff_context::get_reporter() const
988 if (!priv_->reporter_)
990 if (show_leaf_changes_only())
991 priv_->reporter_.reset(new leaf_reporter);
993 priv_->reporter_.reset(new default_reporter);
995 ABG_ASSERT(priv_->reporter_);
996 return priv_->reporter_;
999 /// Setter of the reporter to be used in this context.
1001 /// @param r the reporter to be used in this context.
1003 diff_context::set_reporter(reporter_base_sptr& r)
1004 {priv_->reporter_ = r;}
1006 /// Tests if the current diff context already has a diff for two decls.
1008 /// @param first the first decl to consider.
1010 /// @param second the second decl to consider.
1012 /// @return a pointer to the diff for @p first @p second if found,
1015 diff_context::has_diff_for(const type_or_decl_base_sptr first,
1016 const type_or_decl_base_sptr second) const
1018 types_or_decls_diff_map_type::const_iterator i =
1019 priv_->types_or_decls_diff_map.find(std::make_pair(first, second));
1020 if (i != priv_->types_or_decls_diff_map.end())
1025 /// Tests if the current diff context already has a diff for two types.
1027 /// @param first the first type to consider.
1029 /// @param second the second type to consider.
1031 /// @return a pointer to the diff for @p first @p second if found,
1034 diff_context::has_diff_for_types(const type_base_sptr first,
1035 const type_base_sptr second) const
1036 {return has_diff_for(first, second);}
1038 /// Tests if the current diff context already has a given diff.
1040 ///@param d the diff to consider.
1042 /// @return a pointer to the diff found for @p d
1044 diff_context::has_diff_for(const diff* d) const
1045 {return has_diff_for(d->first_subject(), d->second_subject()).get();}
1047 /// Tests if the current diff context already has a given diff.
1049 ///@param d the diff to consider.
1051 /// @return a pointer to the diff found for @p d
1053 diff_context::has_diff_for(const diff_sptr d) const
1054 {return has_diff_for(d->first_subject(), d->second_subject());}
1056 /// Getter for the bitmap that represents the set of categories that
1057 /// the user wants to see reported.
1059 /// @return a bitmap that represents the set of categories that the
1060 /// user wants to see reported.
1062 diff_context::get_allowed_category() const
1063 {return priv_->allowed_category_;}
1065 /// Setter for the bitmap that represents the set of categories that
1066 /// the user wants to see reported.
1068 /// @param c a bitmap that represents the set of categories that the
1069 /// user wants to see represented.
1071 diff_context::set_allowed_category(diff_category c)
1072 {priv_->allowed_category_ = c;}
1074 /// Setter for the bitmap that represents the set of categories that
1075 /// the user wants to see reported
1077 /// This function perform a bitwise or between the new set of
1078 /// categories and the current ones, and then sets the current
1079 /// categories to the result of the or.
1081 /// @param c a bitmap that represents the set of categories that the
1082 /// user wants to see represented.
1084 diff_context::switch_categories_on(diff_category c)
1085 {priv_->allowed_category_ = priv_->allowed_category_ | c;}
1087 /// Setter for the bitmap that represents the set of categories that
1088 /// the user wants to see reported
1090 /// This function actually unsets bits from the current categories.
1092 /// @param c a bitmap that represents the set of categories to unset
1093 /// from the current categories.
1095 diff_context::switch_categories_off(diff_category c)
1096 {priv_->allowed_category_ = priv_->allowed_category_ & ~c;}
1098 /// Add a diff for two decls to the cache of the current diff_context.
1100 /// Doing this allows to later find the added diff from its two
1103 /// @param first the first decl to consider.
1105 /// @param second the second decl to consider.
1107 /// @param the diff to add.
1109 diff_context::add_diff(type_or_decl_base_sptr first,
1110 type_or_decl_base_sptr second,
1112 {priv_->types_or_decls_diff_map[std::make_pair(first, second)] = d;}
1114 /// Add a diff tree node to the cache of the current diff_context
1116 /// @param d the diff tree node to add.
1118 diff_context::add_diff(const diff* d)
1122 diff_sptr dif(const_cast<diff*>(d), noop_deleter());
1123 add_diff(d->first_subject(), d->second_subject(), dif);
1127 /// Add a diff tree node to the cache of the current diff_context
1129 /// @param d the diff tree node to add.
1131 diff_context::add_diff(const diff_sptr d)
1134 add_diff(d->first_subject(), d->second_subject(), d);
1137 /// Getter for the @ref CanonicalDiff "canonical diff node" for the
1138 /// @ref diff represented by their two subjects.
1140 /// @param first the first subject of the diff.
1142 /// @param second the second subject of the diff.
1144 /// @return the canonical diff for the diff node represented by the
1145 /// two diff subjects @p first and @p second. If no canonical diff
1146 /// node was registered for these subjects, then a nil node is
1149 diff_context::get_canonical_diff_for(const type_or_decl_base_sptr first,
1150 const type_or_decl_base_sptr second) const
1151 {return has_diff_for(first, second);}
1153 /// Getter for the @ref CanonicalDiff "canonical diff node" for the
1154 /// @ref diff represented by the two subjects of a given diff node.
1156 /// @param d the diff node to get the canonical node for.
1158 /// @return the canonical diff for the diff node represented by the
1159 /// two diff subjects of @p d. If no canonical diff node was
1160 /// registered for these subjects, then a nil node is returned.
1162 diff_context::get_canonical_diff_for(const diff_sptr d) const
1163 {return has_diff_for(d);}
1165 /// Setter for the @ref CanonicalDiff "canonical diff node" for the
1166 /// @ref diff represented by their two subjects.
1168 /// @param first the first subject of the diff.
1170 /// @param second the second subject of the diff.
1172 /// @param d the new canonical diff.
1174 diff_context::set_canonical_diff_for(const type_or_decl_base_sptr first,
1175 const type_or_decl_base_sptr second,
1179 if (!has_diff_for(first, second))
1181 add_diff(first, second, d);
1182 priv_->canonical_diffs.push_back(d);
1186 /// If there is is a @ref CanonicalDiff "canonical diff node"
1187 /// registered for two diff subjects, return it. Otherwise, register
1188 /// a canonical diff node for these two diff subjects and return it.
1190 /// @param first the first subject of the diff.
1192 /// @param second the second subject of the diff.
1194 /// @param d the new canonical diff node.
1196 /// @return the canonical diff node.
1198 diff_context::set_or_get_canonical_diff_for(const type_or_decl_base_sptr first,
1199 const type_or_decl_base_sptr second,
1200 const diff_sptr canonical_diff)
1202 ABG_ASSERT(canonical_diff);
1204 diff_sptr canonical = get_canonical_diff_for(first, second);
1207 canonical = canonical_diff;
1208 set_canonical_diff_for(first, second, canonical);
1213 /// Set the canonical diff node property of a given diff node
1216 /// For a given diff node that has no canonical diff node, retrieve
1217 /// the canonical diff node (by looking at its diff subjects and at
1218 /// the current context) and set the canonical diff node property of
1219 /// the diff node to that canonical diff node. If no canonical diff
1220 /// node has been registered to the diff context for the subjects of
1221 /// the diff node then, register the canonical diff node as being the
1222 /// diff node itself; and set its canonical diff node property as
1223 /// such. Otherwise, if the diff node already has a canonical diff
1224 /// node, do nothing.
1226 /// @param diff the diff node to initialize the canonical diff node
1229 diff_context::initialize_canonical_diff(const diff_sptr diff)
1231 if (diff->get_canonical_diff() == 0)
1233 diff_sptr canonical =
1234 set_or_get_canonical_diff_for(diff->first_subject(),
1235 diff->second_subject(),
1237 diff->set_canonical_diff(canonical.get());
1241 /// Add a diff node to the set of diff nodes that are kept alive for
1242 /// the life time of the current instance of diff_context.
1244 /// Note that diff added to the diff cache are kept alive as well, and
1245 /// don't need to be passed to this function to be kept alive.
1247 /// @param d the diff node to be kept alive during the life time of
1248 /// the current instance of @ref diff_context.
1250 diff_context::keep_diff_alive(diff_sptr& d)
1251 {priv_->live_diffs_.insert(d);}
1253 /// Test if a diff node has been traversed.
1255 /// @param d the diff node to consider.
1257 /// @return the first diff node against which @p d is redundant.
1259 diff_context::diff_has_been_visited(const diff* d) const
1261 const diff* canonical = d->get_canonical_diff();
1262 ABG_ASSERT(canonical);
1264 size_t ptr_value = reinterpret_cast<size_t>(canonical);
1265 pointer_map::iterator it = priv_->visited_diff_nodes_.find(ptr_value);
1266 if (it != priv_->visited_diff_nodes_.end())
1267 return reinterpret_cast<diff*>(it->second);
1272 /// Test if a diff node has been traversed.
1274 /// @param d the diff node to consider.
1276 /// @return the first diff node against which @p d is redundant.
1278 diff_context::diff_has_been_visited(const diff_sptr d) const
1280 diff_sptr diff(diff_has_been_visited(d.get()));
1284 /// Mark a diff node as traversed by a traversing algorithm.
1286 /// Actually, it's the @ref CanonicalDiff "canonical diff" of this
1287 /// node that is marked as traversed.
1289 /// Subsequent invocations of diff_has_been_visited() on the diff node
1290 /// will yield true.
1292 diff_context::mark_diff_as_visited(const diff* d)
1294 if (diff_has_been_visited(d))
1297 const diff* canonical = d->get_canonical_diff();
1298 ABG_ASSERT(canonical);
1300 size_t canonical_ptr_value = reinterpret_cast<size_t>(canonical);
1301 size_t diff_ptr_value = reinterpret_cast<size_t>(d);;
1302 priv_->visited_diff_nodes_[canonical_ptr_value] = diff_ptr_value;
1305 /// Unmark all the diff nodes that were marked as being traversed.
1307 diff_context::forget_visited_diffs()
1308 {priv_->visited_diff_nodes_.clear();}
1310 /// Mark a given diff node as being the last one that has been visited
1311 /// in its class of equivalence.
1313 /// @param d the diff node to mark.
1315 diff_context::mark_last_diff_visited_per_class_of_equivalence(const diff* d)
1317 if (!d->get_canonical_diff())
1320 size_t v0 = reinterpret_cast<size_t>(d->get_canonical_diff());
1321 size_t v1 = reinterpret_cast<size_t>(d);
1322 priv_->last_visited_diff_node_[v0]= v1;
1325 /// Clear the marking about the diff diff nodes in a given class of
1328 diff_context::clear_last_diffs_visited_per_class_of_equivalence()
1329 {priv_->last_visited_diff_node_.clear();}
1331 /// Return the last diff node visited in the class of equivalence of
1332 /// a given diff node.
1334 /// @param d the diff node which class of equivalence to consider.
1336 /// @return the last diff node visited in the class of equivalence of
1337 /// the diff node @p d.
1339 diff_context::get_last_visited_diff_of_class_of_equivalence(const diff* d)
1341 size_t v0 = reinterpret_cast<size_t>(d);
1343 pointer_map::const_iterator it = priv_->last_visited_diff_node_.find(v0);
1344 if (it != priv_->last_visited_diff_node_.end())
1345 return reinterpret_cast<const diff*>(it->second);
1349 /// This sets a flag that, if it's true, then during the traversing of
1350 /// a diff nodes tree each node is visited at most once.
1352 /// @param f if true then during the traversing of a diff nodes tree
1353 /// each node is visited at most once.
1356 diff_context::forbid_visiting_a_node_twice(bool f)
1357 {priv_->forbid_visiting_a_node_twice_ = f;}
1359 /// This function sets a flag os that if @ref
1360 /// forbid_visiting_a_node_twice() returns true, then each time the
1361 /// node visitor starts visiting a new interface, it resets the
1362 /// memory the systems has about already visited node.
1364 /// @param f the flag to set.
1366 diff_context::forbid_visiting_a_node_twice_per_interface(bool f)
1367 {priv_->reset_visited_diffs_for_each_interface_ = f;}
1369 /// Return a flag that, if true, then during the traversing of a diff
1370 /// nodes tree each node is visited at most once.
1372 /// @return the boolean flag.
1374 diff_context::visiting_a_node_twice_is_forbidden() const
1375 {return priv_->forbid_visiting_a_node_twice_;}
1377 /// Return a flag that, if true, then during the traversing of a diff
1378 /// nodes tree each node is visited at most once, while visiting the
1379 /// diff tree underneath a given interface (public function or
1380 /// variable). Each time a new interface is visited, the nodes
1381 /// visited while visiting previous interfaces can be visited again.
1383 /// @return the boolean flag.
1385 /// @return the boolean flag.
1387 diff_context::visiting_a_node_twice_is_forbidden_per_interface() const
1389 return (priv_->forbid_visiting_a_node_twice_
1390 && priv_->reset_visited_diffs_for_each_interface_);
1393 /// Getter for the diff tree nodes filters to apply to diff sub-trees.
1395 /// @return the vector of tree filters to apply to diff sub-trees.
1396 const filtering::filters&
1397 diff_context::diff_filters() const
1398 {return priv_->filters_;}
1400 /// Setter for the diff filters to apply to a given diff sub-tree.
1402 /// @param f the new diff filter to add to the vector of diff filters
1403 /// to apply to diff sub-trees.
1405 diff_context::add_diff_filter(filtering::filter_base_sptr f)
1406 {priv_->filters_.push_back(f);}
1408 /// Apply the diff filters to a given diff sub-tree.
1410 /// If the current context is instructed to filter out some categories
1411 /// then this function walks the given sub-tree and categorizes its
1412 /// nodes by using the filters held by the context.
1414 /// @param diff the diff sub-tree to apply the filters to.
1416 diff_context::maybe_apply_filters(diff_sptr diff)
1421 if (get_allowed_category() == EVERYTHING_CATEGORY)
1424 if (!diff->has_changes())
1427 for (filtering::filters::const_iterator i = diff_filters().begin();
1428 i != diff_filters().end();
1431 filtering::apply_filter(*i, diff);
1432 propagate_categories(diff);
1437 /// Apply the diff filters to the diff nodes of a @ref corpus_diff
1440 /// If the current context is instructed to filter out some categories
1441 /// then this function walks the diff tree and categorizes its nodes
1442 /// by using the filters held by the context.
1444 /// @param diff the corpus diff to apply the filters to.
1446 diff_context::maybe_apply_filters(corpus_diff_sptr diff)
1449 if (!diff || !diff->has_changes())
1452 for (filtering::filters::const_iterator i = diff_filters().begin();
1453 i != diff_filters().end();
1456 filtering::apply_filter(**i, diff);
1457 propagate_categories(diff);
1461 /// Getter for the vector of suppressions that specify which diff node
1462 /// reports should be dropped on the floor.
1464 /// @return the set of suppressions.
1466 diff_context::suppressions() const
1467 {return priv_->suppressions_;}
1469 /// Add a new suppression specification that specifies which diff node
1470 /// reports should be dropped on the floor.
1472 /// @param suppr the new suppression specification to add to the
1473 /// existing set of suppressions specifications of the diff context.
1475 diff_context::add_suppression(const suppression_sptr suppr)
1476 {priv_->suppressions_.push_back(suppr);}
1478 /// Add new suppression specifications that specify which diff node
1479 /// reports should be dropped on the floor.
1481 /// @param supprs the new suppression specifications to add to the
1482 /// existing set of suppression specifications of the diff context.
1484 diff_context::add_suppressions(const suppressions_type& supprs)
1486 priv_->suppressions_.insert(priv_->suppressions_.end(),
1487 supprs.begin(), supprs.end());
1490 /// Set the flag that indicates if the diff using this context should
1491 /// show only leaf changes or not.
1493 /// @param f the new value of the flag that indicates if the diff
1494 /// using this context should show only leaf changes or not.
1496 diff_context::show_leaf_changes_only(bool f)
1498 // This function can be called only if the reporter hasn't yet been
1499 // created. Once it's been created, we are supposed to live with
1501 ABG_ASSERT(priv_->reporter_ == 0);
1503 priv_->leaf_changes_only_ = f;
1504 // So when we are showing only leaf changes, we want to show
1505 // redundant changes because of this: Suppose several functions have
1506 // their return type changed from void* to int*. We want them all
1507 // to be reported. In that case the change is not redundant. As
1508 // far as user-defined type changes (like struct/class) they are
1509 // already put inside a map which makes them be non-redundant, so we
1510 // don't have to worry about that case.
1512 // TODO: maybe that in this case we should avoid firing the
1513 // redundancy analysis pass altogether. That could help save a
1514 // couple of CPU cycle here and there!
1515 priv_->show_redundant_changes_ = f;
1518 /// Get the flag that indicates if the diff using this context should
1519 /// show only leaf changes or not.
1521 /// @return the value of the flag that indicates if the diff using
1522 /// this context should show only leaf changes or not.
1524 diff_context::show_leaf_changes_only() const
1525 {return priv_->leaf_changes_only_;}
1527 /// Get the flag that indicates if the diff reports using this context
1528 /// should show sizes and offsets in an hexadecimal base or not. If
1529 /// not, then they are to be shown in a decimal base.
1531 /// @return true iff sizes and offsets are to be shown in an
1532 /// hexadecimal base.
1534 diff_context::show_hex_values() const
1535 {return priv_->hex_values_;}
1537 /// Set the flag that indicates if diff reports using this context
1538 /// should show sizes and offsets in an hexadecimal base or not. If
1539 /// not, then they are to be shown in a decimal base.
1541 /// @param f if true then sizes and offsets are to be shown in an
1542 /// hexadecimal base.
1544 diff_context::show_hex_values(bool f)
1545 {priv_->hex_values_ = f;}
1547 /// Get the flag that indicates if diff reports using this context
1548 /// should show sizes and offsets in bits, rather than bytes.
1550 /// @return true iff sizes and offsets are to be shown in bits.
1551 /// Otherwise they are to be shown in bytes.
1553 diff_context::show_offsets_sizes_in_bits() const
1554 {return priv_->show_offsets_sizes_in_bits_;}
1556 /// Set the flag that indicates if diff reports using this context
1557 /// should show sizes and offsets in bits, rather than bytes.
1559 /// @param f if true then sizes and offsets are to be shown in bits.
1560 /// Otherwise they are to be shown in bytes.
1562 diff_context::show_offsets_sizes_in_bits(bool f)
1563 {priv_->show_offsets_sizes_in_bits_ = f;}
1565 /// Set a flag saying if offset changes should be reported in a
1566 /// relative way. That is, if the report should say how of many bits
1567 /// a class/struct data member did move.
1569 /// @param f the new boolean value of the flag.
1571 diff_context::show_relative_offset_changes(bool f)
1572 {priv_->show_relative_offset_changes_ = f;}
1574 /// Get the flag saying if offset changes should be reported in a
1575 /// relative way. That is, if the report should say how of many bits
1576 /// a class/struct data member did move.
1578 /// @return the boolean value of the flag.
1580 diff_context::show_relative_offset_changes(void)
1581 {return priv_->show_relative_offset_changes_;}
1584 show_relative_offset_changes(void);
1586 /// Set a flag saying if the comparison module should only show the
1589 /// @param f the flag to set.
1591 diff_context::show_stats_only(bool f)
1592 {priv_->show_stats_only_ = f;}
1594 /// Test if the comparison module should only show the diff stats.
1596 /// @return true if the comparison module should only show the diff
1597 /// stats, false otherwise.
1599 diff_context::show_stats_only() const
1600 {return priv_->show_stats_only_;}
1602 /// Setter for the property that says if the comparison module should
1603 /// show the soname changes in its report.
1605 /// @param f the new value of the property.
1607 diff_context::show_soname_change(bool f)
1608 {priv_->show_soname_change_ = f;}
1610 /// Getter for the property that says if the comparison module should
1611 /// show the soname changes in its report.
1613 /// @return the value of the property.
1615 diff_context::show_soname_change() const
1616 {return priv_->show_soname_change_;}
1618 /// Setter for the property that says if the comparison module should
1619 /// show the architecture changes in its report.
1621 /// @param f the new value of the property.
1623 diff_context::show_architecture_change(bool f)
1624 {priv_->show_architecture_change_ = f;}
1626 /// Getter for the property that says if the comparison module should
1627 /// show the architecture changes in its report.
1629 /// @return the value of the property.
1631 diff_context::show_architecture_change() const
1632 {return priv_->show_architecture_change_;}
1634 /// Set a flag saying to show the deleted functions.
1636 /// @param f true to show deleted functions.
1638 diff_context::show_deleted_fns(bool f)
1639 {priv_->show_deleted_fns_ = f;}
1641 /// @return true if we want to show the deleted functions, false
1644 diff_context::show_deleted_fns() const
1645 {return priv_->show_deleted_fns_;}
1647 /// Set a flag saying to show the changed functions.
1649 /// @param f true to show the changed functions.
1651 diff_context::show_changed_fns(bool f)
1652 {priv_->show_changed_fns_ = f;}
1654 /// @return true if we want to show the changed functions, false otherwise.
1656 diff_context::show_changed_fns() const
1657 {return priv_->show_changed_fns_;}
1659 /// Set a flag saying to show the added functions.
1661 /// @param f true to show the added functions.
1663 diff_context::show_added_fns(bool f)
1664 {priv_->show_added_fns_ = f;}
1666 /// @return true if we want to show the added functions, false
1669 diff_context::show_added_fns() const
1670 {return priv_->show_added_fns_;}
1672 /// Set a flag saying to show the deleted variables.
1674 /// @param f true to show the deleted variables.
1676 diff_context::show_deleted_vars(bool f)
1677 {priv_->show_deleted_vars_ = f;}
1679 /// @return true if we want to show the deleted variables, false
1682 diff_context::show_deleted_vars() const
1683 {return priv_->show_deleted_vars_;}
1685 /// Set a flag saying to show the changed variables.
1687 /// @param f true to show the changed variables.
1689 diff_context::show_changed_vars(bool f)
1690 {priv_->show_changed_vars_ = f;}
1692 /// @return true if we want to show the changed variables, false otherwise.
1694 diff_context::show_changed_vars() const
1695 {return priv_->show_changed_vars_;}
1697 /// Set a flag saying to show the added variables.
1699 /// @param f true to show the added variables.
1701 diff_context::show_added_vars(bool f)
1702 {priv_->show_added_vars_ = f;}
1704 /// @return true if we want to show the added variables, false
1707 diff_context::show_added_vars() const
1708 {return priv_->show_added_vars_;}
1711 diff_context::show_linkage_names() const
1712 {return priv_->show_linkage_names_;}
1715 diff_context::show_linkage_names(bool f)
1716 {priv_->show_linkage_names_= f;}
1718 /// Set a flag saying to show location information.
1720 /// @param f true to show location information.
1722 diff_context::show_locs(bool f)
1723 {priv_->show_locs_= f;}
1725 /// @return true if we want to show location information, false
1728 diff_context::show_locs() const
1729 {return priv_->show_locs_;}
1731 /// A getter for the flag that says if we should report about
1732 /// functions or variables diff nodes that have *exclusively*
1733 /// redundant diff tree children nodes.
1735 /// @return the flag.
1737 diff_context::show_redundant_changes() const
1738 {return priv_->show_redundant_changes_;}
1740 /// A setter for the flag that says if we should report about
1741 /// functions or variables diff nodes that have *exclusively*
1742 /// redundant diff tree children nodes.
1744 /// @param f the flag to set.
1746 diff_context::show_redundant_changes(bool f)
1747 {priv_->show_redundant_changes_ = f;}
1749 /// Getter for the flag that indicates if symbols not referenced by
1750 /// any debug info are to be compared and reported about.
1752 /// @return the boolean flag.
1754 diff_context::show_symbols_unreferenced_by_debug_info() const
1755 {return priv_->show_syms_unreferenced_by_di_;}
1757 /// Setter for the flag that indicates if symbols not referenced by
1758 /// any debug info are to be compared and reported about.
1760 /// @param f the new flag to set.
1762 diff_context::show_symbols_unreferenced_by_debug_info(bool f)
1763 {priv_->show_syms_unreferenced_by_di_ = f;}
1765 /// Getter for the flag that indicates if symbols not referenced by
1766 /// any debug info and that got added are to be reported about.
1768 /// @return true iff symbols not referenced by any debug info and that
1769 /// got added are to be reported about.
1771 diff_context::show_added_symbols_unreferenced_by_debug_info() const
1772 {return priv_->show_added_syms_unreferenced_by_di_;}
1774 /// Setter for the flag that indicates if symbols not referenced by
1775 /// any debug info and that got added are to be reported about.
1777 /// @param f the new flag that says if symbols not referenced by any
1778 /// debug info and that got added are to be reported about.
1780 diff_context::show_added_symbols_unreferenced_by_debug_info(bool f)
1781 {priv_->show_added_syms_unreferenced_by_di_ = f;}
1783 /// Getter of the flag that indicates if the leaf reporter should
1784 /// display a summary of the interfaces impacted by a given leaf
1787 /// @return the flag that indicates if the leaf reporter should
1788 /// display a summary of the interfaces impacted by a given leaf
1791 diff_context::show_impacted_interfaces() const
1792 {return priv_->show_impacted_interfaces_;}
1794 /// Setter of the flag that indicates if the leaf reporter should
1795 /// display a summary of the interfaces impacted by a given leaf
1798 /// @param f the new value of the flag that indicates if the leaf
1799 /// reporter should display a summary of the interfaces impacted by a
1800 /// given leaf change or not.
1802 diff_context::show_impacted_interfaces(bool f)
1803 {priv_->show_impacted_interfaces_ = f;}
1805 /// Setter for the default output stream used by code of the
1806 /// comparison engine. By default the default output stream is a NULL
1809 /// @param o a pointer to the default output stream.
1811 diff_context::default_output_stream(ostream* o)
1812 {priv_->default_output_stream_ = o;}
1814 /// Getter for the default output stream used by code of the
1815 /// comparison engine. By default the default output stream is a NULL
1818 /// @return a pointer to the default output stream.
1820 diff_context::default_output_stream()
1821 {return priv_->default_output_stream_;}
1823 /// Setter for the errror output stream used by code of the comparison
1824 /// engine. By default the error output stream is a NULL pointer.
1826 /// @param o a pointer to the error output stream.
1828 diff_context::error_output_stream(ostream* o)
1829 {priv_->error_output_stream_ = o;}
1831 /// Getter for the errror output stream used by code of the comparison
1832 /// engine. By default the error output stream is a NULL pointer.
1834 /// @return a pointer to the error output stream.
1836 diff_context::error_output_stream() const
1837 {return priv_->error_output_stream_;}
1839 /// Test if the comparison engine should dump the diff tree for the
1840 /// changed functions and variables it has.
1842 /// @return true if after the comparison, the engine should dump the
1843 /// diff tree for the changed functions and variables it has.
1845 diff_context::dump_diff_tree() const
1846 {return priv_->dump_diff_tree_;}
1848 /// Set if the comparison engine should dump the diff tree for the
1849 /// changed functions and variables it has.
1851 /// @param f true if after the comparison, the engine should dump the
1852 /// diff tree for the changed functions and variables it has.
1854 diff_context::dump_diff_tree(bool f)
1855 {priv_->dump_diff_tree_ = f;}
1857 /// Emit a textual representation of a diff tree to the error output
1858 /// stream of the current context, for debugging purposes.
1860 /// @param d the diff tree to serialize to the error output associated
1861 /// to the current instance of @ref diff_context.
1863 diff_context::do_dump_diff_tree(const diff_sptr d) const
1865 if (error_output_stream())
1866 print_diff_tree(d, *error_output_stream());
1869 /// Emit a textual representation of a @ref corpus_diff tree to the error
1870 /// output stream of the current context, for debugging purposes.
1872 /// @param d the @ref corpus_diff tree to serialize to the error
1873 /// output associated to the current instance of @ref diff_context.
1875 diff_context::do_dump_diff_tree(const corpus_diff_sptr d) const
1877 if (error_output_stream())
1878 print_diff_tree(d, *error_output_stream());
1880 // </diff_context stuff>
1884 /// Constructor for the @ref diff type.
1886 /// This constructs a diff between two subjects that are actually
1887 /// declarations; the first and the second one.
1889 /// @param first_subject the first decl (subject) of the diff.
1891 /// @param second_subject the second decl (subject) of the diff.
1892 diff::diff(type_or_decl_base_sptr first_subject,
1893 type_or_decl_base_sptr second_subject)
1894 : priv_(new priv(first_subject, second_subject,
1895 diff_context_sptr(),
1897 /*reported_once=*/false,
1898 /*currently_reporting=*/false))
1901 /// Constructor for the @ref diff type.
1903 /// This constructs a diff between two subjects that are actually
1904 /// declarations; the first and the second one.
1906 /// @param first_subject the first decl (subject) of the diff.
1908 /// @param second_subject the second decl (subject) of the diff.
1910 /// @param ctxt the context of the diff. Note that this context
1911 /// object must stay alive during the entire life time of the current
1912 /// instance of @ref diff. Otherwise, memory corruption issues occur.
1913 diff::diff(type_or_decl_base_sptr first_subject,
1914 type_or_decl_base_sptr second_subject,
1915 diff_context_sptr ctxt)
1916 : priv_(new priv(first_subject, second_subject,
1917 ctxt, NO_CHANGE_CATEGORY,
1918 /*reported_once=*/false,
1919 /*currently_reporting=*/false))
1922 /// Flag a given diff node as being traversed.
1924 /// For certain diff nodes like @ref class_diff, it's important to
1925 /// avoid traversing the node again while it's already being
1926 /// traversed; otherwise this leads to infinite loops. So the
1927 /// diff::begin_traversing() and diff::end_traversing() methods flag a
1928 /// given node as being traversed (or not), so that
1929 /// diff::is_traversing() can tell if the node is being traversed.
1931 /// Note that traversing a node means visiting it *and* visiting its
1934 /// The canonical node is marked as being traversed too.
1936 /// These functions are called by the traversing code.
1938 diff::begin_traversing()
1940 ABG_ASSERT(!is_traversing());
1941 if (priv_->canonical_diff_)
1942 priv_->canonical_diff_->priv_->traversing_ = true;
1943 priv_->traversing_ = true;
1946 /// Tell if a given node is being traversed or not.
1948 /// Note that traversing a node means visiting it *and* visiting its
1951 /// It's the canonical node which is looked at, actually.
1953 /// Please read the comments for the diff::begin_traversing() for mode
1956 /// @return true if the current instance of @diff is being traversed.
1958 diff::is_traversing() const
1960 if (priv_->canonical_diff_)
1961 return priv_->canonical_diff_->priv_->traversing_;
1962 return priv_->traversing_;
1965 /// Flag a given diff node as not being traversed anymore.
1967 /// Note that traversing a node means visiting it *and* visiting its
1970 /// Please read the comments of the function diff::begin_traversing()
1971 /// for mode context.
1973 diff::end_traversing()
1975 ABG_ASSERT(is_traversing());
1976 if (priv_->canonical_diff_)
1977 priv_->canonical_diff_->priv_->traversing_ = false;
1978 priv_->traversing_ = false;
1981 /// Finish the building of a given kind of a diff tree node.
1983 /// For instance, certain kinds of diff tree node have specific
1984 /// children nodes that are populated after the constructor of the
1985 /// diff tree node has been called. In that case, calling overloads
1986 /// of this method ensures that these children nodes are properly
1987 /// gathered and setup.
1989 diff::finish_diff_type()
1993 /// Getter of the first subject of the diff.
1995 /// @return the first subject of the diff.
1996 type_or_decl_base_sptr
1997 diff::first_subject() const
1998 {return dynamic_pointer_cast<type_or_decl_base>(priv_->first_subject_);}
2000 /// Getter of the second subject of the diff.
2002 /// @return the second subject of the diff.
2003 type_or_decl_base_sptr
2004 diff::second_subject() const
2005 {return dynamic_pointer_cast<type_or_decl_base>(priv_->second_subject_);}
2007 /// Getter for the children nodes of the current @ref diff node.
2009 /// @return a vector of the children nodes.
2010 const vector<diff*>&
2011 diff::children_nodes() const
2012 {return priv_->children_;}
2014 /// Getter for the parent node of the current @ref diff node.
2016 /// @return the parent node of the current @ref diff node.
2018 diff::parent_node() const
2019 {return priv_->parent_;}
2021 /// Getter for the canonical diff of the current instance of @ref
2024 /// Note that the canonical diff node for the current instanc eof diff
2025 /// node must have been set by invoking
2026 /// class_diff::initialize_canonical_diff() on the current instance of
2029 /// @return the canonical diff node or null if none was set.
2031 diff::get_canonical_diff() const
2032 {return priv_->canonical_diff_;}
2034 /// Setter for the canonical diff of the current instance of @ref
2037 /// @param d the new canonical node to set.
2039 diff::set_canonical_diff(diff * d)
2040 {priv_->canonical_diff_ = d;}
2042 /// Add a new child node to the vector of children nodes for the
2043 /// current @ref diff node.
2045 /// @param d the new child node to add to the children nodes.
2047 diff::append_child_node(diff_sptr d)
2051 // Ensure 'd' is kept alive for the life time of the context of this
2053 context()->keep_diff_alive(d);
2055 // Add the underlying pointer of 'd' to the vector of children.
2056 // Note that this vector holds no reference to 'd'. This is to avoid
2057 // reference cycles. The reference to 'd' is held by the context of
2058 // this diff, thanks to the call to context()->keep_diff_alive(d)
2060 priv_->children_.push_back(d.get());
2062 diff_less_than_functor comp;
2063 std::sort(priv_->children_.begin(),
2064 priv_->children_.end(),
2067 d->priv_->parent_ = this;
2070 /// Getter of the context of the current diff.
2072 /// @return the context of the current diff.
2073 const diff_context_sptr
2074 diff::context() const
2075 {return priv_->get_context();}
2077 /// Setter of the context of the current diff.
2079 /// @param c the new context to set.
2081 diff::context(diff_context_sptr c)
2084 /// Tests if we are currently in the middle of emitting a report for
2087 /// @return true if we are currently emitting a report for the
2088 /// current diff, false otherwise.
2090 diff::currently_reporting() const
2092 if (priv_->canonical_diff_)
2093 return priv_->canonical_diff_->priv_->currently_reporting_;
2094 return priv_->currently_reporting_;
2097 /// Sets a flag saying if we are currently in the middle of emitting
2098 /// a report for this diff.
2100 /// @param f true if we are currently emitting a report for the
2101 /// current diff, false otherwise.
2103 diff::currently_reporting(bool f) const
2105 if (priv_->canonical_diff_)
2106 priv_->canonical_diff_->priv_->currently_reporting_ = f;
2107 priv_->currently_reporting_ = f;
2110 /// Tests if a report has already been emitted for the current diff.
2112 /// @return true if a report has already been emitted for the
2113 /// current diff, false otherwise.
2115 diff::reported_once() const
2117 ABG_ASSERT(priv_->canonical_diff_);
2118 return priv_->canonical_diff_->priv_->reported_once_;
2121 /// The generic traversing code that walks a given diff sub-tree.
2123 /// Note that there is a difference between traversing a diff node and
2124 /// visiting it. Basically, traversing a diff node means visiting it
2125 /// and visiting its children nodes too. So one can visit a node
2126 /// without traversing it. But traversing a node without visiting it
2127 /// is not possible.
2129 /// Note that by default this traversing code visits a given class of
2130 /// equivalence of a diff node only once. This behaviour can been
2131 /// changed by calling
2132 /// diff_context::visiting_a_node_twice_is_forbidden(), but this is
2133 /// very risky as it might create endless loops while visiting a diff
2134 /// tree graph that has changes that refer to themselves; that is,
2135 /// diff tree graphs with cycles.
2137 /// When a diff node is encountered, the
2138 /// diff_node_visitor::visit_begin() method is invoked on the diff
2141 /// If the diff node has already been visited, then
2142 /// node_visitor::visit_end() is called on it and the node traversing
2143 /// is done; the children of the diff node are not visited in this
2146 /// If the diff node has *NOT* been visited yet, then the
2147 /// diff_node_visitor::visit() method is invoked with it's 'pre'
2148 /// argument set to true. Then if the diff_node_visitor::visit()
2149 /// returns true, then the children nodes of the diff node are
2150 /// visited. Otherwise, no children nodes of the diff node is
2151 /// visited and the diff_node_visitor::visit_end() is called.
2153 /// After the children nodes are visited (and only if they are
2154 /// visited) the diff_node_visitor::visit() method is invoked with
2155 /// it's 'pre' argument set to false. And then the
2156 /// diff_node_visitor::visit_end() is called.
2158 /// @param v the entity that visits each node of the diff sub-tree.
2160 /// @return true to tell the caller that all of the sub-tree could be
2161 /// walked. This instructs the caller to keep walking the rest of the
2162 /// tree. Return false otherwise.
2164 diff::traverse(diff_node_visitor& v)
2168 v.visit_begin(this);
2170 bool already_visited = false;
2171 if (context()->visiting_a_node_twice_is_forbidden()
2172 && context()->diff_has_been_visited(this))
2173 already_visited = true;
2175 bool mark_visited_nodes_as_traversed =
2176 !(v.get_visiting_kind() & DO_NOT_MARK_VISITED_NODES_AS_VISITED);
2178 if (!already_visited && !v.visit(this, /*pre=*/true))
2181 if (mark_visited_nodes_as_traversed)
2182 context()->mark_diff_as_visited(this);
2186 if (!(v.get_visiting_kind() & SKIP_CHILDREN_VISITING_KIND)
2188 && !already_visited)
2191 for (vector<diff*>::const_iterator i = children_nodes().begin();
2192 i != children_nodes().end();
2195 if (!(*i)->traverse(v))
2198 if (mark_visited_nodes_as_traversed)
2199 context()->mark_diff_as_visited(this);
2207 if (!v.visit(this, /*pref=*/false))
2210 if (mark_visited_nodes_as_traversed)
2211 context()->mark_diff_as_visited(this);
2216 if (!already_visited && mark_visited_nodes_as_traversed)
2217 context()->mark_diff_as_visited(this);
2222 /// Sets a flag saying if a report has already been emitted for the
2225 /// @param f true if a report has already been emitted for the
2226 /// current diff, false otherwise.
2228 diff::reported_once(bool f) const
2230 ABG_ASSERT(priv_->canonical_diff_);
2231 priv_->canonical_diff_->priv_->reported_once_ = f;
2232 priv_->reported_once_ = f;
2235 /// Getter for the local category of the current diff tree node.
2237 /// The local category represents the set of categories of a diff
2238 /// node, not taking in account the categories inherited from its
2241 /// @return the local category of the current diff tree node.
2243 diff::get_local_category() const
2244 {return priv_->local_category_;}
2246 /// Getter of the category of the class of equivalence of the current
2249 /// That is, if the current diff tree node has a canonical node,
2250 /// return the category of that canonical node. Otherwise, return the
2251 /// category of the current node.
2253 /// @return the category of the class of equivalence of the current
2256 diff::get_class_of_equiv_category() const
2258 diff* canonical = get_canonical_diff();
2259 return canonical ? canonical->get_category() : get_category();
2262 /// Getter for the category of the current diff tree node.
2264 /// This category represents the union of the local category and the
2265 /// categories inherited from the children diff nodes.
2267 /// @return the category of the current diff tree node.
2269 diff::get_category() const
2270 {return priv_->category_;}
2272 /// Adds the current diff tree node to an additional set of
2273 /// categories. Note that the categories include thoses inherited
2274 /// from the children nodes of this diff node.
2276 /// @param c a bit-map representing the set of categories to add the
2277 /// current diff tree node to.
2279 /// @return the resulting bit-map representing the categories this
2280 /// current diff tree node belongs to, including those inherited from
2281 /// its children nodes.
2283 diff::add_to_category(diff_category c)
2285 priv_->category_ = priv_->category_ | c;
2286 return priv_->category_;
2289 /// Adds the current diff tree node to the categories resulting from
2290 /// the local changes of the current diff node.
2292 /// @param c a bit-map representing the set of categories to add the
2293 /// current diff tree node to.
2295 /// @return the resulting bit-map representing the categories this
2296 /// current diff tree node belongs to.
2298 diff::add_to_local_category(diff_category c)
2300 priv_->local_category_ = priv_->local_category_ | c;
2301 return priv_->local_category_;
2304 /// Adds the current diff tree node to the categories resulting from
2305 /// the local and inherited changes of the current diff node.
2307 /// @param c a bit-map representing the set of categories to add the
2308 /// current diff tree node to.
2310 diff::add_to_local_and_inherited_categories(diff_category c)
2312 add_to_local_category(c);
2316 /// Remove the current diff tree node from an a existing sef of
2317 /// categories. The categories include those inherited from the
2318 /// children nodes of the current diff node.
2320 /// @param c a bit-map representing the set of categories to add the
2321 /// current diff tree node to.
2323 /// @return the resulting bit-map representing the categories this
2324 /// current diff tree onde belongs to, including the categories
2325 /// inherited from the children nodes of the current diff node.
2327 diff::remove_from_category(diff_category c)
2329 priv_->category_ = priv_->category_ & ~c;
2330 return priv_->category_;
2333 /// Remove the current diff tree node from the categories resulting
2334 /// from the local changes.
2336 /// @param c a bit-map representing the set of categories to add the
2337 /// current diff tree node to.
2339 /// @return the resulting bit-map representing the categories this
2340 /// current diff tree onde belongs to.
2342 diff::remove_from_local_category(diff_category c)
2344 priv_->local_category_ = priv_->local_category_ & ~c;
2345 return priv_->local_category_;
2348 /// Set the category of the current @ref diff node. This category
2349 /// includes the categories inherited from the children nodes of the
2350 /// current diff node.
2352 /// @param c the new category for the current diff node.
2354 diff::set_category(diff_category c)
2355 {priv_->category_ = c;}
2357 /// Set the local category of the current @ref diff node.
2359 /// @param c the new category for the current diff node.
2361 diff::set_local_category(diff_category c)
2362 {priv_->local_category_ = c;}
2364 /// Test if this diff tree node is to be filtered out for reporting
2367 /// The function tests if the categories of the diff tree node are
2368 /// "forbidden" by the context or not.
2370 /// @return true iff the current diff node should NOT be reported.
2372 diff::is_filtered_out() const
2374 if (diff * canonical = get_canonical_diff())
2375 if (canonical->get_category() & SUPPRESSED_CATEGORY
2376 || canonical->get_category() & PRIVATE_TYPE_CATEGORY)
2377 // The canonical type was suppressed either by a user-provided
2378 // suppression specification or by a "private-type" suppression
2379 // specification.. This means all the class of equivalence of
2380 // that canonical type was suppressed. So this node should be
2383 return priv_->is_filtered_out(get_category());
2386 /// Test if this diff tree node is to be filtered out for reporting
2387 /// purposes, but by considering only the categories that were *NOT*
2388 /// inherited from its children nodes.
2390 /// The function tests if the local categories of the diff tree node
2391 /// are "forbidden" by the context or not.
2393 /// @return true iff the current diff node should NOT be reported,
2394 /// with respect to its local categories.
2396 diff::is_filtered_out_wrt_non_inherited_categories() const
2397 {return priv_->is_filtered_out(get_local_category());}
2399 /// Test if the current diff node has been suppressed by a
2400 /// user-provided suppression specification.
2402 /// @return true if the current diff node has been suppressed by a
2403 /// user-provided suppression list.
2405 diff::is_suppressed() const
2407 bool is_private = false;
2408 return is_suppressed(is_private);
2411 /// Test if the current diff node has been suppressed by a
2412 /// user-provided suppression specification or by an auto-generated
2413 /// "private type" suppression specification.
2415 /// Note that private type suppressions are auto-generated from the
2416 /// path to where public headers are, as given by the user.
2418 /// @param is_private_type out parameter if the current diff node was
2419 /// suppressed because it's a private type then this parameter is set
2422 /// @return true if the current diff node has been suppressed by a
2423 /// user-provided suppression list.
2425 diff::is_suppressed(bool &is_private_type) const
2427 const suppressions_type& suppressions = context()->suppressions();
2428 for (suppressions_type::const_iterator i = suppressions.begin();
2429 i != suppressions.end();
2432 if ((*i)->suppresses_diff(this))
2434 if (is_private_type_suppr_spec(*i))
2435 is_private_type = true;
2442 /// Test if this diff tree node should be reported.
2444 /// @return true iff the current node should be reported.
2446 diff::to_be_reported() const
2448 if (has_changes() && !is_filtered_out())
2453 /// Test if this diff tree node should be reported when considering
2454 /// the categories that were *NOT* inherited from its children nodes.
2456 /// @return true iff the current node should be reported.
2458 diff::has_local_changes_to_be_reported() const
2460 if (has_local_changes()
2461 && !is_filtered_out_wrt_non_inherited_categories())
2466 /// Get a pretty representation of the current @ref diff node.
2468 /// This is suitable for e.g. emitting debugging traces for the diff
2471 /// @return the pretty representation of the diff node.
2473 diff::get_pretty_representation() const
2475 if (priv_->pretty_representation_.empty())
2476 priv_->pretty_representation_ = "empty_diff";
2477 return priv_->pretty_representation_;
2480 /// Default implementation of the hierachy chaining virtual function.
2482 /// There are several types of diff nodes that have logical children
2483 /// nodes; for instance, a typedef_diff has the diff of the underlying
2484 /// type as a child node. A var_diff has the diff of the types of the
2485 /// variables as a child node, etc.
2487 /// But because the @ref diff base has a generic representation for
2488 /// children nodes of the all the types of @ref diff nodes (regardless
2489 /// of the specific most-derived type of diff node) that one can get
2490 /// using the method diff::children_nodes(), one need to populate that
2491 /// vector of children node.
2493 /// Populating that vector of children node is done by this function;
2494 /// it must be overloaded by each most-derived type of diff node that
2495 /// extends the @ref diff type.
2497 diff::chain_into_hierarchy()
2502 // <type_diff_base stuff>
2504 type_diff_base::type_diff_base(type_base_sptr first_subject,
2505 type_base_sptr second_subject,
2506 diff_context_sptr ctxt)
2507 : diff(first_subject, second_subject, ctxt),
2511 type_diff_base::~type_diff_base()
2513 // </type_diff_base stuff>
2515 // <decl_diff_base stuff>
2517 /// Constructor of @ref decl_diff_base.
2519 /// @param first_subject the first subject of the diff.
2521 /// @param second_subject the second subject of the diff.
2523 /// @param ctxt the context of the diff. This object must stay alive
2524 /// at least during the life time of the current instance of @ref
2525 /// decl_diff_base, otherwise, memory corruption issues occur.
2526 decl_diff_base::decl_diff_base(decl_base_sptr first_subject,
2527 decl_base_sptr second_subject,
2528 diff_context_sptr ctxt)
2529 : diff(first_subject, second_subject, ctxt),
2533 decl_diff_base::~decl_diff_base()
2536 // </decl_diff_base stuff>
2538 // <distinct_diff stuff>
2540 /// @return a pretty representation for the @ref distinct_diff node.
2542 distinct_diff::get_pretty_representation() const
2544 if (diff::priv_->pretty_representation_.empty())
2546 std::ostringstream o;
2547 o << "distinct_diff[";
2548 if (first_subject())
2549 o << first_subject()->get_pretty_representation();
2553 if (second_subject())
2554 o << second_subject()->get_pretty_representation() ;
2558 diff::priv_->pretty_representation_ = o.str();
2560 return diff::priv_->pretty_representation_;
2563 /// Populate the vector of children node of the @ref diff base type
2564 /// sub-object of this instance of @distinct_diff.
2566 /// The children nodes can then later be retrieved using
2567 /// diff::children_nodes().
2569 distinct_diff::chain_into_hierarchy()
2571 ABG_ASSERT(entities_are_of_distinct_kinds(first(), second()));
2573 if (diff_sptr d = compatible_child_diff())
2574 append_child_node(d);
2577 /// Constructor for @ref distinct_diff.
2579 /// Note that the two entities considered for the diff (and passed in
2580 /// parameter) must be of different kinds.
2582 /// @param first the first entity to consider for the diff.
2584 /// @param second the second entity to consider for the diff.
2586 /// @param ctxt the context of the diff. Note that this context
2587 /// object must stay alive at least during the life time of the
2588 /// current instance of @ref distinct_diff. Otherwise memory
2589 /// corruption issues occur.
2590 distinct_diff::distinct_diff(type_or_decl_base_sptr first,
2591 type_or_decl_base_sptr second,
2592 diff_context_sptr ctxt)
2593 : diff(first, second, ctxt),
2595 {ABG_ASSERT(entities_are_of_distinct_kinds(first, second));}
2597 /// Finish building the current instance of @ref distinct_diff.
2599 distinct_diff::finish_diff_type()
2601 if (diff::priv_->finished_)
2604 chain_into_hierarchy();
2605 diff::priv_->finished_ = true;
2608 /// Getter for the first subject of the diff.
2610 /// @return the first subject of the diff.
2611 const type_or_decl_base_sptr
2612 distinct_diff::first() const
2613 {return first_subject();}
2615 /// Getter for the second subject of the diff.
2617 /// @return the second subject of the diff.
2618 const type_or_decl_base_sptr
2619 distinct_diff::second() const
2620 {return second_subject();}
2622 /// Getter for the child diff of this distinct_diff instance.
2624 /// When a distinct_diff has two subjects that are different but
2625 /// compatible, then the distinct_diff instance has a child diff node
2626 /// (named the compatible child diff) that is the diff between the two
2627 /// subjects stripped from their typedefs. Otherwise, the compatible
2628 /// child diff is nul.
2630 /// Note that two diff subjects (that compare different) are
2631 /// considered compatible if stripping typedefs out of them makes them
2632 /// comparing equal.
2634 /// @return the compatible child diff node, if any. Otherwise, null.
2636 distinct_diff::compatible_child_diff() const
2638 if (!priv_->compatible_child_diff)
2640 type_base_sptr fs = strip_typedef(is_type(first())),
2641 ss = strip_typedef(is_type(second()));
2644 && !entities_are_of_distinct_kinds(get_type_declaration(fs),
2645 get_type_declaration(ss)))
2646 priv_->compatible_child_diff = compute_diff(get_type_declaration(fs),
2647 get_type_declaration(ss),
2650 return priv_->compatible_child_diff;
2653 /// Test if the two arguments are of different kind, or that are both
2656 /// @param first the first argument to test for similarity in kind.
2658 /// @param second the second argument to test for similarity in kind.
2660 /// @return true iff the two arguments are of different kind.
2662 distinct_diff::entities_are_of_distinct_kinds(type_or_decl_base_sptr first,
2663 type_or_decl_base_sptr second)
2665 if (!!first != !!second)
2667 if (!first && !second)
2668 // We do consider diffs of two empty decls as a diff of distinct
2671 if (first == second)
2674 const type_or_decl_base &f = *first, &s = *second;
2675 return typeid(f) != typeid(s);
2678 /// @return true if the two subjects of the diff are different, false
2681 distinct_diff::has_changes() const
2682 {return first() != second();}
2684 /// @return the kind of local change carried by the current diff node.
2685 /// The value returned is zero if the current node carries no local
2688 distinct_diff::has_local_changes() const
2690 // Changes on a distinct_diff are all local.
2692 return (LOCAL_CHANGE_KIND | LOCAL_TYPE_CHANGE_KIND);
2693 return NO_CHANGE_KIND;
2696 /// Emit a report about the current diff instance.
2698 /// @param out the output stream to send the diff report to.
2700 /// @param indent the indentation string to use in the report.
2702 distinct_diff::report(ostream& out, const string& indent) const
2704 context()->get_reporter()->report(*this, out, indent);
2707 /// Try to diff entities that are of distinct kinds.
2709 /// @param first the first entity to consider for the diff.
2711 /// @param second the second entity to consider for the diff.
2713 /// @param ctxt the context of the diff.
2715 /// @return a non-null diff if a diff object could be built, null
2718 compute_diff_for_distinct_kinds(const type_or_decl_base_sptr first,
2719 const type_or_decl_base_sptr second,
2720 diff_context_sptr ctxt)
2722 if (!distinct_diff::entities_are_of_distinct_kinds(first, second))
2723 return distinct_diff_sptr();
2725 distinct_diff_sptr result(new distinct_diff(first, second, ctxt));
2727 ctxt->initialize_canonical_diff(result);
2732 /// </distinct_diff stuff>
2734 /// Try to compute a diff on two instances of DiffType representation.
2736 /// The function template performs the diff if and only if the decl
2737 /// representations are of a DiffType.
2739 /// @tparm DiffType the type of instances to diff.
2741 /// @param first the first representation of decl to consider in the
2742 /// diff computation.
2744 /// @param second the second representation of decl to consider in the
2745 /// diff computation.
2747 /// @param ctxt the diff context to use.
2749 ///@return the diff of the two types @p first and @p second if and
2750 ///only if they represent the parametrized type DiffType. Otherwise,
2751 ///returns a NULL pointer value.
2752 template<typename DiffType>
2754 try_to_diff(const type_or_decl_base_sptr first,
2755 const type_or_decl_base_sptr second,
2756 diff_context_sptr ctxt)
2758 if (shared_ptr<DiffType> f =
2759 dynamic_pointer_cast<DiffType>(first))
2761 shared_ptr<DiffType> s =
2762 dynamic_pointer_cast<DiffType>(second);
2765 return compute_diff(f, s, ctxt);
2771 /// This is a specialization of @ref try_to_diff() template to diff
2772 /// instances of @ref class_decl.
2774 /// @param first the first representation of decl to consider in the
2775 /// diff computation.
2777 /// @param second the second representation of decl to consider in the
2778 /// diff computation.
2780 /// @param ctxt the diff context to use.
2783 try_to_diff<class_decl>(const type_or_decl_base_sptr first,
2784 const type_or_decl_base_sptr second,
2785 diff_context_sptr ctxt)
2787 if (class_decl_sptr f =
2788 dynamic_pointer_cast<class_decl>(first))
2790 class_decl_sptr s = dynamic_pointer_cast<class_decl>(second);
2794 if (f->get_is_declaration_only())
2796 class_decl_sptr f2 = f->get_definition_of_declaration();
2800 if (s->get_is_declaration_only())
2802 class_decl_sptr s2 = s->get_definition_of_declaration();
2806 return compute_diff(f, s, ctxt);
2811 /// Try to diff entities that are of distinct kinds.
2813 /// @param first the first entity to consider for the diff.
2815 /// @param second the second entity to consider for the diff.
2817 /// @param ctxt the context of the diff.
2819 /// @return a non-null diff if a diff object could be built, null
2822 try_to_diff_distinct_kinds(const type_or_decl_base_sptr first,
2823 const type_or_decl_base_sptr second,
2824 diff_context_sptr ctxt)
2825 {return compute_diff_for_distinct_kinds(first, second, ctxt);}
2827 /// Compute the difference between two types.
2829 /// The function considers every possible types known to libabigail
2830 /// and runs the appropriate diff function on them.
2832 /// Whenever a new kind of type decl is supported by abigail, if we
2833 /// want to be able to diff two instances of it, we need to update
2834 /// this function to support it.
2836 /// @param first the first type decl to consider for the diff
2838 /// @param second the second type decl to consider for the diff.
2840 /// @param ctxt the diff context to use.
2842 /// @return the resulting diff. It's a pointer to a descendent of
2843 /// abigail::comparison::diff.
2845 compute_diff_for_types(const type_or_decl_base_sptr& first,
2846 const type_or_decl_base_sptr& second,
2847 const diff_context_sptr& ctxt)
2849 type_or_decl_base_sptr f = first;
2850 type_or_decl_base_sptr s = second;
2852 // Look through no-op qualified types.
2853 f = look_through_no_op_qualified_type(is_type(f));
2854 s = look_through_no_op_qualified_type(is_type(s));
2858 ((d = try_to_diff<type_decl>(f, s, ctxt))
2859 ||(d = try_to_diff<enum_type_decl>(f, s, ctxt))
2860 ||(d = try_to_diff<union_decl>(f, s,ctxt))
2861 ||(d = try_to_diff<class_decl>(f, s,ctxt))
2862 ||(d = try_to_diff<pointer_type_def>(f, s, ctxt))
2863 ||(d = try_to_diff<reference_type_def>(f, s, ctxt))
2864 ||(d = try_to_diff<array_type_def>(f, s, ctxt))
2865 ||(d = try_to_diff<qualified_type_def>(f, s, ctxt))
2866 ||(d = try_to_diff<typedef_decl>(f, s, ctxt))
2867 ||(d = try_to_diff<function_type>(f, s, ctxt))
2868 ||(d = try_to_diff_distinct_kinds(f, s, ctxt)));
2876 operator|(diff_category c1, diff_category c2)
2877 {return static_cast<diff_category>(static_cast<unsigned>(c1)
2878 | static_cast<unsigned>(c2));}
2881 operator|=(diff_category& c1, diff_category c2)
2888 operator&=(diff_category& c1, diff_category c2)
2895 operator^(diff_category c1, diff_category c2)
2896 {return static_cast<diff_category>(static_cast<unsigned>(c1)
2897 ^ static_cast<unsigned>(c2));}
2900 operator&(diff_category c1, diff_category c2)
2901 {return static_cast<diff_category>(static_cast<unsigned>(c1)
2902 & static_cast<unsigned>(c2));}
2905 operator~(diff_category c)
2906 {return static_cast<diff_category>(~static_cast<unsigned>(c));}
2909 /// Getter of a bitmap made of the set of change categories that are
2910 /// considered harmless.
2912 /// @return the bitmap made of the set of change categories that are
2913 /// considered harmless.
2915 get_default_harmless_categories_bitmap()
2917 return (abigail::comparison::ACCESS_CHANGE_CATEGORY
2918 | abigail::comparison::COMPATIBLE_TYPE_CHANGE_CATEGORY
2919 | abigail::comparison::HARMLESS_DECL_NAME_CHANGE_CATEGORY
2920 | abigail::comparison::NON_VIRT_MEM_FUN_CHANGE_CATEGORY
2921 | abigail::comparison::STATIC_DATA_MEMBER_CHANGE_CATEGORY
2922 | abigail::comparison::HARMLESS_ENUM_CHANGE_CATEGORY
2923 | abigail::comparison::HARMLESS_SYMBOL_ALIAS_CHANGE_CATEORY
2924 | abigail::comparison::HARMLESS_UNION_CHANGE_CATEGORY
2925 | abigail::comparison::CLASS_DECL_ONLY_DEF_CHANGE_CATEGORY
2926 | abigail::comparison::FN_PARM_TYPE_TOP_CV_CHANGE_CATEGORY
2927 | abigail::comparison::FN_PARM_TYPE_CV_CHANGE_CATEGORY
2928 | abigail::comparison::FN_RETURN_TYPE_CV_CHANGE_CATEGORY
2929 | abigail::comparison::VAR_TYPE_CV_CHANGE_CATEGORY
2930 | abigail::comparison::VOID_PTR_TO_PTR_CHANGE_CATEGORY
2931 | abigail::comparison::BENIGN_INFINITE_ARRAY_CHANGE_CATEGORY);
2934 /// Getter of a bitmap made of the set of change categories that are
2935 /// considered harmful.
2937 /// @return the bitmap made of the set of change categories that are
2938 /// considered harmful.
2940 get_default_harmful_categories_bitmap()
2942 return (abigail::comparison::SIZE_OR_OFFSET_CHANGE_CATEGORY
2943 | abigail::comparison::VIRTUAL_MEMBER_CHANGE_CATEGORY);
2946 /// Serialize an instance of @ref diff_category to an output stream.
2948 /// @param o the output stream to serialize @p c to.
2950 /// @param c the instance of diff_category to serialize.
2952 /// @return the output stream to serialize @p c to.
2954 operator<<(ostream& o, diff_category c)
2956 bool emitted_a_category = false;
2958 if (c == NO_CHANGE_CATEGORY)
2960 o << "NO_CHANGE_CATEGORY";
2961 emitted_a_category = true;
2964 if (c & ACCESS_CHANGE_CATEGORY)
2966 if (emitted_a_category)
2968 o << "ACCESS_CHANGE_CATEGORY";
2969 emitted_a_category |= true;
2972 if (c & COMPATIBLE_TYPE_CHANGE_CATEGORY)
2974 if (emitted_a_category)
2976 o << "COMPATIBLE_TYPE_CHANGE_CATEGORY";
2977 emitted_a_category |= true;
2980 if (c & HARMLESS_DECL_NAME_CHANGE_CATEGORY)
2982 if (emitted_a_category)
2984 o << "HARMLESS_DECL_NAME_CHANGE_CATEGORY";
2985 emitted_a_category |= true;
2988 if (c & NON_VIRT_MEM_FUN_CHANGE_CATEGORY)
2990 if (emitted_a_category)
2992 o << "NON_VIRT_MEM_FUN_CHANGE_CATEGORY";
2993 emitted_a_category |= true;
2996 if (c & STATIC_DATA_MEMBER_CHANGE_CATEGORY)
2998 if (emitted_a_category)
3000 o << "STATIC_DATA_MEMBER_CHANGE_CATEGORY";
3001 emitted_a_category |= true;
3004 if (c & HARMLESS_ENUM_CHANGE_CATEGORY)
3006 if (emitted_a_category)
3008 o << "HARMLESS_ENUM_CHANGE_CATEGORY";
3009 emitted_a_category |= true;
3012 if (c & HARMLESS_SYMBOL_ALIAS_CHANGE_CATEORY)
3014 if (emitted_a_category)
3016 o << "HARMLESS_SYMBOL_ALIAS_CHANGE_CATEORY";
3017 emitted_a_category |= true;
3020 if (c & HARMLESS_UNION_CHANGE_CATEGORY)
3022 if (emitted_a_category)
3024 o << "HARMLESS_UNION_CHANGE_CATEORY";
3025 emitted_a_category |= true;
3028 if (c & SUPPRESSED_CATEGORY)
3030 if (emitted_a_category)
3032 o << "SUPPRESSED_CATEGORY";
3033 emitted_a_category |= true;
3036 if (c & PRIVATE_TYPE_CATEGORY)
3038 if (emitted_a_category)
3040 o << "PRIVATE_TYPE_CATEGORY";
3041 emitted_a_category |= true;
3044 if (c & SIZE_OR_OFFSET_CHANGE_CATEGORY)
3046 if (emitted_a_category)
3048 o << "SIZE_OR_OFFSET_CHANGE_CATEGORY";
3049 emitted_a_category |= true;
3052 if (c & VIRTUAL_MEMBER_CHANGE_CATEGORY)
3054 if (emitted_a_category)
3056 o << "VIRTUAL_MEMBER_CHANGE_CATEGORY";
3057 emitted_a_category |= true;
3060 if (c & REDUNDANT_CATEGORY)
3062 if (emitted_a_category)
3064 o << "REDUNDANT_CATEGORY";
3065 emitted_a_category |= true;
3068 if (c & CLASS_DECL_ONLY_DEF_CHANGE_CATEGORY)
3070 if (emitted_a_category)
3072 o << "CLASS_DECL_ONLY_DEF_CHANGE_CATEGORY";
3073 emitted_a_category |= true;
3076 if (c & FN_PARM_TYPE_TOP_CV_CHANGE_CATEGORY)
3078 if (emitted_a_category)
3080 o << "FN_PARM_TYPE_TOP_CV_CHANGE_CATEGORY";
3081 emitted_a_category |= true;
3084 if (c & FN_PARM_TYPE_CV_CHANGE_CATEGORY)
3086 if (emitted_a_category)
3088 o << "FN_PARM_TYPE_CV_CHANGE_CATEGORY";
3089 emitted_a_category |= true;
3092 if (c & FN_RETURN_TYPE_CV_CHANGE_CATEGORY)
3094 if (emitted_a_category)
3096 o << "FN_RETURN_TYPE_CV_CHANGE_CATEGORY";
3097 emitted_a_category |= true;
3100 if (c & VAR_TYPE_CV_CHANGE_CATEGORY)
3102 if (emitted_a_category)
3104 o << "VAR_TYPE_CV_CHANGE_CATEGORY";
3105 emitted_a_category |= true;
3108 if (c & VOID_PTR_TO_PTR_CHANGE_CATEGORY)
3110 if (emitted_a_category)
3112 o << "VOID_PTR_TO_PTR_CHANGE_CATEGORY";
3113 emitted_a_category |= true;
3116 if (c & BENIGN_INFINITE_ARRAY_CHANGE_CATEGORY)
3118 if (emitted_a_category)
3120 o << "BENIGN_INFINITE_ARRAY_CHANGE_CATEGORY";
3121 emitted_a_category |= true;
3127 /// Compute the difference between two decls.
3129 /// The function consider every possible decls known to libabigail and
3130 /// runs the appropriate diff function on them.
3132 /// Whenever a new kind of non-type decl is supported by abigail, if
3133 /// we want to be able to diff two instances of it, we need to update
3134 /// this function to support it.
3136 /// @param first the first decl to consider for the diff
3138 /// @param second the second decl to consider for the diff.
3140 /// @param ctxt the diff context to use.
3142 /// @return the resulting diff.
3144 compute_diff_for_decls(const decl_base_sptr first,
3145 const decl_base_sptr second,
3146 diff_context_sptr ctxt)
3151 ((d = try_to_diff<function_decl>(first, second, ctxt))
3152 || (d = try_to_diff<var_decl>(first, second, ctxt))
3153 || (d = try_to_diff_distinct_kinds(first, second, ctxt)));
3160 /// Compute the difference between two decls. The decls can represent
3161 /// either type declarations, or non-type declaration.
3163 /// Note that the two decls must have been created in the same @ref
3164 /// environment, otherwise, this function aborts.
3166 /// @param first the first decl to consider.
3168 /// @param second the second decl to consider.
3170 /// @param ctxt the diff context to use.
3172 /// @return the resulting diff, or NULL if the diff could not be
3175 compute_diff(const decl_base_sptr first,
3176 const decl_base_sptr second,
3177 diff_context_sptr ctxt)
3179 if (!first || !second)
3182 ABG_ASSERT(first->get_environment() == second->get_environment());
3185 if (is_type(first) && is_type(second))
3186 d = compute_diff_for_types(first, second, ctxt);
3188 d = compute_diff_for_decls(first, second, ctxt);
3193 /// Compute the difference between two types.
3195 /// Note that the two types must have been created in the same @ref
3196 /// environment, otherwise, this function aborts.
3198 /// @param first the first type to consider.
3200 /// @param second the second type to consider.
3202 /// @param ctxt the diff context to use.
3204 /// @return the resulting diff, or NULL if the diff couldn't be
3207 compute_diff(const type_base_sptr first,
3208 const type_base_sptr second,
3209 diff_context_sptr ctxt)
3211 decl_base_sptr f = get_type_declaration(first),
3212 s = get_type_declaration(second);
3214 if (first && second)
3215 ABG_ASSERT(first->get_environment() == second->get_environment());
3217 diff_sptr d = compute_diff_for_types(f,s, ctxt);
3222 /// Get a copy of the pretty representation of a diff node.
3224 /// @param d the diff node to consider.
3226 /// @return the pretty representation string.
3228 get_pretty_representation(diff* d)
3232 string prefix= "diff of ";
3233 return prefix + get_pretty_representation(d->first_subject());
3238 /// Populate the vector of children node of the @ref diff base type
3239 /// sub-object of this instance of @ref var_diff.
3241 /// The children node can then later be retrieved using
3242 /// diff::children_node().
3244 var_diff::chain_into_hierarchy()
3245 {append_child_node(type_diff());}
3247 /// @return the pretty representation for this current instance of
3250 var_diff::get_pretty_representation() const
3252 if (diff::priv_->pretty_representation_.empty())
3254 std::ostringstream o;
3256 << first_subject()->get_pretty_representation()
3258 << second_subject()->get_pretty_representation()
3260 diff::priv_->pretty_representation_ = o.str();
3262 return diff::priv_->pretty_representation_;
3264 /// Constructor for @ref var_diff.
3266 /// @param first the first instance of @ref var_decl to consider in
3269 /// @param second the second instance of @ref var_decl to consider in
3272 /// @param type_diff the diff between types of the instances of
3275 /// @param ctxt the diff context to use.
3276 var_diff::var_diff(var_decl_sptr first,
3277 var_decl_sptr second,
3278 diff_sptr type_diff,
3279 diff_context_sptr ctxt)
3280 : decl_diff_base(first, second, ctxt),
3282 {priv_->type_diff_ = type_diff;}
3284 /// Finish building the current instance of @ref var_diff.
3286 var_diff::finish_diff_type()
3288 if (diff::priv_->finished_)
3290 chain_into_hierarchy();
3291 diff::priv_->finished_ = true;
3294 /// Getter for the first @ref var_decl of the diff.
3296 /// @return the first @ref var_decl of the diff.
3298 var_diff::first_var() const
3299 {return dynamic_pointer_cast<var_decl>(first_subject());}
3301 /// Getter for the second @ref var_decl of the diff.
3303 /// @return the second @ref var_decl of the diff.
3305 var_diff::second_var() const
3306 {return dynamic_pointer_cast<var_decl>(second_subject());}
3308 /// Getter for the diff of the types of the instances of @ref
3311 /// @return the diff of the types of the instances of @ref var_decl.
3313 var_diff::type_diff() const
3315 if (priv_->type_diff_.expired())
3317 diff_sptr d = compute_diff(first_var()->get_type(),
3318 second_var()->get_type(),
3320 context()->keep_diff_alive(d);
3321 priv_->type_diff_ = d;
3323 return diff_sptr(priv_->type_diff_);
3326 /// Return true iff the diff node has a change.
3328 /// @return true iff the diff node has a change.
3330 var_diff::has_changes() const
3331 {return *first_var() != *second_var();}
3333 /// @return the kind of local change carried by the current diff node.
3334 /// The value returned is zero if the current node carries no local
3337 var_diff::has_local_changes() const
3339 ir::change_kind k = ir::NO_CHANGE_KIND;
3340 if (!equals(*first_var(), *second_var(), &k))
3341 return k & ir::ALL_LOCAL_CHANGES_MASK;
3342 return ir::NO_CHANGE_KIND;
3345 /// Report the diff in a serialized form.
3347 /// @param out the stream to serialize the diff to.
3349 /// @param indent the prefix to use for the indentation of this
3352 var_diff::report(ostream& out, const string& indent) const
3354 context()->get_reporter()->report(*this, out, indent);
3357 /// Compute the diff between two instances of @ref var_decl.
3359 /// Note that the two decls must have been created in the same @ref
3360 /// environment, otherwise, this function aborts.
3362 /// @param first the first @ref var_decl to consider for the diff.
3364 /// @param second the second @ref var_decl to consider for the diff.
3366 /// @param ctxt the diff context to use.
3368 /// @return the resulting diff between the two @ref var_decl.
3370 compute_diff(const var_decl_sptr first,
3371 const var_decl_sptr second,
3372 diff_context_sptr ctxt)
3374 if (first && second)
3375 ABG_ASSERT(first->get_environment() == second->get_environment());
3377 var_diff_sptr d(new var_diff(first, second, diff_sptr(), ctxt));
3378 ctxt->initialize_canonical_diff(d);
3383 // </var_diff stuff>
3385 // <pointer_type_def stuff>
3387 /// Populate the vector of children node of the @ref diff base type
3388 /// sub-object of this instance of @ref pointer_diff.
3390 /// The children node can then later be retrieved using
3391 /// diff::children_node().
3393 pointer_diff::chain_into_hierarchy()
3394 {append_child_node(underlying_type_diff());}
3396 /// Constructor for a pointer_diff.
3398 /// @param first the first pointer to consider for the diff.
3400 /// @param second the secon pointer to consider for the diff.
3402 /// @param ctxt the diff context to use.
3403 pointer_diff::pointer_diff(pointer_type_def_sptr first,
3404 pointer_type_def_sptr second,
3405 diff_sptr underlying,
3406 diff_context_sptr ctxt)
3407 : type_diff_base(first, second, ctxt),
3408 priv_(new priv(underlying))
3411 /// Finish building the current instance of @ref pointer_diff.
3413 pointer_diff::finish_diff_type()
3415 if (diff::priv_->finished_)
3417 chain_into_hierarchy();
3418 diff::priv_->finished_ = true;
3421 /// Getter for the first subject of a pointer diff
3423 /// @return the first pointer considered in this pointer diff.
3424 const pointer_type_def_sptr
3425 pointer_diff::first_pointer() const
3426 {return dynamic_pointer_cast<pointer_type_def>(first_subject());}
3428 /// Getter for the second subject of a pointer diff
3430 /// @return the second pointer considered in this pointer diff.
3431 const pointer_type_def_sptr
3432 pointer_diff::second_pointer() const
3433 {return dynamic_pointer_cast<pointer_type_def>(second_subject());}
3435 /// @return the pretty represenation for the current instance of @ref
3438 pointer_diff::get_pretty_representation() const
3440 if (diff::priv_->pretty_representation_.empty())
3442 std::ostringstream o;
3443 o << "pointer_diff["
3444 << first_subject()->get_pretty_representation()
3446 << second_subject()->get_pretty_representation()
3448 diff::priv_->pretty_representation_ = o.str();
3450 return diff::priv_->pretty_representation_;
3453 /// Return true iff the current diff node carries a change.
3455 /// @return true iff the current diff node carries a change.
3457 pointer_diff::has_changes() const
3458 {return first_pointer() != second_pointer();}
3460 /// @return the kind of local change carried by the current diff node.
3461 /// The value returned is zero if the current node carries no local
3464 pointer_diff::has_local_changes() const
3466 ir::change_kind k = ir::NO_CHANGE_KIND;
3467 if (!equals(*first_pointer(), *second_pointer(), &k))
3468 return k & ir::ALL_LOCAL_CHANGES_MASK;
3469 return ir::NO_CHANGE_KIND;
3472 /// Getter for the diff between the pointed-to types of the pointers
3475 /// @return the diff between the pointed-to types.
3477 pointer_diff::underlying_type_diff() const
3478 {return priv_->underlying_type_diff_;}
3480 /// Setter for the diff between the pointed-to types of the pointers
3483 /// @param d the new diff between the pointed-to types of the pointers
3486 pointer_diff::underlying_type_diff(const diff_sptr d)
3487 {priv_->underlying_type_diff_ = d;}
3489 /// Report the diff in a serialized form.
3491 /// @param out the stream to serialize the diff to.
3493 /// @param indent the prefix to use for the indentation of this
3496 pointer_diff::report(ostream& out, const string& indent) const
3498 context()->get_reporter()->report(*this, out, indent);
3501 /// Compute the diff between between two pointers.
3503 /// Note that the two types must have been created in the same @ref
3504 /// environment, otherwise, this function aborts.
3506 /// @param first the pointer to consider for the diff.
3508 /// @param second the pointer to consider for the diff.
3510 /// @return the resulting diff between the two pointers.
3512 /// @param ctxt the diff context to use.
3514 compute_diff(pointer_type_def_sptr first,
3515 pointer_type_def_sptr second,
3516 diff_context_sptr ctxt)
3518 if (first && second)
3519 ABG_ASSERT(first->get_environment() == second->get_environment());
3521 diff_sptr d = compute_diff_for_types(first->get_pointed_to_type(),
3522 second->get_pointed_to_type(),
3524 pointer_diff_sptr result(new pointer_diff(first, second, d, ctxt));
3525 ctxt->initialize_canonical_diff(result);
3530 // </pointer_type_def>
3534 /// Populate the vector of children node of the @ref diff base type
3535 /// sub-object of this instance of @ref array_diff.
3537 /// The children node can then later be retrieved using
3538 /// diff::children_node().
3540 array_diff::chain_into_hierarchy()
3541 {append_child_node(element_type_diff());}
3543 /// Constructor for array_diff
3545 /// @param first the first array_type of the diff.
3547 /// @param second the second array_type of the diff.
3549 /// @param element_type_diff the diff between the two array element
3552 /// @param ctxt the diff context to use.
3553 array_diff::array_diff(const array_type_def_sptr first,
3554 const array_type_def_sptr second,
3555 diff_sptr element_type_diff,
3556 diff_context_sptr ctxt)
3557 : type_diff_base(first, second, ctxt),
3558 priv_(new priv(element_type_diff))
3561 /// Finish building the current instance of @ref array_diff.
3563 array_diff::finish_diff_type()
3565 if (diff::priv_->finished_)
3567 chain_into_hierarchy();
3568 diff::priv_->finished_ = true;
3571 /// Getter for the first array of the diff.
3573 /// @return the first array of the diff.
3574 const array_type_def_sptr
3575 array_diff::first_array() const
3576 {return dynamic_pointer_cast<array_type_def>(first_subject());}
3578 /// Getter for the second array of the diff.
3580 /// @return for the second array of the diff.
3581 const array_type_def_sptr
3582 array_diff::second_array() const
3583 {return dynamic_pointer_cast<array_type_def>(second_subject());}
3585 /// Getter for the diff between the two types of array elements.
3587 /// @return the diff between the two types of array elements.
3589 array_diff::element_type_diff() const
3590 {return priv_->element_type_diff_;}
3592 /// Setter for the diff between the two array element types.
3594 /// @param d the new diff betweend the two array element types.
3596 array_diff::element_type_diff(diff_sptr d)
3597 {priv_->element_type_diff_ = d;}
3599 /// @return the pretty representation for the current instance of @ref
3602 array_diff::get_pretty_representation() const
3604 if (diff::priv_->pretty_representation_.empty())
3606 std::ostringstream o;
3608 << first_subject()->get_pretty_representation()
3610 << second_subject()->get_pretty_representation()
3612 diff::priv_->pretty_representation_ = o.str();
3614 return diff::priv_->pretty_representation_;
3617 /// Return true iff the current diff node carries a change.
3619 /// @return true iff the current diff node carries a change.
3621 array_diff::has_changes() const
3625 // the array element types match check for differing dimensions
3628 f = dynamic_pointer_cast<array_type_def>(first_subject()),
3629 s = dynamic_pointer_cast<array_type_def>(second_subject());
3631 if (f->get_name() != s->get_name())
3633 if (f->get_size_in_bits() != s->get_size_in_bits())
3635 if (f->get_alignment_in_bits() != s->get_alignment_in_bits())
3638 l |= element_type_diff()
3639 ? element_type_diff()->has_changes()
3646 /// @return the kind of local change carried by the current diff node.
3647 /// The value returned is zero if the current node carries no local
3650 array_diff::has_local_changes() const
3652 ir::change_kind k = ir::NO_CHANGE_KIND;
3653 if (!equals(*first_array(), *second_array(), &k))
3654 return k & ir::ALL_LOCAL_CHANGES_MASK;
3655 return ir::NO_CHANGE_KIND;;
3658 /// Report the diff in a serialized form.
3660 /// @param out the output stream to serialize the dif to.
3662 /// @param indent the string to use for indenting the report.
3664 array_diff::report(ostream& out, const string& indent) const
3666 context()->get_reporter()->report(*this, out, indent);
3669 /// Compute the diff between two arrays.
3671 /// Note that the two types must have been created in the same @ref
3672 /// environment, otherwise, this function aborts.
3674 /// @param first the first array to consider for the diff.
3676 /// @param second the second array to consider for the diff.
3678 /// @param ctxt the diff context to use.
3680 compute_diff(array_type_def_sptr first,
3681 array_type_def_sptr second,
3682 diff_context_sptr ctxt)
3684 if (first && second)
3685 ABG_ASSERT(first->get_environment() == second->get_environment());
3687 diff_sptr d = compute_diff_for_types(first->get_element_type(),
3688 second->get_element_type(),
3690 array_diff_sptr result(new array_diff(first, second, d, ctxt));
3691 ctxt->initialize_canonical_diff(result);
3694 // </array_type_def>
3696 // <reference_type_def>
3698 /// Populate the vector of children node of the @ref diff base type
3699 /// sub-object of this instance of @ref reference_diff.
3701 /// The children node can then later be retrieved using
3702 /// diff::children_node().
3704 reference_diff::chain_into_hierarchy()
3705 {append_child_node(underlying_type_diff());}
3707 /// Constructor for reference_diff
3709 /// @param first the first reference_type of the diff.
3711 /// @param second the second reference_type of the diff.
3713 /// @param ctxt the diff context to use.
3714 reference_diff::reference_diff(const reference_type_def_sptr first,
3715 const reference_type_def_sptr second,
3716 diff_sptr underlying,
3717 diff_context_sptr ctxt)
3718 : type_diff_base(first, second, ctxt),
3719 priv_(new priv(underlying))
3722 /// Finish building the current instance of @ref reference_diff.
3724 reference_diff::finish_diff_type()
3726 if (diff::priv_->finished_)
3728 chain_into_hierarchy();
3729 diff::priv_->finished_ = true;
3732 /// Getter for the first reference of the diff.
3734 /// @return the first reference of the diff.
3735 reference_type_def_sptr
3736 reference_diff::first_reference() const
3737 {return dynamic_pointer_cast<reference_type_def>(first_subject());}
3739 /// Getter for the second reference of the diff.
3741 /// @return for the second reference of the diff.
3742 reference_type_def_sptr
3743 reference_diff::second_reference() const
3744 {return dynamic_pointer_cast<reference_type_def>(second_subject());}
3747 /// Getter for the diff between the two referred-to types.
3749 /// @return the diff between the two referred-to types.
3751 reference_diff::underlying_type_diff() const
3752 {return priv_->underlying_type_diff_;}
3754 /// Setter for the diff between the two referred-to types.
3756 /// @param d the new diff betweend the two referred-to types.
3758 reference_diff::underlying_type_diff(diff_sptr d)
3760 priv_->underlying_type_diff_ = d;
3761 return priv_->underlying_type_diff_;
3764 /// @return the pretty representation for the current instance of @ref
3767 reference_diff::get_pretty_representation() const
3769 if (diff::priv_->pretty_representation_.empty())
3771 std::ostringstream o;
3772 o << "reference_diff["
3773 << first_subject()->get_pretty_representation()
3775 << second_subject()->get_pretty_representation()
3777 diff::priv_->pretty_representation_ = o.str();
3779 return diff::priv_->pretty_representation_;
3782 /// Return true iff the current diff node carries a change.
3784 /// @return true iff the current diff node carries a change.
3786 reference_diff::has_changes() const
3788 return first_reference() != second_reference();
3791 /// @return the kind of local change carried by the current diff node.
3792 /// The value returned is zero if the current node carries no local
3795 reference_diff::has_local_changes() const
3797 ir::change_kind k = ir::NO_CHANGE_KIND;
3798 if (!equals(*first_reference(), *second_reference(), &k))
3799 return k & ir::ALL_LOCAL_CHANGES_MASK;
3800 return ir::NO_CHANGE_KIND;
3803 /// Report the diff in a serialized form.
3805 /// @param out the output stream to serialize the dif to.
3807 /// @param indent the string to use for indenting the report.
3809 reference_diff::report(ostream& out, const string& indent) const
3811 context()->get_reporter()->report(*this, out, indent);
3814 /// Compute the diff between two references.
3816 /// Note that the two types must have been created in the same @ref
3817 /// environment, otherwise, this function aborts.
3819 /// @param first the first reference to consider for the diff.
3821 /// @param second the second reference to consider for the diff.
3823 /// @param ctxt the diff context to use.
3825 compute_diff(reference_type_def_sptr first,
3826 reference_type_def_sptr second,
3827 diff_context_sptr ctxt)
3829 if (first && second)
3830 ABG_ASSERT(first->get_environment() == second->get_environment());
3832 diff_sptr d = compute_diff_for_types(first->get_pointed_to_type(),
3833 second->get_pointed_to_type(),
3835 reference_diff_sptr result(new reference_diff(first, second, d, ctxt));
3836 ctxt->initialize_canonical_diff(result);
3839 // </reference_type_def>
3841 // <qualified_type_diff stuff>
3843 /// Populate the vector of children node of the @ref diff base type
3844 /// sub-object of this instance of @ref qualified_type_diff.
3846 /// The children node can then later be retrieved using
3847 /// diff::children_node().
3849 qualified_type_diff::chain_into_hierarchy()
3850 {append_child_node(leaf_underlying_type_diff());}
3852 /// Constructor for qualified_type_diff.
3854 /// @param first the first qualified type of the diff.
3856 /// @param second the second qualified type of the diff.
3858 /// @param ctxt the diff context to use.
3859 qualified_type_diff::qualified_type_diff(qualified_type_def_sptr first,
3860 qualified_type_def_sptr second,
3862 diff_context_sptr ctxt)
3863 : type_diff_base(first, second, ctxt),
3864 priv_(new priv(under))
3867 /// Finish building the current instance of @ref qualified_type_diff.
3869 qualified_type_diff::finish_diff_type()
3871 if (diff::priv_->finished_)
3873 chain_into_hierarchy();
3874 diff::priv_->finished_ = true;
3877 /// Getter for the first qualified type of the diff.
3879 /// @return the first qualified type of the diff.
3880 const qualified_type_def_sptr
3881 qualified_type_diff::first_qualified_type() const
3882 {return dynamic_pointer_cast<qualified_type_def>(first_subject());}
3884 /// Getter for the second qualified type of the diff.
3886 /// @return the second qualified type of the diff.
3887 const qualified_type_def_sptr
3888 qualified_type_diff::second_qualified_type() const
3889 {return dynamic_pointer_cast<qualified_type_def>(second_subject());}
3891 /// Getter for the diff between the underlying types of the two
3892 /// qualified types.
3894 /// @return the diff between the underlying types of the two qualified
3897 qualified_type_diff::underlying_type_diff() const
3898 {return priv_->underlying_type_diff;}
3900 /// Getter for the diff between the most underlying non-qualified
3901 /// types of two qualified types.
3903 /// @return the diff between the most underlying non-qualified types
3904 /// of two qualified types.
3906 qualified_type_diff::leaf_underlying_type_diff() const
3908 if (!priv_->leaf_underlying_type_diff)
3909 priv_->leaf_underlying_type_diff
3910 = compute_diff_for_types(get_leaf_type(first_qualified_type()),
3911 get_leaf_type(second_qualified_type()),
3914 return priv_->leaf_underlying_type_diff;
3917 /// Setter for the diff between the underlying types of the two
3918 /// qualified types.
3920 /// @return the diff between the underlying types of the two qualified
3923 qualified_type_diff::underlying_type_diff(const diff_sptr d)
3924 {priv_->underlying_type_diff = d;}
3926 /// @return the pretty representation of the current instance of @ref
3927 /// qualified_type_diff.
3929 qualified_type_diff::get_pretty_representation() const
3931 if (diff::priv_->pretty_representation_.empty())
3933 std::ostringstream o;
3934 o << "qualified_type_diff["
3935 << first_subject()->get_pretty_representation()
3937 << second_subject()->get_pretty_representation()
3939 diff::priv_->pretty_representation_ = o.str();
3941 return diff::priv_->pretty_representation_;
3944 /// Return true iff the current diff node carries a change.
3946 /// @return true iff the current diff node carries a change.
3948 qualified_type_diff::has_changes() const
3949 {return first_qualified_type() != second_qualified_type();}
3951 /// @return the kind of local change carried by the current diff node.
3952 /// The value returned is zero if the current node carries no local
3955 qualified_type_diff::has_local_changes() const
3957 ir::change_kind k = ir::NO_CHANGE_KIND;
3958 if (!equals(*first_qualified_type(), *second_qualified_type(), &k))
3959 return k & ir::ALL_LOCAL_CHANGES_MASK;
3960 return ir::NO_CHANGE_KIND;
3963 /// Report the diff in a serialized form.
3965 /// @param out the output stream to serialize to.
3967 /// @param indent the string to use to indent the lines of the report.
3969 qualified_type_diff::report(ostream& out, const string& indent) const
3971 context()->get_reporter()->report(*this, out, indent);
3974 /// Compute the diff between two qualified types.
3976 /// Note that the two types must have been created in the same @ref
3977 /// environment, otherwise, this function aborts.
3979 /// @param first the first qualified type to consider for the diff.
3981 /// @param second the second qualified type to consider for the diff.
3983 /// @param ctxt the diff context to use.
3984 qualified_type_diff_sptr
3985 compute_diff(const qualified_type_def_sptr first,
3986 const qualified_type_def_sptr second,
3987 diff_context_sptr ctxt)
3989 if (first && second)
3990 ABG_ASSERT(first->get_environment() == second->get_environment());
3992 diff_sptr d = compute_diff_for_types(first->get_underlying_type(),
3993 second->get_underlying_type(),
3995 qualified_type_diff_sptr result(new qualified_type_diff(first, second,
3997 ctxt->initialize_canonical_diff(result);
4001 // </qualified_type_diff stuff>
4003 // <enum_diff stuff>
4005 /// Clear the lookup tables useful for reporting an enum_diff.
4007 /// This function must be updated each time a lookup table is added or
4008 /// removed from the class_diff::priv.
4010 enum_diff::clear_lookup_tables()
4012 priv_->deleted_enumerators_.clear();
4013 priv_->inserted_enumerators_.clear();
4014 priv_->changed_enumerators_.clear();
4017 /// Tests if the lookup tables are empty.
4019 /// @return true if the lookup tables are empty, false otherwise.
4021 enum_diff::lookup_tables_empty() const
4023 return (priv_->deleted_enumerators_.empty()
4024 && priv_->inserted_enumerators_.empty()
4025 && priv_->changed_enumerators_.empty());
4028 /// If the lookup tables are not yet built, walk the differences and
4029 /// fill the lookup tables.
4031 enum_diff::ensure_lookup_tables_populated()
4033 if (!lookup_tables_empty())
4037 edit_script e = priv_->enumerators_changes_;
4039 for (vector<deletion>::const_iterator it = e.deletions().begin();
4040 it != e.deletions().end();
4043 unsigned i = it->index();
4044 const enum_type_decl::enumerator& n =
4045 first_enum()->get_enumerators()[i];
4046 const string& name = n.get_name();
4047 ABG_ASSERT(priv_->deleted_enumerators_.find(n.get_name())
4048 == priv_->deleted_enumerators_.end());
4049 priv_->deleted_enumerators_[name] = n;
4052 for (vector<insertion>::const_iterator it = e.insertions().begin();
4053 it != e.insertions().end();
4056 for (vector<unsigned>::const_iterator iit =
4057 it->inserted_indexes().begin();
4058 iit != it->inserted_indexes().end();
4062 const enum_type_decl::enumerator& n =
4063 second_enum()->get_enumerators()[i];
4064 const string& name = n.get_name();
4065 ABG_ASSERT(priv_->inserted_enumerators_.find(n.get_name())
4066 == priv_->inserted_enumerators_.end());
4067 string_enumerator_map::const_iterator j =
4068 priv_->deleted_enumerators_.find(name);
4069 if (j == priv_->deleted_enumerators_.end())
4070 priv_->inserted_enumerators_[name] = n;
4074 priv_->changed_enumerators_[j->first] =
4075 std::make_pair(j->second, n);
4076 priv_->deleted_enumerators_.erase(j);
4083 /// Populate the vector of children node of the @ref diff base type
4084 /// sub-object of this instance of @ref enum_diff.
4086 /// The children node can then later be retrieved using
4087 /// diff::children_node().
4089 enum_diff::chain_into_hierarchy()
4090 {append_child_node(underlying_type_diff());}
4092 /// Constructor for enum_diff.
4094 /// @param first the first enum type of the diff.
4096 /// @param second the second enum type of the diff.
4098 /// @param underlying_type_diff the diff of the two underlying types
4099 /// of the two enum types.
4101 /// @param ctxt the diff context to use.
4102 enum_diff::enum_diff(const enum_type_decl_sptr first,
4103 const enum_type_decl_sptr second,
4104 const diff_sptr underlying_type_diff,
4105 const diff_context_sptr ctxt)
4106 : type_diff_base(first, second, ctxt),
4107 priv_(new priv(underlying_type_diff))
4110 /// Finish building the current instance of @ref enum_diff.
4112 enum_diff::finish_diff_type()
4114 if (diff::priv_->finished_)
4116 chain_into_hierarchy();
4117 diff::priv_->finished_ = true;
4120 /// @return the first enum of the diff.
4121 const enum_type_decl_sptr
4122 enum_diff::first_enum() const
4123 {return dynamic_pointer_cast<enum_type_decl>(first_subject());}
4125 /// @return the second enum of the diff.
4126 const enum_type_decl_sptr
4127 enum_diff::second_enum() const
4128 {return dynamic_pointer_cast<enum_type_decl>(second_subject());}
4130 /// @return the diff of the two underlying enum types.
4132 enum_diff::underlying_type_diff() const
4133 {return priv_->underlying_type_diff_;}
4135 /// @return a map of the enumerators that were deleted.
4136 const string_enumerator_map&
4137 enum_diff::deleted_enumerators() const
4138 {return priv_->deleted_enumerators_;}
4140 /// @return a map of the enumerators that were inserted
4141 const string_enumerator_map&
4142 enum_diff::inserted_enumerators() const
4143 {return priv_->inserted_enumerators_;}
4145 /// @return a map of the enumerators that were changed
4146 const string_changed_enumerator_map&
4147 enum_diff::changed_enumerators() const
4148 {return priv_->changed_enumerators_;}
4150 /// @return the pretty representation of the current instance of @ref
4153 enum_diff::get_pretty_representation() const
4155 if (diff::priv_->pretty_representation_.empty())
4157 std::ostringstream o;
4159 << first_subject()->get_pretty_representation()
4161 << second_subject()->get_pretty_representation()
4163 diff::priv_->pretty_representation_ = o.str();
4165 return diff::priv_->pretty_representation_;
4168 /// Return true iff the current diff node carries a change.
4170 /// @return true iff the current diff node carries a change.
4172 enum_diff::has_changes() const
4173 {return first_enum() != second_enum();}
4175 /// @return the kind of local change carried by the current diff node.
4176 /// The value returned is zero if the current node carries no local
4179 enum_diff::has_local_changes() const
4181 ir::change_kind k = ir::NO_CHANGE_KIND;
4182 if (!equals(*first_enum(), *second_enum(), &k))
4183 return k & ir::ALL_LOCAL_CHANGES_MASK;
4184 return ir::NO_CHANGE_KIND;
4187 /// Report the differences between the two enums.
4189 /// @param out the output stream to send the report to.
4191 /// @param indent the string to use for indentation.
4193 enum_diff::report(ostream& out, const string& indent) const
4195 context()->get_reporter()->report(*this, out, indent);
4198 /// Compute the set of changes between two instances of @ref
4201 /// Note that the two types must have been created in the same @ref
4202 /// environment, otherwise, this function aborts.
4204 /// @param first a pointer to the first enum_type_decl to consider.
4206 /// @param second a pointer to the second enum_type_decl to consider.
4208 /// @return the resulting diff of the two enums @p first and @p
4211 /// @param ctxt the diff context to use.
4213 compute_diff(const enum_type_decl_sptr first,
4214 const enum_type_decl_sptr second,
4215 diff_context_sptr ctxt)
4217 if (first && second)
4218 ABG_ASSERT(first->get_environment() == second->get_environment());
4220 diff_sptr ud = compute_diff_for_types(first->get_underlying_type(),
4221 second->get_underlying_type(),
4223 enum_diff_sptr d(new enum_diff(first, second, ud, ctxt));
4225 compute_diff(first->get_enumerators().begin(),
4226 first->get_enumerators().end(),
4227 second->get_enumerators().begin(),
4228 second->get_enumerators().end(),
4229 d->priv_->enumerators_changes_);
4231 d->ensure_lookup_tables_populated();
4233 ctxt->initialize_canonical_diff(d);
4237 // </enum_diff stuff>
4239 // <class_or_union_diff stuff>
4241 /// Test if the current diff node carries a member type change for a
4242 /// member type which name is the same as the name of a given type
4245 /// @param d the type declaration which name should be equal to the
4246 /// name of the member type that might have changed.
4248 /// @return the member type that has changed, iff there were a member
4249 /// type (which name is the same as the name of @p d) that changed.
4250 /// Note that the member type that is returned is the new value of the
4251 /// member type that changed.
4252 type_or_decl_base_sptr
4253 class_or_union_diff::priv::member_type_has_changed(decl_base_sptr d) const
4255 string qname = d->get_qualified_name();
4256 string_diff_sptr_map::const_iterator it =
4257 changed_member_types_.find(qname);
4259 return ((it == changed_member_types_.end())
4260 ? type_or_decl_base_sptr()
4261 : it->second->second_subject());
4264 /// Test if the current diff node carries a data member change for a
4265 /// data member which name is the same as the name of a given type
4268 /// @param d the type declaration which name should be equal to the
4269 /// name of the data member that might have changed.
4271 /// @return the data member that has changed, iff there were a data
4272 /// member type (which name is the same as the name of @p d) that
4273 /// changed. Note that the data member that is returned is the new
4274 /// value of the data member that changed.
4276 class_or_union_diff::priv::subtype_changed_dm(decl_base_sptr d) const
4278 string qname = d->get_qualified_name();
4279 string_var_diff_sptr_map::const_iterator it =
4280 subtype_changed_dm_.find(qname);
4282 if (it == subtype_changed_dm_.end())
4283 return decl_base_sptr();
4284 return it->second->second_var();
4287 /// Test if the current diff node carries a member class template
4288 /// change for a member class template which name is the same as the
4289 /// name of a given type declaration.
4291 /// @param d the type declaration which name should be equal to the
4292 /// name of the member class template that might have changed.
4294 /// @return the member class template that has changed, iff there were
4295 /// a member class template (which name is the same as the name of @p
4296 /// d) that changed. Note that the member class template that is
4297 /// returned is the new value of the member class template that
4300 class_or_union_diff::priv::member_class_tmpl_has_changed(decl_base_sptr d) const
4302 string qname = d->get_qualified_name();
4303 string_diff_sptr_map::const_iterator it =
4304 changed_member_class_tmpls_.find(qname);
4306 return ((it == changed_member_class_tmpls_.end())
4308 : dynamic_pointer_cast<decl_base>(it->second->second_subject()));
4311 /// Get the number of non static data members that were deleted.
4313 /// @return the number of non static data members that were deleted.
4315 class_or_union_diff::priv::get_deleted_non_static_data_members_number() const
4319 for (string_decl_base_sptr_map::const_iterator i =
4320 deleted_data_members_.begin();
4321 i != deleted_data_members_.end();
4323 if (is_member_decl(i->second)
4324 && !get_member_is_static(i->second))
4330 /// Get the number of non static data members that were inserted.
4332 /// @return the number of non static data members that were inserted.
4334 class_or_union_diff::priv::get_inserted_non_static_data_members_number() const
4338 for (string_decl_base_sptr_map::const_iterator i =
4339 inserted_data_members_.begin();
4340 i != inserted_data_members_.end();
4342 if (is_member_decl(i->second)
4343 && !get_member_is_static(i->second))
4349 /// Get the number of data member sub-type changes carried by the
4350 /// current diff node that were filtered out.
4352 /// @param local_only if true, it means that only (filtered) local
4353 /// changes are considered.
4355 /// @return the number of data member sub-type changes carried by the
4356 /// current diff node that were filtered out.
4358 class_or_union_diff::priv::count_filtered_subtype_changed_dm(bool local_only)
4360 size_t num_filtered= 0;
4361 for (var_diff_sptrs_type::const_iterator i =
4362 sorted_subtype_changed_dm_.begin();
4363 i != sorted_subtype_changed_dm_.end();
4368 if ((*i)->has_changes()
4369 && !(*i)->has_local_changes_to_be_reported())
4374 if ((*i)->is_filtered_out())
4378 return num_filtered;
4381 /// Get the number of data member changes carried by the current diff
4382 /// node that were filtered out.
4384 /// @param local_only if true, it means that only (filtered) local
4385 /// changes are considered.
4387 /// @return the number of data member changes carried by the current
4388 /// diff node that were filtered out.
4390 class_or_union_diff::priv::count_filtered_changed_dm(bool local_only)
4392 size_t num_filtered= 0;
4394 for (unsigned_var_diff_sptr_map::const_iterator i = changed_dm_.begin();
4395 i != changed_dm_.end();
4398 diff_sptr diff = i->second;
4401 if ((diff->has_changes() && !diff->has_local_changes_to_be_reported())
4402 || diff->is_filtered_out())
4407 if (diff->is_filtered_out())
4411 return num_filtered;
4414 /// Skip the processing of the current member function if its
4415 /// virtual-ness is disallowed by the user.
4417 /// This is to be used in the member functions below that are used to
4418 /// count the number of filtered inserted, deleted and changed member
4420 #define SKIP_MEM_FN_IF_VIRTUALITY_DISALLOWED \
4422 if (get_member_function_is_virtual(f) \
4423 || get_member_function_is_virtual(s)) \
4425 if (!(allowed_category | VIRTUAL_MEMBER_CHANGE_CATEGORY)) \
4430 if (!(allowed_category | NON_VIRT_MEM_FUN_CHANGE_CATEGORY)) \
4435 /// Get the number of member functions changes carried by the current
4436 /// diff node that were filtered out.
4438 /// @return the number of member functions changes carried by the
4439 /// current diff node that were filtered out.
4441 class_or_union_diff::priv::count_filtered_changed_mem_fns
4442 (const diff_context_sptr& ctxt)
4445 diff_category allowed_category = ctxt->get_allowed_category();
4447 for (function_decl_diff_sptrs_type::const_iterator i =
4448 sorted_changed_member_functions_.begin();
4449 i != sorted_changed_member_functions_.end();
4452 method_decl_sptr f =
4453 dynamic_pointer_cast<method_decl>
4454 ((*i)->first_function_decl());
4457 method_decl_sptr s =
4458 dynamic_pointer_cast<method_decl>
4459 ((*i)->second_function_decl());
4462 SKIP_MEM_FN_IF_VIRTUALITY_DISALLOWED;
4464 diff_sptr diff = *i;
4465 ctxt->maybe_apply_filters(diff);
4467 if (diff->is_filtered_out())
4474 /// Get the number of member functions insertions carried by the current
4475 /// diff node that were filtered out.
4477 /// @return the number of member functions insertions carried by the
4478 /// current diff node that were filtered out.
4480 class_or_union_diff::priv::count_filtered_inserted_mem_fns
4481 (const diff_context_sptr& ctxt)
4484 diff_category allowed_category = ctxt->get_allowed_category();
4486 for (string_member_function_sptr_map::const_iterator i =
4487 inserted_member_functions_.begin();
4488 i != inserted_member_functions_.end();
4491 method_decl_sptr f = i->second,
4494 SKIP_MEM_FN_IF_VIRTUALITY_DISALLOWED;
4496 diff_sptr diff = compute_diff_for_decls(f, s, ctxt);
4497 ctxt->maybe_apply_filters(diff);
4499 if (diff->get_category() != NO_CHANGE_CATEGORY
4500 && diff->is_filtered_out())
4507 /// Get the number of member functions deletions carried by the current
4508 /// diff node that were filtered out.
4510 /// @return the number of member functions deletions carried by the
4511 /// current diff node that were filtered out.
4513 class_or_union_diff::priv::count_filtered_deleted_mem_fns
4514 (const diff_context_sptr& ctxt)
4517 diff_category allowed_category = ctxt->get_allowed_category();
4519 for (string_member_function_sptr_map::const_iterator i =
4520 deleted_member_functions_.begin();
4521 i != deleted_member_functions_.end();
4524 method_decl_sptr f = i->second,
4527 SKIP_MEM_FN_IF_VIRTUALITY_DISALLOWED;
4529 diff_sptr diff = compute_diff_for_decls(f, s, ctxt);
4530 ctxt->maybe_apply_filters(diff);
4532 if (diff->get_category() != NO_CHANGE_CATEGORY
4533 && diff->is_filtered_out())
4540 /// Clear the lookup tables useful for reporting.
4542 /// This function must be updated each time a lookup table is added or
4543 /// removed from the class_or_union_diff::priv.
4545 class_or_union_diff::clear_lookup_tables()
4547 priv_->deleted_member_types_.clear();
4548 priv_->inserted_member_types_.clear();
4549 priv_->changed_member_types_.clear();
4550 priv_->deleted_data_members_.clear();
4551 priv_->inserted_data_members_.clear();
4552 priv_->subtype_changed_dm_.clear();
4553 priv_->deleted_member_functions_.clear();
4554 priv_->inserted_member_functions_.clear();
4555 priv_->changed_member_functions_.clear();
4556 priv_->deleted_member_class_tmpls_.clear();
4557 priv_->inserted_member_class_tmpls_.clear();
4558 priv_->changed_member_class_tmpls_.clear();
4561 /// Tests if the lookup tables are empty.
4563 /// @return true if the lookup tables are empty, false otherwise.
4565 class_or_union_diff::lookup_tables_empty(void) const
4567 return (priv_->deleted_member_types_.empty()
4568 && priv_->inserted_member_types_.empty()
4569 && priv_->changed_member_types_.empty()
4570 && priv_->deleted_data_members_.empty()
4571 && priv_->inserted_data_members_.empty()
4572 && priv_->subtype_changed_dm_.empty()
4573 && priv_->inserted_member_functions_.empty()
4574 && priv_->deleted_member_functions_.empty()
4575 && priv_->changed_member_functions_.empty()
4576 && priv_->deleted_member_class_tmpls_.empty()
4577 && priv_->inserted_member_class_tmpls_.empty()
4578 && priv_->changed_member_class_tmpls_.empty());
4581 /// If the lookup tables are not yet built, walk the differences and
4584 class_or_union_diff::ensure_lookup_tables_populated(void) const
4587 edit_script& e = priv_->member_types_changes_;
4589 for (vector<deletion>::const_iterator it = e.deletions().begin();
4590 it != e.deletions().end();
4593 unsigned i = it->index();
4595 get_type_declaration(first_class_or_union()->get_member_types()[i]);
4596 class_or_union_sptr record_type = is_class_or_union_type(d);
4597 if (record_type && record_type->get_is_declaration_only())
4599 string name = d->get_name();
4600 priv_->deleted_member_types_[name] = d;
4603 for (vector<insertion>::const_iterator it = e.insertions().begin();
4604 it != e.insertions().end();
4607 for (vector<unsigned>::const_iterator iit =
4608 it->inserted_indexes().begin();
4609 iit != it->inserted_indexes().end();
4614 get_type_declaration(second_class_or_union()->get_member_types()[i]);
4615 class_or_union_sptr record_type = is_class_or_union_type(d);
4616 if (record_type && record_type->get_is_declaration_only())
4618 string name = d->get_name();
4619 string_decl_base_sptr_map::const_iterator j =
4620 priv_->deleted_member_types_.find(name);
4621 if (j != priv_->deleted_member_types_.end())
4623 if (*j->second != *d)
4624 priv_->changed_member_types_[name] =
4625 compute_diff(j->second, d, context());
4627 priv_->deleted_member_types_.erase(j);
4630 priv_->inserted_member_types_[name] = d;
4636 edit_script& e = priv_->data_members_changes_;
4638 for (vector<deletion>::const_iterator it = e.deletions().begin();
4639 it != e.deletions().end();
4642 unsigned i = it->index();
4643 decl_base_sptr d = first_class_or_union()->get_non_static_data_members()[i];
4644 string name = d->get_name();
4645 ABG_ASSERT(priv_->deleted_data_members_.find(name)
4646 == priv_->deleted_data_members_.end());
4647 priv_->deleted_data_members_[name] = d;
4650 for (vector<insertion>::const_iterator it = e.insertions().begin();
4651 it != e.insertions().end();
4654 for (vector<unsigned>::const_iterator iit =
4655 it->inserted_indexes().begin();
4656 iit != it->inserted_indexes().end();
4661 second_class_or_union()->get_non_static_data_members()[i];
4662 var_decl_sptr dm = is_var_decl(d);
4663 string name = dm->get_name();
4664 ABG_ASSERT(priv_->inserted_data_members_.find(name)
4665 == priv_->inserted_data_members_.end());
4666 string_decl_base_sptr_map::const_iterator j =
4667 priv_->deleted_data_members_.find(name);
4668 if (j != priv_->deleted_data_members_.end())
4670 if (*j->second != *d)
4672 var_decl_sptr old_dm = is_var_decl(j->second);
4673 priv_->subtype_changed_dm_[name]=
4674 compute_diff(old_dm, dm, context());
4676 priv_->deleted_data_members_.erase(j);
4679 priv_->inserted_data_members_[name] = d;
4683 // Now detect when a data member is deleted from offset N and
4684 // another one is added to offset N. In that case, we want to be
4685 // able to say that the data member at offset N changed.
4686 for (string_decl_base_sptr_map::const_iterator i =
4687 priv_->deleted_data_members_.begin();
4688 i != priv_->deleted_data_members_.end();
4691 unsigned offset = get_data_member_offset(i->second);
4692 priv_->deleted_dm_by_offset_[offset] = i->second;
4695 for (string_decl_base_sptr_map::const_iterator i =
4696 priv_->inserted_data_members_.begin();
4697 i != priv_->inserted_data_members_.end();
4700 unsigned offset = get_data_member_offset(i->second);
4701 priv_->inserted_dm_by_offset_[offset] = i->second;
4704 for (unsigned_decl_base_sptr_map::const_iterator i =
4705 priv_->inserted_dm_by_offset_.begin();
4706 i != priv_->inserted_dm_by_offset_.end();
4709 unsigned_decl_base_sptr_map::const_iterator j =
4710 priv_->deleted_dm_by_offset_.find(i->first);
4711 if (j != priv_->deleted_dm_by_offset_.end())
4713 var_decl_sptr old_dm = is_var_decl(j->second);
4714 var_decl_sptr new_dm = is_var_decl(i->second);
4715 priv_->changed_dm_[i->first] =
4716 compute_diff(old_dm, new_dm, context());
4720 for (unsigned_var_diff_sptr_map::const_iterator i =
4721 priv_->changed_dm_.begin();
4722 i != priv_->changed_dm_.end();
4725 priv_->deleted_dm_by_offset_.erase(i->first);
4726 priv_->inserted_dm_by_offset_.erase(i->first);
4727 priv_->deleted_data_members_.erase
4728 (i->second->first_var()->get_name());
4729 priv_->inserted_data_members_.erase
4730 (i->second->second_var()->get_name());
4733 sort_string_data_member_diff_sptr_map(priv_->subtype_changed_dm_,
4734 priv_->sorted_subtype_changed_dm_);
4735 sort_unsigned_data_member_diff_sptr_map(priv_->changed_dm_,
4736 priv_->sorted_changed_dm_);
4739 edit_script& e = priv_->member_class_tmpls_changes_;
4741 for (vector<deletion>::const_iterator it = e.deletions().begin();
4742 it != e.deletions().end();
4745 unsigned i = it->index();
4747 first_class_or_union()->get_member_class_templates()[i]->
4749 string name = d->get_name();
4750 ABG_ASSERT(priv_->deleted_member_class_tmpls_.find(name)
4751 == priv_->deleted_member_class_tmpls_.end());
4752 priv_->deleted_member_class_tmpls_[name] = d;
4755 for (vector<insertion>::const_iterator it = e.insertions().begin();
4756 it != e.insertions().end();
4759 for (vector<unsigned>::const_iterator iit =
4760 it->inserted_indexes().begin();
4761 iit != it->inserted_indexes().end();
4766 second_class_or_union()->get_member_class_templates()[i]->
4768 string name = d->get_name();
4769 ABG_ASSERT(priv_->inserted_member_class_tmpls_.find(name)
4770 == priv_->inserted_member_class_tmpls_.end());
4771 string_decl_base_sptr_map::const_iterator j =
4772 priv_->deleted_member_class_tmpls_.find(name);
4773 if (j != priv_->deleted_member_class_tmpls_.end())
4775 if (*j->second != *d)
4776 priv_->changed_member_types_[name]=
4777 compute_diff(j->second, d, context());
4778 priv_->deleted_member_class_tmpls_.erase(j);
4781 priv_->inserted_member_class_tmpls_[name] = d;
4785 sort_string_diff_sptr_map(priv_->changed_member_types_,
4786 priv_->sorted_changed_member_types_);
4789 /// Allocate the memory for the priv_ pimpl data member of the @ref
4790 /// class_or_union_diff class.
4792 class_or_union_diff::allocate_priv_data()
4795 priv_.reset(new priv);
4798 /// Constructor for the @ref class_or_union_diff class.
4800 /// @param first_scope the first @ref class_or_union of the diff node.
4802 /// @param second_scope the second @ref class_or_union of the diff node.
4804 /// @param ctxt the context of the diff.
4805 class_or_union_diff::class_or_union_diff(class_or_union_sptr first_scope,
4806 class_or_union_sptr second_scope,
4807 diff_context_sptr ctxt)
4808 : type_diff_base(first_scope, second_scope, ctxt)
4812 /// Finish building the current instance of @ref class_or_union_diff.
4814 class_or_union_diff::finish_diff_type()
4816 if (diff::priv_->finished_)
4818 chain_into_hierarchy();
4819 diff::priv_->finished_ = true;
4822 /// Getter of the private data of the @ref class_or_union_diff type.
4824 /// Note that due to an optimization, the private data of @ref
4825 /// class_or_union_diff can be shared among several instances of
4826 /// class_or_union_diff, so you should never try to access
4827 /// class_or_union_diff::priv directly.
4829 /// When class_or_union_diff::priv is shared, this function returns
4830 /// the correct shared one.
4832 /// @return the (possibly) shared private data of the current instance
4833 /// of @ref class_or_union_diff.
4834 const class_or_union_diff::priv_sptr&
4835 class_or_union_diff::get_priv() const
4840 // If the current class_or_union_diff::priv member is empty, then look for
4841 // the shared one, from the canonical type.
4842 class_or_union_diff *canonical =
4843 dynamic_cast<class_or_union_diff*>(get_canonical_diff());
4844 ABG_ASSERT(canonical);
4845 ABG_ASSERT(canonical->priv_);
4847 return canonical->priv_;
4850 /// Destructor of class_or_union_diff.
4851 class_or_union_diff::~class_or_union_diff()
4855 /// @return the first @ref class_or_union involved in the diff.
4857 class_or_union_diff::first_class_or_union() const
4858 {return is_class_or_union_type(first_subject());}
4860 /// @return the second @ref class_or_union involved in the diff.
4862 class_or_union_diff::second_class_or_union() const
4863 {return is_class_or_union_type(second_subject());}
4865 /// @return the edit script of the member types of the two @ref
4868 class_or_union_diff::member_types_changes() const
4869 {return get_priv()->member_types_changes_;}
4871 /// @return the edit script of the member types of the two @ref
4874 class_or_union_diff::member_types_changes()
4875 {return get_priv()->member_types_changes_;}
4877 /// @return the edit script of the data members of the two @ref
4880 class_or_union_diff::data_members_changes() const
4881 {return get_priv()->data_members_changes_;}
4883 /// @return the edit script of the data members of the two @ref
4886 class_or_union_diff::data_members_changes()
4887 {return get_priv()->data_members_changes_;}
4889 /// Getter for the data members that got inserted.
4891 /// @return a map of data members that got inserted.
4892 const string_decl_base_sptr_map&
4893 class_or_union_diff::inserted_data_members() const
4894 {return get_priv()->inserted_data_members_;}
4896 /// Getter for the data members that got deleted.
4898 /// @return a map of data members that got deleted.
4899 const string_decl_base_sptr_map&
4900 class_or_union_diff::deleted_data_members() const
4901 {return get_priv()->deleted_data_members_;}
4903 /// @return the edit script of the member functions of the two @ref
4906 class_or_union_diff::member_fns_changes() const
4907 {return get_priv()->member_fns_changes_;}
4909 /// Getter for the virtual members functions that have had a change in
4910 /// a sub-type, without having a change in their symbol name.
4912 /// @return a sorted vector of virtual member functions that have a
4913 /// sub-type change.
4914 const function_decl_diff_sptrs_type&
4915 class_or_union_diff::changed_member_fns() const
4916 {return get_priv()->sorted_changed_member_functions_;}
4918 /// @return the edit script of the member functions of the two
4921 class_or_union_diff::member_fns_changes()
4922 {return get_priv()->member_fns_changes_;}
4924 /// @return a map of member functions that got deleted.
4925 const string_member_function_sptr_map&
4926 class_or_union_diff::deleted_member_fns() const
4927 {return get_priv()->deleted_member_functions_;}
4929 /// @return a map of member functions that got inserted.
4930 const string_member_function_sptr_map&
4931 class_or_union_diff::inserted_member_fns() const
4932 {return get_priv()->inserted_member_functions_;}
4934 /// @return the edit script of the member function templates of the two
4935 /// @ref class_or_union.
4937 class_or_union_diff::member_fn_tmpls_changes() const
4938 {return get_priv()->member_fn_tmpls_changes_;}
4940 /// @return the edit script of the member function templates of the
4941 /// two @ref class_or_union.
4943 class_or_union_diff::member_fn_tmpls_changes()
4944 {return get_priv()->member_fn_tmpls_changes_;}
4946 /// @return the edit script of the member class templates of the two
4947 /// @ref class_or_union.
4949 class_or_union_diff::member_class_tmpls_changes() const
4950 {return get_priv()->member_class_tmpls_changes_;}
4952 /// @return the edit script of the member class templates of the two
4953 /// @ref class_or_union.
4955 class_or_union_diff::member_class_tmpls_changes()
4956 {return get_priv()->member_class_tmpls_changes_;}
4958 /// Test if the current diff node carries a change.
4960 class_or_union_diff::has_changes() const
4961 {return first_class_or_union() != second_class_or_union();}
4963 /// @return the kind of local change carried by the current diff node.
4964 /// The value returned is zero if the current node carries no local
4967 class_or_union_diff::has_local_changes() const
4969 ir::change_kind k = ir::NO_CHANGE_KIND;
4970 if (!equals(*first_class_or_union(), *second_class_or_union(), &k))
4971 return k & ir::ALL_LOCAL_CHANGES_MASK;
4972 return ir::NO_CHANGE_KIND;
4976 /// Report the changes carried by the current @ref class_or_union_diff
4977 /// node in a textual format.
4979 /// @param out the output stream to write the textual report to.
4981 /// @param indent the number of white space to use as indentation.
4983 class_or_union_diff::report(ostream& out, const string& indent) const
4985 context()->get_reporter()->report(*this, out, indent);
4988 /// Populate the vector of children node of the @ref diff base type
4989 /// sub-object of this instance of @ref class_or_union_diff.
4991 /// The children node can then later be retrieved using
4992 /// diff::children_node().
4994 class_or_union_diff::chain_into_hierarchy()
4996 // data member changes
4997 for (var_diff_sptrs_type::const_iterator i =
4998 get_priv()->sorted_subtype_changed_dm_.begin();
4999 i != get_priv()->sorted_subtype_changed_dm_.end();
5001 if (diff_sptr d = *i)
5002 append_child_node(d);
5004 for (unsigned_var_diff_sptr_map::const_iterator i =
5005 get_priv()->changed_dm_.begin();
5006 i != get_priv()->changed_dm_.end();
5008 if (diff_sptr d = i->second)
5009 append_child_node(d);
5011 // member types changes
5012 for (diff_sptrs_type::const_iterator i =
5013 get_priv()->sorted_changed_member_types_.begin();
5014 i != get_priv()->sorted_changed_member_types_.end();
5016 if (diff_sptr d = *i)
5017 append_child_node(d);
5019 // member function changes
5020 for (function_decl_diff_sptrs_type::const_iterator i =
5021 get_priv()->sorted_changed_member_functions_.begin();
5022 i != get_priv()->sorted_changed_member_functions_.end();
5024 if (diff_sptr d = *i)
5025 append_child_node(d);
5028 // </class_or_union_diff stuff>
5030 //<class_diff stuff>
5032 /// Clear the lookup tables useful for reporting.
5034 /// This function must be updated each time a lookup table is added or
5035 /// removed from the class_diff::priv.
5037 class_diff::clear_lookup_tables(void)
5039 priv_->deleted_bases_.clear();
5040 priv_->inserted_bases_.clear();
5041 priv_->changed_bases_.clear();
5044 /// Tests if the lookup tables are empty.
5046 /// @return true if the lookup tables are empty, false otherwise.
5048 class_diff::lookup_tables_empty(void) const
5050 return (priv_->deleted_bases_.empty()
5051 && priv_->inserted_bases_.empty()
5052 && priv_->changed_bases_.empty());
5055 /// If the lookup tables are not yet built, walk the differences and
5058 class_diff::ensure_lookup_tables_populated(void) const
5060 class_or_union_diff::ensure_lookup_tables_populated();
5062 if (!lookup_tables_empty())
5066 edit_script& e = get_priv()->base_changes_;
5068 for (vector<deletion>::const_iterator it = e.deletions().begin();
5069 it != e.deletions().end();
5072 unsigned i = it->index();
5073 class_decl::base_spec_sptr b =
5074 first_class_decl()->get_base_specifiers()[i];
5075 string name = b->get_base_class()->get_name();
5076 ABG_ASSERT(get_priv()->deleted_bases_.find(name)
5077 == get_priv()->deleted_bases_.end());
5078 get_priv()->deleted_bases_[name] = b;
5081 for (vector<insertion>::const_iterator it = e.insertions().begin();
5082 it != e.insertions().end();
5085 for (vector<unsigned>::const_iterator iit =
5086 it->inserted_indexes().begin();
5087 iit != it->inserted_indexes().end();
5091 class_decl::base_spec_sptr b =
5092 second_class_decl()->get_base_specifiers()[i];
5093 string name = b->get_base_class()->get_name();
5094 ABG_ASSERT(get_priv()->inserted_bases_.find(name)
5095 == get_priv()->inserted_bases_.end());
5096 string_base_sptr_map::const_iterator j =
5097 get_priv()->deleted_bases_.find(name);
5098 if (j != get_priv()->deleted_bases_.end())
5101 get_priv()->changed_bases_[name] =
5102 compute_diff(j->second, b, context());
5103 get_priv()->deleted_bases_.erase(j);
5106 get_priv()->inserted_bases_[name] = b;
5111 sort_string_base_sptr_map(get_priv()->deleted_bases_,
5112 get_priv()->sorted_deleted_bases_);
5113 sort_string_base_sptr_map(get_priv()->inserted_bases_,
5114 get_priv()->sorted_inserted_bases_);
5115 sort_string_base_diff_sptr_map(get_priv()->changed_bases_,
5116 get_priv()->sorted_changed_bases_);
5119 const class_or_union_diff::priv_sptr &p = class_or_union_diff::get_priv();
5121 edit_script& e = p->member_fns_changes_;
5123 for (vector<deletion>::const_iterator it = e.deletions().begin();
5124 it != e.deletions().end();
5127 unsigned i = it->index();
5128 method_decl_sptr mem_fn =
5129 first_class_decl()->get_virtual_mem_fns()[i];
5130 string name = mem_fn->get_linkage_name();
5132 name = mem_fn->get_pretty_representation();
5133 ABG_ASSERT(!name.empty());
5134 if (p->deleted_member_functions_.find(name)
5135 != p->deleted_member_functions_.end())
5137 p->deleted_member_functions_[name] = mem_fn;
5140 for (vector<insertion>::const_iterator it = e.insertions().begin();
5141 it != e.insertions().end();
5144 for (vector<unsigned>::const_iterator iit =
5145 it->inserted_indexes().begin();
5146 iit != it->inserted_indexes().end();
5151 method_decl_sptr mem_fn =
5152 second_class_decl()->get_virtual_mem_fns()[i];
5153 string name = mem_fn->get_linkage_name();
5155 name = mem_fn->get_pretty_representation();
5156 ABG_ASSERT(!name.empty());
5157 if (p->inserted_member_functions_.find(name)
5158 != p->inserted_member_functions_.end())
5160 string_member_function_sptr_map::const_iterator j =
5161 p->deleted_member_functions_.find(name);
5163 if (j != p->deleted_member_functions_.end())
5165 if (*j->second != *mem_fn)
5166 p->changed_member_functions_[name] =
5167 compute_diff(static_pointer_cast<function_decl>(j->second),
5168 static_pointer_cast<function_decl>(mem_fn),
5170 p->deleted_member_functions_.erase(j);
5173 p->inserted_member_functions_[name] = mem_fn;
5177 // Now walk the allegedly deleted member functions; check if their
5178 // underlying symbols are deleted as well; otherwise, consider
5179 // that the member function in question hasn't been deleted.
5181 vector<string> to_delete;
5182 corpus_sptr f = context()->get_first_corpus(),
5183 s = context()->get_second_corpus();;
5185 for (string_member_function_sptr_map::const_iterator i =
5186 deleted_member_fns().begin();
5187 i != deleted_member_fns().end();
5190 if (get_member_function_is_virtual(i->second))
5192 // We assume that all non-virtual member functions functions
5193 // we look at here have ELF symbols.
5194 if (!i->second->get_symbol()
5195 || s->lookup_function_symbol(*i->second->get_symbol()))
5196 to_delete.push_back(i->first);
5200 for (vector<string>::const_iterator i = to_delete.begin();
5201 i != to_delete.end();
5203 p->deleted_member_functions_.erase(*i);
5205 // Do something similar for added functions.
5208 for (string_member_function_sptr_map::const_iterator i =
5209 inserted_member_fns().begin();
5210 i != inserted_member_fns().end();
5213 if (get_member_function_is_virtual(i->second))
5215 // We assume that all non-virtual member functions functions
5216 // we look at here have ELF symbols.
5217 if (!i->second->get_symbol()
5218 || f->lookup_function_symbol(*i->second->get_symbol()))
5219 to_delete.push_back(i->first);
5222 for (vector<string>::const_iterator i = to_delete.begin();
5223 i != to_delete.end();
5225 p->inserted_member_functions_.erase(*i);
5227 sort_string_virtual_member_function_diff_sptr_map
5228 (p->changed_member_functions_,
5229 p->sorted_changed_member_functions_);
5233 /// Allocate the memory for the priv_ pimpl data member of the @ref
5234 /// class_diff class.
5236 class_diff::allocate_priv_data()
5238 class_or_union_diff::allocate_priv_data();
5240 priv_.reset(new priv);
5243 /// Test whether a given base class has changed. A base class has
5244 /// changed if it's in both in deleted *and* inserted bases.
5246 ///@param d the declaration for the base class to consider.
5248 /// @return the new base class if the given base class has changed, or
5249 /// NULL if it hasn't.
5250 class_decl::base_spec_sptr
5251 class_diff::priv::base_has_changed(class_decl::base_spec_sptr d) const
5253 string qname = d->get_base_class()->get_qualified_name();
5254 string_base_diff_sptr_map::const_iterator it =
5255 changed_bases_.find(qname);
5257 return (it == changed_bases_.end())
5258 ? class_decl::base_spec_sptr()
5259 : it->second->second_base();
5263 /// Count the number of bases classes whose changes got filtered out.
5265 /// @return the number of bases classes whose changes got filtered
5268 class_diff::priv::count_filtered_bases()
5270 size_t num_filtered = 0;
5271 for (base_diff_sptrs_type::const_iterator i = sorted_changed_bases_.begin();
5272 i != sorted_changed_bases_.end();
5275 diff_sptr diff = *i;
5276 if (diff && diff->is_filtered_out())
5279 return num_filtered;
5282 /// Populate the vector of children node of the @ref diff base type
5283 /// sub-object of this instance of @ref class_diff.
5285 /// The children node can then later be retrieved using
5286 /// diff::children_node().
5288 class_diff::chain_into_hierarchy()
5290 class_or_union_diff::chain_into_hierarchy();
5292 // base class changes.
5293 for (base_diff_sptrs_type::const_iterator i =
5294 get_priv()->sorted_changed_bases_.begin();
5295 i != get_priv()->sorted_changed_bases_.end();
5297 if (diff_sptr d = *i)
5298 append_child_node(d);
5301 /// Constructor of class_diff
5303 /// @param first_scope the first class of the diff.
5305 /// @param second_scope the second class of the diff.
5307 /// @param ctxt the diff context to use.
5308 class_diff::class_diff(class_decl_sptr first_scope,
5309 class_decl_sptr second_scope,
5310 diff_context_sptr ctxt)
5311 : class_or_union_diff(first_scope, second_scope, ctxt)
5312 // We don't initialize the priv_ data member here. This is an
5313 // optimization to reduce memory consumption (and also execution
5314 // time) for cases where there are a lot of instances of
5315 // class_diff in the same equivalence class. In compute_diff(),
5316 // the priv_ is set to the priv_ of the canonical diff node.
5317 // See PR libabigail/17948.
5320 class_diff::~class_diff()
5323 /// Getter of the private data of the @ref class_diff type.
5325 /// Note that due to an optimization, the private data of @ref
5326 /// class_diff can be shared among several instances of class_diff, so
5327 /// you should never try to access class_diff::priv directly.
5329 /// When class_diff::priv is shared, this function returns the correct
5332 /// @return the (possibly) shared private data of the current instance
5334 const class_diff::priv_sptr&
5335 class_diff::get_priv() const
5340 // If the current class_diff::priv member is empty, then look for
5341 // the shared one, from the canonical type.
5342 class_diff *canonical =
5343 dynamic_cast<class_diff*>(get_canonical_diff());
5344 ABG_ASSERT(canonical);
5345 ABG_ASSERT(canonical->priv_);
5347 return canonical->priv_;
5350 /// Finish building the current instance of @ref class_diff.
5352 class_diff::finish_diff_type()
5354 if (diff::priv_->finished_)
5356 chain_into_hierarchy();
5357 diff::priv_->finished_ = true;
5360 /// @return the pretty representation of the current instance of @ref
5363 class_diff::get_pretty_representation() const
5365 if (diff::priv_->pretty_representation_.empty())
5367 std::ostringstream o;
5369 << first_subject()->get_pretty_representation()
5371 << second_subject()->get_pretty_representation()
5373 diff::priv_->pretty_representation_ = o.str();
5375 return diff::priv_->pretty_representation_;
5378 /// Return true iff the current diff node carries a change.
5380 /// @return true iff the current diff node carries a change.
5382 class_diff::has_changes() const
5383 {return (first_class_decl() != second_class_decl());}
5385 /// @return the kind of local change carried by the current diff node.
5386 /// The value returned is zero if the current node carries no local
5389 class_diff::has_local_changes() const
5391 ir::change_kind k = ir::NO_CHANGE_KIND;
5392 if (!equals(*first_class_decl(), *second_class_decl(), &k))
5393 return k & ir::ALL_LOCAL_CHANGES_MASK;
5394 return ir::NO_CHANGE_KIND;
5397 /// @return the first class invoveld in the diff.
5398 shared_ptr<class_decl>
5399 class_diff::first_class_decl() const
5400 {return dynamic_pointer_cast<class_decl>(first_subject());}
5402 /// Getter of the second class involved in the diff.
5404 /// @return the second class invoveld in the diff
5405 shared_ptr<class_decl>
5406 class_diff::second_class_decl() const
5407 {return dynamic_pointer_cast<class_decl>(second_subject());}
5409 /// @return the edit script of the bases of the two classes.
5411 class_diff::base_changes() const
5412 {return get_priv()->base_changes_;}
5414 /// Getter for the deleted base classes of the diff.
5416 /// @return a map containing the deleted base classes, keyed with
5417 /// their pretty representation.
5418 const string_base_sptr_map&
5419 class_diff::deleted_bases() const
5420 {return get_priv()->deleted_bases_;}
5422 /// Getter for the inserted base classes of the diff.
5424 /// @return a map containing the inserted base classes, keyed with
5425 /// their pretty representation.
5426 const string_base_sptr_map&
5427 class_diff::inserted_bases() const
5428 {return get_priv()->inserted_bases_;}
5430 /// Getter for the changed base classes of the diff.
5432 /// @return a sorted vector containing the changed base classes
5433 const base_diff_sptrs_type&
5434 class_diff::changed_bases()
5435 {return get_priv()->sorted_changed_bases_;}
5437 /// @return the edit script of the bases of the two classes.
5439 class_diff::base_changes()
5440 {return get_priv()->base_changes_;}
5442 /// Produce a basic report about the changes between two class_decl.
5444 /// @param out the output stream to report the changes to.
5446 /// @param indent the string to use as an indentation prefix in the
5449 class_diff::report(ostream& out, const string& indent) const
5451 context()->get_reporter()->report(*this, out, indent);
5454 /// Compute the set of changes between two instances of class_decl.
5456 /// Note that the two types must have been created in the same @ref
5457 /// environment, otherwise, this function aborts.
5459 /// @param first the first class_decl to consider.
5461 /// @param second the second class_decl to consider.
5463 /// @return changes the resulting changes.
5465 /// @param ctxt the diff context to use.
5467 compute_diff(const class_decl_sptr first,
5468 const class_decl_sptr second,
5469 diff_context_sptr ctxt)
5471 if (first && second)
5472 ABG_ASSERT(first->get_environment() == second->get_environment());
5474 class_decl_sptr f = is_class_type(look_through_decl_only_class(first)),
5475 s = is_class_type(look_through_decl_only_class(second));
5477 class_diff_sptr changes(new class_diff(f, s, ctxt));
5479 ctxt->initialize_canonical_diff(changes);
5480 ABG_ASSERT(changes->get_canonical_diff());
5482 if (!ctxt->get_canonical_diff_for(first, second))
5484 // Either first or second is a decl-only class; let's set the
5485 // canonical diff here in that case.
5486 diff_sptr canonical_diff = ctxt->get_canonical_diff_for(changes);
5487 ABG_ASSERT(canonical_diff);
5488 ctxt->set_canonical_diff_for(first, second, canonical_diff);
5491 // Ok, so this is an optimization. Do not freak out if it looks
5492 // weird, because, well, it does look weird. This speeds up
5493 // greatly, for instance, the test case given at PR
5494 // libabigail/17948.
5496 // We are setting the private data of the new instance of class_diff
5497 // (which is 'changes') to the private data of its canonical
5498 // instance. That is, we are sharing the private data of 'changes'
5499 // with the private data of its canonical instance to consume less
5500 // memory in cases where the equivalence class of 'changes' is huge.
5502 // But if changes is its own canonical instance, then we initialize
5503 // its private data properly
5504 if (is_class_diff(changes->get_canonical_diff()) == changes.get())
5505 // changes is its own canonical instance, so it gets a brand new
5507 changes->allocate_priv_data();
5510 // changes has a non-empty equivalence class so it's going to
5511 // share its private data with its canonical instance. Next
5512 // time class_diff::get_priv() is invoked, it's going to return
5513 // the shared private data of the canonical instance.
5517 // Compare base specs
5518 compute_diff(f->get_base_specifiers().begin(),
5519 f->get_base_specifiers().end(),
5520 s->get_base_specifiers().begin(),
5521 s->get_base_specifiers().end(),
5522 changes->base_changes());
5524 // Do *not* compare member types because it generates lots of noise
5525 // and I doubt it's really useful.
5527 compute_diff(f->get_member_types().begin(),
5528 f->get_member_types().end(),
5529 s->get_member_types().begin(),
5530 s->get_member_types().end(),
5531 changes->member_types_changes());
5534 // Compare data member
5535 compute_diff(f->get_non_static_data_members().begin(),
5536 f->get_non_static_data_members().end(),
5537 s->get_non_static_data_members().begin(),
5538 s->get_non_static_data_members().end(),
5539 changes->data_members_changes());
5541 // Compare virtual member functions
5542 compute_diff(f->get_virtual_mem_fns().begin(),
5543 f->get_virtual_mem_fns().end(),
5544 s->get_virtual_mem_fns().begin(),
5545 s->get_virtual_mem_fns().end(),
5546 changes->member_fns_changes());
5548 // Compare member function templates
5549 compute_diff(f->get_member_function_templates().begin(),
5550 f->get_member_function_templates().end(),
5551 s->get_member_function_templates().begin(),
5552 s->get_member_function_templates().end(),
5553 changes->member_fn_tmpls_changes());
5555 // Likewise, do not compare member class templates
5557 compute_diff(f->get_member_class_templates().begin(),
5558 f->get_member_class_templates().end(),
5559 s->get_member_class_templates().begin(),
5560 s->get_member_class_templates().end(),
5561 changes->member_class_tmpls_changes());
5564 changes->ensure_lookup_tables_populated();
5569 //</class_diff stuff>
5571 // <base_diff stuff>
5573 /// Populate the vector of children node of the @ref diff base type
5574 /// sub-object of this instance of @ref base_diff.
5576 /// The children node can then later be retrieved using
5577 /// diff::children_node().
5579 base_diff::chain_into_hierarchy()
5580 {append_child_node(get_underlying_class_diff());}
5582 /// @param first the first base spec to consider.
5584 /// @param second the second base spec to consider.
5586 /// @param ctxt the context of the diff. Note that this context
5587 /// object must stay alive at least during the life time of the
5588 /// current instance of @ref base_diff. Otherwise memory corruption
5590 base_diff::base_diff(class_decl::base_spec_sptr first,
5591 class_decl::base_spec_sptr second,
5592 class_diff_sptr underlying,
5593 diff_context_sptr ctxt)
5594 : diff(first, second, ctxt),
5595 priv_(new priv(underlying))
5598 /// Finish building the current instance of @ref base_diff.
5600 base_diff::finish_diff_type()
5602 if (diff::priv_->finished_)
5605 chain_into_hierarchy();
5606 diff::priv_->finished_ = true;
5609 /// Getter for the first base spec of the diff object.
5611 /// @return the first base specifier for the diff object.
5612 class_decl::base_spec_sptr
5613 base_diff::first_base() const
5614 {return dynamic_pointer_cast<class_decl::base_spec>(first_subject());}
5616 /// Getter for the second base spec of the diff object.
5618 /// @return the second base specifier for the diff object.
5619 class_decl::base_spec_sptr
5620 base_diff::second_base() const
5621 {return dynamic_pointer_cast<class_decl::base_spec>(second_subject());}
5623 /// Getter for the diff object for the diff of the underlying base
5626 /// @return the diff object for the diff of the underlying base
5628 const class_diff_sptr
5629 base_diff::get_underlying_class_diff() const
5630 {return priv_->underlying_class_diff_;}
5632 /// Setter for the diff object for the diff of the underlyng base
5635 /// @param d the new diff object for the diff of the underlying base
5638 base_diff::set_underlying_class_diff(class_diff_sptr d)
5639 {priv_->underlying_class_diff_ = d;}
5641 /// @return the pretty representation for the current instance of @ref
5644 base_diff::get_pretty_representation() const
5646 if (diff::priv_->pretty_representation_.empty())
5648 std::ostringstream o;
5650 << first_subject()->get_pretty_representation()
5652 << second_subject()->get_pretty_representation()
5654 diff::priv_->pretty_representation_ = o.str();
5656 return diff::priv_->pretty_representation_;
5659 /// Return true iff the current diff node carries a change.
5661 /// Return true iff the current diff node carries a change.
5663 base_diff::has_changes() const
5664 {return first_base() != second_base();}
5666 /// @return the kind of local change carried by the current diff node.
5667 /// The value returned is zero if the current node carries no local
5670 base_diff::has_local_changes() const
5672 ir::change_kind k = ir::NO_CHANGE_KIND;
5673 if (!equals(*first_base(), *second_base(), &k))
5674 return k & ir::ALL_LOCAL_CHANGES_MASK;
5675 return ir::NO_CHANGE_KIND;
5678 /// Generates a report for the current instance of base_diff.
5680 /// @param out the output stream to send the report to.
5682 /// @param indent the string to use for indentation.
5684 base_diff::report(ostream& out, const string& indent) const
5686 context()->get_reporter()->report(*this, out, indent);
5689 /// Constructs the diff object representing a diff between two base
5690 /// class specifications.
5692 /// Note that the two artifacts must have been created in the same
5693 /// @ref environment, otherwise, this function aborts.
5695 /// @param first the first base class specification.
5697 /// @param second the second base class specification.
5699 /// @param ctxt the content of the diff.
5701 /// @return the resulting diff object.
5703 compute_diff(const class_decl::base_spec_sptr first,
5704 const class_decl::base_spec_sptr second,
5705 diff_context_sptr ctxt)
5707 if (first && second)
5709 ABG_ASSERT(first->get_environment() == second->get_environment());
5710 ABG_ASSERT(first->get_base_class()->get_environment()
5711 == second->get_base_class()->get_environment());
5712 ABG_ASSERT(first->get_environment()
5713 == first->get_base_class()->get_environment());
5716 class_diff_sptr cl = compute_diff(first->get_base_class(),
5717 second->get_base_class(),
5719 base_diff_sptr changes(new base_diff(first, second, cl, ctxt));
5721 ctxt->initialize_canonical_diff(changes);
5726 // </base_diff stuff>
5729 // <union_diff stuff>
5731 /// Clear the lookup tables useful for reporting.
5733 /// This function must be updated each time a lookup table is added or
5734 /// removed from the union_diff::priv.
5736 union_diff::clear_lookup_tables(void)
5737 {class_or_union_diff::clear_lookup_tables();}
5739 /// Tests if the lookup tables are empty.
5741 /// @return true if the lookup tables are empty, false otherwise.
5743 union_diff::lookup_tables_empty(void) const
5744 {return class_or_union_diff::lookup_tables_empty();}
5746 /// If the lookup tables are not yet built, walk the differences and
5749 union_diff::ensure_lookup_tables_populated(void) const
5750 {class_or_union_diff::ensure_lookup_tables_populated();}
5752 /// Allocate the memory for the priv_ pimpl data member of the @ref
5753 /// union_diff class.
5755 union_diff::allocate_priv_data()
5757 class_or_union_diff::allocate_priv_data();
5760 /// Constructor for the @ref union_diff type.
5762 /// @param first_union the first object of the comparison.
5764 /// @param second_union the second object of the comparison.
5766 /// @param ctxt the context of the comparison.
5767 union_diff::union_diff(union_decl_sptr first_union,
5768 union_decl_sptr second_union,
5769 diff_context_sptr ctxt)
5770 : class_or_union_diff(first_union, second_union, ctxt)
5773 /// Finish building the current instance of @ref union_diff.
5775 union_diff::finish_diff_type()
5776 {class_or_union_diff::finish_diff_type();}
5778 /// Destructor of the union_diff node.
5779 union_diff::~union_diff()
5782 /// @return the first object of the comparison.
5784 union_diff::first_union_decl() const
5785 {return is_union_type(first_subject());}
5787 /// @return the second object of the comparison.
5789 union_diff::second_union_decl() const
5790 {return is_union_type(second_subject());}
5792 /// @return the pretty representation of the current diff node.
5794 union_diff::get_pretty_representation() const
5796 if (diff::priv_->pretty_representation_.empty())
5798 std::ostringstream o;
5800 << first_subject()->get_pretty_representation()
5802 << second_subject()->get_pretty_representation()
5804 diff::priv_->pretty_representation_ = o.str();
5806 return diff::priv_->pretty_representation_;
5809 /// Report the changes carried by the current @ref union_diff node in
5810 /// a textual format.
5812 /// @param out the output stream to write the textual report to.
5814 /// @param indent the number of white space to use as indentation.
5816 union_diff::report(ostream& out, const string& indent) const
5818 context()->get_reporter()->report(*this, out, indent);
5821 /// Compute the difference between two @ref union_decl types.
5823 /// Note that the two types must hav been created in the same
5824 /// environment, otherwise, this function aborts.
5826 /// @param first the first @ref union_decl to consider.
5828 /// @param second the second @ref union_decl to consider.
5830 /// @param ctxt the context of the diff to use.
5832 compute_diff(const union_decl_sptr first,
5833 const union_decl_sptr second,
5834 diff_context_sptr ctxt)
5836 if (first && second)
5837 ABG_ASSERT(first->get_environment() == second->get_environment());
5839 union_diff_sptr changes(new union_diff(first, second, ctxt));
5841 ctxt->initialize_canonical_diff(changes);
5842 ABG_ASSERT(changes->get_canonical_diff());
5844 // Ok, so this is an optimization. Do not freak out if it looks
5845 // weird, because, well, it does look weird. This speeds up
5846 // greatly, for instance, the test case given at PR
5847 // libabigail/17948.
5849 // We are setting the private data of the new instance of class_diff
5850 // (which is 'changes') to the private data of its canonical
5851 // instance. That is, we are sharing the private data of 'changes'
5852 // with the private data of its canonical instance to consume less
5853 // memory in cases where the equivalence class of 'changes' is huge.
5855 // But if changes is its own canonical instance, then we initialize
5856 // its private data properly.
5857 if (is_union_diff(changes->get_canonical_diff()) == changes.get())
5858 // changes is its own canonical instance, so it gets a brand new
5860 changes->allocate_priv_data();
5863 // changes has a non-empty equivalence class so it's going to
5864 // share its private data with its canonical instance. Next
5865 // time class_diff::get_priv() is invoked, it's going to return
5866 // the shared private data of the canonical instance.
5870 // Compare data member
5871 compute_diff(first->get_non_static_data_members().begin(),
5872 first->get_non_static_data_members().end(),
5873 second->get_non_static_data_members().begin(),
5874 second->get_non_static_data_members().end(),
5875 changes->data_members_changes());
5878 // Compare member functions
5879 compute_diff(first->get_mem_fns().begin(),
5880 first->get_mem_fns().end(),
5881 second->get_mem_fns().begin(),
5882 second->get_mem_fns().end(),
5883 changes->member_fns_changes());
5885 // Compare member function templates
5886 compute_diff(first->get_member_function_templates().begin(),
5887 first->get_member_function_templates().end(),
5888 second->get_member_function_templates().begin(),
5889 second->get_member_function_templates().end(),
5890 changes->member_fn_tmpls_changes());
5893 changes->ensure_lookup_tables_populated();
5898 // </union_diff stuff>
5900 //<scope_diff stuff>
5902 /// Clear the lookup tables that are useful for reporting.
5904 /// This function must be updated each time a lookup table is added or
5907 scope_diff::clear_lookup_tables()
5909 priv_->deleted_types_.clear();
5910 priv_->deleted_decls_.clear();
5911 priv_->inserted_types_.clear();
5912 priv_->inserted_decls_.clear();
5913 priv_->changed_types_.clear();
5914 priv_->changed_decls_.clear();
5915 priv_->removed_types_.clear();
5916 priv_->removed_decls_.clear();
5917 priv_->added_types_.clear();
5918 priv_->added_decls_.clear();
5921 /// Tests if the lookup tables are empty.
5923 /// This function must be updated each time a lookup table is added or
5926 /// @return true iff all the lookup tables are empty.
5928 scope_diff::lookup_tables_empty() const
5930 return (priv_->deleted_types_.empty()
5931 && priv_->deleted_decls_.empty()
5932 && priv_->inserted_types_.empty()
5933 && priv_->inserted_decls_.empty()
5934 && priv_->changed_types_.empty()
5935 && priv_->changed_decls_.empty()
5936 && priv_->removed_types_.empty()
5937 && priv_->removed_decls_.empty()
5938 && priv_->added_types_.empty()
5939 && priv_->added_decls_.empty());
5942 /// If the lookup tables are not yet built, walk the member_changes_
5943 /// member and fill the lookup tables.
5945 scope_diff::ensure_lookup_tables_populated()
5947 if (!lookup_tables_empty())
5950 edit_script& e = priv_->member_changes_;
5952 // Populate deleted types & decls lookup tables.
5953 for (vector<deletion>::const_iterator i = e.deletions().begin();
5954 i != e.deletions().end();
5957 decl_base_sptr decl = deleted_member_at(i);
5958 string qname = decl->get_qualified_name();
5961 class_decl_sptr klass_decl = dynamic_pointer_cast<class_decl>(decl);
5962 if (klass_decl && klass_decl->get_is_declaration_only())
5965 ABG_ASSERT(priv_->deleted_types_.find(qname)
5966 == priv_->deleted_types_.end());
5967 priv_->deleted_types_[qname] = decl;
5971 ABG_ASSERT(priv_->deleted_decls_.find(qname)
5972 == priv_->deleted_decls_.end());
5973 priv_->deleted_decls_[qname] = decl;
5977 // Populate inserted types & decls as well as chagned types & decls
5979 for (vector<insertion>::const_iterator it = e.insertions().begin();
5980 it != e.insertions().end();
5983 for (vector<unsigned>::const_iterator i = it->inserted_indexes().begin();
5984 i != it->inserted_indexes().end();
5987 decl_base_sptr decl = inserted_member_at(i);
5988 string qname = decl->get_qualified_name();
5991 class_decl_sptr klass_decl =
5992 dynamic_pointer_cast<class_decl>(decl);
5993 if (klass_decl && klass_decl->get_is_declaration_only())
5996 ABG_ASSERT(priv_->inserted_types_.find(qname)
5997 == priv_->inserted_types_.end());
5998 string_decl_base_sptr_map::const_iterator j =
5999 priv_->deleted_types_.find(qname);
6000 if (j != priv_->deleted_types_.end())
6002 if (*j->second != *decl)
6003 priv_->changed_types_[qname] =
6004 compute_diff(j->second, decl, context());
6005 priv_->deleted_types_.erase(j);
6008 priv_->inserted_types_[qname] = decl;
6012 ABG_ASSERT(priv_->inserted_decls_.find(qname)
6013 == priv_->inserted_decls_.end());
6014 string_decl_base_sptr_map::const_iterator j =
6015 priv_->deleted_decls_.find(qname);
6016 if (j != priv_->deleted_decls_.end())
6018 if (*j->second != *decl)
6019 priv_->changed_decls_[qname] =
6020 compute_diff(j->second, decl, context());
6021 priv_->deleted_decls_.erase(j);
6024 priv_->inserted_decls_[qname] = decl;
6029 sort_string_diff_sptr_map(priv_->changed_decls_,
6030 priv_->sorted_changed_decls_);
6031 sort_string_diff_sptr_map(priv_->changed_types_,
6032 priv_->sorted_changed_types_);
6034 // Populate removed types/decls lookup tables
6035 for (string_decl_base_sptr_map::const_iterator i =
6036 priv_->deleted_types_.begin();
6037 i != priv_->deleted_types_.end();
6040 string_decl_base_sptr_map::const_iterator r =
6041 priv_->inserted_types_.find(i->first);
6042 if (r == priv_->inserted_types_.end())
6043 priv_->removed_types_[i->first] = i->second;
6045 for (string_decl_base_sptr_map::const_iterator i =
6046 priv_->deleted_decls_.begin();
6047 i != priv_->deleted_decls_.end();
6050 string_decl_base_sptr_map::const_iterator r =
6051 priv_->inserted_decls_.find(i->first);
6052 if (r == priv_->inserted_decls_.end())
6053 priv_->removed_decls_[i->first] = i->second;
6056 // Populate added types/decls.
6057 for (string_decl_base_sptr_map::const_iterator i =
6058 priv_->inserted_types_.begin();
6059 i != priv_->inserted_types_.end();
6062 string_decl_base_sptr_map::const_iterator r =
6063 priv_->deleted_types_.find(i->first);
6064 if (r == priv_->deleted_types_.end())
6065 priv_->added_types_[i->first] = i->second;
6067 for (string_decl_base_sptr_map::const_iterator i =
6068 priv_->inserted_decls_.begin();
6069 i != priv_->inserted_decls_.end();
6072 string_decl_base_sptr_map::const_iterator r =
6073 priv_->deleted_decls_.find(i->first);
6074 if (r == priv_->deleted_decls_.end())
6075 priv_->added_decls_[i->first] = i->second;
6079 /// Populate the vector of children node of the @ref diff base type
6080 /// sub-object of this instance of @ref scope_diff.
6082 /// The children node can then later be retrieved using
6083 /// diff::children_node().
6085 scope_diff::chain_into_hierarchy()
6087 for (diff_sptrs_type::const_iterator i = changed_types().begin();
6088 i != changed_types().end();
6091 append_child_node(*i);
6093 for (diff_sptrs_type::const_iterator i = changed_decls().begin();
6094 i != changed_decls().end();
6097 append_child_node(*i);
6100 /// Constructor for scope_diff
6102 /// @param first_scope the first scope to consider for the diff.
6104 /// @param second_scope the second scope to consider for the diff.
6106 /// @param ctxt the diff context to use. Note that this context
6107 /// object must stay alive at least during the life time of the
6108 /// current instance of @ref scope_diff. Otherwise memory corruption
6110 scope_diff::scope_diff(scope_decl_sptr first_scope,
6111 scope_decl_sptr second_scope,
6112 diff_context_sptr ctxt)
6113 : diff(first_scope, second_scope, ctxt),
6117 /// Finish building the current instance of @ref scope_diff.
6119 scope_diff::finish_diff_type()
6121 if (diff::priv_->finished_)
6123 chain_into_hierarchy();
6124 diff::priv_->finished_ = true;
6127 /// Getter for the first scope of the diff.
6129 /// @return the first scope of the diff.
6130 const scope_decl_sptr
6131 scope_diff::first_scope() const
6132 {return dynamic_pointer_cast<scope_decl>(first_subject());}
6134 /// Getter for the second scope of the diff.
6136 /// @return the second scope of the diff.
6137 const scope_decl_sptr
6138 scope_diff::second_scope() const
6139 {return dynamic_pointer_cast<scope_decl>(second_subject());}
6141 /// Accessor of the edit script of the members of a scope.
6143 /// This edit script is computed using the equality operator that
6144 /// applies to shared_ptr<decl_base>.
6146 /// That has interesting consequences. For instance, consider two
6147 /// scopes S0 and S1. S0 contains a class C0 and S1 contains a class
6148 /// S0'. C0 and C0' have the same qualified name, but have different
6149 /// members. The edit script will consider that C0 has been deleted
6150 /// from S0 and that S0' has been inserted. This is a low level
6151 /// canonical representation of the changes; a higher level
6152 /// representation would give us a simpler way to say "the class C0
6153 /// has been modified into C0'". But worry not. We do have such
6154 /// higher representation as well; that is what changed_types() and
6155 /// changed_decls() is for.
6157 /// @return the edit script of the changes encapsulatd in this
6158 /// instance of scope_diff.
6160 scope_diff::member_changes() const
6161 {return priv_->member_changes_;}
6163 /// Accessor of the edit script of the members of a scope.
6165 /// This edit script is computed using the equality operator that
6166 /// applies to shared_ptr<decl_base>.
6168 /// That has interesting consequences. For instance, consider two
6169 /// scopes S0 and S1. S0 contains a class C0 and S1 contains a class
6170 /// S0'. C0 and C0' have the same qualified name, but have different
6171 /// members. The edit script will consider that C0 has been deleted
6172 /// from S0 and that S0' has been inserted. This is a low level
6173 /// canonical representation of the changes; a higher level
6174 /// representation would give us a simpler way to say "the class C0
6175 /// has been modified into C0'". But worry not. We do have such
6176 /// higher representation as well; that is what changed_types() and
6177 /// changed_decls() is for.
6179 /// @return the edit script of the changes encapsulatd in this
6180 /// instance of scope_diff.
6182 scope_diff::member_changes()
6183 {return priv_->member_changes_;}
6185 /// Accessor that eases the manipulation of the edit script associated
6186 /// to this instance. It returns the scope member that is reported
6187 /// (in the edit script) as deleted at a given index.
6189 /// @param i the index (in the edit script) of an element of the first
6190 /// scope that has been reported as being delete.
6192 /// @return the scope member that has been reported by the edit script
6193 /// as being deleted at index i.
6194 const decl_base_sptr
6195 scope_diff::deleted_member_at(unsigned i) const
6197 scope_decl_sptr scope = dynamic_pointer_cast<scope_decl>(first_subject());
6198 return scope->get_member_decls()[i];
6201 /// Accessor that eases the manipulation of the edit script associated
6202 /// to this instance. It returns the scope member (of the first scope
6203 /// of this diff instance) that is reported (in the edit script) as
6204 /// deleted at a given iterator.
6206 /// @param i the iterator of an element of the first scope that has
6207 /// been reported as being delete.
6209 /// @return the scope member of the first scope of this diff that has
6210 /// been reported by the edit script as being deleted at iterator i.
6211 const decl_base_sptr
6212 scope_diff::deleted_member_at(vector<deletion>::const_iterator i) const
6213 {return deleted_member_at(i->index());}
6215 /// Accessor that eases the manipulation of the edit script associated
6216 /// to this instance. It returns the scope member (of the second
6217 /// scope of this diff instance) that is reported as being inserted
6218 /// from a given index.
6220 /// @param i the index of an element of the second scope this diff
6221 /// that has been reported by the edit script as being inserted.
6223 /// @return the scope member of the second scope of this diff that has
6224 /// been reported as being inserted from index i.
6225 const decl_base_sptr
6226 scope_diff::inserted_member_at(unsigned i)
6228 scope_decl_sptr scope = dynamic_pointer_cast<scope_decl>(second_subject());
6229 return scope->get_member_decls()[i];
6232 /// Accessor that eases the manipulation of the edit script associated
6233 /// to this instance. It returns the scope member (of the second
6234 /// scope of this diff instance) that is reported as being inserted
6235 /// from a given iterator.
6237 /// @param i the iterator of an element of the second scope this diff
6238 /// that has been reported by the edit script as being inserted.
6240 /// @return the scope member of the second scope of this diff that has
6241 /// been reported as being inserted from iterator i.
6242 const decl_base_sptr
6243 scope_diff::inserted_member_at(vector<unsigned>::const_iterator i)
6244 {return inserted_member_at(*i);}
6246 /// @return a sorted vector of the types which content has changed
6247 /// from the first scope to the other.
6248 const diff_sptrs_type&
6249 scope_diff::changed_types() const
6250 {return priv_->sorted_changed_types_;}
6252 /// @return a sorted vector of the decls which content has changed
6253 /// from the first scope to the other.
6254 const diff_sptrs_type&
6255 scope_diff::changed_decls() const
6256 {return priv_->sorted_changed_decls_;}
6258 const string_decl_base_sptr_map&
6259 scope_diff::removed_types() const
6260 {return priv_->removed_types_;}
6262 const string_decl_base_sptr_map&
6263 scope_diff::removed_decls() const
6264 {return priv_->removed_decls_;}
6266 const string_decl_base_sptr_map&
6267 scope_diff::added_types() const
6268 {return priv_->added_types_;}
6270 const string_decl_base_sptr_map&
6271 scope_diff::added_decls() const
6272 {return priv_->added_decls_;}
6274 /// @return the pretty representation for the current instance of @ref
6277 scope_diff::get_pretty_representation() const
6279 if (diff::priv_->pretty_representation_.empty())
6281 std::ostringstream o;
6283 << first_subject()->get_pretty_representation()
6285 << second_subject()->get_pretty_representation()
6287 diff::priv_->pretty_representation_ = o.str();
6289 return diff::priv_->pretty_representation_;
6292 /// Return true iff the current diff node carries a change.
6294 /// Return true iff the current diff node carries a change.
6296 scope_diff::has_changes() const
6298 // TODO: add the number of really removed/added stuff.
6299 return changed_types().size() + changed_decls().size();
6302 /// @return the kind of local change carried by the current diff node.
6303 /// The value returned is zero if the current node carries no local
6306 scope_diff::has_local_changes() const
6308 ir::change_kind k = ir::NO_CHANGE_KIND;
6309 if (!equals(*first_scope(), *second_scope(), &k))
6310 return k & ir::ALL_LOCAL_CHANGES_MASK;
6311 return ir::NO_CHANGE_KIND;
6314 /// Report the changes of one scope against another.
6316 /// @param out the out stream to report the changes to.
6318 /// @param indent the string to use for indentation.
6320 scope_diff::report(ostream& out, const string& indent) const
6322 context()->get_reporter()->report(*this, out, indent);
6325 /// Compute the diff between two scopes.
6327 /// Note that the two decls must have been created in the same @ref
6328 /// environment, otherwise, this function aborts.
6330 /// @param first the first scope to consider in computing the diff.
6332 /// @param second the second scope to consider in the diff
6333 /// computation. The second scope is diffed against the first scope.
6335 /// @param d a pointer to the diff object to populate with the
6338 /// @return return the populated \a d parameter passed to this
6341 /// @param ctxt the diff context to use.
6343 compute_diff(const scope_decl_sptr first,
6344 const scope_decl_sptr second,
6346 diff_context_sptr ctxt)
6348 ABG_ASSERT(d->first_scope() == first && d->second_scope() == second);
6350 if (first && second)
6351 ABG_ASSERT(first->get_environment() == second->get_environment());
6353 compute_diff(first->get_member_decls().begin(),
6354 first->get_member_decls().end(),
6355 second->get_member_decls().begin(),
6356 second->get_member_decls().end(),
6357 d->member_changes());
6359 d->ensure_lookup_tables_populated();
6365 /// Compute the diff between two scopes.
6367 /// Note that the two decls must have been created in the same @ref
6368 /// environment, otherwise, this function aborts.
6370 /// @param first_scope the first scope to consider in computing the diff.
6372 /// @param second_scope the second scope to consider in the diff
6373 /// computation. The second scope is diffed against the first scope.
6375 /// @param ctxt the diff context to use.
6377 /// @return return the resulting diff
6379 compute_diff(const scope_decl_sptr first_scope,
6380 const scope_decl_sptr second_scope,
6381 diff_context_sptr ctxt)
6383 if (first_scope && second_scope)
6384 ABG_ASSERT(first_scope->get_environment()
6385 == second_scope->get_environment());
6387 scope_diff_sptr d(new scope_diff(first_scope, second_scope, ctxt));
6388 d = compute_diff(first_scope, second_scope, d, ctxt);
6389 ctxt->initialize_canonical_diff(d);
6393 //</scope_diff stuff>
6395 // <fn_parm_diff stuff>
6397 /// Constructor for the fn_parm_diff type.
6399 /// @param first the first subject of the diff.
6401 /// @param second the second subject of the diff.
6403 /// @param ctxt the context of the diff. Note that this context
6404 /// object must stay alive at least during the life time of the
6405 /// current instance of @ref fn_parm_diff. Otherwise memory
6406 /// corruption issues occur.
6407 fn_parm_diff::fn_parm_diff(const function_decl::parameter_sptr first,
6408 const function_decl::parameter_sptr second,
6409 diff_context_sptr ctxt)
6410 : decl_diff_base(first, second, ctxt),
6413 ABG_ASSERT(first->get_index() == second->get_index());
6414 priv_->type_diff = compute_diff(first->get_type(),
6417 ABG_ASSERT(priv_->type_diff);
6420 /// Finish the building of the current instance of @ref fn_parm_diff.
6422 fn_parm_diff::finish_diff_type()
6424 if (diff::priv_->finished_)
6426 chain_into_hierarchy();
6427 diff::priv_->finished_ = true;
6430 /// Getter for the first subject of this diff node.
6432 /// @return the first function_decl::parameter_sptr subject of this
6434 const function_decl::parameter_sptr
6435 fn_parm_diff::first_parameter() const
6436 {return dynamic_pointer_cast<function_decl::parameter>(first_subject());}
6438 /// Getter for the second subject of this diff node.
6440 /// @return the second function_decl::parameter_sptr subject of this
6442 const function_decl::parameter_sptr
6443 fn_parm_diff::second_parameter() const
6444 {return dynamic_pointer_cast<function_decl::parameter>(second_subject());}
6446 /// Getter for the diff representing the changes on the type of the
6447 /// function parameter involved in the current instance of @ref
6450 /// @return a diff_sptr representing the changes on the type of the
6451 /// function parameter we are interested in.
6453 fn_parm_diff::type_diff() const
6454 {return priv_->type_diff;}
6456 /// Build and return a textual representation of the current instance
6457 /// of @ref fn_parm_diff.
6459 /// @return the string representing the current instance of
6462 fn_parm_diff::get_pretty_representation() const
6464 if (diff::priv_->pretty_representation_.empty())
6466 std::ostringstream o;
6467 o << "function_parameter_diff["
6468 << first_subject()->get_pretty_representation()
6470 << second_subject()->get_pretty_representation()
6472 diff::priv_->pretty_representation_ = o.str();
6474 return diff::priv_->pretty_representation_;
6477 /// Return true iff the current diff node carries a change.
6479 /// @return true iff the current diff node carries a change.
6481 fn_parm_diff::has_changes() const
6482 {return *first_parameter() != *second_parameter();}
6484 /// Check if the current diff node carries a local change.
6486 /// @return the kind of local change carried by the current diff node.
6487 /// The value returned is zero if the current node carries no local
6490 fn_parm_diff::has_local_changes() const
6492 ir::change_kind k = ir::NO_CHANGE_KIND;
6493 if (!equals(*first_parameter(), *second_parameter(), &k))
6494 return k & ir::ALL_LOCAL_CHANGES_MASK;
6495 return ir::NO_CHANGE_KIND;
6498 /// Emit a textual report about the current fn_parm_diff instance.
6500 /// @param out the output stream to emit the textual report to.
6502 /// @param indent the indentation string to use in the report.
6504 fn_parm_diff::report(ostream& out, const string& indent) const
6506 context()->get_reporter()->report(*this, out, indent);
6509 /// Populate the vector of children nodes of the @ref diff base type
6510 /// sub-object of this instance of @ref fn_parm_diff.
6512 /// The children nodes can then later be retrieved using
6513 /// diff::children_nodes()
6515 fn_parm_diff::chain_into_hierarchy()
6518 append_child_node(type_diff());
6521 /// Compute the difference between two function_decl::parameter_sptr;
6522 /// that is, between two function parameters. Return a resulting
6523 /// fn_parm_diff_sptr that represents the changes.
6525 /// Note that the two decls must have been created in the same @ref
6526 /// environment, otherwise, this function aborts.
6528 /// @param first the first subject of the diff.
6530 /// @param second the second subject of the diff.
6532 /// @param ctxt the context of the diff.
6534 /// @return fn_parm_diff_sptr the resulting diff node.
6536 compute_diff(const function_decl::parameter_sptr first,
6537 const function_decl::parameter_sptr second,
6538 diff_context_sptr ctxt)
6540 if (!first || !second)
6541 return fn_parm_diff_sptr();
6543 ABG_ASSERT(first->get_environment() == second->get_environment());
6545 fn_parm_diff_sptr result(new fn_parm_diff(first, second, ctxt));
6546 ctxt->initialize_canonical_diff(result);
6550 // </fn_parm_diff stuff>
6552 // <function_type_diff stuff>
6555 function_type_diff::ensure_lookup_tables_populated()
6557 priv_->return_type_diff_ =
6558 compute_diff(first_function_type()->get_return_type(),
6559 second_function_type()->get_return_type(),
6563 function_decl::parameter_sptr parm;
6564 for (vector<deletion>::const_iterator i =
6565 priv_->parm_changes_.deletions().begin();
6566 i != priv_->parm_changes_.deletions().end();
6569 parm = *(first_function_type()->get_first_non_implicit_parm()
6571 parm_name = parm->get_name_id();
6572 // If for a reason the type name is empty we want to know and
6574 ABG_ASSERT(!parm_name.empty());
6575 priv_->deleted_parms_[parm_name] = parm;
6576 priv_->deleted_parms_by_id_[parm->get_index()] = parm;
6579 for (vector<insertion>::const_iterator i =
6580 priv_->parm_changes_.insertions().begin();
6581 i != priv_->parm_changes_.insertions().end();
6584 for (vector<unsigned>::const_iterator j =
6585 i->inserted_indexes().begin();
6586 j != i->inserted_indexes().end();
6589 parm = *(second_function_type()->get_first_non_implicit_parm() + *j);
6590 parm_name = parm->get_name_id();
6591 // If for a reason the type name is empty we want to know and
6593 ABG_ASSERT(!parm_name.empty());
6595 string_parm_map::const_iterator k =
6596 priv_->deleted_parms_.find(parm_name);
6597 if (k != priv_->deleted_parms_.end())
6599 if (*k->second != *parm)
6600 priv_->subtype_changed_parms_[parm_name] =
6601 compute_diff(k->second, parm, context());
6602 priv_->deleted_parms_.erase(parm_name);
6605 priv_->added_parms_[parm_name] = parm;
6608 unsigned_parm_map::const_iterator k =
6609 priv_->deleted_parms_by_id_.find(parm->get_index());
6610 if (k != priv_->deleted_parms_by_id_.end())
6612 if (*k->second != *parm
6613 && (k->second->get_name_id() != parm_name))
6614 priv_->changed_parms_by_id_[parm->get_index()] =
6615 compute_diff(k->second, parm, context());
6616 priv_->added_parms_.erase(parm_name);
6617 priv_->deleted_parms_.erase(k->second->get_name_id());
6618 priv_->deleted_parms_by_id_.erase(parm->get_index());
6621 priv_->added_parms_by_id_[parm->get_index()] = parm;
6626 sort_string_fn_parm_diff_sptr_map(priv_->subtype_changed_parms_,
6627 priv_->sorted_subtype_changed_parms_);
6628 sort_string_fn_parm_diff_sptr_map(priv_->changed_parms_by_id_,
6629 priv_->sorted_changed_parms_by_id_);
6630 sort_string_parm_map(priv_->deleted_parms_,
6631 priv_->sorted_deleted_parms_);
6633 sort_string_parm_map(priv_->added_parms_,
6634 priv_->sorted_added_parms_);
6637 /// In the vector of deleted parameters, get the one that is at a given
6640 /// @param i the index of the deleted parameter to get.
6642 /// @return the parameter returned.
6643 const function_decl::parameter_sptr
6644 function_type_diff::deleted_parameter_at(int i) const
6645 {return first_function_type()->get_parameters()[i];}
6647 /// In the vector of inserted parameters, get the one that is at a
6650 /// @param i the index of the inserted parameter to get.
6652 /// @return the parameter returned.
6653 const function_decl::parameter_sptr
6654 function_type_diff::inserted_parameter_at(int i) const
6655 {return second_function_type()->get_parameters()[i];}
6657 /// Consutrctor of the @ref function_type type.
6659 /// @param first the first @ref function_type subject of the diff to
6662 /// @param second the second @ref function_type subject of the diff to
6665 /// @param ctxt the diff context to be used by the newly created
6666 /// instance of function_type_diff. Note that this context object
6667 /// must stay alive at least during the life time of the current
6668 /// instance of @ref function_type_diff. Otherwise memory corruption
6670 function_type_diff::function_type_diff(const function_type_sptr first,
6671 const function_type_sptr second,
6672 diff_context_sptr ctxt)
6673 : type_diff_base(first, second, ctxt),
6677 /// Finish building the current instance of @ref function_type_diff
6679 function_type_diff::finish_diff_type()
6681 if (diff::priv_->finished_)
6683 chain_into_hierarchy();
6684 diff::priv_->finished_ = true;
6687 /// Getter for the first subject of the diff.
6689 /// @return the first function type involved in the diff.
6690 const function_type_sptr
6691 function_type_diff::first_function_type() const
6692 {return dynamic_pointer_cast<function_type>(first_subject());}
6694 /// Getter for the second subject of the diff.
6696 /// @return the second function type involved in the diff.
6697 const function_type_sptr
6698 function_type_diff::second_function_type() const
6699 {return dynamic_pointer_cast<function_type>(second_subject());}
6701 /// Getter for the diff of the return types of the two function types
6702 /// of the current diff.
6704 /// @return the diff of the return types of the two function types of
6705 /// the current diff.
6707 function_type_diff::return_type_diff() const
6708 {return priv_->return_type_diff_;}
6710 /// Getter for the map of function parameter changes of the current diff.
6712 /// @return a map of function parameter changes of the current diff.
6713 const string_fn_parm_diff_sptr_map&
6714 function_type_diff::subtype_changed_parms() const
6715 {return priv_->subtype_changed_parms_;}
6717 /// Getter for the map of parameters that got removed.
6719 /// @return the map of parameters that got removed.
6720 const string_parm_map&
6721 function_type_diff::removed_parms() const
6722 {return priv_->deleted_parms_;}
6724 /// Getter for the map of parameters that got added.
6726 /// @return the map of parameters that got added.
6727 const string_parm_map&
6728 function_type_diff::added_parms() const
6729 {return priv_->added_parms_;}
6731 /// Build and return a copy of a pretty representation of the current
6732 /// instance of @ref function_type_diff.
6734 /// @return a copy of the pretty representation of the current
6735 /// instance of @ref function_type_diff.
6737 function_type_diff::get_pretty_representation() const
6739 if (diff::priv_->pretty_representation_.empty())
6741 std::ostringstream o;
6742 o << "function_type_diff["
6743 << abigail::ir::get_pretty_representation(first_function_type())
6745 << abigail::ir::get_pretty_representation(second_function_type())
6747 diff::priv_->pretty_representation_ = o.str();
6749 return diff::priv_->pretty_representation_;
6752 /// Test if the current diff node carries changes.
6754 /// @return true iff the current diff node carries changes.
6756 function_type_diff::has_changes() const
6757 {return *first_function_type() != *second_function_type();}
6759 /// Test if the current diff node carries local changes.
6761 /// A local change is a change that is carried by this diff node, not
6762 /// by any of its children nodes.
6764 /// @return the kind of local change carried by the current diff node.
6765 /// The value returned is zero if the current node carries no local
6768 function_type_diff::has_local_changes() const
6770 ir::change_kind k = ir::NO_CHANGE_KIND;
6771 if (!equals(*first_function_type(), *second_function_type(), &k))
6772 return k & ir::ALL_LOCAL_CHANGES_MASK;
6773 return ir::NO_CHANGE_KIND;
6776 /// Build and emit a textual report about the current @ref
6777 /// function_type_diff instance.
6779 /// @param out the output stream.
6781 /// @param indent the indentation string to use.
6783 function_type_diff::report(ostream& out, const string& indent) const
6785 context()->get_reporter()->report(*this, out, indent);
6788 /// Populate the vector of children node of the @ref diff base type
6789 /// sub-object of this instance of @ref function_type_diff.
6791 /// The children node can then later be retrieved using
6792 /// diff::children_node().
6794 function_type_diff::chain_into_hierarchy()
6796 if (diff_sptr d = return_type_diff())
6797 append_child_node(d);
6799 for (vector<fn_parm_diff_sptr>::const_iterator i =
6800 priv_->sorted_subtype_changed_parms_.begin();
6801 i != priv_->sorted_subtype_changed_parms_.end();
6803 if (diff_sptr d = *i)
6804 append_child_node(d);
6806 for (vector<fn_parm_diff_sptr>::const_iterator i =
6807 priv_->sorted_changed_parms_by_id_.begin();
6808 i != priv_->sorted_changed_parms_by_id_.end();
6810 if (diff_sptr d = *i)
6811 append_child_node(d);
6814 /// Compute the diff between two instances of @ref function_type.
6816 /// Note that the two types must have been created in the same @ref
6817 /// environment, otherwise, this function aborts.
6819 /// @param first the first @ref function_type to consider for the diff.
6821 /// @param second the second @ref function_type to consider for the diff.
6823 /// @param ctxt the diff context to use.
6825 /// @return the resulting diff between the two @ref function_type.
6826 function_type_diff_sptr
6827 compute_diff(const function_type_sptr first,
6828 const function_type_sptr second,
6829 diff_context_sptr ctxt)
6831 if (!first || !second)
6833 // TODO: implement this for either first or second being NULL.
6834 return function_type_diff_sptr();
6837 ABG_ASSERT(first->get_environment() == second->get_environment());
6839 function_type_diff_sptr result(new function_type_diff(first, second, ctxt));
6841 diff_utils::compute_diff(first->get_first_non_implicit_parm(),
6842 first->get_parameters().end(),
6843 second->get_first_non_implicit_parm(),
6844 second->get_parameters().end(),
6845 result->priv_->parm_changes_);
6847 result->ensure_lookup_tables_populated();
6849 ctxt->initialize_canonical_diff(result);
6853 // </function_type_diff stuff>
6855 // <function_decl_diff stuff>
6857 /// Build the lookup tables of the diff, if necessary.
6859 function_decl_diff::ensure_lookup_tables_populated()
6863 /// Populate the vector of children node of the @ref diff base type
6864 /// sub-object of this instance of @ref function_decl_diff.
6866 /// The children node can then later be retrieved using
6867 /// diff::children_node().
6869 function_decl_diff::chain_into_hierarchy()
6871 if (diff_sptr d = type_diff())
6872 append_child_node(d);
6875 /// Constructor for function_decl_diff
6877 /// @param first the first function considered by the diff.
6879 /// @param second the second function considered by the diff.
6881 /// @param ctxt the context of the diff. Note that this context
6882 /// object must stay alive at least during the life time of the
6883 /// current instance of @ref function_decl_diff. Otherwise memory
6884 /// corruption issues occur.
6885 function_decl_diff::function_decl_diff(const function_decl_sptr first,
6886 const function_decl_sptr second,
6887 diff_context_sptr ctxt)
6888 : decl_diff_base(first, second, ctxt),
6893 /// Finish building the current instance of @ref function_decl_diff.
6895 function_decl_diff::finish_diff_type()
6897 if (diff::priv_->finished_)
6899 chain_into_hierarchy();
6900 diff::priv_->finished_ = true;
6903 /// @return the first function considered by the diff.
6904 const function_decl_sptr
6905 function_decl_diff::first_function_decl() const
6906 {return dynamic_pointer_cast<function_decl>(first_subject());}
6908 /// @return the second function considered by the diff.
6909 const function_decl_sptr
6910 function_decl_diff::second_function_decl() const
6911 {return dynamic_pointer_cast<function_decl>(second_subject());}
6913 const function_type_diff_sptr
6914 function_decl_diff::type_diff() const
6915 {return priv_->type_diff_;}
6917 /// @return the pretty representation for the current instance of @ref
6918 /// function_decl_diff.
6920 function_decl_diff::get_pretty_representation() const
6922 if (diff::priv_->pretty_representation_.empty())
6924 std::ostringstream o;
6925 o << "function_diff["
6926 << first_subject()->get_pretty_representation()
6928 << second_subject()->get_pretty_representation()
6930 diff::priv_->pretty_representation_ = o.str();
6932 return diff::priv_->pretty_representation_;
6935 /// Return true iff the current diff node carries a change.
6937 /// @return true iff the current diff node carries a change.
6939 function_decl_diff::has_changes() const
6940 {return *first_function_decl() != *second_function_decl();}
6942 /// @return the kind of local change carried by the current diff node.
6943 /// The value returned is zero if the current node carries no local
6946 function_decl_diff::has_local_changes() const
6948 ir::change_kind k = ir::NO_CHANGE_KIND;
6949 if (!equals(*first_function_decl(), *second_function_decl(), &k))
6950 return k & ir::ALL_LOCAL_CHANGES_MASK;
6951 return ir::NO_CHANGE_KIND;
6954 /// Serialize a report of the changes encapsulated in the current
6955 /// instance of @ref function_decl_diff over to an output stream.
6957 /// @param out the output stream to serialize the report to.
6959 /// @param indent the string to use an an indentation prefix.
6961 function_decl_diff::report(ostream& out, const string& indent) const
6963 context()->get_reporter()->report(*this, out, indent);
6966 /// Compute the diff between two function_decl.
6968 /// Note that the two decls must have been created in the same @ref
6969 /// environment, otherwise, this function aborts.
6971 /// @param first the first function_decl to consider for the diff
6973 /// @param second the second function_decl to consider for the diff
6975 /// @param ctxt the diff context to use.
6977 /// @return the computed diff
6978 function_decl_diff_sptr
6979 compute_diff(const function_decl_sptr first,
6980 const function_decl_sptr second,
6981 diff_context_sptr ctxt)
6983 if (!first || !second)
6985 // TODO: implement this for either first or second being NULL.
6986 return function_decl_diff_sptr();
6989 ABG_ASSERT(first->get_environment() == second->get_environment());
6991 function_type_diff_sptr type_diff = compute_diff(first->get_type(),
6995 function_decl_diff_sptr result(new function_decl_diff(first, second,
6997 result->priv_->type_diff_ = type_diff;
6999 result->ensure_lookup_tables_populated();
7001 ctxt->initialize_canonical_diff(result);
7006 // </function_decl_diff stuff>
7008 // <type_decl_diff stuff>
7010 /// Constructor for type_decl_diff.
7012 /// @param first the first subject of the diff.
7014 /// @param second the second subject of the diff.
7016 /// @param ctxt the context of the diff. Note that this context
7017 /// object must stay alive at least during the life time of the
7018 /// current instance of @ref type_decl_diff. Otherwise memory
7019 /// corruption issues occur.
7020 type_decl_diff::type_decl_diff(const type_decl_sptr first,
7021 const type_decl_sptr second,
7022 diff_context_sptr ctxt)
7023 : type_diff_base(first, second, ctxt)
7026 /// Finish building the current instance of @ref type_decl_diff.
7028 type_decl_diff::finish_diff_type()
7030 if (diff::priv_->finished_)
7032 diff::priv_->finished_ = true;
7035 /// Getter for the first subject of the type_decl_diff.
7037 /// @return the first type_decl involved in the diff.
7038 const type_decl_sptr
7039 type_decl_diff::first_type_decl() const
7040 {return dynamic_pointer_cast<type_decl>(first_subject());}
7042 /// Getter for the second subject of the type_decl_diff.
7044 /// @return the second type_decl involved in the diff.
7045 const type_decl_sptr
7046 type_decl_diff::second_type_decl() const
7047 {return dynamic_pointer_cast<type_decl>(second_subject());}
7049 /// @return the pretty representation for the current instance of @ref
7052 type_decl_diff::get_pretty_representation() const
7054 if (diff::priv_->pretty_representation_.empty())
7056 std::ostringstream o;
7057 o << "type_decl_diff["
7058 << first_subject()->get_pretty_representation()
7060 << second_subject()->get_pretty_representation()
7062 diff::priv_->pretty_representation_ = o.str();
7064 return diff::priv_->pretty_representation_;
7066 /// Return true iff the current diff node carries a change.
7068 /// @return true iff the current diff node carries a change.
7070 type_decl_diff::has_changes() const
7071 {return first_type_decl() != second_type_decl();}
7073 /// @return the kind of local change carried by the current diff node.
7074 /// The value returned is zero if the current node carries no local
7077 type_decl_diff::has_local_changes() const
7079 ir::change_kind k = ir::NO_CHANGE_KIND;
7080 if (!equals(*first_type_decl(), *second_type_decl(), &k))
7081 return k & ir::ALL_LOCAL_CHANGES_MASK;
7082 return ir::NO_CHANGE_KIND;
7084 /// Ouputs a report of the differences between of the two type_decl
7085 /// involved in the type_decl_diff.
7087 /// @param out the output stream to emit the report to.
7089 /// @param indent the string to use for indentatino indent.
7091 type_decl_diff::report(ostream& out, const string& indent) const
7093 context()->get_reporter()->report(*this, out, indent);
7096 /// Compute a diff between two type_decl.
7098 /// Note that the two types must have been created in the same @ref
7099 /// environment, otherwise, this function aborts.
7101 /// This function doesn't actually compute a diff. As a type_decl is
7102 /// very simple (unlike compound constructs like function_decl or
7103 /// class_decl) it's easy to just compare the components of the
7104 /// type_decl to know what has changed. Thus this function just
7105 /// builds and return a type_decl_diff object. The
7106 /// type_decl_diff::report function will just compare the components
7107 /// of the the two type_decl and display where and how they differ.
7109 /// @param first a pointer to the first type_decl to
7112 /// @param second a pointer to the second type_decl to consider.
7114 /// @param ctxt the diff context to use.
7116 /// @return a pointer to the resulting type_decl_diff.
7118 compute_diff(const type_decl_sptr first,
7119 const type_decl_sptr second,
7120 diff_context_sptr ctxt)
7122 if (first && second)
7123 ABG_ASSERT(first->get_environment() == second->get_environment());
7125 type_decl_diff_sptr result(new type_decl_diff(first, second, ctxt));
7127 // We don't need to actually compute a diff here as a type_decl
7128 // doesn't have complicated sub-components. type_decl_diff::report
7129 // just walks the members of the type_decls and display information
7130 // about the ones that have changed. On a similar note,
7131 // type_decl_diff::length returns 0 if the two type_decls are equal,
7134 ctxt->initialize_canonical_diff(result);
7139 // </type_decl_diff stuff>
7141 // <typedef_diff stuff>
7143 /// Populate the vector of children node of the @ref diff base type
7144 /// sub-object of this instance of @ref typedef_diff.
7146 /// The children node can then later be retrieved using
7147 /// diff::children_node().
7149 typedef_diff::chain_into_hierarchy()
7150 {append_child_node(underlying_type_diff());}
7152 /// Constructor for typedef_diff.
7154 /// @param first the first subject of the diff.
7156 /// @param second the second subject of the diff.
7158 /// @param underlying the underlying diff of the @ref typedef_diff.
7159 /// That is the diff between the underlying types of @p first and @p
7162 /// @param ctxt the context of the diff. Note that this context
7163 /// object must stay alive at least during the life time of the
7164 /// current instance of @ref typedef_diff. Otherwise memory
7165 /// corruption issues occur.
7166 typedef_diff::typedef_diff(const typedef_decl_sptr first,
7167 const typedef_decl_sptr second,
7168 const diff_sptr underlying,
7169 diff_context_sptr ctxt)
7170 : type_diff_base(first, second, ctxt),
7171 priv_(new priv(underlying))
7174 /// Finish building the current instance of @ref typedef_diff.
7176 typedef_diff::finish_diff_type()
7178 if (diff::priv_->finished_)
7180 chain_into_hierarchy();
7181 diff::priv_->finished_ = true;
7184 /// Getter for the firt typedef_decl involved in the diff.
7186 /// @return the first subject of the diff.
7187 const typedef_decl_sptr
7188 typedef_diff::first_typedef_decl() const
7189 {return dynamic_pointer_cast<typedef_decl>(first_subject());}
7191 /// Getter for the second typedef_decl involved in the diff.
7193 /// @return the second subject of the diff.
7194 const typedef_decl_sptr
7195 typedef_diff::second_typedef_decl() const
7196 {return dynamic_pointer_cast<typedef_decl>(second_subject());}
7198 /// Getter for the diff between the two underlying types of the
7201 /// @return the diff object reprensenting the difference between the
7202 /// two underlying types of the typedefs.
7204 typedef_diff::underlying_type_diff() const
7205 {return priv_->underlying_type_diff_;}
7207 /// Setter for the diff between the two underlying types of the
7210 /// @param d the new diff object reprensenting the difference between
7211 /// the two underlying types of the typedefs.
7213 typedef_diff::underlying_type_diff(const diff_sptr d)
7214 {priv_->underlying_type_diff_ = d;}
7216 /// @return the pretty representation for the current instance of @ref
7219 typedef_diff::get_pretty_representation() const
7221 if (diff::priv_->pretty_representation_.empty())
7223 std::ostringstream o;
7224 o << "typedef_diff["
7225 << first_subject()->get_pretty_representation()
7227 << second_subject()->get_pretty_representation()
7229 diff::priv_->pretty_representation_ = o.str();
7231 return diff::priv_->pretty_representation_;
7234 /// Return true iff the current diff node carries a change.
7236 /// @return true iff the current diff node carries a change.
7238 typedef_diff::has_changes() const
7240 decl_base_sptr second = second_typedef_decl();
7241 return !(*first_typedef_decl() == *second);
7244 /// @return the kind of local change carried by the current diff node.
7245 /// The value returned is zero if the current node carries no local
7248 typedef_diff::has_local_changes() const
7250 ir::change_kind k = ir::NO_CHANGE_KIND;
7251 if (!equals(*first_typedef_decl(), *second_typedef_decl(), &k))
7252 return k & ir::ALL_LOCAL_CHANGES_MASK;
7253 return ir::NO_CHANGE_KIND;
7256 /// Reports the difference between the two subjects of the diff in a
7257 /// serialized form.
7259 /// @param out the output stream to emit the report to.
7261 /// @param indent the indentation string to use.
7263 typedef_diff::report(ostream& out, const string& indent) const
7265 context()->get_reporter()->report(*this, out, indent);
7268 /// Compute a diff between two typedef_decl.
7270 /// Note that the two types must have been created in the same @ref
7271 /// environment, otherwise, this function aborts.
7273 /// @param first a pointer to the first typedef_decl to consider.
7275 /// @param second a pointer to the second typedef_decl to consider.
7277 /// @param ctxt the diff context to use.
7279 /// @return a pointer to the the resulting typedef_diff.
7281 compute_diff(const typedef_decl_sptr first,
7282 const typedef_decl_sptr second,
7283 diff_context_sptr ctxt)
7285 if (first && second)
7286 ABG_ASSERT(first->get_environment() == second->get_environment());
7288 diff_sptr d = compute_diff_for_types(first->get_underlying_type(),
7289 second->get_underlying_type(),
7291 typedef_diff_sptr result(new typedef_diff(first, second, d, ctxt));
7293 ctxt->initialize_canonical_diff(result);
7298 /// Return the leaf underlying diff node of a @ref typedef_diff node.
7300 /// If the underlying diff node of a @ref typedef_diff node is itself
7301 /// a @ref typedef_diff node, then recursively look at the underlying
7302 /// diff nodes to get the first one that is not a a @ref typedef_diff
7303 /// node. This is what a leaf underlying diff node means.
7305 /// Otherwise, if the underlying diff node of @ref typedef_diff is
7306 /// *NOT* a @ref typedef_diff node, then just return the underlying
7309 /// And if the diff node considered is not a @ref typedef_diff node,
7310 /// then just return it.
7312 /// @return the leaf underlying diff node of a @p diff.
7314 get_typedef_diff_underlying_type_diff(const diff* diff)
7316 const typedef_diff* d = dynamic_cast<const typedef_diff*>(diff);
7320 if (const typedef_diff* deef =
7321 dynamic_cast<const typedef_diff*>(d->underlying_type_diff().get()))
7322 return get_typedef_diff_underlying_type_diff(deef);
7324 return d->underlying_type_diff().get();
7327 // </typedef_diff stuff>
7329 // <translation_unit_diff stuff>
7331 /// Constructor for translation_unit_diff.
7333 /// @param first the first translation unit to consider for this diff.
7335 /// @param second the second translation unit to consider for this diff.
7337 /// @param ctxt the context of the diff. Note that this context
7338 /// object must stay alive at least during the life time of the
7339 /// current instance of @ref translation_unit_diff. Otherwise memory
7340 /// corruption issues occur.
7341 translation_unit_diff::translation_unit_diff(translation_unit_sptr first,
7342 translation_unit_sptr second,
7343 diff_context_sptr ctxt)
7344 : scope_diff(first->get_global_scope(), second->get_global_scope(), ctxt),
7345 priv_(new priv(first, second))
7349 /// Getter for the first translation unit of this diff.
7351 /// @return the first translation unit of this diff.
7352 const translation_unit_sptr
7353 translation_unit_diff::first_translation_unit() const
7354 {return priv_->first_;}
7356 /// Getter for the second translation unit of this diff.
7358 /// @return the second translation unit of this diff.
7359 const translation_unit_sptr
7360 translation_unit_diff::second_translation_unit() const
7361 {return priv_->second_;}
7363 /// Return true iff the current diff node carries a change.
7365 /// @return true iff the current diff node carries a change.
7367 translation_unit_diff::has_changes() const
7368 {return scope_diff::has_changes();}
7370 /// @return the kind of local change carried by the current diff node.
7371 /// The value returned is zero if the current node carries no local
7374 translation_unit_diff::has_local_changes() const
7375 {return ir::NO_CHANGE_KIND;}
7377 /// Report the diff in a serialized form.
7379 /// @param out the output stream to serialize the report to.
7381 /// @param indent the prefix to use as indentation for the report.
7383 translation_unit_diff::report(ostream& out, const string& indent) const
7384 {scope_diff::report(out, indent);}
7386 /// Compute the diff between two translation_units.
7388 /// Note that the two translation units must have been created in the
7389 /// same @ref environment, otherwise, this function aborts.
7391 /// @param first the first translation_unit to consider.
7393 /// @param second the second translation_unit to consider.
7395 /// @param ctxt the diff context to use. If null, this function will
7396 /// create a new context and set to the diff object returned.
7398 /// @return the newly created diff object.
7399 translation_unit_diff_sptr
7400 compute_diff(const translation_unit_sptr first,
7401 const translation_unit_sptr second,
7402 diff_context_sptr ctxt)
7404 ABG_ASSERT(first && second);
7406 ABG_ASSERT(first->get_environment() == second->get_environment());
7409 ctxt.reset(new diff_context);
7411 // TODO: handle first or second having empty contents.
7412 translation_unit_diff_sptr tu_diff(new translation_unit_diff(first, second,
7414 scope_diff_sptr sc_diff = dynamic_pointer_cast<scope_diff>(tu_diff);
7416 compute_diff(static_pointer_cast<scope_decl>(first->get_global_scope()),
7417 static_pointer_cast<scope_decl>(second->get_global_scope()),
7421 ctxt->initialize_canonical_diff(tu_diff);
7426 // </translation_unit_diff stuff>
7428 // <diff_maps stuff>
7430 /// The private data of the @ref diff_maps type.
7431 struct diff_maps::priv
7433 string_diff_ptr_map type_decl_diff_map_;
7434 string_diff_ptr_map enum_diff_map_;
7435 string_diff_ptr_map class_diff_map_;
7436 string_diff_ptr_map union_diff_map_;
7437 string_diff_ptr_map typedef_diff_map_;
7438 string_diff_ptr_map array_diff_map_;
7439 string_diff_ptr_map reference_diff_map_;
7440 string_diff_ptr_map function_type_diff_map_;
7441 string_diff_ptr_map function_decl_diff_map_;
7442 string_diff_ptr_map var_decl_diff_map_;
7443 string_diff_ptr_map distinct_diff_map_;
7444 string_diff_ptr_map fn_parm_diff_map_;
7445 diff_artifact_set_map_type impacted_artifacts_map_;
7446 }; // end struct diff_maps::priv
7448 /// Default constructor of the @ref diff_maps type.
7449 diff_maps::diff_maps()
7450 : priv_(new diff_maps::priv())
7453 /// Getter of the map that contains basic type diffs.
7455 /// @return the map that contains basic type diffs.
7456 const string_diff_ptr_map&
7457 diff_maps::get_type_decl_diff_map() const
7458 {return priv_->type_decl_diff_map_;}
7460 /// Getter of the map that contains basic type diffs.
7462 /// @return the map that contains basic type diffs.
7463 string_diff_ptr_map&
7464 diff_maps::get_type_decl_diff_map()
7465 {return priv_->type_decl_diff_map_;}
7467 /// Getter of the map that contains enum type diffs.
7469 /// @return the map that contains enum type diffs.
7470 const string_diff_ptr_map&
7471 diff_maps::get_enum_diff_map() const
7472 {return priv_->enum_diff_map_;}
7474 /// Getter of the map that contains enum type diffs.
7476 /// @return the map that contains enum type diffs.
7477 string_diff_ptr_map&
7478 diff_maps::get_enum_diff_map()
7479 {return priv_->enum_diff_map_;}
7481 /// Getter of the map that contains class type diffs.
7483 /// @return the map that contains class type diffs.
7484 const string_diff_ptr_map&
7485 diff_maps::get_class_diff_map() const
7486 {return priv_->class_diff_map_;}
7488 /// Getter of the map that contains class type diffs.
7490 /// @return the map that contains class type diffs.
7491 string_diff_ptr_map&
7492 diff_maps::get_class_diff_map()
7493 {return priv_->class_diff_map_;}
7495 /// Getter of the map that contains union type diffs.
7497 /// @return the map that contains union type diffs.
7498 const string_diff_ptr_map&
7499 diff_maps::get_union_diff_map() const
7500 {return priv_->union_diff_map_;}
7502 /// Getter of the map that contains union type diffs.
7504 /// @return the map that contains union type diffs.
7505 string_diff_ptr_map&
7506 diff_maps::get_union_diff_map()
7507 {return priv_->union_diff_map_;}
7509 /// Getter of the map that contains typedef type diffs.
7511 /// @return the map that contains typedef type diffs.
7512 const string_diff_ptr_map&
7513 diff_maps::get_typedef_diff_map() const
7514 {return priv_->typedef_diff_map_;}
7516 /// Getter of the map that contains typedef type diffs.
7518 /// @return the map that contains typedef type diffs.
7519 string_diff_ptr_map&
7520 diff_maps::get_typedef_diff_map()
7521 {return priv_->typedef_diff_map_;}
7523 /// Getter of the map that contains array type diffs.
7525 /// @return the map that contains array type diffs.
7526 const string_diff_ptr_map&
7527 diff_maps::get_array_diff_map() const
7528 {return priv_->array_diff_map_;}
7530 /// Getter of the map that contains array type diffs.
7532 /// @return the map that contains array type diffs.
7533 string_diff_ptr_map&
7534 diff_maps::get_array_diff_map()
7535 {return priv_->array_diff_map_;}
7537 /// Getter of the map that contains reference type diffs.
7539 /// @return the map that contains reference type diffs.
7540 const string_diff_ptr_map&
7541 diff_maps::get_reference_diff_map() const
7542 {return priv_->reference_diff_map_;}
7544 /// Getter of the map that contains reference type diffs.
7546 /// @return the map that contains reference type diffs.
7547 string_diff_ptr_map&
7548 diff_maps::get_reference_diff_map()
7549 {{return priv_->reference_diff_map_;}}
7551 /// Getter of the map that contains function parameter diffs.
7553 /// @return the map that contains function parameter diffs.
7554 const string_diff_ptr_map&
7555 diff_maps::get_fn_parm_diff_map() const
7556 {return priv_->fn_parm_diff_map_;}
7558 /// Getter of the map that contains function parameter diffs.
7560 /// @return the map that contains function parameter diffs.
7561 string_diff_ptr_map&
7562 diff_maps::get_fn_parm_diff_map()
7563 {return priv_->fn_parm_diff_map_;}
7565 /// Getter of the map that contains function type diffs.
7567 /// @return the map that contains function type diffs.
7568 const string_diff_ptr_map&
7569 diff_maps::get_function_type_diff_map() const
7570 {return priv_->function_type_diff_map_;}
7572 /// Getter of the map that contains function type diffs.
7574 /// @return the map that contains function type diffs.
7575 string_diff_ptr_map&
7576 diff_maps::get_function_type_diff_map()
7577 {return priv_->function_type_diff_map_;}
7579 /// Getter of the map that contains function decl diffs.
7581 /// @return the map that contains function decl diffs.
7582 const string_diff_ptr_map&
7583 diff_maps::get_function_decl_diff_map() const
7584 {return priv_->function_decl_diff_map_;}
7586 /// Getter of the map that contains function decl diffs.
7588 /// @return the map that contains function decl diffs.
7589 string_diff_ptr_map&
7590 diff_maps::get_function_decl_diff_map()
7591 {return priv_->function_decl_diff_map_;}
7593 /// Getter of the map that contains var decl diffs.
7595 /// @return the map that contains var decl diffs.
7596 const string_diff_ptr_map&
7597 diff_maps::get_var_decl_diff_map() const
7598 {return priv_->var_decl_diff_map_;}
7600 /// Getter of the map that contains var decl diffs.
7602 /// @return the map that contains var decl diffs.
7603 string_diff_ptr_map&
7604 diff_maps::get_var_decl_diff_map()
7605 {return priv_->var_decl_diff_map_;}
7607 /// Getter of the map that contains distinct diffs.
7609 /// @return the map that contains distinct diffs.
7610 const string_diff_ptr_map&
7611 diff_maps::get_distinct_diff_map() const
7612 {return priv_->distinct_diff_map_;}
7614 /// Getter of the map that contains distinct diffs.
7616 /// @return the map that contains distinct diffs.
7617 string_diff_ptr_map&
7618 diff_maps::get_distinct_diff_map()
7619 {return priv_->distinct_diff_map_;}
7621 /// Insert a new diff node into the current instance of @ref diff_maps.
7623 /// @param dif the new diff node to insert into the @ref diff_maps.
7625 /// @return true iff the diff node could be added to the current
7626 /// instance of @ref diff_maps.
7628 diff_maps::insert_diff_node(const diff *dif,
7629 const type_or_decl_base_sptr& impacted_iface)
7631 string n = get_pretty_representation(dif->first_subject(),
7633 if (const type_decl_diff *d = is_diff_of_basic_type(dif))
7634 get_type_decl_diff_map()[n] = const_cast<type_decl_diff*>(d);
7635 else if (const enum_diff *d = is_enum_diff(dif))
7636 get_enum_diff_map()[n] = const_cast<enum_diff*>(d);
7637 else if (const class_diff *d = is_class_diff(dif))
7638 get_class_diff_map()[n] = const_cast<class_diff*>(d);
7639 else if (const union_diff *d = is_union_diff(dif))
7640 get_union_diff_map()[n] = const_cast<union_diff*>(d);
7641 else if (const typedef_diff *d = is_typedef_diff(dif))
7642 get_typedef_diff_map()[n] = const_cast<typedef_diff*>(d);
7643 else if (const array_diff *d = is_array_diff(dif))
7644 get_array_diff_map()[n] = const_cast<array_diff*>(d);
7645 else if (const reference_diff *d = is_reference_diff(dif))
7646 get_reference_diff_map()[n] = const_cast<reference_diff*>(d);
7647 else if (const fn_parm_diff *d = is_fn_parm_diff(dif))
7648 get_fn_parm_diff_map()[n] = const_cast<fn_parm_diff*>(d);
7649 else if (const function_type_diff *d = is_function_type_diff(dif))
7650 get_function_type_diff_map()[n] = const_cast<function_type_diff*>(d);
7651 else if (const var_diff *d = is_var_diff(dif))
7652 get_var_decl_diff_map()[n] = const_cast<var_diff*>(d);
7653 else if (const function_decl_diff *d = is_function_decl_diff(dif))
7654 get_function_decl_diff_map()[n] = const_cast<function_decl_diff*>(d);
7655 else if (const distinct_diff *d = is_distinct_diff(dif))
7656 get_distinct_diff_map()[n] = const_cast<distinct_diff*>(d);
7657 else if (is_base_diff(dif))
7658 // we silently drop this case.
7661 ABG_ASSERT_NOT_REACHED;
7663 // Update the map that associate the interface that is impacted by
7664 // this diff, to this diff node.
7666 diff_artifact_set_map_type::iterator i =
7667 priv_->impacted_artifacts_map_.find(dif);
7669 if (i == priv_->impacted_artifacts_map_.end())
7671 artifact_sptr_set_type set;
7672 set.insert(impacted_iface);
7673 priv_->impacted_artifacts_map_[dif] = set;
7676 i->second.insert(impacted_iface);
7681 /// Lookup the interfaces that are impacted by a given leaf diff node.
7683 /// @param d the diff node to consider.
7685 /// @return the set of artifacts impacted by @p d.
7686 artifact_sptr_set_type*
7687 diff_maps::lookup_impacted_interfaces(const diff *d) const
7689 diff_artifact_set_map_type::iterator i =
7690 priv_->impacted_artifacts_map_.find(d);
7692 if (i == priv_->impacted_artifacts_map_.end())
7699 // </diff_maps stuff>
7701 /// Constructor for the @ref diff_stat type.
7703 /// @param ctxt the context of the corpus diff. Note that this
7704 /// context object must stay alive at least during the life time of
7705 /// the current instance of @ref corpus_diff::diff_stats. Otherwise
7706 /// memory corruption issues occur.
7707 corpus_diff::diff_stats::diff_stats(diff_context_sptr ctxt)
7708 : priv_(new priv(ctxt))
7711 /// Getter for the number of functions removed.
7713 /// @return the number of functions removed.
7715 corpus_diff::diff_stats::num_func_removed() const
7716 {return priv_->num_func_removed;}
7718 /// Setter for the number of functions removed.
7720 /// @param n the new number of functions removed.
7722 corpus_diff::diff_stats::num_func_removed(size_t n)
7723 {priv_->num_func_removed = n;}
7725 /// Getter for the number of removed functions that have been filtered
7728 /// @return the number of removed functions that have been filtered
7731 corpus_diff::diff_stats::num_removed_func_filtered_out() const
7733 if (priv_->ctxt() && !priv_->ctxt()->show_deleted_fns())
7734 return num_func_removed();
7735 return priv_->num_removed_func_filtered_out;
7738 /// Setter for the number of removed functions that have been filtered
7741 /// @param t the new value.
7743 corpus_diff::diff_stats::num_removed_func_filtered_out(size_t t)
7744 {priv_->num_removed_func_filtered_out = t;}
7746 /// Getter for the net number of function removed.
7748 /// This is the difference between the number of functions removed and
7749 /// the number of functons removed that have been filtered out.
7751 /// @return the net number of function removed.
7753 corpus_diff::diff_stats::net_num_func_removed() const
7755 ABG_ASSERT(num_func_removed() >= num_removed_func_filtered_out());
7756 return num_func_removed() - num_removed_func_filtered_out();
7759 /// Getter for the number of functions added.
7761 /// @return the number of functions added.
7763 corpus_diff::diff_stats::num_func_added() const
7764 {return priv_->num_func_added;}
7766 /// Setter for the number of functions added.
7768 /// @param n the new number of functions added.
7770 corpus_diff::diff_stats::num_func_added(size_t n)
7771 {priv_->num_func_added = n;}
7773 /// Getter for the number of added function that have been filtered out.
7775 /// @return the number of added function that have been filtered out.
7777 corpus_diff::diff_stats::num_added_func_filtered_out() const
7779 if (priv_->ctxt() && !priv_->ctxt()->show_added_fns())
7780 return num_func_added();
7781 return priv_->num_added_func_filtered_out;
7784 /// Setter for the number of added function that have been filtered
7787 /// @param n the new value.
7789 corpus_diff::diff_stats::num_added_func_filtered_out(size_t n)
7790 {priv_->num_added_func_filtered_out = n;}
7792 /// Getter for the net number of added functions.
7794 /// The net number of added functions is the difference between the
7795 /// number of added functions and the number of added functions that
7796 /// have been filtered out.
7798 /// @return the net number of added functions.
7800 corpus_diff::diff_stats::net_num_func_added() const
7802 ABG_ASSERT(num_func_added() >= num_added_func_filtered_out());
7803 return num_func_added() - num_added_func_filtered_out();
7806 /// Getter for the number of functions that have a change in one of
7807 /// their sub-types.
7809 /// @return the number of functions that have a change in one of their
7812 corpus_diff::diff_stats::num_func_changed() const
7813 {return priv_->num_func_changed;}
7815 /// Setter for the number of functions that have a change in one of
7816 /// their sub-types.
7818 /// @@param n the new number of functions that have a change in one of
7819 /// their sub-types.
7821 corpus_diff::diff_stats::num_func_changed(size_t n)
7822 {priv_->num_func_changed = n;}
7824 /// Getter for the number of functions that have a change in one of
7825 /// their sub-types, and that have been filtered out.
7827 /// @return the number of functions that have a change in one of their
7828 /// sub-types, and that have been filtered out.
7830 corpus_diff::diff_stats::num_changed_func_filtered_out() const
7831 {return priv_->num_changed_func_filtered_out;}
7833 /// Setter for the number of functions that have a change in one of
7834 /// their sub-types, and that have been filtered out.
7836 /// @param n the new number of functions that have a change in one of their
7837 /// sub-types, and that have been filtered out.
7839 corpus_diff::diff_stats::num_changed_func_filtered_out(size_t n)
7840 {priv_->num_changed_func_filtered_out = n;}
7842 /// Getter for the number of functions that carry virtual member
7845 /// @return the number of functions that carry virtual member changes.
7847 corpus_diff::diff_stats::num_func_with_virtual_offset_changes() const
7848 {return priv_->num_func_with_virt_offset_changes;}
7850 /// Setter for the number of functions that carry virtual member
7853 /// @param n the new number of functions that carry virtual member
7854 /// offset. changes.
7856 corpus_diff::diff_stats::num_func_with_virtual_offset_changes(size_t n)
7857 {priv_->num_func_with_virt_offset_changes = n;}
7859 /// Getter for the number of functions that have a change in their
7860 /// sub-types, minus the number of these functions that got filtered
7861 /// out from the diff.
7863 /// @return for the the number of functions that have a change in
7864 /// their sub-types, minus the number of these functions that got
7865 /// filtered out from the diff.
7867 corpus_diff::diff_stats::net_num_func_changed() const
7868 {return num_func_changed() - num_changed_func_filtered_out();}
7870 /// Getter for the number of variables removed.
7872 /// @return the number of variables removed.
7874 corpus_diff::diff_stats::num_vars_removed() const
7875 {return priv_->num_vars_removed;}
7877 /// Setter for the number of variables removed.
7879 /// @param n the new number of variables removed.
7881 corpus_diff::diff_stats::num_vars_removed(size_t n)
7882 {priv_->num_vars_removed = n;}
7884 /// Getter for the number removed variables that have been filtered
7887 /// @return the number removed variables that have been filtered out.
7889 corpus_diff::diff_stats::num_removed_vars_filtered_out() const
7891 if (priv_->ctxt() && !priv_->ctxt()->show_deleted_vars())
7892 return num_vars_removed();
7893 return priv_->num_removed_vars_filtered_out;
7896 /// Setter for the number of removed variables that have been filtered
7899 /// @param n the new value.
7901 corpus_diff::diff_stats::num_removed_vars_filtered_out(size_t n) const
7902 {priv_->num_removed_vars_filtered_out = n;}
7904 /// Getter for the net number of removed variables.
7906 /// The net number of removed variables is the difference between the
7907 /// number of removed variables and the number of removed variables
7908 /// that have been filtered out.
7910 /// @return the net number of removed variables.
7912 corpus_diff::diff_stats::net_num_vars_removed() const
7914 ABG_ASSERT(num_vars_removed() >= num_removed_vars_filtered_out());
7915 return num_vars_removed() - num_removed_vars_filtered_out();
7918 /// Getter for the number of variables added.
7920 /// @return the number of variables added.
7922 corpus_diff::diff_stats::num_vars_added() const
7923 {return priv_->num_vars_added;}
7925 /// Setter for the number of variables added.
7927 /// @param n the new number of variables added.
7929 corpus_diff::diff_stats::num_vars_added(size_t n)
7930 {priv_->num_vars_added = n;}
7932 /// Getter for the number of added variables that have been filtered
7935 /// @return the number of added variables that have been filtered out.
7937 corpus_diff::diff_stats::num_added_vars_filtered_out() const
7939 if (priv_->ctxt() && !priv_->ctxt()->show_added_vars())
7940 return num_vars_added();
7941 return priv_->num_added_vars_filtered_out;
7944 /// Setter for the number of added variables that have been filtered
7947 /// @param n the new value.
7949 corpus_diff::diff_stats::num_added_vars_filtered_out(size_t n)
7950 {priv_->num_added_vars_filtered_out = n;}
7952 /// Getter for the net number of added variables.
7954 /// The net number of added variables is the difference between the
7955 /// number of added variables and the number of added variables that
7956 /// have been filetered out.
7958 /// @return the net number of added variables.
7960 corpus_diff::diff_stats::net_num_vars_added() const
7962 ABG_ASSERT(num_vars_added() >= num_added_vars_filtered_out());
7963 return num_vars_added() - num_added_vars_filtered_out();
7966 /// Getter for the number of variables that have a change in one of
7967 /// their sub-types.
7969 /// @return the number of variables that have a change in one of their
7972 corpus_diff::diff_stats::num_vars_changed() const
7973 {return priv_->num_vars_changed;}
7975 /// Setter for the number of variables that have a change in one of
7976 /// their sub-types.
7978 /// @param n the new number of variables that have a change in one of
7979 /// their sub-types.
7981 corpus_diff::diff_stats::num_vars_changed(size_t n)
7982 {priv_->num_vars_changed = n;}
7984 /// Getter for the number of variables that have a change in one of
7985 /// their sub-types, and that have been filtered out.
7987 /// @return the number of functions that have a change in one of their
7988 /// sub-types, and that have been filtered out.
7990 corpus_diff::diff_stats::num_changed_vars_filtered_out() const
7991 {return priv_->num_changed_vars_filtered_out;}
7993 /// Setter for the number of variables that have a change in one of
7994 /// their sub-types, and that have been filtered out.
7996 /// @param n the new number of variables that have a change in one of their
7997 /// sub-types, and that have been filtered out.
7999 corpus_diff::diff_stats::num_changed_vars_filtered_out(size_t n)
8000 {priv_->num_changed_vars_filtered_out = n;}
8002 /// Getter for the number of variables that have a change in their
8003 /// sub-types, minus the number of these variables that got filtered
8004 /// out from the diff.
8006 /// @return for the the number of variables that have a change in
8007 /// their sub-types, minus the number of these variables that got
8008 /// filtered out from the diff.
8010 corpus_diff::diff_stats::net_num_vars_changed() const
8011 {return num_vars_changed() - num_changed_vars_filtered_out();}
8013 /// Getter for the number of function symbols (not referenced by any
8014 /// debug info) that got removed.
8016 /// @return the number of function symbols (not referenced by any
8017 /// debug info) that got removed.
8019 corpus_diff::diff_stats::num_func_syms_removed() const
8020 {return priv_->num_func_syms_removed;}
8022 /// Setter for the number of function symbols (not referenced by any
8023 /// debug info) that got removed.
8025 /// @param n the number of function symbols (not referenced by any
8026 /// debug info) that got removed.
8028 corpus_diff::diff_stats::num_func_syms_removed(size_t n)
8029 {priv_->num_func_syms_removed = n;}
8031 /// Getter for the number of removed function symbols, not referenced
8032 /// by debug info, that have been filtered out.
8034 /// @return the number of removed function symbols, not referenced by
8035 /// debug info, that have been filtered out.
8037 corpus_diff::diff_stats::num_removed_func_syms_filtered_out() const
8040 && !priv_->ctxt()->show_symbols_unreferenced_by_debug_info())
8041 return num_func_syms_removed();
8042 return priv_->num_removed_func_syms_filtered_out;
8045 /// Setter for the number of removed function symbols, not referenced
8046 /// by debug info, that have been filtered out.
8048 /// @param n the new the number of removed function symbols, not
8049 /// referenced by debug info, that have been filtered out.
8051 corpus_diff::diff_stats::num_removed_func_syms_filtered_out(size_t n)
8052 {priv_->num_removed_func_syms_filtered_out = n;}
8054 /// Getter of the net number of removed function symbols that are not
8055 /// referenced by any debug info.
8057 /// This is the difference between the total number of removed
8058 /// function symbols and the number of removed function symbols that
8059 /// have been filteted out. Both numbers are for symbols not
8060 /// referenced by debug info.
8062 /// return the net number of removed function symbols that are not
8063 /// referenced by any debug info.
8065 corpus_diff::diff_stats::net_num_removed_func_syms() const
8067 ABG_ASSERT(num_func_syms_removed() >= num_removed_func_syms_filtered_out());
8068 return num_func_syms_removed() - num_removed_func_syms_filtered_out();
8071 /// Getter for the number of function symbols (not referenced by any
8072 /// debug info) that got added.
8074 /// @return the number of function symbols (not referenced by any
8075 /// debug info) that got added.
8077 corpus_diff::diff_stats::num_func_syms_added() const
8078 {return priv_->num_func_syms_added;}
8080 /// Setter for the number of function symbols (not referenced by any
8081 /// debug info) that got added.
8083 /// @param n the new number of function symbols (not referenced by any
8084 /// debug info) that got added.
8086 corpus_diff::diff_stats::num_func_syms_added(size_t n)
8087 {priv_->num_func_syms_added = n;}
8089 /// Getter for the number of added function symbols, not referenced by
8090 /// any debug info, that have been filtered out.
8092 /// @return the number of added function symbols, not referenced by
8093 /// any debug info, that have been filtered out.
8095 corpus_diff::diff_stats::num_added_func_syms_filtered_out() const
8098 && !(priv_->ctxt()->show_added_symbols_unreferenced_by_debug_info()
8099 && priv_->ctxt()->show_symbols_unreferenced_by_debug_info()))
8100 return num_func_syms_added();
8101 return priv_->num_added_func_syms_filtered_out;
8104 /// Setter for the number of added function symbols, not referenced by
8105 /// any debug info, that have been filtered out.
8107 /// @param n the new number of added function symbols, not referenced
8108 /// by any debug info, that have been filtered out.
8110 corpus_diff::diff_stats::num_added_func_syms_filtered_out(size_t n)
8111 {priv_->num_added_func_syms_filtered_out = n;}
8113 /// Getter of the net number of added function symbols that are not
8114 /// referenced by any debug info.
8116 /// This is the difference between the total number of added
8117 /// function symbols and the number of added function symbols that
8118 /// have been filteted out. Both numbers are for symbols not
8119 /// referenced by debug info.
8121 /// return the net number of added function symbols that are not
8122 /// referenced by any debug info.
8124 corpus_diff::diff_stats::net_num_added_func_syms() const
8126 ABG_ASSERT(num_func_syms_added() >= num_added_func_syms_filtered_out());
8127 return num_func_syms_added()- num_added_func_syms_filtered_out();
8130 /// Getter for the number of variable symbols (not referenced by any
8131 /// debug info) that got removed.
8133 /// @return the number of variable symbols (not referenced by any
8134 /// debug info) that got removed.
8136 corpus_diff::diff_stats::num_var_syms_removed() const
8137 {return priv_->num_var_syms_removed;}
8139 /// Setter for the number of variable symbols (not referenced by any
8140 /// debug info) that got removed.
8142 /// @param n the number of variable symbols (not referenced by any
8143 /// debug info) that got removed.
8145 corpus_diff::diff_stats::num_var_syms_removed(size_t n)
8146 {priv_->num_var_syms_removed = n;}
8148 /// Getter for the number of removed variable symbols, not referenced
8149 /// by any debug info, that have been filtered out.
8151 /// @return the number of removed variable symbols, not referenced
8152 /// by any debug info, that have been filtered out.
8154 corpus_diff::diff_stats::num_removed_var_syms_filtered_out() const
8157 && !priv_->ctxt()->show_symbols_unreferenced_by_debug_info())
8158 return num_var_syms_removed();
8159 return priv_->num_removed_var_syms_filtered_out;
8162 /// Setter for the number of removed variable symbols, not referenced
8163 /// by any debug info, that have been filtered out.
8165 /// @param n the number of removed variable symbols, not referenced by
8166 /// any debug info, that have been filtered out.
8168 corpus_diff::diff_stats::num_removed_var_syms_filtered_out(size_t n)
8169 {priv_->num_removed_var_syms_filtered_out = n;}
8171 /// Getter of the net number of removed variable symbols that are not
8172 /// referenced by any debug info.
8174 /// This is the difference between the total number of removed
8175 /// variable symbols and the number of removed variable symbols that
8176 /// have been filteted out. Both numbers are for symbols not
8177 /// referenced by debug info.
8179 /// return the net number of removed variable symbols that are not
8180 /// referenced by any debug info.
8182 corpus_diff::diff_stats::net_num_removed_var_syms() const
8184 ABG_ASSERT(num_var_syms_removed() >= num_removed_var_syms_filtered_out());
8185 return num_var_syms_removed() - num_removed_var_syms_filtered_out();
8188 /// Getter for the number of variable symbols (not referenced by any
8189 /// debug info) that got added.
8191 /// @return the number of variable symbols (not referenced by any
8192 /// debug info) that got added.
8194 corpus_diff::diff_stats::num_var_syms_added() const
8195 {return priv_->num_var_syms_added;}
8197 /// Setter for the number of variable symbols (not referenced by any
8198 /// debug info) that got added.
8200 /// @param n the new number of variable symbols (not referenced by any
8201 /// debug info) that got added.
8203 corpus_diff::diff_stats::num_var_syms_added(size_t n)
8204 {priv_->num_var_syms_added = n;}
8206 /// Getter for the number of added variable symbols, not referenced by
8207 /// any debug info, that have been filtered out.
8209 /// @return the number of added variable symbols, not referenced by
8210 /// any debug info, that have been filtered out.
8212 corpus_diff::diff_stats::num_added_var_syms_filtered_out() const
8215 && !(priv_->ctxt()->show_added_symbols_unreferenced_by_debug_info()
8216 && priv_->ctxt()->show_symbols_unreferenced_by_debug_info()))
8217 return num_var_syms_added();
8218 return priv_->num_added_var_syms_filtered_out;
8221 /// Setter for the number of added variable symbols, not referenced by
8222 /// any debug info, that have been filtered out.
8224 /// @param n the new number of added variable symbols, not referenced
8225 /// by any debug info, that have been filtered out.
8227 corpus_diff::diff_stats::num_added_var_syms_filtered_out(size_t n)
8228 {priv_->num_added_var_syms_filtered_out = n;}
8230 /// Getter of the net number of added variable symbols that are not
8231 /// referenced by any debug info.
8233 /// This is the difference between the total number of added
8234 /// variable symbols and the number of added variable symbols that
8235 /// have been filteted out. Both numbers are for symbols not
8236 /// referenced by debug info.
8238 /// return the net number of added variable symbols that are not
8239 /// referenced by any debug info.
8241 corpus_diff::diff_stats::net_num_added_var_syms() const
8243 ABG_ASSERT(num_var_syms_added() >= num_added_var_syms_filtered_out());
8244 return num_var_syms_added() - num_added_var_syms_filtered_out();
8247 /// Getter of the number of leaf type change diff nodes.
8249 /// @return the number of leaf type change diff nodes.
8251 corpus_diff::diff_stats::num_leaf_changes() const
8252 {return priv_->num_leaf_changes;}
8254 /// Setter of the number of leaf type change diff nodes.
8256 /// @param n the new number of leaf type change diff nodes.
8258 corpus_diff::diff_stats::num_leaf_changes(size_t n)
8259 {priv_->num_leaf_changes = n;}
8261 /// Getter of the number of leaf type change diff nodes that have been
8264 /// @return the number of leaf type change diff nodes that have been
8266 corpus_diff::diff_stats::num_leaf_changes_filtered_out() const
8267 {return priv_->num_leaf_changes_filtered_out;}
8269 /// Setter of the number of leaf type change diff nodes that have been
8272 /// @param n the new number of leaf type change diff nodes that have
8273 /// been filtered out.
8275 corpus_diff::diff_stats::num_leaf_changes_filtered_out(size_t n)
8276 {priv_->num_leaf_changes_filtered_out = n;}
8278 /// Getter of the net number of leaf change diff nodes.
8280 /// This is the difference between the total number of leaf change
8281 /// diff nodes, and the number of the leaf change diff nodes that have
8282 /// been filtered out.
8284 /// A leaf change is either a type change, a function change or a
8285 /// variable change.
8287 corpus_diff::diff_stats::net_num_leaf_changes() const
8289 ABG_ASSERT(num_leaf_changes() >= num_leaf_changes_filtered_out());
8290 return num_leaf_changes() - num_leaf_changes_filtered_out();
8293 /// Getter for the number of leaf type change diff nodes.
8295 /// @return the number of leaf type changes diff nodes.
8297 corpus_diff::diff_stats::num_leaf_type_changes() const
8298 {return priv_->num_leaf_type_changes;}
8300 /// Setter for the number of leaf type change diff nodes.
8302 /// @param n the new number of leaf type change diff nodes.
8304 corpus_diff::diff_stats::num_leaf_type_changes(size_t n)
8305 {priv_->num_leaf_type_changes = n;}
8307 /// Getter for the number of filtered out leaf type change diff nodes.
8309 /// @return the number of filtered out leaf type change diff nodes.
8311 corpus_diff::diff_stats::num_leaf_type_changes_filtered_out() const
8312 {return priv_->num_leaf_type_changes_filtered_out;}
8314 /// Setter for the number of filtered out leaf type change diff nodes.
8315 /// @param n the new number of filtered out leaf type change diff nodes.
8317 corpus_diff::diff_stats::num_leaf_type_changes_filtered_out(size_t n)
8318 {priv_->num_leaf_type_changes_filtered_out = n;}
8320 /// Getter for the net number of leaf type change diff nodes.
8322 /// This is the difference between the number of leaf type changes and
8323 /// the number of filtered out leaf type changes.
8325 /// @return the net number of leaf type change diff nodes.
8327 corpus_diff::diff_stats::net_num_leaf_type_changes() const
8328 {return num_leaf_type_changes() - num_leaf_type_changes_filtered_out();}
8330 /// Getter for the number of leaf function change diff nodes.
8332 /// @return the number of leaf function change diff nodes.
8334 corpus_diff::diff_stats::num_leaf_func_changes() const
8335 {return priv_->num_leaf_func_changes;}
8337 /// Setter for the number of leaf function change diff nodes.
8339 /// @param n the new number of leaf function change diff nodes.
8341 corpus_diff::diff_stats::num_leaf_func_changes(size_t n)
8342 {priv_->num_leaf_func_changes = n;}
8344 /// Getter for the number of leaf function change diff nodes that were
8347 /// @return the number of leaf function change diff nodes that were
8350 corpus_diff::diff_stats::num_leaf_func_changes_filtered_out() const
8351 {return priv_->num_leaf_func_changes_filtered_out;}
8353 /// Setter for the number of leaf function change diff nodes that were
8356 /// @param n the new number of leaf function change diff nodes that
8357 /// were filtered out.
8359 corpus_diff::diff_stats::num_leaf_func_changes_filtered_out(size_t n)
8360 {priv_->num_leaf_func_changes_filtered_out = n;}
8362 /// Getter for the net number of leaf function change diff nodes.
8364 /// This is the difference between the number of leaf function change
8365 /// diff nodes and the number of filtered out leaf function change
8368 /// @return the net number of leaf function change diff nodes.
8370 corpus_diff::diff_stats::net_num_leaf_func_changes() const
8371 {return num_leaf_func_changes() - num_leaf_func_changes_filtered_out();}
8373 /// Getter for the number of leaf variable change diff nodes.
8375 /// @return the number of leaf variable change diff nodes.
8377 corpus_diff::diff_stats::num_leaf_var_changes() const
8378 {return priv_->num_leaf_var_changes;}
8380 /// Setter for the number of leaf variable change diff nodes.
8382 /// @param n the number of leaf variable change diff nodes.
8384 corpus_diff::diff_stats::num_leaf_var_changes(size_t n)
8385 {priv_->num_leaf_var_changes = n;}
8387 /// Getter for the number of leaf variable changes diff nodes that
8388 /// have been filtered out.
8390 /// @return the number of leaf variable changes diff nodes that have
8391 /// been filtered out.
8393 corpus_diff::diff_stats::num_leaf_var_changes_filtered_out() const
8394 {return priv_->num_leaf_var_changes_filtered_out;}
8396 /// Setter for the number of leaf variable changes diff nodes that
8397 /// have been filtered out.
8399 /// @param n the number of leaf variable changes diff nodes that have
8400 /// been filtered out.
8402 corpus_diff::diff_stats::num_leaf_var_changes_filtered_out(size_t n)
8403 {priv_->num_leaf_var_changes_filtered_out = n;}
8405 /// Getter for the net number of leaf variable change diff nodes.
8407 /// This the difference between the number of leaf variable change
8408 /// diff nodes and the number of filtered out leaf variable change
8411 /// @return the net number of leaf variable change diff nodes.
8413 corpus_diff::diff_stats::net_num_leaf_var_changes() const
8414 {return num_leaf_var_changes() - num_leaf_var_changes_filtered_out();}
8417 /// Getter of the context associated with this corpus.
8419 /// @return a smart pointer to the context associate with the corpus.
8421 corpus_diff::priv::get_context()
8423 if (ctxt_.expired())
8424 return diff_context_sptr();
8425 return diff_context_sptr(ctxt_);
8428 /// Tests if the lookup tables are empty.
8430 /// @return true if the lookup tables are empty, false otherwise.
8432 corpus_diff::priv::lookup_tables_empty() const
8434 return (deleted_fns_.empty()
8435 && added_fns_.empty()
8436 && changed_fns_map_.empty()
8437 && deleted_vars_.empty()
8438 && added_vars_.empty()
8439 && changed_vars_map_.empty());
8442 /// Clear the lookup tables useful for reporting an enum_diff.
8444 corpus_diff::priv::clear_lookup_tables()
8446 deleted_fns_.clear();
8448 changed_fns_map_.clear();
8449 deleted_vars_.clear();
8450 added_vars_.clear();
8451 changed_vars_map_.clear();
8454 /// If the lookup tables are not yet built, walk the differences and
8455 /// fill the lookup tables.
8457 corpus_diff::priv::ensure_lookup_tables_populated()
8459 if (!lookup_tables_empty())
8462 diff_context_sptr ctxt = get_context();
8465 edit_script& e = fns_edit_script_;
8467 for (vector<deletion>::const_iterator it = e.deletions().begin();
8468 it != e.deletions().end();
8471 unsigned i = it->index();
8472 ABG_ASSERT(i < first_->get_functions().size());
8474 function_decl* deleted_fn = first_->get_functions()[i];
8475 string n = deleted_fn->get_id();
8476 ABG_ASSERT(!n.empty());
8477 // The below is commented out because there can be several
8478 // functions with the same ID in the corpus. So several
8479 // functions with the same ID can be deleted.
8480 // ABG_ASSERT(deleted_fns_.find(n) == deleted_fns_.end());
8481 deleted_fns_[n] = deleted_fn;
8484 for (vector<insertion>::const_iterator it = e.insertions().begin();
8485 it != e.insertions().end();
8488 for (vector<unsigned>::const_iterator iit =
8489 it->inserted_indexes().begin();
8490 iit != it->inserted_indexes().end();
8494 function_decl* added_fn = second_->get_functions()[i];
8495 string n = added_fn->get_id();
8496 ABG_ASSERT(!n.empty());
8497 // The below is commented out because there can be several
8498 // functions with the same ID in the corpus. So several
8499 // functions with the same ID can be added.
8500 // ABG_ASSERT(added_fns_.find(n) == added_fns_.end());
8501 string_function_ptr_map::const_iterator j =
8502 deleted_fns_.find(n);
8503 if (j != deleted_fns_.end())
8505 function_decl_sptr f(j->second, noop_deleter());
8506 function_decl_sptr s(added_fn, noop_deleter());
8507 function_decl_diff_sptr d = compute_diff(f, s, ctxt);
8508 if (*j->second != *added_fn)
8509 changed_fns_map_[j->first] = d;
8510 deleted_fns_.erase(j);
8513 added_fns_[n] = added_fn;
8516 sort_string_function_decl_diff_sptr_map(changed_fns_map_, changed_fns_);
8518 // Now walk the allegedly deleted functions; check if their
8519 // underlying symbols are deleted as well; otherwise, consider
8520 // that the function in question hasn't been deleted.
8522 vector<string> to_delete;
8523 for (string_function_ptr_map::const_iterator i = deleted_fns_.begin();
8524 i != deleted_fns_.end();
8526 if (second_->lookup_function_symbol(*i->second->get_symbol()))
8527 to_delete.push_back(i->first);
8529 for (vector<string>::const_iterator i = to_delete.begin();
8530 i != to_delete.end();
8532 deleted_fns_.erase(*i);
8534 // Do something similar for added functions.
8537 for (string_function_ptr_map::const_iterator i = added_fns_.begin();
8538 i != added_fns_.end();
8541 if (first_->lookup_function_symbol(*i->second->get_symbol()))
8542 to_delete.push_back(i->first);
8543 else if (! i->second->get_symbol()->get_version().is_empty()
8544 && i->second->get_symbol()->get_version().is_default())
8545 // We are looking for a symbol that has a default version,
8546 // and which seems to be newly added. Let's see if the same
8547 // symbol with *no* version was already present in the
8548 // former corpus. If yes, then the symbol shouldn't be
8549 // considered as 'added'.
8551 elf_symbol::version empty_version;
8552 if (first_->lookup_function_symbol(i->second->get_symbol()->get_name(),
8554 to_delete.push_back(i->first);
8558 for (vector<string>::const_iterator i = to_delete.begin();
8559 i != to_delete.end();
8561 added_fns_.erase(*i);
8565 edit_script& e = vars_edit_script_;
8567 for (vector<deletion>::const_iterator it = e.deletions().begin();
8568 it != e.deletions().end();
8571 unsigned i = it->index();
8572 ABG_ASSERT(i < first_->get_variables().size());
8574 var_decl* deleted_var = first_->get_variables()[i];
8575 string n = deleted_var->get_id();
8576 ABG_ASSERT(!n.empty());
8577 ABG_ASSERT(deleted_vars_.find(n) == deleted_vars_.end());
8578 deleted_vars_[n] = deleted_var;
8581 for (vector<insertion>::const_iterator it = e.insertions().begin();
8582 it != e.insertions().end();
8585 for (vector<unsigned>::const_iterator iit =
8586 it->inserted_indexes().begin();
8587 iit != it->inserted_indexes().end();
8591 var_decl* added_var = second_->get_variables()[i];
8592 string n = added_var->get_id();
8593 ABG_ASSERT(!n.empty());
8595 string_var_ptr_map::const_iterator k = added_vars_.find(n);
8596 if ( k != added_vars_.end())
8598 ABG_ASSERT(is_member_decl(k->second)
8599 && get_member_is_static(k->second));
8603 string_var_ptr_map::const_iterator j =
8604 deleted_vars_.find(n);
8605 if (j != deleted_vars_.end())
8607 if (*j->second != *added_var)
8609 var_decl_sptr f(j->second, noop_deleter());
8610 var_decl_sptr s(added_var, noop_deleter());
8611 changed_vars_map_[n] = compute_diff(f, s, ctxt);
8613 deleted_vars_.erase(j);
8616 added_vars_[n] = added_var;
8619 sort_string_var_diff_sptr_map(changed_vars_map_,
8620 sorted_changed_vars_);
8622 // Now walk the allegedly deleted variables; check if their
8623 // underlying symbols are deleted as well; otherwise consider
8624 // that the variable in question hasn't been deleted.
8626 vector<string> to_delete;
8627 for (string_var_ptr_map::const_iterator i = deleted_vars_.begin();
8628 i != deleted_vars_.end();
8630 if (second_->lookup_variable_symbol(*i->second->get_symbol()))
8631 to_delete.push_back(i->first);
8633 for (vector<string>::const_iterator i = to_delete.begin();
8634 i != to_delete.end();
8636 deleted_vars_.erase(*i);
8638 // Do something similar for added variables.
8641 for (string_var_ptr_map::const_iterator i = added_vars_.begin();
8642 i != added_vars_.end();
8644 if (first_->lookup_variable_symbol(*i->second->get_symbol()))
8645 to_delete.push_back(i->first);
8646 else if (! i->second->get_symbol()->get_version().is_empty()
8647 && i->second->get_symbol()->get_version().is_default())
8648 // We are looking for a symbol that has a default version,
8649 // and which seems to be newly added. Let's see if the same
8650 // symbol with *no* version was already present in the
8651 // former corpus. If yes, then the symbol shouldn't be
8652 // considered as 'added'.
8654 elf_symbol::version empty_version;
8655 if (first_->lookup_variable_symbol(i->second->get_symbol()->get_name(),
8657 to_delete.push_back(i->first);
8660 for (vector<string>::const_iterator i = to_delete.begin();
8661 i != to_delete.end();
8663 added_vars_.erase(*i);
8666 // Massage the edit script for added/removed function symbols that
8667 // were not referenced by any debug info and turn them into maps of
8668 // {symbol_name, symbol}.
8670 edit_script& e = unrefed_fn_syms_edit_script_;
8671 for (vector<deletion>::const_iterator it = e.deletions().begin();
8672 it != e.deletions().end();
8675 unsigned i = it->index();
8676 ABG_ASSERT(i < first_->get_unreferenced_function_symbols().size());
8677 elf_symbol_sptr deleted_sym =
8678 first_->get_unreferenced_function_symbols()[i];
8679 if (!second_->lookup_function_symbol(*deleted_sym))
8680 deleted_unrefed_fn_syms_[deleted_sym->get_id_string()] = deleted_sym;
8683 for (vector<insertion>::const_iterator it = e.insertions().begin();
8684 it != e.insertions().end();
8687 for (vector<unsigned>::const_iterator iit =
8688 it->inserted_indexes().begin();
8689 iit != it->inserted_indexes().end();
8693 ABG_ASSERT(i < second_->get_unreferenced_function_symbols().size());
8694 elf_symbol_sptr added_sym =
8695 second_->get_unreferenced_function_symbols()[i];
8696 if ((deleted_unrefed_fn_syms_.find(added_sym->get_id_string())
8697 == deleted_unrefed_fn_syms_.end()))
8699 if (!first_->lookup_function_symbol(*added_sym))
8702 if (! added_sym->get_version().is_empty()
8703 && added_sym->get_version().is_default())
8705 // So added_seem has a default version. If
8706 // the former corpus had a symbol with the
8707 // same name as added_sym but with *no*
8708 // version, then added_sym shouldn't be
8709 // considered as a newly added symbol.
8710 elf_symbol::version empty_version;
8711 if (first_->lookup_function_symbol(added_sym->get_name(),
8717 added_unrefed_fn_syms_[added_sym->get_id_string()] =
8722 deleted_unrefed_fn_syms_.erase(added_sym->get_id_string());
8727 // Massage the edit script for added/removed variable symbols that
8728 // were not referenced by any debug info and turn them into maps of
8729 // {symbol_name, symbol}.
8731 edit_script& e = unrefed_var_syms_edit_script_;
8732 for (vector<deletion>::const_iterator it = e.deletions().begin();
8733 it != e.deletions().end();
8736 unsigned i = it->index();
8737 ABG_ASSERT(i < first_->get_unreferenced_variable_symbols().size());
8738 elf_symbol_sptr deleted_sym =
8739 first_->get_unreferenced_variable_symbols()[i];
8740 if (!second_->lookup_variable_symbol(*deleted_sym))
8741 deleted_unrefed_var_syms_[deleted_sym->get_id_string()] = deleted_sym;
8744 for (vector<insertion>::const_iterator it = e.insertions().begin();
8745 it != e.insertions().end();
8748 for (vector<unsigned>::const_iterator iit =
8749 it->inserted_indexes().begin();
8750 iit != it->inserted_indexes().end();
8754 ABG_ASSERT(i < second_->get_unreferenced_variable_symbols().size());
8755 elf_symbol_sptr added_sym =
8756 second_->get_unreferenced_variable_symbols()[i];
8757 if (deleted_unrefed_var_syms_.find(added_sym->get_id_string())
8758 == deleted_unrefed_var_syms_.end())
8760 if (!first_->lookup_variable_symbol(*added_sym))
8763 if (! added_sym->get_version().is_empty()
8764 && added_sym->get_version().is_default())
8766 // So added_seem has a default version. If
8767 // the former corpus had a symbol with the
8768 // same name as added_sym but with *no*
8769 // version, then added_sym shouldn't be
8770 // considered as a newly added symbol.
8771 elf_symbol::version empty_version;
8772 if (first_->lookup_variable_symbol(added_sym->get_name(),
8778 added_unrefed_var_syms_[added_sym->get_id_string()] =
8783 deleted_unrefed_var_syms_.erase(added_sym->get_id_string());
8789 /// Test if a change reports about a given @ref function_decl that is
8790 /// changed in a certain way is suppressed by a given suppression
8793 /// @param fn the @ref function_decl to consider.
8795 /// @param suppr the suppression specification to consider.
8797 /// @param k the kind of change that happened to @p fn.
8799 /// @param ctxt the context of the current diff.
8801 /// @return true iff the suppression specification @p suppr suppresses
8802 /// change reports about function @p fn, if that function changes in
8803 /// the way expressed by @p k.
8805 function_is_suppressed(const function_decl* fn,
8806 const suppression_sptr suppr,
8807 function_suppression::change_kind k,
8808 const diff_context_sptr ctxt)
8810 function_suppression_sptr fn_suppr = is_function_suppression(suppr);
8813 return fn_suppr->suppresses_function(fn, k, ctxt);
8816 /// Test if a change reports about a given @ref var_decl that is
8817 /// changed in a certain way is suppressed by a given suppression
8820 /// @param fn the @ref var_decl to consider.
8822 /// @param suppr the suppression specification to consider.
8824 /// @param k the kind of change that happened to @p fn.
8826 /// @param ctxt the context of the current diff.
8828 /// @return true iff the suppression specification @p suppr suppresses
8829 /// change reports about variable @p fn, if that variable changes in
8830 /// the way expressed by @p k.
8832 variable_is_suppressed(const var_decl* var,
8833 const suppression_sptr suppr,
8834 variable_suppression::change_kind k,
8835 const diff_context_sptr ctxt)
8837 variable_suppression_sptr var_suppr = is_variable_suppression(suppr);
8840 return var_suppr->suppresses_variable(var, k, ctxt);
8843 /// Apply the suppression specifications for this corpus diff to the
8844 /// set of added and removed functions and variables.
8846 corpus_diff::priv::apply_suppressions_to_added_removed_fns_vars()
8848 diff_context_sptr ctxt = get_context();
8850 const suppressions_type& suppressions = ctxt->suppressions();
8851 for (suppressions_type::const_iterator i = suppressions.begin();
8852 i != suppressions.end();
8855 // Added/Deleted functions.
8856 if (function_suppression_sptr fn_suppr = is_function_suppression(*i))
8859 for (string_function_ptr_map::const_iterator e = added_fns_.begin();
8860 e != added_fns_.end();
8862 if (function_is_suppressed(e->second, fn_suppr,
8863 function_suppression::ADDED_FUNCTION_CHANGE_KIND,
8865 suppressed_added_fns_[e->first] = e->second;
8867 // Deleted functions.
8868 for (string_function_ptr_map::const_iterator e = deleted_fns_.begin();
8869 e != deleted_fns_.end();
8871 if (function_is_suppressed(e->second, fn_suppr,
8872 function_suppression::DELETED_FUNCTION_CHANGE_KIND,
8874 suppressed_deleted_fns_[e->first] = e->second;
8876 // Added function symbols not referenced by any debug info
8877 for (string_elf_symbol_map::const_iterator e =
8878 added_unrefed_fn_syms_.begin();
8879 e != added_unrefed_fn_syms_.end();
8881 if (fn_suppr->suppresses_function_symbol(e->second,
8882 function_suppression::ADDED_FUNCTION_CHANGE_KIND,
8884 suppressed_added_unrefed_fn_syms_[e->first] = e->second;
8886 // Removed function symbols not referenced by any debug info
8887 for (string_elf_symbol_map::const_iterator e =
8888 deleted_unrefed_fn_syms_.begin();
8889 e != deleted_unrefed_fn_syms_.end();
8891 if (fn_suppr->suppresses_function_symbol(e->second,
8892 function_suppression::DELETED_FUNCTION_CHANGE_KIND,
8894 suppressed_deleted_unrefed_fn_syms_[e->first] = e->second;
8896 // Added/Delete virtual member functions changes that might be
8897 // suppressed by a type_suppression that matches the enclosing
8898 // class of the virtual member function.
8899 else if (type_suppression_sptr type_suppr = is_type_suppression(*i))
8901 // Added virtual functions
8902 for (string_function_ptr_map::const_iterator e = added_fns_.begin();
8903 e != added_fns_.end();
8905 if (is_member_function(e->second)
8906 && get_member_function_is_virtual(e->second))
8908 function_decl *f = e->second;
8910 is_class_type(is_method_type(f->get_type())->get_class_type());
8912 if (type_suppr->suppresses_type(c, ctxt))
8913 suppressed_added_fns_[e->first] = e->second;
8915 // Deleted virtual functions
8916 for (string_function_ptr_map::const_iterator e = deleted_fns_.begin();
8917 e != deleted_fns_.end();
8919 if (is_member_function(e->second)
8920 && get_member_function_is_virtual(e->second))
8922 function_decl *f = e->second;
8924 is_class_type(is_method_type(f->get_type())->get_class_type());
8926 if (type_suppr->suppresses_type(c, ctxt))
8927 suppressed_deleted_fns_[e->first] = e->second;
8930 // Added/Deleted variables
8931 else if (variable_suppression_sptr var_suppr =
8932 is_variable_suppression(*i))
8935 for (string_var_ptr_map::const_iterator e = added_vars_.begin();
8936 e != added_vars_.end();
8938 if (variable_is_suppressed(e->second, var_suppr,
8939 variable_suppression::ADDED_VARIABLE_CHANGE_KIND,
8941 suppressed_added_vars_[e->first] = e->second;
8944 for (string_var_ptr_map::const_iterator e = deleted_vars_.begin();
8945 e != deleted_vars_.end();
8947 if (variable_is_suppressed(e->second, var_suppr,
8948 variable_suppression::DELETED_VARIABLE_CHANGE_KIND,
8950 suppressed_deleted_vars_[e->first] = e->second;
8952 // Added variable symbols not referenced by any debug info
8953 for (string_elf_symbol_map::const_iterator e =
8954 added_unrefed_var_syms_.begin();
8955 e != added_unrefed_var_syms_.end();
8957 if (var_suppr->suppresses_variable_symbol(e->second,
8958 variable_suppression::ADDED_VARIABLE_CHANGE_KIND,
8960 suppressed_added_unrefed_var_syms_[e->first] = e->second;
8962 // Removed variable symbols not referenced by any debug info
8963 for (string_elf_symbol_map::const_iterator e =
8964 deleted_unrefed_var_syms_.begin();
8965 e != deleted_unrefed_var_syms_.end();
8967 if (var_suppr->suppresses_variable_symbol(e->second,
8968 variable_suppression::DELETED_VARIABLE_CHANGE_KIND,
8970 suppressed_deleted_unrefed_var_syms_[e->first] = e->second;
8975 /// Test if the change reports for a given deleted function have
8978 /// @param fn the function to consider.
8980 /// @return true iff the change reports for a give given deleted
8981 /// function have been deleted.
8983 corpus_diff::priv::deleted_function_is_suppressed(const function_decl* fn) const
8988 string_function_ptr_map::const_iterator i =
8989 suppressed_deleted_fns_.find(fn->get_id());
8991 return (i != suppressed_deleted_fns_.end());
8994 /// Test if the change reports for a give given added function has
8997 /// @param fn the function to consider.
8999 /// @return true iff the change reports for a give given added
9000 /// function has been deleted.
9002 corpus_diff::priv::added_function_is_suppressed(const function_decl* fn) const
9007 string_function_ptr_map::const_iterator i =
9008 suppressed_added_fns_.find(fn->get_id());
9010 return (i != suppressed_added_fns_.end());
9013 /// Test if the change reports for a give given deleted variable has
9016 /// @param var the variable to consider.
9018 /// @return true iff the change reports for a give given deleted
9019 /// variable has been deleted.
9021 corpus_diff::priv::deleted_variable_is_suppressed(const var_decl* var) const
9026 string_var_ptr_map::const_iterator i =
9027 suppressed_deleted_vars_.find(var->get_id());
9029 return (i != suppressed_deleted_vars_.end());
9032 /// Test if the change reports for a given added variable have been
9035 /// @param var the variable to consider.
9037 /// @return true iff the change reports for a given deleted
9038 /// variable has been deleted.
9040 corpus_diff::priv::added_variable_is_suppressed(const var_decl* var) const
9045 string_var_ptr_map::const_iterator i =
9046 suppressed_added_vars_.find(var->get_id());
9048 return (i != suppressed_added_vars_.end());
9051 /// Test if the change reports for a given deleted function symbol
9052 /// (that is not referenced by any debug info) has been suppressed.
9054 /// @param var the function to consider.
9056 /// @return true iff the change reports for a given deleted function
9057 /// symbol has been suppressed.
9059 corpus_diff::priv::deleted_unrefed_fn_sym_is_suppressed(const elf_symbol* s) const
9064 string_elf_symbol_map::const_iterator i =
9065 suppressed_deleted_unrefed_fn_syms_.find(s->get_id_string());
9067 return (i != suppressed_deleted_unrefed_fn_syms_.end());
9070 /// Test if the change reports for a given added function symbol
9071 /// (that is not referenced by any debug info) has been suppressed.
9073 /// @param var the function to consider.
9075 /// @return true iff the change reports for a given added function
9076 /// symbol has been suppressed.
9078 corpus_diff::priv::added_unrefed_fn_sym_is_suppressed(const elf_symbol* s) const
9083 string_elf_symbol_map::const_iterator i =
9084 suppressed_added_unrefed_fn_syms_.find(s->get_id_string());
9086 return (i != suppressed_added_unrefed_fn_syms_.end());
9089 /// Test if the change reports for a given deleted variable symbol
9090 /// (that is not referenced by any debug info) has been suppressed.
9092 /// @param var the variable to consider.
9094 /// @return true iff the change reports for a given deleted variable
9095 /// symbol has been suppressed.
9097 corpus_diff::priv::deleted_unrefed_var_sym_is_suppressed(const elf_symbol* s) const
9102 string_elf_symbol_map::const_iterator i =
9103 suppressed_deleted_unrefed_var_syms_.find(s->get_id_string());
9105 return (i != suppressed_deleted_unrefed_var_syms_.end());
9108 /// Test if the change reports for a given added variable symbol
9109 /// (that is not referenced by any debug info) has been suppressed.
9111 /// @param var the variable to consider.
9113 /// @return true iff the change reports for a given added variable
9114 /// symbol has been suppressed.
9116 corpus_diff::priv::added_unrefed_var_sym_is_suppressed(const elf_symbol* s) const
9121 string_elf_symbol_map::const_iterator i =
9122 suppressed_added_unrefed_var_syms_.find(s->get_id_string());
9124 return (i != suppressed_added_unrefed_var_syms_.end());
9127 #ifdef do_count_diff_map_changes
9128 #undef do_count_diff_map_changes
9130 #define do_count_diff_map_changes(diff_map, n_changes, n_filtered) \
9132 string_diff_ptr_map::const_iterator i; \
9133 for (i = diff_map.begin(); \
9134 i != diff_map.end(); \
9137 if (const var_diff* d = is_var_diff(i->second)) \
9138 if (is_data_member(d->first_var())) \
9141 if (i->second->has_local_changes()) \
9143 if (!i->second->get_canonical_diff()->to_be_reported()) \
9148 /// Count the number of leaf changes as well as the number of the
9149 /// changes that have been filtered out.
9151 /// @param num_changes out parameter. This is set to the total number
9152 /// of leaf changes.
9154 /// @param num_filtered out parameter. This is set to the number of
9155 /// leaf changes that have been filtered out.
9157 corpus_diff::priv::count_leaf_changes(size_t &num_changes, size_t &num_filtered)
9159 count_leaf_type_changes(num_changes, num_filtered);
9161 // Now count the non-type changes.
9162 do_count_diff_map_changes(leaf_diffs_.get_function_decl_diff_map(),
9163 num_changes, num_filtered);
9164 do_count_diff_map_changes(leaf_diffs_.get_var_decl_diff_map(),
9165 num_changes, num_filtered);
9168 /// Count the number of leaf *type* changes as well as the number of
9169 /// the leaf type changes that have been filtered out.
9171 /// @param num_changes out parameter. This is set to the total number
9172 /// of leaf type changes.
9174 /// @param num_filtered out parameter. This is set to the number of
9175 /// leaf type changes that have been filtered out.
9177 corpus_diff::priv::count_leaf_type_changes(size_t &num_changes,
9178 size_t &num_filtered)
9180 do_count_diff_map_changes(leaf_diffs_.get_type_decl_diff_map(),
9181 num_changes, num_filtered);
9182 do_count_diff_map_changes(leaf_diffs_.get_enum_diff_map(),
9183 num_changes, num_filtered);
9184 do_count_diff_map_changes(leaf_diffs_.get_class_diff_map(),
9185 num_changes, num_filtered);
9186 do_count_diff_map_changes(leaf_diffs_.get_union_diff_map(),
9187 num_changes, num_filtered);
9188 do_count_diff_map_changes(leaf_diffs_.get_typedef_diff_map(),
9189 num_changes, num_filtered);
9190 do_count_diff_map_changes(leaf_diffs_.get_array_diff_map(),
9191 num_changes, num_filtered);
9192 do_count_diff_map_changes(leaf_diffs_.get_distinct_diff_map(),
9193 num_changes, num_filtered);
9194 do_count_diff_map_changes(leaf_diffs_.get_fn_parm_diff_map(),
9195 num_changes, num_filtered);
9198 /// Compute the diff stats.
9200 /// To know the number of functions that got filtered out, this
9201 /// function applies the categorizing filters to the diff sub-trees of
9202 /// each function changes diff, prior to calculating the stats.
9204 /// @param num_removed the number of removed functions.
9206 /// @param num_added the number of added functions.
9208 /// @param num_changed the number of changed functions.
9210 /// @param num_filtered_out the number of changed functions that are
9211 /// got filtered out from the report
9213 corpus_diff::priv::apply_filters_and_compute_diff_stats(diff_stats& stat)
9216 stat.num_func_removed(deleted_fns_.size());
9217 stat.num_removed_func_filtered_out(suppressed_deleted_fns_.size());
9218 stat.num_func_added(added_fns_.size());
9219 stat.num_added_func_filtered_out(suppressed_added_fns_.size());
9220 stat.num_func_changed(changed_fns_map_.size());
9222 stat.num_vars_removed(deleted_vars_.size());
9223 stat.num_removed_vars_filtered_out(suppressed_deleted_vars_.size());
9224 stat.num_vars_added(added_vars_.size());
9225 stat.num_added_vars_filtered_out(suppressed_added_vars_.size());
9226 stat.num_vars_changed(changed_vars_map_.size());
9228 diff_context_sptr ctxt = get_context();
9230 // Walk the changed function diff nodes to apply the categorization
9233 for (function_decl_diff_sptrs_type::const_iterator i =
9234 changed_fns_.begin();
9235 i != changed_fns_.end();
9238 diff_sptr diff = *i;
9239 ctxt->maybe_apply_filters(diff);
9242 // Walk the changed variable diff nodes to apply the categorization
9244 for (var_diff_sptrs_type::const_iterator i = sorted_changed_vars_.begin();
9245 i != sorted_changed_vars_.end();
9248 diff_sptr diff = *i;
9249 ctxt->maybe_apply_filters(diff);
9252 categorize_redundant_changed_sub_nodes();
9254 // Walk the changed function diff nodes to count the number of
9255 // filtered-out functions and the number of functions with virtual
9257 for (function_decl_diff_sptrs_type::const_iterator i =
9258 changed_fns_.begin();
9259 i != changed_fns_.end();
9262 if ((*i)->is_filtered_out())
9264 stat.num_changed_func_filtered_out
9265 (stat.num_changed_func_filtered_out() + 1);
9267 if ((*i)->has_local_changes())
9268 stat.num_leaf_func_changes_filtered_out
9269 (stat.num_leaf_func_changes_filtered_out() + 1);
9273 if ((*i)->get_category() & VIRTUAL_MEMBER_CHANGE_CATEGORY)
9274 stat.num_func_with_virtual_offset_changes
9275 (stat.num_func_with_virtual_offset_changes() + 1);
9278 if ((*i)->has_local_changes())
9279 stat.num_leaf_func_changes
9280 (stat.num_leaf_func_changes() + 1);
9283 // Walk the changed variables diff nodes to count the number of
9284 // filtered-out variables.
9285 for (var_diff_sptrs_type ::const_iterator i = sorted_changed_vars_.begin();
9286 i != sorted_changed_vars_.end();
9289 if ((*i)->is_filtered_out())
9291 stat.num_changed_vars_filtered_out
9292 (stat.num_changed_vars_filtered_out() + 1);
9294 if ((*i)->has_local_changes())
9295 stat.num_leaf_var_changes_filtered_out
9296 (stat.num_leaf_var_changes_filtered_out() + 1);
9298 if ((*i)->has_local_changes())
9299 stat.num_leaf_func_changes
9300 (stat.num_leaf_func_changes() + 1);
9303 stat.num_func_syms_added(added_unrefed_fn_syms_.size());
9304 stat.num_added_func_syms_filtered_out(suppressed_added_unrefed_fn_syms_.size());
9305 stat.num_func_syms_removed(deleted_unrefed_fn_syms_.size());
9306 stat.num_removed_func_syms_filtered_out(suppressed_deleted_unrefed_fn_syms_.size());
9307 stat.num_var_syms_added(added_unrefed_var_syms_.size());
9308 stat.num_added_var_syms_filtered_out(suppressed_added_unrefed_var_syms_.size());
9309 stat.num_var_syms_removed(deleted_unrefed_var_syms_.size());
9310 stat.num_removed_var_syms_filtered_out(suppressed_deleted_unrefed_var_syms_.size());
9312 // Walk the general leaf type diff nodes to count them
9314 size_t num_type_changes = 0, num_type_filtered = 0;
9315 count_leaf_type_changes(num_type_changes, num_type_filtered);
9317 stat.num_leaf_type_changes(num_type_changes);
9318 stat.num_leaf_type_changes_filtered_out(num_type_filtered);
9321 // Walk the general leaf artefacts diff nodes to count them
9323 size_t num_changes = 0, num_filtered = 0;
9324 count_leaf_changes(num_changes, num_filtered);
9326 stat.num_leaf_changes(num_changes);
9327 stat.num_leaf_changes_filtered_out(num_filtered);
9331 /// Emit the summary of the functions & variables that got
9332 /// removed/changed/added.
9334 /// @param out the output stream to emit the stats to.
9336 /// @param indent the indentation string to use in the summary.
9338 corpus_diff::priv::emit_diff_stats(const diff_stats& s,
9340 const string& indent)
9342 /// Report added/removed/changed functions.
9343 size_t net_num_leaf_changes =
9344 s.net_num_func_removed() +
9345 s.net_num_func_added() +
9346 s.net_num_leaf_func_changes() +
9347 s.net_num_vars_removed() +
9348 s.net_num_vars_added() +
9349 s.net_num_vars_changed() +
9350 s.net_num_leaf_type_changes();
9352 if (!sonames_equal_)
9353 out << indent << "ELF SONAME changed\n";
9355 if (!architectures_equal_)
9356 out << indent << "ELF architecture changed\n";
9358 diff_context_sptr ctxt = get_context();
9360 if (ctxt->show_leaf_changes_only())
9362 out << "Leaf changes summary: ";
9363 out << net_num_leaf_changes << " artifact";
9364 if (net_num_leaf_changes > 1)
9368 if (size_t num_filtered = s.num_leaf_changes_filtered_out())
9369 out << " (" << num_filtered << " filtered out)";
9373 out << indent << "Changed leaf types summary: "
9374 << s.net_num_leaf_type_changes();
9375 if (s.num_leaf_type_changes_filtered_out())
9376 out << " (" << s.num_leaf_type_changes_filtered_out()
9377 << " filtered out)";
9378 out << " leaf type";
9379 if (s.num_leaf_type_changes() > 1)
9381 out << " changed\n";
9383 // function changes summary
9384 out << indent << "Removed/Changed/Added functions summary: ";
9385 out << s.net_num_func_removed() << " Removed";
9386 if (s.num_removed_func_filtered_out())
9388 << s.num_removed_func_filtered_out()
9389 << " filtered out)";
9392 out << s.net_num_leaf_func_changes() << " Changed";
9393 if (s.num_leaf_func_changes_filtered_out())
9395 << s.num_leaf_func_changes_filtered_out()
9396 << " filtered out)";
9399 out << s.net_num_func_added()<< " Added ";
9400 if (s.net_num_func_added() <= 1)
9404 if (s.num_added_func_filtered_out())
9405 out << " (" << s.num_added_func_filtered_out() << " filtered out)";
9408 // variables changes summary
9409 out << indent << "Removed/Changed/Added variables summary: ";
9411 out << s.net_num_vars_removed() << " Removed";
9412 if (s.num_removed_vars_filtered_out())
9413 out << " (" << s.num_removed_vars_filtered_out()
9414 << " filtered out)";
9417 out << s.net_num_leaf_var_changes() << " Changed";
9418 if (s.num_leaf_var_changes_filtered_out())
9420 << s.num_leaf_var_changes_filtered_out()
9421 << " filtered out)";
9424 out << s.net_num_vars_added() << " Added ";
9425 if (s.net_num_vars_added() <= 1)
9429 if (s.num_added_vars_filtered_out())
9430 out << " (" << s.num_added_vars_filtered_out()
9431 << " filtered out)";
9434 else // if (ctxt->show_leaf_changes_only())
9436 size_t total_nb_function_changes = s.num_func_removed()
9437 + s.num_func_changed() + s.num_func_added();
9439 // function changes summary
9440 out << indent << "Functions changes summary: ";
9441 out << s.net_num_func_removed() << " Removed";
9442 if (s.num_removed_func_filtered_out())
9444 << s.num_removed_func_filtered_out()
9445 << " filtered out)";
9448 out << s.net_num_func_changed() << " Changed";
9449 if (s.num_changed_func_filtered_out())
9450 out << " (" << s.num_changed_func_filtered_out() << " filtered out)";
9453 out << s.net_num_func_added()<< " Added";
9454 if (s.num_added_func_filtered_out())
9455 out << " (" << s.num_added_func_filtered_out() << " filtered out)";
9456 if (total_nb_function_changes <= 1)
9459 out << " functions";
9462 // variables changes summary
9463 size_t total_nb_variable_changes = s.num_vars_removed()
9464 + s.num_vars_changed() + s.num_vars_added();
9466 out << indent << "Variables changes summary: ";
9468 out << s.net_num_vars_removed() << " Removed";
9469 if (s.num_removed_vars_filtered_out())
9470 out << " (" << s.num_removed_vars_filtered_out()
9471 << " filtered out)";
9474 out << s.num_vars_changed() - s.num_changed_vars_filtered_out() << " Changed";
9475 if (s.num_changed_vars_filtered_out())
9476 out << " (" << s.num_changed_vars_filtered_out() << " filtered out)";
9479 out << s.net_num_vars_added() << " Added";
9480 if (s.num_added_vars_filtered_out())
9481 out << " (" << s.num_added_vars_filtered_out()
9482 << " filtered out)";
9483 if (total_nb_variable_changes <= 1)
9486 out << " variables";
9490 if (ctxt->show_symbols_unreferenced_by_debug_info()
9491 && (s.num_func_syms_removed()
9492 || s.num_func_syms_added()
9493 || s.num_var_syms_removed()
9494 || s.num_var_syms_added()))
9496 // function symbols changes summary.
9498 if (!ctxt->show_added_symbols_unreferenced_by_debug_info()
9499 && s.num_func_syms_removed() == 0
9500 && s.num_func_syms_added() != 0)
9501 // If the only unreferenced function symbol change is function
9502 // syms that got added, but we were forbidden to show function
9503 // syms being added, do nothing.
9508 << "Function symbols changes summary: "
9509 << s.net_num_removed_func_syms() << " Removed";
9510 if (s.num_removed_func_syms_filtered_out())
9511 out << " (" << s.num_removed_func_syms_filtered_out()
9512 << " filtered out)";
9514 out << s.net_num_added_func_syms() << " Added";
9515 if (s.num_added_func_syms_filtered_out())
9516 out << " (" << s.num_added_func_syms_filtered_out()
9517 << " filtered out)";
9518 out << " function symbol";
9519 if (s.num_func_syms_added() + s.num_func_syms_removed() > 1)
9521 out << " not referenced by debug info\n";
9524 // variable symbol changes summary.
9526 if (!ctxt->show_added_symbols_unreferenced_by_debug_info()
9527 && s.num_var_syms_removed() == 0
9528 && s.num_var_syms_added() != 0)
9529 // If the only unreferenced variable symbol change is variable
9530 // syms that got added, but we were forbidden to show variable
9531 // syms being added, do nothing.
9536 << "Variable symbols changes summary: "
9537 << s.net_num_removed_var_syms() << " Removed";
9538 if (s.num_removed_var_syms_filtered_out())
9539 out << " (" << s.num_removed_var_syms_filtered_out()
9540 << " filtered out)";
9542 out << s.net_num_added_var_syms() << " Added";
9543 if (s.num_added_var_syms_filtered_out())
9544 out << " (" << s.num_added_var_syms_filtered_out()
9545 << " filtered out)";
9546 out << " variable symbol";
9547 if (s.num_var_syms_added() + s.num_var_syms_removed() > 1)
9549 out << " not referenced by debug info\n";
9554 /// Walk the changed functions and variables diff nodes to categorize
9555 /// redundant nodes.
9557 corpus_diff::priv::categorize_redundant_changed_sub_nodes()
9561 diff_context_sptr ctxt = get_context();
9563 ctxt->forget_visited_diffs();
9564 for (function_decl_diff_sptrs_type::const_iterator i =
9565 changed_fns_.begin();
9566 i!= changed_fns_.end();
9570 categorize_redundancy(diff);
9573 for (var_diff_sptrs_type::const_iterator i = sorted_changed_vars_.begin();
9574 i!= sorted_changed_vars_.end();
9577 diff_sptr diff = *i;
9578 categorize_redundancy(diff);
9582 /// Walk the changed functions and variables diff nodes and clear the
9583 /// redundancy categorization they might carry.
9585 corpus_diff::priv::clear_redundancy_categorization()
9588 for (function_decl_diff_sptrs_type::const_iterator i = changed_fns_.begin();
9589 i!= changed_fns_.end();
9593 abigail::comparison::clear_redundancy_categorization(diff);
9596 for (var_diff_sptrs_type::const_iterator i = sorted_changed_vars_.begin();
9597 i!= sorted_changed_vars_.end();
9601 abigail::comparison::clear_redundancy_categorization(diff);
9605 /// If the user asked to dump the diff tree node (for changed
9606 /// variables and functions) on the error output stream, then just do
9609 /// This function is used for debugging purposes.
9611 corpus_diff::priv::maybe_dump_diff_tree()
9613 diff_context_sptr ctxt = get_context();
9615 if (!ctxt->dump_diff_tree()
9616 || ctxt->error_output_stream() == 0)
9619 if (!changed_fns_.empty())
9621 *ctxt->error_output_stream() << "changed functions diff tree: \n\n";
9622 for (function_decl_diff_sptrs_type::const_iterator i =
9623 changed_fns_.begin();
9624 i != changed_fns_.end();
9628 print_diff_tree(d, *ctxt->error_output_stream());
9632 if (!sorted_changed_vars_.empty())
9634 *ctxt->error_output_stream() << "\nchanged variables diff tree: \n\n";
9635 for (var_diff_sptrs_type::const_iterator i =
9636 sorted_changed_vars_.begin();
9637 i != sorted_changed_vars_.end();
9641 print_diff_tree(d, *ctxt->error_output_stream());
9646 /// Populate the vector of children node of the @ref corpus_diff type.
9648 /// The children node can then later be retrieved using
9649 /// corpus_diff::children_node().
9651 corpus_diff::chain_into_hierarchy()
9653 for (function_decl_diff_sptrs_type::const_iterator i =
9654 changed_functions_sorted().begin();
9655 i != changed_functions_sorted().end();
9657 if (diff_sptr d = *i)
9658 append_child_node(d);
9661 /// Constructor for @ref corpus_diff.
9663 /// @param first the first corpus of the diff.
9665 /// @param second the second corpus of the diff.
9667 /// @param ctxt the diff context to use. Note that this context
9668 /// object must stay alive at least during the life time of the
9669 /// current instance of @ref corpus_diff. Otherwise memory corruption
9671 corpus_diff::corpus_diff(corpus_sptr first,
9673 diff_context_sptr ctxt)
9674 : priv_(new priv(first, second, ctxt))
9677 /// Finish building the current instance of @ref corpus_diff.
9679 corpus_diff::finish_diff_type()
9681 if (priv_->finished_)
9683 chain_into_hierarchy();
9684 priv_->finished_ = true;
9687 /// @return the first corpus of the diff.
9689 corpus_diff::first_corpus() const
9690 {return priv_->first_;}
9692 /// @return the second corpus of the diff.
9694 corpus_diff::second_corpus() const
9695 {return priv_->second_;}
9697 /// @return the children nodes of the current instance of corpus_diff.
9698 const vector<diff*>&
9699 corpus_diff::children_nodes() const
9700 {return priv_->children_;}
9702 /// Append a new child node to the vector of children nodes for the
9703 /// current instance of @ref corpus_diff node.
9705 /// Note that the vector of children nodes for the current instance of
9706 /// @ref corpus_diff node must remain sorted, using
9707 /// diff_less_than_functor.
9709 /// @param d the new child node. Note that the life time of the
9710 /// object held by @p d will thus equal the life time of the current
9711 /// instance of @ref corpus_diff.
9713 corpus_diff::append_child_node(diff_sptr d)
9717 diff_less_than_functor is_less_than;
9718 bool inserted = false;
9719 for (vector<diff*>::iterator i = priv_->children_.begin();
9720 i != priv_->children_.end();
9722 // Look for the point where to insert the diff child node.
9723 if (!is_less_than(d.get(), *i))
9725 context()->keep_diff_alive(d);
9726 priv_->children_.insert(i, d.get());
9727 // As we have just inserted 'd' into the vector, the iterator
9728 // 'i' is invalidated. We must *NOT* use it anymore.
9735 context()->keep_diff_alive(d);
9736 // We didn't insert anything to the vector, presumably b/c it was
9737 // empty or had one element that was "less than" 'd'. We can thus
9738 // just append 'd' to the end of the vector.
9739 priv_->children_.push_back(d.get());
9743 /// @return the bare edit script of the functions changed as recorded
9746 corpus_diff::function_changes() const
9747 {return priv_->fns_edit_script_;}
9749 /// @return the bare edit script of the variables changed as recorded
9752 corpus_diff::variable_changes() const
9753 {return priv_->vars_edit_script_;}
9755 /// Test if the soname of the underlying corpus has changed.
9757 /// @return true iff the soname has changed.
9759 corpus_diff::soname_changed() const
9760 {return !priv_->sonames_equal_;}
9762 /// Test if the architecture of the underlying corpus has changed.
9764 /// @return true iff the architecture has changed.
9766 corpus_diff::architecture_changed() const
9767 {return !priv_->architectures_equal_;}
9769 /// Getter for the deleted functions of the diff.
9771 /// @return the the deleted functions of the diff.
9772 const string_function_ptr_map&
9773 corpus_diff::deleted_functions() const
9774 {return priv_->deleted_fns_;}
9776 /// Getter for the added functions of the diff.
9778 /// @return the added functions of the diff.
9779 const string_function_ptr_map&
9780 corpus_diff::added_functions()
9781 {return priv_->added_fns_;}
9783 /// Getter for the functions which signature didn't change, but which
9784 /// do have some indirect changes in their parms.
9786 /// @return a non-sorted map of functions which signature didn't
9787 /// change, but which do have some indirect changes in their parms.
9788 /// The key of the map is a unique identifier for the function; it's
9789 /// usually made of the name and version of the underlying ELF symbol
9790 /// of the function for corpora that were built from ELF files.
9791 const string_function_decl_diff_sptr_map&
9792 corpus_diff::changed_functions()
9793 {return priv_->changed_fns_map_;}
9795 /// Getter for a sorted vector of functions which signature didn't
9796 /// change, but which do have some indirect changes in their parms.
9798 /// @return a sorted vector of functions which signature didn't
9799 /// change, but which do have some indirect changes in their parms.
9800 const function_decl_diff_sptrs_type&
9801 corpus_diff::changed_functions_sorted()
9802 {return priv_->changed_fns_;}
9804 /// Getter for the variables that got deleted from the first subject
9807 /// @return the map of deleted variable.
9808 const string_var_ptr_map&
9809 corpus_diff::deleted_variables() const
9810 {return priv_->deleted_vars_;}
9812 /// Getter for the added variables of the diff.
9814 /// @return the map of added variable.
9815 const string_var_ptr_map&
9816 corpus_diff::added_variables() const
9817 {return priv_->added_vars_;}
9819 /// Getter for the non-sorted map of variables which signature didn't
9820 /// change but which do have some indirect changes in some sub-types.
9822 /// @return the non-sorted map of changed variables.
9823 const string_var_diff_sptr_map&
9824 corpus_diff::changed_variables()
9825 {return priv_->changed_vars_map_;}
9827 /// Getter for the sorted vector of variables which signature didn't
9828 /// change but which do have some indirect changes in some sub-types.
9830 /// @return a sorted vector of changed variables.
9831 const var_diff_sptrs_type&
9832 corpus_diff::changed_variables_sorted()
9833 {return priv_->sorted_changed_vars_;}
9835 /// Getter for function symbols not referenced by any debug info and
9836 /// that got deleted.
9838 /// @return a map of elf function symbols not referenced by any debug
9839 /// info and that got deleted.
9840 const string_elf_symbol_map&
9841 corpus_diff::deleted_unrefed_function_symbols() const
9842 {return priv_->deleted_unrefed_fn_syms_;}
9844 /// Getter for function symbols not referenced by any debug info and
9847 /// @return a map of elf function symbols not referenced by any debug
9848 /// info and that got added.
9849 const string_elf_symbol_map&
9850 corpus_diff::added_unrefed_function_symbols() const
9851 {return priv_->added_unrefed_fn_syms_;}
9853 /// Getter for variable symbols not referenced by any debug info and
9854 /// that got deleted.
9856 /// @return a map of elf variable symbols not referenced by any debug
9857 /// info and that got deleted.
9858 const string_elf_symbol_map&
9859 corpus_diff::deleted_unrefed_variable_symbols() const
9860 {return priv_->deleted_unrefed_var_syms_;}
9862 /// Getter for variable symbols not referenced by any debug info and
9865 /// @return a map of elf variable symbols not referenced by any debug
9866 /// info and that got added.
9867 const string_elf_symbol_map&
9868 corpus_diff::added_unrefed_variable_symbols() const
9869 {return priv_->added_unrefed_var_syms_;}
9871 /// Getter of the diff context of this diff
9873 /// @return the diff context for this diff.
9874 const diff_context_sptr
9875 corpus_diff::context() const
9876 {return priv_->get_context();}
9878 /// @return the pretty representation for the current instance of @ref
9881 corpus_diff::get_pretty_representation() const
9883 if (priv_->pretty_representation_.empty())
9885 std::ostringstream o;
9887 << first_corpus()->get_path()
9889 << second_corpus()->get_path()
9891 priv_->pretty_representation_ = o.str();
9893 return priv_->pretty_representation_;
9895 /// Return true iff the current diff node carries a change.
9897 /// @return true iff the current diff node carries a change.
9899 corpus_diff::has_changes() const
9901 return (soname_changed()
9902 || architecture_changed()
9903 || priv_->deleted_fns_.size()
9904 || priv_->added_fns_.size()
9905 || priv_->changed_fns_map_.size()
9906 || priv_->deleted_vars_.size()
9907 || priv_->added_vars_.size()
9908 || priv_->changed_vars_map_.size()
9909 || priv_->added_unrefed_fn_syms_.size()
9910 || priv_->deleted_unrefed_fn_syms_.size()
9911 || priv_->added_unrefed_var_syms_.size()
9912 || priv_->deleted_unrefed_var_syms_.size());
9915 /// Test if the current instance of @ref corpus_diff carries changes
9916 /// that we are sure are incompatible. By incompatible change we mean
9917 /// a change that "breaks" the ABI of the corpus we are looking at.
9919 /// In concrete terms, this function considers the following changes
9920 /// as being ABI incompatible for sure:
9922 /// - a soname change
9923 /// - if exported functions or variables got removed
9925 /// Note that subtype changes *can* represent changes that break ABI
9926 /// too. But they also can be changes that are OK, ABI-wise.
9928 /// It's up to the user to provide suppression specifications to say
9929 /// explicitely which subtype change is OK. The remaining sub-type
9930 /// changes are then considered to be ABI incompatible. But to test
9931 /// if such ABI incompatible subtype changes are present you need to
9932 /// use the function @ref corpus_diff::has_net_subtype_changes()
9934 /// @return true iff the current instance of @ref corpus_diff carries
9935 /// changes that we are sure are ABI incompatible.
9937 corpus_diff::has_incompatible_changes() const
9939 const diff_stats& stats = const_cast<corpus_diff*>(this)->
9940 apply_filters_and_suppressions_before_reporting();
9942 return (soname_changed() || architecture_changed()
9943 || stats.net_num_func_removed() != 0
9944 || (stats.num_func_with_virtual_offset_changes() != 0
9945 // If all reports about functions with sub-type changes
9946 // have been suppressd, then even those about functions
9947 // that are virtual don't matter anymore because the
9948 // user willingly requested to shut them down
9949 && stats.net_num_func_changed() != 0)
9950 || stats.net_num_vars_removed() != 0
9951 || stats.net_num_removed_func_syms() != 0
9952 || stats.net_num_removed_var_syms() != 0);
9955 /// Test if the current instance of @ref corpus_diff carries subtype
9956 /// changes whose reports are not suppressed by any suppression
9957 /// specification. In effect, these are deemed incompatible ABI
9960 /// @return true iff the the current instance of @ref corpus_diff
9961 /// carries subtype changes that are deemed incompatible ABI changes.
9963 corpus_diff::has_net_subtype_changes() const
9965 const diff_stats& stats = const_cast<corpus_diff*>(this)->
9966 apply_filters_and_suppressions_before_reporting();
9968 return (stats.net_num_func_changed() != 0
9969 || stats.net_num_vars_changed() != 0);
9972 /// Test if the current instance of @ref corpus_diff carries changes
9973 /// whose reports are not suppressed by any suppression specification.
9974 /// In effect, these are deemed incompatible ABI changes.
9976 /// @return true iff the the current instance of @ref corpus_diff
9977 /// carries subtype changes that are deemed incompatible ABI changes.
9979 corpus_diff::has_net_changes() const
9981 const diff_stats& stats = const_cast<corpus_diff*>(this)->
9982 apply_filters_and_suppressions_before_reporting();
9984 return (architecture_changed()
9986 || stats.net_num_func_changed()
9987 || stats.net_num_vars_changed()
9988 || stats.net_num_func_added()
9989 || stats.net_num_added_func_syms()
9990 || stats.net_num_func_removed()
9991 || stats.net_num_removed_func_syms()
9992 || stats.net_num_vars_added()
9993 || stats.net_num_added_var_syms()
9994 || stats.net_num_vars_removed()
9995 || stats.net_num_removed_var_syms());
9998 /// Apply the different filters that are registered to be applied to
9999 /// the diff tree; that includes the categorization filters. Also,
10000 /// apply the suppression interpretation filters.
10002 /// After the filters are applied, this function calculates some
10003 /// statistics about the changes carried by the current instance of
10004 /// @ref corpus_diff. These statistics are represented by an instance
10005 /// of @ref corpus_diff::diff_stats.
10007 /// This member function is called by the reporting function
10008 /// corpus_diff::report().
10010 /// Note that for a given instance of corpus_diff, this function
10011 /// applies the filters and suppressions only the first time it is
10012 /// invoked. Subsequent invocations just return the instance of
10013 /// corpus_diff::diff_stats that was cached after the first
10016 /// @return a reference to the statistics about the changes carried by
10017 /// the current instance of @ref corpus_diff.
10018 const corpus_diff::diff_stats&
10019 corpus_diff::apply_filters_and_suppressions_before_reporting()
10021 if (priv_->diff_stats_)
10022 return *priv_->diff_stats_;
10024 apply_suppressions(this);
10025 priv_->diff_stats_.reset(new diff_stats(context()));
10026 mark_leaf_diff_nodes();
10027 priv_->apply_filters_and_compute_diff_stats(*priv_->diff_stats_);
10028 return *priv_->diff_stats_;
10031 /// A visitor that marks leaf diff nodes by storing them in the
10032 /// instance of @ref diff_maps returned by
10033 /// corpus_diff::get_leaf_diffs() invoked on the current instance of
10035 struct leaf_diff_node_marker_visitor : public diff_node_visitor
10037 /// This is called when the visitor visits a diff node.
10039 /// It basically tests if the diff node being visited is a leaf diff
10040 /// node - that is, if contains local changes. If it does, then the
10041 /// node is added to the set of maps that hold leaf diffs in the
10042 /// current corpus_diff.
10044 /// @param d the diff node being visited.
10046 visit_begin(diff *d)
10048 if (d->has_local_changes()
10049 // A leaf basic (or class/union) type name change makes no
10050 // sense when showing just leaf changes. It only makes sense
10051 // when it can explain the details about a non-leaf change.
10052 // In other words, it doesn't make sense to say that an "int"
10053 // became "unsigned int". But it does make sense to say that
10054 // a typedef changed because its underlying type was 'int' and
10055 // is now an "unsigned int".
10056 && !filtering::has_basic_or_class_type_name_change(d)
10057 // Similarly, a *local* change describing a type that changed
10058 // its nature doesn't make sense.
10059 && !is_distinct_diff(d)
10060 // Similarly, a pointer (or reference or array) or qualified
10061 // type change in itself doesn't make sense. It's would
10062 // rather make sense to show that pointer change as part of
10063 // the variable change whose pointer type changed, for
10065 && !is_pointer_diff(d)
10066 && !is_reference_diff(d)
10067 && !is_qualified_type_diff(d)
10068 && !is_array_diff(d)
10069 // Similarly a parameter chagne in itself doesn't make sense.
10070 // It should have already been reported as part of the change
10071 // of the function it belongs to.
10072 && !is_fn_parm_diff(d)
10073 // An anonymous class or union diff doesn't make sense on its
10074 // own. It must have been described already by the diff of
10075 // the enclosing struct or union if 'd' is from an anonymous
10076 // data member, or from a typedef change if 'd' is from a
10077 // typedef change which underlying type is an anonymous
10079 && !is_anonymous_class_or_union_diff(d)
10080 // Don't show decl-only-ness changes of classes either.
10081 && !filtering::has_class_decl_only_def_change(d))
10083 diff_context_sptr ctxt = d->context();
10084 const corpus_diff *corpus_diff_node = ctxt->get_corpus_diff().get();
10085 ABG_ASSERT(corpus_diff_node);
10086 type_or_decl_base_sptr iface =
10087 get_current_topmost_iface_diff()->first_subject();
10088 // So this is diff node carries a leaf change. Let's add it
10089 // to the set of of leaf diffs of corpus_diff_node.
10090 const_cast<corpus_diff*>(corpus_diff_node)->
10091 get_leaf_diffs().insert_diff_node(d, iface);
10094 }; // end struct leaf_diff_node_marker_visitor
10096 /// Walks the diff nodes associated to the current corpus diff and
10097 /// mark those that carry local changes. They are said to be leaf
10100 /// The marked nodes are available from the
10101 /// corpus_diff::get_leaf_diffs() function.
10103 corpus_diff::mark_leaf_diff_nodes()
10105 if (!has_changes())
10108 if (!context()->show_leaf_changes_only())
10111 leaf_diff_node_marker_visitor v;
10112 context()->forget_visited_diffs();
10113 bool s = context()->visiting_a_node_twice_is_forbidden();
10114 context()->forbid_visiting_a_node_twice(true);
10115 context()->forbid_visiting_a_node_twice_per_interface(true);
10117 context()->forbid_visiting_a_node_twice(s);
10118 context()->forbid_visiting_a_node_twice_per_interface(false);
10121 /// Get the set of maps that contain leaf nodes. A leaf node being a
10122 /// node with a local change.
10124 /// @return the set of maps that contain leaf nodes. A leaf node
10125 /// being a node with a local change.
10127 corpus_diff::get_leaf_diffs()
10128 {return priv_->leaf_diffs_;}
10130 /// Get the set of maps that contain leaf nodes. A leaf node being a
10131 /// node with a local change.
10133 /// @return the set of maps that contain leaf nodes. A leaf node
10134 /// being a node with a local change.
10136 corpus_diff::get_leaf_diffs() const
10137 {return priv_->leaf_diffs_;}
10139 /// Report the diff in a serialized form.
10141 /// @param out the stream to serialize the diff to.
10143 /// @param indent the prefix to use for the indentation of this
10146 corpus_diff::report(ostream& out, const string& indent) const
10148 context()->get_reporter()->report(*this, out, indent);
10151 /// Traverse the diff sub-tree under the current instance corpus_diff.
10153 /// @param v the visitor to invoke on each diff node of the sub-tree.
10155 /// @return true if the traversing has to keep going on, false otherwise.
10157 corpus_diff::traverse(diff_node_visitor& v)
10159 finish_diff_type();
10161 v.visit_begin(this);
10163 if (!v.visit(this, true))
10169 for (function_decl_diff_sptrs_type::const_iterator i =
10170 changed_functions_sorted().begin();
10171 i != changed_functions_sorted().end();
10174 if (diff_sptr d = *i)
10176 const diff_context_sptr &ctxt = context();
10177 if (ctxt->visiting_a_node_twice_is_forbidden_per_interface())
10178 ctxt->forget_visited_diffs();
10180 v.set_current_topmost_iface_diff(d.get());
10182 if (!d->traverse(v))
10185 v.set_current_topmost_iface_diff(0);
10191 for (var_diff_sptrs_type::const_iterator i =
10192 changed_variables_sorted().begin();
10193 i != changed_variables_sorted().end();
10196 if (diff_sptr d = *i)
10198 const diff_context_sptr &ctxt = context();
10199 if (ctxt->visiting_a_node_twice_is_forbidden_per_interface())
10200 ctxt->forget_visited_diffs();
10202 v.set_current_topmost_iface_diff(d.get());
10204 if (!d->traverse(v))
10207 v.set_current_topmost_iface_diff(0);
10213 v.set_current_topmost_iface_diff(0);
10219 /// Compute the diff between two instances of @ref corpus.
10221 /// Note that the two corpora must have been created in the same @ref
10222 /// environment, otherwise, this function aborts.
10224 /// @param f the first @ref corpus to consider for the diff.
10226 /// @param s the second @ref corpus to consider for the diff.
10228 /// @param ctxt the diff context to use.
10230 /// @return the resulting diff between the two @ref corpus.
10232 compute_diff(const corpus_sptr f,
10233 const corpus_sptr s,
10234 diff_context_sptr ctxt)
10236 typedef corpus::functions::const_iterator fns_it_type;
10237 typedef corpus::variables::const_iterator vars_it_type;
10238 typedef elf_symbols::const_iterator symbols_it_type;
10239 typedef diff_utils::deep_ptr_eq_functor eq_type;
10241 ABG_ASSERT(f && s);
10243 // We can only compare two corpora that were built out of the same
10245 ABG_ASSERT(f->get_environment() == s->get_environment());
10248 ctxt.reset(new diff_context);
10250 corpus_diff_sptr r(new corpus_diff(f, s, ctxt));
10252 ctxt->set_corpus_diff(r);
10254 r->priv_->sonames_equal_ = f->get_soname() == s->get_soname();
10256 r->priv_->architectures_equal_ =
10257 f->get_architecture_name() == s->get_architecture_name();
10259 diff_utils::compute_diff<fns_it_type, eq_type>(f->get_functions().begin(),
10260 f->get_functions().end(),
10261 s->get_functions().begin(),
10262 s->get_functions().end(),
10263 r->priv_->fns_edit_script_);
10265 diff_utils::compute_diff<vars_it_type, eq_type>
10266 (f->get_variables().begin(), f->get_variables().end(),
10267 s->get_variables().begin(), s->get_variables().end(),
10268 r->priv_->vars_edit_script_);
10270 diff_utils::compute_diff<symbols_it_type, eq_type>
10271 (f->get_unreferenced_function_symbols().begin(),
10272 f->get_unreferenced_function_symbols().end(),
10273 s->get_unreferenced_function_symbols().begin(),
10274 s->get_unreferenced_function_symbols().end(),
10275 r->priv_->unrefed_fn_syms_edit_script_);
10277 diff_utils::compute_diff<symbols_it_type, eq_type>
10278 (f->get_unreferenced_variable_symbols().begin(),
10279 f->get_unreferenced_variable_symbols().end(),
10280 s->get_unreferenced_variable_symbols().begin(),
10281 s->get_unreferenced_variable_symbols().end(),
10282 r->priv_->unrefed_var_syms_edit_script_);
10284 r->priv_->ensure_lookup_tables_populated();
10291 /// Compute the diff between two instances of @ref corpus_group.
10293 /// Note that the two corpus_diff must have been created in the same
10294 /// @ref environment, otherwise, this function aborts.
10296 /// @param f the first @ref corpus_group to consider for the diff.
10298 /// @param s the second @ref corpus_group to consider for the diff.
10300 /// @param ctxt the diff context to use.
10302 /// @return the resulting diff between the two @ref corpus_group.
10304 compute_diff(const corpus_group_sptr& f,
10305 const corpus_group_sptr& s,
10306 diff_context_sptr ctxt)
10309 corpus_sptr c1 = f;
10310 corpus_sptr c2 = s;
10312 return compute_diff(c1, c2, ctxt);
10315 // <corpus_group stuff>
10317 // </corpus_group stuff>
10318 // <diff_node_visitor stuff>
10320 /// The private data of the @diff_node_visitor type.
10321 struct diff_node_visitor::priv
10323 diff* topmost_interface_diff;
10324 visiting_kind kind;
10327 : topmost_interface_diff(),
10331 priv(visiting_kind k)
10332 : topmost_interface_diff(),
10335 }; // end struct diff_node_visitor
10337 /// Default constructor of the @ref diff_node_visitor type.
10338 diff_node_visitor::diff_node_visitor()
10342 /// Constructor of the @ref diff_node_visitor type.
10344 /// @param k how the visiting has to be performed.
10345 diff_node_visitor::diff_node_visitor(visiting_kind k)
10346 : priv_(new priv(k))
10349 /// Getter for the visiting policy of the traversing code while
10350 /// invoking this visitor.
10352 /// @return the visiting policy used by the traversing code when
10353 /// invoking this visitor.
10355 diff_node_visitor::get_visiting_kind() const
10356 {return priv_->kind;}
10358 /// Setter for the visiting policy of the traversing code while
10359 /// invoking this visitor.
10361 /// @param v a bit map representing the new visiting policy used by
10362 /// the traversing code when invoking this visitor.
10364 diff_node_visitor::set_visiting_kind(visiting_kind v)
10367 /// Setter for the visiting policy of the traversing code while
10368 /// invoking this visitor. This one makes a logical or between the
10369 /// current policy and the bitmap given in argument and assigns the
10370 /// current policy to the result.
10372 /// @param v a bitmap representing the visiting policy to or with
10373 /// the current policy.
10375 diff_node_visitor::or_visiting_kind(visiting_kind v)
10376 {priv_->kind = priv_->kind | v;}
10378 /// Setter of the diff current topmost interface which is impacted by
10379 /// the current diff node being visited.
10381 /// @param d the current topmost interface diff impacted.
10383 diff_node_visitor::set_current_topmost_iface_diff(diff* d)
10384 {priv_->topmost_interface_diff = d;}
10386 /// Getter of the diff current topmost interface which is impacted by
10387 /// the current diff node being visited.
10389 /// @return the current topmost interface diff impacted.
10391 diff_node_visitor::get_current_topmost_iface_diff() const
10392 {return priv_->topmost_interface_diff;}
10394 /// This is called by the traversing code on a @ref diff node just
10395 /// before visiting it. That is, before visiting it and its children
10398 /// @param d the diff node to visit.
10400 diff_node_visitor::visit_begin(diff* /*p*/)
10403 /// This is called by the traversing code on a @ref diff node just
10404 /// after visiting it. That is after visiting it and its children
10407 /// @param d the diff node that got visited.
10409 diff_node_visitor::visit_end(diff* /*p*/)
10412 /// This is called by the traversing code on a @ref corpus_diff node
10413 /// just before visiting it. That is, before visiting it and its
10416 /// @param p the corpus_diff node to visit.
10419 diff_node_visitor::visit_begin(corpus_diff* /*p*/)
10422 /// This is called by the traversing code on a @ref corpus_diff node
10423 /// just after visiting it. That is after visiting it and its children
10426 /// @param d the diff node that got visited.
10428 diff_node_visitor::visit_end(corpus_diff* /*d*/)
10431 /// Default visitor implementation
10435 diff_node_visitor::visit(diff*, bool)
10438 /// Default visitor implementation.
10442 diff_node_visitor::visit(distinct_diff* dif, bool pre)
10450 /// Default visitor implementation.
10454 diff_node_visitor::visit(var_diff* dif, bool pre)
10462 /// Default visitor implementation.
10466 diff_node_visitor::visit(pointer_diff* dif, bool pre)
10474 /// Default visitor implementation.
10478 diff_node_visitor::visit(reference_diff* dif, bool pre)
10486 /// Default visitor implementation.
10490 diff_node_visitor::visit(qualified_type_diff* dif, bool pre)
10498 /// Default visitor implementation.
10502 diff_node_visitor::visit(enum_diff* dif, bool pre)
10510 /// Default visitor implementation.
10514 diff_node_visitor::visit(class_diff* dif, bool pre)
10522 /// Default visitor implementation.
10526 diff_node_visitor::visit(base_diff* dif, bool pre)
10534 /// Default visitor implementation.
10538 diff_node_visitor::visit(scope_diff* dif, bool pre)
10546 /// Default visitor implementation.
10550 diff_node_visitor::visit(function_decl_diff* dif, bool pre)
10558 /// Default visitor implementation.
10562 diff_node_visitor::visit(type_decl_diff* dif, bool pre)
10570 /// Default visitor implementation.
10574 diff_node_visitor::visit(typedef_diff* dif, bool pre)
10582 /// Default visitor implementation.
10586 diff_node_visitor::visit(translation_unit_diff* dif, bool pre)
10594 /// Default visitor implementation.
10598 diff_node_visitor::visit(corpus_diff*, bool)
10601 // </diff_node_visitor stuff>
10603 // <redundant diff node marking>
10605 // </redundant diff node marking>
10607 // <diff tree category propagation>
10609 /// A visitor to propagate the category of a node up to its parent
10610 /// nodes. This visitor doesn't touch the REDUNDANT_CATEGORY or the
10611 /// SUPPRESSED_CATEGORY because those are propagated using other
10612 /// specific visitors.
10613 struct category_propagation_visitor : public diff_node_visitor
10618 // Has this diff node 'd' been already visited ?
10619 bool already_visited = d->context()->diff_has_been_visited(d);
10621 // The canonical diff node of the class of equivalence of the diff
10623 diff* canonical = d->get_canonical_diff();
10625 // If this class of equivalence of diff node is being visited for
10626 // the first time, then update its canonical node's category too.
10627 bool update_canonical = !already_visited && canonical;
10629 for (vector<diff*>::const_iterator i = d->children_nodes().begin();
10630 i != d->children_nodes().end();
10633 // If we are visiting the class of equivalence of 'd' for the
10634 // first time, then let's look at the children of 'd' and
10635 // propagate their categories to 'd'.
10637 // If the class of equivalence of 'd' has already been
10638 // visited, then let's look at the canonical diff nodes of the
10639 // children of 'd' and propagate their categories to 'd'.
10640 diff* diff = already_visited
10641 ? (*i)->get_canonical_diff()
10646 diff_category c = diff->get_category();
10647 // Do not propagate redundant and suppressed categories. Those
10648 // are propagated in a specific pass elsewhere.
10649 c &= ~(REDUNDANT_CATEGORY
10650 | SUPPRESSED_CATEGORY
10651 | PRIVATE_TYPE_CATEGORY);
10652 // Also, if a (class) type has got a harmful name change, do not
10653 // propagate harmless name changes coming from its sub-types
10654 // (i.e, data members) to the class itself.
10655 if (filtering::has_harmful_name_change(d))
10656 c &= ~HARMLESS_DECL_NAME_CHANGE_CATEGORY;
10658 d->add_to_category(c);
10659 if (!already_visited && canonical)
10660 if (update_canonical)
10661 canonical->add_to_category(c);
10664 };// end struct category_propagation_visitor
10666 /// Visit all the nodes of a given sub-tree. For each node that has a
10667 /// particular category set, propagate that category set up to its
10670 /// @param diff_tree the diff sub-tree to walk for categorization
10673 propagate_categories(diff* diff_tree)
10675 category_propagation_visitor v;
10676 bool s = diff_tree->context()->visiting_a_node_twice_is_forbidden();
10677 diff_tree->context()->forbid_visiting_a_node_twice(true);
10678 diff_tree->context()->forget_visited_diffs();
10679 diff_tree->traverse(v);
10680 diff_tree->context()->forbid_visiting_a_node_twice(s);
10683 /// Visit all the nodes of a given sub-tree. For each node that has a
10684 /// particular category set, propagate that category set up to its
10687 /// @param diff_tree the diff sub-tree to walk for categorization
10690 propagate_categories(diff_sptr diff_tree)
10691 {propagate_categories(diff_tree.get());}
10693 /// Visit all the nodes of a given corpus tree. For each node that
10694 /// has a particular category set, propagate that category set up to
10695 /// its parent nodes.
10697 /// @param diff_tree the corpus_diff tree to walk for categorization
10700 propagate_categories(corpus_diff* diff_tree)
10702 category_propagation_visitor v;
10703 bool s = diff_tree->context()->visiting_a_node_twice_is_forbidden();
10704 diff_tree->context()->forbid_visiting_a_node_twice(false);
10705 diff_tree->traverse(v);
10706 diff_tree->context()->forbid_visiting_a_node_twice(s);
10709 /// Visit all the nodes of a given corpus tree. For each node that
10710 /// has a particular category set, propagate that category set up to
10711 /// its parent nodes.
10713 /// @param diff_tree the corpus_diff tree to walk for categorization
10716 propagate_categories(corpus_diff_sptr diff_tree)
10717 {propagate_categories(diff_tree.get());}
10719 /// A tree node visitor that knows how to categorizes a given in the
10720 /// SUPPRESSED_CATEGORY category and how to propagate that
10721 /// categorization.
10722 struct suppression_categorization_visitor : public diff_node_visitor
10725 /// Before visiting the children of the diff node, check if the node
10726 /// is suppressed by a suppression specification. If it is, mark
10727 /// the node as belonging to the SUPPRESSED_CATEGORY category.
10729 /// @param p the diff node to visit.
10731 visit_begin(diff* d)
10733 bool is_private_type = false;
10734 if (d->is_suppressed(is_private_type))
10736 diff_category c = is_private_type
10737 ? PRIVATE_TYPE_CATEGORY
10738 : SUPPRESSED_CATEGORY;
10739 d->add_to_local_and_inherited_categories(c);
10741 // If a node was suppressed, all the other nodes of its class
10742 // of equivalence are suppressed too.
10743 diff *canonical_diff = d->get_canonical_diff();
10744 if (canonical_diff != d)
10745 canonical_diff->add_to_category(c);
10749 /// After visiting the children nodes of a given diff node,
10750 /// propagate the SUPPRESSED_CATEGORY from the children nodes to the
10751 /// diff node, if need be.
10753 /// That is, if all children nodes carry a suppressed change the
10754 /// current node should be marked as suppressed as well.
10756 /// In practice, this might be too strong of a condition. If the
10757 /// current node carries a local change (i.e, a change not carried
10758 /// by any of its children node) and if that change is not
10759 /// suppressed, then the current node should *NOT* be suppressed.
10761 /// But right now, the IR doesn't let us know about local vs
10762 /// children-carried changes. So we cannot be that precise yet.
10766 bool has_non_suppressed_child = false;
10767 bool has_non_empty_child = false;
10768 bool has_suppressed_child = false;
10769 bool has_non_private_child = false;
10770 bool has_private_child = false;
10772 if (// A node to which we can propagate the "SUPPRESSED_CATEGORY"
10773 // (or the PRIVATE_TYPE_CATEGORY for the same matter)
10774 // category from its children is a node which:
10776 // 1/ hasn't been suppressed already
10778 // 2/ and has no local change (unless it's a pointer,
10779 // reference or qualified diff node).
10781 // Note that qualified type diff nodes are a bit special.
10782 // The local changes of the underlying type are considered
10783 // local for the qualified type, just like for
10784 // pointer/reference types. But then the qualified type
10785 // itself can have local changes of its own, and those
10786 // changes are of the kind LOCAL_NON_TYPE_CHANGE_KIND. So a
10787 // qualified type which have local changes that are *NOT* of
10788 // LOCAL_NON_TYPE_CHANGE_KIND (or that has no local changes
10789 // at all) and which is in the PRIVATE_TYPE_CATEGORY or
10790 // SUPPRESSED_CATEGORY can see these categories be
10793 // Note that all pointer/reference diff node changes are
10794 // potentially considered local, i.e, local changes of the
10795 // pointed-to-type are considered local to the pointer itself.
10796 !(d->get_category() & SUPPRESSED_CATEGORY)
10797 && (!d->has_local_changes()
10798 || is_pointer_diff(d)
10799 || is_reference_diff(d)
10800 || (is_qualified_type_diff(d)
10801 && (!(d->has_local_changes() & LOCAL_NON_TYPE_CHANGE_KIND)))))
10803 // Note that we handle private diff nodes differently from
10804 // generally suppressed diff nodes. E.g, it's not because a
10805 // type is private (and suppressed because of that; i.e, in
10806 // the category PRIVATE_TYPE_CATEGORY) that a typedef to that
10807 // type should also be private and so suppressed. Private
10808 // diff nodes thus have different propagation rules than
10809 // generally suppressed rules.
10810 for (vector<diff*>::const_iterator i = d->children_nodes().begin();
10811 i != d->children_nodes().end();
10815 if (child->has_changes())
10817 has_non_empty_child = true;
10818 if (child->get_class_of_equiv_category() & SUPPRESSED_CATEGORY)
10819 has_suppressed_child = true;
10820 else if (child->get_class_of_equiv_category()
10821 & PRIVATE_TYPE_CATEGORY)
10822 // Propagation of the PRIVATE_TYPE_CATEGORY is going
10823 // to be handled later below.
10826 has_non_suppressed_child = true;
10828 if (child->get_class_of_equiv_category()
10829 & PRIVATE_TYPE_CATEGORY)
10830 has_private_child = true;
10831 else if (child->get_class_of_equiv_category()
10832 & SUPPRESSED_CATEGORY)
10833 // Propagation of the SUPPRESSED_CATEGORY is going
10834 // to be handled later below.
10837 has_non_private_child = true;
10841 if (has_non_empty_child
10842 && has_suppressed_child
10843 && !has_non_suppressed_child)
10845 d->add_to_category(SUPPRESSED_CATEGORY);
10846 // If a node was suppressed, all the other nodes of its class
10847 // of equivalence are suppressed too.
10848 diff *canonical_diff = d->get_canonical_diff();
10849 if (canonical_diff != d)
10850 canonical_diff->add_to_category(SUPPRESSED_CATEGORY);
10853 if (// We don't propagate "private type"-ness to typedefs
10854 // because defining "public" typedefs of private (opaque)
10855 // types is a common idiom. So the typedef must stay
10857 !is_typedef_diff(d)
10858 && has_non_empty_child
10859 && has_private_child
10860 && !has_non_private_child)
10862 d->add_to_category(PRIVATE_TYPE_CATEGORY);
10863 // If a node was suppressed, all the other nodes of its class
10864 // of equivalence are suppressed too.
10865 diff *canonical_diff = d->get_canonical_diff();
10866 if (canonical_diff != d)
10867 canonical_diff->add_to_category(PRIVATE_TYPE_CATEGORY);
10870 // If the underlying type of a typedef is private and carries
10871 // changes (that are implicitely suppressed because it's
10872 // private) then the typedef must be suppressed too, so that
10873 // those changes to the underlying type are not seen.
10874 if (is_typedef_diff(d)
10875 && !d->has_local_changes()
10876 && has_private_child
10877 && has_non_empty_child)
10879 d->add_to_category(SUPPRESSED_CATEGORY|PRIVATE_TYPE_CATEGORY);
10880 // If a node was suppressed, all the other nodes of its class
10881 // of equivalence are suppressed too.
10882 diff *canonical_diff = d->get_canonical_diff();
10883 if (canonical_diff != d)
10884 canonical_diff->add_to_category
10885 (SUPPRESSED_CATEGORY|PRIVATE_TYPE_CATEGORY);
10889 }; //end struct suppression_categorization_visitor
10891 /// Walk a given diff-sub tree and appply the suppressions carried by
10892 /// the context. If the suppression applies to a given node than
10893 /// categorize the node into the SUPPRESSED_CATEGORY category and
10894 /// propagate that categorization.
10896 /// @param diff_tree the diff-sub tree to apply the suppressions to.
10898 apply_suppressions(diff* diff_tree)
10900 if (diff_tree && !diff_tree->context()->suppressions().empty())
10902 // Apply suppressions to functions and variables that have
10903 // changed sub-types.
10904 suppression_categorization_visitor v;
10905 diff_tree->context()->forget_visited_diffs();
10906 bool s = diff_tree->context()->visiting_a_node_twice_is_forbidden();
10907 diff_tree->context()->forbid_visiting_a_node_twice(true);
10908 diff_tree->traverse(v);
10909 diff_tree->context()->forbid_visiting_a_node_twice(s);
10913 /// Walk a given diff-sub tree and appply the suppressions carried by
10914 /// the context. If the suppression applies to a given node than
10915 /// categorize the node into the SUPPRESSED_CATEGORY category and
10916 /// propagate that categorization.
10918 /// @param diff_tree the diff-sub tree to apply the suppressions to.
10920 apply_suppressions(diff_sptr diff_tree)
10921 {apply_suppressions(diff_tree.get());}
10923 /// Walk a diff tree and appply the suppressions carried by the
10924 /// context. If the suppression applies to a given node than
10925 /// categorize the node into the SUPPRESSED_CATEGORY category and
10926 /// propagate that categorization.
10928 /// @param diff_tree the diff tree to apply the suppressions to.
10930 apply_suppressions(const corpus_diff* diff_tree)
10932 if (diff_tree && !diff_tree->context()->suppressions().empty())
10934 // First, visit the children trees of changed constructs:
10935 // changed functions, variables, as well as sub-types of these,
10936 // and apply suppression specifications to these ...
10937 suppression_categorization_visitor v;
10938 diff_tree->context()->forget_visited_diffs();
10939 bool s = diff_tree->context()->visiting_a_node_twice_is_forbidden();
10940 diff_tree->context()->forbid_visiting_a_node_twice(true);
10941 const_cast<corpus_diff*>(diff_tree)->traverse(v);
10942 diff_tree->context()->forbid_visiting_a_node_twice(s);
10944 // ... then also visit the set added and removed functions,
10945 // variables, and symbols
10946 diff_tree->priv_->apply_suppressions_to_added_removed_fns_vars();
10950 /// Walk a diff tree and appply the suppressions carried by the
10951 /// context. If the suppression applies to a given node than
10952 /// categorize the node into the SUPPRESSED_CATEGORY category and
10953 /// propagate that categorization.
10955 /// @param diff_tree the diff tree to apply the suppressions to.
10957 apply_suppressions(corpus_diff_sptr diff_tree)
10958 {apply_suppressions(diff_tree.get());}
10960 // </diff tree category propagation>
10962 // <diff tree printing stuff>
10964 /// A visitor to print (to an output stream) a pretty representation
10965 /// of a @ref diff sub-tree or of a complete @ref corpus_diff tree.
10966 struct diff_node_printer : public diff_node_visitor
10971 /// Emit a certain number of spaces to the output stream associated
10972 /// to this diff_node_printer.
10974 /// @param level half of the numver of spaces to emit.
10976 do_indent(unsigned level)
10978 for (unsigned i = 0; i < level; ++i)
10982 diff_node_printer(ostream& out)
10983 : diff_node_visitor(DO_NOT_MARK_VISITED_NODES_AS_VISITED),
11001 visit_begin(corpus_diff*)
11007 visit_end(corpus_diff*)
11013 visit(diff* d, bool pre)
11016 // We are post-visiting the diff node D. Which means, we have
11017 // printed a pretty representation for it already. So do
11022 out_ << d->get_pretty_representation();
11026 do_indent(level_ + 1);
11027 out_ << "category: "<< d->get_category() << "\n";
11028 do_indent(level_ + 1);
11029 out_ << "@: " << std::hex << d << std::dec << "\n";
11030 do_indent(level_ + 1);
11031 out_ << "@-canonical: " << std::hex
11032 << d->get_canonical_diff()
11033 << std::dec << "\n";
11041 visit(corpus_diff* d, bool pre)
11044 // We are post-visiting the diff node D. Which means, we have
11045 // printed a pretty representation for it already. So do
11050 for (unsigned i = 0; i < level_; ++i)
11052 out_ << d->get_pretty_representation();
11056 }; // end struct diff_printer_visitor
11058 // </ diff tree printing stuff>
11060 /// Emit a textual representation of a @ref diff sub-tree to an
11063 /// @param diff_tree the sub-tree to emit the textual representation
11066 /// @param out the output stream to emit the textual representation
11067 /// for @p diff_tree to.
11069 print_diff_tree(diff* diff_tree, ostream& out)
11071 diff_node_printer p(out);
11072 bool s = diff_tree->context()->visiting_a_node_twice_is_forbidden();
11073 diff_tree->context()->forbid_visiting_a_node_twice(false);
11074 diff_tree->traverse(p);
11075 diff_tree->context()->forbid_visiting_a_node_twice(s);
11078 /// Emit a textual representation of a @ref corpus_diff tree to an
11081 /// @param diff_tree the @ref corpus_diff tree to emit the textual
11082 /// representation for.
11084 /// @param out the output stream to emit the textual representation
11085 /// for @p diff_tree to.
11087 print_diff_tree(corpus_diff* diff_tree, std::ostream& out)
11089 diff_node_printer p(out);
11090 bool s = diff_tree->context()->visiting_a_node_twice_is_forbidden();
11091 diff_tree->context()->forbid_visiting_a_node_twice(false);
11092 diff_tree->traverse(p);
11093 diff_tree->context()->forbid_visiting_a_node_twice(s);
11096 /// Emit a textual representation of a @ref diff sub-tree to an
11099 /// @param diff_tree the sub-tree to emit the textual representation
11102 /// @param out the output stream to emit the textual representation
11103 /// for @p diff_tree to.
11105 print_diff_tree(diff_sptr diff_tree,
11107 {print_diff_tree(diff_tree.get(), o);}
11109 /// Emit a textual representation of a @ref corpus_diff tree to an
11112 /// @param diff_tree the @ref corpus_diff tree to emit the textual
11113 /// representation for.
11115 /// @param out the output stream to emit the textual representation
11116 /// for @p diff_tree to.
11118 print_diff_tree(corpus_diff_sptr diff_tree,
11120 {print_diff_tree(diff_tree.get(), o);}
11122 // <redundancy_marking_visitor>
11124 /// A tree visitor to categorize nodes with respect to the
11125 /// REDUNDANT_CATEGORY. That is, detect if a node is redundant (is
11126 /// present on several spots of the tree) and mark such nodes
11127 /// appropriatly. This visitor also takes care of propagating the
11128 /// REDUNDANT_CATEGORY of a given node to its parent nodes as
11130 struct redundancy_marking_visitor : public diff_node_visitor
11132 bool skip_children_nodes_;
11134 redundancy_marking_visitor()
11135 : skip_children_nodes_()
11139 visit_begin(diff* d)
11141 if (d->to_be_reported())
11143 // A diff node that carries a change and that has been already
11144 // traversed elsewhere is considered redundant. So let's mark
11145 // it as such and let's not traverse it; that is, let's not
11146 // visit its children.
11147 if ((d->context()->diff_has_been_visited(d)
11148 || d->get_canonical_diff()->is_traversing())
11149 && d->has_changes())
11151 // But if two diff nodes are redundant sibbling that carry
11152 // changes of base types, do not mark them as being
11153 // redundant. This is to avoid marking nodes as redundant
11156 // int foo(int a, int b);
11158 // float foo(float a, float b); (in C).
11160 // In this case, we want to report all the occurences of
11161 // the int->float change because logically, they are at
11162 // the same level in the diff tree.
11164 bool redundant_with_sibling_node = false;
11165 const diff* p = d->parent_node();
11167 // If this is a child node of a fn_parm_diff, look through
11168 // the fn_parm_diff node to get the function diff node.
11169 if (p && dynamic_cast<const fn_parm_diff*>(p))
11170 p = p->parent_node();
11173 for (vector<diff*>::const_iterator s =
11174 p->children_nodes().begin();
11175 s != p->children_nodes().end();
11181 // If this is a fn_parm_diff, look through the
11182 // fn_parm_diff node to get at the real type node.
11183 if (fn_parm_diff* f = dynamic_cast<fn_parm_diff*>(*s))
11184 sib = f->type_diff().get();
11187 if (sib->get_canonical_diff() == d->get_canonical_diff()
11188 // Sibbling diff nodes that carry base type
11189 // changes ar to be marked as redundant.
11190 && (is_base_diff(sib) || is_distinct_diff(sib)))
11192 redundant_with_sibling_node = true;
11196 if (!redundant_with_sibling_node
11197 // Changes to basic types should never be considered
11198 // redundant. For instance, if a member of integer
11199 // type is changed into a char type in both a struct A
11200 // and a struct B, we want to see both changes.
11201 && !has_basic_type_change_only(d)
11202 // The same goes for distinct type changes
11203 && !filtering::is_mostly_distinct_diff(d)
11204 // Functions with similar *local* changes are never marked
11205 // redundant because otherwise one could miss important
11206 // similar local changes that are applied to different
11208 && !is_function_type_diff_with_local_changes(d)
11209 // Changes involving variadic parameters of functions
11210 // should never be marked redundant because we want to see
11212 && !is_diff_of_variadic_parameter(d)
11213 && !is_diff_of_variadic_parameter_type(d)
11214 // If the canonical diff itself has been filtered out,
11215 // then this one is not marked redundant, obviously.
11216 && !d->get_canonical_diff()->is_filtered_out()
11217 && !(diff_has_ancestor_filtered_out
11219 get_last_visited_diff_of_class_of_equivalence(d)))
11220 // If the *same* diff node (not one that is merely
11221 // equivalent to this one) has already been visited
11222 // the do not mark it as beind redundant. It's only
11223 // the other nodes that are equivalent to this one
11224 // that must be marked redundant.
11225 && d->context()->diff_has_been_visited(d) != d
11226 // If the diff node is a function parameter and is not
11227 // a reference/pointer (to a non basic or a non
11228 // distinct type diff) then do not mark it as
11231 // Children nodes of base class diff nodes are never
11232 // redundant either, we want to see them all.
11233 && (is_reference_or_ptr_diff_to_non_basic_nor_distinct_types(d)
11234 || (!is_child_node_of_function_parm_diff(d)
11235 && !is_child_node_of_base_diff(d))))
11237 d->add_to_category(REDUNDANT_CATEGORY);
11238 // As we said in preamble, as this node is marked as
11239 // being redundant, let's not visit its children.
11240 // This is not an optimization; it's needed for
11241 // correctness. In the case of a diff node involving
11242 // a class type that refers to himself, visiting the
11243 // children nodes might cause them to be wrongly
11244 // marked as redundant.
11245 set_visiting_kind(get_visiting_kind()
11246 | SKIP_CHILDREN_VISITING_KIND);
11247 skip_children_nodes_ = true;
11253 // If the node is not to be reported, do not look at it children.
11254 set_visiting_kind(get_visiting_kind() | SKIP_CHILDREN_VISITING_KIND);
11255 skip_children_nodes_ = true;
11258 d->context()->mark_last_diff_visited_per_class_of_equivalence(d);
11262 visit_begin(corpus_diff*)
11269 if (skip_children_nodes_)
11270 // When visiting this node, we decided to skip its children
11271 // node. Now that we are done visiting the node, lets stop
11272 // avoiding the children nodes visiting for the other tree
11275 set_visiting_kind(get_visiting_kind() & (~SKIP_CHILDREN_VISITING_KIND));
11276 skip_children_nodes_ = false;
11280 // Propagate the redundancy categorization of the children nodes
11281 // to this node. But if this node has local changes, then it
11282 // doesn't inherit redundancy from its children nodes.
11283 if (!(d->get_category() & REDUNDANT_CATEGORY)
11284 && (!d->has_local_changes_to_be_reported()
11285 // By default, pointer, reference and qualified types
11286 // consider that a local changes to their underlying
11287 // type is always a local change for themselves.
11289 // This is as if those types don't have local changes
11290 // in the same sense as other types. So we always
11291 // propagate redundancy to them, regardless of if they
11292 // have local changes or not.
11293 || is_pointer_diff(d)
11294 || is_qualified_type_diff(d)))
11296 bool has_non_redundant_child = false;
11297 bool has_non_empty_child = false;
11298 for (vector<diff*>::const_iterator i =
11299 d->children_nodes().begin();
11300 i != d->children_nodes().end();
11303 if ((*i)->has_changes())
11305 has_non_empty_child = true;
11306 if ((*i)->to_be_reported()
11307 && ((*i)->get_category() & REDUNDANT_CATEGORY) == 0)
11308 has_non_redundant_child = true;
11310 if (has_non_redundant_child)
11314 // A diff node for which at least a child node carries a
11315 // change, and for which all the children are redundant is
11316 // deemed redundant too, unless it has local changes.
11317 if (has_non_empty_child
11318 && !has_non_redundant_child)
11319 d->add_to_category(REDUNDANT_CATEGORY);
11325 visit_end(corpus_diff*)
11334 visit(corpus_diff*, bool)
11338 };// end struct redundancy_marking_visitor
11340 /// A visitor of @ref diff nodes that clears the REDUNDANT_CATEGORY
11341 /// category out of the nodes.
11342 struct redundancy_clearing_visitor : public diff_node_visitor
11345 visit(corpus_diff*, bool)
11349 visit(diff* d, bool)
11351 // clear the REDUNDANT_CATEGORY out of the current node.
11352 diff_category c = d->get_category();
11353 c &= ~REDUNDANT_CATEGORY;
11354 d->set_category(c);
11357 }; // end struct redundancy_clearing_visitor
11359 /// Walk a given @ref diff sub-tree to categorize each of the nodes
11360 /// with respect to the REDUNDANT_CATEGORY.
11362 /// @param diff_tree the @ref diff sub-tree to walk.
11364 categorize_redundancy(diff* diff_tree)
11366 if (diff_tree->context()->show_redundant_changes())
11368 redundancy_marking_visitor v;
11369 diff_tree->context()->clear_last_diffs_visited_per_class_of_equivalence();
11370 bool s = diff_tree->context()->visiting_a_node_twice_is_forbidden();
11371 diff_tree->context()->forbid_visiting_a_node_twice(false);
11372 diff_tree->traverse(v);
11373 diff_tree->context()->forbid_visiting_a_node_twice(s);
11374 diff_tree->context()->clear_last_diffs_visited_per_class_of_equivalence();
11377 /// Walk a given @ref diff sub-tree to categorize each of the nodes
11378 /// with respect to the REDUNDANT_CATEGORY.
11380 /// @param diff_tree the @ref diff sub-tree to walk.
11382 categorize_redundancy(diff_sptr diff_tree)
11383 {categorize_redundancy(diff_tree.get());}
11385 /// Walk a given @ref corpus_diff tree to categorize each of the nodes
11386 /// with respect to the REDUNDANT_CATEGORY.
11388 /// @param diff_tree the @ref corpus_diff tree to walk.
11390 categorize_redundancy(corpus_diff* diff_tree)
11392 redundancy_marking_visitor v;
11393 diff_tree->context()->forget_visited_diffs();
11394 bool s = diff_tree->context()->visiting_a_node_twice_is_forbidden();
11395 diff_tree->context()->forbid_visiting_a_node_twice(false);
11396 diff_tree->traverse(v);
11397 diff_tree->context()->forbid_visiting_a_node_twice(s);
11400 /// Walk a given @ref corpus_diff tree to categorize each of the nodes
11401 /// with respect to the REDUNDANT_CATEGORY.
11403 /// @param diff_tree the @ref corpus_diff tree to walk.
11405 categorize_redundancy(corpus_diff_sptr diff_tree)
11406 {categorize_redundancy(diff_tree.get());}
11408 // </redundancy_marking_visitor>
11410 /// Walk a given @ref diff sub-tree to clear the REDUNDANT_CATEGORY
11411 /// out of the category of the nodes.
11413 /// @param diff_tree the @ref diff sub-tree to walk.
11415 clear_redundancy_categorization(diff* diff_tree)
11417 redundancy_clearing_visitor v;
11418 bool s = diff_tree->context()->visiting_a_node_twice_is_forbidden();
11419 diff_tree->context()->forbid_visiting_a_node_twice(false);
11420 diff_tree->traverse(v);
11421 diff_tree->context()->forbid_visiting_a_node_twice(s);
11422 diff_tree->context()->forget_visited_diffs();
11425 /// Walk a given @ref diff sub-tree to clear the REDUNDANT_CATEGORY
11426 /// out of the category of the nodes.
11428 /// @param diff_tree the @ref diff sub-tree to walk.
11430 clear_redundancy_categorization(diff_sptr diff_tree)
11431 {clear_redundancy_categorization(diff_tree.get());}
11433 /// Walk a given @ref corpus_diff tree to clear the REDUNDANT_CATEGORY
11434 /// out of the category of the nodes.
11436 /// @param diff_tree the @ref corpus_diff tree to walk.
11438 clear_redundancy_categorization(corpus_diff* diff_tree)
11440 redundancy_clearing_visitor v;
11441 bool s = diff_tree->context()->visiting_a_node_twice_is_forbidden();
11442 diff_tree->context()->forbid_visiting_a_node_twice(false);
11443 diff_tree->traverse(v);
11444 diff_tree->context()->forbid_visiting_a_node_twice(s);
11445 diff_tree->context()->forget_visited_diffs();
11448 /// Walk a given @ref corpus_diff tree to clear the REDUNDANT_CATEGORY
11449 /// out of the category of the nodes.
11451 /// @param diff_tree the @ref corpus_diff tree to walk.
11453 clear_redundancy_categorization(corpus_diff_sptr diff_tree)
11454 {clear_redundancy_categorization(diff_tree.get());}
11456 /// Apply the @ref diff tree filters that have been associated to the
11457 /// context of the a given @ref corpus_diff tree. As a result, the
11458 /// nodes of the @diff tree are going to be categorized into one of
11459 /// several of the categories of @ref diff_category.
11461 /// @param diff_tree the @ref corpus_diff instance which @ref diff are
11462 /// to be categorized.
11464 apply_filters(corpus_diff_sptr diff_tree)
11466 diff_tree->context()->maybe_apply_filters(diff_tree);
11467 propagate_categories(diff_tree);
11470 /// Test if a diff node represents the difference between a variadic
11471 /// parameter type and something else.
11473 /// @param d the diff node to consider.
11475 /// @return true iff @p d is a diff node that represents the
11476 /// difference between a variadic parameter type and something else.
11478 is_diff_of_variadic_parameter_type(const diff* d)
11483 type_base_sptr t = is_type(d->first_subject());
11484 if (t && t->get_environment()->is_variadic_parameter_type(t))
11487 t = is_type(d->second_subject());
11488 if (t && t->get_environment()->is_variadic_parameter_type(t))
11494 /// Test if a diff node represents the difference between a variadic
11495 /// parameter type and something else.
11497 /// @param d the diff node to consider.
11499 /// @return true iff @p d is a diff node that represents the
11500 /// difference between a variadic parameter type and something else.
11502 is_diff_of_variadic_parameter_type(const diff_sptr& d)
11503 {return is_diff_of_variadic_parameter_type(d.get());}
11505 /// Test if a diff node represents the difference between a variadic
11506 /// parameter and something else.
11508 /// @param d the diff node to consider.
11510 /// @return true iff @p d is a diff node that represents the
11511 /// difference between a variadic parameter and something else.
11513 is_diff_of_variadic_parameter(const diff* d)
11515 fn_parm_diff* diff =
11516 dynamic_cast<fn_parm_diff*>(const_cast<abigail::comparison::diff*>(d));
11517 return (diff && is_diff_of_variadic_parameter_type(diff->type_diff()));
11520 /// Test if a diff node represents the difference between a variadic
11521 /// parameter and something else.
11523 /// @param d the diff node to consider.
11525 /// @return true iff @p d is a diff node that represents the
11526 /// difference between a variadic parameter and something else.
11528 is_diff_of_variadic_parameter(const diff_sptr& d)
11529 {return is_diff_of_variadic_parameter(d.get());}
11531 /// Test if a diff node represents a diff between two basic types.
11533 /// @param d the diff node to consider.
11535 /// @return true iff @p d is a diff between two basic types.
11536 const type_decl_diff*
11537 is_diff_of_basic_type(const diff *d)
11538 {return dynamic_cast<const type_decl_diff*>(d);}
11540 /// Test if a diff node represents a diff between two basic types, or
11541 /// between pointers, references or qualified type to basic types.
11543 /// @param diff the diff node to consider.
11545 /// @param allow_indirect_type if true, then this function looks into
11546 /// pointer, reference or qualified diff types to see if they "point
11547 /// to" basic types.
11549 /// @return true iff @p d is a diff between two basic types.
11550 const type_decl_diff*
11551 is_diff_of_basic_type(const diff* diff, bool allow_indirect_type)
11553 if (allow_indirect_type)
11554 diff = peel_pointer_or_qualified_type(diff);
11555 return is_diff_of_basic_type(diff);
11558 /// If a diff node is about changes between two typedef types, get the
11559 /// diff node about changes between the underlying types.
11561 /// Note that this function walks the tree of underlying diff nodes
11562 /// returns the first diff node about types that are not typedefs.
11564 /// @param dif the dif node to consider.
11566 /// @return the underlying diff node of @p dif, or just return @p dif
11567 /// if it's not a typedef diff node.
11569 peel_typedef_diff(const diff* dif)
11571 const typedef_diff *d = 0;
11572 while ((d = is_typedef_diff(dif)))
11573 dif = d->underlying_type_diff().get();
11577 /// If a diff node is about changes between two pointer types, get the
11578 /// diff node about changes between the underlying (pointed-to) types.
11580 /// Note that this function walks the tree of underlying diff nodes
11581 /// returns the first diff node about types that are not pointers.
11583 /// @param dif the dif node to consider.
11585 /// @return the underlying diff node of @p dif, or just return @p dif
11586 /// if it's not a pointer diff node.
11588 peel_pointer_diff(const diff* dif)
11590 const pointer_diff *d = 0;
11591 while ((d = is_pointer_diff(dif)))
11592 dif = d->underlying_type_diff().get();
11596 /// If a diff node is about changes between two reference types, get
11597 /// the diff node about changes between the underlying (pointed-to)
11600 /// Note that this function walks the tree of underlying diff nodes
11601 /// returns the first diff node about types that are not references.
11603 /// @param dif the dif node to consider.
11605 /// @return the underlying diff node of @p dif, or just return @p dif
11606 /// if it's not a reference diff node.
11608 peel_reference_diff(const diff* dif)
11610 const reference_diff *d = 0;
11611 while ((d = is_reference_diff(dif)))
11612 dif = d->underlying_type_diff().get();
11616 /// If a diff node is about changes between two qualified types, get
11617 /// the diff node about changes between the underlying (non-qualified)
11620 /// Note that this function walks the tree of underlying diff nodes
11621 /// returns the first diff node about types that are not qualified.
11623 /// @param dif the dif node to consider.
11625 /// @return the underlying diff node of @p dif, or just return @p dif
11626 /// if it's not a qualified diff node.
11628 peel_qualified_diff(const diff* dif)
11630 const qualified_type_diff *d = 0;
11631 while ((d = is_qualified_type_diff(dif)))
11632 dif = d->underlying_type_diff().get();
11636 /// If a diff node is about changes between two pointer, reference or
11637 /// qualified types, get the diff node about changes between the
11638 /// underlying types.
11640 /// Note that this function walks the tree of underlying diff nodes
11641 /// returns the first diff node about types that are not pointer,
11642 /// reference or qualified.
11644 /// @param dif the dif node to consider.
11646 /// @return the underlying diff node of @p dif, or just return @p dif
11647 /// if it's not a pointer, reference or qualified diff node.
11649 peel_pointer_or_qualified_type(const diff*dif)
11653 if (const pointer_diff *d = is_pointer_diff(dif))
11654 dif = peel_pointer_diff(d);
11655 else if (const reference_diff *d = is_reference_diff(dif))
11656 dif = peel_reference_diff(d);
11657 else if (const qualified_type_diff *d = is_qualified_type_diff(dif))
11658 dif = peel_qualified_diff(d);
11665 /// Test if a diff node represents a diff between two class or union
11668 /// @param d the diff node to consider.
11670 /// @return iff @p is a diff between two class or union types then
11671 /// return the instance of @ref class_or_union_diff that @p derives
11672 /// from. Otherwise, return nil.
11673 const class_or_union_diff*
11674 is_diff_of_class_or_union_type(const diff *d)
11675 {return dynamic_cast<const class_or_union_diff*>(d);}
11677 /// Test if a given diff node carries *only* a local type change.
11679 /// @param d the diff node to consider.
11681 /// @return true iff @p has a change and that change is a local type
11684 has_local_type_change_only(const diff *d)
11686 if (enum change_kind k = d->has_local_changes())
11687 if ((k & LOCAL_NON_TYPE_CHANGE_KIND) == 0
11688 && (k & LOCAL_TYPE_CHANGE_KIND) != 0)
11694 /// Test if a diff node is a decl diff that only carries a basic type
11695 /// change on its type diff sub-node.
11697 ///Note that that pointers/references/qualified types diffs to basic
11698 /// type diffs are considered as having basic type change only.
11700 /// @param d the diff node to consider.
11702 /// @return true iff @p d is a decl diff that only carries a basic
11703 /// type change on its type diff sub-node.
11705 has_basic_type_change_only(const diff *d)
11707 if (is_diff_of_basic_type(d, true) && d->has_changes())
11709 else if (const var_diff * v = dynamic_cast<const var_diff*>(d))
11710 return (has_local_type_change_only(v)
11711 && is_diff_of_basic_type(v->type_diff().get(), true));
11712 else if (const fn_parm_diff * p = dynamic_cast<const fn_parm_diff*>(d))
11713 return (has_local_type_change_only(p)
11714 && is_diff_of_basic_type(p->type_diff().get(), true));
11715 else if (const function_decl_diff* f =
11716 dynamic_cast<const function_decl_diff*>(d))
11717 return (has_local_type_change_only(f)
11719 && is_diff_of_basic_type(f->type_diff()->return_type_diff().get(),
11723 }// end namespace comparison
11724 } // end namespace abigail