libabigail
abg-comparison.cc
Go to the documentation of this file.
1 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
2 // -*- Mode: C++ -*-
3 //
4 // Copyright (C) 2013-2023 Red Hat, Inc.
5 //
6 // Author: Dodji Seketeli
7 
8 /// @file
9 ///
10 /// This contains the implementation of the comparison engine of
11 /// libabigail.
12 
13 #include <ctype.h>
14 #include <libgen.h>
15 #include <algorithm>
16 #include <sstream>
17 #include <set>
18 
19 #include "abg-comparison-priv.h"
20 #include "abg-reporter-priv.h"
21 #include "abg-tools-utils.h"
22 
23 namespace abigail
24 {
25 
26 namespace comparison
27 {
28 
29 ///
30 ///
31 ///@defgroup DiffNode Internal Representation of the comparison engine
32 /// @{
33 ///
34 /// @brief How changes are represented in libabigail's comparison engine.
35 ///
36 ///@par diff nodes
37 ///
38 /// The internal representation of the comparison engine is basically
39 /// a graph of @ref instances of @ref diff node. We refer to these
40 /// just as <em>diff nodes</em>. A diff node represents a change
41 /// between two ABI artifacts represented by instances of types of the
42 /// abigail::ir namespace. These two artifacts that are being
43 /// compared are called the <em>subjects of the diff</em>.
44 ///
45 /// The types of that IR are in the abigail::comparison namespace.
46 ///
47 ///@par comparing diff nodes
48 ///
49 /// Comparing two instances of @ref diff nodes amounts to comparing
50 /// the subject of the diff. In other words, two @ref diff nodes are
51 /// equal if and only if their subjects are equal. Thus, two @ref
52 /// diff nodes can have different memory addresses and yet be equal.
53 ///
54 ///@par diff reporting and context
55 ///
56 /// A diff node can be serialized to an output stream to express, in
57 /// a human-readable textual form, the different changes that exist
58 /// between its two subjects. This is done by invoking the
59 /// diff::report() method. That reporting is controlled by several
60 /// parameters that are conceptually part of the context of the diff.
61 /// That context is materialized by an instance of the @ref
62 /// diff_context type.
63 ///
64 /// Please note that the role of the instance(s) of @ref diff_context
65 /// is boreader than just controlling the reporting of @ref diff
66 /// nodes. Basically, a @ref diff node itself is created following
67 /// behaviours that are controlled by a particular instance of
68 /// diff_context. A diff node is created in a particular diff
69 /// context, so to speak.
70 ///
71 /// @}
72 ///
73 
74 ///
75 ///@defgroup CanonicalDiff Canonical diff tree nodes
76 /// @{
77 ///
78 /// @brief How equivalent diff nodes are quickly spotted.
79 ///
80 /// @par Equivalence of diff nodes.
81 ///
82 /// Each @ref diff node has a property named <em>Canonical Diff
83 /// Node</em>. If \c D is a diff node, the canonical diff node of @c
84 /// D, noted @c C(D) is a particular diff node that is equal to @c D.
85 /// Thus, a fast way to compare two @ref diff node is to perform a
86 /// pointer comparison of their canonical diff nodes.
87 ///
88 /// A set of equivalent @ref diff nodes is a set of diff nodes that
89 /// all have the same canonical node. All the nodes of that set are
90 /// equal.
91 ///
92 /// A canonical node is registereded for a given diff node by invoking
93 /// the method diff_context::initialize_canonical_diff().
94 ///
95 /// Please note that the diff_context holds all the canonical diffs
96 /// that got registered through it. Thus, the life time of all of
97 /// canonical diff objects is the same as the life time of the @ref
98 /// diff_context they relate to.
99 ///
100 /// @}
101 ///
102 
103 // -----------------------------------------
104 // <private functions re-usable elsewhere>
105 // -----------------------------------------
106 /// Sort a map of enumerators by their value.
107 ///
108 /// @param enumerators_map the map to sort.
109 ///
110 /// @param sorted the resulting vector of sorted enumerators.
111 void
114 {
115  for (string_enumerator_map::const_iterator i = enumerators_map.begin();
116  i != enumerators_map.end();
117  ++i)
118  sorted.push_back(i->second);
120  std::sort(sorted.begin(), sorted.end(), comp);
121 }
122 
123 /// Sort a map of changed enumerators.
124 ///
125 /// @param enumerators_map the map to sort.
126 ///
127 ///@param output parameter. The resulting sorted enumerators.
128 void
130  changed_enumerators_type& sorted)
131 {
132  for (string_changed_enumerator_map::const_iterator i =
133  enumerators_map.begin();
134  i != enumerators_map.end();
135  ++i)
136  sorted.push_back(i->second);
137 
139  std::sort(sorted.begin(), sorted.end(), comp);
140 }
141 
142 /// Sort a map of data members by the offset of their initial value.
143 ///
144 /// @param data_members the map of changed data members to sort.
145 ///
146 /// @param sorted the resulting vector of sorted changed data members.
147 void
149  vector<decl_base_sptr>& sorted)
150 {
151  sorted.reserve(data_members.size());
152  for (string_decl_base_sptr_map::const_iterator i = data_members.begin();
153  i != data_members.end();
154  ++i)
155  sorted.push_back(i->second);
156 
157  data_member_comp comp;
158  std::sort(sorted.begin(), sorted.end(), comp);
159 }
160 
161 /// Sort (in place) a vector of changed data members.
162 ///
163 /// @param to_sort the vector to sort.
164 void
166 {
167  data_member_comp comp;
168  std::sort(to_sort.begin(), to_sort.end(), comp);
169 }
170 
171 /// Sort an instance of @ref string_function_ptr_map map and stuff a
172 /// resulting sorted vector of pointers to function_decl.
173 ///
174 /// @param map the map to sort.
175 ///
176 /// @param sorted the resulting sorted vector.
177 void
179  vector<function_decl*>& sorted)
180 {
181  sorted.reserve(map.size());
182  for (string_function_ptr_map::const_iterator i = map.begin();
183  i != map.end();
184  ++i)
185  sorted.push_back(i->second);
186 
187  function_comp comp;
188  std::sort(sorted.begin(), sorted.end(), comp);
189 }
190 
191 /// Sort a map that's an instance of @ref
192 /// string_member_function_sptr_map and fill a vector of member
193 /// functions with the sorted result.
194 ///
195 /// @param map the map to sort.
196 ///
197 /// @param sorted the resulting sorted vector.
198 void
201 {
202  sorted.reserve(map.size());
203  for (string_member_function_sptr_map::const_iterator i = map.begin();
204  i != map.end();
205  ++i)
206  sorted.push_back(i->second);
207 
208  function_comp comp;
209  std::sort(sorted.begin(), sorted.end(), comp);
210 }
211 
212 /// Sort the values of a @ref string_function_decl_diff_sptr_map map
213 /// and store the result in a vector of @ref function_decl_diff_sptr
214 /// objects.
215 ///
216 /// @param map the map whose values to store.
217 ///
218 /// @param sorted the vector of function_decl_diff_sptr to store the
219 /// result of the sort into.
220 void
224 {
225  sorted.reserve(map.size());
226  for (string_function_decl_diff_sptr_map::const_iterator i = map.begin();
227  i != map.end();
228  ++i)
229  sorted.push_back(i->second);
231  std::sort(sorted.begin(), sorted.end(), comp);
232 }
233 
234 /// Sort of an instance of @ref string_var_diff_sptr_map map.
235 ///
236 /// @param map the input map to sort.
237 ///
238 /// @param sorted the ouptut sorted vector of @ref var_diff_sptr.
239 /// It's populated with the sorted content.
240 void
242  var_diff_sptrs_type& sorted)
243 {
244  sorted.reserve(map.size());
245  for (string_var_diff_sptr_map::const_iterator i = map.begin();
246  i != map.end();
247  ++i)
248  sorted.push_back(i->second);
249 
250  var_diff_sptr_comp comp;
251  std::sort(sorted.begin(), sorted.end(), comp);
252 }
253 
254 /// Sort a map of string -> pointer to @ref elf_symbol.
255 ///
256 /// The result is a vector of @ref elf_symbol_sptr sorted by the
257 /// name of the symbol.
258 ///
259 /// @param map the map to sort.
260 ///
261 /// @param sorted out parameter; the sorted vector of @ref
262 /// elf_symbol_sptr.
263 void
265  vector<elf_symbol_sptr>& sorted)
266 {
267  for (string_elf_symbol_map::const_iterator i = map.begin();
268  i!= map.end();
269  ++i)
270  sorted.push_back(i->second);
271 
272  elf_symbol_comp comp;
273  std::sort(sorted.begin(), sorted.end(), comp);
274 }
275 
276 /// Sort a map of string -> pointer to @ref var_decl.
277 ///
278 /// The result is a vector of var_decl* sorted by the qualified name
279 /// of the variables.
280 ///
281 /// @param map the map to sort.
282 ///
283 /// @param sorted out parameter; the sorted vector of @ref var_decl.
284 void
286  vector<var_decl*>& sorted)
287 {
288  for (string_var_ptr_map::const_iterator i = map.begin();
289  i != map.end();
290  ++i)
291  sorted.push_back(i->second);
292 
293  var_comp comp;
294  std::sort(sorted.begin(), sorted.end(), comp);
295 }
296 
297 /// Sort the values of a string_var_diff_sptr_map and store the result
298 /// in a vector of var_diff_sptr.
299 ///
300 /// @param map the map of changed data members to sort.
301 ///
302 /// @param sorted the resulting vector of var_diff_sptr.
303 void
305  var_diff_sptrs_type& sorted)
306 {
307  sorted.reserve(map.size());
308  for (string_var_diff_sptr_map::const_iterator i = map.begin();
309  i != map.end();
310  ++i)
311  sorted.push_back(i->second);
313  std::sort(sorted.begin(), sorted.end(), comp);
314 }
315 
316 /// Sort the values of a unsigned_var_diff_sptr_map map and store the
317 /// result into a vector of var_diff_sptr.
318 ///
319 /// @param map the map of changed data members to sort.
320 ///
321 /// @param sorted the resulting vector of sorted var_diff_sptr.
322 void
324  var_diff_sptrs_type& sorted)
325 {
326  sorted.reserve(map.size());
327  for (unsigned_var_diff_sptr_map::const_iterator i = map.begin();
328  i != map.end();
329  ++i)
330  sorted.push_back(i->second);
332  std::sort(sorted.begin(), sorted.end(), comp);
333 }
334 
335 /// Sort an map of string -> virtual member function into a vector of
336 /// virtual member functions. The virtual member functions are sorted
337 /// by increasing order of their virtual index.
338 ///
339 /// @param map the input map.
340 ///
341 /// @param sorted the resulting sorted vector of virtual function
342 /// member.
343 void
347 {
348  sorted.reserve(map.size());
349  for (string_function_decl_diff_sptr_map::const_iterator i = map.begin();
350  i != map.end();
351  ++i)
352  sorted.push_back(i->second);
353 
355  sort(sorted.begin(), sorted.end(), comp);
356 }
357 
358 /// Sort a map ofg string -> @ref diff_sptr into a vector of @ref
359 /// diff_sptr. The diff_sptr are sorted lexicographically wrt
360 /// qualified names of their first subjects.
361 ///
362 /// @param map the map to sort.
363 ///
364 /// @param sorted the resulting sorted vector.
365 void
367  diff_sptrs_type& sorted)
368 {
369  sorted.reserve(map.size());
370  for (string_diff_sptr_map::const_iterator i = map.begin();
371  i != map.end();
372  ++i)
373  sorted.push_back(i->second);
374 
375  diff_comp comp;
376  sort(sorted.begin(), sorted.end(), comp);
377 }
378 
379 /// Sort a map ofg string -> @ref diff* into a vector of @ref
380 /// diff_ptr. The diff_ptr are sorted lexicographically wrt
381 /// qualified names of their first subjects.
382 ///
383 /// @param map the map to sort.
384 ///
385 /// @param sorted the resulting sorted vector.
386 void
388  diff_ptrs_type& sorted)
389 {
390  sorted.reserve(map.size());
391  for (string_diff_ptr_map::const_iterator i = map.begin();
392  i != map.end();
393  ++i)
394  sorted.push_back(i->second);
395 
396  diff_comp comp;
397  sort(sorted.begin(), sorted.end(), comp);
398 }
399 
400 /// Sort a map of string -> base_diff_sptr into a sorted vector of
401 /// base_diff_sptr. The base_diff_sptr are sorted by increasing value
402 /// of their offset in their containing type.
403 ///
404 /// @param map the input map to sort.
405 ///
406 /// @param sorted the resulting sorted vector.
407 void
409  base_diff_sptrs_type& sorted)
410 {
411  for (string_base_diff_sptr_map::const_iterator i = map.begin();
412  i != map.end();
413  ++i)
414  sorted.push_back(i->second);
415  base_diff_comp comp;
416  sort(sorted.begin(), sorted.end(), comp);
417 }
418 
419 /// Lexicographically sort base specifications found
420 /// in instances of string_base_sptr_map.
421 void
423  class_decl::base_specs& sorted)
424 {
425  for (string_base_sptr_map::const_iterator i = m.begin();
426  i != m.end();
427  ++i)
428  sorted.push_back(i->second);
429 
430  base_spec_comp comp;
431  std::sort(sorted.begin(), sorted.end(), comp);
432 }
433 
434 /// Sort a map of @ref fn_parm_diff by the indexes of the function
435 /// parameters.
436 ///
437 /// @param map the map to sort.
438 ///
439 /// @param sorted the resulting sorted vector of changed function
440 /// parms.
441 void
443  vector<fn_parm_diff_sptr>& sorted)
444 {
445  sorted.reserve(map.size());
446  for (unsigned_fn_parm_diff_sptr_map::const_iterator i = map.begin();
447  i != map.end();
448  ++i)
449  sorted.push_back(i->second);
450 
451  fn_parm_diff_comp comp;
452  std::sort(sorted.begin(), sorted.end(), comp);
453 }
454 
455 /// Sort a map of changed function parameters by the indexes of the
456 /// function parameters.
457 ///
458 /// @param map the map to sort.
459 ///
460 /// @param sorted the resulting sorted vector of instances of @ref
461 /// fn_parm_diff_sptr
462 void
464  vector<fn_parm_diff_sptr>& sorted)
465 {
466  sorted.reserve(map.size());
467  for (string_fn_parm_diff_sptr_map::const_iterator i = map.begin();
468  i != map.end();
469  ++i)
470  sorted.push_back(i->second);
471 
472  fn_parm_diff_comp comp;
473  std::sort(sorted.begin(), sorted.end(), comp);
474 }
475 
476 /// Sort a map of string -> function parameters.
477 ///
478 /// @param map the map to sort.
479 ///
480 /// @param sorted the resulting sorted vector of
481 /// @ref vector<function_decl::parameter_sptr>
482 void
484  vector<function_decl::parameter_sptr>& sorted)
485 {
486  for (string_parm_map::const_iterator i = map.begin();
487  i != map.end();
488  ++i)
489  sorted.push_back(i->second);
490 
491  parm_comp comp;
492  std::sort(sorted.begin(), sorted.end(), comp);
493 }
494 
495 /// Sort the set of ABI artifacts contained in a @ref
496 /// artifact_sptr_set_type.
497 ///
498 /// @param set the set of ABI artifacts to sort.
499 ///
500 /// @param output parameter the vector containing the sorted ABI
501 /// artifacts.
502 void
504  vector<type_or_decl_base_sptr>& sorted)
505 {
506 
507  for (artifact_sptr_set_type::const_iterator it = set.begin();
508  it != set.end();
509  ++it)
510  sorted.push_back(*it);
511 
513  std::sort(sorted.begin(), sorted.end(), comp);
514 }
515 
516 /// Sort a map of string to type_base_sptr entities.
517 ///
518 /// The entries are sorted based on the lexicographic order of the
519 /// pretty representation of the type_sptr_sptr. The sorted result is
520 /// put in a vector of type_base_sptr.
521 ///
522 /// @param map the map to sort.
523 ///
524 /// @param sorted the resulting vector of type_base_sptr
525 /// lexicographically sorted using their pretty representation.
526 void
528  vector<type_base_sptr>& sorted)
529 {
530  for (string_type_base_sptr_map::const_iterator i = map.begin();
531  i != map.end();
532  ++i)
533  sorted.push_back(i->second);
534 
536  std::sort(sorted.begin(), sorted.end(), comp);
537 }
538 
539 /// Return the first underlying type that is not a qualified type.
540 /// @param t the qualified type to consider.
541 ///
542 /// @return the first underlying type that is not a qualified type, or
543 /// NULL if t is NULL.
544 type_base_sptr
545 get_leaf_type(qualified_type_def_sptr t)
546 {
547  if (!t)
548  return type_base_sptr();
549 
550  type_base_sptr ut = t->get_underlying_type();
551  qualified_type_def_sptr qut = dynamic_pointer_cast<qualified_type_def>(ut);
552 
553  if (!qut)
554  return ut;
555  return get_leaf_type(qut);
556 }
557 
558 /// Tests if a given diff node is to represent the changes between two
559 /// gobal decls.
560 ///
561 /// @param d the diff node to consider.
562 ///
563 /// @return true iff @p d represents the changes between two global
564 /// decls.
565 bool
567 {
568  ABG_ASSERT(d != 0);
569 
570  if (d == 0)
571  return false;
572 
574  ABG_ASSERT(first);
575 
577  ABG_ASSERT(second);
578 
579  if (decl_base_sptr decl = is_decl(first))
580  if (is_at_global_scope(decl))
581  if ((decl = is_decl(second)))
582  if (is_at_global_scope(decl))
583  return true;
584 
585  return false;
586 }
587 
588 // -----------------------------------------
589 // </private functions re-usable elsewhere>
590 // -----------------------------------------
591 
592 /// The overloaded or operator for @ref visiting_kind.
595 {return static_cast<visiting_kind>(static_cast<unsigned>(l)
596  | static_cast<unsigned>(r));}
597 
598 /// The overloaded and operator for @ref visiting_kind.
601 {
602  return static_cast<visiting_kind>(static_cast<unsigned>(l)
603  & static_cast<unsigned>(r));
604 }
605 
606 /// The overloaded 'bit inversion' operator for @ref visiting_kind.
609 {return static_cast<visiting_kind>(~static_cast<unsigned>(l));}
610 
611 /// Test if a diff node is about differences between types.
612 ///
613 /// @param diff the diff node to test.
614 ///
615 /// @return a pointer to the actual type_diff_base* that @p diff
616 /// extends, iff it is about differences between types.
617 const type_diff_base*
619 {return dynamic_cast<const type_diff_base*>(diff);}
620 
621 /// Test if a diff node is about differences between declarations.
622 ///
623 /// @param diff the diff node to test.
624 ///
625 /// @return a pointer to the actual decl_diff_base @p diff extends,
626 /// iff it is about differences between declarations.
627 const decl_diff_base*
629 {return dynamic_cast<const decl_diff_base*>(diff);}
630 
631 /// Test if a diff node is a @ref class_diff node.
632 ///
633 /// @param diff the diff node to consider.
634 ///
635 /// @return a non-nil pointer to a @ref class_diff iff @p diff is a
636 /// @ref class_diff node.
637 const class_diff*
639 {return dynamic_cast<const class_diff*>(diff);}
640 
641 /// Test if a diff node is a @ref enum_diff node.
642 ///
643 /// @param diff the diff node to consider.
644 ///
645 /// @return a non-nil pointer to ad @ref enum_diff node iff @p diff is
646 /// a @ref enum_diff node.
647 const enum_diff*
649 {return dynamic_cast<const enum_diff*>(diff);}
650 
651 /// Test if a diff node is a @ref union_diff node.
652 ///
653 /// @param diff the diff node to consider.
654 ///
655 /// @return a non-nil pointer to a @ref union_diff iff @p diff is a
656 /// @ref union_diff node.
657 const union_diff*
659 {return dynamic_cast<const union_diff*>(diff);}
660 
661 /// Test if a diff node is a @ref class_or_union_diff node.
662 ///
663 /// @param d the diff node to consider.
664 ///
665 /// @return a non-nil pointer to the @ref class_or_union_diff denoted
666 /// by @p d iff @p d is a @ref class_or_union_diff.
667 const class_or_union_diff*
669 {return dynamic_cast<const class_or_union_diff*>(d);}
670 
671 /// Test if a diff node is a @ref class_or_union_diff between two
672 /// anonymous classes or unions.
673 ///
674 /// @param d the diff node to consider.
675 ///
676 /// @return a non-nil pointer to the @ref class_or_union_diff iff @p
677 /// denoted by @p d iff @p is pointer to an anonymous class or union
678 /// diff.
679 const class_or_union_diff*
681 {
682  if (const class_or_union_diff *dif = is_class_or_union_diff(d))
683  if (dif->first_class_or_union()->get_is_anonymous())
684  return dif;
685  return 0;
686 }
687 
688 /// Test if a diff node is a @ref typedef_diff node.
689 ///
690 /// @param diff the diff node to consider.
691 ///
692 /// @return a non-nil pointer to a @ref typedef_diff iff @p diff is a
693 /// @ref typedef_diff node.
694 const typedef_diff*
696 {return dynamic_cast<const typedef_diff*>(diff);}
697 
698 /// Test if a diff node is a @ref subrange_diff node.
699 ///
700 /// @param diff the diff node to consider.
701 ///
702 /// @return a non-nil pointer to a @ref subrange_diff iff @p diff is a
703 /// @ref subrange_diff node.
704 const subrange_diff*
706 {return dynamic_cast<const subrange_diff*>(diff);}
707 
708 /// Test if a diff node is a @ref array_diff node.
709 ///
710 /// @param diff the diff node to consider.
711 ///
712 /// @return a non-nil pointer to a @ref array_diff iff @p diff is a
713 /// @ref array_diff node.
714 const array_diff*
716 {return dynamic_cast<const array_diff*>(diff);}
717 
718 /// Test if a diff node is a @ref function_type_diff node.
719 ///
720 /// @param diff the diff node to consider.
721 ///
722 /// @return a non-nil pointer to a @ref function_type_diff iff @p diff is a
723 /// @ref function_type_diff node.
724 const function_type_diff*
726 {return dynamic_cast<const function_type_diff*>(diff);}
727 
728 /// Test if a given diff node carries a function type change with
729 /// local changes.
730 ///
731 /// @param diff the diff node to consider.
732 ///
733 /// @return a non-nil pointer to a @ref function_type_diff iff @p diff
734 /// is a function_type_diff node that carries a local change.
735 const function_type_diff*
737 {
738  if (const function_type_diff* d = is_function_type_diff(diff))
739  if (d->has_local_changes())
740  return d;
741 
742  return 0;
743 }
744 
745 /// Test if a diff node is about differences between variables.
746 ///
747 /// @param diff the diff node to test.
748 ///
749 /// @return a pointer to the actual var_diff that @p diff is a type
750 /// of, iff it is about differences between variables.
751 const var_diff*
753 {
754  const var_diff* d = dynamic_cast<const var_diff*>(diff);
755  if (d)
756  ABG_ASSERT(is_decl_diff(diff));
757  return d;
758 }
759 
760 /// Test if a diff node is about differences between functions.
761 ///
762 /// @param diff the diff node to test.
763 ///
764 /// @return a pointer to the actual var_diff that @p diff is a type
765 /// of, iff it is about differences between variables.
766 const function_decl_diff*
768 {
769  const function_decl_diff *d = dynamic_cast<const function_decl_diff*>(diff);
770  if (d)
771  ABG_ASSERT(is_decl_diff(diff));
772  return d;
773 }
774 
775 /// Test if a diff node is about differences between two pointers.
776 ///
777 /// @param diff the diff node to consider.
778 ///
779 /// @return the @p diff converted into an instance of @ref
780 /// pointer_diff iff @p diff is about differences between two
781 /// pointers.
782 const pointer_diff*
784 {return dynamic_cast<const pointer_diff*>(diff);}
785 
786 /// Test if a diff node is about differences between two references.
787 ///
788 /// @param diff the diff node to consider.
789 ///
790 /// @return the @p diff converted into an instance of @ref
791 /// reference_diff iff @p diff is about differences between two
792 /// references.
793 const reference_diff*
795 {return dynamic_cast<const reference_diff*>(diff);}
796 
797 /// Test if a diff node is about differences between two qualified
798 /// types.
799 ///
800 /// @param diff the diff node to consider.
801 ///
802 /// @return @p diff converted into an instance of @ref
803 /// qualified_type_diff iff @p diff is about differences between two
804 /// qualified types.
805 const qualified_type_diff*
807 {return dynamic_cast<const qualified_type_diff*>(diff);}
808 
809 /// Test if a diff node is a reference or pointer diff node to a
810 /// change that is neither basic type change nor distinct type change.
811 ///
812 /// Note that this function also works on diffs of typedefs of
813 /// reference or pointer.
814 ///
815 /// @param diff the diff node to consider.
816 ///
817 /// @return true iff @p diff is a eference or pointer diff node to a
818 /// change that is neither basic type change nor distinct type change.
819 bool
821 {
822  diff = peel_typedef_diff(diff);
823  if (const reference_diff* d = is_reference_diff(diff))
824  {
825  diff = peel_reference_diff(d);
826  if (is_diff_of_basic_type(diff) || is_distinct_diff(diff))
827  return false;
828  return true;
829  }
830  else if (const pointer_diff *d = is_pointer_diff(diff))
831  {
832  diff = peel_pointer_diff(d);
833  if (is_diff_of_basic_type(diff) || is_distinct_diff(diff))
834  return false;
835  return true;
836  }
837 
838  return false;
839 }
840 
841 /// Test if a diff node is about differences between two function
842 /// parameters.
843 ///
844 /// @param diff the diff node to consider.
845 ///
846 /// @return the @p diff converted into an instance of @ref
847 /// reference_diff iff @p diff is about differences between two
848 /// function parameters.
849 const fn_parm_diff*
851 {return dynamic_cast<const fn_parm_diff*>(diff);}
852 
853 /// Test if a diff node is about differences between two base class
854 /// specifiers.
855 ///
856 /// @param diff the diff node to consider.
857 ///
858 /// @return the @p diff converted into an instance of @ref base_diff
859 /// iff @p diff is about differences between two base class
860 /// specifiers.
861 const base_diff*
863 {return dynamic_cast<const base_diff*>(diff);}
864 
865 /// Test if a diff node is about differences between two diff nodes of
866 /// different kinds.
867 ///
868 /// @param diff the diff node to consider.
869 ///
870 /// @return the @p diff converted into an instance of @ref
871 /// distintc_diff iff @p diff is about differences between two diff
872 /// nodes of different kinds.
873 const distinct_diff*
875 {return dynamic_cast<const distinct_diff*>(diff);}
876 
877 /// Test if a diff node is a @ref corpus_diff node.
878 ///
879 /// @param diff the diff node to consider.
880 ///
881 /// @return a non-nil pointer to a @ref corpus_diff iff @p diff is a
882 /// @ref corpus_diff node.
883 const corpus_diff*
885 {return dynamic_cast<const corpus_diff*>(diff);}
886 
887 /// Test if a diff node is a child node of a function parameter diff node.
888 ///
889 /// @param diff the diff node to test.
890 ///
891 /// @return true iff @p diff is a child node of a function parameter
892 /// diff node.
893 bool
895 {return diff && is_fn_parm_diff(diff->parent_node());}
896 
897 /// Test if a diff node is a child node of a base diff node.
898 ///
899 /// @param diff the diff node to test.
900 ///
901 /// @return true iff @p diff is a child node of a base diff node.
902 bool
904 {return diff && is_base_diff(diff->parent_node());}
905 
906 /// The default traverse function.
907 ///
908 /// @return true.
909 bool
911 {return true;}
912 
913 diff_context::diff_context()
914  : priv_(new diff_context::priv)
915 {
916  // Setup all the diff output filters we have.
918 
920  add_diff_filter(f);
921 
922  // f.reset(new filtering::harmless_filter);
923  // add_diff_filter(f);
924 
925  // f.reset(new filtering::harmful_filter);
926  // add_diff_filter(f);
927 }
928 
929 diff_context::~diff_context() = default;
930 
931 /// Test if logging was requested.
932 ///
933 /// @return true iff logging was requested.
934 bool
936 {return priv_->do_log_;}
937 
938 /// Set logging as requested.
939 ///
940 /// @param f the flag
941 void
943 {priv_->do_log_ = f;}
944 
945 /// Set the corpus diff relevant to this context.
946 ///
947 /// @param d the corpus_diff we are interested in.
948 void
950 {priv_->corpus_diff_ = d;}
951 
952 /// Get the corpus diff for the current context.
953 ///
954 /// @return the corpus diff of this context.
955 const corpus_diff_sptr&
957 {return priv_->corpus_diff_;}
958 
959 /// Getter for the first corpus of the corpus diff of the current context.
960 ///
961 /// @return the first corpus of the corpus diff of the current
962 /// context, if no corpus diff is associated to the context.
963 corpus_sptr
965 {
966  if (priv_->corpus_diff_)
967  return priv_->corpus_diff_->first_corpus();
968  return corpus_sptr();
969 }
970 
971 /// Getter for the second corpus of the corpus diff of the current
972 /// context.
973 ///
974 /// @return the second corpus of the corpus diff of the current
975 /// context, if no corpus diff is associated to the context.
976 corpus_sptr
978 {
979  if (priv_->corpus_diff_)
980  return priv_->corpus_diff_->second_corpus();
981  return corpus_sptr();
982 }
983 
984 /// Getter of the reporter to be used in this context.
985 ///
986 /// @return the reporter to be used in this context.
989 {
990  if (!priv_->reporter_)
991  {
993  priv_->reporter_.reset(new leaf_reporter);
994  else
995  priv_->reporter_.reset(new default_reporter);
996  }
997  ABG_ASSERT(priv_->reporter_);
998  return priv_->reporter_;
999 }
1000 
1001 /// Setter of the reporter to be used in this context.
1002 ///
1003 /// @param r the reporter to be used in this context.
1004 void
1006 {priv_->reporter_ = r;}
1007 
1008 /// Tests if the current diff context already has a diff for two decls.
1009 ///
1010 /// @param first the first decl to consider.
1011 ///
1012 /// @param second the second decl to consider.
1013 ///
1014 /// @return a pointer to the diff for @p first @p second if found,
1015 /// null otherwise.
1016 diff_sptr
1017 diff_context::has_diff_for(const type_or_decl_base_sptr first,
1018  const type_or_decl_base_sptr second) const
1019 {
1020  types_or_decls_diff_map_type::const_iterator i =
1021  priv_->types_or_decls_diff_map.find(std::make_pair(first, second));
1022  if (i != priv_->types_or_decls_diff_map.end())
1023  return i->second;
1024  return diff_sptr();
1025 }
1026 
1027 /// Tests if the current diff context already has a diff for two types.
1028 ///
1029 /// @param first the first type to consider.
1030 ///
1031 /// @param second the second type to consider.
1032 ///
1033 /// @return a pointer to the diff for @p first @p second if found,
1034 /// null otherwise.
1035 diff_sptr
1036 diff_context::has_diff_for_types(const type_base_sptr first,
1037  const type_base_sptr second) const
1038 {return has_diff_for(first, second);}
1039 
1040 /// Tests if the current diff context already has a given diff.
1041 ///
1042 ///@param d the diff to consider.
1043 ///
1044 /// @return a pointer to the diff found for @p d
1045 const diff*
1046 diff_context::has_diff_for(const diff* d) const
1047 {return has_diff_for(d->first_subject(), d->second_subject()).get();}
1048 
1049 /// Tests if the current diff context already has a given diff.
1050 ///
1051 ///@param d the diff to consider.
1052 ///
1053 /// @return a pointer to the diff found for @p d
1054 diff_sptr
1055 diff_context::has_diff_for(const diff_sptr d) const
1056 {return has_diff_for(d->first_subject(), d->second_subject());}
1057 
1058 /// Getter for the bitmap that represents the set of categories that
1059 /// the user wants to see reported.
1060 ///
1061 /// @return a bitmap that represents the set of categories that the
1062 /// user wants to see reported.
1065 {return priv_->allowed_category_;}
1066 
1067 /// Setter for the bitmap that represents the set of categories that
1068 /// the user wants to see reported.
1069 ///
1070 /// @param c a bitmap that represents the set of categories that the
1071 /// user wants to see represented.
1072 void
1074 {priv_->allowed_category_ = c;}
1075 
1076 /// Setter for the bitmap that represents the set of categories that
1077 /// the user wants to see reported
1078 ///
1079 /// This function perform a bitwise or between the new set of
1080 /// categories and the current ones, and then sets the current
1081 /// categories to the result of the or.
1082 ///
1083 /// @param c a bitmap that represents the set of categories that the
1084 /// user wants to see represented.
1085 void
1087 {priv_->allowed_category_ = priv_->allowed_category_ | c;}
1088 
1089 /// Setter for the bitmap that represents the set of categories that
1090 /// the user wants to see reported
1091 ///
1092 /// This function actually unsets bits from the current categories.
1093 ///
1094 /// @param c a bitmap that represents the set of categories to unset
1095 /// from the current categories.
1096 void
1098 {priv_->allowed_category_ = priv_->allowed_category_ & ~c;}
1099 
1100 /// Add a diff for two decls to the cache of the current diff_context.
1101 ///
1102 /// Doing this allows to later find the added diff from its two
1103 /// subject decls.
1104 ///
1105 /// @param first the first decl to consider.
1106 ///
1107 /// @param second the second decl to consider.
1108 ///
1109 /// @param the diff to add.
1110 void
1111 diff_context::add_diff(type_or_decl_base_sptr first,
1112  type_or_decl_base_sptr second,
1113  const diff_sptr d)
1114 {priv_->types_or_decls_diff_map[std::make_pair(first, second)] = d;}
1115 
1116 /// Add a diff tree node to the cache of the current diff_context
1117 ///
1118 /// @param d the diff tree node to add.
1119 void
1120 diff_context::add_diff(const diff* d)
1121 {
1122  if (d)
1123  {
1124  diff_sptr dif(const_cast<diff*>(d), noop_deleter());
1125  add_diff(d->first_subject(), d->second_subject(), dif);
1126  }
1127 }
1128 
1129 /// Add a diff tree node to the cache of the current diff_context
1130 ///
1131 /// @param d the diff tree node to add.
1132 void
1133 diff_context::add_diff(const diff_sptr d)
1134 {
1135  if (d)
1136  add_diff(d->first_subject(), d->second_subject(), d);
1137 }
1138 
1139 /// Getter for the @ref CanonicalDiff "canonical diff node" for the
1140 /// @ref diff represented by their two subjects.
1141 ///
1142 /// @param first the first subject of the diff.
1143 ///
1144 /// @param second the second subject of the diff.
1145 ///
1146 /// @return the canonical diff for the diff node represented by the
1147 /// two diff subjects @p first and @p second. If no canonical diff
1148 /// node was registered for these subjects, then a nil node is
1149 /// returned.
1150 diff_sptr
1152  const type_or_decl_base_sptr second) const
1153 {return has_diff_for(first, second);}
1154 
1155 /// Getter for the @ref CanonicalDiff "canonical diff node" for the
1156 /// @ref diff represented by the two subjects of a given diff node.
1157 ///
1158 /// @param d the diff node to get the canonical node for.
1159 ///
1160 /// @return the canonical diff for the diff node represented by the
1161 /// two diff subjects of @p d. If no canonical diff node was
1162 /// registered for these subjects, then a nil node is returned.
1163 diff_sptr
1165 {return has_diff_for(d);}
1166 
1167 /// Setter for the @ref CanonicalDiff "canonical diff node" for the
1168 /// @ref diff represented by their two subjects.
1169 ///
1170 /// @param first the first subject of the diff.
1171 ///
1172 /// @param second the second subject of the diff.
1173 ///
1174 /// @param d the new canonical diff.
1175 void
1176 diff_context::set_canonical_diff_for(const type_or_decl_base_sptr first,
1177  const type_or_decl_base_sptr second,
1178  const diff_sptr d)
1179 {
1180  ABG_ASSERT(d);
1181  if (!has_diff_for(first, second))
1182  {
1183  add_diff(first, second, d);
1184  priv_->canonical_diffs.push_back(d);
1185  }
1186 }
1187 
1188 /// If there is is a @ref CanonicalDiff "canonical diff node"
1189 /// registered for two diff subjects, return it. Otherwise, register
1190 /// a canonical diff node for these two diff subjects and return it.
1191 ///
1192 /// @param first the first subject of the diff.
1193 ///
1194 /// @param second the second subject of the diff.
1195 ///
1196 /// @param d the new canonical diff node.
1197 ///
1198 /// @return the canonical diff node.
1199 diff_sptr
1200 diff_context::set_or_get_canonical_diff_for(const type_or_decl_base_sptr first,
1201  const type_or_decl_base_sptr second,
1202  const diff_sptr canonical_diff)
1203 {
1204  ABG_ASSERT(canonical_diff);
1205 
1206  diff_sptr canonical = get_canonical_diff_for(first, second);
1207  if (!canonical)
1208  {
1209  canonical = canonical_diff;
1210  set_canonical_diff_for(first, second, canonical);
1211  }
1212  return canonical;
1213 }
1214 
1215 /// Set the canonical diff node property of a given diff node
1216 /// appropriately.
1217 ///
1218 /// For a given diff node that has no canonical diff node, retrieve
1219 /// the canonical diff node (by looking at its diff subjects and at
1220 /// the current context) and set the canonical diff node property of
1221 /// the diff node to that canonical diff node. If no canonical diff
1222 /// node has been registered to the diff context for the subjects of
1223 /// the diff node then, register the canonical diff node as being the
1224 /// diff node itself; and set its canonical diff node property as
1225 /// such. Otherwise, if the diff node already has a canonical diff
1226 /// node, do nothing.
1227 ///
1228 /// @param diff the diff node to initialize the canonical diff node
1229 /// property for.
1230 void
1232 {
1233  if (diff->get_canonical_diff() == 0)
1234  {
1235  diff_sptr canonical =
1236  set_or_get_canonical_diff_for(diff->first_subject(),
1237  diff->second_subject(),
1238  diff);
1239  diff->set_canonical_diff(canonical.get());
1240  }
1241 }
1242 
1243 /// Add a diff node to the set of diff nodes that are kept alive for
1244 /// the life time of the current instance of diff_context.
1245 ///
1246 /// Note that diff added to the diff cache are kept alive as well, and
1247 /// don't need to be passed to this function to be kept alive.
1248 ///
1249 /// @param d the diff node to be kept alive during the life time of
1250 /// the current instance of @ref diff_context.
1251 void
1253 {priv_->live_diffs_.insert(d);}
1254 
1255 /// Test if a diff node has been traversed.
1256 ///
1257 /// @param d the diff node to consider.
1258 ///
1259 /// @return the first diff node against which @p d is redundant.
1260 diff*
1262 {
1263  const diff* canonical = d->get_canonical_diff();
1264  ABG_ASSERT(canonical);
1265 
1266  size_t ptr_value = reinterpret_cast<size_t>(canonical);
1267  pointer_map::iterator it = priv_->visited_diff_nodes_.find(ptr_value);
1268  if (it != priv_->visited_diff_nodes_.end())
1269  return reinterpret_cast<diff*>(it->second);
1270  else
1271  return 0;
1272 }
1273 
1274 /// Test if a diff node has been traversed.
1275 ///
1276 /// @param d the diff node to consider.
1277 ///
1278 /// @return the first diff node against which @p d is redundant.
1279 diff_sptr
1281 {
1283  return diff;
1284 }
1285 
1286 /// Mark a diff node as traversed by a traversing algorithm.
1287 ///
1288 /// Actually, it's the @ref CanonicalDiff "canonical diff" of this
1289 /// node that is marked as traversed.
1290 ///
1291 /// Subsequent invocations of diff_has_been_visited() on the diff node
1292 /// will yield true.
1293 void
1295 {
1296  if (diff_has_been_visited(d))
1297  return;
1298 
1299  const diff* canonical = d->get_canonical_diff();
1300  ABG_ASSERT(canonical);
1301 
1302  size_t canonical_ptr_value = reinterpret_cast<size_t>(canonical);
1303  size_t diff_ptr_value = reinterpret_cast<size_t>(d);
1304  priv_->visited_diff_nodes_[canonical_ptr_value] = diff_ptr_value;
1305 }
1306 
1307 /// Unmark all the diff nodes that were marked as being traversed.
1308 void
1310 {priv_->visited_diff_nodes_.clear();}
1311 
1312 /// This sets a flag that, if it's true, then during the traversing of
1313 /// a diff nodes tree each node is visited at most once.
1314 ///
1315 /// @param f if true then during the traversing of a diff nodes tree
1316 /// each node is visited at most once.
1317 ///
1318 void
1320 {priv_->forbid_visiting_a_node_twice_ = f;}
1321 
1322 /// This function sets a flag os that if @ref
1323 /// forbid_visiting_a_node_twice() returns true, then each time the
1324 /// node visitor starts visiting a new interface, it resets the
1325 /// memory the systems has about already visited node.
1326 ///
1327 /// @param f the flag to set.
1328 void
1330 {priv_->reset_visited_diffs_for_each_interface_ = f;}
1331 
1332 /// Return a flag that, if true, then during the traversing of a diff
1333 /// nodes tree each node is visited at most once.
1334 ///
1335 /// @return the boolean flag.
1336 bool
1338 {return priv_->forbid_visiting_a_node_twice_;}
1339 
1340 /// Return a flag that, if true, then during the traversing of a diff
1341 /// nodes tree each node is visited at most once, while visiting the
1342 /// diff tree underneath a given interface (public function or
1343 /// variable). Each time a new interface is visited, the nodes
1344 /// visited while visiting previous interfaces can be visited again.
1345 ///
1346 /// @return the boolean flag.
1347 ///
1348 /// @return the boolean flag.
1349 bool
1351 {
1352  return (priv_->forbid_visiting_a_node_twice_
1353  && priv_->reset_visited_diffs_for_each_interface_);
1354 }
1355 
1356 /// Getter for the diff tree nodes filters to apply to diff sub-trees.
1357 ///
1358 /// @return the vector of tree filters to apply to diff sub-trees.
1359 const filtering::filters&
1361 {return priv_->filters_;}
1362 
1363 /// Setter for the diff filters to apply to a given diff sub-tree.
1364 ///
1365 /// @param f the new diff filter to add to the vector of diff filters
1366 /// to apply to diff sub-trees.
1367 void
1369 {priv_->filters_.push_back(f);}
1370 
1371 /// Apply the diff filters to a given diff sub-tree.
1372 ///
1373 /// If the current context is instructed to filter out some categories
1374 /// then this function walks the given sub-tree and categorizes its
1375 /// nodes by using the filters held by the context.
1376 ///
1377 /// @param diff the diff sub-tree to apply the filters to.
1378 void
1380 {
1381  if (!diff)
1382  return;
1383 
1384  if (!diff->has_changes())
1385  return;
1386 
1387  for (filtering::filters::const_iterator i = diff_filters().begin();
1388  i != diff_filters().end();
1389  ++i)
1390  {
1392  if (do_log())
1393  {
1394  std::cerr << "applying a filter to diff '"
1395  << diff->get_pretty_representation()
1396  << "'...\n";
1397  t.start();
1398  }
1399 
1400  filtering::apply_filter(*i, diff);
1401 
1402  if (do_log())
1403  {
1404  t.stop();
1405  std::cerr << "filter applied!:" << t << "\n";
1406 
1407  std::cerr << "propagating categories for the same diff node ... \n";
1408  t.start();
1409  }
1410 
1411  propagate_categories(diff);
1412 
1413  if (do_log())
1414  {
1415  t.stop();
1416  std::cerr << "category propagated!: " << t << "\n";
1417  }
1418  }
1419 
1420  }
1421 
1422 /// Apply the diff filters to the diff nodes of a @ref corpus_diff
1423 /// instance.
1424 ///
1425 /// If the current context is instructed to filter out some categories
1426 /// then this function walks the diff tree and categorizes its nodes
1427 /// by using the filters held by the context.
1428 ///
1429 /// @param diff the corpus diff to apply the filters to.
1430 void
1432 {
1433 
1434  if (!diff || !diff->has_changes())
1435  return;
1436 
1437  for (filtering::filters::const_iterator i = diff_filters().begin();
1438  i != diff_filters().end();
1439  ++i)
1440  {
1441  filtering::apply_filter(**i, diff);
1442  propagate_categories(diff);
1443  }
1444 }
1445 
1446 /// Getter for the vector of suppressions that specify which diff node
1447 /// reports should be dropped on the floor.
1448 ///
1449 /// @return the set of suppressions.
1450 const suppressions_type&
1452 {return priv_->suppressions_;}
1453 
1454 /// Getter for the vector of suppressions that specify which diff node
1455 /// reports should be dropped on the floor.
1456 ///
1457 /// @return the set of suppressions.
1460 {
1461  // Invalidate negated and direct suppressions caches that are built
1462  // from priv_->suppressions_;
1463  priv_->negated_suppressions_.clear();
1464  priv_->direct_suppressions_.clear();
1465  return priv_->suppressions_;
1466 }
1467 
1468 /// Getter of the negated suppression specifications that are
1469 /// comprised in the general vector of suppression specifications
1470 /// returned by diff_context::suppressions().
1471 ///
1472 /// Note that the first invocation of this function scans the vector
1473 /// returned by diff_context::suppressions() and caches the negated
1474 /// suppressions from there.
1475 ///
1476 /// Subsequent invocations of this function just return the cached
1477 /// negated suppressions.
1478 ///
1479 /// @return the negated suppression specifications stored in this diff
1480 /// context.
1483 {
1484  if (priv_->negated_suppressions_.empty())
1485  for (auto s : suppressions())
1486  if (is_negated_suppression(s))
1487  priv_->negated_suppressions_.push_back(s);
1488 
1489  return priv_->negated_suppressions_;
1490 }
1491 
1492 /// Getter of the direct suppression specification (those that are
1493 /// not negated) comprised in the general vector of suppression
1494 /// specifications returned by diff_context::suppression().
1495 ///
1496 /// Note that the first invocation of this function scans the vector
1497 /// returned by diff_context::suppressions() and caches the direct
1498 /// suppressions from there.
1499 ///
1500 /// Subsequent invocations of this function just return the cached
1501 /// direct suppressions.
1502 ///
1503 /// @return the direct suppression specifications.
1506 {
1507  if (priv_->direct_suppressions_.empty())
1508  {
1509  for (auto s : suppressions())
1510  if (!is_negated_suppression(s))
1511  priv_->direct_suppressions_.push_back(s);
1512  }
1513  return priv_->direct_suppressions_;
1514 }
1515 
1516 /// Add a new suppression specification that specifies which diff node
1517 /// reports should be dropped on the floor.
1518 ///
1519 /// @param suppr the new suppression specification to add to the
1520 /// existing set of suppressions specifications of the diff context.
1521 void
1523 {
1524  priv_->suppressions_.push_back(suppr);
1525  // Invalidate negated and direct suppressions caches that are built
1526  // from priv_->suppressions_;
1527  priv_->negated_suppressions_.clear();
1528  priv_->direct_suppressions_.clear();
1529 }
1530 
1531 /// Add new suppression specifications that specify which diff node
1532 /// reports should be dropped on the floor.
1533 ///
1534 /// @param supprs the new suppression specifications to add to the
1535 /// existing set of suppression specifications of the diff context.
1536 void
1538 {
1539  priv_->suppressions_.insert(priv_->suppressions_.end(),
1540  supprs.begin(), supprs.end());
1541 }
1542 
1543 /// Test if it's requested to perform diff node categorization.
1544 ///
1545 /// @return true iff it's requested to perform diff node
1546 /// categorization.
1547 bool
1549 {return priv_->perform_change_categorization_;}
1550 
1551 /// Request change categorization or not.
1552 ///
1553 /// @param f true iff change categorization is requested.
1554 void
1556 {priv_->perform_change_categorization_ = f;}
1557 
1558 /// Set the flag that indicates if the diff using this context should
1559 /// show only leaf changes or not.
1560 ///
1561 /// @param f the new value of the flag that indicates if the diff
1562 /// using this context should show only leaf changes or not.
1563 void
1565 {
1566  // This function can be called only if the reporter hasn't yet been
1567  // created. Once it's been created, we are supposed to live with
1568  // it.
1569  ABG_ASSERT(priv_->reporter_ == 0);
1570  priv_->leaf_changes_only_ = f;
1571 }
1572 
1573 /// Get the flag that indicates if the diff using this context should
1574 /// show only leaf changes or not.
1575 ///
1576 /// @return the value of the flag that indicates if the diff using
1577 /// this context should show only leaf changes or not.
1578 bool
1580 {return priv_->leaf_changes_only_;}
1581 
1582 /// Get the flag that indicates if the diff reports using this context
1583 /// should show sizes and offsets in an hexadecimal base or not. If
1584 /// not, then they are to be shown in a decimal base.
1585 ///
1586 /// @return true iff sizes and offsets are to be shown in an
1587 /// hexadecimal base.
1588 bool
1590 {return priv_->hex_values_;}
1591 
1592 /// Set the flag that indicates if diff reports using this context
1593 /// should show sizes and offsets in an hexadecimal base or not. If
1594 /// not, then they are to be shown in a decimal base.
1595 ///
1596 /// @param f if true then sizes and offsets are to be shown in an
1597 /// hexadecimal base.
1598 void
1600 {priv_->hex_values_ = f;}
1601 
1602 /// Get the flag that indicates if diff reports using this context
1603 /// should show sizes and offsets in bits, rather than bytes.
1604 ///
1605 /// @return true iff sizes and offsets are to be shown in bits.
1606 /// Otherwise they are to be shown in bytes.
1607 bool
1609 {return priv_->show_offsets_sizes_in_bits_;}
1610 
1611 /// Set the flag that indicates if diff reports using this context
1612 /// should show sizes and offsets in bits, rather than bytes.
1613 ///
1614 /// @param f if true then sizes and offsets are to be shown in bits.
1615 /// Otherwise they are to be shown in bytes.
1616 void
1618 {priv_->show_offsets_sizes_in_bits_ = f;}
1619 
1620 /// Set a flag saying if offset changes should be reported in a
1621 /// relative way. That is, if the report should say how of many bits
1622 /// a class/struct data member did move.
1623 ///
1624 /// @param f the new boolean value of the flag.
1625 void
1627 {priv_->show_relative_offset_changes_ = f;}
1628 
1629 /// Get the flag saying if offset changes should be reported in a
1630 /// relative way. That is, if the report should say how of many bits
1631 /// a class/struct data member did move.
1632 ///
1633 /// @return the boolean value of the flag.
1634 bool
1636 {return priv_->show_relative_offset_changes_;}
1637 
1638 /// Set a flag saying if the comparison module should only show the
1639 /// diff stats.
1640 ///
1641 /// @param f the flag to set.
1642 void
1644 {priv_->show_stats_only_ = f;}
1645 
1646 /// Test if the comparison module should only show the diff stats.
1647 ///
1648 /// @return true if the comparison module should only show the diff
1649 /// stats, false otherwise.
1650 bool
1652 {return priv_->show_stats_only_;}
1653 
1654 /// Setter for the property that says if the comparison module should
1655 /// show the soname changes in its report.
1656 ///
1657 /// @param f the new value of the property.
1658 void
1660 {priv_->show_soname_change_ = f;}
1661 
1662 /// Getter for the property that says if the comparison module should
1663 /// show the soname changes in its report.
1664 ///
1665 /// @return the value of the property.
1666 bool
1668 {return priv_->show_soname_change_;}
1669 
1670 /// Setter for the property that says if the comparison module should
1671 /// show the architecture changes in its report.
1672 ///
1673 /// @param f the new value of the property.
1674 void
1676 {priv_->show_architecture_change_ = f;}
1677 
1678 /// Getter for the property that says if the comparison module should
1679 /// show the architecture changes in its report.
1680 ///
1681 /// @return the value of the property.
1682 bool
1684 {return priv_->show_architecture_change_;}
1685 
1686 /// Set a flag saying to show the deleted functions.
1687 ///
1688 /// @param f true to show deleted functions.
1689 void
1691 {priv_->show_deleted_fns_ = f;}
1692 
1693 /// @return true if we want to show the deleted functions, false
1694 /// otherwise.
1695 bool
1697 {return priv_->show_deleted_fns_;}
1698 
1699 /// Set a flag saying to show the changed functions.
1700 ///
1701 /// @param f true to show the changed functions.
1702 void
1704 {priv_->show_changed_fns_ = f;}
1705 
1706 /// @return true if we want to show the changed functions, false otherwise.
1707 bool
1709 {return priv_->show_changed_fns_;}
1710 
1711 /// Set a flag saying to show the added functions.
1712 ///
1713 /// @param f true to show the added functions.
1714 void
1716 {priv_->show_added_fns_ = f;}
1717 
1718 /// @return true if we want to show the added functions, false
1719 /// otherwise.
1720 bool
1722 {return priv_->show_added_fns_;}
1723 
1724 /// Set a flag saying to show the deleted variables.
1725 ///
1726 /// @param f true to show the deleted variables.
1727 void
1729 {priv_->show_deleted_vars_ = f;}
1730 
1731 /// @return true if we want to show the deleted variables, false
1732 /// otherwise.
1733 bool
1735 {return priv_->show_deleted_vars_;}
1736 
1737 /// Set a flag saying to show the changed variables.
1738 ///
1739 /// @param f true to show the changed variables.
1740 void
1742 {priv_->show_changed_vars_ = f;}
1743 
1744 /// @return true if we want to show the changed variables, false otherwise.
1745 bool
1747 {return priv_->show_changed_vars_;}
1748 
1749 /// Set a flag saying to show the added variables.
1750 ///
1751 /// @param f true to show the added variables.
1752 void
1754 {priv_->show_added_vars_ = f;}
1755 
1756 /// @return true if we want to show the added variables, false
1757 /// otherwise.
1758 bool
1760 {return priv_->show_added_vars_;}
1761 
1762 bool
1763 diff_context::show_linkage_names() const
1764 {return priv_->show_linkage_names_;}
1765 
1766 void
1767 diff_context::show_linkage_names(bool f)
1768 {priv_->show_linkage_names_= f;}
1769 
1770 /// Set a flag saying to show location information.
1771 ///
1772 /// @param f true to show location information.
1773 void
1775 {priv_->show_locs_= f;}
1776 
1777 /// @return true if we want to show location information, false
1778 /// otherwise.
1779 bool
1781 {return priv_->show_locs_;}
1782 
1783 /// A getter for the flag that says if we should report about
1784 /// functions or variables diff nodes that have *exclusively*
1785 /// redundant diff tree children nodes.
1786 ///
1787 /// @return the flag.
1788 bool
1790 {return priv_->show_redundant_changes_;}
1791 
1792 /// A setter for the flag that says if we should report about
1793 /// functions or variables diff nodes that have *exclusively*
1794 /// redundant diff tree children nodes.
1795 ///
1796 /// @param f the flag to set.
1797 void
1799 {priv_->show_redundant_changes_ = f;}
1800 
1801 /// Getter for the flag that indicates if symbols not referenced by
1802 /// any debug info are to be compared and reported about.
1803 ///
1804 /// @return the boolean flag.
1805 bool
1807 {return priv_->show_syms_unreferenced_by_di_;}
1808 
1809 /// Setter for the flag that indicates if symbols not referenced by
1810 /// any debug info are to be compared and reported about.
1811 ///
1812 /// @param f the new flag to set.
1813 void
1815 {priv_->show_syms_unreferenced_by_di_ = f;}
1816 
1817 /// Getter for the flag that indicates if symbols not referenced by
1818 /// any debug info and that got added are to be reported about.
1819 ///
1820 /// @return true iff symbols not referenced by any debug info and that
1821 /// got added are to be reported about.
1822 bool
1824 {return priv_->show_added_syms_unreferenced_by_di_;}
1825 
1826 /// Setter for the flag that indicates if symbols not referenced by
1827 /// any debug info and that got added are to be reported about.
1828 ///
1829 /// @param f the new flag that says if symbols not referenced by any
1830 /// debug info and that got added are to be reported about.
1831 void
1833 {priv_->show_added_syms_unreferenced_by_di_ = f;}
1834 
1835 /// Setter for the flag that indicates if changes on types unreachable
1836 /// from global functions and variables are to be reported.
1837 ///
1838 /// @param f if true, then changes on types unreachable from global
1839 /// functions and variables are to be reported.
1840 void
1842 {priv_->show_unreachable_types_ = f;}
1843 
1844 /// Getter for the flag that indicates if changes on types unreachable
1845 /// from global functions and variables are to be reported.
1846 ///
1847 /// @return true iff changes on types unreachable from global
1848 /// functions and variables are to be reported.
1849 bool
1851 {return priv_->show_unreachable_types_;}
1852 
1853 /// Getter of the flag that indicates if the leaf reporter should
1854 /// display a summary of the interfaces impacted by a given leaf
1855 /// change or not.
1856 ///
1857 /// @return the flag that indicates if the leaf reporter should
1858 /// display a summary of the interfaces impacted by a given leaf
1859 /// change or not.
1860 bool
1862 {return priv_->show_impacted_interfaces_;}
1863 
1864 /// Setter of the flag that indicates if the leaf reporter should
1865 /// display a summary of the interfaces impacted by a given leaf
1866 /// change or not.
1867 ///
1868 /// @param f the new value of the flag that indicates if the leaf
1869 /// reporter should display a summary of the interfaces impacted by a
1870 /// given leaf change or not.
1871 void
1873 {priv_->show_impacted_interfaces_ = f;}
1874 
1875 /// Setter for the default output stream used by code of the
1876 /// comparison engine. By default the default output stream is a NULL
1877 /// pointer.
1878 ///
1879 /// @param o a pointer to the default output stream.
1880 void
1882 {priv_->default_output_stream_ = o;}
1883 
1884 /// Getter for the default output stream used by code of the
1885 /// comparison engine. By default the default output stream is a NULL
1886 /// pointer.
1887 ///
1888 /// @return a pointer to the default output stream.
1889 ostream*
1891 {return priv_->default_output_stream_;}
1892 
1893 /// Setter for the errror output stream used by code of the comparison
1894 /// engine. By default the error output stream is a NULL pointer.
1895 ///
1896 /// @param o a pointer to the error output stream.
1897 void
1899 {priv_->error_output_stream_ = o;}
1900 
1901 /// Getter for the errror output stream used by code of the comparison
1902 /// engine. By default the error output stream is a NULL pointer.
1903 ///
1904 /// @return a pointer to the error output stream.
1905 ostream*
1907 {return priv_->error_output_stream_;}
1908 
1909 /// Test if the comparison engine should dump the diff tree for the
1910 /// changed functions and variables it has.
1911 ///
1912 /// @return true if after the comparison, the engine should dump the
1913 /// diff tree for the changed functions and variables it has.
1914 bool
1916 {return priv_->dump_diff_tree_;}
1917 
1918 /// Set if the comparison engine should dump the diff tree for the
1919 /// changed functions and variables it has.
1920 ///
1921 /// @param f true if after the comparison, the engine should dump the
1922 /// diff tree for the changed functions and variables it has.
1923 void
1925 {priv_->dump_diff_tree_ = f;}
1926 
1927 /// Emit a textual representation of a diff tree to the error output
1928 /// stream of the current context, for debugging purposes.
1929 ///
1930 /// @param d the diff tree to serialize to the error output associated
1931 /// to the current instance of @ref diff_context.
1932 void
1934 {
1935  if (error_output_stream())
1937 }
1938 
1939 /// Emit a textual representation of a @ref corpus_diff tree to the error
1940 /// output stream of the current context, for debugging purposes.
1941 ///
1942 /// @param d the @ref corpus_diff tree to serialize to the error
1943 /// output associated to the current instance of @ref diff_context.
1944 void
1946 {
1947  if (error_output_stream())
1949 }
1950 // </diff_context stuff>
1951 
1952 // <diff stuff>
1953 
1954 /// Constructor for the @ref diff type.
1955 ///
1956 /// This constructs a diff between two subjects that are actually
1957 /// declarations; the first and the second one.
1958 ///
1959 /// @param first_subject the first decl (subject) of the diff.
1960 ///
1961 /// @param second_subject the second decl (subject) of the diff.
1962 diff::diff(type_or_decl_base_sptr first_subject,
1963  type_or_decl_base_sptr second_subject)
1964  : priv_(new priv(first_subject, second_subject,
1967  /*reported_once=*/false,
1968  /*currently_reporting=*/false))
1969 {}
1970 
1971 /// Constructor for the @ref diff type.
1972 ///
1973 /// This constructs a diff between two subjects that are actually
1974 /// declarations; the first and the second one.
1975 ///
1976 /// @param first_subject the first decl (subject) of the diff.
1977 ///
1978 /// @param second_subject the second decl (subject) of the diff.
1979 ///
1980 /// @param ctxt the context of the diff. Note that this context
1981 /// object must stay alive during the entire life time of the current
1982 /// instance of @ref diff. Otherwise, memory corruption issues occur.
1983 diff::diff(type_or_decl_base_sptr first_subject,
1984  type_or_decl_base_sptr second_subject,
1985  diff_context_sptr ctxt)
1986  : priv_(new priv(first_subject, second_subject,
1987  ctxt, NO_CHANGE_CATEGORY,
1988  /*reported_once=*/false,
1989  /*currently_reporting=*/false))
1990 {}
1991 
1992 /// Test if logging was requested
1993 ///
1994 /// @return true iff logging was requested.
1995 bool
1997 {return context()->do_log();}
1998 
1999 /// Request logging (or not)
2000 ///
2001 /// @param f true iff logging is to be requested.
2002 void
2004 {context()->do_log(f);}
2005 
2006 /// Flag a given diff node as being traversed.
2007 ///
2008 /// For certain diff nodes like @ref class_diff, it's important to
2009 /// avoid traversing the node again while it's already being
2010 /// traversed; otherwise this leads to infinite loops. So the
2011 /// diff::begin_traversing() and diff::end_traversing() methods flag a
2012 /// given node as being traversed (or not), so that
2013 /// diff::is_traversing() can tell if the node is being traversed.
2014 ///
2015 /// Note that traversing a node means visiting it *and* visiting its
2016 /// children nodes.
2017 ///
2018 /// The canonical node is marked as being traversed too.
2019 ///
2020 /// These functions are called by the traversing code.
2021 void
2023 {
2025  if (priv_->canonical_diff_)
2026  priv_->canonical_diff_->priv_->traversing_ = true;
2027  priv_->traversing_ = true;
2028 }
2029 
2030 /// Tell if a given node is being traversed or not.
2031 ///
2032 /// Note that traversing a node means visiting it *and* visiting its
2033 /// children nodes.
2034 ///
2035 /// It's the canonical node which is looked at, actually.
2036 ///
2037 /// Please read the comments for the diff::begin_traversing() for mode
2038 /// context.
2039 ///
2040 /// @return true if the current instance of @diff is being traversed.
2041 bool
2043 {
2044  if (priv_->canonical_diff_)
2045  return priv_->canonical_diff_->priv_->traversing_;
2046  return priv_->traversing_;
2047 }
2048 
2049 /// Flag a given diff node as not being traversed anymore.
2050 ///
2051 /// Note that traversing a node means visiting it *and* visiting its
2052 /// children nodes.
2053 ///
2054 /// Please read the comments of the function diff::begin_traversing()
2055 /// for mode context.
2056 void
2058 {
2060  if (priv_->canonical_diff_)
2061  priv_->canonical_diff_->priv_->traversing_ = false;
2062  priv_->traversing_ = false;
2063 }
2064 
2065 /// Finish the insertion of a diff tree node into the diff graph.
2066 ///
2067 /// This function might be called several times. It must perform the
2068 /// insertion only once.
2069 ///
2070 /// For instance, certain kinds of diff tree node have specific
2071 /// children nodes that are populated after the constructor of the
2072 /// diff tree node has been called. In that case, calling overloads
2073 /// of this method ensures that these children nodes are properly
2074 /// gathered and setup.
2075 void
2077 {
2078  if (diff::priv_->finished_)
2079  return;
2081  diff::priv_->finished_ = true;
2082 }
2083 
2084 /// Getter of the first subject of the diff.
2085 ///
2086 /// @return the first subject of the diff.
2089 {return dynamic_pointer_cast<type_or_decl_base>(priv_->first_subject_);}
2090 
2091 /// Getter of the second subject of the diff.
2092 ///
2093 /// @return the second subject of the diff.
2096 {return dynamic_pointer_cast<type_or_decl_base>(priv_->second_subject_);}
2097 
2098 /// Getter for the children nodes of the current @ref diff node.
2099 ///
2100 /// @return a vector of the children nodes.
2101 const vector<diff*>&
2103 {return priv_->children_;}
2104 
2105 /// Getter for the parent node of the current @ref diff node.
2106 ///
2107 /// @return the parent node of the current @ref diff node.
2108 const diff*
2110 {return priv_->parent_;}
2111 
2112 /// Getter for the canonical diff of the current instance of @ref
2113 /// diff.
2114 ///
2115 /// Note that the canonical diff node for the current instanc eof diff
2116 /// node must have been set by invoking
2117 /// class_diff::initialize_canonical_diff() on the current instance of
2118 /// diff node.
2119 ///
2120 /// @return the canonical diff node or null if none was set.
2121 diff*
2123 {return priv_->canonical_diff_;}
2124 
2125 /// Setter for the canonical diff of the current instance of @ref
2126 /// diff.
2127 ///
2128 /// @param d the new canonical node to set.
2129 void
2131 {priv_->canonical_diff_ = d;}
2132 
2133 /// Add a new child node to the vector of children nodes for the
2134 /// current @ref diff node.
2135 ///
2136 /// @param d the new child node to add to the children nodes.
2137 void
2139 {
2140  ABG_ASSERT(d);
2141 
2142  // Ensure 'd' is kept alive for the life time of the context of this
2143  // diff.
2144  context()->keep_diff_alive(d);
2145 
2146  // Add the underlying pointer of 'd' to the vector of children.
2147  // Note that this vector holds no reference to 'd'. This is to avoid
2148  // reference cycles. The reference to 'd' is held by the context of
2149  // this diff, thanks to the call to context()->keep_diff_alive(d)
2150  // above.
2151  priv_->children_.push_back(d.get());
2152 
2153  d->priv_->parent_ = this;
2154 }
2155 
2156 /// Getter of the context of the current diff.
2157 ///
2158 /// @return the context of the current diff.
2159 const diff_context_sptr
2161 {return priv_->get_context();}
2162 
2163 /// Setter of the context of the current diff.
2164 ///
2165 /// @param c the new context to set.
2166 void
2168 {priv_->ctxt_ = c;}
2169 
2170 /// Tests if we are currently in the middle of emitting a report for
2171 /// this diff.
2172 ///
2173 /// @return true if we are currently emitting a report for the
2174 /// current diff, false otherwise.
2175 bool
2177 {
2178  if (priv_->canonical_diff_)
2179  return priv_->canonical_diff_->priv_->currently_reporting_;
2180  return priv_->currently_reporting_;
2181 }
2182 
2183 /// Sets a flag saying if we are currently in the middle of emitting
2184 /// a report for this diff.
2185 ///
2186 /// @param f true if we are currently emitting a report for the
2187 /// current diff, false otherwise.
2188 void
2190 {
2191  if (priv_->canonical_diff_)
2192  priv_->canonical_diff_->priv_->currently_reporting_ = f;
2193  priv_->currently_reporting_ = f;
2194 }
2195 
2196 /// Tests if a report has already been emitted for the current diff.
2197 ///
2198 /// @return true if a report has already been emitted for the
2199 /// current diff, false otherwise.
2200 bool
2202 {
2203  ABG_ASSERT(priv_->canonical_diff_);
2204  return priv_->canonical_diff_->priv_->reported_once_;
2205 }
2206 
2207 /// The generic traversing code that walks a given diff sub-tree.
2208 ///
2209 /// Note that there is a difference between traversing a diff node and
2210 /// visiting it. Basically, traversing a diff node means visiting it
2211 /// and visiting its children nodes too. So one can visit a node
2212 /// without traversing it. But traversing a node without visiting it
2213 /// is not possible.
2214 ///
2215 /// Note that the insertion of the "generic view" of the diff node
2216 /// into the graph being traversed is done "on the fly". The
2217 /// insertion of the "typed view" of the diff node into the graph is
2218 /// done implicitely. To learn more about the generic and typed view
2219 /// of the diff node, please read the introductory comments of the
2220 /// @ref diff class.
2221 ///
2222 /// Note that by default this traversing code visits a given class of
2223 /// equivalence of a diff node only once. This behaviour can been
2224 /// changed by calling
2225 /// diff_context::visiting_a_node_twice_is_forbidden(), but this is
2226 /// very risky as it might create endless loops while visiting a diff
2227 /// tree graph that has changes that refer to themselves; that is,
2228 /// diff tree graphs with cycles.
2229 ///
2230 /// When a diff node is encountered, the
2231 /// diff_node_visitor::visit_begin() method is invoked on the diff
2232 /// node first.
2233 ///
2234 /// If the diff node has already been visited, then
2235 /// node_visitor::visit_end() is called on it and the node traversing
2236 /// is done; the children of the diff node are not visited in this
2237 /// case.
2238 ///
2239 /// If the diff node has *NOT* been visited yet, then the
2240 /// diff_node_visitor::visit() method is invoked with it's 'pre'
2241 /// argument set to true. Then if the diff_node_visitor::visit()
2242 /// returns true, then the children nodes of the diff node are
2243 /// visited. Otherwise, no children nodes of the diff node is
2244 /// visited and the diff_node_visitor::visit_end() is called.
2245 
2246 /// After the children nodes are visited (and only if they are
2247 /// visited) the diff_node_visitor::visit() method is invoked with
2248 /// it's 'pre' argument set to false. And then the
2249 /// diff_node_visitor::visit_end() is called.
2250 ///
2251 /// @param v the entity that visits each node of the diff sub-tree.
2252 ///
2253 /// @return true to tell the caller that all of the sub-tree could be
2254 /// walked. This instructs the caller to keep walking the rest of the
2255 /// tree. Return false otherwise.
2256 bool
2258 {
2259  // Insert the "generic view" of the diff node into its graph.
2260  finish_diff_type();
2261 
2262  v.visit_begin(this);
2263 
2264  bool already_visited = false;
2265  if (context()->visiting_a_node_twice_is_forbidden()
2266  && context()->diff_has_been_visited(this))
2267  already_visited = true;
2268 
2269  bool mark_visited_nodes_as_traversed =
2271 
2272  if (!already_visited && !v.visit(this, /*pre=*/true))
2273  {
2274  v.visit_end(this);
2275  if (mark_visited_nodes_as_traversed)
2276  context()->mark_diff_as_visited(this);
2277  return false;
2278  }
2279 
2281  && !is_traversing()
2282  && !already_visited)
2283  {
2284  begin_traversing();
2285  for (vector<diff*>::const_iterator i = children_nodes().begin();
2286  i != children_nodes().end();
2287  ++i)
2288  {
2289  if (!(*i)->traverse(v))
2290  {
2291  v.visit_end(this);
2292  if (mark_visited_nodes_as_traversed)
2293  context()->mark_diff_as_visited(this);
2294  end_traversing();
2295  return false;
2296  }
2297  }
2298  end_traversing();
2299  }
2300 
2301  if (!v.visit(this, /*pref=*/false))
2302  {
2303  v.visit_end(this);
2304  if (mark_visited_nodes_as_traversed)
2305  context()->mark_diff_as_visited(this);
2306  return false;
2307  }
2308 
2309  v.visit_end(this);
2310  if (!already_visited && mark_visited_nodes_as_traversed)
2311  context()->mark_diff_as_visited(this);
2312 
2313  return true;
2314 }
2315 
2316 /// Sets a flag saying if a report has already been emitted for the
2317 /// current diff.
2318 ///
2319 /// @param f true if a report has already been emitted for the
2320 /// current diff, false otherwise.
2321 void
2322 diff::reported_once(bool f) const
2323 {
2324  ABG_ASSERT(priv_->canonical_diff_);
2325  priv_->canonical_diff_->priv_->reported_once_ = f;
2326  priv_->reported_once_ = f;
2327 }
2328 
2329 /// Getter for the local category of the current diff tree node.
2330 ///
2331 /// The local category represents the set of categories of a diff
2332 /// node, not taking in account the categories inherited from its
2333 /// children nodes.
2334 ///
2335 /// @return the local category of the current diff tree node.
2338 {return priv_->local_category_;}
2339 
2340 /// Getter of the category of the class of equivalence of the current
2341 /// diff tree node.
2342 ///
2343 /// That is, if the current diff tree node has a canonical node,
2344 /// return the category of that canonical node. Otherwise, return the
2345 /// category of the current node.
2346 ///
2347 /// @return the category of the class of equivalence of the current
2348 /// tree node.
2351 {
2352  diff* canonical = get_canonical_diff();
2353  return canonical ? canonical->get_category() : get_category();
2354 }
2355 
2356 /// Getter for the category of the current diff tree node.
2357 ///
2358 /// This category represents the union of the local category and the
2359 /// categories inherited from the children diff nodes.
2360 ///
2361 /// @return the category of the current diff tree node.
2364 {return priv_->category_;}
2365 
2366 /// Adds the current diff tree node to an additional set of
2367 /// categories. Note that the categories include thoses inherited
2368 /// from the children nodes of this diff node.
2369 ///
2370 /// @param c a bit-map representing the set of categories to add the
2371 /// current diff tree node to.
2372 ///
2373 /// @return the resulting bit-map representing the categories this
2374 /// current diff tree node belongs to, including those inherited from
2375 /// its children nodes.
2378 {
2379  priv_->category_ = priv_->category_ | c;
2380  return priv_->category_;
2381 }
2382 
2383 /// Adds the current diff tree node to the categories resulting from
2384 /// the local changes of the current diff node.
2385 ///
2386 /// @param c a bit-map representing the set of categories to add the
2387 /// current diff tree node to.
2388 ///
2389 /// @return the resulting bit-map representing the categories this
2390 /// current diff tree node belongs to.
2393 {
2394  priv_->local_category_ = priv_->local_category_ | c;
2395  return priv_->local_category_;
2396 }
2397 
2398 /// Adds the current diff tree node to the categories resulting from
2399 /// the local and inherited changes of the current diff node.
2400 ///
2401 /// @param c a bit-map representing the set of categories to add the
2402 /// current diff tree node to.
2403 void
2405 {
2407  add_to_category(c);
2408 }
2409 
2410 /// Remove the current diff tree node from an a existing sef of
2411 /// categories. The categories include those inherited from the
2412 /// children nodes of the current diff node.
2413 ///
2414 /// @param c a bit-map representing the set of categories to add the
2415 /// current diff tree node to.
2416 ///
2417 /// @return the resulting bit-map representing the categories this
2418 /// current diff tree onde belongs to, including the categories
2419 /// inherited from the children nodes of the current diff node.
2422 {
2423  priv_->category_ = priv_->category_ & ~c;
2424  return priv_->category_;
2425 }
2426 
2427 /// Remove the current diff tree node from the categories resulting
2428 /// from the local changes.
2429 ///
2430 /// @param c a bit-map representing the set of categories to add the
2431 /// current diff tree node to.
2432 ///
2433 /// @return the resulting bit-map representing the categories this
2434 /// current diff tree onde belongs to.
2437 {
2438  priv_->local_category_ = priv_->local_category_ & ~c;
2439  return priv_->local_category_;
2440 }
2441 
2442 /// Set the category of the current @ref diff node. This category
2443 /// includes the categories inherited from the children nodes of the
2444 /// current diff node.
2445 ///
2446 /// @param c the new category for the current diff node.
2447 void
2449 {priv_->category_ = c;}
2450 
2451 /// Set the local category of the current @ref diff node.
2452 ///
2453 /// @param c the new category for the current diff node.
2454 void
2456 {priv_->local_category_ = c;}
2457 
2458 /// Test if this diff tree node is to be filtered out for reporting
2459 /// purposes.
2460 ///
2461 /// There is a difference between a diff node being filtered out and
2462 /// being suppressed. Being suppressed means that there is a
2463 /// suppression specification that suppresses the diff node
2464 /// specifically. Being filtered out mean the node is either
2465 /// suppressed, or it's filtered out because the suppression of a set
2466 /// of (children) nodes caused this node to be filtered out as well.
2467 /// For instance, if a function diff has all its children diff nodes
2468 /// suppressed and if the function diff node carries no local change,
2469 /// then the function diff node itself is going to be filtered out.
2470 ///
2471 /// The function tests if the categories of the diff tree node are
2472 /// "forbidden" by the context or not.
2473 ///
2474 /// @return true iff the current diff node should NOT be reported.
2475 bool
2477 {
2478  if (diff * canonical = get_canonical_diff())
2479  if ((canonical->get_category() & SUPPRESSED_CATEGORY
2480  || canonical->get_category() & PRIVATE_TYPE_CATEGORY)
2481  && !canonical->is_allowed_by_specific_negated_suppression()
2482  && !canonical->has_descendant_allowed_by_specific_negated_suppression()
2483  && !canonical->has_parent_allowed_by_specific_negated_suppression())
2484  // The canonical type was suppressed either by a user-provided
2485  // suppression specification or by a "private-type" suppression
2486  // specification.. This means all the classes of equivalence of
2487  // that canonical type were suppressed. So this node should be
2488  // filtered out.
2489  return true;
2490  return priv_->is_filtered_out(get_category());
2491 }
2492 
2493 /// Test if this diff tree node is to be filtered out for reporting
2494 /// purposes, but by considering only the categories that were *NOT*
2495 /// inherited from its children nodes.
2496 ///
2497 /// The function tests if the local categories of the diff tree node
2498 /// are "forbidden" by the context or not.
2499 ///
2500 /// @return true iff the current diff node should NOT be reported,
2501 /// with respect to its local categories.
2502 bool
2504 {return priv_->is_filtered_out(get_local_category());}
2505 
2506 /// Test if this diff tree node is to be filtered out for reporting
2507 /// purposes, but without considering the categories that can /force/
2508 /// the node to be unfiltered.
2509 ///
2510 /// The function tests if the categories of the diff tree node are
2511 /// "forbidden" by the context or not.
2512 ///
2513 /// @return true iff the current diff node should should NOT be
2514 /// reported, with respect to the categories that might filter it out
2515 /// only.
2516 bool
2518 {
2523 
2524  return priv_->is_filtered_out(c);
2525 }
2526 
2527 /// Test if the current diff node has been suppressed by a
2528 /// user-provided suppression specification.
2529 ///
2530 /// @return true if the current diff node has been suppressed by a
2531 /// user-provided suppression list.
2532 bool
2534 {
2535  bool is_private = false;
2536  return is_suppressed(is_private);
2537 }
2538 
2539 /// Test if the current diff node has been suppressed by a
2540 /// user-provided suppression specification or by an auto-generated
2541 /// "private type" suppression specification.
2542 ///
2543 /// Note that private type suppressions are auto-generated from the
2544 /// path to where public headers are, as given by the user.
2545 ///
2546 /// Here is the current algorithm:
2547 ///
2548 /// First, suppress this diff node if it's not matched by any
2549 /// negated suppression specifications. If it's not
2550 /// suppressed, then suppress it if it's matched by direct
2551 /// suppression specifications.
2552 ///
2553 /// @param is_private_type out parameter if the current diff node was
2554 /// suppressed because it's a private type then this parameter is set
2555 /// to true.
2556 ///
2557 /// @return true if the current diff node has been suppressed by a
2558 /// user-provided suppression list.
2559 bool
2560 diff::is_suppressed(bool &is_private_type) const
2561 {
2562  // If there is at least one negated suppression, then suppress the
2563  // current diff node by default ...
2564  bool do_suppress = !context()->negated_suppressions().empty();
2565 
2566  // ... unless there is at least one negated suppression that
2567  // specifically asks to keep this diff node around (un-suppressed).
2568  for (auto n : context()->negated_suppressions())
2569  if (!n->suppresses_diff(this))
2570  {
2571  do_suppress = false;
2572  break;
2573  }
2574 
2575  // Then walk the set of non-negated, AKA direct, suppressions. If at
2576  // least one suppression suppresses the current diff node then the
2577  // diff node must be suppressed.
2578  for (auto d : context()->direct_suppressions())
2579  if (d->suppresses_diff(this))
2580  {
2581  do_suppress = true;
2583  is_private_type = true;
2584  break;
2585  }
2586 
2587  return do_suppress;
2588 }
2589 
2590 /// Test if this diff tree node should be reported.
2591 ///
2592 /// @return true iff the current node should be reported.
2593 bool
2595 {
2596  if (has_changes() && !is_filtered_out())
2597  return true;
2598  return false;
2599 }
2600 
2601 /// Test if this diff tree node should be reported when considering
2602 /// the categories that were *NOT* inherited from its children nodes.
2603 ///
2604 /// @return true iff the current node should be reported.
2605 bool
2607 {
2608  if (has_local_changes()
2610  return true;
2611  return false;
2612 }
2613 
2614 /// Test if this diff node is allowed (prevented from being
2615 /// suppressed) by at least one negated suppression specification.
2616 ///
2617 /// @return true if this diff node is meant to be allowed by at least
2618 /// one negated suppression specification.
2619 bool
2621 {
2622  const suppressions_type& suppressions = context()->suppressions();
2623  for (suppressions_type::const_iterator i = suppressions.begin();
2624  i != suppressions.end();
2625  ++i)
2626  {
2627  if (is_negated_suppression(*i)
2628  && !(*i)->suppresses_diff(this))
2629  return true;
2630  }
2631  return false;
2632 }
2633 
2634 /// Test if the current diff node has a descendant node which is
2635 /// specifically allowed by a negated suppression specification.
2636 ///
2637 /// @return true iff the current diff node has a descendant node
2638 /// which is specifically allowed by a negated suppression
2639 /// specification.
2640 bool
2642 {
2644  return result;
2645 }
2646 
2647 /// Test if the current diff node has a parent node which is
2648 /// specifically allowed by a negated suppression specification.
2649 ///
2650 /// @return true iff the current diff node has a parent node which is
2651 /// specifically allowed by a negated suppression specification.
2652 bool
2654 {
2656  return result;
2657 }
2658 
2659 /// Get a pretty representation of the current @ref diff node.
2660 ///
2661 /// This is suitable for e.g. emitting debugging traces for the diff
2662 /// tree nodes.
2663 ///
2664 /// @return the pretty representation of the diff node.
2665 const string&
2667 {
2668  if (priv_->pretty_representation_.empty())
2669  priv_->pretty_representation_ = "empty_diff";
2670  return priv_->pretty_representation_;
2671 }
2672 
2673 /// Default implementation of the hierachy chaining virtual function.
2674 ///
2675 /// There are several types of diff nodes that have logical children
2676 /// nodes; for instance, a typedef_diff has the diff of the underlying
2677 /// type as a child node. A var_diff has the diff of the types of the
2678 /// variables as a child node, etc.
2679 ///
2680 /// But because the @ref diff base has a generic representation for
2681 /// children nodes of the all the types of @ref diff nodes (regardless
2682 /// of the specific most-derived type of diff node) that one can get
2683 /// using the method diff::children_nodes(), one need to populate that
2684 /// vector of children node.
2685 ///
2686 /// Populating that vector of children node is done by this function;
2687 /// it must be overloaded by each most-derived type of diff node that
2688 /// extends the @ref diff type.
2689 void
2691 {}
2692 
2693 // </diff stuff>
2694 
2695 // <type_diff_base stuff>
2696 
2697 type_diff_base::type_diff_base(type_base_sptr first_subject,
2698  type_base_sptr second_subject,
2699  diff_context_sptr ctxt)
2700  : diff(first_subject, second_subject, ctxt),
2701  priv_(new priv)
2702 {}
2703 
2704 type_diff_base::~type_diff_base()
2705 {}
2706 // </type_diff_base stuff>
2707 
2708 // <decl_diff_base stuff>
2709 
2710 /// Constructor of @ref decl_diff_base.
2711 ///
2712 /// @param first_subject the first subject of the diff.
2713 ///
2714 /// @param second_subject the second subject of the diff.
2715 ///
2716 /// @param ctxt the context of the diff. This object must stay alive
2717 /// at least during the life time of the current instance of @ref
2718 /// decl_diff_base, otherwise, memory corruption issues occur.
2719 decl_diff_base::decl_diff_base(decl_base_sptr first_subject,
2720  decl_base_sptr second_subject,
2721  diff_context_sptr ctxt)
2722  : diff(first_subject, second_subject, ctxt),
2723  priv_(new priv)
2724 {}
2725 
2726 decl_diff_base::~decl_diff_base()
2727 {}
2728 
2729 // </decl_diff_base stuff>
2730 
2731 // <distinct_diff stuff>
2732 
2733 /// @return a pretty representation for the @ref distinct_diff node.
2734 const string&
2736 {
2737  if (diff::priv_->pretty_representation_.empty())
2738  {
2739  std::ostringstream o;
2740  o << "distinct_diff[";
2741  if (first_subject())
2742  o << first_subject()->get_pretty_representation();
2743  else
2744  o << "null";
2745  o << ", ";
2746  if (second_subject())
2747  o << second_subject()->get_pretty_representation() ;
2748  else
2749  o << "null";
2750  o << "]" ;
2751  diff::priv_->pretty_representation_ = o.str();
2752  }
2753  return diff::priv_->pretty_representation_;
2754 }
2755 
2756 /// Populate the vector of children node of the @ref diff base type
2757 /// sub-object of this instance of @distinct_diff.
2758 ///
2759 /// The children nodes can then later be retrieved using
2760 /// diff::children_nodes().
2761 void
2763 {
2765 
2766  if (diff_sptr d = compatible_child_diff())
2767  append_child_node(d);
2768 }
2769 
2770 /// Constructor for @ref distinct_diff.
2771 ///
2772 /// Note that the two entities considered for the diff (and passed in
2773 /// parameter) must be of different kinds.
2774 ///
2775 /// @param first the first entity to consider for the diff.
2776 ///
2777 /// @param second the second entity to consider for the diff.
2778 ///
2779 /// @param ctxt the context of the diff. Note that this context
2780 /// object must stay alive at least during the life time of the
2781 /// current instance of @ref distinct_diff. Otherwise memory
2782 /// corruption issues occur.
2784  type_or_decl_base_sptr second,
2785  diff_context_sptr ctxt)
2786  : diff(first, second, ctxt),
2787  priv_(new priv)
2788 {ABG_ASSERT(entities_are_of_distinct_kinds(first, second));}
2789 
2790 /// Getter for the first subject of the diff.
2791 ///
2792 /// @return the first subject of the diff.
2795 {return first_subject();}
2796 
2797 /// Getter for the second subject of the diff.
2798 ///
2799 /// @return the second subject of the diff.
2802 {return second_subject();}
2803 
2804 /// Getter for the child diff of this distinct_diff instance.
2805 ///
2806 /// When a distinct_diff has two subjects that are different but
2807 /// compatible, then the distinct_diff instance has a child diff node
2808 /// (named the compatible child diff) that is the diff between the two
2809 /// subjects stripped from their typedefs. Otherwise, the compatible
2810 /// child diff is nul.
2811 ///
2812 /// Note that two diff subjects (that compare different) are
2813 /// considered compatible if stripping typedefs out of them makes them
2814 /// comparing equal.
2815 ///
2816 /// @return the compatible child diff node, if any. Otherwise, null.
2817 const diff_sptr
2819 {
2820  if (!priv_->compatible_child_diff)
2821  {
2822  type_base_sptr fs = strip_typedef(is_type(first())),
2823  ss = strip_typedef(is_type(second()));
2824 
2825  if (fs && ss
2827  get_type_declaration(ss)))
2828  priv_->compatible_child_diff = compute_diff(get_type_declaration(fs),
2830  context());
2831  }
2832  return priv_->compatible_child_diff;
2833 }
2834 
2835 /// Test if the two arguments are of different kind, or that are both
2836 /// NULL.
2837 ///
2838 /// @param first the first argument to test for similarity in kind.
2839 ///
2840 /// @param second the second argument to test for similarity in kind.
2841 ///
2842 /// @return true iff the two arguments are of different kind.
2843 bool
2845  type_or_decl_base_sptr second)
2846 {
2847  if (!!first != !!second)
2848  return true;
2849  if (!first && !second)
2850  // We do consider diffs of two empty decls as a diff of distinct
2851  // kinds, for now.
2852  return true;
2853  if (first == second)
2854  return false;
2855 
2856  const type_or_decl_base &f = *first, &s = *second;
2857  return typeid(f) != typeid(s);
2858 }
2859 
2860 /// @return true if the two subjects of the diff are different, false
2861 /// otherwise.
2862 bool
2864 {return first() != second();}
2865 
2866 /// @return the kind of local change carried by the current diff node.
2867 /// The value returned is zero if the current node carries no local
2868 /// change.
2869 enum change_kind
2871 {
2872  // Changes on a distinct_diff are all local.
2873  if (has_changes())
2874  return LOCAL_TYPE_CHANGE_KIND;
2875  return NO_CHANGE_KIND;
2876 }
2877 
2878 /// Emit a report about the current diff instance.
2879 ///
2880 /// @param out the output stream to send the diff report to.
2881 ///
2882 /// @param indent the indentation string to use in the report.
2883 void
2884 distinct_diff::report(ostream& out, const string& indent) const
2885 {
2886  context()->get_reporter()->report(*this, out, indent);
2887 }
2888 
2889 /// Try to diff entities that are of distinct kinds.
2890 ///
2891 /// @param first the first entity to consider for the diff.
2892 ///
2893 /// @param second the second entity to consider for the diff.
2894 ///
2895 /// @param ctxt the context of the diff.
2896 ///
2897 /// @return a non-null diff if a diff object could be built, null
2898 /// otherwise.
2901  const type_or_decl_base_sptr second,
2902  diff_context_sptr ctxt)
2903 {
2905  return distinct_diff_sptr();
2906 
2907  distinct_diff_sptr result(new distinct_diff(first, second, ctxt));
2908 
2909  ctxt->initialize_canonical_diff(result);
2910 
2911  return result;
2912 }
2913 
2914 /// </distinct_diff stuff>
2915 
2916 /// Try to compute a diff on two instances of DiffType representation.
2917 ///
2918 /// The function template performs the diff if and only if the decl
2919 /// representations are of a DiffType.
2920 ///
2921 /// @tparm DiffType the type of instances to diff.
2922 ///
2923 /// @param first the first representation of decl to consider in the
2924 /// diff computation.
2925 ///
2926 /// @param second the second representation of decl to consider in the
2927 /// diff computation.
2928 ///
2929 /// @param ctxt the diff context to use.
2930 ///
2931 ///@return the diff of the two types @p first and @p second if and
2932 ///only if they represent the parametrized type DiffType. Otherwise,
2933 ///returns a NULL pointer value.
2934 template<typename DiffType>
2935 diff_sptr
2937  const type_or_decl_base_sptr second,
2938  diff_context_sptr ctxt)
2939 {
2940  if (shared_ptr<DiffType> f =
2941  dynamic_pointer_cast<DiffType>(first))
2942  {
2943  shared_ptr<DiffType> s =
2944  dynamic_pointer_cast<DiffType>(second);
2945  if (!s)
2946  return diff_sptr();
2947  return compute_diff(f, s, ctxt);
2948  }
2949  return diff_sptr();
2950 }
2951 
2952 
2953 /// This is a specialization of @ref try_to_diff() template to diff
2954 /// instances of @ref class_decl.
2955 ///
2956 /// @param first the first representation of decl to consider in the
2957 /// diff computation.
2958 ///
2959 /// @param second the second representation of decl to consider in the
2960 /// diff computation.
2961 ///
2962 /// @param ctxt the diff context to use.
2963 template<>
2964 diff_sptr
2966  const type_or_decl_base_sptr second,
2967  diff_context_sptr ctxt)
2968 {
2969  if (class_decl_sptr f =
2970  dynamic_pointer_cast<class_decl>(first))
2971  {
2972  class_decl_sptr s = dynamic_pointer_cast<class_decl>(second);
2973  if (!s)
2974  return diff_sptr();
2975 
2976  if (f->get_is_declaration_only())
2977  {
2978  class_decl_sptr f2 =
2979  is_class_type (f->get_definition_of_declaration());
2980  if (f2)
2981  f = f2;
2982  }
2983  if (s->get_is_declaration_only())
2984  {
2985  class_decl_sptr s2 =
2986  is_class_type(s->get_definition_of_declaration());
2987  if (s2)
2988  s = s2;
2989  }
2990  return compute_diff(f, s, ctxt);
2991  }
2992  return diff_sptr();
2993 }
2994 
2995 /// Try to diff entities that are of distinct kinds.
2996 ///
2997 /// @param first the first entity to consider for the diff.
2998 ///
2999 /// @param second the second entity to consider for the diff.
3000 ///
3001 /// @param ctxt the context of the diff.
3002 ///
3003 /// @return a non-null diff if a diff object could be built, null
3004 /// otherwise.
3005 static diff_sptr
3006 try_to_diff_distinct_kinds(const type_or_decl_base_sptr first,
3007  const type_or_decl_base_sptr second,
3008  diff_context_sptr ctxt)
3009 {return compute_diff_for_distinct_kinds(first, second, ctxt);}
3010 
3011 /// Compute the difference between two types.
3012 ///
3013 /// The function considers every possible types known to libabigail
3014 /// and runs the appropriate diff function on them.
3015 ///
3016 /// Whenever a new kind of type decl is supported by abigail, if we
3017 /// want to be able to diff two instances of it, we need to update
3018 /// this function to support it.
3019 ///
3020 /// @param first the first type decl to consider for the diff
3021 ///
3022 /// @param second the second type decl to consider for the diff.
3023 ///
3024 /// @param ctxt the diff context to use.
3025 ///
3026 /// @return the resulting diff. It's a pointer to a descendent of
3027 /// abigail::comparison::diff.
3028 static diff_sptr
3029 compute_diff_for_types(const type_or_decl_base_sptr& first,
3030  const type_or_decl_base_sptr& second,
3031  const diff_context_sptr& ctxt)
3032 {
3033  type_or_decl_base_sptr f = first;
3034  type_or_decl_base_sptr s = second;
3035 
3036  diff_sptr d;
3037 
3038  ((d = try_to_diff<type_decl>(f, s, ctxt))
3039  ||(d = try_to_diff<enum_type_decl>(f, s, ctxt))
3040  ||(d = try_to_diff<union_decl>(f, s,ctxt))
3041  ||(d = try_to_diff<class_decl>(f, s,ctxt))
3042  ||(d = try_to_diff<pointer_type_def>(f, s, ctxt))
3043  ||(d = try_to_diff<reference_type_def>(f, s, ctxt))
3044  ||(d = try_to_diff<array_type_def::subrange_type>(f, s, ctxt))
3045  ||(d = try_to_diff<array_type_def>(f, s, ctxt))
3046  ||(d = try_to_diff<qualified_type_def>(f, s, ctxt))
3047  ||(d = try_to_diff<typedef_decl>(f, s, ctxt))
3048  ||(d = try_to_diff<function_type>(f, s, ctxt))
3049  ||(d = try_to_diff_distinct_kinds(f, s, ctxt)));
3050 
3051  ABG_ASSERT(d);
3052 
3053  return d;
3054 }
3055 
3058 {return static_cast<diff_category>(static_cast<unsigned>(c1)
3059  | static_cast<unsigned>(c2));}
3060 
3062 operator|=(diff_category& c1, diff_category c2)
3063 {
3064  c1 = c1 | c2;
3065  return c1;
3066 }
3067 
3069 operator&=(diff_category& c1, diff_category c2)
3070 {
3071  c1 = c1 & c2;
3072  return c1;
3073 }
3074 
3076 operator^(diff_category c1, diff_category c2)
3077 {return static_cast<diff_category>(static_cast<unsigned>(c1)
3078  ^ static_cast<unsigned>(c2));}
3079 
3082 {return static_cast<diff_category>(static_cast<unsigned>(c1)
3083  & static_cast<unsigned>(c2));}
3084 
3087 {return static_cast<diff_category>(~static_cast<unsigned>(c));}
3088 
3089 
3090 /// Getter of a bitmap made of the set of change categories that are
3091 /// considered harmless.
3092 ///
3093 /// @return the bitmap made of the set of change categories that are
3094 /// considered harmless.
3097 {
3114 }
3115 
3116 /// Getter of a bitmap made of the set of change categories that are
3117 /// considered harmful.
3118 ///
3119 /// @return the bitmap made of the set of change categories that are
3120 /// considered harmful.
3123 {
3127 }
3128 
3129 /// Serialize an instance of @ref diff_category to an output stream.
3130 ///
3131 /// @param o the output stream to serialize @p c to.
3132 ///
3133 /// @param c the instance of diff_category to serialize.
3134 ///
3135 /// @return the output stream to serialize @p c to.
3136 ostream&
3138 {
3139  bool emitted_a_category = false;
3140 
3141  if (c == NO_CHANGE_CATEGORY)
3142  {
3143  o << "NO_CHANGE_CATEGORY";
3144  emitted_a_category = true;
3145  }
3146 
3147  if (c & ACCESS_CHANGE_CATEGORY)
3148  {
3149  if (emitted_a_category)
3150  o << "|";
3151  o << "ACCESS_CHANGE_CATEGORY";
3152  emitted_a_category |= true;
3153  }
3154 
3156  {
3157  if (emitted_a_category)
3158  o << "|";
3159  o << "COMPATIBLE_TYPE_CHANGE_CATEGORY";
3160  emitted_a_category |= true;
3161  }
3162 
3164  {
3165  if (emitted_a_category)
3166  o << "|";
3167  o << "HARMLESS_DECL_NAME_CHANGE_CATEGORY";
3168  emitted_a_category |= true;
3169  }
3170 
3172  {
3173  if (emitted_a_category)
3174  o << "|";
3175  o << "NON_VIRT_MEM_FUN_CHANGE_CATEGORY";
3176  emitted_a_category |= true;
3177  }
3178 
3180  {
3181  if (emitted_a_category)
3182  o << "|";
3183  o << "STATIC_DATA_MEMBER_CHANGE_CATEGORY";
3184  emitted_a_category |= true;
3185  }
3186 
3188  {
3189  if (emitted_a_category)
3190  o << "|";
3191  o << "HARMLESS_ENUM_CHANGE_CATEGORY";
3192  emitted_a_category |= true;
3193  }
3194 
3196  {
3197  if (emitted_a_category)
3198  o << "|";
3199  o << "HARMLESS_DATA_MEMBER_CHANGE_CATEGORY";
3200  emitted_a_category |= true;
3201  }
3202 
3204  {
3205  if (emitted_a_category)
3206  o << "|";
3207  o << "HARMLESS_SYMBOL_ALIAS_CHANGE_CATEGORY";
3208  emitted_a_category |= true;
3209  }
3210 
3212  {
3213  if (emitted_a_category)
3214  o << "|";
3215  o << "HARMLESS_UNION_CHANGE_CATEGORY";
3216  emitted_a_category |= true;
3217  }
3218 
3219  if (c & SUPPRESSED_CATEGORY)
3220  {
3221  if (emitted_a_category)
3222  o << "|";
3223  o << "SUPPRESSED_CATEGORY";
3224  emitted_a_category |= true;
3225  }
3226 
3227  if (c & PRIVATE_TYPE_CATEGORY)
3228  {
3229  if (emitted_a_category)
3230  o << "|";
3231  o << "PRIVATE_TYPE_CATEGORY";
3232  emitted_a_category |= true;
3233  }
3234 
3236  {
3237  if (emitted_a_category)
3238  o << "|";
3239  o << "SIZE_OR_OFFSET_CHANGE_CATEGORY";
3240  emitted_a_category |= true;
3241  }
3242 
3244  {
3245  if (emitted_a_category)
3246  o << "|";
3247  o << "VIRTUAL_MEMBER_CHANGE_CATEGORY";
3248  emitted_a_category |= true;
3249  }
3250 
3251  if (c & REDUNDANT_CATEGORY)
3252  {
3253  if (emitted_a_category)
3254  o << "|";
3255  o << "REDUNDANT_CATEGORY";
3256  emitted_a_category |= true;
3257  }
3258 
3260  {
3261  if (emitted_a_category)
3262  o << "|";
3263  o << "TYPE_DECL_ONLY_DEF_CHANGE_CATEGORY";
3264  emitted_a_category |= true;
3265  }
3266 
3268  {
3269  if (emitted_a_category)
3270  o << "|";
3271  o << "FN_PARM_TYPE_TOP_CV_CHANGE_CATEGORY";
3272  emitted_a_category |= true;
3273  }
3274 
3276  {
3277  if (emitted_a_category)
3278  o << "|";
3279  o << "FN_PARM_TYPE_CV_CHANGE_CATEGORY";
3280  emitted_a_category |= true;
3281  }
3282 
3284  {
3285  if (emitted_a_category)
3286  o << "|";
3287  o << "FN_RETURN_TYPE_CV_CHANGE_CATEGORY";
3288  emitted_a_category |= true;
3289  }
3290 
3292  {
3293  if (emitted_a_category)
3294  o << "|";
3295  o << "FN_PARM_ADD_REMOVE_CHANGE_CATEGORY";
3296  emitted_a_category |= true;
3297  }
3298 
3300  {
3301  if (emitted_a_category)
3302  o << "|";
3303  o << "VAR_TYPE_CV_CHANGE_CATEGORY";
3304  emitted_a_category |= true;
3305  }
3306 
3308  {
3309  if (emitted_a_category)
3310  o << "|";
3311  o << "VOID_PTR_TO_PTR_CHANGE_CATEGORY";
3312  emitted_a_category |= true;
3313  }
3314 
3316  {
3317  if (emitted_a_category)
3318  o << "|";
3319  o << "BENIGN_INFINITE_ARRAY_CHANGE_CATEGORY";
3320  emitted_a_category |= true;
3321  }
3322 
3324  {
3325  if (emitted_a_category)
3326  o << "|";
3327  o << "HAS_ALLOWED_CHANGE_CATEGORY";
3328  emitted_a_category |= true;
3329  }
3330 
3332  {
3333  if (emitted_a_category)
3334  o << "|";
3335  o << "HAS_DESCENDANT_WITH_ALLOWED_CHANGE_CATEGORY";
3336  emitted_a_category |= true;
3337  }
3338 
3340  {
3341  if (emitted_a_category)
3342  o << "|";
3343  o << "HAS_PARENT_WITH_ALLOWED_CHANGE_CATEGORY";
3344  emitted_a_category |= true;
3345  }
3346 
3347  return o;
3348 }
3349 
3350 /// Compute the difference between two decls.
3351 ///
3352 /// The function consider every possible decls known to libabigail and
3353 /// runs the appropriate diff function on them.
3354 ///
3355 /// Whenever a new kind of non-type decl is supported by abigail, if
3356 /// we want to be able to diff two instances of it, we need to update
3357 /// this function to support it.
3358 ///
3359 /// @param first the first decl to consider for the diff
3360 ///
3361 /// @param second the second decl to consider for the diff.
3362 ///
3363 /// @param ctxt the diff context to use.
3364 ///
3365 /// @return the resulting diff.
3366 static diff_sptr
3367 compute_diff_for_decls(const decl_base_sptr first,
3368  const decl_base_sptr second,
3369  diff_context_sptr ctxt)
3370 {
3371 
3372  diff_sptr d;
3373 
3374  ((d = try_to_diff<function_decl>(first, second, ctxt))
3375  || (d = try_to_diff<var_decl>(first, second, ctxt))
3376  || (d = try_to_diff_distinct_kinds(first, second, ctxt)));
3377 
3378  ABG_ASSERT(d);
3379 
3380  return d;
3381 }
3382 
3383 /// Compute the difference between two decls. The decls can represent
3384 /// either type declarations, or non-type declaration.
3385 ///
3386 /// Note that the two decls must have been created in the same @ref
3387 /// environment, otherwise, this function aborts.
3388 ///
3389 /// @param first the first decl to consider.
3390 ///
3391 /// @param second the second decl to consider.
3392 ///
3393 /// @param ctxt the diff context to use.
3394 ///
3395 /// @return the resulting diff, or NULL if the diff could not be
3396 /// computed.
3397 diff_sptr
3398 compute_diff(const decl_base_sptr first,
3399  const decl_base_sptr second,
3400  diff_context_sptr ctxt)
3401 {
3402  if (!first || !second)
3403  return diff_sptr();
3404 
3405  diff_sptr d;
3406  if (is_type(first) && is_type(second))
3407  d = compute_diff_for_types(first, second, ctxt);
3408  else
3409  d = compute_diff_for_decls(first, second, ctxt);
3410  ABG_ASSERT(d);
3411  return d;
3412 }
3413 
3414 /// Compute the difference between two types.
3415 ///
3416 /// Note that the two types must have been created in the same @ref
3417 /// environment, otherwise, this function aborts.
3418 ///
3419 /// @param first the first type to consider.
3420 ///
3421 /// @param second the second type to consider.
3422 ///
3423 /// @param ctxt the diff context to use.
3424 ///
3425 /// @return the resulting diff, or NULL if the diff couldn't be
3426 /// computed.
3427 diff_sptr
3428 compute_diff(const type_base_sptr first,
3429  const type_base_sptr second,
3430  diff_context_sptr ctxt)
3431 {
3432  decl_base_sptr f = get_type_declaration(first),
3433  s = get_type_declaration(second);
3434 
3435  diff_sptr d = compute_diff_for_types(f,s, ctxt);
3436  ABG_ASSERT(d);
3437  return d;
3438 }
3439 
3440 /// Get a copy of the pretty representation of a diff node.
3441 ///
3442 /// @param d the diff node to consider.
3443 ///
3444 /// @return the pretty representation string.
3445 string
3447 {
3448  if (!d)
3449  return "";
3450  string prefix= "diff of ";
3451  return prefix + get_pretty_representation(d->first_subject());
3452 }
3453 
3454 // <var_diff stuff>
3455 
3456 /// Populate the vector of children node of the @ref diff base type
3457 /// sub-object of this instance of @ref var_diff.
3458 ///
3459 /// The children node can then later be retrieved using
3460 /// diff::children_node().
3461 void
3464 
3465 /// @return the pretty representation for this current instance of
3466 /// @ref var_diff.
3467 const string&
3469 {
3470  if (diff::priv_->pretty_representation_.empty())
3471  {
3472  std::ostringstream o;
3473  o << "var_diff["
3474  << first_subject()->get_pretty_representation()
3475  << ", "
3476  << second_subject()->get_pretty_representation()
3477  << "]";
3478  diff::priv_->pretty_representation_ = o.str();
3479  }
3480  return diff::priv_->pretty_representation_;
3481 }
3482 /// Constructor for @ref var_diff.
3483 ///
3484 /// @param first the first instance of @ref var_decl to consider in
3485 /// the diff.
3486 ///
3487 /// @param second the second instance of @ref var_decl to consider in
3488 /// the diff.
3489 ///
3490 /// @param type_diff the diff between types of the instances of
3491 /// var_decl.
3492 ///
3493 /// @param ctxt the diff context to use.
3495  var_decl_sptr second,
3496  diff_sptr type_diff,
3497  diff_context_sptr ctxt)
3498  : decl_diff_base(first, second, ctxt),
3499  priv_(new priv)
3500 {priv_->type_diff_ = type_diff;}
3501 
3502 /// Getter for the first @ref var_decl of the diff.
3503 ///
3504 /// @return the first @ref var_decl of the diff.
3507 {return dynamic_pointer_cast<var_decl>(first_subject());}
3508 
3509 /// Getter for the second @ref var_decl of the diff.
3510 ///
3511 /// @return the second @ref var_decl of the diff.
3514 {return dynamic_pointer_cast<var_decl>(second_subject());}
3515 
3516 /// Getter for the diff of the types of the instances of @ref
3517 /// var_decl.
3518 ///
3519 /// @return the diff of the types of the instances of @ref var_decl.
3520 diff_sptr
3522 {
3523  if (diff_sptr result = priv_->type_diff_.lock())
3524  return result;
3525  else
3526  {
3527  result = compute_diff(first_var()->get_type(),
3528  second_var()->get_type(),
3529  context());
3530  context()->keep_diff_alive(result);
3531  priv_->type_diff_ = result;
3532  return result;
3533  }
3534 }
3535 
3536 /// Return true iff the diff node has a change.
3537 ///
3538 /// @return true iff the diff node has a change.
3539 bool
3541 {return *first_var() != *second_var();}
3542 
3543 /// @return the kind of local change carried by the current diff node.
3544 /// The value returned is zero if the current node carries no local
3545 /// change.
3546 enum change_kind
3548 {
3549  ir::change_kind k = ir::NO_CHANGE_KIND;
3550  if (!equals(*first_var(), *second_var(), &k))
3551  return k & ir::ALL_LOCAL_CHANGES_MASK;
3552  return ir::NO_CHANGE_KIND;
3553 }
3554 
3555 /// Report the diff in a serialized form.
3556 ///
3557 /// @param out the stream to serialize the diff to.
3558 ///
3559 /// @param indent the prefix to use for the indentation of this
3560 /// serialization.
3561 void
3562 var_diff::report(ostream& out, const string& indent) const
3563 {
3564  context()->get_reporter()->report(*this, out, indent);
3565 }
3566 
3567 /// Compute the diff between two instances of @ref var_decl.
3568 ///
3569 /// Note that the two decls must have been created in the same @ref
3570 /// environment, otherwise, this function aborts.
3571 ///
3572 /// @param first the first @ref var_decl to consider for the diff.
3573 ///
3574 /// @param second the second @ref var_decl to consider for the diff.
3575 ///
3576 /// @param ctxt the diff context to use.
3577 ///
3578 /// @return the resulting diff between the two @ref var_decl.
3581  const var_decl_sptr second,
3582  diff_context_sptr ctxt)
3583 {
3584  var_diff_sptr d(new var_diff(first, second, diff_sptr(), ctxt));
3585  ctxt->initialize_canonical_diff(d);
3586 
3587  return d;
3588 }
3589 
3590 // </var_diff stuff>
3591 
3592 // <pointer_type_def stuff>
3593 
3594 /// Populate the vector of children node of the @ref diff base type
3595 /// sub-object of this instance of @ref pointer_diff.
3596 ///
3597 /// The children node can then later be retrieved using
3598 /// diff::children_node().
3599 void
3602 
3603 /// Constructor for a pointer_diff.
3604 ///
3605 /// @param first the first pointer to consider for the diff.
3606 ///
3607 /// @param second the secon pointer to consider for the diff.
3608 ///
3609 /// @param ctxt the diff context to use.
3611  pointer_type_def_sptr second,
3612  diff_sptr underlying,
3613  diff_context_sptr ctxt)
3614  : type_diff_base(first, second, ctxt),
3615  priv_(new priv(underlying))
3616 {}
3617 
3618 /// Getter for the first subject of a pointer diff
3619 ///
3620 /// @return the first pointer considered in this pointer diff.
3623 {return dynamic_pointer_cast<pointer_type_def>(first_subject());}
3624 
3625 /// Getter for the second subject of a pointer diff
3626 ///
3627 /// @return the second pointer considered in this pointer diff.
3630 {return dynamic_pointer_cast<pointer_type_def>(second_subject());}
3631 
3632 /// @return the pretty represenation for the current instance of @ref
3633 /// pointer_diff.
3634 const string&
3636 {
3637  if (diff::priv_->pretty_representation_.empty())
3638  {
3639  std::ostringstream o;
3640  o << "pointer_diff["
3641  << first_subject()->get_pretty_representation()
3642  << ", "
3643  << second_subject()->get_pretty_representation()
3644  << "]";
3645  diff::priv_->pretty_representation_ = o.str();
3646  }
3647  return diff::priv_->pretty_representation_;
3648 }
3649 
3650 /// Return true iff the current diff node carries a change.
3651 ///
3652 /// @return true iff the current diff node carries a change.
3653 bool
3655 {return first_pointer() != second_pointer();}
3656 
3657 /// @return the kind of local change carried by the current diff node.
3658 /// The value returned is zero if the current node carries no local
3659 /// change.
3660 enum change_kind
3662 {
3663  ir::change_kind k = ir::NO_CHANGE_KIND;
3664  if (!equals(*first_pointer(), *second_pointer(), &k))
3665  return k & ir::ALL_LOCAL_CHANGES_MASK;
3666  return ir::NO_CHANGE_KIND;
3667 }
3668 
3669 /// Getter for the diff between the pointed-to types of the pointers
3670 /// of this diff.
3671 ///
3672 /// @return the diff between the pointed-to types.
3673 diff_sptr
3675 {return priv_->underlying_type_diff_;}
3676 
3677 /// Setter for the diff between the pointed-to types of the pointers
3678 /// of this diff.
3679 ///
3680 /// @param d the new diff between the pointed-to types of the pointers
3681 /// of this diff.
3682 void
3684 {priv_->underlying_type_diff_ = d;}
3685 
3686 /// Report the diff in a serialized form.
3687 ///
3688 /// @param out the stream to serialize the diff to.
3689 ///
3690 /// @param indent the prefix to use for the indentation of this
3691 /// serialization.
3692 void
3693 pointer_diff::report(ostream& out, const string& indent) const
3694 {
3695  context()->get_reporter()->report(*this, out, indent);
3696 }
3697 
3698 /// Compute the diff between between two pointers.
3699 ///
3700 /// Note that the two types must have been created in the same @ref
3701 /// environment, otherwise, this function aborts.
3702 ///
3703 /// @param first the pointer to consider for the diff.
3704 ///
3705 /// @param second the pointer to consider for the diff.
3706 ///
3707 /// @return the resulting diff between the two pointers.
3708 ///
3709 /// @param ctxt the diff context to use.
3712  pointer_type_def_sptr second,
3713  diff_context_sptr ctxt)
3714 {
3715  diff_sptr d = compute_diff_for_types(first->get_pointed_to_type(),
3716  second->get_pointed_to_type(),
3717  ctxt);
3718  pointer_diff_sptr result(new pointer_diff(first, second, d, ctxt));
3719  ctxt->initialize_canonical_diff(result);
3720 
3721  return result;
3722 }
3723 
3724 // </pointer_type_def>
3725 
3726 // <subrange_diff >
3727 
3728 /// Constructor of the @ref subrange_diff diff node type.
3729 ///
3730 /// @param first the first subrange type to consider for the diff.
3731 ///
3732 /// @param second the second subrange type to consider for the diff.
3733 ///
3734 /// @param underlying_type_diff the underlying type diff between @p
3735 /// first and @p second.
3736 ///
3737 /// @param ctxt the diff context to use.
3740  const array_type_def::subrange_sptr& second,
3741  const diff_sptr& underlying_type_diff,
3742  const diff_context_sptr ctxt)
3743  : type_diff_base(first, second, ctxt),
3744  priv_(new priv(underlying_type_diff))
3745 {}
3746 
3747 
3748 /// Getter of the first subrange of the current instance @ref
3749 /// subrange_diff.
3750 ///
3751 /// @return The first subrange of the current instance @ref subrange_diff.
3754 {return is_subrange_type(first_subject());}
3755 
3756 /// Getter of the second subrange of the current instance @ref
3757 /// subrange_diff.
3758 ///
3759 /// @return The second subrange of the current instance @ref
3760 /// subrange_diff.
3763 {return is_subrange_type(second_subject());}
3764 
3765 /// Getter of the diff node of the underlying types of the current
3766 /// @ref subrange_diff diff node.
3767 ///
3768 /// @return The diff node of the underlying types of the current @ref
3769 /// subrange_diff diff node.
3770 const diff_sptr
3772 {return priv_->underlying_type_diff_;}
3773 
3774 /// Getter the pretty representation of the @ref subrange_diff diff
3775 /// node.
3776 ///
3777 /// @return The pretty representation of the @ref subrange_diff diff node.
3778 const string&
3780 {
3781  if (diff::priv_->pretty_representation_.empty())
3782  {
3783  std::ostringstream o;
3784  o << "subrange_diff["
3785  << first_subject()->get_pretty_representation()
3786  << ","
3787  << second_subject()->get_pretty_representation()
3788  << "]";
3789  diff::priv_->pretty_representation_ = o.str();
3790  }
3791  return diff::priv_->pretty_representation_;
3792 }
3793 
3794 /// Test if the current @ref subrange_diff node carries any change.
3795 ///
3796 /// @return true iff the current @ref subrange_diff node carries any
3797 /// change.
3798 bool
3800 {return *first_subrange() != *second_subrange();}
3801 
3802 /// Test if the current @ref subrange_diff node carries any local
3803 /// change.
3804 ///
3805 /// @return true iff the current @ref subrange_diff node carries any
3806 /// local change.
3807 enum change_kind
3809 {
3810  ir::change_kind k = ir::NO_CHANGE_KIND;
3811  if (!equals(*first_subrange(), *second_subrange(), &k))
3812  return k & ir::ALL_LOCAL_CHANGES_MASK;
3813  return ir::NO_CHANGE_KIND;
3814 }
3815 
3816 /// Report about the changes carried by this node.
3817 ///
3818 /// @param out the output stream to send the report to.
3819 ///
3820 /// @param indent the indentation string to use.
3821 void
3822 subrange_diff::report(ostream& out, const string& indent) const
3823 {context()->get_reporter()->report(*this, out, indent);}
3824 
3825 /// Populate the vector of children node of the @ref diff base type
3826 /// sub-object of this instance of @ref subrange_diff.
3827 ///
3828 /// The children node can then later be retrieved using
3829 /// diff::children_node().
3830 void
3833 
3834 /// Compute the diff between two instances of @ref subrange_diff.
3835 ///
3836 /// Note that the two decls must have been created in the same @ref
3837 /// environment, otherwise, this function aborts.
3838 ///
3839 /// @param first the first @ref subrange_diff to consider for the diff.
3840 ///
3841 /// @param second the second @ref subrange_diff to consider for the diff.
3842 ///
3843 /// @param ctxt the diff context to use.
3844 ///
3845 /// @return the resulting diff between the two @ref subrange_diff.
3849  diff_context_sptr ctxt)
3850 {
3851  diff_sptr d = compute_diff_for_types(first->get_underlying_type(),
3852  second->get_underlying_type(),
3853  ctxt);
3854 
3855  subrange_diff_sptr result(new subrange_diff(first, second, d, ctxt));
3856  ctxt->initialize_canonical_diff(result);
3857  return result;
3858 }
3859 
3860 //</subrange_diff >
3861 
3862 
3863 // <array_type_def>
3864 
3865 /// Populate the vector of children node of the @ref diff base type
3866 /// sub-object of this instance of @ref array_diff.
3867 ///
3868 /// The children node can then later be retrieved using
3869 /// diff::children_node().
3870 void
3873 
3874 /// Constructor for array_diff
3875 ///
3876 /// @param first the first array_type of the diff.
3877 ///
3878 /// @param second the second array_type of the diff.
3879 ///
3880 /// @param element_type_diff the diff between the two array element
3881 /// types.
3882 ///
3883 /// @param ctxt the diff context to use.
3885  const array_type_def_sptr second,
3886  diff_sptr element_type_diff,
3887  diff_context_sptr ctxt)
3888  : type_diff_base(first, second, ctxt),
3889  priv_(new priv(element_type_diff))
3890 {}
3891 
3892 /// Getter for the first array of the diff.
3893 ///
3894 /// @return the first array of the diff.
3895 const array_type_def_sptr
3897 {return dynamic_pointer_cast<array_type_def>(first_subject());}
3898 
3899 /// Getter for the second array of the diff.
3900 ///
3901 /// @return for the second array of the diff.
3902 const array_type_def_sptr
3904 {return dynamic_pointer_cast<array_type_def>(second_subject());}
3905 
3906 /// Getter for the diff between the two types of array elements.
3907 ///
3908 /// @return the diff between the two types of array elements.
3909 const diff_sptr&
3911 {return priv_->element_type_diff_;}
3912 
3913 /// Setter for the diff between the two array element types.
3914 ///
3915 /// @param d the new diff betweend the two array element types.
3916 void
3918 {priv_->element_type_diff_ = d;}
3919 
3920 /// @return the pretty representation for the current instance of @ref
3921 /// array_diff.
3922 const string&
3924 {
3925  if (diff::priv_->pretty_representation_.empty())
3926  {
3927  std::ostringstream o;
3928  o << "array_diff["
3929  << first_subject()->get_pretty_representation()
3930  << ", "
3931  << second_subject()->get_pretty_representation()
3932  << "]";
3933  diff::priv_->pretty_representation_ = o.str();
3934  }
3935  return diff::priv_->pretty_representation_;
3936 }
3937 
3938 /// Return true iff the current diff node carries a change.
3939 ///
3940 /// @return true iff the current diff node carries a change.
3941 bool
3943 {
3944  bool l = false;
3945 
3946  // the array element types match check for differing dimensions
3947  // etc...
3949  f = dynamic_pointer_cast<array_type_def>(first_subject()),
3950  s = dynamic_pointer_cast<array_type_def>(second_subject());
3951 
3952  if (f->get_name() != s->get_name())
3953  l |= true;
3954  if (f->get_size_in_bits() != s->get_size_in_bits())
3955  l |= true;
3956  if (f->get_alignment_in_bits() != s->get_alignment_in_bits())
3957  l |= true;
3958 
3959  l |= element_type_diff()
3960  ? element_type_diff()->has_changes()
3961  : false;
3962 
3963  return l;
3964 }
3965 
3966 
3967 /// @return the kind of local change carried by the current diff node.
3968 /// The value returned is zero if the current node carries no local
3969 /// change.
3970 enum change_kind
3972 {
3973  ir::change_kind k = ir::NO_CHANGE_KIND;
3974  if (!equals(*first_array(), *second_array(), &k))
3975  return k & ir::ALL_LOCAL_CHANGES_MASK;
3976  return ir::NO_CHANGE_KIND;
3977 }
3978 
3979 /// Report the diff in a serialized form.
3980 ///
3981 /// @param out the output stream to serialize the dif to.
3982 ///
3983 /// @param indent the string to use for indenting the report.
3984 void
3985 array_diff::report(ostream& out, const string& indent) const
3986 {
3987  context()->get_reporter()->report(*this, out, indent);
3988 }
3989 
3990 /// Compute the diff between two arrays.
3991 ///
3992 /// Note that the two types must have been created in the same @ref
3993 /// environment, otherwise, this function aborts.
3994 ///
3995 /// @param first the first array to consider for the diff.
3996 ///
3997 /// @param second the second array to consider for the diff.
3998 ///
3999 /// @param ctxt the diff context to use.
4002  array_type_def_sptr second,
4003  diff_context_sptr ctxt)
4004 {
4005  diff_sptr d = compute_diff_for_types(first->get_element_type(),
4006  second->get_element_type(),
4007  ctxt);
4008  array_diff_sptr result(new array_diff(first, second, d, ctxt));
4009  ctxt->initialize_canonical_diff(result);
4010  return result;
4011 }
4012 // </array_type_def>
4013 
4014 // <reference_type_def>
4015 
4016 /// Populate the vector of children node of the @ref diff base type
4017 /// sub-object of this instance of @ref reference_diff.
4018 ///
4019 /// The children node can then later be retrieved using
4020 /// diff::children_node().
4021 void
4024 
4025 /// Constructor for reference_diff
4026 ///
4027 /// @param first the first reference_type of the diff.
4028 ///
4029 /// @param second the second reference_type of the diff.
4030 ///
4031 /// @param ctxt the diff context to use.
4033  const reference_type_def_sptr second,
4034  diff_sptr underlying,
4035  diff_context_sptr ctxt)
4036  : type_diff_base(first, second, ctxt),
4037  priv_(new priv(underlying))
4038 {}
4039 
4040 /// Getter for the first reference of the diff.
4041 ///
4042 /// @return the first reference of the diff.
4045 {return dynamic_pointer_cast<reference_type_def>(first_subject());}
4046 
4047 /// Getter for the second reference of the diff.
4048 ///
4049 /// @return for the second reference of the diff.
4052 {return dynamic_pointer_cast<reference_type_def>(second_subject());}
4053 
4054 
4055 /// Getter for the diff between the two referred-to types.
4056 ///
4057 /// @return the diff between the two referred-to types.
4058 const diff_sptr&
4060 {return priv_->underlying_type_diff_;}
4061 
4062 /// Setter for the diff between the two referred-to types.
4063 ///
4064 /// @param d the new diff betweend the two referred-to types.
4065 diff_sptr&
4067 {
4068  priv_->underlying_type_diff_ = d;
4069  return priv_->underlying_type_diff_;
4070 }
4071 
4072 /// @return the pretty representation for the current instance of @ref
4073 /// reference_diff.
4074 const string&
4076 {
4077  if (diff::priv_->pretty_representation_.empty())
4078  {
4079  std::ostringstream o;
4080  o << "reference_diff["
4081  << first_subject()->get_pretty_representation()
4082  << ", "
4083  << second_subject()->get_pretty_representation()
4084  << "]";
4085  diff::priv_->pretty_representation_ = o.str();
4086  }
4087  return diff::priv_->pretty_representation_;
4088 }
4089 
4090 /// Return true iff the current diff node carries a change.
4091 ///
4092 /// @return true iff the current diff node carries a change.
4093 bool
4095 {
4096  return first_reference() != second_reference();
4097 }
4098 
4099 /// @return the kind of local change carried by the current diff node.
4100 /// The value returned is zero if the current node carries no local
4101 /// change.
4102 enum change_kind
4104 {
4105  ir::change_kind k = ir::NO_CHANGE_KIND;
4106  if (!equals(*first_reference(), *second_reference(), &k))
4107  return k & ir::ALL_LOCAL_CHANGES_MASK;
4108  return ir::NO_CHANGE_KIND;
4109 }
4110 
4111 /// Report the diff in a serialized form.
4112 ///
4113 /// @param out the output stream to serialize the dif to.
4114 ///
4115 /// @param indent the string to use for indenting the report.
4116 void
4117 reference_diff::report(ostream& out, const string& indent) const
4118 {
4119  context()->get_reporter()->report(*this, out, indent);
4120 }
4121 
4122 /// Compute the diff between two references.
4123 ///
4124 /// Note that the two types must have been created in the same @ref
4125 /// environment, otherwise, this function aborts.
4126 ///
4127 /// @param first the first reference to consider for the diff.
4128 ///
4129 /// @param second the second reference to consider for the diff.
4130 ///
4131 /// @param ctxt the diff context to use.
4134  reference_type_def_sptr second,
4135  diff_context_sptr ctxt)
4136 {
4137  diff_sptr d = compute_diff_for_types(first->get_pointed_to_type(),
4138  second->get_pointed_to_type(),
4139  ctxt);
4140  reference_diff_sptr result(new reference_diff(first, second, d, ctxt));
4141  ctxt->initialize_canonical_diff(result);
4142  return result;
4143 }
4144 // </reference_type_def>
4145 
4146 // <qualified_type_diff stuff>
4147 
4148 /// Populate the vector of children node of the @ref diff base type
4149 /// sub-object of this instance of @ref qualified_type_diff.
4150 ///
4151 /// The children node can then later be retrieved using
4152 /// diff::children_node().
4153 void
4156 
4157 /// Constructor for qualified_type_diff.
4158 ///
4159 /// @param first the first qualified type of the diff.
4160 ///
4161 /// @param second the second qualified type of the diff.
4162 ///
4163 /// @param ctxt the diff context to use.
4164 qualified_type_diff::qualified_type_diff(qualified_type_def_sptr first,
4165  qualified_type_def_sptr second,
4166  diff_sptr under,
4167  diff_context_sptr ctxt)
4168  : type_diff_base(first, second, ctxt),
4169  priv_(new priv(under))
4170 {}
4171 
4172 /// Getter for the first qualified type of the diff.
4173 ///
4174 /// @return the first qualified type of the diff.
4175 const qualified_type_def_sptr
4177 {return dynamic_pointer_cast<qualified_type_def>(first_subject());}
4178 
4179 /// Getter for the second qualified type of the diff.
4180 ///
4181 /// @return the second qualified type of the diff.
4182 const qualified_type_def_sptr
4184 {return dynamic_pointer_cast<qualified_type_def>(second_subject());}
4185 
4186 /// Getter for the diff between the underlying types of the two
4187 /// qualified types.
4188 ///
4189 /// @return the diff between the underlying types of the two qualified
4190 /// types.
4191 diff_sptr
4193 {return priv_->underlying_type_diff;}
4194 
4195 /// Getter for the diff between the most underlying non-qualified
4196 /// types of two qualified types.
4197 ///
4198 /// @return the diff between the most underlying non-qualified types
4199 /// of two qualified types.
4200 diff_sptr
4202 {
4203  if (!priv_->leaf_underlying_type_diff)
4204  priv_->leaf_underlying_type_diff
4205  = compute_diff_for_types(get_leaf_type(first_qualified_type()),
4207  context());
4208 
4209  return priv_->leaf_underlying_type_diff;
4210 }
4211 
4212 /// Setter for the diff between the underlying types of the two
4213 /// qualified types.
4214 ///
4215 /// @return the diff between the underlying types of the two qualified
4216 /// types.
4217 void
4219 {priv_->underlying_type_diff = d;}
4220 
4221 /// @return the pretty representation of the current instance of @ref
4222 /// qualified_type_diff.
4223 const string&
4225 {
4226  if (diff::priv_->pretty_representation_.empty())
4227  {
4228  std::ostringstream o;
4229  o << "qualified_type_diff["
4230  << first_subject()->get_pretty_representation()
4231  << ", "
4232  << second_subject()->get_pretty_representation()
4233  << "]";
4234  diff::priv_->pretty_representation_ = o.str();
4235  }
4236  return diff::priv_->pretty_representation_;
4237 }
4238 
4239 /// Return true iff the current diff node carries a change.
4240 ///
4241 /// @return true iff the current diff node carries a change.
4242 bool
4245 
4246 /// @return the kind of local change carried by the current diff node.
4247 /// The value returned is zero if the current node carries no local
4248 /// change.
4249 enum change_kind
4251 {
4252  ir::change_kind k = ir::NO_CHANGE_KIND;
4254  return k & ir::ALL_LOCAL_CHANGES_MASK;
4255  return ir::NO_CHANGE_KIND;
4256 }
4257 
4258 /// Report the diff in a serialized form.
4259 ///
4260 /// @param out the output stream to serialize to.
4261 ///
4262 /// @param indent the string to use to indent the lines of the report.
4263 void
4264 qualified_type_diff::report(ostream& out, const string& indent) const
4265 {
4266  context()->get_reporter()->report(*this, out, indent);
4267 }
4268 
4269 /// Compute the diff between two qualified types.
4270 ///
4271 /// Note that the two types must have been created in the same @ref
4272 /// environment, otherwise, this function aborts.
4273 ///
4274 /// @param first the first qualified type to consider for the diff.
4275 ///
4276 /// @param second the second qualified type to consider for the diff.
4277 ///
4278 /// @param ctxt the diff context to use.
4279 qualified_type_diff_sptr
4280 compute_diff(const qualified_type_def_sptr first,
4281  const qualified_type_def_sptr second,
4282  diff_context_sptr ctxt)
4283 {
4284  diff_sptr d = compute_diff_for_types(first->get_underlying_type(),
4285  second->get_underlying_type(),
4286  ctxt);
4287  qualified_type_diff_sptr result(new qualified_type_diff(first, second,
4288  d, ctxt));
4289  ctxt->initialize_canonical_diff(result);
4290  return result;
4291 }
4292 
4293 // </qualified_type_diff stuff>
4294 
4295 // <enum_diff stuff>
4296 
4297 /// Clear the lookup tables useful for reporting an enum_diff.
4298 ///
4299 /// This function must be updated each time a lookup table is added or
4300 /// removed from the class_diff::priv.
4301 void
4302 enum_diff::clear_lookup_tables()
4303 {
4304  priv_->deleted_enumerators_.clear();
4305  priv_->inserted_enumerators_.clear();
4306  priv_->changed_enumerators_.clear();
4307 }
4308 
4309 /// Tests if the lookup tables are empty.
4310 ///
4311 /// @return true if the lookup tables are empty, false otherwise.
4312 bool
4313 enum_diff::lookup_tables_empty() const
4314 {
4315  return (priv_->deleted_enumerators_.empty()
4316  && priv_->inserted_enumerators_.empty()
4317  && priv_->changed_enumerators_.empty());
4318 }
4319 
4320 /// If the lookup tables are not yet built, walk the differences and
4321 /// fill the lookup tables.
4322 void
4323 enum_diff::ensure_lookup_tables_populated()
4324 {
4325  if (!lookup_tables_empty())
4326  return;
4327 
4328  {
4329  edit_script e = priv_->enumerators_changes_;
4330 
4331  for (vector<deletion>::const_iterator it = e.deletions().begin();
4332  it != e.deletions().end();
4333  ++it)
4334  {
4335  unsigned i = it->index();
4336  const enum_type_decl::enumerator& n =
4337  first_enum()->get_enumerators()[i];
4338  const string& name = n.get_name();
4339  ABG_ASSERT(priv_->deleted_enumerators_.find(n.get_name())
4340  == priv_->deleted_enumerators_.end());
4341  priv_->deleted_enumerators_[name] = n;
4342  }
4343 
4344  for (vector<insertion>::const_iterator it = e.insertions().begin();
4345  it != e.insertions().end();
4346  ++it)
4347  {
4348  for (vector<unsigned>::const_iterator iit =
4349  it->inserted_indexes().begin();
4350  iit != it->inserted_indexes().end();
4351  ++iit)
4352  {
4353  unsigned i = *iit;
4354  const enum_type_decl::enumerator& n =
4355  second_enum()->get_enumerators()[i];
4356  const string& name = n.get_name();
4357  ABG_ASSERT(priv_->inserted_enumerators_.find(n.get_name())
4358  == priv_->inserted_enumerators_.end());
4359  string_enumerator_map::const_iterator j =
4360  priv_->deleted_enumerators_.find(name);
4361  if (j == priv_->deleted_enumerators_.end())
4362  priv_->inserted_enumerators_[name] = n;
4363  else
4364  {
4365  if (j->second != n)
4366  priv_->changed_enumerators_[j->first] =
4367  std::make_pair(j->second, n);
4368  priv_->deleted_enumerators_.erase(j);
4369  }
4370  }
4371  }
4372  }
4373 }
4374 
4375 /// Populate the vector of children node of the @ref diff base type
4376 /// sub-object of this instance of @ref enum_diff.
4377 ///
4378 /// The children node can then later be retrieved using
4379 /// diff::children_node().
4380 void
4383 
4384 /// Constructor for enum_diff.
4385 ///
4386 /// @param first the first enum type of the diff.
4387 ///
4388 /// @param second the second enum type of the diff.
4389 ///
4390 /// @param underlying_type_diff the diff of the two underlying types
4391 /// of the two enum types.
4392 ///
4393 /// @param ctxt the diff context to use.
4395  const enum_type_decl_sptr second,
4396  const diff_sptr underlying_type_diff,
4397  const diff_context_sptr ctxt)
4398  : type_diff_base(first, second, ctxt),
4399  priv_(new priv(underlying_type_diff))
4400 {}
4401 
4402 /// @return the first enum of the diff.
4403 const enum_type_decl_sptr
4405 {return dynamic_pointer_cast<enum_type_decl>(first_subject());}
4406 
4407 /// @return the second enum of the diff.
4408 const enum_type_decl_sptr
4410 {return dynamic_pointer_cast<enum_type_decl>(second_subject());}
4411 
4412 /// @return the diff of the two underlying enum types.
4413 diff_sptr
4415 {return priv_->underlying_type_diff_;}
4416 
4417 /// @return a map of the enumerators that were deleted.
4418 const string_enumerator_map&
4420 {return priv_->deleted_enumerators_;}
4421 
4422 /// @return a map of the enumerators that were inserted
4423 const string_enumerator_map&
4425 {return priv_->inserted_enumerators_;}
4426 
4427 /// @return a map of the enumerators that were changed
4430 {return priv_->changed_enumerators_;}
4431 
4432 /// @return the pretty representation of the current instance of @ref
4433 /// enum_diff.
4434 const string&
4436 {
4437  if (diff::priv_->pretty_representation_.empty())
4438  {
4439  std::ostringstream o;
4440  o << "enum_diff["
4441  << first_subject()->get_pretty_representation()
4442  << ", "
4443  << second_subject()->get_pretty_representation()
4444  << "]";
4445  diff::priv_->pretty_representation_ = o.str();
4446  }
4447  return diff::priv_->pretty_representation_;
4448 }
4449 
4450 /// Return true iff the current diff node carries a change.
4451 ///
4452 /// @return true iff the current diff node carries a change.
4453 bool
4455 {return first_enum() != second_enum();}
4456 
4457 /// @return the kind of local change carried by the current diff node.
4458 /// The value returned is zero if the current node carries no local
4459 /// change.
4460 enum change_kind
4462 {
4463  ir::change_kind k = ir::NO_CHANGE_KIND;
4464  if (!equals(*first_enum(), *second_enum(), &k))
4465  return k & ir::ALL_LOCAL_CHANGES_MASK;
4466  return ir::NO_CHANGE_KIND;
4467 }
4468 
4469 /// Report the differences between the two enums.
4470 ///
4471 /// @param out the output stream to send the report to.
4472 ///
4473 /// @param indent the string to use for indentation.
4474 void
4475 enum_diff::report(ostream& out, const string& indent) const
4476 {
4477  context()->get_reporter()->report(*this, out, indent);
4478 }
4479 
4480 /// Compute the set of changes between two instances of @ref
4481 /// enum_type_decl.
4482 ///
4483 /// Note that the two types must have been created in the same @ref
4484 /// environment, otherwise, this function aborts.
4485 ///
4486 /// @param first a pointer to the first enum_type_decl to consider.
4487 ///
4488 /// @param second a pointer to the second enum_type_decl to consider.
4489 ///
4490 /// @return the resulting diff of the two enums @p first and @p
4491 /// second.
4492 ///
4493 /// @param ctxt the diff context to use.
4494 enum_diff_sptr
4496  const enum_type_decl_sptr second,
4497  diff_context_sptr ctxt)
4498 {
4499  diff_sptr ud = compute_diff_for_types(first->get_underlying_type(),
4500  second->get_underlying_type(),
4501  ctxt);
4502  enum_diff_sptr d(new enum_diff(first, second, ud, ctxt));
4503  if (first != second)
4504  {
4505  compute_diff(first->get_enumerators().begin(),
4506  first->get_enumerators().end(),
4507  second->get_enumerators().begin(),
4508  second->get_enumerators().end(),
4509  d->priv_->enumerators_changes_);
4510  d->ensure_lookup_tables_populated();
4511  }
4512  ctxt->initialize_canonical_diff(d);
4513 
4514  return d;
4515 }
4516 // </enum_diff stuff>
4517 
4518 // <class_or_union_diff stuff>
4519 
4520 /// Test if the current diff node carries a member type change for a
4521 /// member type which name is the same as the name of a given type
4522 /// declaration.
4523 ///
4524 /// @param d the type declaration which name should be equal to the
4525 /// name of the member type that might have changed.
4526 ///
4527 /// @return the member type that has changed, iff there were a member
4528 /// type (which name is the same as the name of @p d) that changed.
4529 /// Note that the member type that is returned is the new value of the
4530 /// member type that changed.
4533 {
4534  string qname = d->get_qualified_name();
4535  string_diff_sptr_map::const_iterator it =
4536  changed_member_types_.find(qname);
4537 
4538  return ((it == changed_member_types_.end())
4540  : it->second->second_subject());
4541 }
4542 
4543 /// Test if the current diff node carries a data member change for a
4544 /// data member which name is the same as the name of a given type
4545 /// declaration.
4546 ///
4547 /// @param d the type declaration which name should be equal to the
4548 /// name of the data member that might have changed.
4549 ///
4550 /// @return the data member that has changed, iff there were a data
4551 /// member type (which name is the same as the name of @p d) that
4552 /// changed. Note that the data member that is returned is the new
4553 /// value of the data member that changed.
4554 decl_base_sptr
4556 {
4557  string qname = d->get_qualified_name();
4558  string_var_diff_sptr_map::const_iterator it =
4559  subtype_changed_dm_.find(qname);
4560 
4561  if (it == subtype_changed_dm_.end())
4562  return decl_base_sptr();
4563  return it->second->second_var();
4564 }
4565 
4566 /// Test if the current diff node carries a member class template
4567 /// change for a member class template which name is the same as the
4568 /// name of a given type declaration.
4569 ///
4570 /// @param d the type declaration which name should be equal to the
4571 /// name of the member class template that might have changed.
4572 ///
4573 /// @return the member class template that has changed, iff there were
4574 /// a member class template (which name is the same as the name of @p
4575 /// d) that changed. Note that the member class template that is
4576 /// returned is the new value of the member class template that
4577 /// changed.
4578 decl_base_sptr
4580 {
4581  string qname = d->get_qualified_name();
4582  string_diff_sptr_map::const_iterator it =
4583  changed_member_class_tmpls_.find(qname);
4584 
4585  return ((it == changed_member_class_tmpls_.end())
4586  ? decl_base_sptr()
4587  : dynamic_pointer_cast<decl_base>(it->second->second_subject()));
4588 }
4589 
4590 /// Get the number of non static data members that were deleted.
4591 ///
4592 /// @return the number of non static data members that were deleted.
4593 size_t
4595 {
4596  size_t result = 0;
4597 
4598  for (string_decl_base_sptr_map::const_iterator i =
4599  deleted_data_members_.begin();
4600  i != deleted_data_members_.end();
4601  ++i)
4602  if (is_member_decl(i->second)
4603  && !get_member_is_static(i->second))
4604  ++result;
4605 
4606  return result;
4607 }
4608 
4609 /// Get the number of non static data members that were inserted.
4610 ///
4611 /// @return the number of non static data members that were inserted.
4612 size_t
4614 {
4615  size_t result = 0;
4616 
4617  for (string_decl_base_sptr_map::const_iterator i =
4618  inserted_data_members_.begin();
4619  i != inserted_data_members_.end();
4620  ++i)
4621  if (is_member_decl(i->second)
4622  && !get_member_is_static(i->second))
4623  ++result;
4624 
4625  return result;
4626 }
4627 
4628 /// Get the number of data member sub-type changes carried by the
4629 /// current diff node that were filtered out.
4630 ///
4631 /// @param local_only if true, it means that only (filtered) local
4632 /// changes are considered.
4633 ///
4634 /// @return the number of data member sub-type changes carried by the
4635 /// current diff node that were filtered out.
4636 size_t
4638 {
4639  size_t num_filtered= 0;
4640  for (var_diff_sptrs_type::const_iterator i =
4641  sorted_subtype_changed_dm_.begin();
4642  i != sorted_subtype_changed_dm_.end();
4643  ++i)
4644  {
4645  if (local_only)
4646  {
4647  if ((*i)->has_changes()
4648  && !(*i)->has_local_changes_to_be_reported())
4649  ++num_filtered;
4650  }
4651  else
4652  {
4653  if ((*i)->is_filtered_out())
4654  ++num_filtered;
4655  }
4656  }
4657  return num_filtered;
4658 }
4659 
4660 /// Get the number of data member changes carried by the current diff
4661 /// node that were filtered out.
4662 ///
4663 /// @param local_only if true, it means that only (filtered) local
4664 /// changes are considered.
4665 ///
4666 /// @return the number of data member changes carried by the current
4667 /// diff node that were filtered out.
4668 size_t
4670 {
4671  size_t num_filtered= 0;
4672 
4673  for (unsigned_var_diff_sptr_map::const_iterator i = changed_dm_.begin();
4674  i != changed_dm_.end();
4675  ++i)
4676  {
4677  diff_sptr diff = i->second;
4678  if (local_only)
4679  {
4680  if ((diff->has_changes() && !diff->has_local_changes_to_be_reported())
4681  || diff->is_filtered_out())
4682  ++num_filtered;
4683  }
4684  else
4685  {
4686  if (diff->is_filtered_out())
4687  ++num_filtered;
4688  }
4689  }
4690  return num_filtered;
4691 }
4692 
4693 /// Skip the processing of the current member function if its
4694 /// virtual-ness is disallowed by the user.
4695 ///
4696 /// This is to be used in the member functions below that are used to
4697 /// count the number of filtered inserted, deleted and changed member
4698 /// functions.
4699 #define SKIP_MEM_FN_IF_VIRTUALITY_DISALLOWED \
4700  do { \
4701  if (get_member_function_is_virtual(f) \
4702  || get_member_function_is_virtual(s)) \
4703  { \
4704  if (!(allowed_category | VIRTUAL_MEMBER_CHANGE_CATEGORY)) \
4705  continue; \
4706  } \
4707  else \
4708  { \
4709  if (!(allowed_category | NON_VIRT_MEM_FUN_CHANGE_CATEGORY)) \
4710  continue; \
4711  } \
4712  } while (false)
4713 
4714 /// Get the number of member functions changes carried by the current
4715 /// diff node that were filtered out.
4716 ///
4717 /// @return the number of member functions changes carried by the
4718 /// current diff node that were filtered out.
4719 size_t
4721 (const diff_context_sptr& ctxt)
4722 {
4723  size_t count = 0;
4724  diff_category allowed_category = ctxt->get_allowed_category();
4725 
4726  for (function_decl_diff_sptrs_type::const_iterator i =
4727  sorted_changed_member_functions_.begin();
4728  i != sorted_changed_member_functions_.end();
4729  ++i)
4730  {
4731  method_decl_sptr f =
4732  dynamic_pointer_cast<method_decl>
4733  ((*i)->first_function_decl());
4734  ABG_ASSERT(f);
4735 
4736  method_decl_sptr s =
4737  dynamic_pointer_cast<method_decl>
4738  ((*i)->second_function_decl());
4739  ABG_ASSERT(s);
4740 
4742 
4743  diff_sptr diff = *i;
4744  ctxt->maybe_apply_filters(diff);
4745 
4746  if (diff->is_filtered_out())
4747  ++count;
4748  }
4749 
4750  return count;
4751 }
4752 
4753 /// Get the number of member functions insertions carried by the current
4754 /// diff node that were filtered out.
4755 ///
4756 /// @return the number of member functions insertions carried by the
4757 /// current diff node that were filtered out.
4758 size_t
4760 (const diff_context_sptr& ctxt)
4761 {
4762  size_t count = 0;
4763  diff_category allowed_category = ctxt->get_allowed_category();
4764 
4765  for (string_member_function_sptr_map::const_iterator i =
4766  inserted_member_functions_.begin();
4767  i != inserted_member_functions_.end();
4768  ++i)
4769  {
4770  method_decl_sptr f = i->second,
4771  s = i->second;
4772 
4774 
4775  diff_sptr diff = compute_diff_for_decls(f, s, ctxt);
4776  ctxt->maybe_apply_filters(diff);
4777 
4778  if (diff->get_category() != NO_CHANGE_CATEGORY
4779  && diff->is_filtered_out())
4780  ++count;
4781  }
4782 
4783  return count;
4784 }
4785 
4786 /// Get the number of member functions deletions carried by the current
4787 /// diff node that were filtered out.
4788 ///
4789 /// @return the number of member functions deletions carried by the
4790 /// current diff node that were filtered out.
4791 size_t
4793 (const diff_context_sptr& ctxt)
4794 {
4795  size_t count = 0;
4796  diff_category allowed_category = ctxt->get_allowed_category();
4797 
4798  for (string_member_function_sptr_map::const_iterator i =
4799  deleted_member_functions_.begin();
4800  i != deleted_member_functions_.end();
4801  ++i)
4802  {
4803  method_decl_sptr f = i->second,
4804  s = i->second;
4805 
4807 
4808  diff_sptr diff = compute_diff_for_decls(f, s, ctxt);
4809  ctxt->maybe_apply_filters(diff);
4810 
4811  if (diff->get_category() != NO_CHANGE_CATEGORY
4812  && diff->is_filtered_out())
4813  ++count;
4814  }
4815 
4816  return count;
4817 }
4818 
4819 /// Clear the lookup tables useful for reporting.
4820 ///
4821 /// This function must be updated each time a lookup table is added or
4822 /// removed from the class_or_union_diff::priv.
4823 void
4825 {
4826  priv_->deleted_member_types_.clear();
4827  priv_->inserted_member_types_.clear();
4828  priv_->changed_member_types_.clear();
4829  priv_->deleted_data_members_.clear();
4830  priv_->inserted_data_members_.clear();
4831  priv_->subtype_changed_dm_.clear();
4832  priv_->deleted_member_functions_.clear();
4833  priv_->inserted_member_functions_.clear();
4834  priv_->changed_member_functions_.clear();
4835  priv_->deleted_member_class_tmpls_.clear();
4836  priv_->inserted_member_class_tmpls_.clear();
4837  priv_->changed_member_class_tmpls_.clear();
4838 }
4839 
4840 /// Tests if the lookup tables are empty.
4841 ///
4842 /// @return true if the lookup tables are empty, false otherwise.
4843 bool
4845 {
4846  return (priv_->deleted_member_types_.empty()
4847  && priv_->inserted_member_types_.empty()
4848  && priv_->changed_member_types_.empty()
4849  && priv_->deleted_data_members_.empty()
4850  && priv_->inserted_data_members_.empty()
4851  && priv_->subtype_changed_dm_.empty()
4852  && priv_->inserted_member_functions_.empty()
4853  && priv_->deleted_member_functions_.empty()
4854  && priv_->changed_member_functions_.empty()
4855  && priv_->deleted_member_class_tmpls_.empty()
4856  && priv_->inserted_member_class_tmpls_.empty()
4857  && priv_->changed_member_class_tmpls_.empty());
4858 }
4859 
4860 /// If the lookup tables are not yet built, walk the differences and
4861 /// fill them.
4862 void
4864 {
4865  {
4866  edit_script& e = priv_->member_types_changes_;
4867 
4868  for (vector<deletion>::const_iterator it = e.deletions().begin();
4869  it != e.deletions().end();
4870  ++it)
4871  {
4872  unsigned i = it->index();
4873  decl_base_sptr d =
4874  get_type_declaration(first_class_or_union()->get_member_types()[i]);
4875  class_or_union_sptr record_type = is_class_or_union_type(d);
4876  if (record_type && record_type->get_is_declaration_only())
4877  continue;
4878  string name = d->get_name();
4879  priv_->deleted_member_types_[name] = d;
4880  }
4881 
4882  for (vector<insertion>::const_iterator it = e.insertions().begin();
4883  it != e.insertions().end();
4884  ++it)
4885  {
4886  for (vector<unsigned>::const_iterator iit =
4887  it->inserted_indexes().begin();
4888  iit != it->inserted_indexes().end();
4889  ++iit)
4890  {
4891  unsigned i = *iit;
4892  decl_base_sptr d =
4893  get_type_declaration(second_class_or_union()->get_member_types()[i]);
4894  class_or_union_sptr record_type = is_class_or_union_type(d);
4895  if (record_type && record_type->get_is_declaration_only())
4896  continue;
4897  string name = d->get_name();
4898  string_decl_base_sptr_map::const_iterator j =
4899  priv_->deleted_member_types_.find(name);
4900  if (j != priv_->deleted_member_types_.end())
4901  {
4902  if (*j->second != *d)
4903  priv_->changed_member_types_[name] =
4904  compute_diff(j->second, d, context());
4905 
4906  priv_->deleted_member_types_.erase(j);
4907  }
4908  else
4909  priv_->inserted_member_types_[name] = d;
4910  }
4911  }
4912  }
4913 
4914  {
4915  edit_script& e = priv_->data_members_changes_;
4916 
4917  for (vector<deletion>::const_iterator it = e.deletions().begin();
4918  it != e.deletions().end();
4919  ++it)
4920  {
4921  unsigned i = it->index();
4922  var_decl_sptr data_member =
4923  is_var_decl(first_class_or_union()->get_non_static_data_members()[i]);
4924  string name = data_member->get_anon_dm_reliable_name();
4925 
4926  ABG_ASSERT(priv_->deleted_data_members_.find(name)
4927  == priv_->deleted_data_members_.end());
4928  priv_->deleted_data_members_[name] = data_member;
4929  }
4930 
4931  for (vector<insertion>::const_iterator it = e.insertions().begin();
4932  it != e.insertions().end();
4933  ++it)
4934  {
4935  for (vector<unsigned>::const_iterator iit =
4936  it->inserted_indexes().begin();
4937  iit != it->inserted_indexes().end();
4938  ++iit)
4939  {
4940  unsigned i = *iit;
4941  decl_base_sptr d =
4942  second_class_or_union()->get_non_static_data_members()[i];
4943  var_decl_sptr added_dm = is_var_decl(d);
4944  string name = added_dm->get_anon_dm_reliable_name();
4945  ABG_ASSERT(priv_->inserted_data_members_.find(name)
4946  == priv_->inserted_data_members_.end());
4947 
4948  bool ignore_added_anonymous_data_member = false;
4949  if (is_anonymous_data_member(added_dm))
4950  {
4951  //
4952  // Handle insertion of anonymous data member to
4953  // replace existing data members.
4954  //
4955  // For instance consider this:
4956  // struct S
4957  // {
4958  // int a;
4959  // int b;
4960  // int c;
4961  // };// end struct S
4962  //
4963  // Where the data members 'a' and 'b' are replaced
4964  // by an anonymous data member without changing the
4965  // effective bit layout of the structure:
4966  //
4967  // struct S
4968  // {
4969  // struct
4970  // {
4971  // union
4972  // {
4973  // int a;
4974  // char a_1;
4975  // };
4976  // union
4977  // {
4978  // int b;
4979  // char b_1;
4980  // };
4981  // };
4982  // int c;
4983  // }; // end struct S
4984  //
4985  var_decl_sptr replaced_dm, replacing_dm;
4986  bool added_anon_dm_changes_dm = false;
4987  // The vector of data members replaced by anonymous
4988  // data members.
4989  vector<var_decl_sptr> dms_replaced_by_anon_dm;
4990 
4991  //
4992  // Let's start collecting the set of data members
4993  // which have been replaced by anonymous types in a
4994  // harmless way. These are going to be collected into
4995  // dms_replaced_by_anon_dm and, ultimately, into
4996  // priv_->dms_replaced_by_adms_
4997  //
4998  for (string_decl_base_sptr_map::const_iterator it =
4999  priv_->deleted_data_members_.begin();
5000  it != priv_->deleted_data_members_.end();
5001  ++it)
5002  {
5003  // We don't support this pattern for anonymous
5004  // data members themselves being replaced. If
5005  // that occurs then we'll just report it verbatim.
5006  if (is_anonymous_data_member(it->second))
5007  continue;
5008 
5009  string deleted_dm_name = it->second->get_name();
5010  if ((replacing_dm =
5012  deleted_dm_name)))
5013  {
5014  // So it looks like replacing_dm might have
5015  // replaced the data member which name is
5016  // 'deleted_dm_name'. Let's look deeper to be
5017  // sure.
5018  //
5019  // Note that replacing_dm is part (member) of
5020  // an anonymous data member that might replace
5021  // replaced_dm.
5022 
5023  // So let's get that replaced data member.
5024  replaced_dm = is_var_decl(it->second);
5025  size_t replaced_dm_offset =
5026  get_data_member_offset(replaced_dm),
5027  replacing_dm_offset =
5028  get_absolute_data_member_offset(replacing_dm);
5029 
5030  if (replaced_dm_offset != replacing_dm_offset)
5031  {
5032  // So the replacing data member and the
5033  // replaced data member don't have the
5034  // same offset. This is not the pattern we
5035  // are looking for. Rather, it looks like
5036  // the anonymous data member has *changed*
5037  // the data member.
5038  added_anon_dm_changes_dm = true;
5039  break;
5040  }
5041 
5042  if (replaced_dm->get_type()->get_size_in_bits()
5043  == replaced_dm->get_type()->get_size_in_bits())
5044  dms_replaced_by_anon_dm.push_back(replaced_dm);
5045  else
5046  {
5047  added_anon_dm_changes_dm = true;
5048  break;
5049  }
5050  }
5051  }
5052 
5053  // Now walk dms_replaced_by_anon_dm to fill up
5054  // priv_->dms_replaced_by_adms_ with the set of data
5055  // members replaced by anonymous data members.
5056  if (!added_anon_dm_changes_dm
5057  && !dms_replaced_by_anon_dm.empty())
5058  {
5059  // See if the added data member isn't too big.
5060  type_base_sptr added_dm_type = added_dm->get_type();
5061  ABG_ASSERT(added_dm_type);
5062  var_decl_sptr new_next_dm =
5064  added_dm);
5065  var_decl_sptr old_next_dm =
5066  first_class_or_union()->find_data_member(new_next_dm);
5067 
5068  if (!old_next_dm
5069  || (old_next_dm
5070  && (get_absolute_data_member_offset(old_next_dm)
5071  == get_absolute_data_member_offset(new_next_dm))))
5072  {
5073  // None of the data members that are replaced
5074  // by the added union should be considered as
5075  // having been deleted.
5076  ignore_added_anonymous_data_member = true;
5077  for (vector<var_decl_sptr>::const_iterator i =
5078  dms_replaced_by_anon_dm.begin();
5079  i != dms_replaced_by_anon_dm.end();
5080  ++i)
5081  {
5082  string n = (*i)->get_name();
5083  priv_->dms_replaced_by_adms_[n] =
5084  added_dm;
5085  priv_->deleted_data_members_.erase(n);
5086  }
5087  }
5088  }
5089  }
5090 
5091  if (!ignore_added_anonymous_data_member)
5092  {
5093  // Detect changed data members.
5094  //
5095  // A changed data member (that we shall name D) is a data
5096  // member that satisfies the conditions below:
5097  //
5098  // 1/ It must have been added.
5099  //
5100  // 2/ It must have been deleted as well.
5101  //
5102  // 3/ It there must be a non-empty difference between the
5103  // deleted D and the added D.
5104  string_decl_base_sptr_map::const_iterator j =
5105  priv_->deleted_data_members_.find(name);
5106  if (j != priv_->deleted_data_members_.end())
5107  {
5108  if (*j->second != *d)
5109  {
5110  var_decl_sptr old_dm = is_var_decl(j->second);
5111  priv_->subtype_changed_dm_[name]=
5112  compute_diff(old_dm, added_dm, context());
5113  }
5114  priv_->deleted_data_members_.erase(j);
5115  }
5116  else
5117  priv_->inserted_data_members_[name] = d;
5118  }
5119  }
5120  }
5121 
5122  // Now detect when a data member is deleted from offset N and
5123  // another one is added to offset N. In that case, we want to be
5124  // able to say that the data member at offset N changed.
5125  for (string_decl_base_sptr_map::const_iterator i =
5126  priv_->deleted_data_members_.begin();
5127  i != priv_->deleted_data_members_.end();
5128  ++i)
5129  {
5130  unsigned offset = get_data_member_offset(i->second);
5131  priv_->deleted_dm_by_offset_[offset] = i->second;
5132  }
5133 
5134  for (string_decl_base_sptr_map::const_iterator i =
5135  priv_->inserted_data_members_.begin();
5136  i != priv_->inserted_data_members_.end();
5137  ++i)
5138  {
5139  unsigned offset = get_data_member_offset(i->second);
5140  priv_->inserted_dm_by_offset_[offset] = i->second;
5141  }
5142 
5143  for (unsigned_decl_base_sptr_map::const_iterator i =
5144  priv_->inserted_dm_by_offset_.begin();
5145  i != priv_->inserted_dm_by_offset_.end();
5146  ++i)
5147  {
5148  unsigned_decl_base_sptr_map::const_iterator j =
5149  priv_->deleted_dm_by_offset_.find(i->first);
5150  if (j != priv_->deleted_dm_by_offset_.end())
5151  {
5152  var_decl_sptr old_dm = is_var_decl(j->second);
5153  var_decl_sptr new_dm = is_var_decl(i->second);
5154  priv_->changed_dm_[i->first] =
5155  compute_diff(old_dm, new_dm, context());
5156  }
5157  }
5158 
5159  for (unsigned_var_diff_sptr_map::const_iterator i =
5160  priv_->changed_dm_.begin();
5161  i != priv_->changed_dm_.end();
5162  ++i)
5163  {
5164  priv_->deleted_dm_by_offset_.erase(i->first);
5165  priv_->inserted_dm_by_offset_.erase(i->first);
5166  priv_->deleted_data_members_.erase
5167  (i->second->first_var()->get_anon_dm_reliable_name());
5168  priv_->inserted_data_members_.erase
5169  (i->second->second_var()->get_anon_dm_reliable_name());
5170  }
5171  }
5172  sort_string_data_member_diff_sptr_map(priv_->subtype_changed_dm_,
5173  priv_->sorted_subtype_changed_dm_);
5174  sort_unsigned_data_member_diff_sptr_map(priv_->changed_dm_,
5175  priv_->sorted_changed_dm_);
5176 
5177  {
5178  edit_script& e = priv_->member_class_tmpls_changes_;
5179 
5180  for (vector<deletion>::const_iterator it = e.deletions().begin();
5181  it != e.deletions().end();
5182  ++it)
5183  {
5184  unsigned i = it->index();
5185  decl_base_sptr d =
5186  first_class_or_union()->get_member_class_templates()[i]->
5187  as_class_tdecl();
5188  string name = d->get_name();
5189  ABG_ASSERT(priv_->deleted_member_class_tmpls_.find(name)
5190  == priv_->deleted_member_class_tmpls_.end());
5191  priv_->deleted_member_class_tmpls_[name] = d;
5192  }
5193 
5194  for (vector<insertion>::const_iterator it = e.insertions().begin();
5195  it != e.insertions().end();
5196  ++it)
5197  {
5198  for (vector<unsigned>::const_iterator iit =
5199  it->inserted_indexes().begin();
5200  iit != it->inserted_indexes().end();
5201  ++iit)
5202  {
5203  unsigned i = *iit;
5204  decl_base_sptr d =
5205  second_class_or_union()->get_member_class_templates()[i]->
5206  as_class_tdecl();
5207  string name = d->get_name();
5208  ABG_ASSERT(priv_->inserted_member_class_tmpls_.find(name)
5209  == priv_->inserted_member_class_tmpls_.end());
5210  string_decl_base_sptr_map::const_iterator j =
5211  priv_->deleted_member_class_tmpls_.find(name);
5212  if (j != priv_->deleted_member_class_tmpls_.end())
5213  {
5214  if (*j->second != *d)
5215  priv_->changed_member_types_[name]=
5216  compute_diff(j->second, d, context());
5217  priv_->deleted_member_class_tmpls_.erase(j);
5218  }
5219  else
5220  priv_->inserted_member_class_tmpls_[name] = d;
5221  }
5222  }
5223  }
5224  sort_string_diff_sptr_map(priv_->changed_member_types_,
5225  priv_->sorted_changed_member_types_);
5226 }
5227 
5228 /// Allocate the memory for the priv_ pimpl data member of the @ref
5229 /// class_or_union_diff class.
5230 void
5232 {
5233  if (!priv_)
5234  priv_.reset(new priv);
5235 }
5236 
5237 /// Constructor for the @ref class_or_union_diff class.
5238 ///
5239 /// @param first_scope the first @ref class_or_union of the diff node.
5240 ///
5241 /// @param second_scope the second @ref class_or_union of the diff node.
5242 ///
5243 /// @param ctxt the context of the diff.
5244 class_or_union_diff::class_or_union_diff(class_or_union_sptr first_scope,
5245  class_or_union_sptr second_scope,
5246  diff_context_sptr ctxt)
5247  : type_diff_base(first_scope, second_scope, ctxt)
5248  //priv_(new priv)
5249 {}
5250 
5251 /// Getter of the private data of the @ref class_or_union_diff type.
5252 ///
5253 /// Note that due to an optimization, the private data of @ref
5254 /// class_or_union_diff can be shared among several instances of
5255 /// class_or_union_diff, so you should never try to access
5256 /// class_or_union_diff::priv directly.
5257 ///
5258 /// When class_or_union_diff::priv is shared, this function returns
5259 /// the correct shared one.
5260 ///
5261 /// @return the (possibly) shared private data of the current instance
5262 /// of @ref class_or_union_diff.
5263 const class_or_union_diff::priv_ptr&
5265 {
5266  if (priv_)
5267  return priv_;
5268 
5269  // If the current class_or_union_diff::priv member is empty, then look for
5270  // the shared one, from the canonical type.
5271  class_or_union_diff *canonical =
5272  dynamic_cast<class_or_union_diff*>(get_canonical_diff());
5273  ABG_ASSERT(canonical);
5274  ABG_ASSERT(canonical->priv_);
5275 
5276  return canonical->priv_;
5277 }
5278 
5279 /// Destructor of class_or_union_diff.
5281 {
5282 }
5283 
5284 /// @return the first @ref class_or_union involved in the diff.
5285 class_or_union_sptr
5288 
5289 /// @return the second @ref class_or_union involved in the diff.
5290 class_or_union_sptr
5293 
5294 /// @return the edit script of the member types of the two @ref
5295 /// class_or_union.
5296 const edit_script&
5298 {return get_priv()->member_types_changes_;}
5299 
5300 /// @return the edit script of the member types of the two @ref
5301 /// class_or_union.
5302 edit_script&
5304 {return get_priv()->member_types_changes_;}
5305 
5306 /// @return the edit script of the data members of the two @ref
5307 /// class_or_union.
5308 const edit_script&
5310 {return get_priv()->data_members_changes_;}
5311 
5312 /// @return the edit script of the data members of the two @ref
5313 /// class_or_union.
5314 edit_script&
5316 {return get_priv()->data_members_changes_;}
5317 
5318 /// Getter for the data members that got inserted.
5319 ///
5320 /// @return a map of data members that got inserted.
5323 {return get_priv()->inserted_data_members_;}
5324 
5325 /// Getter for the data members that got deleted.
5326 ///
5327 /// @return a map of data members that got deleted.
5330 {return get_priv()->deleted_data_members_;}
5331 
5332 /// @return the edit script of the member functions of the two @ref
5333 /// class_or_union.
5334 const edit_script&
5336 {return get_priv()->member_fns_changes_;}
5337 
5338 /// Getter for the virtual members functions that have had a change in
5339 /// a sub-type, without having a change in their symbol name.
5340 ///
5341 /// @return a sorted vector of virtual member functions that have a
5342 /// sub-type change.
5345 {return get_priv()->sorted_changed_member_functions_;}
5346 
5347 /// @return the edit script of the member functions of the two
5348 /// classes.
5349 edit_script&
5351 {return get_priv()->member_fns_changes_;}
5352 
5353 /// @return a map of member functions that got deleted.
5356 {return get_priv()->deleted_member_functions_;}
5357 
5358 /// @return a map of member functions that got inserted.
5361 {return get_priv()->inserted_member_functions_;}
5362 
5363 /// Getter of the map of data members that got replaced by another
5364 /// data member. The key of the map is the offset at which the
5365 /// element got replaced and the value is a pointer to the @ref
5366 /// var_diff representing the replacement of the data member.
5367 ///
5368 /// @return sorted vector of changed data member.
5371 {return get_priv()->changed_dm_;}
5372 
5373 /// Getter of the sorted vector of data members that got replaced by
5374 /// another data member.
5375 ///
5376 /// @return sorted vector of changed data member.
5377 const var_diff_sptrs_type&
5379 {return get_priv()->sorted_changed_dm_;}
5380 
5381 /// Count the number of /filtered/ data members that got replaced by
5382 /// another data member.
5383 ///
5384 /// @return the number of changed data member that got filtered out.
5385 size_t
5387 {return get_priv()->count_filtered_changed_dm(local);}
5388 
5389 /// Getter of the sorted vector of data members with a (sub-)type change.
5390 ///
5391 /// @return sorted vector of changed data member.
5392 const var_diff_sptrs_type&
5394 {return get_priv()->sorted_subtype_changed_dm_;}
5395 
5396 /// Count the number of /filtered/ data members with a sub-type change.
5397 ///
5398 /// @return the number of changed data member that got filtered out.
5399 size_t
5401 {return get_priv()->count_filtered_subtype_changed_dm(local);}
5402 
5403 /// Get the map of data members that got replaced by anonymous data
5404 /// members.
5405 ///
5406 /// The key of a map entry is the name of the replaced data member and
5407 /// the value is the anonymous data member that replaces it.
5408 ///
5409 /// @return the map of data members replaced by anonymous data
5410 /// members.
5413 {return get_priv()->dms_replaced_by_adms_;}
5414 
5415 /// Get an ordered vector of of data members that got replaced by
5416 /// anonymous data members.
5417 ///
5418 /// This returns a vector of pair of two data members: the one that
5419 /// was replaced, and the anonymous data member that replaced it.
5420 ///
5421 /// @return the sorted vector data members replaced by anonymous data members.
5424 {
5425  if (priv_->dms_replaced_by_adms_ordered_.empty())
5426  {
5427  for (string_decl_base_sptr_map::const_iterator it =
5428  priv_->dms_replaced_by_adms_.begin();
5429  it != priv_->dms_replaced_by_adms_.end();
5430  ++it)
5431  {
5432  const var_decl_sptr dm =
5433  first_class_or_union()->find_data_member(it->first);
5434  ABG_ASSERT(dm);
5435  changed_var_sptr changed_dm(dm, is_data_member(it->second));
5436  priv_->dms_replaced_by_adms_ordered_.push_back(changed_dm);
5437  }
5438  sort_changed_data_members(priv_->dms_replaced_by_adms_ordered_);
5439  }
5440 
5441  return priv_->dms_replaced_by_adms_ordered_;
5442 }
5443 
5444 /// @return the edit script of the member function templates of the two
5445 /// @ref class_or_union.
5446 const edit_script&
5448 {return get_priv()->member_fn_tmpls_changes_;}
5449 
5450 /// @return the edit script of the member function templates of the
5451 /// two @ref class_or_union.
5452 edit_script&
5454 {return get_priv()->member_fn_tmpls_changes_;}
5455 
5456 /// @return the edit script of the member class templates of the two
5457 /// @ref class_or_union.
5458 const edit_script&
5460 {return get_priv()->member_class_tmpls_changes_;}
5461 
5462 /// @return the edit script of the member class templates of the two
5463 /// @ref class_or_union.
5464 edit_script&
5466 {return get_priv()->member_class_tmpls_changes_;}
5467 
5468 /// Test if the current diff node carries a change.
5469 bool
5472 
5473 /// @return the kind of local change carried by the current diff node.
5474 /// The value returned is zero if the current node carries no local
5475 /// change.
5476 enum change_kind
5478 {
5479  ir::change_kind k = ir::NO_CHANGE_KIND;
5481  return k & ir::ALL_LOCAL_CHANGES_MASK;
5482  return ir::NO_CHANGE_KIND;
5483 }
5484 
5485 
5486 /// Report the changes carried by the current @ref class_or_union_diff
5487 /// node in a textual format.
5488 ///
5489 /// @param out the output stream to write the textual report to.
5490 ///
5491 /// @param indent the number of white space to use as indentation.
5492 void
5493 class_or_union_diff::report(ostream& out, const string& indent) const
5494 {
5495  context()->get_reporter()->report(*this, out, indent);
5496 }
5497 
5498 /// Populate the vector of children node of the @ref diff base type
5499 /// sub-object of this instance of @ref class_or_union_diff.
5500 ///
5501 /// The children node can then later be retrieved using
5502 /// diff::children_node().
5503 void
5505 {
5506  // data member changes
5507  for (var_diff_sptrs_type::const_iterator i =
5508  get_priv()->sorted_subtype_changed_dm_.begin();
5509  i != get_priv()->sorted_subtype_changed_dm_.end();
5510  ++i)
5511  if (diff_sptr d = *i)
5512  append_child_node(d);
5513 
5514  for (var_diff_sptrs_type::const_iterator i =
5515  get_priv()->sorted_changed_dm_.begin();
5516  i != get_priv()->sorted_changed_dm_.end();
5517  ++i)
5518  if (diff_sptr d = *i)
5519  append_child_node(d);
5520 
5521  // member types changes
5522  for (diff_sptrs_type::const_iterator i =
5523  get_priv()->sorted_changed_member_types_.begin();
5524  i != get_priv()->sorted_changed_member_types_.end();
5525  ++i)
5526  if (diff_sptr d = *i)
5527  append_child_node(d);
5528 
5529  // member function changes
5530  for (function_decl_diff_sptrs_type::const_iterator i =
5531  get_priv()->sorted_changed_member_functions_.begin();
5532  i != get_priv()->sorted_changed_member_functions_.end();
5533  ++i)
5534  if (diff_sptr d = *i)
5535  append_child_node(d);
5536 }
5537 
5538 // </class_or_union_diff stuff>
5539 
5540 //<class_diff stuff>
5541 
5542 /// Clear the lookup tables useful for reporting.
5543 ///
5544 /// This function must be updated each time a lookup table is added or
5545 /// removed from the class_diff::priv.
5546 void
5547 class_diff::clear_lookup_tables(void)
5548 {
5549  priv_->deleted_bases_.clear();
5550  priv_->inserted_bases_.clear();
5551  priv_->changed_bases_.clear();
5552 }
5553 
5554 /// Tests if the lookup tables are empty.
5555 ///
5556 /// @return true if the lookup tables are empty, false otherwise.
5557 bool
5558 class_diff::lookup_tables_empty(void) const
5559 {
5560  return (priv_->deleted_bases_.empty()
5561  && priv_->inserted_bases_.empty()
5562  && priv_->changed_bases_.empty());
5563 }
5564 
5565 /// Find a virtual destructor in a map of member functions
5566 ///
5567 /// @param map the map of member functions. Note that the key of the
5568 /// map is the member function name. The key is the member function.
5569 ///
5570 /// @return an iterator to the destructor found or, if no virtual destructor
5571 /// was found, return map.end()
5572 static string_member_function_sptr_map::const_iterator
5573 find_virtual_dtor_in_map(const string_member_function_sptr_map& map)
5574 {
5575  for (string_member_function_sptr_map::const_iterator i = map.begin();
5576  i !=map.end();
5577  ++i)
5578  {
5579  if (get_member_function_is_dtor(i->second)
5580  && get_member_function_is_virtual(i->second))
5581  return i;
5582  }
5583  return map.end();
5584 }
5585 
5586 /// If the lookup tables are not yet built, walk the differences and
5587 /// fill them.
5588 void
5589 class_diff::ensure_lookup_tables_populated(void) const
5590 {
5592 
5593  if (!lookup_tables_empty())
5594  return;
5595 
5596  {
5597  edit_script& e = get_priv()->base_changes_;
5598 
5599  for (vector<deletion>::const_iterator it = e.deletions().begin();
5600  it != e.deletions().end();
5601  ++it)
5602  {
5603  unsigned i = it->index();
5605  first_class_decl()->get_base_specifiers()[i];
5606  string name = b->get_base_class()->get_qualified_name();
5607  ABG_ASSERT(get_priv()->deleted_bases_.find(name)
5608  == get_priv()->deleted_bases_.end());
5609  get_priv()->deleted_bases_[name] = b;
5610  }
5611 
5612  for (vector<insertion>::const_iterator it = e.insertions().begin();
5613  it != e.insertions().end();
5614  ++it)
5615  {
5616  for (vector<unsigned>::const_iterator iit =
5617  it->inserted_indexes().begin();
5618  iit != it->inserted_indexes().end();
5619  ++iit)
5620  {
5621  unsigned i = *iit;
5623  second_class_decl()->get_base_specifiers()[i];
5624  string name = b->get_base_class()->get_qualified_name();
5625  ABG_ASSERT(get_priv()->inserted_bases_.find(name)
5626  == get_priv()->inserted_bases_.end());
5627  string_base_sptr_map::const_iterator j =
5628  get_priv()->deleted_bases_.find(name);
5629  if (j != get_priv()->deleted_bases_.end())
5630  {
5631  if (j->second != b)
5632  get_priv()->changed_bases_[name] =
5633  compute_diff(j->second, b, context());
5634  else
5635  // The base class changed place. IOW, the base
5636  // classes got re-arranged. Let's keep track of the
5637  // base classes that moved.
5638  get_priv()->moved_bases_.push_back(b);
5639  get_priv()->deleted_bases_.erase(j);
5640  }
5641  else
5642  get_priv()->inserted_bases_[name] = b;
5643  }
5644  }
5645  }
5646 
5647  sort_string_base_sptr_map(get_priv()->deleted_bases_,
5648  get_priv()->sorted_deleted_bases_);
5649  sort_string_base_sptr_map(get_priv()->inserted_bases_,
5650  get_priv()->sorted_inserted_bases_);
5651  sort_string_base_diff_sptr_map(get_priv()->changed_bases_,
5652  get_priv()->sorted_changed_bases_);
5653 
5654  {
5655  const class_or_union_diff::priv_ptr &p = class_or_union_diff::get_priv();
5656 
5657  edit_script& e = p->member_fns_changes_;
5658 
5659  for (vector<deletion>::const_iterator it = e.deletions().begin();
5660  it != e.deletions().end();
5661  ++it)
5662  {
5663  unsigned i = it->index();
5664  method_decl_sptr mem_fn =
5665  first_class_decl()->get_virtual_mem_fns()[i];
5666  string name = mem_fn->get_linkage_name();
5667  if (name.empty())
5668  name = mem_fn->get_pretty_representation();
5669  ABG_ASSERT(!name.empty());
5670  if (p->deleted_member_functions_.find(name)
5671  != p->deleted_member_functions_.end())
5672  continue;
5673  p->deleted_member_functions_[name] = mem_fn;
5674  }
5675 
5676  for (vector<insertion>::const_iterator it = e.insertions().begin();
5677  it != e.insertions().end();
5678  ++it)
5679  {
5680  for (vector<unsigned>::const_iterator iit =
5681  it->inserted_indexes().begin();
5682  iit != it->inserted_indexes().end();
5683  ++iit)
5684  {
5685  unsigned i = *iit;
5686 
5687  method_decl_sptr mem_fn =
5688  second_class_decl()->get_virtual_mem_fns()[i];
5689  string name = mem_fn->get_linkage_name();
5690  if (name.empty())
5691  name = mem_fn->get_pretty_representation();
5692  ABG_ASSERT(!name.empty());
5693  if (p->inserted_member_functions_.find(name)
5694  != p->inserted_member_functions_.end())
5695  continue;
5696  string_member_function_sptr_map::const_iterator j =
5697  p->deleted_member_functions_.find(name);
5698 
5699  if (j != p->deleted_member_functions_.end())
5700  {
5701  if (*j->second != *mem_fn)
5702  p->changed_member_functions_[name] =
5703  compute_diff(static_pointer_cast<function_decl>(j->second),
5704  static_pointer_cast<function_decl>(mem_fn),
5705  context());
5706  p->deleted_member_functions_.erase(j);
5707  }
5708  else
5709  p->inserted_member_functions_[name] = mem_fn;
5710  }
5711  }
5712 
5713  // Now walk the allegedly deleted member functions; check if their
5714  // underlying symbols are deleted as well; otherwise, consider
5715  // that the member function in question hasn't been deleted.
5716 
5717  // Also, while walking the deleted member functions, we attend at
5718  // a particular cleanup business related to (virtual) C++
5719  // destructors:
5720  //
5721  // In the binary, there can be at least three types of
5722  // destructors, defined in the document
5723  // https://itanium-cxx-abi.github.io/cxx-abi/abi.html#definitions:
5724  //
5725  // 1/ Base object destructor (aka D2 destructor):
5726  //
5727  // "A function that runs the destructors for non-static data
5728  // members of T and non-virtual direct base classes of T. "
5729  //
5730  // 2/ Complete object destructor (aka D1 destructor):
5731  //
5732  // "A function that, in addition to the actions required of a
5733  // base object destructor, runs the destructors for the
5734  // virtual base classes of T."
5735  //
5736  // 3/ Deleting destructor (aka D0 destructor):
5737  //
5738  // "A function that, in addition to the actions required of a
5739  // complete object destructor, calls the appropriate
5740  // deallocation function (i.e,. operator delete) for T."
5741  //
5742  // With binaries generated by GCC, these destructors might be ELF
5743  // clones of each others, meaning, their ELF symbols can be
5744  // aliases.
5745  //
5746  // Also, note that because the actual destructor invoked by user
5747  // code is virtual, it's invoked through the vtable. So the
5748  // presence of the underlying D0, D1, D2 in the binary might vary
5749  // without that variation being an ABI issue, provided that the
5750  // destructor invoked through the vtable is present.
5751  //
5752  // So, a particular virtual destructor implementation for a class
5753  // might disapear and be replaced by another one in a subsequent
5754  // version of the binary. If all versions of the binary have an
5755  // actual virtual destructor, things might be considered fine.
5756  vector<string> to_delete;
5757  corpus_sptr f = context()->get_first_corpus(),
5758  s = context()->get_second_corpus();
5759  if (s)
5760  for (string_member_function_sptr_map::const_iterator i =
5761  deleted_member_fns().begin();
5762  i != deleted_member_fns().end();
5763  ++i)
5764  {
5765  if (get_member_function_is_virtual(i->second))
5766  {
5767  if (get_member_function_is_dtor(i->second))
5768  {
5769  // If a particular virtual destructor is deleted,
5770  // but the new binary still have a virtual
5771  // destructor for that class we consider that things
5772  // are fine. For instance, in the
5773  // tests/data/test-diff-pkg/tbb-4.1-9.20130314.fc22.x86_64--tbb-4.3-3.20141204.fc23.x86_64-report-0.txt
5774  // test, a new D4 destructor replaces the old ones.
5775  // But because the virtual destructor is still
5776  // there, this is not an ABI issue. So let's detect
5777  // this case.
5778  auto it =
5779  find_virtual_dtor_in_map(p->inserted_member_functions_);
5780  if (it != p->inserted_member_functions_.end())
5781  {
5782  // So the deleted virtual destructor is not
5783  // really deleted, because a proper virtual
5784  // destructor was added to the new version.
5785  // Let's remove the deleted/added virtual
5786  // destructor then.
5787  string name =
5788  (!i->second->get_linkage_name().empty())
5789  ? i->second->get_linkage_name()
5790  : i->second->get_pretty_representation();
5791  to_delete.push_back(name);
5792  p->inserted_member_functions_.erase(it);
5793  }
5794  }
5795  continue;
5796  }
5797  // We assume that all non-virtual member functions functions
5798  // we look at here have ELF symbols.
5799  if (!i->second->get_symbol()
5800  || s->lookup_function_symbol(*i->second->get_symbol()))
5801  to_delete.push_back(i->first);
5802  }
5803 
5804 
5805  for (vector<string>::const_iterator i = to_delete.begin();
5806  i != to_delete.end();
5807  ++i)
5808  p->deleted_member_functions_.erase(*i);
5809 
5810  // Do something similar for added functions.
5811  to_delete.clear();
5812  if (f)
5813  for (string_member_function_sptr_map::const_iterator i =
5814  inserted_member_fns().begin();
5815  i != inserted_member_fns().end();
5816  ++i)
5817  {
5818  if (get_member_function_is_virtual(i->second))
5819  continue;
5820  // We assume that all non-virtual member functions functions
5821  // we look at here have ELF symbols.
5822  if (!i->second->get_symbol()
5823  || f->lookup_function_symbol(*i->second->get_symbol()))
5824  to_delete.push_back(i->first);
5825  }
5826 
5827  for (vector<string>::const_iterator i = to_delete.begin();
5828  i != to_delete.end();
5829  ++i)
5830  p->inserted_member_functions_.erase(*i);
5831 
5832  sort_string_member_function_sptr_map(p->deleted_member_functions_,
5833  p->sorted_deleted_member_functions_);
5834 
5835  sort_string_member_function_sptr_map(p->inserted_member_functions_,
5836  p->sorted_inserted_member_functions_);
5837 
5839  (p->changed_member_functions_,
5840  p->sorted_changed_member_functions_);
5841  }
5842 }
5843 
5844 /// Allocate the memory for the priv_ pimpl data member of the @ref
5845 /// class_diff class.
5846 void
5847 class_diff::allocate_priv_data()
5848 {
5850  if (!priv_)
5851  priv_.reset(new priv);
5852 }
5853 
5854 /// Test whether a given base class has changed. A base class has
5855 /// changed if it's in both in deleted *and* inserted bases.
5856 ///
5857 ///@param d the declaration for the base class to consider.
5858 ///
5859 /// @return the new base class if the given base class has changed, or
5860 /// NULL if it hasn't.
5863 {
5864  string qname = d->get_base_class()->get_qualified_name();
5865  string_base_diff_sptr_map::const_iterator it =
5866  changed_bases_.find(qname);
5867 
5868  return (it == changed_bases_.end())
5870  : it->second->second_base();
5871 
5872 }
5873 
5874 /// Count the number of bases classes whose changes got filtered out.
5875 ///
5876 /// @return the number of bases classes whose changes got filtered
5877 /// out.
5878 size_t
5880 {
5881  size_t num_filtered = 0;
5882  for (base_diff_sptrs_type::const_iterator i = sorted_changed_bases_.begin();
5883  i != sorted_changed_bases_.end();
5884  ++i)
5885  {
5886  diff_sptr diff = *i;
5887  if (diff && diff->is_filtered_out())
5888  ++num_filtered;
5889  }
5890  return num_filtered;
5891 }
5892 
5893 /// Populate the vector of children node of the @ref diff base type
5894 /// sub-object of this instance of @ref class_diff.
5895 ///
5896 /// The children node can then later be retrieved using
5897 /// diff::children_node().
5898 void
5900 {
5902 
5903  // base class changes.
5904  for (base_diff_sptrs_type::const_iterator i =
5905  get_priv()->sorted_changed_bases_.begin();
5906  i != get_priv()->sorted_changed_bases_.end();
5907  ++i)
5908  if (diff_sptr d = *i)
5909  append_child_node(d);
5910 }
5911 
5912 /// Constructor of class_diff
5913 ///
5914 /// @param first_scope the first class of the diff.
5915 ///
5916 /// @param second_scope the second class of the diff.
5917 ///
5918 /// @param ctxt the diff context to use.
5920  class_decl_sptr second_scope,
5921  diff_context_sptr ctxt)
5922  : class_or_union_diff(first_scope, second_scope, ctxt)
5923  // We don't initialize the priv_ data member here. This is an
5924  // optimization to reduce memory consumption (and also execution
5925  // time) for cases where there are a lot of instances of
5926  // class_diff in the same equivalence class. In compute_diff(),
5927  // the priv_ is set to the priv_ of the canonical diff node.
5928  // See PR libabigail/17948.
5929 {}
5930 
5931 class_diff::~class_diff()
5932 {}
5933 
5934 /// Getter of the private data of the @ref class_diff type.
5935 ///
5936 /// Note that due to an optimization, the private data of @ref
5937 /// class_diff can be shared among several instances of class_diff, so
5938 /// you should never try to access class_diff::priv directly.
5939 ///
5940 /// When class_diff::priv is shared, this function returns the correct
5941 /// shared one.
5942 ///
5943 /// @return the (possibly) shared private data of the current instance
5944 /// of class_diff.
5945 const class_diff::priv_ptr&
5946 class_diff::get_priv() const
5947 {
5948  if (priv_)
5949  return priv_;
5950 
5951  // If the current class_diff::priv member is empty, then look for
5952  // the shared one, from the canonical type.
5953  class_diff *canonical =
5954  dynamic_cast<class_diff*>(get_canonical_diff());
5955  ABG_ASSERT(canonical);
5956  ABG_ASSERT(canonical->priv_);
5957 
5958  return canonical->priv_;
5959 }
5960 
5961 /// @return the pretty representation of the current instance of @ref
5962 /// class_diff.
5963 const string&
5965 {
5966  if (diff::priv_->pretty_representation_.empty())
5967  {
5968  std::ostringstream o;
5969  o << "class_diff["
5970  << first_subject()->get_pretty_representation()
5971  << ", "
5972  << second_subject()->get_pretty_representation()
5973  << "]";
5974  diff::priv_->pretty_representation_ = o.str();
5975  }
5976  return diff::priv_->pretty_representation_;
5977 }
5978 
5979 /// Return true iff the current diff node carries a change.
5980 ///
5981 /// @return true iff the current diff node carries a change.
5982 bool
5984 {return (first_class_decl() != second_class_decl());}
5985 
5986 /// @return the kind of local change carried by the current diff node.
5987 /// The value returned is zero if the current node carries no local
5988 /// change.
5989 enum change_kind
5991 {
5992  ir::change_kind k = ir::NO_CHANGE_KIND;
5993  if (!equals(*first_class_decl(), *second_class_decl(), &k))
5994  return k & ir::ALL_LOCAL_CHANGES_MASK;
5995  return ir::NO_CHANGE_KIND;
5996 }
5997 
5998 /// @return the first class invoveld in the diff.
5999 shared_ptr<class_decl>
6001 {return dynamic_pointer_cast<class_decl>(first_subject());}
6002 
6003 /// Getter of the second class involved in the diff.
6004 ///
6005 /// @return the second class invoveld in the diff
6006 shared_ptr<class_decl>
6008 {return dynamic_pointer_cast<class_decl>(second_subject());}
6009 
6010 /// @return the edit script of the bases of the two classes.
6011 const edit_script&
6013 {return get_priv()->base_changes_;}
6014 
6015 /// Getter for the deleted base classes of the diff.
6016 ///
6017 /// @return a map containing the deleted base classes, keyed with
6018 /// their pretty representation.
6019 const string_base_sptr_map&
6021 {return get_priv()->deleted_bases_;}
6022 
6023 /// Getter for the inserted base classes of the diff.
6024 ///
6025 /// @return a map containing the inserted base classes, keyed with
6026 /// their pretty representation.
6027 const string_base_sptr_map&
6029 {return get_priv()->inserted_bases_;}
6030 
6031 /// Getter for the changed base classes of the diff.
6032 ///
6033 /// @return a sorted vector containing the changed base classes
6034 const base_diff_sptrs_type&
6036 {return get_priv()->sorted_changed_bases_;}
6037 
6038 /// Getter for the vector of bases that "moved".
6039 /// That is, the vector of base types which position changed. If this
6040 /// vector is not empty, it means the bases of the underlying class
6041 /// type got re-ordered.
6042 ///
6043 /// @return the vector of bases that moved.
6044 const vector<class_decl::base_spec_sptr>&
6046 {return get_priv()->moved_bases_;}
6047 
6048 /// @return the edit script of the bases of the two classes.
6049 edit_script&
6051 {return get_priv()->base_changes_;}
6052 
6053 /// Produce a basic report about the changes between two class_decl.
6054 ///
6055 /// @param out the output stream to report the changes to.
6056 ///
6057 /// @param indent the string to use as an indentation prefix in the
6058 /// report.
6059 void
6060 class_diff::report(ostream& out, const string& indent) const
6061 {
6062  context()->get_reporter()->report(*this, out, indent);
6063 }
6064 
6065 /// Compute the set of changes between two instances of class_decl.
6066 ///
6067 /// Note that the two types must have been created in the same @ref
6068 /// environment, otherwise, this function aborts.
6069 ///
6070 /// @param first the first class_decl to consider.
6071 ///
6072 /// @param second the second class_decl to consider.
6073 ///
6074 /// @return changes the resulting changes.
6075 ///
6076 /// @param ctxt the diff context to use.
6079  const class_decl_sptr second,
6080  diff_context_sptr ctxt)
6081 {
6084 
6085  class_diff_sptr changes(new class_diff(f, s, ctxt));
6086 
6087  ctxt->initialize_canonical_diff(changes);
6088  ABG_ASSERT(changes->get_canonical_diff());
6089 
6090  if (!ctxt->get_canonical_diff_for(first, second))
6091  {
6092  // Either first or second is a decl-only class; let's set the
6093  // canonical diff here in that case.
6094  diff_sptr canonical_diff = ctxt->get_canonical_diff_for(changes);
6095  ABG_ASSERT(canonical_diff);
6096  ctxt->set_canonical_diff_for(first, second, canonical_diff);
6097  }
6098 
6099  // Ok, so this is an optimization. Do not freak out if it looks
6100  // weird, because, well, it does look weird. This speeds up
6101  // greatly, for instance, the test case given at PR
6102  // libabigail/17948.
6103  //
6104  // We are setting the private data of the new instance of class_diff
6105  // (which is 'changes') to the private data of its canonical
6106  // instance. That is, we are sharing the private data of 'changes'
6107  // with the private data of its canonical instance to consume less
6108  // memory in cases where the equivalence class of 'changes' is huge.
6109  //
6110  // But if changes is its own canonical instance, then we initialize
6111  // its private data properly
6112  if (is_class_diff(changes->get_canonical_diff()) == changes.get())
6113  // changes is its own canonical instance, so it gets a brand new
6114  // private data.
6115  changes->allocate_priv_data();
6116  else
6117  {
6118  // changes has a non-empty equivalence class so it's going to
6119  // share its private data with its canonical instance. Next
6120  // time class_diff::get_priv() is invoked, it's going to return
6121  // the shared private data of the canonical instance.
6122  return changes;
6123  }
6124 
6125  // Compare base specs
6126  compute_diff(f->get_base_specifiers().begin(),
6127  f->get_base_specifiers().end(),
6128  s->get_base_specifiers().begin(),
6129  s->get_base_specifiers().end(),
6130  changes->base_changes());
6131 
6132  // Do *not* compare member types because it generates lots of noise
6133  // and I doubt it's really useful.
6134 #if 0
6135  compute_diff(f->get_member_types().begin(),
6136  f->get_member_types().end(),
6137  s->get_member_types().begin(),
6138  s->get_member_types().end(),
6139  changes->member_types_changes());
6140 #endif
6141 
6142  // Compare data member
6143  compute_diff(f->get_non_static_data_members().begin(),
6144  f->get_non_static_data_members().end(),
6145  s->get_non_static_data_members().begin(),
6146  s->get_non_static_data_members().end(),
6147  changes->data_members_changes());
6148 
6149  // Compare virtual member functions
6150  compute_diff(f->get_virtual_mem_fns().begin(),
6151  f->get_virtual_mem_fns().end(),
6152  s->get_virtual_mem_fns().begin(),
6153  s->get_virtual_mem_fns().end(),
6154  changes->member_fns_changes());
6155 
6156  // Compare member function templates
6157  compute_diff(f->get_member_function_templates().begin(),
6158  f->get_member_function_templates().end(),
6159  s->get_member_function_templates().begin(),
6160  s->get_member_function_templates().end(),
6161  changes->member_fn_tmpls_changes());
6162 
6163  // Likewise, do not compare member class templates
6164 #if 0
6165  compute_diff(f->get_member_class_templates().begin(),
6166  f->get_member_class_templates().end(),
6167  s->get_member_class_templates().begin(),
6168  s->get_member_class_templates().end(),
6169  changes->member_class_tmpls_changes());
6170 #endif
6171 
6172  changes->ensure_lookup_tables_populated();
6173 
6174  return changes;
6175 }
6176 
6177 //</class_diff stuff>
6178 
6179 // <base_diff stuff>
6180 
6181 /// Populate the vector of children node of the @ref diff base type
6182 /// sub-object of this instance of @ref base_diff.
6183 ///
6184 /// The children node can then later be retrieved using
6185 /// diff::children_node().
6186 void
6189 
6190 /// @param first the first base spec to consider.
6191 ///
6192 /// @param second the second base spec to consider.
6193 ///
6194 /// @param ctxt the context of the diff. Note that this context
6195 /// object must stay alive at least during the life time of the
6196 /// current instance of @ref base_diff. Otherwise memory corruption
6197 /// issues occur.
6200  class_diff_sptr underlying,
6201  diff_context_sptr ctxt)
6202  : diff(first, second, ctxt),
6203  priv_(new priv(underlying))
6204 {}
6205 
6206 /// Getter for the first base spec of the diff object.
6207 ///
6208 /// @return the first base specifier for the diff object.
6211 {return dynamic_pointer_cast<class_decl::base_spec>(first_subject());}
6212 
6213 /// Getter for the second base spec of the diff object.
6214 ///
6215 /// @return the second base specifier for the diff object.
6218 {return dynamic_pointer_cast<class_decl::base_spec>(second_subject());}
6219 
6220 /// Getter for the diff object for the diff of the underlying base
6221 /// classes.
6222 ///
6223 /// @return the diff object for the diff of the underlying base
6224 /// classes.
6225 const class_diff_sptr
6227 {return priv_->underlying_class_diff_;}
6228 
6229 /// Setter for the diff object for the diff of the underlyng base
6230 /// classes.
6231 ///
6232 /// @param d the new diff object for the diff of the underlying base
6233 /// classes.
6234 void
6236 {priv_->underlying_class_diff_ = d;}
6237 
6238 /// @return the pretty representation for the current instance of @ref
6239 /// base_diff.
6240 const string&
6242 {
6243  if (diff::priv_->pretty_representation_.empty())
6244  {
6245  std::ostringstream o;
6246  o << "base_diff["
6247  << first_subject()->get_pretty_representation()
6248  << ", "
6249  << second_subject()->get_pretty_representation()
6250  << "]";
6251  diff::priv_->pretty_representation_ = o.str();
6252  }
6253  return diff::priv_->pretty_representation_;
6254 }
6255 
6256 /// Return true iff the current diff node carries a change.
6257 ///
6258 /// Return true iff the current diff node carries a change.
6259 bool
6261 {return first_base() != second_base();}
6262 
6263 /// @return the kind of local change carried by the current diff node.
6264 /// The value returned is zero if the current node carries no local
6265 /// change.
6266 enum change_kind
6268 {
6269  ir::change_kind k = ir::NO_CHANGE_KIND;
6270  if (!equals(*first_base(), *second_base(), &k))
6271  return k & ir::ALL_LOCAL_CHANGES_MASK;
6272  return ir::NO_CHANGE_KIND;
6273 }
6274 
6275 /// Generates a report for the current instance of base_diff.
6276 ///
6277 /// @param out the output stream to send the report to.
6278 ///
6279 /// @param indent the string to use for indentation.
6280 void
6281 base_diff::report(ostream& out, const string& indent) const
6282 {
6283  context()->get_reporter()->report(*this, out, indent);
6284 }
6285 
6286 /// Constructs the diff object representing a diff between two base
6287 /// class specifications.
6288 ///
6289 /// Note that the two artifacts must have been created in the same
6290 /// @ref environment, otherwise, this function aborts.
6291 ///
6292 /// @param first the first base class specification.
6293 ///
6294 /// @param second the second base class specification.
6295 ///
6296 /// @param ctxt the content of the diff.
6297 ///
6298 /// @return the resulting diff object.
6301  const class_decl::base_spec_sptr second,
6302  diff_context_sptr ctxt)
6303 {
6304  class_diff_sptr cl = compute_diff(first->get_base_class(),
6305  second->get_base_class(),
6306  ctxt);
6307  base_diff_sptr changes(new base_diff(first, second, cl, ctxt));
6308 
6309  ctxt->initialize_canonical_diff(changes);
6310 
6311  return changes;
6312 }
6313 
6314 // </base_diff stuff>
6315 
6316 
6317 // <union_diff stuff>
6318 
6319 /// Clear the lookup tables useful for reporting.
6320 ///
6321 /// This function must be updated each time a lookup table is added or
6322 /// removed from the union_diff::priv.
6323 void
6324 union_diff::clear_lookup_tables(void)
6326 
6327 /// Tests if the lookup tables are empty.
6328 ///
6329 /// @return true if the lookup tables are empty, false otherwise.
6330 bool
6331 union_diff::lookup_tables_empty(void) const
6333 
6334 /// If the lookup tables are not yet built, walk the differences and
6335 /// fill them.
6336 void
6337 union_diff::ensure_lookup_tables_populated(void) const
6339 
6340 /// Allocate the memory for the priv_ pimpl data member of the @ref
6341 /// union_diff class.
6342 void
6343 union_diff::allocate_priv_data()
6344 {
6346 }
6347 
6348 /// Constructor for the @ref union_diff type.
6349 ///
6350 /// @param first_union the first object of the comparison.
6351 ///
6352 /// @param second_union the second object of the comparison.
6353 ///
6354 /// @param ctxt the context of the comparison.
6355 union_diff::union_diff(union_decl_sptr first_union,
6356  union_decl_sptr second_union,
6357  diff_context_sptr ctxt)
6358  : class_or_union_diff(first_union, second_union, ctxt)
6359 {}
6360 
6361 /// Destructor of the union_diff node.
6363 {}
6364 
6365 /// @return the first object of the comparison.
6366 union_decl_sptr
6368 {return is_union_type(first_subject());}
6369 
6370 /// @return the second object of the comparison.
6371 union_decl_sptr
6373 {return is_union_type(second_subject());}
6374 
6375 /// @return the pretty representation of the current diff node.
6376 const string&
6378 {
6379  if (diff::priv_->pretty_representation_.empty())
6380  {
6381  std::ostringstream o;
6382  o << "union_diff["
6383  << first_subject()->get_pretty_representation()
6384  << ", "
6385  << second_subject()->get_pretty_representation()
6386  << "]";
6387  diff::priv_->pretty_representation_ = o.str();
6388  }
6389  return diff::priv_->pretty_representation_;
6390 }
6391 
6392 /// Report the changes carried by the current @ref union_diff node in
6393 /// a textual format.
6394 ///
6395 /// @param out the output stream to write the textual report to.
6396 ///
6397 /// @param indent the number of white space to use as indentation.
6398 void
6399 union_diff::report(ostream& out, const string& indent) const
6400 {
6401  context()->get_reporter()->report(*this, out, indent);
6402 }
6403 
6404 /// Compute the difference between two @ref union_decl types.
6405 ///
6406 /// Note that the two types must hav been created in the same
6407 /// environment, otherwise, this function aborts.
6408 ///
6409 /// @param first the first @ref union_decl to consider.
6410 ///
6411 /// @param second the second @ref union_decl to consider.
6412 ///
6413 /// @param ctxt the context of the diff to use.
6414 union_diff_sptr
6415 compute_diff(const union_decl_sptr first,
6416  const union_decl_sptr second,
6417  diff_context_sptr ctxt)
6418 {
6419  union_diff_sptr changes(new union_diff(first, second, ctxt));
6420 
6421  ctxt->initialize_canonical_diff(changes);
6422  ABG_ASSERT(changes->get_canonical_diff());
6423 
6424  // Ok, so this is an optimization. Do not freak out if it looks
6425  // weird, because, well, it does look weird. This speeds up
6426  // greatly, for instance, the test case given at PR
6427  // libabigail/17948.
6428  //
6429  // We are setting the private data of the new instance of class_diff
6430  // (which is 'changes') to the private data of its canonical
6431  // instance. That is, we are sharing the private data of 'changes'
6432  // with the private data of its canonical instance to consume less
6433  // memory in cases where the equivalence class of 'changes' is huge.
6434  //
6435  // But if changes is its own canonical instance, then we initialize
6436  // its private data properly.
6437  if (is_union_diff(changes->get_canonical_diff()) == changes.get())
6438  // changes is its own canonical instance, so it gets a brand new
6439  // private data.
6440  changes->allocate_priv_data();
6441  else
6442  {
6443  // changes has a non-empty equivalence class so it's going to
6444  // share its private data with its canonical instance. Next
6445  // time class_diff::get_priv() is invoked, it's going to return
6446  // the shared private data of the canonical instance.
6447  return changes;
6448  }
6449 
6450  // Compare data member
6451  compute_diff(first->get_non_static_data_members().begin(),
6452  first->get_non_static_data_members().end(),
6453  second->get_non_static_data_members().begin(),
6454  second->get_non_static_data_members().end(),
6455  changes->data_members_changes());
6456 
6457 #if 0
6458  // Compare member functions
6459  compute_diff(first->get_mem_fns().begin(),
6460  first->get_mem_fns().end(),
6461  second->get_mem_fns().begin(),
6462  second->get_mem_fns().end(),
6463  changes->member_fns_changes());
6464 
6465  // Compare member function templates
6466  compute_diff(first->get_member_function_templates().begin(),
6467  first->get_member_function_templates().end(),
6468  second->get_member_function_templates().begin(),
6469  second->get_member_function_templates().end(),
6470  changes->member_fn_tmpls_changes());
6471 #endif
6472 
6473  changes->ensure_lookup_tables_populated();
6474 
6475  return changes;
6476 }
6477 
6478 // </union_diff stuff>
6479 
6480 //<scope_diff stuff>
6481 
6482 /// Clear the lookup tables that are useful for reporting.
6483 ///
6484 /// This function must be updated each time a lookup table is added or
6485 /// removed.
6486 void
6487 scope_diff::clear_lookup_tables()
6488 {
6489  priv_->deleted_types_.clear();
6490  priv_->deleted_decls_.clear();
6491  priv_->inserted_types_.clear();
6492  priv_->inserted_decls_.clear();
6493  priv_->changed_types_.clear();
6494  priv_->changed_decls_.clear();
6495  priv_->removed_types_.clear();
6496  priv_->removed_decls_.clear();
6497  priv_->added_types_.clear();
6498  priv_->added_decls_.clear();
6499 }
6500 
6501 /// Tests if the lookup tables are empty.
6502 ///
6503 /// This function must be updated each time a lookup table is added or
6504 /// removed.
6505 ///
6506 /// @return true iff all the lookup tables are empty.
6507 bool
6508 scope_diff::lookup_tables_empty() const
6509 {
6510  return (priv_->deleted_types_.empty()
6511  && priv_->deleted_decls_.empty()
6512  && priv_->inserted_types_.empty()
6513  && priv_->inserted_decls_.empty()
6514  && priv_->changed_types_.empty()
6515  && priv_->changed_decls_.empty()
6516  && priv_->removed_types_.empty()
6517  && priv_->removed_decls_.empty()
6518  && priv_->added_types_.empty()
6519  && priv_->added_decls_.empty());
6520 }
6521 
6522 /// If the lookup tables are not yet built, walk the member_changes_
6523 /// member and fill the lookup tables.
6524 void
6525 scope_diff::ensure_lookup_tables_populated()
6526 {
6527  if (!lookup_tables_empty())
6528  return;
6529 
6530  edit_script& e = priv_->member_changes_;
6531 
6532  // Populate deleted types & decls lookup tables.
6533  for (const auto& deletion : e.deletions())
6534  {
6535  unsigned i = deletion.index();
6536  decl_base_sptr decl = deleted_member_at(i);
6537  string qname = decl->get_qualified_name();
6538  if (is_type(decl))
6539  {
6540  class_decl_sptr klass_decl = dynamic_pointer_cast<class_decl>(decl);
6541  if (klass_decl && klass_decl->get_is_declaration_only())
6542  continue;
6543 
6544  // Unique types are artifically put in a scope because they
6545  // have to belong somewhere, but they should not be
6546  // considered added/removed from any scope because they are
6547  // artificial and always present in the system.
6548  if (is_unique_type(is_type(decl)))
6549  continue;
6550 
6551  ABG_ASSERT(priv_->deleted_types_.find(qname)
6552  == priv_->deleted_types_.end());
6553  priv_->deleted_types_[qname] = decl;
6554  }
6555  else
6556  {
6557  ABG_ASSERT(priv_->deleted_decls_.find(qname)
6558  == priv_->deleted_decls_.end());
6559  priv_->deleted_decls_[qname] = decl;
6560  }
6561  }
6562 
6563  // Populate inserted types & decls as well as chagned types & decls
6564  // lookup tables.
6565  for (vector<insertion>::const_iterator it = e.insertions().begin();
6566  it != e.insertions().end();
6567  ++it)
6568  {
6569  for (vector<unsigned>::const_iterator i = it->inserted_indexes().begin();
6570  i != it->inserted_indexes().end();
6571  ++i)
6572  {
6573  decl_base_sptr decl = inserted_member_at(i);
6574  string qname = decl->get_qualified_name();
6575  if (is_type(decl))
6576  {
6577  class_decl_sptr klass_decl =
6578  dynamic_pointer_cast<class_decl>(decl);
6579  if (klass_decl && klass_decl->get_is_declaration_only())
6580  continue;
6581 
6582  // Unique types are artifically put in a scope because they
6583  // have to belong somewhere, but they should not be
6584  // considered added/removed from any scope because they are
6585  // artificial and always present in the system.
6586  if (is_unique_type(is_type(decl)))
6587  continue;
6588 
6589  ABG_ASSERT(priv_->inserted_types_.find(qname)
6590  == priv_->inserted_types_.end());
6591  string_decl_base_sptr_map::const_iterator j =
6592  priv_->deleted_types_.find(qname);
6593  if (j != priv_->deleted_types_.end())
6594  {
6595  if (*j->second != *decl)
6596  priv_->changed_types_[qname] =
6597  compute_diff(j->second, decl, context());
6598  priv_->deleted_types_.erase(j);
6599  }
6600  else
6601  priv_->inserted_types_[qname] = decl;
6602  }
6603  else
6604  {
6605  ABG_ASSERT(priv_->inserted_decls_.find(qname)
6606  == priv_->inserted_decls_.end());
6607  string_decl_base_sptr_map::const_iterator j =
6608  priv_->deleted_decls_.find(qname);
6609  if (j != priv_->deleted_decls_.end())
6610  {
6611  if (*j->second != *decl)
6612  priv_->changed_decls_[qname] =
6613  compute_diff(j->second, decl, context());
6614  priv_->deleted_decls_.erase(j);
6615  }
6616  else
6617  priv_->inserted_decls_[qname] = decl;
6618  }
6619  }
6620  }
6621 
6622  sort_string_diff_sptr_map(priv_->changed_decls_,
6623  priv_->sorted_changed_decls_);
6624  sort_string_diff_sptr_map(priv_->changed_types_,
6625  priv_->sorted_changed_types_);
6626 
6627  // Populate removed types/decls lookup tables
6628  for (string_decl_base_sptr_map::const_iterator i =
6629  priv_->deleted_types_.begin();
6630  i != priv_->deleted_types_.end();
6631  ++i)
6632  {
6633  string_decl_base_sptr_map::const_iterator r =
6634  priv_->inserted_types_.find(i->first);
6635  if (r == priv_->inserted_types_.end())
6636  priv_->removed_types_[i->first] = i->second;
6637  }
6638  for (string_decl_base_sptr_map::const_iterator i =
6639  priv_->deleted_decls_.begin();
6640  i != priv_->deleted_decls_.end();
6641  ++i)
6642  {
6643  string_decl_base_sptr_map::const_iterator r =
6644  priv_->inserted_decls_.find(i->first);
6645  if (r == priv_->inserted_decls_.end())
6646  priv_->removed_decls_[i->first] = i->second;
6647  }
6648 
6649  // Populate added types/decls.
6650  for (string_decl_base_sptr_map::const_iterator i =
6651  priv_->inserted_types_.begin();
6652  i != priv_->inserted_types_.end();
6653  ++i)
6654  {
6655  string_decl_base_sptr_map::const_iterator r =
6656  priv_->deleted_types_.find(i->first);
6657  if (r == priv_->deleted_types_.end())
6658  priv_->added_types_[i->first] = i->second;
6659  }
6660  for (string_decl_base_sptr_map::const_iterator i =
6661  priv_->inserted_decls_.begin();
6662  i != priv_->inserted_decls_.end();
6663  ++i)
6664  {
6665  string_decl_base_sptr_map::const_iterator r =
6666  priv_->deleted_decls_.find(i->first);
6667  if (r == priv_->deleted_decls_.end())
6668  priv_->added_decls_[i->first] = i->second;
6669  }
6670 }
6671 
6672 /// Populate the vector of children node of the @ref diff base type
6673 /// sub-object of this instance of @ref scope_diff.
6674 ///
6675 /// The children node can then later be retrieved using
6676 /// diff::children_node().
6677 void
6679 {
6680  for (diff_sptrs_type::const_iterator i = changed_types().begin();
6681  i != changed_types().end();
6682  ++i)
6683  if (*i)
6684  append_child_node(*i);
6685 
6686  for (diff_sptrs_type::const_iterator i = changed_decls().begin();
6687  i != changed_decls().end();
6688  ++i)
6689  if (*i)
6690  append_child_node(*i);
6691 }
6692 
6693 /// Constructor for scope_diff
6694 ///
6695 /// @param first_scope the first scope to consider for the diff.
6696 ///
6697 /// @param second_scope the second scope to consider for the diff.
6698 ///
6699 /// @param ctxt the diff context to use. Note that this context
6700 /// object must stay alive at least during the life time of the
6701 /// current instance of @ref scope_diff. Otherwise memory corruption
6702 /// issues occur.
6704  scope_decl_sptr second_scope,
6705  diff_context_sptr ctxt)
6706  : diff(first_scope, second_scope, ctxt),
6707  priv_(new priv)
6708 {}
6709 
6710 /// Getter for the first scope of the diff.
6711 ///
6712 /// @return the first scope of the diff.
6713 const scope_decl_sptr
6715 {return dynamic_pointer_cast<scope_decl>(first_subject());}
6716 
6717 /// Getter for the second scope of the diff.
6718 ///
6719 /// @return the second scope of the diff.
6720 const scope_decl_sptr
6722 {return dynamic_pointer_cast<scope_decl>(second_subject());}
6723 
6724 /// Accessor of the edit script of the members of a scope.
6725 ///
6726 /// This edit script is computed using the equality operator that
6727 /// applies to shared_ptr<decl_base>.
6728 ///
6729 /// That has interesting consequences. For instance, consider two
6730 /// scopes S0 and S1. S0 contains a class C0 and S1 contains a class
6731 /// S0'. C0 and C0' have the same qualified name, but have different
6732 /// members. The edit script will consider that C0 has been deleted
6733 /// from S0 and that S0' has been inserted. This is a low level
6734 /// canonical representation of the changes; a higher level
6735 /// representation would give us a simpler way to say "the class C0
6736 /// has been modified into C0'". But worry not. We do have such
6737 /// higher representation as well; that is what changed_types() and
6738 /// changed_decls() is for.
6739 ///
6740 /// @return the edit script of the changes encapsulatd in this
6741 /// instance of scope_diff.
6742 const edit_script&
6744 {return priv_->member_changes_;}
6745 
6746 /// Accessor of the edit script of the members of a scope.
6747 ///
6748 /// This edit script is computed using the equality operator that
6749 /// applies to shared_ptr<decl_base>.
6750 ///
6751 /// That has interesting consequences. For instance, consider two
6752 /// scopes S0 and S1. S0 contains a class C0 and S1 contains a class
6753 /// S0'. C0 and C0' have the same qualified name, but have different
6754 /// members. The edit script will consider that C0 has been deleted
6755 /// from S0 and that S0' has been inserted. This is a low level
6756 /// canonical representation of the changes; a higher level
6757 /// representation would give us a simpler way to say "the class C0
6758 /// has been modified into C0'". But worry not. We do have such
6759 /// higher representation as well; that is what changed_types() and
6760 /// changed_decls() is for.
6761 ///
6762 /// @return the edit script of the changes encapsulatd in this
6763 /// instance of scope_diff.
6764 edit_script&
6766 {return priv_->member_changes_;}
6767 
6768 /// Accessor that eases the manipulation of the edit script associated
6769 /// to this instance. It returns the scope member that is reported
6770 /// (in the edit script) as deleted at a given index.
6771 ///
6772 /// @param i the index (in the edit script) of an element of the first
6773 /// scope that has been reported as being delete.
6774 ///
6775 /// @return the scope member that has been reported by the edit script
6776 /// as being deleted at index i.
6777 const decl_base_sptr
6779 {
6780  scope_decl_sptr scope = dynamic_pointer_cast<scope_decl>(first_subject());
6781  return scope->get_member_decls()[i];
6782 }
6783 
6784 /// Accessor that eases the manipulation of the edit script associated
6785 /// to this instance. It returns the scope member (of the first scope
6786 /// of this diff instance) that is reported (in the edit script) as
6787 /// deleted at a given iterator.
6788 ///
6789 /// @param i the iterator of an element of the first scope that has
6790 /// been reported as being delete.
6791 ///
6792 /// @return the scope member of the first scope of this diff that has
6793 /// been reported by the edit script as being deleted at iterator i.
6794 const decl_base_sptr
6795 scope_diff::deleted_member_at(vector<deletion>::const_iterator i) const
6796 {return deleted_member_at(i->index());}
6797 
6798 /// Accessor that eases the manipulation of the edit script associated
6799 /// to this instance. It returns the scope member (of the second
6800 /// scope of this diff instance) that is reported as being inserted
6801 /// from a given index.
6802 ///
6803 /// @param i the index of an element of the second scope this diff
6804 /// that has been reported by the edit script as being inserted.
6805 ///
6806 /// @return the scope member of the second scope of this diff that has
6807 /// been reported as being inserted from index i.
6808 const decl_base_sptr
6810 {
6811  scope_decl_sptr scope = dynamic_pointer_cast<scope_decl>(second_subject());
6812  return scope->get_member_decls()[i];
6813 }
6814 
6815 /// Accessor that eases the manipulation of the edit script associated
6816 /// to this instance. It returns the scope member (of the second
6817 /// scope of this diff instance) that is reported as being inserted
6818 /// from a given iterator.
6819 ///
6820 /// @param i the iterator of an element of the second scope this diff
6821 /// that has been reported by the edit script as being inserted.
6822 ///
6823 /// @return the scope member of the second scope of this diff that has
6824 /// been reported as being inserted from iterator i.
6825 const decl_base_sptr
6826 scope_diff::inserted_member_at(vector<unsigned>::const_iterator i)
6827 {return inserted_member_at(*i);}
6828 
6829 /// @return a sorted vector of the types which content has changed
6830 /// from the first scope to the other.
6831 const diff_sptrs_type&
6833 {return priv_->sorted_changed_types_;}
6834 
6835 /// @return a sorted vector of the decls which content has changed
6836 /// from the first scope to the other.
6837 const diff_sptrs_type&
6839 {return priv_->sorted_changed_decls_;}
6840 
6842 scope_diff::removed_types() const
6843 {return priv_->removed_types_;}
6844 
6846 scope_diff::removed_decls() const
6847 {return priv_->removed_decls_;}
6848 
6850 scope_diff::added_types() const
6851 {return priv_->added_types_;}
6852 
6854 scope_diff::added_decls() const
6855 {return priv_->added_decls_;}
6856 
6857 /// @return the pretty representation for the current instance of @ref
6858 /// scope_diff.
6859 const string&
6861 {
6862  if (diff::priv_->pretty_representation_.empty())
6863  {
6864  std::ostringstream o;
6865  o << "scope_diff["
6866  << first_subject()->get_pretty_representation()
6867  << ", "
6868  << second_subject()->get_pretty_representation()
6869  << "]";
6870  diff::priv_->pretty_representation_ = o.str();
6871  }
6872  return diff::priv_->pretty_representation_;
6873 }
6874 
6875 /// Return true iff the current diff node carries a change.
6876 ///
6877 /// Return true iff the current diff node carries a change.
6878 bool
6880 {
6881  // TODO: add the number of really removed/added stuff.
6882  return changed_types().size() + changed_decls().size();
6883 }
6884 
6885 /// @return the kind of local change carried by the current diff node.
6886 /// The value returned is zero if the current node carries no local
6887 /// change.
6888 enum change_kind
6890 {
6891  ir::change_kind k = ir::NO_CHANGE_KIND;
6892  if (!equals(*first_scope(), *second_scope(), &k))
6893  return k & ir::ALL_LOCAL_CHANGES_MASK;
6894  return ir::NO_CHANGE_KIND;
6895 }
6896 
6897 /// Report the changes of one scope against another.
6898 ///
6899 /// @param out the out stream to report the changes to.
6900 ///
6901 /// @param indent the string to use for indentation.
6902 void
6903 scope_diff::report(ostream& out, const string& indent) const
6904 {
6905  context()->get_reporter()->report(*this, out, indent);
6906 }
6907 
6908 /// Compute the diff between two scopes.
6909 ///
6910 /// Note that the two decls must have been created in the same @ref
6911 /// environment, otherwise, this function aborts.
6912 ///
6913 /// @param first the first scope to consider in computing the diff.
6914 ///
6915 /// @param second the second scope to consider in the diff
6916 /// computation. The second scope is diffed against the first scope.
6917 ///
6918 /// @param d a pointer to the diff object to populate with the
6919 /// computed diff.
6920 ///
6921 /// @return return the populated \a d parameter passed to this
6922 /// function.
6923 ///
6924 /// @param ctxt the diff context to use.
6927  const scope_decl_sptr second,
6928  scope_diff_sptr d,
6929  diff_context_sptr ctxt)
6930 {
6931  ABG_ASSERT(d->first_scope() == first && d->second_scope() == second);
6932 
6933  compute_diff(first->get_member_decls().begin(),
6934  first->get_member_decls().end(),
6935  second->get_member_decls().begin(),
6936  second->get_member_decls().end(),
6937  d->member_changes());
6938 
6939  d->ensure_lookup_tables_populated();
6940  d->context(ctxt);
6941 
6942  return d;
6943 }
6944 
6945 /// Compute the diff between two scopes.
6946 ///
6947 /// Note that the two decls must have been created in the same @ref
6948 /// environment, otherwise, this function aborts.
6949 ///
6950 /// @param first_scope the first scope to consider in computing the diff.
6951 ///
6952 /// @param second_scope the second scope to consider in the diff
6953 /// computation. The second scope is diffed against the first scope.
6954 ///
6955 /// @param ctxt the diff context to use.
6956 ///
6957 /// @return return the resulting diff
6959 compute_diff(const scope_decl_sptr first_scope,
6960  const scope_decl_sptr second_scope,
6961  diff_context_sptr ctxt)
6962 {
6963  scope_diff_sptr d(new scope_diff(first_scope, second_scope, ctxt));
6964  d = compute_diff(first_scope, second_scope, d, ctxt);
6965  ctxt->initialize_canonical_diff(d);
6966  return d;
6967 }
6968 
6969 //</scope_diff stuff>
6970 
6971 // <fn_parm_diff stuff>
6972 
6973 /// Constructor for the fn_parm_diff type.
6974 ///
6975 /// @param first the first subject of the diff.
6976 ///
6977 /// @param second the second subject of the diff.
6978 ///
6979 /// @param ctxt the context of the diff. Note that this context
6980 /// object must stay alive at least during the life time of the
6981 /// current instance of @ref fn_parm_diff. Otherwise memory
6982 /// corruption issues occur.
6983 fn_parm_diff::fn_parm_diff(const function_decl::parameter_sptr first,
6984  const function_decl::parameter_sptr second,
6985  diff_context_sptr ctxt)
6986  : decl_diff_base(first, second, ctxt),
6987  priv_(new priv)
6988 {
6989  ABG_ASSERT(first->get_index() == second->get_index());
6990  priv_->type_diff = compute_diff(first->get_type(),
6991  second->get_type(),
6992  ctxt);
6993  ABG_ASSERT(priv_->type_diff);
6994 }
6995 
6996 /// Getter for the first subject of this diff node.
6997 ///
6998 /// @return the first function_decl::parameter_sptr subject of this
6999 /// diff node.
7002 {return dynamic_pointer_cast<function_decl::parameter>(first_subject());}
7003 
7004 /// Getter for the second subject of this diff node.
7005 ///
7006 /// @return the second function_decl::parameter_sptr subject of this
7007 /// diff node.
7010 {return dynamic_pointer_cast<function_decl::parameter>(second_subject());}
7011 
7012 /// Getter for the diff representing the changes on the type of the
7013 /// function parameter involved in the current instance of @ref
7014 /// fn_parm_diff.
7015 ///
7016 /// @return a diff_sptr representing the changes on the type of the
7017 /// function parameter we are interested in.
7018 diff_sptr
7020 {return priv_->type_diff;}
7021 
7022 /// Build and return a textual representation of the current instance
7023 /// of @ref fn_parm_diff.
7024 ///
7025 /// @return the string representing the current instance of
7026 /// fn_parm_diff.
7027 const string&
7029 {
7030  if (diff::priv_->pretty_representation_.empty())
7031  {
7032  std::ostringstream o;
7033  o << "function_parameter_diff["
7034  << first_subject()->get_pretty_representation()
7035  << ", "
7036  << second_subject()->get_pretty_representation()
7037  << "]";
7038  diff::priv_->pretty_representation_ = o.str();
7039  }
7040  return diff::priv_->pretty_representation_;
7041 }
7042 
7043 /// Return true iff the current diff node carries a change.
7044 ///
7045 /// @return true iff the current diff node carries a change.
7046 bool
7048 {return *first_parameter() != *second_parameter();}
7049 
7050 /// Check if the current diff node carries a local change.
7051 ///
7052 /// @return the kind of local change carried by the current diff node.
7053 /// The value returned is zero if the current node carries no local
7054 /// change.
7055 enum change_kind
7057 {
7058  ir::change_kind k = ir::NO_CHANGE_KIND;
7059  if (!equals(*first_parameter(), *second_parameter(), &k))
7060  return k & ir::ALL_LOCAL_CHANGES_MASK;
7061  return ir::NO_CHANGE_KIND;
7062 }
7063 
7064 /// Emit a textual report about the current fn_parm_diff instance.
7065 ///
7066 /// @param out the output stream to emit the textual report to.
7067 ///
7068 /// @param indent the indentation string to use in the report.
7069 void
7070 fn_parm_diff::report(ostream& out, const string& indent) const
7071 {
7072  context()->get_reporter()->report(*this, out, indent);
7073 }
7074 
7075 /// Populate the vector of children nodes of the @ref diff base type
7076 /// sub-object of this instance of @ref fn_parm_diff.
7077 ///
7078 /// The children nodes can then later be retrieved using
7079 /// diff::children_nodes()
7080 void
7082 {
7083  if (type_diff())
7085 }
7086 
7087 /// Compute the difference between two function_decl::parameter_sptr;
7088 /// that is, between two function parameters. Return a resulting
7089 /// fn_parm_diff_sptr that represents the changes.
7090 ///
7091 /// Note that the two decls must have been created in the same @ref
7092 /// environment, otherwise, this function aborts.
7093 ///
7094 /// @param first the first subject of the diff.
7095 ///
7096 /// @param second the second subject of the diff.
7097 ///
7098 /// @param ctxt the context of the diff.
7099 ///
7100 /// @return fn_parm_diff_sptr the resulting diff node.
7103  const function_decl::parameter_sptr second,
7104  diff_context_sptr ctxt)
7105 {
7106  if (!first || !second)
7107  return fn_parm_diff_sptr();
7108 
7109  fn_parm_diff_sptr result(new fn_parm_diff(first, second, ctxt));
7110  ctxt->initialize_canonical_diff(result);
7111 
7112  return result;
7113 }
7114 // </fn_parm_diff stuff>
7115 
7116 // <function_type_diff stuff>
7117 
7118 void
7119 function_type_diff::ensure_lookup_tables_populated()
7120 {
7121  priv_->return_type_diff_ =
7122  compute_diff(first_function_type()->get_return_type(),
7123  second_function_type()->get_return_type(),
7124  context());
7125 
7126  string parm_name;
7128  for (vector<deletion>::const_iterator i =
7129  priv_->parm_changes_.deletions().begin();
7130  i != priv_->parm_changes_.deletions().end();
7131  ++i)
7132  {
7133  parm = *(first_function_type()->get_first_parm()
7134  + i->index());
7135  parm_name = parm->get_name_id();
7136  // If for a reason the type name is empty we want to know and
7137  // fix that.
7138  ABG_ASSERT(!parm_name.empty());
7139  priv_->deleted_parms_[parm_name] = parm;
7140  priv_->deleted_parms_by_id_[parm->get_index()] = parm;
7141  }
7142 
7143  for (vector<insertion>::const_iterator i =
7144  priv_->parm_changes_.insertions().begin();
7145  i != priv_->parm_changes_.insertions().end();
7146  ++i)
7147  {
7148  for (vector<unsigned>::const_iterator j =
7149  i->inserted_indexes().begin();
7150  j != i->inserted_indexes().end();
7151  ++j)
7152  {
7153  parm = *(second_function_type()->get_first_parm() + *j);
7154  parm_name = parm->get_name_id();
7155  // If for a reason the type name is empty we want to know and
7156  // fix that.
7157  ABG_ASSERT(!parm_name.empty());
7158  {
7159  string_parm_map::const_iterator k =
7160  priv_->deleted_parms_.find(parm_name);
7161  if (k != priv_->deleted_parms_.end())
7162  {
7163  if (*k->second != *parm)
7164  priv_->subtype_changed_parms_[parm_name] =
7165  compute_diff(k->second, parm, context());
7166  priv_->deleted_parms_.erase(parm_name);
7167  }
7168  else
7169  priv_->added_parms_[parm_name] = parm;
7170  }
7171  {
7172  unsigned_parm_map::const_iterator k =
7173  priv_->deleted_parms_by_id_.find(parm->get_index());
7174  if (k != priv_->deleted_parms_by_id_.end())
7175  {
7176  if (*k->second != *parm
7177  && (k->second->get_name_id() != parm_name))
7178  priv_->changed_parms_by_id_[parm->get_index()] =
7179  compute_diff(k->second, parm, context());
7180  priv_->added_parms_.erase(parm_name);
7181  priv_->deleted_parms_.erase(k->second->get_name_id());
7182  priv_->deleted_parms_by_id_.erase(parm->get_index());
7183  }
7184  else
7185  priv_->added_parms_by_id_[parm->get_index()] = parm;
7186  }
7187  }
7188  }
7189 
7190  sort_string_fn_parm_diff_sptr_map(priv_->subtype_changed_parms_,
7191  priv_->sorted_subtype_changed_parms_);
7192  sort_string_fn_parm_diff_sptr_map(priv_->changed_parms_by_id_,
7193  priv_->sorted_changed_parms_by_id_);
7194  sort_string_parm_map(priv_->deleted_parms_,
7195  priv_->sorted_deleted_parms_);
7196 
7197  sort_string_parm_map(priv_->added_parms_,
7198  priv_->sorted_added_parms_);
7199 }
7200 
7201 /// In the vector of deleted parameters, get the one that is at a given
7202 /// index.
7203 ///
7204 /// @param i the index of the deleted parameter to get.
7205 ///
7206 /// @return the parameter returned.
7208 function_type_diff::deleted_parameter_at(int i) const
7209 {return first_function_type()->get_parameters()[i];}
7210 
7211 /// Getter for the sorted vector of deleted parameters.
7212 ///
7213 /// @return the sorted vector of deleted parameters.
7214 const vector<function_decl::parameter_sptr>&
7216 {return priv_->sorted_deleted_parms_;}
7217 
7218 /// Getter for the sorted vector of added parameters .
7219 ///
7220 /// @return the sorted vector of added parameters.
7221 const vector<function_decl::parameter_sptr>&
7223 {return priv_->sorted_added_parms_;}
7224 
7225 /// In the vector of inserted parameters, get the one that is at a
7226 /// given index.
7227 ///
7228 /// @param i the index of the inserted parameter to get.
7229 ///
7230 /// @return the parameter returned.
7232 function_type_diff::inserted_parameter_at(int i) const
7233 {return second_function_type()->get_parameters()[i];}
7234 
7235 /// Consutrctor of the @ref function_type type.
7236 ///
7237 /// @param first the first @ref function_type subject of the diff to
7238 /// create.
7239 ///
7240 /// @param second the second @ref function_type subject of the diff to
7241 /// create.
7242 ///
7243 /// @param ctxt the diff context to be used by the newly created
7244 /// instance of function_type_diff. Note that this context object
7245 /// must stay alive at least during the life time of the current
7246 /// instance of @ref function_type_diff. Otherwise memory corruption
7247 /// issues occur.
7249  const function_type_sptr second,
7250  diff_context_sptr ctxt)
7251  : type_diff_base(first, second, ctxt),
7252  priv_(new priv)
7253 {}
7254 
7255 /// Getter for the first subject of the diff.
7256 ///
7257 /// @return the first function type involved in the diff.
7258 const function_type_sptr
7260 {return dynamic_pointer_cast<function_type>(first_subject());}
7261 
7262 /// Getter for the second subject of the diff.
7263 ///
7264 /// @return the second function type involved in the diff.
7265 const function_type_sptr
7267 {return dynamic_pointer_cast<function_type>(second_subject());}
7268 
7269 /// Getter for the diff of the return types of the two function types
7270 /// of the current diff.
7271 ///
7272 /// @return the diff of the return types of the two function types of
7273 /// the current diff.
7274 const diff_sptr
7276 {return priv_->return_type_diff_;}
7277 
7278 /// Getter for the map of function parameter changes of the current diff.
7279 ///
7280 /// @return a map of function parameter changes of the current diff.
7283 {return priv_->subtype_changed_parms_;}
7284 
7285 /// Getter for the map of parameters that got removed.
7286 ///
7287 /// @return the map of parameters that got removed.
7288 const string_parm_map&
7290 {return priv_->deleted_parms_;}
7291 
7292 /// Getter for the map of parameters that got added.
7293 ///
7294 /// @return the map of parameters that got added.
7295 const string_parm_map&
7297 {return priv_->added_parms_;}
7298 
7299 /// Build and return a copy of a pretty representation of the current
7300 /// instance of @ref function_type_diff.
7301 ///
7302 /// @return a copy of the pretty representation of the current
7303 /// instance of @ref function_type_diff.
7304 const string&
7306 {
7307  if (diff::priv_->pretty_representation_.empty())
7308  {
7309  std::ostringstream o;
7310  o << "function_type_diff["
7312  << ", "
7314  << "]";
7315  diff::priv_->pretty_representation_ = o.str();
7316  }
7317  return diff::priv_->pretty_representation_;
7318 }
7319 
7320 /// Test if the current diff node carries changes.
7321 ///
7322 /// @return true iff the current diff node carries changes.
7323 bool
7325 {return *first_function_type() != *second_function_type();}
7326 
7327 /// Test if the current diff node carries local changes.
7328 ///
7329 /// A local change is a change that is carried by this diff node, not
7330 /// by any of its children nodes.
7331 ///
7332 /// @return the kind of local change carried by the current diff node.
7333 /// The value returned is zero if the current node carries no local
7334 /// change.
7335 enum change_kind
7337 {
7338  ir::change_kind k = ir::NO_CHANGE_KIND;
7340  return k & ir::ALL_LOCAL_CHANGES_MASK;
7341  return ir::NO_CHANGE_KIND;
7342 }
7343 
7344 /// Build and emit a textual report about the current @ref
7345 /// function_type_diff instance.
7346 ///
7347 /// @param out the output stream.
7348 ///
7349 /// @param indent the indentation string to use.
7350 void
7351 function_type_diff::report(ostream& out, const string& indent) const
7352 {
7353  context()->get_reporter()->report(*this, out, indent);
7354 }
7355 
7356 /// Populate the vector of children node of the @ref diff base type
7357 /// sub-object of this instance of @ref function_type_diff.
7358 ///
7359 /// The children node can then later be retrieved using
7360 /// diff::children_node().
7361 void
7363 {
7364  if (diff_sptr d = return_type_diff())
7365  append_child_node(d);
7366 
7367  for (vector<fn_parm_diff_sptr>::const_iterator i =
7368  priv_->sorted_subtype_changed_parms_.begin();
7369  i != priv_->sorted_subtype_changed_parms_.end();
7370  ++i)
7371  if (diff_sptr d = *i)
7372  append_child_node(d);
7373 
7374  for (vector<fn_parm_diff_sptr>::const_iterator i =
7375  priv_->sorted_changed_parms_by_id_.begin();
7376  i != priv_->sorted_changed_parms_by_id_.end();
7377  ++i)
7378  if (diff_sptr d = *i)
7379  append_child_node(d);
7380 }
7381 
7382 /// Compute the diff between two instances of @ref function_type.
7383 ///
7384 /// Note that the two types must have been created in the same @ref
7385 /// environment, otherwise, this function aborts.
7386 ///
7387 /// @param first the first @ref function_type to consider for the diff.
7388 ///
7389 /// @param second the second @ref function_type to consider for the diff.
7390 ///
7391 /// @param ctxt the diff context to use.
7392 ///
7393 /// @return the resulting diff between the two @ref function_type.
7396  const function_type_sptr second,
7397  diff_context_sptr ctxt)
7398 {
7399  if (!first || !second)
7400  {
7401  // TODO: implement this for either first or second being NULL.
7402  return function_type_diff_sptr();
7403  }
7404 
7405  function_type_diff_sptr result(new function_type_diff(first, second, ctxt));
7406 
7407  diff_utils::compute_diff(first->get_first_parm(),
7408  first->get_parameters().end(),
7409  second->get_first_parm(),
7410  second->get_parameters().end(),
7411  result->priv_->parm_changes_);
7412 
7413  result->ensure_lookup_tables_populated();
7414 
7415  ctxt->initialize_canonical_diff(result);
7416 
7417  return result;
7418 }
7419 // </function_type_diff stuff>
7420 
7421 // <function_decl_diff stuff>
7422 
7423 /// Build the lookup tables of the diff, if necessary.
7424 void
7425 function_decl_diff::ensure_lookup_tables_populated()
7426 {
7427 }
7428 
7429 /// Populate the vector of children node of the @ref diff base type
7430 /// sub-object of this instance of @ref function_decl_diff.
7431 ///
7432 /// The children node can then later be retrieved using
7433 /// diff::children_node().
7434 void
7436 {
7437  if (diff_sptr d = type_diff())
7438  append_child_node(d);
7439 }
7440 
7441 /// Constructor for function_decl_diff
7442 ///
7443 /// @param first the first function considered by the diff.
7444 ///
7445 /// @param second the second function considered by the diff.
7446 ///
7447 /// @param ctxt the context of the diff. Note that this context
7448 /// object must stay alive at least during the life time of the
7449 /// current instance of @ref function_decl_diff. Otherwise memory
7450 /// corruption issues occur.
7452  const function_decl_sptr second,
7453  diff_context_sptr ctxt)
7454  : decl_diff_base(first, second, ctxt),
7455  priv_(new priv)
7456 {
7457 }
7458 
7459 /// @return the first function considered by the diff.
7460 const function_decl_sptr
7462 {return dynamic_pointer_cast<function_decl>(first_subject());}
7463 
7464 /// @return the second function considered by the diff.
7465 const function_decl_sptr
7467 {return dynamic_pointer_cast<function_decl>(second_subject());}
7468 
7470 function_decl_diff::type_diff() const
7471 {return priv_->type_diff_;}
7472 
7473 /// @return the pretty representation for the current instance of @ref
7474 /// function_decl_diff.
7475 const string&
7477 {
7478  if (diff::priv_->pretty_representation_.empty())
7479  {
7480  std::ostringstream o;
7481  o << "function_diff["
7482  << first_subject()->get_pretty_representation()
7483  << ", "
7484  << second_subject()->get_pretty_representation()
7485  << "]";
7486  diff::priv_->pretty_representation_ = o.str();
7487  }
7488  return diff::priv_->pretty_representation_;
7489 }
7490 
7491 /// Return true iff the current diff node carries a change.
7492 ///
7493 /// @return true iff the current diff node carries a change.
7494 bool
7496 {return *first_function_decl() != *second_function_decl();}
7497 
7498 /// @return the kind of local change carried by the current diff node.
7499 /// The value returned is zero if the current node carries no local
7500 /// change.
7501 enum change_kind
7503 {
7504  ir::change_kind k = ir::NO_CHANGE_KIND;
7506  return k & ir::ALL_LOCAL_CHANGES_MASK;
7507  return ir::NO_CHANGE_KIND;
7508 }
7509 
7510 /// Serialize a report of the changes encapsulated in the current
7511 /// instance of @ref function_decl_diff over to an output stream.
7512 ///
7513 /// @param out the output stream to serialize the report to.
7514 ///
7515 /// @param indent the string to use an an indentation prefix.
7516 void
7517 function_decl_diff::report(ostream& out, const string& indent) const
7518 {
7519  context()->get_reporter()->report(*this, out, indent);
7520 }
7521 
7522 /// Compute the diff between two function_decl.
7523 ///
7524 /// Note that the two decls must have been created in the same @ref
7525 /// environment, otherwise, this function aborts.
7526 ///
7527 /// @param first the first function_decl to consider for the diff
7528 ///
7529 /// @param second the second function_decl to consider for the diff
7530 ///
7531 /// @param ctxt the diff context to use.
7532 ///
7533 /// @return the computed diff
7536  const function_decl_sptr second,
7537  diff_context_sptr ctxt)
7538 {
7539  if (!first || !second)
7540  {
7541  // TODO: implement this for either first or second being NULL.
7542  return function_decl_diff_sptr();
7543  }
7544 
7545  function_type_diff_sptr type_diff = compute_diff(first->get_type(),
7546  second->get_type(),
7547  ctxt);
7548 
7549  function_decl_diff_sptr result(new function_decl_diff(first, second,
7550  ctxt));
7551  result->priv_->type_diff_ = type_diff;
7552 
7553  result->ensure_lookup_tables_populated();
7554 
7555  ctxt->initialize_canonical_diff(result);
7556 
7557  return result;
7558 }
7559 
7560 // </function_decl_diff stuff>
7561 
7562 // <type_decl_diff stuff>
7563 
7564 /// Constructor for type_decl_diff.
7565 ///
7566 /// @param first the first subject of the diff.
7567 ///
7568 /// @param second the second subject of the diff.
7569 ///
7570 /// @param ctxt the context of the diff. Note that this context
7571 /// object must stay alive at least during the life time of the
7572 /// current instance of @ref type_decl_diff. Otherwise memory
7573 /// corruption issues occur.
7574 type_decl_diff::type_decl_diff(const type_decl_sptr first,
7575  const type_decl_sptr second,
7576  diff_context_sptr ctxt)
7577  : type_diff_base(first, second, ctxt)
7578 {}
7579 
7580 /// Getter for the first subject of the type_decl_diff.
7581 ///
7582 /// @return the first type_decl involved in the diff.
7583 const type_decl_sptr
7585 {return dynamic_pointer_cast<type_decl>(first_subject());}
7586 
7587 /// Getter for the second subject of the type_decl_diff.
7588 ///
7589 /// @return the second type_decl involved in the diff.
7590 const type_decl_sptr
7592 {return dynamic_pointer_cast<type_decl>(second_subject());}
7593 
7594 /// @return the pretty representation for the current instance of @ref
7595 /// type_decl_diff.
7596 const string&
7598 {
7599  if (diff::priv_->pretty_representation_.empty())
7600  {
7601  std::ostringstream o;
7602  o << "type_decl_diff["
7603  << first_subject()->get_pretty_representation()
7604  << ", "
7605  << second_subject()->get_pretty_representation()
7606  << "]";
7607  diff::priv_->pretty_representation_ = o.str();
7608  }
7609  return diff::priv_->pretty_representation_;
7610 }
7611 /// Return true iff the current diff node carries a change.
7612 ///
7613 /// @return true iff the current diff node carries a change.
7614 bool
7616 {return first_type_decl() != second_type_decl();}
7617 
7618 /// @return the kind of local change carried by the current diff node.
7619 /// The value returned is zero if the current node carries no local
7620 /// change.
7621 enum change_kind
7623 {
7624  ir::change_kind k = ir::NO_CHANGE_KIND;
7625  if (!equals(*first_type_decl(), *second_type_decl(), &k))
7626  return k & ir::ALL_LOCAL_CHANGES_MASK;
7627  return ir::NO_CHANGE_KIND;
7628 }
7629 /// Ouputs a report of the differences between of the two type_decl
7630 /// involved in the type_decl_diff.
7631 ///
7632 /// @param out the output stream to emit the report to.
7633 ///
7634 /// @param indent the string to use for indentatino indent.
7635 void
7636 type_decl_diff::report(ostream& out, const string& indent) const
7637 {
7638  context()->get_reporter()->report(*this, out, indent);
7639 }
7640 
7641 /// Compute a diff between two type_decl.
7642 ///
7643 /// Note that the two types must have been created in the same @ref
7644 /// environment, otherwise, this function aborts.
7645 ///
7646 /// This function doesn't actually compute a diff. As a type_decl is
7647 /// very simple (unlike compound constructs like function_decl or
7648 /// class_decl) it's easy to just compare the components of the
7649 /// type_decl to know what has changed. Thus this function just
7650 /// builds and return a type_decl_diff object. The
7651 /// type_decl_diff::report function will just compare the components
7652 /// of the the two type_decl and display where and how they differ.
7653 ///
7654 /// @param first a pointer to the first type_decl to
7655 /// consider.
7656 ///
7657 /// @param second a pointer to the second type_decl to consider.
7658 ///
7659 /// @param ctxt the diff context to use.
7660 ///
7661 /// @return a pointer to the resulting type_decl_diff.
7664  const type_decl_sptr second,
7665  diff_context_sptr ctxt)
7666 {
7667  type_decl_diff_sptr result(new type_decl_diff(first, second, ctxt));
7668 
7669  // We don't need to actually compute a diff here as a type_decl
7670  // doesn't have complicated sub-components. type_decl_diff::report
7671  // just walks the members of the type_decls and display information
7672  // about the ones that have changed. On a similar note,
7673  // type_decl_diff::length returns 0 if the two type_decls are equal,
7674  // and 1 otherwise.
7675 
7676  ctxt->initialize_canonical_diff(result);
7677 
7678  return result;
7679 }
7680 
7681 // </type_decl_diff stuff>
7682 
7683 // <typedef_diff stuff>
7684 
7685 /// Populate the vector of children node of the @ref diff base type
7686 /// sub-object of this instance of @ref typedef_diff.
7687 ///
7688 /// The children node can then later be retrieved using
7689 /// diff::children_node().
7690 void
7693 
7694 /// Constructor for typedef_diff.
7695 ///
7696 /// @param first the first subject of the diff.
7697 ///
7698 /// @param second the second subject of the diff.
7699 ///
7700 /// @param underlying the underlying diff of the @ref typedef_diff.
7701 /// That is the diff between the underlying types of @p first and @p
7702 /// second.
7703 ///
7704 /// @param ctxt the context of the diff. Note that this context
7705 /// object must stay alive at least during the life time of the
7706 /// current instance of @ref typedef_diff. Otherwise memory
7707 /// corruption issues occur.
7708 typedef_diff::typedef_diff(const typedef_decl_sptr first,
7709  const typedef_decl_sptr second,
7710  const diff_sptr underlying,
7711  diff_context_sptr ctxt)
7712  : type_diff_base(first, second, ctxt),
7713  priv_(new priv(underlying))
7714 {}
7715 
7716 /// Getter for the firt typedef_decl involved in the diff.
7717 ///
7718 /// @return the first subject of the diff.
7719 const typedef_decl_sptr
7721 {return dynamic_pointer_cast<typedef_decl>(first_subject());}
7722 
7723 /// Getter for the second typedef_decl involved in the diff.
7724 ///
7725 /// @return the second subject of the diff.
7726 const typedef_decl_sptr
7728 {return dynamic_pointer_cast<typedef_decl>(second_subject());}
7729 
7730 /// Getter for the diff between the two underlying types of the
7731 /// typedefs.
7732 ///
7733 /// @return the diff object reprensenting the difference between the
7734 /// two underlying types of the typedefs.
7735 const diff_sptr
7737 {return priv_->underlying_type_diff_;}
7738 
7739 /// Setter for the diff between the two underlying types of the
7740 /// typedefs.
7741 ///
7742 /// @param d the new diff object reprensenting the difference between
7743 /// the two underlying types of the typedefs.
7744 void
7746 {priv_->underlying_type_diff_ = d;}
7747 
7748 /// @return the pretty representation for the current instance of @ref
7749 /// typedef_diff.
7750 const string&
7752 {
7753  if (diff::priv_->pretty_representation_.empty())
7754  {
7755  std::ostringstream o;
7756  o << "typedef_diff["
7757  << first_subject()->get_pretty_representation()
7758  << ", "
7759  << second_subject()->get_pretty_representation()
7760  << "]";
7761  diff::priv_->pretty_representation_ = o.str();
7762  }
7763  return diff::priv_->pretty_representation_;
7764 }
7765 
7766 /// Return true iff the current diff node carries a change.
7767 ///
7768 /// @return true iff the current diff node carries a change.
7769 bool
7771 {
7772  decl_base_sptr second = second_typedef_decl();
7773  return !(*first_typedef_decl() == *second);
7774 }
7775 
7776 /// @return the kind of local change carried by the current diff node.
7777 /// The value returned is zero if the current node carries no local
7778 /// change.
7779 enum change_kind
7781 {
7782  ir::change_kind k = ir::NO_CHANGE_KIND;
7784  return k & ir::ALL_LOCAL_CHANGES_MASK;
7785  return ir::NO_CHANGE_KIND;
7786 }
7787 
7788 /// Reports the difference between the two subjects of the diff in a
7789 /// serialized form.
7790 ///
7791 /// @param out the output stream to emit the report to.
7792 ///
7793 /// @param indent the indentation string to use.
7794 void
7795 typedef_diff::report(ostream& out, const string& indent) const
7796 {
7797  context()->get_reporter()->report(*this, out, indent);
7798 }
7799 
7800 /// Compute a diff between two typedef_decl.
7801 ///
7802 /// Note that the two types must have been created in the same @ref
7803 /// environment, otherwise, this function aborts.
7804 ///
7805 /// @param first a pointer to the first typedef_decl to consider.
7806 ///
7807 /// @param second a pointer to the second typedef_decl to consider.
7808 ///
7809 /// @param ctxt the diff context to use.
7810 ///
7811 /// @return a pointer to the the resulting typedef_diff.
7814  const typedef_decl_sptr second,
7815  diff_context_sptr ctxt)
7816 {
7817  diff_sptr d = compute_diff_for_types(first->get_underlying_type(),
7818  second->get_underlying_type(),
7819  ctxt);
7820  typedef_diff_sptr result(new typedef_diff(first, second, d, ctxt));
7821 
7822  ctxt->initialize_canonical_diff(result);
7823 
7824  return result;
7825 }
7826 
7827 /// Return the leaf underlying diff node of a @ref typedef_diff node.
7828 ///
7829 /// If the underlying diff node of a @ref typedef_diff node is itself
7830 /// a @ref typedef_diff node, then recursively look at the underlying
7831 /// diff nodes to get the first one that is not a a @ref typedef_diff
7832 /// node. This is what a leaf underlying diff node means.
7833 ///
7834 /// Otherwise, if the underlying diff node of @ref typedef_diff is
7835 /// *NOT* a @ref typedef_diff node, then just return the underlying
7836 /// diff node.
7837 ///
7838 /// And if the diff node considered is not a @ref typedef_diff node,
7839 /// then just return it.
7840 ///
7841 /// @return the leaf underlying diff node of a @p diff.
7842 const diff*
7844 {
7845  const typedef_diff* d = dynamic_cast<const typedef_diff*>(diff);
7846  if (!d)
7847  return diff;
7848 
7849  if (const typedef_diff* deef =
7850  dynamic_cast<const typedef_diff*>(d->underlying_type_diff().get()))
7852 
7853  return d->underlying_type_diff().get();
7854 }
7855 
7856 // </typedef_diff stuff>
7857 
7858 // <translation_unit_diff stuff>
7859 
7860 /// Constructor for translation_unit_diff.
7861 ///
7862 /// @param first the first translation unit to consider for this diff.
7863 ///
7864 /// @param second the second translation unit to consider for this diff.
7865 ///
7866 /// @param ctxt the context of the diff. Note that this context
7867 /// object must stay alive at least during the life time of the
7868 /// current instance of @ref translation_unit_diff. Otherwise memory
7869 /// corruption issues occur.
7871  translation_unit_sptr second,
7872  diff_context_sptr ctxt)
7873  : scope_diff(first->get_global_scope(), second->get_global_scope(), ctxt),
7874  priv_(new priv(first, second))
7875 {
7876 }
7877 
7878 /// Getter for the first translation unit of this diff.
7879 ///
7880 /// @return the first translation unit of this diff.
7883 {return priv_->first_;}
7884 
7885 /// Getter for the second translation unit of this diff.
7886 ///
7887 /// @return the second translation unit of this diff.
7890 {return priv_->second_;}
7891 
7892 /// Return true iff the current diff node carries a change.
7893 ///
7894 /// @return true iff the current diff node carries a change.
7895 bool
7897 {return scope_diff::has_changes();}
7898 
7899 /// @return the kind of local change carried by the current diff node.
7900 /// The value returned is zero if the current node carries no local
7901 /// change.
7902 enum change_kind
7904 {return ir::NO_CHANGE_KIND;}
7905 
7906 /// Report the diff in a serialized form.
7907 ///
7908 /// @param out the output stream to serialize the report to.
7909 ///
7910 /// @param indent the prefix to use as indentation for the report.
7911 void
7912 translation_unit_diff::report(ostream& out, const string& indent) const
7913 {scope_diff::report(out, indent);}
7914 
7915 /// Compute the diff between two translation_units.
7916 ///
7917 /// Note that the two translation units must have been created in the
7918 /// same @ref environment, otherwise, this function aborts.
7919 ///
7920 /// @param first the first translation_unit to consider.
7921 ///
7922 /// @param second the second translation_unit to consider.
7923 ///
7924 /// @param ctxt the diff context to use. If null, this function will
7925 /// create a new context and set to the diff object returned.
7926 ///
7927 /// @return the newly created diff object.
7930  const translation_unit_sptr second,
7931  diff_context_sptr ctxt)
7932 {
7933  ABG_ASSERT(first && second);
7934 
7935  if (!ctxt)
7936  ctxt.reset(new diff_context);
7937 
7938  // TODO: handle first or second having empty contents.
7939  translation_unit_diff_sptr tu_diff(new translation_unit_diff(first, second,
7940  ctxt));
7941  scope_diff_sptr sc_diff = dynamic_pointer_cast<scope_diff>(tu_diff);
7942 
7943  compute_diff(static_pointer_cast<scope_decl>(first->get_global_scope()),
7944  static_pointer_cast<scope_decl>(second->get_global_scope()),
7945  sc_diff,
7946  ctxt);
7947 
7948  ctxt->initialize_canonical_diff(tu_diff);
7949 
7950  return tu_diff;
7951 }
7952 
7953 // </translation_unit_diff stuff>
7954 
7955 // <diff_maps stuff>
7956 
7957 /// The private data of the @ref diff_maps type.
7958 struct diff_maps::priv
7959 {
7960  string_diff_ptr_map type_decl_diff_map_;
7961  string_diff_ptr_map enum_diff_map_;
7962  string_diff_ptr_map class_diff_map_;
7963  string_diff_ptr_map union_diff_map_;
7964  string_diff_ptr_map typedef_diff_map_;
7965  string_diff_ptr_map subrange_diff_map_;
7966  string_diff_ptr_map array_diff_map_;
7967  string_diff_ptr_map reference_diff_map_;
7968  string_diff_ptr_map function_type_diff_map_;
7969  string_diff_ptr_map function_decl_diff_map_;
7970  string_diff_ptr_map var_decl_diff_map_;
7971  string_diff_ptr_map distinct_diff_map_;
7972  string_diff_ptr_map fn_parm_diff_map_;
7973  diff_artifact_set_map_type impacted_artifacts_map_;
7974 }; // end struct diff_maps::priv
7975 
7976 /// Default constructor of the @ref diff_maps type.
7978  : priv_(new diff_maps::priv())
7979 {}
7980 
7981 diff_maps::~diff_maps() = default;
7982 
7983 /// Getter of the map that contains basic type diffs.
7984 ///
7985 /// @return the map that contains basic type diffs.
7986 const string_diff_ptr_map&
7988 {return priv_->type_decl_diff_map_;}
7989 
7990 /// Getter of the map that contains basic type diffs.
7991 ///
7992 /// @return the map that contains basic type diffs.
7995 {return priv_->type_decl_diff_map_;}
7996 
7997 /// Getter of the map that contains enum type diffs.
7998 ///
7999 /// @return the map that contains enum type diffs.
8000 const string_diff_ptr_map&
8002 {return priv_->enum_diff_map_;}
8003 
8004 /// Getter of the map that contains enum type diffs.
8005 ///
8006 /// @return the map that contains enum type diffs.
8009 {return priv_->enum_diff_map_;}
8010 
8011 /// Getter of the map that contains class type diffs.
8012 ///
8013 /// @return the map that contains class type diffs.
8014 const string_diff_ptr_map&
8016 {return priv_->class_diff_map_;}
8017 
8018 /// Getter of the map that contains class type diffs.
8019 ///
8020 /// @return the map that contains class type diffs.
8023 {return priv_->class_diff_map_;}
8024 
8025 /// Getter of the map that contains union type diffs.
8026 ///
8027 /// @return the map that contains union type diffs.
8028 const string_diff_ptr_map&
8030 {return priv_->union_diff_map_;}
8031 
8032 /// Getter of the map that contains union type diffs.
8033 ///
8034 /// @return the map that contains union type diffs.
8037 {return priv_->union_diff_map_;}
8038 
8039 /// Getter of the map that contains typedef type diffs.
8040 ///
8041 /// @return the map that contains typedef type diffs.
8042 const string_diff_ptr_map&
8044 {return priv_->typedef_diff_map_;}
8045 
8046 /// Getter of the map that contains typedef type diffs.
8047 ///
8048 /// @return the map that contains typedef type diffs.
8051 {return priv_->typedef_diff_map_;}
8052 
8053 /// Getter of the map that contains subrange type diffs.
8054 ///
8055 /// @return the map that contains subrange type diffs.
8056 const string_diff_ptr_map&
8058 {return priv_->subrange_diff_map_;}
8059 
8060 /// Getter of the map that contains subrange type diffs.
8061 ///
8062 /// @return the map that contains subrange type diffs.
8065 {return priv_->subrange_diff_map_;}
8066 
8067 /// Getter of the map that contains array type diffs.
8068 ///
8069 /// @return the map that contains array type diffs.
8070 const string_diff_ptr_map&
8072 {return priv_->array_diff_map_;}
8073 
8074 /// Getter of the map that contains array type diffs.
8075 ///
8076 /// @return the map that contains array type diffs.
8079 {return priv_->array_diff_map_;}
8080 
8081 /// Getter of the map that contains reference type diffs.
8082 ///
8083 /// @return the map that contains reference type diffs.
8084 const string_diff_ptr_map&
8086 {return priv_->reference_diff_map_;}
8087 
8088 /// Getter of the map that contains reference type diffs.
8089 ///
8090 /// @return the map that contains reference type diffs.
8093 {{return priv_->reference_diff_map_;}}
8094 
8095 /// Getter of the map that contains function parameter diffs.
8096 ///
8097 /// @return the map that contains function parameter diffs.
8098 const string_diff_ptr_map&
8100 {return priv_->fn_parm_diff_map_;}
8101 
8102 /// Getter of the map that contains function parameter diffs.
8103 ///
8104 /// @return the map that contains function parameter diffs.
8107 {return priv_->fn_parm_diff_map_;}
8108 
8109 /// Getter of the map that contains function type diffs.
8110 ///
8111 /// @return the map that contains function type diffs.
8112 const string_diff_ptr_map&
8114 {return priv_->function_type_diff_map_;}
8115 
8116 /// Getter of the map that contains function type diffs.
8117 ///
8118 /// @return the map that contains function type diffs.
8121 {return priv_->function_type_diff_map_;}
8122 
8123 /// Getter of the map that contains function decl diffs.
8124 ///
8125 /// @return the map that contains function decl diffs.
8126 const string_diff_ptr_map&
8128 {return priv_->function_decl_diff_map_;}
8129 
8130 /// Getter of the map that contains function decl diffs.
8131 ///
8132 /// @return the map that contains function decl diffs.
8135 {return priv_->function_decl_diff_map_;}
8136 
8137 /// Getter of the map that contains var decl diffs.
8138 ///
8139 /// @return the map that contains var decl diffs.
8140 const string_diff_ptr_map&
8142 {return priv_->var_decl_diff_map_;}
8143 
8144 /// Getter of the map that contains var decl diffs.
8145 ///
8146 /// @return the map that contains var decl diffs.
8149 {return priv_->var_decl_diff_map_;}
8150 
8151 /// Getter of the map that contains distinct diffs.
8152 ///
8153 /// @return the map that contains distinct diffs.
8154 const string_diff_ptr_map&
8156 {return priv_->distinct_diff_map_;}
8157 
8158 /// Getter of the map that contains distinct diffs.
8159 ///
8160 /// @return the map that contains distinct diffs.
8163 {return priv_->distinct_diff_map_;}
8164 
8165 /// Insert a new diff node into the current instance of @ref diff_maps.
8166 ///
8167 /// @param dif the new diff node to insert into the @ref diff_maps.
8168 ///
8169 /// @param impacted_iface the interface (global function or variable)
8170 /// currently being analysed that led to analysing the diff node @p
8171 /// dif. In other words, this is the interface impacted by the diff
8172 /// node @p dif. Note that this can be nil in cases where we are
8173 /// directly analysing changes to a type that is not reachable from
8174 /// any global function or variable.
8175 ///
8176 /// @return true iff the diff node could be added to the current
8177 /// instance of @ref diff_maps.
8178 bool
8180  const type_or_decl_base_sptr& impacted_iface)
8181 {
8182  string n = get_pretty_representation(dif->first_subject(),
8183  /*internal=*/true);
8184  if (const type_decl_diff *d = is_diff_of_basic_type(dif))
8185  get_type_decl_diff_map()[n] = const_cast<type_decl_diff*>(d);
8186  else if (const enum_diff *d = is_enum_diff(dif))
8187  get_enum_diff_map()[n] = const_cast<enum_diff*>(d);
8188  else if (const class_diff *d = is_class_diff(dif))
8189  get_class_diff_map()[n] = const_cast<class_diff*>(d);
8190  else if (const union_diff *d = is_union_diff(dif))
8191  get_union_diff_map()[n] = const_cast<union_diff*>(d);
8192  else if (const typedef_diff *d = is_typedef_diff(dif))
8193  get_typedef_diff_map()[n] = const_cast<typedef_diff*>(d);
8194  else if (const subrange_diff *d = is_subrange_diff(dif))
8195  get_subrange_diff_map()[n] = const_cast<subrange_diff*>(d);
8196  else if (const array_diff *d = is_array_diff(dif))
8197  get_array_diff_map()[n] = const_cast<array_diff*>(d);
8198  else if (const reference_diff *d = is_reference_diff(dif))
8199  get_reference_diff_map()[n] = const_cast<reference_diff*>(d);
8200  else if (const fn_parm_diff *d = is_fn_parm_diff(dif))
8201  get_fn_parm_diff_map()[n] = const_cast<fn_parm_diff*>(d);
8202  else if (const function_type_diff *d = is_function_type_diff(dif))
8203  get_function_type_diff_map()[n] = const_cast<function_type_diff*>(d);
8204  else if (const var_diff *d = is_var_diff(dif))
8205  get_var_decl_diff_map()[n] = const_cast<var_diff*>(d);
8206  else if (const function_decl_diff *d = is_function_decl_diff(dif))
8207  get_function_decl_diff_map()[n] = const_cast<function_decl_diff*>(d);
8208  else if (const distinct_diff *d = is_distinct_diff(dif))
8209  get_distinct_diff_map()[n] = const_cast<distinct_diff*>(d);
8210  else if (is_base_diff(dif))
8211  // we silently drop this case.
8212  return true;
8213  else
8215 
8216  // Update the map that associates this diff node to the set of
8217  // interfaces it impacts.
8218 
8219  if (impacted_iface)
8220  {
8221  diff_artifact_set_map_type::iterator i =
8222  priv_->impacted_artifacts_map_.find(dif);
8223 
8224  if (i == priv_->impacted_artifacts_map_.end())
8225  {
8227  set.insert(impacted_iface);
8228  priv_->impacted_artifacts_map_[dif] = set;
8229  }
8230  else
8231  i->second.insert(impacted_iface);
8232  }
8233 
8234  return true;
8235 }
8236 
8237 /// Lookup the interfaces that are impacted by a given leaf diff node.
8238 ///
8239 /// @param d the diff node to consider.
8240 ///
8241 /// @return the set of artifacts impacted by @p d.
8244 {
8245  diff_artifact_set_map_type::iterator i =
8246  priv_->impacted_artifacts_map_.find(d);
8247 
8248  if (i == priv_->impacted_artifacts_map_.end())
8249  return 0;
8250 
8251  return &i->second;
8252 }
8253 
8254 //
8255 // </diff_maps stuff>
8256 
8257 /// Constructor for the @ref diff_stat type.
8258 ///
8259 /// @param ctxt the context of the corpus diff. Note that this
8260 /// context object must stay alive at least during the life time of
8261 /// the current instance of @ref corpus_diff::diff_stats. Otherwise
8262 /// memory corruption issues occur.
8263 corpus_diff::diff_stats::diff_stats(diff_context_sptr ctxt)
8264  : priv_(new priv(ctxt))
8265 {}
8266 
8267 /// Getter for the number of functions removed.
8268 ///
8269 /// @return the number of functions removed.
8270 size_t
8272 {return priv_->num_func_removed;}
8273 
8274 /// Setter for the number of functions removed.
8275 ///
8276 /// @param n the new number of functions removed.
8277 void
8279 {priv_->num_func_removed = n;}
8280 
8281 /// Getter for the number of removed functions that have been filtered
8282 /// out.
8283 ///
8284 /// @return the number of removed functions that have been filtered
8285 /// out.
8286 size_t
8288 {
8289  if (priv_->ctxt() && !priv_->ctxt()->show_deleted_fns())
8290  return num_func_removed();
8291  return priv_->num_removed_func_filtered_out;
8292 }
8293 
8294 /// Setter for the number of removed functions that have been filtered
8295 /// out.
8296 ///
8297 /// @param t the new value.
8298 void
8300 {priv_->num_removed_func_filtered_out = t;}
8301 
8302 /// Getter for the net number of function removed.
8303 ///
8304 /// This is the difference between the number of functions removed and
8305 /// the number of functons removed that have been filtered out.
8306 ///
8307 /// @return the net number of function removed.
8308 size_t
8310 {
8311  ABG_ASSERT(num_func_removed() >= num_removed_func_filtered_out());
8312  return num_func_removed() - num_removed_func_filtered_out();
8313 }
8314 
8315 /// Getter for the number of functions added.
8316 ///
8317 /// @return the number of functions added.
8318 size_t
8320 {return priv_->num_func_added;}
8321 
8322 /// Setter for the number of functions added.
8323 ///
8324 /// @param n the new number of functions added.
8325 void
8327 {priv_->num_func_added = n;}
8328 
8329 /// Getter for the number of added function that have been filtered out.
8330 ///
8331 /// @return the number of added function that have been filtered out.
8332 size_t
8334 {
8335  if (priv_->ctxt() && !priv_->ctxt()->show_added_fns())
8336  return num_func_added();
8337  return priv_->num_added_func_filtered_out;
8338 }
8339 
8340 /// Setter for the number of added function that have been filtered
8341 /// out.
8342 ///
8343 /// @param n the new value.
8344 void
8346 {priv_->num_added_func_filtered_out = n;}
8347 
8348 /// Getter for the net number of added functions.
8349 ///
8350 /// The net number of added functions is the difference between the
8351 /// number of added functions and the number of added functions that
8352 /// have been filtered out.
8353 ///
8354 /// @return the net number of added functions.
8355 size_t
8357 {
8358  ABG_ASSERT(num_func_added() >= num_added_func_filtered_out());
8359  return num_func_added() - num_added_func_filtered_out();
8360 }
8361 
8362 /// Getter for the number of functions that have a change in one of
8363 /// their sub-types.
8364 ///
8365 /// @return the number of functions that have a change in one of their
8366 /// sub-types.
8367 size_t
8369 {return priv_->num_func_changed;}
8370 
8371 /// Setter for the number of functions that have a change in one of
8372 /// their sub-types.
8373 ///
8374 /// @@param n the new number of functions that have a change in one of
8375 /// their sub-types.
8376 void
8378 {priv_->num_func_changed = n;}
8379 
8380 /// Getter for the number of functions that have a change in one of
8381 /// their sub-types, and that have been filtered out.
8382 ///
8383 /// @return the number of functions that have a change in one of their
8384 /// sub-types, and that have been filtered out.
8385 size_t
8387 {return priv_->num_changed_func_filtered_out;}
8388 
8389 /// Setter for the number of functions that have a change in one of
8390 /// their sub-types, and that have been filtered out.
8391 ///
8392 /// @param n the new number of functions that have a change in one of their
8393 /// sub-types, and that have been filtered out.
8394 void
8396 {priv_->num_changed_func_filtered_out = n;}
8397 
8398 /// Getter for the number of functions that carry virtual member
8399 /// offset changes.
8400 ///
8401 /// @return the number of functions that carry virtual member changes.
8402 size_t
8404 {return priv_->num_func_with_virt_offset_changes;}
8405 
8406 /// Setter for the number of functions that carry virtual member
8407 /// offset changes.
8408 ///
8409 /// @param n the new number of functions that carry virtual member
8410 /// offset. changes.
8411 void
8413 {priv_->num_func_with_virt_offset_changes = n;}
8414 
8415 /// Getter for the number of functions that have a change in their
8416 /// sub-types, minus the number of these functions that got filtered
8417 /// out from the diff.
8418 ///
8419 /// @return for the the number of functions that have a change in
8420 /// their sub-types, minus the number of these functions that got
8421 /// filtered out from the diff.
8422 size_t
8424 {return num_func_changed() - num_changed_func_filtered_out();}
8425 
8426 /// Getter for the number of variables removed.
8427 ///
8428 /// @return the number of variables removed.
8429 size_t
8431 {return priv_->num_vars_removed;}
8432 
8433 /// Setter for the number of variables removed.
8434 ///
8435 /// @param n the new number of variables removed.
8436 void
8438 {priv_->num_vars_removed = n;}
8439 
8440 /// Getter for the number removed variables that have been filtered
8441 /// out.
8442 ///
8443 /// @return the number removed variables that have been filtered out.
8444 size_t
8446 {
8447  if (priv_->ctxt() && !priv_->ctxt()->show_deleted_vars())
8448  return num_vars_removed();
8449  return priv_->num_removed_vars_filtered_out;
8450 }
8451 
8452 /// Setter for the number of removed variables that have been filtered
8453 /// out.
8454 ///
8455 /// @param n the new value.
8456 void
8458 {priv_->num_removed_vars_filtered_out = n;}
8459 
8460 /// Getter for the net number of removed variables.
8461 ///
8462 /// The net number of removed variables is the difference between the
8463 /// number of removed variables and the number of removed variables
8464 /// that have been filtered out.
8465 ///
8466 /// @return the net number of removed variables.
8467 size_t
8469 {
8470  ABG_ASSERT(num_vars_removed() >= num_removed_vars_filtered_out());
8471  return num_vars_removed() - num_removed_vars_filtered_out();
8472 }
8473 
8474 /// Getter for the number of variables added.
8475 ///
8476 /// @return the number of variables added.
8477 size_t
8479 {return priv_->num_vars_added;}
8480 
8481 /// Setter for the number of variables added.
8482 ///
8483 /// @param n the new number of variables added.
8484 void
8486 {priv_->num_vars_added = n;}
8487 
8488 /// Getter for the number of added variables that have been filtered
8489 /// out.
8490 ///
8491 /// @return the number of added variables that have been filtered out.
8492 size_t
8494 {
8495  if (priv_->ctxt() && !priv_->ctxt()->show_added_vars())
8496  return num_vars_added();
8497  return priv_->num_added_vars_filtered_out;
8498 }
8499 
8500 /// Setter for the number of added variables that have been filtered
8501 /// out.
8502 ///
8503 /// @param n the new value.
8504 void
8506 {priv_->num_added_vars_filtered_out = n;}
8507 
8508 /// Getter for the net number of added variables.
8509 ///
8510 /// The net number of added variables is the difference between the
8511 /// number of added variables and the number of added variables that
8512 /// have been filetered out.
8513 ///
8514 /// @return the net number of added variables.
8515 size_t
8517 {
8518  ABG_ASSERT(num_vars_added() >= num_added_vars_filtered_out());
8519  return num_vars_added() - num_added_vars_filtered_out();
8520 }
8521 
8522 /// Getter for the number of variables that have a change in one of
8523 /// their sub-types.
8524 ///
8525 /// @return the number of variables that have a change in one of their
8526 /// sub-types.
8527 size_t
8529 {return priv_->num_vars_changed;}
8530 
8531 /// Setter for the number of variables that have a change in one of
8532 /// their sub-types.
8533 ///
8534 /// @param n the new number of variables that have a change in one of
8535 /// their sub-types.
8536 void
8538 {priv_->num_vars_changed = n;}
8539 
8540 /// Getter for the number of variables that have a change in one of
8541 /// their sub-types, and that have been filtered out.
8542 ///
8543 /// @return the number of functions that have a change in one of their
8544 /// sub-types, and that have been filtered out.
8545 size_t
8547 {return priv_->num_changed_vars_filtered_out;}
8548 
8549 /// Setter for the number of variables that have a change in one of
8550 /// their sub-types, and that have been filtered out.
8551 ///
8552 /// @param n the new number of variables that have a change in one of their
8553 /// sub-types, and that have been filtered out.
8554 void
8556 {priv_->num_changed_vars_filtered_out = n;}
8557 
8558 /// Getter for the number of variables that have a change in their
8559 /// sub-types, minus the number of these variables that got filtered
8560 /// out from the diff.
8561 ///
8562 /// @return for the the number of variables that have a change in
8563 /// their sub-types, minus the number of these variables that got
8564 /// filtered out from the diff.
8565 size_t
8567 {return num_vars_changed() - num_changed_vars_filtered_out();}
8568 
8569 /// Getter for the number of function symbols (not referenced by any
8570 /// debug info) that got removed.
8571 ///
8572 /// @return the number of function symbols (not referenced by any
8573 /// debug info) that got removed.
8574 size_t
8576 {return priv_->num_func_syms_removed;}
8577 
8578 /// Setter for the number of function symbols (not referenced by any
8579 /// debug info) that got removed.
8580 ///
8581 /// @param n the number of function symbols (not referenced by any
8582 /// debug info) that got removed.
8583 void
8585 {priv_->num_func_syms_removed = n;}
8586 
8587 /// Getter for the number of removed function symbols, not referenced
8588 /// by debug info, that have been filtered out.
8589 ///
8590 /// @return the number of removed function symbols, not referenced by
8591 /// debug info, that have been filtered out.
8592 size_t
8594 {
8595  if (priv_->ctxt()
8596  && !priv_->ctxt()->show_symbols_unreferenced_by_debug_info())
8597  return num_func_syms_removed();
8598  return priv_->num_removed_func_syms_filtered_out;
8599 }
8600 
8601 /// Setter for the number of removed function symbols, not referenced
8602 /// by debug info, that have been filtered out.
8603 ///
8604 /// @param n the new the number of removed function symbols, not
8605 /// referenced by debug info, that have been filtered out.
8606 void
8608 {priv_->num_removed_func_syms_filtered_out = n;}
8609 
8610 /// Getter of the net number of removed function symbols that are not
8611 /// referenced by any debug info.
8612 ///
8613 /// This is the difference between the total number of removed
8614 /// function symbols and the number of removed function symbols that
8615 /// have been filteted out. Both numbers are for symbols not
8616 /// referenced by debug info.
8617 ///
8618 /// return the net number of removed function symbols that are not
8619 /// referenced by any debug info.
8620 size_t
8622 {
8623  ABG_ASSERT(num_func_syms_removed() >= num_removed_func_syms_filtered_out());
8624  return num_func_syms_removed() - num_removed_func_syms_filtered_out();
8625 }
8626 
8627 /// Getter for the number of function symbols (not referenced by any
8628 /// debug info) that got added.
8629 ///
8630 /// @return the number of function symbols (not referenced by any
8631 /// debug info) that got added.
8632 size_t
8634 {return priv_->num_func_syms_added;}
8635 
8636 /// Setter for the number of function symbols (not referenced by any
8637 /// debug info) that got added.
8638 ///
8639 /// @param n the new number of function symbols (not referenced by any
8640 /// debug info) that got added.
8641 void
8643 {priv_->num_func_syms_added = n;}
8644 
8645 /// Getter for the number of added function symbols, not referenced by
8646 /// any debug info, that have been filtered out.
8647 ///
8648 /// @return the number of added function symbols, not referenced by
8649 /// any debug info, that have been filtered out.
8650 size_t
8652 {
8653  if (priv_->ctxt()
8654  && !(priv_->ctxt()->show_added_symbols_unreferenced_by_debug_info()
8655  && priv_->ctxt()->show_symbols_unreferenced_by_debug_info()))
8656  return num_func_syms_added();
8657  return priv_->num_added_func_syms_filtered_out;
8658 }
8659 
8660 /// Setter for the number of added function symbols, not referenced by
8661 /// any debug info, that have been filtered out.
8662 ///
8663 /// @param n the new number of added function symbols, not referenced
8664 /// by any debug info, that have been filtered out.
8665 void
8667 {priv_->num_added_func_syms_filtered_out = n;}
8668 
8669 /// Getter of the net number of added function symbols that are not
8670 /// referenced by any debug info.
8671 ///
8672 /// This is the difference between the total number of added
8673 /// function symbols and the number of added function symbols that
8674 /// have been filteted out. Both numbers are for symbols not
8675 /// referenced by debug info.
8676 ///
8677 /// return the net number of added function symbols that are not
8678 /// referenced by any debug info.
8679 size_t
8681 {
8682  ABG_ASSERT(num_func_syms_added() >= num_added_func_syms_filtered_out());
8683  return num_func_syms_added()- num_added_func_syms_filtered_out();
8684 }
8685 
8686 /// Getter for the number of variable symbols (not referenced by any
8687 /// debug info) that got removed.
8688 ///
8689 /// @return the number of variable symbols (not referenced by any
8690 /// debug info) that got removed.
8691 size_t
8693 {return priv_->num_var_syms_removed;}
8694 
8695 /// Setter for the number of variable symbols (not referenced by any
8696 /// debug info) that got removed.
8697 ///
8698 /// @param n the number of variable symbols (not referenced by any
8699 /// debug info) that got removed.
8700 void
8702 {priv_->num_var_syms_removed = n;}
8703 
8704 /// Getter for the number of removed variable symbols, not referenced
8705 /// by any debug info, that have been filtered out.
8706 ///
8707 /// @return the number of removed variable symbols, not referenced
8708 /// by any debug info, that have been filtered out.
8709 size_t
8711 {
8712  if (priv_->ctxt()
8713  && !priv_->ctxt()->show_symbols_unreferenced_by_debug_info())
8714  return num_var_syms_removed();
8715  return priv_->num_removed_var_syms_filtered_out;
8716 }
8717 
8718 /// Setter for the number of removed variable symbols, not referenced
8719 /// by any debug info, that have been filtered out.
8720 ///
8721 /// @param n the number of removed variable symbols, not referenced by
8722 /// any debug info, that have been filtered out.
8723 void
8725 {priv_->num_removed_var_syms_filtered_out = n;}
8726 
8727 /// Getter of the net number of removed variable symbols that are not
8728 /// referenced by any debug info.
8729 ///
8730 /// This is the difference between the total number of removed
8731 /// variable symbols and the number of removed variable symbols that
8732 /// have been filteted out. Both numbers are for symbols not
8733 /// referenced by debug info.
8734 ///
8735 /// return the net number of removed variable symbols that are not
8736 /// referenced by any debug info.
8737 size_t
8739 {
8740  ABG_ASSERT(num_var_syms_removed() >= num_removed_var_syms_filtered_out());
8741  return num_var_syms_removed() - num_removed_var_syms_filtered_out();
8742 }
8743 
8744 /// Getter for the number of variable symbols (not referenced by any
8745 /// debug info) that got added.
8746 ///
8747 /// @return the number of variable symbols (not referenced by any
8748 /// debug info) that got added.
8749 size_t
8751 {return priv_->num_var_syms_added;}
8752 
8753 /// Setter for the number of variable symbols (not referenced by any
8754 /// debug info) that got added.
8755 ///
8756 /// @param n the new number of variable symbols (not referenced by any
8757 /// debug info) that got added.
8758 void
8760 {priv_->num_var_syms_added = n;}
8761 
8762 /// Getter for the number of added variable symbols, not referenced by
8763 /// any debug info, that have been filtered out.
8764 ///
8765 /// @return the number of added variable symbols, not referenced by
8766 /// any debug info, that have been filtered out.
8767 size_t
8769 {
8770  if (priv_->ctxt()
8771  && !(priv_->ctxt()->show_added_symbols_unreferenced_by_debug_info()
8772  && priv_->ctxt()->show_symbols_unreferenced_by_debug_info()))
8773  return num_var_syms_added();
8774  return priv_->num_added_var_syms_filtered_out;
8775 }
8776 
8777 /// Setter for the number of added variable symbols, not referenced by
8778 /// any debug info, that have been filtered out.
8779 ///
8780 /// @param n the new number of added variable symbols, not referenced
8781 /// by any debug info, that have been filtered out.
8782 void
8784 {priv_->num_added_var_syms_filtered_out = n;}
8785 
8786 /// Getter of the net number of added variable symbols that are not
8787 /// referenced by any debug info.
8788 ///
8789 /// This is the difference between the total number of added
8790 /// variable symbols and the number of added variable symbols that
8791 /// have been filteted out. Both numbers are for symbols not
8792 /// referenced by debug info.
8793 ///
8794 /// return the net number of added variable symbols that are not
8795 /// referenced by any debug info.
8796 size_t
8798 {
8799  ABG_ASSERT(num_var_syms_added() >= num_added_var_syms_filtered_out());
8800  return num_var_syms_added() - num_added_var_syms_filtered_out();
8801 }
8802 
8803 /// Getter of the number of leaf type change diff nodes.
8804 ///
8805 /// @return the number of leaf type change diff nodes.
8806 size_t
8808 {return priv_->num_leaf_changes;}
8809 
8810 /// Setter of the number of leaf type change diff nodes.
8811 ///
8812 /// @param n the new number of leaf type change diff nodes.
8813 void
8815 {priv_->num_leaf_changes = n;}
8816 
8817 /// Getter of the number of leaf type change diff nodes that have been
8818 /// filtered out.
8819 ///
8820 /// @return the number of leaf type change diff nodes that have been
8821 size_t
8823 {return priv_->num_leaf_changes_filtered_out;}
8824 
8825 /// Setter of the number of leaf type change diff nodes that have been
8826 /// filtered out.
8827 ///
8828 /// @param n the new number of leaf type change diff nodes that have
8829 /// been filtered out.
8830 void
8832 {priv_->num_leaf_changes_filtered_out = n;}
8833 
8834 /// Getter of the net number of leaf change diff nodes.
8835 ///
8836 /// This is the difference between the total number of leaf change
8837 /// diff nodes, and the number of the leaf change diff nodes that have
8838 /// been filtered out.
8839 ///
8840 /// A leaf change is either a type change, a function change or a
8841 /// variable change.
8842 size_t
8844 {
8845  ABG_ASSERT(num_leaf_changes() >= num_leaf_changes_filtered_out());
8846  return num_leaf_changes() - num_leaf_changes_filtered_out();
8847 }
8848 
8849 /// Getter for the number of leaf type change diff nodes.
8850 ///
8851 /// @return the number of leaf type changes diff nodes.
8852 size_t
8854 {return priv_->num_leaf_type_changes;}
8855 
8856 /// Setter for the number of leaf type change diff nodes.
8857 ///
8858 /// @param n the new number of leaf type change diff nodes.
8859 void
8861 {priv_->num_leaf_type_changes = n;}
8862 
8863 /// Getter for the number of filtered out leaf type change diff nodes.
8864 ///
8865 /// @return the number of filtered out leaf type change diff nodes.
8866 size_t
8868 {return priv_->num_leaf_type_changes_filtered_out;}
8869 
8870 /// Setter for the number of filtered out leaf type change diff nodes.
8871 /// @param n the new number of filtered out leaf type change diff nodes.
8872 void
8874 {priv_->num_leaf_type_changes_filtered_out = n;}
8875 
8876 /// Getter for the net number of leaf type change diff nodes.
8877 ///
8878 /// This is the difference between the number of leaf type changes and
8879 /// the number of filtered out leaf type changes.
8880 ///
8881 /// @return the net number of leaf type change diff nodes.
8882 size_t
8884 {return num_leaf_type_changes() - num_leaf_type_changes_filtered_out();}
8885 
8886 /// Getter for the number of leaf function change diff nodes.
8887 ///
8888 /// @return the number of leaf function change diff nodes.
8889 size_t
8891 {return priv_->num_leaf_func_changes;}
8892 
8893 /// Setter for the number of leaf function change diff nodes.
8894 ///
8895 /// @param n the new number of leaf function change diff nodes.
8896 void
8898 {priv_->num_leaf_func_changes = n;}
8899 
8900 /// Getter for the number of leaf function change diff nodes that were
8901 /// filtered out.
8902 ///
8903 /// @return the number of leaf function change diff nodes that were
8904 /// filtered out.
8905 size_t
8907 {return priv_->num_leaf_func_changes_filtered_out;}
8908 
8909 /// Setter for the number of leaf function change diff nodes that were
8910 /// filtered out.
8911 ///
8912 /// @param n the new number of leaf function change diff nodes that
8913 /// were filtered out.
8914 void
8916 {priv_->num_leaf_func_changes_filtered_out = n;}
8917 
8918 /// Getter for the net number of leaf function change diff nodes.
8919 ///
8920 /// This is the difference between the number of leaf function change
8921 /// diff nodes and the number of filtered out leaf function change
8922 /// diff nodes.
8923 ///
8924 /// @return the net number of leaf function change diff nodes.
8925 size_t
8927 {return num_leaf_func_changes() - num_leaf_func_changes_filtered_out();}
8928 
8929 /// Getter for the number of leaf variable change diff nodes.
8930 ///
8931 /// @return the number of leaf variable change diff nodes.
8932 size_t
8934 {return priv_->num_leaf_var_changes;}
8935 
8936 /// Setter for the number of leaf variable change diff nodes.
8937 ///
8938 /// @param n the number of leaf variable change diff nodes.
8939 void
8941 {priv_->num_leaf_var_changes = n;}
8942 
8943 /// Getter of the number of added types that are unreachable from the
8944 /// public interface of the ABI corpus.
8945 ///
8946 /// Public interface means the set of defined and publicly exported
8947 /// functions and variables of the ABI corpus.
8948 ///
8949 /// @return the number of added types that are unreachable from the
8950 /// public interface of the ABI corpus.
8951 size_t
8953 {return priv_->num_added_unreachable_types;}
8954 
8955 /// Setter of the number of added types that are unreachable from the
8956 /// public interface (global functions or variables) of the ABI
8957 /// corpus.
8958 ///
8959 /// Public interface means the set of defined and publicly exported
8960 /// functions and variables of the ABI corpus.
8961 ///
8962 /// @param n the new number of added types that are unreachable from
8963 /// the public interface of the ABI corpus.
8964 void
8966 {priv_->num_added_unreachable_types = n;}
8967 
8968 /// Getter of the number of added types that are unreachable from
8969 /// public interfaces and that are filtered out by suppression
8970 /// specifications.
8971 ///
8972 /// @return the number of added types that are unreachable from public
8973 /// interfaces and that are filtered out by suppression
8974 /// specifications.
8975 size_t
8977 {return priv_->num_added_unreachable_types_filtered_out;}
8978 
8979 /// Setter of the number of added types that are unreachable from
8980 /// public interfaces and that are filtered out by suppression
8981 /// specifications.
8982 ///
8983 /// @param n the new number of added types that are unreachable from
8984 /// public interfaces and that are filtered out by suppression
8985 /// specifications.
8986 void
8988 {priv_->num_added_unreachable_types_filtered_out = n;}
8989 
8990 /// Getter of the number of added types that are unreachable from
8991 /// public interfaces and that are *NOT* filtered out by suppression
8992 /// specifications.
8993 ///
8994 /// @return the number of added types that are unreachable from public
8995 /// interfaces and that are *NOT* filtered out by suppression
8996 /// specifications.
8997 size_t
8999 {
9000  ABG_ASSERT(num_added_unreachable_types()
9001  >=
9002  num_added_unreachable_types_filtered_out());
9003 
9004  return (num_added_unreachable_types()
9005  -
9006  num_added_unreachable_types_filtered_out());
9007 }
9008 
9009 /// Getter of the number of removed types that are unreachable from
9010 /// the public interface of the ABI corpus.
9011 ///
9012 /// Public interface means the set of defined and publicly exported
9013 /// functions and variables of the ABI corpus.
9014 ///
9015 /// @return the number of removed types that are unreachable from
9016 /// the public interface of the ABI corpus.
9017 size_t
9019 {return priv_->num_removed_unreachable_types;}
9020 
9021 /// Setter of the number of removed types that are unreachable from
9022 /// the public interface of the ABI corpus.
9023 ///
9024 /// Public interface means the set of defined and publicly exported
9025 /// functions and variables of the ABI corpus.
9026 ///
9027 ///@param n the new number of removed types that are unreachable from
9028 /// the public interface of the ABI corpus.
9029 void
9031 {priv_->num_removed_unreachable_types = n;}
9032 
9033 /// Getter of the number of removed types that are not reachable from
9034 /// public interfaces and that have been filtered out by suppression
9035 /// specifications.
9036 ///
9037 /// @return the number of removed types that are not reachable from
9038 /// public interfaces and that have been filtered out by suppression
9039 /// specifications.
9040 size_t
9042 {return priv_->num_removed_unreachable_types_filtered_out;}
9043 
9044 /// Setter of the number of removed types that are not reachable from
9045 /// public interfaces and that have been filtered out by suppression
9046 /// specifications.
9047 ///
9048 /// @param n the new number of removed types that are not reachable
9049 /// from public interfaces and that have been filtered out by
9050 /// suppression specifications.
9051 void
9053 {priv_->num_removed_unreachable_types_filtered_out = n;}
9054 
9055 /// Getter of the number of removed types that are not reachable from
9056 /// public interfaces and that have *NOT* been filtered out by
9057 /// suppression specifications.
9058 ///
9059 /// @return the number of removed types that are not reachable from
9060 /// public interfaces and that have *NOT* been filtered out by
9061 /// suppression specifications.
9062 size_t
9064 {
9065  ABG_ASSERT(num_removed_unreachable_types()
9066  >=
9067  num_removed_unreachable_types_filtered_out());
9068 
9069  return (num_removed_unreachable_types()
9070  -
9071  num_removed_unreachable_types_filtered_out());
9072 }
9073 
9074 /// Getter of the number of changed types that are unreachable from
9075 /// the public interface of the ABI corpus.
9076 ///
9077 /// Public interface means the set of defined and publicly exported
9078 /// functions and variables of the ABI corpus.
9079 ///
9080 /// @return the number of changed types that are unreachable from the
9081 /// public interface of the ABI corpus.
9082 size_t
9084 {return priv_->num_changed_unreachable_types;}
9085 
9086 /// Setter of the number of changed types that are unreachable from
9087 /// the public interface of the ABI corpus.
9088 ///
9089 /// Public interface means the set of defined and publicly exported
9090 /// functions and variables of the ABI corpus.
9091 ///
9092 ///@param n the new number of changed types that are unreachable from
9093 /// the public interface of the ABI corpus.
9094 void
9096 {priv_->num_changed_unreachable_types = n;}
9097 
9098 /// Getter of the number of changed types that are unreachable from
9099 /// public interfaces and that have been filtered out by suppression
9100 /// specifications.
9101 ///
9102 /// @return the number of changed types that are unreachable from
9103 /// public interfaces and that have been filtered out by suppression
9104 /// specifications.
9105 size_t
9107 {return priv_->num_changed_unreachable_types_filtered_out;}
9108 
9109 /// Setter of the number of changed types that are unreachable from
9110 /// public interfaces and that have been filtered out by suppression
9111 /// specifications.
9112 ///
9113 /// @param n the new number of changed types that are unreachable from
9114 /// public interfaces and that have been filtered out by suppression
9115 /// specifications.
9116 void
9118 {priv_->num_changed_unreachable_types_filtered_out = n;}
9119 
9120 /// Getter of the number of changed types that are unreachable from
9121 /// public interfaces and that have *NOT* been filtered out by
9122 /// suppression specifications.
9123 ///
9124 /// @return the number of changed types that are unreachable from
9125 /// public interfaces and that have *NOT* been filtered out by
9126 /// suppression specifications.
9127 size_t
9129 {
9130  ABG_ASSERT(num_changed_unreachable_types()
9131  >=
9132  num_changed_unreachable_types_filtered_out());
9133 
9134  return (num_changed_unreachable_types()
9135  -
9136  num_changed_unreachable_types_filtered_out());
9137 }
9138 
9139 /// Getter for the number of leaf variable changes diff nodes that
9140 /// have been filtered out.
9141 ///
9142 /// @return the number of leaf variable changes diff nodes that have
9143 /// been filtered out.
9144 size_t
9146 {return priv_->num_leaf_var_changes_filtered_out;}
9147 
9148 /// Setter for the number of leaf variable changes diff nodes that
9149 /// have been filtered out.
9150 ///
9151 /// @param n the number of leaf variable changes diff nodes that have
9152 /// been filtered out.
9153 void
9155 {priv_->num_leaf_var_changes_filtered_out = n;}
9156 
9157 /// Getter for the net number of leaf variable change diff nodes.
9158 ///
9159 /// This the difference between the number of leaf variable change
9160 /// diff nodes and the number of filtered out leaf variable change
9161 /// diff nodes.
9162 ///
9163 /// @return the net number of leaf variable change diff nodes.
9164 size_t
9166 {return num_leaf_var_changes() - num_leaf_var_changes_filtered_out();}
9167 
9168 
9169 // <corpus_diff stuff>
9170 
9171 /// Getter of the context associated with this corpus.
9172 ///
9173 /// @return a smart pointer to the context associate with the corpus.
9176 {return ctxt_.lock();}
9177 
9178 /// Tests if the lookup tables are empty.
9179 ///
9180 /// @return true if the lookup tables are empty, false otherwise.
9181 bool
9183 {
9184  return (deleted_fns_.empty()
9185  && added_fns_.empty()
9186  && changed_fns_map_.empty()
9187  && deleted_vars_.empty()
9188  && added_vars_.empty()
9189  && changed_vars_map_.empty());
9190 }
9191 
9192 /// Clear the lookup tables useful for reporting an enum_diff.
9193 void
9195 {
9196  deleted_fns_.clear();
9197  added_fns_.clear();
9198  changed_fns_map_.clear();
9199  deleted_vars_.clear();
9200  added_vars_.clear();
9201  changed_vars_map_.clear();
9202 }
9203 
9204 /// If the lookup tables are not yet built, walk the differences and
9205 /// fill the lookup tables.
9206 void
9208 {
9209  if (!lookup_tables_empty())
9210  return;
9211 
9212  diff_context_sptr ctxt = get_context();
9213 
9214  {
9215  edit_script& e = fns_edit_script_;
9216 
9217  for (vector<deletion>::const_iterator it = e.deletions().begin();
9218  it != e.deletions().end();
9219  ++it)
9220  {
9221  unsigned i = it->index();
9222  ABG_ASSERT(i < first_->get_functions().size());
9223 
9224  function_decl* deleted_fn = first_->get_functions()[i];
9225  string n = get_function_id_or_pretty_representation(deleted_fn);
9226  ABG_ASSERT(!n.empty());
9227  // The below is commented out because there can be several
9228  // functions with the same ID in the corpus. So several
9229  // functions with the same ID can be deleted.
9230  // ABG_ASSERT(deleted_fns_.find(n) == deleted_fns_.end());
9231  deleted_fns_[n] = deleted_fn;
9232  }
9233 
9234  for (vector<insertion>::const_iterator it = e.insertions().begin();
9235  it != e.insertions().end();
9236  ++it)
9237  {
9238  for (vector<unsigned>::const_iterator iit =
9239  it->inserted_indexes().begin();
9240  iit != it->inserted_indexes().end();
9241  ++iit)
9242  {
9243  unsigned i = *iit;
9244  function_decl* added_fn = second_->get_functions()[i];
9245  string n = get_function_id_or_pretty_representation(added_fn);
9246  ABG_ASSERT(!n.empty());
9247  // The below is commented out because there can be several
9248  // functions with the same ID in the corpus. So several
9249  // functions with the same ID can be added.
9250  // ABG_ASSERT(added_fns_.find(n) == added_fns_.end());
9251  string_function_ptr_map::const_iterator j =
9252  deleted_fns_.find(n);
9253  if (j != deleted_fns_.end())
9254  {
9255  function_decl_sptr f(j->second, noop_deleter());
9256  function_decl_sptr s(added_fn, noop_deleter());
9257  function_decl_diff_sptr d = compute_diff(f, s, ctxt);
9258  if (*j->second != *added_fn)
9259  changed_fns_map_[j->first] = d;
9260  deleted_fns_.erase(j);
9261  }
9262  else
9263  added_fns_[n] = added_fn;
9264  }
9265  }
9266  sort_string_function_decl_diff_sptr_map(changed_fns_map_, changed_fns_);
9267 
9268  // Now walk the allegedly deleted functions; check if their
9269  // underlying symbols are deleted as well; otherwise, consider
9270  // that the function in question hasn't been deleted.
9271 
9272  vector<string> to_delete;
9273  for (string_function_ptr_map::const_iterator i = deleted_fns_.begin();
9274  i != deleted_fns_.end();
9275  ++i)
9276  if (second_->lookup_function_symbol(*i->second->get_symbol()))
9277  to_delete.push_back(i->first);
9278 
9279  for (vector<string>::const_iterator i = to_delete.begin();
9280  i != to_delete.end();
9281  ++i)
9282  deleted_fns_.erase(*i);
9283 
9284  // Do something similar for added functions.
9285 
9286  to_delete.clear();
9287  for (string_function_ptr_map::const_iterator i = added_fns_.begin();
9288  i != added_fns_.end();
9289  ++i)
9290  {
9291  if (first_->lookup_function_symbol(*i->second->get_symbol()))
9292  to_delete.push_back(i->first);
9293  else if (! i->second->get_symbol()->get_version().is_empty()
9294  && i->second->get_symbol()->get_version().is_default())
9295  // We are looking for a symbol that has a default version,
9296  // and which seems to be newly added. Let's see if the same
9297  // symbol with *no* version was already present in the
9298  // former corpus. If yes, then the symbol shouldn't be
9299  // considered as 'added'.
9300  {
9301  elf_symbol::version empty_version;
9302  if (first_->lookup_function_symbol(i->second->get_symbol()->get_name(),
9303  empty_version))
9304  to_delete.push_back(i->first);
9305  }
9306  }
9307 
9308  for (vector<string>::const_iterator i = to_delete.begin();
9309  i != to_delete.end();
9310  ++i)
9311  added_fns_.erase(*i);
9312  }
9313 
9314  {
9315  edit_script& e = vars_edit_script_;
9316 
9317  for (vector<deletion>::const_iterator it = e.deletions().begin();
9318  it != e.deletions().end();
9319  ++it)
9320  {
9321  unsigned i = it->index();
9322  ABG_ASSERT(i < first_->get_variables().size());
9323 
9324  var_decl* deleted_var = first_->get_variables()[i];
9325  string n = deleted_var->get_id();
9326  ABG_ASSERT(!n.empty());
9327  ABG_ASSERT(deleted_vars_.find(n) == deleted_vars_.end());
9328  deleted_vars_[n] = deleted_var;
9329  }
9330 
9331  for (vector<insertion>::const_iterator it = e.insertions().begin();
9332  it != e.insertions().end();
9333  ++it)
9334  {
9335  for (vector<unsigned>::const_iterator iit =
9336  it->inserted_indexes().begin();
9337  iit != it->inserted_indexes().end();
9338  ++iit)
9339  {
9340  unsigned i = *iit;
9341  var_decl* added_var = second_->get_variables()[i];
9342  string n = added_var->get_id();
9343  ABG_ASSERT(!n.empty());
9344  {
9345  string_var_ptr_map::const_iterator k = added_vars_.find(n);
9346  if ( k != added_vars_.end())
9347  {
9348  ABG_ASSERT(is_member_decl(k->second)
9349  && get_member_is_static(k->second));
9350  continue;
9351  }
9352  }
9353  string_var_ptr_map::const_iterator j =
9354  deleted_vars_.find(n);
9355  if (j != deleted_vars_.end())
9356  {
9357  if (*j->second != *added_var)
9358  {
9359  var_decl_sptr f(j->second, noop_deleter());
9360  var_decl_sptr s(added_var, noop_deleter());
9361  changed_vars_map_[n] = compute_diff(f, s, ctxt);
9362  }
9363  deleted_vars_.erase(j);
9364  }
9365  else
9366  added_vars_[n] = added_var;
9367  }
9368  }
9369  sort_string_var_diff_sptr_map(changed_vars_map_,
9370  sorted_changed_vars_);
9371 
9372  // Now walk the allegedly deleted variables; check if their
9373  // underlying symbols are deleted as well; otherwise consider
9374  // that the variable in question hasn't been deleted.
9375 
9376  vector<string> to_delete;
9377  for (string_var_ptr_map::const_iterator i = deleted_vars_.begin();
9378  i != deleted_vars_.end();
9379  ++i)
9380  if (second_->lookup_variable_symbol(*i->second->get_symbol()))
9381  to_delete.push_back(i->first);
9382 
9383  for (vector<string>::const_iterator i = to_delete.begin();
9384  i != to_delete.end();
9385  ++i)
9386  deleted_vars_.erase(*i);
9387 
9388  // Do something similar for added variables.
9389 
9390  to_delete.clear();
9391  for (string_var_ptr_map::const_iterator i = added_vars_.begin();
9392  i != added_vars_.end();
9393  ++i)
9394  if (first_->lookup_variable_symbol(*i->second->get_symbol()))
9395  to_delete.push_back(i->first);
9396  else if (! i->second->get_symbol()->get_version().is_empty()
9397  && i->second->get_symbol()->get_version().is_default())
9398  // We are looking for a symbol that has a default version,
9399  // and which seems to be newly added. Let's see if the same
9400  // symbol with *no* version was already present in the
9401  // former corpus. If yes, then the symbol shouldn't be
9402  // considered as 'added'.
9403  {
9404  elf_symbol::version empty_version;
9405  if (first_->lookup_variable_symbol(i->second->get_symbol()->get_name(),
9406  empty_version))
9407  to_delete.push_back(i->first);
9408  }
9409 
9410  for (vector<string>::const_iterator i = to_delete.begin();
9411  i != to_delete.end();
9412  ++i)
9413  added_vars_.erase(*i);
9414  }
9415 
9416  // Massage the edit script for added/removed function symbols that
9417  // were not referenced by any debug info and turn them into maps of
9418  // {symbol_name, symbol}.
9419  {
9420  edit_script& e = unrefed_fn_syms_edit_script_;
9421  for (vector<deletion>::const_iterator it = e.deletions().begin();
9422  it != e.deletions().end();
9423  ++it)
9424  {
9425  unsigned i = it->index();
9426  ABG_ASSERT(i < first_->get_unreferenced_function_symbols().size());
9427  elf_symbol_sptr deleted_sym =
9428  first_->get_unreferenced_function_symbols()[i];
9429  if (!second_->lookup_function_symbol(*deleted_sym))
9430  deleted_unrefed_fn_syms_[deleted_sym->get_id_string()] = deleted_sym;
9431  }
9432 
9433  for (vector<insertion>::const_iterator it = e.insertions().begin();
9434  it != e.insertions().end();
9435  ++it)
9436  {
9437  for (vector<unsigned>::const_iterator iit =
9438  it->inserted_indexes().begin();
9439  iit != it->inserted_indexes().end();
9440  ++iit)
9441  {
9442  unsigned i = *iit;
9443  ABG_ASSERT(i < second_->get_unreferenced_function_symbols().size());
9444  elf_symbol_sptr added_sym =
9445  second_->get_unreferenced_function_symbols()[i];
9446  if ((deleted_unrefed_fn_syms_.find(added_sym->get_id_string())
9447  == deleted_unrefed_fn_syms_.end()))
9448  {
9449  if (!first_->lookup_function_symbol(*added_sym))
9450  {
9451  bool do_add = true;
9452  if (! added_sym->get_version().is_empty()
9453  && added_sym->get_version().is_default())
9454  {
9455  // So added_seem has a default version. If
9456  // the former corpus had a symbol with the
9457  // same name as added_sym but with *no*
9458  // version, then added_sym shouldn't be
9459  // considered as a newly added symbol.
9460  elf_symbol::version empty_version;
9461  if (first_->lookup_function_symbol(added_sym->get_name(),
9462  empty_version))
9463  do_add = false;
9464  }
9465 
9466  if (do_add)
9467  added_unrefed_fn_syms_[added_sym->get_id_string()] =
9468  added_sym;
9469  }
9470  }
9471  else
9472  deleted_unrefed_fn_syms_.erase(added_sym->get_id_string());
9473  }
9474  }
9475  }
9476 
9477  // Massage the edit script for added/removed variable symbols that
9478  // were not referenced by any debug info and turn them into maps of
9479  // {symbol_name, symbol}.
9480  {
9481  edit_script& e = unrefed_var_syms_edit_script_;
9482  for (vector<deletion>::const_iterator it = e.deletions().begin();
9483  it != e.deletions().end();
9484  ++it)
9485  {
9486  unsigned i = it->index();
9487  ABG_ASSERT(i < first_->get_unreferenced_variable_symbols().size());
9488  elf_symbol_sptr deleted_sym =
9489  first_->get_unreferenced_variable_symbols()[i];
9490  if (!second_->lookup_variable_symbol(*deleted_sym))
9491  deleted_unrefed_var_syms_[deleted_sym->get_id_string()] = deleted_sym;
9492  }
9493 
9494  for (vector<insertion>::const_iterator it = e.insertions().begin();
9495  it != e.insertions().end();
9496  ++it)
9497  {
9498  for (vector<unsigned>::const_iterator iit =
9499  it->inserted_indexes().begin();
9500  iit != it->inserted_indexes().end();
9501  ++iit)
9502  {
9503  unsigned i = *iit;
9504  ABG_ASSERT(i < second_->get_unreferenced_variable_symbols().size());
9505  elf_symbol_sptr added_sym =
9506  second_->get_unreferenced_variable_symbols()[i];
9507  if (deleted_unrefed_var_syms_.find(added_sym->get_id_string())
9508  == deleted_unrefed_var_syms_.end())
9509  {
9510  if (!first_->lookup_variable_symbol(*added_sym))
9511  {
9512  bool do_add = true;
9513  if (! added_sym->get_version().is_empty()
9514  && added_sym->get_version().is_default())
9515  {
9516  // So added_seem has a default version. If
9517  // the former corpus had a symbol with the
9518  // same name as added_sym but with *no*
9519  // version, then added_sym shouldn't be
9520  // considered as a newly added symbol.
9521  elf_symbol::version empty_version;
9522  if (first_->lookup_variable_symbol(added_sym->get_name(),
9523  empty_version))
9524  do_add = false;
9525  }
9526 
9527  if (do_add)
9528  added_unrefed_var_syms_[added_sym->get_id_string()] =
9529  added_sym;
9530  }
9531  }
9532  else
9533  deleted_unrefed_var_syms_.erase(added_sym->get_id_string());
9534  }
9535  }
9536  }
9537 
9538  // Handle the unreachable_types_edit_script_
9539  {
9540  edit_script& e = unreachable_types_edit_script_;
9541 
9542  // Populate the map of deleted unreachable types from the
9543  // deletions of the edit script.
9544  for (vector<deletion>::const_iterator it = e.deletions().begin();
9545  it != e.deletions().end();
9546  ++it)
9547  {
9548  unsigned i = it->index();
9549  type_base_sptr t
9550  (first_->get_types_not_reachable_from_public_interfaces()[i]);
9551 
9552  if (!is_user_defined_type(t))
9553  continue;
9554 
9555  string repr =
9556  abigail::ir::get_pretty_representation(t, /*internal=*/false);
9557  deleted_unreachable_types_[repr] = t;
9558  }
9559 
9560  // Populate the map of added and change unreachable types from the
9561  // insertions of the edit script.
9562  for (vector<insertion>::const_iterator it = e.insertions().begin();
9563  it != e.insertions().end();
9564  ++it)
9565  {
9566  for (vector<unsigned>::const_iterator iit =
9567  it->inserted_indexes().begin();
9568  iit != it->inserted_indexes().end();
9569  ++iit)
9570  {
9571  unsigned i = *iit;
9572  type_base_sptr t
9573  (second_->get_types_not_reachable_from_public_interfaces()[i]);
9574 
9575  if (!is_user_defined_type(t))
9576  continue;
9577 
9578  string repr =
9579  abigail::ir::get_pretty_representation(t, /*internal=*/false);
9580 
9581  // Let's see if the inserted type we are looking at was
9582  // reported as deleted as well.
9583  //
9584  // If it's been deleted and a different version of it has
9585  // now been added, it means it's been *changed*. In that
9586  // case we'll compute the diff of that change and store it
9587  // in the map of changed unreachable types.
9588  //
9589  // Otherwise, it means the type's been added so we'll add
9590  // it to the set of added unreachable types.
9591 
9592  string_type_base_sptr_map::const_iterator j =
9593  deleted_unreachable_types_.find(repr);
9594  if (j != deleted_unreachable_types_.end())
9595  {
9596  // So there was another type of the same pretty
9597  // representation which was reported as deleted.
9598  // Let's see if they are different or not ...
9599  decl_base_sptr old_type = is_decl(j->second);
9600  decl_base_sptr new_type = is_decl(t);
9601  if (old_type != new_type)
9602  {
9603  // The previously added type is different from this
9604  // one that is added. That means the initial type
9605  // was changed. Let's compute its diff and store it
9606  // as a changed type.
9607  diff_sptr d = compute_diff(old_type, new_type, ctxt);
9608  ABG_ASSERT(d->has_changes());
9609  changed_unreachable_types_[repr]= d;
9610  }
9611 
9612  // In any case, the type was both deleted and added,
9613  // so we cannot have it marked as being deleted. So
9614  // let's remove it from the deleted types.
9615  deleted_unreachable_types_.erase(j);
9616  }
9617  else
9618  // The type wasn't previously reported as deleted, so
9619  // it's really added.
9620  added_unreachable_types_[repr] = t;
9621  }
9622  }
9623 
9624  // Handle anonymous enums that got changed. An anonymous enum is
9625  // designated by its flat textual representation. So a change to
9626  // any of its enumerators results in a different enum. That is
9627  // represented by a deletion of the previous anonymous enum, and
9628  // the addition of a new one. For the user however, it's the same
9629  // enum that changed. Let's massage this "added/removed" pattern
9630  // to show what the user expects, namely, a changed anonymous
9631  // enum.
9632  {
9633  std::set<type_base_sptr> deleted_anon_types;
9634  std::set<type_base_sptr> added_anon_types;
9635 
9636  for (auto entry : deleted_unreachable_types_)
9637  {
9638  if ((is_enum_type(entry.second)
9639  && is_enum_type(entry.second)->get_is_anonymous())
9640  || (is_class_or_union_type(entry.second)
9641  && is_class_or_union_type(entry.second)->get_is_anonymous()))
9642  deleted_anon_types.insert(entry.second);
9643  }
9644 
9645 
9646  for (auto entry : added_unreachable_types_)
9647  if ((is_enum_type(entry.second)
9648  && is_enum_type(entry.second)->get_is_anonymous())
9649  || (is_class_or_union_type(entry.second)
9650  && is_class_or_union_type(entry.second)->get_is_anonymous()))
9651  added_anon_types.insert(entry.second);
9652 
9653  string_type_base_sptr_map added_anon_types_to_erase;
9654  string_type_base_sptr_map removed_anon_types_to_erase;
9655  enum_type_decl_sptr deleted_enum;
9656  class_or_union_sptr deleted_class;
9657 
9658  // Look for deleted anonymous types (enums, unions, structs &
9659  // classes) which have enumerators or data members present in an
9660  // added anonymous type ...
9661  for (auto deleted: deleted_anon_types)
9662  {
9663  deleted_enum = is_enum_type(deleted);
9664  deleted_class = is_class_or_union_type(deleted);
9665 
9666  // For enums, look for any enumerator of 'deleted_enum' that
9667  // is also present in an added anonymous enum.
9668  if (deleted_enum)
9669  {
9670  for (auto enr : deleted_enum->get_enumerators())
9671  {
9672  bool this_enum_got_changed = false;
9673  for (auto t : added_anon_types)
9674  {
9675  if (enum_type_decl_sptr added_enum = is_enum_type(t))
9676  if (is_enumerator_present_in_enum(enr, *added_enum))
9677  {
9678  // So the enumerator 'enr' from the
9679  // 'deleted_enum' enum is also present in the
9680  // 'added_enum' enum so we assume that
9681  // 'deleted_enum' and 'added_enum' are the same
9682  // enum that got changed. Let's represent it
9683  // using a diff node.
9684  diff_sptr d = compute_diff(deleted_enum,
9685  added_enum, ctxt);
9686  ABG_ASSERT(d->has_changes());
9687  string repr =
9689  /*internal=*/false);
9690  changed_unreachable_types_[repr]= d;
9691  this_enum_got_changed = true;
9692  string r1 =
9694  /*internal=*/false);
9695  string r2 =
9697  /*internal=*/false);
9698  removed_anon_types_to_erase[r1] = deleted_enum;
9699  added_anon_types_to_erase[r2] = added_enum;
9700  break;
9701  }
9702  }
9703  if (this_enum_got_changed)
9704  break;
9705  }
9706  }
9707  else if (deleted_class)
9708  {
9709  // For unions, structs & classes, look for any data
9710  // member of 'deleted_class' that is also present in an
9711  // added anonymous class.
9712  for (auto dm : deleted_class->get_data_members())
9713  {
9714  bool this_class_got_changed = false;
9715  for (auto klass : added_anon_types)
9716  {
9717  if (class_or_union_sptr added_class =
9718  is_class_or_union_type(klass))
9719  if (class_or_union_types_of_same_kind(deleted_class,
9720  added_class)
9721  && lookup_data_member(added_class, dm))
9722  {
9723  // So the data member 'dm' from the
9724  // 'deleted_class' class is also present in
9725  // the 'added_class' class so we assume that
9726  // 'deleted_class' and 'added_class' are the
9727  // same anonymous class that got changed.
9728  // Let's represent it using a diff node.
9729  diff_sptr d = compute_diff(is_type(deleted_class),
9730  is_type(added_class),
9731  ctxt);
9732  ABG_ASSERT(d->has_changes());
9733  string repr =
9735  /*internal=*/false);
9736  changed_unreachable_types_[repr]= d;
9737  this_class_got_changed = true;
9738  string r1 =
9740  /*internal=*/false);
9741  string r2 =
9743  /*internal=*/false);
9744  removed_anon_types_to_erase[r1] = deleted_class;
9745  added_anon_types_to_erase[r2] = added_class;
9746  break;
9747  }
9748  }
9749  if (this_class_got_changed)
9750  break;
9751  }
9752  }
9753  }
9754 
9755  // Now remove the added/removed anonymous types from their maps,
9756  // as they are now represented as a changed type, not an added
9757  // and removed anonymous type.
9758  for (auto entry : added_anon_types_to_erase)
9759  added_unreachable_types_.erase(entry.first);
9760 
9761  for (auto entry : removed_anon_types_to_erase)
9762  deleted_unreachable_types_.erase(entry.first);
9763  }
9764  }
9765 }
9766 
9767 /// Test if a change reports about a given @ref function_decl that is
9768 /// changed in a certain way is suppressed by a given suppression
9769 /// specifiation
9770 ///
9771 /// @param fn the @ref function_decl to consider.
9772 ///
9773 /// @param suppr the suppression specification to consider.
9774 ///
9775 /// @param k the kind of change that happened to @p fn.
9776 ///
9777 /// @param ctxt the context of the current diff.
9778 ///
9779 /// @return true iff the suppression specification @p suppr suppresses
9780 /// change reports about function @p fn, if that function changes in
9781 /// the way expressed by @p k.
9782 static bool
9783 function_is_suppressed(const function_decl* fn,
9784  const suppression_sptr suppr,
9786  const diff_context_sptr ctxt)
9787 {
9789  if (!fn_suppr)
9790  return false;
9791  return fn_suppr->suppresses_function(fn, k, ctxt);
9792 }
9793 
9794 /// Test if a change reports about a given @ref var_decl that is
9795 /// changed in a certain way is suppressed by a given suppression
9796 /// specifiation
9797 ///
9798 /// @param fn the @ref var_decl to consider.
9799 ///
9800 /// @param suppr the suppression specification to consider.
9801 ///
9802 /// @param k the kind of change that happened to @p fn.
9803 ///
9804 /// @param ctxt the context of the current diff.
9805 ///
9806 /// @return true iff the suppression specification @p suppr suppresses
9807 /// change reports about variable @p fn, if that variable changes in
9808 /// the way expressed by @p k.
9809 static bool
9810 variable_is_suppressed(const var_decl* var,
9811  const suppression_sptr suppr,
9813  const diff_context_sptr ctxt)
9814 {
9816  if (!var_suppr)
9817  return false;
9818  return var_suppr->suppresses_variable(var, k, ctxt);
9819 }
9820 
9821 /// Apply suppression specifications for this corpus diff to the set
9822 /// of added/removed functions/variables, as well as to types not
9823 /// reachable from global functions/variables.
9824 void
9826 {
9827  diff_context_sptr ctxt = get_context();
9828 
9829  const suppressions_type& suppressions = ctxt->suppressions();
9830  for (suppressions_type::const_iterator i = suppressions.begin();
9831  i != suppressions.end();
9832  ++i)
9833  {
9834  // Added/Deleted functions.
9836  {
9837  // Added functions
9838  for (string_function_ptr_map::const_iterator e = added_fns_.begin();
9839  e != added_fns_.end();
9840  ++e)
9841  if (function_is_suppressed(e->second, fn_suppr,
9843  ctxt))
9844  suppressed_added_fns_[e->first] = e->second;
9845 
9846  // Deleted functions.
9847  for (string_function_ptr_map::const_iterator e = deleted_fns_.begin();
9848  e != deleted_fns_.end();
9849  ++e)
9850  if (function_is_suppressed(e->second, fn_suppr,
9852  ctxt))
9853  suppressed_deleted_fns_[e->first] = e->second;
9854 
9855  // Added function symbols not referenced by any debug info
9856  for (string_elf_symbol_map::const_iterator e =
9857  added_unrefed_fn_syms_.begin();
9858  e != added_unrefed_fn_syms_.end();
9859  ++e)
9860  if (fn_suppr->suppresses_function_symbol(e->second,
9862  ctxt))
9863  suppressed_added_unrefed_fn_syms_[e->first] = e->second;
9864 
9865  // Removed function symbols not referenced by any debug info
9866  for (string_elf_symbol_map::const_iterator e =
9867  deleted_unrefed_fn_syms_.begin();
9868  e != deleted_unrefed_fn_syms_.end();
9869  ++e)
9870  if (fn_suppr->suppresses_function_symbol(e->second,
9872  ctxt))
9873  suppressed_deleted_unrefed_fn_syms_[e->first] = e->second;
9874  }
9875  // Added/Delete virtual member functions changes that might be
9876  // suppressed by a type_suppression that matches the enclosing
9877  // class of the virtual member function.
9878  else if (type_suppression_sptr type_suppr = is_type_suppression(*i))
9879  {
9880  // Added virtual functions
9881  for (string_function_ptr_map::const_iterator e = added_fns_.begin();
9882  e != added_fns_.end();
9883  ++e)
9884  if (is_member_function(e->second)
9885  && get_member_function_is_virtual(e->second))
9886  {
9887  function_decl *f = e->second;
9888  class_decl_sptr c =
9889  is_class_type(is_method_type(f->get_type())->get_class_type());
9890  ABG_ASSERT(c);
9891  if (type_suppr->suppresses_type(c, ctxt))
9892  suppressed_added_fns_[e->first] = e->second;
9893  }
9894  // Deleted virtual functions
9895  for (string_function_ptr_map::const_iterator e = deleted_fns_.begin();
9896  e != deleted_fns_.end();
9897  ++e)
9898  if (is_member_function(e->second)
9899  && get_member_function_is_virtual(e->second))
9900  {
9901  function_decl *f = e->second;
9902  class_decl_sptr c =
9903  is_class_type(is_method_type(f->get_type())->get_class_type());
9904  ABG_ASSERT(c);
9905  if (type_suppr->suppresses_type(c, ctxt))
9906  suppressed_deleted_fns_[e->first] = e->second;
9907  }
9908 
9909  // Apply this type suppression to deleted types
9910  // non-reachable from a public interface.
9911  for (string_type_base_sptr_map::const_iterator e =
9912  deleted_unreachable_types_.begin();
9913  e != deleted_unreachable_types_.end();
9914  ++e)
9915  if (type_suppr->suppresses_type(e->second, ctxt))
9916  suppressed_deleted_unreachable_types_[e->first] = e->second;
9917 
9918  // Apply this type suppression to added types
9919  // non-reachable from a public interface.
9920  for (string_type_base_sptr_map::const_iterator e =
9921  added_unreachable_types_.begin();
9922  e != added_unreachable_types_.end();
9923  ++e)
9924  if (type_suppr->suppresses_type(e->second, ctxt))
9925  suppressed_added_unreachable_types_[e->first] = e->second;
9926  }
9927  // Added/Deleted variables
9928  else if (variable_suppression_sptr var_suppr =
9930  {
9931  // Added variables
9932  for (string_var_ptr_map::const_iterator e = added_vars_.begin();
9933  e != added_vars_.end();
9934  ++e)
9935  if (variable_is_suppressed(e->second, var_suppr,
9937  ctxt))
9938  suppressed_added_vars_[e->first] = e->second;
9939 
9940  //Deleted variables
9941  for (string_var_ptr_map::const_iterator e = deleted_vars_.begin();
9942  e != deleted_vars_.end();
9943  ++e)
9944  if (variable_is_suppressed(e->second, var_suppr,
9946  ctxt))
9947  suppressed_deleted_vars_[e->first] = e->second;
9948 
9949  // Added variable symbols not referenced by any debug info
9950  for (string_elf_symbol_map::const_iterator e =
9951  added_unrefed_var_syms_.begin();
9952  e != added_unrefed_var_syms_.end();
9953  ++e)
9954  if (var_suppr->suppresses_variable_symbol(e->second,
9956  ctxt))
9957  suppressed_added_unrefed_var_syms_[e->first] = e->second;
9958 
9959  // Removed variable symbols not referenced by any debug info
9960  for (string_elf_symbol_map::const_iterator e =
9961  deleted_unrefed_var_syms_.begin();
9962  e != deleted_unrefed_var_syms_.end();
9963  ++e)
9964  if (var_suppr->suppresses_variable_symbol(e->second,
9966  ctxt))
9967  suppressed_deleted_unrefed_var_syms_[e->first] = e->second;
9968  }
9969  }
9970 }
9971 
9972 /// Test if the change reports for a given deleted function have
9973 /// been deleted.
9974 ///
9975 /// @param fn the function to consider.
9976 ///
9977 /// @return true iff the change reports for a give given deleted
9978 /// function have been deleted.
9979 bool
9981 {
9982  if (!fn)
9983  return false;
9984 
9985  string_function_ptr_map::const_iterator i =
9986  suppressed_deleted_fns_.find(fn->get_id());
9987 
9988  return (i != suppressed_deleted_fns_.end());
9989 }
9990 
9991 /// Test if an added type that is unreachable from public interface
9992 /// has been suppressed by a suppression specification.
9993 ///
9994 /// @param t the added unreachable type to be considered.
9995 ///
9996 /// @return true iff @p t has been suppressed by a suppression
9997 /// specification.
9998 bool
10000 {
10001  if (!t)
10002  return false;
10003 
10004  string repr = abigail::ir::get_pretty_representation(t, /*internal=*/false);
10005  string_type_base_sptr_map::const_iterator i =
10006  suppressed_added_unreachable_types_.find(repr);
10007  if (i == suppressed_added_unreachable_types_.end())
10008  return false;
10009 
10010  return true;
10011 }
10012 
10013 /// Test if a deleted type that is unreachable from public interface
10014 /// has been suppressed by a suppression specification.
10015 ///
10016 /// @param t the deleted unreachable type to be considered.
10017 ///
10018 /// @return true iff @p t has been suppressed by a suppression
10019 /// specification.
10020 bool
10022 {
10023  if (!t)
10024  return false;
10025 
10026  string repr = abigail::ir::get_pretty_representation(t, /*internal=*/false);
10027  string_type_base_sptr_map::const_iterator i =
10028  suppressed_deleted_unreachable_types_.find(repr);
10029  if (i == suppressed_deleted_unreachable_types_.end())
10030  return false;
10031 
10032  return true;
10033 }
10034 
10035 /// Test if the change reports for a give given added function has
10036 /// been deleted.
10037 ///
10038 /// @param fn the function to consider.
10039 ///
10040 /// @return true iff the change reports for a give given added
10041 /// function has been deleted.
10042 bool
10044 {
10045  if (!fn)
10046  return false;
10047 
10048  string_function_ptr_map::const_iterator i =
10049  suppressed_added_fns_.find(fn->get_id());
10050 
10051  return (i != suppressed_added_fns_.end());
10052 }
10053 
10054 /// Test if the change reports for a give given deleted variable has
10055 /// been deleted.
10056 ///
10057 /// @param var the variable to consider.
10058 ///
10059 /// @return true iff the change reports for a give given deleted
10060 /// variable has been deleted.
10061 bool
10063 {
10064  if (!var)
10065  return false;
10066 
10067  string_var_ptr_map::const_iterator i =
10068  suppressed_deleted_vars_.find(var->get_id());
10069 
10070  return (i != suppressed_deleted_vars_.end());
10071 }
10072 
10073 /// Test if the change reports for a given added variable have been
10074 /// suppressed.
10075 ///
10076 /// @param var the variable to consider.
10077 ///
10078 /// @return true iff the change reports for a given deleted
10079 /// variable has been deleted.
10080 bool
10082 {
10083  if (!var)
10084  return false;
10085 
10086  string_var_ptr_map::const_iterator i =
10087  suppressed_added_vars_.find(var->get_id());
10088 
10089  return (i != suppressed_added_vars_.end());
10090 }
10091 
10092 /// Test if the change reports for a given deleted function symbol
10093 /// (that is not referenced by any debug info) has been suppressed.
10094 ///
10095 /// @param var the function to consider.
10096 ///
10097 /// @return true iff the change reports for a given deleted function
10098 /// symbol has been suppressed.
10099 bool
10101 {
10102  if (!s)
10103  return false;
10104 
10105  string_elf_symbol_map::const_iterator i =
10106  suppressed_deleted_unrefed_fn_syms_.find(s->get_id_string());
10107 
10108  return (i != suppressed_deleted_unrefed_fn_syms_.end());
10109 }
10110 
10111 /// Test if the change reports for a given added function symbol
10112 /// (that is not referenced by any debug info) has been suppressed.
10113 ///
10114 /// @param var the function to consider.
10115 ///
10116 /// @return true iff the change reports for a given added function
10117 /// symbol has been suppressed.
10118 bool
10120 {
10121  if (!s)
10122  return false;
10123 
10124  string_elf_symbol_map::const_iterator i =
10125  suppressed_added_unrefed_fn_syms_.find(s->get_id_string());
10126 
10127  return (i != suppressed_added_unrefed_fn_syms_.end());
10128 }
10129 
10130 /// Test if the change reports for a given deleted variable symbol
10131 /// (that is not referenced by any debug info) has been suppressed.
10132 ///
10133 /// @param var the variable to consider.
10134 ///
10135 /// @return true iff the change reports for a given deleted variable
10136 /// symbol has been suppressed.
10137 bool
10139 {
10140  if (!s)
10141  return false;
10142 
10143  string_elf_symbol_map::const_iterator i =
10144  suppressed_deleted_unrefed_var_syms_.find(s->get_id_string());
10145 
10146  return (i != suppressed_deleted_unrefed_var_syms_.end());
10147 }
10148 
10149 /// Test if the change reports for a given added variable symbol
10150 /// (that is not referenced by any debug info) has been suppressed.
10151 ///
10152 /// @param var the variable to consider.
10153 ///
10154 /// @return true iff the change reports for a given added variable
10155 /// symbol has been suppressed.
10156 bool
10158 {
10159  if (!s)
10160  return false;
10161 
10162  string_elf_symbol_map::const_iterator i =
10163  suppressed_added_unrefed_var_syms_.find(s->get_id_string());
10164 
10165  return (i != suppressed_added_unrefed_var_syms_.end());
10166 }
10167 
10168 #ifdef do_count_diff_map_changes
10169 #undef do_count_diff_map_changes
10170 #endif
10171 #define do_count_diff_map_changes(diff_map, n_changes, n_filtered) \
10172  { \
10173  string_diff_ptr_map::const_iterator i; \
10174  for (i = diff_map.begin(); \
10175  i != diff_map.end(); \
10176  ++i) \
10177  { \
10178  if (const var_diff* d = is_var_diff(i->second)) \
10179  if (is_data_member(d->first_var())) \
10180  continue; \
10181  \
10182  if (i->second->has_local_changes()) \
10183  ++n_changes; \
10184  if (!i->second->get_canonical_diff()->to_be_reported()) \
10185  ++n_filtered; \
10186  } \
10187  }
10188 
10189 /// Count the number of leaf changes as well as the number of the
10190 /// changes that have been filtered out.
10191 ///
10192 /// @param num_changes out parameter. This is set to the total number
10193 /// of leaf changes.
10194 ///
10195 /// @param num_filtered out parameter. This is set to the number of
10196 /// leaf changes that have been filtered out.
10197 void
10198 corpus_diff::priv::count_leaf_changes(size_t &num_changes, size_t &num_filtered)
10199 {
10200  count_leaf_type_changes(num_changes, num_filtered);
10201 
10202  // Now count the non-type changes.
10203  do_count_diff_map_changes(leaf_diffs_.get_function_decl_diff_map(),
10204  num_changes, num_filtered);
10205  do_count_diff_map_changes(leaf_diffs_.get_var_decl_diff_map(),
10206  num_changes, num_filtered);
10207 }
10208 
10209 /// Count the number of leaf *type* changes as well as the number of
10210 /// the leaf type changes that have been filtered out.
10211 ///
10212 /// @param num_changes out parameter. This is set to the total number
10213 /// of leaf type changes.
10214 ///
10215 /// @param num_filtered out parameter. This is set to the number of
10216 /// leaf type changes that have been filtered out.
10217 void
10219  size_t &num_filtered)
10220 {
10221  do_count_diff_map_changes(leaf_diffs_.get_type_decl_diff_map(),
10222  num_changes, num_filtered);
10223  do_count_diff_map_changes(leaf_diffs_.get_enum_diff_map(),
10224  num_changes, num_filtered);
10225  do_count_diff_map_changes(leaf_diffs_.get_class_diff_map(),
10226  num_changes, num_filtered);
10227  do_count_diff_map_changes(leaf_diffs_.get_union_diff_map(),
10228  num_changes, num_filtered);
10229  do_count_diff_map_changes(leaf_diffs_.get_typedef_diff_map(),
10230  num_changes, num_filtered);
10231  do_count_diff_map_changes(leaf_diffs_.get_subrange_diff_map(),
10232  num_changes, num_filtered);
10233  do_count_diff_map_changes(leaf_diffs_.get_array_diff_map(),
10234  num_changes, num_filtered);
10235  do_count_diff_map_changes(leaf_diffs_.get_distinct_diff_map(),
10236  num_changes, num_filtered);
10237  do_count_diff_map_changes(leaf_diffs_.get_fn_parm_diff_map(),
10238  num_changes, num_filtered);
10239 }
10240 
10241 /// Count the number of types not reachable from the interface (i.e,
10242 /// not reachable from global functions or variables).
10243 ///
10244 /// @param num_added this is set to the number of added types not
10245 /// reachable from the interface.
10246 ///
10247 /// @param num_deleted this is set to the number of deleted types not
10248 /// reachable from the interface.
10249 ///
10250 /// @param num_changed this is set to the number of changed types not
10251 /// reachable from the interface.
10252 ///
10253 /// @param num_filtered_added this is set to the number of added types
10254 /// not reachable from the interface and that have been filtered out
10255 /// by suppression specifications.
10256 ///
10257 /// @param num_filtered_deleted this is set to the number of deleted
10258 /// types not reachable from the interface and that have been filtered
10259 /// out by suppression specifications.
10260 ///
10261 /// @param num_filtered_changed this is set to the number of changed
10262 /// types not reachable from the interface and that have been filtered
10263 /// out by suppression specifications.
10264 void
10266  size_t &num_deleted,
10267  size_t &num_changed,
10268  size_t &num_filtered_added,
10269  size_t &num_filtered_deleted,
10270  size_t &num_filtered_changed)
10271 {
10272  num_added = added_unreachable_types_.size();
10273  num_deleted = deleted_unreachable_types_.size();
10274  num_changed = changed_unreachable_types_.size();
10275  num_filtered_added = suppressed_added_unreachable_types_.size();
10276  num_filtered_deleted = suppressed_deleted_unreachable_types_.size();
10277 
10278  for (vector<diff_sptr>::const_iterator i =
10280  i != changed_unreachable_types_sorted().end();
10281  ++i)
10282  if (!(*i)->to_be_reported())
10283  ++num_filtered_changed;
10284 }
10285 
10286 /// Get the map of diff nodes representing changed unreachable types.
10287 ///
10288 /// @return the map of diff nodes representing changed unreachable
10289 /// types.
10290 const string_diff_sptr_map&
10292 {return changed_unreachable_types_;}
10293 
10294 /// Get the sorted vector of diff nodes representing changed
10295 /// unreachable types.
10296 ///
10297 /// Upon the first invocation of this method, if the vector is empty,
10298 /// this function gets the diff nodes representing changed
10299 /// unreachable, sort them, and return the sorted vector.
10300 ///
10301 /// @return the sorted vector of diff nodes representing changed
10302 /// unreachable types.
10303 const vector<diff_sptr>&
10305 {
10306 if (changed_unreachable_types_sorted_.empty())
10307  if (!changed_unreachable_types_.empty())
10308  sort_string_diff_sptr_map(changed_unreachable_types_,
10309  changed_unreachable_types_sorted_);
10310 
10311  return changed_unreachable_types_sorted_;
10312 }
10313 
10314 /// Compute the diff stats.
10315 ///
10316 /// To know the number of functions that got filtered out, this
10317 /// function applies the categorizing filters to the diff sub-trees of
10318 /// each function changes diff, prior to calculating the stats.
10319 ///
10320 /// @param num_removed the number of removed functions.
10321 ///
10322 /// @param num_added the number of added functions.
10323 ///
10324 /// @param num_changed the number of changed functions.
10325 ///
10326 /// @param num_filtered_out the number of changed functions that are
10327 /// got filtered out from the report
10328 void
10330 {
10331  stat.num_func_removed(deleted_fns_.size());
10332  stat.num_removed_func_filtered_out(suppressed_deleted_fns_.size());
10333  stat.num_func_added(added_fns_.size());
10334  stat.num_added_func_filtered_out(suppressed_added_fns_.size());
10335  stat.num_func_changed(changed_fns_map_.size());
10336 
10337  stat.num_vars_removed(deleted_vars_.size());
10338  stat.num_removed_vars_filtered_out(suppressed_deleted_vars_.size());
10339  stat.num_vars_added(added_vars_.size());
10340  stat.num_added_vars_filtered_out(suppressed_added_vars_.size());
10341  stat.num_vars_changed(changed_vars_map_.size());
10342 
10343  diff_context_sptr ctxt = get_context();
10344 
10346  if (ctxt->perform_change_categorization())
10347  {
10348  if (get_context()->do_log())
10349  {
10350  std::cerr << "in apply_filters_and_compute_diff_stats:"
10351  << "applying filters to "
10352  << changed_fns_.size()
10353  << " changed fns ...\n";
10354  t.start();
10355  }
10356  // Walk the changed function diff nodes to apply the categorization
10357  // filters.
10358  diff_sptr diff;
10359  for (function_decl_diff_sptrs_type::const_iterator i =
10360  changed_fns_.begin();
10361  i != changed_fns_.end();
10362  ++i)
10363  {
10364  diff_sptr diff = *i;
10365  ctxt->maybe_apply_filters(diff);
10366  }
10367 
10368  if (get_context()->do_log())
10369  {
10370  t.stop();
10371  std::cerr << "in apply_filters_and_compute_diff_stats:"
10372  << "filters to changed fn applied!:" << t << "\n";
10373 
10374  std::cerr << "in apply_filters_and_compute_diff_stats:"
10375  << "applying filters to "
10376  << sorted_changed_vars_.size()
10377  << " changed vars ...\n";
10378  t.start();
10379  }
10380 
10381  // Walk the changed variable diff nodes to apply the categorization
10382  // filters.
10383  for (var_diff_sptrs_type::const_iterator i = sorted_changed_vars_.begin();
10384  i != sorted_changed_vars_.end();
10385  ++i)
10386  {
10387  diff_sptr diff = *i;
10388  ctxt->maybe_apply_filters(diff);
10389  }
10390 
10391  if (get_context()->do_log())
10392  {
10393  t.stop();
10394  std::cerr << "in apply_filters_and_compute_diff_stats:"
10395  << "filters to changed vars applied!:" << t << "\n";
10396 
10397  std::cerr << "in apply_filters_and_compute_diff_stats:"
10398  << "applying filters to unreachable types ...\n";
10399  t.start();
10400  }
10401 
10402  // walk the changed unreachable types to apply categorization
10403  // filters
10404  for (auto& diff : changed_unreachable_types_sorted())
10405  ctxt->maybe_apply_filters(diff);
10406 
10407  for (auto& entry : changed_unreachable_types())
10408  ctxt->maybe_apply_filters(entry.second);
10409 
10410  if (get_context()->do_log())
10411  {
10412  t.stop();
10413  std::cerr << "in apply_filters_and_compute_diff_stats:"
10414  << "filters to unreachable types applied!:" << t << "\n";
10415 
10416  std::cerr << "in apply_filters_and_compute_diff_stats:"
10417  << "categorizing redundant changed sub nodes ...\n";
10418  t.start();
10419  }
10420 
10421  categorize_redundant_changed_sub_nodes();
10422 
10423  if (get_context()->do_log())
10424  {
10425  t.stop();
10426  std::cerr << "in apply_filters_and_compute_diff_stats:"
10427  << "redundant changed sub nodes categorized!:" << t << "\n";
10428 
10429  std::cerr << "in apply_filters_and_compute_diff_stats:"
10430  << "count changed fns ...\n";
10431  t.start();
10432  }
10433  }
10434 
10435  // Walk the changed function diff nodes to count the number of
10436  // filtered-out functions and the number of functions with virtual
10437  // offset changes.
10438  for (function_decl_diff_sptrs_type::const_iterator i =
10439  changed_fns_.begin();
10440  i != changed_fns_.end();
10441  ++i)
10442  {
10443  if ((*i)->is_filtered_out())
10444  {
10446  (stat.num_changed_func_filtered_out() + 1);
10447 
10448  if ((*i)->has_local_changes())
10451  }
10452  else
10453  {
10454  if ((*i)->get_category() & VIRTUAL_MEMBER_CHANGE_CATEGORY)
10457  }
10458 
10459  if ((*i)->has_local_changes())
10461  (stat.num_leaf_func_changes() + 1);
10462  }
10463 
10464  if (get_context()->do_log())
10465  {
10466  t.stop();
10467  std::cerr << "in apply_filters_and_compute_diff_stats:"
10468  << "changed fn counted!:" << t << "\n";
10469 
10470  std::cerr << "in apply_filters_and_compute_diff_stats:"
10471  << "count changed vars ...\n";
10472  t.start();
10473  }
10474 
10475  // Walk the changed variables diff nodes to count the number of
10476  // filtered-out variables.
10477  for (var_diff_sptrs_type ::const_iterator i = sorted_changed_vars_.begin();
10478  i != sorted_changed_vars_.end();
10479  ++i)
10480  {
10481  if ((*i)->is_filtered_out())
10482  {
10484  (stat.num_changed_vars_filtered_out() + 1);
10485 
10486  if ((*i)->has_local_changes())
10488  (stat.num_leaf_var_changes_filtered_out() + 1);
10489  }
10490  if ((*i)->has_local_changes())
10492  (stat.num_leaf_var_changes() + 1);
10493  }
10494 
10495  if (get_context()->do_log())
10496  {
10497  t.stop();
10498  std::cerr << "in apply_filters_and_compute_diff_stats:"
10499  << "changed vars counted!:" << t << "\n";
10500 
10501  std::cerr << "in apply_filters_and_compute_diff_stats:"
10502  << "count leaf changed types ...\n";
10503  t.start();
10504  }
10505 
10506  stat.num_func_syms_added(added_unrefed_fn_syms_.size());
10507  stat.num_added_func_syms_filtered_out(suppressed_added_unrefed_fn_syms_.size());
10508  stat.num_func_syms_removed(deleted_unrefed_fn_syms_.size());
10509  stat.num_removed_func_syms_filtered_out(suppressed_deleted_unrefed_fn_syms_.size());
10510  stat.num_var_syms_added(added_unrefed_var_syms_.size());
10511  stat.num_added_var_syms_filtered_out(suppressed_added_unrefed_var_syms_.size());
10512  stat.num_var_syms_removed(deleted_unrefed_var_syms_.size());
10513  stat.num_removed_var_syms_filtered_out(suppressed_deleted_unrefed_var_syms_.size());
10514 
10515  // Walk the general leaf type diff nodes to count them
10516  {
10517  size_t num_type_changes = 0, num_type_filtered = 0;
10518  count_leaf_type_changes(num_type_changes, num_type_filtered);
10519 
10520  stat.num_leaf_type_changes(num_type_changes);
10521  stat.num_leaf_type_changes_filtered_out(num_type_filtered);
10522  }
10523 
10524  if (get_context()->do_log())
10525  {
10526  t.stop();
10527  std::cerr << "in apply_filters_and_compute_diff_stats:"
10528  << "changed leaf types counted!:" << t << "\n";
10529 
10530  std::cerr << "in apply_filters_and_compute_diff_stats:"
10531  << "count leaf changed artefacts ...\n";
10532  t.start();
10533  }
10534 
10535  // Walk the general leaf artefacts diff nodes to count them
10536  {
10537  size_t num_changes = 0, num_filtered = 0;
10538  count_leaf_changes(num_changes, num_filtered);
10539 
10540  stat.num_leaf_changes(num_changes);
10541  stat.num_leaf_changes_filtered_out(num_filtered);
10542  }
10543 
10544  if (get_context()->do_log())
10545  {
10546  t.stop();
10547  std::cerr << "in apply_filters_and_compute_diff_stats:"
10548  << "changed leaf artefacts counted!:" << t << "\n";
10549 
10550  std::cerr << "in apply_filters_and_compute_diff_stats:"
10551  << "count unreachable types ...\n";
10552  t.start();
10553  }
10554 
10555  // Walk the unreachable types to count them
10556  {
10557  size_t num_added_unreachable_types = 0,
10558  num_changed_unreachable_types = 0,
10559  num_deleted_unreachable_types = 0,
10560  num_added_unreachable_types_filtered = 0,
10561  num_changed_unreachable_types_filtered = 0,
10562  num_deleted_unreachable_types_filtered = 0;
10563 
10564  count_unreachable_types(num_added_unreachable_types,
10565  num_deleted_unreachable_types,
10566  num_changed_unreachable_types,
10567  num_added_unreachable_types_filtered,
10568  num_deleted_unreachable_types_filtered,
10569  num_changed_unreachable_types_filtered);
10570 
10571  if (get_context()->do_log())
10572  {
10573  t.stop();
10574  std::cerr << "in apply_filters_and_compute_diff_stats:"
10575  << "unreachable types counted!:" << t << "\n";
10576  }
10577 
10578  stat.num_added_unreachable_types(num_added_unreachable_types);
10579  stat.num_removed_unreachable_types(num_deleted_unreachable_types);
10580  stat.num_changed_unreachable_types(num_changed_unreachable_types);
10582  (num_added_unreachable_types_filtered);
10584  (num_deleted_unreachable_types_filtered);
10586  (num_changed_unreachable_types_filtered);
10587  }
10588 }
10589 
10590 /// Emit the summary of the functions & variables that got
10591 /// removed/changed/added.
10592 ///
10593 /// TODO: This should be handled by the reporters, just like what is
10594 /// done for reporter_base::diff_to_be_reported.
10595 ///
10596 /// @param out the output stream to emit the stats to.
10597 ///
10598 /// @param indent the indentation string to use in the summary.
10599 void
10601  ostream& out,
10602  const string& indent)
10603 {
10604  /// Report added/removed/changed functions.
10605  size_t net_num_leaf_changes =
10606  s.net_num_func_removed() +
10607  s.net_num_func_added() +
10609  s.net_num_vars_removed() +
10610  s.net_num_vars_added() +
10617 
10618  if (!sonames_equal_)
10619  out << indent << "ELF SONAME changed\n";
10620 
10621  if (!architectures_equal_)
10622  out << indent << "ELF architecture changed\n";
10623 
10624  diff_context_sptr ctxt = get_context();
10625 
10626  if (ctxt->show_leaf_changes_only())
10627  {
10628  out << "Leaf changes summary: ";
10629  out << net_num_leaf_changes << " artifact";
10630  if (net_num_leaf_changes > 1)
10631  out << "s";
10632  out << " changed";
10633 
10634  if (size_t num_filtered = s.num_leaf_changes_filtered_out())
10635  out << " (" << num_filtered << " filtered out)";
10636  out << "\n";
10637 
10638  out << indent << "Changed leaf types summary: "
10641  out << " (" << s.num_leaf_type_changes_filtered_out()
10642  << " filtered out)";
10643  out << " leaf type";
10644  if (s.num_leaf_type_changes() > 1)
10645  out << "s";
10646  out << " changed\n";
10647 
10648  // function changes summary
10649  out << indent << "Removed/Changed/Added functions summary: ";
10650  out << s.net_num_func_removed() << " Removed";
10652  out << " ("
10654  << " filtered out)";
10655  out << ", ";
10656 
10657  out << s.net_num_leaf_func_changes() << " Changed";
10659  out << " ("
10661  << " filtered out)";
10662  out << ", ";
10663 
10664  out << s.net_num_func_added()<< " Added ";
10665  if (s.net_num_func_added() <= 1)
10666  out << "function";
10667  else
10668  out << "functions";
10670  out << " (" << s.num_added_func_filtered_out() << " filtered out)";
10671  out << "\n";
10672 
10673  // variables changes summary
10674  out << indent << "Removed/Changed/Added variables summary: ";
10675  out << s.net_num_vars_removed() << " Removed";
10677  out << " (" << s.num_removed_vars_filtered_out()
10678  << " filtered out)";
10679  out << ", ";
10680 
10681  out << s.net_num_leaf_var_changes() << " Changed";
10683  out << " ("
10685  << " filtered out)";
10686  out << ", ";
10687 
10688  out << s.net_num_vars_added() << " Added ";
10689  if (s.net_num_vars_added() <= 1)
10690  out << "variable";
10691  else
10692  out << "variables";
10694  out << " (" << s.num_added_vars_filtered_out()
10695  << " filtered out)";
10696  out << "\n";
10697  }
10698  else // if (ctxt->show_leaf_changes_only())
10699  {
10700  size_t total_nb_function_changes = s.num_func_removed()
10701  + s.num_func_changed() + s.num_func_added();
10702 
10703  // function changes summary
10704  out << indent << "Functions changes summary: ";
10705  out << s.net_num_func_removed() << " Removed";
10707  out << " ("
10709  << " filtered out)";
10710  out << ", ";
10711 
10712  out << s.net_num_func_changed() << " Changed";
10714  out << " (" << s.num_changed_func_filtered_out() << " filtered out)";
10715  out << ", ";
10716 
10717  out << s.net_num_func_added() << " Added";
10719  out << " (" << s.num_added_func_filtered_out() << " filtered out)";
10720  if (total_nb_function_changes <= 1)
10721  out << " function";
10722  else
10723  out << " functions";
10724  out << "\n";
10725 
10726  // variables changes summary
10727  size_t total_nb_variable_changes = s.num_vars_removed()
10728  + s.num_vars_changed() + s.num_vars_added();
10729 
10730  out << indent << "Variables changes summary: ";
10731  out << s.net_num_vars_removed() << " Removed";
10733  out << " (" << s.num_removed_vars_filtered_out()
10734  << " filtered out)";
10735  out << ", ";
10736 
10737  out << s.num_vars_changed() - s.num_changed_vars_filtered_out() << " Changed";
10739  out << " (" << s.num_changed_vars_filtered_out() << " filtered out)";
10740  out << ", ";
10741 
10742  out << s.net_num_vars_added() << " Added";
10744  out << " (" << s.num_added_vars_filtered_out()
10745  << " filtered out)";
10746  if (total_nb_variable_changes <= 1)
10747  out << " variable";
10748  else
10749  out << " variables";
10750  out << "\n";
10751  }
10752 
10753  // Show statistics about types not reachable from global
10754  // functions/variables.
10755  if (ctxt->show_unreachable_types())
10756  {
10757  size_t total_nb_unreachable_type_changes =
10761 
10762  // Show summary of unreachable types
10763  out << indent << "Unreachable types summary: "
10765  << " removed";
10768  << " filtered out)";
10769  out << ", ";
10770 
10772  << " changed";
10775  << " filtered out)";
10776  out << ", ";
10777 
10779  << " added";
10781  out << " (" << s.num_added_unreachable_types_filtered_out()
10782  << " filtered out)";
10783  if (total_nb_unreachable_type_changes <= 1)
10784  out << " type";
10785  else
10786  out << " types";
10787  out << "\n";
10788  }
10789 
10790  if (ctxt->show_symbols_unreferenced_by_debug_info()
10791  && (s.num_func_syms_removed()
10792  || s.num_func_syms_added()
10793  || s.num_var_syms_removed()
10794  || s.num_var_syms_added()))
10795  {
10796  // function symbols changes summary.
10797 
10798  if (!ctxt->show_added_symbols_unreferenced_by_debug_info()
10799  && s.num_func_syms_removed() == 0
10800  && s.num_func_syms_added() != 0)
10801  // If the only unreferenced function symbol change is function
10802  // syms that got added, but we were forbidden to show function
10803  // syms being added, do nothing.
10804  ;
10805  else
10806  {
10807  out << indent
10808  << "Function symbols changes summary: "
10809  << s.net_num_removed_func_syms() << " Removed";
10811  out << " (" << s.num_removed_func_syms_filtered_out()
10812  << " filtered out)";
10813  out << ", ";
10814  out << s.net_num_added_func_syms() << " Added";
10816  out << " (" << s.num_added_func_syms_filtered_out()
10817  << " filtered out)";
10818  out << " function symbol";
10819  if (s.num_func_syms_added() + s.num_func_syms_removed() > 1)
10820  out << "s";
10821  out << " not referenced by debug info\n";
10822  }
10823 
10824  // variable symbol changes summary.
10825 
10826  if (!ctxt->show_added_symbols_unreferenced_by_debug_info()
10827  && s.num_var_syms_removed() == 0
10828  && s.num_var_syms_added() != 0)
10829  // If the only unreferenced variable symbol change is variable
10830  // syms that got added, but we were forbidden to show variable
10831  // syms being added, do nothing.
10832  ;
10833  else
10834  {
10835  out << indent
10836  << "Variable symbols changes summary: "
10837  << s.net_num_removed_var_syms() << " Removed";
10839  out << " (" << s.num_removed_var_syms_filtered_out()
10840  << " filtered out)";
10841  out << ", ";
10842  out << s.net_num_added_var_syms() << " Added";
10844  out << " (" << s.num_added_var_syms_filtered_out()
10845  << " filtered out)";
10846  out << " variable symbol";
10847  if (s.num_var_syms_added() + s.num_var_syms_removed() > 1)
10848  out << "s";
10849  out << " not referenced by debug info\n";
10850  }
10851  }
10852 }
10853 
10854 /// Walk the changed functions and variables diff nodes to categorize
10855 /// redundant nodes.
10856 void
10858 {
10859  diff_sptr diff;
10860 
10861  diff_context_sptr ctxt = get_context();
10862 
10863  ctxt->forget_visited_diffs();
10864  for (function_decl_diff_sptrs_type::const_iterator i =
10865  changed_fns_.begin();
10866  i!= changed_fns_.end();
10867  ++i)
10868  {
10869  diff = *i;
10870  categorize_redundancy(diff);
10871  }
10872 
10873  for (var_diff_sptrs_type::const_iterator i = sorted_changed_vars_.begin();
10874  i!= sorted_changed_vars_.end();
10875  ++i)
10876  {
10877  diff_sptr diff = *i;
10878  categorize_redundancy(diff);
10879  }
10880 
10881  for (diff_sptrs_type::const_iterator i =
10884  ++i)
10885  {
10886  diff_sptr diff = *i;
10887  categorize_redundancy(diff);
10888  }
10889 }
10890 
10891 /// Walk the changed functions and variables diff nodes and clear the
10892 /// redundancy categorization they might carry.
10893 void
10895 {
10896  diff_sptr diff;
10897  for (function_decl_diff_sptrs_type::const_iterator i = changed_fns_.begin();
10898  i!= changed_fns_.end();
10899  ++i)
10900  {
10901  diff = *i;
10903  }
10904 
10905  for (var_diff_sptrs_type::const_iterator i = sorted_changed_vars_.begin();
10906  i!= sorted_changed_vars_.end();
10907  ++i)
10908  {
10909  diff = *i;
10911  }
10912 }
10913 
10914 /// If the user asked to dump the diff tree node (for changed
10915 /// variables and functions) on the error output stream, then just do
10916 /// that.
10917 ///
10918 /// This function is used for debugging purposes.
10919 void
10921 {
10922  diff_context_sptr ctxt = get_context();
10923 
10924  if (!ctxt->dump_diff_tree()
10925  || ctxt->error_output_stream() == 0)
10926  return;
10927 
10928  if (!changed_fns_.empty())
10929  {
10930  *ctxt->error_output_stream() << "changed functions diff tree: \n\n";
10931  for (function_decl_diff_sptrs_type::const_iterator i =
10932  changed_fns_.begin();
10933  i != changed_fns_.end();
10934  ++i)
10935  {
10936  diff_sptr d = *i;
10937  print_diff_tree(d, *ctxt->error_output_stream());
10938  }
10939  }
10940 
10941  if (!sorted_changed_vars_.empty())
10942  {
10943  *ctxt->error_output_stream() << "\nchanged variables diff tree: \n\n";
10944  for (var_diff_sptrs_type::const_iterator i =
10945  sorted_changed_vars_.begin();
10946  i != sorted_changed_vars_.end();
10947  ++i)
10948  {
10949  diff_sptr d = *i;
10950  print_diff_tree(d, *ctxt->error_output_stream());
10951  }
10952  }
10953 
10954  if (!changed_unreachable_types_sorted().empty())
10955  {
10956  *ctxt->error_output_stream() << "\nchanged unreachable "
10957  "types diff tree: \n\n";
10958  for (vector<diff_sptr>::const_iterator i =
10960  i != changed_unreachable_types_sorted().end();
10961  ++i)
10962  {
10963  diff_sptr d = *i;
10964  print_diff_tree(d, *ctxt->error_output_stream());
10965  }
10966  }
10967 }
10968 
10969 /// Populate the vector of children node of the @ref corpus_diff type.
10970 ///
10971 /// The children node can then later be retrieved using
10972 /// corpus_diff::children_node().
10973 void
10975 {
10976  for (function_decl_diff_sptrs_type::const_iterator i =
10977  changed_functions_sorted().begin();
10978  i != changed_functions_sorted().end();
10979  ++i)
10980  if (diff_sptr d = *i)
10981  append_child_node(d);
10982 }
10983 
10984 /// Constructor for @ref corpus_diff.
10985 ///
10986 /// @param first the first corpus of the diff.
10987 ///
10988 /// @param second the second corpus of the diff.
10989 ///
10990 /// @param ctxt the diff context to use. Note that this context
10991 /// object must stay alive at least during the life time of the
10992 /// current instance of @ref corpus_diff. Otherwise memory corruption
10993 /// issues occur.
10994 corpus_diff::corpus_diff(corpus_sptr first,
10995  corpus_sptr second,
10996  diff_context_sptr ctxt)
10997  : priv_(new priv(first, second, ctxt))
10998 {}
10999 
11000 corpus_diff::~corpus_diff() = default;
11001 
11002 /// Finish building the current instance of @ref corpus_diff.
11003 void
11005 {
11006  if (priv_->finished_)
11007  return;
11009  priv_->finished_ = true;
11010 }
11011 
11012 /// Test if logging was requested.
11013 ///
11014 /// @return true iff logging was requested.
11015 bool
11017 {return context()->do_log();}
11018 
11019 /// Request logging, or not.
11020 ///
11021 /// @param f true iff logging is requested.
11022 void
11024 {context()->do_log(f);}
11025 
11026 /// @return the first corpus of the diff.
11027 corpus_sptr
11029 {return priv_->first_;}
11030 
11031 /// @return the second corpus of the diff.
11032 corpus_sptr
11034 {return priv_->second_;}
11035 
11036 /// @return the children nodes of the current instance of corpus_diff.
11037 const vector<diff*>&
11039 {return priv_->children_;}
11040 
11041 /// Append a new child node to the vector of children nodes for the
11042 /// current instance of @ref corpus_diff node.
11043 ///
11044 /// Note that the vector of children nodes for the current instance of
11045 /// @ref corpus_diff node must remain sorted, using
11046 /// diff_less_than_functor.
11047 ///
11048 /// @param d the new child node. Note that the life time of the
11049 /// object held by @p d will thus equal the life time of the current
11050 /// instance of @ref corpus_diff.
11051 void
11053 {
11054  ABG_ASSERT(d);
11055 
11056  diff_less_than_functor is_less_than;
11057  bool inserted = false;
11058  for (vector<diff*>::iterator i = priv_->children_.begin();
11059  i != priv_->children_.end();
11060  ++i)
11061  // Look for the point where to insert the diff child node.
11062  if (!is_less_than(d.get(), *i))
11063  {
11064  context()->keep_diff_alive(d);
11065  priv_->children_.insert(i, d.get());
11066  // As we have just inserted 'd' into the vector, the iterator
11067  // 'i' is invalidated. We must *NOT* use it anymore.
11068  inserted = true;
11069  break;
11070  }
11071 
11072  if (!inserted)
11073  {
11074  context()->keep_diff_alive(d);
11075  // We didn't insert anything to the vector, presumably b/c it was
11076  // empty or had one element that was "less than" 'd'. We can thus
11077  // just append 'd' to the end of the vector.
11078  priv_->children_.push_back(d.get());
11079  }
11080 }
11081 
11082 /// @return the bare edit script of the functions changed as recorded
11083 /// by the diff.
11084 edit_script&
11086 {return priv_->fns_edit_script_;}
11087 
11088 /// @return the bare edit script of the variables changed as recorded
11089 /// by the diff.
11090 edit_script&
11092 {return priv_->vars_edit_script_;}
11093 
11094 /// Test if the soname of the underlying corpus has changed.
11095 ///
11096 /// @return true iff the soname has changed.
11097 bool
11099 {return !priv_->sonames_equal_;}
11100 
11101 /// Test if the architecture of the underlying corpus has changed.
11102 ///
11103 /// @return true iff the architecture has changed.
11104 bool
11106 {return !priv_->architectures_equal_;}
11107 
11108 /// Getter for the deleted functions of the diff.
11109 ///
11110 /// @return the the deleted functions of the diff.
11113 {return priv_->deleted_fns_;}
11114 
11115 /// Getter for the added functions of the diff.
11116 ///
11117 /// @return the added functions of the diff.
11120 {return priv_->added_fns_;}
11121 
11122 /// Getter for the functions which signature didn't change, but which
11123 /// do have some indirect changes in their parms.
11124 ///
11125 /// @return a non-sorted map of functions which signature didn't
11126 /// change, but which do have some indirect changes in their parms.
11127 /// The key of the map is a unique identifier for the function; it's
11128 /// usually made of the name and version of the underlying ELF symbol
11129 /// of the function for corpora that were built from ELF files.
11132 {return priv_->changed_fns_map_;}
11133 
11134 /// Getter for a sorted vector of functions which signature didn't
11135 /// change, but which do have some indirect changes in their parms.
11136 ///
11137 /// @return a sorted vector of functions which signature didn't
11138 /// change, but which do have some indirect changes in their parms.
11141 {return priv_->changed_fns_;}
11142 
11143 /// Getter for the variables that got deleted from the first subject
11144 /// of the diff.
11145 ///
11146 /// @return the map of deleted variable.
11147 const string_var_ptr_map&
11149 {return priv_->deleted_vars_;}
11150 
11151 /// Getter for the added variables of the diff.
11152 ///
11153 /// @return the map of added variable.
11154 const string_var_ptr_map&
11156 {return priv_->added_vars_;}
11157 
11158 /// Getter for the non-sorted map of variables which signature didn't
11159 /// change but which do have some indirect changes in some sub-types.
11160 ///
11161 /// @return the non-sorted map of changed variables.
11164 {return priv_->changed_vars_map_;}
11165 
11166 /// Getter for the sorted vector of variables which signature didn't
11167 /// change but which do have some indirect changes in some sub-types.
11168 ///
11169 /// @return a sorted vector of changed variables.
11170 const var_diff_sptrs_type&
11172 {return priv_->sorted_changed_vars_;}
11173 
11174 /// Getter for function symbols not referenced by any debug info and
11175 /// that got deleted.
11176 ///
11177 /// @return a map of elf function symbols not referenced by any debug
11178 /// info and that got deleted.
11179 const string_elf_symbol_map&
11181 {return priv_->deleted_unrefed_fn_syms_;}
11182 
11183 /// Getter for function symbols not referenced by any debug info and
11184 /// that got added.
11185 ///
11186 /// @return a map of elf function symbols not referenced by any debug
11187 /// info and that got added.
11188 const string_elf_symbol_map&
11190 {return priv_->added_unrefed_fn_syms_;}
11191 
11192 /// Getter for variable symbols not referenced by any debug info and
11193 /// that got deleted.
11194 ///
11195 /// @return a map of elf variable symbols not referenced by any debug
11196 /// info and that got deleted.
11197 const string_elf_symbol_map&
11199 {return priv_->deleted_unrefed_var_syms_;}
11200 
11201 /// Getter for variable symbols not referenced by any debug info and
11202 /// that got added.
11203 ///
11204 /// @return a map of elf variable symbols not referenced by any debug
11205 /// info and that got added.
11206 const string_elf_symbol_map&
11208 {return priv_->added_unrefed_var_syms_;}
11209 
11210 /// Getter for a map of deleted types that are not reachable from
11211 /// global functions/variables.
11212 ///
11213 /// @return a map that associates pretty representation of deleted
11214 /// unreachable types and said types.
11217 {return priv_->deleted_unreachable_types_;}
11218 
11219 /// Getter of a sorted vector of deleted types that are not reachable
11220 /// from global functions/variables.
11221 ///
11222 /// @return a sorted vector of deleted types that are not reachable
11223 /// from global functions/variables. The types are lexicographically
11224 /// sorted by considering their pretty representation.
11225 const vector<type_base_sptr>&
11227 {
11228  if (priv_->deleted_unreachable_types_sorted_.empty())
11229  if (!priv_->deleted_unreachable_types_.empty())
11230  sort_string_type_base_sptr_map(priv_->deleted_unreachable_types_,
11231  priv_->deleted_unreachable_types_sorted_);
11232 
11233  return priv_->deleted_unreachable_types_sorted_;
11234 }
11235 
11236 /// Getter for a map of added types that are not reachable from global
11237 /// functions/variables.
11238 ///
11239 /// @return a map that associates pretty representation of added
11240 /// unreachable types and said types.
11243 {return priv_->added_unreachable_types_;}
11244 
11245 /// Getter of a sorted vector of added types that are not reachable
11246 /// from global functions/variables.
11247 ///
11248 /// @return a sorted vector of added types that are not reachable from
11249 /// global functions/variables. The types are lexicographically
11250 /// sorted by considering their pretty representation.
11251 const vector<type_base_sptr>&
11253 {
11254  if (priv_->added_unreachable_types_sorted_.empty())
11255  if (!priv_->added_unreachable_types_.empty())
11256  sort_string_type_base_sptr_map(priv_->added_unreachable_types_,
11257  priv_->added_unreachable_types_sorted_);
11258 
11259  return priv_->added_unreachable_types_sorted_;
11260 }
11261 
11262 /// Getter for a map of changed types that are not reachable from
11263 /// global functions/variables.
11264 ///
11265 /// @return a map that associates pretty representation of changed
11266 /// unreachable types and said types.
11267 const string_diff_sptr_map&
11269 {return priv_->changed_unreachable_types_;}
11270 
11271 /// Getter of a sorted vector of changed types that are not reachable
11272 /// from global functions/variables.
11273 ///
11274 /// @return a sorted vector of changed types that are not reachable
11275 /// from global functions/variables. The diffs are lexicographically
11276 /// sorted by considering their pretty representation.
11277 const vector<diff_sptr>&
11279 {return priv_->changed_unreachable_types_sorted();}
11280 
11281 /// Getter of the diff context of this diff
11282 ///
11283 /// @return the diff context for this diff.
11284 const diff_context_sptr
11286 {return priv_->get_context();}
11287 
11288 /// @return the pretty representation for the current instance of @ref
11289 /// corpus_diff
11290 const string&
11292 {
11293  if (priv_->pretty_representation_.empty())
11294  {
11295  std::ostringstream o;
11296  o << "corpus_diff["
11297  << first_corpus()->get_path()
11298  << ", "
11299  << second_corpus()->get_path()
11300  << "]";
11301  priv_->pretty_representation_ = o.str();
11302  }
11303  return priv_->pretty_representation_;
11304 }
11305 /// Return true iff the current @ref corpus_diff node carries a
11306 /// change.
11307 ///
11308 /// @return true iff the current diff node carries a change.
11309 bool
11311 {
11312  return (soname_changed()
11314  || !(priv_->deleted_fns_.empty()
11315  && priv_->added_fns_.empty()
11316  && priv_->changed_fns_map_.empty()
11317  && priv_->deleted_vars_.empty()
11318  && priv_->added_vars_.empty()
11319  && priv_->changed_vars_map_.empty()
11320  && priv_->added_unrefed_fn_syms_.empty()
11321  && priv_->deleted_unrefed_fn_syms_.empty()
11322  && priv_->added_unrefed_var_syms_.empty()
11323  && priv_->deleted_unrefed_var_syms_.empty()
11324  && priv_->deleted_unreachable_types_.empty()
11325  && priv_->added_unreachable_types_.empty()
11326  && priv_->changed_unreachable_types_.empty()));
11327 }
11328 
11329 /// Test if the current instance of @ref corpus_diff carries changes
11330 /// that we are sure are incompatible. By incompatible change we mean
11331 /// a change that "breaks" the ABI of the corpus we are looking at.
11332 ///
11333 /// In concrete terms, this function considers the following changes
11334 /// as being ABI incompatible for sure:
11335 ///
11336 /// - a soname change
11337 /// - if exported functions or variables got removed
11338 ///
11339 /// Note that subtype changes *can* represent changes that break ABI
11340 /// too. But they also can be changes that are OK, ABI-wise.
11341 ///
11342 /// It's up to the user to provide suppression specifications to say
11343 /// explicitely which subtype change is OK. The remaining sub-type
11344 /// changes are then considered to be ABI incompatible. But to test
11345 /// if such ABI incompatible subtype changes are present you need to
11346 /// use the function @ref corpus_diff::has_net_subtype_changes()
11347 ///
11348 /// @return true iff the current instance of @ref corpus_diff carries
11349 /// changes that we are sure are ABI incompatible.
11350 bool
11352 {
11353  const diff_stats& stats = const_cast<corpus_diff*>(this)->
11355 
11358  || stats.net_num_func_removed() != 0
11359  || (stats.num_func_with_virtual_offset_changes() != 0
11360  // If all reports about functions with sub-type changes
11361  // have been suppressed, then even those about functions
11362  // that are virtual don't matter anymore because the
11363  // user willingly requested to shut them down
11364  && stats.net_num_func_changed() != 0)
11365  || stats.net_num_vars_removed() != 0
11366  || stats.net_num_removed_func_syms() != 0
11367  || stats.net_num_removed_var_syms() != 0
11368  || stats.net_num_removed_unreachable_types() != 0);
11369 
11370  // If stats.net_num_changed_unreachable_types() != 0 then walk the
11371  // corpus_diff::priv::changed_unreachable_types_, and see if there
11372  // is one that is harmful by bitwise and-ing their category with
11373  // abigail::comparison::get_default_harmful_categories_bitmap().
11374  if (!has_incompatible_changes
11376  {
11377  // The changed unreachable types can carry harmful changes.
11378  // Let's figure if they actually do.
11379 
11380  diff_context_sptr ctxt = context();
11381  for (auto &entry : priv_->changed_unreachable_types())
11382  {
11383  diff_sptr dif = entry.second;
11384 
11385  // Let's see if any of the categories of this diff node
11386  // belong to the "harmful" ones.
11387  if (dif->get_category() & get_default_harmful_categories_bitmap())
11388  {
11389  has_incompatible_changes |= true;
11390  break;
11391  }
11392  }
11393  }
11394 
11395  return has_incompatible_changes;
11396 }
11397 
11398 /// Test if the current instance of @ref corpus_diff carries subtype
11399 /// changes whose reports are not suppressed by any suppression
11400 /// specification. In effect, these are deemed incompatible ABI
11401 /// changes.
11402 ///
11403 /// @return true iff the the current instance of @ref corpus_diff
11404 /// carries subtype changes that are deemed incompatible ABI changes.
11405 bool
11407 {
11408  const diff_stats& stats = const_cast<corpus_diff*>(this)->
11410 
11411  return (stats.net_num_func_changed() != 0
11412  || stats.net_num_vars_changed() != 0
11413  || stats.net_num_removed_unreachable_types() != 0
11414  || stats.net_num_changed_unreachable_types() != 0);
11415 }
11416 
11417 /// Test if the current instance of @ref corpus_diff carries changes
11418 /// whose reports are not suppressed by any suppression specification.
11419 /// In effect, these are deemed incompatible ABI changes.
11420 ///
11421 /// @return true iff the the current instance of @ref corpus_diff
11422 /// carries subtype changes that are deemed incompatible ABI changes.
11423 bool
11425 {return context()->get_reporter()->diff_has_net_changes(this);}
11426 
11427 /// Apply the different filters that are registered to be applied to
11428 /// the diff tree; that includes the categorization filters. Also,
11429 /// apply the suppression interpretation filters.
11430 ///
11431 /// After the filters are applied, this function calculates some
11432 /// statistics about the changes carried by the current instance of
11433 /// @ref corpus_diff. These statistics are represented by an instance
11434 /// of @ref corpus_diff::diff_stats.
11435 ///
11436 /// This member function is called by the reporting function
11437 /// corpus_diff::report().
11438 ///
11439 /// Note that for a given instance of corpus_diff, this function
11440 /// applies the filters and suppressions only the first time it is
11441 /// invoked. Subsequent invocations just return the instance of
11442 /// corpus_diff::diff_stats that was cached after the first
11443 /// invocation.
11444 ///
11445 /// @return a reference to the statistics about the changes carried by
11446 /// the current instance of @ref corpus_diff.
11449 {
11450  if (priv_->diff_stats_)
11451  return *priv_->diff_stats_;
11452 
11454  if (do_log())
11455  {
11456  std::cerr << "Applying suppressions ...\n";
11457  t.start();
11458  }
11459 
11460  apply_suppressions(this);
11461 
11462  if (do_log())
11463  {
11464  t.stop();
11465  std::cerr << "suppressions applied!:" << t << "\n";
11466  }
11467 
11468  priv_->diff_stats_.reset(new diff_stats(context()));
11469 
11470  if (do_log())
11471  {
11472  std::cerr << "Marking leaf nodes ...\n";
11473  t.start();
11474  }
11475 
11477 
11478  if (do_log())
11479  {
11480  t.stop();
11481  std::cerr << "leaf nodes marked!:" << t << "\n";
11482  std::cerr << "Applying filters and computing diff stats ...\n";
11483  t.start();
11484  }
11485 
11486  priv_->apply_filters_and_compute_diff_stats(*priv_->diff_stats_);
11487 
11488  if (do_log())
11489  {
11490  t.stop();
11491  std::cerr << "Filters applied and diff stats computed!: " << t << "\n";
11492  }
11493 
11494  return *priv_->diff_stats_;
11495 }
11496 
11497 /// A visitor that marks leaf diff nodes by storing them in the
11498 /// instance of @ref diff_maps returned by
11499 /// corpus_diff::get_leaf_diffs() invoked on the current instance of
11500 /// corpus_diff.
11501 struct leaf_diff_node_marker_visitor : public diff_node_visitor
11502 {
11503  /// This is called when the visitor visits a diff node.
11504  ///
11505  /// It basically tests if the diff node being visited is a leaf diff
11506  /// node - that is, it contains local changes. If it does, then the
11507  /// node is added to the set of maps that hold leaf diffs in the
11508  /// current corpus_diff.
11509  ///
11510  /// Note that only leaf nodes that are reachable from public
11511  /// interfaces (global functions or variables) are collected by this
11512  /// visitor.
11513  ///
11514  /// @param d the diff node being visited.
11515  virtual void
11516  visit_begin(diff *d)
11517  {
11518  if (d->has_local_changes()
11519  // A leaf basic (or class/union) type name change makes no
11520  // sense when showing just leaf changes. It only makes sense
11521  // when it can explain the details about a non-leaf change.
11522  // In other words, it doesn't make sense to say that an "int"
11523  // became "unsigned int". But it does make sense to say that
11524  // a typedef changed because its underlying type was 'int' and
11525  // is now an "unsigned int".
11527  // Similarly, a *local* change describing a type that changed
11528  // its nature doesn't make sense.
11529  && !is_distinct_diff(d)
11530  // Similarly, a pointer (or reference or array), a typedef or
11531  // qualified type change in itself doesn't make sense. It
11532  // would rather make sense to show that pointer change as part
11533  // of the variable change whose pointer type changed, for
11534  // instance.
11535  && !is_pointer_diff(d)
11536  && !is_reference_diff(d)
11537  && !is_qualified_type_diff(d)
11538  && !is_typedef_diff(d)
11539  && !is_array_diff(d)
11540  // Similarly a parameter change in itself doesn't make sense.
11541  // It should have already been reported as part of the change
11542  // of the function it belongs to.
11543  && !is_fn_parm_diff(d)
11544  // An anonymous class or union diff doesn't make sense on its
11545  // own. It must have been described already by the diff of
11546  // the enclosing struct or union if 'd' is from an anonymous
11547  // data member, or from a typedef change if 'd' is from a
11548  // typedef change which underlying type is an anonymous
11549  // struct/union.
11551  // Don't show decl-only-ness changes either.
11553  // Sometime, we can encounter artifacts of bogus DWARF that
11554  // yield a diff node for a decl-only class (and empty class
11555  // with the is_declaration flag set) that carries a non-zero
11556  // size! And of course at some point that non-zero size
11557  // changes. We need to be able to detect that.
11559  {
11560  diff_context_sptr ctxt = d->context();
11561  const corpus_diff *corpus_diff_node = ctxt->get_corpus_diff().get();
11562  ABG_ASSERT(corpus_diff_node);
11563 
11564  if (diff *iface_diff = get_current_topmost_iface_diff())
11565  {
11566  type_or_decl_base_sptr iface = iface_diff->first_subject();
11567  // So, this diff node that is reachable from a global
11568  // function or variable carries a leaf change. Let's add
11569  // it to the set of of leaf diffs of corpus_diff_node.
11570  const_cast<corpus_diff*>(corpus_diff_node)->
11571  get_leaf_diffs().insert_diff_node(d, iface);
11572  }
11573  }
11574  }
11575 }; // end struct leaf_diff_node_marker_visitor
11576 
11577 /// Walks the diff nodes associated to the current corpus diff and
11578 /// mark those that carry local changes. They are said to be leaf
11579 /// diff nodes.
11580 ///
11581 /// The marked nodes are available from the
11582 /// corpus_diff::get_leaf_diffs() function.
11583 void
11585 {
11586  if (!has_changes())
11587  return;
11588 
11589  if (!context()->show_leaf_changes_only())
11590  return;
11591 
11592  leaf_diff_node_marker_visitor v;
11593  context()->forget_visited_diffs();
11594  bool s = context()->visiting_a_node_twice_is_forbidden();
11595  context()->forbid_visiting_a_node_twice(true);
11596  if (context()->show_impacted_interfaces())
11597  context()->forbid_visiting_a_node_twice_per_interface(true);
11598  traverse(v);
11599  context()->forbid_visiting_a_node_twice(s);
11600  context()->forbid_visiting_a_node_twice_per_interface(false);
11601 }
11602 
11603 /// Get the set of maps that contain leaf nodes. A leaf node being a
11604 /// node with a local change.
11605 ///
11606 /// @return the set of maps that contain leaf nodes. A leaf node
11607 /// being a node with a local change.
11608 diff_maps&
11610 {return priv_->leaf_diffs_;}
11611 
11612 /// Get the set of maps that contain leaf nodes. A leaf node being a
11613 /// node with a local change.
11614 ///
11615 /// @return the set of maps that contain leaf nodes. A leaf node
11616 /// being a node with a local change.
11617 const diff_maps&
11619 {return priv_->leaf_diffs_;}
11620 
11621 /// Report the diff in a serialized form.
11622 ///
11623 /// @param out the stream to serialize the diff to.
11624 ///
11625 /// @param indent the prefix to use for the indentation of this
11626 /// serialization.
11627 void
11628 corpus_diff::report(ostream& out, const string& indent) const
11629 {
11630  context()->get_reporter()->report(*this, out, indent);
11631 }
11632 
11633 /// Traverse the diff sub-tree under the current instance corpus_diff.
11634 ///
11635 /// @param v the visitor to invoke on each diff node of the sub-tree.
11636 ///
11637 /// @return true if the traversing has to keep going on, false otherwise.
11638 bool
11640 {
11641  finish_diff_type();
11642 
11643  v.visit_begin(this);
11644 
11645  if (!v.visit(this, true))
11646  {
11647  v.visit_end(this);
11648  return false;
11649  }
11650 
11651  for (function_decl_diff_sptrs_type::const_iterator i =
11652  changed_functions_sorted().begin();
11653  i != changed_functions_sorted().end();
11654  ++i)
11655  {
11656  if (diff_sptr d = *i)
11657  {
11658  const diff_context_sptr &ctxt = context();
11659  if (ctxt->visiting_a_node_twice_is_forbidden_per_interface())
11660  ctxt->forget_visited_diffs();
11661 
11662  v.set_current_topmost_iface_diff(d.get());
11663 
11664  if (!d->traverse(v))
11665  {
11666  v.visit_end(this);
11668  return false;
11669  }
11670  }
11671  }
11672 
11673  for (var_diff_sptrs_type::const_iterator i =
11674  changed_variables_sorted().begin();
11675  i != changed_variables_sorted().end();
11676  ++i)
11677  {
11678  if (diff_sptr d = *i)
11679  {
11680  const diff_context_sptr &ctxt = context();
11681  if (ctxt->visiting_a_node_twice_is_forbidden_per_interface())
11682  ctxt->forget_visited_diffs();
11683 
11684  v.set_current_topmost_iface_diff(d.get());
11685 
11686  if (!d->traverse(v))
11687  {
11688  v.visit_end(this);
11690  return false;
11691  }
11692  }
11693  }
11694 
11696 
11697  // Traverse the changed unreachable type diffs. These diffs are on
11698  // types that are not reachable from global functions or variables.
11699  for (vector<diff_sptr>::const_iterator i =
11701  i != changed_unreachable_types_sorted().end();
11702  ++i)
11703  {
11704  if (diff_sptr d = *i)
11705  {
11706  const diff_context_sptr &ctxt = context();
11707  if (ctxt->visiting_a_node_twice_is_forbidden_per_interface())
11708  ctxt->forget_visited_diffs();
11709 
11710  if (!d->traverse(v))
11711  {
11712  v.visit_end(this);
11713  return false;
11714  }
11715  }
11716  }
11717 
11718  v.visit_end(this);
11719  return true;
11720 }
11721 
11722 /// Compute the diff between two instances of @ref corpus.
11723 ///
11724 /// Note that the two corpora must have been created in the same @ref
11725 /// environment, otherwise, this function aborts.
11726 ///
11727 /// @param f the first @ref corpus to consider for the diff.
11728 ///
11729 /// @param s the second @ref corpus to consider for the diff.
11730 ///
11731 /// @param ctxt the diff context to use.
11732 ///
11733 /// @return the resulting diff between the two @ref corpus.
11735 compute_diff(const corpus_sptr f,
11736  const corpus_sptr s,
11737  diff_context_sptr ctxt)
11738 {
11739  typedef corpus::functions::const_iterator fns_it_type;
11740  typedef corpus::variables::const_iterator vars_it_type;
11741  typedef elf_symbols::const_iterator symbols_it_type;
11742  typedef diff_utils::deep_ptr_eq_functor eq_type;
11743  typedef vector<type_base_wptr>::const_iterator type_base_wptr_it_type;
11744 
11745  ABG_ASSERT(f && s);
11746 
11747  if (!ctxt)
11748  ctxt.reset(new diff_context);
11749 
11750  corpus_diff_sptr r(new corpus_diff(f, s, ctxt));
11751 
11752  ctxt->set_corpus_diff(r);
11753 
11754  if(ctxt->show_soname_change())
11755  r->priv_->sonames_equal_ = f->get_soname() == s->get_soname();
11756  else
11757  r->priv_->sonames_equal_ = true;
11758 
11759  r->priv_->architectures_equal_ =
11760  f->get_architecture_name() == s->get_architecture_name();
11761 
11762  // Compute the diff of publicly defined and exported functions
11763  diff_utils::compute_diff<fns_it_type, eq_type>(f->get_functions().begin(),
11764  f->get_functions().end(),
11765  s->get_functions().begin(),
11766  s->get_functions().end(),
11767  r->priv_->fns_edit_script_);
11768 
11769  // Compute the diff of publicly defined and exported variables.
11770  diff_utils::compute_diff<vars_it_type, eq_type>
11771  (f->get_variables().begin(), f->get_variables().end(),
11772  s->get_variables().begin(), s->get_variables().end(),
11773  r->priv_->vars_edit_script_);
11774 
11775  // Compute the diff of function elf symbols not referenced by debug
11776  // info.
11777  diff_utils::compute_diff<symbols_it_type, eq_type>
11778  (f->get_unreferenced_function_symbols().begin(),
11779  f->get_unreferenced_function_symbols().end(),
11780  s->get_unreferenced_function_symbols().begin(),
11781  s->get_unreferenced_function_symbols().end(),
11782  r->priv_->unrefed_fn_syms_edit_script_);
11783 
11784  // Compute the diff of variable elf symbols not referenced by debug
11785  // info.
11786  diff_utils::compute_diff<symbols_it_type, eq_type>
11787  (f->get_unreferenced_variable_symbols().begin(),
11788  f->get_unreferenced_variable_symbols().end(),
11789  s->get_unreferenced_variable_symbols().begin(),
11790  s->get_unreferenced_variable_symbols().end(),
11791  r->priv_->unrefed_var_syms_edit_script_);
11792 
11793  if (ctxt->show_unreachable_types())
11794  // Compute the diff of types not reachable from public functions
11795  // or global variables that are exported.
11796  diff_utils::compute_diff<type_base_wptr_it_type, eq_type>
11797  (f->get_types_not_reachable_from_public_interfaces().begin(),
11798  f->get_types_not_reachable_from_public_interfaces().end(),
11799  s->get_types_not_reachable_from_public_interfaces().begin(),
11800  s->get_types_not_reachable_from_public_interfaces().end(),
11801  r->priv_->unreachable_types_edit_script_);
11802 
11803  r->priv_->ensure_lookup_tables_populated();
11804 
11805  return r;
11806 }
11807 
11808 // </corpus stuff>
11809 
11810 /// Compute the diff between two instances of @ref corpus_group.
11811 ///
11812 /// Note that the two corpus_diff must have been created in the same
11813 /// @ref environment, otherwise, this function aborts.
11814 ///
11815 /// @param f the first @ref corpus_group to consider for the diff.
11816 ///
11817 /// @param s the second @ref corpus_group to consider for the diff.
11818 ///
11819 /// @param ctxt the diff context to use.
11820 ///
11821 /// @return the resulting diff between the two @ref corpus_group.
11823 compute_diff(const corpus_group_sptr& f,
11824  const corpus_group_sptr& s,
11825  diff_context_sptr ctxt)
11826 {
11827 
11828  corpus_sptr c1 = f;
11829  corpus_sptr c2 = s;
11830 
11831  return compute_diff(c1, c2, ctxt);
11832 }
11833 
11834 // <corpus_group stuff>
11835 
11836 // </corpus_group stuff>
11837 // <diff_node_visitor stuff>
11838 
11839 /// The private data of the @diff_node_visitor type.
11840 struct diff_node_visitor::priv
11841 {
11842  diff* topmost_interface_diff;
11843  visiting_kind kind;
11844 
11845  priv()
11846  : topmost_interface_diff(),
11847  kind()
11848  {}
11849 
11850  priv(visiting_kind k)
11851  : topmost_interface_diff(),
11852  kind(k)
11853  {}
11854 }; // end struct diff_node_visitor
11855 
11856 /// Default constructor of the @ref diff_node_visitor type.
11858  : priv_(new priv)
11859 {}
11860 
11861 diff_node_visitor::~diff_node_visitor() = default;
11862 
11863 /// Constructor of the @ref diff_node_visitor type.
11864 ///
11865 /// @param k how the visiting has to be performed.
11867  : priv_(new priv(k))
11868 {}
11869 
11870 /// Getter for the visiting policy of the traversing code while
11871 /// invoking this visitor.
11872 ///
11873 /// @return the visiting policy used by the traversing code when
11874 /// invoking this visitor.
11877 {return priv_->kind;}
11878 
11879 /// Setter for the visiting policy of the traversing code while
11880 /// invoking this visitor.
11881 ///
11882 /// @param v a bit map representing the new visiting policy used by
11883 /// the traversing code when invoking this visitor.
11884 void
11886 {priv_->kind = v;}
11887 
11888 /// Setter for the visiting policy of the traversing code while
11889 /// invoking this visitor. This one makes a logical or between the
11890 /// current policy and the bitmap given in argument and assigns the
11891 /// current policy to the result.
11892 ///
11893 /// @param v a bitmap representing the visiting policy to or with
11894 /// the current policy.
11895 void
11897 {priv_->kind = priv_->kind | v;}
11898 
11899 /// Setter of the diff current topmost interface which is impacted by
11900 /// the current diff node being visited.
11901 ///
11902 /// @param d the current topmost interface diff impacted.
11903 void
11905 {priv_->topmost_interface_diff = d;}
11906 
11907 /// Getter of the diff current topmost interface which is impacted by
11908 /// the current diff node being visited.
11909 ///
11910 /// @return the current topmost interface diff impacted.
11911 diff*
11913 {return priv_->topmost_interface_diff;}
11914 
11915 /// This is called by the traversing code on a @ref diff node just
11916 /// before visiting it. That is, before visiting it and its children
11917 /// node.
11918 ///
11919 /// @param d the diff node to visit.
11920 void
11922 {}
11923 
11924 /// This is called by the traversing code on a @ref diff node just
11925 /// after visiting it. That is after visiting it and its children
11926 /// nodes.
11927 ///
11928 /// @param d the diff node that got visited.
11929 void
11931 {}
11932 
11933 /// This is called by the traversing code on a @ref corpus_diff node
11934 /// just before visiting it. That is, before visiting it and its
11935 /// children node.
11936 ///
11937 /// @param p the corpus_diff node to visit.
11938 ///
11939 void
11941 {}
11942 
11943 /// This is called by the traversing code on a @ref corpus_diff node
11944 /// just after visiting it. That is after visiting it and its children
11945 /// nodes.
11946 ///
11947 /// @param d the diff node that got visited.
11948 void
11950 {}
11951 
11952 /// Default visitor implementation
11953 ///
11954 /// @return true
11955 bool
11957 {return true;}
11958 
11959 /// Default visitor implementation.
11960 ///
11961 /// @return true
11962 bool
11964 {
11965  diff* d = dif;
11966  visit(d, pre);
11967 
11968  return true;
11969 }
11970 
11971 /// Default visitor implementation.
11972 ///
11973 /// @return true
11974 bool
11976 {
11977  diff* d = dif;
11978  visit(d, pre);
11979 
11980  return true;
11981 }
11982 
11983 /// Default visitor implementation.
11984 ///
11985 /// @return true
11986 bool
11988 {
11989  diff* d = dif;
11990  visit(d, pre);
11991 
11992  return true;
11993 }
11994 
11995 /// Default visitor implementation.
11996 ///
11997 /// @return true
11998 bool
12000 {
12001  diff* d = dif;
12002  visit(d, pre);
12003 
12004  return true;
12005 }
12006 
12007 /// Default visitor implementation.
12008 ///
12009 /// @return true
12010 bool
12012 {
12013  diff* d = dif;
12014  visit(d, pre);
12015 
12016  return true;
12017 }
12018 
12019 /// Default visitor implementation.
12020 ///
12021 /// @return true
12022 bool
12024 {
12025  diff* d = dif;
12026  visit(d, pre);
12027 
12028  return true;
12029 }
12030 
12031 /// Default visitor implementation.
12032 ///
12033 /// @return true
12034 bool
12036 {
12037  diff* d = dif;
12038  visit(d, pre);
12039 
12040  return true;
12041 }
12042 
12043 /// Default visitor implementation.
12044 ///
12045 /// @return true
12046 bool
12048 {
12049  diff* d = dif;
12050  visit(d, pre);
12051 
12052  return true;
12053 }
12054 
12055 /// Default visitor implementation.
12056 ///
12057 /// @return true
12058 bool
12060 {
12061  diff* d = dif;
12062  visit(d, pre);
12063 
12064  return true;
12065 }
12066 
12067 /// Default visitor implementation.
12068 ///
12069 /// @return true
12070 bool
12072 {
12073  diff* d = dif;
12074  visit(d, pre);
12075 
12076  return true;
12077 }
12078 
12079 /// Default visitor implementation.
12080 ///
12081 /// @return true
12082 bool
12084 {
12085  diff* d = dif;
12086  visit(d, pre);
12087 
12088  return true;
12089 }
12090 
12091 /// Default visitor implementation.
12092 ///
12093 /// @return true
12094 bool
12096 {
12097  diff* d = dif;
12098  visit(d, pre);
12099 
12100  return true;
12101 }
12102 
12103 /// Default visitor implementation.
12104 ///
12105 /// @return true
12106 bool
12108 {
12109  diff* d = dif;
12110  visit(d, pre);
12111 
12112  return true;
12113 }
12114 
12115 /// Default visitor implementation.
12116 ///
12117 /// @return true
12118 bool
12120 {return true;}
12121 
12122 // </diff_node_visitor stuff>
12123 
12124 // <redundant diff node marking>
12125 
12126 // </redundant diff node marking>
12127 
12128 // <diff tree category propagation>
12129 
12130 /// A visitor to propagate the category of a node up to its parent
12131 /// nodes. This visitor doesn't touch the REDUNDANT_CATEGORY or the
12132 /// SUPPRESSED_CATEGORY because those are propagated using other
12133 /// specific visitors.
12134 struct category_propagation_visitor : public diff_node_visitor
12135 {
12136  virtual void
12137  visit_end(diff* d)
12138  {
12139  // Has this diff node 'd' been already visited ?
12140  bool already_visited = d->context()->diff_has_been_visited(d);
12141 
12142  // The canonical diff node of the class of equivalence of the diff
12143  // node 'd'.
12144  diff* canonical = d->get_canonical_diff();
12145 
12146  // If this class of equivalence of diff node is being visited for
12147  // the first time, then update its canonical node's category too.
12148  bool update_canonical = !already_visited && canonical;
12149 
12150  for (vector<diff*>::const_iterator i = d->children_nodes().begin();
12151  i != d->children_nodes().end();
12152  ++i)
12153  {
12154  // If we are visiting the class of equivalence of 'd' for the
12155  // first time, then let's look at the children of 'd' and
12156  // propagate their categories to 'd'.
12157  //
12158  // If the class of equivalence of 'd' has already been
12159  // visited, then let's look at the canonical diff nodes of the
12160  // children of 'd' and propagate their categories to 'd'.
12161  diff* diff = already_visited
12162  ? (*i)->get_canonical_diff()
12163  : *i;
12164 
12165  ABG_ASSERT(diff);
12166 
12167  diff_category c = diff->get_category();
12168  // Do not propagate redundant and suppressed categories. Those
12169  // are propagated in a specific pass elsewhere.
12170  c &= ~(REDUNDANT_CATEGORY
12176  // Also, if a (class) type has got a harmful name change, do not
12177  // propagate harmless name changes coming from its sub-types
12178  // (i.e, data members) to the class itself.
12181 
12182  d->add_to_category(c);
12183  if (!already_visited && canonical)
12184  if (update_canonical)
12185  canonical->add_to_category(c);
12186  }
12187  }
12188 };// end struct category_propagation_visitor
12189 
12190 /// Visit all the nodes of a given sub-tree. For each node that has a
12191 /// particular category set, propagate that category set up to its
12192 /// parent nodes.
12193 ///
12194 /// @param diff_tree the diff sub-tree to walk for categorization
12195 /// purpose;
12196 void
12197 propagate_categories(diff* diff_tree)
12198 {
12199  category_propagation_visitor v;
12200  bool s = diff_tree->context()->visiting_a_node_twice_is_forbidden();
12201  diff_tree->context()->forbid_visiting_a_node_twice(true);
12202  diff_tree->context()->forget_visited_diffs();
12203  diff_tree->traverse(v);
12204  diff_tree->context()->forbid_visiting_a_node_twice(s);
12205 }
12206 
12207 /// Visit all the nodes of a given sub-tree. For each node that has a
12208 /// particular category set, propagate that category set up to its
12209 /// parent nodes.
12210 ///
12211 /// @param diff_tree the diff sub-tree to walk for categorization
12212 /// purpose;
12213 void
12215 {propagate_categories(diff_tree.get());}
12216 
12217 /// Visit all the nodes of a given corpus tree. For each node that
12218 /// has a particular category set, propagate that category set up to
12219 /// its parent nodes.
12220 ///
12221 /// @param diff_tree the corpus_diff tree to walk for categorization
12222 /// purpose;
12223 void
12225 {
12226  category_propagation_visitor v;
12227  bool s = diff_tree->context()->visiting_a_node_twice_is_forbidden();
12228  diff_tree->context()->forbid_visiting_a_node_twice(false);
12229  diff_tree->traverse(v);
12230  diff_tree->context()->forbid_visiting_a_node_twice(s);
12231 }
12232 
12233 /// Visit all the nodes of a given corpus tree. For each node that
12234 /// has a particular category set, propagate that category set up to
12235 /// its parent nodes.
12236 ///
12237 /// @param diff_tree the corpus_diff tree to walk for categorization
12238 /// purpose;
12239 void
12241 {propagate_categories(diff_tree.get());}
12242 
12243 /// A tree node visitor that knows how to categorizes a given diff
12244 /// node in the SUPPRESSED_CATEGORY category and how to propagate that
12245 /// categorization.
12246 struct suppression_categorization_visitor : public diff_node_visitor
12247 {
12248 
12249  /// Before visiting the children of the diff node, check if the node
12250  /// is suppressed by a suppression specification. If it is, mark
12251  /// the node as belonging to the SUPPRESSED_CATEGORY category.
12252  ///
12253  /// @param p the diff node to visit.
12254  virtual void
12255  visit_begin(diff* d)
12256  {
12257  bool is_private_type = false;
12258  if (d->is_suppressed(is_private_type))
12259  {
12260  diff_category c = is_private_type
12264 
12265  // If a node was suppressed, all the other nodes of its class
12266  // of equivalence are suppressed too.
12267  diff *canonical_diff = d->get_canonical_diff();
12268  if (canonical_diff != d)
12269  canonical_diff->add_to_category(c);
12270  }
12272  {
12273  // This diff node is specifically allowed by a
12274  // negated_suppression, then mark it as being in the
12275  // HAS_ALLOWED_CHANGE_CATEGORY.
12277  d->add_to_local_category(c);
12278  diff *canonical_diff = d->get_canonical_diff();
12279  canonical_diff->add_to_category(c);
12280 
12281  // Note that some complementary code later down below does
12282  // categorize the descendants and parents nodes of this node
12283  // as HAS_PARENT_WITH_ALLOWED_CHANGE_CATEGORY and
12284  // HAS_DESCENDANT_WITH_ALLOWED_CHANGE_CATEGORY, repectively.
12285  }
12286 
12287  // If a parent node has been allowed by a negated suppression
12288  // specification, then categorize the current node as
12289  // HAS_PARENT_WITH_ALLOWED_CHANGE_CATEGORY.
12290  if (d->parent_node())
12291  {
12296  else
12297  {
12298  c = d->parent_node()->get_category();
12302  }
12303  }
12304 
12305  }
12306 
12307  /// After visiting the children nodes of a given diff node,
12308  /// propagate the SUPPRESSED_CATEGORY from the children nodes to the
12309  /// diff node, if need be.
12310  ///
12311  /// That is, if all children nodes carry a suppressed change the
12312  /// current node should be marked as suppressed as well.
12313  ///
12314  /// In practice, this might be too strong of a condition. If the
12315  /// current node carries a local change (i.e, a change not carried
12316  /// by any of its children node) and if that change is not
12317  /// suppressed, then the current node should *NOT* be suppressed.
12318  ///
12319  /// But right now, the IR doesn't let us know about local vs
12320  /// children-carried changes. So we cannot be that precise yet.
12321  virtual void
12322  visit_end(diff* d)
12323  {
12324  bool has_non_suppressed_child = false;
12325  bool has_non_empty_child = false;
12326  bool has_suppressed_child = false;
12327  bool has_non_private_child = false;
12328  bool has_private_child = false;
12329  bool has_descendant_with_allowed_change = false;
12330 
12331  if (// A node to which we can propagate the "SUPPRESSED_CATEGORY"
12332  // (or the PRIVATE_TYPE_CATEGORY for the same matter)
12333  // category from its children is a node which:
12334  //
12335  // 1/ hasn't been suppressed already
12336  //
12337  // 2/ and has no local change (unless it's a pointer,
12338  // reference or qualified diff node).
12339  //
12340  // Note that qualified type and typedef diff nodes are a bit
12341  // special. The local changes of the underlying type are
12342  // considered local for the qualified/typedef type, just like
12343  // for pointer/reference types. But then the qualified or
12344  // typedef type itself can have local changes of its own, and
12345  // those changes are of the kind LOCAL_NON_TYPE_CHANGE_KIND.
12346  // So a qualified type which have local changes that are
12347  // *NOT* of LOCAL_NON_TYPE_CHANGE_KIND (or that has no local
12348  // changes at all) and which is in the PRIVATE_TYPE_CATEGORY
12349  // or SUPPRESSED_CATEGORY can see these categories be
12350  // propagated.
12351  //
12352  // Note that all pointer/reference diff node changes are
12353  // potentially considered local, i.e, local changes of the
12354  // pointed-to-type are considered local to the pointer itself.
12355  //
12356  // Similarly, changes local to the type of function parameters,
12357  // variables (and data members) and classes (that are not of
12358  // LOCAL_NON_TYPE_CHANGE_KIND kind) and that have been
12359  // suppressed can propagate their SUPPRESSED_CATEGORY-ness to
12360  // those kinds of diff node.
12361  !(d->get_category() & SUPPRESSED_CATEGORY)
12362  && (!d->has_local_changes()
12363  || is_pointer_diff(d)
12364  || is_reference_diff(d)
12365  || (is_qualified_type_diff(d)
12366  && (!(d->has_local_changes() & LOCAL_NON_TYPE_CHANGE_KIND)))
12367  || (is_typedef_diff(d)
12368  && (!(d->has_local_changes() & LOCAL_NON_TYPE_CHANGE_KIND)))
12369  || (is_function_decl_diff(d)
12370  && (!(d->has_local_changes() & LOCAL_NON_TYPE_CHANGE_KIND)))
12371  || (is_fn_parm_diff(d)
12372  && (!(d->has_local_changes() & LOCAL_NON_TYPE_CHANGE_KIND)))
12373  || (is_function_type_diff(d)
12374  && (!(d->has_local_changes() & LOCAL_NON_TYPE_CHANGE_KIND)))
12375  || (is_var_diff(d)
12376  && (!(d->has_local_changes() & LOCAL_NON_TYPE_CHANGE_KIND)))
12377  || (is_class_diff(d)
12378  && (!(d->has_local_changes() & LOCAL_NON_TYPE_CHANGE_KIND)))))
12379  {
12380  // Note that we handle private diff nodes differently from
12381  // generally suppressed diff nodes. E.g, it's not because a
12382  // type is private (and suppressed because of that; i.e, in
12383  // the category PRIVATE_TYPE_CATEGORY) that a typedef to that
12384  // type should also be private and so suppressed. Private
12385  // diff nodes thus have different propagation rules than
12386  // generally suppressed rules.
12387  for (vector<diff*>::const_iterator i = d->children_nodes().begin();
12388  i != d->children_nodes().end();
12389  ++i)
12390  {
12391  diff* child = *i;
12392  if (child->has_changes())
12393  {
12394  has_non_empty_child = true;
12395  if (child->get_class_of_equiv_category() & SUPPRESSED_CATEGORY)
12396  has_suppressed_child = true;
12397  else if (child->get_class_of_equiv_category()
12399  // Propagation of the PRIVATE_TYPE_CATEGORY is going
12400  // to be handled later below.
12401  ;
12402  else
12403  has_non_suppressed_child = true;
12404 
12405  if (child->get_class_of_equiv_category()
12407  has_private_child = true;
12408  else if (child->get_class_of_equiv_category()
12410  // Propagation of the SUPPRESSED_CATEGORY has been
12411  // handled above already.
12412  ;
12413  else
12414  has_non_private_child = true;
12415  }
12416  }
12417 
12418  if (has_non_empty_child
12419  && has_suppressed_child
12420  && !has_non_suppressed_child)
12421  {
12423  // If a node was suppressed, all the other nodes of its class
12424  // of equivalence are suppressed too.
12425  diff *canonical_diff = d->get_canonical_diff();
12426  if (canonical_diff != d)
12427  canonical_diff->add_to_category(SUPPRESSED_CATEGORY);
12428  }
12429 
12430  // Note that the private-ness of a an underlying type won't be
12431  // propagated to its parent typedef, by virtue of the big "if"
12432  // clause at the beginning of this function. So we don't have
12433  // to handle that case here. So the idiom of defining
12434  // typedefs of private (opaque) types will be respected;
12435  // meaning that changes to opaque underlying type will be
12436  // flagged as private and the typedef will be flagged private
12437  // as well, unless the typedef itself has local non-type
12438  // changes. In the later case, changes to the typedef will be
12439  // emitted because the typedef won't inherit the privateness
12440  // of its underlying type. So in practise, the typedef
12441  // remains public for the purpose of change reporting.
12442  if (has_non_empty_child
12443  && has_private_child
12444  && !has_non_private_child)
12445  {
12446  d->add_to_category(PRIVATE_TYPE_CATEGORY);
12447  // If a node was suppressed, all the other nodes of its class
12448  // of equivalence are suppressed too.
12449  diff *canonical_diff = d->get_canonical_diff();
12450  if (canonical_diff != d)
12451  canonical_diff->add_to_category(PRIVATE_TYPE_CATEGORY);
12452  }
12453 
12454  // If the underlying type of a typedef is private and carries
12455  // changes (that are implicitely suppressed because it's
12456  // private) then the typedef must be suppressed too, so that
12457  // those changes to the underlying type are not seen.
12458  if (is_typedef_diff(d)
12459  && !d->has_local_changes()
12460  && has_private_child
12461  && has_non_empty_child)
12462  {
12463  d->add_to_category(SUPPRESSED_CATEGORY|PRIVATE_TYPE_CATEGORY);
12464  // If a node was suppressed, all the other nodes of its class
12465  // of equivalence are suppressed too.
12466  diff *canonical_diff = d->get_canonical_diff();
12467  if (canonical_diff != d)
12468  canonical_diff->add_to_category
12470  }
12471 
12472  if (const function_decl_diff *fn_diff = is_function_decl_diff(d))
12473  if (!(d->has_local_changes() & LOCAL_NON_TYPE_CHANGE_KIND))
12474  {
12475  // d is a function diff that carries a local *type*
12476  // change (that means it's a change to the function
12477  // type). Let's see if the child function type diff
12478  // node is suppressed. That would mean that we are
12479  // instructed to show details of a diff that is deemed
12480  // suppressed; this means the suppression conflicts with
12481  // a local type change. In that case, let's follow what
12482  // the user asked and suppress the function altogether,
12483  if (function_type_diff_sptr fn_type_diff = fn_diff->type_diff())
12484  if (fn_type_diff->is_suppressed())
12485  {
12486  d->add_to_category(SUPPRESSED_CATEGORY);
12487  // If a node was suppressed, all the other nodes
12488  // of its class of equivalence are suppressed too.
12489  diff *canonical_diff = d->get_canonical_diff();
12490  if (canonical_diff != d)
12491  canonical_diff->add_to_category(SUPPRESSED_CATEGORY);
12492  }
12493  }
12494  }
12495 
12496  // If any descendant node was selected by a negated suppression
12497  // specification then categorize the current one as
12498  // HAS_DESCENDANT_WITH_ALLOWED_CHANGE_CATEGORY.
12499  for (auto child_node : d->children_nodes())
12500  {
12501  diff *canonical_diff = child_node->get_canonical_diff();
12502  diff_category c = canonical_diff->get_category();
12505  has_descendant_with_allowed_change = true;
12506  }
12507  if (has_descendant_with_allowed_change)
12508  {
12510  d->add_to_category(c);
12511  d->get_canonical_diff()->add_to_category(c);
12512  }
12513  }
12514 }; //end struct suppression_categorization_visitor
12515 
12516 /// Walk a given diff-sub tree and appply the suppressions carried by
12517 /// the context. If the suppression applies to a given node than
12518 /// categorize the node into the SUPPRESSED_CATEGORY category and
12519 /// propagate that categorization.
12520 ///
12521 /// @param diff_tree the diff-sub tree to apply the suppressions to.
12522 void
12523 apply_suppressions(diff* diff_tree)
12524 {
12525  if (diff_tree && !diff_tree->context()->suppressions().empty())
12526  {
12527  // Apply suppressions to functions and variables that have
12528  // changed sub-types.
12529  suppression_categorization_visitor v;
12530  diff_tree->context()->forget_visited_diffs();
12531  bool s = diff_tree->context()->visiting_a_node_twice_is_forbidden();
12532  diff_tree->context()->forbid_visiting_a_node_twice(true);
12533  diff_tree->traverse(v);
12534  diff_tree->context()->forbid_visiting_a_node_twice(s);
12535  }
12536 }
12537 
12538 /// Walk a given diff-sub tree and appply the suppressions carried by
12539 /// the context. If the suppression applies to a given node than
12540 /// categorize the node into the SUPPRESSED_CATEGORY category and
12541 /// propagate that categorization.
12542 ///
12543 /// @param diff_tree the diff-sub tree to apply the suppressions to.
12544 void
12546 {apply_suppressions(diff_tree.get());}
12547 
12548 /// Walk a @ref corpus_diff tree and appply the suppressions carried
12549 /// by the context. If the suppression applies to a given node then
12550 /// categorize the node into the SUPPRESSED_CATEGORY category and
12551 /// propagate that categorization.
12552 ///
12553 /// @param diff_tree the diff tree to apply the suppressions to.
12554 void
12556 {
12557  if (diff_tree && !diff_tree->context()->suppressions().empty())
12558  {
12559  // First, visit the children trees of changed constructs:
12560  // changed functions, variables, as well as sub-types of these,
12561  // and apply suppression specifications to these ...
12562  suppression_categorization_visitor v;
12563  diff_tree->context()->forget_visited_diffs();
12564  bool s = diff_tree->context()->visiting_a_node_twice_is_forbidden();
12565  diff_tree->context()->forbid_visiting_a_node_twice(true);
12566  const_cast<corpus_diff*>(diff_tree)->traverse(v);
12567  diff_tree->context()->forbid_visiting_a_node_twice(s);
12568 
12569  // ... then also visit the set of added and removed functions,
12570  // variables, symbols, and types not reachable from global
12571  // functions and variables.
12572  diff_tree->priv_->
12573  apply_supprs_to_added_removed_fns_vars_unreachable_types();
12574  }
12575 }
12576 
12577 /// Walk a diff tree and appply the suppressions carried by the
12578 /// context. If the suppression applies to a given node than
12579 /// categorize the node into the SUPPRESSED_CATEGORY category and
12580 /// propagate that categorization.
12581 ///
12582 /// @param diff_tree the diff tree to apply the suppressions to.
12583 void
12585 {apply_suppressions(diff_tree.get());}
12586 
12587 // </diff tree category propagation>
12588 
12589 // <diff tree printing stuff>
12590 
12591 /// A visitor to print (to an output stream) a pretty representation
12592 /// of a @ref diff sub-tree or of a complete @ref corpus_diff tree.
12593 struct diff_node_printer : public diff_node_visitor
12594 {
12595  ostream& out_;
12596  unsigned level_;
12597 
12598  /// Emit a certain number of spaces to the output stream associated
12599  /// to this diff_node_printer.
12600  ///
12601  /// @param level half of the numver of spaces to emit.
12602  void
12603  do_indent(unsigned level)
12604  {
12605  for (unsigned i = 0; i < level; ++i)
12606  out_ << " ";
12607  }
12608 
12609  diff_node_printer(ostream& out)
12610  : diff_node_visitor(DO_NOT_MARK_VISITED_NODES_AS_VISITED),
12611  out_(out),
12612  level_(0)
12613  {}
12614 
12615  virtual void
12616  visit_begin(diff*)
12617  {
12618  ++level_;
12619  }
12620 
12621  virtual void
12622  visit_end(diff*)
12623  {
12624  --level_;
12625  }
12626 
12627  virtual void
12628  visit_begin(corpus_diff*)
12629  {
12630  ++level_;
12631  }
12632 
12633  virtual void
12634  visit_end(corpus_diff*)
12635  {
12636  --level_;
12637  }
12638 
12639  virtual bool
12640  visit(diff* d, bool pre)
12641  {
12642  if (!pre)
12643  // We are post-visiting the diff node D. Which means, we have
12644  // printed a pretty representation for it already. So do
12645  // nothing now.
12646  return true;
12647 
12648  do_indent(level_);
12649  out_ << d->get_pretty_representation();
12650  out_ << "\n";
12651  do_indent(level_);
12652  out_ << "{\n";
12653  do_indent(level_ + 1);
12654  out_ << "category: "<< d->get_category() << "\n";
12655  do_indent(level_ + 1);
12656  out_ << "@: " << std::hex << d << std::dec << "\n";
12657  do_indent(level_ + 1);
12658  out_ << "@-canonical: " << std::hex
12659  << d->get_canonical_diff()
12660  << std::dec << "\n";
12661  do_indent(level_);
12662  out_ << "}\n";
12663 
12664  return true;
12665  }
12666 
12667  virtual bool
12668  visit(corpus_diff* d, bool pre)
12669  {
12670  if (!pre)
12671  // We are post-visiting the diff node D. Which means, we have
12672  // printed a pretty representation for it already. So do
12673  // nothing now.
12674  return true;
12675 
12676  // indent
12677  for (unsigned i = 0; i < level_; ++i)
12678  out_ << ' ';
12679  out_ << d->get_pretty_representation();
12680  out_ << '\n';
12681  return true;
12682  }
12683 }; // end struct diff_printer_visitor
12684 
12685 // </ diff tree printing stuff>
12686 
12687 /// Emit a textual representation of a @ref diff sub-tree to an
12688 /// output stream.
12689 ///
12690 /// @param diff_tree the sub-tree to emit the textual representation
12691 /// for.
12692 ///
12693 /// @param out the output stream to emit the textual representation
12694 /// for @p diff_tree to.
12695 void
12696 print_diff_tree(diff* diff_tree, ostream& out)
12697 {
12698  diff_node_printer p(out);
12699  bool s = diff_tree->context()->visiting_a_node_twice_is_forbidden();
12700  diff_tree->context()->forbid_visiting_a_node_twice(false);
12701  diff_tree->traverse(p);
12702  diff_tree->context()->forbid_visiting_a_node_twice(s);
12703 }
12704 
12705 /// Emit a textual representation of a @ref corpus_diff tree to an
12706 /// output stream.
12707 ///
12708 /// @param diff_tree the @ref corpus_diff tree to emit the textual
12709 /// representation for.
12710 ///
12711 /// @param out the output stream to emit the textual representation
12712 /// for @p diff_tree to.
12713 void
12714 print_diff_tree(corpus_diff* diff_tree, std::ostream& out)
12715 {
12716  diff_node_printer p(out);
12717  bool s = diff_tree->context()->visiting_a_node_twice_is_forbidden();
12718  diff_tree->context()->forbid_visiting_a_node_twice(false);
12719  diff_tree->traverse(p);
12720  diff_tree->context()->forbid_visiting_a_node_twice(s);
12721 }
12722 
12723 /// Emit a textual representation of a @ref diff sub-tree to an
12724 /// output stream.
12725 ///
12726 /// @param diff_tree the sub-tree to emit the textual representation
12727 /// for.
12728 ///
12729 /// @param out the output stream to emit the textual representation
12730 /// for @p diff_tree to.
12731 void
12733  std::ostream& o)
12734 {print_diff_tree(diff_tree.get(), o);}
12735 
12736 /// Emit a textual representation of a @ref corpus_diff tree to an
12737 /// output stream.
12738 ///
12739 /// @param diff_tree the @ref corpus_diff tree to emit the textual
12740 /// representation for.
12741 ///
12742 /// @param out the output stream to emit the textual representation
12743 /// for @p diff_tree to.
12744 void
12746  std::ostream& o)
12747 {print_diff_tree(diff_tree.get(), o);}
12748 
12749 // <redundancy_marking_visitor>
12750 
12751 /// A tree visitor to categorize nodes with respect to the
12752 /// REDUNDANT_CATEGORY. That is, detect if a node is redundant (is
12753 /// present on several spots of the tree) and mark such nodes
12754 /// appropriatly. This visitor also takes care of propagating the
12755 /// REDUNDANT_CATEGORY of a given node to its parent nodes as
12756 /// appropriate.
12757 struct redundancy_marking_visitor : public diff_node_visitor
12758 {
12759  bool skip_children_nodes_;
12760 
12761  redundancy_marking_visitor()
12762  : skip_children_nodes_()
12763  {}
12764 
12765  virtual void
12766  visit_begin(diff* d)
12767  {
12768  if (d->to_be_reported())
12769  {
12770  // A diff node that carries a change and that has been already
12771  // traversed elsewhere is considered redundant. So let's mark
12772  // it as such and let's not traverse it; that is, let's not
12773  // visit its children.
12774  if ((d->context()->diff_has_been_visited(d)
12775  || d->get_canonical_diff()->is_traversing())
12776  && d->has_changes())
12777  {
12778  // But if two diff nodes are redundant sibbling that carry
12779  // changes of base types, do not mark them as being
12780  // redundant. This is to avoid marking nodes as redundant
12781  // in this case:
12782  //
12783  // int foo(int a, int b);
12784  // compared with:
12785  // float foo(float a, float b); (in C).
12786  //
12787  // In this case, we want to report all the occurences of
12788  // the int->float change because logically, they are at
12789  // the same level in the diff tree.
12790 
12791  bool redundant_with_sibling_node = false;
12792  const diff* p = d->parent_node();
12793 
12794  // If this is a child node of a fn_parm_diff, look through
12795  // the fn_parm_diff node to get the function diff node.
12796  if (p && dynamic_cast<const fn_parm_diff*>(p))
12797  p = p->parent_node();
12798 
12799  if (p)
12800  for (vector<diff*>::const_iterator s =
12801  p->children_nodes().begin();
12802  s != p->children_nodes().end();
12803  ++s)
12804  {
12805  if (*s == d)
12806  continue;
12807  diff* sib = *s;
12808  // If this is a fn_parm_diff, look through the
12809  // fn_parm_diff node to get at the real type node.
12810  if (fn_parm_diff* f = dynamic_cast<fn_parm_diff*>(*s))
12811  sib = f->type_diff().get();
12812  if (sib == d)
12813  continue;
12814  if (sib->get_canonical_diff() == d->get_canonical_diff()
12815  // Sibbling diff nodes that carry base type
12816  // changes ar to be marked as redundant.
12817  && (is_base_diff(sib) || is_distinct_diff(sib)))
12818  {
12819  redundant_with_sibling_node = true;
12820  break;
12821  }
12822  }
12823  if (!redundant_with_sibling_node
12824  // Changes to basic types should never be considered
12825  // redundant. For instance, if a member of integer
12826  // type is changed into a char type in both a struct A
12827  // and a struct B, we want to see both changes.
12829  // The same goes for distinct type changes
12831  // Functions with similar *local* changes are never marked
12832  // redundant because otherwise one could miss important
12833  // similar local changes that are applied to different
12834  // functions.
12836  // Changes involving variadic parameters of functions
12837  // should never be marked redundant because we want to see
12838  // them all.
12841  // If the canonical diff itself has been filtered out,
12842  // then this one is not marked redundant, unless the
12843  // canonical diff was already redundant.
12844  && (!d->get_canonical_diff()->is_filtered_out()
12845  || (d->get_canonical_diff()->get_category()
12846  & REDUNDANT_CATEGORY))
12847  // If the *same* diff node (not one that is merely
12848  // equivalent to this one) has already been visited
12849  // the do not mark it as beind redundant. It's only
12850  // the other nodes that are equivalent to this one
12851  // that must be marked redundant.
12852  && d->context()->diff_has_been_visited(d) != d
12853  // If the diff node is a function parameter and is not
12854  // a reference/pointer (to a non basic or a non
12855  // distinct type diff) then do not mark it as
12856  // redundant.
12857  //
12858  // Children nodes of base class diff nodes are never
12859  // redundant either, we want to see them all.
12862  && !is_child_node_of_base_diff(d))))
12863  {
12865  // As we said in preamble, as this node is marked as
12866  // being redundant, let's not visit its children.
12867  // This is not an optimization; it's needed for
12868  // correctness. In the case of a diff node involving
12869  // a class type that refers to himself, visiting the
12870  // children nodes might cause them to be wrongly
12871  // marked as redundant.
12874  skip_children_nodes_ = true;
12875  }
12876  }
12877  }
12878  else
12879  {
12880  // If the node is not to be reported, do not look at it children.
12882  skip_children_nodes_ = true;
12883  }
12884  }
12885 
12886  virtual void
12887  visit_begin(corpus_diff*)
12888  {
12889  }
12890 
12891  virtual void
12892  visit_end(diff* d)
12893  {
12894  if (skip_children_nodes_)
12895  // When visiting this node, we decided to skip its children
12896  // node. Now that we are done visiting the node, lets stop
12897  // avoiding the children nodes visiting for the other tree
12898  // nodes.
12899  {
12901  skip_children_nodes_ = false;
12902  }
12903  else
12904  {
12905  // Propagate the redundancy categorization of the children nodes
12906  // to this node. But if this node has local changes, then it
12907  // doesn't inherit redundancy from its children nodes.
12908  if (!(d->get_category() & REDUNDANT_CATEGORY)
12909  && (!d->has_local_changes_to_be_reported()
12910  // By default, pointer, reference and qualified types
12911  // consider that a local changes to their underlying
12912  // type is always a local change for themselves.
12913  //
12914  // This is as if those types don't have local changes
12915  // in the same sense as other types. So we always
12916  // propagate redundancy to them, regardless of if they
12917  // have local changes or not.
12918  //
12919  // We also propagate redundancy to typedef types if
12920  // these /only/ carry changes to their underlying
12921  // type.
12922  //
12923  // Note that changes to the underlying type of a
12924  // typedef is considered local of
12925  // LOCAL_TYPE_CHANGE_KIND kind. The other changes to the
12926  // typedef itself are considered local of
12927  // LOCAL_NON_TYPE_CHANGE_KIND kind.
12928  || is_pointer_diff(d)
12930  // A typedef with local non-type changes should not
12931  // see redundancy propagation from its underlying
12932  // type, otherwise, the non-type change might be
12933  // "suppressed" away.
12934  || (is_typedef_diff(d)
12935  && (!(d->has_local_changes()
12937  // A (member) variable with non-type local changes
12938  // should not see redundacy propagation from its type.
12939  // If redundant local-type changes are carried by its
12940  // type however, then that redundancy is propagated to
12941  // the variable. This is key to keep the redundancy
12942  // consistency in the system; otherwise, a type change
12943  // would be rightfully considered redundant at some
12944  // places but not at others.
12945  || (is_var_diff(d)
12946  && (!(d->has_local_changes()
12948  // A function parameter with non-type local changes
12949  // should not see redundancy propagation either. But
12950  // a function parameter with local type changes can
12951  // definitely be redundant.
12952  || (is_fn_parm_diff(d)
12953  && (!(d->has_local_changes()
12955  ))
12956  {
12957  bool has_non_redundant_child = false;
12958  bool has_non_empty_child = false;
12959  for (vector<diff*>::const_iterator i =
12960  d->children_nodes().begin();
12961  i != d->children_nodes().end();
12962  ++i)
12963  {
12964  if ((*i)->has_changes())
12965  {
12966  has_non_empty_child = true;
12967  // Let's see if the current child node '*i' is
12968  // "non-redundant".
12969  //
12970  // A non-redundant node would be a node that
12971  // carries a change to be reported and has not
12972  // been marked as being redundant.
12973  if ((*i)->to_be_reported()
12974  && ((*i)->get_category() & REDUNDANT_CATEGORY) == 0)
12975  has_non_redundant_child = true;
12976  }
12977  if (has_non_redundant_child)
12978  break;
12979  }
12980 
12981  // A diff node for which at least a child node carries a
12982  // change, and for which all the children are redundant is
12983  // deemed redundant too, unless it has local changes.
12984  if (has_non_empty_child
12985  && !has_non_redundant_child)
12986  d->add_to_category(REDUNDANT_CATEGORY);
12987  }
12988  }
12989  }
12990 
12991  virtual void
12992  visit_end(corpus_diff*)
12993  {
12994  }
12995 
12996  virtual bool
12997  visit(diff*, bool)
12998  {return true;}
12999 
13000  virtual bool
13001  visit(corpus_diff*, bool)
13002  {
13003  return true;
13004  }
13005 };// end struct redundancy_marking_visitor
13006 
13007 /// A visitor of @ref diff nodes that clears the REDUNDANT_CATEGORY
13008 /// category out of the nodes.
13009 struct redundancy_clearing_visitor : public diff_node_visitor
13010 {
13011  bool
13012  visit(corpus_diff*, bool)
13013  {return true;}
13014 
13015  bool
13016  visit(diff* d, bool)
13017  {
13018  // clear the REDUNDANT_CATEGORY out of the current node.
13019  diff_category c = d->get_category();
13020  c &= ~REDUNDANT_CATEGORY;
13021  d->set_category(c);
13022  return true;
13023  }
13024 }; // end struct redundancy_clearing_visitor
13025 
13026 /// Walk a given @ref diff sub-tree to categorize each of the nodes
13027 /// with respect to the REDUNDANT_CATEGORY.
13028 ///
13029 /// @param diff_tree the @ref diff sub-tree to walk.
13030 void
13031 categorize_redundancy(diff* diff_tree)
13032 {
13033  if (diff_tree->context()->show_redundant_changes())
13034  return;
13035  redundancy_marking_visitor v;
13036  bool s = diff_tree->context()->visiting_a_node_twice_is_forbidden();
13037  diff_tree->context()->forbid_visiting_a_node_twice(false);
13038  diff_tree->traverse(v);
13039  diff_tree->context()->forbid_visiting_a_node_twice(s);
13040 }
13041 
13042 /// Walk a given @ref diff sub-tree to categorize each of the nodes
13043 /// with respect to the REDUNDANT_CATEGORY.
13044 ///
13045 /// @param diff_tree the @ref diff sub-tree to walk.
13046 void
13048 {categorize_redundancy(diff_tree.get());}
13049 
13050 /// Walk a given @ref corpus_diff tree to categorize each of the nodes
13051 /// with respect to the REDUNDANT_CATEGORY.
13052 ///
13053 /// @param diff_tree the @ref corpus_diff tree to walk.
13054 void
13056 {
13057  redundancy_marking_visitor v;
13058  diff_tree->context()->forget_visited_diffs();
13059  bool s = diff_tree->context()->visiting_a_node_twice_is_forbidden();
13060  diff_tree->context()->forbid_visiting_a_node_twice(false);
13061  diff_tree->traverse(v);
13062  diff_tree->context()->forbid_visiting_a_node_twice(s);
13063 }
13064 
13065 /// Walk a given @ref corpus_diff tree to categorize each of the nodes
13066 /// with respect to the REDUNDANT_CATEGORY.
13067 ///
13068 /// @param diff_tree the @ref corpus_diff tree to walk.
13069 void
13071 {categorize_redundancy(diff_tree.get());}
13072 
13073 // </redundancy_marking_visitor>
13074 
13075 /// Walk a given @ref diff sub-tree to clear the REDUNDANT_CATEGORY
13076 /// out of the category of the nodes.
13077 ///
13078 /// @param diff_tree the @ref diff sub-tree to walk.
13079 void
13081 {
13082  redundancy_clearing_visitor v;
13083  bool s = diff_tree->context()->visiting_a_node_twice_is_forbidden();
13084  diff_tree->context()->forbid_visiting_a_node_twice(false);
13085  diff_tree->traverse(v);
13086  diff_tree->context()->forbid_visiting_a_node_twice(s);
13087  diff_tree->context()->forget_visited_diffs();
13088 }
13089 
13090 /// Walk a given @ref diff sub-tree to clear the REDUNDANT_CATEGORY
13091 /// out of the category of the nodes.
13092 ///
13093 /// @param diff_tree the @ref diff sub-tree to walk.
13094 void
13096 {clear_redundancy_categorization(diff_tree.get());}
13097 
13098 /// Walk a given @ref corpus_diff tree to clear the REDUNDANT_CATEGORY
13099 /// out of the category of the nodes.
13100 ///
13101 /// @param diff_tree the @ref corpus_diff tree to walk.
13102 void
13104 {
13105  redundancy_clearing_visitor v;
13106  bool s = diff_tree->context()->visiting_a_node_twice_is_forbidden();
13107  diff_tree->context()->forbid_visiting_a_node_twice(false);
13108  diff_tree->traverse(v);
13109  diff_tree->context()->forbid_visiting_a_node_twice(s);
13110  diff_tree->context()->forget_visited_diffs();
13111 }
13112 
13113 /// Walk a given @ref corpus_diff tree to clear the REDUNDANT_CATEGORY
13114 /// out of the category of the nodes.
13115 ///
13116 /// @param diff_tree the @ref corpus_diff tree to walk.
13117 void
13119 {clear_redundancy_categorization(diff_tree.get());}
13120 
13121 /// Apply the @ref diff tree filters that have been associated to the
13122 /// context of the a given @ref corpus_diff tree. As a result, the
13123 /// nodes of the @diff tree are going to be categorized into one of
13124 /// several of the categories of @ref diff_category.
13125 ///
13126 /// @param diff_tree the @ref corpus_diff instance which @ref diff are
13127 /// to be categorized.
13128 void
13130 {
13131  diff_tree->context()->maybe_apply_filters(diff_tree);
13132  propagate_categories(diff_tree);
13133 }
13134 
13135 /// Test if a diff node represents the difference between a variadic
13136 /// parameter type and something else.
13137 ///
13138 /// @param d the diff node to consider.
13139 ///
13140 /// @return true iff @p d is a diff node that represents the
13141 /// difference between a variadic parameter type and something else.
13142 bool
13144 {
13145  if (!d)
13146  return false;
13147 
13148  type_base_sptr t = is_type(d->first_subject());
13149  if (t && t->get_environment().is_variadic_parameter_type(t))
13150  return true;
13151 
13152  t = is_type(d->second_subject());
13153  if (t && t->get_environment().is_variadic_parameter_type(t))
13154  return true;
13155 
13156  return false;
13157 }
13158 
13159 /// Test if a diff node represents the difference between a variadic
13160 /// parameter type and something else.
13161 ///
13162 /// @param d the diff node to consider.
13163 ///
13164 /// @return true iff @p d is a diff node that represents the
13165 /// difference between a variadic parameter type and something else.
13166 bool
13168 {return is_diff_of_variadic_parameter_type(d.get());}
13169 
13170 /// Test if a diff node represents the difference between a variadic
13171 /// parameter and something else.
13172 ///
13173 /// @param d the diff node to consider.
13174 ///
13175 /// @return true iff @p d is a diff node that represents the
13176 /// difference between a variadic parameter and something else.
13177 bool
13179 {
13180  fn_parm_diff* diff =
13181  dynamic_cast<fn_parm_diff*>(const_cast<abigail::comparison::diff*>(d));
13182  return (diff && is_diff_of_variadic_parameter_type(diff->type_diff()));
13183 }
13184 
13185 /// Test if a diff node represents the difference between a variadic
13186 /// parameter and something else.
13187 ///
13188 /// @param d the diff node to consider.
13189 ///
13190 /// @return true iff @p d is a diff node that represents the
13191 /// difference between a variadic parameter and something else.
13192 bool
13194 {return is_diff_of_variadic_parameter(d.get());}
13195 
13196 /// Test if a diff node represents a diff between two basic types.
13197 ///
13198 /// @param d the diff node to consider.
13199 ///
13200 /// @return true iff @p d is a diff between two basic types.
13201 const type_decl_diff*
13203 {return dynamic_cast<const type_decl_diff*>(d);}
13204 
13205 /// Test if a diff node represents a diff between two basic types, or
13206 /// between pointers, references or qualified type to basic types.
13207 ///
13208 /// @param diff the diff node to consider.
13209 ///
13210 /// @param allow_indirect_type if true, then this function looks into
13211 /// pointer, reference or qualified diff types to see if they "point
13212 /// to" basic types.
13213 ///
13214 /// @return true iff @p d is a diff between two basic types.
13215 const type_decl_diff*
13216 is_diff_of_basic_type(const diff* diff, bool allow_indirect_type)
13217 {
13218  if (allow_indirect_type)
13220  return is_diff_of_basic_type(diff);
13221 }
13222 
13223 /// If a diff node is about changes between two typedef types, get the
13224 /// diff node about changes between the underlying types.
13225 ///
13226 /// Note that this function walks the tree of underlying diff nodes
13227 /// returns the first diff node about types that are not typedefs.
13228 ///
13229 /// @param dif the dif node to consider.
13230 ///
13231 /// @return the underlying diff node of @p dif, or just return @p dif
13232 /// if it's not a typedef diff node.
13233 const diff*
13234 peel_typedef_diff(const diff* dif)
13235 {
13236  const typedef_diff *d = 0;
13237  while ((d = is_typedef_diff(dif)))
13238  dif = d->underlying_type_diff().get();
13239  return dif;
13240 }
13241 
13242 /// If a diff node is about changes between two pointer types, get the
13243 /// diff node about changes between the underlying (pointed-to) types.
13244 ///
13245 /// Note that this function walks the tree of underlying diff nodes
13246 /// returns the first diff node about types that are not pointers.
13247 ///
13248 /// @param dif the dif node to consider.
13249 ///
13250 /// @return the underlying diff node of @p dif, or just return @p dif
13251 /// if it's not a pointer diff node.
13252 const diff*
13253 peel_pointer_diff(const diff* dif)
13254 {
13255  const pointer_diff *d = 0;
13256  while ((d = is_pointer_diff(dif)))
13257  dif = d->underlying_type_diff().get();
13258  return dif;
13259 }
13260 
13261 /// If a diff node is about changes between two reference types, get
13262 /// the diff node about changes between the underlying (pointed-to)
13263 /// types.
13264 ///
13265 /// Note that this function walks the tree of underlying diff nodes
13266 /// returns the first diff node about types that are not references.
13267 ///
13268 /// @param dif the dif node to consider.
13269 ///
13270 /// @return the underlying diff node of @p dif, or just return @p dif
13271 /// if it's not a reference diff node.
13272 const diff*
13273 peel_reference_diff(const diff* dif)
13274 {
13275  const reference_diff *d = 0;
13276  while ((d = is_reference_diff(dif)))
13277  dif = d->underlying_type_diff().get();
13278  return dif;
13279 }
13280 
13281 /// If a diff node is about changes between two qualified types, get
13282 /// the diff node about changes between the underlying (non-qualified)
13283 /// types.
13284 ///
13285 /// Note that this function walks the tree of underlying diff nodes
13286 /// returns the first diff node about types that are not qualified.
13287 ///
13288 /// @param dif the dif node to consider.
13289 ///
13290 /// @return the underlying diff node of @p dif, or just return @p dif
13291 /// if it's not a qualified diff node.
13292 const diff*
13293 peel_qualified_diff(const diff* dif)
13294 {
13295  const qualified_type_diff *d = 0;
13296  while ((d = is_qualified_type_diff(dif)))
13297  dif = d->underlying_type_diff().get();
13298  return dif;
13299 }
13300 
13301 /// If a diff node is about changes between two function parameters
13302 /// get the diff node about changes between the types of the parameters.
13303 ///
13304 /// @param dif the dif node to consider.
13305 ///
13306 /// @return the diff of the types of the parameters.
13307 const diff*
13308 peel_fn_parm_diff(const diff* dif)
13309 {
13310  const fn_parm_diff *d = 0;
13311  while ((d = is_fn_parm_diff(dif)))
13312  dif = d->type_diff().get();
13313  return dif;
13314 }
13315 
13316 /// If a diff node is about changes between two pointer, reference or
13317 /// qualified types, get the diff node about changes between the
13318 /// underlying types.
13319 ///
13320 /// Note that this function walks the tree of underlying diff nodes
13321 /// returns the first diff node about types that are not pointer,
13322 /// reference or qualified.
13323 ///
13324 /// @param dif the dif node to consider.
13325 ///
13326 /// @return the underlying diff node of @p dif, or just return @p dif
13327 /// if it's not a pointer, reference or qualified diff node.
13328 const diff*
13330 {
13331  while (true)
13332  {
13333  if (const pointer_diff *d = is_pointer_diff(dif))
13334  dif = peel_pointer_diff(d);
13335  else if (const reference_diff *d = is_reference_diff(dif))
13336  dif = peel_reference_diff(d);
13337  else if (const qualified_type_diff *d = is_qualified_type_diff(dif))
13338  dif = peel_qualified_diff(d);
13339  else
13340  break;
13341  }
13342  return dif;
13343 }
13344 
13345 /// If a diff node is about changes between two typedefs or qualified
13346 /// types, get the diff node about changes between the underlying
13347 /// types.
13348 ///
13349 /// Note that this function walks the tree of underlying diff nodes
13350 /// returns the first diff node about types that are not typedef or
13351 /// qualified types.
13352 ///
13353 /// @param dif the dif node to consider.
13354 ///
13355 /// @return the underlying diff node of @p dif, or just return @p dif
13356 /// if it's not typedef or qualified diff node.
13357 const diff*
13359 {
13360  while (true)
13361  {
13362  if (const typedef_diff *d = is_typedef_diff(dif))
13363  dif = peel_typedef_diff(d);
13364  else if (const qualified_type_diff *d = is_qualified_type_diff(dif))
13365  dif = peel_qualified_diff(d);
13366  else
13367  break;
13368  }
13369  return dif;
13370 }
13371 
13372 /// If a diff node is about changes between two typedefs or qualified
13373 /// types, get the diff node about changes between the underlying
13374 /// types.
13375 ///
13376 /// Note that this function walks the tree of underlying diff nodes
13377 /// returns the first diff node about types that are neither typedef,
13378 /// qualified type nor parameters.
13379 ///
13380 /// @param dif the dif node to consider.
13381 ///
13382 /// @return the diff node about changes between the underlying types.
13383 const diff*
13385 {
13386  while (true)
13387  {
13388  if (const typedef_diff *d = is_typedef_diff(dif))
13389  dif = peel_typedef_diff(d);
13390  else if (const qualified_type_diff *d = is_qualified_type_diff(dif))
13391  dif = peel_qualified_diff(d);
13392  else if (const fn_parm_diff *d = is_fn_parm_diff(dif))
13393  dif = peel_fn_parm_diff(d);
13394  else
13395  break;
13396  }
13397  return dif;
13398 }
13399 
13400 /// Test if a diff node represents a diff between two class or union
13401 /// types.
13402 ///
13403 /// @param d the diff node to consider.
13404 ///
13405 /// @return iff @p is a diff between two class or union types then
13406 /// return the instance of @ref class_or_union_diff that @p derives
13407 /// from. Otherwise, return nil.
13408 const class_or_union_diff*
13410 {return dynamic_cast<const class_or_union_diff*>(d);}
13411 
13412 /// Test if a given diff node carries *only* a local type change.
13413 ///
13414 /// @param d the diff node to consider.
13415 ///
13416 /// @return true iff @p has a change and that change is a local type
13417 /// change.
13418 static bool
13419 has_local_type_change_only(const diff *d)
13420 {
13421  if (enum change_kind k = d->has_local_changes())
13422  if ((k & LOCAL_NON_TYPE_CHANGE_KIND) == 0
13423  && (k & LOCAL_TYPE_CHANGE_KIND) != 0)
13424  return true;
13425 
13426  return false;
13427 }
13428 
13429 /// Test if a diff node is a decl diff that only carries a basic type
13430 /// change on its type diff sub-node.
13431 ///
13432 ///Note that that pointers/references/qualified types diffs to basic
13433 /// type diffs are considered as having basic type change only.
13434 ///
13435 /// @param d the diff node to consider.
13436 ///
13437 /// @return true iff @p d is a decl diff that only carries a basic
13438 /// type change on its type diff sub-node.
13439 bool
13441 {
13443 
13444  if (is_diff_of_basic_type(d, true) && d->has_changes())
13445  return true;
13446  else if (const var_diff * v = dynamic_cast<const var_diff*>(d))
13447  return (has_local_type_change_only(v)
13448  && is_diff_of_basic_type(v->type_diff().get(), true));
13449  else if (const fn_parm_diff * p = dynamic_cast<const fn_parm_diff*>(d))
13450  return (has_local_type_change_only(p)
13451  && is_diff_of_basic_type(p->type_diff().get(), true));
13452  else if (const function_decl_diff* f =
13453  dynamic_cast<const function_decl_diff*>(d))
13454  return (has_local_type_change_only(f)
13455  && f->type_diff()
13456  && is_diff_of_basic_type(f->type_diff()->return_type_diff().get(),
13457  true));
13458  return false;
13459 }
13460 }// end namespace comparison
13461 } // end namespace abigail
Testing (anding) against this mask means that a given IR artifact has local differences, with respect to the other artifact it was compared against. A local change is a change that is carried by the artifact itself (or its type), rather than by one off its sub-types.
Definition: abg-ir.h:1324
qualified_type_diff(qualified_type_def_sptr first, qualified_type_def_sptr second, diff_sptr underling, diff_context_sptr ctxt=diff_context_sptr())
Constructor for qualified_type_diff.
void set_allowed_category(diff_category c)
Setter for the bitmap that represents the set of categories that the user wants to see reported...
bool is_filtered_out_without_looking_at_allowed_changes() const
Test if this diff tree node is to be filtered out for reporting purposes, but without considering the...
bool is_child_node_of_function_parm_diff(const diff *diff)
Test if a diff node is a child node of a function parameter diff node.
A type used to time various part of the libabigail system.
vector< diff * > diff_ptrs_type
Convenience typedef for a vector of diff*.
const string_diff_ptr_map & get_class_diff_map() const
Getter of the map that contains class type diffs.
std::pair< var_decl_sptr, var_decl_sptr > changed_var_sptr
Convenience typedef for a pair of var_decl_sptr representing a var_decl change. The first member of t...
const string_var_ptr_map & added_variables() const
Getter for the added variables of the diff.
void set_reporter(reporter_base_sptr &)
Setter of the reporter to be used in this context.
size_t net_num_added_unreachable_types() const
Getter of the number of added types that are unreachable from public interfaces and that are *NOT* fi...
A comparison function for instances of base_diff.
const diff * peel_typedef_qualified_type_or_parameter_diff(const diff *dif)
If a diff node is about changes between two typedefs or qualified types, get the diff node about chan...
const string_decl_base_sptr_map & inserted_data_members() const
Getter for the data members that got inserted.
bool is_type(const type_or_decl_base &tod)
Test whether a declaration is a type.
Definition: abg-ir.cc:10469
bool show_offsets_sizes_in_bits() const
Get the flag that indicates if diff reports using this context should show sizes and offsets in bits...
The abstraction of an array type.
Definition: abg-ir.h:2454
bool get_member_function_is_virtual(const function_decl &f)
Test if a given member function is virtual.
Definition: abg-ir.cc:6723
bool has_parent_allowed_by_specific_negated_suppression() const
Test if the current diff node has a parent node which is specifically allowed by a negated suppressio...
This means the diff node (or at least one of its descendant nodes) carries a change involving two com...
void sort_enumerators(const string_enumerator_map &enumerators_map, enum_type_decl::enumerators &sorted)
Sort a map of enumerators by their value.
shared_ptr< function_type_diff > function_type_diff_sptr
A convenience typedef for a shared pointer to function_type_type_diff.
size_t net_num_leaf_var_changes() const
Getter for the net number of leaf variable change diff nodes.
The base type of all declarations.
Definition: abg-ir.h:1524
size_t num_leaf_var_changes_filtered_out() const
Getter for the number of leaf variable changes diff nodes that have been filtered out...
A comparison functor for instances of diff.
virtual void report(ostream &, const string &indent="") const
Report the differences between the two enums.
type_suppression_sptr is_type_suppression(suppression_sptr suppr)
Test if an instance of suppression is an instance of type_suppression.
const string_diff_sptr_map & changed_unreachable_types() const
Getter for a map of changed types that are not reachable from global functions/variables.
const string_member_function_sptr_map & deleted_member_fns() const
virtual void chain_into_hierarchy()
Populate the vector of children node of the diff base type sub-object of this instance of subrange_di...
function_suppression_sptr is_function_suppression(const suppression_sptr suppr)
Test if an instance of suppression is an instance of function_suppression.
vector< function_decl_diff_sptr > function_decl_diff_sptrs_type
Convenience typedef for a vector of function_decl_diff_sptr.
size_t num_changed_unreachable_types_filtered_out() const
Getter of the number of changed types that are unreachable from public interfaces and that have been ...
distinct_diff(type_or_decl_base_sptr first, type_or_decl_base_sptr second, diff_context_sptr ctxt=diff_context_sptr())
Constructor for distinct_diff.
A "Less Than" functor to compare instance of function_decl_diff.
diff_category remove_from_category(diff_category c)
Remove the current diff tree node from an a existing sef of categories. The categories include those ...
void sort_string_member_function_sptr_map(const string_member_function_sptr_map &map, class_or_union::member_functions &sorted)
Sort a map that's an instance of string_member_function_sptr_map and fill a vector of member function...
size_t num_leaf_type_changes_filtered_out() const
Getter for the number of filtered out leaf type change diff nodes.
The abstraction of a change between two ABI artifacts, a.k.a an artifact change.
const pointer_diff * is_pointer_diff(const diff *diff)
Test if a diff node is about differences between two pointers.
virtual ~class_or_union_diff()
Destructor of class_or_union_diff.
virtual void chain_into_hierarchy()
Populate the vector of children node of the diff base type sub-object of this instance of class_or_un...
const edit_script & member_fn_tmpls_changes() const
const string_diff_ptr_map & get_function_decl_diff_map() const
Getter of the map that contains function decl diffs.
const edit_script & member_fns_changes() const
Abstraction of a diff between two qualified types.
virtual enum change_kind has_local_changes() const
size_t net_num_func_removed() const
Getter for the net number of function removed.
virtual enum change_kind has_local_changes() const
shared_ptr< class_diff > class_diff_sptr
Convenience typedef for a shared pointer on a class_diff type.
virtual void chain_into_hierarchy()
Populate the vector of children node of the diff base type sub-object of this instance of enum_diff...
const changed_var_sptrs_type & ordered_data_members_replaced_by_adms() const
Get an ordered vector of of data members that got replaced by anonymous data members.
size_t net_num_vars_changed() const
Getter for the number of variables that have a change in their sub-types, minus the number of these v...
vector< var_diff_sptr > var_diff_sptrs_type
Convenience typedef for a vector of var_diff_sptr.
const edit_script & base_changes() const
class_decl_sptr second_class_decl() const
Getter of the second class involved in the diff.
shared_ptr< typedef_diff > typedef_diff_sptr
Convenience typedef for a shared pointer on a typedef_diff type.
const string_parm_map & removed_parms() const
Getter for the map of parameters that got removed.
const function_decl_sptr first_function_decl() const
const string_diff_ptr_map & get_function_type_diff_map() const
Getter of the map that contains function type diffs.
const vector< diff * > & children_nodes() const
Getter for the children nodes of the current diff node.
const diff_sptrs_type & changed_decls() const
virtual void report(ostream &out, const string &indent="") const
Report the diff in a serialized form.
size_t net_num_changed_unreachable_types() const
Getter of the number of changed types that are unreachable from public interfaces and that have *NOT*...
The internal type for the impl idiom implementation of pointer_diff.
bool added_function_is_suppressed(const function_decl *fn) const
Test if the change reports for a give given added function has been deleted.
const string_var_ptr_map & deleted_variables() const
Getter for the variables that got deleted from the first subject of the diff.
const string_fn_parm_diff_sptr_map & subtype_changed_parms() const
Getter for the map of function parameter changes of the current diff.
virtual bool has_changes() const
Return true iff the diff node has a change.
bool has_net_subtype_changes() const
Test if the current instance of corpus_diff carries subtype changes whose reports are not suppressed ...
diff_sptr underlying_type_diff() const
Getter for the diff between the underlying types of the two qualified types.
shared_ptr< pointer_diff > pointer_diff_sptr
Convenience typedef for a shared pointer on a pointer_diff type.
virtual void report(ostream &, const string &indent="") const
Produce a basic report about the changes between two class_decl.
virtual const string & get_pretty_representation() const
Build and return a textual representation of the current instance of fn_parm_diff.
var_decl_sptr first_var() const
Getter for the first var_decl of the diff.
shared_ptr< suppression_base > suppression_sptr
Convenience typedef for a shared pointer to a suppression.
Definition: abg-fwd.h:1597
const edit_script & data_members_changes() const
void finish_diff_type()
Finish building the current instance of corpus_diff.
size_t num_func_with_virtual_offset_changes() const
Getter for the number of functions that carry virtual member offset changes.
diff_category add_to_category(diff_category c)
Adds the current diff tree node to an additional set of categories. Note that the categories include ...
bool deleted_function_is_suppressed(const function_decl *fn) const
Test if the change reports for a given deleted function have been deleted.
An abstractions of the changes between two scopes.
diff_category get_local_category() const
Getter for the local category of the current diff tree node.
bool is_data_member(const var_decl &v)
Test if a var_decl is a data member.
Definition: abg-ir.cc:5763
An abstraction of a diff between entities that are of a different kind (disctinct).
diff_context_sptr get_context()
Getter of the context associated with this corpus.
bool is_class_type(const type_or_decl_base &t)
Test whether a type is a class.
Definition: abg-ir.cc:10733
virtual void chain_into_hierarchy()
Populate the vector of children node of the diff base type sub-object of this instance of pointer_dif...
virtual void chain_into_hierarchy()
Populate the vector of children node of the diff base type sub-object of this instance of qualified_t...
bool has_incompatible_changes() const
Test if the current instance of corpus_diff carries changes that we are sure are incompatible. By incompatible change we mean a change that "breaks" the ABI of the corpus we are looking at.
bool start()
Start the timer.
const qualified_type_diff * is_qualified_type_diff(const diff *diff)
Test if a diff node is about differences between two qualified types.
bool class_or_union_types_of_same_kind(const class_or_union *first, const class_or_union *second)
Test if two class or union types are of the same kind.
Definition: abg-ir.cc:10904
const corpus_diff * is_corpus_diff(const diff *diff)
Test if a diff node is a corpus_diff node.
virtual enum change_kind has_local_changes() const
virtual const string & get_pretty_representation() const
Getter the pretty representation of the subrange_diff diff node.
interned_string get_id() const
Return an ID that tries to uniquely identify the function inside a program or a library.
Definition: abg-ir.cc:21791
shared_ptr< function_type > function_type_sptr
Convenience typedef for a shared pointer on a function_type.
Definition: abg-fwd.h:205
bool deleted_variable_is_suppressed(const var_decl *var) const
Test if the change reports for a give given deleted variable has been deleted.
bool show_impacted_interfaces() const
Getter of the flag that indicates if the leaf reporter should display a summary of the interfaces imp...
void sort_string_var_diff_sptr_map(const string_var_diff_sptr_map &map, var_diff_sptrs_type &sorted)
Sort of an instance of string_var_diff_sptr_map map.
virtual void visit_begin(diff *)
This is called by the traversing code on a diff node just before visiting it. That is...
void append_child_node(diff_sptr)
Add a new child node to the vector of children nodes for the current diff node.
vector< changed_var_sptr > changed_var_sptrs_type
Convenience typedef for a vector of .gg381.
bool is_member_function(const function_decl &f)
Test whether a function_decl is a member function.
Definition: abg-ir.cc:6450
scope_diff(scope_decl_sptr first_scope, scope_decl_sptr second_scope, diff_context_sptr ctxt=diff_context_sptr())
Constructor for scope_diff.
void mark_diff_as_visited(const diff *)
Mark a diff node as traversed by a traversing algorithm.
diff_sptr try_to_diff< class_decl >(const type_or_decl_base_sptr first, const type_or_decl_base_sptr second, diff_context_sptr ctxt)
This is a specialization of try_to_diff() template to diff instances of class_decl.
An abstraction helper for type declarations.
Definition: abg-ir.h:1959
A diff node in this category is a function (or function type) with at least one parameter added or re...
A functor to compare instances of elf_symbol base on their names.
This means the diff node (or at least one of its descendant nodes) carries a change that modifies the...
const qualified_type_def_sptr first_qualified_type() const
Getter for the first qualified type of the diff.
#define ABG_ASSERT_NOT_REACHED
A macro that expands to aborting the program when executed.
interned_string get_function_id_or_pretty_representation(function_decl *fn)
Get the ID of a function, or, if the ID can designate several different functions, get its pretty representation.
Definition: abg-ir.cc:9134
size_t num_leaf_changes_filtered_out() const
Getter of the number of leaf type change diff nodes that have been filtered out.
bool do_log() const
Test if logging was requested.
size_t count_filtered_subtype_changed_data_members(bool local_only=false) const
Count the number of /filtered/ data members with a sub-type change.
const function_type_sptr get_type() const
Return the type of the current instance of function_decl.
Definition: abg-ir.cc:21454
The base class of both types and declarations.
Definition: abg-ir.h:1353
bool insert_diff_node(const diff *d, const type_or_decl_base_sptr &impacted_iface)
Insert a new diff node into the current instance of diff_maps.
const string_var_diff_sptr_map & changed_variables()
Getter for the non-sorted map of variables which signature didn't change but which do have some indir...
A declaration that introduces a scope.
Definition: abg-ir.h:1795
virtual void chain_into_hierarchy()
This constructs the relation between this diff node and its detail diff nodes, in the generic view of...
bool is_negated_suppression(const suppression_base &s)
Test if a suppression specification is a negated suppression.
virtual bool has_changes() const
Return true iff the current diff node carries a change.
bool is_reference_or_ptr_diff_to_non_basic_nor_distinct_types(const diff *diff)
Test if a diff node is a reference or pointer diff node to a change that is neither basic type change...
var_decl_sptr find_data_member_from_anonymous_data_member(const var_decl_sptr &anon_dm, const string &name)
Find a data member inside an anonymous data member.
Definition: abg-ir.cc:10312
const function_decl::parameter_sptr second_parameter() const
Getter for the second subject of this diff node.
edit_script & function_changes() const
Abstracts a reference type.
Definition: abg-ir.h:2386
This type abstracts changes for a class_decl.
void clear_redundancy_categorization(diff *diff_tree)
Walk a given diff sub-tree to clear the REDUNDANT_CATEGORY out of the category of the nodes...
const array_type_def_sptr second_array() const
Getter for the second array of the diff.
size_t num_removed_var_syms_filtered_out() const
Getter for the number of removed variable symbols, not referenced by any debug info, that have been filtered out.
const function_type_diff * is_function_type_diff_with_local_changes(const diff *diff)
Test if a given diff node carries a function type change with local changes.
The abstraction of a qualified type.
Definition: abg-ir.h:2212
This means that a diff node was marked as suppressed by a user-provided suppression specification...
void sort_string_data_member_diff_sptr_map(const string_var_diff_sptr_map &map, var_diff_sptrs_type &sorted)
Sort the values of a string_var_diff_sptr_map and store the result in a vector of var_diff_sptr...
size_t count_filtered_changed_dm(bool local_only=false)
Get the number of data member changes carried by the current diff node that were filtered out...
const typedef_decl_sptr first_typedef_decl() const
Getter for the firt typedef_decl involved in the diff.
type_or_decl_base_sptr first_subject() const
Getter of the first subject of the diff.
This means the diff node does not carry any (meaningful) change, or that it carries changes that have...
bool show_added_symbols_unreferenced_by_debug_info() const
Getter for the flag that indicates if symbols not referenced by any debug info and that got added are...
const diff * parent_node() const
Getter for the parent node of the current diff node.
const base_diff * is_base_diff(const diff *diff)
Test if a diff node is about differences between two base class specifiers.
Abstraction of a base specifier in a class declaration.
Definition: abg-ir.h:4359
diff_sptr get_canonical_diff_for(const type_or_decl_base_sptr first, const type_or_decl_base_sptr second) const
Getter for the canonical diff node for the diff represented by their two subjects.
const diff_stats & apply_filters_and_suppressions_before_reporting()
Apply the different filters that are registered to be applied to the diff tree; that includes the cat...
size_t net_num_vars_added() const
Getter for the net number of added variables.
const suppr::suppressions_type & suppressions() const
Getter for the vector of suppressions that specify which diff node reports should be dropped on the f...
size_t num_removed_unreachable_types() const
Getter of the number of removed types that are unreachable from the public interface of the ABI corpu...
bool is_filtered_out_wrt_non_inherited_categories() const
Test if this diff tree node is to be filtered out for reporting purposes, but by considering only the...
void forbid_visiting_a_node_twice_per_interface(bool)
This function sets a flag os that if forbid_visiting_a_node_twice() returns true, then each time the ...
unordered_map< string, class_decl::base_spec_sptr > string_base_sptr_map
Convenience typedef for a map of string and class_decl::basse_spec_sptr.
shared_ptr< diff_context > diff_context_sptr
Convenience typedef for a shared pointer of diff_context.
Definition: abg-fwd.h:68
const corpus_diff_sptr & get_corpus_diff() const
Get the corpus diff for the current context.
Abstraction of a diff between two typedef_decl.
const scope_decl_sptr first_scope() const
Getter for the first scope of the diff.
virtual enum change_kind has_local_changes() const
diff_node_visitor()
Default constructor of the diff_node_visitor type.
bool deleted_unrefed_fn_sym_is_suppressed(const elf_symbol *) const
Test if the change reports for a given deleted function symbol (that is not referenced by any debug i...
const var_diff * is_var_diff(const diff *diff)
Test if a diff node is about differences between variables.
virtual const string & get_pretty_representation() const
virtual void report(ostream &, const string &indent="") const
Report the changes carried by the current class_or_union_diff node in a textual format.
diff_category get_default_harmful_categories_bitmap()
Getter of a bitmap made of the set of change categories that are considered harmful.
size_t num_leaf_var_changes() const
Getter for the number of leaf variable change diff nodes.
This means that a diff node in the sub-tree carries an addition of enumerator to an enum type...
bool is_mostly_distinct_diff(const diff *d)
Test if a diff node carries a distinct type change or a pointer/reference/typedef to distinct type ch...
virtual const string & get_pretty_representation() const
const diff * peel_typedef_diff(const diff *dif)
If a diff node is about changes between two typedef types, get the diff node about changes between th...
This means the diff node (or at least one of its descendant nodes) carries access related changes...
void sort_data_members(const string_decl_base_sptr_map &data_members, vector< decl_base_sptr > &sorted)
Sort a map of data members by the offset of their initial value.
shared_ptr< reference_diff > reference_diff_sptr
Convenience typedef for a shared pointer on a reference_diff type.
bool is_user_defined_type(const type_base *t)
Test if a type is user-defined.
Definition: abg-ir.cc:5629
The variable was deleted from the second subject of the diff.
const type_decl_sptr first_type_decl() const
Getter for the first subject of the type_decl_diff.
diff * diff_has_been_visited(const diff *) const
Test if a diff node has been traversed.
virtual void report(ostream &, const string &indent="") const
Generates a report for the current instance of base_diff.
class_decl::base_spec_sptr second_base() const
Getter for the second base spec of the diff object.
A diff node in this category carries a change from void pointer to non-void pointer.
diff * get_current_topmost_iface_diff() const
Getter of the diff current topmost interface which is impacted by the current diff node being visited...
virtual enum change_kind has_local_changes() const
shared_ptr< var_decl > var_decl_sptr
Convenience typedef for a shared pointer on a var_decl.
Definition: abg-fwd.h:246
class_or_union_sptr first_class_or_union() const
A diff node in this category has a parent node that is in the HAS_ALLOWED_CHANGE_CATEGORY category...
bool is_member_decl(const decl_base_sptr d)
Tests if a declaration is a class member.
Definition: abg-ir.cc:5567
void maybe_apply_filters(diff_sptr diff)
Apply the diff filters to a given diff sub-tree.
const global_scope * get_global_scope(const decl_base &decl)
return the global scope as seen by a given declaration.
Definition: abg-ir.cc:8489
The abstraction of a diff between two arrays.
const string_enumerator_map & deleted_enumerators() const
diff_maps()
Default constructor of the diff_maps type.
size_t num_removed_vars_filtered_out() const
Getter for the number removed variables that have been filtered out.
const string_diff_ptr_map & get_distinct_diff_map() const
Getter of the map that contains distinct diffs.
uint64_t get_absolute_data_member_offset(const var_decl &m)
Get the absolute offset of a data member.
Definition: abg-ir.cc:6355
size_t num_added_var_syms_filtered_out() const
Getter for the number of added variable symbols, not referenced by any debug info, that have been filtered out.
Abstraction of the declaration of a method.
Definition: abg-ir.h:3859
bool has_decl_only_def_change(const decl_base_sptr &first, const decl_base_sptr &second)
Test if two decl_base_sptr are different just by the fact that one is decl-only and the other one is ...
size_t net_num_added_func_syms() const
Getter of the net number of added function symbols that are not referenced by any debug info...
This says that the traversing code should not mark visited nodes as having been traversed. This is useful, for instance, for visitors which have debugging purposes.
void categorize_redundant_changed_sub_nodes()
Walk the changed functions and variables diff nodes to categorize redundant nodes.
size_t net_num_func_added() const
Getter for the net number of added functions.
shared_ptr< distinct_diff > distinct_diff_sptr
Convenience typedef for a shared pointer to distinct_types_diff.
ostream & operator<<(ostream &o, diff_category c)
Serialize an instance of diff_category to an output stream.
const fn_parm_diff * is_fn_parm_diff(const diff *diff)
Test if a diff node is about differences between two function parameters.
class_decl::base_spec_sptr first_base() const
Getter for the first base spec of the diff object.
virtual bool traverse(diff_node_visitor &v)
Traverse the diff sub-tree under the current instance corpus_diff.
class_or_union * is_class_or_union_type(const type_or_decl_base *t)
Test if a type is a class_or_union.
Definition: abg-ir.cc:10883
bool added_unreachable_type_is_suppressed(const type_base *t) const
Test if an added type that is unreachable from public interface has been suppressed by a suppression ...
const declarations & get_member_decls() const
Getter for the member declarations carried by the current scope_decl.
Definition: abg-ir.cc:7864
const type_decl_diff * is_diff_of_basic_type(const diff *d)
Test if a diff node represents a diff between two basic types.
virtual enum change_kind has_local_changes() const
Check if the current diff node carries a local change.
shared_ptr< translation_unit > translation_unit_sptr
Convenience typedef for a shared pointer on a translation_unit type.
Definition: abg-fwd.h:134
Abstracts a class declaration.
Definition: abg-ir.h:4163
Abstraction of a diff between two function_decl.
A diff node in this category is a function parameter type which top cv-qualifiers change...
shared_ptr< typedef_decl > typedef_decl_sptr
Convenience typedef for a shared pointer on a typedef_decl.
Definition: abg-fwd.h:161
virtual void report(ostream &out, const string &indent="") const
Report the diff in a serialized form.
void sort_string_diff_sptr_map(const string_diff_sptr_map &map, diff_sptrs_type &sorted)
Sort a map ofg string -> diff_sptr into a vector of diff_sptr. The diff_sptr are sorted lexicographic...
change_kind
A bitfield that gives callers of abigail::ir::equals() some insight about how different two internal ...
Definition: abg-ir.h:1308
bool is_at_global_scope(const decl_base &decl)
Tests whether a given declaration is at global scope.
Definition: abg-ir.cc:10242
void propagate_categories(diff *diff_tree)
Visit all the nodes of a given sub-tree. For each node that has a particular category set...
This means that a diff node in the sub-tree carries an incompatible change to a vtable.
unordered_map< string, diff * > string_diff_ptr_map
Convenience typedef for a map which value is a diff*. The key of the map is the qualified name of the...
function_type_diff(const function_type_sptr first, const function_type_sptr second, diff_context_sptr ctxt)
Consutrctor of the function_type type.
bool currently_reporting() const
Tests if we are currently in the middle of emitting a report for this diff.
corpus_diff(corpus_sptr first, corpus_sptr second, diff_context_sptr ctxt=diff_context_sptr())
Constructor for corpus_diff.
size_t count_filtered_subtype_changed_dm(bool local_only=false)
Get the number of data member sub-type changes carried by the current diff node that were filtered ou...
const string_diff_ptr_map & get_enum_diff_map() const
Getter of the map that contains enum type diffs.
void switch_categories_on(diff_category c)
Setter for the bitmap that represents the set of categories that the user wants to see reported...
diff_category get_allowed_category() const
Getter for the bitmap that represents the set of categories that the user wants to see reported...
void apply_suppressions(diff *diff_tree)
Walk a given diff-sub tree and appply the suppressions carried by the context. If the suppression app...
size_t count_filtered_changed_mem_fns(const diff_context_sptr &)
Get the number of member functions changes carried by the current diff node that were filtered out...
const enum_type_decl_sptr first_enum() const
const string_diff_ptr_map & get_reference_diff_map() const
Getter of the map that contains reference type diffs.
virtual void report(ostream &, const string &indent="") const
Report the diff in a serialized form.
shared_ptr< subrange_diff > subrange_diff_sptr
A convenience typedef for a shared pointer to subrange_diff type.
const class_diff * is_class_diff(const diff *diff)
Test if a diff node is a class_diff node.
const edit_script & member_types_changes() const
shared_ptr< type_suppression > type_suppression_sptr
Convenience typedef for a shared pointer to type_suppression.
shared_ptr< scope_diff > scope_diff_sptr
Convenience typedef for a shared pointer on a scope_diff.
base_diff(class_decl::base_spec_sptr first, class_decl::base_spec_sptr second, class_diff_sptr underlying, diff_context_sptr ctxt=diff_context_sptr())
bool show_unreachable_types()
Getter for the flag that indicates if changes on types unreachable from global functions and variable...
Abstraction of a diff between two enums.
virtual void report(ostream &out, const string &indent="") const
Ouputs a report of the differences between of the two type_decl involved in the type_decl_diff.
The default, initial, reporter of the libabigail comparison engine.
Definition: abg-reporter.h:153
virtual enum change_kind has_local_changes() const
Abstracts a variable declaration.
Definition: abg-ir.h:2943
void sort_string_elf_symbol_map(const string_elf_symbol_map &map, vector< elf_symbol_sptr > &sorted)
Sort a map of string -> pointer to elf_symbol.
The private data structure for distinct_diff.
void set_category(diff_category c)
Set the category of the current diff node. This category includes the categories inherited from the c...
virtual void report(ostream &, const string &indent="") const
Serialize a report of the changes encapsulated in the current instance of function_decl_diff over to ...
void sort_string_parm_map(const string_parm_map &map, vector< function_decl::parameter_sptr > &sorted)
Sort a map of string -> function parameters.
edit_script & variable_changes() const
A functor to compare instances of var_decl base on their qualified names.
void switch_categories_off(diff_category c)
Setter for the bitmap that represents the set of categories that the user wants to see reported...
bool is_diff_of_global_decls(const diff *)
Tests if a given diff node is to represent the changes between two gobal decls.
bool get_member_function_is_dtor(const function_decl &f)
Test whether a member function is a destructor.
Definition: abg-ir.cc:6536
Abstraction of a function parameter.
Definition: abg-ir.h:3218
bool added_variable_is_suppressed(const var_decl *var) const
Test if the change reports for a given added variable have been suppressed.
The base class of diff between decls.
The base class of diff between types.
A reporter that only reports leaf changes.
Definition: abg-reporter.h:266
Abstraction of a diff between two basic type declarations.
const function_decl_sptr second_function_decl() const
void sort_string_var_ptr_map(const string_var_ptr_map &map, vector< var_decl * > &sorted)
Sort a map of string -> pointer to var_decl.
unordered_map< string, var_decl * > string_var_ptr_map
Convenience typedef for a map which key is a string and which value is a point to var_decl...
unordered_map< string, var_diff_sptr > string_var_diff_sptr_map
Convenience typedef for a map whose key is a string and whose value is a changed variable of type var...
unordered_map< string, base_diff_sptr > string_base_diff_sptr_map
Convenience typedef for a map of string and base_diff_sptr.
void initialize_canonical_diff(const diff_sptr diff)
Set the canonical diff node property of a given diff node appropriately.
void allocate_priv_data()
Allocate the memory for the priv_ pimpl data member of the class_or_union_diff class.
virtual bool has_changes() const
Return true iff the current diff node carries a change.
bool soname_changed() const
Test if the soname of the underlying corpus has changed.
size_t net_num_removed_func_syms() const
Getter of the net number of removed function symbols that are not referenced by any debug info...
diff_sptr try_to_diff(const type_or_decl_base_sptr first, const type_or_decl_base_sptr second, diff_context_sptr ctxt)
bool is_suppressed() const
Test if the current diff node has been suppressed by a user-provided suppression specification.
interned_string get_id() const
Return an ID that tries to uniquely identify the variable inside a program or a library.
Definition: abg-ir.cc:20237
var_decl * is_var_decl(const type_or_decl_base *tod)
Tests if a declaration is a variable declaration.
Definition: abg-ir.cc:11368
decl_base_sptr subtype_changed_dm(decl_base_sptr) const
Test if the current diff node carries a data member change for a data member which name is the same a...
bool has_net_changes() const
Test if the current instance of corpus_diff carries changes whose reports are not suppressed by any s...
const type_or_decl_base_sptr first() const
Getter for the first subject of the diff.
visiting_kind get_visiting_kind() const
Getter for the visiting policy of the traversing code while invoking this visitor.
unordered_map< string, elf_symbol_sptr > string_elf_symbol_map
Convenience typedef for a map whose key is a string and whose value is an elf_symbol_sptr.
This is the base class of class_diff and union_diff.
const string_decl_base_sptr_map & deleted_data_members() const
Getter for the data members that got deleted.
The internal type for the impl idiom implementation of subrange_diff.
bool has_changes() const
Return true iff the current corpus_diff node carries a change.
std::vector< enumerator > enumerators
Convenience typedef for a list of enumerator.
Definition: abg-ir.h:2699
size_t num_var_syms_removed() const
Getter for the number of variable symbols (not referenced by any debug info) that got removed...
The abstraction of the diff between two subrange types.
const string_diff_ptr_map & get_type_decl_diff_map() const
Getter of the map that contains basic type diffs.
unordered_map< unsigned, fn_parm_diff_sptr > unsigned_fn_parm_diff_sptr_map
Convenience typedef for a map which key is an integer and which value is a changed parameter...
A functor to compare instances of class_decl::base_spec.
void sort_string_base_diff_sptr_map(const string_base_diff_sptr_map &map, base_diff_sptrs_type &sorted)
Sort a map of string -> base_diff_sptr into a sorted vector of base_diff_sptr. The base_diff_sptr are...
An abstraction of a diff between between two abi corpus.
A functor to compare two instances of diff_sptr.
void sort_unsigned_data_member_diff_sptr_map(const unsigned_var_diff_sptr_map map, var_diff_sptrs_type &sorted)
Sort the values of a unsigned_var_diff_sptr_map map and store the result into a vector of var_diff_sp...
virtual bool traverse(diff_node_visitor &v)
The default traverse function.
virtual void chain_into_hierarchy()
Populate the vector of children node of the diff base type sub-object of this instance of base_diff...
virtual void chain_into_hierarchy()
Populate the vector of children node of the diff base type sub-object of this instance of reference_d...
function_decl_diff(const function_decl_sptr first, const function_decl_sptr second, diff_context_sptr ctxt)
Constructor for function_decl_diff.
const var_decl_sptr get_next_data_member(const class_or_union *klass, const var_decl_sptr &data_member)
In the context of a given class or union, this function returns the data member that is located after...
Definition: abg-ir.cc:5892
void set_canonical_diff(diff *)
Setter for the canonical diff of the current instance of diff.
bool is_unique_type(const type_base_sptr &t)
Test if a type is unique in the entire environment.
Definition: abg-ir.cc:27161
vector< changed_enumerator > changed_enumerators_type
Convenience typedef for a vector of changed enumerators.
void ensure_lookup_tables_populated()
If the lookup tables are not yet built, walk the differences and fill the lookup tables.
Abstracts a declaration for an enum type.
Definition: abg-ir.h:2685
class_or_union_sptr second_class_or_union() const
bool is_traversing() const
Tell if a given node is being traversed or not.
size_t num_added_unreachable_types_filtered_out() const
Getter of the number of added types that are unreachable from public interfaces and that are filtered...
uint64_t get_data_member_offset(const var_decl &m)
Get the offset of a data member.
Definition: abg-ir.cc:6266
translation_unit_diff(translation_unit_sptr first, translation_unit_sptr second, diff_context_sptr ctxt=diff_context_sptr())
Constructor for translation_unit_diff.
const type_or_decl_base_sptr second() const
Getter for the second subject of the diff.
bool show_stats_only() const
Test if the comparison module should only show the diff stats.
diff_category
An enum for the different categories that a diff tree node falls into, regarding the kind of changes ...
ostream * default_output_stream()
Getter for the default output stream used by code of the comparison engine. By default the default ou...
Toplevel namespace for libabigail.
The variable was added to the second second subject of the diff.
bool do_log() const
Test if logging was requested.
virtual bool has_changes() const
Test if the current diff node carries a change.
bool show_leaf_changes_only() const
Get the flag that indicates if the diff using this context should show only leaf changes or not...
size_t num_changed_vars_filtered_out() const
Getter for the number of variables that have a change in one of their sub-types, and that have been f...
unordered_set< type_or_decl_base_sptr, type_or_decl_hash, type_or_decl_equal > artifact_sptr_set_type
A convenience typedef for a hash set of type_or_decl_base_sptr.
Definition: abg-ir.h:550
shared_ptr< scope_decl > scope_decl_sptr
Convenience typedef for a shared pointer on a scope_decl.
Definition: abg-fwd.h:258
virtual void visit_end(corpus_diff *)
This is called by the traversing code on a corpus_diff node just after visiting it. That is after visiting it and its children nodes.
bool added_unrefed_var_sym_is_suppressed(const elf_symbol *) const
Test if the change reports for a given added variable symbol (that is not referenced by any debug inf...
const diff * peel_typedef_or_qualified_type_diff(const diff *dif)
If a diff node is about changes between two typedefs or qualified types, get the diff node about chan...
unordered_map< string, changed_enumerator > string_changed_enumerator_map
Convenience typedef for a map which value is a changed enumerator. The key is the name of the changed...
An abstraction of a diff between two instances of class_decl::base_spec.
#define SKIP_MEM_FN_IF_VIRTUALITY_DISALLOWED
Skip the processing of the current member function if its virtual-ness is disallowed by the user...
visiting_kind operator&(visiting_kind l, visiting_kind r)
The overloaded and operator for visiting_kind.
const string_base_sptr_map & inserted_bases() const
Getter for the inserted base classes of the diff.
size_t count_filtered_deleted_mem_fns(const diff_context_sptr &)
Get the number of member functions deletions carried by the current diff node that were filtered out...
virtual const string & get_pretty_representation() const
shared_ptr< function_decl > function_decl_sptr
Convenience typedef for a shared pointer on a function_decl.
Definition: abg-fwd.h:263
decl_base * is_decl(const type_or_decl_base *d)
Test if an ABI artifact is a declaration.
Definition: abg-ir.cc:10409
virtual const string & get_pretty_representation() const
bool has_harmful_name_change(const decl_base_sptr &f, const decl_base_sptr &s)
Test if two decls represents a harmful name change.
virtual const string & get_pretty_representation() const
const string_diff_ptr_map & get_typedef_diff_map() const
Getter of the map that contains typedef type diffs.
bool reported_once() const
Tests if a report has already been emitted for the current diff.
virtual bool has_changes() const
Test if the current subrange_diff node carries any change.
void set_current_topmost_iface_diff(diff *)
Setter of the diff current topmost interface which is impacted by the current diff node being visited...
const diff * peel_pointer_or_qualified_type_diff(const diff *dif)
If a diff node is about changes between two pointer, reference or qualified types, get the diff node about changes between the underlying types.
bool is_enumerator_present_in_enum(const enum_type_decl::enumerator &enr, const enum_type_decl &enom)
Test if a given enumerator is found present in an enum.
Definition: abg-ir.cc:19133
const string_function_ptr_map & added_functions()
Getter for the added functions of the diff.
type_base_sptr get_leaf_type(qualified_type_def_sptr t)
Return the first underlying type that is not a qualified type.
decl_diff_base(decl_base_sptr first_subject, decl_base_sptr second_subject, diff_context_sptr ctxt)
Constructor of decl_diff_base.
const enum_type_decl * is_enum_type(const type_or_decl_base *d)
Test if a decl is an enum_type_decl.
Definition: abg-ir.cc:10683
const string_function_ptr_map & deleted_functions() const
Getter for the deleted functions of the diff.
friend corpus_diff_sptr compute_diff(const corpus_sptr f, const corpus_sptr s, diff_context_sptr ctxt)
Compute the diff between two instances of corpus.
void sort_string_base_sptr_map(const string_base_sptr_map &m, class_decl::base_specs &sorted)
Lexicographically sort base specifications found in instances of string_base_sptr_map.
virtual bool has_changes() const
Test if the current diff node carries changes.
virtual bool has_changes() const
Return true iff the current diff node carries a change.
void set_corpus_diff(const corpus_diff_sptr &)
Set the corpus diff relevant to this context.
bool show_redundant_changes() const
A getter for the flag that says if we should report about functions or variables diff nodes that have...
const string_enumerator_map & inserted_enumerators() const
virtual void report(ostream &out, const string &indent="") const
Emit a report about the current diff instance.
bool perform_change_categorization() const
Test if it's requested to perform diff node categorization.
shared_ptr< parameter > parameter_sptr
Convenience typedef for a shared pointer on a function_decl::parameter.
Definition: abg-ir.h:3067
const diff_sptrs_type & changed_types() const
size_t num_leaf_changes() const
Getter of the number of leaf type change diff nodes.
The type of the private data of corpus_diff::diff_stats.
size_t net_num_vars_removed() const
Getter for the net number of removed variables.
size_t num_leaf_type_changes() const
Getter for the number of leaf type change diff nodes.
const edit_script & member_changes() const
Accessor of the edit script of the members of a scope.
virtual bool has_changes() const
Return true iff the current diff node carries a change.
shared_ptr< base_spec > base_spec_sptr
Convenience typedef.
Definition: abg-ir.h:4178
diff_category remove_from_local_category(diff_category c)
Remove the current diff tree node from the categories resulting from the local changes.
const string_elf_symbol_map & added_unrefed_function_symbols() const
Getter for function symbols not referenced by any debug info and that got added.
unordered_map< string, type_base_sptr > string_type_base_sptr_map
Convenience typedef for a map which key is a string and which value is a type_base_sptr.
var_decl_sptr second_var() const
Getter for the second var_decl of the diff.
This means that a diff node was warked as being for a private type. That is, the diff node is meant t...
Abstraction of a diff between two function parameters.
virtual enum change_kind has_local_changes() const
const function_decl::parameter_sptr first_parameter() const
Getter for the first subject of this diff node.
size_t num_added_unreachable_types() const
Getter of the number of added types that are unreachable from the public interface of the ABI corpus...
Abstraction for a function declaration.
Definition: abg-ir.h:3046
virtual const string & get_pretty_representation() const
This means that a diff node in the sub-tree carries a harmless union change.
virtual void chain_into_hierarchy()
Populate the vector of children node of the diff base type sub-object of this instance of class_diff...
size_t num_added_func_filtered_out() const
Getter for the number of added function that have been filtered out.
void forget_visited_diffs()
Unmark all the diff nodes that were marked as being traversed.
const string_type_base_sptr_map & added_unreachable_types() const
Getter for a map of added types that are not reachable from global functions/variables.
virtual enum change_kind has_local_changes() const
size_t num_removed_func_syms_filtered_out() const
Getter for the number of removed function symbols, not referenced by debug info, that have been filte...
virtual const string & get_pretty_representation() const
Get a pretty representation of the current diff node.
This means that a diff node in the sub-tree carries a harmless declaration name change. This is set only for name changes for data members and typedefs.
virtual void chain_into_hierarchy()
Populate the vector of children node of the diff base type sub-object of this instance of function_ty...
unordered_map< string, diff_sptr > string_diff_sptr_map
Convenience typedef for a map which value is a diff_sptr. The key of the map is the qualified name of...
const array_type_def::subrange_sptr first_subrange() const
Getter of the first subrange of the current instance subrange_diff.
This means that a diff node in the sub-tree carries a harmless data member change. An example of harmless data member change is an anonymous data member that replaces a given data member without locally changing the layout.
unordered_map< string, function_decl_diff_sptr > string_function_decl_diff_sptr_map
Convenience typedef for a map which key is a string and which value is a function_decl_diff_sptr.
void apply_supprs_to_added_removed_fns_vars_unreachable_types()
Apply suppression specifications for this corpus diff to the set of added/removed functions/variables...
diff_sptr leaf_underlying_type_diff() const
Getter for the diff between the most underlying non-qualified types of two qualified types...
diff_sptr compute_diff(const decl_base_sptr first, const decl_base_sptr second, diff_context_sptr ctxt)
Compute the difference between two decls. The decls can represent either type declarations, or non-type declaration.
virtual enum change_kind has_local_changes() const
size_t num_func_removed() const
Getter for the number of functions removed.
diff_category get_category() const
Getter for the category of the current diff tree node.
void clear_redundancy_categorization()
Walk the changed functions and variables diff nodes and clear the redundancy categorization they migh...
void end_traversing()
Flag a given diff node as not being traversed anymore.
class_decl_sptr first_class_decl() const
The context of the diff. This type holds various bits of information that is going to be used through...
size_t net_num_removed_var_syms() const
Getter of the net number of removed variable symbols that are not referenced by any debug info...
const diff_sptr underlying_type_diff() const
Getter of the diff node of the underlying types of the current subrange_diff diff node...
A diff node in this category is redundant. That means it's present as a child of a other nodes in the...
The abstraction of a diff between two references.
const decl_base * get_type_declaration(const type_base *t)
Get the declaration for a given type.
Definition: abg-ir.cc:10102
shared_ptr< function_decl_diff > function_decl_diff_sptr
Convenience typedef for a shared pointer to a function_decl type.
This means that a diff node in the sub-tree carries a type that was declaration-only and that is now ...
Functor to sort instances of var_diff_sptr.
size_t num_vars_changed() const
Getter for the number of variables that have a change in one of their sub-types.
virtual ~union_diff()
Destructor of the union_diff node.
void emit_diff_stats(const diff_stats &stats, ostream &out, const string &indent)
Emit the summary of the functions & variables that got removed/changed/added.
diff * get_canonical_diff() const
Getter for the canonical diff of the current instance of diff.
bool has_descendant_allowed_by_specific_negated_suppression() const
Test if the current diff node has a descendant node which is specifically allowed by a negated suppre...
unordered_map< const diff *, artifact_sptr_set_type, diff_hash, diff_equal > diff_artifact_set_map_type
A convenience typedef for an unordered_map which key is a diff* and which value is a artifact_sptr_se...
friend var_diff_sptr compute_diff(const var_decl_sptr first, const var_decl_sptr second, diff_context_sptr ctxt)
Compute the diff between two instances of var_decl.
shared_ptr< type_or_decl_base > type_or_decl_base_sptr
A convenience typedef for a shared_ptr to type_or_decl_base.
Definition: abg-fwd.h:119
virtual const string & get_pretty_representation() const
Build and return a copy of a pretty representation of the current instance of function_type_diff.
size_t net_num_leaf_changes() const
Getter of the net number of leaf change diff nodes.
const string_diff_ptr_map & get_var_decl_diff_map() const
Getter of the map that contains var decl diffs.
virtual bool has_changes() const
Return true iff the current diff node carries a change.
shared_ptr< type_decl > type_decl_sptr
Convenience typedef for a shared pointer on a type_decl.
Definition: abg-fwd.h:156
const string_function_decl_diff_sptr_map & changed_functions()
Getter for the functions which signature didn't change, but which do have some indirect changes in th...
shared_ptr< type_decl_diff > type_decl_diff_sptr
Convenience typedef for a shared pointer on a type_decl_diff type.
void keep_diff_alive(diff_sptr &)
Add a diff node to the set of diff nodes that are kept alive for the life time of the current instanc...
bool is_filtered_out() const
Test if this diff tree node is to be filtered out for reporting purposes.
void add_suppressions(const suppr::suppressions_type &supprs)
Add new suppression specifications that specify which diff node reports should be dropped on the floo...
virtual enum change_kind has_local_changes() const =0
Pure interface to know if the current instance of carries a local change. A local change is a change...
virtual bool has_changes() const
Return true iff the current diff node carries a change.
virtual void chain_into_hierarchy()
Populate the vector of children node of the corpus_diff type.
const vector< function_decl::parameter_sptr > & sorted_added_parms() const
Getter for the sorted vector of added parameters .
The abstraction of a diff between two pointers.
Abstraction of an elf symbol.
Definition: abg-ir.h:908
virtual void report(ostream &, const string &indent="") const
Report the changes carried by the current union_diff node in a textual format.
const string_elf_symbol_map & deleted_unrefed_function_symbols() const
Getter for function symbols not referenced by any debug info and that got deleted.
virtual void report(ostream &out, const string &indent="") const
Report the changes of one scope against another.
const var_diff_sptrs_type & changed_variables_sorted()
Getter for the sorted vector of variables which signature didn't change but which do have some indire...
virtual bool has_changes() const
Return true iff the current diff node carries a change.
size_t count_filtered_inserted_mem_fns(const diff_context_sptr &)
Get the number of member functions insertions carried by the current diff node that were filtered out...
size_t count_filtered_bases()
Count the number of bases classes whose changes got filtered out.
virtual const string & get_pretty_representation() const
The function was deleted from the second subject of the diff.
void forbid_visiting_a_node_twice(bool f)
This sets a flag that, if it's true, then during the traversing of a diff nodes tree each node is vis...
void apply_filter(filter_base &filter, corpus_diff_sptr d)
Walk the diff sub-trees of a a corpus_diff and apply a filter to the nodes visted. The filter categorizes each node, assigning it into one or several categories.
vector< method_decl_sptr > member_functions
Convenience typedef.
Definition: abg-ir.h:3993
size_t net_num_added_var_syms() const
Getter of the net number of added variable symbols that are not referenced by any debug info...
const typedef_diff * is_typedef_diff(const diff *diff)
Test if a diff node is a typedef_diff node.
const function_decl_diff * is_function_decl_diff(const diff *diff)
Test if a diff node is about differences between functions.
virtual bool has_changes() const
Return true iff the current diff node carries a change.
const diff * peel_fn_parm_diff(const diff *dif)
If a diff node is about changes between two function parameters get the diff node about changes betwe...
diff_category get_default_harmless_categories_bitmap()
Getter of a bitmap made of the set of change categories that are considered harmless.
friend scope_diff_sptr compute_diff(const scope_decl_sptr first, const scope_decl_sptr second, scope_diff_sptr d, diff_context_sptr ctxt)
Compute the diff between two scopes.
void mark_leaf_diff_nodes()
Walks the diff nodes associated to the current corpus diff and mark those that carry local changes...
void set_local_category(diff_category c)
Set the local category of the current diff node.
virtual bool visit(diff *, bool)
Default visitor implementation.
shared_ptr< translation_unit_diff > translation_unit_diff_sptr
Convenience typedef for a shared pointer on a translation_unit_diff type.
size_t num_vars_removed() const
Getter for the number of variables removed.
A diff node in this category is for a variable which type holds a cv-qualifier change.
void add_suppression(const suppr::suppression_sptr suppr)
Add a new suppression specification that specifies which diff node reports should be dropped on the f...
void clear_lookup_tables()
Clear the lookup tables useful for reporting an enum_diff.
shared_ptr< reference_type_def > reference_type_def_sptr
Convenience typedef for a shared pointer on a reference_type_def.
Definition: abg-fwd.h:229
virtual bool traverse(diff_node_visitor &v)
The generic traversing code that walks a given diff sub-tree.
virtual const string & get_pretty_representation() const
pointer_diff(pointer_type_def_sptr first, pointer_type_def_sptr second, diff_sptr underlying_type_diff, diff_context_sptr ctxt=diff_context_sptr())
Constructor for a pointer_diff.
size_t count_filtered_changed_data_members(bool local_only=false) const
Count the number of /filtered/ data members that got replaced by another data member.
visiting_kind operator|(visiting_kind l, visiting_kind r)
The overloaded or operator for visiting_kind.
diff_sptr underlying_type_diff() const
virtual bool has_changes() const
Return true iff the current diff node carries a change.
unordered_map< string, decl_base_sptr > string_decl_base_sptr_map
Convenience typedef for a map which key is a string and which value is a decl_base_sptr.
shared_ptr< var_diff > var_diff_sptr
Convenience typedef for a shared pointer to a var_diff type.
void count_leaf_changes(size_t &num_changes, size_t &num_filtered)
Count the number of leaf changes as well as the number of the changes that have been filtered out...
shared_ptr< elf_symbol > elf_symbol_sptr
A convenience typedef for a shared pointer to elf_symbol.
Definition: abg-ir.h:872
const pointer_type_def_sptr second_pointer() const
Getter for the second subject of a pointer diff.
diff_category get_class_of_equiv_category() const
Getter of the category of the class of equivalence of the current diff tree node. ...
bool do_log() const
Test if logging was requested.
class_or_union_diff(class_or_union_sptr first_scope, class_or_union_sptr second_scope, diff_context_sptr ctxt=diff_context_sptr())
Constructor for the class_or_union_diff class.
const string_elf_symbol_map & added_unrefed_variable_symbols() const
Getter for variable symbols not referenced by any debug info and that got added.
#define ABG_ASSERT(cond)
This is a wrapper around the 'assert' glibc call. It allows for its argument to have side effects...
Definition: abg-fwd.h:1659
virtual enum change_kind has_local_changes() const
virtual void chain_into_hierarchy()
Populate the vector of children nodes of the diff base type sub-object of this instance of fn_parm_di...
virtual bool has_changes() const
Return true iff the current diff node carries a change.
size_t num_leaf_func_changes() const
Getter for the number of leaf function change diff nodes.
bool has_local_changes_to_be_reported() const
Test if this diff tree node should be reported when considering the categories that were *NOT* inheri...
virtual void visit_end(diff *)
This is called by the traversing code on a diff node just after visiting it. That is after visiting i...
virtual void report(ostream &, const string &indent="") const
Reports the difference between the two subjects of the diff in a serialized form. ...
void apply_filters(corpus_diff_sptr diff_tree)
Apply the diff tree filters that have been associated to the context of the a given corpus_diff tree...
const diff * peel_qualified_diff(const diff *dif)
If a diff node is about changes between two qualified types, get the diff node about changes between ...
size_t num_func_added() const
Getter for the number of functions added.
change_kind
The kind of change the current function suppression should apply to.
An abstraction of a diff between two translation units.
A diff node in this category has a function parameter type with a cv-qualifiers change.
vector< suppression_sptr > suppressions_type
Convenience typedef for a vector of suppression_sptr.
Definition: abg-fwd.h:1603
virtual void report(ostream &, const string &indent="") const
Build and emit a textual report about the current function_type_diff instance.
bool show_architecture_change() const
Getter for the property that says if the comparison module should show the architecture changes in it...
variable_suppression_sptr is_variable_suppression(const suppression_sptr s)
Test if an instance of suppression is an instance of variable_suppression.
visiting_kind
An enum for the different ways to visit a diff tree node.
A diff node in this category has a descendant node that is in the HAS_ALLOWED_CHANGE_CATEGORY categor...
A functor to compare two enumerators based on their value. This implements the "less than" operator...
bool is_union_type(const type_or_decl_base &t)
Test if a type is a union_decl.
Definition: abg-ir.cc:10932
virtual void chain_into_hierarchy()
Populate the vector of children node of the diff base type sub-object of this instance of array_diff...
const string_diff_sptr_map & changed_unreachable_types() const
Get the map of diff nodes representing changed unreachable types.
virtual void chain_into_hierarchy()
Populate the vector of children node of the diff base type sub-object of this instance of var_diff...
const edit_script & member_class_tmpls_changes() const
A comparison functor to compare two instances of fn_parm_diff based on their indexes.
virtual const string & get_pretty_representation() const
void begin_traversing()
Flag a given diff node as being traversed.
virtual void chain_into_hierarchy()
Populate the vector of children node of the diff base type sub-object of this instance of function_de...
const decl_diff_base * is_decl_diff(const diff *diff)
Test if a diff node is about differences between declarations.
size_t num_changed_func_filtered_out() const
Getter for the number of functions that have a change in one of their sub-types, and that have been f...
type_base_sptr strip_typedef(const type_base_sptr type)
Recursively returns the the underlying type of a typedef. The return type should not be a typedef of ...
Definition: abg-ir.cc:6813
virtual void chain_into_hierarchy()
Populate the vector of children node of the diff base type sub-object of this instance of scope_diff...
const string_member_function_sptr_map & inserted_member_fns() const
diff_sptr underlying_type_diff() const
Getter for the diff between the pointed-to types of the pointers of this diff.
const string_parm_map & added_parms() const
Getter for the map of parameters that got added.
const vector< diff * > & children_nodes() const
virtual void report(ostream &, const string &indent="") const
Report the diff in a serialized form.
const decl_base_sptr inserted_member_at(unsigned i)
Accessor that eases the manipulation of the edit script associated to this instance. It returns the scope member (of the second scope of this diff instance) that is reported as being inserted from a given index.
const array_diff * is_array_diff(const diff *diff)
Test if a diff node is a array_diff node.
bool has_basic_type_change_only(const diff *d)
Test if a diff node is a decl diff that only carries a basic type change on its type diff sub-node...
bool lookup_tables_empty() const
Tests if the lookup tables are empty.
diff_sptr type_diff() const
Getter for the diff representing the changes on the type of the function parameter involved in the cu...
size_t num_removed_unreachable_types_filtered_out() const
Getter of the number of removed types that are not reachable from public interfaces and that have bee...
A comparison functor to compare two instances of var_diff that represent changed data members based o...
change_kind
The kind of change the current variable suppression should apply to.
size_t net_num_func_changed() const
Getter for the number of functions that have a change in their sub-types, minus the number of these f...
const filtering::filters & diff_filters() const
Getter for the diff tree nodes filters to apply to diff sub-trees.
The abstraction of a pointer type.
Definition: abg-ir.h:2323
bool lookup_tables_empty(void) const
Tests if the lookup tables are empty.
bool added_unrefed_fn_sym_is_suppressed(const elf_symbol *) const
Test if the change reports for a given added function symbol (that is not referenced by any debug inf...
const string_diff_ptr_map & get_array_diff_map() const
Getter of the map that contains array type diffs.
This type contains maps. Each map associates a type name to a diff of that type. Not all kinds of dif...
virtual bool visit(distinct_diff *, bool)
Default visitor implementation.
unordered_map< unsigned, var_diff_sptr > unsigned_var_diff_sptr_map
Convenience typedef for a map whose key is an unsigned int and whose value is a changed variable of t...
size_t num_added_func_syms_filtered_out() const
Getter for the number of added function symbols, not referenced by any debug info, that have been filtered out.
const diff_sptr & element_type_diff() const
Getter for the diff between the two types of array elements.
const string & get_pretty_representation() const
virtual enum change_kind has_local_changes() const
Test if the current subrange_diff node carries any local change.
friend class_diff_sptr compute_diff(const class_decl_sptr first, const class_decl_sptr second, diff_context_sptr ctxt)
Compute the set of changes between two instances of class_decl.
const type_decl_sptr second_type_decl() const
Getter for the second subject of the type_decl_diff.
The function was added to the second subject of the diff.
bool show_symbols_unreferenced_by_debug_info() const
Getter for the flag that indicates if symbols not referenced by any debug info are to be compared and...
size_t num_var_syms_added() const
Getter for the number of variable symbols (not referenced by any debug info) that got added...
const array_type_def::subrange_sptr second_subrange() const
Getter of the second subrange of the current instance subrange_diff.
const vector< class_decl::base_spec_sptr > & moved_bases() const
Getter for the vector of bases that "moved". That is, the vector of base types which position changed...
const string_diff_ptr_map & get_subrange_diff_map() const
Getter of the map that contains subrange type diffs.
const string_diff_ptr_map & get_union_diff_map() const
Getter of the map that contains union type diffs.
const enum_diff * is_enum_diff(const diff *diff)
Test if a diff node is a enum_diff node.
virtual void report(ostream &, const string &indent="") const
Report the diff in a serialized form.
The base class for the node visitors. These are the types used to visit each node traversed by the di...
bool dump_diff_tree() const
Test if the comparison engine should dump the diff tree for the changed functions and variables it ha...
A filter that walks the diff nodes tree and tags relevant diff nodes into categories considered to re...
const function_type_sptr second_function_type() const
Getter for the second subject of the diff.
void append_child_node(diff_sptr)
Append a new child node to the vector of children nodes for the current instance of corpus_diff node...
A basic type declaration that introduces no scope.
Definition: abg-ir.h:2094
void sort_changed_data_members(changed_var_sptrs_type &input)
Sort (in place) a vector of changed data members.
shared_ptr< enum_type_decl > enum_type_decl_sptr
Convenience typedef for shared pointer to a enum_type_decl.
Definition: abg-fwd.h:169
shared_ptr< base_diff > base_diff_sptr
Convenience typedef for a shared pointer to a base_diff type.
virtual void chain_into_hierarchy()
Populate the vector of children node of the diff base type sub-object of this instance of ...
void sort_changed_enumerators(const string_changed_enumerator_map &enumerators_map, changed_enumerators_type &sorted)
Sort a map of changed enumerators.
const subrange_diff * is_subrange_diff(const diff *diff)
Test if a diff node is a subrange_diff node.
shared_ptr< class_decl > class_decl_sptr
Convenience typedef for a shared pointer on a class_decl.
Definition: abg-fwd.h:187
const decl_base_sptr deleted_member_at(unsigned index) const
Accessor that eases the manipulation of the edit script associated to this instance. It returns the scope member that is reported (in the edit script) as deleted at a given index.
const string_changed_enumerator_map & changed_enumerators() const
shared_ptr< array_diff > array_diff_sptr
Convenience typedef for a shared pointer on a array_diff type.
size_t num_func_syms_added() const
Getter for the number of function symbols (not referenced by any debug info) that got added...
ostream * error_output_stream() const
Getter for the errror output stream used by code of the comparison engine. By default the error outpu...
size_t num_vars_added() const
Getter for the number of variables added.
virtual enum change_kind has_local_changes() const
bool show_soname_change() const
Getter for the property that says if the comparison module should show the soname changes in its repo...
An equality functor to deeply compare pointers.
A comparison functor to compare two data members based on their offset.
bool deleted_unrefed_var_sym_is_suppressed(const elf_symbol *) const
Test if the change reports for a given deleted variable symbol (that is not referenced by any debug i...
static bool entities_are_of_distinct_kinds(type_or_decl_base_sptr first, type_or_decl_base_sptr second)
Test if the two arguments are of different kind, or that are both NULL.
shared_ptr< fn_parm_diff > fn_parm_diff_sptr
Convenience typedef for a shared pointer to a fn_parm_diff type.
unordered_map< string, method_decl_sptr > string_member_function_sptr_map
Convenience typedef for a hash map of strings and member functions.
virtual bool has_changes() const
Return true iff the current diff node carries a change.
const class_or_union_diff * is_anonymous_class_or_union_diff(const diff *d)
Test if a diff node is a class_or_union_diff between two anonymous classes or unions.
const string_decl_base_sptr_map & data_members_replaced_by_adms() const
Get the map of data members that got replaced by anonymous data members.
bool is_diff_of_variadic_parameter(const diff *d)
Test if a diff node represents the difference between a variadic parameter and something else...
union_decl_sptr second_union_decl() const
const var_decl * lookup_data_member(const type_base *type, const char *dm_name)
Look for a data member of a given class, struct or union type and return it.
Definition: abg-ir.cc:27554
void count_leaf_type_changes(size_t &num_type_changes, size_t &num_type_changes_filtered)
Count the number of leaf *type* changes as well as the number of the leaf type changes that have been...
bool show_relative_offset_changes(void)
Get the flag saying if offset changes should be reported in a relative way. That is, if the report should say how of many bits a class/struct data member did move.
The type of private data of class_or_union_diff.
void set_underlying_class_diff(class_diff_sptr d)
Setter for the diff object for the diff of the underlyng base classes.
A deleter for shared pointers that ... doesn't delete the object managed by the shared pointer...
const translation_unit_sptr first_translation_unit() const
Getter for the first translation unit of this diff.
bool to_be_reported() const
Test if this diff tree node should be reported.
void clear_lookup_tables(void)
Clear the lookup tables useful for reporting.
virtual const string & get_pretty_representation() const
void or_visiting_kind(visiting_kind v)
Setter for the visiting policy of the traversing code while invoking this visitor. This one makes a logical or between the current policy and the bitmap given in argument and assigns the current policy to the result.
const function_type_sptr first_function_type() const
Getter for the first subject of the diff.
virtual enum change_kind has_local_changes() const
Test if the current diff node carries local changes.
This means that a given IR artifact has a local type change.
Definition: abg-ir.h:1313
Abstracts a diff between two instances of var_decl.
const pointer_type_def_sptr first_pointer() const
Getter for the first subject of a pointer diff.
diff_sptr type_diff() const
Getter for the diff of the types of the instances of var_decl.
array_type_def::subrange_type * is_subrange_type(const type_or_decl_base *type)
Test if a type is an array_type_def::subrange_type.
Definition: abg-ir.cc:11510
corpus_sptr get_second_corpus() const
Getter for the second corpus of the corpus diff of the current context.
const typedef_decl_sptr second_typedef_decl() const
Getter for the second typedef_decl involved in the diff.
bool get_member_is_static(const decl_base &d)
Gets a flag saying if a class member is static or not.
Definition: abg-ir.cc:5725
const vector< function_decl::parameter_sptr > & sorted_deleted_parms() const
Getter for the sorted vector of deleted parameters.
void maybe_dump_diff_tree()
If the user asked to dump the diff tree node (for changed variables and functions) on the error outpu...
const class_or_union_diff * is_class_or_union_diff(const diff *d)
Test if a diff node is a class_or_union_diff node.
const var_diff_sptrs_type & sorted_subtype_changed_data_members() const
Getter of the sorted vector of data members with a (sub-)type change.
corpus_sptr get_first_corpus() const
Getter for the first corpus of the corpus diff of the current context.
type_or_decl_base_sptr member_type_has_changed(decl_base_sptr) const
Test if the current diff node carries a member type change for a member type which name is the same a...
A comparison functor to compare pointer to instances of type_or_decl_base.
Definition: abg-ir.h:3177
bool get_is_anonymous() const
Test if the current declaration is anonymous.
Definition: abg-ir.cc:4817
This means that a diff node in the sub-tree carries an addition or removal of a non-virtual member fu...
bool is_child_node_of_base_diff(const diff *diff)
Test if a diff node is a child node of a base diff node.
unordered_map< string, fn_parm_diff_sptr > string_fn_parm_diff_sptr_map
Convenience typedef for a map which value is a changed function parameter and which key is the name o...
reference_type_def_sptr second_reference() const
Getter for the second reference of the diff.
void sort_string_fn_parm_diff_sptr_map(const unsigned_fn_parm_diff_sptr_map &map, vector< fn_parm_diff_sptr > &sorted)
Sort a map of fn_parm_diff by the indexes of the function parameters.
The private data and functions of the abigail::ir::comparison types.
void sort_string_virtual_member_function_diff_sptr_map(const string_function_decl_diff_sptr_map &map, function_decl_diff_sptrs_type &sorted)
Sort an map of string -> virtual member function into a vector of virtual member functions. The virtual member functions are sorted by increasing order of their virtual index.
The abstraction of the version of an ELF symbol.
Definition: abg-ir.h:1179
void sort_string_function_decl_diff_sptr_map(const string_function_decl_diff_sptr_map &map, function_decl_diff_sptrs_type &sorted)
Sort the values of a string_function_decl_diff_sptr_map map and store the result in a vector of funct...
const reference_diff * is_reference_diff(const diff *diff)
Test if a diff node is about differences between two references.
size_t net_num_removed_unreachable_types() const
Getter of the number of removed types that are not reachable from public interfaces and that have *NO...
This means that a diff node in the sub-tree carries an a symbol alias change that is harmless...
virtual void report(ostream &, const string &indent="") const
Report the diff in a serialized form.
A diff node in this category carries a change that must be reported, even if the diff node is also in...
vector< diff_sptr > diff_sptrs_type
Convenience typedef for a vector of diff_sptr.
const qualified_type_def_sptr second_qualified_type() const
Getter for the second qualified type of the diff.
bool show_hex_values() const
Get the flag that indicates if the diff reports using this context should show sizes and offsets in a...
const scope_decl_sptr second_scope() const
Getter for the second scope of the diff.
const diff * peel_reference_diff(const diff *dif)
If a diff node is about changes between two reference types, get the diff node about changes between ...
A functor to compare two changed enumerators, based on their initial value.
const diff * get_typedef_diff_underlying_type_diff(const diff *diff)
Return the leaf underlying diff node of a typedef_diff node.
size_t num_func_changed() const
Getter for the number of functions that have a change in one of their sub-types.
union_diff(union_decl_sptr first_union, union_decl_sptr second_union, diff_context_sptr ctxt=diff_context_sptr())
Constructor for the union_diff type.
const type_diff_base * is_type_diff(const diff *diff)
Test if a diff node is about differences between types.
size_t num_leaf_func_changes_filtered_out() const
Getter for the number of leaf function change diff nodes that were filtered out.
shared_ptr< corpus_diff > corpus_diff_sptr
A convenience typedef for a shared pointer to corpus_diff.
size_t get_deleted_non_static_data_members_number() const
Get the number of non static data members that were deleted.
size_t net_num_leaf_type_changes() const
Getter for the net number of leaf type change diff nodes.
const diff_context_sptr context() const
Getter of the diff context of this diff.
const string_elf_symbol_map & deleted_unrefed_variable_symbols() const
Getter for variable symbols not referenced by any debug info and that got deleted.
class_or_union * look_through_decl_only_class(class_or_union *the_class)
If a class (or union) is a decl-only class, get its definition. Otherwise, just return the initial cl...
Definition: abg-ir.cc:11227
subrange_diff(const array_type_def::subrange_sptr &first, const array_type_def::subrange_sptr &second, const diff_sptr &underlying_type_diff, const diff_context_sptr ctxt=diff_context_sptr())
Constructor of the subrange_diff diff node type.
void do_dump_diff_tree(const diff_sptr) const
Emit a textual representation of a diff tree to the error output stream of the current context...
shared_ptr< variable_suppression > variable_suppression_sptr
A convenience typedef for a shared pointer to variable_suppression.
const suppr::suppressions_type & direct_suppressions() const
Getter of the direct suppression specification (those that are not negated) comprised in the general ...
virtual enum change_kind has_local_changes() const
const class_or_union_diff * is_diff_of_class_or_union_type(const diff *d)
Test if a diff node represents a diff between two class or union types.
This means that a given IR artifact has a local non-type change. That is a change that is carried by ...
Definition: abg-ir.h:1318
const suppr::suppressions_type & negated_suppressions() const
Getter of the negated suppression specifications that are comprised in the general vector of suppress...
bool visiting_a_node_twice_is_forbidden_per_interface() const
Return a flag that, if true, then during the traversing of a diff nodes tree each node is visited at ...
reference_type_def_sptr first_reference() const
Getter for the first reference of the diff.
vector< base_diff_sptr > base_diff_sptrs_type
Convenience typedef for a vector of base_diff_sptr.
unordered_map< string, function_decl::parameter_sptr > string_parm_map
Convenience typedef for a map which value is a function parameter. The key is the name of the functio...
const diff_sptr compatible_child_diff() const
Getter for the child diff of this distinct_diff instance.
bool is_anonymous_data_member(const decl_base &d)
Test if a decl is an anonymous data member.
Definition: abg-ir.cc:5954
virtual void report(ostream &, const string &indent="") const
Report about the changes carried by this node.
"Less than" functor to compare instances of function_decl.
void add_to_local_and_inherited_categories(diff_category c)
Adds the current diff tree node to the categories resulting from the local and inherited changes of t...
void sort_string_type_base_sptr_map(string_type_base_sptr_map &map, vector< type_base_sptr > &sorted)
Sort a map of string to type_base_sptr entities.
virtual bool has_changes() const
Return true iff the current diff node carries a change.
Functor that compares two function parameters for the purpose of sorting them.
bool is_private_type_suppr_spec(const type_suppression &s)
Test if a type suppression specification represents a private type suppression automatically generate...
const function_type_diff * is_function_type_diff(const diff *diff)
Test if a diff node is a function_type_diff node.
const function_decl_diff_sptrs_type & changed_member_fns() const
Getter for the virtual members functions that have had a change in a sub-type, without having a chang...
string get_pretty_representation(const type_or_decl_base *tod, bool internal)
Build and return a copy of the pretty representation of an ABI artifact that could be either a type o...
Definition: abg-ir.cc:9260
void compute_diff(RandomAccessOutputIterator a_base, RandomAccessOutputIterator a_begin, RandomAccessOutputIterator a_end, RandomAccessOutputIterator b_base, RandomAccessOutputIterator b_begin, RandomAccessOutputIterator b_end, vector< point > &lcs, edit_script &ses, int &ses_len)
Compute the longest common subsequence of two (sub-regions of) sequences as well as the shortest edit...
virtual enum change_kind has_local_changes() const
virtual bool has_changes() const =0
Pure interface to get the length of the changes encapsulated by this diff. A length of zero means tha...
This says that the traversing code should avoid visiting the children nodes of the current node being...
decl_base_sptr member_class_tmpl_has_changed(decl_base_sptr) const
Test if the current diff node carries a member class template change for a member class template whic...
shared_ptr< function_suppression > function_suppression_sptr
Convenience typedef for a shared pointer to function_suppression.
friend void apply_suppressions(const corpus_diff *diff_tree)
Walk a corpus_diff tree and appply the suppressions carried by the context. If the suppression applie...
virtual const string & get_pretty_representation() const
virtual enum change_kind has_local_changes() const
void sort_string_diff_ptr_map(const string_diff_ptr_map &map, diff_ptrs_type &sorted)
Sort a map ofg string -> diff* into a vector of diff_ptr. The diff_ptr are sorted lexicographically w...
A diff node in this category carries a change in the size of the array type of a global variable...
const translation_unit_sptr second_translation_unit() const
Getter for the second translation unit of this diff.
const vector< diff_sptr > & changed_unreachable_types_sorted() const
Getter of a sorted vector of changed types that are not reachable from global functions/variables.
size_t get_inserted_non_static_data_members_number() const
Get the number of non static data members that were inserted.
const string_base_sptr_map & deleted_bases() const
Getter for the deleted base classes of the diff.
type_or_decl_base_sptr second_subject() const
Getter of the second subject of the diff.
const var_diff_sptrs_type & sorted_changed_data_members() const
Getter of the sorted vector of data members that got replaced by another data member.
size_t num_added_vars_filtered_out() const
Getter for the number of added variables that have been filtered out.
bool deleted_unreachable_type_is_suppressed(const type_base *t) const
Test if a deleted type that is unreachable from public interface has been suppressed by a suppression...
unordered_map< string, enum_type_decl::enumerator > string_enumerator_map
Convenience typedef for a map which value is an enumerator. The key is the name of the enumerator...
const diff_sptr & underlying_type_diff() const
Getter for the diff between the two referred-to types.
bool is_allowed_by_specific_negated_suppression() const
Test if this diff node is allowed (prevented from being suppressed) by at least one negated suppressi...
const function_decl_diff_sptrs_type & changed_functions_sorted()
Getter for a sorted vector of functions which signature didn't change, but which do have some indirec...
bool equals(const decl_base &l, const decl_base &r, change_kind *k)
Compares two instances of decl_base.
Definition: abg-ir.cc:5276
bool has_basic_or_class_type_name_change(const diff *d)
Test if a diff node carries a basic or class type name change.
virtual void report(ostream &out, const string &indent="") const
Report the diff in a serialized form.
union_decl_sptr first_union_decl() const
void categorize_redundancy(diff *diff_tree)
Walk a given diff sub-tree to categorize each of the nodes with respect to the REDUNDANT_CATEGORY.
virtual void chain_into_hierarchy()
Populate the vector of children node of the diff base type sub-object of this instance of typedef_dif...
void apply_filters_and_compute_diff_stats(corpus_diff::diff_stats &)
Compute the diff stats.
size_t num_changed_unreachable_types() const
Getter of the number of changed types that are unreachable from the public interface of the ABI corpu...
The abstraction of a typedef declaration.
Definition: abg-ir.h:2824
std::vector< filter_base_sptr > filters
Convenience typedef for a vector of filter_base_sptr.
const diff_sptr underlying_type_diff() const
Getter for the diff between the two underlying types of the typedefs.
const vector< type_base_sptr > & added_unreachable_types_sorted() const
Getter of a sorted vector of added types that are not reachable from global functions/variables.
const string & get_id_string() const
Get a string that is representative of a given elf_symbol.
Definition: abg-ir.cc:2437
void set_visiting_kind(visiting_kind v)
Setter for the visiting policy of the traversing code while invoking this visitor.
artifact_sptr_set_type * lookup_impacted_interfaces(const diff *d) const
Lookup the interfaces that are impacted by a given leaf diff node.
vector< base_spec_sptr > base_specs
Convenience typedef.
Definition: abg-ir.h:4183
void count_unreachable_types(size_t &num_added, size_t &num_removed, size_t &num_changed, size_t &num_filtered_added, size_t &num_filtered_removed, size_t &num_filtered_changed)
Count the number of types not reachable from the interface (i.e, not reachable from global functions ...
This is a document class that aims to capture statistics about the changes carried by a corpus_diff t...
virtual bool has_changes() const
Return true iff the current diff node carries a change.
bool visiting_a_node_twice_is_forbidden() const
Return a flag that, if true, then during the traversing of a diff nodes tree each node is visited at ...
const union_diff * is_union_diff(const diff *diff)
Test if a diff node is a union_diff node.
virtual const string & get_pretty_representation() const
void print_diff_tree(diff *diff_tree, ostream &out)
Emit a textual representation of a diff sub-tree to an output stream.
diff_maps & get_leaf_diffs()
Get the set of maps that contain leaf nodes. A leaf node being a node with a local change...
The internal type for the impl idiom implementation of var_diff.
A diff node in this category is a function return type with a cv-qualifier change.
array_diff(const array_type_def_sptr first, const array_type_def_sptr second, diff_sptr element_type_diff, diff_context_sptr ctxt=diff_context_sptr())
Constructor for array_diff.
const string_diff_ptr_map & get_fn_parm_diff_map() const
Getter of the map that contains function parameter diffs.
reference_diff(const reference_type_def_sptr first, const reference_type_def_sptr second, diff_sptr underlying, diff_context_sptr ctxt=diff_context_sptr())
Constructor for reference_diff.
shared_ptr< diff > diff_sptr
Convenience typedef for a shared_ptr for the diff class.
Definition: abg-fwd.h:76
shared_ptr< reporter_base > reporter_base_sptr
A convenience typedef for a shared pointer to a reporter_base.
Definition: abg-reporter.h:49
enum_diff(const enum_type_decl_sptr, const enum_type_decl_sptr, const diff_sptr, diff_context_sptr ctxt=diff_context_sptr())
Constructor for enum_diff.
friend function_type_diff_sptr compute_diff(const function_type_sptr first, const function_type_sptr second, diff_context_sptr ctxt)
Compute the diff between two instances of function_type.
const vector< type_base_sptr > & deleted_unreachable_types_sorted() const
Getter of a sorted vector of deleted types that are not reachable from global functions/variables.
const distinct_diff * is_distinct_diff(const diff *diff)
Test if a diff node is about differences between two diff nodes of different kinds.
distinct_diff_sptr compute_diff_for_distinct_kinds(const type_or_decl_base_sptr first, const type_or_decl_base_sptr second, diff_context_sptr ctxt)
Try to diff entities that are of distinct kinds.
const diff * peel_pointer_diff(const diff *dif)
If a diff node is about changes between two pointer types, get the diff node about changes between th...
reporter_base_sptr get_reporter() const
Getter of the reporter to be used in this context.
size_t net_num_leaf_func_changes() const
Getter for the net number of leaf function change diff nodes.
unordered_map< string, function_decl * > string_function_ptr_map
Convenience typedef for a map which key is a string and which value is a pointer to decl_base...
class_decl::base_spec_sptr base_has_changed(class_decl::base_spec_sptr) const
Test whether a given base class has changed. A base class has changed if it's in both in deleted *and...
var_diff(var_decl_sptr first, var_decl_sptr second, diff_sptr type_diff, diff_context_sptr ctxt=diff_context_sptr())
Constructor for var_diff.
void sort_artifacts_set(const artifact_sptr_set_type &set, vector< type_or_decl_base_sptr > &sorted)
Sort the set of ABI artifacts contained in a artifact_sptr_set_type.
shared_ptr< subrange_type > subrange_sptr
Convenience typedef for a shared pointer on a function_decl::subrange.
Definition: abg-ir.h:2469
virtual void report(ostream &, const string &indent="") const
Emit a textual report about the current fn_parm_diff instance.
shared_ptr< array_type_def > array_type_def_sptr
Convenience typedef for a shared pointer on a array_type_def.
Definition: abg-fwd.h:234
bool is_diff_of_variadic_parameter_type(const diff *d)
Test if a diff node represents the difference between a variadic parameter type and something else...
shared_ptr< pointer_type_def > pointer_type_def_sptr
Convenience typedef for a shared pointer on a pointer_type_def.
Definition: abg-fwd.h:220
visiting_kind operator~(visiting_kind l)
The overloaded 'bit inversion' operator for visiting_kind.
virtual const string & get_pretty_representation() const
bool architecture_changed() const
Test if the architecture of the underlying corpus has changed.
method_type_sptr is_method_type(const type_or_decl_base_sptr &t)
Test whether a type is a method_type.
Definition: abg-ir.cc:11197
bool is_decl_only_class_with_size_change(const class_or_union &first, const class_or_union &second)
Test if two classes that are decl-only (have the decl-only flag and carry no data members) but are di...
Abstraction of a diff between two function types.
virtual enum change_kind has_local_changes() const
class_diff(class_decl_sptr first_scope, class_decl_sptr second_scope, diff_context_sptr ctxt=diff_context_sptr())
Constructor of class_diff.
const class_diff_sptr get_underlying_class_diff() const
Getter for the diff object for the diff of the underlying base classes.
string get_pretty_representation(diff *d)
Get a copy of the pretty representation of a diff node.
shared_ptr< filter_base > filter_base_sptr
Convenience typedef for a shared pointer to filter_base.
const array_type_def_sptr first_array() const
Getter for the first array of the diff.
virtual const string & get_pretty_representation() const
const base_diff_sptrs_type & changed_bases()
Getter for the changed base classes of the diff.
const diff_sptr return_type_diff() const
Getter for the diff of the return types of the two function types of the current diff.
void ensure_lookup_tables_populated(void) const
If the lookup tables are not yet built, walk the differences and fill them.
A comparison functor for instances of function_decl_diff that represent changes between two virtual m...
const string_type_base_sptr_map & deleted_unreachable_types() const
Getter for a map of deleted types that are not reachable from global functions/variables.
const diff_context_sptr context() const
Getter of the context of the current diff.
Abstraction of a function type.
Definition: abg-ir.h:3322
virtual void finish_diff_type()
Finish the insertion of a diff tree node into the diff graph.
const enum_type_decl_sptr second_enum() const
void sort_string_function_ptr_map(const string_function_ptr_map &map, vector< function_decl * > &sorted)
Sort an instance of string_function_ptr_map map and stuff a resulting sorted vector of pointers to fu...
size_t num_removed_func_filtered_out() const
Getter for the number of removed functions that have been filtered out.
const class_or_union_diff::priv_ptr & get_priv() const
Getter of the private data of the class_or_union_diff type.
void add_diff_filter(filtering::filter_base_sptr)
Setter for the diff filters to apply to a given diff sub-tree.
bool stop()
Stop the timer.
const vector< diff_sptr > & changed_unreachable_types_sorted() const
Get the sorted vector of diff nodes representing changed unreachable types.
size_t num_func_syms_removed() const
Getter for the number of function symbols (not referenced by any debug info) that got removed...
const unsigned_var_diff_sptr_map & changed_data_members() const
Getter of the map of data members that got replaced by another data member. The key of the map is the...
diff_category add_to_local_category(diff_category c)
Adds the current diff tree node to the categories resulting from the local changes of the current dif...
This means that a diff node in the sub-tree carries an addition or removal of a static data member...