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 
18 #include "abg-comparison-priv.h"
19 #include "abg-reporter-priv.h"
20 #include "abg-tools-utils.h"
21 
22 namespace abigail
23 {
24 
25 namespace comparison
26 {
27 
28 ///
29 ///
30 ///@defgroup DiffNode Internal Representation of the comparison engine
31 /// @{
32 ///
33 /// @brief How changes are represented in libabigail's comparison engine.
34 ///
35 ///@par diff nodes
36 ///
37 /// The internal representation of the comparison engine is basically
38 /// a graph of @ref instances of @ref diff node. We refer to these
39 /// just as <em>diff nodes</em>. A diff node represents a change
40 /// between two ABI artifacts represented by instances of types of the
41 /// abigail::ir namespace. These two artifacts that are being
42 /// compared are called the <em>subjects of the diff</em>.
43 ///
44 /// The types of that IR are in the abigail::comparison namespace.
45 ///
46 ///@par comparing diff nodes
47 ///
48 /// Comparing two instances of @ref diff nodes amounts to comparing
49 /// the subject of the diff. In other words, two @ref diff nodes are
50 /// equal if and only if their subjects are equal. Thus, two @ref
51 /// diff nodes can have different memory addresses and yet be equal.
52 ///
53 ///@par diff reporting and context
54 ///
55 /// A diff node can be serialized to an output stream to express, in
56 /// a human-readable textual form, the different changes that exist
57 /// between its two subjects. This is done by invoking the
58 /// diff::report() method. That reporting is controlled by several
59 /// parameters that are conceptually part of the context of the diff.
60 /// That context is materialized by an instance of the @ref
61 /// diff_context type.
62 ///
63 /// Please note that the role of the instance(s) of @ref diff_context
64 /// is boreader than just controlling the reporting of @ref diff
65 /// nodes. Basically, a @ref diff node itself is created following
66 /// behaviours that are controlled by a particular instance of
67 /// diff_context. A diff node is created in a particular diff
68 /// context, so to speak.
69 ///
70 /// @}
71 ///
72 
73 ///
74 ///@defgroup CanonicalDiff Canonical diff tree nodes
75 /// @{
76 ///
77 /// @brief How equivalent diff nodes are quickly spotted.
78 ///
79 /// @par Equivalence of diff nodes.
80 ///
81 /// Each @ref diff node has a property named <em>Canonical Diff
82 /// Node</em>. If \c D is a diff node, the canonical diff node of @c
83 /// D, noted @c C(D) is a particular diff node that is equal to @c D.
84 /// Thus, a fast way to compare two @ref diff node is to perform a
85 /// pointer comparison of their canonical diff nodes.
86 ///
87 /// A set of equivalent @ref diff nodes is a set of diff nodes that
88 /// all have the same canonical node. All the nodes of that set are
89 /// equal.
90 ///
91 /// A canonical node is registereded for a given diff node by invoking
92 /// the method diff_context::initialize_canonical_diff().
93 ///
94 /// Please note that the diff_context holds all the canonical diffs
95 /// that got registered through it. Thus, the life time of all of
96 /// canonical diff objects is the same as the life time of the @ref
97 /// diff_context they relate to.
98 ///
99 /// @}
100 ///
101 
102 // -----------------------------------------
103 // <private functions re-usable elsewhere>
104 // -----------------------------------------
105 /// Sort a map of enumerators by their value.
106 ///
107 /// @param enumerators_map the map to sort.
108 ///
109 /// @param sorted the resulting vector of sorted enumerators.
110 void
113 {
114  for (string_enumerator_map::const_iterator i = enumerators_map.begin();
115  i != enumerators_map.end();
116  ++i)
117  sorted.push_back(i->second);
119  std::sort(sorted.begin(), sorted.end(), comp);
120 }
121 
122 /// Sort a map of changed enumerators.
123 ///
124 /// @param enumerators_map the map to sort.
125 ///
126 ///@param output parameter. The resulting sorted enumerators.
127 void
129  changed_enumerators_type& sorted)
130 {
131  for (string_changed_enumerator_map::const_iterator i =
132  enumerators_map.begin();
133  i != enumerators_map.end();
134  ++i)
135  sorted.push_back(i->second);
136 
138  std::sort(sorted.begin(), sorted.end(), comp);
139 }
140 
141 /// Sort a map of data members by the offset of their initial value.
142 ///
143 /// @param data_members the map of changed data members to sort.
144 ///
145 /// @param sorted the resulting vector of sorted changed data members.
146 void
148  vector<decl_base_sptr>& sorted)
149 {
150  sorted.reserve(data_members.size());
151  for (string_decl_base_sptr_map::const_iterator i = data_members.begin();
152  i != data_members.end();
153  ++i)
154  sorted.push_back(i->second);
155 
156  data_member_comp comp;
157  std::sort(sorted.begin(), sorted.end(), comp);
158 }
159 
160 /// Sort (in place) a vector of changed data members.
161 ///
162 /// @param to_sort the vector to sort.
163 void
165 {
166  data_member_comp comp;
167  std::sort(to_sort.begin(), to_sort.end(), comp);
168 }
169 
170 /// Sort an instance of @ref string_function_ptr_map map and stuff a
171 /// resulting sorted vector of pointers to function_decl.
172 ///
173 /// @param map the map to sort.
174 ///
175 /// @param sorted the resulting sorted vector.
176 void
178  vector<function_decl*>& sorted)
179 {
180  sorted.reserve(map.size());
181  for (string_function_ptr_map::const_iterator i = map.begin();
182  i != map.end();
183  ++i)
184  sorted.push_back(i->second);
185 
186  function_comp comp;
187  std::sort(sorted.begin(), sorted.end(), comp);
188 }
189 
190 /// Sort a map that's an instance of @ref
191 /// string_member_function_sptr_map and fill a vector of member
192 /// functions with the sorted result.
193 ///
194 /// @param map the map to sort.
195 ///
196 /// @param sorted the resulting sorted vector.
197 void
200 {
201  sorted.reserve(map.size());
202  for (string_member_function_sptr_map::const_iterator i = map.begin();
203  i != map.end();
204  ++i)
205  sorted.push_back(i->second);
206 
207  function_comp comp;
208  std::sort(sorted.begin(), sorted.end(), comp);
209 }
210 
211 /// Sort the values of a @ref string_function_decl_diff_sptr_map map
212 /// and store the result in a vector of @ref function_decl_diff_sptr
213 /// objects.
214 ///
215 /// @param map the map whose values to store.
216 ///
217 /// @param sorted the vector of function_decl_diff_sptr to store the
218 /// result of the sort into.
219 void
223 {
224  sorted.reserve(map.size());
225  for (string_function_decl_diff_sptr_map::const_iterator i = map.begin();
226  i != map.end();
227  ++i)
228  sorted.push_back(i->second);
230  std::sort(sorted.begin(), sorted.end(), comp);
231 }
232 
233 /// Sort of an instance of @ref string_var_diff_sptr_map map.
234 ///
235 /// @param map the input map to sort.
236 ///
237 /// @param sorted the ouptut sorted vector of @ref var_diff_sptr.
238 /// It's populated with the sorted content.
239 void
241  var_diff_sptrs_type& sorted)
242 {
243  sorted.reserve(map.size());
244  for (string_var_diff_sptr_map::const_iterator i = map.begin();
245  i != map.end();
246  ++i)
247  sorted.push_back(i->second);
248 
249  var_diff_sptr_comp comp;
250  std::sort(sorted.begin(), sorted.end(), comp);
251 }
252 
253 /// Sort a map of string -> pointer to @ref elf_symbol.
254 ///
255 /// The result is a vector of @ref elf_symbol_sptr sorted by the
256 /// name of the symbol.
257 ///
258 /// @param map the map to sort.
259 ///
260 /// @param sorted out parameter; the sorted vector of @ref
261 /// elf_symbol_sptr.
262 void
264  vector<elf_symbol_sptr>& sorted)
265 {
266  for (string_elf_symbol_map::const_iterator i = map.begin();
267  i!= map.end();
268  ++i)
269  sorted.push_back(i->second);
270 
271  elf_symbol_comp comp;
272  std::sort(sorted.begin(), sorted.end(), comp);
273 }
274 
275 /// Sort a map of string -> pointer to @ref var_decl.
276 ///
277 /// The result is a vector of var_decl* sorted by the qualified name
278 /// of the variables.
279 ///
280 /// @param map the map to sort.
281 ///
282 /// @param sorted out parameter; the sorted vector of @ref var_decl.
283 void
285  vector<var_decl*>& sorted)
286 {
287  for (string_var_ptr_map::const_iterator i = map.begin();
288  i != map.end();
289  ++i)
290  sorted.push_back(i->second);
291 
292  var_comp comp;
293  std::sort(sorted.begin(), sorted.end(), comp);
294 }
295 
296 /// Sort the values of a string_var_diff_sptr_map and store the result
297 /// in a vector of var_diff_sptr.
298 ///
299 /// @param map the map of changed data members to sort.
300 ///
301 /// @param sorted the resulting vector of var_diff_sptr.
302 void
304  var_diff_sptrs_type& sorted)
305 {
306  sorted.reserve(map.size());
307  for (string_var_diff_sptr_map::const_iterator i = map.begin();
308  i != map.end();
309  ++i)
310  sorted.push_back(i->second);
312  std::sort(sorted.begin(), sorted.end(), comp);
313 }
314 
315 /// Sort the values of a unsigned_var_diff_sptr_map map and store the
316 /// result into a vector of var_diff_sptr.
317 ///
318 /// @param map the map of changed data members to sort.
319 ///
320 /// @param sorted the resulting vector of sorted var_diff_sptr.
321 void
323  var_diff_sptrs_type& sorted)
324 {
325  sorted.reserve(map.size());
326  for (unsigned_var_diff_sptr_map::const_iterator i = map.begin();
327  i != map.end();
328  ++i)
329  sorted.push_back(i->second);
331  std::sort(sorted.begin(), sorted.end(), comp);
332 }
333 
334 /// Sort an map of string -> virtual member function into a vector of
335 /// virtual member functions. The virtual member functions are sorted
336 /// by increasing order of their virtual index.
337 ///
338 /// @param map the input map.
339 ///
340 /// @param sorted the resulting sorted vector of virtual function
341 /// member.
342 void
346 {
347  sorted.reserve(map.size());
348  for (string_function_decl_diff_sptr_map::const_iterator i = map.begin();
349  i != map.end();
350  ++i)
351  sorted.push_back(i->second);
352 
354  sort(sorted.begin(), sorted.end(), comp);
355 }
356 
357 /// Sort a map ofg string -> @ref diff_sptr into a vector of @ref
358 /// diff_sptr. The diff_sptr are sorted lexicographically wrt
359 /// qualified names of their first subjects.
360 ///
361 /// @param map the map to sort.
362 ///
363 /// @param sorted the resulting sorted vector.
364 void
366  diff_sptrs_type& sorted)
367 {
368  sorted.reserve(map.size());
369  for (string_diff_sptr_map::const_iterator i = map.begin();
370  i != map.end();
371  ++i)
372  sorted.push_back(i->second);
373 
374  diff_comp comp;
375  sort(sorted.begin(), sorted.end(), comp);
376 }
377 
378 /// Sort a map ofg string -> @ref diff* into a vector of @ref
379 /// diff_ptr. The diff_ptr are sorted lexicographically wrt
380 /// qualified names of their first subjects.
381 ///
382 /// @param map the map to sort.
383 ///
384 /// @param sorted the resulting sorted vector.
385 void
387  diff_ptrs_type& sorted)
388 {
389  sorted.reserve(map.size());
390  for (string_diff_ptr_map::const_iterator i = map.begin();
391  i != map.end();
392  ++i)
393  sorted.push_back(i->second);
394 
395  diff_comp comp;
396  sort(sorted.begin(), sorted.end(), comp);
397 }
398 
399 /// Sort a map of string -> base_diff_sptr into a sorted vector of
400 /// base_diff_sptr. The base_diff_sptr are sorted by increasing value
401 /// of their offset in their containing type.
402 ///
403 /// @param map the input map to sort.
404 ///
405 /// @param sorted the resulting sorted vector.
406 void
408  base_diff_sptrs_type& sorted)
409 {
410  for (string_base_diff_sptr_map::const_iterator i = map.begin();
411  i != map.end();
412  ++i)
413  sorted.push_back(i->second);
414  base_diff_comp comp;
415  sort(sorted.begin(), sorted.end(), comp);
416 }
417 
418 /// Lexicographically sort base specifications found
419 /// in instances of string_base_sptr_map.
420 void
422  class_decl::base_specs& sorted)
423 {
424  for (string_base_sptr_map::const_iterator i = m.begin();
425  i != m.end();
426  ++i)
427  sorted.push_back(i->second);
428 
429  base_spec_comp comp;
430  std::sort(sorted.begin(), sorted.end(), comp);
431 }
432 
433 /// Sort a map of @ref fn_parm_diff by the indexes of the function
434 /// parameters.
435 ///
436 /// @param map the map to sort.
437 ///
438 /// @param sorted the resulting sorted vector of changed function
439 /// parms.
440 void
442  vector<fn_parm_diff_sptr>& sorted)
443 {
444  sorted.reserve(map.size());
445  for (unsigned_fn_parm_diff_sptr_map::const_iterator i = map.begin();
446  i != map.end();
447  ++i)
448  sorted.push_back(i->second);
449 
450  fn_parm_diff_comp comp;
451  std::sort(sorted.begin(), sorted.end(), comp);
452 }
453 
454 /// Sort a map of changed function parameters by the indexes of the
455 /// function parameters.
456 ///
457 /// @param map the map to sort.
458 ///
459 /// @param sorted the resulting sorted vector of instances of @ref
460 /// fn_parm_diff_sptr
461 void
463  vector<fn_parm_diff_sptr>& sorted)
464 {
465  sorted.reserve(map.size());
466  for (string_fn_parm_diff_sptr_map::const_iterator i = map.begin();
467  i != map.end();
468  ++i)
469  sorted.push_back(i->second);
470 
471  fn_parm_diff_comp comp;
472  std::sort(sorted.begin(), sorted.end(), comp);
473 }
474 
475 /// Sort a map of string -> function parameters.
476 ///
477 /// @param map the map to sort.
478 ///
479 /// @param sorted the resulting sorted vector of
480 /// @ref vector<function_decl::parameter_sptr>
481 void
483  vector<function_decl::parameter_sptr>& sorted)
484 {
485  for (string_parm_map::const_iterator i = map.begin();
486  i != map.end();
487  ++i)
488  sorted.push_back(i->second);
489 
490  parm_comp comp;
491  std::sort(sorted.begin(), sorted.end(), comp);
492 }
493 
494 /// Sort the set of ABI artifacts contained in a @ref
495 /// artifact_sptr_set_type.
496 ///
497 /// @param set the set of ABI artifacts to sort.
498 ///
499 /// @param output parameter the vector containing the sorted ABI
500 /// artifacts.
501 void
503  vector<type_or_decl_base_sptr>& sorted)
504 {
505 
506  for (artifact_sptr_set_type::const_iterator it = set.begin();
507  it != set.end();
508  ++it)
509  sorted.push_back(*it);
510 
512  std::sort(sorted.begin(), sorted.end(), comp);
513 }
514 
515 /// Sort a map of string to type_base_sptr entities.
516 ///
517 /// The entries are sorted based on the lexicographic order of the
518 /// pretty representation of the type_sptr_sptr. The sorted result is
519 /// put in a vector of type_base_sptr.
520 ///
521 /// @param map the map to sort.
522 ///
523 /// @param sorted the resulting vector of type_base_sptr
524 /// lexicographically sorted using their pretty representation.
525 void
527  vector<type_base_sptr>& sorted)
528 {
529  for (string_type_base_sptr_map::const_iterator i = map.begin();
530  i != map.end();
531  ++i)
532  sorted.push_back(i->second);
533 
535  std::sort(sorted.begin(), sorted.end(), comp);
536 }
537 
538 /// Return the first underlying type that is not a qualified type.
539 /// @param t the qualified type to consider.
540 ///
541 /// @return the first underlying type that is not a qualified type, or
542 /// NULL if t is NULL.
543 type_base_sptr
544 get_leaf_type(qualified_type_def_sptr t)
545 {
546  if (!t)
547  return type_base_sptr();
548 
549  type_base_sptr ut = t->get_underlying_type();
550  qualified_type_def_sptr qut = dynamic_pointer_cast<qualified_type_def>(ut);
551 
552  if (!qut)
553  return ut;
554  return get_leaf_type(qut);
555 }
556 
557 /// Tests if a given diff node is to represent the changes between two
558 /// gobal decls.
559 ///
560 /// @param d the diff node to consider.
561 ///
562 /// @return true iff @p d represents the changes between two global
563 /// decls.
564 bool
566 {
567  ABG_ASSERT(d != 0);
568 
569  if (d == 0)
570  return false;
571 
573  ABG_ASSERT(first);
574 
576  ABG_ASSERT(second);
577 
578  if (decl_base_sptr decl = is_decl(first))
579  if (is_at_global_scope(decl))
580  if ((decl = is_decl(second)))
581  if (is_at_global_scope(decl))
582  return true;
583 
584  return false;
585 }
586 
587 // -----------------------------------------
588 // </private functions re-usable elsewhere>
589 // -----------------------------------------
590 
591 /// The overloaded or operator for @ref visiting_kind.
594 {return static_cast<visiting_kind>(static_cast<unsigned>(l)
595  | static_cast<unsigned>(r));}
596 
597 /// The overloaded and operator for @ref visiting_kind.
600 {
601  return static_cast<visiting_kind>(static_cast<unsigned>(l)
602  & static_cast<unsigned>(r));
603 }
604 
605 /// The overloaded 'bit inversion' operator for @ref visiting_kind.
608 {return static_cast<visiting_kind>(~static_cast<unsigned>(l));}
609 
610 /// Test if a diff node is about differences between types.
611 ///
612 /// @param diff the diff node to test.
613 ///
614 /// @return a pointer to the actual type_diff_base* that @p diff
615 /// extends, iff it is about differences between types.
616 const type_diff_base*
618 {return dynamic_cast<const type_diff_base*>(diff);}
619 
620 /// Test if a diff node is about differences between declarations.
621 ///
622 /// @param diff the diff node to test.
623 ///
624 /// @return a pointer to the actual decl_diff_base @p diff extends,
625 /// iff it is about differences between declarations.
626 const decl_diff_base*
628 {return dynamic_cast<const decl_diff_base*>(diff);}
629 
630 /// Test if a diff node is a @ref class_diff node.
631 ///
632 /// @param diff the diff node to consider.
633 ///
634 /// @return a non-nil pointer to a @ref class_diff iff @p diff is a
635 /// @ref class_diff node.
636 const class_diff*
638 {return dynamic_cast<const class_diff*>(diff);}
639 
640 /// Test if a diff node is a @ref enum_diff node.
641 ///
642 /// @param diff the diff node to consider.
643 ///
644 /// @return a non-nil pointer to ad @ref enum_diff node iff @p diff is
645 /// a @ref enum_diff node.
646 const enum_diff*
648 {return dynamic_cast<const enum_diff*>(diff);}
649 
650 /// Test if a diff node is a @ref union_diff node.
651 ///
652 /// @param diff the diff node to consider.
653 ///
654 /// @return a non-nil pointer to a @ref union_diff iff @p diff is a
655 /// @ref union_diff node.
656 const union_diff*
658 {return dynamic_cast<const union_diff*>(diff);}
659 
660 /// Test if a diff node is a @ref class_or_union_diff node.
661 ///
662 /// @param d the diff node to consider.
663 ///
664 /// @return a non-nil pointer to the @ref class_or_union_diff denoted
665 /// by @p d iff @p d is a @ref class_or_union_diff.
666 const class_or_union_diff*
668 {return dynamic_cast<const class_or_union_diff*>(d);}
669 
670 /// Test if a diff node is a @ref class_or_union_diff between two
671 /// anonymous classes or unions.
672 ///
673 /// @param d the diff node to consider.
674 ///
675 /// @return a non-nil pointer to the @ref class_or_union_diff iff @p
676 /// denoted by @p d iff @p is pointer to an anonymous class or union
677 /// diff.
678 const class_or_union_diff*
680 {
681  if (const class_or_union_diff *dif = is_class_or_union_diff(d))
682  if (dif->first_class_or_union()->get_is_anonymous())
683  return dif;
684  return 0;
685 }
686 
687 /// Test if a diff node is a @ref typedef_diff node.
688 ///
689 /// @param diff the diff node to consider.
690 ///
691 /// @return a non-nil pointer to a @ref typedef_diff iff @p diff is a
692 /// @ref typedef_diff node.
693 const typedef_diff*
695 {return dynamic_cast<const typedef_diff*>(diff);}
696 
697 /// Test if a diff node is a @ref subrange_diff node.
698 ///
699 /// @param diff the diff node to consider.
700 ///
701 /// @return a non-nil pointer to a @ref subrange_diff iff @p diff is a
702 /// @ref subrange_diff node.
703 const subrange_diff*
705 {return dynamic_cast<const subrange_diff*>(diff);}
706 
707 /// Test if a diff node is a @ref array_diff node.
708 ///
709 /// @param diff the diff node to consider.
710 ///
711 /// @return a non-nil pointer to a @ref array_diff iff @p diff is a
712 /// @ref array_diff node.
713 const array_diff*
715 {return dynamic_cast<const array_diff*>(diff);}
716 
717 /// Test if a diff node is a @ref function_type_diff node.
718 ///
719 /// @param diff the diff node to consider.
720 ///
721 /// @return a non-nil pointer to a @ref function_type_diff iff @p diff is a
722 /// @ref function_type_diff node.
723 const function_type_diff*
725 {return dynamic_cast<const function_type_diff*>(diff);}
726 
727 /// Test if a given diff node carries a function type change with
728 /// local changes.
729 ///
730 /// @param diff the diff node to consider.
731 ///
732 /// @return a non-nil pointer to a @ref function_type_diff iff @p diff
733 /// is a function_type_diff node that carries a local change.
734 const function_type_diff*
736 {
738  if (d->has_local_changes())
739  return d;
740 
741  return 0;
742 }
743 
744 /// Test if a diff node is about differences between variables.
745 ///
746 /// @param diff the diff node to test.
747 ///
748 /// @return a pointer to the actual var_diff that @p diff is a type
749 /// of, iff it is about differences between variables.
750 const var_diff*
752 {
753  const var_diff* d = dynamic_cast<const var_diff*>(diff);
754  if (d)
756  return d;
757 }
758 
759 /// Test if a diff node is about differences between functions.
760 ///
761 /// @param diff the diff node to test.
762 ///
763 /// @return a pointer to the actual var_diff that @p diff is a type
764 /// of, iff it is about differences between variables.
765 const function_decl_diff*
767 {
768  const function_decl_diff *d = dynamic_cast<const function_decl_diff*>(diff);
769  if (d)
771  return d;
772 }
773 
774 /// Test if a diff node is about differences between two pointers.
775 ///
776 /// @param diff the diff node to consider.
777 ///
778 /// @return the @p diff converted into an instance of @ref
779 /// pointer_diff iff @p diff is about differences between two
780 /// pointers.
781 const pointer_diff*
783 {return dynamic_cast<const pointer_diff*>(diff);}
784 
785 /// Test if a diff node is about differences between two references.
786 ///
787 /// @param diff the diff node to consider.
788 ///
789 /// @return the @p diff converted into an instance of @ref
790 /// reference_diff iff @p diff is about differences between two
791 /// references.
792 const reference_diff*
794 {return dynamic_cast<const reference_diff*>(diff);}
795 
796 /// Test if a diff node is about differences between two qualified
797 /// types.
798 ///
799 /// @param diff the diff node to consider.
800 ///
801 /// @return @p diff converted into an instance of @ref
802 /// qualified_type_diff iff @p diff is about differences between two
803 /// qualified types.
804 const qualified_type_diff*
806 {return dynamic_cast<const qualified_type_diff*>(diff);}
807 
808 /// Test if a diff node is a reference or pointer diff node to a
809 /// change that is neither basic type change nor distinct type change.
810 ///
811 /// Note that this function also works on diffs of typedefs of
812 /// reference or pointer.
813 ///
814 /// @param diff the diff node to consider.
815 ///
816 /// @return true iff @p diff is a eference or pointer diff node to a
817 /// change that is neither basic type change nor distinct type change.
818 bool
820 {
822  if (const reference_diff* d = is_reference_diff(diff))
823  {
826  return false;
827  return true;
828  }
829  else if (const pointer_diff *d = is_pointer_diff(diff))
830  {
831  diff = peel_pointer_diff(d);
833  return false;
834  return true;
835  }
836 
837  return false;
838 }
839 
840 /// Test if a diff node is about differences between two function
841 /// parameters.
842 ///
843 /// @param diff the diff node to consider.
844 ///
845 /// @return the @p diff converted into an instance of @ref
846 /// reference_diff iff @p diff is about differences between two
847 /// function parameters.
848 const fn_parm_diff*
850 {return dynamic_cast<const fn_parm_diff*>(diff);}
851 
852 /// Test if a diff node is about differences between two base class
853 /// specifiers.
854 ///
855 /// @param diff the diff node to consider.
856 ///
857 /// @return the @p diff converted into an instance of @ref base_diff
858 /// iff @p diff is about differences between two base class
859 /// specifiers.
860 const base_diff*
862 {return dynamic_cast<const base_diff*>(diff);}
863 
864 /// Test if a diff node is about differences between two diff nodes of
865 /// different kinds.
866 ///
867 /// @param diff the diff node to consider.
868 ///
869 /// @return the @p diff converted into an instance of @ref
870 /// distintc_diff iff @p diff is about differences between two diff
871 /// nodes of different kinds.
872 const distinct_diff*
874 {return dynamic_cast<const distinct_diff*>(diff);}
875 
876 /// Test if a diff node is a @ref corpus_diff node.
877 ///
878 /// @param diff the diff node to consider.
879 ///
880 /// @return a non-nil pointer to a @ref corpus_diff iff @p diff is a
881 /// @ref corpus_diff node.
882 const corpus_diff*
884 {return dynamic_cast<const corpus_diff*>(diff);}
885 
886 /// Test if a diff node is a child node of a function parameter diff node.
887 ///
888 /// @param diff the diff node to test.
889 ///
890 /// @return true iff @p diff is a child node of a function parameter
891 /// diff node.
892 bool
894 {return diff && is_fn_parm_diff(diff->parent_node());}
895 
896 /// Test if a diff node is a child node of a base diff node.
897 ///
898 /// @param diff the diff node to test.
899 ///
900 /// @return true iff @p diff is a child node of a base diff node.
901 bool
903 {return diff && is_base_diff(diff->parent_node());}
904 
905 /// The default traverse function.
906 ///
907 /// @return true.
908 bool
910 {return true;}
911 
912 diff_context::diff_context()
913  : priv_(new diff_context::priv)
914 {
915  // Setup all the diff output filters we have.
917 
919  add_diff_filter(f);
920 
921  // f.reset(new filtering::harmless_filter);
922  // add_diff_filter(f);
923 
924  // f.reset(new filtering::harmful_filter);
925  // add_diff_filter(f);
926 }
927 
928 diff_context::~diff_context() = default;
929 
930 /// Test if logging was requested.
931 ///
932 /// @return true iff logging was requested.
933 bool
935 {return priv_->do_log_;}
936 
937 /// Set logging as requested.
938 ///
939 /// @param f the flag
940 void
942 {priv_->do_log_ = f;}
943 
944 /// Set the corpus diff relevant to this context.
945 ///
946 /// @param d the corpus_diff we are interested in.
947 void
949 {priv_->corpus_diff_ = d;}
950 
951 /// Get the corpus diff for the current context.
952 ///
953 /// @return the corpus diff of this context.
954 const corpus_diff_sptr&
956 {return priv_->corpus_diff_;}
957 
958 /// Getter for the first corpus of the corpus diff of the current context.
959 ///
960 /// @return the first corpus of the corpus diff of the current
961 /// context, if no corpus diff is associated to the context.
962 corpus_sptr
964 {
965  if (priv_->corpus_diff_)
966  return priv_->corpus_diff_->first_corpus();
967  return corpus_sptr();
968 }
969 
970 /// Getter for the second corpus of the corpus diff of the current
971 /// context.
972 ///
973 /// @return the second corpus of the corpus diff of the current
974 /// context, if no corpus diff is associated to the context.
975 corpus_sptr
977 {
978  if (priv_->corpus_diff_)
979  return priv_->corpus_diff_->second_corpus();
980  return corpus_sptr();
981 }
982 
983 /// Getter of the reporter to be used in this context.
984 ///
985 /// @return the reporter to be used in this context.
988 {
989  if (!priv_->reporter_)
990  {
992  priv_->reporter_.reset(new leaf_reporter);
993  else
994  priv_->reporter_.reset(new default_reporter);
995  }
996  ABG_ASSERT(priv_->reporter_);
997  return priv_->reporter_;
998 }
999 
1000 /// Setter of the reporter to be used in this context.
1001 ///
1002 /// @param r the reporter to be used in this context.
1003 void
1005 {priv_->reporter_ = r;}
1006 
1007 /// Tests if the current diff context already has a diff for two decls.
1008 ///
1009 /// @param first the first decl to consider.
1010 ///
1011 /// @param second the second decl to consider.
1012 ///
1013 /// @return a pointer to the diff for @p first @p second if found,
1014 /// null otherwise.
1015 diff_sptr
1016 diff_context::has_diff_for(const type_or_decl_base_sptr first,
1017  const type_or_decl_base_sptr second) const
1018 {
1019  types_or_decls_diff_map_type::const_iterator i =
1020  priv_->types_or_decls_diff_map.find(std::make_pair(first, second));
1021  if (i != priv_->types_or_decls_diff_map.end())
1022  return i->second;
1023  return diff_sptr();
1024 }
1025 
1026 /// Tests if the current diff context already has a diff for two types.
1027 ///
1028 /// @param first the first type to consider.
1029 ///
1030 /// @param second the second type to consider.
1031 ///
1032 /// @return a pointer to the diff for @p first @p second if found,
1033 /// null otherwise.
1034 diff_sptr
1035 diff_context::has_diff_for_types(const type_base_sptr first,
1036  const type_base_sptr second) const
1037 {return has_diff_for(first, second);}
1038 
1039 /// Tests if the current diff context already has a given diff.
1040 ///
1041 ///@param d the diff to consider.
1042 ///
1043 /// @return a pointer to the diff found for @p d
1044 const diff*
1045 diff_context::has_diff_for(const diff* d) const
1046 {return has_diff_for(d->first_subject(), d->second_subject()).get();}
1047 
1048 /// Tests if the current diff context already has a given diff.
1049 ///
1050 ///@param d the diff to consider.
1051 ///
1052 /// @return a pointer to the diff found for @p d
1053 diff_sptr
1054 diff_context::has_diff_for(const diff_sptr d) const
1055 {return has_diff_for(d->first_subject(), d->second_subject());}
1056 
1057 /// Getter for the bitmap that represents the set of categories that
1058 /// the user wants to see reported.
1059 ///
1060 /// @return a bitmap that represents the set of categories that the
1061 /// user wants to see reported.
1064 {return priv_->allowed_category_;}
1065 
1066 /// Setter for the bitmap that represents the set of categories that
1067 /// the user wants to see reported.
1068 ///
1069 /// @param c a bitmap that represents the set of categories that the
1070 /// user wants to see represented.
1071 void
1073 {priv_->allowed_category_ = c;}
1074 
1075 /// Setter for the bitmap that represents the set of categories that
1076 /// the user wants to see reported
1077 ///
1078 /// This function perform a bitwise or between the new set of
1079 /// categories and the current ones, and then sets the current
1080 /// categories to the result of the or.
1081 ///
1082 /// @param c a bitmap that represents the set of categories that the
1083 /// user wants to see represented.
1084 void
1086 {priv_->allowed_category_ = priv_->allowed_category_ | c;}
1087 
1088 /// Setter for the bitmap that represents the set of categories that
1089 /// the user wants to see reported
1090 ///
1091 /// This function actually unsets bits from the current categories.
1092 ///
1093 /// @param c a bitmap that represents the set of categories to unset
1094 /// from the current categories.
1095 void
1097 {priv_->allowed_category_ = priv_->allowed_category_ & ~c;}
1098 
1099 /// Add a diff for two decls to the cache of the current diff_context.
1100 ///
1101 /// Doing this allows to later find the added diff from its two
1102 /// subject decls.
1103 ///
1104 /// @param first the first decl to consider.
1105 ///
1106 /// @param second the second decl to consider.
1107 ///
1108 /// @param the diff to add.
1109 void
1110 diff_context::add_diff(type_or_decl_base_sptr first,
1111  type_or_decl_base_sptr second,
1112  const diff_sptr d)
1113 {priv_->types_or_decls_diff_map[std::make_pair(first, second)] = d;}
1114 
1115 /// Add a diff tree node to the cache of the current diff_context
1116 ///
1117 /// @param d the diff tree node to add.
1118 void
1119 diff_context::add_diff(const diff* d)
1120 {
1121  if (d)
1122  {
1123  diff_sptr dif(const_cast<diff*>(d), noop_deleter());
1124  add_diff(d->first_subject(), d->second_subject(), dif);
1125  }
1126 }
1127 
1128 /// Add a diff tree node to the cache of the current diff_context
1129 ///
1130 /// @param d the diff tree node to add.
1131 void
1132 diff_context::add_diff(const diff_sptr d)
1133 {
1134  if (d)
1135  add_diff(d->first_subject(), d->second_subject(), d);
1136 }
1137 
1138 /// Getter for the @ref CanonicalDiff "canonical diff node" for the
1139 /// @ref diff represented by their two subjects.
1140 ///
1141 /// @param first the first subject of the diff.
1142 ///
1143 /// @param second the second subject of the diff.
1144 ///
1145 /// @return the canonical diff for the diff node represented by the
1146 /// two diff subjects @p first and @p second. If no canonical diff
1147 /// node was registered for these subjects, then a nil node is
1148 /// returned.
1149 diff_sptr
1151  const type_or_decl_base_sptr second) const
1152 {return has_diff_for(first, second);}
1153 
1154 /// Getter for the @ref CanonicalDiff "canonical diff node" for the
1155 /// @ref diff represented by the two subjects of a given diff node.
1156 ///
1157 /// @param d the diff node to get the canonical node for.
1158 ///
1159 /// @return the canonical diff for the diff node represented by the
1160 /// two diff subjects of @p d. If no canonical diff node was
1161 /// registered for these subjects, then a nil node is returned.
1162 diff_sptr
1164 {return has_diff_for(d);}
1165 
1166 /// Setter for the @ref CanonicalDiff "canonical diff node" for the
1167 /// @ref diff represented by their two subjects.
1168 ///
1169 /// @param first the first subject of the diff.
1170 ///
1171 /// @param second the second subject of the diff.
1172 ///
1173 /// @param d the new canonical diff.
1174 void
1175 diff_context::set_canonical_diff_for(const type_or_decl_base_sptr first,
1176  const type_or_decl_base_sptr second,
1177  const diff_sptr d)
1178 {
1179  ABG_ASSERT(d);
1180  if (!has_diff_for(first, second))
1181  {
1182  add_diff(first, second, d);
1183  priv_->canonical_diffs.push_back(d);
1184  }
1185 }
1186 
1187 /// If there is is a @ref CanonicalDiff "canonical diff node"
1188 /// registered for two diff subjects, return it. Otherwise, register
1189 /// a canonical diff node for these two diff subjects and return it.
1190 ///
1191 /// @param first the first subject of the diff.
1192 ///
1193 /// @param second the second subject of the diff.
1194 ///
1195 /// @param d the new canonical diff node.
1196 ///
1197 /// @return the canonical diff node.
1198 diff_sptr
1199 diff_context::set_or_get_canonical_diff_for(const type_or_decl_base_sptr first,
1200  const type_or_decl_base_sptr second,
1201  const diff_sptr canonical_diff)
1202 {
1203  ABG_ASSERT(canonical_diff);
1204 
1205  diff_sptr canonical = get_canonical_diff_for(first, second);
1206  if (!canonical)
1207  {
1208  canonical = canonical_diff;
1209  set_canonical_diff_for(first, second, canonical);
1210  }
1211  return canonical;
1212 }
1213 
1214 /// Set the canonical diff node property of a given diff node
1215 /// appropriately.
1216 ///
1217 /// For a given diff node that has no canonical diff node, retrieve
1218 /// the canonical diff node (by looking at its diff subjects and at
1219 /// the current context) and set the canonical diff node property of
1220 /// the diff node to that canonical diff node. If no canonical diff
1221 /// node has been registered to the diff context for the subjects of
1222 /// the diff node then, register the canonical diff node as being the
1223 /// diff node itself; and set its canonical diff node property as
1224 /// such. Otherwise, if the diff node already has a canonical diff
1225 /// node, do nothing.
1226 ///
1227 /// @param diff the diff node to initialize the canonical diff node
1228 /// property for.
1229 void
1231 {
1232  if (diff->get_canonical_diff() == 0)
1233  {
1234  diff_sptr canonical =
1235  set_or_get_canonical_diff_for(diff->first_subject(),
1236  diff->second_subject(),
1237  diff);
1238  diff->set_canonical_diff(canonical.get());
1239  }
1240 }
1241 
1242 /// Add a diff node to the set of diff nodes that are kept alive for
1243 /// the life time of the current instance of diff_context.
1244 ///
1245 /// Note that diff added to the diff cache are kept alive as well, and
1246 /// don't need to be passed to this function to be kept alive.
1247 ///
1248 /// @param d the diff node to be kept alive during the life time of
1249 /// the current instance of @ref diff_context.
1250 void
1252 {priv_->live_diffs_.insert(d);}
1253 
1254 /// Test if a diff node has been traversed.
1255 ///
1256 /// @param d the diff node to consider.
1257 ///
1258 /// @return the first diff node against which @p d is redundant.
1259 diff*
1261 {
1262  const diff* canonical = d->get_canonical_diff();
1263  ABG_ASSERT(canonical);
1264 
1265  size_t ptr_value = reinterpret_cast<size_t>(canonical);
1266  pointer_map::iterator it = priv_->visited_diff_nodes_.find(ptr_value);
1267  if (it != priv_->visited_diff_nodes_.end())
1268  return reinterpret_cast<diff*>(it->second);
1269  else
1270  return 0;
1271 }
1272 
1273 /// Test if a diff node has been traversed.
1274 ///
1275 /// @param d the diff node to consider.
1276 ///
1277 /// @return the first diff node against which @p d is redundant.
1278 diff_sptr
1280 {
1282  return diff;
1283 }
1284 
1285 /// Mark a diff node as traversed by a traversing algorithm.
1286 ///
1287 /// Actually, it's the @ref CanonicalDiff "canonical diff" of this
1288 /// node that is marked as traversed.
1289 ///
1290 /// Subsequent invocations of diff_has_been_visited() on the diff node
1291 /// will yield true.
1292 void
1294 {
1295  if (diff_has_been_visited(d))
1296  return;
1297 
1298  const diff* canonical = d->get_canonical_diff();
1299  ABG_ASSERT(canonical);
1300 
1301  size_t canonical_ptr_value = reinterpret_cast<size_t>(canonical);
1302  size_t diff_ptr_value = reinterpret_cast<size_t>(d);
1303  priv_->visited_diff_nodes_[canonical_ptr_value] = diff_ptr_value;
1304 }
1305 
1306 /// Unmark all the diff nodes that were marked as being traversed.
1307 void
1309 {priv_->visited_diff_nodes_.clear();}
1310 
1311 /// This sets a flag that, if it's true, then during the traversing of
1312 /// a diff nodes tree each node is visited at most once.
1313 ///
1314 /// @param f if true then during the traversing of a diff nodes tree
1315 /// each node is visited at most once.
1316 ///
1317 void
1319 {priv_->forbid_visiting_a_node_twice_ = f;}
1320 
1321 /// This function sets a flag os that if @ref
1322 /// forbid_visiting_a_node_twice() returns true, then each time the
1323 /// node visitor starts visiting a new interface, it resets the
1324 /// memory the systems has about already visited node.
1325 ///
1326 /// @param f the flag to set.
1327 void
1329 {priv_->reset_visited_diffs_for_each_interface_ = f;}
1330 
1331 /// Return a flag that, if true, then during the traversing of a diff
1332 /// nodes tree each node is visited at most once.
1333 ///
1334 /// @return the boolean flag.
1335 bool
1337 {return priv_->forbid_visiting_a_node_twice_;}
1338 
1339 /// Return a flag that, if true, then during the traversing of a diff
1340 /// nodes tree each node is visited at most once, while visiting the
1341 /// diff tree underneath a given interface (public function or
1342 /// variable). Each time a new interface is visited, the nodes
1343 /// visited while visiting previous interfaces can be visited again.
1344 ///
1345 /// @return the boolean flag.
1346 ///
1347 /// @return the boolean flag.
1348 bool
1350 {
1351  return (priv_->forbid_visiting_a_node_twice_
1352  && priv_->reset_visited_diffs_for_each_interface_);
1353 }
1354 
1355 /// Getter for the diff tree nodes filters to apply to diff sub-trees.
1356 ///
1357 /// @return the vector of tree filters to apply to diff sub-trees.
1358 const filtering::filters&
1360 {return priv_->filters_;}
1361 
1362 /// Setter for the diff filters to apply to a given diff sub-tree.
1363 ///
1364 /// @param f the new diff filter to add to the vector of diff filters
1365 /// to apply to diff sub-trees.
1366 void
1368 {priv_->filters_.push_back(f);}
1369 
1370 /// Apply the diff filters to a given diff sub-tree.
1371 ///
1372 /// If the current context is instructed to filter out some categories
1373 /// then this function walks the given sub-tree and categorizes its
1374 /// nodes by using the filters held by the context.
1375 ///
1376 /// @param diff the diff sub-tree to apply the filters to.
1377 void
1379 {
1380  if (!diff)
1381  return;
1382 
1384  return;
1385 
1386  if (!diff->has_changes())
1387  return;
1388 
1389  for (filtering::filters::const_iterator i = diff_filters().begin();
1390  i != diff_filters().end();
1391  ++i)
1392  {
1394  if (do_log())
1395  {
1396  std::cerr << "applying a filter to diff '"
1398  << "'...\n";
1399  t.start();
1400  }
1401 
1403 
1404  if (do_log())
1405  {
1406  t.stop();
1407  std::cerr << "filter applied!:" << t << "\n";
1408 
1409  std::cerr << "propagating categories for the same diff node ... \n";
1410  t.start();
1411  }
1412 
1414 
1415  if (do_log())
1416  {
1417  t.stop();
1418  std::cerr << "category propagated!: " << t << "\n";
1419  }
1420  }
1421 
1422  }
1423 
1424 /// Apply the diff filters to the diff nodes of a @ref corpus_diff
1425 /// instance.
1426 ///
1427 /// If the current context is instructed to filter out some categories
1428 /// then this function walks the diff tree and categorizes its nodes
1429 /// by using the filters held by the context.
1430 ///
1431 /// @param diff the corpus diff to apply the filters to.
1432 void
1434 {
1435 
1436  if (!diff || !diff->has_changes())
1437  return;
1438 
1439  for (filtering::filters::const_iterator i = diff_filters().begin();
1440  i != diff_filters().end();
1441  ++i)
1442  {
1445  }
1446 }
1447 
1448 /// Getter for the vector of suppressions that specify which diff node
1449 /// reports should be dropped on the floor.
1450 ///
1451 /// @return the set of suppressions.
1452 const suppressions_type&
1454 {return priv_->suppressions_;}
1455 
1456 /// Getter for the vector of suppressions that specify which diff node
1457 /// reports should be dropped on the floor.
1458 ///
1459 /// @return the set of suppressions.
1462 {
1463  // Invalidate negated and direct suppressions caches that are built
1464  // from priv_->suppressions_;
1465  priv_->negated_suppressions_.clear();
1466  priv_->direct_suppressions_.clear();
1467  return priv_->suppressions_;
1468 }
1469 
1470 /// Getter of the negated suppression specifications that are
1471 /// comprised in the general vector of suppression specifications
1472 /// returned by diff_context::suppressions().
1473 ///
1474 /// Note that the first invocation of this function scans the vector
1475 /// returned by diff_context::suppressions() and caches the negated
1476 /// suppressions from there.
1477 ///
1478 /// Subsequent invocations of this function just return the cached
1479 /// negated suppressions.
1480 ///
1481 /// @return the negated suppression specifications stored in this diff
1482 /// context.
1485 {
1486  if (priv_->negated_suppressions_.empty())
1487  for (auto s : suppressions())
1488  if (is_negated_suppression(s))
1489  priv_->negated_suppressions_.push_back(s);
1490 
1491  return priv_->negated_suppressions_;
1492 }
1493 
1494 /// Getter of the direct suppression specification (those that are
1495 /// not negated) comprised in the general vector of suppression
1496 /// specifications returned by diff_context::suppression().
1497 ///
1498 /// Note that the first invocation of this function scans the vector
1499 /// returned by diff_context::suppressions() and caches the direct
1500 /// suppressions from there.
1501 ///
1502 /// Subsequent invocations of this function just return the cached
1503 /// direct suppressions.
1504 ///
1505 /// @return the direct suppression specifications.
1508 {
1509  if (priv_->direct_suppressions_.empty())
1510  {
1511  for (auto s : suppressions())
1512  if (!is_negated_suppression(s))
1513  priv_->direct_suppressions_.push_back(s);
1514  }
1515  return priv_->direct_suppressions_;
1516 }
1517 
1518 /// Add a new suppression specification that specifies which diff node
1519 /// reports should be dropped on the floor.
1520 ///
1521 /// @param suppr the new suppression specification to add to the
1522 /// existing set of suppressions specifications of the diff context.
1523 void
1525 {
1526  priv_->suppressions_.push_back(suppr);
1527  // Invalidate negated and direct suppressions caches that are built
1528  // from priv_->suppressions_;
1529  priv_->negated_suppressions_.clear();
1530  priv_->direct_suppressions_.clear();
1531 }
1532 
1533 /// Add new suppression specifications that specify which diff node
1534 /// reports should be dropped on the floor.
1535 ///
1536 /// @param supprs the new suppression specifications to add to the
1537 /// existing set of suppression specifications of the diff context.
1538 void
1540 {
1541  priv_->suppressions_.insert(priv_->suppressions_.end(),
1542  supprs.begin(), supprs.end());
1543 }
1544 
1545 /// Test if it's requested to perform diff node categorization.
1546 ///
1547 /// @return true iff it's requested to perform diff node
1548 /// categorization.
1549 bool
1551 {return priv_->perform_change_categorization_;}
1552 
1553 /// Request change categorization or not.
1554 ///
1555 /// @param f true iff change categorization is requested.
1556 void
1558 {priv_->perform_change_categorization_ = f;}
1559 
1560 /// Set the flag that indicates if the diff using this context should
1561 /// show only leaf changes or not.
1562 ///
1563 /// @param f the new value of the flag that indicates if the diff
1564 /// using this context should show only leaf changes or not.
1565 void
1567 {
1568  // This function can be called only if the reporter hasn't yet been
1569  // created. Once it's been created, we are supposed to live with
1570  // it.
1571  ABG_ASSERT(priv_->reporter_ == 0);
1572  priv_->leaf_changes_only_ = f;
1573 }
1574 
1575 /// Get the flag that indicates if the diff using this context should
1576 /// show only leaf changes or not.
1577 ///
1578 /// @return the value of the flag that indicates if the diff using
1579 /// this context should show only leaf changes or not.
1580 bool
1582 {return priv_->leaf_changes_only_;}
1583 
1584 /// Get the flag that indicates if the diff reports using this context
1585 /// should show sizes and offsets in an hexadecimal base or not. If
1586 /// not, then they are to be shown in a decimal base.
1587 ///
1588 /// @return true iff sizes and offsets are to be shown in an
1589 /// hexadecimal base.
1590 bool
1592 {return priv_->hex_values_;}
1593 
1594 /// Set the flag that indicates if diff reports using this context
1595 /// should show sizes and offsets in an hexadecimal base or not. If
1596 /// not, then they are to be shown in a decimal base.
1597 ///
1598 /// @param f if true then sizes and offsets are to be shown in an
1599 /// hexadecimal base.
1600 void
1602 {priv_->hex_values_ = f;}
1603 
1604 /// Get the flag that indicates if diff reports using this context
1605 /// should show sizes and offsets in bits, rather than bytes.
1606 ///
1607 /// @return true iff sizes and offsets are to be shown in bits.
1608 /// Otherwise they are to be shown in bytes.
1609 bool
1611 {return priv_->show_offsets_sizes_in_bits_;}
1612 
1613 /// Set the flag that indicates if diff reports using this context
1614 /// should show sizes and offsets in bits, rather than bytes.
1615 ///
1616 /// @param f if true then sizes and offsets are to be shown in bits.
1617 /// Otherwise they are to be shown in bytes.
1618 void
1620 {priv_->show_offsets_sizes_in_bits_ = f;}
1621 
1622 /// Set a flag saying if offset changes should be reported in a
1623 /// relative way. That is, if the report should say how of many bits
1624 /// a class/struct data member did move.
1625 ///
1626 /// @param f the new boolean value of the flag.
1627 void
1629 {priv_->show_relative_offset_changes_ = f;}
1630 
1631 /// Get the flag saying if offset changes should be reported in a
1632 /// relative way. That is, if the report should say how of many bits
1633 /// a class/struct data member did move.
1634 ///
1635 /// @return the boolean value of the flag.
1636 bool
1638 {return priv_->show_relative_offset_changes_;}
1639 
1640 /// Set a flag saying if the comparison module should only show the
1641 /// diff stats.
1642 ///
1643 /// @param f the flag to set.
1644 void
1646 {priv_->show_stats_only_ = f;}
1647 
1648 /// Test if the comparison module should only show the diff stats.
1649 ///
1650 /// @return true if the comparison module should only show the diff
1651 /// stats, false otherwise.
1652 bool
1654 {return priv_->show_stats_only_;}
1655 
1656 /// Setter for the property that says if the comparison module should
1657 /// show the soname changes in its report.
1658 ///
1659 /// @param f the new value of the property.
1660 void
1662 {priv_->show_soname_change_ = f;}
1663 
1664 /// Getter for the property that says if the comparison module should
1665 /// show the soname changes in its report.
1666 ///
1667 /// @return the value of the property.
1668 bool
1670 {return priv_->show_soname_change_;}
1671 
1672 /// Setter for the property that says if the comparison module should
1673 /// show the architecture changes in its report.
1674 ///
1675 /// @param f the new value of the property.
1676 void
1678 {priv_->show_architecture_change_ = f;}
1679 
1680 /// Getter for the property that says if the comparison module should
1681 /// show the architecture changes in its report.
1682 ///
1683 /// @return the value of the property.
1684 bool
1686 {return priv_->show_architecture_change_;}
1687 
1688 /// Set a flag saying to show the deleted functions.
1689 ///
1690 /// @param f true to show deleted functions.
1691 void
1693 {priv_->show_deleted_fns_ = f;}
1694 
1695 /// @return true if we want to show the deleted functions, false
1696 /// otherwise.
1697 bool
1699 {return priv_->show_deleted_fns_;}
1700 
1701 /// Set a flag saying to show the changed functions.
1702 ///
1703 /// @param f true to show the changed functions.
1704 void
1706 {priv_->show_changed_fns_ = f;}
1707 
1708 /// @return true if we want to show the changed functions, false otherwise.
1709 bool
1711 {return priv_->show_changed_fns_;}
1712 
1713 /// Set a flag saying to show the added functions.
1714 ///
1715 /// @param f true to show the added functions.
1716 void
1718 {priv_->show_added_fns_ = f;}
1719 
1720 /// @return true if we want to show the added functions, false
1721 /// otherwise.
1722 bool
1724 {return priv_->show_added_fns_;}
1725 
1726 /// Set a flag saying to show the deleted variables.
1727 ///
1728 /// @param f true to show the deleted variables.
1729 void
1731 {priv_->show_deleted_vars_ = f;}
1732 
1733 /// @return true if we want to show the deleted variables, false
1734 /// otherwise.
1735 bool
1737 {return priv_->show_deleted_vars_;}
1738 
1739 /// Set a flag saying to show the changed variables.
1740 ///
1741 /// @param f true to show the changed variables.
1742 void
1744 {priv_->show_changed_vars_ = f;}
1745 
1746 /// @return true if we want to show the changed variables, false otherwise.
1747 bool
1749 {return priv_->show_changed_vars_;}
1750 
1751 /// Set a flag saying to show the added variables.
1752 ///
1753 /// @param f true to show the added variables.
1754 void
1756 {priv_->show_added_vars_ = f;}
1757 
1758 /// @return true if we want to show the added variables, false
1759 /// otherwise.
1760 bool
1762 {return priv_->show_added_vars_;}
1763 
1764 bool
1765 diff_context::show_linkage_names() const
1766 {return priv_->show_linkage_names_;}
1767 
1768 void
1769 diff_context::show_linkage_names(bool f)
1770 {priv_->show_linkage_names_= f;}
1771 
1772 /// Set a flag saying to show location information.
1773 ///
1774 /// @param f true to show location information.
1775 void
1777 {priv_->show_locs_= f;}
1778 
1779 /// @return true if we want to show location information, false
1780 /// otherwise.
1781 bool
1783 {return priv_->show_locs_;}
1784 
1785 /// A getter for the flag that says if we should report about
1786 /// functions or variables diff nodes that have *exclusively*
1787 /// redundant diff tree children nodes.
1788 ///
1789 /// @return the flag.
1790 bool
1792 {return priv_->show_redundant_changes_;}
1793 
1794 /// A setter for the flag that says if we should report about
1795 /// functions or variables diff nodes that have *exclusively*
1796 /// redundant diff tree children nodes.
1797 ///
1798 /// @param f the flag to set.
1799 void
1801 {priv_->show_redundant_changes_ = f;}
1802 
1803 /// Getter for the flag that indicates if symbols not referenced by
1804 /// any debug info are to be compared and reported about.
1805 ///
1806 /// @return the boolean flag.
1807 bool
1809 {return priv_->show_syms_unreferenced_by_di_;}
1810 
1811 /// Setter for the flag that indicates if symbols not referenced by
1812 /// any debug info are to be compared and reported about.
1813 ///
1814 /// @param f the new flag to set.
1815 void
1817 {priv_->show_syms_unreferenced_by_di_ = f;}
1818 
1819 /// Getter for the flag that indicates if symbols not referenced by
1820 /// any debug info and that got added are to be reported about.
1821 ///
1822 /// @return true iff symbols not referenced by any debug info and that
1823 /// got added are to be reported about.
1824 bool
1826 {return priv_->show_added_syms_unreferenced_by_di_;}
1827 
1828 /// Setter for the flag that indicates if symbols not referenced by
1829 /// any debug info and that got added are to be reported about.
1830 ///
1831 /// @param f the new flag that says if symbols not referenced by any
1832 /// debug info and that got added are to be reported about.
1833 void
1835 {priv_->show_added_syms_unreferenced_by_di_ = f;}
1836 
1837 /// Setter for the flag that indicates if changes on types unreachable
1838 /// from global functions and variables are to be reported.
1839 ///
1840 /// @param f if true, then changes on types unreachable from global
1841 /// functions and variables are to be reported.
1842 void
1844 {priv_->show_unreachable_types_ = f;}
1845 
1846 /// Getter for the flag that indicates if changes on types unreachable
1847 /// from global functions and variables are to be reported.
1848 ///
1849 /// @return true iff changes on types unreachable from global
1850 /// functions and variables are to be reported.
1851 bool
1853 {return priv_->show_unreachable_types_;}
1854 
1855 /// Getter of the flag that indicates if the leaf reporter should
1856 /// display a summary of the interfaces impacted by a given leaf
1857 /// change or not.
1858 ///
1859 /// @return the flag that indicates if the leaf reporter should
1860 /// display a summary of the interfaces impacted by a given leaf
1861 /// change or not.
1862 bool
1864 {return priv_->show_impacted_interfaces_;}
1865 
1866 /// Setter of the flag that indicates if the leaf reporter should
1867 /// display a summary of the interfaces impacted by a given leaf
1868 /// change or not.
1869 ///
1870 /// @param f the new value of the flag that indicates if the leaf
1871 /// reporter should display a summary of the interfaces impacted by a
1872 /// given leaf change or not.
1873 void
1875 {priv_->show_impacted_interfaces_ = f;}
1876 
1877 /// Setter for the default output stream used by code of the
1878 /// comparison engine. By default the default output stream is a NULL
1879 /// pointer.
1880 ///
1881 /// @param o a pointer to the default output stream.
1882 void
1884 {priv_->default_output_stream_ = o;}
1885 
1886 /// Getter for the default output stream used by code of the
1887 /// comparison engine. By default the default output stream is a NULL
1888 /// pointer.
1889 ///
1890 /// @return a pointer to the default output stream.
1891 ostream*
1893 {return priv_->default_output_stream_;}
1894 
1895 /// Setter for the errror output stream used by code of the comparison
1896 /// engine. By default the error output stream is a NULL pointer.
1897 ///
1898 /// @param o a pointer to the error output stream.
1899 void
1901 {priv_->error_output_stream_ = o;}
1902 
1903 /// Getter for the errror output stream used by code of the comparison
1904 /// engine. By default the error output stream is a NULL pointer.
1905 ///
1906 /// @return a pointer to the error output stream.
1907 ostream*
1909 {return priv_->error_output_stream_;}
1910 
1911 /// Test if the comparison engine should dump the diff tree for the
1912 /// changed functions and variables it has.
1913 ///
1914 /// @return true if after the comparison, the engine should dump the
1915 /// diff tree for the changed functions and variables it has.
1916 bool
1918 {return priv_->dump_diff_tree_;}
1919 
1920 /// Set if the comparison engine should dump the diff tree for the
1921 /// changed functions and variables it has.
1922 ///
1923 /// @param f true if after the comparison, the engine should dump the
1924 /// diff tree for the changed functions and variables it has.
1925 void
1927 {priv_->dump_diff_tree_ = f;}
1928 
1929 /// Emit a textual representation of a diff tree to the error output
1930 /// stream of the current context, for debugging purposes.
1931 ///
1932 /// @param d the diff tree to serialize to the error output associated
1933 /// to the current instance of @ref diff_context.
1934 void
1936 {
1937  if (error_output_stream())
1939 }
1940 
1941 /// Emit a textual representation of a @ref corpus_diff tree to the error
1942 /// output stream of the current context, for debugging purposes.
1943 ///
1944 /// @param d the @ref corpus_diff tree to serialize to the error
1945 /// output associated to the current instance of @ref diff_context.
1946 void
1948 {
1949  if (error_output_stream())
1951 }
1952 // </diff_context stuff>
1953 
1954 // <diff stuff>
1955 
1956 /// Constructor for the @ref diff type.
1957 ///
1958 /// This constructs a diff between two subjects that are actually
1959 /// declarations; the first and the second one.
1960 ///
1961 /// @param first_subject the first decl (subject) of the diff.
1962 ///
1963 /// @param second_subject the second decl (subject) of the diff.
1964 diff::diff(type_or_decl_base_sptr first_subject,
1965  type_or_decl_base_sptr second_subject)
1966  : priv_(new priv(first_subject, second_subject,
1969  /*reported_once=*/false,
1970  /*currently_reporting=*/false))
1971 {}
1972 
1973 /// Constructor for the @ref diff type.
1974 ///
1975 /// This constructs a diff between two subjects that are actually
1976 /// declarations; the first and the second one.
1977 ///
1978 /// @param first_subject the first decl (subject) of the diff.
1979 ///
1980 /// @param second_subject the second decl (subject) of the diff.
1981 ///
1982 /// @param ctxt the context of the diff. Note that this context
1983 /// object must stay alive during the entire life time of the current
1984 /// instance of @ref diff. Otherwise, memory corruption issues occur.
1985 diff::diff(type_or_decl_base_sptr first_subject,
1986  type_or_decl_base_sptr second_subject,
1987  diff_context_sptr ctxt)
1988  : priv_(new priv(first_subject, second_subject,
1989  ctxt, NO_CHANGE_CATEGORY,
1990  /*reported_once=*/false,
1991  /*currently_reporting=*/false))
1992 {}
1993 
1994 /// Test if logging was requested
1995 ///
1996 /// @return true iff logging was requested.
1997 bool
1999 {return context()->do_log();}
2000 
2001 /// Request logging (or not)
2002 ///
2003 /// @param f true iff logging is to be requested.
2004 void
2006 {context()->do_log(f);}
2007 
2008 /// Flag a given diff node as being traversed.
2009 ///
2010 /// For certain diff nodes like @ref class_diff, it's important to
2011 /// avoid traversing the node again while it's already being
2012 /// traversed; otherwise this leads to infinite loops. So the
2013 /// diff::begin_traversing() and diff::end_traversing() methods flag a
2014 /// given node as being traversed (or not), so that
2015 /// diff::is_traversing() can tell if the node is being traversed.
2016 ///
2017 /// Note that traversing a node means visiting it *and* visiting its
2018 /// children nodes.
2019 ///
2020 /// The canonical node is marked as being traversed too.
2021 ///
2022 /// These functions are called by the traversing code.
2023 void
2025 {
2027  if (priv_->canonical_diff_)
2028  priv_->canonical_diff_->priv_->traversing_ = true;
2029  priv_->traversing_ = true;
2030 }
2031 
2032 /// Tell if a given node is being traversed or not.
2033 ///
2034 /// Note that traversing a node means visiting it *and* visiting its
2035 /// children nodes.
2036 ///
2037 /// It's the canonical node which is looked at, actually.
2038 ///
2039 /// Please read the comments for the diff::begin_traversing() for mode
2040 /// context.
2041 ///
2042 /// @return true if the current instance of @diff is being traversed.
2043 bool
2045 {
2046  if (priv_->canonical_diff_)
2047  return priv_->canonical_diff_->priv_->traversing_;
2048  return priv_->traversing_;
2049 }
2050 
2051 /// Flag a given diff node as not being traversed anymore.
2052 ///
2053 /// Note that traversing a node means visiting it *and* visiting its
2054 /// children nodes.
2055 ///
2056 /// Please read the comments of the function diff::begin_traversing()
2057 /// for mode context.
2058 void
2060 {
2062  if (priv_->canonical_diff_)
2063  priv_->canonical_diff_->priv_->traversing_ = false;
2064  priv_->traversing_ = false;
2065 }
2066 
2067 /// Finish the insertion of a diff tree node into the diff graph.
2068 ///
2069 /// This function might be called several times. It must perform the
2070 /// insertion only once.
2071 ///
2072 /// For instance, certain kinds of diff tree node have specific
2073 /// children nodes that are populated after the constructor of the
2074 /// diff tree node has been called. In that case, calling overloads
2075 /// of this method ensures that these children nodes are properly
2076 /// gathered and setup.
2077 void
2079 {
2080  if (diff::priv_->finished_)
2081  return;
2083  diff::priv_->finished_ = true;
2084 }
2085 
2086 /// Getter of the first subject of the diff.
2087 ///
2088 /// @return the first subject of the diff.
2091 {return dynamic_pointer_cast<type_or_decl_base>(priv_->first_subject_);}
2092 
2093 /// Getter of the second subject of the diff.
2094 ///
2095 /// @return the second subject of the diff.
2098 {return dynamic_pointer_cast<type_or_decl_base>(priv_->second_subject_);}
2099 
2100 /// Getter for the children nodes of the current @ref diff node.
2101 ///
2102 /// @return a vector of the children nodes.
2103 const vector<diff*>&
2105 {return priv_->children_;}
2106 
2107 /// Getter for the parent node of the current @ref diff node.
2108 ///
2109 /// @return the parent node of the current @ref diff node.
2110 const diff*
2112 {return priv_->parent_;}
2113 
2114 /// Getter for the canonical diff of the current instance of @ref
2115 /// diff.
2116 ///
2117 /// Note that the canonical diff node for the current instanc eof diff
2118 /// node must have been set by invoking
2119 /// class_diff::initialize_canonical_diff() on the current instance of
2120 /// diff node.
2121 ///
2122 /// @return the canonical diff node or null if none was set.
2123 diff*
2125 {return priv_->canonical_diff_;}
2126 
2127 /// Setter for the canonical diff of the current instance of @ref
2128 /// diff.
2129 ///
2130 /// @param d the new canonical node to set.
2131 void
2133 {priv_->canonical_diff_ = d;}
2134 
2135 /// Add a new child node to the vector of children nodes for the
2136 /// current @ref diff node.
2137 ///
2138 /// @param d the new child node to add to the children nodes.
2139 void
2141 {
2142  ABG_ASSERT(d);
2143 
2144  // Ensure 'd' is kept alive for the life time of the context of this
2145  // diff.
2146  context()->keep_diff_alive(d);
2147 
2148  // Add the underlying pointer of 'd' to the vector of children.
2149  // Note that this vector holds no reference to 'd'. This is to avoid
2150  // reference cycles. The reference to 'd' is held by the context of
2151  // this diff, thanks to the call to context()->keep_diff_alive(d)
2152  // above.
2153  priv_->children_.push_back(d.get());
2154 
2155  d->priv_->parent_ = this;
2156 }
2157 
2158 /// Getter of the context of the current diff.
2159 ///
2160 /// @return the context of the current diff.
2161 const diff_context_sptr
2163 {return priv_->get_context();}
2164 
2165 /// Setter of the context of the current diff.
2166 ///
2167 /// @param c the new context to set.
2168 void
2170 {priv_->ctxt_ = c;}
2171 
2172 /// Tests if we are currently in the middle of emitting a report for
2173 /// this diff.
2174 ///
2175 /// @return true if we are currently emitting a report for the
2176 /// current diff, false otherwise.
2177 bool
2179 {
2180  if (priv_->canonical_diff_)
2181  return priv_->canonical_diff_->priv_->currently_reporting_;
2182  return priv_->currently_reporting_;
2183 }
2184 
2185 /// Sets a flag saying if we are currently in the middle of emitting
2186 /// a report for this diff.
2187 ///
2188 /// @param f true if we are currently emitting a report for the
2189 /// current diff, false otherwise.
2190 void
2192 {
2193  if (priv_->canonical_diff_)
2194  priv_->canonical_diff_->priv_->currently_reporting_ = f;
2195  priv_->currently_reporting_ = f;
2196 }
2197 
2198 /// Tests if a report has already been emitted for the current diff.
2199 ///
2200 /// @return true if a report has already been emitted for the
2201 /// current diff, false otherwise.
2202 bool
2204 {
2205  ABG_ASSERT(priv_->canonical_diff_);
2206  return priv_->canonical_diff_->priv_->reported_once_;
2207 }
2208 
2209 /// The generic traversing code that walks a given diff sub-tree.
2210 ///
2211 /// Note that there is a difference between traversing a diff node and
2212 /// visiting it. Basically, traversing a diff node means visiting it
2213 /// and visiting its children nodes too. So one can visit a node
2214 /// without traversing it. But traversing a node without visiting it
2215 /// is not possible.
2216 ///
2217 /// Note that the insertion of the "generic view" of the diff node
2218 /// into the graph being traversed is done "on the fly". The
2219 /// insertion of the "typed view" of the diff node into the graph is
2220 /// done implicitely. To learn more about the generic and typed view
2221 /// of the diff node, please read the introductory comments of the
2222 /// @ref diff class.
2223 ///
2224 /// Note that by default this traversing code visits a given class of
2225 /// equivalence of a diff node only once. This behaviour can been
2226 /// changed by calling
2227 /// diff_context::visiting_a_node_twice_is_forbidden(), but this is
2228 /// very risky as it might create endless loops while visiting a diff
2229 /// tree graph that has changes that refer to themselves; that is,
2230 /// diff tree graphs with cycles.
2231 ///
2232 /// When a diff node is encountered, the
2233 /// diff_node_visitor::visit_begin() method is invoked on the diff
2234 /// node first.
2235 ///
2236 /// If the diff node has already been visited, then
2237 /// node_visitor::visit_end() is called on it and the node traversing
2238 /// is done; the children of the diff node are not visited in this
2239 /// case.
2240 ///
2241 /// If the diff node has *NOT* been visited yet, then the
2242 /// diff_node_visitor::visit() method is invoked with it's 'pre'
2243 /// argument set to true. Then if the diff_node_visitor::visit()
2244 /// returns true, then the children nodes of the diff node are
2245 /// visited. Otherwise, no children nodes of the diff node is
2246 /// visited and the diff_node_visitor::visit_end() is called.
2247 
2248 /// After the children nodes are visited (and only if they are
2249 /// visited) the diff_node_visitor::visit() method is invoked with
2250 /// it's 'pre' argument set to false. And then the
2251 /// diff_node_visitor::visit_end() is called.
2252 ///
2253 /// @param v the entity that visits each node of the diff sub-tree.
2254 ///
2255 /// @return true to tell the caller that all of the sub-tree could be
2256 /// walked. This instructs the caller to keep walking the rest of the
2257 /// tree. Return false otherwise.
2258 bool
2260 {
2261  // Insert the "generic view" of the diff node into its graph.
2262  finish_diff_type();
2263 
2264  v.visit_begin(this);
2265 
2266  bool already_visited = false;
2267  if (context()->visiting_a_node_twice_is_forbidden()
2268  && context()->diff_has_been_visited(this))
2269  already_visited = true;
2270 
2271  bool mark_visited_nodes_as_traversed =
2273 
2274  if (!already_visited && !v.visit(this, /*pre=*/true))
2275  {
2276  v.visit_end(this);
2277  if (mark_visited_nodes_as_traversed)
2278  context()->mark_diff_as_visited(this);
2279  return false;
2280  }
2281 
2283  && !is_traversing()
2284  && !already_visited)
2285  {
2286  begin_traversing();
2287  for (vector<diff*>::const_iterator i = children_nodes().begin();
2288  i != children_nodes().end();
2289  ++i)
2290  {
2291  if (!(*i)->traverse(v))
2292  {
2293  v.visit_end(this);
2294  if (mark_visited_nodes_as_traversed)
2295  context()->mark_diff_as_visited(this);
2296  end_traversing();
2297  return false;
2298  }
2299  }
2300  end_traversing();
2301  }
2302 
2303  if (!v.visit(this, /*pref=*/false))
2304  {
2305  v.visit_end(this);
2306  if (mark_visited_nodes_as_traversed)
2307  context()->mark_diff_as_visited(this);
2308  return false;
2309  }
2310 
2311  v.visit_end(this);
2312  if (!already_visited && mark_visited_nodes_as_traversed)
2313  context()->mark_diff_as_visited(this);
2314 
2315  return true;
2316 }
2317 
2318 /// Sets a flag saying if a report has already been emitted for the
2319 /// current diff.
2320 ///
2321 /// @param f true if a report has already been emitted for the
2322 /// current diff, false otherwise.
2323 void
2324 diff::reported_once(bool f) const
2325 {
2326  ABG_ASSERT(priv_->canonical_diff_);
2327  priv_->canonical_diff_->priv_->reported_once_ = f;
2328  priv_->reported_once_ = f;
2329 }
2330 
2331 /// Getter for the local category of the current diff tree node.
2332 ///
2333 /// The local category represents the set of categories of a diff
2334 /// node, not taking in account the categories inherited from its
2335 /// children nodes.
2336 ///
2337 /// @return the local category of the current diff tree node.
2340 {return priv_->local_category_;}
2341 
2342 /// Getter of the category of the class of equivalence of the current
2343 /// diff tree node.
2344 ///
2345 /// That is, if the current diff tree node has a canonical node,
2346 /// return the category of that canonical node. Otherwise, return the
2347 /// category of the current node.
2348 ///
2349 /// @return the category of the class of equivalence of the current
2350 /// tree node.
2353 {
2354  diff* canonical = get_canonical_diff();
2355  return canonical ? canonical->get_category() : get_category();
2356 }
2357 
2358 /// Getter for the category of the current diff tree node.
2359 ///
2360 /// This category represents the union of the local category and the
2361 /// categories inherited from the children diff nodes.
2362 ///
2363 /// @return the category of the current diff tree node.
2366 {return priv_->category_;}
2367 
2368 /// Adds the current diff tree node to an additional set of
2369 /// categories. Note that the categories include thoses inherited
2370 /// from the children nodes of this diff node.
2371 ///
2372 /// @param c a bit-map representing the set of categories to add the
2373 /// current diff tree node to.
2374 ///
2375 /// @return the resulting bit-map representing the categories this
2376 /// current diff tree node belongs to, including those inherited from
2377 /// its children nodes.
2380 {
2381  priv_->category_ = priv_->category_ | c;
2382  return priv_->category_;
2383 }
2384 
2385 /// Adds the current diff tree node to the categories resulting from
2386 /// the local changes of the current diff node.
2387 ///
2388 /// @param c a bit-map representing the set of categories to add the
2389 /// current diff tree node to.
2390 ///
2391 /// @return the resulting bit-map representing the categories this
2392 /// current diff tree node belongs to.
2395 {
2396  priv_->local_category_ = priv_->local_category_ | c;
2397  return priv_->local_category_;
2398 }
2399 
2400 /// Adds the current diff tree node to the categories resulting from
2401 /// the local and inherited changes of the current diff node.
2402 ///
2403 /// @param c a bit-map representing the set of categories to add the
2404 /// current diff tree node to.
2405 void
2407 {
2409  add_to_category(c);
2410 }
2411 
2412 /// Remove the current diff tree node from an a existing sef of
2413 /// categories. The categories include those inherited from the
2414 /// children nodes of the current diff node.
2415 ///
2416 /// @param c a bit-map representing the set of categories to add the
2417 /// current diff tree node to.
2418 ///
2419 /// @return the resulting bit-map representing the categories this
2420 /// current diff tree onde belongs to, including the categories
2421 /// inherited from the children nodes of the current diff node.
2424 {
2425  priv_->category_ = priv_->category_ & ~c;
2426  return priv_->category_;
2427 }
2428 
2429 /// Remove the current diff tree node from the categories resulting
2430 /// from the local changes.
2431 ///
2432 /// @param c a bit-map representing the set of categories to add the
2433 /// current diff tree node to.
2434 ///
2435 /// @return the resulting bit-map representing the categories this
2436 /// current diff tree onde belongs to.
2439 {
2440  priv_->local_category_ = priv_->local_category_ & ~c;
2441  return priv_->local_category_;
2442 }
2443 
2444 /// Set the category of the current @ref diff node. This category
2445 /// includes the categories inherited from the children nodes of the
2446 /// current diff node.
2447 ///
2448 /// @param c the new category for the current diff node.
2449 void
2451 {priv_->category_ = c;}
2452 
2453 /// Set the local category of the current @ref diff node.
2454 ///
2455 /// @param c the new category for the current diff node.
2456 void
2458 {priv_->local_category_ = c;}
2459 
2460 /// Test if this diff tree node is to be filtered out for reporting
2461 /// purposes.
2462 ///
2463 /// There is a difference between a diff node being filtered out and
2464 /// being suppressed. Being suppressed means that there is a
2465 /// suppression specification that suppresses the diff node
2466 /// specifically. Being filtered out mean the node is either
2467 /// suppressed, or it's filtered out because the suppression of a set
2468 /// of (children) nodes caused this node to be filtered out as well.
2469 /// For instance, if a function diff has all its children diff nodes
2470 /// suppressed and if the function diff node carries no local change,
2471 /// then the function diff node itself is going to be filtered out.
2472 ///
2473 /// The function tests if the categories of the diff tree node are
2474 /// "forbidden" by the context or not.
2475 ///
2476 /// @return true iff the current diff node should NOT be reported.
2477 bool
2479 {
2480  if (diff * canonical = get_canonical_diff())
2481  if ((canonical->get_category() & SUPPRESSED_CATEGORY
2482  || canonical->get_category() & PRIVATE_TYPE_CATEGORY)
2483  && !canonical->is_allowed_by_specific_negated_suppression()
2484  && !canonical->has_descendant_allowed_by_specific_negated_suppression()
2485  && !canonical->has_parent_allowed_by_specific_negated_suppression())
2486  // The canonical type was suppressed either by a user-provided
2487  // suppression specification or by a "private-type" suppression
2488  // specification.. This means all the classes of equivalence of
2489  // that canonical type were suppressed. So this node should be
2490  // filtered out.
2491  return true;
2492  return priv_->is_filtered_out(get_category());
2493 }
2494 
2495 /// Test if this diff tree node is to be filtered out for reporting
2496 /// purposes, but by considering only the categories that were *NOT*
2497 /// inherited from its children nodes.
2498 ///
2499 /// The function tests if the local categories of the diff tree node
2500 /// are "forbidden" by the context or not.
2501 ///
2502 /// @return true iff the current diff node should NOT be reported,
2503 /// with respect to its local categories.
2504 bool
2506 {return priv_->is_filtered_out(get_local_category());}
2507 
2508 /// Test if this diff tree node is to be filtered out for reporting
2509 /// purposes, but without considering the categories that can /force/
2510 /// the node to be unfiltered.
2511 ///
2512 /// The function tests if the categories of the diff tree node are
2513 /// "forbidden" by the context or not.
2514 ///
2515 /// @return true iff the current diff node should should NOT be
2516 /// reported, with respect to the categories that might filter it out
2517 /// only.
2518 bool
2520 {
2525 
2526  return priv_->is_filtered_out(c);
2527 }
2528 
2529 /// Test if the current diff node has been suppressed by a
2530 /// user-provided suppression specification.
2531 ///
2532 /// @return true if the current diff node has been suppressed by a
2533 /// user-provided suppression list.
2534 bool
2536 {
2537  bool is_private = false;
2538  return is_suppressed(is_private);
2539 }
2540 
2541 /// Test if the current diff node has been suppressed by a
2542 /// user-provided suppression specification or by an auto-generated
2543 /// "private type" suppression specification.
2544 ///
2545 /// Note that private type suppressions are auto-generated from the
2546 /// path to where public headers are, as given by the user.
2547 ///
2548 /// Here is the current algorithm:
2549 ///
2550 /// First, suppress this diff node if it's not matched by any
2551 /// negated suppression specifications. If it's not
2552 /// suppressed, then suppress it if it's matched by direct
2553 /// suppression specifications.
2554 ///
2555 /// @param is_private_type out parameter if the current diff node was
2556 /// suppressed because it's a private type then this parameter is set
2557 /// to true.
2558 ///
2559 /// @return true if the current diff node has been suppressed by a
2560 /// user-provided suppression list.
2561 bool
2562 diff::is_suppressed(bool &is_private_type) const
2563 {
2564  // If there is at least one negated suppression, then suppress the
2565  // current diff node by default ...
2566  bool do_suppress = !context()->negated_suppressions().empty();
2567 
2568  // ... unless there is at least one negated suppression that
2569  // specifically asks to keep this diff node around (un-suppressed).
2570  for (auto n : context()->negated_suppressions())
2571  if (!n->suppresses_diff(this))
2572  {
2573  do_suppress = false;
2574  break;
2575  }
2576 
2577  // Then walk the set of non-negated, AKA direct, suppressions. If at
2578  // least one suppression suppresses the current diff node then the
2579  // diff node must be suppressed.
2580  for (auto d : context()->direct_suppressions())
2581  if (d->suppresses_diff(this))
2582  {
2583  do_suppress = true;
2585  is_private_type = true;
2586  break;
2587  }
2588 
2589  return do_suppress;
2590 }
2591 
2592 /// Test if this diff tree node should be reported.
2593 ///
2594 /// @return true iff the current node should be reported.
2595 bool
2597 {
2598  if (has_changes() && !is_filtered_out())
2599  return true;
2600  return false;
2601 }
2602 
2603 /// Test if this diff tree node should be reported when considering
2604 /// the categories that were *NOT* inherited from its children nodes.
2605 ///
2606 /// @return true iff the current node should be reported.
2607 bool
2609 {
2610  if (has_local_changes()
2612  return true;
2613  return false;
2614 }
2615 
2616 /// Test if this diff node is allowed (prevented from being
2617 /// suppressed) by at least one negated suppression specification.
2618 ///
2619 /// @return true if this diff node is meant to be allowed by at least
2620 /// one negated suppression specification.
2621 bool
2623 {
2624  const suppressions_type& suppressions = context()->suppressions();
2625  for (suppressions_type::const_iterator i = suppressions.begin();
2626  i != suppressions.end();
2627  ++i)
2628  {
2629  if (is_negated_suppression(*i)
2630  && !(*i)->suppresses_diff(this))
2631  return true;
2632  }
2633  return false;
2634 }
2635 
2636 /// Test if the current diff node has a descendant node which is
2637 /// specifically allowed by a negated suppression specification.
2638 ///
2639 /// @return true iff the current diff node has a descendant node
2640 /// which is specifically allowed by a negated suppression
2641 /// specification.
2642 bool
2644 {
2646  return result;
2647 }
2648 
2649 /// Test if the current diff node has a parent node which is
2650 /// specifically allowed by a negated suppression specification.
2651 ///
2652 /// @return true iff the current diff node has a parent node which is
2653 /// specifically allowed by a negated suppression specification.
2654 bool
2656 {
2658  return result;
2659 }
2660 
2661 /// Get a pretty representation of the current @ref diff node.
2662 ///
2663 /// This is suitable for e.g. emitting debugging traces for the diff
2664 /// tree nodes.
2665 ///
2666 /// @return the pretty representation of the diff node.
2667 const string&
2669 {
2670  if (priv_->pretty_representation_.empty())
2671  priv_->pretty_representation_ = "empty_diff";
2672  return priv_->pretty_representation_;
2673 }
2674 
2675 /// Default implementation of the hierachy chaining virtual function.
2676 ///
2677 /// There are several types of diff nodes that have logical children
2678 /// nodes; for instance, a typedef_diff has the diff of the underlying
2679 /// type as a child node. A var_diff has the diff of the types of the
2680 /// variables as a child node, etc.
2681 ///
2682 /// But because the @ref diff base has a generic representation for
2683 /// children nodes of the all the types of @ref diff nodes (regardless
2684 /// of the specific most-derived type of diff node) that one can get
2685 /// using the method diff::children_nodes(), one need to populate that
2686 /// vector of children node.
2687 ///
2688 /// Populating that vector of children node is done by this function;
2689 /// it must be overloaded by each most-derived type of diff node that
2690 /// extends the @ref diff type.
2691 void
2693 {}
2694 
2695 // </diff stuff>
2696 
2697 // <type_diff_base stuff>
2698 
2699 type_diff_base::type_diff_base(type_base_sptr first_subject,
2700  type_base_sptr second_subject,
2701  diff_context_sptr ctxt)
2702  : diff(first_subject, second_subject, ctxt),
2703  priv_(new priv)
2704 {}
2705 
2706 type_diff_base::~type_diff_base()
2707 {}
2708 // </type_diff_base stuff>
2709 
2710 // <decl_diff_base stuff>
2711 
2712 /// Constructor of @ref decl_diff_base.
2713 ///
2714 /// @param first_subject the first subject of the diff.
2715 ///
2716 /// @param second_subject the second subject of the diff.
2717 ///
2718 /// @param ctxt the context of the diff. This object must stay alive
2719 /// at least during the life time of the current instance of @ref
2720 /// decl_diff_base, otherwise, memory corruption issues occur.
2721 decl_diff_base::decl_diff_base(decl_base_sptr first_subject,
2722  decl_base_sptr second_subject,
2723  diff_context_sptr ctxt)
2724  : diff(first_subject, second_subject, ctxt),
2725  priv_(new priv)
2726 {}
2727 
2728 decl_diff_base::~decl_diff_base()
2729 {}
2730 
2731 // </decl_diff_base stuff>
2732 
2733 // <distinct_diff stuff>
2734 
2735 /// @return a pretty representation for the @ref distinct_diff node.
2736 const string&
2738 {
2739  if (diff::priv_->pretty_representation_.empty())
2740  {
2741  std::ostringstream o;
2742  o << "distinct_diff[";
2743  if (first_subject())
2744  o << first_subject()->get_pretty_representation();
2745  else
2746  o << "null";
2747  o << ", ";
2748  if (second_subject())
2749  o << second_subject()->get_pretty_representation() ;
2750  else
2751  o << "null";
2752  o << "]" ;
2753  diff::priv_->pretty_representation_ = o.str();
2754  }
2755  return diff::priv_->pretty_representation_;
2756 }
2757 
2758 /// Populate the vector of children node of the @ref diff base type
2759 /// sub-object of this instance of @distinct_diff.
2760 ///
2761 /// The children nodes can then later be retrieved using
2762 /// diff::children_nodes().
2763 void
2765 {
2767 
2768  if (diff_sptr d = compatible_child_diff())
2769  append_child_node(d);
2770 }
2771 
2772 /// Constructor for @ref distinct_diff.
2773 ///
2774 /// Note that the two entities considered for the diff (and passed in
2775 /// parameter) must be of different kinds.
2776 ///
2777 /// @param first the first entity to consider for the diff.
2778 ///
2779 /// @param second the second entity to consider for the diff.
2780 ///
2781 /// @param ctxt the context of the diff. Note that this context
2782 /// object must stay alive at least during the life time of the
2783 /// current instance of @ref distinct_diff. Otherwise memory
2784 /// corruption issues occur.
2786  type_or_decl_base_sptr second,
2787  diff_context_sptr ctxt)
2788  : diff(first, second, ctxt),
2789  priv_(new priv)
2791 
2792 /// Getter for the first subject of the diff.
2793 ///
2794 /// @return the first subject of the diff.
2797 {return first_subject();}
2798 
2799 /// Getter for the second subject of the diff.
2800 ///
2801 /// @return the second subject of the diff.
2804 {return second_subject();}
2805 
2806 /// Getter for the child diff of this distinct_diff instance.
2807 ///
2808 /// When a distinct_diff has two subjects that are different but
2809 /// compatible, then the distinct_diff instance has a child diff node
2810 /// (named the compatible child diff) that is the diff between the two
2811 /// subjects stripped from their typedefs. Otherwise, the compatible
2812 /// child diff is nul.
2813 ///
2814 /// Note that two diff subjects (that compare different) are
2815 /// considered compatible if stripping typedefs out of them makes them
2816 /// comparing equal.
2817 ///
2818 /// @return the compatible child diff node, if any. Otherwise, null.
2819 const diff_sptr
2821 {
2822  if (!priv_->compatible_child_diff)
2823  {
2824  type_base_sptr fs = strip_typedef(is_type(first())),
2825  ss = strip_typedef(is_type(second()));
2826 
2827  if (fs && ss
2829  get_type_declaration(ss)))
2830  priv_->compatible_child_diff = compute_diff(get_type_declaration(fs),
2832  context());
2833  }
2834  return priv_->compatible_child_diff;
2835 }
2836 
2837 /// Test if the two arguments are of different kind, or that are both
2838 /// NULL.
2839 ///
2840 /// @param first the first argument to test for similarity in kind.
2841 ///
2842 /// @param second the second argument to test for similarity in kind.
2843 ///
2844 /// @return true iff the two arguments are of different kind.
2845 bool
2847  type_or_decl_base_sptr second)
2848 {
2849  if (!!first != !!second)
2850  return true;
2851  if (!first && !second)
2852  // We do consider diffs of two empty decls as a diff of distinct
2853  // kinds, for now.
2854  return true;
2855  if (first == second)
2856  return false;
2857 
2858  const type_or_decl_base &f = *first, &s = *second;
2859  return typeid(f) != typeid(s);
2860 }
2861 
2862 /// @return true if the two subjects of the diff are different, false
2863 /// otherwise.
2864 bool
2866 {return first() != second();}
2867 
2868 /// @return the kind of local change carried by the current diff node.
2869 /// The value returned is zero if the current node carries no local
2870 /// change.
2871 enum change_kind
2873 {
2874  // Changes on a distinct_diff are all local.
2875  if (has_changes())
2876  return LOCAL_TYPE_CHANGE_KIND;
2877  return NO_CHANGE_KIND;
2878 }
2879 
2880 /// Emit a report about the current diff instance.
2881 ///
2882 /// @param out the output stream to send the diff report to.
2883 ///
2884 /// @param indent the indentation string to use in the report.
2885 void
2886 distinct_diff::report(ostream& out, const string& indent) const
2887 {
2888  context()->get_reporter()->report(*this, out, indent);
2889 }
2890 
2891 /// Try to diff entities that are of distinct kinds.
2892 ///
2893 /// @param first the first entity to consider for the diff.
2894 ///
2895 /// @param second the second entity to consider for the diff.
2896 ///
2897 /// @param ctxt the context of the diff.
2898 ///
2899 /// @return a non-null diff if a diff object could be built, null
2900 /// otherwise.
2903  const type_or_decl_base_sptr second,
2904  diff_context_sptr ctxt)
2905 {
2907  return distinct_diff_sptr();
2908 
2909  distinct_diff_sptr result(new distinct_diff(first, second, ctxt));
2910 
2911  ctxt->initialize_canonical_diff(result);
2912 
2913  return result;
2914 }
2915 
2916 /// </distinct_diff stuff>
2917 
2918 /// Try to compute a diff on two instances of DiffType representation.
2919 ///
2920 /// The function template performs the diff if and only if the decl
2921 /// representations are of a DiffType.
2922 ///
2923 /// @tparm DiffType the type of instances to diff.
2924 ///
2925 /// @param first the first representation of decl to consider in the
2926 /// diff computation.
2927 ///
2928 /// @param second the second representation of decl to consider in the
2929 /// diff computation.
2930 ///
2931 /// @param ctxt the diff context to use.
2932 ///
2933 ///@return the diff of the two types @p first and @p second if and
2934 ///only if they represent the parametrized type DiffType. Otherwise,
2935 ///returns a NULL pointer value.
2936 template<typename DiffType>
2937 diff_sptr
2939  const type_or_decl_base_sptr second,
2940  diff_context_sptr ctxt)
2941 {
2942  if (shared_ptr<DiffType> f =
2943  dynamic_pointer_cast<DiffType>(first))
2944  {
2945  shared_ptr<DiffType> s =
2946  dynamic_pointer_cast<DiffType>(second);
2947  if (!s)
2948  return diff_sptr();
2949  return compute_diff(f, s, ctxt);
2950  }
2951  return diff_sptr();
2952 }
2953 
2954 
2955 /// This is a specialization of @ref try_to_diff() template to diff
2956 /// instances of @ref class_decl.
2957 ///
2958 /// @param first the first representation of decl to consider in the
2959 /// diff computation.
2960 ///
2961 /// @param second the second representation of decl to consider in the
2962 /// diff computation.
2963 ///
2964 /// @param ctxt the diff context to use.
2965 template<>
2968  const type_or_decl_base_sptr second,
2969  diff_context_sptr ctxt)
2970 {
2971  if (class_decl_sptr f =
2972  dynamic_pointer_cast<class_decl>(first))
2973  {
2974  class_decl_sptr s = dynamic_pointer_cast<class_decl>(second);
2975  if (!s)
2976  return diff_sptr();
2977 
2978  if (f->get_is_declaration_only())
2979  {
2980  class_decl_sptr f2 =
2981  is_class_type (f->get_definition_of_declaration());
2982  if (f2)
2983  f = f2;
2984  }
2985  if (s->get_is_declaration_only())
2986  {
2987  class_decl_sptr s2 =
2988  is_class_type(s->get_definition_of_declaration());
2989  if (s2)
2990  s = s2;
2991  }
2992  return compute_diff(f, s, ctxt);
2993  }
2994  return diff_sptr();
2995 }
2996 
2997 /// Try to diff entities that are of distinct kinds.
2998 ///
2999 /// @param first the first entity to consider for the diff.
3000 ///
3001 /// @param second the second entity to consider for the diff.
3002 ///
3003 /// @param ctxt the context of the diff.
3004 ///
3005 /// @return a non-null diff if a diff object could be built, null
3006 /// otherwise.
3007 static diff_sptr
3008 try_to_diff_distinct_kinds(const type_or_decl_base_sptr first,
3009  const type_or_decl_base_sptr second,
3010  diff_context_sptr ctxt)
3011 {return compute_diff_for_distinct_kinds(first, second, ctxt);}
3012 
3013 /// Compute the difference between two types.
3014 ///
3015 /// The function considers every possible types known to libabigail
3016 /// and runs the appropriate diff function on them.
3017 ///
3018 /// Whenever a new kind of type decl is supported by abigail, if we
3019 /// want to be able to diff two instances of it, we need to update
3020 /// this function to support it.
3021 ///
3022 /// @param first the first type decl to consider for the diff
3023 ///
3024 /// @param second the second type decl to consider for the diff.
3025 ///
3026 /// @param ctxt the diff context to use.
3027 ///
3028 /// @return the resulting diff. It's a pointer to a descendent of
3029 /// abigail::comparison::diff.
3030 static diff_sptr
3031 compute_diff_for_types(const type_or_decl_base_sptr& first,
3032  const type_or_decl_base_sptr& second,
3033  const diff_context_sptr& ctxt)
3034 {
3035  type_or_decl_base_sptr f = first;
3036  type_or_decl_base_sptr s = second;
3037 
3038  diff_sptr d;
3039 
3040  ((d = try_to_diff<type_decl>(f, s, ctxt))
3041  ||(d = try_to_diff<enum_type_decl>(f, s, ctxt))
3042  ||(d = try_to_diff<union_decl>(f, s,ctxt))
3043  ||(d = try_to_diff<class_decl>(f, s,ctxt))
3044  ||(d = try_to_diff<pointer_type_def>(f, s, ctxt))
3045  ||(d = try_to_diff<reference_type_def>(f, s, ctxt))
3046  ||(d = try_to_diff<array_type_def::subrange_type>(f, s, ctxt))
3047  ||(d = try_to_diff<array_type_def>(f, s, ctxt))
3048  ||(d = try_to_diff<qualified_type_def>(f, s, ctxt))
3049  ||(d = try_to_diff<typedef_decl>(f, s, ctxt))
3050  ||(d = try_to_diff<function_type>(f, s, ctxt))
3051  ||(d = try_to_diff_distinct_kinds(f, s, ctxt)));
3052 
3053  ABG_ASSERT(d);
3054 
3055  return d;
3056 }
3057 
3060 {return static_cast<diff_category>(static_cast<unsigned>(c1)
3061  | static_cast<unsigned>(c2));}
3062 
3064 operator|=(diff_category& c1, diff_category c2)
3065 {
3066  c1 = c1 | c2;
3067  return c1;
3068 }
3069 
3071 operator&=(diff_category& c1, diff_category c2)
3072 {
3073  c1 = c1 & c2;
3074  return c1;
3075 }
3076 
3078 operator^(diff_category c1, diff_category c2)
3079 {return static_cast<diff_category>(static_cast<unsigned>(c1)
3080  ^ static_cast<unsigned>(c2));}
3081 
3084 {return static_cast<diff_category>(static_cast<unsigned>(c1)
3085  & static_cast<unsigned>(c2));}
3086 
3089 {return static_cast<diff_category>(~static_cast<unsigned>(c));}
3090 
3091 
3092 /// Getter of a bitmap made of the set of change categories that are
3093 /// considered harmless.
3094 ///
3095 /// @return the bitmap made of the set of change categories that are
3096 /// considered harmless.
3099 {
3116 }
3117 
3118 /// Getter of a bitmap made of the set of change categories that are
3119 /// considered harmful.
3120 ///
3121 /// @return the bitmap made of the set of change categories that are
3122 /// considered harmful.
3125 {
3129 }
3130 
3131 /// Serialize an instance of @ref diff_category to an output stream.
3132 ///
3133 /// @param o the output stream to serialize @p c to.
3134 ///
3135 /// @param c the instance of diff_category to serialize.
3136 ///
3137 /// @return the output stream to serialize @p c to.
3138 ostream&
3139 operator<<(ostream& o, diff_category c)
3140 {
3141  bool emitted_a_category = false;
3142 
3143  if (c == NO_CHANGE_CATEGORY)
3144  {
3145  o << "NO_CHANGE_CATEGORY";
3146  emitted_a_category = true;
3147  }
3148 
3149  if (c & ACCESS_CHANGE_CATEGORY)
3150  {
3151  if (emitted_a_category)
3152  o << "|";
3153  o << "ACCESS_CHANGE_CATEGORY";
3154  emitted_a_category |= true;
3155  }
3156 
3158  {
3159  if (emitted_a_category)
3160  o << "|";
3161  o << "COMPATIBLE_TYPE_CHANGE_CATEGORY";
3162  emitted_a_category |= true;
3163  }
3164 
3166  {
3167  if (emitted_a_category)
3168  o << "|";
3169  o << "HARMLESS_DECL_NAME_CHANGE_CATEGORY";
3170  emitted_a_category |= true;
3171  }
3172 
3174  {
3175  if (emitted_a_category)
3176  o << "|";
3177  o << "NON_VIRT_MEM_FUN_CHANGE_CATEGORY";
3178  emitted_a_category |= true;
3179  }
3180 
3182  {
3183  if (emitted_a_category)
3184  o << "|";
3185  o << "STATIC_DATA_MEMBER_CHANGE_CATEGORY";
3186  emitted_a_category |= true;
3187  }
3188 
3190  {
3191  if (emitted_a_category)
3192  o << "|";
3193  o << "HARMLESS_ENUM_CHANGE_CATEGORY";
3194  emitted_a_category |= true;
3195  }
3196 
3198  {
3199  if (emitted_a_category)
3200  o << "|";
3201  o << "HARMLESS_DATA_MEMBER_CHANGE_CATEGORY";
3202  emitted_a_category |= true;
3203  }
3204 
3206  {
3207  if (emitted_a_category)
3208  o << "|";
3209  o << "HARMLESS_SYMBOL_ALIAS_CHANGE_CATEGORY";
3210  emitted_a_category |= true;
3211  }
3212 
3214  {
3215  if (emitted_a_category)
3216  o << "|";
3217  o << "HARMLESS_UNION_CHANGE_CATEGORY";
3218  emitted_a_category |= true;
3219  }
3220 
3221  if (c & SUPPRESSED_CATEGORY)
3222  {
3223  if (emitted_a_category)
3224  o << "|";
3225  o << "SUPPRESSED_CATEGORY";
3226  emitted_a_category |= true;
3227  }
3228 
3229  if (c & PRIVATE_TYPE_CATEGORY)
3230  {
3231  if (emitted_a_category)
3232  o << "|";
3233  o << "PRIVATE_TYPE_CATEGORY";
3234  emitted_a_category |= true;
3235  }
3236 
3238  {
3239  if (emitted_a_category)
3240  o << "|";
3241  o << "SIZE_OR_OFFSET_CHANGE_CATEGORY";
3242  emitted_a_category |= true;
3243  }
3244 
3246  {
3247  if (emitted_a_category)
3248  o << "|";
3249  o << "VIRTUAL_MEMBER_CHANGE_CATEGORY";
3250  emitted_a_category |= true;
3251  }
3252 
3253  if (c & REDUNDANT_CATEGORY)
3254  {
3255  if (emitted_a_category)
3256  o << "|";
3257  o << "REDUNDANT_CATEGORY";
3258  emitted_a_category |= true;
3259  }
3260 
3262  {
3263  if (emitted_a_category)
3264  o << "|";
3265  o << "TYPE_DECL_ONLY_DEF_CHANGE_CATEGORY";
3266  emitted_a_category |= true;
3267  }
3268 
3270  {
3271  if (emitted_a_category)
3272  o << "|";
3273  o << "FN_PARM_TYPE_TOP_CV_CHANGE_CATEGORY";
3274  emitted_a_category |= true;
3275  }
3276 
3278  {
3279  if (emitted_a_category)
3280  o << "|";
3281  o << "FN_PARM_TYPE_CV_CHANGE_CATEGORY";
3282  emitted_a_category |= true;
3283  }
3284 
3286  {
3287  if (emitted_a_category)
3288  o << "|";
3289  o << "FN_RETURN_TYPE_CV_CHANGE_CATEGORY";
3290  emitted_a_category |= true;
3291  }
3292 
3294  {
3295  if (emitted_a_category)
3296  o << "|";
3297  o << "FN_PARM_ADD_REMOVE_CHANGE_CATEGORY";
3298  emitted_a_category |= true;
3299  }
3300 
3302  {
3303  if (emitted_a_category)
3304  o << "|";
3305  o << "VAR_TYPE_CV_CHANGE_CATEGORY";
3306  emitted_a_category |= true;
3307  }
3308 
3310  {
3311  if (emitted_a_category)
3312  o << "|";
3313  o << "VOID_PTR_TO_PTR_CHANGE_CATEGORY";
3314  emitted_a_category |= true;
3315  }
3316 
3318  {
3319  if (emitted_a_category)
3320  o << "|";
3321  o << "BENIGN_INFINITE_ARRAY_CHANGE_CATEGORY";
3322  emitted_a_category |= true;
3323  }
3324 
3326  {
3327  if (emitted_a_category)
3328  o << "|";
3329  o << "HAS_ALLOWED_CHANGE_CATEGORY";
3330  emitted_a_category |= true;
3331  }
3332 
3334  {
3335  if (emitted_a_category)
3336  o << "|";
3337  o << "HAS_DESCENDANT_WITH_ALLOWED_CHANGE_CATEGORY";
3338  emitted_a_category |= true;
3339  }
3340 
3342  {
3343  if (emitted_a_category)
3344  o << "|";
3345  o << "HAS_PARENT_WITH_ALLOWED_CHANGE_CATEGORY";
3346  emitted_a_category |= true;
3347  }
3348 
3349  return o;
3350 }
3351 
3352 /// Compute the difference between two decls.
3353 ///
3354 /// The function consider every possible decls known to libabigail and
3355 /// runs the appropriate diff function on them.
3356 ///
3357 /// Whenever a new kind of non-type decl is supported by abigail, if
3358 /// we want to be able to diff two instances of it, we need to update
3359 /// this function to support it.
3360 ///
3361 /// @param first the first decl to consider for the diff
3362 ///
3363 /// @param second the second decl to consider for the diff.
3364 ///
3365 /// @param ctxt the diff context to use.
3366 ///
3367 /// @return the resulting diff.
3368 static diff_sptr
3369 compute_diff_for_decls(const decl_base_sptr first,
3370  const decl_base_sptr second,
3371  diff_context_sptr ctxt)
3372 {
3373 
3374  diff_sptr d;
3375 
3376  ((d = try_to_diff<function_decl>(first, second, ctxt))
3377  || (d = try_to_diff<var_decl>(first, second, ctxt))
3378  || (d = try_to_diff_distinct_kinds(first, second, ctxt)));
3379 
3380  ABG_ASSERT(d);
3381 
3382  return d;
3383 }
3384 
3385 /// Compute the difference between two decls. The decls can represent
3386 /// either type declarations, or non-type declaration.
3387 ///
3388 /// Note that the two decls must have been created in the same @ref
3389 /// environment, otherwise, this function aborts.
3390 ///
3391 /// @param first the first decl to consider.
3392 ///
3393 /// @param second the second decl to consider.
3394 ///
3395 /// @param ctxt the diff context to use.
3396 ///
3397 /// @return the resulting diff, or NULL if the diff could not be
3398 /// computed.
3399 diff_sptr
3400 compute_diff(const decl_base_sptr first,
3401  const decl_base_sptr second,
3402  diff_context_sptr ctxt)
3403 {
3404  if (!first || !second)
3405  return diff_sptr();
3406 
3407  diff_sptr d;
3408  if (is_type(first) && is_type(second))
3409  d = compute_diff_for_types(first, second, ctxt);
3410  else
3411  d = compute_diff_for_decls(first, second, ctxt);
3412  ABG_ASSERT(d);
3413  return d;
3414 }
3415 
3416 /// Compute the difference between two types.
3417 ///
3418 /// Note that the two types must have been created in the same @ref
3419 /// environment, otherwise, this function aborts.
3420 ///
3421 /// @param first the first type to consider.
3422 ///
3423 /// @param second the second type to consider.
3424 ///
3425 /// @param ctxt the diff context to use.
3426 ///
3427 /// @return the resulting diff, or NULL if the diff couldn't be
3428 /// computed.
3429 diff_sptr
3430 compute_diff(const type_base_sptr first,
3431  const type_base_sptr second,
3432  diff_context_sptr ctxt)
3433 {
3434  decl_base_sptr f = get_type_declaration(first),
3435  s = get_type_declaration(second);
3436 
3437  diff_sptr d = compute_diff_for_types(f,s, ctxt);
3438  ABG_ASSERT(d);
3439  return d;
3440 }
3441 
3442 /// Get a copy of the pretty representation of a diff node.
3443 ///
3444 /// @param d the diff node to consider.
3445 ///
3446 /// @return the pretty representation string.
3447 string
3449 {
3450  if (!d)
3451  return "";
3452  string prefix= "diff of ";
3453  return prefix + get_pretty_representation(d->first_subject());
3454 }
3455 
3456 // <var_diff stuff>
3457 
3458 /// Populate the vector of children node of the @ref diff base type
3459 /// sub-object of this instance of @ref var_diff.
3460 ///
3461 /// The children node can then later be retrieved using
3462 /// diff::children_node().
3463 void
3466 
3467 /// @return the pretty representation for this current instance of
3468 /// @ref var_diff.
3469 const string&
3471 {
3472  if (diff::priv_->pretty_representation_.empty())
3473  {
3474  std::ostringstream o;
3475  o << "var_diff["
3476  << first_subject()->get_pretty_representation()
3477  << ", "
3478  << second_subject()->get_pretty_representation()
3479  << "]";
3480  diff::priv_->pretty_representation_ = o.str();
3481  }
3482  return diff::priv_->pretty_representation_;
3483 }
3484 /// Constructor for @ref var_diff.
3485 ///
3486 /// @param first the first instance of @ref var_decl to consider in
3487 /// the diff.
3488 ///
3489 /// @param second the second instance of @ref var_decl to consider in
3490 /// the diff.
3491 ///
3492 /// @param type_diff the diff between types of the instances of
3493 /// var_decl.
3494 ///
3495 /// @param ctxt the diff context to use.
3497  var_decl_sptr second,
3498  diff_sptr type_diff,
3499  diff_context_sptr ctxt)
3500  : decl_diff_base(first, second, ctxt),
3501  priv_(new priv)
3502 {priv_->type_diff_ = type_diff;}
3503 
3504 /// Getter for the first @ref var_decl of the diff.
3505 ///
3506 /// @return the first @ref var_decl of the diff.
3509 {return dynamic_pointer_cast<var_decl>(first_subject());}
3510 
3511 /// Getter for the second @ref var_decl of the diff.
3512 ///
3513 /// @return the second @ref var_decl of the diff.
3516 {return dynamic_pointer_cast<var_decl>(second_subject());}
3517 
3518 /// Getter for the diff of the types of the instances of @ref
3519 /// var_decl.
3520 ///
3521 /// @return the diff of the types of the instances of @ref var_decl.
3522 diff_sptr
3524 {
3525  if (diff_sptr result = priv_->type_diff_.lock())
3526  return result;
3527  else
3528  {
3529  result = compute_diff(first_var()->get_type(),
3530  second_var()->get_type(),
3531  context());
3532  context()->keep_diff_alive(result);
3533  priv_->type_diff_ = result;
3534  return result;
3535  }
3536 }
3537 
3538 /// Return true iff the diff node has a change.
3539 ///
3540 /// @return true iff the diff node has a change.
3541 bool
3543 {return *first_var() != *second_var();}
3544 
3545 /// @return the kind of local change carried by the current diff node.
3546 /// The value returned is zero if the current node carries no local
3547 /// change.
3548 enum change_kind
3550 {
3551  ir::change_kind k = ir::NO_CHANGE_KIND;
3552  if (!equals(*first_var(), *second_var(), &k))
3553  return k & ir::ALL_LOCAL_CHANGES_MASK;
3554  return ir::NO_CHANGE_KIND;
3555 }
3556 
3557 /// Report the diff in a serialized form.
3558 ///
3559 /// @param out the stream to serialize the diff to.
3560 ///
3561 /// @param indent the prefix to use for the indentation of this
3562 /// serialization.
3563 void
3564 var_diff::report(ostream& out, const string& indent) const
3565 {
3566  context()->get_reporter()->report(*this, out, indent);
3567 }
3568 
3569 /// Compute the diff between two instances of @ref var_decl.
3570 ///
3571 /// Note that the two decls must have been created in the same @ref
3572 /// environment, otherwise, this function aborts.
3573 ///
3574 /// @param first the first @ref var_decl to consider for the diff.
3575 ///
3576 /// @param second the second @ref var_decl to consider for the diff.
3577 ///
3578 /// @param ctxt the diff context to use.
3579 ///
3580 /// @return the resulting diff between the two @ref var_decl.
3583  const var_decl_sptr second,
3584  diff_context_sptr ctxt)
3585 {
3586  var_diff_sptr d(new var_diff(first, second, diff_sptr(), ctxt));
3587  ctxt->initialize_canonical_diff(d);
3588 
3589  return d;
3590 }
3591 
3592 // </var_diff stuff>
3593 
3594 // <pointer_type_def stuff>
3595 
3596 /// Populate the vector of children node of the @ref diff base type
3597 /// sub-object of this instance of @ref pointer_diff.
3598 ///
3599 /// The children node can then later be retrieved using
3600 /// diff::children_node().
3601 void
3604 
3605 /// Constructor for a pointer_diff.
3606 ///
3607 /// @param first the first pointer to consider for the diff.
3608 ///
3609 /// @param second the secon pointer to consider for the diff.
3610 ///
3611 /// @param ctxt the diff context to use.
3613  pointer_type_def_sptr second,
3614  diff_sptr underlying,
3615  diff_context_sptr ctxt)
3616  : type_diff_base(first, second, ctxt),
3617  priv_(new priv(underlying))
3618 {}
3619 
3620 /// Getter for the first subject of a pointer diff
3621 ///
3622 /// @return the first pointer considered in this pointer diff.
3625 {return dynamic_pointer_cast<pointer_type_def>(first_subject());}
3626 
3627 /// Getter for the second subject of a pointer diff
3628 ///
3629 /// @return the second pointer considered in this pointer diff.
3632 {return dynamic_pointer_cast<pointer_type_def>(second_subject());}
3633 
3634 /// @return the pretty represenation for the current instance of @ref
3635 /// pointer_diff.
3636 const string&
3638 {
3639  if (diff::priv_->pretty_representation_.empty())
3640  {
3641  std::ostringstream o;
3642  o << "pointer_diff["
3643  << first_subject()->get_pretty_representation()
3644  << ", "
3645  << second_subject()->get_pretty_representation()
3646  << "]";
3647  diff::priv_->pretty_representation_ = o.str();
3648  }
3649  return diff::priv_->pretty_representation_;
3650 }
3651 
3652 /// Return true iff the current diff node carries a change.
3653 ///
3654 /// @return true iff the current diff node carries a change.
3655 bool
3657 {return first_pointer() != second_pointer();}
3658 
3659 /// @return the kind of local change carried by the current diff node.
3660 /// The value returned is zero if the current node carries no local
3661 /// change.
3662 enum change_kind
3664 {
3665  ir::change_kind k = ir::NO_CHANGE_KIND;
3666  if (!equals(*first_pointer(), *second_pointer(), &k))
3667  return k & ir::ALL_LOCAL_CHANGES_MASK;
3668  return ir::NO_CHANGE_KIND;
3669 }
3670 
3671 /// Getter for the diff between the pointed-to types of the pointers
3672 /// of this diff.
3673 ///
3674 /// @return the diff between the pointed-to types.
3675 diff_sptr
3677 {return priv_->underlying_type_diff_;}
3678 
3679 /// Setter for the diff between the pointed-to types of the pointers
3680 /// of this diff.
3681 ///
3682 /// @param d the new diff between the pointed-to types of the pointers
3683 /// of this diff.
3684 void
3686 {priv_->underlying_type_diff_ = d;}
3687 
3688 /// Report the diff in a serialized form.
3689 ///
3690 /// @param out the stream to serialize the diff to.
3691 ///
3692 /// @param indent the prefix to use for the indentation of this
3693 /// serialization.
3694 void
3695 pointer_diff::report(ostream& out, const string& indent) const
3696 {
3697  context()->get_reporter()->report(*this, out, indent);
3698 }
3699 
3700 /// Compute the diff between between two pointers.
3701 ///
3702 /// Note that the two types must have been created in the same @ref
3703 /// environment, otherwise, this function aborts.
3704 ///
3705 /// @param first the pointer to consider for the diff.
3706 ///
3707 /// @param second the pointer to consider for the diff.
3708 ///
3709 /// @return the resulting diff between the two pointers.
3710 ///
3711 /// @param ctxt the diff context to use.
3714  pointer_type_def_sptr second,
3715  diff_context_sptr ctxt)
3716 {
3717  diff_sptr d = compute_diff_for_types(first->get_pointed_to_type(),
3718  second->get_pointed_to_type(),
3719  ctxt);
3720  pointer_diff_sptr result(new pointer_diff(first, second, d, ctxt));
3721  ctxt->initialize_canonical_diff(result);
3722 
3723  return result;
3724 }
3725 
3726 // </pointer_type_def>
3727 
3728 // <subrange_diff >
3729 
3730 /// Constructor of the @ref subrange_diff diff node type.
3731 ///
3732 /// @param first the first subrange type to consider for the diff.
3733 ///
3734 /// @param second the second subrange type to consider for the diff.
3735 ///
3736 /// @param underlying_type_diff the underlying type diff between @p
3737 /// first and @p second.
3738 ///
3739 /// @param ctxt the diff context to use.
3741 (const array_type_def::subrange_sptr& first,
3742  const array_type_def::subrange_sptr& second,
3743  const diff_sptr& underlying_type_diff,
3744  const diff_context_sptr ctxt)
3745  : type_diff_base(first, second, ctxt),
3746  priv_(new priv(underlying_type_diff))
3747 {}
3748 
3749 
3750 /// Getter of the first subrange of the current instance @ref
3751 /// subrange_diff.
3752 ///
3753 /// @return The first subrange of the current instance @ref subrange_diff.
3756 {return is_subrange_type(first_subject());}
3757 
3758 /// Getter of the second subrange of the current instance @ref
3759 /// subrange_diff.
3760 ///
3761 /// @return The second subrange of the current instance @ref
3762 /// subrange_diff.
3765 {return is_subrange_type(second_subject());}
3766 
3767 /// Getter of the diff node of the underlying types of the current
3768 /// @ref subrange_diff diff node.
3769 ///
3770 /// @return The diff node of the underlying types of the current @ref
3771 /// subrange_diff diff node.
3772 const diff_sptr
3774 {return priv_->underlying_type_diff_;}
3775 
3776 /// Getter the pretty representation of the @ref subrange_diff diff
3777 /// node.
3778 ///
3779 /// @return The pretty representation of the @ref subrange_diff diff node.
3780 const string&
3782 {
3783  if (diff::priv_->pretty_representation_.empty())
3784  {
3785  std::ostringstream o;
3786  o << "subrange_diff["
3787  << first_subject()->get_pretty_representation()
3788  << ","
3789  << second_subject()->get_pretty_representation()
3790  << "]";
3791  diff::priv_->pretty_representation_ = o.str();
3792  }
3793  return diff::priv_->pretty_representation_;
3794 }
3795 
3796 /// Test if the current @ref subrange_diff node carries any change.
3797 ///
3798 /// @return true iff the current @ref subrange_diff node carries any
3799 /// change.
3800 bool
3802 {return *first_subrange() != *second_subrange();}
3803 
3804 /// Test if the current @ref subrange_diff node carries any local
3805 /// change.
3806 ///
3807 /// @return true iff the current @ref subrange_diff node carries any
3808 /// local change.
3809 enum change_kind
3811 {
3812  ir::change_kind k = ir::NO_CHANGE_KIND;
3813  if (!equals(*first_subrange(), *second_subrange(), &k))
3814  return k & ir::ALL_LOCAL_CHANGES_MASK;
3815  return ir::NO_CHANGE_KIND;
3816 }
3817 
3818 /// Report about the changes carried by this node.
3819 ///
3820 /// @param out the output stream to send the report to.
3821 ///
3822 /// @param indent the indentation string to use.
3823 void
3824 subrange_diff::report(ostream& out, const string& indent) const
3825 {context()->get_reporter()->report(*this, out, indent);}
3826 
3827 /// Populate the vector of children node of the @ref diff base type
3828 /// sub-object of this instance of @ref subrange_diff.
3829 ///
3830 /// The children node can then later be retrieved using
3831 /// diff::children_node().
3832 void
3835 
3836 /// Compute the diff between two instances of @ref subrange_diff.
3837 ///
3838 /// Note that the two decls must have been created in the same @ref
3839 /// environment, otherwise, this function aborts.
3840 ///
3841 /// @param first the first @ref subrange_diff to consider for the diff.
3842 ///
3843 /// @param second the second @ref subrange_diff to consider for the diff.
3844 ///
3845 /// @param ctxt the diff context to use.
3846 ///
3847 /// @return the resulting diff between the two @ref subrange_diff.
3851  diff_context_sptr ctxt)
3852 {
3853  diff_sptr d = compute_diff_for_types(first->get_underlying_type(),
3854  second->get_underlying_type(),
3855  ctxt);
3856 
3857  subrange_diff_sptr result(new subrange_diff(first, second, d, ctxt));
3858  ctxt->initialize_canonical_diff(result);
3859  return result;
3860 }
3861 
3862 //</subrange_diff >
3863 
3864 
3865 // <array_type_def>
3866 
3867 /// Populate the vector of children node of the @ref diff base type
3868 /// sub-object of this instance of @ref array_diff.
3869 ///
3870 /// The children node can then later be retrieved using
3871 /// diff::children_node().
3872 void
3875 
3876 /// Constructor for array_diff
3877 ///
3878 /// @param first the first array_type of the diff.
3879 ///
3880 /// @param second the second array_type of the diff.
3881 ///
3882 /// @param element_type_diff the diff between the two array element
3883 /// types.
3884 ///
3885 /// @param ctxt the diff context to use.
3887  const array_type_def_sptr second,
3888  diff_sptr element_type_diff,
3889  diff_context_sptr ctxt)
3890  : type_diff_base(first, second, ctxt),
3891  priv_(new priv(element_type_diff))
3892 {}
3893 
3894 /// Getter for the first array of the diff.
3895 ///
3896 /// @return the first array of the diff.
3897 const array_type_def_sptr
3899 {return dynamic_pointer_cast<array_type_def>(first_subject());}
3900 
3901 /// Getter for the second array of the diff.
3902 ///
3903 /// @return for the second array of the diff.
3904 const array_type_def_sptr
3906 {return dynamic_pointer_cast<array_type_def>(second_subject());}
3907 
3908 /// Getter for the diff between the two types of array elements.
3909 ///
3910 /// @return the diff between the two types of array elements.
3911 const diff_sptr&
3913 {return priv_->element_type_diff_;}
3914 
3915 /// Setter for the diff between the two array element types.
3916 ///
3917 /// @param d the new diff betweend the two array element types.
3918 void
3920 {priv_->element_type_diff_ = d;}
3921 
3922 /// @return the pretty representation for the current instance of @ref
3923 /// array_diff.
3924 const string&
3926 {
3927  if (diff::priv_->pretty_representation_.empty())
3928  {
3929  std::ostringstream o;
3930  o << "array_diff["
3931  << first_subject()->get_pretty_representation()
3932  << ", "
3933  << second_subject()->get_pretty_representation()
3934  << "]";
3935  diff::priv_->pretty_representation_ = o.str();
3936  }
3937  return diff::priv_->pretty_representation_;
3938 }
3939 
3940 /// Return true iff the current diff node carries a change.
3941 ///
3942 /// @return true iff the current diff node carries a change.
3943 bool
3945 {
3946  bool l = false;
3947 
3948  // the array element types match check for differing dimensions
3949  // etc...
3951  f = dynamic_pointer_cast<array_type_def>(first_subject()),
3952  s = dynamic_pointer_cast<array_type_def>(second_subject());
3953 
3954  if (f->get_name() != s->get_name())
3955  l |= true;
3956  if (f->get_size_in_bits() != s->get_size_in_bits())
3957  l |= true;
3958  if (f->get_alignment_in_bits() != s->get_alignment_in_bits())
3959  l |= true;
3960 
3961  l |= element_type_diff()
3962  ? element_type_diff()->has_changes()
3963  : false;
3964 
3965  return l;
3966 }
3967 
3968 
3969 /// @return the kind of local change carried by the current diff node.
3970 /// The value returned is zero if the current node carries no local
3971 /// change.
3972 enum change_kind
3974 {
3975  ir::change_kind k = ir::NO_CHANGE_KIND;
3976  if (!equals(*first_array(), *second_array(), &k))
3977  return k & ir::ALL_LOCAL_CHANGES_MASK;
3978  return ir::NO_CHANGE_KIND;
3979 }
3980 
3981 /// Report the diff in a serialized form.
3982 ///
3983 /// @param out the output stream to serialize the dif to.
3984 ///
3985 /// @param indent the string to use for indenting the report.
3986 void
3987 array_diff::report(ostream& out, const string& indent) const
3988 {
3989  context()->get_reporter()->report(*this, out, indent);
3990 }
3991 
3992 /// Compute the diff between two arrays.
3993 ///
3994 /// Note that the two types must have been created in the same @ref
3995 /// environment, otherwise, this function aborts.
3996 ///
3997 /// @param first the first array to consider for the diff.
3998 ///
3999 /// @param second the second array to consider for the diff.
4000 ///
4001 /// @param ctxt the diff context to use.
4004  array_type_def_sptr second,
4005  diff_context_sptr ctxt)
4006 {
4007  diff_sptr d = compute_diff_for_types(first->get_element_type(),
4008  second->get_element_type(),
4009  ctxt);
4010  array_diff_sptr result(new array_diff(first, second, d, ctxt));
4011  ctxt->initialize_canonical_diff(result);
4012  return result;
4013 }
4014 // </array_type_def>
4015 
4016 // <reference_type_def>
4017 
4018 /// Populate the vector of children node of the @ref diff base type
4019 /// sub-object of this instance of @ref reference_diff.
4020 ///
4021 /// The children node can then later be retrieved using
4022 /// diff::children_node().
4023 void
4026 
4027 /// Constructor for reference_diff
4028 ///
4029 /// @param first the first reference_type of the diff.
4030 ///
4031 /// @param second the second reference_type of the diff.
4032 ///
4033 /// @param ctxt the diff context to use.
4035  const reference_type_def_sptr second,
4036  diff_sptr underlying,
4037  diff_context_sptr ctxt)
4038  : type_diff_base(first, second, ctxt),
4039  priv_(new priv(underlying))
4040 {}
4041 
4042 /// Getter for the first reference of the diff.
4043 ///
4044 /// @return the first reference of the diff.
4047 {return dynamic_pointer_cast<reference_type_def>(first_subject());}
4048 
4049 /// Getter for the second reference of the diff.
4050 ///
4051 /// @return for the second reference of the diff.
4054 {return dynamic_pointer_cast<reference_type_def>(second_subject());}
4055 
4056 
4057 /// Getter for the diff between the two referred-to types.
4058 ///
4059 /// @return the diff between the two referred-to types.
4060 const diff_sptr&
4062 {return priv_->underlying_type_diff_;}
4063 
4064 /// Setter for the diff between the two referred-to types.
4065 ///
4066 /// @param d the new diff betweend the two referred-to types.
4067 diff_sptr&
4069 {
4070  priv_->underlying_type_diff_ = d;
4071  return priv_->underlying_type_diff_;
4072 }
4073 
4074 /// @return the pretty representation for the current instance of @ref
4075 /// reference_diff.
4076 const string&
4078 {
4079  if (diff::priv_->pretty_representation_.empty())
4080  {
4081  std::ostringstream o;
4082  o << "reference_diff["
4083  << first_subject()->get_pretty_representation()
4084  << ", "
4085  << second_subject()->get_pretty_representation()
4086  << "]";
4087  diff::priv_->pretty_representation_ = o.str();
4088  }
4089  return diff::priv_->pretty_representation_;
4090 }
4091 
4092 /// Return true iff the current diff node carries a change.
4093 ///
4094 /// @return true iff the current diff node carries a change.
4095 bool
4097 {
4098  return first_reference() != second_reference();
4099 }
4100 
4101 /// @return the kind of local change carried by the current diff node.
4102 /// The value returned is zero if the current node carries no local
4103 /// change.
4104 enum change_kind
4106 {
4107  ir::change_kind k = ir::NO_CHANGE_KIND;
4108  if (!equals(*first_reference(), *second_reference(), &k))
4109  return k & ir::ALL_LOCAL_CHANGES_MASK;
4110  return ir::NO_CHANGE_KIND;
4111 }
4112 
4113 /// Report the diff in a serialized form.
4114 ///
4115 /// @param out the output stream to serialize the dif to.
4116 ///
4117 /// @param indent the string to use for indenting the report.
4118 void
4119 reference_diff::report(ostream& out, const string& indent) const
4120 {
4121  context()->get_reporter()->report(*this, out, indent);
4122 }
4123 
4124 /// Compute the diff between two references.
4125 ///
4126 /// Note that the two types must have been created in the same @ref
4127 /// environment, otherwise, this function aborts.
4128 ///
4129 /// @param first the first reference to consider for the diff.
4130 ///
4131 /// @param second the second reference to consider for the diff.
4132 ///
4133 /// @param ctxt the diff context to use.
4136  reference_type_def_sptr second,
4137  diff_context_sptr ctxt)
4138 {
4139  diff_sptr d = compute_diff_for_types(first->get_pointed_to_type(),
4140  second->get_pointed_to_type(),
4141  ctxt);
4142  reference_diff_sptr result(new reference_diff(first, second, d, ctxt));
4143  ctxt->initialize_canonical_diff(result);
4144  return result;
4145 }
4146 // </reference_type_def>
4147 
4148 // <qualified_type_diff stuff>
4149 
4150 /// Populate the vector of children node of the @ref diff base type
4151 /// sub-object of this instance of @ref qualified_type_diff.
4152 ///
4153 /// The children node can then later be retrieved using
4154 /// diff::children_node().
4155 void
4158 
4159 /// Constructor for qualified_type_diff.
4160 ///
4161 /// @param first the first qualified type of the diff.
4162 ///
4163 /// @param second the second qualified type of the diff.
4164 ///
4165 /// @param ctxt the diff context to use.
4166 qualified_type_diff::qualified_type_diff(qualified_type_def_sptr first,
4167  qualified_type_def_sptr second,
4168  diff_sptr under,
4169  diff_context_sptr ctxt)
4170  : type_diff_base(first, second, ctxt),
4171  priv_(new priv(under))
4172 {}
4173 
4174 /// Getter for the first qualified type of the diff.
4175 ///
4176 /// @return the first qualified type of the diff.
4177 const qualified_type_def_sptr
4179 {return dynamic_pointer_cast<qualified_type_def>(first_subject());}
4180 
4181 /// Getter for the second qualified type of the diff.
4182 ///
4183 /// @return the second qualified type of the diff.
4184 const qualified_type_def_sptr
4186 {return dynamic_pointer_cast<qualified_type_def>(second_subject());}
4187 
4188 /// Getter for the diff between the underlying types of the two
4189 /// qualified types.
4190 ///
4191 /// @return the diff between the underlying types of the two qualified
4192 /// types.
4193 diff_sptr
4195 {return priv_->underlying_type_diff;}
4196 
4197 /// Getter for the diff between the most underlying non-qualified
4198 /// types of two qualified types.
4199 ///
4200 /// @return the diff between the most underlying non-qualified types
4201 /// of two qualified types.
4202 diff_sptr
4204 {
4205  if (!priv_->leaf_underlying_type_diff)
4206  priv_->leaf_underlying_type_diff
4207  = compute_diff_for_types(get_leaf_type(first_qualified_type()),
4209  context());
4210 
4211  return priv_->leaf_underlying_type_diff;
4212 }
4213 
4214 /// Setter for the diff between the underlying types of the two
4215 /// qualified types.
4216 ///
4217 /// @return the diff between the underlying types of the two qualified
4218 /// types.
4219 void
4221 {priv_->underlying_type_diff = d;}
4222 
4223 /// @return the pretty representation of the current instance of @ref
4224 /// qualified_type_diff.
4225 const string&
4227 {
4228  if (diff::priv_->pretty_representation_.empty())
4229  {
4230  std::ostringstream o;
4231  o << "qualified_type_diff["
4232  << first_subject()->get_pretty_representation()
4233  << ", "
4234  << second_subject()->get_pretty_representation()
4235  << "]";
4236  diff::priv_->pretty_representation_ = o.str();
4237  }
4238  return diff::priv_->pretty_representation_;
4239 }
4240 
4241 /// Return true iff the current diff node carries a change.
4242 ///
4243 /// @return true iff the current diff node carries a change.
4244 bool
4247 
4248 /// @return the kind of local change carried by the current diff node.
4249 /// The value returned is zero if the current node carries no local
4250 /// change.
4251 enum change_kind
4253 {
4254  ir::change_kind k = ir::NO_CHANGE_KIND;
4256  return k & ir::ALL_LOCAL_CHANGES_MASK;
4257  return ir::NO_CHANGE_KIND;
4258 }
4259 
4260 /// Report the diff in a serialized form.
4261 ///
4262 /// @param out the output stream to serialize to.
4263 ///
4264 /// @param indent the string to use to indent the lines of the report.
4265 void
4266 qualified_type_diff::report(ostream& out, const string& indent) const
4267 {
4268  context()->get_reporter()->report(*this, out, indent);
4269 }
4270 
4271 /// Compute the diff between two qualified types.
4272 ///
4273 /// Note that the two types must have been created in the same @ref
4274 /// environment, otherwise, this function aborts.
4275 ///
4276 /// @param first the first qualified type to consider for the diff.
4277 ///
4278 /// @param second the second qualified type to consider for the diff.
4279 ///
4280 /// @param ctxt the diff context to use.
4281 qualified_type_diff_sptr
4282 compute_diff(const qualified_type_def_sptr first,
4283  const qualified_type_def_sptr second,
4284  diff_context_sptr ctxt)
4285 {
4286  diff_sptr d = compute_diff_for_types(first->get_underlying_type(),
4287  second->get_underlying_type(),
4288  ctxt);
4289  qualified_type_diff_sptr result(new qualified_type_diff(first, second,
4290  d, ctxt));
4291  ctxt->initialize_canonical_diff(result);
4292  return result;
4293 }
4294 
4295 // </qualified_type_diff stuff>
4296 
4297 // <enum_diff stuff>
4298 
4299 /// Clear the lookup tables useful for reporting an enum_diff.
4300 ///
4301 /// This function must be updated each time a lookup table is added or
4302 /// removed from the class_diff::priv.
4303 void
4304 enum_diff::clear_lookup_tables()
4305 {
4306  priv_->deleted_enumerators_.clear();
4307  priv_->inserted_enumerators_.clear();
4308  priv_->changed_enumerators_.clear();
4309 }
4310 
4311 /// Tests if the lookup tables are empty.
4312 ///
4313 /// @return true if the lookup tables are empty, false otherwise.
4314 bool
4315 enum_diff::lookup_tables_empty() const
4316 {
4317  return (priv_->deleted_enumerators_.empty()
4318  && priv_->inserted_enumerators_.empty()
4319  && priv_->changed_enumerators_.empty());
4320 }
4321 
4322 /// If the lookup tables are not yet built, walk the differences and
4323 /// fill the lookup tables.
4324 void
4325 enum_diff::ensure_lookup_tables_populated()
4326 {
4327  if (!lookup_tables_empty())
4328  return;
4329 
4330  {
4331  edit_script e = priv_->enumerators_changes_;
4332 
4333  for (vector<deletion>::const_iterator it = e.deletions().begin();
4334  it != e.deletions().end();
4335  ++it)
4336  {
4337  unsigned i = it->index();
4338  const enum_type_decl::enumerator& n =
4339  first_enum()->get_enumerators()[i];
4340  const string& name = n.get_name();
4341  ABG_ASSERT(priv_->deleted_enumerators_.find(n.get_name())
4342  == priv_->deleted_enumerators_.end());
4343  priv_->deleted_enumerators_[name] = n;
4344  }
4345 
4346  for (vector<insertion>::const_iterator it = e.insertions().begin();
4347  it != e.insertions().end();
4348  ++it)
4349  {
4350  for (vector<unsigned>::const_iterator iit =
4351  it->inserted_indexes().begin();
4352  iit != it->inserted_indexes().end();
4353  ++iit)
4354  {
4355  unsigned i = *iit;
4356  const enum_type_decl::enumerator& n =
4357  second_enum()->get_enumerators()[i];
4358  const string& name = n.get_name();
4359  ABG_ASSERT(priv_->inserted_enumerators_.find(n.get_name())
4360  == priv_->inserted_enumerators_.end());
4361  string_enumerator_map::const_iterator j =
4362  priv_->deleted_enumerators_.find(name);
4363  if (j == priv_->deleted_enumerators_.end())
4364  priv_->inserted_enumerators_[name] = n;
4365  else
4366  {
4367  if (j->second != n)
4368  priv_->changed_enumerators_[j->first] =
4369  std::make_pair(j->second, n);
4370  priv_->deleted_enumerators_.erase(j);
4371  }
4372  }
4373  }
4374  }
4375 }
4376 
4377 /// Populate the vector of children node of the @ref diff base type
4378 /// sub-object of this instance of @ref enum_diff.
4379 ///
4380 /// The children node can then later be retrieved using
4381 /// diff::children_node().
4382 void
4385 
4386 /// Constructor for enum_diff.
4387 ///
4388 /// @param first the first enum type of the diff.
4389 ///
4390 /// @param second the second enum type of the diff.
4391 ///
4392 /// @param underlying_type_diff the diff of the two underlying types
4393 /// of the two enum types.
4394 ///
4395 /// @param ctxt the diff context to use.
4397  const enum_type_decl_sptr second,
4398  const diff_sptr underlying_type_diff,
4399  const diff_context_sptr ctxt)
4400  : type_diff_base(first, second, ctxt),
4401  priv_(new priv(underlying_type_diff))
4402 {}
4403 
4404 /// @return the first enum of the diff.
4405 const enum_type_decl_sptr
4407 {return dynamic_pointer_cast<enum_type_decl>(first_subject());}
4408 
4409 /// @return the second enum of the diff.
4410 const enum_type_decl_sptr
4412 {return dynamic_pointer_cast<enum_type_decl>(second_subject());}
4413 
4414 /// @return the diff of the two underlying enum types.
4415 diff_sptr
4417 {return priv_->underlying_type_diff_;}
4418 
4419 /// @return a map of the enumerators that were deleted.
4420 const string_enumerator_map&
4422 {return priv_->deleted_enumerators_;}
4423 
4424 /// @return a map of the enumerators that were inserted
4425 const string_enumerator_map&
4427 {return priv_->inserted_enumerators_;}
4428 
4429 /// @return a map of the enumerators that were changed
4432 {return priv_->changed_enumerators_;}
4433 
4434 /// @return the pretty representation of the current instance of @ref
4435 /// enum_diff.
4436 const string&
4438 {
4439  if (diff::priv_->pretty_representation_.empty())
4440  {
4441  std::ostringstream o;
4442  o << "enum_diff["
4443  << first_subject()->get_pretty_representation()
4444  << ", "
4445  << second_subject()->get_pretty_representation()
4446  << "]";
4447  diff::priv_->pretty_representation_ = o.str();
4448  }
4449  return diff::priv_->pretty_representation_;
4450 }
4451 
4452 /// Return true iff the current diff node carries a change.
4453 ///
4454 /// @return true iff the current diff node carries a change.
4455 bool
4457 {return first_enum() != second_enum();}
4458 
4459 /// @return the kind of local change carried by the current diff node.
4460 /// The value returned is zero if the current node carries no local
4461 /// change.
4462 enum change_kind
4464 {
4465  ir::change_kind k = ir::NO_CHANGE_KIND;
4466  if (!equals(*first_enum(), *second_enum(), &k))
4467  return k & ir::ALL_LOCAL_CHANGES_MASK;
4468  return ir::NO_CHANGE_KIND;
4469 }
4470 
4471 /// Report the differences between the two enums.
4472 ///
4473 /// @param out the output stream to send the report to.
4474 ///
4475 /// @param indent the string to use for indentation.
4476 void
4477 enum_diff::report(ostream& out, const string& indent) const
4478 {
4479  context()->get_reporter()->report(*this, out, indent);
4480 }
4481 
4482 /// Compute the set of changes between two instances of @ref
4483 /// enum_type_decl.
4484 ///
4485 /// Note that the two types must have been created in the same @ref
4486 /// environment, otherwise, this function aborts.
4487 ///
4488 /// @param first a pointer to the first enum_type_decl to consider.
4489 ///
4490 /// @param second a pointer to the second enum_type_decl to consider.
4491 ///
4492 /// @return the resulting diff of the two enums @p first and @p
4493 /// second.
4494 ///
4495 /// @param ctxt the diff context to use.
4496 enum_diff_sptr
4498  const enum_type_decl_sptr second,
4499  diff_context_sptr ctxt)
4500 {
4501  diff_sptr ud = compute_diff_for_types(first->get_underlying_type(),
4502  second->get_underlying_type(),
4503  ctxt);
4504  enum_diff_sptr d(new enum_diff(first, second, ud, ctxt));
4505  if (first != second)
4506  {
4507  compute_diff(first->get_enumerators().begin(),
4508  first->get_enumerators().end(),
4509  second->get_enumerators().begin(),
4510  second->get_enumerators().end(),
4511  d->priv_->enumerators_changes_);
4512  d->ensure_lookup_tables_populated();
4513  }
4514  ctxt->initialize_canonical_diff(d);
4515 
4516  return d;
4517 }
4518 // </enum_diff stuff>
4519 
4520 // <class_or_union_diff stuff>
4521 
4522 /// Test if the current diff node carries a member type change for a
4523 /// member type which name is the same as the name of a given type
4524 /// declaration.
4525 ///
4526 /// @param d the type declaration which name should be equal to the
4527 /// name of the member type that might have changed.
4528 ///
4529 /// @return the member type that has changed, iff there were a member
4530 /// type (which name is the same as the name of @p d) that changed.
4531 /// Note that the member type that is returned is the new value of the
4532 /// member type that changed.
4535 {
4536  string qname = d->get_qualified_name();
4537  string_diff_sptr_map::const_iterator it =
4538  changed_member_types_.find(qname);
4539 
4540  return ((it == changed_member_types_.end())
4542  : it->second->second_subject());
4543 }
4544 
4545 /// Test if the current diff node carries a data member change for a
4546 /// data member which name is the same as the name of a given type
4547 /// declaration.
4548 ///
4549 /// @param d the type declaration which name should be equal to the
4550 /// name of the data member that might have changed.
4551 ///
4552 /// @return the data member that has changed, iff there were a data
4553 /// member type (which name is the same as the name of @p d) that
4554 /// changed. Note that the data member that is returned is the new
4555 /// value of the data member that changed.
4556 decl_base_sptr
4558 {
4559  string qname = d->get_qualified_name();
4560  string_var_diff_sptr_map::const_iterator it =
4561  subtype_changed_dm_.find(qname);
4562 
4563  if (it == subtype_changed_dm_.end())
4564  return decl_base_sptr();
4565  return it->second->second_var();
4566 }
4567 
4568 /// Test if the current diff node carries a member class template
4569 /// change for a member class template which name is the same as the
4570 /// name of a given type declaration.
4571 ///
4572 /// @param d the type declaration which name should be equal to the
4573 /// name of the member class template that might have changed.
4574 ///
4575 /// @return the member class template that has changed, iff there were
4576 /// a member class template (which name is the same as the name of @p
4577 /// d) that changed. Note that the member class template that is
4578 /// returned is the new value of the member class template that
4579 /// changed.
4580 decl_base_sptr
4582 {
4583  string qname = d->get_qualified_name();
4584  string_diff_sptr_map::const_iterator it =
4585  changed_member_class_tmpls_.find(qname);
4586 
4587  return ((it == changed_member_class_tmpls_.end())
4588  ? decl_base_sptr()
4589  : dynamic_pointer_cast<decl_base>(it->second->second_subject()));
4590 }
4591 
4592 /// Get the number of non static data members that were deleted.
4593 ///
4594 /// @return the number of non static data members that were deleted.
4595 size_t
4597 {
4598  size_t result = 0;
4599 
4600  for (string_decl_base_sptr_map::const_iterator i =
4601  deleted_data_members_.begin();
4602  i != deleted_data_members_.end();
4603  ++i)
4604  if (is_member_decl(i->second)
4605  && !get_member_is_static(i->second))
4606  ++result;
4607 
4608  return result;
4609 }
4610 
4611 /// Get the number of non static data members that were inserted.
4612 ///
4613 /// @return the number of non static data members that were inserted.
4614 size_t
4616 {
4617  size_t result = 0;
4618 
4619  for (string_decl_base_sptr_map::const_iterator i =
4620  inserted_data_members_.begin();
4621  i != inserted_data_members_.end();
4622  ++i)
4623  if (is_member_decl(i->second)
4624  && !get_member_is_static(i->second))
4625  ++result;
4626 
4627  return result;
4628 }
4629 
4630 /// Get the number of data member sub-type changes carried by the
4631 /// current diff node that were filtered out.
4632 ///
4633 /// @param local_only if true, it means that only (filtered) local
4634 /// changes are considered.
4635 ///
4636 /// @return the number of data member sub-type changes carried by the
4637 /// current diff node that were filtered out.
4638 size_t
4640 {
4641  size_t num_filtered= 0;
4642  for (var_diff_sptrs_type::const_iterator i =
4643  sorted_subtype_changed_dm_.begin();
4644  i != sorted_subtype_changed_dm_.end();
4645  ++i)
4646  {
4647  if (local_only)
4648  {
4649  if ((*i)->has_changes()
4650  && !(*i)->has_local_changes_to_be_reported())
4651  ++num_filtered;
4652  }
4653  else
4654  {
4655  if ((*i)->is_filtered_out())
4656  ++num_filtered;
4657  }
4658  }
4659  return num_filtered;
4660 }
4661 
4662 /// Get the number of data member changes carried by the current diff
4663 /// node that were filtered out.
4664 ///
4665 /// @param local_only if true, it means that only (filtered) local
4666 /// changes are considered.
4667 ///
4668 /// @return the number of data member changes carried by the current
4669 /// diff node that were filtered out.
4670 size_t
4672 {
4673  size_t num_filtered= 0;
4674 
4675  for (unsigned_var_diff_sptr_map::const_iterator i = changed_dm_.begin();
4676  i != changed_dm_.end();
4677  ++i)
4678  {
4679  diff_sptr diff = i->second;
4680  if (local_only)
4681  {
4683  || diff->is_filtered_out())
4684  ++num_filtered;
4685  }
4686  else
4687  {
4688  if (diff->is_filtered_out())
4689  ++num_filtered;
4690  }
4691  }
4692  return num_filtered;
4693 }
4694 
4695 /// Skip the processing of the current member function if its
4696 /// virtual-ness is disallowed by the user.
4697 ///
4698 /// This is to be used in the member functions below that are used to
4699 /// count the number of filtered inserted, deleted and changed member
4700 /// functions.
4701 #define SKIP_MEM_FN_IF_VIRTUALITY_DISALLOWED \
4702  do { \
4703  if (get_member_function_is_virtual(f) \
4704  || get_member_function_is_virtual(s)) \
4705  { \
4706  if (!(allowed_category | VIRTUAL_MEMBER_CHANGE_CATEGORY)) \
4707  continue; \
4708  } \
4709  else \
4710  { \
4711  if (!(allowed_category | NON_VIRT_MEM_FUN_CHANGE_CATEGORY)) \
4712  continue; \
4713  } \
4714  } while (false)
4715 
4716 /// Get the number of member functions changes carried by the current
4717 /// diff node that were filtered out.
4718 ///
4719 /// @return the number of member functions changes carried by the
4720 /// current diff node that were filtered out.
4721 size_t
4723 (const diff_context_sptr& ctxt)
4724 {
4725  size_t count = 0;
4726  diff_category allowed_category = ctxt->get_allowed_category();
4727 
4728  for (function_decl_diff_sptrs_type::const_iterator i =
4729  sorted_changed_member_functions_.begin();
4730  i != sorted_changed_member_functions_.end();
4731  ++i)
4732  {
4733  method_decl_sptr f =
4734  dynamic_pointer_cast<method_decl>
4735  ((*i)->first_function_decl());
4736  ABG_ASSERT(f);
4737 
4738  method_decl_sptr s =
4739  dynamic_pointer_cast<method_decl>
4740  ((*i)->second_function_decl());
4741  ABG_ASSERT(s);
4742 
4744 
4745  diff_sptr diff = *i;
4746  ctxt->maybe_apply_filters(diff);
4747 
4748  if (diff->is_filtered_out())
4749  ++count;
4750  }
4751 
4752  return count;
4753 }
4754 
4755 /// Get the number of member functions insertions carried by the current
4756 /// diff node that were filtered out.
4757 ///
4758 /// @return the number of member functions insertions carried by the
4759 /// current diff node that were filtered out.
4760 size_t
4762 (const diff_context_sptr& ctxt)
4763 {
4764  size_t count = 0;
4765  diff_category allowed_category = ctxt->get_allowed_category();
4766 
4767  for (string_member_function_sptr_map::const_iterator i =
4768  inserted_member_functions_.begin();
4769  i != inserted_member_functions_.end();
4770  ++i)
4771  {
4772  method_decl_sptr f = i->second,
4773  s = i->second;
4774 
4776 
4777  diff_sptr diff = compute_diff_for_decls(f, s, ctxt);
4778  ctxt->maybe_apply_filters(diff);
4779 
4781  && diff->is_filtered_out())
4782  ++count;
4783  }
4784 
4785  return count;
4786 }
4787 
4788 /// Get the number of member functions deletions carried by the current
4789 /// diff node that were filtered out.
4790 ///
4791 /// @return the number of member functions deletions carried by the
4792 /// current diff node that were filtered out.
4793 size_t
4795 (const diff_context_sptr& ctxt)
4796 {
4797  size_t count = 0;
4798  diff_category allowed_category = ctxt->get_allowed_category();
4799 
4800  for (string_member_function_sptr_map::const_iterator i =
4801  deleted_member_functions_.begin();
4802  i != deleted_member_functions_.end();
4803  ++i)
4804  {
4805  method_decl_sptr f = i->second,
4806  s = i->second;
4807 
4809 
4810  diff_sptr diff = compute_diff_for_decls(f, s, ctxt);
4811  ctxt->maybe_apply_filters(diff);
4812 
4814  && diff->is_filtered_out())
4815  ++count;
4816  }
4817 
4818  return count;
4819 }
4820 
4821 /// Clear the lookup tables useful for reporting.
4822 ///
4823 /// This function must be updated each time a lookup table is added or
4824 /// removed from the class_or_union_diff::priv.
4825 void
4827 {
4828  priv_->deleted_member_types_.clear();
4829  priv_->inserted_member_types_.clear();
4830  priv_->changed_member_types_.clear();
4831  priv_->deleted_data_members_.clear();
4832  priv_->inserted_data_members_.clear();
4833  priv_->subtype_changed_dm_.clear();
4834  priv_->deleted_member_functions_.clear();
4835  priv_->inserted_member_functions_.clear();
4836  priv_->changed_member_functions_.clear();
4837  priv_->deleted_member_class_tmpls_.clear();
4838  priv_->inserted_member_class_tmpls_.clear();
4839  priv_->changed_member_class_tmpls_.clear();
4840 }
4841 
4842 /// Tests if the lookup tables are empty.
4843 ///
4844 /// @return true if the lookup tables are empty, false otherwise.
4845 bool
4847 {
4848  return (priv_->deleted_member_types_.empty()
4849  && priv_->inserted_member_types_.empty()
4850  && priv_->changed_member_types_.empty()
4851  && priv_->deleted_data_members_.empty()
4852  && priv_->inserted_data_members_.empty()
4853  && priv_->subtype_changed_dm_.empty()
4854  && priv_->inserted_member_functions_.empty()
4855  && priv_->deleted_member_functions_.empty()
4856  && priv_->changed_member_functions_.empty()
4857  && priv_->deleted_member_class_tmpls_.empty()
4858  && priv_->inserted_member_class_tmpls_.empty()
4859  && priv_->changed_member_class_tmpls_.empty());
4860 }
4861 
4862 /// If the lookup tables are not yet built, walk the differences and
4863 /// fill them.
4864 void
4866 {
4867  {
4868  edit_script& e = priv_->member_types_changes_;
4869 
4870  for (vector<deletion>::const_iterator it = e.deletions().begin();
4871  it != e.deletions().end();
4872  ++it)
4873  {
4874  unsigned i = it->index();
4875  decl_base_sptr d =
4876  get_type_declaration(first_class_or_union()->get_member_types()[i]);
4877  class_or_union_sptr record_type = is_class_or_union_type(d);
4878  if (record_type && record_type->get_is_declaration_only())
4879  continue;
4880  string name = d->get_name();
4881  priv_->deleted_member_types_[name] = d;
4882  }
4883 
4884  for (vector<insertion>::const_iterator it = e.insertions().begin();
4885  it != e.insertions().end();
4886  ++it)
4887  {
4888  for (vector<unsigned>::const_iterator iit =
4889  it->inserted_indexes().begin();
4890  iit != it->inserted_indexes().end();
4891  ++iit)
4892  {
4893  unsigned i = *iit;
4894  decl_base_sptr d =
4895  get_type_declaration(second_class_or_union()->get_member_types()[i]);
4896  class_or_union_sptr record_type = is_class_or_union_type(d);
4897  if (record_type && record_type->get_is_declaration_only())
4898  continue;
4899  string name = d->get_name();
4900  string_decl_base_sptr_map::const_iterator j =
4901  priv_->deleted_member_types_.find(name);
4902  if (j != priv_->deleted_member_types_.end())
4903  {
4904  if (*j->second != *d)
4905  priv_->changed_member_types_[name] =
4906  compute_diff(j->second, d, context());
4907 
4908  priv_->deleted_member_types_.erase(j);
4909  }
4910  else
4911  priv_->inserted_member_types_[name] = d;
4912  }
4913  }
4914  }
4915 
4916  {
4917  edit_script& e = priv_->data_members_changes_;
4918 
4919  for (vector<deletion>::const_iterator it = e.deletions().begin();
4920  it != e.deletions().end();
4921  ++it)
4922  {
4923  unsigned i = it->index();
4924  var_decl_sptr data_member =
4925  is_var_decl(first_class_or_union()->get_non_static_data_members()[i]);
4926  string name = data_member->get_anon_dm_reliable_name();
4927 
4928  ABG_ASSERT(priv_->deleted_data_members_.find(name)
4929  == priv_->deleted_data_members_.end());
4930  priv_->deleted_data_members_[name] = data_member;
4931  }
4932 
4933  for (vector<insertion>::const_iterator it = e.insertions().begin();
4934  it != e.insertions().end();
4935  ++it)
4936  {
4937  for (vector<unsigned>::const_iterator iit =
4938  it->inserted_indexes().begin();
4939  iit != it->inserted_indexes().end();
4940  ++iit)
4941  {
4942  unsigned i = *iit;
4943  decl_base_sptr d =
4944  second_class_or_union()->get_non_static_data_members()[i];
4945  var_decl_sptr added_dm = is_var_decl(d);
4946  string name = added_dm->get_anon_dm_reliable_name();
4947  ABG_ASSERT(priv_->inserted_data_members_.find(name)
4948  == priv_->inserted_data_members_.end());
4949 
4950  bool ignore_added_anonymous_data_member = false;
4951  if (is_anonymous_data_member(added_dm))
4952  {
4953  //
4954  // Handle insertion of anonymous data member to
4955  // replace existing data members.
4956  //
4957  // For instance consider this:
4958  // struct S
4959  // {
4960  // int a;
4961  // int b;
4962  // int c;
4963  // };// end struct S
4964  //
4965  // Where the data members 'a' and 'b' are replaced
4966  // by an anonymous data member without changing the
4967  // effective bit layout of the structure:
4968  //
4969  // struct S
4970  // {
4971  // struct
4972  // {
4973  // union
4974  // {
4975  // int a;
4976  // char a_1;
4977  // };
4978  // union
4979  // {
4980  // int b;
4981  // char b_1;
4982  // };
4983  // };
4984  // int c;
4985  // }; // end struct S
4986  //
4987  var_decl_sptr replaced_dm, replacing_dm;
4988  bool added_anon_dm_changes_dm = false;
4989  // The vector of data members replaced by anonymous
4990  // data members.
4991  vector<var_decl_sptr> dms_replaced_by_anon_dm;
4992 
4993  //
4994  // Let's start collecting the set of data members
4995  // which have been replaced by anonymous types in a
4996  // harmless way. These are going to be collected into
4997  // dms_replaced_by_anon_dm and, ultimately, into
4998  // priv_->dms_replaced_by_adms_
4999  //
5000  for (string_decl_base_sptr_map::const_iterator it =
5001  priv_->deleted_data_members_.begin();
5002  it != priv_->deleted_data_members_.end();
5003  ++it)
5004  {
5005  // We don't support this pattern for anonymous
5006  // data members themselves being replaced. If
5007  // that occurs then we'll just report it verbatim.
5008  if (is_anonymous_data_member(it->second))
5009  continue;
5010 
5011  string deleted_dm_name = it->second->get_name();
5012  if ((replacing_dm =
5014  deleted_dm_name)))
5015  {
5016  // So it looks like replacing_dm might have
5017  // replaced the data member which name is
5018  // 'deleted_dm_name'. Let's look deeper to be
5019  // sure.
5020  //
5021  // Note that replacing_dm is part (member) of
5022  // an anonymous data member that might replace
5023  // replaced_dm.
5024 
5025  // So let's get that replaced data member.
5026  replaced_dm = is_var_decl(it->second);
5027  size_t replaced_dm_offset =
5028  get_data_member_offset(replaced_dm),
5029  replacing_dm_offset =
5030  get_absolute_data_member_offset(replacing_dm);
5031 
5032  if (replaced_dm_offset != replacing_dm_offset)
5033  {
5034  // So the replacing data member and the
5035  // replaced data member don't have the
5036  // same offset. This is not the pattern we
5037  // are looking for. Rather, it looks like
5038  // the anonymous data member has *changed*
5039  // the data member.
5040  added_anon_dm_changes_dm = true;
5041  break;
5042  }
5043 
5044  if (replaced_dm->get_type()->get_size_in_bits()
5045  == replaced_dm->get_type()->get_size_in_bits())
5046  dms_replaced_by_anon_dm.push_back(replaced_dm);
5047  else
5048  {
5049  added_anon_dm_changes_dm = true;
5050  break;
5051  }
5052  }
5053  }
5054 
5055  // Now walk dms_replaced_by_anon_dm to fill up
5056  // priv_->dms_replaced_by_adms_ with the set of data
5057  // members replaced by anonymous data members.
5058  if (!added_anon_dm_changes_dm
5059  && !dms_replaced_by_anon_dm.empty())
5060  {
5061  // See if the added data member isn't too big.
5062  type_base_sptr added_dm_type = added_dm->get_type();
5063  ABG_ASSERT(added_dm_type);
5064  var_decl_sptr new_next_dm =
5066  added_dm);
5067  var_decl_sptr old_next_dm =
5068  first_class_or_union()->find_data_member(new_next_dm);
5069 
5070  if (!old_next_dm
5071  || (old_next_dm
5072  && (get_absolute_data_member_offset(old_next_dm)
5073  == get_absolute_data_member_offset(new_next_dm))))
5074  {
5075  // None of the data members that are replaced
5076  // by the added union should be considered as
5077  // having been deleted.
5078  ignore_added_anonymous_data_member = true;
5079  for (vector<var_decl_sptr>::const_iterator i =
5080  dms_replaced_by_anon_dm.begin();
5081  i != dms_replaced_by_anon_dm.end();
5082  ++i)
5083  {
5084  string n = (*i)->get_name();
5085  priv_->dms_replaced_by_adms_[n] =
5086  added_dm;
5087  priv_->deleted_data_members_.erase(n);
5088  }
5089  }
5090  }
5091  }
5092 
5093  if (!ignore_added_anonymous_data_member)
5094  {
5095  // Detect changed data members.
5096  //
5097  // A changed data member (that we shall name D) is a data
5098  // member that satisfies the conditions below:
5099  //
5100  // 1/ It must have been added.
5101  //
5102  // 2/ It must have been deleted as well.
5103  //
5104  // 3/ It there must be a non-empty difference between the
5105  // deleted D and the added D.
5106  string_decl_base_sptr_map::const_iterator j =
5107  priv_->deleted_data_members_.find(name);
5108  if (j != priv_->deleted_data_members_.end())
5109  {
5110  if (*j->second != *d)
5111  {
5112  var_decl_sptr old_dm = is_var_decl(j->second);
5113  priv_->subtype_changed_dm_[name]=
5114  compute_diff(old_dm, added_dm, context());
5115  }
5116  priv_->deleted_data_members_.erase(j);
5117  }
5118  else
5119  priv_->inserted_data_members_[name] = d;
5120  }
5121  }
5122  }
5123 
5124  // Now detect when a data member is deleted from offset N and
5125  // another one is added to offset N. In that case, we want to be
5126  // able to say that the data member at offset N changed.
5127  for (string_decl_base_sptr_map::const_iterator i =
5128  priv_->deleted_data_members_.begin();
5129  i != priv_->deleted_data_members_.end();
5130  ++i)
5131  {
5132  unsigned offset = get_data_member_offset(i->second);
5133  priv_->deleted_dm_by_offset_[offset] = i->second;
5134  }
5135 
5136  for (string_decl_base_sptr_map::const_iterator i =
5137  priv_->inserted_data_members_.begin();
5138  i != priv_->inserted_data_members_.end();
5139  ++i)
5140  {
5141  unsigned offset = get_data_member_offset(i->second);
5142  priv_->inserted_dm_by_offset_[offset] = i->second;
5143  }
5144 
5145  for (unsigned_decl_base_sptr_map::const_iterator i =
5146  priv_->inserted_dm_by_offset_.begin();
5147  i != priv_->inserted_dm_by_offset_.end();
5148  ++i)
5149  {
5150  unsigned_decl_base_sptr_map::const_iterator j =
5151  priv_->deleted_dm_by_offset_.find(i->first);
5152  if (j != priv_->deleted_dm_by_offset_.end())
5153  {
5154  var_decl_sptr old_dm = is_var_decl(j->second);
5155  var_decl_sptr new_dm = is_var_decl(i->second);
5156  priv_->changed_dm_[i->first] =
5157  compute_diff(old_dm, new_dm, context());
5158  }
5159  }
5160 
5161  for (unsigned_var_diff_sptr_map::const_iterator i =
5162  priv_->changed_dm_.begin();
5163  i != priv_->changed_dm_.end();
5164  ++i)
5165  {
5166  priv_->deleted_dm_by_offset_.erase(i->first);
5167  priv_->inserted_dm_by_offset_.erase(i->first);
5168  priv_->deleted_data_members_.erase
5169  (i->second->first_var()->get_anon_dm_reliable_name());
5170  priv_->inserted_data_members_.erase
5171  (i->second->second_var()->get_anon_dm_reliable_name());
5172  }
5173  }
5174  sort_string_data_member_diff_sptr_map(priv_->subtype_changed_dm_,
5175  priv_->sorted_subtype_changed_dm_);
5176  sort_unsigned_data_member_diff_sptr_map(priv_->changed_dm_,
5177  priv_->sorted_changed_dm_);
5178 
5179  {
5180  edit_script& e = priv_->member_class_tmpls_changes_;
5181 
5182  for (vector<deletion>::const_iterator it = e.deletions().begin();
5183  it != e.deletions().end();
5184  ++it)
5185  {
5186  unsigned i = it->index();
5187  decl_base_sptr d =
5188  first_class_or_union()->get_member_class_templates()[i]->
5189  as_class_tdecl();
5190  string name = d->get_name();
5191  ABG_ASSERT(priv_->deleted_member_class_tmpls_.find(name)
5192  == priv_->deleted_member_class_tmpls_.end());
5193  priv_->deleted_member_class_tmpls_[name] = d;
5194  }
5195 
5196  for (vector<insertion>::const_iterator it = e.insertions().begin();
5197  it != e.insertions().end();
5198  ++it)
5199  {
5200  for (vector<unsigned>::const_iterator iit =
5201  it->inserted_indexes().begin();
5202  iit != it->inserted_indexes().end();
5203  ++iit)
5204  {
5205  unsigned i = *iit;
5206  decl_base_sptr d =
5207  second_class_or_union()->get_member_class_templates()[i]->
5208  as_class_tdecl();
5209  string name = d->get_name();
5210  ABG_ASSERT(priv_->inserted_member_class_tmpls_.find(name)
5211  == priv_->inserted_member_class_tmpls_.end());
5212  string_decl_base_sptr_map::const_iterator j =
5213  priv_->deleted_member_class_tmpls_.find(name);
5214  if (j != priv_->deleted_member_class_tmpls_.end())
5215  {
5216  if (*j->second != *d)
5217  priv_->changed_member_types_[name]=
5218  compute_diff(j->second, d, context());
5219  priv_->deleted_member_class_tmpls_.erase(j);
5220  }
5221  else
5222  priv_->inserted_member_class_tmpls_[name] = d;
5223  }
5224  }
5225  }
5226  sort_string_diff_sptr_map(priv_->changed_member_types_,
5227  priv_->sorted_changed_member_types_);
5228 }
5229 
5230 /// Allocate the memory for the priv_ pimpl data member of the @ref
5231 /// class_or_union_diff class.
5232 void
5234 {
5235  if (!priv_)
5236  priv_.reset(new priv);
5237 }
5238 
5239 /// Constructor for the @ref class_or_union_diff class.
5240 ///
5241 /// @param first_scope the first @ref class_or_union of the diff node.
5242 ///
5243 /// @param second_scope the second @ref class_or_union of the diff node.
5244 ///
5245 /// @param ctxt the context of the diff.
5246 class_or_union_diff::class_or_union_diff(class_or_union_sptr first_scope,
5247  class_or_union_sptr second_scope,
5248  diff_context_sptr ctxt)
5249  : type_diff_base(first_scope, second_scope, ctxt)
5250  //priv_(new priv)
5251 {}
5252 
5253 /// Getter of the private data of the @ref class_or_union_diff type.
5254 ///
5255 /// Note that due to an optimization, the private data of @ref
5256 /// class_or_union_diff can be shared among several instances of
5257 /// class_or_union_diff, so you should never try to access
5258 /// class_or_union_diff::priv directly.
5259 ///
5260 /// When class_or_union_diff::priv is shared, this function returns
5261 /// the correct shared one.
5262 ///
5263 /// @return the (possibly) shared private data of the current instance
5264 /// of @ref class_or_union_diff.
5265 const class_or_union_diff::priv_ptr&
5267 {
5268  if (priv_)
5269  return priv_;
5270 
5271  // If the current class_or_union_diff::priv member is empty, then look for
5272  // the shared one, from the canonical type.
5273  class_or_union_diff *canonical =
5274  dynamic_cast<class_or_union_diff*>(get_canonical_diff());
5275  ABG_ASSERT(canonical);
5276  ABG_ASSERT(canonical->priv_);
5277 
5278  return canonical->priv_;
5279 }
5280 
5281 /// Destructor of class_or_union_diff.
5283 {
5284 }
5285 
5286 /// @return the first @ref class_or_union involved in the diff.
5287 class_or_union_sptr
5290 
5291 /// @return the second @ref class_or_union involved in the diff.
5292 class_or_union_sptr
5295 
5296 /// @return the edit script of the member types of the two @ref
5297 /// class_or_union.
5298 const edit_script&
5300 {return get_priv()->member_types_changes_;}
5301 
5302 /// @return the edit script of the member types of the two @ref
5303 /// class_or_union.
5304 edit_script&
5306 {return get_priv()->member_types_changes_;}
5307 
5308 /// @return the edit script of the data members of the two @ref
5309 /// class_or_union.
5310 const edit_script&
5312 {return get_priv()->data_members_changes_;}
5313 
5314 /// @return the edit script of the data members of the two @ref
5315 /// class_or_union.
5316 edit_script&
5318 {return get_priv()->data_members_changes_;}
5319 
5320 /// Getter for the data members that got inserted.
5321 ///
5322 /// @return a map of data members that got inserted.
5325 {return get_priv()->inserted_data_members_;}
5326 
5327 /// Getter for the data members that got deleted.
5328 ///
5329 /// @return a map of data members that got deleted.
5332 {return get_priv()->deleted_data_members_;}
5333 
5334 /// @return the edit script of the member functions of the two @ref
5335 /// class_or_union.
5336 const edit_script&
5338 {return get_priv()->member_fns_changes_;}
5339 
5340 /// Getter for the virtual members functions that have had a change in
5341 /// a sub-type, without having a change in their symbol name.
5342 ///
5343 /// @return a sorted vector of virtual member functions that have a
5344 /// sub-type change.
5347 {return get_priv()->sorted_changed_member_functions_;}
5348 
5349 /// @return the edit script of the member functions of the two
5350 /// classes.
5351 edit_script&
5353 {return get_priv()->member_fns_changes_;}
5354 
5355 /// @return a map of member functions that got deleted.
5358 {return get_priv()->deleted_member_functions_;}
5359 
5360 /// @return a map of member functions that got inserted.
5363 {return get_priv()->inserted_member_functions_;}
5364 
5365 /// Getter of the sorted vector of data members that got replaced by
5366 /// another data member.
5367 ///
5368 /// @return sorted vector of changed data member.
5369 const var_diff_sptrs_type&
5371 {return get_priv()->sorted_changed_dm_;}
5372 
5373 /// Count the number of /filtered/ data members that got replaced by
5374 /// another data member.
5375 ///
5376 /// @return the number of changed data member that got filtered out.
5377 size_t
5379 {return get_priv()->count_filtered_changed_dm(local);}
5380 
5381 /// Getter of the sorted vector of data members with a (sub-)type change.
5382 ///
5383 /// @return sorted vector of changed data member.
5384 const var_diff_sptrs_type&
5386 {return get_priv()->sorted_subtype_changed_dm_;}
5387 
5388 /// Count the number of /filtered/ data members with a sub-type change.
5389 ///
5390 /// @return the number of changed data member that got filtered out.
5391 size_t
5393 {return get_priv()->count_filtered_subtype_changed_dm(local);}
5394 
5395 /// Get the map of data members that got replaced by anonymous data
5396 /// members.
5397 ///
5398 /// The key of a map entry is the name of the replaced data member and
5399 /// the value is the anonymous data member that replaces it.
5400 ///
5401 /// @return the map of data members replaced by anonymous data
5402 /// members.
5405 {return get_priv()->dms_replaced_by_adms_;}
5406 
5407 /// Get an ordered vector of of data members that got replaced by
5408 /// anonymous data members.
5409 ///
5410 /// This returns a vector of pair of two data members: the one that
5411 /// was replaced, and the anonymous data member that replaced it.
5412 ///
5413 /// @return the sorted vector data members replaced by anonymous data members.
5416 {
5417  if (priv_->dms_replaced_by_adms_ordered_.empty())
5418  {
5419  for (string_decl_base_sptr_map::const_iterator it =
5420  priv_->dms_replaced_by_adms_.begin();
5421  it != priv_->dms_replaced_by_adms_.end();
5422  ++it)
5423  {
5424  const var_decl_sptr dm =
5425  first_class_or_union()->find_data_member(it->first);
5426  ABG_ASSERT(dm);
5427  changed_var_sptr changed_dm(dm, is_data_member(it->second));
5428  priv_->dms_replaced_by_adms_ordered_.push_back(changed_dm);
5429  }
5430  sort_changed_data_members(priv_->dms_replaced_by_adms_ordered_);
5431  }
5432 
5433  return priv_->dms_replaced_by_adms_ordered_;
5434 }
5435 
5436 /// @return the edit script of the member function templates of the two
5437 /// @ref class_or_union.
5438 const edit_script&
5440 {return get_priv()->member_fn_tmpls_changes_;}
5441 
5442 /// @return the edit script of the member function templates of the
5443 /// two @ref class_or_union.
5444 edit_script&
5446 {return get_priv()->member_fn_tmpls_changes_;}
5447 
5448 /// @return the edit script of the member class templates of the two
5449 /// @ref class_or_union.
5450 const edit_script&
5452 {return get_priv()->member_class_tmpls_changes_;}
5453 
5454 /// @return the edit script of the member class templates of the two
5455 /// @ref class_or_union.
5456 edit_script&
5458 {return get_priv()->member_class_tmpls_changes_;}
5459 
5460 /// Test if the current diff node carries a change.
5461 bool
5464 
5465 /// @return the kind of local change carried by the current diff node.
5466 /// The value returned is zero if the current node carries no local
5467 /// change.
5468 enum change_kind
5470 {
5471  ir::change_kind k = ir::NO_CHANGE_KIND;
5473  return k & ir::ALL_LOCAL_CHANGES_MASK;
5474  return ir::NO_CHANGE_KIND;
5475 }
5476 
5477 
5478 /// Report the changes carried by the current @ref class_or_union_diff
5479 /// node in a textual format.
5480 ///
5481 /// @param out the output stream to write the textual report to.
5482 ///
5483 /// @param indent the number of white space to use as indentation.
5484 void
5485 class_or_union_diff::report(ostream& out, const string& indent) const
5486 {
5487  context()->get_reporter()->report(*this, out, indent);
5488 }
5489 
5490 /// Populate the vector of children node of the @ref diff base type
5491 /// sub-object of this instance of @ref class_or_union_diff.
5492 ///
5493 /// The children node can then later be retrieved using
5494 /// diff::children_node().
5495 void
5497 {
5498  // data member changes
5499  for (var_diff_sptrs_type::const_iterator i =
5500  get_priv()->sorted_subtype_changed_dm_.begin();
5501  i != get_priv()->sorted_subtype_changed_dm_.end();
5502  ++i)
5503  if (diff_sptr d = *i)
5504  append_child_node(d);
5505 
5506  for (var_diff_sptrs_type::const_iterator i =
5507  get_priv()->sorted_changed_dm_.begin();
5508  i != get_priv()->sorted_changed_dm_.end();
5509  ++i)
5510  if (diff_sptr d = *i)
5511  append_child_node(d);
5512 
5513  // member types changes
5514  for (diff_sptrs_type::const_iterator i =
5515  get_priv()->sorted_changed_member_types_.begin();
5516  i != get_priv()->sorted_changed_member_types_.end();
5517  ++i)
5518  if (diff_sptr d = *i)
5519  append_child_node(d);
5520 
5521  // member function changes
5522  for (function_decl_diff_sptrs_type::const_iterator i =
5523  get_priv()->sorted_changed_member_functions_.begin();
5524  i != get_priv()->sorted_changed_member_functions_.end();
5525  ++i)
5526  if (diff_sptr d = *i)
5527  append_child_node(d);
5528 }
5529 
5530 // </class_or_union_diff stuff>
5531 
5532 //<class_diff stuff>
5533 
5534 /// Clear the lookup tables useful for reporting.
5535 ///
5536 /// This function must be updated each time a lookup table is added or
5537 /// removed from the class_diff::priv.
5538 void
5539 class_diff::clear_lookup_tables(void)
5540 {
5541  priv_->deleted_bases_.clear();
5542  priv_->inserted_bases_.clear();
5543  priv_->changed_bases_.clear();
5544 }
5545 
5546 /// Tests if the lookup tables are empty.
5547 ///
5548 /// @return true if the lookup tables are empty, false otherwise.
5549 bool
5550 class_diff::lookup_tables_empty(void) const
5551 {
5552  return (priv_->deleted_bases_.empty()
5553  && priv_->inserted_bases_.empty()
5554  && priv_->changed_bases_.empty());
5555 }
5556 
5557 /// Find a virtual destructor in a map of member functions
5558 ///
5559 /// @param map the map of member functions. Note that the key of the
5560 /// map is the member function name. The key is the member function.
5561 ///
5562 /// @return an iterator to the destructor found or, if no virtual destructor
5563 /// was found, return map.end()
5564 static string_member_function_sptr_map::const_iterator
5565 find_virtual_dtor_in_map(const string_member_function_sptr_map& map)
5566 {
5567  for (string_member_function_sptr_map::const_iterator i = map.begin();
5568  i !=map.end();
5569  ++i)
5570  {
5571  if (get_member_function_is_dtor(i->second)
5572  && get_member_function_is_virtual(i->second))
5573  return i;
5574  }
5575  return map.end();
5576 }
5577 
5578 /// If the lookup tables are not yet built, walk the differences and
5579 /// fill them.
5580 void
5581 class_diff::ensure_lookup_tables_populated(void) const
5582 {
5584 
5585  if (!lookup_tables_empty())
5586  return;
5587 
5588  {
5589  edit_script& e = get_priv()->base_changes_;
5590 
5591  for (vector<deletion>::const_iterator it = e.deletions().begin();
5592  it != e.deletions().end();
5593  ++it)
5594  {
5595  unsigned i = it->index();
5597  first_class_decl()->get_base_specifiers()[i];
5598  string name = b->get_base_class()->get_qualified_name();
5599  ABG_ASSERT(get_priv()->deleted_bases_.find(name)
5600  == get_priv()->deleted_bases_.end());
5601  get_priv()->deleted_bases_[name] = b;
5602  }
5603 
5604  for (vector<insertion>::const_iterator it = e.insertions().begin();
5605  it != e.insertions().end();
5606  ++it)
5607  {
5608  for (vector<unsigned>::const_iterator iit =
5609  it->inserted_indexes().begin();
5610  iit != it->inserted_indexes().end();
5611  ++iit)
5612  {
5613  unsigned i = *iit;
5615  second_class_decl()->get_base_specifiers()[i];
5616  string name = b->get_base_class()->get_qualified_name();
5617  ABG_ASSERT(get_priv()->inserted_bases_.find(name)
5618  == get_priv()->inserted_bases_.end());
5619  string_base_sptr_map::const_iterator j =
5620  get_priv()->deleted_bases_.find(name);
5621  if (j != get_priv()->deleted_bases_.end())
5622  {
5623  if (j->second != b)
5624  get_priv()->changed_bases_[name] =
5625  compute_diff(j->second, b, context());
5626  else
5627  // The base class changed place. IOW, the base
5628  // classes got re-arranged. Let's keep track of the
5629  // base classes that moved.
5630  get_priv()->moved_bases_.push_back(b);
5631  get_priv()->deleted_bases_.erase(j);
5632  }
5633  else
5634  get_priv()->inserted_bases_[name] = b;
5635  }
5636  }
5637  }
5638 
5639  sort_string_base_sptr_map(get_priv()->deleted_bases_,
5640  get_priv()->sorted_deleted_bases_);
5641  sort_string_base_sptr_map(get_priv()->inserted_bases_,
5642  get_priv()->sorted_inserted_bases_);
5643  sort_string_base_diff_sptr_map(get_priv()->changed_bases_,
5644  get_priv()->sorted_changed_bases_);
5645 
5646  {
5647  const class_or_union_diff::priv_ptr &p = class_or_union_diff::get_priv();
5648 
5649  edit_script& e = p->member_fns_changes_;
5650 
5651  for (vector<deletion>::const_iterator it = e.deletions().begin();
5652  it != e.deletions().end();
5653  ++it)
5654  {
5655  unsigned i = it->index();
5656  method_decl_sptr mem_fn =
5657  first_class_decl()->get_virtual_mem_fns()[i];
5658  string name = mem_fn->get_linkage_name();
5659  if (name.empty())
5660  name = mem_fn->get_pretty_representation();
5661  ABG_ASSERT(!name.empty());
5662  if (p->deleted_member_functions_.find(name)
5663  != p->deleted_member_functions_.end())
5664  continue;
5665  p->deleted_member_functions_[name] = mem_fn;
5666  }
5667 
5668  for (vector<insertion>::const_iterator it = e.insertions().begin();
5669  it != e.insertions().end();
5670  ++it)
5671  {
5672  for (vector<unsigned>::const_iterator iit =
5673  it->inserted_indexes().begin();
5674  iit != it->inserted_indexes().end();
5675  ++iit)
5676  {
5677  unsigned i = *iit;
5678 
5679  method_decl_sptr mem_fn =
5680  second_class_decl()->get_virtual_mem_fns()[i];
5681  string name = mem_fn->get_linkage_name();
5682  if (name.empty())
5683  name = mem_fn->get_pretty_representation();
5684  ABG_ASSERT(!name.empty());
5685  if (p->inserted_member_functions_.find(name)
5686  != p->inserted_member_functions_.end())
5687  continue;
5688  string_member_function_sptr_map::const_iterator j =
5689  p->deleted_member_functions_.find(name);
5690 
5691  if (j != p->deleted_member_functions_.end())
5692  {
5693  if (*j->second != *mem_fn)
5694  p->changed_member_functions_[name] =
5695  compute_diff(static_pointer_cast<function_decl>(j->second),
5696  static_pointer_cast<function_decl>(mem_fn),
5697  context());
5698  p->deleted_member_functions_.erase(j);
5699  }
5700  else
5701  p->inserted_member_functions_[name] = mem_fn;
5702  }
5703  }
5704 
5705  // Now walk the allegedly deleted member functions; check if their
5706  // underlying symbols are deleted as well; otherwise, consider
5707  // that the member function in question hasn't been deleted.
5708 
5709  // Also, while walking the deleted member functions, we attend at
5710  // a particular cleanup business related to (virtual) C++
5711  // destructors:
5712  //
5713  // In the binary, there can be at least three types of
5714  // destructors, defined in the document
5715  // https://itanium-cxx-abi.github.io/cxx-abi/abi.html#definitions:
5716  //
5717  // 1/ Base object destructor (aka D2 destructor):
5718  //
5719  // "A function that runs the destructors for non-static data
5720  // members of T and non-virtual direct base classes of T. "
5721  //
5722  // 2/ Complete object destructor (aka D1 destructor):
5723  //
5724  // "A function that, in addition to the actions required of a
5725  // base object destructor, runs the destructors for the
5726  // virtual base classes of T."
5727  //
5728  // 3/ Deleting destructor (aka D0 destructor):
5729  //
5730  // "A function that, in addition to the actions required of a
5731  // complete object destructor, calls the appropriate
5732  // deallocation function (i.e,. operator delete) for T."
5733  //
5734  // With binaries generated by GCC, these destructors might be ELF
5735  // clones of each others, meaning, their ELF symbols can be
5736  // aliases.
5737  //
5738  // Also, note that because the actual destructor invoked by user
5739  // code is virtual, it's invoked through the vtable. So the
5740  // presence of the underlying D0, D1, D2 in the binary might vary
5741  // without that variation being an ABI issue, provided that the
5742  // destructor invoked through the vtable is present.
5743  //
5744  // So, a particular virtual destructor implementation for a class
5745  // might disapear and be replaced by another one in a subsequent
5746  // version of the binary. If all versions of the binary have an
5747  // actual virtual destructor, things might be considered fine.
5748  vector<string> to_delete;
5749  corpus_sptr f = context()->get_first_corpus(),
5750  s = context()->get_second_corpus();
5751  if (s)
5752  for (string_member_function_sptr_map::const_iterator i =
5753  deleted_member_fns().begin();
5754  i != deleted_member_fns().end();
5755  ++i)
5756  {
5757  if (get_member_function_is_virtual(i->second))
5758  {
5759  if (get_member_function_is_dtor(i->second))
5760  {
5761  // If a particular virtual destructor is deleted,
5762  // but the new binary still have a virtual
5763  // destructor for that class we consider that things
5764  // are fine. For instance, in the
5765  // tests/data/test-diff-pkg/tbb-4.1-9.20130314.fc22.x86_64--tbb-4.3-3.20141204.fc23.x86_64-report-0.txt
5766  // test, a new D4 destructor replaces the old ones.
5767  // But because the virtual destructor is still
5768  // there, this is not an ABI issue. So let's detect
5769  // this case.
5770  auto it =
5771  find_virtual_dtor_in_map(p->inserted_member_functions_);
5772  if (it != p->inserted_member_functions_.end())
5773  {
5774  // So the deleted virtual destructor is not
5775  // really deleted, because a proper virtual
5776  // destructor was added to the new version.
5777  // Let's remove the deleted/added virtual
5778  // destructor then.
5779  string name =
5780  (!i->second->get_linkage_name().empty())
5781  ? i->second->get_linkage_name()
5782  : i->second->get_pretty_representation();
5783  to_delete.push_back(name);
5784  p->inserted_member_functions_.erase(it);
5785  }
5786  }
5787  continue;
5788  }
5789  // We assume that all non-virtual member functions functions
5790  // we look at here have ELF symbols.
5791  if (!i->second->get_symbol()
5792  || s->lookup_function_symbol(*i->second->get_symbol()))
5793  to_delete.push_back(i->first);
5794  }
5795 
5796 
5797  for (vector<string>::const_iterator i = to_delete.begin();
5798  i != to_delete.end();
5799  ++i)
5800  p->deleted_member_functions_.erase(*i);
5801 
5802  // Do something similar for added functions.
5803  to_delete.clear();
5804  if (f)
5805  for (string_member_function_sptr_map::const_iterator i =
5806  inserted_member_fns().begin();
5807  i != inserted_member_fns().end();
5808  ++i)
5809  {
5810  if (get_member_function_is_virtual(i->second))
5811  continue;
5812  // We assume that all non-virtual member functions functions
5813  // we look at here have ELF symbols.
5814  if (!i->second->get_symbol()
5815  || f->lookup_function_symbol(*i->second->get_symbol()))
5816  to_delete.push_back(i->first);
5817  }
5818 
5819  for (vector<string>::const_iterator i = to_delete.begin();
5820  i != to_delete.end();
5821  ++i)
5822  p->inserted_member_functions_.erase(*i);
5823 
5824  sort_string_member_function_sptr_map(p->deleted_member_functions_,
5825  p->sorted_deleted_member_functions_);
5826 
5827  sort_string_member_function_sptr_map(p->inserted_member_functions_,
5828  p->sorted_inserted_member_functions_);
5829 
5831  (p->changed_member_functions_,
5832  p->sorted_changed_member_functions_);
5833  }
5834 }
5835 
5836 /// Allocate the memory for the priv_ pimpl data member of the @ref
5837 /// class_diff class.
5838 void
5839 class_diff::allocate_priv_data()
5840 {
5842  if (!priv_)
5843  priv_.reset(new priv);
5844 }
5845 
5846 /// Test whether a given base class has changed. A base class has
5847 /// changed if it's in both in deleted *and* inserted bases.
5848 ///
5849 ///@param d the declaration for the base class to consider.
5850 ///
5851 /// @return the new base class if the given base class has changed, or
5852 /// NULL if it hasn't.
5855 {
5856  string qname = d->get_base_class()->get_qualified_name();
5857  string_base_diff_sptr_map::const_iterator it =
5858  changed_bases_.find(qname);
5859 
5860  return (it == changed_bases_.end())
5862  : it->second->second_base();
5863 
5864 }
5865 
5866 /// Count the number of bases classes whose changes got filtered out.
5867 ///
5868 /// @return the number of bases classes whose changes got filtered
5869 /// out.
5870 size_t
5872 {
5873  size_t num_filtered = 0;
5874  for (base_diff_sptrs_type::const_iterator i = sorted_changed_bases_.begin();
5875  i != sorted_changed_bases_.end();
5876  ++i)
5877  {
5878  diff_sptr diff = *i;
5879  if (diff && diff->is_filtered_out())
5880  ++num_filtered;
5881  }
5882  return num_filtered;
5883 }
5884 
5885 /// Populate the vector of children node of the @ref diff base type
5886 /// sub-object of this instance of @ref class_diff.
5887 ///
5888 /// The children node can then later be retrieved using
5889 /// diff::children_node().
5890 void
5892 {
5894 
5895  // base class changes.
5896  for (base_diff_sptrs_type::const_iterator i =
5897  get_priv()->sorted_changed_bases_.begin();
5898  i != get_priv()->sorted_changed_bases_.end();
5899  ++i)
5900  if (diff_sptr d = *i)
5901  append_child_node(d);
5902 }
5903 
5904 /// Constructor of class_diff
5905 ///
5906 /// @param first_scope the first class of the diff.
5907 ///
5908 /// @param second_scope the second class of the diff.
5909 ///
5910 /// @param ctxt the diff context to use.
5912  class_decl_sptr second_scope,
5913  diff_context_sptr ctxt)
5914  : class_or_union_diff(first_scope, second_scope, ctxt)
5915  // We don't initialize the priv_ data member here. This is an
5916  // optimization to reduce memory consumption (and also execution
5917  // time) for cases where there are a lot of instances of
5918  // class_diff in the same equivalence class. In compute_diff(),
5919  // the priv_ is set to the priv_ of the canonical diff node.
5920  // See PR libabigail/17948.
5921 {}
5922 
5923 class_diff::~class_diff()
5924 {}
5925 
5926 /// Getter of the private data of the @ref class_diff type.
5927 ///
5928 /// Note that due to an optimization, the private data of @ref
5929 /// class_diff can be shared among several instances of class_diff, so
5930 /// you should never try to access class_diff::priv directly.
5931 ///
5932 /// When class_diff::priv is shared, this function returns the correct
5933 /// shared one.
5934 ///
5935 /// @return the (possibly) shared private data of the current instance
5936 /// of class_diff.
5937 const class_diff::priv_ptr&
5938 class_diff::get_priv() const
5939 {
5940  if (priv_)
5941  return priv_;
5942 
5943  // If the current class_diff::priv member is empty, then look for
5944  // the shared one, from the canonical type.
5945  class_diff *canonical =
5946  dynamic_cast<class_diff*>(get_canonical_diff());
5947  ABG_ASSERT(canonical);
5948  ABG_ASSERT(canonical->priv_);
5949 
5950  return canonical->priv_;
5951 }
5952 
5953 /// @return the pretty representation of the current instance of @ref
5954 /// class_diff.
5955 const string&
5957 {
5958  if (diff::priv_->pretty_representation_.empty())
5959  {
5960  std::ostringstream o;
5961  o << "class_diff["
5962  << first_subject()->get_pretty_representation()
5963  << ", "
5964  << second_subject()->get_pretty_representation()
5965  << "]";
5966  diff::priv_->pretty_representation_ = o.str();
5967  }
5968  return diff::priv_->pretty_representation_;
5969 }
5970 
5971 /// Return true iff the current diff node carries a change.
5972 ///
5973 /// @return true iff the current diff node carries a change.
5974 bool
5976 {return (first_class_decl() != second_class_decl());}
5977 
5978 /// @return the kind of local change carried by the current diff node.
5979 /// The value returned is zero if the current node carries no local
5980 /// change.
5981 enum change_kind
5983 {
5984  ir::change_kind k = ir::NO_CHANGE_KIND;
5985  if (!equals(*first_class_decl(), *second_class_decl(), &k))
5986  return k & ir::ALL_LOCAL_CHANGES_MASK;
5987  return ir::NO_CHANGE_KIND;
5988 }
5989 
5990 /// @return the first class invoveld in the diff.
5991 shared_ptr<class_decl>
5993 {return dynamic_pointer_cast<class_decl>(first_subject());}
5994 
5995 /// Getter of the second class involved in the diff.
5996 ///
5997 /// @return the second class invoveld in the diff
5998 shared_ptr<class_decl>
6000 {return dynamic_pointer_cast<class_decl>(second_subject());}
6001 
6002 /// @return the edit script of the bases of the two classes.
6003 const edit_script&
6005 {return get_priv()->base_changes_;}
6006 
6007 /// Getter for the deleted base classes of the diff.
6008 ///
6009 /// @return a map containing the deleted base classes, keyed with
6010 /// their pretty representation.
6011 const string_base_sptr_map&
6013 {return get_priv()->deleted_bases_;}
6014 
6015 /// Getter for the inserted base classes of the diff.
6016 ///
6017 /// @return a map containing the inserted base classes, keyed with
6018 /// their pretty representation.
6019 const string_base_sptr_map&
6021 {return get_priv()->inserted_bases_;}
6022 
6023 /// Getter for the changed base classes of the diff.
6024 ///
6025 /// @return a sorted vector containing the changed base classes
6026 const base_diff_sptrs_type&
6028 {return get_priv()->sorted_changed_bases_;}
6029 
6030 /// Getter for the vector of bases that "moved".
6031 /// That is, the vector of base types which position changed. If this
6032 /// vector is not empty, it means the bases of the underlying class
6033 /// type got re-ordered.
6034 ///
6035 /// @return the vector of bases that moved.
6036 const vector<class_decl::base_spec_sptr>&
6038 {return get_priv()->moved_bases_;}
6039 
6040 /// @return the edit script of the bases of the two classes.
6041 edit_script&
6043 {return get_priv()->base_changes_;}
6044 
6045 /// Produce a basic report about the changes between two class_decl.
6046 ///
6047 /// @param out the output stream to report the changes to.
6048 ///
6049 /// @param indent the string to use as an indentation prefix in the
6050 /// report.
6051 void
6052 class_diff::report(ostream& out, const string& indent) const
6053 {
6054  context()->get_reporter()->report(*this, out, indent);
6055 }
6056 
6057 /// Compute the set of changes between two instances of class_decl.
6058 ///
6059 /// Note that the two types must have been created in the same @ref
6060 /// environment, otherwise, this function aborts.
6061 ///
6062 /// @param first the first class_decl to consider.
6063 ///
6064 /// @param second the second class_decl to consider.
6065 ///
6066 /// @return changes the resulting changes.
6067 ///
6068 /// @param ctxt the diff context to use.
6071  const class_decl_sptr second,
6072  diff_context_sptr ctxt)
6073 {
6076 
6077  class_diff_sptr changes(new class_diff(f, s, ctxt));
6078 
6079  ctxt->initialize_canonical_diff(changes);
6080  ABG_ASSERT(changes->get_canonical_diff());
6081 
6082  if (!ctxt->get_canonical_diff_for(first, second))
6083  {
6084  // Either first or second is a decl-only class; let's set the
6085  // canonical diff here in that case.
6086  diff_sptr canonical_diff = ctxt->get_canonical_diff_for(changes);
6087  ABG_ASSERT(canonical_diff);
6088  ctxt->set_canonical_diff_for(first, second, canonical_diff);
6089  }
6090 
6091  // Ok, so this is an optimization. Do not freak out if it looks
6092  // weird, because, well, it does look weird. This speeds up
6093  // greatly, for instance, the test case given at PR
6094  // libabigail/17948.
6095  //
6096  // We are setting the private data of the new instance of class_diff
6097  // (which is 'changes') to the private data of its canonical
6098  // instance. That is, we are sharing the private data of 'changes'
6099  // with the private data of its canonical instance to consume less
6100  // memory in cases where the equivalence class of 'changes' is huge.
6101  //
6102  // But if changes is its own canonical instance, then we initialize
6103  // its private data properly
6104  if (is_class_diff(changes->get_canonical_diff()) == changes.get())
6105  // changes is its own canonical instance, so it gets a brand new
6106  // private data.
6107  changes->allocate_priv_data();
6108  else
6109  {
6110  // changes has a non-empty equivalence class so it's going to
6111  // share its private data with its canonical instance. Next
6112  // time class_diff::get_priv() is invoked, it's going to return
6113  // the shared private data of the canonical instance.
6114  return changes;
6115  }
6116 
6117  // Compare base specs
6118  compute_diff(f->get_base_specifiers().begin(),
6119  f->get_base_specifiers().end(),
6120  s->get_base_specifiers().begin(),
6121  s->get_base_specifiers().end(),
6122  changes->base_changes());
6123 
6124  // Do *not* compare member types because it generates lots of noise
6125  // and I doubt it's really useful.
6126 #if 0
6127  compute_diff(f->get_member_types().begin(),
6128  f->get_member_types().end(),
6129  s->get_member_types().begin(),
6130  s->get_member_types().end(),
6131  changes->member_types_changes());
6132 #endif
6133 
6134  // Compare data member
6135  compute_diff(f->get_non_static_data_members().begin(),
6136  f->get_non_static_data_members().end(),
6137  s->get_non_static_data_members().begin(),
6138  s->get_non_static_data_members().end(),
6139  changes->data_members_changes());
6140 
6141  // Compare virtual member functions
6142  compute_diff(f->get_virtual_mem_fns().begin(),
6143  f->get_virtual_mem_fns().end(),
6144  s->get_virtual_mem_fns().begin(),
6145  s->get_virtual_mem_fns().end(),
6146  changes->member_fns_changes());
6147 
6148  // Compare member function templates
6149  compute_diff(f->get_member_function_templates().begin(),
6150  f->get_member_function_templates().end(),
6151  s->get_member_function_templates().begin(),
6152  s->get_member_function_templates().end(),
6153  changes->member_fn_tmpls_changes());
6154 
6155  // Likewise, do not compare member class templates
6156 #if 0
6157  compute_diff(f->get_member_class_templates().begin(),
6158  f->get_member_class_templates().end(),
6159  s->get_member_class_templates().begin(),
6160  s->get_member_class_templates().end(),
6161  changes->member_class_tmpls_changes());
6162 #endif
6163 
6164  changes->ensure_lookup_tables_populated();
6165 
6166  return changes;
6167 }
6168 
6169 //</class_diff stuff>
6170 
6171 // <base_diff stuff>
6172 
6173 /// Populate the vector of children node of the @ref diff base type
6174 /// sub-object of this instance of @ref base_diff.
6175 ///
6176 /// The children node can then later be retrieved using
6177 /// diff::children_node().
6178 void
6181 
6182 /// @param first the first base spec to consider.
6183 ///
6184 /// @param second the second base spec to consider.
6185 ///
6186 /// @param ctxt the context of the diff. Note that this context
6187 /// object must stay alive at least during the life time of the
6188 /// current instance of @ref base_diff. Otherwise memory corruption
6189 /// issues occur.
6192  class_diff_sptr underlying,
6193  diff_context_sptr ctxt)
6194  : diff(first, second, ctxt),
6195  priv_(new priv(underlying))
6196 {}
6197 
6198 /// Getter for the first base spec of the diff object.
6199 ///
6200 /// @return the first base specifier for the diff object.
6203 {return dynamic_pointer_cast<class_decl::base_spec>(first_subject());}
6204 
6205 /// Getter for the second base spec of the diff object.
6206 ///
6207 /// @return the second base specifier for the diff object.
6210 {return dynamic_pointer_cast<class_decl::base_spec>(second_subject());}
6211 
6212 /// Getter for the diff object for the diff of the underlying base
6213 /// classes.
6214 ///
6215 /// @return the diff object for the diff of the underlying base
6216 /// classes.
6217 const class_diff_sptr
6219 {return priv_->underlying_class_diff_;}
6220 
6221 /// Setter for the diff object for the diff of the underlyng base
6222 /// classes.
6223 ///
6224 /// @param d the new diff object for the diff of the underlying base
6225 /// classes.
6226 void
6228 {priv_->underlying_class_diff_ = d;}
6229 
6230 /// @return the pretty representation for the current instance of @ref
6231 /// base_diff.
6232 const string&
6234 {
6235  if (diff::priv_->pretty_representation_.empty())
6236  {
6237  std::ostringstream o;
6238  o << "base_diff["
6239  << first_subject()->get_pretty_representation()
6240  << ", "
6241  << second_subject()->get_pretty_representation()
6242  << "]";
6243  diff::priv_->pretty_representation_ = o.str();
6244  }
6245  return diff::priv_->pretty_representation_;
6246 }
6247 
6248 /// Return true iff the current diff node carries a change.
6249 ///
6250 /// Return true iff the current diff node carries a change.
6251 bool
6253 {return first_base() != second_base();}
6254 
6255 /// @return the kind of local change carried by the current diff node.
6256 /// The value returned is zero if the current node carries no local
6257 /// change.
6258 enum change_kind
6260 {
6261  ir::change_kind k = ir::NO_CHANGE_KIND;
6262  if (!equals(*first_base(), *second_base(), &k))
6263  return k & ir::ALL_LOCAL_CHANGES_MASK;
6264  return ir::NO_CHANGE_KIND;
6265 }
6266 
6267 /// Generates a report for the current instance of base_diff.
6268 ///
6269 /// @param out the output stream to send the report to.
6270 ///
6271 /// @param indent the string to use for indentation.
6272 void
6273 base_diff::report(ostream& out, const string& indent) const
6274 {
6275  context()->get_reporter()->report(*this, out, indent);
6276 }
6277 
6278 /// Constructs the diff object representing a diff between two base
6279 /// class specifications.
6280 ///
6281 /// Note that the two artifacts must have been created in the same
6282 /// @ref environment, otherwise, this function aborts.
6283 ///
6284 /// @param first the first base class specification.
6285 ///
6286 /// @param second the second base class specification.
6287 ///
6288 /// @param ctxt the content of the diff.
6289 ///
6290 /// @return the resulting diff object.
6293  const class_decl::base_spec_sptr second,
6294  diff_context_sptr ctxt)
6295 {
6296  class_diff_sptr cl = compute_diff(first->get_base_class(),
6297  second->get_base_class(),
6298  ctxt);
6299  base_diff_sptr changes(new base_diff(first, second, cl, ctxt));
6300 
6301  ctxt->initialize_canonical_diff(changes);
6302 
6303  return changes;
6304 }
6305 
6306 // </base_diff stuff>
6307 
6308 
6309 // <union_diff stuff>
6310 
6311 /// Clear the lookup tables useful for reporting.
6312 ///
6313 /// This function must be updated each time a lookup table is added or
6314 /// removed from the union_diff::priv.
6315 void
6316 union_diff::clear_lookup_tables(void)
6318 
6319 /// Tests if the lookup tables are empty.
6320 ///
6321 /// @return true if the lookup tables are empty, false otherwise.
6322 bool
6323 union_diff::lookup_tables_empty(void) const
6325 
6326 /// If the lookup tables are not yet built, walk the differences and
6327 /// fill them.
6328 void
6329 union_diff::ensure_lookup_tables_populated(void) const
6331 
6332 /// Allocate the memory for the priv_ pimpl data member of the @ref
6333 /// union_diff class.
6334 void
6335 union_diff::allocate_priv_data()
6336 {
6338 }
6339 
6340 /// Constructor for the @ref union_diff type.
6341 ///
6342 /// @param first_union the first object of the comparison.
6343 ///
6344 /// @param second_union the second object of the comparison.
6345 ///
6346 /// @param ctxt the context of the comparison.
6347 union_diff::union_diff(union_decl_sptr first_union,
6348  union_decl_sptr second_union,
6349  diff_context_sptr ctxt)
6350  : class_or_union_diff(first_union, second_union, ctxt)
6351 {}
6352 
6353 /// Destructor of the union_diff node.
6355 {}
6356 
6357 /// @return the first object of the comparison.
6358 union_decl_sptr
6360 {return is_union_type(first_subject());}
6361 
6362 /// @return the second object of the comparison.
6363 union_decl_sptr
6365 {return is_union_type(second_subject());}
6366 
6367 /// @return the pretty representation of the current diff node.
6368 const string&
6370 {
6371  if (diff::priv_->pretty_representation_.empty())
6372  {
6373  std::ostringstream o;
6374  o << "union_diff["
6375  << first_subject()->get_pretty_representation()
6376  << ", "
6377  << second_subject()->get_pretty_representation()
6378  << "]";
6379  diff::priv_->pretty_representation_ = o.str();
6380  }
6381  return diff::priv_->pretty_representation_;
6382 }
6383 
6384 /// Report the changes carried by the current @ref union_diff node in
6385 /// a textual format.
6386 ///
6387 /// @param out the output stream to write the textual report to.
6388 ///
6389 /// @param indent the number of white space to use as indentation.
6390 void
6391 union_diff::report(ostream& out, const string& indent) const
6392 {
6393  context()->get_reporter()->report(*this, out, indent);
6394 }
6395 
6396 /// Compute the difference between two @ref union_decl types.
6397 ///
6398 /// Note that the two types must hav been created in the same
6399 /// environment, otherwise, this function aborts.
6400 ///
6401 /// @param first the first @ref union_decl to consider.
6402 ///
6403 /// @param second the second @ref union_decl to consider.
6404 ///
6405 /// @param ctxt the context of the diff to use.
6406 union_diff_sptr
6407 compute_diff(const union_decl_sptr first,
6408  const union_decl_sptr second,
6409  diff_context_sptr ctxt)
6410 {
6411  union_diff_sptr changes(new union_diff(first, second, ctxt));
6412 
6413  ctxt->initialize_canonical_diff(changes);
6414  ABG_ASSERT(changes->get_canonical_diff());
6415 
6416  // Ok, so this is an optimization. Do not freak out if it looks
6417  // weird, because, well, it does look weird. This speeds up
6418  // greatly, for instance, the test case given at PR
6419  // libabigail/17948.
6420  //
6421  // We are setting the private data of the new instance of class_diff
6422  // (which is 'changes') to the private data of its canonical
6423  // instance. That is, we are sharing the private data of 'changes'
6424  // with the private data of its canonical instance to consume less
6425  // memory in cases where the equivalence class of 'changes' is huge.
6426  //
6427  // But if changes is its own canonical instance, then we initialize
6428  // its private data properly.
6429  if (is_union_diff(changes->get_canonical_diff()) == changes.get())
6430  // changes is its own canonical instance, so it gets a brand new
6431  // private data.
6432  changes->allocate_priv_data();
6433  else
6434  {
6435  // changes has a non-empty equivalence class so it's going to
6436  // share its private data with its canonical instance. Next
6437  // time class_diff::get_priv() is invoked, it's going to return
6438  // the shared private data of the canonical instance.
6439  return changes;
6440  }
6441 
6442  // Compare data member
6443  compute_diff(first->get_non_static_data_members().begin(),
6444  first->get_non_static_data_members().end(),
6445  second->get_non_static_data_members().begin(),
6446  second->get_non_static_data_members().end(),
6447  changes->data_members_changes());
6448 
6449 #if 0
6450  // Compare member functions
6451  compute_diff(first->get_mem_fns().begin(),
6452  first->get_mem_fns().end(),
6453  second->get_mem_fns().begin(),
6454  second->get_mem_fns().end(),
6455  changes->member_fns_changes());
6456 
6457  // Compare member function templates
6458  compute_diff(first->get_member_function_templates().begin(),
6459  first->get_member_function_templates().end(),
6460  second->get_member_function_templates().begin(),
6461  second->get_member_function_templates().end(),
6462  changes->member_fn_tmpls_changes());
6463 #endif
6464 
6465  changes->ensure_lookup_tables_populated();
6466 
6467  return changes;
6468 }
6469 
6470 // </union_diff stuff>
6471 
6472 //<scope_diff stuff>
6473 
6474 /// Clear the lookup tables that are useful for reporting.
6475 ///
6476 /// This function must be updated each time a lookup table is added or
6477 /// removed.
6478 void
6479 scope_diff::clear_lookup_tables()
6480 {
6481  priv_->deleted_types_.clear();
6482  priv_->deleted_decls_.clear();
6483  priv_->inserted_types_.clear();
6484  priv_->inserted_decls_.clear();
6485  priv_->changed_types_.clear();
6486  priv_->changed_decls_.clear();
6487  priv_->removed_types_.clear();
6488  priv_->removed_decls_.clear();
6489  priv_->added_types_.clear();
6490  priv_->added_decls_.clear();
6491 }
6492 
6493 /// Tests if the lookup tables are empty.
6494 ///
6495 /// This function must be updated each time a lookup table is added or
6496 /// removed.
6497 ///
6498 /// @return true iff all the lookup tables are empty.
6499 bool
6500 scope_diff::lookup_tables_empty() const
6501 {
6502  return (priv_->deleted_types_.empty()
6503  && priv_->deleted_decls_.empty()
6504  && priv_->inserted_types_.empty()
6505  && priv_->inserted_decls_.empty()
6506  && priv_->changed_types_.empty()
6507  && priv_->changed_decls_.empty()
6508  && priv_->removed_types_.empty()
6509  && priv_->removed_decls_.empty()
6510  && priv_->added_types_.empty()
6511  && priv_->added_decls_.empty());
6512 }
6513 
6514 /// If the lookup tables are not yet built, walk the member_changes_
6515 /// member and fill the lookup tables.
6516 void
6517 scope_diff::ensure_lookup_tables_populated()
6518 {
6519  if (!lookup_tables_empty())
6520  return;
6521 
6522  edit_script& e = priv_->member_changes_;
6523 
6524  // Populate deleted types & decls lookup tables.
6525  for (const auto& deletion : e.deletions())
6526  {
6527  unsigned i = deletion.index();
6528  decl_base_sptr decl = deleted_member_at(i);
6529  string qname = decl->get_qualified_name();
6530  if (is_type(decl))
6531  {
6532  class_decl_sptr klass_decl = dynamic_pointer_cast<class_decl>(decl);
6533  if (klass_decl && klass_decl->get_is_declaration_only())
6534  continue;
6535 
6536  ABG_ASSERT(priv_->deleted_types_.find(qname)
6537  == priv_->deleted_types_.end());
6538  priv_->deleted_types_[qname] = decl;
6539  }
6540  else
6541  {
6542  ABG_ASSERT(priv_->deleted_decls_.find(qname)
6543  == priv_->deleted_decls_.end());
6544  priv_->deleted_decls_[qname] = decl;
6545  }
6546  }
6547 
6548  // Populate inserted types & decls as well as chagned types & decls
6549  // lookup tables.
6550  for (vector<insertion>::const_iterator it = e.insertions().begin();
6551  it != e.insertions().end();
6552  ++it)
6553  {
6554  for (vector<unsigned>::const_iterator i = it->inserted_indexes().begin();
6555  i != it->inserted_indexes().end();
6556  ++i)
6557  {
6558  decl_base_sptr decl = inserted_member_at(i);
6559  string qname = decl->get_qualified_name();
6560  if (is_type(decl))
6561  {
6562  class_decl_sptr klass_decl =
6563  dynamic_pointer_cast<class_decl>(decl);
6564  if (klass_decl && klass_decl->get_is_declaration_only())
6565  continue;
6566 
6567  ABG_ASSERT(priv_->inserted_types_.find(qname)
6568  == priv_->inserted_types_.end());
6569  string_decl_base_sptr_map::const_iterator j =
6570  priv_->deleted_types_.find(qname);
6571  if (j != priv_->deleted_types_.end())
6572  {
6573  if (*j->second != *decl)
6574  priv_->changed_types_[qname] =
6575  compute_diff(j->second, decl, context());
6576  priv_->deleted_types_.erase(j);
6577  }
6578  else
6579  priv_->inserted_types_[qname] = decl;
6580  }
6581  else
6582  {
6583  ABG_ASSERT(priv_->inserted_decls_.find(qname)
6584  == priv_->inserted_decls_.end());
6585  string_decl_base_sptr_map::const_iterator j =
6586  priv_->deleted_decls_.find(qname);
6587  if (j != priv_->deleted_decls_.end())
6588  {
6589  if (*j->second != *decl)
6590  priv_->changed_decls_[qname] =
6591  compute_diff(j->second, decl, context());
6592  priv_->deleted_decls_.erase(j);
6593  }
6594  else
6595  priv_->inserted_decls_[qname] = decl;
6596  }
6597  }
6598  }
6599 
6600  sort_string_diff_sptr_map(priv_->changed_decls_,
6601  priv_->sorted_changed_decls_);
6602  sort_string_diff_sptr_map(priv_->changed_types_,
6603  priv_->sorted_changed_types_);
6604 
6605  // Populate removed types/decls lookup tables
6606  for (string_decl_base_sptr_map::const_iterator i =
6607  priv_->deleted_types_.begin();
6608  i != priv_->deleted_types_.end();
6609  ++i)
6610  {
6611  string_decl_base_sptr_map::const_iterator r =
6612  priv_->inserted_types_.find(i->first);
6613  if (r == priv_->inserted_types_.end())
6614  priv_->removed_types_[i->first] = i->second;
6615  }
6616  for (string_decl_base_sptr_map::const_iterator i =
6617  priv_->deleted_decls_.begin();
6618  i != priv_->deleted_decls_.end();
6619  ++i)
6620  {
6621  string_decl_base_sptr_map::const_iterator r =
6622  priv_->inserted_decls_.find(i->first);
6623  if (r == priv_->inserted_decls_.end())
6624  priv_->removed_decls_[i->first] = i->second;
6625  }
6626 
6627  // Populate added types/decls.
6628  for (string_decl_base_sptr_map::const_iterator i =
6629  priv_->inserted_types_.begin();
6630  i != priv_->inserted_types_.end();
6631  ++i)
6632  {
6633  string_decl_base_sptr_map::const_iterator r =
6634  priv_->deleted_types_.find(i->first);
6635  if (r == priv_->deleted_types_.end())
6636  priv_->added_types_[i->first] = i->second;
6637  }
6638  for (string_decl_base_sptr_map::const_iterator i =
6639  priv_->inserted_decls_.begin();
6640  i != priv_->inserted_decls_.end();
6641  ++i)
6642  {
6643  string_decl_base_sptr_map::const_iterator r =
6644  priv_->deleted_decls_.find(i->first);
6645  if (r == priv_->deleted_decls_.end())
6646  priv_->added_decls_[i->first] = i->second;
6647  }
6648 }
6649 
6650 /// Populate the vector of children node of the @ref diff base type
6651 /// sub-object of this instance of @ref scope_diff.
6652 ///
6653 /// The children node can then later be retrieved using
6654 /// diff::children_node().
6655 void
6657 {
6658  for (diff_sptrs_type::const_iterator i = changed_types().begin();
6659  i != changed_types().end();
6660  ++i)
6661  if (*i)
6662  append_child_node(*i);
6663 
6664  for (diff_sptrs_type::const_iterator i = changed_decls().begin();
6665  i != changed_decls().end();
6666  ++i)
6667  if (*i)
6668  append_child_node(*i);
6669 }
6670 
6671 /// Constructor for scope_diff
6672 ///
6673 /// @param first_scope the first scope to consider for the diff.
6674 ///
6675 /// @param second_scope the second scope to consider for the diff.
6676 ///
6677 /// @param ctxt the diff context to use. Note that this context
6678 /// object must stay alive at least during the life time of the
6679 /// current instance of @ref scope_diff. Otherwise memory corruption
6680 /// issues occur.
6682  scope_decl_sptr second_scope,
6683  diff_context_sptr ctxt)
6684  : diff(first_scope, second_scope, ctxt),
6685  priv_(new priv)
6686 {}
6687 
6688 /// Getter for the first scope of the diff.
6689 ///
6690 /// @return the first scope of the diff.
6691 const scope_decl_sptr
6693 {return dynamic_pointer_cast<scope_decl>(first_subject());}
6694 
6695 /// Getter for the second scope of the diff.
6696 ///
6697 /// @return the second scope of the diff.
6698 const scope_decl_sptr
6700 {return dynamic_pointer_cast<scope_decl>(second_subject());}
6701 
6702 /// Accessor of the edit script of the members of a scope.
6703 ///
6704 /// This edit script is computed using the equality operator that
6705 /// applies to shared_ptr<decl_base>.
6706 ///
6707 /// That has interesting consequences. For instance, consider two
6708 /// scopes S0 and S1. S0 contains a class C0 and S1 contains a class
6709 /// S0'. C0 and C0' have the same qualified name, but have different
6710 /// members. The edit script will consider that C0 has been deleted
6711 /// from S0 and that S0' has been inserted. This is a low level
6712 /// canonical representation of the changes; a higher level
6713 /// representation would give us a simpler way to say "the class C0
6714 /// has been modified into C0'". But worry not. We do have such
6715 /// higher representation as well; that is what changed_types() and
6716 /// changed_decls() is for.
6717 ///
6718 /// @return the edit script of the changes encapsulatd in this
6719 /// instance of scope_diff.
6720 const edit_script&
6722 {return priv_->member_changes_;}
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 edit_script&
6744 {return priv_->member_changes_;}
6745 
6746 /// Accessor that eases the manipulation of the edit script associated
6747 /// to this instance. It returns the scope member that is reported
6748 /// (in the edit script) as deleted at a given index.
6749 ///
6750 /// @param i the index (in the edit script) of an element of the first
6751 /// scope that has been reported as being delete.
6752 ///
6753 /// @return the scope member that has been reported by the edit script
6754 /// as being deleted at index i.
6755 const decl_base_sptr
6757 {
6758  scope_decl_sptr scope = dynamic_pointer_cast<scope_decl>(first_subject());
6759  return scope->get_member_decls()[i];
6760 }
6761 
6762 /// Accessor that eases the manipulation of the edit script associated
6763 /// to this instance. It returns the scope member (of the first scope
6764 /// of this diff instance) that is reported (in the edit script) as
6765 /// deleted at a given iterator.
6766 ///
6767 /// @param i the iterator of an element of the first scope that has
6768 /// been reported as being delete.
6769 ///
6770 /// @return the scope member of the first scope of this diff that has
6771 /// been reported by the edit script as being deleted at iterator i.
6772 const decl_base_sptr
6773 scope_diff::deleted_member_at(vector<deletion>::const_iterator i) const
6774 {return deleted_member_at(i->index());}
6775 
6776 /// Accessor that eases the manipulation of the edit script associated
6777 /// to this instance. It returns the scope member (of the second
6778 /// scope of this diff instance) that is reported as being inserted
6779 /// from a given index.
6780 ///
6781 /// @param i the index of an element of the second scope this diff
6782 /// that has been reported by the edit script as being inserted.
6783 ///
6784 /// @return the scope member of the second scope of this diff that has
6785 /// been reported as being inserted from index i.
6786 const decl_base_sptr
6788 {
6789  scope_decl_sptr scope = dynamic_pointer_cast<scope_decl>(second_subject());
6790  return scope->get_member_decls()[i];
6791 }
6792 
6793 /// Accessor that eases the manipulation of the edit script associated
6794 /// to this instance. It returns the scope member (of the second
6795 /// scope of this diff instance) that is reported as being inserted
6796 /// from a given iterator.
6797 ///
6798 /// @param i the iterator of an element of the second scope this diff
6799 /// that has been reported by the edit script as being inserted.
6800 ///
6801 /// @return the scope member of the second scope of this diff that has
6802 /// been reported as being inserted from iterator i.
6803 const decl_base_sptr
6804 scope_diff::inserted_member_at(vector<unsigned>::const_iterator i)
6805 {return inserted_member_at(*i);}
6806 
6807 /// @return a sorted vector of the types which content has changed
6808 /// from the first scope to the other.
6809 const diff_sptrs_type&
6811 {return priv_->sorted_changed_types_;}
6812 
6813 /// @return a sorted vector of the decls which content has changed
6814 /// from the first scope to the other.
6815 const diff_sptrs_type&
6817 {return priv_->sorted_changed_decls_;}
6818 
6820 scope_diff::removed_types() const
6821 {return priv_->removed_types_;}
6822 
6824 scope_diff::removed_decls() const
6825 {return priv_->removed_decls_;}
6826 
6828 scope_diff::added_types() const
6829 {return priv_->added_types_;}
6830 
6832 scope_diff::added_decls() const
6833 {return priv_->added_decls_;}
6834 
6835 /// @return the pretty representation for the current instance of @ref
6836 /// scope_diff.
6837 const string&
6839 {
6840  if (diff::priv_->pretty_representation_.empty())
6841  {
6842  std::ostringstream o;
6843  o << "scope_diff["
6844  << first_subject()->get_pretty_representation()
6845  << ", "
6846  << second_subject()->get_pretty_representation()
6847  << "]";
6848  diff::priv_->pretty_representation_ = o.str();
6849  }
6850  return diff::priv_->pretty_representation_;
6851 }
6852 
6853 /// Return true iff the current diff node carries a change.
6854 ///
6855 /// Return true iff the current diff node carries a change.
6856 bool
6858 {
6859  // TODO: add the number of really removed/added stuff.
6860  return changed_types().size() + changed_decls().size();
6861 }
6862 
6863 /// @return the kind of local change carried by the current diff node.
6864 /// The value returned is zero if the current node carries no local
6865 /// change.
6866 enum change_kind
6868 {
6869  ir::change_kind k = ir::NO_CHANGE_KIND;
6870  if (!equals(*first_scope(), *second_scope(), &k))
6871  return k & ir::ALL_LOCAL_CHANGES_MASK;
6872  return ir::NO_CHANGE_KIND;
6873 }
6874 
6875 /// Report the changes of one scope against another.
6876 ///
6877 /// @param out the out stream to report the changes to.
6878 ///
6879 /// @param indent the string to use for indentation.
6880 void
6881 scope_diff::report(ostream& out, const string& indent) const
6882 {
6883  context()->get_reporter()->report(*this, out, indent);
6884 }
6885 
6886 /// Compute the diff between two scopes.
6887 ///
6888 /// Note that the two decls must have been created in the same @ref
6889 /// environment, otherwise, this function aborts.
6890 ///
6891 /// @param first the first scope to consider in computing the diff.
6892 ///
6893 /// @param second the second scope to consider in the diff
6894 /// computation. The second scope is diffed against the first scope.
6895 ///
6896 /// @param d a pointer to the diff object to populate with the
6897 /// computed diff.
6898 ///
6899 /// @return return the populated \a d parameter passed to this
6900 /// function.
6901 ///
6902 /// @param ctxt the diff context to use.
6905  const scope_decl_sptr second,
6906  scope_diff_sptr d,
6907  diff_context_sptr ctxt)
6908 {
6909  ABG_ASSERT(d->first_scope() == first && d->second_scope() == second);
6910 
6911  compute_diff(first->get_member_decls().begin(),
6912  first->get_member_decls().end(),
6913  second->get_member_decls().begin(),
6914  second->get_member_decls().end(),
6915  d->member_changes());
6916 
6917  d->ensure_lookup_tables_populated();
6918  d->context(ctxt);
6919 
6920  return d;
6921 }
6922 
6923 /// Compute the diff between two scopes.
6924 ///
6925 /// Note that the two decls must have been created in the same @ref
6926 /// environment, otherwise, this function aborts.
6927 ///
6928 /// @param first_scope the first scope to consider in computing the diff.
6929 ///
6930 /// @param second_scope the second scope to consider in the diff
6931 /// computation. The second scope is diffed against the first scope.
6932 ///
6933 /// @param ctxt the diff context to use.
6934 ///
6935 /// @return return the resulting diff
6937 compute_diff(const scope_decl_sptr first_scope,
6938  const scope_decl_sptr second_scope,
6939  diff_context_sptr ctxt)
6940 {
6941  scope_diff_sptr d(new scope_diff(first_scope, second_scope, ctxt));
6942  d = compute_diff(first_scope, second_scope, d, ctxt);
6943  ctxt->initialize_canonical_diff(d);
6944  return d;
6945 }
6946 
6947 //</scope_diff stuff>
6948 
6949 // <fn_parm_diff stuff>
6950 
6951 /// Constructor for the fn_parm_diff type.
6952 ///
6953 /// @param first the first subject of the diff.
6954 ///
6955 /// @param second the second subject of the diff.
6956 ///
6957 /// @param ctxt the context of the diff. Note that this context
6958 /// object must stay alive at least during the life time of the
6959 /// current instance of @ref fn_parm_diff. Otherwise memory
6960 /// corruption issues occur.
6961 fn_parm_diff::fn_parm_diff(const function_decl::parameter_sptr first,
6962  const function_decl::parameter_sptr second,
6963  diff_context_sptr ctxt)
6964  : decl_diff_base(first, second, ctxt),
6965  priv_(new priv)
6966 {
6967  ABG_ASSERT(first->get_index() == second->get_index());
6968  priv_->type_diff = compute_diff(first->get_type(),
6969  second->get_type(),
6970  ctxt);
6971  ABG_ASSERT(priv_->type_diff);
6972 }
6973 
6974 /// Getter for the first subject of this diff node.
6975 ///
6976 /// @return the first function_decl::parameter_sptr subject of this
6977 /// diff node.
6980 {return dynamic_pointer_cast<function_decl::parameter>(first_subject());}
6981 
6982 /// Getter for the second subject of this diff node.
6983 ///
6984 /// @return the second function_decl::parameter_sptr subject of this
6985 /// diff node.
6988 {return dynamic_pointer_cast<function_decl::parameter>(second_subject());}
6989 
6990 /// Getter for the diff representing the changes on the type of the
6991 /// function parameter involved in the current instance of @ref
6992 /// fn_parm_diff.
6993 ///
6994 /// @return a diff_sptr representing the changes on the type of the
6995 /// function parameter we are interested in.
6996 diff_sptr
6998 {return priv_->type_diff;}
6999 
7000 /// Build and return a textual representation of the current instance
7001 /// of @ref fn_parm_diff.
7002 ///
7003 /// @return the string representing the current instance of
7004 /// fn_parm_diff.
7005 const string&
7007 {
7008  if (diff::priv_->pretty_representation_.empty())
7009  {
7010  std::ostringstream o;
7011  o << "function_parameter_diff["
7012  << first_subject()->get_pretty_representation()
7013  << ", "
7014  << second_subject()->get_pretty_representation()
7015  << "]";
7016  diff::priv_->pretty_representation_ = o.str();
7017  }
7018  return diff::priv_->pretty_representation_;
7019 }
7020 
7021 /// Return true iff the current diff node carries a change.
7022 ///
7023 /// @return true iff the current diff node carries a change.
7024 bool
7026 {return *first_parameter() != *second_parameter();}
7027 
7028 /// Check if the current diff node carries a local change.
7029 ///
7030 /// @return the kind of local change carried by the current diff node.
7031 /// The value returned is zero if the current node carries no local
7032 /// change.
7033 enum change_kind
7035 {
7036  ir::change_kind k = ir::NO_CHANGE_KIND;
7037  if (!equals(*first_parameter(), *second_parameter(), &k))
7038  return k & ir::ALL_LOCAL_CHANGES_MASK;
7039  return ir::NO_CHANGE_KIND;
7040 }
7041 
7042 /// Emit a textual report about the current fn_parm_diff instance.
7043 ///
7044 /// @param out the output stream to emit the textual report to.
7045 ///
7046 /// @param indent the indentation string to use in the report.
7047 void
7048 fn_parm_diff::report(ostream& out, const string& indent) const
7049 {
7050  context()->get_reporter()->report(*this, out, indent);
7051 }
7052 
7053 /// Populate the vector of children nodes of the @ref diff base type
7054 /// sub-object of this instance of @ref fn_parm_diff.
7055 ///
7056 /// The children nodes can then later be retrieved using
7057 /// diff::children_nodes()
7058 void
7060 {
7061  if (type_diff())
7063 }
7064 
7065 /// Compute the difference between two function_decl::parameter_sptr;
7066 /// that is, between two function parameters. Return a resulting
7067 /// fn_parm_diff_sptr that represents the changes.
7068 ///
7069 /// Note that the two decls must have been created in the same @ref
7070 /// environment, otherwise, this function aborts.
7071 ///
7072 /// @param first the first subject of the diff.
7073 ///
7074 /// @param second the second subject of the diff.
7075 ///
7076 /// @param ctxt the context of the diff.
7077 ///
7078 /// @return fn_parm_diff_sptr the resulting diff node.
7081  const function_decl::parameter_sptr second,
7082  diff_context_sptr ctxt)
7083 {
7084  if (!first || !second)
7085  return fn_parm_diff_sptr();
7086 
7087  fn_parm_diff_sptr result(new fn_parm_diff(first, second, ctxt));
7088  ctxt->initialize_canonical_diff(result);
7089 
7090  return result;
7091 }
7092 // </fn_parm_diff stuff>
7093 
7094 // <function_type_diff stuff>
7095 
7096 void
7097 function_type_diff::ensure_lookup_tables_populated()
7098 {
7099  priv_->return_type_diff_ =
7100  compute_diff(first_function_type()->get_return_type(),
7101  second_function_type()->get_return_type(),
7102  context());
7103 
7104  string parm_name;
7106  for (vector<deletion>::const_iterator i =
7107  priv_->parm_changes_.deletions().begin();
7108  i != priv_->parm_changes_.deletions().end();
7109  ++i)
7110  {
7111  parm = *(first_function_type()->get_first_parm()
7112  + i->index());
7113  parm_name = parm->get_name_id();
7114  // If for a reason the type name is empty we want to know and
7115  // fix that.
7116  ABG_ASSERT(!parm_name.empty());
7117  priv_->deleted_parms_[parm_name] = parm;
7118  priv_->deleted_parms_by_id_[parm->get_index()] = parm;
7119  }
7120 
7121  for (vector<insertion>::const_iterator i =
7122  priv_->parm_changes_.insertions().begin();
7123  i != priv_->parm_changes_.insertions().end();
7124  ++i)
7125  {
7126  for (vector<unsigned>::const_iterator j =
7127  i->inserted_indexes().begin();
7128  j != i->inserted_indexes().end();
7129  ++j)
7130  {
7131  parm = *(second_function_type()->get_first_parm() + *j);
7132  parm_name = parm->get_name_id();
7133  // If for a reason the type name is empty we want to know and
7134  // fix that.
7135  ABG_ASSERT(!parm_name.empty());
7136  {
7137  string_parm_map::const_iterator k =
7138  priv_->deleted_parms_.find(parm_name);
7139  if (k != priv_->deleted_parms_.end())
7140  {
7141  if (*k->second != *parm)
7142  priv_->subtype_changed_parms_[parm_name] =
7143  compute_diff(k->second, parm, context());
7144  priv_->deleted_parms_.erase(parm_name);
7145  }
7146  else
7147  priv_->added_parms_[parm_name] = parm;
7148  }
7149  {
7150  unsigned_parm_map::const_iterator k =
7151  priv_->deleted_parms_by_id_.find(parm->get_index());
7152  if (k != priv_->deleted_parms_by_id_.end())
7153  {
7154  if (*k->second != *parm
7155  && (k->second->get_name_id() != parm_name))
7156  priv_->changed_parms_by_id_[parm->get_index()] =
7157  compute_diff(k->second, parm, context());
7158  priv_->added_parms_.erase(parm_name);
7159  priv_->deleted_parms_.erase(k->second->get_name_id());
7160  priv_->deleted_parms_by_id_.erase(parm->get_index());
7161  }
7162  else
7163  priv_->added_parms_by_id_[parm->get_index()] = parm;
7164  }
7165  }
7166  }
7167 
7168  sort_string_fn_parm_diff_sptr_map(priv_->subtype_changed_parms_,
7169  priv_->sorted_subtype_changed_parms_);
7170  sort_string_fn_parm_diff_sptr_map(priv_->changed_parms_by_id_,
7171  priv_->sorted_changed_parms_by_id_);
7172  sort_string_parm_map(priv_->deleted_parms_,
7173  priv_->sorted_deleted_parms_);
7174 
7175  sort_string_parm_map(priv_->added_parms_,
7176  priv_->sorted_added_parms_);
7177 }
7178 
7179 /// In the vector of deleted parameters, get the one that is at a given
7180 /// index.
7181 ///
7182 /// @param i the index of the deleted parameter to get.
7183 ///
7184 /// @return the parameter returned.
7186 function_type_diff::deleted_parameter_at(int i) const
7187 {return first_function_type()->get_parameters()[i];}
7188 
7189 /// Getter for the sorted vector of deleted parameters.
7190 ///
7191 /// @return the sorted vector of deleted parameters.
7192 const vector<function_decl::parameter_sptr>&
7194 {return priv_->sorted_deleted_parms_;}
7195 
7196 /// Getter for the sorted vector of added parameters .
7197 ///
7198 /// @return the sorted vector of added parameters.
7199 const vector<function_decl::parameter_sptr>&
7201 {return priv_->sorted_added_parms_;}
7202 
7203 /// In the vector of inserted parameters, get the one that is at a
7204 /// given index.
7205 ///
7206 /// @param i the index of the inserted parameter to get.
7207 ///
7208 /// @return the parameter returned.
7210 function_type_diff::inserted_parameter_at(int i) const
7211 {return second_function_type()->get_parameters()[i];}
7212 
7213 /// Consutrctor of the @ref function_type type.
7214 ///
7215 /// @param first the first @ref function_type subject of the diff to
7216 /// create.
7217 ///
7218 /// @param second the second @ref function_type subject of the diff to
7219 /// create.
7220 ///
7221 /// @param ctxt the diff context to be used by the newly created
7222 /// instance of function_type_diff. Note that this context object
7223 /// must stay alive at least during the life time of the current
7224 /// instance of @ref function_type_diff. Otherwise memory corruption
7225 /// issues occur.
7227  const function_type_sptr second,
7228  diff_context_sptr ctxt)
7229  : type_diff_base(first, second, ctxt),
7230  priv_(new priv)
7231 {}
7232 
7233 /// Getter for the first subject of the diff.
7234 ///
7235 /// @return the first function type involved in the diff.
7236 const function_type_sptr
7238 {return dynamic_pointer_cast<function_type>(first_subject());}
7239 
7240 /// Getter for the second subject of the diff.
7241 ///
7242 /// @return the second function type involved in the diff.
7243 const function_type_sptr
7245 {return dynamic_pointer_cast<function_type>(second_subject());}
7246 
7247 /// Getter for the diff of the return types of the two function types
7248 /// of the current diff.
7249 ///
7250 /// @return the diff of the return types of the two function types of
7251 /// the current diff.
7252 const diff_sptr
7254 {return priv_->return_type_diff_;}
7255 
7256 /// Getter for the map of function parameter changes of the current diff.
7257 ///
7258 /// @return a map of function parameter changes of the current diff.
7261 {return priv_->subtype_changed_parms_;}
7262 
7263 /// Getter for the map of parameters that got removed.
7264 ///
7265 /// @return the map of parameters that got removed.
7266 const string_parm_map&
7268 {return priv_->deleted_parms_;}
7269 
7270 /// Getter for the map of parameters that got added.
7271 ///
7272 /// @return the map of parameters that got added.
7273 const string_parm_map&
7275 {return priv_->added_parms_;}
7276 
7277 /// Build and return a copy of a pretty representation of the current
7278 /// instance of @ref function_type_diff.
7279 ///
7280 /// @return a copy of the pretty representation of the current
7281 /// instance of @ref function_type_diff.
7282 const string&
7284 {
7285  if (diff::priv_->pretty_representation_.empty())
7286  {
7287  std::ostringstream o;
7288  o << "function_type_diff["
7290  << ", "
7292  << "]";
7293  diff::priv_->pretty_representation_ = o.str();
7294  }
7295  return diff::priv_->pretty_representation_;
7296 }
7297 
7298 /// Test if the current diff node carries changes.
7299 ///
7300 /// @return true iff the current diff node carries changes.
7301 bool
7303 {return *first_function_type() != *second_function_type();}
7304 
7305 /// Test if the current diff node carries local changes.
7306 ///
7307 /// A local change is a change that is carried by this diff node, not
7308 /// by any of its children nodes.
7309 ///
7310 /// @return the kind of local change carried by the current diff node.
7311 /// The value returned is zero if the current node carries no local
7312 /// change.
7313 enum change_kind
7315 {
7316  ir::change_kind k = ir::NO_CHANGE_KIND;
7318  return k & ir::ALL_LOCAL_CHANGES_MASK;
7319  return ir::NO_CHANGE_KIND;
7320 }
7321 
7322 /// Build and emit a textual report about the current @ref
7323 /// function_type_diff instance.
7324 ///
7325 /// @param out the output stream.
7326 ///
7327 /// @param indent the indentation string to use.
7328 void
7329 function_type_diff::report(ostream& out, const string& indent) const
7330 {
7331  context()->get_reporter()->report(*this, out, indent);
7332 }
7333 
7334 /// Populate the vector of children node of the @ref diff base type
7335 /// sub-object of this instance of @ref function_type_diff.
7336 ///
7337 /// The children node can then later be retrieved using
7338 /// diff::children_node().
7339 void
7341 {
7342  if (diff_sptr d = return_type_diff())
7343  append_child_node(d);
7344 
7345  for (vector<fn_parm_diff_sptr>::const_iterator i =
7346  priv_->sorted_subtype_changed_parms_.begin();
7347  i != priv_->sorted_subtype_changed_parms_.end();
7348  ++i)
7349  if (diff_sptr d = *i)
7350  append_child_node(d);
7351 
7352  for (vector<fn_parm_diff_sptr>::const_iterator i =
7353  priv_->sorted_changed_parms_by_id_.begin();
7354  i != priv_->sorted_changed_parms_by_id_.end();
7355  ++i)
7356  if (diff_sptr d = *i)
7357  append_child_node(d);
7358 }
7359 
7360 /// Compute the diff between two instances of @ref function_type.
7361 ///
7362 /// Note that the two types must have been created in the same @ref
7363 /// environment, otherwise, this function aborts.
7364 ///
7365 /// @param first the first @ref function_type to consider for the diff.
7366 ///
7367 /// @param second the second @ref function_type to consider for the diff.
7368 ///
7369 /// @param ctxt the diff context to use.
7370 ///
7371 /// @return the resulting diff between the two @ref function_type.
7374  const function_type_sptr second,
7375  diff_context_sptr ctxt)
7376 {
7377  if (!first || !second)
7378  {
7379  // TODO: implement this for either first or second being NULL.
7380  return function_type_diff_sptr();
7381  }
7382 
7383  function_type_diff_sptr result(new function_type_diff(first, second, ctxt));
7384 
7385  diff_utils::compute_diff(first->get_first_parm(),
7386  first->get_parameters().end(),
7387  second->get_first_parm(),
7388  second->get_parameters().end(),
7389  result->priv_->parm_changes_);
7390 
7391  result->ensure_lookup_tables_populated();
7392 
7393  ctxt->initialize_canonical_diff(result);
7394 
7395  return result;
7396 }
7397 // </function_type_diff stuff>
7398 
7399 // <function_decl_diff stuff>
7400 
7401 /// Build the lookup tables of the diff, if necessary.
7402 void
7403 function_decl_diff::ensure_lookup_tables_populated()
7404 {
7405 }
7406 
7407 /// Populate the vector of children node of the @ref diff base type
7408 /// sub-object of this instance of @ref function_decl_diff.
7409 ///
7410 /// The children node can then later be retrieved using
7411 /// diff::children_node().
7412 void
7414 {
7415  if (diff_sptr d = type_diff())
7416  append_child_node(d);
7417 }
7418 
7419 /// Constructor for function_decl_diff
7420 ///
7421 /// @param first the first function considered by the diff.
7422 ///
7423 /// @param second the second function considered by the diff.
7424 ///
7425 /// @param ctxt the context of the diff. Note that this context
7426 /// object must stay alive at least during the life time of the
7427 /// current instance of @ref function_decl_diff. Otherwise memory
7428 /// corruption issues occur.
7430  const function_decl_sptr second,
7431  diff_context_sptr ctxt)
7432  : decl_diff_base(first, second, ctxt),
7433  priv_(new priv)
7434 {
7435 }
7436 
7437 /// @return the first function considered by the diff.
7438 const function_decl_sptr
7440 {return dynamic_pointer_cast<function_decl>(first_subject());}
7441 
7442 /// @return the second function considered by the diff.
7443 const function_decl_sptr
7445 {return dynamic_pointer_cast<function_decl>(second_subject());}
7446 
7448 function_decl_diff::type_diff() const
7449 {return priv_->type_diff_;}
7450 
7451 /// @return the pretty representation for the current instance of @ref
7452 /// function_decl_diff.
7453 const string&
7455 {
7456  if (diff::priv_->pretty_representation_.empty())
7457  {
7458  std::ostringstream o;
7459  o << "function_diff["
7460  << first_subject()->get_pretty_representation()
7461  << ", "
7462  << second_subject()->get_pretty_representation()
7463  << "]";
7464  diff::priv_->pretty_representation_ = o.str();
7465  }
7466  return diff::priv_->pretty_representation_;
7467 }
7468 
7469 /// Return true iff the current diff node carries a change.
7470 ///
7471 /// @return true iff the current diff node carries a change.
7472 bool
7474 {return *first_function_decl() != *second_function_decl();}
7475 
7476 /// @return the kind of local change carried by the current diff node.
7477 /// The value returned is zero if the current node carries no local
7478 /// change.
7479 enum change_kind
7481 {
7482  ir::change_kind k = ir::NO_CHANGE_KIND;
7484  return k & ir::ALL_LOCAL_CHANGES_MASK;
7485  return ir::NO_CHANGE_KIND;
7486 }
7487 
7488 /// Serialize a report of the changes encapsulated in the current
7489 /// instance of @ref function_decl_diff over to an output stream.
7490 ///
7491 /// @param out the output stream to serialize the report to.
7492 ///
7493 /// @param indent the string to use an an indentation prefix.
7494 void
7495 function_decl_diff::report(ostream& out, const string& indent) const
7496 {
7497  context()->get_reporter()->report(*this, out, indent);
7498 }
7499 
7500 /// Compute the diff between two function_decl.
7501 ///
7502 /// Note that the two decls must have been created in the same @ref
7503 /// environment, otherwise, this function aborts.
7504 ///
7505 /// @param first the first function_decl to consider for the diff
7506 ///
7507 /// @param second the second function_decl to consider for the diff
7508 ///
7509 /// @param ctxt the diff context to use.
7510 ///
7511 /// @return the computed diff
7514  const function_decl_sptr second,
7515  diff_context_sptr ctxt)
7516 {
7517  if (!first || !second)
7518  {
7519  // TODO: implement this for either first or second being NULL.
7520  return function_decl_diff_sptr();
7521  }
7522 
7523  function_type_diff_sptr type_diff = compute_diff(first->get_type(),
7524  second->get_type(),
7525  ctxt);
7526 
7527  function_decl_diff_sptr result(new function_decl_diff(first, second,
7528  ctxt));
7529  result->priv_->type_diff_ = type_diff;
7530 
7531  result->ensure_lookup_tables_populated();
7532 
7533  ctxt->initialize_canonical_diff(result);
7534 
7535  return result;
7536 }
7537 
7538 // </function_decl_diff stuff>
7539 
7540 // <type_decl_diff stuff>
7541 
7542 /// Constructor for type_decl_diff.
7543 ///
7544 /// @param first the first subject of the diff.
7545 ///
7546 /// @param second the second subject of the diff.
7547 ///
7548 /// @param ctxt the context of the diff. Note that this context
7549 /// object must stay alive at least during the life time of the
7550 /// current instance of @ref type_decl_diff. Otherwise memory
7551 /// corruption issues occur.
7552 type_decl_diff::type_decl_diff(const type_decl_sptr first,
7553  const type_decl_sptr second,
7554  diff_context_sptr ctxt)
7555  : type_diff_base(first, second, ctxt)
7556 {}
7557 
7558 /// Getter for the first subject of the type_decl_diff.
7559 ///
7560 /// @return the first type_decl involved in the diff.
7561 const type_decl_sptr
7563 {return dynamic_pointer_cast<type_decl>(first_subject());}
7564 
7565 /// Getter for the second subject of the type_decl_diff.
7566 ///
7567 /// @return the second type_decl involved in the diff.
7568 const type_decl_sptr
7570 {return dynamic_pointer_cast<type_decl>(second_subject());}
7571 
7572 /// @return the pretty representation for the current instance of @ref
7573 /// type_decl_diff.
7574 const string&
7576 {
7577  if (diff::priv_->pretty_representation_.empty())
7578  {
7579  std::ostringstream o;
7580  o << "type_decl_diff["
7581  << first_subject()->get_pretty_representation()
7582  << ", "
7583  << second_subject()->get_pretty_representation()
7584  << "]";
7585  diff::priv_->pretty_representation_ = o.str();
7586  }
7587  return diff::priv_->pretty_representation_;
7588 }
7589 /// Return true iff the current diff node carries a change.
7590 ///
7591 /// @return true iff the current diff node carries a change.
7592 bool
7594 {return first_type_decl() != second_type_decl();}
7595 
7596 /// @return the kind of local change carried by the current diff node.
7597 /// The value returned is zero if the current node carries no local
7598 /// change.
7599 enum change_kind
7601 {
7602  ir::change_kind k = ir::NO_CHANGE_KIND;
7603  if (!equals(*first_type_decl(), *second_type_decl(), &k))
7604  return k & ir::ALL_LOCAL_CHANGES_MASK;
7605  return ir::NO_CHANGE_KIND;
7606 }
7607 /// Ouputs a report of the differences between of the two type_decl
7608 /// involved in the type_decl_diff.
7609 ///
7610 /// @param out the output stream to emit the report to.
7611 ///
7612 /// @param indent the string to use for indentatino indent.
7613 void
7614 type_decl_diff::report(ostream& out, const string& indent) const
7615 {
7616  context()->get_reporter()->report(*this, out, indent);
7617 }
7618 
7619 /// Compute a diff between two type_decl.
7620 ///
7621 /// Note that the two types must have been created in the same @ref
7622 /// environment, otherwise, this function aborts.
7623 ///
7624 /// This function doesn't actually compute a diff. As a type_decl is
7625 /// very simple (unlike compound constructs like function_decl or
7626 /// class_decl) it's easy to just compare the components of the
7627 /// type_decl to know what has changed. Thus this function just
7628 /// builds and return a type_decl_diff object. The
7629 /// type_decl_diff::report function will just compare the components
7630 /// of the the two type_decl and display where and how they differ.
7631 ///
7632 /// @param first a pointer to the first type_decl to
7633 /// consider.
7634 ///
7635 /// @param second a pointer to the second type_decl to consider.
7636 ///
7637 /// @param ctxt the diff context to use.
7638 ///
7639 /// @return a pointer to the resulting type_decl_diff.
7642  const type_decl_sptr second,
7643  diff_context_sptr ctxt)
7644 {
7645  type_decl_diff_sptr result(new type_decl_diff(first, second, ctxt));
7646 
7647  // We don't need to actually compute a diff here as a type_decl
7648  // doesn't have complicated sub-components. type_decl_diff::report
7649  // just walks the members of the type_decls and display information
7650  // about the ones that have changed. On a similar note,
7651  // type_decl_diff::length returns 0 if the two type_decls are equal,
7652  // and 1 otherwise.
7653 
7654  ctxt->initialize_canonical_diff(result);
7655 
7656  return result;
7657 }
7658 
7659 // </type_decl_diff stuff>
7660 
7661 // <typedef_diff stuff>
7662 
7663 /// Populate the vector of children node of the @ref diff base type
7664 /// sub-object of this instance of @ref typedef_diff.
7665 ///
7666 /// The children node can then later be retrieved using
7667 /// diff::children_node().
7668 void
7671 
7672 /// Constructor for typedef_diff.
7673 ///
7674 /// @param first the first subject of the diff.
7675 ///
7676 /// @param second the second subject of the diff.
7677 ///
7678 /// @param underlying the underlying diff of the @ref typedef_diff.
7679 /// That is the diff between the underlying types of @p first and @p
7680 /// second.
7681 ///
7682 /// @param ctxt the context of the diff. Note that this context
7683 /// object must stay alive at least during the life time of the
7684 /// current instance of @ref typedef_diff. Otherwise memory
7685 /// corruption issues occur.
7686 typedef_diff::typedef_diff(const typedef_decl_sptr first,
7687  const typedef_decl_sptr second,
7688  const diff_sptr underlying,
7689  diff_context_sptr ctxt)
7690  : type_diff_base(first, second, ctxt),
7691  priv_(new priv(underlying))
7692 {}
7693 
7694 /// Getter for the firt typedef_decl involved in the diff.
7695 ///
7696 /// @return the first subject of the diff.
7697 const typedef_decl_sptr
7699 {return dynamic_pointer_cast<typedef_decl>(first_subject());}
7700 
7701 /// Getter for the second typedef_decl involved in the diff.
7702 ///
7703 /// @return the second subject of the diff.
7704 const typedef_decl_sptr
7706 {return dynamic_pointer_cast<typedef_decl>(second_subject());}
7707 
7708 /// Getter for the diff between the two underlying types of the
7709 /// typedefs.
7710 ///
7711 /// @return the diff object reprensenting the difference between the
7712 /// two underlying types of the typedefs.
7713 const diff_sptr
7715 {return priv_->underlying_type_diff_;}
7716 
7717 /// Setter for the diff between the two underlying types of the
7718 /// typedefs.
7719 ///
7720 /// @param d the new diff object reprensenting the difference between
7721 /// the two underlying types of the typedefs.
7722 void
7724 {priv_->underlying_type_diff_ = d;}
7725 
7726 /// @return the pretty representation for the current instance of @ref
7727 /// typedef_diff.
7728 const string&
7730 {
7731  if (diff::priv_->pretty_representation_.empty())
7732  {
7733  std::ostringstream o;
7734  o << "typedef_diff["
7735  << first_subject()->get_pretty_representation()
7736  << ", "
7737  << second_subject()->get_pretty_representation()
7738  << "]";
7739  diff::priv_->pretty_representation_ = o.str();
7740  }
7741  return diff::priv_->pretty_representation_;
7742 }
7743 
7744 /// Return true iff the current diff node carries a change.
7745 ///
7746 /// @return true iff the current diff node carries a change.
7747 bool
7749 {
7750  decl_base_sptr second = second_typedef_decl();
7751  return !(*first_typedef_decl() == *second);
7752 }
7753 
7754 /// @return the kind of local change carried by the current diff node.
7755 /// The value returned is zero if the current node carries no local
7756 /// change.
7757 enum change_kind
7759 {
7760  ir::change_kind k = ir::NO_CHANGE_KIND;
7762  return k & ir::ALL_LOCAL_CHANGES_MASK;
7763  return ir::NO_CHANGE_KIND;
7764 }
7765 
7766 /// Reports the difference between the two subjects of the diff in a
7767 /// serialized form.
7768 ///
7769 /// @param out the output stream to emit the report to.
7770 ///
7771 /// @param indent the indentation string to use.
7772 void
7773 typedef_diff::report(ostream& out, const string& indent) const
7774 {
7775  context()->get_reporter()->report(*this, out, indent);
7776 }
7777 
7778 /// Compute a diff between two typedef_decl.
7779 ///
7780 /// Note that the two types must have been created in the same @ref
7781 /// environment, otherwise, this function aborts.
7782 ///
7783 /// @param first a pointer to the first typedef_decl to consider.
7784 ///
7785 /// @param second a pointer to the second typedef_decl to consider.
7786 ///
7787 /// @param ctxt the diff context to use.
7788 ///
7789 /// @return a pointer to the the resulting typedef_diff.
7792  const typedef_decl_sptr second,
7793  diff_context_sptr ctxt)
7794 {
7795  diff_sptr d = compute_diff_for_types(first->get_underlying_type(),
7796  second->get_underlying_type(),
7797  ctxt);
7798  typedef_diff_sptr result(new typedef_diff(first, second, d, ctxt));
7799 
7800  ctxt->initialize_canonical_diff(result);
7801 
7802  return result;
7803 }
7804 
7805 /// Return the leaf underlying diff node of a @ref typedef_diff node.
7806 ///
7807 /// If the underlying diff node of a @ref typedef_diff node is itself
7808 /// a @ref typedef_diff node, then recursively look at the underlying
7809 /// diff nodes to get the first one that is not a a @ref typedef_diff
7810 /// node. This is what a leaf underlying diff node means.
7811 ///
7812 /// Otherwise, if the underlying diff node of @ref typedef_diff is
7813 /// *NOT* a @ref typedef_diff node, then just return the underlying
7814 /// diff node.
7815 ///
7816 /// And if the diff node considered is not a @ref typedef_diff node,
7817 /// then just return it.
7818 ///
7819 /// @return the leaf underlying diff node of a @p diff.
7820 const diff*
7822 {
7823  const typedef_diff* d = dynamic_cast<const typedef_diff*>(diff);
7824  if (!d)
7825  return diff;
7826 
7827  if (const typedef_diff* deef =
7828  dynamic_cast<const typedef_diff*>(d->underlying_type_diff().get()))
7830 
7831  return d->underlying_type_diff().get();
7832 }
7833 
7834 // </typedef_diff stuff>
7835 
7836 // <translation_unit_diff stuff>
7837 
7838 /// Constructor for translation_unit_diff.
7839 ///
7840 /// @param first the first translation unit to consider for this diff.
7841 ///
7842 /// @param second the second translation unit to consider for this diff.
7843 ///
7844 /// @param ctxt the context of the diff. Note that this context
7845 /// object must stay alive at least during the life time of the
7846 /// current instance of @ref translation_unit_diff. Otherwise memory
7847 /// corruption issues occur.
7849  translation_unit_sptr second,
7850  diff_context_sptr ctxt)
7851  : scope_diff(first->get_global_scope(), second->get_global_scope(), ctxt),
7852  priv_(new priv(first, second))
7853 {
7854 }
7855 
7856 /// Getter for the first translation unit of this diff.
7857 ///
7858 /// @return the first translation unit of this diff.
7861 {return priv_->first_;}
7862 
7863 /// Getter for the second translation unit of this diff.
7864 ///
7865 /// @return the second translation unit of this diff.
7868 {return priv_->second_;}
7869 
7870 /// Return true iff the current diff node carries a change.
7871 ///
7872 /// @return true iff the current diff node carries a change.
7873 bool
7875 {return scope_diff::has_changes();}
7876 
7877 /// @return the kind of local change carried by the current diff node.
7878 /// The value returned is zero if the current node carries no local
7879 /// change.
7880 enum change_kind
7882 {return ir::NO_CHANGE_KIND;}
7883 
7884 /// Report the diff in a serialized form.
7885 ///
7886 /// @param out the output stream to serialize the report to.
7887 ///
7888 /// @param indent the prefix to use as indentation for the report.
7889 void
7890 translation_unit_diff::report(ostream& out, const string& indent) const
7891 {scope_diff::report(out, indent);}
7892 
7893 /// Compute the diff between two translation_units.
7894 ///
7895 /// Note that the two translation units must have been created in the
7896 /// same @ref environment, otherwise, this function aborts.
7897 ///
7898 /// @param first the first translation_unit to consider.
7899 ///
7900 /// @param second the second translation_unit to consider.
7901 ///
7902 /// @param ctxt the diff context to use. If null, this function will
7903 /// create a new context and set to the diff object returned.
7904 ///
7905 /// @return the newly created diff object.
7908  const translation_unit_sptr second,
7909  diff_context_sptr ctxt)
7910 {
7911  ABG_ASSERT(first && second);
7912 
7913  if (!ctxt)
7914  ctxt.reset(new diff_context);
7915 
7916  // TODO: handle first or second having empty contents.
7917  translation_unit_diff_sptr tu_diff(new translation_unit_diff(first, second,
7918  ctxt));
7919  scope_diff_sptr sc_diff = dynamic_pointer_cast<scope_diff>(tu_diff);
7920 
7921  compute_diff(static_pointer_cast<scope_decl>(first->get_global_scope()),
7922  static_pointer_cast<scope_decl>(second->get_global_scope()),
7923  sc_diff,
7924  ctxt);
7925 
7926  ctxt->initialize_canonical_diff(tu_diff);
7927 
7928  return tu_diff;
7929 }
7930 
7931 // </translation_unit_diff stuff>
7932 
7933 // <diff_maps stuff>
7934 
7935 /// The private data of the @ref diff_maps type.
7936 struct diff_maps::priv
7937 {
7938  string_diff_ptr_map type_decl_diff_map_;
7939  string_diff_ptr_map enum_diff_map_;
7940  string_diff_ptr_map class_diff_map_;
7941  string_diff_ptr_map union_diff_map_;
7942  string_diff_ptr_map typedef_diff_map_;
7943  string_diff_ptr_map subrange_diff_map_;
7944  string_diff_ptr_map array_diff_map_;
7945  string_diff_ptr_map reference_diff_map_;
7946  string_diff_ptr_map function_type_diff_map_;
7947  string_diff_ptr_map function_decl_diff_map_;
7948  string_diff_ptr_map var_decl_diff_map_;
7949  string_diff_ptr_map distinct_diff_map_;
7950  string_diff_ptr_map fn_parm_diff_map_;
7951  diff_artifact_set_map_type impacted_artifacts_map_;
7952 }; // end struct diff_maps::priv
7953 
7954 /// Default constructor of the @ref diff_maps type.
7956  : priv_(new diff_maps::priv())
7957 {}
7958 
7959 diff_maps::~diff_maps() = default;
7960 
7961 /// Getter of the map that contains basic type diffs.
7962 ///
7963 /// @return the map that contains basic type diffs.
7964 const string_diff_ptr_map&
7966 {return priv_->type_decl_diff_map_;}
7967 
7968 /// Getter of the map that contains basic type diffs.
7969 ///
7970 /// @return the map that contains basic type diffs.
7973 {return priv_->type_decl_diff_map_;}
7974 
7975 /// Getter of the map that contains enum type diffs.
7976 ///
7977 /// @return the map that contains enum type diffs.
7978 const string_diff_ptr_map&
7980 {return priv_->enum_diff_map_;}
7981 
7982 /// Getter of the map that contains enum type diffs.
7983 ///
7984 /// @return the map that contains enum type diffs.
7987 {return priv_->enum_diff_map_;}
7988 
7989 /// Getter of the map that contains class type diffs.
7990 ///
7991 /// @return the map that contains class type diffs.
7992 const string_diff_ptr_map&
7994 {return priv_->class_diff_map_;}
7995 
7996 /// Getter of the map that contains class type diffs.
7997 ///
7998 /// @return the map that contains class type diffs.
8001 {return priv_->class_diff_map_;}
8002 
8003 /// Getter of the map that contains union type diffs.
8004 ///
8005 /// @return the map that contains union type diffs.
8006 const string_diff_ptr_map&
8008 {return priv_->union_diff_map_;}
8009 
8010 /// Getter of the map that contains union type diffs.
8011 ///
8012 /// @return the map that contains union type diffs.
8015 {return priv_->union_diff_map_;}
8016 
8017 /// Getter of the map that contains typedef type diffs.
8018 ///
8019 /// @return the map that contains typedef type diffs.
8020 const string_diff_ptr_map&
8022 {return priv_->typedef_diff_map_;}
8023 
8024 /// Getter of the map that contains typedef type diffs.
8025 ///
8026 /// @return the map that contains typedef type diffs.
8029 {return priv_->typedef_diff_map_;}
8030 
8031 /// Getter of the map that contains subrange type diffs.
8032 ///
8033 /// @return the map that contains subrange type diffs.
8034 const string_diff_ptr_map&
8036 {return priv_->subrange_diff_map_;}
8037 
8038 /// Getter of the map that contains subrange type diffs.
8039 ///
8040 /// @return the map that contains subrange type diffs.
8043 {return priv_->subrange_diff_map_;}
8044 
8045 /// Getter of the map that contains array type diffs.
8046 ///
8047 /// @return the map that contains array type diffs.
8048 const string_diff_ptr_map&
8050 {return priv_->array_diff_map_;}
8051 
8052 /// Getter of the map that contains array type diffs.
8053 ///
8054 /// @return the map that contains array type diffs.
8057 {return priv_->array_diff_map_;}
8058 
8059 /// Getter of the map that contains reference type diffs.
8060 ///
8061 /// @return the map that contains reference type diffs.
8062 const string_diff_ptr_map&
8064 {return priv_->reference_diff_map_;}
8065 
8066 /// Getter of the map that contains reference type diffs.
8067 ///
8068 /// @return the map that contains reference type diffs.
8071 {{return priv_->reference_diff_map_;}}
8072 
8073 /// Getter of the map that contains function parameter diffs.
8074 ///
8075 /// @return the map that contains function parameter diffs.
8076 const string_diff_ptr_map&
8078 {return priv_->fn_parm_diff_map_;}
8079 
8080 /// Getter of the map that contains function parameter diffs.
8081 ///
8082 /// @return the map that contains function parameter diffs.
8085 {return priv_->fn_parm_diff_map_;}
8086 
8087 /// Getter of the map that contains function type diffs.
8088 ///
8089 /// @return the map that contains function type diffs.
8090 const string_diff_ptr_map&
8092 {return priv_->function_type_diff_map_;}
8093 
8094 /// Getter of the map that contains function type diffs.
8095 ///
8096 /// @return the map that contains function type diffs.
8099 {return priv_->function_type_diff_map_;}
8100 
8101 /// Getter of the map that contains function decl diffs.
8102 ///
8103 /// @return the map that contains function decl diffs.
8104 const string_diff_ptr_map&
8106 {return priv_->function_decl_diff_map_;}
8107 
8108 /// Getter of the map that contains function decl diffs.
8109 ///
8110 /// @return the map that contains function decl diffs.
8113 {return priv_->function_decl_diff_map_;}
8114 
8115 /// Getter of the map that contains var decl diffs.
8116 ///
8117 /// @return the map that contains var decl diffs.
8118 const string_diff_ptr_map&
8120 {return priv_->var_decl_diff_map_;}
8121 
8122 /// Getter of the map that contains var decl diffs.
8123 ///
8124 /// @return the map that contains var decl diffs.
8127 {return priv_->var_decl_diff_map_;}
8128 
8129 /// Getter of the map that contains distinct diffs.
8130 ///
8131 /// @return the map that contains distinct diffs.
8132 const string_diff_ptr_map&
8134 {return priv_->distinct_diff_map_;}
8135 
8136 /// Getter of the map that contains distinct diffs.
8137 ///
8138 /// @return the map that contains distinct diffs.
8141 {return priv_->distinct_diff_map_;}
8142 
8143 /// Insert a new diff node into the current instance of @ref diff_maps.
8144 ///
8145 /// @param dif the new diff node to insert into the @ref diff_maps.
8146 ///
8147 /// @param impacted_iface the interface (global function or variable)
8148 /// currently being analysed that led to analysing the diff node @p
8149 /// dif. In other words, this is the interface impacted by the diff
8150 /// node @p dif. Note that this can be nil in cases where we are
8151 /// directly analysing changes to a type that is not reachable from
8152 /// any global function or variable.
8153 ///
8154 /// @return true iff the diff node could be added to the current
8155 /// instance of @ref diff_maps.
8156 bool
8158  const type_or_decl_base_sptr& impacted_iface)
8159 {
8160  string n = get_pretty_representation(dif->first_subject(),
8161  /*internal=*/true);
8162  if (const type_decl_diff *d = is_diff_of_basic_type(dif))
8163  get_type_decl_diff_map()[n] = const_cast<type_decl_diff*>(d);
8164  else if (const enum_diff *d = is_enum_diff(dif))
8165  get_enum_diff_map()[n] = const_cast<enum_diff*>(d);
8166  else if (const class_diff *d = is_class_diff(dif))
8167  get_class_diff_map()[n] = const_cast<class_diff*>(d);
8168  else if (const union_diff *d = is_union_diff(dif))
8169  get_union_diff_map()[n] = const_cast<union_diff*>(d);
8170  else if (const typedef_diff *d = is_typedef_diff(dif))
8171  get_typedef_diff_map()[n] = const_cast<typedef_diff*>(d);
8172  else if (const subrange_diff *d = is_subrange_diff(dif))
8173  get_subrange_diff_map()[n] = const_cast<subrange_diff*>(d);
8174  else if (const array_diff *d = is_array_diff(dif))
8175  get_array_diff_map()[n] = const_cast<array_diff*>(d);
8176  else if (const reference_diff *d = is_reference_diff(dif))
8177  get_reference_diff_map()[n] = const_cast<reference_diff*>(d);
8178  else if (const fn_parm_diff *d = is_fn_parm_diff(dif))
8179  get_fn_parm_diff_map()[n] = const_cast<fn_parm_diff*>(d);
8180  else if (const function_type_diff *d = is_function_type_diff(dif))
8181  get_function_type_diff_map()[n] = const_cast<function_type_diff*>(d);
8182  else if (const var_diff *d = is_var_diff(dif))
8183  get_var_decl_diff_map()[n] = const_cast<var_diff*>(d);
8184  else if (const function_decl_diff *d = is_function_decl_diff(dif))
8185  get_function_decl_diff_map()[n] = const_cast<function_decl_diff*>(d);
8186  else if (const distinct_diff *d = is_distinct_diff(dif))
8187  get_distinct_diff_map()[n] = const_cast<distinct_diff*>(d);
8188  else if (is_base_diff(dif))
8189  // we silently drop this case.
8190  return true;
8191  else
8193 
8194  // Update the map that associates this diff node to the set of
8195  // interfaces it impacts.
8196 
8197  if (impacted_iface)
8198  {
8199  diff_artifact_set_map_type::iterator i =
8200  priv_->impacted_artifacts_map_.find(dif);
8201 
8202  if (i == priv_->impacted_artifacts_map_.end())
8203  {
8205  set.insert(impacted_iface);
8206  priv_->impacted_artifacts_map_[dif] = set;
8207  }
8208  else
8209  i->second.insert(impacted_iface);
8210  }
8211 
8212  return true;
8213 }
8214 
8215 /// Lookup the interfaces that are impacted by a given leaf diff node.
8216 ///
8217 /// @param d the diff node to consider.
8218 ///
8219 /// @return the set of artifacts impacted by @p d.
8222 {
8223  diff_artifact_set_map_type::iterator i =
8224  priv_->impacted_artifacts_map_.find(d);
8225 
8226  if (i == priv_->impacted_artifacts_map_.end())
8227  return 0;
8228 
8229  return &i->second;
8230 }
8231 
8232 //
8233 // </diff_maps stuff>
8234 
8235 /// Constructor for the @ref diff_stat type.
8236 ///
8237 /// @param ctxt the context of the corpus diff. Note that this
8238 /// context object must stay alive at least during the life time of
8239 /// the current instance of @ref corpus_diff::diff_stats. Otherwise
8240 /// memory corruption issues occur.
8241 corpus_diff::diff_stats::diff_stats(diff_context_sptr ctxt)
8242  : priv_(new priv(ctxt))
8243 {}
8244 
8245 /// Getter for the number of functions removed.
8246 ///
8247 /// @return the number of functions removed.
8248 size_t
8250 {return priv_->num_func_removed;}
8251 
8252 /// Setter for the number of functions removed.
8253 ///
8254 /// @param n the new number of functions removed.
8255 void
8257 {priv_->num_func_removed = n;}
8258 
8259 /// Getter for the number of removed functions that have been filtered
8260 /// out.
8261 ///
8262 /// @return the number of removed functions that have been filtered
8263 /// out.
8264 size_t
8266 {
8267  if (priv_->ctxt() && !priv_->ctxt()->show_deleted_fns())
8268  return num_func_removed();
8269  return priv_->num_removed_func_filtered_out;
8270 }
8271 
8272 /// Setter for the number of removed functions that have been filtered
8273 /// out.
8274 ///
8275 /// @param t the new value.
8276 void
8278 {priv_->num_removed_func_filtered_out = t;}
8279 
8280 /// Getter for the net number of function removed.
8281 ///
8282 /// This is the difference between the number of functions removed and
8283 /// the number of functons removed that have been filtered out.
8284 ///
8285 /// @return the net number of function removed.
8286 size_t
8288 {
8289  ABG_ASSERT(num_func_removed() >= num_removed_func_filtered_out());
8290  return num_func_removed() - num_removed_func_filtered_out();
8291 }
8292 
8293 /// Getter for the number of functions added.
8294 ///
8295 /// @return the number of functions added.
8296 size_t
8298 {return priv_->num_func_added;}
8299 
8300 /// Setter for the number of functions added.
8301 ///
8302 /// @param n the new number of functions added.
8303 void
8305 {priv_->num_func_added = n;}
8306 
8307 /// Getter for the number of added function that have been filtered out.
8308 ///
8309 /// @return the number of added function that have been filtered out.
8310 size_t
8312 {
8313  if (priv_->ctxt() && !priv_->ctxt()->show_added_fns())
8314  return num_func_added();
8315  return priv_->num_added_func_filtered_out;
8316 }
8317 
8318 /// Setter for the number of added function that have been filtered
8319 /// out.
8320 ///
8321 /// @param n the new value.
8322 void
8324 {priv_->num_added_func_filtered_out = n;}
8325 
8326 /// Getter for the net number of added functions.
8327 ///
8328 /// The net number of added functions is the difference between the
8329 /// number of added functions and the number of added functions that
8330 /// have been filtered out.
8331 ///
8332 /// @return the net number of added functions.
8333 size_t
8335 {
8336  ABG_ASSERT(num_func_added() >= num_added_func_filtered_out());
8337  return num_func_added() - num_added_func_filtered_out();
8338 }
8339 
8340 /// Getter for the number of functions that have a change in one of
8341 /// their sub-types.
8342 ///
8343 /// @return the number of functions that have a change in one of their
8344 /// sub-types.
8345 size_t
8347 {return priv_->num_func_changed;}
8348 
8349 /// Setter for the number of functions that have a change in one of
8350 /// their sub-types.
8351 ///
8352 /// @@param n the new number of functions that have a change in one of
8353 /// their sub-types.
8354 void
8356 {priv_->num_func_changed = n;}
8357 
8358 /// Getter for the number of functions that have a change in one of
8359 /// their sub-types, and that have been filtered out.
8360 ///
8361 /// @return the number of functions that have a change in one of their
8362 /// sub-types, and that have been filtered out.
8363 size_t
8365 {return priv_->num_changed_func_filtered_out;}
8366 
8367 /// Setter for the number of functions that have a change in one of
8368 /// their sub-types, and that have been filtered out.
8369 ///
8370 /// @param n the new number of functions that have a change in one of their
8371 /// sub-types, and that have been filtered out.
8372 void
8374 {priv_->num_changed_func_filtered_out = n;}
8375 
8376 /// Getter for the number of functions that carry virtual member
8377 /// offset changes.
8378 ///
8379 /// @return the number of functions that carry virtual member changes.
8380 size_t
8382 {return priv_->num_func_with_virt_offset_changes;}
8383 
8384 /// Setter for the number of functions that carry virtual member
8385 /// offset changes.
8386 ///
8387 /// @param n the new number of functions that carry virtual member
8388 /// offset. changes.
8389 void
8391 {priv_->num_func_with_virt_offset_changes = n;}
8392 
8393 /// Getter for the number of functions that have a change in their
8394 /// sub-types, minus the number of these functions that got filtered
8395 /// out from the diff.
8396 ///
8397 /// @return for the the number of functions that have a change in
8398 /// their sub-types, minus the number of these functions that got
8399 /// filtered out from the diff.
8400 size_t
8402 {return num_func_changed() - num_changed_func_filtered_out();}
8403 
8404 /// Getter for the number of variables removed.
8405 ///
8406 /// @return the number of variables removed.
8407 size_t
8409 {return priv_->num_vars_removed;}
8410 
8411 /// Setter for the number of variables removed.
8412 ///
8413 /// @param n the new number of variables removed.
8414 void
8416 {priv_->num_vars_removed = n;}
8417 
8418 /// Getter for the number removed variables that have been filtered
8419 /// out.
8420 ///
8421 /// @return the number removed variables that have been filtered out.
8422 size_t
8424 {
8425  if (priv_->ctxt() && !priv_->ctxt()->show_deleted_vars())
8426  return num_vars_removed();
8427  return priv_->num_removed_vars_filtered_out;
8428 }
8429 
8430 /// Setter for the number of removed variables that have been filtered
8431 /// out.
8432 ///
8433 /// @param n the new value.
8434 void
8436 {priv_->num_removed_vars_filtered_out = n;}
8437 
8438 /// Getter for the net number of removed variables.
8439 ///
8440 /// The net number of removed variables is the difference between the
8441 /// number of removed variables and the number of removed variables
8442 /// that have been filtered out.
8443 ///
8444 /// @return the net number of removed variables.
8445 size_t
8447 {
8448  ABG_ASSERT(num_vars_removed() >= num_removed_vars_filtered_out());
8449  return num_vars_removed() - num_removed_vars_filtered_out();
8450 }
8451 
8452 /// Getter for the number of variables added.
8453 ///
8454 /// @return the number of variables added.
8455 size_t
8457 {return priv_->num_vars_added;}
8458 
8459 /// Setter for the number of variables added.
8460 ///
8461 /// @param n the new number of variables added.
8462 void
8464 {priv_->num_vars_added = n;}
8465 
8466 /// Getter for the number of added variables that have been filtered
8467 /// out.
8468 ///
8469 /// @return the number of added variables that have been filtered out.
8470 size_t
8472 {
8473  if (priv_->ctxt() && !priv_->ctxt()->show_added_vars())
8474  return num_vars_added();
8475  return priv_->num_added_vars_filtered_out;
8476 }
8477 
8478 /// Setter for the number of added variables that have been filtered
8479 /// out.
8480 ///
8481 /// @param n the new value.
8482 void
8484 {priv_->num_added_vars_filtered_out = n;}
8485 
8486 /// Getter for the net number of added variables.
8487 ///
8488 /// The net number of added variables is the difference between the
8489 /// number of added variables and the number of added variables that
8490 /// have been filetered out.
8491 ///
8492 /// @return the net number of added variables.
8493 size_t
8495 {
8496  ABG_ASSERT(num_vars_added() >= num_added_vars_filtered_out());
8497  return num_vars_added() - num_added_vars_filtered_out();
8498 }
8499 
8500 /// Getter for the number of variables that have a change in one of
8501 /// their sub-types.
8502 ///
8503 /// @return the number of variables that have a change in one of their
8504 /// sub-types.
8505 size_t
8507 {return priv_->num_vars_changed;}
8508 
8509 /// Setter for the number of variables that have a change in one of
8510 /// their sub-types.
8511 ///
8512 /// @param n the new number of variables that have a change in one of
8513 /// their sub-types.
8514 void
8516 {priv_->num_vars_changed = n;}
8517 
8518 /// Getter for the number of variables that have a change in one of
8519 /// their sub-types, and that have been filtered out.
8520 ///
8521 /// @return the number of functions that have a change in one of their
8522 /// sub-types, and that have been filtered out.
8523 size_t
8525 {return priv_->num_changed_vars_filtered_out;}
8526 
8527 /// Setter for the number of variables that have a change in one of
8528 /// their sub-types, and that have been filtered out.
8529 ///
8530 /// @param n the new number of variables that have a change in one of their
8531 /// sub-types, and that have been filtered out.
8532 void
8534 {priv_->num_changed_vars_filtered_out = n;}
8535 
8536 /// Getter for the number of variables that have a change in their
8537 /// sub-types, minus the number of these variables that got filtered
8538 /// out from the diff.
8539 ///
8540 /// @return for the the number of variables that have a change in
8541 /// their sub-types, minus the number of these variables that got
8542 /// filtered out from the diff.
8543 size_t
8545 {return num_vars_changed() - num_changed_vars_filtered_out();}
8546 
8547 /// Getter for the number of function symbols (not referenced by any
8548 /// debug info) that got removed.
8549 ///
8550 /// @return the number of function symbols (not referenced by any
8551 /// debug info) that got removed.
8552 size_t
8554 {return priv_->num_func_syms_removed;}
8555 
8556 /// Setter for the number of function symbols (not referenced by any
8557 /// debug info) that got removed.
8558 ///
8559 /// @param n the number of function symbols (not referenced by any
8560 /// debug info) that got removed.
8561 void
8563 {priv_->num_func_syms_removed = n;}
8564 
8565 /// Getter for the number of removed function symbols, not referenced
8566 /// by debug info, that have been filtered out.
8567 ///
8568 /// @return the number of removed function symbols, not referenced by
8569 /// debug info, that have been filtered out.
8570 size_t
8572 {
8573  if (priv_->ctxt()
8574  && !priv_->ctxt()->show_symbols_unreferenced_by_debug_info())
8575  return num_func_syms_removed();
8576  return priv_->num_removed_func_syms_filtered_out;
8577 }
8578 
8579 /// Setter for the number of removed function symbols, not referenced
8580 /// by debug info, that have been filtered out.
8581 ///
8582 /// @param n the new the number of removed function symbols, not
8583 /// referenced by debug info, that have been filtered out.
8584 void
8586 {priv_->num_removed_func_syms_filtered_out = n;}
8587 
8588 /// Getter of the net number of removed function symbols that are not
8589 /// referenced by any debug info.
8590 ///
8591 /// This is the difference between the total number of removed
8592 /// function symbols and the number of removed function symbols that
8593 /// have been filteted out. Both numbers are for symbols not
8594 /// referenced by debug info.
8595 ///
8596 /// return the net number of removed function symbols that are not
8597 /// referenced by any debug info.
8598 size_t
8600 {
8601  ABG_ASSERT(num_func_syms_removed() >= num_removed_func_syms_filtered_out());
8602  return num_func_syms_removed() - num_removed_func_syms_filtered_out();
8603 }
8604 
8605 /// Getter for the number of function symbols (not referenced by any
8606 /// debug info) that got added.
8607 ///
8608 /// @return the number of function symbols (not referenced by any
8609 /// debug info) that got added.
8610 size_t
8612 {return priv_->num_func_syms_added;}
8613 
8614 /// Setter for the number of function symbols (not referenced by any
8615 /// debug info) that got added.
8616 ///
8617 /// @param n the new number of function symbols (not referenced by any
8618 /// debug info) that got added.
8619 void
8621 {priv_->num_func_syms_added = n;}
8622 
8623 /// Getter for the number of added function symbols, not referenced by
8624 /// any debug info, that have been filtered out.
8625 ///
8626 /// @return the number of added function symbols, not referenced by
8627 /// any debug info, that have been filtered out.
8628 size_t
8630 {
8631  if (priv_->ctxt()
8632  && !(priv_->ctxt()->show_added_symbols_unreferenced_by_debug_info()
8633  && priv_->ctxt()->show_symbols_unreferenced_by_debug_info()))
8634  return num_func_syms_added();
8635  return priv_->num_added_func_syms_filtered_out;
8636 }
8637 
8638 /// Setter for the number of added function symbols, not referenced by
8639 /// any debug info, that have been filtered out.
8640 ///
8641 /// @param n the new number of added function symbols, not referenced
8642 /// by any debug info, that have been filtered out.
8643 void
8645 {priv_->num_added_func_syms_filtered_out = n;}
8646 
8647 /// Getter of the net number of added function symbols that are not
8648 /// referenced by any debug info.
8649 ///
8650 /// This is the difference between the total number of added
8651 /// function symbols and the number of added function symbols that
8652 /// have been filteted out. Both numbers are for symbols not
8653 /// referenced by debug info.
8654 ///
8655 /// return the net number of added function symbols that are not
8656 /// referenced by any debug info.
8657 size_t
8659 {
8660  ABG_ASSERT(num_func_syms_added() >= num_added_func_syms_filtered_out());
8661  return num_func_syms_added()- num_added_func_syms_filtered_out();
8662 }
8663 
8664 /// Getter for the number of variable symbols (not referenced by any
8665 /// debug info) that got removed.
8666 ///
8667 /// @return the number of variable symbols (not referenced by any
8668 /// debug info) that got removed.
8669 size_t
8671 {return priv_->num_var_syms_removed;}
8672 
8673 /// Setter for the number of variable symbols (not referenced by any
8674 /// debug info) that got removed.
8675 ///
8676 /// @param n the number of variable symbols (not referenced by any
8677 /// debug info) that got removed.
8678 void
8680 {priv_->num_var_syms_removed = n;}
8681 
8682 /// Getter for the number of removed variable symbols, not referenced
8683 /// by any debug info, that have been filtered out.
8684 ///
8685 /// @return the number of removed variable symbols, not referenced
8686 /// by any debug info, that have been filtered out.
8687 size_t
8689 {
8690  if (priv_->ctxt()
8691  && !priv_->ctxt()->show_symbols_unreferenced_by_debug_info())
8692  return num_var_syms_removed();
8693  return priv_->num_removed_var_syms_filtered_out;
8694 }
8695 
8696 /// Setter for the number of removed variable symbols, not referenced
8697 /// by any debug info, that have been filtered out.
8698 ///
8699 /// @param n the number of removed variable symbols, not referenced by
8700 /// any debug info, that have been filtered out.
8701 void
8703 {priv_->num_removed_var_syms_filtered_out = n;}
8704 
8705 /// Getter of the net number of removed variable symbols that are not
8706 /// referenced by any debug info.
8707 ///
8708 /// This is the difference between the total number of removed
8709 /// variable symbols and the number of removed variable symbols that
8710 /// have been filteted out. Both numbers are for symbols not
8711 /// referenced by debug info.
8712 ///
8713 /// return the net number of removed variable symbols that are not
8714 /// referenced by any debug info.
8715 size_t
8717 {
8718  ABG_ASSERT(num_var_syms_removed() >= num_removed_var_syms_filtered_out());
8719  return num_var_syms_removed() - num_removed_var_syms_filtered_out();
8720 }
8721 
8722 /// Getter for the number of variable symbols (not referenced by any
8723 /// debug info) that got added.
8724 ///
8725 /// @return the number of variable symbols (not referenced by any
8726 /// debug info) that got added.
8727 size_t
8729 {return priv_->num_var_syms_added;}
8730 
8731 /// Setter for the number of variable symbols (not referenced by any
8732 /// debug info) that got added.
8733 ///
8734 /// @param n the new number of variable symbols (not referenced by any
8735 /// debug info) that got added.
8736 void
8738 {priv_->num_var_syms_added = n;}
8739 
8740 /// Getter for the number of added variable symbols, not referenced by
8741 /// any debug info, that have been filtered out.
8742 ///
8743 /// @return the number of added variable symbols, not referenced by
8744 /// any debug info, that have been filtered out.
8745 size_t
8747 {
8748  if (priv_->ctxt()
8749  && !(priv_->ctxt()->show_added_symbols_unreferenced_by_debug_info()
8750  && priv_->ctxt()->show_symbols_unreferenced_by_debug_info()))
8751  return num_var_syms_added();
8752  return priv_->num_added_var_syms_filtered_out;
8753 }
8754 
8755 /// Setter for the number of added variable symbols, not referenced by
8756 /// any debug info, that have been filtered out.
8757 ///
8758 /// @param n the new number of added variable symbols, not referenced
8759 /// by any debug info, that have been filtered out.
8760 void
8762 {priv_->num_added_var_syms_filtered_out = n;}
8763 
8764 /// Getter of the net number of added variable symbols that are not
8765 /// referenced by any debug info.
8766 ///
8767 /// This is the difference between the total number of added
8768 /// variable symbols and the number of added variable symbols that
8769 /// have been filteted out. Both numbers are for symbols not
8770 /// referenced by debug info.
8771 ///
8772 /// return the net number of added variable symbols that are not
8773 /// referenced by any debug info.
8774 size_t
8776 {
8777  ABG_ASSERT(num_var_syms_added() >= num_added_var_syms_filtered_out());
8778  return num_var_syms_added() - num_added_var_syms_filtered_out();
8779 }
8780 
8781 /// Getter of the number of leaf type change diff nodes.
8782 ///
8783 /// @return the number of leaf type change diff nodes.
8784 size_t
8786 {return priv_->num_leaf_changes;}
8787 
8788 /// Setter of the number of leaf type change diff nodes.
8789 ///
8790 /// @param n the new number of leaf type change diff nodes.
8791 void
8793 {priv_->num_leaf_changes = n;}
8794 
8795 /// Getter of the number of leaf type change diff nodes that have been
8796 /// filtered out.
8797 ///
8798 /// @return the number of leaf type change diff nodes that have been
8799 size_t
8801 {return priv_->num_leaf_changes_filtered_out;}
8802 
8803 /// Setter of the number of leaf type change diff nodes that have been
8804 /// filtered out.
8805 ///
8806 /// @param n the new number of leaf type change diff nodes that have
8807 /// been filtered out.
8808 void
8810 {priv_->num_leaf_changes_filtered_out = n;}
8811 
8812 /// Getter of the net number of leaf change diff nodes.
8813 ///
8814 /// This is the difference between the total number of leaf change
8815 /// diff nodes, and the number of the leaf change diff nodes that have
8816 /// been filtered out.
8817 ///
8818 /// A leaf change is either a type change, a function change or a
8819 /// variable change.
8820 size_t
8822 {
8823  ABG_ASSERT(num_leaf_changes() >= num_leaf_changes_filtered_out());
8824  return num_leaf_changes() - num_leaf_changes_filtered_out();
8825 }
8826 
8827 /// Getter for the number of leaf type change diff nodes.
8828 ///
8829 /// @return the number of leaf type changes diff nodes.
8830 size_t
8832 {return priv_->num_leaf_type_changes;}
8833 
8834 /// Setter for the number of leaf type change diff nodes.
8835 ///
8836 /// @param n the new number of leaf type change diff nodes.
8837 void
8839 {priv_->num_leaf_type_changes = n;}
8840 
8841 /// Getter for the number of filtered out leaf type change diff nodes.
8842 ///
8843 /// @return the number of filtered out leaf type change diff nodes.
8844 size_t
8846 {return priv_->num_leaf_type_changes_filtered_out;}
8847 
8848 /// Setter for the number of filtered out leaf type change diff nodes.
8849 /// @param n the new number of filtered out leaf type change diff nodes.
8850 void
8852 {priv_->num_leaf_type_changes_filtered_out = n;}
8853 
8854 /// Getter for the net number of leaf type change diff nodes.
8855 ///
8856 /// This is the difference between the number of leaf type changes and
8857 /// the number of filtered out leaf type changes.
8858 ///
8859 /// @return the net number of leaf type change diff nodes.
8860 size_t
8862 {return num_leaf_type_changes() - num_leaf_type_changes_filtered_out();}
8863 
8864 /// Getter for the number of leaf function change diff nodes.
8865 ///
8866 /// @return the number of leaf function change diff nodes.
8867 size_t
8869 {return priv_->num_leaf_func_changes;}
8870 
8871 /// Setter for the number of leaf function change diff nodes.
8872 ///
8873 /// @param n the new number of leaf function change diff nodes.
8874 void
8876 {priv_->num_leaf_func_changes = n;}
8877 
8878 /// Getter for the number of leaf function change diff nodes that were
8879 /// filtered out.
8880 ///
8881 /// @return the number of leaf function change diff nodes that were
8882 /// filtered out.
8883 size_t
8885 {return priv_->num_leaf_func_changes_filtered_out;}
8886 
8887 /// Setter for the number of leaf function change diff nodes that were
8888 /// filtered out.
8889 ///
8890 /// @param n the new number of leaf function change diff nodes that
8891 /// were filtered out.
8892 void
8894 {priv_->num_leaf_func_changes_filtered_out = n;}
8895 
8896 /// Getter for the net number of leaf function change diff nodes.
8897 ///
8898 /// This is the difference between the number of leaf function change
8899 /// diff nodes and the number of filtered out leaf function change
8900 /// diff nodes.
8901 ///
8902 /// @return the net number of leaf function change diff nodes.
8903 size_t
8905 {return num_leaf_func_changes() - num_leaf_func_changes_filtered_out();}
8906 
8907 /// Getter for the number of leaf variable change diff nodes.
8908 ///
8909 /// @return the number of leaf variable change diff nodes.
8910 size_t
8912 {return priv_->num_leaf_var_changes;}
8913 
8914 /// Setter for the number of leaf variable change diff nodes.
8915 ///
8916 /// @param n the number of leaf variable change diff nodes.
8917 void
8919 {priv_->num_leaf_var_changes = n;}
8920 
8921 /// Getter of the number of added types that are unreachable from the
8922 /// public interface of the ABI corpus.
8923 ///
8924 /// Public interface means the set of defined and publicly exported
8925 /// functions and variables of the ABI corpus.
8926 ///
8927 /// @return the number of added types that are unreachable from the
8928 /// public interface of the ABI corpus.
8929 size_t
8931 {return priv_->num_added_unreachable_types;}
8932 
8933 /// Setter of the number of added types that are unreachable from the
8934 /// public interface (global functions or variables) of the ABI
8935 /// corpus.
8936 ///
8937 /// Public interface means the set of defined and publicly exported
8938 /// functions and variables of the ABI corpus.
8939 ///
8940 /// @param n the new number of added types that are unreachable from
8941 /// the public interface of the ABI corpus.
8942 void
8944 {priv_->num_added_unreachable_types = n;}
8945 
8946 /// Getter of the number of added types that are unreachable from
8947 /// public interfaces and that are filtered out by suppression
8948 /// specifications.
8949 ///
8950 /// @return the number of added types that are unreachable from public
8951 /// interfaces and that are filtered out by suppression
8952 /// specifications.
8953 size_t
8955 {return priv_->num_added_unreachable_types_filtered_out;}
8956 
8957 /// Setter of the number of added types that are unreachable from
8958 /// public interfaces and that are filtered out by suppression
8959 /// specifications.
8960 ///
8961 /// @param n the new number of added types that are unreachable from
8962 /// public interfaces and that are filtered out by suppression
8963 /// specifications.
8964 void
8966 {priv_->num_added_unreachable_types_filtered_out = n;}
8967 
8968 /// Getter of the number of added types that are unreachable from
8969 /// public interfaces and that are *NOT* filtered out by suppression
8970 /// specifications.
8971 ///
8972 /// @return the number of added types that are unreachable from public
8973 /// interfaces and that are *NOT* filtered out by suppression
8974 /// specifications.
8975 size_t
8977 {
8978  ABG_ASSERT(num_added_unreachable_types()
8979  >=
8980  num_added_unreachable_types_filtered_out());
8981 
8982  return (num_added_unreachable_types()
8983  -
8984  num_added_unreachable_types_filtered_out());
8985 }
8986 
8987 /// Getter of the number of removed types that are unreachable from
8988 /// the public interface of the ABI corpus.
8989 ///
8990 /// Public interface means the set of defined and publicly exported
8991 /// functions and variables of the ABI corpus.
8992 ///
8993 /// @return the number of removed types that are unreachable from
8994 /// the public interface of the ABI corpus.
8995 size_t
8997 {return priv_->num_removed_unreachable_types;}
8998 
8999 /// Setter of the number of removed types that are unreachable from
9000 /// the public interface of the ABI corpus.
9001 ///
9002 /// Public interface means the set of defined and publicly exported
9003 /// functions and variables of the ABI corpus.
9004 ///
9005 ///@param n the new number of removed types that are unreachable from
9006 /// the public interface of the ABI corpus.
9007 void
9009 {priv_->num_removed_unreachable_types = n;}
9010 
9011 /// Getter of the number of removed types that are not reachable from
9012 /// public interfaces and that have been filtered out by suppression
9013 /// specifications.
9014 ///
9015 /// @return the number of removed types that are not reachable from
9016 /// public interfaces and that have been filtered out by suppression
9017 /// specifications.
9018 size_t
9020 {return priv_->num_removed_unreachable_types_filtered_out;}
9021 
9022 /// Setter of the number of removed types that are not reachable from
9023 /// public interfaces and that have been filtered out by suppression
9024 /// specifications.
9025 ///
9026 /// @param n the new number of removed types that are not reachable
9027 /// from public interfaces and that have been filtered out by
9028 /// suppression specifications.
9029 void
9031 {priv_->num_removed_unreachable_types_filtered_out = n;}
9032 
9033 /// Getter of the number of removed types that are not reachable from
9034 /// public interfaces and that have *NOT* been filtered out by
9035 /// suppression specifications.
9036 ///
9037 /// @return the number of removed types that are not reachable from
9038 /// public interfaces and that have *NOT* been filtered out by
9039 /// suppression specifications.
9040 size_t
9042 {
9043  ABG_ASSERT(num_removed_unreachable_types()
9044  >=
9045  num_removed_unreachable_types_filtered_out());
9046 
9047  return (num_removed_unreachable_types()
9048  -
9049  num_removed_unreachable_types_filtered_out());
9050 }
9051 
9052 /// Getter of the number of changed types that are unreachable from
9053 /// the public interface of the ABI corpus.
9054 ///
9055 /// Public interface means the set of defined and publicly exported
9056 /// functions and variables of the ABI corpus.
9057 ///
9058 /// @return the number of changed types that are unreachable from the
9059 /// public interface of the ABI corpus.
9060 size_t
9062 {return priv_->num_changed_unreachable_types;}
9063 
9064 /// Setter of the number of changed types that are unreachable from
9065 /// the public interface of the ABI corpus.
9066 ///
9067 /// Public interface means the set of defined and publicly exported
9068 /// functions and variables of the ABI corpus.
9069 ///
9070 ///@param n the new number of changed types that are unreachable from
9071 /// the public interface of the ABI corpus.
9072 void
9074 {priv_->num_changed_unreachable_types = n;}
9075 
9076 /// Getter of the number of changed types that are unreachable from
9077 /// public interfaces and that have been filtered out by suppression
9078 /// specifications.
9079 ///
9080 /// @return the number of changed types that are unreachable from
9081 /// public interfaces and that have been filtered out by suppression
9082 /// specifications.
9083 size_t
9085 {return priv_->num_changed_unreachable_types_filtered_out;}
9086 
9087 /// Setter of the number of changed types that are unreachable from
9088 /// public interfaces and that have been filtered out by suppression
9089 /// specifications.
9090 ///
9091 /// @param n the new number of changed types that are unreachable from
9092 /// public interfaces and that have been filtered out by suppression
9093 /// specifications.
9094 void
9096 {priv_->num_changed_unreachable_types_filtered_out = n;}
9097 
9098 /// Getter of the number of changed types that are unreachable from
9099 /// public interfaces and that have *NOT* been filtered out by
9100 /// suppression specifications.
9101 ///
9102 /// @return the number of changed types that are unreachable from
9103 /// public interfaces and that have *NOT* been filtered out by
9104 /// suppression specifications.
9105 size_t
9107 {
9108  ABG_ASSERT(num_changed_unreachable_types()
9109  >=
9110  num_changed_unreachable_types_filtered_out());
9111 
9112  return (num_changed_unreachable_types()
9113  -
9114  num_changed_unreachable_types_filtered_out());
9115 }
9116 
9117 /// Getter for the number of leaf variable changes diff nodes that
9118 /// have been filtered out.
9119 ///
9120 /// @return the number of leaf variable changes diff nodes that have
9121 /// been filtered out.
9122 size_t
9124 {return priv_->num_leaf_var_changes_filtered_out;}
9125 
9126 /// Setter for the number of leaf variable changes diff nodes that
9127 /// have been filtered out.
9128 ///
9129 /// @param n the number of leaf variable changes diff nodes that have
9130 /// been filtered out.
9131 void
9133 {priv_->num_leaf_var_changes_filtered_out = n;}
9134 
9135 /// Getter for the net number of leaf variable change diff nodes.
9136 ///
9137 /// This the difference between the number of leaf variable change
9138 /// diff nodes and the number of filtered out leaf variable change
9139 /// diff nodes.
9140 ///
9141 /// @return the net number of leaf variable change diff nodes.
9142 size_t
9144 {return num_leaf_var_changes() - num_leaf_var_changes_filtered_out();}
9145 
9146 
9147 // <corpus_diff stuff>
9148 
9149 /// Getter of the context associated with this corpus.
9150 ///
9151 /// @return a smart pointer to the context associate with the corpus.
9154 {return ctxt_.lock();}
9155 
9156 /// Tests if the lookup tables are empty.
9157 ///
9158 /// @return true if the lookup tables are empty, false otherwise.
9159 bool
9161 {
9162  return (deleted_fns_.empty()
9163  && added_fns_.empty()
9164  && changed_fns_map_.empty()
9165  && deleted_vars_.empty()
9166  && added_vars_.empty()
9167  && changed_vars_map_.empty());
9168 }
9169 
9170 /// Clear the lookup tables useful for reporting an enum_diff.
9171 void
9173 {
9174  deleted_fns_.clear();
9175  added_fns_.clear();
9176  changed_fns_map_.clear();
9177  deleted_vars_.clear();
9178  added_vars_.clear();
9179  changed_vars_map_.clear();
9180 }
9181 
9182 /// If the lookup tables are not yet built, walk the differences and
9183 /// fill the lookup tables.
9184 void
9186 {
9187  if (!lookup_tables_empty())
9188  return;
9189 
9190  diff_context_sptr ctxt = get_context();
9191 
9192  {
9193  edit_script& e = fns_edit_script_;
9194 
9195  for (vector<deletion>::const_iterator it = e.deletions().begin();
9196  it != e.deletions().end();
9197  ++it)
9198  {
9199  unsigned i = it->index();
9200  ABG_ASSERT(i < first_->get_functions().size());
9201 
9202  function_decl* deleted_fn = first_->get_functions()[i];
9203  string n = get_function_id_or_pretty_representation(deleted_fn);
9204  ABG_ASSERT(!n.empty());
9205  // The below is commented out because there can be several
9206  // functions with the same ID in the corpus. So several
9207  // functions with the same ID can be deleted.
9208  // ABG_ASSERT(deleted_fns_.find(n) == deleted_fns_.end());
9209  deleted_fns_[n] = deleted_fn;
9210  }
9211 
9212  for (vector<insertion>::const_iterator it = e.insertions().begin();
9213  it != e.insertions().end();
9214  ++it)
9215  {
9216  for (vector<unsigned>::const_iterator iit =
9217  it->inserted_indexes().begin();
9218  iit != it->inserted_indexes().end();
9219  ++iit)
9220  {
9221  unsigned i = *iit;
9222  function_decl* added_fn = second_->get_functions()[i];
9223  string n = get_function_id_or_pretty_representation(added_fn);
9224  ABG_ASSERT(!n.empty());
9225  // The below is commented out because there can be several
9226  // functions with the same ID in the corpus. So several
9227  // functions with the same ID can be added.
9228  // ABG_ASSERT(added_fns_.find(n) == added_fns_.end());
9229  string_function_ptr_map::const_iterator j =
9230  deleted_fns_.find(n);
9231  if (j != deleted_fns_.end())
9232  {
9233  function_decl_sptr f(j->second, noop_deleter());
9234  function_decl_sptr s(added_fn, noop_deleter());
9235  function_decl_diff_sptr d = compute_diff(f, s, ctxt);
9236  if (*j->second != *added_fn)
9237  changed_fns_map_[j->first] = d;
9238  deleted_fns_.erase(j);
9239  }
9240  else
9241  added_fns_[n] = added_fn;
9242  }
9243  }
9244  sort_string_function_decl_diff_sptr_map(changed_fns_map_, changed_fns_);
9245 
9246  // Now walk the allegedly deleted functions; check if their
9247  // underlying symbols are deleted as well; otherwise, consider
9248  // that the function in question hasn't been deleted.
9249 
9250  vector<string> to_delete;
9251  for (string_function_ptr_map::const_iterator i = deleted_fns_.begin();
9252  i != deleted_fns_.end();
9253  ++i)
9254  if (second_->lookup_function_symbol(*i->second->get_symbol()))
9255  to_delete.push_back(i->first);
9256 
9257  for (vector<string>::const_iterator i = to_delete.begin();
9258  i != to_delete.end();
9259  ++i)
9260  deleted_fns_.erase(*i);
9261 
9262  // Do something similar for added functions.
9263 
9264  to_delete.clear();
9265  for (string_function_ptr_map::const_iterator i = added_fns_.begin();
9266  i != added_fns_.end();
9267  ++i)
9268  {
9269  if (first_->lookup_function_symbol(*i->second->get_symbol()))
9270  to_delete.push_back(i->first);
9271  else if (! i->second->get_symbol()->get_version().is_empty()
9272  && i->second->get_symbol()->get_version().is_default())
9273  // We are looking for a symbol that has a default version,
9274  // and which seems to be newly added. Let's see if the same
9275  // symbol with *no* version was already present in the
9276  // former corpus. If yes, then the symbol shouldn't be
9277  // considered as 'added'.
9278  {
9279  elf_symbol::version empty_version;
9280  if (first_->lookup_function_symbol(i->second->get_symbol()->get_name(),
9281  empty_version))
9282  to_delete.push_back(i->first);
9283  }
9284  }
9285 
9286  for (vector<string>::const_iterator i = to_delete.begin();
9287  i != to_delete.end();
9288  ++i)
9289  added_fns_.erase(*i);
9290  }
9291 
9292  {
9293  edit_script& e = vars_edit_script_;
9294 
9295  for (vector<deletion>::const_iterator it = e.deletions().begin();
9296  it != e.deletions().end();
9297  ++it)
9298  {
9299  unsigned i = it->index();
9300  ABG_ASSERT(i < first_->get_variables().size());
9301 
9302  var_decl* deleted_var = first_->get_variables()[i];
9303  string n = deleted_var->get_id();
9304  ABG_ASSERT(!n.empty());
9305  ABG_ASSERT(deleted_vars_.find(n) == deleted_vars_.end());
9306  deleted_vars_[n] = deleted_var;
9307  }
9308 
9309  for (vector<insertion>::const_iterator it = e.insertions().begin();
9310  it != e.insertions().end();
9311  ++it)
9312  {
9313  for (vector<unsigned>::const_iterator iit =
9314  it->inserted_indexes().begin();
9315  iit != it->inserted_indexes().end();
9316  ++iit)
9317  {
9318  unsigned i = *iit;
9319  var_decl* added_var = second_->get_variables()[i];
9320  string n = added_var->get_id();
9321  ABG_ASSERT(!n.empty());
9322  {
9323  string_var_ptr_map::const_iterator k = added_vars_.find(n);
9324  if ( k != added_vars_.end())
9325  {
9326  ABG_ASSERT(is_member_decl(k->second)
9327  && get_member_is_static(k->second));
9328  continue;
9329  }
9330  }
9331  string_var_ptr_map::const_iterator j =
9332  deleted_vars_.find(n);
9333  if (j != deleted_vars_.end())
9334  {
9335  if (*j->second != *added_var)
9336  {
9337  var_decl_sptr f(j->second, noop_deleter());
9338  var_decl_sptr s(added_var, noop_deleter());
9339  changed_vars_map_[n] = compute_diff(f, s, ctxt);
9340  }
9341  deleted_vars_.erase(j);
9342  }
9343  else
9344  added_vars_[n] = added_var;
9345  }
9346  }
9347  sort_string_var_diff_sptr_map(changed_vars_map_,
9348  sorted_changed_vars_);
9349 
9350  // Now walk the allegedly deleted variables; check if their
9351  // underlying symbols are deleted as well; otherwise consider
9352  // that the variable in question hasn't been deleted.
9353 
9354  vector<string> to_delete;
9355  for (string_var_ptr_map::const_iterator i = deleted_vars_.begin();
9356  i != deleted_vars_.end();
9357  ++i)
9358  if (second_->lookup_variable_symbol(*i->second->get_symbol()))
9359  to_delete.push_back(i->first);
9360 
9361  for (vector<string>::const_iterator i = to_delete.begin();
9362  i != to_delete.end();
9363  ++i)
9364  deleted_vars_.erase(*i);
9365 
9366  // Do something similar for added variables.
9367 
9368  to_delete.clear();
9369  for (string_var_ptr_map::const_iterator i = added_vars_.begin();
9370  i != added_vars_.end();
9371  ++i)
9372  if (first_->lookup_variable_symbol(*i->second->get_symbol()))
9373  to_delete.push_back(i->first);
9374  else if (! i->second->get_symbol()->get_version().is_empty()
9375  && i->second->get_symbol()->get_version().is_default())
9376  // We are looking for a symbol that has a default version,
9377  // and which seems to be newly added. Let's see if the same
9378  // symbol with *no* version was already present in the
9379  // former corpus. If yes, then the symbol shouldn't be
9380  // considered as 'added'.
9381  {
9382  elf_symbol::version empty_version;
9383  if (first_->lookup_variable_symbol(i->second->get_symbol()->get_name(),
9384  empty_version))
9385  to_delete.push_back(i->first);
9386  }
9387 
9388  for (vector<string>::const_iterator i = to_delete.begin();
9389  i != to_delete.end();
9390  ++i)
9391  added_vars_.erase(*i);
9392  }
9393 
9394  // Massage the edit script for added/removed function symbols that
9395  // were not referenced by any debug info and turn them into maps of
9396  // {symbol_name, symbol}.
9397  {
9398  edit_script& e = unrefed_fn_syms_edit_script_;
9399  for (vector<deletion>::const_iterator it = e.deletions().begin();
9400  it != e.deletions().end();
9401  ++it)
9402  {
9403  unsigned i = it->index();
9404  ABG_ASSERT(i < first_->get_unreferenced_function_symbols().size());
9405  elf_symbol_sptr deleted_sym =
9406  first_->get_unreferenced_function_symbols()[i];
9407  if (!second_->lookup_function_symbol(*deleted_sym))
9408  deleted_unrefed_fn_syms_[deleted_sym->get_id_string()] = deleted_sym;
9409  }
9410 
9411  for (vector<insertion>::const_iterator it = e.insertions().begin();
9412  it != e.insertions().end();
9413  ++it)
9414  {
9415  for (vector<unsigned>::const_iterator iit =
9416  it->inserted_indexes().begin();
9417  iit != it->inserted_indexes().end();
9418  ++iit)
9419  {
9420  unsigned i = *iit;
9421  ABG_ASSERT(i < second_->get_unreferenced_function_symbols().size());
9422  elf_symbol_sptr added_sym =
9423  second_->get_unreferenced_function_symbols()[i];
9424  if ((deleted_unrefed_fn_syms_.find(added_sym->get_id_string())
9425  == deleted_unrefed_fn_syms_.end()))
9426  {
9427  if (!first_->lookup_function_symbol(*added_sym))
9428  {
9429  bool do_add = true;
9430  if (! added_sym->get_version().is_empty()
9431  && added_sym->get_version().is_default())
9432  {
9433  // So added_seem has a default version. If
9434  // the former corpus had a symbol with the
9435  // same name as added_sym but with *no*
9436  // version, then added_sym shouldn't be
9437  // considered as a newly added symbol.
9438  elf_symbol::version empty_version;
9439  if (first_->lookup_function_symbol(added_sym->get_name(),
9440  empty_version))
9441  do_add = false;
9442  }
9443 
9444  if (do_add)
9445  added_unrefed_fn_syms_[added_sym->get_id_string()] =
9446  added_sym;
9447  }
9448  }
9449  else
9450  deleted_unrefed_fn_syms_.erase(added_sym->get_id_string());
9451  }
9452  }
9453  }
9454 
9455  // Massage the edit script for added/removed variable symbols that
9456  // were not referenced by any debug info and turn them into maps of
9457  // {symbol_name, symbol}.
9458  {
9459  edit_script& e = unrefed_var_syms_edit_script_;
9460  for (vector<deletion>::const_iterator it = e.deletions().begin();
9461  it != e.deletions().end();
9462  ++it)
9463  {
9464  unsigned i = it->index();
9465  ABG_ASSERT(i < first_->get_unreferenced_variable_symbols().size());
9466  elf_symbol_sptr deleted_sym =
9467  first_->get_unreferenced_variable_symbols()[i];
9468  if (!second_->lookup_variable_symbol(*deleted_sym))
9469  deleted_unrefed_var_syms_[deleted_sym->get_id_string()] = deleted_sym;
9470  }
9471 
9472  for (vector<insertion>::const_iterator it = e.insertions().begin();
9473  it != e.insertions().end();
9474  ++it)
9475  {
9476  for (vector<unsigned>::const_iterator iit =
9477  it->inserted_indexes().begin();
9478  iit != it->inserted_indexes().end();
9479  ++iit)
9480  {
9481  unsigned i = *iit;
9482  ABG_ASSERT(i < second_->get_unreferenced_variable_symbols().size());
9483  elf_symbol_sptr added_sym =
9484  second_->get_unreferenced_variable_symbols()[i];
9485  if (deleted_unrefed_var_syms_.find(added_sym->get_id_string())
9486  == deleted_unrefed_var_syms_.end())
9487  {
9488  if (!first_->lookup_variable_symbol(*added_sym))
9489  {
9490  bool do_add = true;
9491  if (! added_sym->get_version().is_empty()
9492  && added_sym->get_version().is_default())
9493  {
9494  // So added_seem has a default version. If
9495  // the former corpus had a symbol with the
9496  // same name as added_sym but with *no*
9497  // version, then added_sym shouldn't be
9498  // considered as a newly added symbol.
9499  elf_symbol::version empty_version;
9500  if (first_->lookup_variable_symbol(added_sym->get_name(),
9501  empty_version))
9502  do_add = false;
9503  }
9504 
9505  if (do_add)
9506  added_unrefed_var_syms_[added_sym->get_id_string()] =
9507  added_sym;
9508  }
9509  }
9510  else
9511  deleted_unrefed_var_syms_.erase(added_sym->get_id_string());
9512  }
9513  }
9514  }
9515 
9516  // Handle the unreachable_types_edit_script_
9517  {
9518  edit_script& e = unreachable_types_edit_script_;
9519 
9520  // Populate the map of deleted unreachable types from the
9521  // deletions of the edit script.
9522  for (vector<deletion>::const_iterator it = e.deletions().begin();
9523  it != e.deletions().end();
9524  ++it)
9525  {
9526  unsigned i = it->index();
9527  type_base_sptr t
9528  (first_->get_types_not_reachable_from_public_interfaces()[i]);
9529 
9530  if (!is_user_defined_type(t))
9531  continue;
9532 
9533  string repr = abigail::ir::get_pretty_representation(t, true);
9534  deleted_unreachable_types_[repr] = t;
9535  }
9536 
9537  // Populate the map of added and change unreachable types from the
9538  // insertions of the edit script.
9539  for (vector<insertion>::const_iterator it = e.insertions().begin();
9540  it != e.insertions().end();
9541  ++it)
9542  {
9543  for (vector<unsigned>::const_iterator iit =
9544  it->inserted_indexes().begin();
9545  iit != it->inserted_indexes().end();
9546  ++iit)
9547  {
9548  unsigned i = *iit;
9549  type_base_sptr t
9550  (second_->get_types_not_reachable_from_public_interfaces()[i]);
9551 
9552  if (!is_user_defined_type(t))
9553  continue;
9554 
9555  string repr = abigail::ir::get_pretty_representation(t, true);
9556 
9557  // Let's see if the inserted type we are looking at was
9558  // reported as deleted as well.
9559  //
9560  // If it's been deleted and a different version of it has
9561  // now been added, it means it's been *changed*. In that
9562  // case we'll compute the diff of that change and store it
9563  // in the map of changed unreachable types.
9564  //
9565  // Otherwise, it means the type's been added so we'll add
9566  // it to the set of added unreachable types.
9567 
9568  string_type_base_sptr_map::const_iterator j =
9569  deleted_unreachable_types_.find(repr);
9570  if (j != deleted_unreachable_types_.end())
9571  {
9572  // So there was another type of the same pretty
9573  // representation which was reported as deleted.
9574  // Let's see if they are different or not ...
9575  decl_base_sptr old_type = is_decl(j->second);
9576  decl_base_sptr new_type = is_decl(t);
9577  if (old_type != new_type)
9578  {
9579  // The previously added type is different from this
9580  // one that is added. That means the initial type
9581  // was changed. Let's compute its diff and store it
9582  // as a changed type.
9583  diff_sptr d = compute_diff(old_type, new_type, ctxt);
9584  ABG_ASSERT(d->has_changes());
9585  changed_unreachable_types_[repr]= d;
9586  }
9587 
9588  // In any case, the type was both deleted and added,
9589  // so we cannot have it marked as being deleted. So
9590  // let's remove it from the deleted types.
9591  deleted_unreachable_types_.erase(j);
9592  }
9593  else
9594  // The type wasn't previously reported as deleted, so
9595  // it's really added.
9596  added_unreachable_types_[repr] = t;
9597  }
9598  }
9599  }
9600 }
9601 
9602 /// Test if a change reports about a given @ref function_decl that is
9603 /// changed in a certain way is suppressed by a given suppression
9604 /// specifiation
9605 ///
9606 /// @param fn the @ref function_decl to consider.
9607 ///
9608 /// @param suppr the suppression specification to consider.
9609 ///
9610 /// @param k the kind of change that happened to @p fn.
9611 ///
9612 /// @param ctxt the context of the current diff.
9613 ///
9614 /// @return true iff the suppression specification @p suppr suppresses
9615 /// change reports about function @p fn, if that function changes in
9616 /// the way expressed by @p k.
9617 static bool
9618 function_is_suppressed(const function_decl* fn,
9619  const suppression_sptr suppr,
9621  const diff_context_sptr ctxt)
9622 {
9624  if (!fn_suppr)
9625  return false;
9626  return fn_suppr->suppresses_function(fn, k, ctxt);
9627 }
9628 
9629 /// Test if a change reports about a given @ref var_decl that is
9630 /// changed in a certain way is suppressed by a given suppression
9631 /// specifiation
9632 ///
9633 /// @param fn the @ref var_decl to consider.
9634 ///
9635 /// @param suppr the suppression specification to consider.
9636 ///
9637 /// @param k the kind of change that happened to @p fn.
9638 ///
9639 /// @param ctxt the context of the current diff.
9640 ///
9641 /// @return true iff the suppression specification @p suppr suppresses
9642 /// change reports about variable @p fn, if that variable changes in
9643 /// the way expressed by @p k.
9644 static bool
9645 variable_is_suppressed(const var_decl* var,
9646  const suppression_sptr suppr,
9648  const diff_context_sptr ctxt)
9649 {
9651  if (!var_suppr)
9652  return false;
9653  return var_suppr->suppresses_variable(var, k, ctxt);
9654 }
9655 
9656 /// Apply suppression specifications for this corpus diff to the set
9657 /// of added/removed functions/variables, as well as to types not
9658 /// reachable from global functions/variables.
9659 void
9661 {
9662  diff_context_sptr ctxt = get_context();
9663 
9664  const suppressions_type& suppressions = ctxt->suppressions();
9665  for (suppressions_type::const_iterator i = suppressions.begin();
9666  i != suppressions.end();
9667  ++i)
9668  {
9669  // Added/Deleted functions.
9671  {
9672  // Added functions
9673  for (string_function_ptr_map::const_iterator e = added_fns_.begin();
9674  e != added_fns_.end();
9675  ++e)
9676  if (function_is_suppressed(e->second, fn_suppr,
9678  ctxt))
9679  suppressed_added_fns_[e->first] = e->second;
9680 
9681  // Deleted functions.
9682  for (string_function_ptr_map::const_iterator e = deleted_fns_.begin();
9683  e != deleted_fns_.end();
9684  ++e)
9685  if (function_is_suppressed(e->second, fn_suppr,
9687  ctxt))
9688  suppressed_deleted_fns_[e->first] = e->second;
9689 
9690  // Added function symbols not referenced by any debug info
9691  for (string_elf_symbol_map::const_iterator e =
9692  added_unrefed_fn_syms_.begin();
9693  e != added_unrefed_fn_syms_.end();
9694  ++e)
9695  if (fn_suppr->suppresses_function_symbol(e->second,
9697  ctxt))
9698  suppressed_added_unrefed_fn_syms_[e->first] = e->second;
9699 
9700  // Removed function symbols not referenced by any debug info
9701  for (string_elf_symbol_map::const_iterator e =
9702  deleted_unrefed_fn_syms_.begin();
9703  e != deleted_unrefed_fn_syms_.end();
9704  ++e)
9705  if (fn_suppr->suppresses_function_symbol(e->second,
9707  ctxt))
9708  suppressed_deleted_unrefed_fn_syms_[e->first] = e->second;
9709  }
9710  // Added/Delete virtual member functions changes that might be
9711  // suppressed by a type_suppression that matches the enclosing
9712  // class of the virtual member function.
9713  else if (type_suppression_sptr type_suppr = is_type_suppression(*i))
9714  {
9715  // Added virtual functions
9716  for (string_function_ptr_map::const_iterator e = added_fns_.begin();
9717  e != added_fns_.end();
9718  ++e)
9719  if (is_member_function(e->second)
9720  && get_member_function_is_virtual(e->second))
9721  {
9722  function_decl *f = e->second;
9723  class_decl_sptr c =
9724  is_class_type(is_method_type(f->get_type())->get_class_type());
9725  ABG_ASSERT(c);
9726  if (type_suppr->suppresses_type(c, ctxt))
9727  suppressed_added_fns_[e->first] = e->second;
9728  }
9729  // Deleted virtual functions
9730  for (string_function_ptr_map::const_iterator e = deleted_fns_.begin();
9731  e != deleted_fns_.end();
9732  ++e)
9733  if (is_member_function(e->second)
9734  && get_member_function_is_virtual(e->second))
9735  {
9736  function_decl *f = e->second;
9737  class_decl_sptr c =
9738  is_class_type(is_method_type(f->get_type())->get_class_type());
9739  ABG_ASSERT(c);
9740  if (type_suppr->suppresses_type(c, ctxt))
9741  suppressed_deleted_fns_[e->first] = e->second;
9742  }
9743 
9744  // Apply this type suppression to deleted types
9745  // non-reachable from a public interface.
9746  for (string_type_base_sptr_map::const_iterator e =
9747  deleted_unreachable_types_.begin();
9748  e != deleted_unreachable_types_.end();
9749  ++e)
9750  if (type_suppr->suppresses_type(e->second, ctxt))
9751  suppressed_deleted_unreachable_types_[e->first] = e->second;
9752 
9753  // Apply this type suppression to added types
9754  // non-reachable from a public interface.
9755  for (string_type_base_sptr_map::const_iterator e =
9756  added_unreachable_types_.begin();
9757  e != added_unreachable_types_.end();
9758  ++e)
9759  if (type_suppr->suppresses_type(e->second, ctxt))
9760  suppressed_added_unreachable_types_[e->first] = e->second;
9761  }
9762  // Added/Deleted variables
9763  else if (variable_suppression_sptr var_suppr =
9765  {
9766  // Added variables
9767  for (string_var_ptr_map::const_iterator e = added_vars_.begin();
9768  e != added_vars_.end();
9769  ++e)
9770  if (variable_is_suppressed(e->second, var_suppr,
9772  ctxt))
9773  suppressed_added_vars_[e->first] = e->second;
9774 
9775  //Deleted variables
9776  for (string_var_ptr_map::const_iterator e = deleted_vars_.begin();
9777  e != deleted_vars_.end();
9778  ++e)
9779  if (variable_is_suppressed(e->second, var_suppr,
9781  ctxt))
9782  suppressed_deleted_vars_[e->first] = e->second;
9783 
9784  // Added variable symbols not referenced by any debug info
9785  for (string_elf_symbol_map::const_iterator e =
9786  added_unrefed_var_syms_.begin();
9787  e != added_unrefed_var_syms_.end();
9788  ++e)
9789  if (var_suppr->suppresses_variable_symbol(e->second,
9791  ctxt))
9792  suppressed_added_unrefed_var_syms_[e->first] = e->second;
9793 
9794  // Removed variable symbols not referenced by any debug info
9795  for (string_elf_symbol_map::const_iterator e =
9796  deleted_unrefed_var_syms_.begin();
9797  e != deleted_unrefed_var_syms_.end();
9798  ++e)
9799  if (var_suppr->suppresses_variable_symbol(e->second,
9801  ctxt))
9802  suppressed_deleted_unrefed_var_syms_[e->first] = e->second;
9803  }
9804  }
9805 }
9806 
9807 /// Test if the change reports for a given deleted function have
9808 /// been deleted.
9809 ///
9810 /// @param fn the function to consider.
9811 ///
9812 /// @return true iff the change reports for a give given deleted
9813 /// function have been deleted.
9814 bool
9816 {
9817  if (!fn)
9818  return false;
9819 
9820  string_function_ptr_map::const_iterator i =
9821  suppressed_deleted_fns_.find(fn->get_id());
9822 
9823  return (i != suppressed_deleted_fns_.end());
9824 }
9825 
9826 /// Test if an added type that is unreachable from public interface
9827 /// has been suppressed by a suppression specification.
9828 ///
9829 /// @param t the added unreachable type to be considered.
9830 ///
9831 /// @return true iff @p t has been suppressed by a suppression
9832 /// specification.
9833 bool
9835 {
9836  if (!t)
9837  return false;
9838 
9839  string repr = abigail::ir::get_pretty_representation(t, /*internal=*/true);
9840  string_type_base_sptr_map::const_iterator i =
9841  suppressed_added_unreachable_types_.find(repr);
9842  if (i == suppressed_added_unreachable_types_.end())
9843  return false;
9844 
9845  return true;
9846 }
9847 
9848 /// Test if a deleted type that is unreachable from public interface
9849 /// has been suppressed by a suppression specification.
9850 ///
9851 /// @param t the deleted unreachable type to be considered.
9852 ///
9853 /// @return true iff @p t has been suppressed by a suppression
9854 /// specification.
9855 bool
9857 {
9858  if (!t)
9859  return false;
9860 
9861  string repr = abigail::ir::get_pretty_representation(t, /*internal=*/true);
9862  string_type_base_sptr_map::const_iterator i =
9863  suppressed_deleted_unreachable_types_.find(repr);
9864  if (i == suppressed_deleted_unreachable_types_.end())
9865  return false;
9866 
9867  return true;
9868 }
9869 
9870 /// Test if the change reports for a give given added function has
9871 /// been deleted.
9872 ///
9873 /// @param fn the function to consider.
9874 ///
9875 /// @return true iff the change reports for a give given added
9876 /// function has been deleted.
9877 bool
9879 {
9880  if (!fn)
9881  return false;
9882 
9883  string_function_ptr_map::const_iterator i =
9884  suppressed_added_fns_.find(fn->get_id());
9885 
9886  return (i != suppressed_added_fns_.end());
9887 }
9888 
9889 /// Test if the change reports for a give given deleted variable has
9890 /// been deleted.
9891 ///
9892 /// @param var the variable to consider.
9893 ///
9894 /// @return true iff the change reports for a give given deleted
9895 /// variable has been deleted.
9896 bool
9898 {
9899  if (!var)
9900  return false;
9901 
9902  string_var_ptr_map::const_iterator i =
9903  suppressed_deleted_vars_.find(var->get_id());
9904 
9905  return (i != suppressed_deleted_vars_.end());
9906 }
9907 
9908 /// Test if the change reports for a given added variable have been
9909 /// suppressed.
9910 ///
9911 /// @param var the variable to consider.
9912 ///
9913 /// @return true iff the change reports for a given deleted
9914 /// variable has been deleted.
9915 bool
9917 {
9918  if (!var)
9919  return false;
9920 
9921  string_var_ptr_map::const_iterator i =
9922  suppressed_added_vars_.find(var->get_id());
9923 
9924  return (i != suppressed_added_vars_.end());
9925 }
9926 
9927 /// Test if the change reports for a given deleted function symbol
9928 /// (that is not referenced by any debug info) has been suppressed.
9929 ///
9930 /// @param var the function to consider.
9931 ///
9932 /// @return true iff the change reports for a given deleted function
9933 /// symbol has been suppressed.
9934 bool
9936 {
9937  if (!s)
9938  return false;
9939 
9940  string_elf_symbol_map::const_iterator i =
9941  suppressed_deleted_unrefed_fn_syms_.find(s->get_id_string());
9942 
9943  return (i != suppressed_deleted_unrefed_fn_syms_.end());
9944 }
9945 
9946 /// Test if the change reports for a given added function symbol
9947 /// (that is not referenced by any debug info) has been suppressed.
9948 ///
9949 /// @param var the function to consider.
9950 ///
9951 /// @return true iff the change reports for a given added function
9952 /// symbol has been suppressed.
9953 bool
9955 {
9956  if (!s)
9957  return false;
9958 
9959  string_elf_symbol_map::const_iterator i =
9960  suppressed_added_unrefed_fn_syms_.find(s->get_id_string());
9961 
9962  return (i != suppressed_added_unrefed_fn_syms_.end());
9963 }
9964 
9965 /// Test if the change reports for a given deleted variable symbol
9966 /// (that is not referenced by any debug info) has been suppressed.
9967 ///
9968 /// @param var the variable to consider.
9969 ///
9970 /// @return true iff the change reports for a given deleted variable
9971 /// symbol has been suppressed.
9972 bool
9974 {
9975  if (!s)
9976  return false;
9977 
9978  string_elf_symbol_map::const_iterator i =
9979  suppressed_deleted_unrefed_var_syms_.find(s->get_id_string());
9980 
9981  return (i != suppressed_deleted_unrefed_var_syms_.end());
9982 }
9983 
9984 /// Test if the change reports for a given added variable symbol
9985 /// (that is not referenced by any debug info) has been suppressed.
9986 ///
9987 /// @param var the variable to consider.
9988 ///
9989 /// @return true iff the change reports for a given added variable
9990 /// symbol has been suppressed.
9991 bool
9993 {
9994  if (!s)
9995  return false;
9996 
9997  string_elf_symbol_map::const_iterator i =
9998  suppressed_added_unrefed_var_syms_.find(s->get_id_string());
9999 
10000  return (i != suppressed_added_unrefed_var_syms_.end());
10001 }
10002 
10003 #ifdef do_count_diff_map_changes
10004 #undef do_count_diff_map_changes
10005 #endif
10006 #define do_count_diff_map_changes(diff_map, n_changes, n_filtered) \
10007  { \
10008  string_diff_ptr_map::const_iterator i; \
10009  for (i = diff_map.begin(); \
10010  i != diff_map.end(); \
10011  ++i) \
10012  { \
10013  if (const var_diff* d = is_var_diff(i->second)) \
10014  if (is_data_member(d->first_var())) \
10015  continue; \
10016  \
10017  if (i->second->has_local_changes()) \
10018  ++n_changes; \
10019  if (!i->second->get_canonical_diff()->to_be_reported()) \
10020  ++n_filtered; \
10021  } \
10022  }
10023 
10024 /// Count the number of leaf changes as well as the number of the
10025 /// changes that have been filtered out.
10026 ///
10027 /// @param num_changes out parameter. This is set to the total number
10028 /// of leaf changes.
10029 ///
10030 /// @param num_filtered out parameter. This is set to the number of
10031 /// leaf changes that have been filtered out.
10032 void
10033 corpus_diff::priv::count_leaf_changes(size_t &num_changes, size_t &num_filtered)
10034 {
10035  count_leaf_type_changes(num_changes, num_filtered);
10036 
10037  // Now count the non-type changes.
10038  do_count_diff_map_changes(leaf_diffs_.get_function_decl_diff_map(),
10039  num_changes, num_filtered);
10040  do_count_diff_map_changes(leaf_diffs_.get_var_decl_diff_map(),
10041  num_changes, num_filtered);
10042 }
10043 
10044 /// Count the number of leaf *type* changes as well as the number of
10045 /// the leaf type changes that have been filtered out.
10046 ///
10047 /// @param num_changes out parameter. This is set to the total number
10048 /// of leaf type changes.
10049 ///
10050 /// @param num_filtered out parameter. This is set to the number of
10051 /// leaf type changes that have been filtered out.
10052 void
10054  size_t &num_filtered)
10055 {
10056  do_count_diff_map_changes(leaf_diffs_.get_type_decl_diff_map(),
10057  num_changes, num_filtered);
10058  do_count_diff_map_changes(leaf_diffs_.get_enum_diff_map(),
10059  num_changes, num_filtered);
10060  do_count_diff_map_changes(leaf_diffs_.get_class_diff_map(),
10061  num_changes, num_filtered);
10062  do_count_diff_map_changes(leaf_diffs_.get_union_diff_map(),
10063  num_changes, num_filtered);
10064  do_count_diff_map_changes(leaf_diffs_.get_typedef_diff_map(),
10065  num_changes, num_filtered);
10066  do_count_diff_map_changes(leaf_diffs_.get_subrange_diff_map(),
10067  num_changes, num_filtered);
10068  do_count_diff_map_changes(leaf_diffs_.get_array_diff_map(),
10069  num_changes, num_filtered);
10070  do_count_diff_map_changes(leaf_diffs_.get_distinct_diff_map(),
10071  num_changes, num_filtered);
10072  do_count_diff_map_changes(leaf_diffs_.get_fn_parm_diff_map(),
10073  num_changes, num_filtered);
10074 }
10075 
10076 /// Count the number of types not reachable from the interface (i.e,
10077 /// not reachable from global functions or variables).
10078 ///
10079 /// @param num_added this is set to the number of added types not
10080 /// reachable from the interface.
10081 ///
10082 /// @param num_deleted this is set to the number of deleted types not
10083 /// reachable from the interface.
10084 ///
10085 /// @param num_changed this is set to the number of changed types not
10086 /// reachable from the interface.
10087 ///
10088 /// @param num_filtered_added this is set to the number of added types
10089 /// not reachable from the interface and that have been filtered out
10090 /// by suppression specifications.
10091 ///
10092 /// @param num_filtered_deleted this is set to the number of deleted
10093 /// types not reachable from the interface and that have been filtered
10094 /// out by suppression specifications.
10095 ///
10096 /// @param num_filtered_changed this is set to the number of changed
10097 /// types not reachable from the interface and that have been filtered
10098 /// out by suppression specifications.
10099 void
10101  size_t &num_deleted,
10102  size_t &num_changed,
10103  size_t &num_filtered_added,
10104  size_t &num_filtered_deleted,
10105  size_t &num_filtered_changed)
10106 {
10107  num_added = added_unreachable_types_.size();
10108  num_deleted = deleted_unreachable_types_.size();
10109  num_changed = changed_unreachable_types_.size();
10110  num_filtered_added = suppressed_added_unreachable_types_.size();
10111  num_filtered_deleted = suppressed_deleted_unreachable_types_.size();
10112 
10113  for (vector<diff_sptr>::const_iterator i =
10115  i != changed_unreachable_types_sorted().end();
10116  ++i)
10117  if (!(*i)->to_be_reported())
10118  ++num_filtered_changed;
10119 }
10120 
10121 /// Get the sorted vector of diff nodes representing changed
10122 /// unreachable types.
10123 ///
10124 /// Upon the first invocation of this method, if the vector is empty,
10125 /// this function gets the diff nodes representing changed
10126 /// unreachable, sort them, and return the sorted vector.
10127 ///
10128 /// @return the sorted vector of diff nodes representing changed
10129 /// unreachable types.
10130 const vector<diff_sptr>&
10132 {
10133 if (changed_unreachable_types_sorted_.empty())
10134  if (!changed_unreachable_types_.empty())
10135  sort_string_diff_sptr_map(changed_unreachable_types_,
10136  changed_unreachable_types_sorted_);
10137 
10138  return changed_unreachable_types_sorted_;
10139 }
10140 
10141 /// Compute the diff stats.
10142 ///
10143 /// To know the number of functions that got filtered out, this
10144 /// function applies the categorizing filters to the diff sub-trees of
10145 /// each function changes diff, prior to calculating the stats.
10146 ///
10147 /// @param num_removed the number of removed functions.
10148 ///
10149 /// @param num_added the number of added functions.
10150 ///
10151 /// @param num_changed the number of changed functions.
10152 ///
10153 /// @param num_filtered_out the number of changed functions that are
10154 /// got filtered out from the report
10155 void
10157 {
10158  stat.num_func_removed(deleted_fns_.size());
10159  stat.num_removed_func_filtered_out(suppressed_deleted_fns_.size());
10160  stat.num_func_added(added_fns_.size());
10161  stat.num_added_func_filtered_out(suppressed_added_fns_.size());
10162  stat.num_func_changed(changed_fns_map_.size());
10163 
10164  stat.num_vars_removed(deleted_vars_.size());
10165  stat.num_removed_vars_filtered_out(suppressed_deleted_vars_.size());
10166  stat.num_vars_added(added_vars_.size());
10167  stat.num_added_vars_filtered_out(suppressed_added_vars_.size());
10168  stat.num_vars_changed(changed_vars_map_.size());
10169 
10170  diff_context_sptr ctxt = get_context();
10171 
10173  if (ctxt->perform_change_categorization())
10174  {
10175  if (get_context()->do_log())
10176  {
10177  std::cerr << "in apply_filters_and_compute_diff_stats:"
10178  << "applying filters to "
10179  << changed_fns_.size()
10180  << " changed fns ...\n";
10181  t.start();
10182  }
10183  // Walk the changed function diff nodes to apply the categorization
10184  // filters.
10185  diff_sptr diff;
10186  for (function_decl_diff_sptrs_type::const_iterator i =
10187  changed_fns_.begin();
10188  i != changed_fns_.end();
10189  ++i)
10190  {
10191  diff_sptr diff = *i;
10192  ctxt->maybe_apply_filters(diff);
10193  }
10194 
10195  if (get_context()->do_log())
10196  {
10197  t.stop();
10198  std::cerr << "in apply_filters_and_compute_diff_stats:"
10199  << "filters to changed fn applied!:" << t << "\n";
10200 
10201  std::cerr << "in apply_filters_and_compute_diff_stats:"
10202  << "applying filters to "
10203  << sorted_changed_vars_.size()
10204  << " changed vars ...\n";
10205  t.start();
10206  }
10207 
10208  // Walk the changed variable diff nodes to apply the categorization
10209  // filters.
10210  for (var_diff_sptrs_type::const_iterator i = sorted_changed_vars_.begin();
10211  i != sorted_changed_vars_.end();
10212  ++i)
10213  {
10214  diff_sptr diff = *i;
10215  ctxt->maybe_apply_filters(diff);
10216  }
10217 
10218  if (get_context()->do_log())
10219  {
10220  t.stop();
10221  std::cerr << "in apply_filters_and_compute_diff_stats:"
10222  << "filters to changed vars applied!:" << t << "\n";
10223 
10224  std::cerr << "in apply_filters_and_compute_diff_stats:"
10225  << "applying filters to unreachable types ...\n";
10226  t.start();
10227  }
10228 
10229  // walk the changed unreachable types to apply categorization
10230  // filters
10231  for (diff_sptrs_type::const_iterator i =
10233  i != changed_unreachable_types_sorted().end();
10234  ++i)
10235  {
10236  diff_sptr diff = *i;
10237  ctxt->maybe_apply_filters(diff);
10238  }
10239 
10240  if (get_context()->do_log())
10241  {
10242  t.stop();
10243  std::cerr << "in apply_filters_and_compute_diff_stats:"
10244  << "filters to unreachable types applied!:" << t << "\n";
10245 
10246  std::cerr << "in apply_filters_and_compute_diff_stats:"
10247  << "categorizing redundant changed sub nodes ...\n";
10248  t.start();
10249  }
10250 
10251  categorize_redundant_changed_sub_nodes();
10252 
10253  if (get_context()->do_log())
10254  {
10255  t.stop();
10256  std::cerr << "in apply_filters_and_compute_diff_stats:"
10257  << "redundant changed sub nodes categorized!:" << t << "\n";
10258 
10259  std::cerr << "in apply_filters_and_compute_diff_stats:"
10260  << "count changed fns ...\n";
10261  t.start();
10262  }
10263  }
10264 
10265  // Walk the changed function diff nodes to count the number of
10266  // filtered-out functions and the number of functions with virtual
10267  // offset changes.
10268  for (function_decl_diff_sptrs_type::const_iterator i =
10269  changed_fns_.begin();
10270  i != changed_fns_.end();
10271  ++i)
10272  {
10273  if ((*i)->is_filtered_out())
10274  {
10276  (stat.num_changed_func_filtered_out() + 1);
10277 
10278  if ((*i)->has_local_changes())
10281  }
10282  else
10283  {
10284  if ((*i)->get_category() & VIRTUAL_MEMBER_CHANGE_CATEGORY)
10287  }
10288 
10289  if ((*i)->has_local_changes())
10291  (stat.num_leaf_func_changes() + 1);
10292  }
10293 
10294  if (get_context()->do_log())
10295  {
10296  t.stop();
10297  std::cerr << "in apply_filters_and_compute_diff_stats:"
10298  << "changed fn counted!:" << t << "\n";
10299 
10300  std::cerr << "in apply_filters_and_compute_diff_stats:"
10301  << "count changed vars ...\n";
10302  t.start();
10303  }
10304 
10305  // Walk the changed variables diff nodes to count the number of
10306  // filtered-out variables.
10307  for (var_diff_sptrs_type ::const_iterator i = sorted_changed_vars_.begin();
10308  i != sorted_changed_vars_.end();
10309  ++i)
10310  {
10311  if ((*i)->is_filtered_out())
10312  {
10314  (stat.num_changed_vars_filtered_out() + 1);
10315 
10316  if ((*i)->has_local_changes())
10318  (stat.num_leaf_var_changes_filtered_out() + 1);
10319  }
10320  if ((*i)->has_local_changes())
10322  (stat.num_leaf_var_changes() + 1);
10323  }
10324 
10325  if (get_context()->do_log())
10326  {
10327  t.stop();
10328  std::cerr << "in apply_filters_and_compute_diff_stats:"
10329  << "changed vars counted!:" << t << "\n";
10330 
10331  std::cerr << "in apply_filters_and_compute_diff_stats:"
10332  << "count leaf changed types ...\n";
10333  t.start();
10334  }
10335 
10336  stat.num_func_syms_added(added_unrefed_fn_syms_.size());
10337  stat.num_added_func_syms_filtered_out(suppressed_added_unrefed_fn_syms_.size());
10338  stat.num_func_syms_removed(deleted_unrefed_fn_syms_.size());
10339  stat.num_removed_func_syms_filtered_out(suppressed_deleted_unrefed_fn_syms_.size());
10340  stat.num_var_syms_added(added_unrefed_var_syms_.size());
10341  stat.num_added_var_syms_filtered_out(suppressed_added_unrefed_var_syms_.size());
10342  stat.num_var_syms_removed(deleted_unrefed_var_syms_.size());
10343  stat.num_removed_var_syms_filtered_out(suppressed_deleted_unrefed_var_syms_.size());
10344 
10345  // Walk the general leaf type diff nodes to count them
10346  {
10347  size_t num_type_changes = 0, num_type_filtered = 0;
10348  count_leaf_type_changes(num_type_changes, num_type_filtered);
10349 
10350  stat.num_leaf_type_changes(num_type_changes);
10351  stat.num_leaf_type_changes_filtered_out(num_type_filtered);
10352  }
10353 
10354  if (get_context()->do_log())
10355  {
10356  t.stop();
10357  std::cerr << "in apply_filters_and_compute_diff_stats:"
10358  << "changed leaf types counted!:" << t << "\n";
10359 
10360  std::cerr << "in apply_filters_and_compute_diff_stats:"
10361  << "count leaf changed artefacts ...\n";
10362  t.start();
10363  }
10364 
10365  // Walk the general leaf artefacts diff nodes to count them
10366  {
10367  size_t num_changes = 0, num_filtered = 0;
10368  count_leaf_changes(num_changes, num_filtered);
10369 
10370  stat.num_leaf_changes(num_changes);
10371  stat.num_leaf_changes_filtered_out(num_filtered);
10372  }
10373 
10374  if (get_context()->do_log())
10375  {
10376  t.stop();
10377  std::cerr << "in apply_filters_and_compute_diff_stats:"
10378  << "changed leaf artefacts counted!:" << t << "\n";
10379 
10380  std::cerr << "in apply_filters_and_compute_diff_stats:"
10381  << "count unreachable types ...\n";
10382  t.start();
10383  }
10384 
10385  // Walk the unreachable types to count them
10386  {
10387  size_t num_added_unreachable_types = 0,
10388  num_changed_unreachable_types = 0,
10389  num_deleted_unreachable_types = 0,
10390  num_added_unreachable_types_filtered = 0,
10391  num_changed_unreachable_types_filtered = 0,
10392  num_deleted_unreachable_types_filtered = 0;
10393 
10394  count_unreachable_types(num_added_unreachable_types,
10395  num_deleted_unreachable_types,
10396  num_changed_unreachable_types,
10397  num_added_unreachable_types_filtered,
10398  num_deleted_unreachable_types_filtered,
10399  num_changed_unreachable_types_filtered);
10400 
10401  if (get_context()->do_log())
10402  {
10403  t.stop();
10404  std::cerr << "in apply_filters_and_compute_diff_stats:"
10405  << "unreachable types counted!:" << t << "\n";
10406  }
10407 
10408  stat.num_added_unreachable_types(num_added_unreachable_types);
10409  stat.num_removed_unreachable_types(num_deleted_unreachable_types);
10410  stat.num_changed_unreachable_types(num_changed_unreachable_types);
10412  (num_added_unreachable_types_filtered);
10414  (num_deleted_unreachable_types_filtered);
10416  (num_changed_unreachable_types_filtered);
10417  }
10418 }
10419 
10420 /// Emit the summary of the functions & variables that got
10421 /// removed/changed/added.
10422 ///
10423 /// TODO: This should be handled by the reporters, just like what is
10424 /// done for reporter_base::diff_to_be_reported.
10425 ///
10426 /// @param out the output stream to emit the stats to.
10427 ///
10428 /// @param indent the indentation string to use in the summary.
10429 void
10431  ostream& out,
10432  const string& indent)
10433 {
10434  /// Report added/removed/changed functions.
10435  size_t net_num_leaf_changes =
10436  s.net_num_func_removed() +
10437  s.net_num_func_added() +
10439  s.net_num_vars_removed() +
10440  s.net_num_vars_added() +
10447 
10448  if (!sonames_equal_)
10449  out << indent << "ELF SONAME changed\n";
10450 
10451  if (!architectures_equal_)
10452  out << indent << "ELF architecture changed\n";
10453 
10454  diff_context_sptr ctxt = get_context();
10455 
10456  if (ctxt->show_leaf_changes_only())
10457  {
10458  out << "Leaf changes summary: ";
10459  out << net_num_leaf_changes << " artifact";
10460  if (net_num_leaf_changes > 1)
10461  out << "s";
10462  out << " changed";
10463 
10464  if (size_t num_filtered = s.num_leaf_changes_filtered_out())
10465  out << " (" << num_filtered << " filtered out)";
10466  out << "\n";
10467 
10468  out << indent << "Changed leaf types summary: "
10471  out << " (" << s.num_leaf_type_changes_filtered_out()
10472  << " filtered out)";
10473  out << " leaf type";
10474  if (s.num_leaf_type_changes() > 1)
10475  out << "s";
10476  out << " changed\n";
10477 
10478  // function changes summary
10479  out << indent << "Removed/Changed/Added functions summary: ";
10480  out << s.net_num_func_removed() << " Removed";
10482  out << " ("
10484  << " filtered out)";
10485  out << ", ";
10486 
10487  out << s.net_num_leaf_func_changes() << " Changed";
10489  out << " ("
10491  << " filtered out)";
10492  out << ", ";
10493 
10494  out << s.net_num_func_added()<< " Added ";
10495  if (s.net_num_func_added() <= 1)
10496  out << "function";
10497  else
10498  out << "functions";
10500  out << " (" << s.num_added_func_filtered_out() << " filtered out)";
10501  out << "\n";
10502 
10503  // variables changes summary
10504  out << indent << "Removed/Changed/Added variables summary: ";
10505  out << s.net_num_vars_removed() << " Removed";
10507  out << " (" << s.num_removed_vars_filtered_out()
10508  << " filtered out)";
10509  out << ", ";
10510 
10511  out << s.net_num_leaf_var_changes() << " Changed";
10513  out << " ("
10515  << " filtered out)";
10516  out << ", ";
10517 
10518  out << s.net_num_vars_added() << " Added ";
10519  if (s.net_num_vars_added() <= 1)
10520  out << "variable";
10521  else
10522  out << "variables";
10524  out << " (" << s.num_added_vars_filtered_out()
10525  << " filtered out)";
10526  out << "\n";
10527  }
10528  else // if (ctxt->show_leaf_changes_only())
10529  {
10530  size_t total_nb_function_changes = s.num_func_removed()
10531  + s.num_func_changed() + s.num_func_added();
10532 
10533  // function changes summary
10534  out << indent << "Functions changes summary: ";
10535  out << s.net_num_func_removed() << " Removed";
10537  out << " ("
10539  << " filtered out)";
10540  out << ", ";
10541 
10542  out << s.net_num_func_changed() << " Changed";
10544  out << " (" << s.num_changed_func_filtered_out() << " filtered out)";
10545  out << ", ";
10546 
10547  out << s.net_num_func_added() << " Added";
10549  out << " (" << s.num_added_func_filtered_out() << " filtered out)";
10550  if (total_nb_function_changes <= 1)
10551  out << " function";
10552  else
10553  out << " functions";
10554  out << "\n";
10555 
10556  // variables changes summary
10557  size_t total_nb_variable_changes = s.num_vars_removed()
10558  + s.num_vars_changed() + s.num_vars_added();
10559 
10560  out << indent << "Variables changes summary: ";
10561  out << s.net_num_vars_removed() << " Removed";
10563  out << " (" << s.num_removed_vars_filtered_out()
10564  << " filtered out)";
10565  out << ", ";
10566 
10567  out << s.num_vars_changed() - s.num_changed_vars_filtered_out() << " Changed";
10569  out << " (" << s.num_changed_vars_filtered_out() << " filtered out)";
10570  out << ", ";
10571 
10572  out << s.net_num_vars_added() << " Added";
10574  out << " (" << s.num_added_vars_filtered_out()
10575  << " filtered out)";
10576  if (total_nb_variable_changes <= 1)
10577  out << " variable";
10578  else
10579  out << " variables";
10580  out << "\n";
10581  }
10582 
10583  // Show statistics about types not reachable from global
10584  // functions/variables.
10585  if (ctxt->show_unreachable_types())
10586  {
10587  size_t total_nb_unreachable_type_changes =
10591 
10592  // Show summary of unreachable types
10593  out << indent << "Unreachable types summary: "
10595  << " removed";
10598  << " filtered out)";
10599  out << ", ";
10600 
10602  << " changed";
10605  << " filtered out)";
10606  out << ", ";
10607 
10609  << " added";
10611  out << " (" << s.num_added_unreachable_types_filtered_out()
10612  << " filtered out)";
10613  if (total_nb_unreachable_type_changes <= 1)
10614  out << " type";
10615  else
10616  out << " types";
10617  out << "\n";
10618  }
10619 
10620  if (ctxt->show_symbols_unreferenced_by_debug_info()
10621  && (s.num_func_syms_removed()
10622  || s.num_func_syms_added()
10623  || s.num_var_syms_removed()
10624  || s.num_var_syms_added()))
10625  {
10626  // function symbols changes summary.
10627 
10628  if (!ctxt->show_added_symbols_unreferenced_by_debug_info()
10629  && s.num_func_syms_removed() == 0
10630  && s.num_func_syms_added() != 0)
10631  // If the only unreferenced function symbol change is function
10632  // syms that got added, but we were forbidden to show function
10633  // syms being added, do nothing.
10634  ;
10635  else
10636  {
10637  out << indent
10638  << "Function symbols changes summary: "
10639  << s.net_num_removed_func_syms() << " Removed";
10641  out << " (" << s.num_removed_func_syms_filtered_out()
10642  << " filtered out)";
10643  out << ", ";
10644  out << s.net_num_added_func_syms() << " Added";
10646  out << " (" << s.num_added_func_syms_filtered_out()
10647  << " filtered out)";
10648  out << " function symbol";
10649  if (s.num_func_syms_added() + s.num_func_syms_removed() > 1)
10650  out << "s";
10651  out << " not referenced by debug info\n";
10652  }
10653 
10654  // variable symbol changes summary.
10655 
10656  if (!ctxt->show_added_symbols_unreferenced_by_debug_info()
10657  && s.num_var_syms_removed() == 0
10658  && s.num_var_syms_added() != 0)
10659  // If the only unreferenced variable symbol change is variable
10660  // syms that got added, but we were forbidden to show variable
10661  // syms being added, do nothing.
10662  ;
10663  else
10664  {
10665  out << indent
10666  << "Variable symbols changes summary: "
10667  << s.net_num_removed_var_syms() << " Removed";
10669  out << " (" << s.num_removed_var_syms_filtered_out()
10670  << " filtered out)";
10671  out << ", ";
10672  out << s.net_num_added_var_syms() << " Added";
10674  out << " (" << s.num_added_var_syms_filtered_out()
10675  << " filtered out)";
10676  out << " variable symbol";
10677  if (s.num_var_syms_added() + s.num_var_syms_removed() > 1)
10678  out << "s";
10679  out << " not referenced by debug info\n";
10680  }
10681  }
10682 }
10683 
10684 /// Walk the changed functions and variables diff nodes to categorize
10685 /// redundant nodes.
10686 void
10688 {
10689  diff_sptr diff;
10690 
10691  diff_context_sptr ctxt = get_context();
10692 
10693  ctxt->forget_visited_diffs();
10694  for (function_decl_diff_sptrs_type::const_iterator i =
10695  changed_fns_.begin();
10696  i!= changed_fns_.end();
10697  ++i)
10698  {
10699  diff = *i;
10701  }
10702 
10703  for (var_diff_sptrs_type::const_iterator i = sorted_changed_vars_.begin();
10704  i!= sorted_changed_vars_.end();
10705  ++i)
10706  {
10707  diff_sptr diff = *i;
10709  }
10710 
10711  for (diff_sptrs_type::const_iterator i =
10714  ++i)
10715  {
10716  diff_sptr diff = *i;
10718  }
10719 }
10720 
10721 /// Walk the changed functions and variables diff nodes and clear the
10722 /// redundancy categorization they might carry.
10723 void
10725 {
10726  diff_sptr diff;
10727  for (function_decl_diff_sptrs_type::const_iterator i = changed_fns_.begin();
10728  i!= changed_fns_.end();
10729  ++i)
10730  {
10731  diff = *i;
10733  }
10734 
10735  for (var_diff_sptrs_type::const_iterator i = sorted_changed_vars_.begin();
10736  i!= sorted_changed_vars_.end();
10737  ++i)
10738  {
10739  diff = *i;
10741  }
10742 }
10743 
10744 /// If the user asked to dump the diff tree node (for changed
10745 /// variables and functions) on the error output stream, then just do
10746 /// that.
10747 ///
10748 /// This function is used for debugging purposes.
10749 void
10751 {
10752  diff_context_sptr ctxt = get_context();
10753 
10754  if (!ctxt->dump_diff_tree()
10755  || ctxt->error_output_stream() == 0)
10756  return;
10757 
10758  if (!changed_fns_.empty())
10759  {
10760  *ctxt->error_output_stream() << "changed functions diff tree: \n\n";
10761  for (function_decl_diff_sptrs_type::const_iterator i =
10762  changed_fns_.begin();
10763  i != changed_fns_.end();
10764  ++i)
10765  {
10766  diff_sptr d = *i;
10767  print_diff_tree(d, *ctxt->error_output_stream());
10768  }
10769  }
10770 
10771  if (!sorted_changed_vars_.empty())
10772  {
10773  *ctxt->error_output_stream() << "\nchanged variables diff tree: \n\n";
10774  for (var_diff_sptrs_type::const_iterator i =
10775  sorted_changed_vars_.begin();
10776  i != sorted_changed_vars_.end();
10777  ++i)
10778  {
10779  diff_sptr d = *i;
10780  print_diff_tree(d, *ctxt->error_output_stream());
10781  }
10782  }
10783 
10784  if (!changed_unreachable_types_sorted().empty())
10785  {
10786  *ctxt->error_output_stream() << "\nchanged unreachable "
10787  "types diff tree: \n\n";
10788  for (vector<diff_sptr>::const_iterator i =
10790  i != changed_unreachable_types_sorted().end();
10791  ++i)
10792  {
10793  diff_sptr d = *i;
10794  print_diff_tree(d, *ctxt->error_output_stream());
10795  }
10796  }
10797 }
10798 
10799 /// Populate the vector of children node of the @ref corpus_diff type.
10800 ///
10801 /// The children node can then later be retrieved using
10802 /// corpus_diff::children_node().
10803 void
10805 {
10806  for (function_decl_diff_sptrs_type::const_iterator i =
10807  changed_functions_sorted().begin();
10808  i != changed_functions_sorted().end();
10809  ++i)
10810  if (diff_sptr d = *i)
10811  append_child_node(d);
10812 }
10813 
10814 /// Constructor for @ref corpus_diff.
10815 ///
10816 /// @param first the first corpus of the diff.
10817 ///
10818 /// @param second the second corpus of the diff.
10819 ///
10820 /// @param ctxt the diff context to use. Note that this context
10821 /// object must stay alive at least during the life time of the
10822 /// current instance of @ref corpus_diff. Otherwise memory corruption
10823 /// issues occur.
10824 corpus_diff::corpus_diff(corpus_sptr first,
10825  corpus_sptr second,
10826  diff_context_sptr ctxt)
10827  : priv_(new priv(first, second, ctxt))
10828 {}
10829 
10830 corpus_diff::~corpus_diff() = default;
10831 
10832 /// Finish building the current instance of @ref corpus_diff.
10833 void
10835 {
10836  if (priv_->finished_)
10837  return;
10839  priv_->finished_ = true;
10840 }
10841 
10842 /// Test if logging was requested.
10843 ///
10844 /// @return true iff logging was requested.
10845 bool
10847 {return context()->do_log();}
10848 
10849 /// Request logging, or not.
10850 ///
10851 /// @param f true iff logging is requested.
10852 void
10854 {context()->do_log(f);}
10855 
10856 /// @return the first corpus of the diff.
10857 corpus_sptr
10859 {return priv_->first_;}
10860 
10861 /// @return the second corpus of the diff.
10862 corpus_sptr
10864 {return priv_->second_;}
10865 
10866 /// @return the children nodes of the current instance of corpus_diff.
10867 const vector<diff*>&
10869 {return priv_->children_;}
10870 
10871 /// Append a new child node to the vector of children nodes for the
10872 /// current instance of @ref corpus_diff node.
10873 ///
10874 /// Note that the vector of children nodes for the current instance of
10875 /// @ref corpus_diff node must remain sorted, using
10876 /// diff_less_than_functor.
10877 ///
10878 /// @param d the new child node. Note that the life time of the
10879 /// object held by @p d will thus equal the life time of the current
10880 /// instance of @ref corpus_diff.
10881 void
10883 {
10884  ABG_ASSERT(d);
10885 
10886  diff_less_than_functor is_less_than;
10887  bool inserted = false;
10888  for (vector<diff*>::iterator i = priv_->children_.begin();
10889  i != priv_->children_.end();
10890  ++i)
10891  // Look for the point where to insert the diff child node.
10892  if (!is_less_than(d.get(), *i))
10893  {
10894  context()->keep_diff_alive(d);
10895  priv_->children_.insert(i, d.get());
10896  // As we have just inserted 'd' into the vector, the iterator
10897  // 'i' is invalidated. We must *NOT* use it anymore.
10898  inserted = true;
10899  break;
10900  }
10901 
10902  if (!inserted)
10903  {
10904  context()->keep_diff_alive(d);
10905  // We didn't insert anything to the vector, presumably b/c it was
10906  // empty or had one element that was "less than" 'd'. We can thus
10907  // just append 'd' to the end of the vector.
10908  priv_->children_.push_back(d.get());
10909  }
10910 }
10911 
10912 /// @return the bare edit script of the functions changed as recorded
10913 /// by the diff.
10914 edit_script&
10916 {return priv_->fns_edit_script_;}
10917 
10918 /// @return the bare edit script of the variables changed as recorded
10919 /// by the diff.
10920 edit_script&
10922 {return priv_->vars_edit_script_;}
10923 
10924 /// Test if the soname of the underlying corpus has changed.
10925 ///
10926 /// @return true iff the soname has changed.
10927 bool
10929 {return !priv_->sonames_equal_;}
10930 
10931 /// Test if the architecture of the underlying corpus has changed.
10932 ///
10933 /// @return true iff the architecture has changed.
10934 bool
10936 {return !priv_->architectures_equal_;}
10937 
10938 /// Getter for the deleted functions of the diff.
10939 ///
10940 /// @return the the deleted functions of the diff.
10943 {return priv_->deleted_fns_;}
10944 
10945 /// Getter for the added functions of the diff.
10946 ///
10947 /// @return the added functions of the diff.
10950 {return priv_->added_fns_;}
10951 
10952 /// Getter for the functions which signature didn't change, but which
10953 /// do have some indirect changes in their parms.
10954 ///
10955 /// @return a non-sorted map of functions which signature didn't
10956 /// change, but which do have some indirect changes in their parms.
10957 /// The key of the map is a unique identifier for the function; it's
10958 /// usually made of the name and version of the underlying ELF symbol
10959 /// of the function for corpora that were built from ELF files.
10962 {return priv_->changed_fns_map_;}
10963 
10964 /// Getter for a sorted vector of functions which signature didn't
10965 /// change, but which do have some indirect changes in their parms.
10966 ///
10967 /// @return a sorted vector of functions which signature didn't
10968 /// change, but which do have some indirect changes in their parms.
10971 {return priv_->changed_fns_;}
10972 
10973 /// Getter for the variables that got deleted from the first subject
10974 /// of the diff.
10975 ///
10976 /// @return the map of deleted variable.
10977 const string_var_ptr_map&
10979 {return priv_->deleted_vars_;}
10980 
10981 /// Getter for the added variables of the diff.
10982 ///
10983 /// @return the map of added variable.
10984 const string_var_ptr_map&
10986 {return priv_->added_vars_;}
10987 
10988 /// Getter for the non-sorted map of variables which signature didn't
10989 /// change but which do have some indirect changes in some sub-types.
10990 ///
10991 /// @return the non-sorted map of changed variables.
10994 {return priv_->changed_vars_map_;}
10995 
10996 /// Getter for the sorted vector of variables which signature didn't
10997 /// change but which do have some indirect changes in some sub-types.
10998 ///
10999 /// @return a sorted vector of changed variables.
11000 const var_diff_sptrs_type&
11002 {return priv_->sorted_changed_vars_;}
11003 
11004 /// Getter for function symbols not referenced by any debug info and
11005 /// that got deleted.
11006 ///
11007 /// @return a map of elf function symbols not referenced by any debug
11008 /// info and that got deleted.
11009 const string_elf_symbol_map&
11011 {return priv_->deleted_unrefed_fn_syms_;}
11012 
11013 /// Getter for function symbols not referenced by any debug info and
11014 /// that got added.
11015 ///
11016 /// @return a map of elf function symbols not referenced by any debug
11017 /// info and that got added.
11018 const string_elf_symbol_map&
11020 {return priv_->added_unrefed_fn_syms_;}
11021 
11022 /// Getter for variable symbols not referenced by any debug info and
11023 /// that got deleted.
11024 ///
11025 /// @return a map of elf variable symbols not referenced by any debug
11026 /// info and that got deleted.
11027 const string_elf_symbol_map&
11029 {return priv_->deleted_unrefed_var_syms_;}
11030 
11031 /// Getter for variable symbols not referenced by any debug info and
11032 /// that got added.
11033 ///
11034 /// @return a map of elf variable symbols not referenced by any debug
11035 /// info and that got added.
11036 const string_elf_symbol_map&
11038 {return priv_->added_unrefed_var_syms_;}
11039 
11040 /// Getter for a map of deleted types that are not reachable from
11041 /// global functions/variables.
11042 ///
11043 /// @return a map that associates pretty representation of deleted
11044 /// unreachable types and said types.
11047 {return priv_->deleted_unreachable_types_;}
11048 
11049 /// Getter of a sorted vector of deleted types that are not reachable
11050 /// from global functions/variables.
11051 ///
11052 /// @return a sorted vector of deleted types that are not reachable
11053 /// from global functions/variables. The types are lexicographically
11054 /// sorted by considering their pretty representation.
11055 const vector<type_base_sptr>&
11057 {
11058  if (priv_->deleted_unreachable_types_sorted_.empty())
11059  if (!priv_->deleted_unreachable_types_.empty())
11060  sort_string_type_base_sptr_map(priv_->deleted_unreachable_types_,
11061  priv_->deleted_unreachable_types_sorted_);
11062 
11063  return priv_->deleted_unreachable_types_sorted_;
11064 }
11065 
11066 /// Getter for a map of added types that are not reachable from global
11067 /// functions/variables.
11068 ///
11069 /// @return a map that associates pretty representation of added
11070 /// unreachable types and said types.
11073 {return priv_->added_unreachable_types_;}
11074 
11075 /// Getter of a sorted vector of added types that are not reachable
11076 /// from global functions/variables.
11077 ///
11078 /// @return a sorted vector of added types that are not reachable from
11079 /// global functions/variables. The types are lexicographically
11080 /// sorted by considering their pretty representation.
11081 const vector<type_base_sptr>&
11083 {
11084  if (priv_->added_unreachable_types_sorted_.empty())
11085  if (!priv_->added_unreachable_types_.empty())
11086  sort_string_type_base_sptr_map(priv_->added_unreachable_types_,
11087  priv_->added_unreachable_types_sorted_);
11088 
11089  return priv_->added_unreachable_types_sorted_;
11090 }
11091 
11092 /// Getter for a map of changed types that are not reachable from
11093 /// global functions/variables.
11094 ///
11095 /// @return a map that associates pretty representation of changed
11096 /// unreachable types and said types.
11097 const string_diff_sptr_map&
11099 {return priv_->changed_unreachable_types_;}
11100 
11101 /// Getter of a sorted vector of changed types that are not reachable
11102 /// from global functions/variables.
11103 ///
11104 /// @return a sorted vector of changed types that are not reachable
11105 /// from global functions/variables. The diffs are lexicographically
11106 /// sorted by considering their pretty representation.
11107 const vector<diff_sptr>&
11109 {return priv_->changed_unreachable_types_sorted();}
11110 
11111 /// Getter of the diff context of this diff
11112 ///
11113 /// @return the diff context for this diff.
11114 const diff_context_sptr
11116 {return priv_->get_context();}
11117 
11118 /// @return the pretty representation for the current instance of @ref
11119 /// corpus_diff
11120 const string&
11122 {
11123  if (priv_->pretty_representation_.empty())
11124  {
11125  std::ostringstream o;
11126  o << "corpus_diff["
11127  << first_corpus()->get_path()
11128  << ", "
11129  << second_corpus()->get_path()
11130  << "]";
11131  priv_->pretty_representation_ = o.str();
11132  }
11133  return priv_->pretty_representation_;
11134 }
11135 /// Return true iff the current @ref corpus_diff node carries a
11136 /// change.
11137 ///
11138 /// @return true iff the current diff node carries a change.
11139 bool
11141 {
11142  return (soname_changed()
11144  || !(priv_->deleted_fns_.empty()
11145  && priv_->added_fns_.empty()
11146  && priv_->changed_fns_map_.empty()
11147  && priv_->deleted_vars_.empty()
11148  && priv_->added_vars_.empty()
11149  && priv_->changed_vars_map_.empty()
11150  && priv_->added_unrefed_fn_syms_.empty()
11151  && priv_->deleted_unrefed_fn_syms_.empty()
11152  && priv_->added_unrefed_var_syms_.empty()
11153  && priv_->deleted_unrefed_var_syms_.empty()
11154  && priv_->deleted_unreachable_types_.empty()
11155  && priv_->added_unreachable_types_.empty()
11156  && priv_->changed_unreachable_types_.empty()));
11157 }
11158 
11159 /// Test if the current instance of @ref corpus_diff carries changes
11160 /// that we are sure are incompatible. By incompatible change we mean
11161 /// a change that "breaks" the ABI of the corpus we are looking at.
11162 ///
11163 /// In concrete terms, this function considers the following changes
11164 /// as being ABI incompatible for sure:
11165 ///
11166 /// - a soname change
11167 /// - if exported functions or variables got removed
11168 ///
11169 /// Note that subtype changes *can* represent changes that break ABI
11170 /// too. But they also can be changes that are OK, ABI-wise.
11171 ///
11172 /// It's up to the user to provide suppression specifications to say
11173 /// explicitely which subtype change is OK. The remaining sub-type
11174 /// changes are then considered to be ABI incompatible. But to test
11175 /// if such ABI incompatible subtype changes are present you need to
11176 /// use the function @ref corpus_diff::has_net_subtype_changes()
11177 ///
11178 /// @return true iff the current instance of @ref corpus_diff carries
11179 /// changes that we are sure are ABI incompatible.
11180 bool
11182 {
11183  const diff_stats& stats = const_cast<corpus_diff*>(this)->
11185 
11186  return (soname_changed() || architecture_changed()
11187  || stats.net_num_func_removed() != 0
11188  || (stats.num_func_with_virtual_offset_changes() != 0
11189  // If all reports about functions with sub-type changes
11190  // have been suppressed, then even those about functions
11191  // that are virtual don't matter anymore because the
11192  // user willingly requested to shut them down
11193  && stats.net_num_func_changed() != 0)
11194  || stats.net_num_vars_removed() != 0
11195  || stats.net_num_removed_func_syms() != 0
11196  || stats.net_num_removed_var_syms() != 0
11197  || stats.net_num_removed_unreachable_types() != 0
11198  || stats.net_num_changed_unreachable_types() != 0);
11199 }
11200 
11201 /// Test if the current instance of @ref corpus_diff carries subtype
11202 /// changes whose reports are not suppressed by any suppression
11203 /// specification. In effect, these are deemed incompatible ABI
11204 /// changes.
11205 ///
11206 /// @return true iff the the current instance of @ref corpus_diff
11207 /// carries subtype changes that are deemed incompatible ABI changes.
11208 bool
11210 {
11211  const diff_stats& stats = const_cast<corpus_diff*>(this)->
11213 
11214  return (stats.net_num_func_changed() != 0
11215  || stats.net_num_vars_changed() != 0
11216  || stats.net_num_removed_unreachable_types() != 0
11217  || stats.net_num_changed_unreachable_types() != 0);
11218 }
11219 
11220 /// Test if the current instance of @ref corpus_diff carries changes
11221 /// whose reports are not suppressed by any suppression specification.
11222 /// In effect, these are deemed incompatible ABI changes.
11223 ///
11224 /// @return true iff the the current instance of @ref corpus_diff
11225 /// carries subtype changes that are deemed incompatible ABI changes.
11226 bool
11228 {return context()->get_reporter()->diff_has_net_changes(this);}
11229 
11230 /// Apply the different filters that are registered to be applied to
11231 /// the diff tree; that includes the categorization filters. Also,
11232 /// apply the suppression interpretation filters.
11233 ///
11234 /// After the filters are applied, this function calculates some
11235 /// statistics about the changes carried by the current instance of
11236 /// @ref corpus_diff. These statistics are represented by an instance
11237 /// of @ref corpus_diff::diff_stats.
11238 ///
11239 /// This member function is called by the reporting function
11240 /// corpus_diff::report().
11241 ///
11242 /// Note that for a given instance of corpus_diff, this function
11243 /// applies the filters and suppressions only the first time it is
11244 /// invoked. Subsequent invocations just return the instance of
11245 /// corpus_diff::diff_stats that was cached after the first
11246 /// invocation.
11247 ///
11248 /// @return a reference to the statistics about the changes carried by
11249 /// the current instance of @ref corpus_diff.
11252 {
11253  if (priv_->diff_stats_)
11254  return *priv_->diff_stats_;
11255 
11257  if (do_log())
11258  {
11259  std::cerr << "Applying suppressions ...\n";
11260  t.start();
11261  }
11262 
11263  apply_suppressions(this);
11264 
11265  if (do_log())
11266  {
11267  t.stop();
11268  std::cerr << "suppressions applied!:" << t << "\n";
11269  }
11270 
11271  priv_->diff_stats_.reset(new diff_stats(context()));
11272 
11273  if (do_log())
11274  {
11275  std::cerr << "Marking leaf nodes ...\n";
11276  t.start();
11277  }
11278 
11280 
11281  if (do_log())
11282  {
11283  t.stop();
11284  std::cerr << "leaf nodes marked!:" << t << "\n";
11285  std::cerr << "Applying filters and computing diff stats ...\n";
11286  t.start();
11287  }
11288 
11289  priv_->apply_filters_and_compute_diff_stats(*priv_->diff_stats_);
11290 
11291  if (do_log())
11292  {
11293  t.stop();
11294  std::cerr << "Filters applied and diff stats computed!: " << t << "\n";
11295  }
11296 
11297  return *priv_->diff_stats_;
11298 }
11299 
11300 /// A visitor that marks leaf diff nodes by storing them in the
11301 /// instance of @ref diff_maps returned by
11302 /// corpus_diff::get_leaf_diffs() invoked on the current instance of
11303 /// corpus_diff.
11304 struct leaf_diff_node_marker_visitor : public diff_node_visitor
11305 {
11306  /// This is called when the visitor visits a diff node.
11307  ///
11308  /// It basically tests if the diff node being visited is a leaf diff
11309  /// node - that is, it contains local changes. If it does, then the
11310  /// node is added to the set of maps that hold leaf diffs in the
11311  /// current corpus_diff.
11312  ///
11313  /// Note that only leaf nodes that are reachable from public
11314  /// interfaces (global functions or variables) are collected by this
11315  /// visitor.
11316  ///
11317  /// @param d the diff node being visited.
11318  virtual void
11319  visit_begin(diff *d)
11320  {
11321  if (d->has_local_changes()
11322  // A leaf basic (or class/union) type name change makes no
11323  // sense when showing just leaf changes. It only makes sense
11324  // when it can explain the details about a non-leaf change.
11325  // In other words, it doesn't make sense to say that an "int"
11326  // became "unsigned int". But it does make sense to say that
11327  // a typedef changed because its underlying type was 'int' and
11328  // is now an "unsigned int".
11330  // Similarly, a *local* change describing a type that changed
11331  // its nature doesn't make sense.
11332  && !is_distinct_diff(d)
11333  // Similarly, a pointer (or reference or array), a typedef or
11334  // qualified type change in itself doesn't make sense. It
11335  // would rather make sense to show that pointer change as part
11336  // of the variable change whose pointer type changed, for
11337  // instance.
11338  && !is_pointer_diff(d)
11339  && !is_reference_diff(d)
11340  && !is_qualified_type_diff(d)
11341  && !is_typedef_diff(d)
11342  && !is_array_diff(d)
11343  // Similarly a parameter change in itself doesn't make sense.
11344  // It should have already been reported as part of the change
11345  // of the function it belongs to.
11346  && !is_fn_parm_diff(d)
11347  // An anonymous class or union diff doesn't make sense on its
11348  // own. It must have been described already by the diff of
11349  // the enclosing struct or union if 'd' is from an anonymous
11350  // data member, or from a typedef change if 'd' is from a
11351  // typedef change which underlying type is an anonymous
11352  // struct/union.
11354  // Don't show decl-only-ness changes either.
11356  // Sometime, we can encounter artifacts of bogus DWARF that
11357  // yield a diff node for a decl-only class (and empty class
11358  // with the is_declaration flag set) that carries a non-zero
11359  // size! And of course at some point that non-zero size
11360  // changes. We need to be able to detect that.
11362  {
11363  diff_context_sptr ctxt = d->context();
11364  const corpus_diff *corpus_diff_node = ctxt->get_corpus_diff().get();
11365  ABG_ASSERT(corpus_diff_node);
11366 
11367  if (diff *iface_diff = get_current_topmost_iface_diff())
11368  {
11369  type_or_decl_base_sptr iface = iface_diff->first_subject();
11370  // So, this diff node that is reachable from a global
11371  // function or variable carries a leaf change. Let's add
11372  // it to the set of of leaf diffs of corpus_diff_node.
11373  const_cast<corpus_diff*>(corpus_diff_node)->
11374  get_leaf_diffs().insert_diff_node(d, iface);
11375  }
11376  }
11377  }
11378 }; // end struct leaf_diff_node_marker_visitor
11379 
11380 /// Walks the diff nodes associated to the current corpus diff and
11381 /// mark those that carry local changes. They are said to be leaf
11382 /// diff nodes.
11383 ///
11384 /// The marked nodes are available from the
11385 /// corpus_diff::get_leaf_diffs() function.
11386 void
11388 {
11389  if (!has_changes())
11390  return;
11391 
11392  if (!context()->show_leaf_changes_only())
11393  return;
11394 
11395  leaf_diff_node_marker_visitor v;
11396  context()->forget_visited_diffs();
11397  bool s = context()->visiting_a_node_twice_is_forbidden();
11398  context()->forbid_visiting_a_node_twice(true);
11399  if (context()->show_impacted_interfaces())
11400  context()->forbid_visiting_a_node_twice_per_interface(true);
11401  traverse(v);
11402  context()->forbid_visiting_a_node_twice(s);
11403  context()->forbid_visiting_a_node_twice_per_interface(false);
11404 }
11405 
11406 /// Get the set of maps that contain leaf nodes. A leaf node being a
11407 /// node with a local change.
11408 ///
11409 /// @return the set of maps that contain leaf nodes. A leaf node
11410 /// being a node with a local change.
11411 diff_maps&
11413 {return priv_->leaf_diffs_;}
11414 
11415 /// Get the set of maps that contain leaf nodes. A leaf node being a
11416 /// node with a local change.
11417 ///
11418 /// @return the set of maps that contain leaf nodes. A leaf node
11419 /// being a node with a local change.
11420 const diff_maps&
11422 {return priv_->leaf_diffs_;}
11423 
11424 /// Report the diff in a serialized form.
11425 ///
11426 /// @param out the stream to serialize the diff to.
11427 ///
11428 /// @param indent the prefix to use for the indentation of this
11429 /// serialization.
11430 void
11431 corpus_diff::report(ostream& out, const string& indent) const
11432 {
11433  context()->get_reporter()->report(*this, out, indent);
11434 }
11435 
11436 /// Traverse the diff sub-tree under the current instance corpus_diff.
11437 ///
11438 /// @param v the visitor to invoke on each diff node of the sub-tree.
11439 ///
11440 /// @return true if the traversing has to keep going on, false otherwise.
11441 bool
11443 {
11444  finish_diff_type();
11445 
11446  v.visit_begin(this);
11447 
11448  if (!v.visit(this, true))
11449  {
11450  v.visit_end(this);
11451  return false;
11452  }
11453 
11454  for (function_decl_diff_sptrs_type::const_iterator i =
11455  changed_functions_sorted().begin();
11456  i != changed_functions_sorted().end();
11457  ++i)
11458  {
11459  if (diff_sptr d = *i)
11460  {
11461  const diff_context_sptr &ctxt = context();
11462  if (ctxt->visiting_a_node_twice_is_forbidden_per_interface())
11463  ctxt->forget_visited_diffs();
11464 
11465  v.set_current_topmost_iface_diff(d.get());
11466 
11467  if (!d->traverse(v))
11468  {
11469  v.visit_end(this);
11471  return false;
11472  }
11473  }
11474  }
11475 
11476  for (var_diff_sptrs_type::const_iterator i =
11477  changed_variables_sorted().begin();
11478  i != changed_variables_sorted().end();
11479  ++i)
11480  {
11481  if (diff_sptr d = *i)
11482  {
11483  const diff_context_sptr &ctxt = context();
11484  if (ctxt->visiting_a_node_twice_is_forbidden_per_interface())
11485  ctxt->forget_visited_diffs();
11486 
11487  v.set_current_topmost_iface_diff(d.get());
11488 
11489  if (!d->traverse(v))
11490  {
11491  v.visit_end(this);
11493  return false;
11494  }
11495  }
11496  }
11497 
11499 
11500  // Traverse the changed unreachable type diffs. These diffs are on
11501  // types that are not reachable from global functions or variables.
11502  for (vector<diff_sptr>::const_iterator i =
11504  i != changed_unreachable_types_sorted().end();
11505  ++i)
11506  {
11507  if (diff_sptr d = *i)
11508  {
11509  const diff_context_sptr &ctxt = context();
11510  if (ctxt->visiting_a_node_twice_is_forbidden_per_interface())
11511  ctxt->forget_visited_diffs();
11512 
11513  if (!d->traverse(v))
11514  {
11515  v.visit_end(this);
11516  return false;
11517  }
11518  }
11519  }
11520 
11521  v.visit_end(this);
11522  return true;
11523 }
11524 
11525 /// Compute the diff between two instances of @ref corpus.
11526 ///
11527 /// Note that the two corpora must have been created in the same @ref
11528 /// environment, otherwise, this function aborts.
11529 ///
11530 /// @param f the first @ref corpus to consider for the diff.
11531 ///
11532 /// @param s the second @ref corpus to consider for the diff.
11533 ///
11534 /// @param ctxt the diff context to use.
11535 ///
11536 /// @return the resulting diff between the two @ref corpus.
11538 compute_diff(const corpus_sptr f,
11539  const corpus_sptr s,
11540  diff_context_sptr ctxt)
11541 {
11542  typedef corpus::functions::const_iterator fns_it_type;
11543  typedef corpus::variables::const_iterator vars_it_type;
11544  typedef elf_symbols::const_iterator symbols_it_type;
11545  typedef diff_utils::deep_ptr_eq_functor eq_type;
11546  typedef vector<type_base_wptr>::const_iterator type_base_wptr_it_type;
11547 
11548  ABG_ASSERT(f && s);
11549 
11550  if (!ctxt)
11551  ctxt.reset(new diff_context);
11552 
11553  corpus_diff_sptr r(new corpus_diff(f, s, ctxt));
11554 
11555  ctxt->set_corpus_diff(r);
11556 
11557  if(ctxt->show_soname_change())
11558  r->priv_->sonames_equal_ = f->get_soname() == s->get_soname();
11559  else
11560  r->priv_->sonames_equal_ = true;
11561 
11562  r->priv_->architectures_equal_ =
11563  f->get_architecture_name() == s->get_architecture_name();
11564 
11565  // Compute the diff of publicly defined and exported functions
11566  diff_utils::compute_diff<fns_it_type, eq_type>(f->get_functions().begin(),
11567  f->get_functions().end(),
11568  s->get_functions().begin(),
11569  s->get_functions().end(),
11570  r->priv_->fns_edit_script_);
11571 
11572  // Compute the diff of publicly defined and exported variables.
11573  diff_utils::compute_diff<vars_it_type, eq_type>
11574  (f->get_variables().begin(), f->get_variables().end(),
11575  s->get_variables().begin(), s->get_variables().end(),
11576  r->priv_->vars_edit_script_);
11577 
11578  // Compute the diff of function elf symbols not referenced by debug
11579  // info.
11580  diff_utils::compute_diff<symbols_it_type, eq_type>
11581  (f->get_unreferenced_function_symbols().begin(),
11582  f->get_unreferenced_function_symbols().end(),
11583  s->get_unreferenced_function_symbols().begin(),
11584  s->get_unreferenced_function_symbols().end(),
11585  r->priv_->unrefed_fn_syms_edit_script_);
11586 
11587  // Compute the diff of variable elf symbols not referenced by debug
11588  // info.
11589  diff_utils::compute_diff<symbols_it_type, eq_type>
11590  (f->get_unreferenced_variable_symbols().begin(),
11591  f->get_unreferenced_variable_symbols().end(),
11592  s->get_unreferenced_variable_symbols().begin(),
11593  s->get_unreferenced_variable_symbols().end(),
11594  r->priv_->unrefed_var_syms_edit_script_);
11595 
11596  if (ctxt->show_unreachable_types())
11597  // Compute the diff of types not reachable from public functions
11598  // or global variables that are exported.
11599  diff_utils::compute_diff<type_base_wptr_it_type, eq_type>
11600  (f->get_types_not_reachable_from_public_interfaces().begin(),
11601  f->get_types_not_reachable_from_public_interfaces().end(),
11602  s->get_types_not_reachable_from_public_interfaces().begin(),
11603  s->get_types_not_reachable_from_public_interfaces().end(),
11604  r->priv_->unreachable_types_edit_script_);
11605 
11606  r->priv_->ensure_lookup_tables_populated();
11607 
11608  return r;
11609 }
11610 
11611 // </corpus stuff>
11612 
11613 /// Compute the diff between two instances of @ref corpus_group.
11614 ///
11615 /// Note that the two corpus_diff must have been created in the same
11616 /// @ref environment, otherwise, this function aborts.
11617 ///
11618 /// @param f the first @ref corpus_group to consider for the diff.
11619 ///
11620 /// @param s the second @ref corpus_group to consider for the diff.
11621 ///
11622 /// @param ctxt the diff context to use.
11623 ///
11624 /// @return the resulting diff between the two @ref corpus_group.
11626 compute_diff(const corpus_group_sptr& f,
11627  const corpus_group_sptr& s,
11628  diff_context_sptr ctxt)
11629 {
11630 
11631  corpus_sptr c1 = f;
11632  corpus_sptr c2 = s;
11633 
11634  return compute_diff(c1, c2, ctxt);
11635 }
11636 
11637 // <corpus_group stuff>
11638 
11639 // </corpus_group stuff>
11640 // <diff_node_visitor stuff>
11641 
11642 /// The private data of the @diff_node_visitor type.
11643 struct diff_node_visitor::priv
11644 {
11645  diff* topmost_interface_diff;
11646  visiting_kind kind;
11647 
11648  priv()
11649  : topmost_interface_diff(),
11650  kind()
11651  {}
11652 
11653  priv(visiting_kind k)
11654  : topmost_interface_diff(),
11655  kind(k)
11656  {}
11657 }; // end struct diff_node_visitor
11658 
11659 /// Default constructor of the @ref diff_node_visitor type.
11661  : priv_(new priv)
11662 {}
11663 
11664 diff_node_visitor::~diff_node_visitor() = default;
11665 
11666 /// Constructor of the @ref diff_node_visitor type.
11667 ///
11668 /// @param k how the visiting has to be performed.
11670  : priv_(new priv(k))
11671 {}
11672 
11673 /// Getter for the visiting policy of the traversing code while
11674 /// invoking this visitor.
11675 ///
11676 /// @return the visiting policy used by the traversing code when
11677 /// invoking this visitor.
11680 {return priv_->kind;}
11681 
11682 /// Setter for the visiting policy of the traversing code while
11683 /// invoking this visitor.
11684 ///
11685 /// @param v a bit map representing the new visiting policy used by
11686 /// the traversing code when invoking this visitor.
11687 void
11689 {priv_->kind = v;}
11690 
11691 /// Setter for the visiting policy of the traversing code while
11692 /// invoking this visitor. This one makes a logical or between the
11693 /// current policy and the bitmap given in argument and assigns the
11694 /// current policy to the result.
11695 ///
11696 /// @param v a bitmap representing the visiting policy to or with
11697 /// the current policy.
11698 void
11700 {priv_->kind = priv_->kind | v;}
11701 
11702 /// Setter of the diff current topmost interface which is impacted by
11703 /// the current diff node being visited.
11704 ///
11705 /// @param d the current topmost interface diff impacted.
11706 void
11708 {priv_->topmost_interface_diff = d;}
11709 
11710 /// Getter of the diff current topmost interface which is impacted by
11711 /// the current diff node being visited.
11712 ///
11713 /// @return the current topmost interface diff impacted.
11714 diff*
11716 {return priv_->topmost_interface_diff;}
11717 
11718 /// This is called by the traversing code on a @ref diff node just
11719 /// before visiting it. That is, before visiting it and its children
11720 /// node.
11721 ///
11722 /// @param d the diff node to visit.
11723 void
11725 {}
11726 
11727 /// This is called by the traversing code on a @ref diff node just
11728 /// after visiting it. That is after visiting it and its children
11729 /// nodes.
11730 ///
11731 /// @param d the diff node that got visited.
11732 void
11734 {}
11735 
11736 /// This is called by the traversing code on a @ref corpus_diff node
11737 /// just before visiting it. That is, before visiting it and its
11738 /// children node.
11739 ///
11740 /// @param p the corpus_diff node to visit.
11741 ///
11742 void
11744 {}
11745 
11746 /// This is called by the traversing code on a @ref corpus_diff node
11747 /// just after visiting it. That is after visiting it and its children
11748 /// nodes.
11749 ///
11750 /// @param d the diff node that got visited.
11751 void
11753 {}
11754 
11755 /// Default visitor implementation
11756 ///
11757 /// @return true
11758 bool
11760 {return true;}
11761 
11762 /// Default visitor implementation.
11763 ///
11764 /// @return true
11765 bool
11767 {
11768  diff* d = dif;
11769  visit(d, pre);
11770 
11771  return true;
11772 }
11773 
11774 /// Default visitor implementation.
11775 ///
11776 /// @return true
11777 bool
11779 {
11780  diff* d = dif;
11781  visit(d, pre);
11782 
11783  return true;
11784 }
11785 
11786 /// Default visitor implementation.
11787 ///
11788 /// @return true
11789 bool
11791 {
11792  diff* d = dif;
11793  visit(d, pre);
11794 
11795  return true;
11796 }
11797 
11798 /// Default visitor implementation.
11799 ///
11800 /// @return true
11801 bool
11803 {
11804  diff* d = dif;
11805  visit(d, pre);
11806 
11807  return true;
11808 }
11809 
11810 /// Default visitor implementation.
11811 ///
11812 /// @return true
11813 bool
11815 {
11816  diff* d = dif;
11817  visit(d, pre);
11818 
11819  return true;
11820 }
11821 
11822 /// Default visitor implementation.
11823 ///
11824 /// @return true
11825 bool
11827 {
11828  diff* d = dif;
11829  visit(d, pre);
11830 
11831  return true;
11832 }
11833 
11834 /// Default visitor implementation.
11835 ///
11836 /// @return true
11837 bool
11839 {
11840  diff* d = dif;
11841  visit(d, pre);
11842 
11843  return true;
11844 }
11845 
11846 /// Default visitor implementation.
11847 ///
11848 /// @return true
11849 bool
11851 {
11852  diff* d = dif;
11853  visit(d, pre);
11854 
11855  return true;
11856 }
11857 
11858 /// Default visitor implementation.
11859 ///
11860 /// @return true
11861 bool
11863 {
11864  diff* d = dif;
11865  visit(d, pre);
11866 
11867  return true;
11868 }
11869 
11870 /// Default visitor implementation.
11871 ///
11872 /// @return true
11873 bool
11875 {
11876  diff* d = dif;
11877  visit(d, pre);
11878 
11879  return true;
11880 }
11881 
11882 /// Default visitor implementation.
11883 ///
11884 /// @return true
11885 bool
11887 {
11888  diff* d = dif;
11889  visit(d, pre);
11890 
11891  return true;
11892 }
11893 
11894 /// Default visitor implementation.
11895 ///
11896 /// @return true
11897 bool
11899 {
11900  diff* d = dif;
11901  visit(d, pre);
11902 
11903  return true;
11904 }
11905 
11906 /// Default visitor implementation.
11907 ///
11908 /// @return true
11909 bool
11911 {
11912  diff* d = dif;
11913  visit(d, pre);
11914 
11915  return true;
11916 }
11917 
11918 /// Default visitor implementation.
11919 ///
11920 /// @return true
11921 bool
11923 {return true;}
11924 
11925 // </diff_node_visitor stuff>
11926 
11927 // <redundant diff node marking>
11928 
11929 // </redundant diff node marking>
11930 
11931 // <diff tree category propagation>
11932 
11933 /// A visitor to propagate the category of a node up to its parent
11934 /// nodes. This visitor doesn't touch the REDUNDANT_CATEGORY or the
11935 /// SUPPRESSED_CATEGORY because those are propagated using other
11936 /// specific visitors.
11937 struct category_propagation_visitor : public diff_node_visitor
11938 {
11939  virtual void
11940  visit_end(diff* d)
11941  {
11942  // Has this diff node 'd' been already visited ?
11943  bool already_visited = d->context()->diff_has_been_visited(d);
11944 
11945  // The canonical diff node of the class of equivalence of the diff
11946  // node 'd'.
11947  diff* canonical = d->get_canonical_diff();
11948 
11949  // If this class of equivalence of diff node is being visited for
11950  // the first time, then update its canonical node's category too.
11951  bool update_canonical = !already_visited && canonical;
11952 
11953  for (vector<diff*>::const_iterator i = d->children_nodes().begin();
11954  i != d->children_nodes().end();
11955  ++i)
11956  {
11957  // If we are visiting the class of equivalence of 'd' for the
11958  // first time, then let's look at the children of 'd' and
11959  // propagate their categories to 'd'.
11960  //
11961  // If the class of equivalence of 'd' has already been
11962  // visited, then let's look at the canonical diff nodes of the
11963  // children of 'd' and propagate their categories to 'd'.
11964  diff* diff = already_visited
11965  ? (*i)->get_canonical_diff()
11966  : *i;
11967 
11968  ABG_ASSERT(diff);
11969 
11971  // Do not propagate redundant and suppressed categories. Those
11972  // are propagated in a specific pass elsewhere.
11973  c &= ~(REDUNDANT_CATEGORY
11979  // Also, if a (class) type has got a harmful name change, do not
11980  // propagate harmless name changes coming from its sub-types
11981  // (i.e, data members) to the class itself.
11984 
11985  d->add_to_category(c);
11986  if (!already_visited && canonical)
11987  if (update_canonical)
11988  canonical->add_to_category(c);
11989  }
11990  }
11991 };// end struct category_propagation_visitor
11992 
11993 /// Visit all the nodes of a given sub-tree. For each node that has a
11994 /// particular category set, propagate that category set up to its
11995 /// parent nodes.
11996 ///
11997 /// @param diff_tree the diff sub-tree to walk for categorization
11998 /// purpose;
11999 void
12001 {
12002  category_propagation_visitor v;
12003  bool s = diff_tree->context()->visiting_a_node_twice_is_forbidden();
12004  diff_tree->context()->forbid_visiting_a_node_twice(true);
12005  diff_tree->context()->forget_visited_diffs();
12006  diff_tree->traverse(v);
12007  diff_tree->context()->forbid_visiting_a_node_twice(s);
12008 }
12009 
12010 /// Visit all the nodes of a given sub-tree. For each node that has a
12011 /// particular category set, propagate that category set up to its
12012 /// parent nodes.
12013 ///
12014 /// @param diff_tree the diff sub-tree to walk for categorization
12015 /// purpose;
12016 void
12018 {propagate_categories(diff_tree.get());}
12019 
12020 /// Visit all the nodes of a given corpus tree. For each node that
12021 /// has a particular category set, propagate that category set up to
12022 /// its parent nodes.
12023 ///
12024 /// @param diff_tree the corpus_diff tree to walk for categorization
12025 /// purpose;
12026 void
12028 {
12029  category_propagation_visitor v;
12030  bool s = diff_tree->context()->visiting_a_node_twice_is_forbidden();
12031  diff_tree->context()->forbid_visiting_a_node_twice(false);
12032  diff_tree->traverse(v);
12033  diff_tree->context()->forbid_visiting_a_node_twice(s);
12034 }
12035 
12036 /// Visit all the nodes of a given corpus tree. For each node that
12037 /// has a particular category set, propagate that category set up to
12038 /// its parent nodes.
12039 ///
12040 /// @param diff_tree the corpus_diff tree to walk for categorization
12041 /// purpose;
12042 void
12044 {propagate_categories(diff_tree.get());}
12045 
12046 /// A tree node visitor that knows how to categorizes a given diff
12047 /// node in the SUPPRESSED_CATEGORY category and how to propagate that
12048 /// categorization.
12049 struct suppression_categorization_visitor : public diff_node_visitor
12050 {
12051 
12052  /// Before visiting the children of the diff node, check if the node
12053  /// is suppressed by a suppression specification. If it is, mark
12054  /// the node as belonging to the SUPPRESSED_CATEGORY category.
12055  ///
12056  /// @param p the diff node to visit.
12057  virtual void
12058  visit_begin(diff* d)
12059  {
12060  bool is_private_type = false;
12061  if (d->is_suppressed(is_private_type))
12062  {
12063  diff_category c = is_private_type
12067 
12068  // If a node was suppressed, all the other nodes of its class
12069  // of equivalence are suppressed too.
12070  diff *canonical_diff = d->get_canonical_diff();
12071  if (canonical_diff != d)
12072  canonical_diff->add_to_category(c);
12073  }
12075  {
12076  // This diff node is specifically allowed by a
12077  // negated_suppression, then mark it as being in the
12078  // HAS_ALLOWED_CHANGE_CATEGORY.
12080  d->add_to_local_category(c);
12081  diff *canonical_diff = d->get_canonical_diff();
12082  canonical_diff->add_to_category(c);
12083 
12084  // Note that some complementary code later down below does
12085  // categorize the descendants and parents nodes of this node
12086  // as HAS_PARENT_WITH_ALLOWED_CHANGE_CATEGORY and
12087  // HAS_DESCENDANT_WITH_ALLOWED_CHANGE_CATEGORY, repectively.
12088  }
12089 
12090  // If a parent node has been allowed by a negated suppression
12091  // specification, then categorize the current node as
12092  // HAS_PARENT_WITH_ALLOWED_CHANGE_CATEGORY.
12093  if (d->parent_node())
12094  {
12099  else
12100  {
12101  c = d->parent_node()->get_category();
12105  }
12106  }
12107 
12108  }
12109 
12110  /// After visiting the children nodes of a given diff node,
12111  /// propagate the SUPPRESSED_CATEGORY from the children nodes to the
12112  /// diff node, if need be.
12113  ///
12114  /// That is, if all children nodes carry a suppressed change the
12115  /// current node should be marked as suppressed as well.
12116  ///
12117  /// In practice, this might be too strong of a condition. If the
12118  /// current node carries a local change (i.e, a change not carried
12119  /// by any of its children node) and if that change is not
12120  /// suppressed, then the current node should *NOT* be suppressed.
12121  ///
12122  /// But right now, the IR doesn't let us know about local vs
12123  /// children-carried changes. So we cannot be that precise yet.
12124  virtual void
12125  visit_end(diff* d)
12126  {
12127  bool has_non_suppressed_child = false;
12128  bool has_non_empty_child = false;
12129  bool has_suppressed_child = false;
12130  bool has_non_private_child = false;
12131  bool has_private_child = false;
12132  bool has_descendant_with_allowed_change = false;
12133 
12134  if (// A node to which we can propagate the "SUPPRESSED_CATEGORY"
12135  // (or the PRIVATE_TYPE_CATEGORY for the same matter)
12136  // category from its children is a node which:
12137  //
12138  // 1/ hasn't been suppressed already
12139  //
12140  // 2/ and has no local change (unless it's a pointer,
12141  // reference or qualified diff node).
12142  //
12143  // Note that qualified type and typedef diff nodes are a bit
12144  // special. The local changes of the underlying type are
12145  // considered local for the qualified/typedef type, just like
12146  // for pointer/reference types. But then the qualified or
12147  // typedef type itself can have local changes of its own, and
12148  // those changes are of the kind LOCAL_NON_TYPE_CHANGE_KIND.
12149  // So a qualified type which have local changes that are
12150  // *NOT* of LOCAL_NON_TYPE_CHANGE_KIND (or that has no local
12151  // changes at all) and which is in the PRIVATE_TYPE_CATEGORY
12152  // or SUPPRESSED_CATEGORY can see these categories be
12153  // propagated.
12154  //
12155  // Note that all pointer/reference diff node changes are
12156  // potentially considered local, i.e, local changes of the
12157  // pointed-to-type are considered local to the pointer itself.
12158  //
12159  // Similarly, changes local to the type of function parameters,
12160  // variables (and data members) and classes (that are not of
12161  // LOCAL_NON_TYPE_CHANGE_KIND kind) and that have been
12162  // suppressed can propagate their SUPPRESSED_CATEGORY-ness to
12163  // those kinds of diff node.
12164  !(d->get_category() & SUPPRESSED_CATEGORY)
12165  && (!d->has_local_changes()
12166  || is_pointer_diff(d)
12167  || is_reference_diff(d)
12168  || (is_qualified_type_diff(d)
12169  && (!(d->has_local_changes() & LOCAL_NON_TYPE_CHANGE_KIND)))
12170  || (is_typedef_diff(d)
12171  && (!(d->has_local_changes() & LOCAL_NON_TYPE_CHANGE_KIND)))
12172  || (is_function_decl_diff(d)
12173  && (!(d->has_local_changes() & LOCAL_NON_TYPE_CHANGE_KIND)))
12174  || (is_fn_parm_diff(d)
12175  && (!(d->has_local_changes() & LOCAL_NON_TYPE_CHANGE_KIND)))
12176  || (is_function_type_diff(d)
12177  && (!(d->has_local_changes() & LOCAL_NON_TYPE_CHANGE_KIND)))
12178  || (is_var_diff(d)
12179  && (!(d->has_local_changes() & LOCAL_NON_TYPE_CHANGE_KIND)))
12180  || (is_class_diff(d)
12181  && (!(d->has_local_changes() & LOCAL_NON_TYPE_CHANGE_KIND)))))
12182  {
12183  // Note that we handle private diff nodes differently from
12184  // generally suppressed diff nodes. E.g, it's not because a
12185  // type is private (and suppressed because of that; i.e, in
12186  // the category PRIVATE_TYPE_CATEGORY) that a typedef to that
12187  // type should also be private and so suppressed. Private
12188  // diff nodes thus have different propagation rules than
12189  // generally suppressed rules.
12190  for (vector<diff*>::const_iterator i = d->children_nodes().begin();
12191  i != d->children_nodes().end();
12192  ++i)
12193  {
12194  diff* child = *i;
12195  if (child->has_changes())
12196  {
12197  has_non_empty_child = true;
12198  if (child->get_class_of_equiv_category() & SUPPRESSED_CATEGORY)
12199  has_suppressed_child = true;
12200  else if (child->get_class_of_equiv_category()
12202  // Propagation of the PRIVATE_TYPE_CATEGORY is going
12203  // to be handled later below.
12204  ;
12205  else
12206  has_non_suppressed_child = true;
12207 
12208  if (child->get_class_of_equiv_category()
12210  has_private_child = true;
12211  else if (child->get_class_of_equiv_category()
12213  // Propagation of the SUPPRESSED_CATEGORY has been
12214  // handled above already.
12215  ;
12216  else
12217  has_non_private_child = true;
12218  }
12219  }
12220 
12221  if (has_non_empty_child
12222  && has_suppressed_child
12223  && !has_non_suppressed_child)
12224  {
12226  // If a node was suppressed, all the other nodes of its class
12227  // of equivalence are suppressed too.
12228  diff *canonical_diff = d->get_canonical_diff();
12229  if (canonical_diff != d)
12230  canonical_diff->add_to_category(SUPPRESSED_CATEGORY);
12231  }
12232 
12233  // Note that the private-ness of a an underlying type won't be
12234  // propagated to its parent typedef, by virtue of the big "if"
12235  // clause at the beginning of this function. So we don't have
12236  // to handle that case here. So the idiom of defining
12237  // typedefs of private (opaque) types will be respected;
12238  // meaning that changes to opaque underlying type will be
12239  // flagged as private and the typedef will be flagged private
12240  // as well, unless the typedef itself has local non-type
12241  // changes. In the later case, changes to the typedef will be
12242  // emitted because the typedef won't inherit the privateness
12243  // of its underlying type. So in practise, the typedef
12244  // remains public for the purpose of change reporting.
12245  if (has_non_empty_child
12246  && has_private_child
12247  && !has_non_private_child)
12248  {
12249  d->add_to_category(PRIVATE_TYPE_CATEGORY);
12250  // If a node was suppressed, all the other nodes of its class
12251  // of equivalence are suppressed too.
12252  diff *canonical_diff = d->get_canonical_diff();
12253  if (canonical_diff != d)
12254  canonical_diff->add_to_category(PRIVATE_TYPE_CATEGORY);
12255  }
12256 
12257  // If the underlying type of a typedef is private and carries
12258  // changes (that are implicitely suppressed because it's
12259  // private) then the typedef must be suppressed too, so that
12260  // those changes to the underlying type are not seen.
12261  if (is_typedef_diff(d)
12262  && !d->has_local_changes()
12263  && has_private_child
12264  && has_non_empty_child)
12265  {
12266  d->add_to_category(SUPPRESSED_CATEGORY|PRIVATE_TYPE_CATEGORY);
12267  // If a node was suppressed, all the other nodes of its class
12268  // of equivalence are suppressed too.
12269  diff *canonical_diff = d->get_canonical_diff();
12270  if (canonical_diff != d)
12271  canonical_diff->add_to_category
12273  }
12274 
12275  if (const function_decl_diff *fn_diff = is_function_decl_diff(d))
12276  if (!(d->has_local_changes() & LOCAL_NON_TYPE_CHANGE_KIND))
12277  {
12278  // d is a function diff that carries a local *type*
12279  // change (that means it's a change to the function
12280  // type). Let's see if the child function type diff
12281  // node is suppressed. That would mean that we are
12282  // instructed to show details of a diff that is deemed
12283  // suppressed; this means the suppression conflicts with
12284  // a local type change. In that case, let's follow what
12285  // the user asked and suppress the function altogether,
12286  if (function_type_diff_sptr fn_type_diff = fn_diff->type_diff())
12287  if (fn_type_diff->is_suppressed())
12288  {
12289  d->add_to_category(SUPPRESSED_CATEGORY);
12290  // If a node was suppressed, all the other nodes
12291  // of its class of equivalence are suppressed too.
12292  diff *canonical_diff = d->get_canonical_diff();
12293  if (canonical_diff != d)
12294  canonical_diff->add_to_category(SUPPRESSED_CATEGORY);
12295  }
12296  }
12297  }
12298 
12299  // If any descendant node was selected by a negated suppression
12300  // specification then categorize the current one as
12301  // HAS_DESCENDANT_WITH_ALLOWED_CHANGE_CATEGORY.
12302  for (auto child_node : d->children_nodes())
12303  {
12304  diff *canonical_diff = child_node->get_canonical_diff();
12305  diff_category c = canonical_diff->get_category();
12308  has_descendant_with_allowed_change = true;
12309  }
12310  if (has_descendant_with_allowed_change)
12311  {
12313  d->add_to_category(c);
12314  d->get_canonical_diff()->add_to_category(c);
12315  }
12316  }
12317 }; //end struct suppression_categorization_visitor
12318 
12319 /// Walk a given diff-sub tree and appply the suppressions carried by
12320 /// the context. If the suppression applies to a given node than
12321 /// categorize the node into the SUPPRESSED_CATEGORY category and
12322 /// propagate that categorization.
12323 ///
12324 /// @param diff_tree the diff-sub tree to apply the suppressions to.
12325 void
12327 {
12328  if (diff_tree && !diff_tree->context()->suppressions().empty())
12329  {
12330  // Apply suppressions to functions and variables that have
12331  // changed sub-types.
12332  suppression_categorization_visitor v;
12333  diff_tree->context()->forget_visited_diffs();
12334  bool s = diff_tree->context()->visiting_a_node_twice_is_forbidden();
12335  diff_tree->context()->forbid_visiting_a_node_twice(true);
12336  diff_tree->traverse(v);
12337  diff_tree->context()->forbid_visiting_a_node_twice(s);
12338  }
12339 }
12340 
12341 /// Walk a given diff-sub tree and appply the suppressions carried by
12342 /// the context. If the suppression applies to a given node than
12343 /// categorize the node into the SUPPRESSED_CATEGORY category and
12344 /// propagate that categorization.
12345 ///
12346 /// @param diff_tree the diff-sub tree to apply the suppressions to.
12347 void
12349 {apply_suppressions(diff_tree.get());}
12350 
12351 /// Walk a @ref corpus_diff tree and appply the suppressions carried
12352 /// by the context. If the suppression applies to a given node then
12353 /// categorize the node into the SUPPRESSED_CATEGORY category and
12354 /// propagate that categorization.
12355 ///
12356 /// @param diff_tree the diff tree to apply the suppressions to.
12357 void
12359 {
12360  if (diff_tree && !diff_tree->context()->suppressions().empty())
12361  {
12362  // First, visit the children trees of changed constructs:
12363  // changed functions, variables, as well as sub-types of these,
12364  // and apply suppression specifications to these ...
12365  suppression_categorization_visitor v;
12366  diff_tree->context()->forget_visited_diffs();
12367  bool s = diff_tree->context()->visiting_a_node_twice_is_forbidden();
12368  diff_tree->context()->forbid_visiting_a_node_twice(true);
12369  const_cast<corpus_diff*>(diff_tree)->traverse(v);
12370  diff_tree->context()->forbid_visiting_a_node_twice(s);
12371 
12372  // ... then also visit the set of added and removed functions,
12373  // variables, symbols, and types not reachable from global
12374  // functions and variables.
12375  diff_tree->priv_->
12376  apply_supprs_to_added_removed_fns_vars_unreachable_types();
12377  }
12378 }
12379 
12380 /// Walk a diff tree and appply the suppressions carried by the
12381 /// context. If the suppression applies to a given node than
12382 /// categorize the node into the SUPPRESSED_CATEGORY category and
12383 /// propagate that categorization.
12384 ///
12385 /// @param diff_tree the diff tree to apply the suppressions to.
12386 void
12388 {apply_suppressions(diff_tree.get());}
12389 
12390 // </diff tree category propagation>
12391 
12392 // <diff tree printing stuff>
12393 
12394 /// A visitor to print (to an output stream) a pretty representation
12395 /// of a @ref diff sub-tree or of a complete @ref corpus_diff tree.
12396 struct diff_node_printer : public diff_node_visitor
12397 {
12398  ostream& out_;
12399  unsigned level_;
12400 
12401  /// Emit a certain number of spaces to the output stream associated
12402  /// to this diff_node_printer.
12403  ///
12404  /// @param level half of the numver of spaces to emit.
12405  void
12406  do_indent(unsigned level)
12407  {
12408  for (unsigned i = 0; i < level; ++i)
12409  out_ << " ";
12410  }
12411 
12412  diff_node_printer(ostream& out)
12413  : diff_node_visitor(DO_NOT_MARK_VISITED_NODES_AS_VISITED),
12414  out_(out),
12415  level_(0)
12416  {}
12417 
12418  virtual void
12419  visit_begin(diff*)
12420  {
12421  ++level_;
12422  }
12423 
12424  virtual void
12425  visit_end(diff*)
12426  {
12427  --level_;
12428  }
12429 
12430  virtual void
12431  visit_begin(corpus_diff*)
12432  {
12433  ++level_;
12434  }
12435 
12436  virtual void
12437  visit_end(corpus_diff*)
12438  {
12439  --level_;
12440  }
12441 
12442  virtual bool
12443  visit(diff* d, bool pre)
12444  {
12445  if (!pre)
12446  // We are post-visiting the diff node D. Which means, we have
12447  // printed a pretty representation for it already. So do
12448  // nothing now.
12449  return true;
12450 
12451  do_indent(level_);
12452  out_ << d->get_pretty_representation();
12453  out_ << "\n";
12454  do_indent(level_);
12455  out_ << "{\n";
12456  do_indent(level_ + 1);
12457  out_ << "category: "<< d->get_category() << "\n";
12458  do_indent(level_ + 1);
12459  out_ << "@: " << std::hex << d << std::dec << "\n";
12460  do_indent(level_ + 1);
12461  out_ << "@-canonical: " << std::hex
12462  << d->get_canonical_diff()
12463  << std::dec << "\n";
12464  do_indent(level_);
12465  out_ << "}\n";
12466 
12467  return true;
12468  }
12469 
12470  virtual bool
12471  visit(corpus_diff* d, bool pre)
12472  {
12473  if (!pre)
12474  // We are post-visiting the diff node D. Which means, we have
12475  // printed a pretty representation for it already. So do
12476  // nothing now.
12477  return true;
12478 
12479  // indent
12480  for (unsigned i = 0; i < level_; ++i)
12481  out_ << ' ';
12482  out_ << d->get_pretty_representation();
12483  out_ << '\n';
12484  return true;
12485  }
12486 }; // end struct diff_printer_visitor
12487 
12488 // </ diff tree printing stuff>
12489 
12490 /// Emit a textual representation of a @ref diff sub-tree to an
12491 /// output stream.
12492 ///
12493 /// @param diff_tree the sub-tree to emit the textual representation
12494 /// for.
12495 ///
12496 /// @param out the output stream to emit the textual representation
12497 /// for @p diff_tree to.
12498 void
12499 print_diff_tree(diff* diff_tree, ostream& out)
12500 {
12501  diff_node_printer p(out);
12502  bool s = diff_tree->context()->visiting_a_node_twice_is_forbidden();
12503  diff_tree->context()->forbid_visiting_a_node_twice(false);
12504  diff_tree->traverse(p);
12505  diff_tree->context()->forbid_visiting_a_node_twice(s);
12506 }
12507 
12508 /// Emit a textual representation of a @ref corpus_diff tree to an
12509 /// output stream.
12510 ///
12511 /// @param diff_tree the @ref corpus_diff tree to emit the textual
12512 /// representation for.
12513 ///
12514 /// @param out the output stream to emit the textual representation
12515 /// for @p diff_tree to.
12516 void
12517 print_diff_tree(corpus_diff* diff_tree, std::ostream& out)
12518 {
12519  diff_node_printer p(out);
12520  bool s = diff_tree->context()->visiting_a_node_twice_is_forbidden();
12521  diff_tree->context()->forbid_visiting_a_node_twice(false);
12522  diff_tree->traverse(p);
12523  diff_tree->context()->forbid_visiting_a_node_twice(s);
12524 }
12525 
12526 /// Emit a textual representation of a @ref diff sub-tree to an
12527 /// output stream.
12528 ///
12529 /// @param diff_tree the sub-tree to emit the textual representation
12530 /// for.
12531 ///
12532 /// @param out the output stream to emit the textual representation
12533 /// for @p diff_tree to.
12534 void
12536  std::ostream& o)
12537 {print_diff_tree(diff_tree.get(), o);}
12538 
12539 /// Emit a textual representation of a @ref corpus_diff tree to an
12540 /// output stream.
12541 ///
12542 /// @param diff_tree the @ref corpus_diff tree to emit the textual
12543 /// representation for.
12544 ///
12545 /// @param out the output stream to emit the textual representation
12546 /// for @p diff_tree to.
12547 void
12549  std::ostream& o)
12550 {print_diff_tree(diff_tree.get(), o);}
12551 
12552 // <redundancy_marking_visitor>
12553 
12554 /// A tree visitor to categorize nodes with respect to the
12555 /// REDUNDANT_CATEGORY. That is, detect if a node is redundant (is
12556 /// present on several spots of the tree) and mark such nodes
12557 /// appropriatly. This visitor also takes care of propagating the
12558 /// REDUNDANT_CATEGORY of a given node to its parent nodes as
12559 /// appropriate.
12560 struct redundancy_marking_visitor : public diff_node_visitor
12561 {
12562  bool skip_children_nodes_;
12563 
12564  redundancy_marking_visitor()
12565  : skip_children_nodes_()
12566  {}
12567 
12568  virtual void
12569  visit_begin(diff* d)
12570  {
12571  if (d->to_be_reported())
12572  {
12573  // A diff node that carries a change and that has been already
12574  // traversed elsewhere is considered redundant. So let's mark
12575  // it as such and let's not traverse it; that is, let's not
12576  // visit its children.
12577  if ((d->context()->diff_has_been_visited(d)
12578  || d->get_canonical_diff()->is_traversing())
12579  && d->has_changes())
12580  {
12581  // But if two diff nodes are redundant sibbling that carry
12582  // changes of base types, do not mark them as being
12583  // redundant. This is to avoid marking nodes as redundant
12584  // in this case:
12585  //
12586  // int foo(int a, int b);
12587  // compared with:
12588  // float foo(float a, float b); (in C).
12589  //
12590  // In this case, we want to report all the occurences of
12591  // the int->float change because logically, they are at
12592  // the same level in the diff tree.
12593 
12594  bool redundant_with_sibling_node = false;
12595  const diff* p = d->parent_node();
12596 
12597  // If this is a child node of a fn_parm_diff, look through
12598  // the fn_parm_diff node to get the function diff node.
12599  if (p && dynamic_cast<const fn_parm_diff*>(p))
12600  p = p->parent_node();
12601 
12602  if (p)
12603  for (vector<diff*>::const_iterator s =
12604  p->children_nodes().begin();
12605  s != p->children_nodes().end();
12606  ++s)
12607  {
12608  if (*s == d)
12609  continue;
12610  diff* sib = *s;
12611  // If this is a fn_parm_diff, look through the
12612  // fn_parm_diff node to get at the real type node.
12613  if (fn_parm_diff* f = dynamic_cast<fn_parm_diff*>(*s))
12614  sib = f->type_diff().get();
12615  if (sib == d)
12616  continue;
12617  if (sib->get_canonical_diff() == d->get_canonical_diff()
12618  // Sibbling diff nodes that carry base type
12619  // changes ar to be marked as redundant.
12620  && (is_base_diff(sib) || is_distinct_diff(sib)))
12621  {
12622  redundant_with_sibling_node = true;
12623  break;
12624  }
12625  }
12626  if (!redundant_with_sibling_node
12627  // Changes to basic types should never be considered
12628  // redundant. For instance, if a member of integer
12629  // type is changed into a char type in both a struct A
12630  // and a struct B, we want to see both changes.
12632  // The same goes for distinct type changes
12634  // Functions with similar *local* changes are never marked
12635  // redundant because otherwise one could miss important
12636  // similar local changes that are applied to different
12637  // functions.
12639  // Changes involving variadic parameters of functions
12640  // should never be marked redundant because we want to see
12641  // them all.
12644  // If the canonical diff itself has been filtered out,
12645  // then this one is not marked redundant, unless the
12646  // canonical diff was already redundant.
12647  && (!d->get_canonical_diff()->is_filtered_out()
12648  || (d->get_canonical_diff()->get_category()
12649  & REDUNDANT_CATEGORY))
12650  // If the *same* diff node (not one that is merely
12651  // equivalent to this one) has already been visited
12652  // the do not mark it as beind redundant. It's only
12653  // the other nodes that are equivalent to this one
12654  // that must be marked redundant.
12655  && d->context()->diff_has_been_visited(d) != d
12656  // If the diff node is a function parameter and is not
12657  // a reference/pointer (to a non basic or a non
12658  // distinct type diff) then do not mark it as
12659  // redundant.
12660  //
12661  // Children nodes of base class diff nodes are never
12662  // redundant either, we want to see them all.
12665  && !is_child_node_of_base_diff(d))))
12666  {
12668  // As we said in preamble, as this node is marked as
12669  // being redundant, let's not visit its children.
12670  // This is not an optimization; it's needed for
12671  // correctness. In the case of a diff node involving
12672  // a class type that refers to himself, visiting the
12673  // children nodes might cause them to be wrongly
12674  // marked as redundant.
12677  skip_children_nodes_ = true;
12678  }
12679  }
12680  }
12681  else
12682  {
12683  // If the node is not to be reported, do not look at it children.
12685  skip_children_nodes_ = true;
12686  }
12687  }
12688 
12689  virtual void
12690  visit_begin(corpus_diff*)
12691  {
12692  }
12693 
12694  virtual void
12695  visit_end(diff* d)
12696  {
12697  if (skip_children_nodes_)
12698  // When visiting this node, we decided to skip its children
12699  // node. Now that we are done visiting the node, lets stop
12700  // avoiding the children nodes visiting for the other tree
12701  // nodes.
12702  {
12704  skip_children_nodes_ = false;
12705  }
12706  else
12707  {
12708  // Propagate the redundancy categorization of the children nodes
12709  // to this node. But if this node has local changes, then it
12710  // doesn't inherit redundancy from its children nodes.
12711  if (!(d->get_category() & REDUNDANT_CATEGORY)
12712  && (!d->has_local_changes_to_be_reported()
12713  // By default, pointer, reference and qualified types
12714  // consider that a local changes to their underlying
12715  // type is always a local change for themselves.
12716  //
12717  // This is as if those types don't have local changes
12718  // in the same sense as other types. So we always
12719  // propagate redundancy to them, regardless of if they
12720  // have local changes or not.
12721  //
12722  // We also propagate redundancy to typedef types if
12723  // these /only/ carry changes to their underlying
12724  // type.
12725  //
12726  // Note that changes to the underlying type of a
12727  // typedef is considered local of
12728  // LOCAL_TYPE_CHANGE_KIND kind. The other changes to the
12729  // typedef itself are considered local of
12730  // LOCAL_NON_TYPE_CHANGE_KIND kind.
12731  || is_pointer_diff(d)
12733  // A typedef with local non-type changes should not
12734  // see redundancy propagation from its underlying
12735  // type, otherwise, the non-type change might be
12736  // "suppressed" away.
12737  || (is_typedef_diff(d)
12738  && (!(d->has_local_changes()
12740  // A (member) variable with non-type local changes
12741  // should not see redundacy propagation from its type.
12742  // If redundant local-type changes are carried by its
12743  // type however, then that redundancy is propagated to
12744  // the variable. This is key to keep the redundancy
12745  // consistency in the system; otherwise, a type change
12746  // would be rightfully considered redundant at some
12747  // places but not at others.
12748  || (is_var_diff(d)
12749  && (!(d->has_local_changes()
12751  // A function parameter with non-type local changes
12752  // should not see redundancy propagation either. But
12753  // a function parameter with local type changes can
12754  // definitely be redundant.
12755  || (is_fn_parm_diff(d)
12756  && (!(d->has_local_changes()
12758  ))
12759  {
12760  bool has_non_redundant_child = false;
12761  bool has_non_empty_child = false;
12762  for (vector<diff*>::const_iterator i =
12763  d->children_nodes().begin();
12764  i != d->children_nodes().end();
12765  ++i)
12766  {
12767  if ((*i)->has_changes())
12768  {
12769  has_non_empty_child = true;
12770  // Let's see if the current child node '*i' is
12771  // "non-redundant".
12772  //
12773  // A non-redundant node would be a node that
12774  // carries a change to be reported and has not
12775  // been marked as being redundant.
12776  if ((*i)->to_be_reported()
12777  && ((*i)->get_category() & REDUNDANT_CATEGORY) == 0)
12778  has_non_redundant_child = true;
12779  }
12780  if (has_non_redundant_child)
12781  break;
12782  }
12783 
12784  // A diff node for which at least a child node carries a
12785  // change, and for which all the children are redundant is
12786  // deemed redundant too, unless it has local changes.
12787  if (has_non_empty_child
12788  && !has_non_redundant_child)
12789  d->add_to_category(REDUNDANT_CATEGORY);
12790  }
12791  }
12792  }
12793 
12794  virtual void
12795  visit_end(corpus_diff*)
12796  {
12797  }
12798 
12799  virtual bool
12800  visit(diff*, bool)
12801  {return true;}
12802 
12803  virtual bool
12804  visit(corpus_diff*, bool)
12805  {
12806  return true;
12807  }
12808 };// end struct redundancy_marking_visitor
12809 
12810 /// A visitor of @ref diff nodes that clears the REDUNDANT_CATEGORY
12811 /// category out of the nodes.
12812 struct redundancy_clearing_visitor : public diff_node_visitor
12813 {
12814  bool
12815  visit(corpus_diff*, bool)
12816  {return true;}
12817 
12818  bool
12819  visit(diff* d, bool)
12820  {
12821  // clear the REDUNDANT_CATEGORY out of the current node.
12822  diff_category c = d->get_category();
12823  c &= ~REDUNDANT_CATEGORY;
12824  d->set_category(c);
12825  return true;
12826  }
12827 }; // end struct redundancy_clearing_visitor
12828 
12829 /// Walk a given @ref diff sub-tree to categorize each of the nodes
12830 /// with respect to the REDUNDANT_CATEGORY.
12831 ///
12832 /// @param diff_tree the @ref diff sub-tree to walk.
12833 void
12835 {
12836  if (diff_tree->context()->show_redundant_changes())
12837  return;
12838  redundancy_marking_visitor v;
12839  bool s = diff_tree->context()->visiting_a_node_twice_is_forbidden();
12840  diff_tree->context()->forbid_visiting_a_node_twice(false);
12841  diff_tree->traverse(v);
12842  diff_tree->context()->forbid_visiting_a_node_twice(s);
12843 }
12844 
12845 /// Walk a given @ref diff sub-tree to categorize each of the nodes
12846 /// with respect to the REDUNDANT_CATEGORY.
12847 ///
12848 /// @param diff_tree the @ref diff sub-tree to walk.
12849 void
12851 {categorize_redundancy(diff_tree.get());}
12852 
12853 /// Walk a given @ref corpus_diff tree to categorize each of the nodes
12854 /// with respect to the REDUNDANT_CATEGORY.
12855 ///
12856 /// @param diff_tree the @ref corpus_diff tree to walk.
12857 void
12859 {
12860  redundancy_marking_visitor v;
12861  diff_tree->context()->forget_visited_diffs();
12862  bool s = diff_tree->context()->visiting_a_node_twice_is_forbidden();
12863  diff_tree->context()->forbid_visiting_a_node_twice(false);
12864  diff_tree->traverse(v);
12865  diff_tree->context()->forbid_visiting_a_node_twice(s);
12866 }
12867 
12868 /// Walk a given @ref corpus_diff tree to categorize each of the nodes
12869 /// with respect to the REDUNDANT_CATEGORY.
12870 ///
12871 /// @param diff_tree the @ref corpus_diff tree to walk.
12872 void
12874 {categorize_redundancy(diff_tree.get());}
12875 
12876 // </redundancy_marking_visitor>
12877 
12878 /// Walk a given @ref diff sub-tree to clear the REDUNDANT_CATEGORY
12879 /// out of the category of the nodes.
12880 ///
12881 /// @param diff_tree the @ref diff sub-tree to walk.
12882 void
12884 {
12885  redundancy_clearing_visitor v;
12886  bool s = diff_tree->context()->visiting_a_node_twice_is_forbidden();
12887  diff_tree->context()->forbid_visiting_a_node_twice(false);
12888  diff_tree->traverse(v);
12889  diff_tree->context()->forbid_visiting_a_node_twice(s);
12890  diff_tree->context()->forget_visited_diffs();
12891 }
12892 
12893 /// Walk a given @ref diff sub-tree to clear the REDUNDANT_CATEGORY
12894 /// out of the category of the nodes.
12895 ///
12896 /// @param diff_tree the @ref diff sub-tree to walk.
12897 void
12899 {clear_redundancy_categorization(diff_tree.get());}
12900 
12901 /// Walk a given @ref corpus_diff tree to clear the REDUNDANT_CATEGORY
12902 /// out of the category of the nodes.
12903 ///
12904 /// @param diff_tree the @ref corpus_diff tree to walk.
12905 void
12907 {
12908  redundancy_clearing_visitor v;
12909  bool s = diff_tree->context()->visiting_a_node_twice_is_forbidden();
12910  diff_tree->context()->forbid_visiting_a_node_twice(false);
12911  diff_tree->traverse(v);
12912  diff_tree->context()->forbid_visiting_a_node_twice(s);
12913  diff_tree->context()->forget_visited_diffs();
12914 }
12915 
12916 /// Walk a given @ref corpus_diff tree to clear the REDUNDANT_CATEGORY
12917 /// out of the category of the nodes.
12918 ///
12919 /// @param diff_tree the @ref corpus_diff tree to walk.
12920 void
12922 {clear_redundancy_categorization(diff_tree.get());}
12923 
12924 /// Apply the @ref diff tree filters that have been associated to the
12925 /// context of the a given @ref corpus_diff tree. As a result, the
12926 /// nodes of the @diff tree are going to be categorized into one of
12927 /// several of the categories of @ref diff_category.
12928 ///
12929 /// @param diff_tree the @ref corpus_diff instance which @ref diff are
12930 /// to be categorized.
12931 void
12933 {
12934  diff_tree->context()->maybe_apply_filters(diff_tree);
12935  propagate_categories(diff_tree);
12936 }
12937 
12938 /// Test if a diff node represents the difference between a variadic
12939 /// parameter type and something else.
12940 ///
12941 /// @param d the diff node to consider.
12942 ///
12943 /// @return true iff @p d is a diff node that represents the
12944 /// difference between a variadic parameter type and something else.
12945 bool
12947 {
12948  if (!d)
12949  return false;
12950 
12951  type_base_sptr t = is_type(d->first_subject());
12952  if (t && t->get_environment().is_variadic_parameter_type(t))
12953  return true;
12954 
12955  t = is_type(d->second_subject());
12956  if (t && t->get_environment().is_variadic_parameter_type(t))
12957  return true;
12958 
12959  return false;
12960 }
12961 
12962 /// Test if a diff node represents the difference between a variadic
12963 /// parameter type and something else.
12964 ///
12965 /// @param d the diff node to consider.
12966 ///
12967 /// @return true iff @p d is a diff node that represents the
12968 /// difference between a variadic parameter type and something else.
12969 bool
12971 {return is_diff_of_variadic_parameter_type(d.get());}
12972 
12973 /// Test if a diff node represents the difference between a variadic
12974 /// parameter and something else.
12975 ///
12976 /// @param d the diff node to consider.
12977 ///
12978 /// @return true iff @p d is a diff node that represents the
12979 /// difference between a variadic parameter and something else.
12980 bool
12982 {
12983  fn_parm_diff* diff =
12984  dynamic_cast<fn_parm_diff*>(const_cast<abigail::comparison::diff*>(d));
12985  return (diff && is_diff_of_variadic_parameter_type(diff->type_diff()));
12986 }
12987 
12988 /// Test if a diff node represents the difference between a variadic
12989 /// parameter and something else.
12990 ///
12991 /// @param d the diff node to consider.
12992 ///
12993 /// @return true iff @p d is a diff node that represents the
12994 /// difference between a variadic parameter and something else.
12995 bool
12997 {return is_diff_of_variadic_parameter(d.get());}
12998 
12999 /// Test if a diff node represents a diff between two basic types.
13000 ///
13001 /// @param d the diff node to consider.
13002 ///
13003 /// @return true iff @p d is a diff between two basic types.
13004 const type_decl_diff*
13006 {return dynamic_cast<const type_decl_diff*>(d);}
13007 
13008 /// Test if a diff node represents a diff between two basic types, or
13009 /// between pointers, references or qualified type to basic types.
13010 ///
13011 /// @param diff the diff node to consider.
13012 ///
13013 /// @param allow_indirect_type if true, then this function looks into
13014 /// pointer, reference or qualified diff types to see if they "point
13015 /// to" basic types.
13016 ///
13017 /// @return true iff @p d is a diff between two basic types.
13018 const type_decl_diff*
13019 is_diff_of_basic_type(const diff* diff, bool allow_indirect_type)
13020 {
13021  if (allow_indirect_type)
13023  return is_diff_of_basic_type(diff);
13024 }
13025 
13026 /// If a diff node is about changes between two typedef types, get the
13027 /// diff node about changes between the underlying types.
13028 ///
13029 /// Note that this function walks the tree of underlying diff nodes
13030 /// returns the first diff node about types that are not typedefs.
13031 ///
13032 /// @param dif the dif node to consider.
13033 ///
13034 /// @return the underlying diff node of @p dif, or just return @p dif
13035 /// if it's not a typedef diff node.
13036 const diff*
13038 {
13039  const typedef_diff *d = 0;
13040  while ((d = is_typedef_diff(dif)))
13041  dif = d->underlying_type_diff().get();
13042  return dif;
13043 }
13044 
13045 /// If a diff node is about changes between two pointer types, get the
13046 /// diff node about changes between the underlying (pointed-to) types.
13047 ///
13048 /// Note that this function walks the tree of underlying diff nodes
13049 /// returns the first diff node about types that are not pointers.
13050 ///
13051 /// @param dif the dif node to consider.
13052 ///
13053 /// @return the underlying diff node of @p dif, or just return @p dif
13054 /// if it's not a pointer diff node.
13055 const diff*
13057 {
13058  const pointer_diff *d = 0;
13059  while ((d = is_pointer_diff(dif)))
13060  dif = d->underlying_type_diff().get();
13061  return dif;
13062 }
13063 
13064 /// If a diff node is about changes between two reference types, get
13065 /// the diff node about changes between the underlying (pointed-to)
13066 /// types.
13067 ///
13068 /// Note that this function walks the tree of underlying diff nodes
13069 /// returns the first diff node about types that are not references.
13070 ///
13071 /// @param dif the dif node to consider.
13072 ///
13073 /// @return the underlying diff node of @p dif, or just return @p dif
13074 /// if it's not a reference diff node.
13075 const diff*
13077 {
13078  const reference_diff *d = 0;
13079  while ((d = is_reference_diff(dif)))
13080  dif = d->underlying_type_diff().get();
13081  return dif;
13082 }
13083 
13084 /// If a diff node is about changes between two qualified types, get
13085 /// the diff node about changes between the underlying (non-qualified)
13086 /// types.
13087 ///
13088 /// Note that this function walks the tree of underlying diff nodes
13089 /// returns the first diff node about types that are not qualified.
13090 ///
13091 /// @param dif the dif node to consider.
13092 ///
13093 /// @return the underlying diff node of @p dif, or just return @p dif
13094 /// if it's not a qualified diff node.
13095 const diff*
13097 {
13098  const qualified_type_diff *d = 0;
13099  while ((d = is_qualified_type_diff(dif)))
13100  dif = d->underlying_type_diff().get();
13101  return dif;
13102 }
13103 
13104 /// If a diff node is about changes between two function parameters
13105 /// get the diff node about changes between the types of the parameters.
13106 ///
13107 /// @param dif the dif node to consider.
13108 ///
13109 /// @return the diff of the types of the parameters.
13110 const diff*
13112 {
13113  const fn_parm_diff *d = 0;
13114  while ((d = is_fn_parm_diff(dif)))
13115  dif = d->type_diff().get();
13116  return dif;
13117 }
13118 
13119 /// If a diff node is about changes between two pointer, reference or
13120 /// qualified types, get the diff node about changes between the
13121 /// underlying types.
13122 ///
13123 /// Note that this function walks the tree of underlying diff nodes
13124 /// returns the first diff node about types that are not pointer,
13125 /// reference or qualified.
13126 ///
13127 /// @param dif the dif node to consider.
13128 ///
13129 /// @return the underlying diff node of @p dif, or just return @p dif
13130 /// if it's not a pointer, reference or qualified diff node.
13131 const diff*
13133 {
13134  while (true)
13135  {
13136  if (const pointer_diff *d = is_pointer_diff(dif))
13137  dif = peel_pointer_diff(d);
13138  else if (const reference_diff *d = is_reference_diff(dif))
13139  dif = peel_reference_diff(d);
13140  else if (const qualified_type_diff *d = is_qualified_type_diff(dif))
13141  dif = peel_qualified_diff(d);
13142  else
13143  break;
13144  }
13145  return dif;
13146 }
13147 
13148 /// If a diff node is about changes between two typedefs or qualified
13149 /// types, get the diff node about changes between the underlying
13150 /// types.
13151 ///
13152 /// Note that this function walks the tree of underlying diff nodes
13153 /// returns the first diff node about types that are not typedef or
13154 /// qualified types.
13155 ///
13156 /// @param dif the dif node to consider.
13157 ///
13158 /// @return the underlying diff node of @p dif, or just return @p dif
13159 /// if it's not typedef or qualified diff node.
13160 const diff*
13162 {
13163  while (true)
13164  {
13165  if (const typedef_diff *d = is_typedef_diff(dif))
13166  dif = peel_typedef_diff(d);
13167  else if (const qualified_type_diff *d = is_qualified_type_diff(dif))
13168  dif = peel_qualified_diff(d);
13169  else
13170  break;
13171  }
13172  return dif;
13173 }
13174 
13175 /// If a diff node is about changes between two typedefs or qualified
13176 /// types, get the diff node about changes between the underlying
13177 /// types.
13178 ///
13179 /// Note that this function walks the tree of underlying diff nodes
13180 /// returns the first diff node about types that are neither typedef,
13181 /// qualified type nor parameters.
13182 ///
13183 /// @param dif the dif node to consider.
13184 ///
13185 /// @return the diff node about changes between the underlying types.
13186 const diff*
13188 {
13189  while (true)
13190  {
13191  if (const typedef_diff *d = is_typedef_diff(dif))
13192  dif = peel_typedef_diff(d);
13193  else if (const qualified_type_diff *d = is_qualified_type_diff(dif))
13194  dif = peel_qualified_diff(d);
13195  else if (const fn_parm_diff *d = is_fn_parm_diff(dif))
13196  dif = peel_fn_parm_diff(d);
13197  else
13198  break;
13199  }
13200  return dif;
13201 }
13202 
13203 /// Test if a diff node represents a diff between two class or union
13204 /// types.
13205 ///
13206 /// @param d the diff node to consider.
13207 ///
13208 /// @return iff @p is a diff between two class or union types then
13209 /// return the instance of @ref class_or_union_diff that @p derives
13210 /// from. Otherwise, return nil.
13211 const class_or_union_diff*
13213 {return dynamic_cast<const class_or_union_diff*>(d);}
13214 
13215 /// Test if a given diff node carries *only* a local type change.
13216 ///
13217 /// @param d the diff node to consider.
13218 ///
13219 /// @return true iff @p has a change and that change is a local type
13220 /// change.
13221 static bool
13222 has_local_type_change_only(const diff *d)
13223 {
13224  if (enum change_kind k = d->has_local_changes())
13225  if ((k & LOCAL_NON_TYPE_CHANGE_KIND) == 0
13226  && (k & LOCAL_TYPE_CHANGE_KIND) != 0)
13227  return true;
13228 
13229  return false;
13230 }
13231 
13232 /// Test if a diff node is a decl diff that only carries a basic type
13233 /// change on its type diff sub-node.
13234 ///
13235 ///Note that that pointers/references/qualified types diffs to basic
13236 /// type diffs are considered as having basic type change only.
13237 ///
13238 /// @param d the diff node to consider.
13239 ///
13240 /// @return true iff @p d is a decl diff that only carries a basic
13241 /// type change on its type diff sub-node.
13242 bool
13244 {
13246 
13247  if (is_diff_of_basic_type(d, true) && d->has_changes())
13248  return true;
13249  else if (const var_diff * v = dynamic_cast<const var_diff*>(d))
13250  return (has_local_type_change_only(v)
13251  && is_diff_of_basic_type(v->type_diff().get(), true));
13252  else if (const fn_parm_diff * p = dynamic_cast<const fn_parm_diff*>(d))
13253  return (has_local_type_change_only(p)
13254  && is_diff_of_basic_type(p->type_diff().get(), true));
13255  else if (const function_decl_diff* f =
13256  dynamic_cast<const function_decl_diff*>(d))
13257  return (has_local_type_change_only(f)
13258  && f->type_diff()
13259  && is_diff_of_basic_type(f->type_diff()->return_type_diff().get(),
13260  true));
13261  return false;
13262 }
13263 }// end namespace comparison
13264 } // end namespace abigail
The private data and functions of the abigail::ir::comparison types.
#define SKIP_MEM_FN_IF_VIRTUALITY_DISALLOWED
Skip the processing of the current member function if its virtual-ness is disallowed by the user.
#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:1589
#define ABG_ASSERT_NOT_REACHED
A macro that expands to aborting the program when executed.
The abstraction of a diff between two arrays.
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 diff base type sub-object of this instance of array_diff.
const diff_sptr & element_type_diff() const
Getter for the diff between the two types of array elements.
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 array_type_def_sptr second_array() const
Getter for the second array of the diff.
const array_type_def_sptr first_array() const
Getter for the first array of the diff.
virtual enum change_kind has_local_changes() const
virtual const string & get_pretty_representation() const
virtual void report(ostream &, const string &indent="") const
Report the diff in a serialized form.
An abstraction of a diff between two instances of class_decl::base_spec.
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 diff base type sub-object of this instance of base_diff.
void set_underlying_class_diff(class_diff_sptr d)
Setter for the diff object for the diff of the underlyng base classes.
class_decl::base_spec_sptr second_base() const
Getter for the second base spec of the diff object.
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())
const class_diff_sptr get_underlying_class_diff() const
Getter for the diff object for the diff of the underlying base classes.
class_decl::base_spec_sptr first_base() const
Getter for the first base spec of the diff object.
virtual enum change_kind has_local_changes() const
virtual const string & get_pretty_representation() const
virtual void report(ostream &, const string &indent="") const
Generates a report for the current instance of base_diff.
This type abstracts changes for a class_decl.
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 diff base type sub-object of this instance of class_diff.
class_decl_sptr first_class_decl() const
const base_diff_sptrs_type & changed_bases()
Getter for the changed base classes of the 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_base_sptr_map & inserted_bases() const
Getter for the inserted base classes of the diff.
const string_base_sptr_map & deleted_bases() const
Getter for the deleted base classes of the diff.
virtual enum change_kind has_local_changes() const
const edit_script & base_changes() const
virtual const string & get_pretty_representation() const
class_diff(class_decl_sptr first_scope, class_decl_sptr second_scope, diff_context_sptr ctxt=diff_context_sptr())
Constructor of class_diff.
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.
class_decl_sptr second_class_decl() const
Getter of the second class involved in the diff.
virtual void report(ostream &, const string &indent="") const
Produce a basic report about the changes between two class_decl.
This is the base class of class_diff and union_diff.
virtual bool has_changes() const
Test if the current diff node carries a change.
const edit_script & member_fn_tmpls_changes() const
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 class_or_union_diff::priv_ptr & get_priv() const
Getter of the private data of the class_or_union_diff type.
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_class_tmpls_changes() const
void allocate_priv_data()
Allocate the memory for the priv_ pimpl data member of the class_or_union_diff class.
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 edit_script & member_types_changes() const
const string_member_function_sptr_map & deleted_member_fns() const
class_or_union_sptr first_class_or_union() const
const var_diff_sptrs_type & sorted_subtype_changed_data_members() const
Getter of the sorted vector of data members with a (sub-)type change.
bool lookup_tables_empty(void) const
Tests if the lookup tables are empty.
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.
void clear_lookup_tables(void)
Clear the lookup tables useful for reporting.
const string_decl_base_sptr_map & deleted_data_members() const
Getter for the data members that got deleted.
virtual ~class_or_union_diff()
Destructor of class_or_union_diff.
const string_decl_base_sptr_map & inserted_data_members() const
Getter for the data members that got inserted.
void ensure_lookup_tables_populated(void) const
If the lookup tables are not yet built, walk the differences and fill them.
const string_member_function_sptr_map & inserted_member_fns() const
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...
const edit_script & data_members_changes() const
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.
virtual enum change_kind has_local_changes() const
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.
const edit_script & member_fns_changes() const
class_or_union_sptr second_class_or_union() const
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.
virtual void report(ostream &, const string &indent="") const
Report the changes carried by the current class_or_union_diff node in a textual format.
This is a document class that aims to capture statistics about the changes carried by a corpus_diff t...
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 ...
size_t num_func_removed() const
Getter for the number of functions removed.
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...
size_t num_vars_changed() const
Getter for the number of variables that have a change in one of their sub-types.
size_t net_num_leaf_var_changes() const
Getter for the net number of leaf variable change diff nodes.
size_t num_vars_added() const
Getter for the number of variables added.
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...
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...
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...
size_t num_removed_vars_filtered_out() const
Getter for the number removed variables that have been filtered out.
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...
size_t net_num_vars_removed() const
Getter for the net number of removed variables.
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...
size_t num_removed_var_syms_filtered_out() const
Getter for the number of removed variable symbols, not referenced by any debug info,...
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.
size_t num_added_var_syms_filtered_out() const
Getter for the number of added variable symbols, not referenced by any debug info,...
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.
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.
size_t num_var_syms_added() const
Getter for the number of variable symbols (not referenced by any debug info) that got added.
size_t num_leaf_var_changes() const
Getter for the number of leaf variable change diff nodes.
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.
size_t net_num_func_removed() const
Getter for the net number of function removed.
size_t net_num_func_added() const
Getter for the net number of added functions.
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...
size_t net_num_leaf_changes() const
Getter of the net number of leaf change diff nodes.
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...
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...
size_t num_added_func_filtered_out() const
Getter for the number of added function that have been filtered out.
size_t num_func_syms_added() const
Getter for the number of function symbols (not referenced by any debug info) that got added.
size_t net_num_leaf_type_changes() const
Getter for the net number of leaf type change diff nodes.
size_t num_func_added() const
Getter for the number of functions added.
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.
size_t num_leaf_type_changes() const
Getter for the number of leaf type change diff nodes.
size_t num_leaf_var_changes_filtered_out() const
Getter for the number of leaf variable changes diff nodes that have been filtered out.
size_t num_added_vars_filtered_out() const
Getter for the number of added variables that have been filtered out.
size_t num_func_with_virtual_offset_changes() const
Getter for the number of functions that carry virtual member offset changes.
size_t num_func_changed() const
Getter for the number of functions that have a change in one of their sub-types.
size_t num_removed_func_filtered_out() const
Getter for the number of removed functions that have been filtered out.
size_t net_num_vars_added() const
Getter for the net number of added variables.
size_t num_leaf_changes() const
Getter of the number of leaf type change diff nodes.
size_t num_leaf_func_changes_filtered_out() const
Getter for the number of leaf function change diff nodes that were filtered out.
size_t num_added_func_syms_filtered_out() const
Getter for the number of added function symbols, not referenced by any debug info,...
size_t num_leaf_type_changes_filtered_out() const
Getter for the number of filtered out leaf type change diff nodes.
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...
size_t net_num_leaf_func_changes() const
Getter for the net number of leaf function change diff nodes.
size_t num_leaf_func_changes() const
Getter for the number of leaf function change diff nodes.
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*...
size_t num_func_syms_removed() const
Getter for the number of function symbols (not referenced by any debug info) that got removed.
size_t num_leaf_changes_filtered_out() const
Getter of the number of leaf type change diff nodes that have been filtered out.
size_t num_vars_removed() const
Getter for the number of variables removed.
size_t num_var_syms_removed() const
Getter for the number of variable symbols (not referenced by any debug info) that got removed.
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...
An abstraction of a diff between between two abi corpus.
bool has_incompatible_changes() const
Test if the current instance of corpus_diff carries changes that we are sure are incompatible....
bool has_changes() const
Return true iff the current corpus_diff node carries a change.
void finish_diff_type()
Finish building the current instance of corpus_diff.
virtual void chain_into_hierarchy()
Populate the vector of children node of the corpus_diff type.
const string_var_ptr_map & deleted_variables() const
Getter for the variables that got deleted from the first subject of the 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.
bool soname_changed() const
Test if the soname of the underlying corpus has changed.
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.
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.
edit_script & function_changes() const
edit_script & variable_changes() const
const vector< diff * > & children_nodes() const
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 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...
const string_elf_symbol_map & deleted_unrefed_function_symbols() const
Getter for function symbols not referenced by any debug info and that got deleted.
const string_elf_symbol_map & deleted_unrefed_variable_symbols() const
Getter for variable symbols not referenced by any debug info and that got deleted.
corpus_diff(corpus_sptr first, corpus_sptr second, diff_context_sptr ctxt=diff_context_sptr())
Constructor for corpus_diff.
bool do_log() const
Test if logging was requested.
const string_elf_symbol_map & added_unrefed_function_symbols() const
Getter for function symbols not referenced by any debug info and that got added.
bool has_net_subtype_changes() const
Test if the current instance of corpus_diff carries subtype changes whose reports are not suppressed ...
const string_var_ptr_map & added_variables() const
Getter for the added variables of the diff.
diff_maps & get_leaf_diffs()
Get the set of maps that contain leaf nodes. A leaf node being a node with a local change.
const diff_context_sptr context() const
Getter of the diff context of this diff.
bool has_net_changes() const
Test if the current instance of corpus_diff carries changes whose reports are not suppressed by any s...
virtual bool traverse(diff_node_visitor &v)
Traverse the diff sub-tree under the current instance corpus_diff.
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...
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...
const string_function_ptr_map & added_functions()
Getter for the added functions of the diff.
void mark_leaf_diff_nodes()
Walks the diff nodes associated to the current corpus diff and mark those that carry local changes....
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 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.
virtual void report(ostream &out, const string &indent="") const
Report the diff in a serialized form.
const string_elf_symbol_map & added_unrefed_variable_symbols() const
Getter for variable symbols not referenced by any debug info and that got added.
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...
const string & get_pretty_representation() const
const string_function_ptr_map & deleted_functions() const
Getter for the deleted functions 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.
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...
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.
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...
bool architecture_changed() const
Test if the architecture of the underlying corpus has changed.
The base class of diff between decls.
decl_diff_base(decl_base_sptr first_subject, decl_base_sptr second_subject, diff_context_sptr ctxt)
Constructor of decl_diff_base.
The default, initial, reporter of the libabigail comparison engine.
Definition: abg-reporter.h:154
The context of the diff. This type holds various bits of information that is going to be used through...
void add_suppressions(const suppr::suppressions_type &supprs)
Add new suppression specifications that specify which diff node reports should be dropped on the floo...
diff_category get_allowed_category() const
Getter for the bitmap that represents the set of categories that the user wants to see reported.
void forget_visited_diffs()
Unmark all the diff nodes that were marked as being traversed.
corpus_sptr get_first_corpus() const
Getter for the first corpus of the corpus diff of the current context.
bool show_architecture_change() const
Getter for the property that says if the comparison module should show the architecture changes in it...
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,...
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 initialize_canonical_diff(const diff_sptr diff)
Set the canonical diff node property of a given diff node appropriately.
bool show_redundant_changes() const
A getter for the flag that says if we should report about functions or variables diff nodes that have...
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 ...
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...
diff * diff_has_been_visited(const diff *) const
Test if a diff node has been traversed.
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 ...
void set_corpus_diff(const corpus_diff_sptr &)
Set the corpus diff relevant to this context.
bool show_leaf_changes_only() const
Get the flag that indicates if the diff using this context should show only leaf changes or not.
bool perform_change_categorization() const
Test if it's requested to perform diff node categorization.
bool show_impacted_interfaces() const
Getter of the flag that indicates if the leaf reporter should display a summary of the interfaces imp...
bool show_soname_change() const
Getter for the property that says if the comparison module should show the soname changes in its repo...
reporter_base_sptr get_reporter() const
Getter of the reporter to be used in this context.
void add_diff_filter(filtering::filter_base_sptr)
Setter for the diff filters to apply to a given diff sub-tree.
bool do_log() const
Test if logging was requested.
const suppr::suppressions_type & direct_suppressions() const
Getter of the direct suppression specification (those that are not negated) comprised in the general ...
void maybe_apply_filters(diff_sptr diff)
Apply the diff filters to a given diff sub-tree.
const suppr::suppressions_type & suppressions() const
Getter for the vector of suppressions that specify which diff node reports should be dropped on the f...
bool show_relative_offset_changes(void)
Get the flag saying if offset changes should be reported in a relative way. That is,...
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 ...
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,...
const suppr::suppressions_type & negated_suppressions() const
Getter of the negated suppression specifications that are comprised in the general vector of suppress...
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...
bool show_hex_values() const
Get the flag that indicates if the diff reports using this context should show sizes and offsets in a...
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 show_stats_only() const
Test if the comparison module should only show the diff stats.
const filtering::filters & diff_filters() const
Getter for the diff tree nodes filters to apply to diff sub-trees.
bool show_unreachable_types()
Getter for the flag that indicates if changes on types unreachable from global functions and variable...
const corpus_diff_sptr & get_corpus_diff() const
Get the corpus diff for the current context.
void mark_diff_as_visited(const diff *)
Mark a diff node as traversed by a traversing algorithm.
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.
void switch_categories_on(diff_category c)
Setter for the bitmap that represents the set of categories that the user wants to see reported.
ostream * default_output_stream()
Getter for the default output stream used by code of the comparison engine. By default the default ou...
bool dump_diff_tree() const
Test if the comparison engine should dump the diff tree for the changed functions and variables it ha...
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...
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...
corpus_sptr get_second_corpus() const
Getter for the second corpus of the corpus diff of the current context.
void set_allowed_category(diff_category c)
Setter for the bitmap that represents the set of categories that the user wants to see reported.
void set_reporter(reporter_base_sptr &)
Setter of the reporter to be used in this context.
ostream * error_output_stream() const
Getter for the errror output stream used by code of the comparison engine. By default the error outpu...
This type contains maps. Each map associates a type name to a diff of that type. Not all kinds of dif...
const string_diff_ptr_map & get_function_decl_diff_map() const
Getter of the map that contains function decl diffs.
const string_diff_ptr_map & get_var_decl_diff_map() const
Getter of the map that contains var decl diffs.
const string_diff_ptr_map & get_enum_diff_map() const
Getter of the map that contains enum type diffs.
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.
diff_maps()
Default constructor of the diff_maps type.
const string_diff_ptr_map & get_union_diff_map() const
Getter of the map that contains union type diffs.
artifact_sptr_set_type * lookup_impacted_interfaces(const diff *d) const
Lookup the interfaces that are impacted by a given leaf diff node.
const string_diff_ptr_map & get_function_type_diff_map() const
Getter of the map that contains function type diffs.
const string_diff_ptr_map & get_typedef_diff_map() const
Getter of the map that contains typedef type diffs.
const string_diff_ptr_map & get_distinct_diff_map() const
Getter of the map that contains distinct diffs.
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_reference_diff_map() const
Getter of the map that contains reference type diffs.
const string_diff_ptr_map & get_array_diff_map() const
Getter of the map that contains array type diffs.
const string_diff_ptr_map & get_type_decl_diff_map() const
Getter of the map that contains basic type diffs.
const string_diff_ptr_map & get_fn_parm_diff_map() const
Getter of the map that contains function parameter diffs.
const string_diff_ptr_map & get_class_diff_map() const
Getter of the map that contains class type diffs.
The base class for the node visitors. These are the types used to visit each node traversed by the di...
void or_visiting_kind(visiting_kind v)
Setter for the visiting policy of the traversing code while invoking this visitor....
virtual bool visit(diff *, bool)
Default visitor implementation.
virtual bool visit(distinct_diff *, bool)
Default visitor implementation.
virtual void visit_end(corpus_diff *)
This is called by the traversing code on a corpus_diff node just after visiting it....
void set_current_topmost_iface_diff(diff *)
Setter of the diff current topmost interface which is impacted by the current diff node being visited...
virtual void visit_begin(diff *)
This is called by the traversing code on a diff node just before visiting it. That is,...
visiting_kind get_visiting_kind() const
Getter for the visiting policy of the traversing code while invoking this visitor.
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...
diff_node_visitor()
Default constructor of the diff_node_visitor type.
void set_visiting_kind(visiting_kind v)
Setter for the visiting policy of the traversing code while invoking this visitor.
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 bool traverse(diff_node_visitor &v)
The default traverse function.
The abstraction of a change between two ABI artifacts, a.k.a an artifact change.
void begin_traversing()
Flag a given diff node as being traversed.
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 finish_diff_type()
Finish the insertion of a diff tree node into the diff graph.
virtual void chain_into_hierarchy()
This constructs the relation between this diff node and its detail diff nodes, in the generic view of...
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 ...
type_or_decl_base_sptr second_subject() const
Getter of the second subject of the diff.
bool is_traversing() const
Tell if a given node is being traversed or not.
type_or_decl_base_sptr first_subject() const
Getter of the first subject of the diff.
bool is_suppressed() const
Test if the current diff node has been suppressed by a user-provided suppression specification.
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...
diff * get_canonical_diff() const
Getter for the canonical diff of the current instance of diff.
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...
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...
const vector< diff * > & children_nodes() const
Getter for the children nodes of the current diff node.
diff_category get_category() const
Getter for the category of the current diff tree node.
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...
diff_category remove_from_local_category(diff_category c)
Remove the current diff tree node from the categories resulting from the local changes.
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...
bool do_log() const
Test if logging was requested.
diff_category get_local_category() const
Getter for the local category of the current diff tree node.
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 ...
const diff_context_sptr context() const
Getter of the context of the current diff.
virtual enum change_kind has_local_changes() const =0
Pure interface to know if the current instance of @diff carries a local change. A local change is a c...
virtual bool traverse(diff_node_visitor &v)
The generic traversing code that walks a given diff sub-tree.
bool currently_reporting() const
Tests if we are currently in the middle of emitting a report for this diff.
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...
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...
bool to_be_reported() const
Test if this diff tree node should be reported.
const diff * parent_node() const
Getter for the parent node of the current diff node.
diff_category get_class_of_equiv_category() const
Getter of the category of the class of equivalence of the current diff tree node.
void set_canonical_diff(diff *)
Setter for the canonical diff of the current instance of diff.
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...
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...
void set_local_category(diff_category c)
Set the local category of the current diff node.
virtual const string & get_pretty_representation() const
Get a pretty representation of the current diff node.
void append_child_node(diff_sptr)
Add a new child node to the vector of children nodes for the current diff node.
bool is_filtered_out() const
Test if this diff tree node is to be filtered out for reporting purposes.
void end_traversing()
Flag a given diff node as not being traversed anymore.
bool reported_once() const
Tests if a report has already been emitted for the current diff.
An abstraction of a diff between entities that are of a different kind (disctinct).
virtual void chain_into_hierarchy()
Populate the vector of children node of the diff base type sub-object of this instance of @distinct_d...
const diff_sptr compatible_child_diff() const
Getter for the child diff of this distinct_diff instance.
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.
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.
virtual void report(ostream &out, const string &indent="") const
Emit a report about the current diff instance.
const type_or_decl_base_sptr first() const
Getter for the first subject of the diff.
virtual enum change_kind has_local_changes() const
virtual const string & get_pretty_representation() const
const type_or_decl_base_sptr second() const
Getter for the second subject of the diff.
Abstraction of a diff between two enums.
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 diff base type sub-object of this instance of enum_diff.
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.
diff_sptr underlying_type_diff() const
const string_changed_enumerator_map & changed_enumerators() const
virtual enum change_kind has_local_changes() const
virtual const string & get_pretty_representation() const
const enum_type_decl_sptr first_enum() const
const string_enumerator_map & deleted_enumerators() const
const enum_type_decl_sptr second_enum() const
const string_enumerator_map & inserted_enumerators() const
virtual void report(ostream &, const string &indent="") const
Report the differences between the two enums.
A filter that walks the diff nodes tree and tags relevant diff nodes into categories considered to re...
Abstraction of a diff between two function parameters.
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 nodes of the diff base type sub-object of this instance of fn_parm_di...
const function_decl::parameter_sptr first_parameter() const
Getter for the first subject of this diff node.
virtual enum change_kind has_local_changes() const
Check if the current diff node carries a local change.
virtual const string & get_pretty_representation() const
Build and return a textual representation of the current instance of fn_parm_diff.
const function_decl::parameter_sptr second_parameter() const
Getter for the second subject of this diff node.
diff_sptr type_diff() const
Getter for the diff representing the changes on the type of the function parameter involved in the cu...
virtual void report(ostream &, const string &indent="") const
Emit a textual report about the current fn_parm_diff instance.
Abstraction of a diff between two function_decl.
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 diff base type sub-object of this instance of function_de...
const function_decl_sptr second_function_decl() const
function_decl_diff(const function_decl_sptr first, const function_decl_sptr second, diff_context_sptr ctxt)
Constructor for function_decl_diff.
virtual enum change_kind has_local_changes() const
const function_decl_sptr first_function_decl() const
virtual const string & get_pretty_representation() const
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 ...
Abstraction of a diff between two function types.
virtual bool has_changes() const
Test if the current diff node carries changes.
virtual void chain_into_hierarchy()
Populate the vector of children node of the diff base type sub-object of this instance of function_ty...
const string_fn_parm_diff_sptr_map & subtype_changed_parms() const
Getter for the map of function parameter changes of the current 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.
const string_parm_map & removed_parms() const
Getter for the map of parameters that got removed.
const string_parm_map & added_parms() const
Getter for the map of parameters that got added.
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< function_decl::parameter_sptr > & sorted_added_parms() const
Getter for the sorted vector of added parameters .
const function_type_sptr first_function_type() const
Getter for the first subject of the diff.
const function_type_sptr second_function_type() const
Getter for the second subject of the diff.
function_type_diff(const function_type_sptr first, const function_type_sptr second, diff_context_sptr ctxt)
Consutrctor of the function_type type.
virtual enum change_kind has_local_changes() const
Test if the current diff node carries local changes.
virtual const string & get_pretty_representation() const
Build and return a copy of a pretty representation of the current instance of function_type_diff.
const vector< function_decl::parameter_sptr > & sorted_deleted_parms() const
Getter for the sorted vector of deleted parameters.
virtual void report(ostream &, const string &indent="") const
Build and emit a textual report about the current function_type_diff instance.
A reporter that only reports leaf changes.
Definition: abg-reporter.h:267
The abstraction of a diff between two pointers.
virtual bool has_changes() const
Return true iff the current diff node carries a change.
const pointer_type_def_sptr first_pointer() const
Getter for the first subject of a pointer diff.
virtual void chain_into_hierarchy()
Populate the vector of children node of the diff base type sub-object of this instance of pointer_dif...
const pointer_type_def_sptr second_pointer() const
Getter for the second subject of a pointer diff.
diff_sptr underlying_type_diff() const
Getter for the diff between the pointed-to types of the pointers of this diff.
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.
virtual enum change_kind has_local_changes() const
virtual const string & get_pretty_representation() const
virtual void report(ostream &, const string &indent="") const
Report the diff in a serialized form.
Abstraction of a diff between two qualified types.
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 diff base type sub-object of this instance of qualified_t...
diff_sptr leaf_underlying_type_diff() const
Getter for the diff between the most underlying non-qualified types of two qualified types.
diff_sptr underlying_type_diff() const
Getter for the diff between the underlying types of the two qualified types.
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.
const qualified_type_def_sptr second_qualified_type() const
Getter for the second qualified type of the diff.
virtual enum change_kind has_local_changes() const
const qualified_type_def_sptr first_qualified_type() const
Getter for the first qualified type of the diff.
virtual const string & get_pretty_representation() const
virtual void report(ostream &, const string &indent="") const
Report the diff in a serialized form.
The abstraction of a diff between two references.
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 diff base type sub-object of this instance of reference_d...
reference_type_def_sptr first_reference() const
Getter for the first reference of the diff.
reference_type_def_sptr second_reference() const
Getter for the second reference of the diff.
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.
virtual enum change_kind has_local_changes() const
virtual const string & get_pretty_representation() const
const diff_sptr & underlying_type_diff() const
Getter for the diff between the two referred-to types.
virtual void report(ostream &, const string &indent="") const
Report the diff in a serialized form.
An abstractions of the changes between two scopes.
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 diff base type sub-object of this instance of scope_diff.
const diff_sptrs_type & changed_types() const
const scope_decl_sptr second_scope() const
Getter for the second scope of the diff.
const scope_decl_sptr first_scope() const
Getter for the first scope of the diff.
const decl_base_sptr deleted_member_at(unsigned index) const
Accessor that eases the manipulation of the edit script associated to this instance....
const diff_sptrs_type & changed_decls() const
scope_diff(scope_decl_sptr first_scope, scope_decl_sptr second_scope, diff_context_sptr ctxt=diff_context_sptr())
Constructor for scope_diff.
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.
const decl_base_sptr inserted_member_at(unsigned i)
Accessor that eases the manipulation of the edit script associated to this instance....
virtual void report(ostream &out, const string &indent="") const
Report the changes of one scope against another.
virtual enum change_kind has_local_changes() const
virtual const string & get_pretty_representation() const
const edit_script & member_changes() const
Accessor of the edit script of the members of a scope.
The abstraction of the diff between two subrange types.
virtual bool has_changes() const
Test if the current subrange_diff node carries any change.
virtual void chain_into_hierarchy()
Populate the vector of children node of the diff base type sub-object of this instance of subrange_di...
const array_type_def::subrange_sptr second_subrange() const
Getter of the second subrange of the current instance subrange_diff.
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.
const array_type_def::subrange_sptr first_subrange() const
Getter of the first subrange of the current instance subrange_diff.
const diff_sptr underlying_type_diff() const
Getter of the diff node of the underlying types of the current subrange_diff diff node.
virtual enum change_kind has_local_changes() const
Test if the current subrange_diff node carries any local change.
virtual const string & get_pretty_representation() const
Getter the pretty representation of the subrange_diff diff node.
virtual void report(ostream &, const string &indent="") const
Report about the changes carried by this node.
An abstraction of a diff between two translation units.
virtual bool has_changes() const
Return true iff the current diff node carries a change.
const translation_unit_sptr second_translation_unit() const
Getter for the second translation unit of this diff.
translation_unit_diff(translation_unit_sptr first, translation_unit_sptr second, diff_context_sptr ctxt=diff_context_sptr())
Constructor for translation_unit_diff.
virtual void report(ostream &out, const string &indent="") const
Report the diff in a serialized form.
virtual enum change_kind has_local_changes() const
const translation_unit_sptr first_translation_unit() const
Getter for the first translation unit of this diff.
Abstraction of a diff between two basic type declarations.
virtual bool has_changes() const
Return true iff the current diff node carries a change.
const type_decl_sptr first_type_decl() const
Getter for the first subject of the type_decl_diff.
const type_decl_sptr second_type_decl() const
Getter for the second subject of the type_decl_diff.
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.
virtual enum change_kind has_local_changes() const
virtual const string & get_pretty_representation() const
The base class of diff between types.
Abstraction of a diff between two typedef_decl.
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 diff base type sub-object of this instance of typedef_dif...
const typedef_decl_sptr second_typedef_decl() const
Getter for the second typedef_decl involved in the diff.
const typedef_decl_sptr first_typedef_decl() const
Getter for the firt typedef_decl involved in the diff.
const diff_sptr underlying_type_diff() const
Getter for the diff between the two underlying types of the typedefs.
virtual enum change_kind has_local_changes() const
virtual const string & get_pretty_representation() const
virtual void report(ostream &, const string &indent="") const
Reports the difference between the two subjects of the diff in a serialized form.
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.
union_decl_sptr first_union_decl() const
union_decl_sptr second_union_decl() const
virtual ~union_diff()
Destructor of the union_diff node.
virtual const string & get_pretty_representation() const
virtual void report(ostream &, const string &indent="") const
Report the changes carried by the current union_diff node in a textual format.
Abstracts a diff between two instances of var_decl.
virtual bool has_changes() const
Return true iff the diff node has a change.
virtual void chain_into_hierarchy()
Populate the vector of children node of the diff base type sub-object of this instance of var_diff.
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.
var_decl_sptr first_var() const
Getter for the first var_decl of the diff.
virtual void report(ostream &out, const string &indent="") const
Report the diff in a serialized form.
virtual enum change_kind has_local_changes() const
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.
virtual const string & get_pretty_representation() const
diff_sptr type_diff() const
Getter for the diff of the types of the instances of var_decl.
var_decl_sptr second_var() const
Getter for the second var_decl of the diff.
The abstraction of an edit script for transforming a sequence A into a sequence B.
shared_ptr< subrange_type > subrange_sptr
Convenience typedef for a shared pointer on a function_decl::subrange.
Definition: abg-ir.h:2460
shared_ptr< base_spec > base_spec_sptr
Convenience typedef.
Definition: abg-ir.h:4155
vector< base_spec_sptr > base_specs
Convenience typedef.
Definition: abg-ir.h:4160
vector< method_decl_sptr > member_functions
Convenience typedef.
Definition: abg-ir.h:3970
The abstraction of the version of an ELF symbol.
Definition: abg-ir.h:1171
Abstraction of an elf symbol.
Definition: abg-ir.h:900
const string & get_id_string() const
Get a string that is representative of a given elf_symbol.
Definition: abg-ir.cc:2430
std::vector< enumerator > enumerators
Convenience typedef for a list of enumerator.
Definition: abg-ir.h:2690
Abstraction for a function declaration.
Definition: abg-ir.h:3024
shared_ptr< parameter > parameter_sptr
Convenience typedef for a shared pointer on a function_decl::parameter.
Definition: abg-ir.h:3044
const function_type_sptr get_type() const
Return the type of the current instance of function_decl.
Definition: abg-ir.cc:20803
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:21140
An abstraction helper for type declarations.
Definition: abg-ir.h:1951
The base class of both types and declarations.
Definition: abg-ir.h:1345
Abstracts a variable declaration.
Definition: abg-ir.h:2921
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:19588
change_kind
The kind of change the current function suppression should apply to.
@ ADDED_FUNCTION_CHANGE_KIND
The function was added to the second subject of the diff.
@ DELETED_FUNCTION_CHANGE_KIND
The function was deleted from the second subject of the diff.
change_kind
The kind of change the current variable suppression should apply to.
@ ADDED_VARIABLE_CHANGE_KIND
The variable was added to the second second subject of the diff.
@ DELETED_VARIABLE_CHANGE_KIND
The variable was deleted from the second subject of the diff.
A type used to time various part of the libabigail system.
bool stop()
Stop the timer.
bool start()
Start the timer.
std::vector< filter_base_sptr > filters
Convenience typedef for a vector of filter_base_sptr.
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...
shared_ptr< filter_base > filter_base_sptr
Convenience typedef for a shared pointer to filter_base.
bool has_harmful_name_change(const decl_base_sptr &f, const decl_base_sptr &s)
Test if two decls represents a harmful name change.
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 ...
bool has_basic_or_class_type_name_change(const diff *d)
Test if a diff node carries a basic or class type name change.
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....
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...
shared_ptr< diff > diff_sptr
Convenience typedef for a shared_ptr for the diff class.
Definition: abg-fwd.h:76
visiting_kind operator~(visiting_kind l)
The overloaded 'bit inversion' operator for visiting_kind.
const decl_diff_base * is_decl_diff(const diff *diff)
Test if a diff node is about differences between declarations.
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 ...
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,...
void categorize_redundancy(diff *diff_tree)
Walk a given diff sub-tree to categorize each of the nodes with respect to the REDUNDANT_CATEGORY.
vector< diff * > diff_ptrs_type
Convenience typedef for a vector of diff*.
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...
diff_category
An enum for the different categories that a diff tree node falls into, regarding the kind of changes ...
@ ACCESS_CHANGE_CATEGORY
This means the diff node (or at least one of its descendant nodes) carries access related changes,...
@ HARMLESS_DATA_MEMBER_CHANGE_CATEGORY
This means that a diff node in the sub-tree carries a harmless data member change....
@ SUPPRESSED_CATEGORY
This means that a diff node was marked as suppressed by a user-provided suppression specification.
@ VIRTUAL_MEMBER_CHANGE_CATEGORY
This means that a diff node in the sub-tree carries an incompatible change to a vtable.
@ REDUNDANT_CATEGORY
A diff node in this category is redundant. That means it's present as a child of a other nodes in the...
@ SIZE_OR_OFFSET_CHANGE_CATEGORY
This means the diff node (or at least one of its descendant nodes) carries a change that modifies the...
@ NON_VIRT_MEM_FUN_CHANGE_CATEGORY
This means that a diff node in the sub-tree carries an addition or removal of a non-virtual member fu...
@ HAS_DESCENDANT_WITH_ALLOWED_CHANGE_CATEGORY
A diff node in this category has a descendant node that is in the HAS_ALLOWED_CHANGE_CATEGORY categor...
@ HARMLESS_ENUM_CHANGE_CATEGORY
This means that a diff node in the sub-tree carries an addition of enumerator to an enum type.
@ FN_PARM_ADD_REMOVE_CHANGE_CATEGORY
A diff node in this category is a function (or function type) with at least one parameter added or re...
@ VOID_PTR_TO_PTR_CHANGE_CATEGORY
A diff node in this category carries a change from void pointer to non-void pointer.
@ PRIVATE_TYPE_CATEGORY
This means that a diff node was warked as being for a private type. That is, the diff node is meant t...
@ COMPATIBLE_TYPE_CHANGE_CATEGORY
This means the diff node (or at least one of its descendant nodes) carries a change involving two com...
@ TYPE_DECL_ONLY_DEF_CHANGE_CATEGORY
This means that a diff node in the sub-tree carries a type that was declaration-only and that is now ...
@ STATIC_DATA_MEMBER_CHANGE_CATEGORY
This means that a diff node in the sub-tree carries an addition or removal of a static data member.
@ HARMLESS_DECL_NAME_CHANGE_CATEGORY
This means that a diff node in the sub-tree carries a harmless declaration name change....
@ EVERYTHING_CATEGORY
A special enumerator that is the logical 'or' all the enumerators above.
@ NO_CHANGE_CATEGORY
This means the diff node does not carry any (meaningful) change, or that it carries changes that have...
@ HARMLESS_UNION_CHANGE_CATEGORY
This means that a diff node in the sub-tree carries a harmless union change.
@ HAS_PARENT_WITH_ALLOWED_CHANGE_CATEGORY
A diff node in this category has a parent node that is in the HAS_ALLOWED_CHANGE_CATEGORY category....
@ BENIGN_INFINITE_ARRAY_CHANGE_CATEGORY
A diff node in this category carries a change in the size of the array type of a global variable,...
@ VAR_TYPE_CV_CHANGE_CATEGORY
A diff node in this category is for a variable which type holds a cv-qualifier change.
@ HAS_ALLOWED_CHANGE_CATEGORY
A diff node in this category carries a change that must be reported, even if the diff node is also in...
@ FN_PARM_TYPE_CV_CHANGE_CATEGORY
A diff node in this category has a function parameter type with a cv-qualifiers change.
@ FN_PARM_TYPE_TOP_CV_CHANGE_CATEGORY
A diff node in this category is a function parameter type which top cv-qualifiers change.
@ FN_RETURN_TYPE_CV_CHANGE_CATEGORY
A diff node in this category is a function return type with a cv-qualifier change.
@ HARMLESS_SYMBOL_ALIAS_CHANGE_CATEGORY
This means that a diff node in the sub-tree carries an a symbol alias change that is harmless.
shared_ptr< reporter_base > reporter_base_sptr
A convenience typedef for a shared pointer to a reporter_base.
Definition: abg-reporter.h:49
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.
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...
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.
const pointer_diff * is_pointer_diff(const diff *diff)
Test if a diff node is about differences between two pointers.
vector< var_diff_sptr > var_diff_sptrs_type
Convenience typedef for a vector of var_diff_sptr.
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.
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.
void propagate_categories(diff *diff_tree)
Visit all the nodes of a given sub-tree. For each node that has a particular category set,...
const subrange_diff * is_subrange_diff(const diff *diff)
Test if a diff node is a subrange_diff node.
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.
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.
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.
diff_category get_default_harmless_categories_bitmap()
Getter of a bitmap made of the set of change categories that are considered harmless.
vector< diff_sptr > diff_sptrs_type
Convenience typedef for a vector of diff_sptr.
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.
void sort_changed_data_members(changed_var_sptrs_type &input)
Sort (in place) a vector of changed data members.
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.
shared_ptr< type_decl_diff > type_decl_diff_sptr
Convenience typedef for a shared pointer on a type_decl_diff type.
bool is_diff_of_variadic_parameter(const diff *d)
Test if a diff node represents the difference between a variadic parameter and something else.
shared_ptr< diff_context > diff_context_sptr
Convenience typedef for a shared pointer of diff_context.
Definition: abg-fwd.h:68
bool is_diff_of_global_decls(const diff *)
Tests if a given diff node is to represent the changes between two gobal decls.
shared_ptr< subrange_diff > subrange_diff_sptr
A convenience typedef for a shared pointer to subrange_diff type.
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.
diff_category get_default_harmful_categories_bitmap()
Getter of a bitmap made of the set of change categories that are considered harmful.
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...
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.
shared_ptr< var_diff > var_diff_sptr
Convenience typedef for a shared pointer to a var_diff type.
unordered_map< string, method_decl_sptr > string_member_function_sptr_map
Convenience typedef for a hash map of strings and member functions.
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...
shared_ptr< reference_diff > reference_diff_sptr
Convenience typedef for a shared pointer on a reference_diff type.
vector< base_diff_sptr > base_diff_sptrs_type
Convenience typedef for a vector of base_diff_sptr.
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.
shared_ptr< function_decl_diff > function_decl_diff_sptr
Convenience typedef for a shared pointer to a function_decl type.
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.
const function_decl_diff * is_function_decl_diff(const diff *diff)
Test if a diff node is about differences between functions.
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...
shared_ptr< fn_parm_diff > fn_parm_diff_sptr
Convenience typedef for a shared pointer to a fn_parm_diff type.
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 clear_redundancy_categorization(diff *diff_tree)
Walk a given diff sub-tree to clear the REDUNDANT_CATEGORY out of the category of the nodes.
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...
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.
bool is_child_node_of_base_diff(const diff *diff)
Test if a diff node is a child node of a base diff node.
visiting_kind
An enum for the different ways to visit a diff tree node.
@ SKIP_CHILDREN_VISITING_KIND
This says that the traversing code should avoid visiting the children nodes of the current node being...
@ DO_NOT_MARK_VISITED_NODES_AS_VISITED
This says that the traversing code should not mark visited nodes as having been traversed....
visiting_kind operator&(visiting_kind l, visiting_kind r)
The overloaded and operator for visiting_kind.
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.
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...
const function_type_diff * is_function_type_diff(const diff *diff)
Test if a diff node is a function_type_diff node.
const distinct_diff * is_distinct_diff(const diff *diff)
Test if a diff node is about differences between two diff nodes of different kinds.
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...
visiting_kind operator|(visiting_kind l, visiting_kind r)
The overloaded or operator for visiting_kind.
const array_diff * is_array_diff(const diff *diff)
Test if a diff node is a array_diff node.
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 ...
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...
string get_pretty_representation(diff *d)
Get a copy of the pretty representation of a diff node.
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.
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.
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.
shared_ptr< base_diff > base_diff_sptr
Convenience typedef for a shared pointer to a base_diff type.
shared_ptr< scope_diff > scope_diff_sptr
Convenience typedef for a shared pointer on a scope_diff.
shared_ptr< class_diff > class_diff_sptr
Convenience typedef for a shared pointer on a class_diff type.
const base_diff * is_base_diff(const diff *diff)
Test if a diff node is about differences between two base class specifiers.
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.
const fn_parm_diff * is_fn_parm_diff(const diff *diff)
Test if a diff node is about differences between two function parameters.
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...
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...
const union_diff * is_union_diff(const diff *diff)
Test if a diff node is a union_diff node.
vector< changed_var_sptr > changed_var_sptrs_type
Convenience typedef for a vector of @changed_var_sptr.gg381.
shared_ptr< pointer_diff > pointer_diff_sptr
Convenience typedef for a shared pointer on a pointer_diff type.
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...
void apply_suppressions(diff *diff_tree)
Walk a given diff-sub tree and appply the suppressions carried by the context. If the suppression app...
void sort_string_parm_map(const string_parm_map &map, vector< function_decl::parameter_sptr > &sorted)
Sort a map of string -> function parameters.
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.
const enum_diff * is_enum_diff(const diff *diff)
Test if a diff node is a enum_diff node.
unordered_map< string, base_diff_sptr > string_base_diff_sptr_map
Convenience typedef for a map of string and base_diff_sptr.
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.
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 corpus_diff * is_corpus_diff(const diff *diff)
Test if a diff node is a corpus_diff node.
const diff * get_typedef_diff_underlying_type_diff(const diff *diff)
Return the leaf underlying diff node of a typedef_diff node.
const typedef_diff * is_typedef_diff(const diff *diff)
Test if a diff node is a typedef_diff node.
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...
type_base_sptr get_leaf_type(qualified_type_def_sptr t)
Return the first underlying type that is not a qualified type.
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...
shared_ptr< array_diff > array_diff_sptr
Convenience typedef for a shared pointer on a array_diff type.
const class_diff * is_class_diff(const diff *diff)
Test if a diff node is a class_diff node.
diff_sptr try_to_diff(const type_or_decl_base_sptr first, const type_or_decl_base_sptr second, diff_context_sptr ctxt)
</distinct_diff>
const type_decl_diff * is_diff_of_basic_type(const diff *d)
Test if a diff node represents a diff between two basic types.
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...
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...
const qualified_type_diff * is_qualified_type_diff(const diff *diff)
Test if a diff node is about differences between 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,...
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...
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...
void sort_changed_enumerators(const string_changed_enumerator_map &enumerators_map, changed_enumerators_type &sorted)
Sort a map of changed enumerators.
vector< changed_enumerator > changed_enumerators_type
Convenience typedef for a vector of changed enumerators.
vector< function_decl_diff_sptr > function_decl_diff_sptrs_type
Convenience typedef for a vector of function_decl_diff_sptr.
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.
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....
shared_ptr< function_type_diff > function_type_diff_sptr
A convenience typedef for a shared pointer to function_type_type_diff.
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.
const var_diff * is_var_diff(const diff *diff)
Test if a diff node is about differences between variables.
const type_diff_base * is_type_diff(const diff *diff)
Test if a diff node is about differences between types.
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.
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...
const reference_diff * is_reference_diff(const diff *diff)
Test if a diff node is about differences between two references.
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.
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....
shared_ptr< distinct_diff > distinct_diff_sptr
Convenience typedef for a shared pointer to distinct_types_diff.
shared_ptr< corpus_diff > corpus_diff_sptr
A convenience typedef for a shared pointer to corpus_diff.
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...
void print_diff_tree(diff *diff_tree, ostream &out)
Emit a textual representation of a diff sub-tree to an output stream.
shared_ptr< typedef_diff > typedef_diff_sptr
Convenience typedef for a shared pointer on a typedef_diff type.
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...
void sort_enumerators(const string_enumerator_map &enumerators_map, enum_type_decl::enumerators &sorted)
Sort a map of enumerators by their value.
ostream & operator<<(ostream &o, diff_category c)
Serialize an instance of diff_category to an output stream.
shared_ptr< translation_unit_diff > translation_unit_diff_sptr
Convenience typedef for a shared pointer on a translation_unit_diff type.
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...
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...
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
bool get_member_function_is_dtor(const function_decl &f)
Test whether a member function is a destructor.
Definition: abg-ir.cc:6434
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:5648
shared_ptr< function_decl > function_decl_sptr
Convenience typedef for a shared pointer on a function_decl.
Definition: abg-fwd.h:263
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:541
bool is_type(const type_or_decl_base &tod)
Test whether a declaration is a type.
Definition: abg-ir.cc:10194
bool is_anonymous_data_member(const decl_base &d)
Test if a decl is an anonymous data member.
Definition: abg-ir.cc:5877
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:11032
shared_ptr< elf_symbol > elf_symbol_sptr
A convenience typedef for a shared pointer to elf_symbol.
Definition: abg-ir.h:863
change_kind
A bitfield that gives callers of abigail::ir::equals() some insight about how different two internal ...
Definition: abg-ir.h:1300
@ LOCAL_TYPE_CHANGE_KIND
This means that a given IR artifact has a local type change.
Definition: abg-ir.h:1304
@ ALL_LOCAL_CHANGES_MASK
Testing (anding) against this mask means that a given IR artifact has local differences,...
Definition: abg-ir.h:1315
@ LOCAL_NON_TYPE_CHANGE_KIND
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:1309
bool is_user_defined_type(const type_base *t)
Test if a type is user-defined.
Definition: abg-ir.cc:5552
bool is_class_type(const type_or_decl_base &t)
Test whether a type is a class.
Definition: abg-ir.cc:10449
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
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:9144
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:10509
shared_ptr< class_decl > class_decl_sptr
Convenience typedef for a shared pointer on a class_decl.
Definition: abg-fwd.h:187
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:5815
shared_ptr< function_type > function_type_sptr
Convenience typedef for a shared pointer on a function_type.
Definition: abg-fwd.h:205
shared_ptr< typedef_decl > typedef_decl_sptr
Convenience typedef for a shared pointer on a typedef_decl.
Definition: abg-fwd.h:161
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:10037
const global_scope * get_global_scope(const decl_base &decl)
return the global scope as seen by a given declaration.
Definition: abg-ir.cc:8386
shared_ptr< var_decl > var_decl_sptr
Convenience typedef for a shared pointer on a var_decl.
Definition: abg-fwd.h:246
shared_ptr< scope_decl > scope_decl_sptr
Convenience typedef for a shared pointer on a scope_decl.
Definition: abg-fwd.h:258
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
shared_ptr< translation_unit > translation_unit_sptr
Convenience typedef for a shared pointer on a translation_unit type.
Definition: abg-fwd.h:134
bool equals(const decl_base &l, const decl_base &r, change_kind *k)
Compares two instances of decl_base.
Definition: abg-ir.cc:5199
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
uint64_t get_absolute_data_member_offset(const var_decl &m)
Get the absolute offset of a data member.
Definition: abg-ir.cc:6253
bool is_member_function(const function_decl &f)
Test whether a function_decl is a member function.
Definition: abg-ir.cc:6348
var_decl * is_var_decl(const type_or_decl_base *tod)
Tests if a declaration is a variable declaration.
Definition: abg-ir.cc:10890
decl_base * is_decl(const type_or_decl_base *d)
Test if an ABI artifact is a declaration.
Definition: abg-ir.cc:10134
shared_ptr< enum_type_decl > enum_type_decl_sptr
Convenience typedef for shared pointer to a enum_type_decl.
Definition: abg-fwd.h:169
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:6711
uint64_t get_data_member_offset(const var_decl &m)
Get the offset of a data member.
Definition: abg-ir.cc:6164
bool get_member_function_is_virtual(const function_decl &f)
Test if a given member function is virtual.
Definition: abg-ir.cc:6621
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:10749
bool is_union_type(const type_or_decl_base &t)
Test if a type is a union_decl.
Definition: abg-ir.cc:10528
bool is_data_member(const var_decl &v)
Test if a var_decl is a data member.
Definition: abg-ir.cc:5686
const decl_base * get_type_declaration(const type_base *t)
Get the declaration for a given type.
Definition: abg-ir.cc:9827
shared_ptr< type_decl > type_decl_sptr
Convenience typedef for a shared pointer on a type_decl.
Definition: abg-fwd.h:156
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:10719
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,...
Definition: abg-ir.cc:9018
bool is_at_global_scope(const decl_base &decl)
Tests whether a given declaration is at global scope.
Definition: abg-ir.cc:9967
bool is_member_decl(const decl_base_sptr d)
Tests if a declaration is a class member.
Definition: abg-ir.cc:5490
shared_ptr< variable_suppression > variable_suppression_sptr
A convenience typedef for a shared pointer to variable_suppression.
vector< suppression_sptr > suppressions_type
Convenience typedef for a vector of suppression_sptr.
Definition: abg-fwd.h:1533
shared_ptr< function_suppression > function_suppression_sptr
Convenience typedef for a shared pointer to function_suppression.
variable_suppression_sptr is_variable_suppression(const suppression_sptr s)
Test if an instance of suppression is an instance of variable_suppression.
bool is_private_type_suppr_spec(const type_suppression &s)
Test if a type suppression specification represents a private type suppression automatically generate...
shared_ptr< type_suppression > type_suppression_sptr
Convenience typedef for a shared pointer to type_suppression.
function_suppression_sptr is_function_suppression(const suppression_sptr suppr)
Test if an instance of suppression is an instance of function_suppression.
type_suppression_sptr is_type_suppression(suppression_sptr suppr)
Test if an instance of suppression is an instance of type_suppression.
shared_ptr< suppression_base > suppression_sptr
Convenience typedef for a shared pointer to a suppression.
Definition: abg-fwd.h:1527
bool is_negated_suppression(const suppression_base &s)
Test if a suppression specification is a negated suppression.
Toplevel namespace for libabigail.
A comparison function for instances of base_diff.
A functor to compare instances of class_decl::base_spec.
A functor to compare two changed enumerators, based on their initial value.
size_t count_filtered_bases()
Count the number of bases classes whose changes got filtered out.
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...
The type of private data of class_or_union_diff.
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.
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...
size_t get_deleted_non_static_data_members_number() const
Get the number of non static data members that were deleted.
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.
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...
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...
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...
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_deleted_mem_fns(const diff_context_sptr &)
Get the number of member functions deletions carried by the current diff node that were filtered out.
size_t get_inserted_non_static_data_members_number() const
Get the number of non static data members that were inserted.
The type of the private data of corpus_diff::diff_stats.
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 ...
void ensure_lookup_tables_populated()
If the lookup tables are not yet built, walk the differences and fill the lookup tables.
const vector< diff_sptr > & changed_unreachable_types_sorted() const
Get the sorted vector of diff nodes representing changed unreachable types.
diff_context_sptr get_context()
Getter of the context associated with this corpus.
void categorize_redundant_changed_sub_nodes()
Walk the changed functions and variables diff nodes to categorize redundant 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...
bool lookup_tables_empty() const
Tests if the lookup tables are empty.
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...
void apply_filters_and_compute_diff_stats(corpus_diff::diff_stats &)
Compute the diff stats.
bool added_variable_is_suppressed(const var_decl *var) const
Test if the change reports for a given added variable have been suppressed.
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...
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 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...
void maybe_dump_diff_tree()
If the user asked to dump the diff tree node (for changed variables and functions) on the error outpu...
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 ...
void clear_redundancy_categorization()
Walk the changed functions and variables diff nodes and clear the redundancy categorization they migh...
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.
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 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...
bool deleted_function_is_suppressed(const function_decl *fn) const
Test if the change reports for a given deleted function have been deleted.
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...
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.
bool added_function_is_suppressed(const function_decl *fn) const
Test if the change reports for a give given added function has been deleted.
void clear_lookup_tables()
Clear the lookup tables useful for reporting an enum_diff.
A comparison functor to compare two data members based on their offset.
A comparison functor to compare two instances of var_diff that represent changed data members based o...
A comparison functor for instances of diff.
A functor to compare two instances of diff_sptr.
The private data structure for distinct_diff.
A functor to compare instances of elf_symbol base on their names.
A functor to compare two enumerators based on their value. This implements the "less than" operator.
A comparison functor to compare two instances of fn_parm_diff based on their indexes.
"Less than" functor to compare instances of function_decl.
A "Less Than" functor to compare instance of function_decl_diff.
Functor that compares two function parameters for the purpose of sorting them.
The internal type for the impl idiom implementation of pointer_diff.
The internal type for the impl idiom implementation of subrange_diff.
A functor to compare instances of var_decl base on their qualified names.
The internal type for the impl idiom implementation of var_diff.
Functor to sort instances of var_diff_sptr.
A comparison functor for instances of function_decl_diff that represent changes between two virtual m...
An equality functor to deeply compare pointers.
A comparison functor to compare pointer to instances of type_or_decl_base.
Definition: abg-ir.h:3155
A deleter for shared pointers that ... doesn't delete the object managed by the shared pointer.