libabigail
abg-comparison.cc
Go to the documentation of this file.
1 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
2 // -*- Mode: C++ -*-
3 //
4 // Copyright (C) 2013-2023 Red Hat, Inc.
5 //
6 // Author: Dodji Seketeli
7 
8 /// @file
9 ///
10 /// This contains the implementation of the comparison engine of
11 /// libabigail.
12 
13 #include <ctype.h>
14 #include <libgen.h>
15 #include <algorithm>
16 #include <sstream>
17 #include <set>
18 
19 #include "abg-comparison-priv.h"
20 #include "abg-reporter-priv.h"
21 #include "abg-tools-utils.h"
22 
23 namespace abigail
24 {
25 
26 namespace comparison
27 {
28 
29 ///
30 ///
31 ///@defgroup DiffNode Internal Representation of the comparison engine
32 /// @{
33 ///
34 /// @brief How changes are represented in libabigail's comparison engine.
35 ///
36 ///@par diff nodes
37 ///
38 /// The internal representation of the comparison engine is basically
39 /// a graph of @ref instances of @ref diff node. We refer to these
40 /// just as <em>diff nodes</em>. A diff node represents a change
41 /// between two ABI artifacts represented by instances of types of the
42 /// abigail::ir namespace. These two artifacts that are being
43 /// compared are called the <em>subjects of the diff</em>.
44 ///
45 /// The types of that IR are in the abigail::comparison namespace.
46 ///
47 ///@par comparing diff nodes
48 ///
49 /// Comparing two instances of @ref diff nodes amounts to comparing
50 /// the subject of the diff. In other words, two @ref diff nodes are
51 /// equal if and only if their subjects are equal. Thus, two @ref
52 /// diff nodes can have different memory addresses and yet be equal.
53 ///
54 ///@par diff reporting and context
55 ///
56 /// A diff node can be serialized to an output stream to express, in
57 /// a human-readable textual form, the different changes that exist
58 /// between its two subjects. This is done by invoking the
59 /// diff::report() method. That reporting is controlled by several
60 /// parameters that are conceptually part of the context of the diff.
61 /// That context is materialized by an instance of the @ref
62 /// diff_context type.
63 ///
64 /// Please note that the role of the instance(s) of @ref diff_context
65 /// is boreader than just controlling the reporting of @ref diff
66 /// nodes. Basically, a @ref diff node itself is created following
67 /// behaviours that are controlled by a particular instance of
68 /// diff_context. A diff node is created in a particular diff
69 /// context, so to speak.
70 ///
71 /// @}
72 ///
73 
74 ///
75 ///@defgroup CanonicalDiff Canonical diff tree nodes
76 /// @{
77 ///
78 /// @brief How equivalent diff nodes are quickly spotted.
79 ///
80 /// @par Equivalence of diff nodes.
81 ///
82 /// Each @ref diff node has a property named <em>Canonical Diff
83 /// Node</em>. If \c D is a diff node, the canonical diff node of @c
84 /// D, noted @c C(D) is a particular diff node that is equal to @c D.
85 /// Thus, a fast way to compare two @ref diff node is to perform a
86 /// pointer comparison of their canonical diff nodes.
87 ///
88 /// A set of equivalent @ref diff nodes is a set of diff nodes that
89 /// all have the same canonical node. All the nodes of that set are
90 /// equal.
91 ///
92 /// A canonical node is registereded for a given diff node by invoking
93 /// the method diff_context::initialize_canonical_diff().
94 ///
95 /// Please note that the diff_context holds all the canonical diffs
96 /// that got registered through it. Thus, the life time of all of
97 /// canonical diff objects is the same as the life time of the @ref
98 /// diff_context they relate to.
99 ///
100 /// @}
101 ///
102 
103 // -----------------------------------------
104 // <private functions re-usable elsewhere>
105 // -----------------------------------------
106 /// Sort a map of enumerators by their value.
107 ///
108 /// @param enumerators_map the map to sort.
109 ///
110 /// @param sorted the resulting vector of sorted enumerators.
111 void
114 {
115  for (string_enumerator_map::const_iterator i = enumerators_map.begin();
116  i != enumerators_map.end();
117  ++i)
118  sorted.push_back(i->second);
120  std::sort(sorted.begin(), sorted.end(), comp);
121 }
122 
123 /// Sort a map of changed enumerators.
124 ///
125 /// @param enumerators_map the map to sort.
126 ///
127 ///@param output parameter. The resulting sorted enumerators.
128 void
130  changed_enumerators_type& sorted)
131 {
132  for (string_changed_enumerator_map::const_iterator i =
133  enumerators_map.begin();
134  i != enumerators_map.end();
135  ++i)
136  sorted.push_back(i->second);
137 
139  std::sort(sorted.begin(), sorted.end(), comp);
140 }
141 
142 /// Sort a map of data members by the offset of their initial value.
143 ///
144 /// @param data_members the map of changed data members to sort.
145 ///
146 /// @param sorted the resulting vector of sorted changed data members.
147 void
149  vector<decl_base_sptr>& sorted)
150 {
151  sorted.reserve(data_members.size());
152  for (string_decl_base_sptr_map::const_iterator i = data_members.begin();
153  i != data_members.end();
154  ++i)
155  sorted.push_back(i->second);
156 
157  data_member_comp comp;
158  std::sort(sorted.begin(), sorted.end(), comp);
159 }
160 
161 /// Sort (in place) a vector of changed data members.
162 ///
163 /// @param to_sort the vector to sort.
164 void
166 {
167  data_member_comp comp;
168  std::sort(to_sort.begin(), to_sort.end(), comp);
169 }
170 
171 /// Compare two @ref function_decl_diff for the purpose of sorting.
172 ///
173 /// @param first the first @ref function_decl_diff to consider.
174 ///
175 /// @param second the second @ref function_decl_diff to consider.
176 ///
177 /// @return true iff @p first compares less than @p second.
178 bool
180 {
182  s = second.first_function_decl();
183 
184  string fr = f->get_qualified_name(), sr = s->get_qualified_name();
185 
186  if (fr != sr)
187  return fr < sr;
188 
189  if (!f->get_linkage_name().empty()
190  && !s->get_linkage_name().empty())
191  {
192  fr = f->get_linkage_name();
193  sr = s->get_linkage_name();
194  if (fr != sr)
195  return fr < sr;
196  }
197 
198  if (f->get_symbol() && s->get_symbol())
199  {
200  fr = f->get_symbol()->get_id_string();
201  sr = s->get_symbol()->get_id_string();
202  if (fr != sr)
203  return fr < sr;
204  }
205 
206  fr = f->get_pretty_representation(true, true);
207  sr = s->get_pretty_representation(true, true);
208 
209  return fr < sr;
210 }
211 
212 /// Sort an instance of @ref string_function_ptr_map map and stuff a
213 /// resulting sorted vector of pointers to function_decl.
214 ///
215 /// @param map the map to sort.
216 ///
217 /// @param sorted the resulting sorted vector.
218 void
220  vector<const function_decl*>& sorted)
221 {
222  sorted.reserve(map.size());
223  for (string_function_ptr_map::const_iterator i = map.begin();
224  i != map.end();
225  ++i)
226  sorted.push_back(i->second);
227 
228  function_comp comp;
229  std::sort(sorted.begin(), sorted.end(), comp);
230 }
231 
232 /// Sort a map that's an instance of @ref
233 /// string_member_function_sptr_map and fill a vector of member
234 /// functions with the sorted result.
235 ///
236 /// @param map the map to sort.
237 ///
238 /// @param sorted the resulting sorted vector.
239 void
242 {
243  sorted.reserve(map.size());
244  for (string_member_function_sptr_map::const_iterator i = map.begin();
245  i != map.end();
246  ++i)
247  sorted.push_back(i->second);
248 
249  function_comp comp;
250  std::sort(sorted.begin(), sorted.end(), comp);
251 }
252 
253 /// Sort the values of a @ref string_function_decl_diff_sptr_map map
254 /// and store the result in a vector of @ref function_decl_diff_sptr
255 /// objects.
256 ///
257 /// @param map the map whose values to store.
258 ///
259 /// @param sorted the vector of function_decl_diff_sptr to store the
260 /// result of the sort into.
261 void
265 {
266  sorted.reserve(map.size());
267  for (string_function_decl_diff_sptr_map::const_iterator i = map.begin();
268  i != map.end();
269  ++i)
270  sorted.push_back(i->second);
272  std::sort(sorted.begin(), sorted.end(), comp);
273 }
274 
275 /// Sort of an instance of @ref string_var_diff_sptr_map map.
276 ///
277 /// @param map the input map to sort.
278 ///
279 /// @param sorted the ouptut sorted vector of @ref var_diff_sptr.
280 /// It's populated with the sorted content.
281 void
283  var_diff_sptrs_type& sorted)
284 {
285  sorted.reserve(map.size());
286  for (string_var_diff_sptr_map::const_iterator i = map.begin();
287  i != map.end();
288  ++i)
289  sorted.push_back(i->second);
290 
291  var_diff_sptr_comp comp;
292  std::sort(sorted.begin(), sorted.end(), comp);
293 }
294 
295 /// Sort a map of string -> pointer to @ref elf_symbol.
296 ///
297 /// The result is a vector of @ref elf_symbol_sptr sorted by the
298 /// name of the symbol.
299 ///
300 /// @param map the map to sort.
301 ///
302 /// @param sorted out parameter; the sorted vector of @ref
303 /// elf_symbol_sptr.
304 void
306  vector<elf_symbol_sptr>& sorted)
307 {
308  for (string_elf_symbol_map::const_iterator i = map.begin();
309  i!= map.end();
310  ++i)
311  sorted.push_back(i->second);
312 
313  elf_symbol_comp comp;
314  std::sort(sorted.begin(), sorted.end(), comp);
315 }
316 
317 /// Sort a map of string -> pointer to @ref var_decl.
318 ///
319 /// The result is a vector of var_decl* sorted by the qualified name
320 /// of the variables.
321 ///
322 /// @param map the map to sort.
323 ///
324 /// @param sorted out parameter; the sorted vector of @ref var_decl.
325 void
327  vector<const var_decl*>& sorted)
328 {
329  for (string_var_ptr_map::const_iterator i = map.begin();
330  i != map.end();
331  ++i)
332  sorted.push_back(i->second);
333 
334  var_comp comp;
335  std::sort(sorted.begin(), sorted.end(), comp);
336 }
337 
338 /// Sort the values of a string_var_diff_sptr_map and store the result
339 /// in a vector of var_diff_sptr.
340 ///
341 /// @param map the map of changed data members to sort.
342 ///
343 /// @param sorted the resulting vector of var_diff_sptr.
344 void
346  var_diff_sptrs_type& sorted)
347 {
348  sorted.reserve(map.size());
349  for (string_var_diff_sptr_map::const_iterator i = map.begin();
350  i != map.end();
351  ++i)
352  sorted.push_back(i->second);
354  std::sort(sorted.begin(), sorted.end(), comp);
355 }
356 
357 /// Sort the values of a unsigned_var_diff_sptr_map map and store the
358 /// result into a vector of var_diff_sptr.
359 ///
360 /// @param map the map of changed data members to sort.
361 ///
362 /// @param sorted the resulting vector of sorted var_diff_sptr.
363 void
365  var_diff_sptrs_type& sorted)
366 {
367  sorted.reserve(map.size());
368  for (unsigned_var_diff_sptr_map::const_iterator i = map.begin();
369  i != map.end();
370  ++i)
371  sorted.push_back(i->second);
373  std::sort(sorted.begin(), sorted.end(), comp);
374 }
375 
376 /// Sort an map of string -> virtual member function into a vector of
377 /// virtual member functions. The virtual member functions are sorted
378 /// by increasing order of their virtual index.
379 ///
380 /// @param map the input map.
381 ///
382 /// @param sorted the resulting sorted vector of virtual function
383 /// member.
384 void
388 {
389  sorted.reserve(map.size());
390  for (string_function_decl_diff_sptr_map::const_iterator i = map.begin();
391  i != map.end();
392  ++i)
393  sorted.push_back(i->second);
394 
396  sort(sorted.begin(), sorted.end(), comp);
397 }
398 
399 /// Sort a map ofg string -> @ref diff_sptr into a vector of @ref
400 /// diff_sptr. The diff_sptr are sorted lexicographically wrt
401 /// qualified names of their first subjects.
402 ///
403 /// @param map the map to sort.
404 ///
405 /// @param sorted the resulting sorted vector.
406 void
408  diff_sptrs_type& sorted)
409 {
410  sorted.reserve(map.size());
411  for (string_diff_sptr_map::const_iterator i = map.begin();
412  i != map.end();
413  ++i)
414  sorted.push_back(i->second);
415 
416  diff_comp comp;
417  sort(sorted.begin(), sorted.end(), comp);
418 }
419 
420 /// Sort a map ofg string -> @ref diff* into a vector of @ref
421 /// diff_ptr. The diff_ptr are sorted lexicographically wrt
422 /// qualified names of their first subjects.
423 ///
424 /// @param map the map to sort.
425 ///
426 /// @param sorted the resulting sorted vector.
427 void
429  diff_ptrs_type& sorted)
430 {
431  sorted.reserve(map.size());
432  for (string_diff_ptr_map::const_iterator i = map.begin();
433  i != map.end();
434  ++i)
435  sorted.push_back(i->second);
436 
437  diff_comp comp;
438  sort(sorted.begin(), sorted.end(), comp);
439 }
440 
441 /// Sort a map of string -> base_diff_sptr into a sorted vector of
442 /// base_diff_sptr. The base_diff_sptr are sorted by increasing value
443 /// of their offset in their containing type.
444 ///
445 /// @param map the input map to sort.
446 ///
447 /// @param sorted the resulting sorted vector.
448 void
450  base_diff_sptrs_type& sorted)
451 {
452  for (string_base_diff_sptr_map::const_iterator i = map.begin();
453  i != map.end();
454  ++i)
455  sorted.push_back(i->second);
456  base_diff_comp comp;
457  sort(sorted.begin(), sorted.end(), comp);
458 }
459 
460 /// Lexicographically sort base specifications found
461 /// in instances of string_base_sptr_map.
462 void
464  class_decl::base_specs& sorted)
465 {
466  for (string_base_sptr_map::const_iterator i = m.begin();
467  i != m.end();
468  ++i)
469  sorted.push_back(i->second);
470 
471  base_spec_comp comp;
472  std::sort(sorted.begin(), sorted.end(), comp);
473 }
474 
475 /// Sort a map of @ref fn_parm_diff by the indexes of the function
476 /// parameters.
477 ///
478 /// @param map the map to sort.
479 ///
480 /// @param sorted the resulting sorted vector of changed function
481 /// parms.
482 void
484  vector<fn_parm_diff_sptr>& sorted)
485 {
486  sorted.reserve(map.size());
487  for (unsigned_fn_parm_diff_sptr_map::const_iterator i = map.begin();
488  i != map.end();
489  ++i)
490  sorted.push_back(i->second);
491 
492  fn_parm_diff_comp comp;
493  std::sort(sorted.begin(), sorted.end(), comp);
494 }
495 
496 /// Sort a map of changed function parameters by the indexes of the
497 /// function parameters.
498 ///
499 /// @param map the map to sort.
500 ///
501 /// @param sorted the resulting sorted vector of instances of @ref
502 /// fn_parm_diff_sptr
503 void
505  vector<fn_parm_diff_sptr>& sorted)
506 {
507  sorted.reserve(map.size());
508  for (string_fn_parm_diff_sptr_map::const_iterator i = map.begin();
509  i != map.end();
510  ++i)
511  sorted.push_back(i->second);
512 
513  fn_parm_diff_comp comp;
514  std::sort(sorted.begin(), sorted.end(), comp);
515 }
516 
517 /// Sort a map of string -> function parameters.
518 ///
519 /// @param map the map to sort.
520 ///
521 /// @param sorted the resulting sorted vector of
522 /// @ref vector<function_decl::parameter_sptr>
523 void
525  vector<function_decl::parameter_sptr>& sorted)
526 {
527  for (string_parm_map::const_iterator i = map.begin();
528  i != map.end();
529  ++i)
530  sorted.push_back(i->second);
531 
532  parm_comp comp;
533  std::sort(sorted.begin(), sorted.end(), comp);
534 }
535 
536 /// Sort the set of ABI artifacts contained in a @ref
537 /// artifact_sptr_set_type.
538 ///
539 /// @param set the set of ABI artifacts to sort.
540 ///
541 /// @param output parameter the vector containing the sorted ABI
542 /// artifacts.
543 void
545  vector<type_or_decl_base_sptr>& sorted)
546 {
547 
548  for (artifact_sptr_set_type::const_iterator it = set.begin();
549  it != set.end();
550  ++it)
551  sorted.push_back(*it);
552 
554  std::sort(sorted.begin(), sorted.end(), comp);
555 }
556 
557 /// Sort a map of string to type_base_sptr entities.
558 ///
559 /// The entries are sorted based on the lexicographic order of the
560 /// pretty representation of the type_sptr_sptr. The sorted result is
561 /// put in a vector of type_base_sptr.
562 ///
563 /// @param map the map to sort.
564 ///
565 /// @param sorted the resulting vector of type_base_sptr
566 /// lexicographically sorted using their pretty representation.
567 void
569  vector<type_base_sptr>& sorted)
570 {
571  for (string_type_base_sptr_map::const_iterator i = map.begin();
572  i != map.end();
573  ++i)
574  sorted.push_back(i->second);
575 
577  std::sort(sorted.begin(), sorted.end(), comp);
578 }
579 
580 /// Return the first underlying type that is not a qualified type.
581 /// @param t the qualified type to consider.
582 ///
583 /// @return the first underlying type that is not a qualified type, or
584 /// NULL if t is NULL.
585 type_base_sptr
586 get_leaf_type(qualified_type_def_sptr t)
587 {
588  if (!t)
589  return type_base_sptr();
590 
591  type_base_sptr ut = t->get_underlying_type();
592  qualified_type_def_sptr qut = dynamic_pointer_cast<qualified_type_def>(ut);
593 
594  if (!qut)
595  return ut;
596  return get_leaf_type(qut);
597 }
598 
599 /// Tests if a given diff node is to represent the changes between two
600 /// gobal decls.
601 ///
602 /// @param d the diff node to consider.
603 ///
604 /// @return true iff @p d represents the changes between two global
605 /// decls.
606 bool
608 {
609  ABG_ASSERT(d != 0);
610 
611  if (d == 0)
612  return false;
613 
615  ABG_ASSERT(first);
616 
618  ABG_ASSERT(second);
619 
620  if (decl_base_sptr decl = is_decl(first))
621  if (is_at_global_scope(decl))
622  if ((decl = is_decl(second)))
623  if (is_at_global_scope(decl))
624  return true;
625 
626  return false;
627 }
628 
629 // -----------------------------------------
630 // </private functions re-usable elsewhere>
631 // -----------------------------------------
632 
633 /// The overloaded or operator for @ref visiting_kind.
636 {return static_cast<visiting_kind>(static_cast<unsigned>(l)
637  | static_cast<unsigned>(r));}
638 
639 /// The overloaded and operator for @ref visiting_kind.
642 {
643  return static_cast<visiting_kind>(static_cast<unsigned>(l)
644  & static_cast<unsigned>(r));
645 }
646 
647 /// The overloaded 'bit inversion' operator for @ref visiting_kind.
650 {return static_cast<visiting_kind>(~static_cast<unsigned>(l));}
651 
652 /// Test if a diff node is about differences between types.
653 ///
654 /// @param diff the diff node to test.
655 ///
656 /// @return a pointer to the actual type_diff_base* that @p diff
657 /// extends, iff it is about differences between types.
658 const type_diff_base*
660 {return dynamic_cast<const type_diff_base*>(diff);}
661 
662 /// Test if a diff node is about differences between declarations.
663 ///
664 /// @param diff the diff node to test.
665 ///
666 /// @return a pointer to the actual decl_diff_base @p diff extends,
667 /// iff it is about differences between declarations.
668 const decl_diff_base*
670 {return dynamic_cast<const decl_diff_base*>(diff);}
671 
672 /// Test if a diff node is a @ref class_diff node.
673 ///
674 /// @param diff the diff node to consider.
675 ///
676 /// @return a non-nil pointer to a @ref class_diff iff @p diff is a
677 /// @ref class_diff node.
678 const class_diff*
680 {return dynamic_cast<const class_diff*>(diff);}
681 
682 /// Test if a diff node is a @ref enum_diff node.
683 ///
684 /// @param diff the diff node to consider.
685 ///
686 /// @return a non-nil pointer to ad @ref enum_diff node iff @p diff is
687 /// a @ref enum_diff node.
688 const enum_diff*
690 {return dynamic_cast<const enum_diff*>(diff);}
691 
692 /// Test if a diff node is a @ref union_diff node.
693 ///
694 /// @param diff the diff node to consider.
695 ///
696 /// @return a non-nil pointer to a @ref union_diff iff @p diff is a
697 /// @ref union_diff node.
698 const union_diff*
700 {return dynamic_cast<const union_diff*>(diff);}
701 
702 /// Test if a diff node is a @ref class_or_union_diff node.
703 ///
704 /// @param d the diff node to consider.
705 ///
706 /// @return a non-nil pointer to the @ref class_or_union_diff denoted
707 /// by @p d iff @p d is a @ref class_or_union_diff.
708 const class_or_union_diff*
710 {return dynamic_cast<const class_or_union_diff*>(d);}
711 
712 /// Test if a diff node is a @ref class_or_union_diff between two
713 /// anonymous classes or unions.
714 ///
715 /// @param d the diff node to consider.
716 ///
717 /// @return a non-nil pointer to the @ref class_or_union_diff iff @p
718 /// denoted by @p d iff @p is pointer to an anonymous class or union
719 /// diff.
720 const class_or_union_diff*
722 {
723  if (const class_or_union_diff *dif = is_class_or_union_diff(d))
724  if (dif->first_class_or_union()->get_is_anonymous())
725  return dif;
726  return 0;
727 }
728 
729 /// Test if a diff node is a @ref typedef_diff node.
730 ///
731 /// @param diff the diff node to consider.
732 ///
733 /// @return a non-nil pointer to a @ref typedef_diff iff @p diff is a
734 /// @ref typedef_diff node.
735 const typedef_diff*
737 {return dynamic_cast<const typedef_diff*>(diff);}
738 
739 /// Test if a diff node is a @ref subrange_diff node.
740 ///
741 /// @param diff the diff node to consider.
742 ///
743 /// @return a non-nil pointer to a @ref subrange_diff iff @p diff is a
744 /// @ref subrange_diff node.
745 const subrange_diff*
747 {return dynamic_cast<const subrange_diff*>(diff);}
748 
749 /// Test if a diff node is a @ref array_diff node.
750 ///
751 /// @param diff the diff node to consider.
752 ///
753 /// @return a non-nil pointer to a @ref array_diff iff @p diff is a
754 /// @ref array_diff node.
755 const array_diff*
757 {return dynamic_cast<const array_diff*>(diff);}
758 
759 /// Test if a diff node is a @ref function_type_diff node.
760 ///
761 /// @param diff the diff node to consider.
762 ///
763 /// @return a non-nil pointer to a @ref function_type_diff iff @p diff is a
764 /// @ref function_type_diff node.
765 const function_type_diff*
767 {return dynamic_cast<const function_type_diff*>(diff);}
768 
769 /// Test if a given diff node carries a function type change with
770 /// local changes.
771 ///
772 /// @param diff the diff node to consider.
773 ///
774 /// @return a non-nil pointer to a @ref function_type_diff iff @p diff
775 /// is a function_type_diff node that carries a local change.
776 const function_type_diff*
778 {
780  if (d->has_local_changes())
781  return d;
782 
783  return 0;
784 }
785 
786 /// Test if a diff node is about differences between variables.
787 ///
788 /// @param diff the diff node to test.
789 ///
790 /// @return a pointer to the actual var_diff that @p diff is a type
791 /// of, iff it is about differences between variables.
792 const var_diff*
794 {
795  const var_diff* d = dynamic_cast<const var_diff*>(diff);
796  if (d)
798  return d;
799 }
800 
801 /// Test if a diff node is about differences between functions.
802 ///
803 /// @param diff the diff node to test.
804 ///
805 /// @return a pointer to the actual var_diff that @p diff is a type
806 /// of, iff it is about differences between variables.
807 const function_decl_diff*
809 {
810  const function_decl_diff *d = dynamic_cast<const function_decl_diff*>(diff);
811  if (d)
813  return d;
814 }
815 
816 /// Test if a diff node is about differences between two pointers.
817 ///
818 /// @param diff the diff node to consider.
819 ///
820 /// @return the @p diff converted into an instance of @ref
821 /// pointer_diff iff @p diff is about differences between two
822 /// pointers.
823 const pointer_diff*
825 {return dynamic_cast<const pointer_diff*>(diff);}
826 
827 /// Test if a diff node is about differences between two references.
828 ///
829 /// @param diff the diff node to consider.
830 ///
831 /// @return the @p diff converted into an instance of @ref
832 /// reference_diff iff @p diff is about differences between two
833 /// references.
834 const reference_diff*
836 {return dynamic_cast<const reference_diff*>(diff);}
837 
838 /// Test if a diff node is about differences between two qualified
839 /// types.
840 ///
841 /// @param diff the diff node to consider.
842 ///
843 /// @return @p diff converted into an instance of @ref
844 /// qualified_type_diff iff @p diff is about differences between two
845 /// qualified types.
846 const qualified_type_diff*
848 {return dynamic_cast<const qualified_type_diff*>(diff);}
849 
850 /// Test if a diff node is a reference or pointer diff node to a
851 /// change that is neither basic type change nor distinct type change.
852 ///
853 /// Note that this function also works on diffs of typedefs of
854 /// reference or pointer.
855 ///
856 /// @param diff the diff node to consider.
857 ///
858 /// @return true iff @p diff is a eference or pointer diff node to a
859 /// change that is neither basic type change nor distinct type change.
860 bool
862 {
864  if (const reference_diff* d = is_reference_diff(diff))
865  {
868  return false;
869  return true;
870  }
871  else if (const pointer_diff *d = is_pointer_diff(diff))
872  {
873  diff = peel_pointer_diff(d);
875  return false;
876  return true;
877  }
878 
879  return false;
880 }
881 
882 /// Test if a diff node is about differences between two function
883 /// parameters.
884 ///
885 /// @param diff the diff node to consider.
886 ///
887 /// @return the @p diff converted into an instance of @ref
888 /// reference_diff iff @p diff is about differences between two
889 /// function parameters.
890 const fn_parm_diff*
892 {return dynamic_cast<const fn_parm_diff*>(diff);}
893 
894 /// Test if a diff node is about differences between two base class
895 /// specifiers.
896 ///
897 /// @param diff the diff node to consider.
898 ///
899 /// @return the @p diff converted into an instance of @ref base_diff
900 /// iff @p diff is about differences between two base class
901 /// specifiers.
902 const base_diff*
904 {return dynamic_cast<const base_diff*>(diff);}
905 
906 /// Test if a diff node is about differences between two diff nodes of
907 /// different kinds.
908 ///
909 /// @param diff the diff node to consider.
910 ///
911 /// @return the @p diff converted into an instance of @ref
912 /// distintc_diff iff @p diff is about differences between two diff
913 /// nodes of different kinds.
914 const distinct_diff*
916 {return dynamic_cast<const distinct_diff*>(diff);}
917 
918 /// Test if a diff node is a @ref corpus_diff node.
919 ///
920 /// @param diff the diff node to consider.
921 ///
922 /// @return a non-nil pointer to a @ref corpus_diff iff @p diff is a
923 /// @ref corpus_diff node.
924 const corpus_diff*
926 {return dynamic_cast<const corpus_diff*>(diff);}
927 
928 /// Test if a diff node is a child node of a function parameter diff node.
929 ///
930 /// @param diff the diff node to test.
931 ///
932 /// @return true iff @p diff is a child node of a function parameter
933 /// diff node.
934 bool
936 {return diff && is_fn_parm_diff(diff->parent_node());}
937 
938 /// Test if a diff node is a child node of a base diff node.
939 ///
940 /// @param diff the diff node to test.
941 ///
942 /// @return true iff @p diff is a child node of a base diff node.
943 bool
945 {return diff && is_base_diff(diff->parent_node());}
946 
947 /// The default traverse function.
948 ///
949 /// @return true.
950 bool
952 {return true;}
953 
954 diff_context::diff_context()
955  : priv_(new diff_context::priv)
956 {
957  // Setup all the diff output filters we have.
959 
961  add_diff_filter(f);
962 
963  // f.reset(new filtering::harmless_filter);
964  // add_diff_filter(f);
965 
966  // f.reset(new filtering::harmful_filter);
967  // add_diff_filter(f);
968 }
969 
970 diff_context::~diff_context() = default;
971 
972 /// Test if logging was requested.
973 ///
974 /// @return true iff logging was requested.
975 bool
977 {return priv_->do_log_;}
978 
979 /// Set logging as requested.
980 ///
981 /// @param f the flag
982 void
984 {priv_->do_log_ = f;}
985 
986 /// Set the corpus diff relevant to this context.
987 ///
988 /// @param d the corpus_diff we are interested in.
989 void
991 {priv_->corpus_diff_ = d;}
992 
993 /// Get the corpus diff for the current context.
994 ///
995 /// @return the corpus diff of this context.
996 const corpus_diff_sptr&
998 {return priv_->corpus_diff_;}
999 
1000 /// Getter for the first corpus of the corpus diff of the current context.
1001 ///
1002 /// @return the first corpus of the corpus diff of the current
1003 /// context, if no corpus diff is associated to the context.
1004 corpus_sptr
1006 {
1007  if (priv_->corpus_diff_)
1008  return priv_->corpus_diff_->first_corpus();
1009  return corpus_sptr();
1010 }
1011 
1012 /// Getter for the second corpus of the corpus diff of the current
1013 /// context.
1014 ///
1015 /// @return the second corpus of the corpus diff of the current
1016 /// context, if no corpus diff is associated to the context.
1017 corpus_sptr
1019 {
1020  if (priv_->corpus_diff_)
1021  return priv_->corpus_diff_->second_corpus();
1022  return corpus_sptr();
1023 }
1024 
1025 /// Getter of the reporter to be used in this context.
1026 ///
1027 /// @return the reporter to be used in this context.
1030 {
1031  if (!priv_->reporter_)
1032  {
1033  if (show_leaf_changes_only())
1034  priv_->reporter_.reset(new leaf_reporter);
1035  else
1036  priv_->reporter_.reset(new default_reporter);
1037  }
1038  ABG_ASSERT(priv_->reporter_);
1039  return priv_->reporter_;
1040 }
1041 
1042 /// Setter of the reporter to be used in this context.
1043 ///
1044 /// @param r the reporter to be used in this context.
1045 void
1047 {priv_->reporter_ = r;}
1048 
1049 /// Tests if the current diff context already has a diff for two decls.
1050 ///
1051 /// @param first the first decl to consider.
1052 ///
1053 /// @param second the second decl to consider.
1054 ///
1055 /// @return a pointer to the diff for @p first @p second if found,
1056 /// null otherwise.
1057 diff_sptr
1058 diff_context::has_diff_for(const type_or_decl_base_sptr first,
1059  const type_or_decl_base_sptr second) const
1060 {
1061  types_or_decls_diff_map_type::const_iterator i =
1062  priv_->types_or_decls_diff_map.find(std::make_pair(first, second));
1063  if (i != priv_->types_or_decls_diff_map.end())
1064  return i->second;
1065  return diff_sptr();
1066 }
1067 
1068 /// Tests if the current diff context already has a diff for two types.
1069 ///
1070 /// @param first the first type to consider.
1071 ///
1072 /// @param second the second type to consider.
1073 ///
1074 /// @return a pointer to the diff for @p first @p second if found,
1075 /// null otherwise.
1076 diff_sptr
1077 diff_context::has_diff_for_types(const type_base_sptr first,
1078  const type_base_sptr second) const
1079 {return has_diff_for(first, second);}
1080 
1081 /// Tests if the current diff context already has a given diff.
1082 ///
1083 ///@param d the diff to consider.
1084 ///
1085 /// @return a pointer to the diff found for @p d
1086 const diff*
1087 diff_context::has_diff_for(const diff* d) const
1088 {return has_diff_for(d->first_subject(), d->second_subject()).get();}
1089 
1090 /// Tests if the current diff context already has a given diff.
1091 ///
1092 ///@param d the diff to consider.
1093 ///
1094 /// @return a pointer to the diff found for @p d
1095 diff_sptr
1096 diff_context::has_diff_for(const diff_sptr d) const
1097 {return has_diff_for(d->first_subject(), d->second_subject());}
1098 
1099 /// Getter for the bitmap that represents the set of categories that
1100 /// the user wants to see reported.
1101 ///
1102 /// @return a bitmap that represents the set of categories that the
1103 /// user wants to see reported.
1106 {return priv_->allowed_category_;}
1107 
1108 /// Setter for the bitmap that represents the set of categories that
1109 /// the user wants to see reported.
1110 ///
1111 /// @param c a bitmap that represents the set of categories that the
1112 /// user wants to see represented.
1113 void
1115 {priv_->allowed_category_ = c;}
1116 
1117 /// Setter for the bitmap that represents the set of categories that
1118 /// the user wants to see reported
1119 ///
1120 /// This function perform a bitwise or between the new set of
1121 /// categories and the current ones, and then sets the current
1122 /// categories to the result of the or.
1123 ///
1124 /// @param c a bitmap that represents the set of categories that the
1125 /// user wants to see represented.
1126 void
1128 {priv_->allowed_category_ = priv_->allowed_category_ | c;}
1129 
1130 /// Setter for the bitmap that represents the set of categories that
1131 /// the user wants to see reported
1132 ///
1133 /// This function actually unsets bits from the current categories.
1134 ///
1135 /// @param c a bitmap that represents the set of categories to unset
1136 /// from the current categories.
1137 void
1139 {priv_->allowed_category_ = priv_->allowed_category_ & ~c;}
1140 
1141 /// Add a diff for two decls to the cache of the current diff_context.
1142 ///
1143 /// Doing this allows to later find the added diff from its two
1144 /// subject decls.
1145 ///
1146 /// @param first the first decl to consider.
1147 ///
1148 /// @param second the second decl to consider.
1149 ///
1150 /// @param the diff to add.
1151 void
1152 diff_context::add_diff(type_or_decl_base_sptr first,
1153  type_or_decl_base_sptr second,
1154  const diff_sptr d)
1155 {priv_->types_or_decls_diff_map[std::make_pair(first, second)] = d;}
1156 
1157 /// Add a diff tree node to the cache of the current diff_context
1158 ///
1159 /// @param d the diff tree node to add.
1160 void
1161 diff_context::add_diff(const diff* d)
1162 {
1163  if (d)
1164  {
1165  diff_sptr dif(const_cast<diff*>(d), noop_deleter());
1166  add_diff(d->first_subject(), d->second_subject(), dif);
1167  }
1168 }
1169 
1170 /// Add a diff tree node to the cache of the current diff_context
1171 ///
1172 /// @param d the diff tree node to add.
1173 void
1174 diff_context::add_diff(const diff_sptr d)
1175 {
1176  if (d)
1177  add_diff(d->first_subject(), d->second_subject(), d);
1178 }
1179 
1180 /// Getter for the @ref CanonicalDiff "canonical diff node" for the
1181 /// @ref diff represented by their two subjects.
1182 ///
1183 /// @param first the first subject of the diff.
1184 ///
1185 /// @param second the second subject of the diff.
1186 ///
1187 /// @return the canonical diff for the diff node represented by the
1188 /// two diff subjects @p first and @p second. If no canonical diff
1189 /// node was registered for these subjects, then a nil node is
1190 /// returned.
1191 diff_sptr
1193  const type_or_decl_base_sptr second) const
1194 {return has_diff_for(first, second);}
1195 
1196 /// Getter for the @ref CanonicalDiff "canonical diff node" for the
1197 /// @ref diff represented by the two subjects of a given diff node.
1198 ///
1199 /// @param d the diff node to get the canonical node for.
1200 ///
1201 /// @return the canonical diff for the diff node represented by the
1202 /// two diff subjects of @p d. If no canonical diff node was
1203 /// registered for these subjects, then a nil node is returned.
1204 diff_sptr
1206 {return has_diff_for(d);}
1207 
1208 /// Setter for the @ref CanonicalDiff "canonical diff node" for the
1209 /// @ref diff represented by their two subjects.
1210 ///
1211 /// @param first the first subject of the diff.
1212 ///
1213 /// @param second the second subject of the diff.
1214 ///
1215 /// @param d the new canonical diff.
1216 void
1217 diff_context::set_canonical_diff_for(const type_or_decl_base_sptr first,
1218  const type_or_decl_base_sptr second,
1219  const diff_sptr d)
1220 {
1221  ABG_ASSERT(d);
1222  if (!has_diff_for(first, second))
1223  {
1224  add_diff(first, second, d);
1225  priv_->canonical_diffs.push_back(d);
1226  }
1227 }
1228 
1229 /// If there is is a @ref CanonicalDiff "canonical diff node"
1230 /// registered for two diff subjects, return it. Otherwise, register
1231 /// a canonical diff node for these two diff subjects and return it.
1232 ///
1233 /// @param first the first subject of the diff.
1234 ///
1235 /// @param second the second subject of the diff.
1236 ///
1237 /// @param d the new canonical diff node.
1238 ///
1239 /// @return the canonical diff node.
1240 diff_sptr
1241 diff_context::set_or_get_canonical_diff_for(const type_or_decl_base_sptr first,
1242  const type_or_decl_base_sptr second,
1243  const diff_sptr canonical_diff)
1244 {
1245  ABG_ASSERT(canonical_diff);
1246 
1247  diff_sptr canonical = get_canonical_diff_for(first, second);
1248  if (!canonical)
1249  {
1250  canonical = canonical_diff;
1251  set_canonical_diff_for(first, second, canonical);
1252  }
1253  return canonical;
1254 }
1255 
1256 /// Set the canonical diff node property of a given diff node
1257 /// appropriately.
1258 ///
1259 /// For a given diff node that has no canonical diff node, retrieve
1260 /// the canonical diff node (by looking at its diff subjects and at
1261 /// the current context) and set the canonical diff node property of
1262 /// the diff node to that canonical diff node. If no canonical diff
1263 /// node has been registered to the diff context for the subjects of
1264 /// the diff node then, register the canonical diff node as being the
1265 /// diff node itself; and set its canonical diff node property as
1266 /// such. Otherwise, if the diff node already has a canonical diff
1267 /// node, do nothing.
1268 ///
1269 /// @param diff the diff node to initialize the canonical diff node
1270 /// property for.
1271 void
1273 {
1274  if (diff->get_canonical_diff() == 0)
1275  {
1276  diff_sptr canonical =
1277  set_or_get_canonical_diff_for(diff->first_subject(),
1278  diff->second_subject(),
1279  diff);
1280  diff->set_canonical_diff(canonical.get());
1281  }
1282 }
1283 
1284 /// Add a diff node to the set of diff nodes that are kept alive for
1285 /// the life time of the current instance of diff_context.
1286 ///
1287 /// Note that diff added to the diff cache are kept alive as well, and
1288 /// don't need to be passed to this function to be kept alive.
1289 ///
1290 /// @param d the diff node to be kept alive during the life time of
1291 /// the current instance of @ref diff_context.
1292 void
1294 {priv_->live_diffs_.insert(d);}
1295 
1296 /// Test if a diff node has been traversed.
1297 ///
1298 /// @param d the diff node to consider.
1299 ///
1300 /// @return the first diff node against which @p d is redundant.
1301 diff*
1303 {
1304  const diff* canonical = d->get_canonical_diff();
1305  ABG_ASSERT(canonical);
1306 
1307  size_t ptr_value = reinterpret_cast<size_t>(canonical);
1308  pointer_map::iterator it = priv_->visited_diff_nodes_.find(ptr_value);
1309  if (it != priv_->visited_diff_nodes_.end())
1310  return reinterpret_cast<diff*>(it->second);
1311  else
1312  return 0;
1313 }
1314 
1315 /// Test if a diff node has been traversed.
1316 ///
1317 /// @param d the diff node to consider.
1318 ///
1319 /// @return the first diff node against which @p d is redundant.
1320 diff_sptr
1322 {
1324  return diff;
1325 }
1326 
1327 /// Mark a diff node as traversed by a traversing algorithm.
1328 ///
1329 /// Actually, it's the @ref CanonicalDiff "canonical diff" of this
1330 /// node that is marked as traversed.
1331 ///
1332 /// Subsequent invocations of diff_has_been_visited() on the diff node
1333 /// will yield true.
1334 void
1336 {
1337  if (diff_has_been_visited(d))
1338  return;
1339 
1340  const diff* canonical = d->get_canonical_diff();
1341  ABG_ASSERT(canonical);
1342 
1343  size_t canonical_ptr_value = reinterpret_cast<size_t>(canonical);
1344  size_t diff_ptr_value = reinterpret_cast<size_t>(d);
1345  priv_->visited_diff_nodes_[canonical_ptr_value] = diff_ptr_value;
1346 }
1347 
1348 /// Unmark all the diff nodes that were marked as being traversed.
1349 void
1351 {priv_->visited_diff_nodes_.clear();}
1352 
1353 /// This sets a flag that, if it's true, then during the traversing of
1354 /// a diff nodes tree each node is visited at most once.
1355 ///
1356 /// @param f if true then during the traversing of a diff nodes tree
1357 /// each node is visited at most once.
1358 ///
1359 void
1361 {priv_->forbid_visiting_a_node_twice_ = f;}
1362 
1363 /// This function sets a flag os that if @ref
1364 /// forbid_visiting_a_node_twice() returns true, then each time the
1365 /// node visitor starts visiting a new interface, it resets the
1366 /// memory the systems has about already visited node.
1367 ///
1368 /// @param f the flag to set.
1369 void
1371 {priv_->reset_visited_diffs_for_each_interface_ = f;}
1372 
1373 /// Return a flag that, if true, then during the traversing of a diff
1374 /// nodes tree each node is visited at most once.
1375 ///
1376 /// @return the boolean flag.
1377 bool
1379 {return priv_->forbid_visiting_a_node_twice_;}
1380 
1381 /// Return a flag that, if true, then during the traversing of a diff
1382 /// nodes tree each node is visited at most once, while visiting the
1383 /// diff tree underneath a given interface (public function or
1384 /// variable). Each time a new interface is visited, the nodes
1385 /// visited while visiting previous interfaces can be visited again.
1386 ///
1387 /// @return the boolean flag.
1388 ///
1389 /// @return the boolean flag.
1390 bool
1392 {
1393  return (priv_->forbid_visiting_a_node_twice_
1394  && priv_->reset_visited_diffs_for_each_interface_);
1395 }
1396 
1397 /// Getter for the diff tree nodes filters to apply to diff sub-trees.
1398 ///
1399 /// @return the vector of tree filters to apply to diff sub-trees.
1400 const filtering::filters&
1402 {return priv_->filters_;}
1403 
1404 /// Setter for the diff filters to apply to a given diff sub-tree.
1405 ///
1406 /// @param f the new diff filter to add to the vector of diff filters
1407 /// to apply to diff sub-trees.
1408 void
1410 {priv_->filters_.push_back(f);}
1411 
1412 /// Apply the diff filters to a given diff sub-tree.
1413 ///
1414 /// If the current context is instructed to filter out some categories
1415 /// then this function walks the given sub-tree and categorizes its
1416 /// nodes by using the filters held by the context.
1417 ///
1418 /// @param diff the diff sub-tree to apply the filters to.
1419 void
1421 {
1422  if (!diff)
1423  return;
1424 
1425  if (!diff->has_changes())
1426  return;
1427 
1428  for (filtering::filters::const_iterator i = diff_filters().begin();
1429  i != diff_filters().end();
1430  ++i)
1431  {
1433  if (do_log())
1434  {
1435  std::cerr << "applying a filter to diff '"
1437  << "'...\n";
1438  t.start();
1439  }
1440 
1442 
1443  if (do_log())
1444  {
1445  t.stop();
1446  std::cerr << "filter applied!:" << t << "\n";
1447 
1448  std::cerr << "propagating categories for the same diff node ... \n";
1449  t.start();
1450  }
1451 
1453 
1454  if (do_log())
1455  {
1456  t.stop();
1457  std::cerr << "category propagated!: " << t << "\n";
1458  }
1459  }
1460 
1461  }
1462 
1463 /// Apply the diff filters to the diff nodes of a @ref corpus_diff
1464 /// instance.
1465 ///
1466 /// If the current context is instructed to filter out some categories
1467 /// then this function walks the diff tree and categorizes its nodes
1468 /// by using the filters held by the context.
1469 ///
1470 /// @param diff the corpus diff to apply the filters to.
1471 void
1473 {
1474 
1475  if (!diff || !diff->has_changes())
1476  return;
1477 
1478  for (filtering::filters::const_iterator i = diff_filters().begin();
1479  i != diff_filters().end();
1480  ++i)
1481  {
1484  }
1485 }
1486 
1487 /// Getter for the vector of suppressions that specify which diff node
1488 /// reports should be dropped on the floor.
1489 ///
1490 /// @return the set of suppressions.
1491 const suppressions_type&
1493 {return priv_->suppressions_;}
1494 
1495 /// Getter for the vector of suppressions that specify which diff node
1496 /// reports should be dropped on the floor.
1497 ///
1498 /// @return the set of suppressions.
1501 {
1502  // Invalidate negated and direct suppressions caches that are built
1503  // from priv_->suppressions_;
1504  priv_->negated_suppressions_.clear();
1505  priv_->direct_suppressions_.clear();
1506  return priv_->suppressions_;
1507 }
1508 
1509 /// Getter of the negated suppression specifications that are
1510 /// comprised in the general vector of suppression specifications
1511 /// returned by diff_context::suppressions().
1512 ///
1513 /// Note that the first invocation of this function scans the vector
1514 /// returned by diff_context::suppressions() and caches the negated
1515 /// suppressions from there.
1516 ///
1517 /// Subsequent invocations of this function just return the cached
1518 /// negated suppressions.
1519 ///
1520 /// @return the negated suppression specifications stored in this diff
1521 /// context.
1524 {
1525  if (priv_->negated_suppressions_.empty())
1526  for (auto s : suppressions())
1527  if (is_negated_suppression(s))
1528  priv_->negated_suppressions_.push_back(s);
1529 
1530  return priv_->negated_suppressions_;
1531 }
1532 
1533 /// Getter of the direct suppression specification (those that are
1534 /// not negated) comprised in the general vector of suppression
1535 /// specifications returned by diff_context::suppression().
1536 ///
1537 /// Note that the first invocation of this function scans the vector
1538 /// returned by diff_context::suppressions() and caches the direct
1539 /// suppressions from there.
1540 ///
1541 /// Subsequent invocations of this function just return the cached
1542 /// direct suppressions.
1543 ///
1544 /// @return the direct suppression specifications.
1547 {
1548  if (priv_->direct_suppressions_.empty())
1549  {
1550  for (auto s : suppressions())
1551  if (!is_negated_suppression(s))
1552  priv_->direct_suppressions_.push_back(s);
1553  }
1554  return priv_->direct_suppressions_;
1555 }
1556 
1557 /// Add a new suppression specification that specifies which diff node
1558 /// reports should be dropped on the floor.
1559 ///
1560 /// @param suppr the new suppression specification to add to the
1561 /// existing set of suppressions specifications of the diff context.
1562 void
1564 {
1565  priv_->suppressions_.push_back(suppr);
1566  // Invalidate negated and direct suppressions caches that are built
1567  // from priv_->suppressions_;
1568  priv_->negated_suppressions_.clear();
1569  priv_->direct_suppressions_.clear();
1570 }
1571 
1572 /// Add new suppression specifications that specify which diff node
1573 /// reports should be dropped on the floor.
1574 ///
1575 /// @param supprs the new suppression specifications to add to the
1576 /// existing set of suppression specifications of the diff context.
1577 void
1579 {
1580  priv_->suppressions_.insert(priv_->suppressions_.end(),
1581  supprs.begin(), supprs.end());
1582 }
1583 
1584 /// Test if it's requested to perform diff node categorization.
1585 ///
1586 /// @return true iff it's requested to perform diff node
1587 /// categorization.
1588 bool
1590 {return priv_->perform_change_categorization_;}
1591 
1592 /// Request change categorization or not.
1593 ///
1594 /// @param f true iff change categorization is requested.
1595 void
1597 {priv_->perform_change_categorization_ = f;}
1598 
1599 /// Set the flag that indicates if the diff using this context should
1600 /// show only leaf changes or not.
1601 ///
1602 /// @param f the new value of the flag that indicates if the diff
1603 /// using this context should show only leaf changes or not.
1604 void
1606 {
1607  // This function can be called only if the reporter hasn't yet been
1608  // created. Once it's been created, we are supposed to live with
1609  // it.
1610  ABG_ASSERT(priv_->reporter_ == 0);
1611  priv_->leaf_changes_only_ = f;
1612 }
1613 
1614 /// Get the flag that indicates if the diff using this context should
1615 /// show only leaf changes or not.
1616 ///
1617 /// @return the value of the flag that indicates if the diff using
1618 /// this context should show only leaf changes or not.
1619 bool
1621 {return priv_->leaf_changes_only_;}
1622 
1623 /// Get the flag that indicates if the diff reports using this context
1624 /// should show sizes and offsets in an hexadecimal base or not. If
1625 /// not, then they are to be shown in a decimal base.
1626 ///
1627 /// @return true iff sizes and offsets are to be shown in an
1628 /// hexadecimal base.
1629 bool
1631 {return priv_->hex_values_;}
1632 
1633 /// Set the flag that indicates if diff reports using this context
1634 /// should show sizes and offsets in an hexadecimal base or not. If
1635 /// not, then they are to be shown in a decimal base.
1636 ///
1637 /// @param f if true then sizes and offsets are to be shown in an
1638 /// hexadecimal base.
1639 void
1641 {priv_->hex_values_ = f;}
1642 
1643 /// Get the flag that indicates if diff reports using this context
1644 /// should show sizes and offsets in bits, rather than bytes.
1645 ///
1646 /// @return true iff sizes and offsets are to be shown in bits.
1647 /// Otherwise they are to be shown in bytes.
1648 bool
1650 {return priv_->show_offsets_sizes_in_bits_;}
1651 
1652 /// Set the flag that indicates if diff reports using this context
1653 /// should show sizes and offsets in bits, rather than bytes.
1654 ///
1655 /// @param f if true then sizes and offsets are to be shown in bits.
1656 /// Otherwise they are to be shown in bytes.
1657 void
1659 {priv_->show_offsets_sizes_in_bits_ = f;}
1660 
1661 /// Set a flag saying if offset changes should be reported in a
1662 /// relative way. That is, if the report should say how of many bits
1663 /// a class/struct data member did move.
1664 ///
1665 /// @param f the new boolean value of the flag.
1666 void
1668 {priv_->show_relative_offset_changes_ = f;}
1669 
1670 /// Get the flag saying if offset changes should be reported in a
1671 /// relative way. That is, if the report should say how of many bits
1672 /// a class/struct data member did move.
1673 ///
1674 /// @return the boolean value of the flag.
1675 bool
1677 {return priv_->show_relative_offset_changes_;}
1678 
1679 /// Set a flag saying if the comparison module should only show the
1680 /// diff stats.
1681 ///
1682 /// @param f the flag to set.
1683 void
1685 {priv_->show_stats_only_ = f;}
1686 
1687 /// Test if the comparison module should only show the diff stats.
1688 ///
1689 /// @return true if the comparison module should only show the diff
1690 /// stats, false otherwise.
1691 bool
1693 {return priv_->show_stats_only_;}
1694 
1695 /// Setter for the property that says if the comparison module should
1696 /// show the soname changes in its report.
1697 ///
1698 /// @param f the new value of the property.
1699 void
1701 {priv_->show_soname_change_ = f;}
1702 
1703 /// Getter for the property that says if the comparison module should
1704 /// show the soname changes in its report.
1705 ///
1706 /// @return the value of the property.
1707 bool
1709 {return priv_->show_soname_change_;}
1710 
1711 /// Setter for the property that says if the comparison module should
1712 /// show the architecture changes in its report.
1713 ///
1714 /// @param f the new value of the property.
1715 void
1717 {priv_->show_architecture_change_ = f;}
1718 
1719 /// Getter for the property that says if the comparison module should
1720 /// show the architecture changes in its report.
1721 ///
1722 /// @return the value of the property.
1723 bool
1725 {return priv_->show_architecture_change_;}
1726 
1727 /// Set a flag saying to show the deleted functions.
1728 ///
1729 /// @param f true to show deleted functions.
1730 void
1732 {priv_->show_deleted_fns_ = f;}
1733 
1734 /// @return true if we want to show the deleted functions, false
1735 /// otherwise.
1736 bool
1738 {return priv_->show_deleted_fns_;}
1739 
1740 /// Set a flag saying to show the changed functions.
1741 ///
1742 /// @param f true to show the changed functions.
1743 void
1745 {priv_->show_changed_fns_ = f;}
1746 
1747 /// @return true if we want to show the changed functions, false otherwise.
1748 bool
1750 {return priv_->show_changed_fns_;}
1751 
1752 /// Set a flag saying to show the added functions.
1753 ///
1754 /// @param f true to show the added functions.
1755 void
1757 {priv_->show_added_fns_ = f;}
1758 
1759 /// @return true if we want to show the added functions, false
1760 /// otherwise.
1761 bool
1763 {return priv_->show_added_fns_;}
1764 
1765 /// Set a flag saying to show the deleted variables.
1766 ///
1767 /// @param f true to show the deleted variables.
1768 void
1770 {priv_->show_deleted_vars_ = f;}
1771 
1772 /// @return true if we want to show the deleted variables, false
1773 /// otherwise.
1774 bool
1776 {return priv_->show_deleted_vars_;}
1777 
1778 /// Set a flag saying to show the changed variables.
1779 ///
1780 /// @param f true to show the changed variables.
1781 void
1783 {priv_->show_changed_vars_ = f;}
1784 
1785 /// @return true if we want to show the changed variables, false otherwise.
1786 bool
1788 {return priv_->show_changed_vars_;}
1789 
1790 /// Set a flag saying to show the added variables.
1791 ///
1792 /// @param f true to show the added variables.
1793 void
1795 {priv_->show_added_vars_ = f;}
1796 
1797 /// @return true if we want to show the added variables, false
1798 /// otherwise.
1799 bool
1801 {return priv_->show_added_vars_;}
1802 
1803 bool
1804 diff_context::show_linkage_names() const
1805 {return priv_->show_linkage_names_;}
1806 
1807 void
1808 diff_context::show_linkage_names(bool f)
1809 {priv_->show_linkage_names_= f;}
1810 
1811 /// Set a flag saying to show location information.
1812 ///
1813 /// @param f true to show location information.
1814 void
1816 {priv_->show_locs_= f;}
1817 
1818 /// @return true if we want to show location information, false
1819 /// otherwise.
1820 bool
1822 {return priv_->show_locs_;}
1823 
1824 /// A getter for the flag that says if we should report about
1825 /// functions or variables diff nodes that have *exclusively*
1826 /// redundant diff tree children nodes.
1827 ///
1828 /// @return the flag.
1829 bool
1831 {return priv_->show_redundant_changes_;}
1832 
1833 /// A setter for the flag that says if we should report about
1834 /// functions or variables diff nodes that have *exclusively*
1835 /// redundant diff tree children nodes.
1836 ///
1837 /// @param f the flag to set.
1838 void
1840 {priv_->show_redundant_changes_ = f;}
1841 
1842 /// Getter for the flag that indicates if symbols not referenced by
1843 /// any debug info are to be compared and reported about.
1844 ///
1845 /// @return the boolean flag.
1846 bool
1848 {return priv_->show_syms_unreferenced_by_di_;}
1849 
1850 /// Setter for the flag that indicates if symbols not referenced by
1851 /// any debug info are to be compared and reported about.
1852 ///
1853 /// @param f the new flag to set.
1854 void
1856 {priv_->show_syms_unreferenced_by_di_ = f;}
1857 
1858 /// Getter for the flag that indicates if symbols not referenced by
1859 /// any debug info and that got added are to be reported about.
1860 ///
1861 /// @return true iff symbols not referenced by any debug info and that
1862 /// got added are to be reported about.
1863 bool
1865 {return priv_->show_added_syms_unreferenced_by_di_;}
1866 
1867 /// Setter for the flag that indicates if symbols not referenced by
1868 /// any debug info and that got added are to be reported about.
1869 ///
1870 /// @param f the new flag that says if symbols not referenced by any
1871 /// debug info and that got added are to be reported about.
1872 void
1874 {priv_->show_added_syms_unreferenced_by_di_ = f;}
1875 
1876 /// Setter for the flag that indicates if changes on types unreachable
1877 /// from global functions and variables are to be reported.
1878 ///
1879 /// @param f if true, then changes on types unreachable from global
1880 /// functions and variables are to be reported.
1881 void
1883 {priv_->show_unreachable_types_ = f;}
1884 
1885 /// Getter for the flag that indicates if changes on types unreachable
1886 /// from global functions and variables are to be reported.
1887 ///
1888 /// @return true iff changes on types unreachable from global
1889 /// functions and variables are to be reported.
1890 bool
1892 {return priv_->show_unreachable_types_;}
1893 
1894 /// Getter of the flag that indicates if the leaf reporter should
1895 /// display a summary of the interfaces impacted by a given leaf
1896 /// change or not.
1897 ///
1898 /// @return the flag that indicates if the leaf reporter should
1899 /// display a summary of the interfaces impacted by a given leaf
1900 /// change or not.
1901 bool
1903 {return priv_->show_impacted_interfaces_;}
1904 
1905 /// Setter of the flag that indicates if the leaf reporter should
1906 /// display a summary of the interfaces impacted by a given leaf
1907 /// change or not.
1908 ///
1909 /// @param f the new value of the flag that indicates if the leaf
1910 /// reporter should display a summary of the interfaces impacted by a
1911 /// given leaf change or not.
1912 void
1914 {priv_->show_impacted_interfaces_ = f;}
1915 
1916 /// Setter for the default output stream used by code of the
1917 /// comparison engine. By default the default output stream is a NULL
1918 /// pointer.
1919 ///
1920 /// @param o a pointer to the default output stream.
1921 void
1923 {priv_->default_output_stream_ = o;}
1924 
1925 /// Getter for the default output stream used by code of the
1926 /// comparison engine. By default the default output stream is a NULL
1927 /// pointer.
1928 ///
1929 /// @return a pointer to the default output stream.
1930 ostream*
1932 {return priv_->default_output_stream_;}
1933 
1934 /// Setter for the errror output stream used by code of the comparison
1935 /// engine. By default the error output stream is a NULL pointer.
1936 ///
1937 /// @param o a pointer to the error output stream.
1938 void
1940 {priv_->error_output_stream_ = o;}
1941 
1942 /// Getter for the errror output stream used by code of the comparison
1943 /// engine. By default the error output stream is a NULL pointer.
1944 ///
1945 /// @return a pointer to the error output stream.
1946 ostream*
1948 {return priv_->error_output_stream_;}
1949 
1950 /// Test if the comparison engine should dump the diff tree for the
1951 /// changed functions and variables it has.
1952 ///
1953 /// @return true if after the comparison, the engine should dump the
1954 /// diff tree for the changed functions and variables it has.
1955 bool
1957 {return priv_->dump_diff_tree_;}
1958 
1959 /// Set if the comparison engine should dump the diff tree for the
1960 /// changed functions and variables it has.
1961 ///
1962 /// @param f true if after the comparison, the engine should dump the
1963 /// diff tree for the changed functions and variables it has.
1964 void
1966 {priv_->dump_diff_tree_ = f;}
1967 
1968 /// Emit a textual representation of a diff tree to the error output
1969 /// stream of the current context, for debugging purposes.
1970 ///
1971 /// @param d the diff tree to serialize to the error output associated
1972 /// to the current instance of @ref diff_context.
1973 void
1975 {
1976  if (error_output_stream())
1978 }
1979 
1980 /// Emit a textual representation of a @ref corpus_diff tree to the error
1981 /// output stream of the current context, for debugging purposes.
1982 ///
1983 /// @param d the @ref corpus_diff tree to serialize to the error
1984 /// output associated to the current instance of @ref diff_context.
1985 void
1987 {
1988  if (error_output_stream())
1990 }
1991 // </diff_context stuff>
1992 
1993 // <diff stuff>
1994 
1995 /// Constructor for the @ref diff type.
1996 ///
1997 /// This constructs a diff between two subjects that are actually
1998 /// declarations; the first and the second one.
1999 ///
2000 /// @param first_subject the first decl (subject) of the diff.
2001 ///
2002 /// @param second_subject the second decl (subject) of the diff.
2003 diff::diff(type_or_decl_base_sptr first_subject,
2004  type_or_decl_base_sptr second_subject)
2005  : priv_(new priv(first_subject, second_subject,
2008  /*reported_once=*/false,
2009  /*currently_reporting=*/false))
2010 {}
2011 
2012 /// Constructor for the @ref diff type.
2013 ///
2014 /// This constructs a diff between two subjects that are actually
2015 /// declarations; the first and the second one.
2016 ///
2017 /// @param first_subject the first decl (subject) of the diff.
2018 ///
2019 /// @param second_subject the second decl (subject) of the diff.
2020 ///
2021 /// @param ctxt the context of the diff. Note that this context
2022 /// object must stay alive during the entire life time of the current
2023 /// instance of @ref diff. Otherwise, memory corruption issues occur.
2024 diff::diff(type_or_decl_base_sptr first_subject,
2025  type_or_decl_base_sptr second_subject,
2026  diff_context_sptr ctxt)
2027  : priv_(new priv(first_subject, second_subject,
2028  ctxt, NO_CHANGE_CATEGORY,
2029  /*reported_once=*/false,
2030  /*currently_reporting=*/false))
2031 {}
2032 
2033 /// Test if logging was requested
2034 ///
2035 /// @return true iff logging was requested.
2036 bool
2038 {return context()->do_log();}
2039 
2040 /// Request logging (or not)
2041 ///
2042 /// @param f true iff logging is to be requested.
2043 void
2045 {context()->do_log(f);}
2046 
2047 /// Flag a given diff node as being traversed.
2048 ///
2049 /// For certain diff nodes like @ref class_diff, it's important to
2050 /// avoid traversing the node again while it's already being
2051 /// traversed; otherwise this leads to infinite loops. So the
2052 /// diff::begin_traversing() and diff::end_traversing() methods flag a
2053 /// given node as being traversed (or not), so that
2054 /// diff::is_traversing() can tell if the node is being traversed.
2055 ///
2056 /// Note that traversing a node means visiting it *and* visiting its
2057 /// children nodes.
2058 ///
2059 /// The canonical node is marked as being traversed too.
2060 ///
2061 /// These functions are called by the traversing code.
2062 void
2064 {
2066  if (priv_->canonical_diff_)
2067  priv_->canonical_diff_->priv_->traversing_ = true;
2068  priv_->traversing_ = true;
2069 }
2070 
2071 /// Tell if a given node is being traversed or not.
2072 ///
2073 /// Note that traversing a node means visiting it *and* visiting its
2074 /// children nodes.
2075 ///
2076 /// It's the canonical node which is looked at, actually.
2077 ///
2078 /// Please read the comments for the diff::begin_traversing() for mode
2079 /// context.
2080 ///
2081 /// @return true if the current instance of @diff is being traversed.
2082 bool
2084 {
2085  if (priv_->canonical_diff_)
2086  return priv_->canonical_diff_->priv_->traversing_;
2087  return priv_->traversing_;
2088 }
2089 
2090 /// Flag a given diff node as not being traversed anymore.
2091 ///
2092 /// Note that traversing a node means visiting it *and* visiting its
2093 /// children nodes.
2094 ///
2095 /// Please read the comments of the function diff::begin_traversing()
2096 /// for mode context.
2097 void
2099 {
2101  if (priv_->canonical_diff_)
2102  priv_->canonical_diff_->priv_->traversing_ = false;
2103  priv_->traversing_ = false;
2104 }
2105 
2106 /// Finish the insertion of a diff tree node into the diff graph.
2107 ///
2108 /// This function might be called several times. It must perform the
2109 /// insertion only once.
2110 ///
2111 /// For instance, certain kinds of diff tree node have specific
2112 /// children nodes that are populated after the constructor of the
2113 /// diff tree node has been called. In that case, calling overloads
2114 /// of this method ensures that these children nodes are properly
2115 /// gathered and setup.
2116 void
2118 {
2119  if (diff::priv_->finished_)
2120  return;
2122  diff::priv_->finished_ = true;
2123 }
2124 
2125 /// Getter of the first subject of the diff.
2126 ///
2127 /// @return the first subject of the diff.
2130 {return dynamic_pointer_cast<type_or_decl_base>(priv_->first_subject_);}
2131 
2132 /// Getter of the second subject of the diff.
2133 ///
2134 /// @return the second subject of the diff.
2137 {return dynamic_pointer_cast<type_or_decl_base>(priv_->second_subject_);}
2138 
2139 /// Getter for the children nodes of the current @ref diff node.
2140 ///
2141 /// @return a vector of the children nodes.
2142 const vector<diff*>&
2144 {return priv_->children_;}
2145 
2146 /// Getter for the parent node of the current @ref diff node.
2147 ///
2148 /// @return the parent node of the current @ref diff node.
2149 const diff*
2151 {return priv_->parent_;}
2152 
2153 /// Getter for the canonical diff of the current instance of @ref
2154 /// diff.
2155 ///
2156 /// Note that the canonical diff node for the current instanc eof diff
2157 /// node must have been set by invoking
2158 /// class_diff::initialize_canonical_diff() on the current instance of
2159 /// diff node.
2160 ///
2161 /// @return the canonical diff node or null if none was set.
2162 diff*
2164 {return priv_->canonical_diff_;}
2165 
2166 /// Setter for the canonical diff of the current instance of @ref
2167 /// diff.
2168 ///
2169 /// @param d the new canonical node to set.
2170 void
2172 {priv_->canonical_diff_ = d;}
2173 
2174 /// Add a new child node to the vector of children nodes for the
2175 /// current @ref diff node.
2176 ///
2177 /// @param d the new child node to add to the children nodes.
2178 void
2180 {
2181  ABG_ASSERT(d);
2182 
2183  // Ensure 'd' is kept alive for the life time of the context of this
2184  // diff.
2185  context()->keep_diff_alive(d);
2186 
2187  // Add the underlying pointer of 'd' to the vector of children.
2188  // Note that this vector holds no reference to 'd'. This is to avoid
2189  // reference cycles. The reference to 'd' is held by the context of
2190  // this diff, thanks to the call to context()->keep_diff_alive(d)
2191  // above.
2192  priv_->children_.push_back(d.get());
2193 
2194  d->priv_->parent_ = this;
2195 }
2196 
2197 /// Getter of the context of the current diff.
2198 ///
2199 /// @return the context of the current diff.
2200 const diff_context_sptr
2202 {return priv_->get_context();}
2203 
2204 /// Setter of the context of the current diff.
2205 ///
2206 /// @param c the new context to set.
2207 void
2209 {priv_->ctxt_ = c;}
2210 
2211 /// Tests if we are currently in the middle of emitting a report for
2212 /// this diff.
2213 ///
2214 /// @return true if we are currently emitting a report for the
2215 /// current diff, false otherwise.
2216 bool
2218 {
2219  if (priv_->canonical_diff_)
2220  return priv_->canonical_diff_->priv_->currently_reporting_;
2221  return priv_->currently_reporting_;
2222 }
2223 
2224 /// Sets a flag saying if we are currently in the middle of emitting
2225 /// a report for this diff.
2226 ///
2227 /// @param f true if we are currently emitting a report for the
2228 /// current diff, false otherwise.
2229 void
2231 {
2232  if (priv_->canonical_diff_)
2233  priv_->canonical_diff_->priv_->currently_reporting_ = f;
2234  priv_->currently_reporting_ = f;
2235 }
2236 
2237 /// Tests if a report has already been emitted for the current diff.
2238 ///
2239 /// @return true if a report has already been emitted for the
2240 /// current diff, false otherwise.
2241 bool
2243 {
2244  ABG_ASSERT(priv_->canonical_diff_);
2245  return priv_->canonical_diff_->priv_->reported_once_;
2246 }
2247 
2248 /// The generic traversing code that walks a given diff sub-tree.
2249 ///
2250 /// Note that there is a difference between traversing a diff node and
2251 /// visiting it. Basically, traversing a diff node means visiting it
2252 /// and visiting its children nodes too. So one can visit a node
2253 /// without traversing it. But traversing a node without visiting it
2254 /// is not possible.
2255 ///
2256 /// Note that the insertion of the "generic view" of the diff node
2257 /// into the graph being traversed is done "on the fly". The
2258 /// insertion of the "typed view" of the diff node into the graph is
2259 /// done implicitely. To learn more about the generic and typed view
2260 /// of the diff node, please read the introductory comments of the
2261 /// @ref diff class.
2262 ///
2263 /// Note that by default this traversing code visits a given class of
2264 /// equivalence of a diff node only once. This behaviour can been
2265 /// changed by calling
2266 /// diff_context::visiting_a_node_twice_is_forbidden(), but this is
2267 /// very risky as it might create endless loops while visiting a diff
2268 /// tree graph that has changes that refer to themselves; that is,
2269 /// diff tree graphs with cycles.
2270 ///
2271 /// When a diff node is encountered, the
2272 /// diff_node_visitor::visit_begin() method is invoked on the diff
2273 /// node first.
2274 ///
2275 /// If the diff node has already been visited, then
2276 /// node_visitor::visit_end() is called on it and the node traversing
2277 /// is done; the children of the diff node are not visited in this
2278 /// case.
2279 ///
2280 /// If the diff node has *NOT* been visited yet, then the
2281 /// diff_node_visitor::visit() method is invoked with it's 'pre'
2282 /// argument set to true. Then if the diff_node_visitor::visit()
2283 /// returns true, then the children nodes of the diff node are
2284 /// visited. Otherwise, no children nodes of the diff node is
2285 /// visited and the diff_node_visitor::visit_end() is called.
2286 
2287 /// After the children nodes are visited (and only if they are
2288 /// visited) the diff_node_visitor::visit() method is invoked with
2289 /// it's 'pre' argument set to false. And then the
2290 /// diff_node_visitor::visit_end() is called.
2291 ///
2292 /// @param v the entity that visits each node of the diff sub-tree.
2293 ///
2294 /// @return true to tell the caller that all of the sub-tree could be
2295 /// walked. This instructs the caller to keep walking the rest of the
2296 /// tree. Return false otherwise.
2297 bool
2299 {
2300  // Insert the "generic view" of the diff node into its graph.
2301  finish_diff_type();
2302 
2303  v.visit_begin(this);
2304 
2305  bool already_visited = false;
2306  if (context()->visiting_a_node_twice_is_forbidden()
2307  && context()->diff_has_been_visited(this))
2308  already_visited = true;
2309 
2310  bool mark_visited_nodes_as_traversed =
2312 
2313  if (!already_visited && !v.visit(this, /*pre=*/true))
2314  {
2315  v.visit_end(this);
2316  if (mark_visited_nodes_as_traversed)
2317  context()->mark_diff_as_visited(this);
2318  return false;
2319  }
2320 
2322  && !is_traversing()
2323  && !already_visited)
2324  {
2325  begin_traversing();
2326  for (vector<diff*>::const_iterator i = children_nodes().begin();
2327  i != children_nodes().end();
2328  ++i)
2329  {
2330  if (!(*i)->traverse(v))
2331  {
2332  v.visit_end(this);
2333  if (mark_visited_nodes_as_traversed)
2334  context()->mark_diff_as_visited(this);
2335  end_traversing();
2336  return false;
2337  }
2338  }
2339  end_traversing();
2340  }
2341 
2342  if (!v.visit(this, /*pref=*/false))
2343  {
2344  v.visit_end(this);
2345  if (mark_visited_nodes_as_traversed)
2346  context()->mark_diff_as_visited(this);
2347  return false;
2348  }
2349 
2350  v.visit_end(this);
2351  if (!already_visited && mark_visited_nodes_as_traversed)
2352  context()->mark_diff_as_visited(this);
2353 
2354  return true;
2355 }
2356 
2357 /// Sets a flag saying if a report has already been emitted for the
2358 /// current diff.
2359 ///
2360 /// @param f true if a report has already been emitted for the
2361 /// current diff, false otherwise.
2362 void
2363 diff::reported_once(bool f) const
2364 {
2365  ABG_ASSERT(priv_->canonical_diff_);
2366  priv_->canonical_diff_->priv_->reported_once_ = f;
2367  priv_->reported_once_ = f;
2368 }
2369 
2370 /// Getter for the local category of the current diff tree node.
2371 ///
2372 /// The local category represents the set of categories of a diff
2373 /// node, not taking in account the categories inherited from its
2374 /// children nodes.
2375 ///
2376 /// @return the local category of the current diff tree node.
2379 {return priv_->local_category_;}
2380 
2381 /// Getter of the category of the class of equivalence of the current
2382 /// diff tree node.
2383 ///
2384 /// That is, if the current diff tree node has a canonical node,
2385 /// return the category of that canonical node. Otherwise, return the
2386 /// category of the current node.
2387 ///
2388 /// @return the category of the class of equivalence of the current
2389 /// tree node.
2392 {
2393  diff* canonical = get_canonical_diff();
2394  return canonical ? canonical->get_category() : get_category();
2395 }
2396 
2397 /// Getter for the category of the current diff tree node.
2398 ///
2399 /// This category represents the union of the local category and the
2400 /// categories inherited from the children diff nodes.
2401 ///
2402 /// @return the category of the current diff tree node.
2405 {return priv_->category_;}
2406 
2407 /// Adds the current diff tree node to an additional set of
2408 /// categories. Note that the categories include thoses inherited
2409 /// from the children nodes of this diff node.
2410 ///
2411 /// @param c a bit-map representing the set of categories to add the
2412 /// current diff tree node to.
2413 ///
2414 /// @return the resulting bit-map representing the categories this
2415 /// current diff tree node belongs to, including those inherited from
2416 /// its children nodes.
2419 {
2420  priv_->category_ = priv_->category_ | c;
2421  return priv_->category_;
2422 }
2423 
2424 /// Adds the current diff tree node to the categories resulting from
2425 /// the local changes of the current diff node.
2426 ///
2427 /// @param c a bit-map representing the set of categories to add the
2428 /// current diff tree node to.
2429 ///
2430 /// @return the resulting bit-map representing the categories this
2431 /// current diff tree node belongs to.
2434 {
2435  priv_->local_category_ = priv_->local_category_ | c;
2436  return priv_->local_category_;
2437 }
2438 
2439 /// Adds the current diff tree node to the categories resulting from
2440 /// the local and inherited changes of the current diff node.
2441 ///
2442 /// @param c a bit-map representing the set of categories to add the
2443 /// current diff tree node to.
2444 void
2446 {
2448  add_to_category(c);
2449 }
2450 
2451 /// Remove the current diff tree node from an a existing sef of
2452 /// categories. The categories include those inherited from the
2453 /// children nodes of the current diff node.
2454 ///
2455 /// @param c a bit-map representing the set of categories to add the
2456 /// current diff tree node to.
2457 ///
2458 /// @return the resulting bit-map representing the categories this
2459 /// current diff tree onde belongs to, including the categories
2460 /// inherited from the children nodes of the current diff node.
2463 {
2464  priv_->category_ = priv_->category_ & ~c;
2465  return priv_->category_;
2466 }
2467 
2468 /// Remove the current diff tree node from the categories resulting
2469 /// from the local changes.
2470 ///
2471 /// @param c a bit-map representing the set of categories to add the
2472 /// current diff tree node to.
2473 ///
2474 /// @return the resulting bit-map representing the categories this
2475 /// current diff tree onde belongs to.
2478 {
2479  priv_->local_category_ = priv_->local_category_ & ~c;
2480  return priv_->local_category_;
2481 }
2482 
2483 /// Set the category of the current @ref diff node. This category
2484 /// includes the categories inherited from the children nodes of the
2485 /// current diff node.
2486 ///
2487 /// @param c the new category for the current diff node.
2488 void
2490 {priv_->category_ = c;}
2491 
2492 /// Set the local category of the current @ref diff node.
2493 ///
2494 /// @param c the new category for the current diff node.
2495 void
2497 {priv_->local_category_ = c;}
2498 
2499 /// Test if this diff tree node is to be filtered out for reporting
2500 /// purposes.
2501 ///
2502 /// There is a difference between a diff node being filtered out and
2503 /// being suppressed. Being suppressed means that there is a
2504 /// suppression specification that suppresses the diff node
2505 /// specifically. Being filtered out mean the node is either
2506 /// suppressed, or it's filtered out because the suppression of a set
2507 /// of (children) nodes caused this node to be filtered out as well.
2508 /// For instance, if a function diff has all its children diff nodes
2509 /// suppressed and if the function diff node carries no local change,
2510 /// then the function diff node itself is going to be filtered out.
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 NOT be reported.
2516 bool
2518 {
2519  if (diff * canonical = get_canonical_diff())
2520  if ((canonical->get_category() & SUPPRESSED_CATEGORY
2521  || canonical->get_category() & PRIVATE_TYPE_CATEGORY)
2522  && !canonical->is_allowed_by_specific_negated_suppression()
2523  && !canonical->has_descendant_allowed_by_specific_negated_suppression()
2524  && !canonical->has_parent_allowed_by_specific_negated_suppression())
2525  // The canonical type was suppressed either by a user-provided
2526  // suppression specification or by a "private-type" suppression
2527  // specification.. This means all the classes of equivalence of
2528  // that canonical type were suppressed. So this node should be
2529  // filtered out.
2530  return true;
2531  return priv_->is_filtered_out(get_category());
2532 }
2533 
2534 /// Test if this diff tree node is to be filtered out for reporting
2535 /// purposes, but by considering only the categories that were *NOT*
2536 /// inherited from its children nodes.
2537 ///
2538 /// The function tests if the local categories of the diff tree node
2539 /// are "forbidden" by the context or not.
2540 ///
2541 /// @return true iff the current diff node should NOT be reported,
2542 /// with respect to its local categories.
2543 bool
2545 {return priv_->is_filtered_out(get_local_category());}
2546 
2547 /// Test if this diff tree node is to be filtered out for reporting
2548 /// purposes, but without considering the categories that can /force/
2549 /// the node to be unfiltered.
2550 ///
2551 /// The function tests if the categories of the diff tree node are
2552 /// "forbidden" by the context or not.
2553 ///
2554 /// @return true iff the current diff node should should NOT be
2555 /// reported, with respect to the categories that might filter it out
2556 /// only.
2557 bool
2559 {
2564 
2565  return priv_->is_filtered_out(c);
2566 }
2567 
2568 /// Test if the current diff node has been suppressed by a
2569 /// user-provided suppression specification.
2570 ///
2571 /// @return true if the current diff node has been suppressed by a
2572 /// user-provided suppression list.
2573 bool
2575 {
2576  bool is_private = false;
2577  return is_suppressed(is_private);
2578 }
2579 
2580 /// Test if the current diff node has been suppressed by a
2581 /// user-provided suppression specification or by an auto-generated
2582 /// "private type" suppression specification.
2583 ///
2584 /// Note that private type suppressions are auto-generated from the
2585 /// path to where public headers are, as given by the user.
2586 ///
2587 /// Here is the current algorithm:
2588 ///
2589 /// First, suppress this diff node if it's not matched by any
2590 /// negated suppression specifications. If it's not
2591 /// suppressed, then suppress it if it's matched by direct
2592 /// suppression specifications.
2593 ///
2594 /// @param is_private_type out parameter if the current diff node was
2595 /// suppressed because it's a private type then this parameter is set
2596 /// to true.
2597 ///
2598 /// @return true if the current diff node has been suppressed by a
2599 /// user-provided suppression list.
2600 bool
2601 diff::is_suppressed(bool &is_private_type) const
2602 {
2603  // If there is at least one negated suppression, then suppress the
2604  // current diff node by default ...
2605  bool do_suppress = !context()->negated_suppressions().empty();
2606 
2607  // ... unless there is at least one negated suppression that
2608  // specifically asks to keep this diff node around (un-suppressed).
2609  for (auto n : context()->negated_suppressions())
2610  if (!n->suppresses_diff(this))
2611  {
2612  do_suppress = false;
2613  break;
2614  }
2615 
2616  // Then walk the set of non-negated, AKA direct, suppressions. If at
2617  // least one suppression suppresses the current diff node then the
2618  // diff node must be suppressed.
2619  for (auto d : context()->direct_suppressions())
2620  if (d->suppresses_diff(this))
2621  {
2622  do_suppress = true;
2624  is_private_type = true;
2625  break;
2626  }
2627 
2628  return do_suppress;
2629 }
2630 
2631 /// Test if this diff tree node should be reported.
2632 ///
2633 /// @return true iff the current node should be reported.
2634 bool
2636 {
2637  if (has_changes() && !is_filtered_out())
2638  return true;
2639  return false;
2640 }
2641 
2642 /// Test if this diff tree node should be reported when considering
2643 /// the categories that were *NOT* inherited from its children nodes.
2644 ///
2645 /// @return true iff the current node should be reported.
2646 bool
2648 {
2649  if (has_local_changes()
2651  return true;
2652  return false;
2653 }
2654 
2655 /// Test if this diff node is allowed (prevented from being
2656 /// suppressed) by at least one negated suppression specification.
2657 ///
2658 /// @return true if this diff node is meant to be allowed by at least
2659 /// one negated suppression specification.
2660 bool
2662 {
2663  const suppressions_type& suppressions = context()->suppressions();
2664  for (suppressions_type::const_iterator i = suppressions.begin();
2665  i != suppressions.end();
2666  ++i)
2667  {
2668  if (is_negated_suppression(*i)
2669  && !(*i)->suppresses_diff(this))
2670  return true;
2671  }
2672  return false;
2673 }
2674 
2675 /// Test if the current diff node has a descendant node which is
2676 /// specifically allowed by a negated suppression specification.
2677 ///
2678 /// @return true iff the current diff node has a descendant node
2679 /// which is specifically allowed by a negated suppression
2680 /// specification.
2681 bool
2683 {
2685  return result;
2686 }
2687 
2688 /// Test if the current diff node has a parent node which is
2689 /// specifically allowed by a negated suppression specification.
2690 ///
2691 /// @return true iff the current diff node has a parent node which is
2692 /// specifically allowed by a negated suppression specification.
2693 bool
2695 {
2697  return result;
2698 }
2699 
2700 /// Get a pretty representation of the current @ref diff node.
2701 ///
2702 /// This is suitable for e.g. emitting debugging traces for the diff
2703 /// tree nodes.
2704 ///
2705 /// @return the pretty representation of the diff node.
2706 const string&
2708 {
2709  if (priv_->pretty_representation_.empty())
2710  priv_->pretty_representation_ = "empty_diff";
2711  return priv_->pretty_representation_;
2712 }
2713 
2714 /// Default implementation of the hierachy chaining virtual function.
2715 ///
2716 /// There are several types of diff nodes that have logical children
2717 /// nodes; for instance, a typedef_diff has the diff of the underlying
2718 /// type as a child node. A var_diff has the diff of the types of the
2719 /// variables as a child node, etc.
2720 ///
2721 /// But because the @ref diff base has a generic representation for
2722 /// children nodes of the all the types of @ref diff nodes (regardless
2723 /// of the specific most-derived type of diff node) that one can get
2724 /// using the method diff::children_nodes(), one need to populate that
2725 /// vector of children node.
2726 ///
2727 /// Populating that vector of children node is done by this function;
2728 /// it must be overloaded by each most-derived type of diff node that
2729 /// extends the @ref diff type.
2730 void
2732 {}
2733 
2734 // </diff stuff>
2735 
2736 // <type_diff_base stuff>
2737 
2738 type_diff_base::type_diff_base(type_base_sptr first_subject,
2739  type_base_sptr second_subject,
2740  diff_context_sptr ctxt)
2741  : diff(first_subject, second_subject, ctxt),
2742  priv_(new priv)
2743 {}
2744 
2745 type_diff_base::~type_diff_base()
2746 {}
2747 // </type_diff_base stuff>
2748 
2749 // <decl_diff_base stuff>
2750 
2751 /// Constructor of @ref decl_diff_base.
2752 ///
2753 /// @param first_subject the first subject of the diff.
2754 ///
2755 /// @param second_subject the second subject of the diff.
2756 ///
2757 /// @param ctxt the context of the diff. This object must stay alive
2758 /// at least during the life time of the current instance of @ref
2759 /// decl_diff_base, otherwise, memory corruption issues occur.
2760 decl_diff_base::decl_diff_base(decl_base_sptr first_subject,
2761  decl_base_sptr second_subject,
2762  diff_context_sptr ctxt)
2763  : diff(first_subject, second_subject, ctxt),
2764  priv_(new priv)
2765 {}
2766 
2767 decl_diff_base::~decl_diff_base()
2768 {}
2769 
2770 // </decl_diff_base stuff>
2771 
2772 // <distinct_diff stuff>
2773 
2774 /// @return a pretty representation for the @ref distinct_diff node.
2775 const string&
2777 {
2778  if (diff::priv_->pretty_representation_.empty())
2779  {
2780  std::ostringstream o;
2781  o << "distinct_diff[";
2782  if (first_subject())
2783  o << first_subject()->get_pretty_representation();
2784  else
2785  o << "null";
2786  o << ", ";
2787  if (second_subject())
2788  o << second_subject()->get_pretty_representation() ;
2789  else
2790  o << "null";
2791  o << "]" ;
2792  diff::priv_->pretty_representation_ = o.str();
2793  }
2794  return diff::priv_->pretty_representation_;
2795 }
2796 
2797 /// Populate the vector of children node of the @ref diff base type
2798 /// sub-object of this instance of @distinct_diff.
2799 ///
2800 /// The children nodes can then later be retrieved using
2801 /// diff::children_nodes().
2802 void
2804 {
2806 
2807  if (diff_sptr d = compatible_child_diff())
2808  append_child_node(d);
2809 }
2810 
2811 /// Constructor for @ref distinct_diff.
2812 ///
2813 /// Note that the two entities considered for the diff (and passed in
2814 /// parameter) must be of different kinds.
2815 ///
2816 /// @param first the first entity to consider for the diff.
2817 ///
2818 /// @param second the second entity to consider for the diff.
2819 ///
2820 /// @param ctxt the context of the diff. Note that this context
2821 /// object must stay alive at least during the life time of the
2822 /// current instance of @ref distinct_diff. Otherwise memory
2823 /// corruption issues occur.
2825  type_or_decl_base_sptr second,
2826  diff_context_sptr ctxt)
2827  : diff(first, second, ctxt),
2828  priv_(new priv)
2830 
2831 /// Getter for the first subject of the diff.
2832 ///
2833 /// @return the first subject of the diff.
2836 {return first_subject();}
2837 
2838 /// Getter for the second subject of the diff.
2839 ///
2840 /// @return the second subject of the diff.
2843 {return second_subject();}
2844 
2845 /// Getter for the child diff of this distinct_diff instance.
2846 ///
2847 /// When a distinct_diff has two subjects that are different but
2848 /// compatible, then the distinct_diff instance has a child diff node
2849 /// (named the compatible child diff) that is the diff between the two
2850 /// subjects stripped from their typedefs. Otherwise, the compatible
2851 /// child diff is nul.
2852 ///
2853 /// Note that two diff subjects (that compare different) are
2854 /// considered compatible if stripping typedefs out of them makes them
2855 /// comparing equal.
2856 ///
2857 /// @return the compatible child diff node, if any. Otherwise, null.
2858 const diff_sptr
2860 {
2861  if (!priv_->compatible_child_diff)
2862  {
2863  type_base_sptr fs = strip_typedef(is_type(first())),
2864  ss = strip_typedef(is_type(second()));
2865 
2866  if (fs && ss
2868  get_type_declaration(ss)))
2869  priv_->compatible_child_diff = compute_diff(get_type_declaration(fs),
2871  context());
2872  }
2873  return priv_->compatible_child_diff;
2874 }
2875 
2876 /// Test if the two arguments are of different kind, or that are both
2877 /// NULL.
2878 ///
2879 /// @param first the first argument to test for similarity in kind.
2880 ///
2881 /// @param second the second argument to test for similarity in kind.
2882 ///
2883 /// @return true iff the two arguments are of different kind.
2884 bool
2886  type_or_decl_base_sptr second)
2887 {
2888  if (!!first != !!second)
2889  return true;
2890  if (!first && !second)
2891  // We do consider diffs of two empty decls as a diff of distinct
2892  // kinds, for now.
2893  return true;
2894  if (first == second)
2895  return false;
2896 
2897  const type_or_decl_base &f = *first, &s = *second;
2898  return typeid(f) != typeid(s);
2899 }
2900 
2901 /// @return true if the two subjects of the diff are different, false
2902 /// otherwise.
2903 bool
2905 {return first() != second();}
2906 
2907 /// @return the kind of local change carried by the current diff node.
2908 /// The value returned is zero if the current node carries no local
2909 /// change.
2910 enum change_kind
2912 {
2913  // Changes on a distinct_diff are all local.
2914  if (has_changes())
2915  return LOCAL_TYPE_CHANGE_KIND;
2916  return NO_CHANGE_KIND;
2917 }
2918 
2919 /// Emit a report about the current diff instance.
2920 ///
2921 /// @param out the output stream to send the diff report to.
2922 ///
2923 /// @param indent the indentation string to use in the report.
2924 void
2925 distinct_diff::report(ostream& out, const string& indent) const
2926 {
2927  context()->get_reporter()->report(*this, out, indent);
2928 }
2929 
2930 /// Try to diff entities that are of distinct kinds.
2931 ///
2932 /// @param first the first entity to consider for the diff.
2933 ///
2934 /// @param second the second entity to consider for the diff.
2935 ///
2936 /// @param ctxt the context of the diff.
2937 ///
2938 /// @return a non-null diff if a diff object could be built, null
2939 /// otherwise.
2942  const type_or_decl_base_sptr second,
2943  diff_context_sptr ctxt)
2944 {
2946  return distinct_diff_sptr();
2947 
2948  distinct_diff_sptr result(new distinct_diff(first, second, ctxt));
2949 
2950  ctxt->initialize_canonical_diff(result);
2951 
2952  return result;
2953 }
2954 
2955 /// </distinct_diff stuff>
2956 
2957 /// Try to compute a diff on two instances of DiffType representation.
2958 ///
2959 /// The function template performs the diff if and only if the decl
2960 /// representations are of a DiffType.
2961 ///
2962 /// @tparm DiffType the type of instances to diff.
2963 ///
2964 /// @param first the first representation of decl to consider in the
2965 /// diff computation.
2966 ///
2967 /// @param second the second representation of decl to consider in the
2968 /// diff computation.
2969 ///
2970 /// @param ctxt the diff context to use.
2971 ///
2972 ///@return the diff of the two types @p first and @p second if and
2973 ///only if they represent the parametrized type DiffType. Otherwise,
2974 ///returns a NULL pointer value.
2975 template<typename DiffType>
2976 diff_sptr
2978  const type_or_decl_base_sptr second,
2979  diff_context_sptr ctxt)
2980 {
2981  if (shared_ptr<DiffType> f =
2982  dynamic_pointer_cast<DiffType>(first))
2983  {
2984  shared_ptr<DiffType> s =
2985  dynamic_pointer_cast<DiffType>(second);
2986  if (!s)
2987  return diff_sptr();
2988  return compute_diff(f, s, ctxt);
2989  }
2990  return diff_sptr();
2991 }
2992 
2993 
2994 /// This is a specialization of @ref try_to_diff() template to diff
2995 /// instances of @ref class_decl.
2996 ///
2997 /// @param first the first representation of decl to consider in the
2998 /// diff computation.
2999 ///
3000 /// @param second the second representation of decl to consider in the
3001 /// diff computation.
3002 ///
3003 /// @param ctxt the diff context to use.
3004 template<>
3007  const type_or_decl_base_sptr second,
3008  diff_context_sptr ctxt)
3009 {
3010  if (class_decl_sptr f =
3011  dynamic_pointer_cast<class_decl>(first))
3012  {
3013  class_decl_sptr s = dynamic_pointer_cast<class_decl>(second);
3014  if (!s)
3015  return diff_sptr();
3016 
3017  if (f->get_is_declaration_only())
3018  {
3019  class_decl_sptr f2 =
3020  is_class_type (f->get_definition_of_declaration());
3021  if (f2)
3022  f = f2;
3023  }
3024  if (s->get_is_declaration_only())
3025  {
3026  class_decl_sptr s2 =
3027  is_class_type(s->get_definition_of_declaration());
3028  if (s2)
3029  s = s2;
3030  }
3031  return compute_diff(f, s, ctxt);
3032  }
3033  return diff_sptr();
3034 }
3035 
3036 /// Try to diff entities that are of distinct kinds.
3037 ///
3038 /// @param first the first entity to consider for the diff.
3039 ///
3040 /// @param second the second entity to consider for the diff.
3041 ///
3042 /// @param ctxt the context of the diff.
3043 ///
3044 /// @return a non-null diff if a diff object could be built, null
3045 /// otherwise.
3046 static diff_sptr
3047 try_to_diff_distinct_kinds(const type_or_decl_base_sptr first,
3048  const type_or_decl_base_sptr second,
3049  diff_context_sptr ctxt)
3050 {return compute_diff_for_distinct_kinds(first, second, ctxt);}
3051 
3052 /// Compute the difference between two types.
3053 ///
3054 /// The function considers every possible types known to libabigail
3055 /// and runs the appropriate diff function on them.
3056 ///
3057 /// Whenever a new kind of type decl is supported by abigail, if we
3058 /// want to be able to diff two instances of it, we need to update
3059 /// this function to support it.
3060 ///
3061 /// @param first the first type decl to consider for the diff
3062 ///
3063 /// @param second the second type decl to consider for the diff.
3064 ///
3065 /// @param ctxt the diff context to use.
3066 ///
3067 /// @return the resulting diff. It's a pointer to a descendent of
3068 /// abigail::comparison::diff.
3069 static diff_sptr
3070 compute_diff_for_types(const type_or_decl_base_sptr& first,
3071  const type_or_decl_base_sptr& second,
3072  const diff_context_sptr& ctxt)
3073 {
3074  type_or_decl_base_sptr f = first;
3075  type_or_decl_base_sptr s = second;
3076 
3077  diff_sptr d;
3078 
3079  ((d = try_to_diff<type_decl>(f, s, ctxt))
3080  ||(d = try_to_diff<enum_type_decl>(f, s, ctxt))
3081  ||(d = try_to_diff<union_decl>(f, s,ctxt))
3082  ||(d = try_to_diff<class_decl>(f, s,ctxt))
3083  ||(d = try_to_diff<pointer_type_def>(f, s, ctxt))
3084  ||(d = try_to_diff<reference_type_def>(f, s, ctxt))
3085  ||(d = try_to_diff<ptr_to_mbr_type>(f, s, ctxt))
3086  ||(d = try_to_diff<array_type_def::subrange_type>(f, s, ctxt))
3087  ||(d = try_to_diff<array_type_def>(f, s, ctxt))
3088  ||(d = try_to_diff<qualified_type_def>(f, s, ctxt))
3089  ||(d = try_to_diff<typedef_decl>(f, s, ctxt))
3090  ||(d = try_to_diff<function_type>(f, s, ctxt))
3091  ||(d = try_to_diff_distinct_kinds(f, s, ctxt)));
3092 
3093  ABG_ASSERT(d);
3094 
3095  return d;
3096 }
3097 
3100 {return static_cast<diff_category>(static_cast<unsigned>(c1)
3101  | static_cast<unsigned>(c2));}
3102 
3104 operator|=(diff_category& c1, diff_category c2)
3105 {
3106  c1 = c1 | c2;
3107  return c1;
3108 }
3109 
3111 operator&=(diff_category& c1, diff_category c2)
3112 {
3113  c1 = c1 & c2;
3114  return c1;
3115 }
3116 
3118 operator^(diff_category c1, diff_category c2)
3119 {return static_cast<diff_category>(static_cast<unsigned>(c1)
3120  ^ static_cast<unsigned>(c2));}
3121 
3124 {return static_cast<diff_category>(static_cast<unsigned>(c1)
3125  & static_cast<unsigned>(c2));}
3126 
3129 {return static_cast<diff_category>(~static_cast<unsigned>(c));}
3130 
3131 
3132 /// Getter of a bitmap made of the set of change categories that are
3133 /// considered harmless.
3134 ///
3135 /// @return the bitmap made of the set of change categories that are
3136 /// considered harmless.
3139 {
3156 }
3157 
3158 /// Getter of a bitmap made of the set of change categories that are
3159 /// considered harmful.
3160 ///
3161 /// @return the bitmap made of the set of change categories that are
3162 /// considered harmful.
3165 {
3169 }
3170 
3171 /// Serialize an instance of @ref diff_category to an output stream.
3172 ///
3173 /// @param o the output stream to serialize @p c to.
3174 ///
3175 /// @param c the instance of diff_category to serialize.
3176 ///
3177 /// @return the output stream to serialize @p c to.
3178 ostream&
3179 operator<<(ostream& o, diff_category c)
3180 {
3181  bool emitted_a_category = false;
3182 
3183  if (c == NO_CHANGE_CATEGORY)
3184  {
3185  o << "NO_CHANGE_CATEGORY";
3186  emitted_a_category = true;
3187  }
3188 
3189  if (c & ACCESS_CHANGE_CATEGORY)
3190  {
3191  if (emitted_a_category)
3192  o << "|";
3193  o << "ACCESS_CHANGE_CATEGORY";
3194  emitted_a_category |= true;
3195  }
3196 
3198  {
3199  if (emitted_a_category)
3200  o << "|";
3201  o << "COMPATIBLE_TYPE_CHANGE_CATEGORY";
3202  emitted_a_category |= true;
3203  }
3204 
3206  {
3207  if (emitted_a_category)
3208  o << "|";
3209  o << "HARMLESS_DECL_NAME_CHANGE_CATEGORY";
3210  emitted_a_category |= true;
3211  }
3212 
3214  {
3215  if (emitted_a_category)
3216  o << "|";
3217  o << "NON_VIRT_MEM_FUN_CHANGE_CATEGORY";
3218  emitted_a_category |= true;
3219  }
3220 
3222  {
3223  if (emitted_a_category)
3224  o << "|";
3225  o << "STATIC_DATA_MEMBER_CHANGE_CATEGORY";
3226  emitted_a_category |= true;
3227  }
3228 
3230  {
3231  if (emitted_a_category)
3232  o << "|";
3233  o << "HARMLESS_ENUM_CHANGE_CATEGORY";
3234  emitted_a_category |= true;
3235  }
3236 
3238  {
3239  if (emitted_a_category)
3240  o << "|";
3241  o << "HARMLESS_DATA_MEMBER_CHANGE_CATEGORY";
3242  emitted_a_category |= true;
3243  }
3244 
3246  {
3247  if (emitted_a_category)
3248  o << "|";
3249  o << "HARMLESS_SYMBOL_ALIAS_CHANGE_CATEGORY";
3250  emitted_a_category |= true;
3251  }
3252 
3254  {
3255  if (emitted_a_category)
3256  o << "|";
3257  o << "HARMLESS_UNION_OR_CLASS_CHANGE_CATEGORY";
3258  emitted_a_category |= true;
3259  }
3260 
3261  if (c & SUPPRESSED_CATEGORY)
3262  {
3263  if (emitted_a_category)
3264  o << "|";
3265  o << "SUPPRESSED_CATEGORY";
3266  emitted_a_category |= true;
3267  }
3268 
3269  if (c & PRIVATE_TYPE_CATEGORY)
3270  {
3271  if (emitted_a_category)
3272  o << "|";
3273  o << "PRIVATE_TYPE_CATEGORY";
3274  emitted_a_category |= true;
3275  }
3276 
3278  {
3279  if (emitted_a_category)
3280  o << "|";
3281  o << "SIZE_OR_OFFSET_CHANGE_CATEGORY";
3282  emitted_a_category |= true;
3283  }
3284 
3286  {
3287  if (emitted_a_category)
3288  o << "|";
3289  o << "VIRTUAL_MEMBER_CHANGE_CATEGORY";
3290  emitted_a_category |= true;
3291  }
3292 
3293  if (c & REDUNDANT_CATEGORY)
3294  {
3295  if (emitted_a_category)
3296  o << "|";
3297  o << "REDUNDANT_CATEGORY";
3298  emitted_a_category |= true;
3299  }
3300 
3302  {
3303  if (emitted_a_category)
3304  o << "|";
3305  o << "TYPE_DECL_ONLY_DEF_CHANGE_CATEGORY";
3306  emitted_a_category |= true;
3307  }
3308 
3310  {
3311  if (emitted_a_category)
3312  o << "|";
3313  o << "FN_PARM_TYPE_TOP_CV_CHANGE_CATEGORY";
3314  emitted_a_category |= true;
3315  }
3316 
3318  {
3319  if (emitted_a_category)
3320  o << "|";
3321  o << "FN_PARM_TYPE_CV_CHANGE_CATEGORY";
3322  emitted_a_category |= true;
3323  }
3324 
3326  {
3327  if (emitted_a_category)
3328  o << "|";
3329  o << "FN_RETURN_TYPE_CV_CHANGE_CATEGORY";
3330  emitted_a_category |= true;
3331  }
3332 
3334  {
3335  if (emitted_a_category)
3336  o << "|";
3337  o << "FN_PARM_ADD_REMOVE_CHANGE_CATEGORY";
3338  emitted_a_category |= true;
3339  }
3340 
3342  {
3343  if (emitted_a_category)
3344  o << "|";
3345  o << "VAR_TYPE_CV_CHANGE_CATEGORY";
3346  emitted_a_category |= true;
3347  }
3348 
3350  {
3351  if (emitted_a_category)
3352  o << "|";
3353  o << "VOID_PTR_TO_PTR_CHANGE_CATEGORY";
3354  emitted_a_category |= true;
3355  }
3356 
3358  {
3359  if (emitted_a_category)
3360  o << "|";
3361  o << "BENIGN_INFINITE_ARRAY_CHANGE_CATEGORY";
3362  emitted_a_category |= true;
3363  }
3364 
3366  {
3367  if (emitted_a_category)
3368  o << "|";
3369  o << "HAS_ALLOWED_CHANGE_CATEGORY";
3370  emitted_a_category |= true;
3371  }
3372 
3374  {
3375  if (emitted_a_category)
3376  o << "|";
3377  o << "HAS_DESCENDANT_WITH_ALLOWED_CHANGE_CATEGORY";
3378  emitted_a_category |= true;
3379  }
3380 
3382  {
3383  if (emitted_a_category)
3384  o << "|";
3385  o << "HAS_PARENT_WITH_ALLOWED_CHANGE_CATEGORY";
3386  emitted_a_category |= true;
3387  }
3388 
3389  return o;
3390 }
3391 
3392 /// Compute the difference between two decls.
3393 ///
3394 /// The function consider every possible decls known to libabigail and
3395 /// runs the appropriate diff function on them.
3396 ///
3397 /// Whenever a new kind of non-type decl is supported by abigail, if
3398 /// we want to be able to diff two instances of it, we need to update
3399 /// this function to support it.
3400 ///
3401 /// @param first the first decl to consider for the diff
3402 ///
3403 /// @param second the second decl to consider for the diff.
3404 ///
3405 /// @param ctxt the diff context to use.
3406 ///
3407 /// @return the resulting diff.
3408 static diff_sptr
3409 compute_diff_for_decls(const decl_base_sptr first,
3410  const decl_base_sptr second,
3411  diff_context_sptr ctxt)
3412 {
3413 
3414  diff_sptr d;
3415 
3416  ((d = try_to_diff<function_decl>(first, second, ctxt))
3417  || (d = try_to_diff<var_decl>(first, second, ctxt))
3418  || (d = try_to_diff_distinct_kinds(first, second, ctxt)));
3419 
3420  ABG_ASSERT(d);
3421 
3422  return d;
3423 }
3424 
3425 /// Compute the difference between two decls. The decls can represent
3426 /// either type declarations, or non-type declaration.
3427 ///
3428 /// Note that the two decls must have been created in the same @ref
3429 /// environment, otherwise, this function aborts.
3430 ///
3431 /// @param first the first decl to consider.
3432 ///
3433 /// @param second the second decl to consider.
3434 ///
3435 /// @param ctxt the diff context to use.
3436 ///
3437 /// @return the resulting diff, or NULL if the diff could not be
3438 /// computed.
3439 diff_sptr
3440 compute_diff(const decl_base_sptr first,
3441  const decl_base_sptr second,
3442  diff_context_sptr ctxt)
3443 {
3444  if (!first || !second)
3445  return diff_sptr();
3446 
3447  diff_sptr d;
3448  if (is_type(first) && is_type(second))
3449  d = compute_diff_for_types(first, second, ctxt);
3450  else
3451  d = compute_diff_for_decls(first, second, ctxt);
3452  ABG_ASSERT(d);
3453  return d;
3454 }
3455 
3456 /// Compute the difference between two types.
3457 ///
3458 /// Note that the two types must have been created in the same @ref
3459 /// environment, otherwise, this function aborts.
3460 ///
3461 /// @param first the first type to consider.
3462 ///
3463 /// @param second the second type to consider.
3464 ///
3465 /// @param ctxt the diff context to use.
3466 ///
3467 /// @return the resulting diff, or NULL if the diff couldn't be
3468 /// computed.
3469 diff_sptr
3470 compute_diff(const type_base_sptr first,
3471  const type_base_sptr second,
3472  diff_context_sptr ctxt)
3473 {
3474  decl_base_sptr f = get_type_declaration(first),
3475  s = get_type_declaration(second);
3476 
3477  diff_sptr d = compute_diff_for_types(f,s, ctxt);
3478  ABG_ASSERT(d);
3479  return d;
3480 }
3481 
3482 /// Get a copy of the pretty representation of a diff node.
3483 ///
3484 /// @param d the diff node to consider.
3485 ///
3486 /// @return the pretty representation string.
3487 string
3489 {
3490  if (!d)
3491  return "";
3492  string prefix= "diff of ";
3493  return prefix + get_pretty_representation(d->first_subject());
3494 }
3495 
3496 // <var_diff stuff>
3497 
3498 /// Populate the vector of children node of the @ref diff base type
3499 /// sub-object of this instance of @ref var_diff.
3500 ///
3501 /// The children node can then later be retrieved using
3502 /// diff::children_node().
3503 void
3506 
3507 /// @return the pretty representation for this current instance of
3508 /// @ref var_diff.
3509 const string&
3511 {
3512  if (diff::priv_->pretty_representation_.empty())
3513  {
3514  std::ostringstream o;
3515  o << "var_diff["
3516  << first_subject()->get_pretty_representation()
3517  << ", "
3518  << second_subject()->get_pretty_representation()
3519  << "]";
3520  diff::priv_->pretty_representation_ = o.str();
3521  }
3522  return diff::priv_->pretty_representation_;
3523 }
3524 /// Constructor for @ref var_diff.
3525 ///
3526 /// @param first the first instance of @ref var_decl to consider in
3527 /// the diff.
3528 ///
3529 /// @param second the second instance of @ref var_decl to consider in
3530 /// the diff.
3531 ///
3532 /// @param type_diff the diff between types of the instances of
3533 /// var_decl.
3534 ///
3535 /// @param ctxt the diff context to use.
3537  var_decl_sptr second,
3538  diff_sptr type_diff,
3539  diff_context_sptr ctxt)
3540  : decl_diff_base(first, second, ctxt),
3541  priv_(new priv)
3542 {priv_->type_diff_ = type_diff;}
3543 
3544 /// Getter for the first @ref var_decl of the diff.
3545 ///
3546 /// @return the first @ref var_decl of the diff.
3549 {return dynamic_pointer_cast<var_decl>(first_subject());}
3550 
3551 /// Getter for the second @ref var_decl of the diff.
3552 ///
3553 /// @return the second @ref var_decl of the diff.
3556 {return dynamic_pointer_cast<var_decl>(second_subject());}
3557 
3558 /// Getter for the diff of the types of the instances of @ref
3559 /// var_decl.
3560 ///
3561 /// @return the diff of the types of the instances of @ref var_decl.
3562 diff_sptr
3564 {
3565  if (diff_sptr result = priv_->type_diff_.lock())
3566  return result;
3567  else
3568  {
3569  result = compute_diff(first_var()->get_type(),
3570  second_var()->get_type(),
3571  context());
3572  context()->keep_diff_alive(result);
3573  priv_->type_diff_ = result;
3574  return result;
3575  }
3576 }
3577 
3578 /// Return true iff the diff node has a change.
3579 ///
3580 /// @return true iff the diff node has a change.
3581 bool
3583 {return *first_var() != *second_var();}
3584 
3585 /// @return the kind of local change carried by the current diff node.
3586 /// The value returned is zero if the current node carries no local
3587 /// change.
3588 enum change_kind
3590 {
3591  ir::change_kind k = ir::NO_CHANGE_KIND;
3592  if (!equals(*first_var(), *second_var(), &k))
3593  return k & ir::ALL_LOCAL_CHANGES_MASK;
3594  return ir::NO_CHANGE_KIND;
3595 }
3596 
3597 /// Report the diff in a serialized form.
3598 ///
3599 /// @param out the stream to serialize the diff to.
3600 ///
3601 /// @param indent the prefix to use for the indentation of this
3602 /// serialization.
3603 void
3604 var_diff::report(ostream& out, const string& indent) const
3605 {
3606  context()->get_reporter()->report(*this, out, indent);
3607 }
3608 
3609 /// Compute the diff between two instances of @ref var_decl.
3610 ///
3611 /// Note that the two decls must have been created in the same @ref
3612 /// environment, otherwise, this function aborts.
3613 ///
3614 /// @param first the first @ref var_decl to consider for the diff.
3615 ///
3616 /// @param second the second @ref var_decl to consider for the diff.
3617 ///
3618 /// @param ctxt the diff context to use.
3619 ///
3620 /// @return the resulting diff between the two @ref var_decl.
3623  const var_decl_sptr second,
3624  diff_context_sptr ctxt)
3625 {
3626  var_diff_sptr d(new var_diff(first, second, diff_sptr(), ctxt));
3627  ctxt->initialize_canonical_diff(d);
3628 
3629  return d;
3630 }
3631 
3632 // </var_diff stuff>
3633 
3634 // <pointer_type_def stuff>
3635 
3636 /// Populate the vector of children node of the @ref diff base type
3637 /// sub-object of this instance of @ref pointer_diff.
3638 ///
3639 /// The children node can then later be retrieved using
3640 /// diff::children_node().
3641 void
3644 
3645 /// Constructor for a pointer_diff.
3646 ///
3647 /// @param first the first pointer to consider for the diff.
3648 ///
3649 /// @param second the secon pointer to consider for the diff.
3650 ///
3651 /// @param ctxt the diff context to use.
3653  pointer_type_def_sptr second,
3654  diff_sptr underlying,
3655  diff_context_sptr ctxt)
3656  : type_diff_base(first, second, ctxt),
3657  priv_(new priv(underlying))
3658 {}
3659 
3660 /// Getter for the first subject of a pointer diff
3661 ///
3662 /// @return the first pointer considered in this pointer diff.
3665 {return dynamic_pointer_cast<pointer_type_def>(first_subject());}
3666 
3667 /// Getter for the second subject of a pointer diff
3668 ///
3669 /// @return the second pointer considered in this pointer diff.
3672 {return dynamic_pointer_cast<pointer_type_def>(second_subject());}
3673 
3674 /// @return the pretty represenation for the current instance of @ref
3675 /// pointer_diff.
3676 const string&
3678 {
3679  if (diff::priv_->pretty_representation_.empty())
3680  {
3681  std::ostringstream o;
3682  o << "pointer_diff["
3683  << first_subject()->get_pretty_representation()
3684  << ", "
3685  << second_subject()->get_pretty_representation()
3686  << "]";
3687  diff::priv_->pretty_representation_ = o.str();
3688  }
3689  return diff::priv_->pretty_representation_;
3690 }
3691 
3692 /// Return true iff the current diff node carries a change.
3693 ///
3694 /// @return true iff the current diff node carries a change.
3695 bool
3697 {return first_pointer() != second_pointer();}
3698 
3699 /// @return the kind of local change carried by the current diff node.
3700 /// The value returned is zero if the current node carries no local
3701 /// change.
3702 enum change_kind
3704 {
3705  ir::change_kind k = ir::NO_CHANGE_KIND;
3706  if (!equals(*first_pointer(), *second_pointer(), &k))
3707  return k & ir::ALL_LOCAL_CHANGES_MASK;
3708  return ir::NO_CHANGE_KIND;
3709 }
3710 
3711 /// Getter for the diff between the pointed-to types of the pointers
3712 /// of this diff.
3713 ///
3714 /// @return the diff between the pointed-to types.
3715 diff_sptr
3717 {return priv_->underlying_type_diff_;}
3718 
3719 /// Setter for the diff between the pointed-to types of the pointers
3720 /// of this diff.
3721 ///
3722 /// @param d the new diff between the pointed-to types of the pointers
3723 /// of this diff.
3724 void
3726 {priv_->underlying_type_diff_ = d;}
3727 
3728 /// Report the diff in a serialized form.
3729 ///
3730 /// @param out the stream to serialize the diff to.
3731 ///
3732 /// @param indent the prefix to use for the indentation of this
3733 /// serialization.
3734 void
3735 pointer_diff::report(ostream& out, const string& indent) const
3736 {
3737  context()->get_reporter()->report(*this, out, indent);
3738 }
3739 
3740 /// Compute the diff between between two pointers.
3741 ///
3742 /// Note that the two types must have been created in the same @ref
3743 /// environment, otherwise, this function aborts.
3744 ///
3745 /// @param first the pointer to consider for the diff.
3746 ///
3747 /// @param second the pointer to consider for the diff.
3748 ///
3749 /// @return the resulting diff between the two pointers.
3750 ///
3751 /// @param ctxt the diff context to use.
3754  pointer_type_def_sptr second,
3755  diff_context_sptr ctxt)
3756 {
3757  diff_sptr d = compute_diff_for_types(first->get_pointed_to_type(),
3758  second->get_pointed_to_type(),
3759  ctxt);
3760  pointer_diff_sptr result(new pointer_diff(first, second, d, ctxt));
3761  ctxt->initialize_canonical_diff(result);
3762 
3763  return result;
3764 }
3765 
3766 // </pointer_type_def>
3767 
3768 // <subrange_diff >
3769 
3770 /// Constructor of the @ref subrange_diff diff node type.
3771 ///
3772 /// @param first the first subrange type to consider for the diff.
3773 ///
3774 /// @param second the second subrange type to consider for the diff.
3775 ///
3776 /// @param underlying_type_diff the underlying type diff between @p
3777 /// first and @p second.
3778 ///
3779 /// @param ctxt the diff context to use.
3781 (const array_type_def::subrange_sptr& first,
3782  const array_type_def::subrange_sptr& second,
3783  const diff_sptr& underlying_type_diff,
3784  const diff_context_sptr ctxt)
3785  : type_diff_base(first, second, ctxt),
3786  priv_(new priv(underlying_type_diff))
3787 {}
3788 
3789 
3790 /// Getter of the first subrange of the current instance @ref
3791 /// subrange_diff.
3792 ///
3793 /// @return The first subrange of the current instance @ref subrange_diff.
3796 {return is_subrange_type(first_subject());}
3797 
3798 /// Getter of the second subrange of the current instance @ref
3799 /// subrange_diff.
3800 ///
3801 /// @return The second subrange of the current instance @ref
3802 /// subrange_diff.
3805 {return is_subrange_type(second_subject());}
3806 
3807 /// Getter of the diff node of the underlying types of the current
3808 /// @ref subrange_diff diff node.
3809 ///
3810 /// @return The diff node of the underlying types of the current @ref
3811 /// subrange_diff diff node.
3812 const diff_sptr
3814 {return priv_->underlying_type_diff_;}
3815 
3816 /// Getter the pretty representation of the @ref subrange_diff diff
3817 /// node.
3818 ///
3819 /// @return The pretty representation of the @ref subrange_diff diff node.
3820 const string&
3822 {
3823  if (diff::priv_->pretty_representation_.empty())
3824  {
3825  std::ostringstream o;
3826  o << "subrange_diff["
3827  << first_subject()->get_pretty_representation()
3828  << ","
3829  << second_subject()->get_pretty_representation()
3830  << "]";
3831  diff::priv_->pretty_representation_ = o.str();
3832  }
3833  return diff::priv_->pretty_representation_;
3834 }
3835 
3836 /// Test if the current @ref subrange_diff node carries any change.
3837 ///
3838 /// @return true iff the current @ref subrange_diff node carries any
3839 /// change.
3840 bool
3842 {return *first_subrange() != *second_subrange();}
3843 
3844 /// Test if the current @ref subrange_diff node carries any local
3845 /// change.
3846 ///
3847 /// @return true iff the current @ref subrange_diff node carries any
3848 /// local change.
3849 enum change_kind
3851 {
3852  ir::change_kind k = ir::NO_CHANGE_KIND;
3853  if (!equals(*first_subrange(), *second_subrange(), &k))
3854  return k & ir::ALL_LOCAL_CHANGES_MASK;
3855  return ir::NO_CHANGE_KIND;
3856 }
3857 
3858 /// Report about the changes carried by this node.
3859 ///
3860 /// @param out the output stream to send the report to.
3861 ///
3862 /// @param indent the indentation string to use.
3863 void
3864 subrange_diff::report(ostream& out, const string& indent) const
3865 {context()->get_reporter()->report(*this, out, indent);}
3866 
3867 /// Populate the vector of children node of the @ref diff base type
3868 /// sub-object of this instance of @ref subrange_diff.
3869 ///
3870 /// The children node can then later be retrieved using
3871 /// diff::children_node().
3872 void
3875 
3876 /// Compute the diff between two instances of @ref subrange_diff.
3877 ///
3878 /// Note that the two decls must have been created in the same @ref
3879 /// environment, otherwise, this function aborts.
3880 ///
3881 /// @param first the first @ref subrange_diff to consider for the diff.
3882 ///
3883 /// @param second the second @ref subrange_diff to consider for the diff.
3884 ///
3885 /// @param ctxt the diff context to use.
3886 ///
3887 /// @return the resulting diff between the two @ref subrange_diff.
3891  diff_context_sptr ctxt)
3892 {
3893  diff_sptr d = compute_diff_for_types(first->get_underlying_type(),
3894  second->get_underlying_type(),
3895  ctxt);
3896 
3897  subrange_diff_sptr result(new subrange_diff(first, second, d, ctxt));
3898  ctxt->initialize_canonical_diff(result);
3899  return result;
3900 }
3901 
3902 //</subrange_diff >
3903 
3904 
3905 // <array_type_def>
3906 
3907 /// Populate the vector of children node of the @ref diff base type
3908 /// sub-object of this instance of @ref array_diff.
3909 ///
3910 /// The children node can then later be retrieved using
3911 /// diff::children_node().
3912 void
3915 
3916 /// Constructor for array_diff
3917 ///
3918 /// @param first the first array_type of the diff.
3919 ///
3920 /// @param second the second array_type of the diff.
3921 ///
3922 /// @param element_type_diff the diff between the two array element
3923 /// types.
3924 ///
3925 /// @param ctxt the diff context to use.
3927  const array_type_def_sptr second,
3928  diff_sptr element_type_diff,
3929  diff_context_sptr ctxt)
3930  : type_diff_base(first, second, ctxt),
3931  priv_(new priv(element_type_diff))
3932 {}
3933 
3934 /// Getter for the first array of the diff.
3935 ///
3936 /// @return the first array of the diff.
3937 const array_type_def_sptr
3939 {return dynamic_pointer_cast<array_type_def>(first_subject());}
3940 
3941 /// Getter for the second array of the diff.
3942 ///
3943 /// @return for the second array of the diff.
3944 const array_type_def_sptr
3946 {return dynamic_pointer_cast<array_type_def>(second_subject());}
3947 
3948 /// Getter for the diff between the two types of array elements.
3949 ///
3950 /// @return the diff between the two types of array elements.
3951 const diff_sptr&
3953 {return priv_->element_type_diff_;}
3954 
3955 /// Setter for the diff between the two array element types.
3956 ///
3957 /// @param d the new diff betweend the two array element types.
3958 void
3960 {priv_->element_type_diff_ = d;}
3961 
3962 /// @return the pretty representation for the current instance of @ref
3963 /// array_diff.
3964 const string&
3966 {
3967  if (diff::priv_->pretty_representation_.empty())
3968  {
3969  std::ostringstream o;
3970  o << "array_diff["
3971  << first_subject()->get_pretty_representation()
3972  << ", "
3973  << second_subject()->get_pretty_representation()
3974  << "]";
3975  diff::priv_->pretty_representation_ = o.str();
3976  }
3977  return diff::priv_->pretty_representation_;
3978 }
3979 
3980 /// Return true iff the current diff node carries a change.
3981 ///
3982 /// @return true iff the current diff node carries a change.
3983 bool
3985 {
3986  bool l = false;
3987 
3988  // the array element types match check for differing dimensions
3989  // etc...
3991  f = dynamic_pointer_cast<array_type_def>(first_subject()),
3992  s = dynamic_pointer_cast<array_type_def>(second_subject());
3993 
3994  if (f->get_name() != s->get_name())
3995  l |= true;
3996  if (f->get_size_in_bits() != s->get_size_in_bits())
3997  l |= true;
3998  if (f->get_alignment_in_bits() != s->get_alignment_in_bits())
3999  l |= true;
4000 
4001  l |= element_type_diff()
4002  ? element_type_diff()->has_changes()
4003  : false;
4004 
4005  return l;
4006 }
4007 
4008 
4009 /// @return the kind of local change carried by the current diff node.
4010 /// The value returned is zero if the current node carries no local
4011 /// change.
4012 enum change_kind
4014 {
4015  ir::change_kind k = ir::NO_CHANGE_KIND;
4016  if (!equals(*first_array(), *second_array(), &k))
4017  return k & ir::ALL_LOCAL_CHANGES_MASK;
4018  return ir::NO_CHANGE_KIND;
4019 }
4020 
4021 /// Report the diff in a serialized form.
4022 ///
4023 /// @param out the output stream to serialize the dif to.
4024 ///
4025 /// @param indent the string to use for indenting the report.
4026 void
4027 array_diff::report(ostream& out, const string& indent) const
4028 {
4029  context()->get_reporter()->report(*this, out, indent);
4030 }
4031 
4032 /// Compute the diff between two arrays.
4033 ///
4034 /// Note that the two types must have been created in the same @ref
4035 /// environment, otherwise, this function aborts.
4036 ///
4037 /// @param first the first array to consider for the diff.
4038 ///
4039 /// @param second the second array to consider for the diff.
4040 ///
4041 /// @param ctxt the diff context to use.
4044  array_type_def_sptr second,
4045  diff_context_sptr ctxt)
4046 {
4047  diff_sptr d = compute_diff_for_types(first->get_element_type(),
4048  second->get_element_type(),
4049  ctxt);
4050  array_diff_sptr result(new array_diff(first, second, d, ctxt));
4051  ctxt->initialize_canonical_diff(result);
4052  return result;
4053 }
4054 // </array_type_def>
4055 
4056 // <reference_type_def>
4057 
4058 /// Populate the vector of children node of the @ref diff base type
4059 /// sub-object of this instance of @ref reference_diff.
4060 ///
4061 /// The children node can then later be retrieved using
4062 /// diff::children_node().
4063 void
4066 
4067 /// Constructor for reference_diff
4068 ///
4069 /// @param first the first reference_type of the diff.
4070 ///
4071 /// @param second the second reference_type of the diff.
4072 ///
4073 /// @param ctxt the diff context to use.
4075  const reference_type_def_sptr second,
4076  diff_sptr underlying,
4077  diff_context_sptr ctxt)
4078  : type_diff_base(first, second, ctxt),
4079  priv_(new priv(underlying))
4080 {}
4081 
4082 /// Getter for the first reference of the diff.
4083 ///
4084 /// @return the first reference of the diff.
4087 {return dynamic_pointer_cast<reference_type_def>(first_subject());}
4088 
4089 /// Getter for the second reference of the diff.
4090 ///
4091 /// @return for the second reference of the diff.
4094 {return dynamic_pointer_cast<reference_type_def>(second_subject());}
4095 
4096 
4097 /// Getter for the diff between the two referred-to types.
4098 ///
4099 /// @return the diff between the two referred-to types.
4100 const diff_sptr&
4102 {return priv_->underlying_type_diff_;}
4103 
4104 /// Setter for the diff between the two referred-to types.
4105 ///
4106 /// @param d the new diff betweend the two referred-to types.
4107 diff_sptr&
4109 {
4110  priv_->underlying_type_diff_ = d;
4111  return priv_->underlying_type_diff_;
4112 }
4113 
4114 /// @return the pretty representation for the current instance of @ref
4115 /// reference_diff.
4116 const string&
4118 {
4119  if (diff::priv_->pretty_representation_.empty())
4120  {
4121  std::ostringstream o;
4122  o << "reference_diff["
4123  << first_subject()->get_pretty_representation()
4124  << ", "
4125  << second_subject()->get_pretty_representation()
4126  << "]";
4127  diff::priv_->pretty_representation_ = o.str();
4128  }
4129  return diff::priv_->pretty_representation_;
4130 }
4131 
4132 /// Return true iff the current diff node carries a change.
4133 ///
4134 /// @return true iff the current diff node carries a change.
4135 bool
4137 {
4138  return first_reference() != second_reference();
4139 }
4140 
4141 /// @return the kind of local change carried by the current diff node.
4142 /// The value returned is zero if the current node carries no local
4143 /// change.
4144 enum change_kind
4146 {
4147  ir::change_kind k = ir::NO_CHANGE_KIND;
4148  if (!equals(*first_reference(), *second_reference(), &k))
4149  return k & ir::ALL_LOCAL_CHANGES_MASK;
4150  return ir::NO_CHANGE_KIND;
4151 }
4152 
4153 /// Report the diff in a serialized form.
4154 ///
4155 /// @param out the output stream to serialize the dif to.
4156 ///
4157 /// @param indent the string to use for indenting the report.
4158 void
4159 reference_diff::report(ostream& out, const string& indent) const
4160 {
4161  context()->get_reporter()->report(*this, out, indent);
4162 }
4163 
4164 /// Compute the diff between two references.
4165 ///
4166 /// Note that the two types must have been created in the same @ref
4167 /// environment, otherwise, this function aborts.
4168 ///
4169 /// @param first the first reference to consider for the diff.
4170 ///
4171 /// @param second the second reference to consider for the diff.
4172 ///
4173 /// @param ctxt the diff context to use.
4176  reference_type_def_sptr second,
4177  diff_context_sptr ctxt)
4178 {
4179  diff_sptr d = compute_diff_for_types(first->get_pointed_to_type(),
4180  second->get_pointed_to_type(),
4181  ctxt);
4182  reference_diff_sptr result(new reference_diff(first, second, d, ctxt));
4183  ctxt->initialize_canonical_diff(result);
4184  return result;
4185 }
4186 // </reference_type_def>
4187 
4188 // <ptr_to_mbr_diff stuff>
4189 
4190 
4191 /// Constructor of @ref ptr_to_mbr_diff.
4192 ///
4193 /// @param first the first pointer-to-member subject of the diff.
4194 ///
4195 /// @param second the second pointer-to-member subject of the diff.
4196 ///
4197 /// @param member_type_diff the diff node carrying changes to the
4198 /// member type of the pointer-to-member we are considering.
4199 ///
4200 /// @param containing_type_diff the diff node carrying changes to the
4201 /// containing type of the pointer-to-member we are considering.
4202 ///
4203 /// @param ctxt the context of the diff we are considering.
4204 ptr_to_mbr_diff::ptr_to_mbr_diff(const ptr_to_mbr_type_sptr& first,
4205  const ptr_to_mbr_type_sptr& second,
4206  const diff_sptr& member_type_diff,
4207  const diff_sptr& containing_type_diff,
4208  diff_context_sptr ctxt)
4209  : type_diff_base(first, second, ctxt),
4210  priv_(new priv(member_type_diff, containing_type_diff))
4211 {}
4212 
4213 /// Getter of the first pointer-to-member subject of the current diff
4214 /// node.
4215 ///
4216 /// @return the first pointer-to-member subject of the current diff
4217 /// node.
4220 {return dynamic_pointer_cast<ptr_to_mbr_type>(first_subject());}
4221 
4222 /// Getter of the second pointer-to-member subject of the current diff
4223 /// node.
4224 ///
4225 /// @return the second pointer-to-member subject of the current diff
4226 /// node.
4229 {return dynamic_pointer_cast<ptr_to_mbr_type>(second_subject());}
4230 
4231 /// Getter of the diff node carrying changes to the member type of
4232 /// first subject of the current diff node.
4233 ///
4234 /// @return The diff node carrying changes to the member type of first
4235 /// subject of the current diff node.
4236 const diff_sptr
4238 {return priv_->member_type_diff_;}
4239 
4240 /// Getter of the diff node carrying changes to the containing type of
4241 /// first subject of the current diff node.
4242 ///
4243 /// @return The diff node carrying changes to the containing type of
4244 /// first subject of the current diff node.
4245 const diff_sptr
4247 {return priv_->containing_type_diff_;}
4248 
4249 /// Test whether the current diff node carries any change.
4250 ///
4251 /// @return true iff the current diff node carries any change.
4252 bool
4254 {
4256 }
4257 
4258 /// Test whether the current diff node carries any local change.
4259 ///
4260 /// @return true iff the current diff node carries any local change.
4261 enum change_kind
4263 {
4264  ir::change_kind k = ir::NO_CHANGE_KIND;
4266  return k & ir::ALL_LOCAL_CHANGES_MASK;
4267  return ir::NO_CHANGE_KIND;
4268 }
4269 
4270 /// Get the pretty representation of the current @ref ptr_to_mbr_diff
4271 /// node.
4272 ///
4273 /// @return the pretty representation of the current diff node.
4274 const string&
4276 {
4277  if (diff::priv_->pretty_representation_.empty())
4278  {
4279  std::ostringstream o;
4280  o << "ptr_to_mbr_diff["
4281  << first_subject()->get_pretty_representation()
4282  << ", "
4283  << second_subject()->get_pretty_representation()
4284  << "]";
4285  diff::priv_->pretty_representation_ = o.str();
4286  }
4287  return diff::priv_->pretty_representation_;
4288 }
4289 
4290 void
4291 ptr_to_mbr_diff::report(ostream& out, const string& indent) const
4292 {
4293  context()->get_reporter()->report(*this, out, indent);
4294 }
4295 
4296 /// Populate the vector of children node of the @ref diff base type
4297 /// sub-object of this instance of @ref ptr_to_mbr_diff.
4298 ///
4299 /// The children node can then later be retrieved using
4300 /// diff::children_node().
4301 void
4303 {
4306 }
4307 
4308 /// Destructor of @ref ptr_to_mbr_diff.
4310 {
4311 }
4312 
4313 /// Compute the diff between two @ref ptr_to_mbr_type types.
4314 ///
4315 /// Note that the two types must have been created in the same @ref
4316 /// environment, otherwise, this function aborts.
4317 ///
4318 /// @param first the first pointer-to-member type to consider for the diff.
4319 ///
4320 /// @param second the second pointer-to-member type to consider for the diff.
4321 ///
4322 /// @param ctxt the diff context to use.
4325  const ptr_to_mbr_type_sptr& second,
4326  diff_context_sptr& ctxt)
4327 {
4328  diff_sptr member_type_diff =
4329  compute_diff(is_type(first->get_member_type()),
4330  is_type(second->get_member_type()),
4331  ctxt);
4332 
4333  diff_sptr containing_type_diff =
4334  compute_diff(is_type(first->get_containing_type()),
4335  is_type(second->get_containing_type()),
4336  ctxt);
4337 
4338  ptr_to_mbr_diff_sptr result(new ptr_to_mbr_diff(first, second,
4339  member_type_diff,
4340  containing_type_diff,
4341  ctxt));
4342  ctxt->initialize_canonical_diff(result);
4343  return result;
4344 }
4345 
4346 // </ptr_to_mbr_diff stuff>
4347 
4348 // <qualified_type_diff stuff>
4349 
4350 /// Populate the vector of children node of the @ref diff base type
4351 /// sub-object of this instance of @ref qualified_type_diff.
4352 ///
4353 /// The children node can then later be retrieved using
4354 /// diff::children_node().
4355 void
4358 
4359 /// Constructor for qualified_type_diff.
4360 ///
4361 /// @param first the first qualified type of the diff.
4362 ///
4363 /// @param second the second qualified type of the diff.
4364 ///
4365 /// @param ctxt the diff context to use.
4366 qualified_type_diff::qualified_type_diff(qualified_type_def_sptr first,
4367  qualified_type_def_sptr second,
4368  diff_sptr under,
4369  diff_context_sptr ctxt)
4370  : type_diff_base(first, second, ctxt),
4371  priv_(new priv(under))
4372 {}
4373 
4374 /// Getter for the first qualified type of the diff.
4375 ///
4376 /// @return the first qualified type of the diff.
4377 const qualified_type_def_sptr
4379 {return dynamic_pointer_cast<qualified_type_def>(first_subject());}
4380 
4381 /// Getter for the second qualified type of the diff.
4382 ///
4383 /// @return the second qualified type of the diff.
4384 const qualified_type_def_sptr
4386 {return dynamic_pointer_cast<qualified_type_def>(second_subject());}
4387 
4388 /// Getter for the diff between the underlying types of the two
4389 /// qualified types.
4390 ///
4391 /// @return the diff between the underlying types of the two qualified
4392 /// types.
4393 diff_sptr
4395 {return priv_->underlying_type_diff;}
4396 
4397 /// Getter for the diff between the most underlying non-qualified
4398 /// types of two qualified types.
4399 ///
4400 /// @return the diff between the most underlying non-qualified types
4401 /// of two qualified types.
4402 diff_sptr
4404 {
4405  if (!priv_->leaf_underlying_type_diff)
4406  priv_->leaf_underlying_type_diff
4407  = compute_diff_for_types(get_leaf_type(first_qualified_type()),
4409  context());
4410 
4411  return priv_->leaf_underlying_type_diff;
4412 }
4413 
4414 /// Setter for the diff between the underlying types of the two
4415 /// qualified types.
4416 ///
4417 /// @return the diff between the underlying types of the two qualified
4418 /// types.
4419 void
4421 {priv_->underlying_type_diff = d;}
4422 
4423 /// @return the pretty representation of the current instance of @ref
4424 /// qualified_type_diff.
4425 const string&
4427 {
4428  if (diff::priv_->pretty_representation_.empty())
4429  {
4430  std::ostringstream o;
4431  o << "qualified_type_diff["
4432  << first_subject()->get_pretty_representation()
4433  << ", "
4434  << second_subject()->get_pretty_representation()
4435  << "]";
4436  diff::priv_->pretty_representation_ = o.str();
4437  }
4438  return diff::priv_->pretty_representation_;
4439 }
4440 
4441 /// Return true iff the current diff node carries a change.
4442 ///
4443 /// @return true iff the current diff node carries a change.
4444 bool
4447 
4448 /// @return the kind of local change carried by the current diff node.
4449 /// The value returned is zero if the current node carries no local
4450 /// change.
4451 enum change_kind
4453 {
4454  ir::change_kind k = ir::NO_CHANGE_KIND;
4456  return k & ir::ALL_LOCAL_CHANGES_MASK;
4457  return ir::NO_CHANGE_KIND;
4458 }
4459 
4460 /// Report the diff in a serialized form.
4461 ///
4462 /// @param out the output stream to serialize to.
4463 ///
4464 /// @param indent the string to use to indent the lines of the report.
4465 void
4466 qualified_type_diff::report(ostream& out, const string& indent) const
4467 {
4468  context()->get_reporter()->report(*this, out, indent);
4469 }
4470 
4471 /// Compute the diff between two qualified types.
4472 ///
4473 /// Note that the two types must have been created in the same @ref
4474 /// environment, otherwise, this function aborts.
4475 ///
4476 /// @param first the first qualified type to consider for the diff.
4477 ///
4478 /// @param second the second qualified type to consider for the diff.
4479 ///
4480 /// @param ctxt the diff context to use.
4481 qualified_type_diff_sptr
4482 compute_diff(const qualified_type_def_sptr first,
4483  const qualified_type_def_sptr second,
4484  diff_context_sptr ctxt)
4485 {
4486  diff_sptr d = compute_diff_for_types(first->get_underlying_type(),
4487  second->get_underlying_type(),
4488  ctxt);
4489  qualified_type_diff_sptr result(new qualified_type_diff(first, second,
4490  d, ctxt));
4491  ctxt->initialize_canonical_diff(result);
4492  return result;
4493 }
4494 
4495 // </qualified_type_diff stuff>
4496 
4497 // <enum_diff stuff>
4498 
4499 /// Clear the lookup tables useful for reporting an enum_diff.
4500 ///
4501 /// This function must be updated each time a lookup table is added or
4502 /// removed from the class_diff::priv.
4503 void
4504 enum_diff::clear_lookup_tables()
4505 {
4506  priv_->deleted_enumerators_.clear();
4507  priv_->inserted_enumerators_.clear();
4508  priv_->changed_enumerators_.clear();
4509 }
4510 
4511 /// Tests if the lookup tables are empty.
4512 ///
4513 /// @return true if the lookup tables are empty, false otherwise.
4514 bool
4515 enum_diff::lookup_tables_empty() const
4516 {
4517  return (priv_->deleted_enumerators_.empty()
4518  && priv_->inserted_enumerators_.empty()
4519  && priv_->changed_enumerators_.empty());
4520 }
4521 
4522 /// If the lookup tables are not yet built, walk the differences and
4523 /// fill the lookup tables.
4524 void
4525 enum_diff::ensure_lookup_tables_populated()
4526 {
4527  if (!lookup_tables_empty())
4528  return;
4529 
4530  {
4531  edit_script e = priv_->enumerators_changes_;
4532 
4533  for (vector<deletion>::const_iterator it = e.deletions().begin();
4534  it != e.deletions().end();
4535  ++it)
4536  {
4537  unsigned i = it->index();
4538  const enum_type_decl::enumerator& n =
4539  first_enum()->get_enumerators()[i];
4540  const string& name = n.get_name();
4541  ABG_ASSERT(priv_->deleted_enumerators_.find(n.get_name())
4542  == priv_->deleted_enumerators_.end());
4543  priv_->deleted_enumerators_[name] = n;
4544  }
4545 
4546  for (vector<insertion>::const_iterator it = e.insertions().begin();
4547  it != e.insertions().end();
4548  ++it)
4549  {
4550  for (vector<unsigned>::const_iterator iit =
4551  it->inserted_indexes().begin();
4552  iit != it->inserted_indexes().end();
4553  ++iit)
4554  {
4555  unsigned i = *iit;
4556  const enum_type_decl::enumerator& n =
4557  second_enum()->get_enumerators()[i];
4558  const string& name = n.get_name();
4559  ABG_ASSERT(priv_->inserted_enumerators_.find(n.get_name())
4560  == priv_->inserted_enumerators_.end());
4561  string_enumerator_map::const_iterator j =
4562  priv_->deleted_enumerators_.find(name);
4563  if (j == priv_->deleted_enumerators_.end())
4564  priv_->inserted_enumerators_[name] = n;
4565  else
4566  {
4567  if (j->second != n)
4568  priv_->changed_enumerators_[j->first] =
4569  std::make_pair(j->second, n);
4570  priv_->deleted_enumerators_.erase(j);
4571  }
4572  }
4573  }
4574  }
4575 }
4576 
4577 /// Populate the vector of children node of the @ref diff base type
4578 /// sub-object of this instance of @ref enum_diff.
4579 ///
4580 /// The children node can then later be retrieved using
4581 /// diff::children_node().
4582 void
4585 
4586 /// Constructor for enum_diff.
4587 ///
4588 /// @param first the first enum type of the diff.
4589 ///
4590 /// @param second the second enum type of the diff.
4591 ///
4592 /// @param underlying_type_diff the diff of the two underlying types
4593 /// of the two enum types.
4594 ///
4595 /// @param ctxt the diff context to use.
4597  const enum_type_decl_sptr second,
4598  const diff_sptr underlying_type_diff,
4599  const diff_context_sptr ctxt)
4600  : type_diff_base(first, second, ctxt),
4601  priv_(new priv(underlying_type_diff))
4602 {}
4603 
4604 /// @return the first enum of the diff.
4605 const enum_type_decl_sptr
4607 {return dynamic_pointer_cast<enum_type_decl>(first_subject());}
4608 
4609 /// @return the second enum of the diff.
4610 const enum_type_decl_sptr
4612 {return dynamic_pointer_cast<enum_type_decl>(second_subject());}
4613 
4614 /// @return the diff of the two underlying enum types.
4615 diff_sptr
4617 {return priv_->underlying_type_diff_;}
4618 
4619 /// @return a map of the enumerators that were deleted.
4620 const string_enumerator_map&
4622 {return priv_->deleted_enumerators_;}
4623 
4624 /// @return a map of the enumerators that were inserted
4625 const string_enumerator_map&
4627 {return priv_->inserted_enumerators_;}
4628 
4629 /// @return a map of the enumerators that were changed
4632 {return priv_->changed_enumerators_;}
4633 
4634 /// @return the pretty representation of the current instance of @ref
4635 /// enum_diff.
4636 const string&
4638 {
4639  if (diff::priv_->pretty_representation_.empty())
4640  {
4641  std::ostringstream o;
4642  o << "enum_diff["
4643  << first_subject()->get_pretty_representation()
4644  << ", "
4645  << second_subject()->get_pretty_representation()
4646  << "]";
4647  diff::priv_->pretty_representation_ = o.str();
4648  }
4649  return diff::priv_->pretty_representation_;
4650 }
4651 
4652 /// Return true iff the current diff node carries a change.
4653 ///
4654 /// @return true iff the current diff node carries a change.
4655 bool
4657 {return first_enum() != second_enum();}
4658 
4659 /// @return the kind of local change carried by the current diff node.
4660 /// The value returned is zero if the current node carries no local
4661 /// change.
4662 enum change_kind
4664 {
4665  ir::change_kind k = ir::NO_CHANGE_KIND;
4666  if (!equals(*first_enum(), *second_enum(), &k))
4667  return k & ir::ALL_LOCAL_CHANGES_MASK;
4668  return ir::NO_CHANGE_KIND;
4669 }
4670 
4671 /// Report the differences between the two enums.
4672 ///
4673 /// @param out the output stream to send the report to.
4674 ///
4675 /// @param indent the string to use for indentation.
4676 void
4677 enum_diff::report(ostream& out, const string& indent) const
4678 {
4679  context()->get_reporter()->report(*this, out, indent);
4680 }
4681 
4682 /// Compute the set of changes between two instances of @ref
4683 /// enum_type_decl.
4684 ///
4685 /// Note that the two types must have been created in the same @ref
4686 /// environment, otherwise, this function aborts.
4687 ///
4688 /// @param first a pointer to the first enum_type_decl to consider.
4689 ///
4690 /// @param second a pointer to the second enum_type_decl to consider.
4691 ///
4692 /// @return the resulting diff of the two enums @p first and @p
4693 /// second.
4694 ///
4695 /// @param ctxt the diff context to use.
4696 enum_diff_sptr
4698  const enum_type_decl_sptr second,
4699  diff_context_sptr ctxt)
4700 {
4701  diff_sptr ud = compute_diff_for_types(first->get_underlying_type(),
4702  second->get_underlying_type(),
4703  ctxt);
4704  enum_diff_sptr d(new enum_diff(first, second, ud, ctxt));
4705  if (first != second)
4706  {
4707  compute_diff(first->get_enumerators().begin(),
4708  first->get_enumerators().end(),
4709  second->get_enumerators().begin(),
4710  second->get_enumerators().end(),
4711  d->priv_->enumerators_changes_);
4712  d->ensure_lookup_tables_populated();
4713  }
4714  ctxt->initialize_canonical_diff(d);
4715 
4716  return d;
4717 }
4718 // </enum_diff stuff>
4719 
4720 // <class_or_union_diff stuff>
4721 
4722 /// Test if the current diff node carries a member type change for a
4723 /// member type which name is the same as the name of a given type
4724 /// declaration.
4725 ///
4726 /// @param d the type declaration which name should be equal to the
4727 /// name of the member type that might have changed.
4728 ///
4729 /// @return the member type that has changed, iff there were a member
4730 /// type (which name is the same as the name of @p d) that changed.
4731 /// Note that the member type that is returned is the new value of the
4732 /// member type that changed.
4735 {
4736  string qname = d->get_qualified_name();
4737  string_diff_sptr_map::const_iterator it =
4738  changed_member_types_.find(qname);
4739 
4740  return ((it == changed_member_types_.end())
4742  : it->second->second_subject());
4743 }
4744 
4745 /// Test if the current diff node carries a data member change for a
4746 /// data member which name is the same as the name of a given type
4747 /// declaration.
4748 ///
4749 /// @param d the type declaration which name should be equal to the
4750 /// name of the data member that might have changed.
4751 ///
4752 /// @return the data member that has changed, iff there were a data
4753 /// member type (which name is the same as the name of @p d) that
4754 /// changed. Note that the data member that is returned is the new
4755 /// value of the data member that changed.
4756 decl_base_sptr
4758 {
4759  string qname = d->get_qualified_name();
4760  string_var_diff_sptr_map::const_iterator it =
4761  subtype_changed_dm_.find(qname);
4762 
4763  if (it == subtype_changed_dm_.end())
4764  return decl_base_sptr();
4765  return it->second->second_var();
4766 }
4767 
4768 /// Test if the current diff node carries a member class template
4769 /// change for a member class template which name is the same as the
4770 /// name of a given type declaration.
4771 ///
4772 /// @param d the type declaration which name should be equal to the
4773 /// name of the member class template that might have changed.
4774 ///
4775 /// @return the member class template that has changed, iff there were
4776 /// a member class template (which name is the same as the name of @p
4777 /// d) that changed. Note that the member class template that is
4778 /// returned is the new value of the member class template that
4779 /// changed.
4780 decl_base_sptr
4782 {
4783  string qname = d->get_qualified_name();
4784  string_diff_sptr_map::const_iterator it =
4785  changed_member_class_tmpls_.find(qname);
4786 
4787  return ((it == changed_member_class_tmpls_.end())
4788  ? decl_base_sptr()
4789  : dynamic_pointer_cast<decl_base>(it->second->second_subject()));
4790 }
4791 
4792 /// Get the number of non static data members that were deleted.
4793 ///
4794 /// @return the number of non static data members that were deleted.
4795 size_t
4797 {
4798  size_t result = 0;
4799 
4800  for (string_decl_base_sptr_map::const_iterator i =
4801  deleted_data_members_.begin();
4802  i != deleted_data_members_.end();
4803  ++i)
4804  if (is_member_decl(i->second)
4805  && !get_member_is_static(i->second))
4806  ++result;
4807 
4808  return result;
4809 }
4810 
4811 /// Get the number of non static data members that were inserted.
4812 ///
4813 /// @return the number of non static data members that were inserted.
4814 size_t
4816 {
4817  size_t result = 0;
4818 
4819  for (string_decl_base_sptr_map::const_iterator i =
4820  inserted_data_members_.begin();
4821  i != inserted_data_members_.end();
4822  ++i)
4823  if (is_member_decl(i->second)
4824  && !get_member_is_static(i->second))
4825  ++result;
4826 
4827  return result;
4828 }
4829 
4830 /// Get the number of data member sub-type changes carried by the
4831 /// current diff node that were filtered out.
4832 ///
4833 /// @param local_only if true, it means that only (filtered) local
4834 /// changes are considered.
4835 ///
4836 /// @return the number of data member sub-type changes carried by the
4837 /// current diff node that were filtered out.
4838 size_t
4840 {
4841  size_t num_filtered= 0;
4842  for (var_diff_sptrs_type::const_iterator i =
4843  sorted_subtype_changed_dm_.begin();
4844  i != sorted_subtype_changed_dm_.end();
4845  ++i)
4846  {
4847  if (local_only)
4848  {
4849  if ((*i)->has_changes()
4850  && !(*i)->has_local_changes_to_be_reported())
4851  ++num_filtered;
4852  }
4853  else
4854  {
4855  if ((*i)->is_filtered_out())
4856  ++num_filtered;
4857  }
4858  }
4859  return num_filtered;
4860 }
4861 
4862 /// Get the number of data member changes carried by the current diff
4863 /// node that were filtered out.
4864 ///
4865 /// @param local_only if true, it means that only (filtered) local
4866 /// changes are considered.
4867 ///
4868 /// @return the number of data member changes carried by the current
4869 /// diff node that were filtered out.
4870 size_t
4872 {
4873  size_t num_filtered= 0;
4874 
4875  for (unsigned_var_diff_sptr_map::const_iterator i = changed_dm_.begin();
4876  i != changed_dm_.end();
4877  ++i)
4878  {
4879  diff_sptr diff = i->second;
4880  if (local_only)
4881  {
4883  || diff->is_filtered_out())
4884  ++num_filtered;
4885  }
4886  else
4887  {
4888  if (diff->is_filtered_out())
4889  ++num_filtered;
4890  }
4891  }
4892  return num_filtered;
4893 }
4894 
4895 /// Skip the processing of the current member function if its
4896 /// virtual-ness is disallowed by the user.
4897 ///
4898 /// This is to be used in the member functions below that are used to
4899 /// count the number of filtered inserted, deleted and changed member
4900 /// functions.
4901 #define SKIP_MEM_FN_IF_VIRTUALITY_DISALLOWED \
4902  do { \
4903  if (get_member_function_is_virtual(f) \
4904  || get_member_function_is_virtual(s)) \
4905  { \
4906  if (!(allowed_category | VIRTUAL_MEMBER_CHANGE_CATEGORY)) \
4907  continue; \
4908  } \
4909  else \
4910  { \
4911  if (!(allowed_category | NON_VIRT_MEM_FUN_CHANGE_CATEGORY)) \
4912  continue; \
4913  } \
4914  } while (false)
4915 
4916 /// Get the number of member functions changes carried by the current
4917 /// diff node that were filtered out.
4918 ///
4919 /// @return the number of member functions changes carried by the
4920 /// current diff node that were filtered out.
4921 size_t
4923 (const diff_context_sptr& ctxt)
4924 {
4925  size_t count = 0;
4926  diff_category allowed_category = ctxt->get_allowed_category();
4927 
4928  for (function_decl_diff_sptrs_type::const_iterator i =
4929  sorted_changed_member_functions_.begin();
4930  i != sorted_changed_member_functions_.end();
4931  ++i)
4932  {
4933  method_decl_sptr f =
4934  dynamic_pointer_cast<method_decl>
4935  ((*i)->first_function_decl());
4936  ABG_ASSERT(f);
4937 
4938  method_decl_sptr s =
4939  dynamic_pointer_cast<method_decl>
4940  ((*i)->second_function_decl());
4941  ABG_ASSERT(s);
4942 
4944 
4945  diff_sptr diff = *i;
4946  ctxt->maybe_apply_filters(diff);
4947 
4948  if (diff->is_filtered_out())
4949  ++count;
4950  }
4951 
4952  return count;
4953 }
4954 
4955 /// Get the number of member functions insertions carried by the current
4956 /// diff node that were filtered out.
4957 ///
4958 /// @return the number of member functions insertions carried by the
4959 /// current diff node that were filtered out.
4960 size_t
4962 (const diff_context_sptr& ctxt)
4963 {
4964  size_t count = 0;
4965  diff_category allowed_category = ctxt->get_allowed_category();
4966 
4967  for (string_member_function_sptr_map::const_iterator i =
4968  inserted_member_functions_.begin();
4969  i != inserted_member_functions_.end();
4970  ++i)
4971  {
4972  method_decl_sptr f = i->second,
4973  s = i->second;
4974 
4976 
4977  diff_sptr diff = compute_diff_for_decls(f, s, ctxt);
4978  ctxt->maybe_apply_filters(diff);
4979 
4981  && diff->is_filtered_out())
4982  ++count;
4983  }
4984 
4985  return count;
4986 }
4987 
4988 /// Get the number of member functions deletions carried by the current
4989 /// diff node that were filtered out.
4990 ///
4991 /// @return the number of member functions deletions carried by the
4992 /// current diff node that were filtered out.
4993 size_t
4995 (const diff_context_sptr& ctxt)
4996 {
4997  size_t count = 0;
4998  diff_category allowed_category = ctxt->get_allowed_category();
4999 
5000  for (string_member_function_sptr_map::const_iterator i =
5001  deleted_member_functions_.begin();
5002  i != deleted_member_functions_.end();
5003  ++i)
5004  {
5005  method_decl_sptr f = i->second,
5006  s = i->second;
5007 
5009 
5010  diff_sptr diff = compute_diff_for_decls(f, s, ctxt);
5011  ctxt->maybe_apply_filters(diff);
5012 
5014  && diff->is_filtered_out())
5015  ++count;
5016  }
5017 
5018  return count;
5019 }
5020 
5021 /// Clear the lookup tables useful for reporting.
5022 ///
5023 /// This function must be updated each time a lookup table is added or
5024 /// removed from the class_or_union_diff::priv.
5025 void
5027 {
5028  priv_->deleted_member_types_.clear();
5029  priv_->inserted_member_types_.clear();
5030  priv_->changed_member_types_.clear();
5031  priv_->deleted_data_members_.clear();
5032  priv_->inserted_data_members_.clear();
5033  priv_->subtype_changed_dm_.clear();
5034  priv_->deleted_member_functions_.clear();
5035  priv_->inserted_member_functions_.clear();
5036  priv_->changed_member_functions_.clear();
5037  priv_->deleted_member_class_tmpls_.clear();
5038  priv_->inserted_member_class_tmpls_.clear();
5039  priv_->changed_member_class_tmpls_.clear();
5040 }
5041 
5042 /// Tests if the lookup tables are empty.
5043 ///
5044 /// @return true if the lookup tables are empty, false otherwise.
5045 bool
5047 {
5048  return (priv_->deleted_member_types_.empty()
5049  && priv_->inserted_member_types_.empty()
5050  && priv_->changed_member_types_.empty()
5051  && priv_->deleted_data_members_.empty()
5052  && priv_->inserted_data_members_.empty()
5053  && priv_->subtype_changed_dm_.empty()
5054  && priv_->inserted_member_functions_.empty()
5055  && priv_->deleted_member_functions_.empty()
5056  && priv_->changed_member_functions_.empty()
5057  && priv_->deleted_member_class_tmpls_.empty()
5058  && priv_->inserted_member_class_tmpls_.empty()
5059  && priv_->changed_member_class_tmpls_.empty());
5060 }
5061 
5062 /// If the lookup tables are not yet built, walk the differences and
5063 /// fill them.
5064 void
5066 {
5067  {
5068  edit_script& e = priv_->member_types_changes_;
5069 
5070  for (vector<deletion>::const_iterator it = e.deletions().begin();
5071  it != e.deletions().end();
5072  ++it)
5073  {
5074  unsigned i = it->index();
5075  decl_base_sptr d =
5076  get_type_declaration(first_class_or_union()->get_member_types()[i]);
5077  class_or_union_sptr record_type = is_class_or_union_type(d);
5078  if (record_type && record_type->get_is_declaration_only())
5079  continue;
5080  string name = d->get_name();
5081  priv_->deleted_member_types_[name] = d;
5082  }
5083 
5084  for (vector<insertion>::const_iterator it = e.insertions().begin();
5085  it != e.insertions().end();
5086  ++it)
5087  {
5088  for (vector<unsigned>::const_iterator iit =
5089  it->inserted_indexes().begin();
5090  iit != it->inserted_indexes().end();
5091  ++iit)
5092  {
5093  unsigned i = *iit;
5094  decl_base_sptr d =
5095  get_type_declaration(second_class_or_union()->get_member_types()[i]);
5096  class_or_union_sptr record_type = is_class_or_union_type(d);
5097  if (record_type && record_type->get_is_declaration_only())
5098  continue;
5099  string name = d->get_name();
5100  string_decl_base_sptr_map::const_iterator j =
5101  priv_->deleted_member_types_.find(name);
5102  if (j != priv_->deleted_member_types_.end())
5103  {
5104  if (*j->second != *d)
5105  priv_->changed_member_types_[name] =
5106  compute_diff(j->second, d, context());
5107 
5108  priv_->deleted_member_types_.erase(j);
5109  }
5110  else
5111  priv_->inserted_member_types_[name] = d;
5112  }
5113  }
5114  }
5115 
5116  {
5117  edit_script& e = priv_->data_members_changes_;
5118 
5119  for (vector<deletion>::const_iterator it = e.deletions().begin();
5120  it != e.deletions().end();
5121  ++it)
5122  {
5123  unsigned i = it->index();
5124  var_decl_sptr data_member =
5125  is_var_decl(first_class_or_union()->get_non_static_data_members()[i]);
5126  string name = data_member->get_anon_dm_reliable_name();
5127 
5128  ABG_ASSERT(priv_->deleted_data_members_.find(name)
5129  == priv_->deleted_data_members_.end());
5130  priv_->deleted_data_members_[name] = data_member;
5131  }
5132 
5133  for (vector<insertion>::const_iterator it = e.insertions().begin();
5134  it != e.insertions().end();
5135  ++it)
5136  {
5137  for (vector<unsigned>::const_iterator iit =
5138  it->inserted_indexes().begin();
5139  iit != it->inserted_indexes().end();
5140  ++iit)
5141  {
5142  unsigned i = *iit;
5143  decl_base_sptr d =
5144  second_class_or_union()->get_non_static_data_members()[i];
5145  var_decl_sptr added_dm = is_var_decl(d);
5146  string name = added_dm->get_anon_dm_reliable_name();
5147  ABG_ASSERT(priv_->inserted_data_members_.find(name)
5148  == priv_->inserted_data_members_.end());
5149 
5150  bool ignore_added_anonymous_data_member = false;
5151  if (is_anonymous_data_member(added_dm))
5152  {
5153  //
5154  // Handle insertion of anonymous data member to
5155  // replace existing data members.
5156  //
5157  // For instance consider this:
5158  // struct S
5159  // {
5160  // int a;
5161  // int b;
5162  // int c;
5163  // };// end struct S
5164  //
5165  // Where the data members 'a' and 'b' are replaced
5166  // by an anonymous data member without changing the
5167  // effective bit layout of the structure:
5168  //
5169  // struct S
5170  // {
5171  // struct
5172  // {
5173  // union
5174  // {
5175  // int a;
5176  // char a_1;
5177  // };
5178  // union
5179  // {
5180  // int b;
5181  // char b_1;
5182  // };
5183  // };
5184  // int c;
5185  // }; // end struct S
5186  //
5187  var_decl_sptr replaced_dm, replacing_dm;
5188  bool added_anon_dm_changes_dm = false;
5189  // The vector of data members replaced by anonymous
5190  // data members.
5191  vector<var_decl_sptr> dms_replaced_by_anon_dm;
5192 
5193  //
5194  // Let's start collecting the set of data members
5195  // which have been replaced by anonymous types in a
5196  // harmless way. These are going to be collected into
5197  // dms_replaced_by_anon_dm and, ultimately, into
5198  // priv_->dms_replaced_by_adms_
5199  //
5200  for (string_decl_base_sptr_map::const_iterator it =
5201  priv_->deleted_data_members_.begin();
5202  it != priv_->deleted_data_members_.end();
5203  ++it)
5204  {
5205  // We don't support this pattern for anonymous
5206  // data members themselves being replaced. If
5207  // that occurs then we'll just report it verbatim.
5208  if (is_anonymous_data_member(it->second))
5209  continue;
5210 
5211  string deleted_dm_name = it->second->get_name();
5212  if ((replacing_dm =
5214  deleted_dm_name)))
5215  {
5216  // So it looks like replacing_dm might have
5217  // replaced the data member which name is
5218  // 'deleted_dm_name'. Let's look deeper to be
5219  // sure.
5220  //
5221  // Note that replacing_dm is part (member) of
5222  // an anonymous data member that might replace
5223  // replaced_dm.
5224 
5225  // So let's get that replaced data member.
5226  replaced_dm = is_var_decl(it->second);
5227  size_t replaced_dm_offset =
5228  get_data_member_offset(replaced_dm),
5229  replacing_dm_offset =
5230  get_absolute_data_member_offset(replacing_dm);
5231 
5232  if (replaced_dm_offset != replacing_dm_offset)
5233  {
5234  // So the replacing data member and the
5235  // replaced data member don't have the
5236  // same offset. This is not the pattern we
5237  // are looking for. Rather, it looks like
5238  // the anonymous data member has *changed*
5239  // the data member.
5240  added_anon_dm_changes_dm = true;
5241  break;
5242  }
5243 
5244  if (replaced_dm->get_type()->get_size_in_bits()
5245  == replaced_dm->get_type()->get_size_in_bits())
5246  dms_replaced_by_anon_dm.push_back(replaced_dm);
5247  else
5248  {
5249  added_anon_dm_changes_dm = true;
5250  break;
5251  }
5252  }
5253  }
5254 
5255  // Now walk dms_replaced_by_anon_dm to fill up
5256  // priv_->dms_replaced_by_adms_ with the set of data
5257  // members replaced by anonymous data members.
5258  if (!added_anon_dm_changes_dm
5259  && !dms_replaced_by_anon_dm.empty())
5260  {
5261  // See if the added data member isn't too big.
5262  type_base_sptr added_dm_type = added_dm->get_type();
5263  ABG_ASSERT(added_dm_type);
5264  var_decl_sptr new_next_dm =
5266  added_dm);
5267  var_decl_sptr old_next_dm =
5268  first_class_or_union()->find_data_member(new_next_dm);
5269 
5270  if (!old_next_dm
5271  || (old_next_dm
5272  && (get_absolute_data_member_offset(old_next_dm)
5273  == get_absolute_data_member_offset(new_next_dm))))
5274  {
5275  // None of the data members that are replaced
5276  // by the added union should be considered as
5277  // having been deleted.
5278  ignore_added_anonymous_data_member = true;
5279  for (vector<var_decl_sptr>::const_iterator i =
5280  dms_replaced_by_anon_dm.begin();
5281  i != dms_replaced_by_anon_dm.end();
5282  ++i)
5283  {
5284  string n = (*i)->get_name();
5285  priv_->dms_replaced_by_adms_[n] =
5286  added_dm;
5287  priv_->deleted_data_members_.erase(n);
5288  }
5289  }
5290  }
5291  }
5292 
5293  if (!ignore_added_anonymous_data_member)
5294  {
5295  // Detect changed data members.
5296  //
5297  // A changed data member (that we shall name D) is a data
5298  // member that satisfies the conditions below:
5299  //
5300  // 1/ It must have been added.
5301  //
5302  // 2/ It must have been deleted as well.
5303  //
5304  // 3/ There must be a non-empty difference between the
5305  // deleted D and the added D.
5306  string_decl_base_sptr_map::const_iterator j =
5307  priv_->deleted_data_members_.find(name);
5308  if (j != priv_->deleted_data_members_.end())
5309  {
5310  if (*j->second != *d)
5311  {
5312  var_decl_sptr old_dm = is_var_decl(j->second);
5313  priv_->subtype_changed_dm_[name]=
5314  compute_diff(old_dm, added_dm, context());
5315  }
5316  priv_->deleted_data_members_.erase(j);
5317  }
5318  else
5319  priv_->inserted_data_members_[name] = d;
5320  }
5321  }
5322  }
5323 
5324  // Now detect when a data member is deleted from offset N and
5325  // another one is added to offset N. In that case, we want to be
5326  // able to say that the data member at offset N changed.
5327  for (string_decl_base_sptr_map::const_iterator i =
5328  priv_->deleted_data_members_.begin();
5329  i != priv_->deleted_data_members_.end();
5330  ++i)
5331  {
5332  unsigned offset = get_data_member_offset(i->second);
5333  priv_->deleted_dm_by_offset_[offset] = i->second;
5334  }
5335 
5336  for (string_decl_base_sptr_map::const_iterator i =
5337  priv_->inserted_data_members_.begin();
5338  i != priv_->inserted_data_members_.end();
5339  ++i)
5340  {
5341  unsigned offset = get_data_member_offset(i->second);
5342  priv_->inserted_dm_by_offset_[offset] = i->second;
5343  }
5344 
5345  for (unsigned_decl_base_sptr_map::const_iterator i =
5346  priv_->inserted_dm_by_offset_.begin();
5347  i != priv_->inserted_dm_by_offset_.end();
5348  ++i)
5349  {
5350  unsigned_decl_base_sptr_map::const_iterator j =
5351  priv_->deleted_dm_by_offset_.find(i->first);
5352  if (j != priv_->deleted_dm_by_offset_.end())
5353  {
5354  var_decl_sptr old_dm = is_var_decl(j->second);
5355  var_decl_sptr new_dm = is_var_decl(i->second);
5356  priv_->changed_dm_[i->first] =
5357  compute_diff(old_dm, new_dm, context());
5358  }
5359  }
5360 
5361  for (unsigned_var_diff_sptr_map::const_iterator i =
5362  priv_->changed_dm_.begin();
5363  i != priv_->changed_dm_.end();
5364  ++i)
5365  {
5366  priv_->deleted_dm_by_offset_.erase(i->first);
5367  priv_->inserted_dm_by_offset_.erase(i->first);
5368  priv_->deleted_data_members_.erase
5369  (i->second->first_var()->get_anon_dm_reliable_name());
5370  priv_->inserted_data_members_.erase
5371  (i->second->second_var()->get_anon_dm_reliable_name());
5372  }
5373 
5374  // Now detect anonymous data members that might appear as deleted
5375  // even though all their data members are still present. Consider
5376  // these as being non-deleted.
5377  string_decl_base_sptr_map non_anonymous_dms_in_second_class;
5379  non_anonymous_dms_in_second_class);
5380  vector<string> deleted_data_members_to_delete;
5381  // Walk data members considered deleted ...
5382  for (auto& entry : priv_->deleted_data_members_)
5383  {
5384  var_decl_sptr data_member = is_var_decl(entry.second);
5385  ABG_ASSERT(data_member);
5386  if (is_anonymous_data_member(data_member))
5387  {
5388  // Let's look at this anonymous data member that is
5389  // considered deleted because it's moved from where it was
5390  // initially, at very least. If its leaf data members are
5391  // still present in the second class then, we won't
5392  // consider it as deleted.
5393  class_or_union_sptr cou = anonymous_data_member_to_class_or_union(data_member);
5394  ABG_ASSERT(cou);
5395  string_decl_base_sptr_map non_anonymous_data_members;
5396  // Lets collect the leaf data members of the anonymous
5397  // data member.
5398  collect_non_anonymous_data_members(cou, non_anonymous_data_members);
5399  bool anonymous_dm_members_present = true;
5400  // Let's see if at least one of the leaf members of the
5401  // anonymous data member is NOT present in the second
5402  // version of the class.
5403  for (auto& e : non_anonymous_data_members)
5404  {
5405  if (non_anonymous_dms_in_second_class.find(e.first)
5406  == non_anonymous_dms_in_second_class.end())
5407  // Grrr, OK, it looks like at least one leaf data
5408  // member of the original anonymous data member was
5409  // removed from the class, so yeah, the anonymous
5410  // data member might have been removed after all.
5411  anonymous_dm_members_present = false;
5412  }
5413  if (anonymous_dm_members_present)
5414  // All leaf data members of the anonymous data member
5415  // are still present in the second version of the class.
5416  // So let's mark that anonymous data member as NOT being
5417  // deleted.
5418  deleted_data_members_to_delete.push_back(data_member->get_anon_dm_reliable_name());
5419  }
5420  }
5421  // All anonymous data members that were recognized as being NOT
5422  // deleted should be removed from the set of deleted data members
5423  // now.
5424  for (string& name_of_dm_to_delete: deleted_data_members_to_delete)
5425  priv_->deleted_data_members_.erase(name_of_dm_to_delete);
5426  }
5427  sort_string_data_member_diff_sptr_map(priv_->subtype_changed_dm_,
5428  priv_->sorted_subtype_changed_dm_);
5429  sort_unsigned_data_member_diff_sptr_map(priv_->changed_dm_,
5430  priv_->sorted_changed_dm_);
5431 
5432  {
5433  edit_script& e = priv_->member_class_tmpls_changes_;
5434 
5435  for (vector<deletion>::const_iterator it = e.deletions().begin();
5436  it != e.deletions().end();
5437  ++it)
5438  {
5439  unsigned i = it->index();
5440  decl_base_sptr d =
5441  first_class_or_union()->get_member_class_templates()[i]->
5442  as_class_tdecl();
5443  string name = d->get_name();
5444  ABG_ASSERT(priv_->deleted_member_class_tmpls_.find(name)
5445  == priv_->deleted_member_class_tmpls_.end());
5446  priv_->deleted_member_class_tmpls_[name] = d;
5447  }
5448 
5449  for (vector<insertion>::const_iterator it = e.insertions().begin();
5450  it != e.insertions().end();
5451  ++it)
5452  {
5453  for (vector<unsigned>::const_iterator iit =
5454  it->inserted_indexes().begin();
5455  iit != it->inserted_indexes().end();
5456  ++iit)
5457  {
5458  unsigned i = *iit;
5459  decl_base_sptr d =
5460  second_class_or_union()->get_member_class_templates()[i]->
5461  as_class_tdecl();
5462  string name = d->get_name();
5463  ABG_ASSERT(priv_->inserted_member_class_tmpls_.find(name)
5464  == priv_->inserted_member_class_tmpls_.end());
5465  string_decl_base_sptr_map::const_iterator j =
5466  priv_->deleted_member_class_tmpls_.find(name);
5467  if (j != priv_->deleted_member_class_tmpls_.end())
5468  {
5469  if (*j->second != *d)
5470  priv_->changed_member_types_[name]=
5471  compute_diff(j->second, d, context());
5472  priv_->deleted_member_class_tmpls_.erase(j);
5473  }
5474  else
5475  priv_->inserted_member_class_tmpls_[name] = d;
5476  }
5477  }
5478  }
5479  sort_string_diff_sptr_map(priv_->changed_member_types_,
5480  priv_->sorted_changed_member_types_);
5481 }
5482 
5483 /// Allocate the memory for the priv_ pimpl data member of the @ref
5484 /// class_or_union_diff class.
5485 void
5487 {
5488  if (!priv_)
5489  priv_.reset(new priv);
5490 }
5491 
5492 /// Constructor for the @ref class_or_union_diff class.
5493 ///
5494 /// @param first_scope the first @ref class_or_union of the diff node.
5495 ///
5496 /// @param second_scope the second @ref class_or_union of the diff node.
5497 ///
5498 /// @param ctxt the context of the diff.
5499 class_or_union_diff::class_or_union_diff(class_or_union_sptr first_scope,
5500  class_or_union_sptr second_scope,
5501  diff_context_sptr ctxt)
5502  : type_diff_base(first_scope, second_scope, ctxt)
5503  //priv_(new priv)
5504 {}
5505 
5506 /// Getter of the private data of the @ref class_or_union_diff type.
5507 ///
5508 /// Note that due to an optimization, the private data of @ref
5509 /// class_or_union_diff can be shared among several instances of
5510 /// class_or_union_diff, so you should never try to access
5511 /// class_or_union_diff::priv directly.
5512 ///
5513 /// When class_or_union_diff::priv is shared, this function returns
5514 /// the correct shared one.
5515 ///
5516 /// @return the (possibly) shared private data of the current instance
5517 /// of @ref class_or_union_diff.
5518 const class_or_union_diff::priv_ptr&
5520 {
5521  if (priv_)
5522  return priv_;
5523 
5524  // If the current class_or_union_diff::priv member is empty, then look for
5525  // the shared one, from the canonical type.
5526  class_or_union_diff *canonical =
5527  dynamic_cast<class_or_union_diff*>(get_canonical_diff());
5528  ABG_ASSERT(canonical);
5529  ABG_ASSERT(canonical->priv_);
5530 
5531  return canonical->priv_;
5532 }
5533 
5534 /// Destructor of class_or_union_diff.
5536 {
5537 }
5538 
5539 /// @return the first @ref class_or_union involved in the diff.
5540 class_or_union_sptr
5543 
5544 /// @return the second @ref class_or_union involved in the diff.
5545 class_or_union_sptr
5548 
5549 /// @return the edit script of the member types of the two @ref
5550 /// class_or_union.
5551 const edit_script&
5553 {return get_priv()->member_types_changes_;}
5554 
5555 /// @return the edit script of the member types of the two @ref
5556 /// class_or_union.
5557 edit_script&
5559 {return get_priv()->member_types_changes_;}
5560 
5561 /// @return the edit script of the data members of the two @ref
5562 /// class_or_union.
5563 const edit_script&
5565 {return get_priv()->data_members_changes_;}
5566 
5567 /// @return the edit script of the data members of the two @ref
5568 /// class_or_union.
5569 edit_script&
5571 {return get_priv()->data_members_changes_;}
5572 
5573 /// Getter for the data members that got inserted.
5574 ///
5575 /// @return a map of data members that got inserted.
5578 {return get_priv()->inserted_data_members_;}
5579 
5580 /// Getter for the data members that got deleted.
5581 ///
5582 /// @return a map of data members that got deleted.
5585 {return get_priv()->deleted_data_members_;}
5586 
5587 /// @return the edit script of the member functions of the two @ref
5588 /// class_or_union.
5589 const edit_script&
5591 {return get_priv()->member_fns_changes_;}
5592 
5593 /// Getter for the virtual members functions that have had a change in
5594 /// a sub-type, without having a change in their symbol name.
5595 ///
5596 /// @return a sorted vector of virtual member functions that have a
5597 /// sub-type change.
5600 {return get_priv()->sorted_changed_member_functions_;}
5601 
5602 /// @return the edit script of the member functions of the two
5603 /// classes.
5604 edit_script&
5606 {return get_priv()->member_fns_changes_;}
5607 
5608 /// @return a map of member functions that got deleted.
5611 {return get_priv()->deleted_member_functions_;}
5612 
5613 /// @return a map of member functions that got inserted.
5616 {return get_priv()->inserted_member_functions_;}
5617 
5618 /// Getter of the map of data members that got replaced by another
5619 /// data member. The key of the map is the offset at which the
5620 /// element got replaced and the value is a pointer to the @ref
5621 /// var_diff representing the replacement of the data member.
5622 ///
5623 /// @return sorted vector of changed data member.
5626 {return get_priv()->changed_dm_;}
5627 
5628 /// Getter of the sorted vector of data members that got replaced by
5629 /// another data member.
5630 ///
5631 /// @return sorted vector of changed data member.
5632 const var_diff_sptrs_type&
5634 {return get_priv()->sorted_changed_dm_;}
5635 
5636 /// Count the number of /filtered/ data members that got replaced by
5637 /// another data member.
5638 ///
5639 /// @return the number of changed data member that got filtered out.
5640 size_t
5642 {return get_priv()->count_filtered_changed_dm(local);}
5643 
5644 /// Getter of the sorted vector of data members with a (sub-)type change.
5645 ///
5646 /// @return sorted vector of changed data member.
5647 const var_diff_sptrs_type&
5649 {return get_priv()->sorted_subtype_changed_dm_;}
5650 
5651 /// Count the number of /filtered/ data members with a sub-type change.
5652 ///
5653 /// @return the number of changed data member that got filtered out.
5654 size_t
5656 {return get_priv()->count_filtered_subtype_changed_dm(local);}
5657 
5658 /// Get the map of data members that got replaced by anonymous data
5659 /// members.
5660 ///
5661 /// The key of a map entry is the name of the replaced data member and
5662 /// the value is the anonymous data member that replaces it.
5663 ///
5664 /// @return the map of data members replaced by anonymous data
5665 /// members.
5668 {return get_priv()->dms_replaced_by_adms_;}
5669 
5670 /// Get an ordered vector of of data members that got replaced by
5671 /// anonymous data members.
5672 ///
5673 /// This returns a vector of pair of two data members: the one that
5674 /// was replaced, and the anonymous data member that replaced it.
5675 ///
5676 /// @return the sorted vector data members replaced by anonymous data members.
5679 {
5680  if (priv_->dms_replaced_by_adms_ordered_.empty())
5681  {
5682  for (string_decl_base_sptr_map::const_iterator it =
5683  priv_->dms_replaced_by_adms_.begin();
5684  it != priv_->dms_replaced_by_adms_.end();
5685  ++it)
5686  {
5687  const var_decl_sptr dm =
5688  first_class_or_union()->find_data_member(it->first);
5689  ABG_ASSERT(dm);
5690  changed_var_sptr changed_dm(dm, is_data_member(it->second));
5691  priv_->dms_replaced_by_adms_ordered_.push_back(changed_dm);
5692  }
5693  sort_changed_data_members(priv_->dms_replaced_by_adms_ordered_);
5694  }
5695 
5696  return priv_->dms_replaced_by_adms_ordered_;
5697 }
5698 
5699 /// @return the edit script of the member function templates of the two
5700 /// @ref class_or_union.
5701 const edit_script&
5703 {return get_priv()->member_fn_tmpls_changes_;}
5704 
5705 /// @return the edit script of the member function templates of the
5706 /// two @ref class_or_union.
5707 edit_script&
5709 {return get_priv()->member_fn_tmpls_changes_;}
5710 
5711 /// @return the edit script of the member class templates of the two
5712 /// @ref class_or_union.
5713 const edit_script&
5715 {return get_priv()->member_class_tmpls_changes_;}
5716 
5717 /// @return the edit script of the member class templates of the two
5718 /// @ref class_or_union.
5719 edit_script&
5721 {return get_priv()->member_class_tmpls_changes_;}
5722 
5723 /// Test if the current diff node carries a change.
5724 bool
5727 
5728 /// @return the kind of local change carried by the current diff node.
5729 /// The value returned is zero if the current node carries no local
5730 /// change.
5731 enum change_kind
5733 {
5734  ir::change_kind k = ir::NO_CHANGE_KIND;
5736  return k & ir::ALL_LOCAL_CHANGES_MASK;
5737  return ir::NO_CHANGE_KIND;
5738 }
5739 
5740 
5741 /// Report the changes carried by the current @ref class_or_union_diff
5742 /// node in a textual format.
5743 ///
5744 /// @param out the output stream to write the textual report to.
5745 ///
5746 /// @param indent the number of white space to use as indentation.
5747 void
5748 class_or_union_diff::report(ostream& out, const string& indent) const
5749 {
5750  context()->get_reporter()->report(*this, out, indent);
5751 }
5752 
5753 /// Populate the vector of children node of the @ref diff base type
5754 /// sub-object of this instance of @ref class_or_union_diff.
5755 ///
5756 /// The children node can then later be retrieved using
5757 /// diff::children_node().
5758 void
5760 {
5761  // data member changes
5762  for (var_diff_sptrs_type::const_iterator i =
5763  get_priv()->sorted_subtype_changed_dm_.begin();
5764  i != get_priv()->sorted_subtype_changed_dm_.end();
5765  ++i)
5766  if (diff_sptr d = *i)
5767  append_child_node(d);
5768 
5769  for (var_diff_sptrs_type::const_iterator i =
5770  get_priv()->sorted_changed_dm_.begin();
5771  i != get_priv()->sorted_changed_dm_.end();
5772  ++i)
5773  if (diff_sptr d = *i)
5774  append_child_node(d);
5775 
5776  // member types changes
5777  for (diff_sptrs_type::const_iterator i =
5778  get_priv()->sorted_changed_member_types_.begin();
5779  i != get_priv()->sorted_changed_member_types_.end();
5780  ++i)
5781  if (diff_sptr d = *i)
5782  append_child_node(d);
5783 
5784  // member function changes
5785  for (function_decl_diff_sptrs_type::const_iterator i =
5786  get_priv()->sorted_changed_member_functions_.begin();
5787  i != get_priv()->sorted_changed_member_functions_.end();
5788  ++i)
5789  if (diff_sptr d = *i)
5790  append_child_node(d);
5791 }
5792 
5793 // </class_or_union_diff stuff>
5794 
5795 //<class_diff stuff>
5796 
5797 /// Clear the lookup tables useful for reporting.
5798 ///
5799 /// This function must be updated each time a lookup table is added or
5800 /// removed from the class_diff::priv.
5801 void
5802 class_diff::clear_lookup_tables(void)
5803 {
5804  priv_->deleted_bases_.clear();
5805  priv_->inserted_bases_.clear();
5806  priv_->changed_bases_.clear();
5807 }
5808 
5809 /// Tests if the lookup tables are empty.
5810 ///
5811 /// @return true if the lookup tables are empty, false otherwise.
5812 bool
5813 class_diff::lookup_tables_empty(void) const
5814 {
5815  return (priv_->deleted_bases_.empty()
5816  && priv_->inserted_bases_.empty()
5817  && priv_->changed_bases_.empty());
5818 }
5819 
5820 /// Find a virtual destructor in a map of member functions
5821 ///
5822 /// @param map the map of member functions. Note that the key of the
5823 /// map is the member function name. The key is the member function.
5824 ///
5825 /// @return an iterator to the destructor found or, if no virtual destructor
5826 /// was found, return map.end()
5827 static string_member_function_sptr_map::const_iterator
5828 find_virtual_dtor_in_map(const string_member_function_sptr_map& map)
5829 {
5830  for (string_member_function_sptr_map::const_iterator i = map.begin();
5831  i !=map.end();
5832  ++i)
5833  {
5834  if (get_member_function_is_dtor(i->second)
5835  && get_member_function_is_virtual(i->second))
5836  return i;
5837  }
5838  return map.end();
5839 }
5840 
5841 /// If the lookup tables are not yet built, walk the differences and
5842 /// fill them.
5843 void
5844 class_diff::ensure_lookup_tables_populated(void) const
5845 {
5847 
5848  if (!lookup_tables_empty())
5849  return;
5850 
5851  {
5852  edit_script& e = get_priv()->base_changes_;
5853 
5854  for (vector<deletion>::const_iterator it = e.deletions().begin();
5855  it != e.deletions().end();
5856  ++it)
5857  {
5858  unsigned i = it->index();
5860  first_class_decl()->get_base_specifiers()[i];
5861  string name = b->get_base_class()->get_qualified_name();
5862  ABG_ASSERT(get_priv()->deleted_bases_.find(name)
5863  == get_priv()->deleted_bases_.end());
5864  get_priv()->deleted_bases_[name] = b;
5865  }
5866 
5867  for (vector<insertion>::const_iterator it = e.insertions().begin();
5868  it != e.insertions().end();
5869  ++it)
5870  {
5871  for (vector<unsigned>::const_iterator iit =
5872  it->inserted_indexes().begin();
5873  iit != it->inserted_indexes().end();
5874  ++iit)
5875  {
5876  unsigned i = *iit;
5878  second_class_decl()->get_base_specifiers()[i];
5879  string name = b->get_base_class()->get_qualified_name();
5880  ABG_ASSERT(get_priv()->inserted_bases_.find(name)
5881  == get_priv()->inserted_bases_.end());
5882  string_base_sptr_map::const_iterator j =
5883  get_priv()->deleted_bases_.find(name);
5884  if (j != get_priv()->deleted_bases_.end())
5885  {
5886  if (j->second != b)
5887  get_priv()->changed_bases_[name] =
5888  compute_diff(j->second, b, context());
5889  else
5890  // The base class changed place. IOW, the base
5891  // classes got re-arranged. Let's keep track of the
5892  // base classes that moved.
5893  get_priv()->moved_bases_.push_back(b);
5894  get_priv()->deleted_bases_.erase(j);
5895  }
5896  else
5897  get_priv()->inserted_bases_[name] = b;
5898  }
5899  }
5900 
5901  // ===============================================================
5902  // Detect when a data member is deleted from the class but is now
5903  // present in one of the bases at the same offset. In that case,
5904  // the data member should not be considered as removed.
5905  // ===============================================================
5907  class_or_union_diff::priv_->deleted_data_members_;
5908 
5909  vector<var_decl_sptr> deleted_data_members_present_in_bases;
5910  for (auto entry : deleted_data_members)
5911  {
5912  var_decl_sptr deleted_member = is_var_decl(entry.second);
5913  ABG_ASSERT(deleted_member);
5914  for (class_decl::base_spec_sptr base : second_class_decl()->get_base_specifiers())
5915  {
5916  class_decl_sptr klass = base->get_base_class();
5917  var_decl_sptr member = klass->find_data_member(deleted_member->get_name());
5918  if (member)
5919  deleted_data_members_present_in_bases.push_back(member);
5920  }
5921  }
5922  // Walk the deleted data members that are now in one of the bases,
5923  // of the new type, at the same offset, and let's see if they have
5924  // sub-type changes. In any cases, these should not be considered
5925  // as being deleted.
5926  for (var_decl_sptr m : deleted_data_members_present_in_bases)
5927  {
5928  string name = m->get_name();
5929  auto it = deleted_data_members.find(name);
5930  ABG_ASSERT(it != deleted_data_members.end());
5931  var_decl_sptr deleted_member = is_var_decl(it->second);
5932  if (*deleted_member != *m)
5933  {
5934  var_diff_sptr dif = compute_diff(deleted_member, m, context());
5935  ABG_ASSERT(dif);
5936  class_or_union_diff::priv_->subtype_changed_dm_[name]= dif;
5937  }
5938  deleted_data_members.erase(name);
5939  }
5940  }
5941 
5942  sort_string_base_sptr_map(get_priv()->deleted_bases_,
5943  get_priv()->sorted_deleted_bases_);
5944  sort_string_base_sptr_map(get_priv()->inserted_bases_,
5945  get_priv()->sorted_inserted_bases_);
5946  sort_string_base_diff_sptr_map(get_priv()->changed_bases_,
5947  get_priv()->sorted_changed_bases_);
5948 
5949  {
5950  const class_or_union_diff::priv_ptr &p = class_or_union_diff::get_priv();
5951 
5952  edit_script& e = p->member_fns_changes_;
5953 
5954  for (vector<deletion>::const_iterator it = e.deletions().begin();
5955  it != e.deletions().end();
5956  ++it)
5957  {
5958  unsigned i = it->index();
5959  method_decl_sptr mem_fn =
5960  first_class_decl()->get_virtual_mem_fns()[i];
5961  string name = mem_fn->get_linkage_name();
5962  if (name.empty())
5963  name = mem_fn->get_pretty_representation();
5964  ABG_ASSERT(!name.empty());
5965  if (p->deleted_member_functions_.find(name)
5966  != p->deleted_member_functions_.end())
5967  continue;
5968  p->deleted_member_functions_[name] = mem_fn;
5969  }
5970 
5971  for (vector<insertion>::const_iterator it = e.insertions().begin();
5972  it != e.insertions().end();
5973  ++it)
5974  {
5975  for (vector<unsigned>::const_iterator iit =
5976  it->inserted_indexes().begin();
5977  iit != it->inserted_indexes().end();
5978  ++iit)
5979  {
5980  unsigned i = *iit;
5981 
5982  method_decl_sptr mem_fn =
5983  second_class_decl()->get_virtual_mem_fns()[i];
5984  string name = mem_fn->get_linkage_name();
5985  if (name.empty())
5986  name = mem_fn->get_pretty_representation();
5987  ABG_ASSERT(!name.empty());
5988  if (p->inserted_member_functions_.find(name)
5989  != p->inserted_member_functions_.end())
5990  continue;
5991  string_member_function_sptr_map::const_iterator j =
5992  p->deleted_member_functions_.find(name);
5993 
5994  if (j != p->deleted_member_functions_.end())
5995  {
5996  if (*j->second != *mem_fn)
5997  p->changed_member_functions_[name] =
5998  compute_diff(static_pointer_cast<function_decl>(j->second),
5999  static_pointer_cast<function_decl>(mem_fn),
6000  context());
6001  p->deleted_member_functions_.erase(j);
6002  }
6003  else
6004  p->inserted_member_functions_[name] = mem_fn;
6005  }
6006  }
6007 
6008  // Now walk the allegedly deleted member functions; check if their
6009  // underlying symbols are deleted as well; otherwise, consider
6010  // that the member function in question hasn't been deleted.
6011 
6012  // Also, while walking the deleted member functions, we attend at
6013  // a particular cleanup business related to (virtual) C++
6014  // destructors:
6015  //
6016  // In the binary, there can be at least three types of
6017  // destructors, defined in the document
6018  // https://itanium-cxx-abi.github.io/cxx-abi/abi.html#definitions:
6019  //
6020  // 1/ Base object destructor (aka D2 destructor):
6021  //
6022  // "A function that runs the destructors for non-static data
6023  // members of T and non-virtual direct base classes of T. "
6024  //
6025  // 2/ Complete object destructor (aka D1 destructor):
6026  //
6027  // "A function that, in addition to the actions required of a
6028  // base object destructor, runs the destructors for the
6029  // virtual base classes of T."
6030  //
6031  // 3/ Deleting destructor (aka D0 destructor):
6032  //
6033  // "A function that, in addition to the actions required of a
6034  // complete object destructor, calls the appropriate
6035  // deallocation function (i.e,. operator delete) for T."
6036  //
6037  // With binaries generated by GCC, these destructors might be ELF
6038  // clones of each others, meaning, their ELF symbols can be
6039  // aliases.
6040  //
6041  // Also, note that because the actual destructor invoked by user
6042  // code is virtual, it's invoked through the vtable. So the
6043  // presence of the underlying D0, D1, D2 in the binary might vary
6044  // without that variation being an ABI issue, provided that the
6045  // destructor invoked through the vtable is present.
6046  //
6047  // So, a particular virtual destructor implementation for a class
6048  // might disapear and be replaced by another one in a subsequent
6049  // version of the binary. If all versions of the binary have an
6050  // actual virtual destructor, things might be considered fine.
6051  vector<string> to_delete;
6052  corpus_sptr f = context()->get_first_corpus(),
6053  s = context()->get_second_corpus();
6054  if (s)
6055  for (string_member_function_sptr_map::const_iterator i =
6056  deleted_member_fns().begin();
6057  i != deleted_member_fns().end();
6058  ++i)
6059  {
6060  if (get_member_function_is_virtual(i->second))
6061  {
6062  if (get_member_function_is_dtor(i->second))
6063  {
6064  // If a particular virtual destructor is deleted,
6065  // but the new binary still have a virtual
6066  // destructor for that class we consider that things
6067  // are fine. For instance, in the
6068  // tests/data/test-diff-pkg/tbb-4.1-9.20130314.fc22.x86_64--tbb-4.3-3.20141204.fc23.x86_64-report-0.txt
6069  // test, a new D4 destructor replaces the old ones.
6070  // But because the virtual destructor is still
6071  // there, this is not an ABI issue. So let's detect
6072  // this case.
6073  auto it =
6074  find_virtual_dtor_in_map(p->inserted_member_functions_);
6075  if (it != p->inserted_member_functions_.end())
6076  {
6077  // So the deleted virtual destructor is not
6078  // really deleted, because a proper virtual
6079  // destructor was added to the new version.
6080  // Let's remove the deleted/added virtual
6081  // destructor then.
6082  string name =
6083  (!i->second->get_linkage_name().empty())
6084  ? i->second->get_linkage_name()
6085  : i->second->get_pretty_representation();
6086  to_delete.push_back(name);
6087  p->inserted_member_functions_.erase(it);
6088  }
6089  }
6090  continue;
6091  }
6092  // We assume that all non-virtual member functions functions
6093  // we look at here have ELF symbols.
6094  if (!i->second->get_symbol()
6095  || s->lookup_function_symbol(*i->second->get_symbol()))
6096  to_delete.push_back(i->first);
6097  }
6098 
6099 
6100  for (vector<string>::const_iterator i = to_delete.begin();
6101  i != to_delete.end();
6102  ++i)
6103  p->deleted_member_functions_.erase(*i);
6104 
6105  // Do something similar for added functions.
6106  to_delete.clear();
6107  if (f)
6108  for (string_member_function_sptr_map::const_iterator i =
6109  inserted_member_fns().begin();
6110  i != inserted_member_fns().end();
6111  ++i)
6112  {
6113  if (get_member_function_is_virtual(i->second))
6114  continue;
6115  // We assume that all non-virtual member functions functions
6116  // we look at here have ELF symbols.
6117  if (!i->second->get_symbol()
6118  || f->lookup_function_symbol(*i->second->get_symbol()))
6119  to_delete.push_back(i->first);
6120  }
6121 
6122  for (vector<string>::const_iterator i = to_delete.begin();
6123  i != to_delete.end();
6124  ++i)
6125  p->inserted_member_functions_.erase(*i);
6126 
6127  sort_string_member_function_sptr_map(p->deleted_member_functions_,
6128  p->sorted_deleted_member_functions_);
6129 
6130  sort_string_member_function_sptr_map(p->inserted_member_functions_,
6131  p->sorted_inserted_member_functions_);
6132 
6134  (p->changed_member_functions_,
6135  p->sorted_changed_member_functions_);
6136  }
6137 }
6138 
6139 /// Allocate the memory for the priv_ pimpl data member of the @ref
6140 /// class_diff class.
6141 void
6142 class_diff::allocate_priv_data()
6143 {
6145  if (!priv_)
6146  priv_.reset(new priv);
6147 }
6148 
6149 /// Test whether a given base class has changed. A base class has
6150 /// changed if it's in both in deleted *and* inserted bases.
6151 ///
6152 ///@param d the declaration for the base class to consider.
6153 ///
6154 /// @return the new base class if the given base class has changed, or
6155 /// NULL if it hasn't.
6158 {
6159  string qname = d->get_base_class()->get_qualified_name();
6160  string_base_diff_sptr_map::const_iterator it =
6161  changed_bases_.find(qname);
6162 
6163  return (it == changed_bases_.end())
6165  : it->second->second_base();
6166 
6167 }
6168 
6169 /// Count the number of bases classes whose changes got filtered out.
6170 ///
6171 /// @return the number of bases classes whose changes got filtered
6172 /// out.
6173 size_t
6175 {
6176  size_t num_filtered = 0;
6177  for (base_diff_sptrs_type::const_iterator i = sorted_changed_bases_.begin();
6178  i != sorted_changed_bases_.end();
6179  ++i)
6180  {
6181  diff_sptr diff = *i;
6182  if (diff && diff->is_filtered_out())
6183  ++num_filtered;
6184  }
6185  return num_filtered;
6186 }
6187 
6188 /// Populate the vector of children node of the @ref diff base type
6189 /// sub-object of this instance of @ref class_diff.
6190 ///
6191 /// The children node can then later be retrieved using
6192 /// diff::children_node().
6193 void
6195 {
6197 
6198  // base class changes.
6199  for (base_diff_sptrs_type::const_iterator i =
6200  get_priv()->sorted_changed_bases_.begin();
6201  i != get_priv()->sorted_changed_bases_.end();
6202  ++i)
6203  if (diff_sptr d = *i)
6204  append_child_node(d);
6205 }
6206 
6207 /// Constructor of class_diff
6208 ///
6209 /// @param first_scope the first class of the diff.
6210 ///
6211 /// @param second_scope the second class of the diff.
6212 ///
6213 /// @param ctxt the diff context to use.
6215  class_decl_sptr second_scope,
6216  diff_context_sptr ctxt)
6217  : class_or_union_diff(first_scope, second_scope, ctxt)
6218  // We don't initialize the priv_ data member here. This is an
6219  // optimization to reduce memory consumption (and also execution
6220  // time) for cases where there are a lot of instances of
6221  // class_diff in the same equivalence class. In compute_diff(),
6222  // the priv_ is set to the priv_ of the canonical diff node.
6223  // See PR libabigail/17948.
6224 {}
6225 
6226 class_diff::~class_diff()
6227 {}
6228 
6229 /// Getter of the private data of the @ref class_diff type.
6230 ///
6231 /// Note that due to an optimization, the private data of @ref
6232 /// class_diff can be shared among several instances of class_diff, so
6233 /// you should never try to access class_diff::priv directly.
6234 ///
6235 /// When class_diff::priv is shared, this function returns the correct
6236 /// shared one.
6237 ///
6238 /// @return the (possibly) shared private data of the current instance
6239 /// of class_diff.
6240 const class_diff::priv_ptr&
6241 class_diff::get_priv() const
6242 {
6243  if (priv_)
6244  return priv_;
6245 
6246  // If the current class_diff::priv member is empty, then look for
6247  // the shared one, from the canonical type.
6248  class_diff *canonical =
6249  dynamic_cast<class_diff*>(get_canonical_diff());
6250  ABG_ASSERT(canonical);
6251  ABG_ASSERT(canonical->priv_);
6252 
6253  return canonical->priv_;
6254 }
6255 
6256 /// @return the pretty representation of the current instance of @ref
6257 /// class_diff.
6258 const string&
6260 {
6261  if (diff::priv_->pretty_representation_.empty())
6262  {
6263  std::ostringstream o;
6264  o << "class_diff["
6265  << first_subject()->get_pretty_representation()
6266  << ", "
6267  << second_subject()->get_pretty_representation()
6268  << "]";
6269  diff::priv_->pretty_representation_ = o.str();
6270  }
6271  return diff::priv_->pretty_representation_;
6272 }
6273 
6274 /// Return true iff the current diff node carries a change.
6275 ///
6276 /// @return true iff the current diff node carries a change.
6277 bool
6279 {return (first_class_decl() != second_class_decl());}
6280 
6281 /// @return the kind of local change carried by the current diff node.
6282 /// The value returned is zero if the current node carries no local
6283 /// change.
6284 enum change_kind
6286 {
6287  ir::change_kind k = ir::NO_CHANGE_KIND;
6288  if (!equals(*first_class_decl(), *second_class_decl(), &k))
6289  return k & ir::ALL_LOCAL_CHANGES_MASK;
6290  return ir::NO_CHANGE_KIND;
6291 }
6292 
6293 /// @return the first class invoveld in the diff.
6294 shared_ptr<class_decl>
6296 {return dynamic_pointer_cast<class_decl>(first_subject());}
6297 
6298 /// Getter of the second class involved in the diff.
6299 ///
6300 /// @return the second class invoveld in the diff
6301 shared_ptr<class_decl>
6303 {return dynamic_pointer_cast<class_decl>(second_subject());}
6304 
6305 /// @return the edit script of the bases of the two classes.
6306 const edit_script&
6308 {return get_priv()->base_changes_;}
6309 
6310 /// Getter for the deleted base classes of the diff.
6311 ///
6312 /// @return a map containing the deleted base classes, keyed with
6313 /// their pretty representation.
6314 const string_base_sptr_map&
6316 {return get_priv()->deleted_bases_;}
6317 
6318 /// Getter for the inserted base classes of the diff.
6319 ///
6320 /// @return a map containing the inserted base classes, keyed with
6321 /// their pretty representation.
6322 const string_base_sptr_map&
6324 {return get_priv()->inserted_bases_;}
6325 
6326 /// Getter for the changed base classes of the diff.
6327 ///
6328 /// @return a sorted vector containing the changed base classes
6329 const base_diff_sptrs_type&
6331 {return get_priv()->sorted_changed_bases_;}
6332 
6333 /// Getter for the vector of bases that "moved".
6334 /// That is, the vector of base types which position changed. If this
6335 /// vector is not empty, it means the bases of the underlying class
6336 /// type got re-ordered.
6337 ///
6338 /// @return the vector of bases that moved.
6339 const vector<class_decl::base_spec_sptr>&
6341 {return get_priv()->moved_bases_;}
6342 
6343 /// @return the edit script of the bases of the two classes.
6344 edit_script&
6346 {return get_priv()->base_changes_;}
6347 
6348 /// Produce a basic report about the changes between two class_decl.
6349 ///
6350 /// @param out the output stream to report the changes to.
6351 ///
6352 /// @param indent the string to use as an indentation prefix in the
6353 /// report.
6354 void
6355 class_diff::report(ostream& out, const string& indent) const
6356 {
6357  context()->get_reporter()->report(*this, out, indent);
6358 }
6359 
6360 /// Compute the set of changes between two instances of class_decl.
6361 ///
6362 /// Note that the two types must have been created in the same @ref
6363 /// environment, otherwise, this function aborts.
6364 ///
6365 /// @param first the first class_decl to consider.
6366 ///
6367 /// @param second the second class_decl to consider.
6368 ///
6369 /// @return changes the resulting changes.
6370 ///
6371 /// @param ctxt the diff context to use.
6374  const class_decl_sptr second,
6375  diff_context_sptr ctxt)
6376 {
6379 
6380  class_diff_sptr changes(new class_diff(f, s, ctxt));
6381 
6382  ctxt->initialize_canonical_diff(changes);
6383  ABG_ASSERT(changes->get_canonical_diff());
6384 
6385  if (!ctxt->get_canonical_diff_for(first, second))
6386  {
6387  // Either first or second is a decl-only class; let's set the
6388  // canonical diff here in that case.
6389  diff_sptr canonical_diff = ctxt->get_canonical_diff_for(changes);
6390  ABG_ASSERT(canonical_diff);
6391  ctxt->set_canonical_diff_for(first, second, canonical_diff);
6392  }
6393 
6394  // Ok, so this is an optimization. Do not freak out if it looks
6395  // weird, because, well, it does look weird. This speeds up
6396  // greatly, for instance, the test case given at PR
6397  // libabigail/17948.
6398  //
6399  // We are setting the private data of the new instance of class_diff
6400  // (which is 'changes') to the private data of its canonical
6401  // instance. That is, we are sharing the private data of 'changes'
6402  // with the private data of its canonical instance to consume less
6403  // memory in cases where the equivalence class of 'changes' is huge.
6404  //
6405  // But if changes is its own canonical instance, then we initialize
6406  // its private data properly
6407  if (is_class_diff(changes->get_canonical_diff()) == changes.get())
6408  // changes is its own canonical instance, so it gets a brand new
6409  // private data.
6410  changes->allocate_priv_data();
6411  else
6412  {
6413  // changes has a non-empty equivalence class so it's going to
6414  // share its private data with its canonical instance. Next
6415  // time class_diff::get_priv() is invoked, it's going to return
6416  // the shared private data of the canonical instance.
6417  return changes;
6418  }
6419 
6420  // Compare base specs
6421  compute_diff(f->get_base_specifiers().begin(),
6422  f->get_base_specifiers().end(),
6423  s->get_base_specifiers().begin(),
6424  s->get_base_specifiers().end(),
6425  changes->base_changes());
6426 
6427  // Do *not* compare member types because it generates lots of noise
6428  // and I doubt it's really useful.
6429 #if 0
6430  compute_diff(f->get_member_types().begin(),
6431  f->get_member_types().end(),
6432  s->get_member_types().begin(),
6433  s->get_member_types().end(),
6434  changes->member_types_changes());
6435 #endif
6436 
6437  // Compare data member
6438  compute_diff(f->get_non_static_data_members().begin(),
6439  f->get_non_static_data_members().end(),
6440  s->get_non_static_data_members().begin(),
6441  s->get_non_static_data_members().end(),
6442  changes->data_members_changes());
6443 
6444  // Compare virtual member functions
6445  compute_diff(f->get_virtual_mem_fns().begin(),
6446  f->get_virtual_mem_fns().end(),
6447  s->get_virtual_mem_fns().begin(),
6448  s->get_virtual_mem_fns().end(),
6449  changes->member_fns_changes());
6450 
6451  // Compare member function templates
6452  compute_diff(f->get_member_function_templates().begin(),
6453  f->get_member_function_templates().end(),
6454  s->get_member_function_templates().begin(),
6455  s->get_member_function_templates().end(),
6456  changes->member_fn_tmpls_changes());
6457 
6458  // Likewise, do not compare member class templates
6459 #if 0
6460  compute_diff(f->get_member_class_templates().begin(),
6461  f->get_member_class_templates().end(),
6462  s->get_member_class_templates().begin(),
6463  s->get_member_class_templates().end(),
6464  changes->member_class_tmpls_changes());
6465 #endif
6466 
6467  changes->ensure_lookup_tables_populated();
6468 
6469  return changes;
6470 }
6471 
6472 //</class_diff stuff>
6473 
6474 // <base_diff stuff>
6475 
6476 /// Populate the vector of children node of the @ref diff base type
6477 /// sub-object of this instance of @ref base_diff.
6478 ///
6479 /// The children node can then later be retrieved using
6480 /// diff::children_node().
6481 void
6484 
6485 /// @param first the first base spec to consider.
6486 ///
6487 /// @param second the second base spec to consider.
6488 ///
6489 /// @param ctxt the context of the diff. Note that this context
6490 /// object must stay alive at least during the life time of the
6491 /// current instance of @ref base_diff. Otherwise memory corruption
6492 /// issues occur.
6495  class_diff_sptr underlying,
6496  diff_context_sptr ctxt)
6497  : diff(first, second, ctxt),
6498  priv_(new priv(underlying))
6499 {}
6500 
6501 /// Getter for the first base spec of the diff object.
6502 ///
6503 /// @return the first base specifier for the diff object.
6506 {return dynamic_pointer_cast<class_decl::base_spec>(first_subject());}
6507 
6508 /// Getter for the second base spec of the diff object.
6509 ///
6510 /// @return the second base specifier for the diff object.
6513 {return dynamic_pointer_cast<class_decl::base_spec>(second_subject());}
6514 
6515 /// Getter for the diff object for the diff of the underlying base
6516 /// classes.
6517 ///
6518 /// @return the diff object for the diff of the underlying base
6519 /// classes.
6520 const class_diff_sptr
6522 {return priv_->underlying_class_diff_;}
6523 
6524 /// Setter for the diff object for the diff of the underlyng base
6525 /// classes.
6526 ///
6527 /// @param d the new diff object for the diff of the underlying base
6528 /// classes.
6529 void
6531 {priv_->underlying_class_diff_ = d;}
6532 
6533 /// @return the pretty representation for the current instance of @ref
6534 /// base_diff.
6535 const string&
6537 {
6538  if (diff::priv_->pretty_representation_.empty())
6539  {
6540  std::ostringstream o;
6541  o << "base_diff["
6542  << first_subject()->get_pretty_representation()
6543  << ", "
6544  << second_subject()->get_pretty_representation()
6545  << "]";
6546  diff::priv_->pretty_representation_ = o.str();
6547  }
6548  return diff::priv_->pretty_representation_;
6549 }
6550 
6551 /// Return true iff the current diff node carries a change.
6552 ///
6553 /// Return true iff the current diff node carries a change.
6554 bool
6556 {return first_base() != second_base();}
6557 
6558 /// @return the kind of local change carried by the current diff node.
6559 /// The value returned is zero if the current node carries no local
6560 /// change.
6561 enum change_kind
6563 {
6564  ir::change_kind k = ir::NO_CHANGE_KIND;
6565  if (!equals(*first_base(), *second_base(), &k))
6566  return k & ir::ALL_LOCAL_CHANGES_MASK;
6567  return ir::NO_CHANGE_KIND;
6568 }
6569 
6570 /// Generates a report for the current instance of base_diff.
6571 ///
6572 /// @param out the output stream to send the report to.
6573 ///
6574 /// @param indent the string to use for indentation.
6575 void
6576 base_diff::report(ostream& out, const string& indent) const
6577 {
6578  context()->get_reporter()->report(*this, out, indent);
6579 }
6580 
6581 /// Constructs the diff object representing a diff between two base
6582 /// class specifications.
6583 ///
6584 /// Note that the two artifacts must have been created in the same
6585 /// @ref environment, otherwise, this function aborts.
6586 ///
6587 /// @param first the first base class specification.
6588 ///
6589 /// @param second the second base class specification.
6590 ///
6591 /// @param ctxt the content of the diff.
6592 ///
6593 /// @return the resulting diff object.
6596  const class_decl::base_spec_sptr second,
6597  diff_context_sptr ctxt)
6598 {
6599  class_diff_sptr cl = compute_diff(first->get_base_class(),
6600  second->get_base_class(),
6601  ctxt);
6602  base_diff_sptr changes(new base_diff(first, second, cl, ctxt));
6603 
6604  ctxt->initialize_canonical_diff(changes);
6605 
6606  return changes;
6607 }
6608 
6609 // </base_diff stuff>
6610 
6611 
6612 // <union_diff stuff>
6613 
6614 /// Clear the lookup tables useful for reporting.
6615 ///
6616 /// This function must be updated each time a lookup table is added or
6617 /// removed from the union_diff::priv.
6618 void
6619 union_diff::clear_lookup_tables(void)
6621 
6622 /// Tests if the lookup tables are empty.
6623 ///
6624 /// @return true if the lookup tables are empty, false otherwise.
6625 bool
6626 union_diff::lookup_tables_empty(void) const
6628 
6629 /// If the lookup tables are not yet built, walk the differences and
6630 /// fill them.
6631 void
6632 union_diff::ensure_lookup_tables_populated(void) const
6634 
6635 /// Allocate the memory for the priv_ pimpl data member of the @ref
6636 /// union_diff class.
6637 void
6638 union_diff::allocate_priv_data()
6639 {
6641 }
6642 
6643 /// Constructor for the @ref union_diff type.
6644 ///
6645 /// @param first_union the first object of the comparison.
6646 ///
6647 /// @param second_union the second object of the comparison.
6648 ///
6649 /// @param ctxt the context of the comparison.
6650 union_diff::union_diff(union_decl_sptr first_union,
6651  union_decl_sptr second_union,
6652  diff_context_sptr ctxt)
6653  : class_or_union_diff(first_union, second_union, ctxt)
6654 {}
6655 
6656 /// Destructor of the union_diff node.
6658 {}
6659 
6660 /// @return the first object of the comparison.
6661 union_decl_sptr
6663 {return is_union_type(first_subject());}
6664 
6665 /// @return the second object of the comparison.
6666 union_decl_sptr
6668 {return is_union_type(second_subject());}
6669 
6670 /// @return the pretty representation of the current diff node.
6671 const string&
6673 {
6674  if (diff::priv_->pretty_representation_.empty())
6675  {
6676  std::ostringstream o;
6677  o << "union_diff["
6678  << first_subject()->get_pretty_representation()
6679  << ", "
6680  << second_subject()->get_pretty_representation()
6681  << "]";
6682  diff::priv_->pretty_representation_ = o.str();
6683  }
6684  return diff::priv_->pretty_representation_;
6685 }
6686 
6687 /// Report the changes carried by the current @ref union_diff node in
6688 /// a textual format.
6689 ///
6690 /// @param out the output stream to write the textual report to.
6691 ///
6692 /// @param indent the number of white space to use as indentation.
6693 void
6694 union_diff::report(ostream& out, const string& indent) const
6695 {
6696  context()->get_reporter()->report(*this, out, indent);
6697 }
6698 
6699 /// Compute the difference between two @ref union_decl types.
6700 ///
6701 /// Note that the two types must hav been created in the same
6702 /// environment, otherwise, this function aborts.
6703 ///
6704 /// @param first the first @ref union_decl to consider.
6705 ///
6706 /// @param second the second @ref union_decl to consider.
6707 ///
6708 /// @param ctxt the context of the diff to use.
6709 union_diff_sptr
6710 compute_diff(const union_decl_sptr first,
6711  const union_decl_sptr second,
6712  diff_context_sptr ctxt)
6713 {
6714  union_diff_sptr changes(new union_diff(first, second, ctxt));
6715 
6716  ctxt->initialize_canonical_diff(changes);
6717  ABG_ASSERT(changes->get_canonical_diff());
6718 
6719  // Ok, so this is an optimization. Do not freak out if it looks
6720  // weird, because, well, it does look weird. This speeds up
6721  // greatly, for instance, the test case given at PR
6722  // libabigail/17948.
6723  //
6724  // We are setting the private data of the new instance of class_diff
6725  // (which is 'changes') to the private data of its canonical
6726  // instance. That is, we are sharing the private data of 'changes'
6727  // with the private data of its canonical instance to consume less
6728  // memory in cases where the equivalence class of 'changes' is huge.
6729  //
6730  // But if changes is its own canonical instance, then we initialize
6731  // its private data properly.
6732  if (is_union_diff(changes->get_canonical_diff()) == changes.get())
6733  // changes is its own canonical instance, so it gets a brand new
6734  // private data.
6735  changes->allocate_priv_data();
6736  else
6737  {
6738  // changes has a non-empty equivalence class so it's going to
6739  // share its private data with its canonical instance. Next
6740  // time class_diff::get_priv() is invoked, it's going to return
6741  // the shared private data of the canonical instance.
6742  return changes;
6743  }
6744 
6745  // Compare data member
6746  compute_diff(first->get_non_static_data_members().begin(),
6747  first->get_non_static_data_members().end(),
6748  second->get_non_static_data_members().begin(),
6749  second->get_non_static_data_members().end(),
6750  changes->data_members_changes());
6751 
6752 #if 0
6753  // Compare member functions
6754  compute_diff(first->get_mem_fns().begin(),
6755  first->get_mem_fns().end(),
6756  second->get_mem_fns().begin(),
6757  second->get_mem_fns().end(),
6758  changes->member_fns_changes());
6759 
6760  // Compare member function templates
6761  compute_diff(first->get_member_function_templates().begin(),
6762  first->get_member_function_templates().end(),
6763  second->get_member_function_templates().begin(),
6764  second->get_member_function_templates().end(),
6765  changes->member_fn_tmpls_changes());
6766 #endif
6767 
6768  changes->ensure_lookup_tables_populated();
6769 
6770  return changes;
6771 }
6772 
6773 // </union_diff stuff>
6774 
6775 //<scope_diff stuff>
6776 
6777 /// Clear the lookup tables that are useful for reporting.
6778 ///
6779 /// This function must be updated each time a lookup table is added or
6780 /// removed.
6781 void
6782 scope_diff::clear_lookup_tables()
6783 {
6784  priv_->deleted_types_.clear();
6785  priv_->deleted_decls_.clear();
6786  priv_->inserted_types_.clear();
6787  priv_->inserted_decls_.clear();
6788  priv_->changed_types_.clear();
6789  priv_->changed_decls_.clear();
6790  priv_->removed_types_.clear();
6791  priv_->removed_decls_.clear();
6792  priv_->added_types_.clear();
6793  priv_->added_decls_.clear();
6794 }
6795 
6796 /// Tests if the lookup tables are empty.
6797 ///
6798 /// This function must be updated each time a lookup table is added or
6799 /// removed.
6800 ///
6801 /// @return true iff all the lookup tables are empty.
6802 bool
6803 scope_diff::lookup_tables_empty() const
6804 {
6805  return (priv_->deleted_types_.empty()
6806  && priv_->deleted_decls_.empty()
6807  && priv_->inserted_types_.empty()
6808  && priv_->inserted_decls_.empty()
6809  && priv_->changed_types_.empty()
6810  && priv_->changed_decls_.empty()
6811  && priv_->removed_types_.empty()
6812  && priv_->removed_decls_.empty()
6813  && priv_->added_types_.empty()
6814  && priv_->added_decls_.empty());
6815 }
6816 
6817 /// If the lookup tables are not yet built, walk the member_changes_
6818 /// member and fill the lookup tables.
6819 void
6820 scope_diff::ensure_lookup_tables_populated()
6821 {
6822  if (!lookup_tables_empty())
6823  return;
6824 
6825  edit_script& e = priv_->member_changes_;
6826 
6827  // Populate deleted types & decls lookup tables.
6828  for (const auto& deletion : e.deletions())
6829  {
6830  unsigned i = deletion.index();
6831  decl_base_sptr decl = deleted_member_at(i);
6832  string qname = decl->get_qualified_name();
6833  if (is_type(decl))
6834  {
6835  class_decl_sptr klass_decl = dynamic_pointer_cast<class_decl>(decl);
6836  if (klass_decl && klass_decl->get_is_declaration_only())
6837  continue;
6838 
6839  // Unique types are artifically put in a scope because they
6840  // have to belong somewhere, but they should not be
6841  // considered added/removed from any scope because they are
6842  // artificial and always present in the system.
6843  if (is_unique_type(is_type(decl)))
6844  continue;
6845 
6846  ABG_ASSERT(priv_->deleted_types_.find(qname)
6847  == priv_->deleted_types_.end());
6848  priv_->deleted_types_[qname] = decl;
6849  }
6850  else
6851  {
6852  ABG_ASSERT(priv_->deleted_decls_.find(qname)
6853  == priv_->deleted_decls_.end());
6854  priv_->deleted_decls_[qname] = decl;
6855  }
6856  }
6857 
6858  // Populate inserted types & decls as well as chagned types & decls
6859  // lookup tables.
6860  for (vector<insertion>::const_iterator it = e.insertions().begin();
6861  it != e.insertions().end();
6862  ++it)
6863  {
6864  for (vector<unsigned>::const_iterator i = it->inserted_indexes().begin();
6865  i != it->inserted_indexes().end();
6866  ++i)
6867  {
6868  decl_base_sptr decl = inserted_member_at(i);
6869  string qname = decl->get_qualified_name();
6870  if (is_type(decl))
6871  {
6872  class_decl_sptr klass_decl =
6873  dynamic_pointer_cast<class_decl>(decl);
6874  if (klass_decl && klass_decl->get_is_declaration_only())
6875  continue;
6876 
6877  // Unique types are artifically put in a scope because they
6878  // have to belong somewhere, but they should not be
6879  // considered added/removed from any scope because they are
6880  // artificial and always present in the system.
6881  if (is_unique_type(is_type(decl)))
6882  continue;
6883 
6884  ABG_ASSERT(priv_->inserted_types_.find(qname)
6885  == priv_->inserted_types_.end());
6886  string_decl_base_sptr_map::const_iterator j =
6887  priv_->deleted_types_.find(qname);
6888  if (j != priv_->deleted_types_.end())
6889  {
6890  if (*j->second != *decl)
6891  priv_->changed_types_[qname] =
6892  compute_diff(j->second, decl, context());
6893  priv_->deleted_types_.erase(j);
6894  }
6895  else
6896  priv_->inserted_types_[qname] = decl;
6897  }
6898  else
6899  {
6900  ABG_ASSERT(priv_->inserted_decls_.find(qname)
6901  == priv_->inserted_decls_.end());
6902  string_decl_base_sptr_map::const_iterator j =
6903  priv_->deleted_decls_.find(qname);
6904  if (j != priv_->deleted_decls_.end())
6905  {
6906  if (*j->second != *decl)
6907  priv_->changed_decls_[qname] =
6908  compute_diff(j->second, decl, context());
6909  priv_->deleted_decls_.erase(j);
6910  }
6911  else
6912  priv_->inserted_decls_[qname] = decl;
6913  }
6914  }
6915  }
6916 
6917  sort_string_diff_sptr_map(priv_->changed_decls_,
6918  priv_->sorted_changed_decls_);
6919  sort_string_diff_sptr_map(priv_->changed_types_,
6920  priv_->sorted_changed_types_);
6921 
6922  // Populate removed types/decls lookup tables
6923  for (string_decl_base_sptr_map::const_iterator i =
6924  priv_->deleted_types_.begin();
6925  i != priv_->deleted_types_.end();
6926  ++i)
6927  {
6928  string_decl_base_sptr_map::const_iterator r =
6929  priv_->inserted_types_.find(i->first);
6930  if (r == priv_->inserted_types_.end())
6931  priv_->removed_types_[i->first] = i->second;
6932  }
6933  for (string_decl_base_sptr_map::const_iterator i =
6934  priv_->deleted_decls_.begin();
6935  i != priv_->deleted_decls_.end();
6936  ++i)
6937  {
6938  string_decl_base_sptr_map::const_iterator r =
6939  priv_->inserted_decls_.find(i->first);
6940  if (r == priv_->inserted_decls_.end())
6941  priv_->removed_decls_[i->first] = i->second;
6942  }
6943 
6944  // Populate added types/decls.
6945  for (string_decl_base_sptr_map::const_iterator i =
6946  priv_->inserted_types_.begin();
6947  i != priv_->inserted_types_.end();
6948  ++i)
6949  {
6950  string_decl_base_sptr_map::const_iterator r =
6951  priv_->deleted_types_.find(i->first);
6952  if (r == priv_->deleted_types_.end())
6953  priv_->added_types_[i->first] = i->second;
6954  }
6955  for (string_decl_base_sptr_map::const_iterator i =
6956  priv_->inserted_decls_.begin();
6957  i != priv_->inserted_decls_.end();
6958  ++i)
6959  {
6960  string_decl_base_sptr_map::const_iterator r =
6961  priv_->deleted_decls_.find(i->first);
6962  if (r == priv_->deleted_decls_.end())
6963  priv_->added_decls_[i->first] = i->second;
6964  }
6965 }
6966 
6967 /// Populate the vector of children node of the @ref diff base type
6968 /// sub-object of this instance of @ref scope_diff.
6969 ///
6970 /// The children node can then later be retrieved using
6971 /// diff::children_node().
6972 void
6974 {
6975  for (diff_sptrs_type::const_iterator i = changed_types().begin();
6976  i != changed_types().end();
6977  ++i)
6978  if (*i)
6979  append_child_node(*i);
6980 
6981  for (diff_sptrs_type::const_iterator i = changed_decls().begin();
6982  i != changed_decls().end();
6983  ++i)
6984  if (*i)
6985  append_child_node(*i);
6986 }
6987 
6988 /// Constructor for scope_diff
6989 ///
6990 /// @param first_scope the first scope to consider for the diff.
6991 ///
6992 /// @param second_scope the second scope to consider for the diff.
6993 ///
6994 /// @param ctxt the diff context to use. Note that this context
6995 /// object must stay alive at least during the life time of the
6996 /// current instance of @ref scope_diff. Otherwise memory corruption
6997 /// issues occur.
6999  scope_decl_sptr second_scope,
7000  diff_context_sptr ctxt)
7001  : diff(first_scope, second_scope, ctxt),
7002  priv_(new priv)
7003 {}
7004 
7005 /// Getter for the first scope of the diff.
7006 ///
7007 /// @return the first scope of the diff.
7008 const scope_decl_sptr
7010 {return dynamic_pointer_cast<scope_decl>(first_subject());}
7011 
7012 /// Getter for the second scope of the diff.
7013 ///
7014 /// @return the second scope of the diff.
7015 const scope_decl_sptr
7017 {return dynamic_pointer_cast<scope_decl>(second_subject());}
7018 
7019 /// Accessor of the edit script of the members of a scope.
7020 ///
7021 /// This edit script is computed using the equality operator that
7022 /// applies to shared_ptr<decl_base>.
7023 ///
7024 /// That has interesting consequences. For instance, consider two
7025 /// scopes S0 and S1. S0 contains a class C0 and S1 contains a class
7026 /// S0'. C0 and C0' have the same qualified name, but have different
7027 /// members. The edit script will consider that C0 has been deleted
7028 /// from S0 and that S0' has been inserted. This is a low level
7029 /// canonical representation of the changes; a higher level
7030 /// representation would give us a simpler way to say "the class C0
7031 /// has been modified into C0'". But worry not. We do have such
7032 /// higher representation as well; that is what changed_types() and
7033 /// changed_decls() is for.
7034 ///
7035 /// @return the edit script of the changes encapsulatd in this
7036 /// instance of scope_diff.
7037 const edit_script&
7039 {return priv_->member_changes_;}
7040 
7041 /// Accessor of the edit script of the members of a scope.
7042 ///
7043 /// This edit script is computed using the equality operator that
7044 /// applies to shared_ptr<decl_base>.
7045 ///
7046 /// That has interesting consequences. For instance, consider two
7047 /// scopes S0 and S1. S0 contains a class C0 and S1 contains a class
7048 /// S0'. C0 and C0' have the same qualified name, but have different
7049 /// members. The edit script will consider that C0 has been deleted
7050 /// from S0 and that S0' has been inserted. This is a low level
7051 /// canonical representation of the changes; a higher level
7052 /// representation would give us a simpler way to say "the class C0
7053 /// has been modified into C0'". But worry not. We do have such
7054 /// higher representation as well; that is what changed_types() and
7055 /// changed_decls() is for.
7056 ///
7057 /// @return the edit script of the changes encapsulatd in this
7058 /// instance of scope_diff.
7059 edit_script&
7061 {return priv_->member_changes_;}
7062 
7063 /// Accessor that eases the manipulation of the edit script associated
7064 /// to this instance. It returns the scope member that is reported
7065 /// (in the edit script) as deleted at a given index.
7066 ///
7067 /// @param i the index (in the edit script) of an element of the first
7068 /// scope that has been reported as being delete.
7069 ///
7070 /// @return the scope member that has been reported by the edit script
7071 /// as being deleted at index i.
7072 const decl_base_sptr
7074 {
7075  scope_decl_sptr scope = dynamic_pointer_cast<scope_decl>(first_subject());
7076  return scope->get_member_decls()[i];
7077 }
7078 
7079 /// Accessor that eases the manipulation of the edit script associated
7080 /// to this instance. It returns the scope member (of the first scope
7081 /// of this diff instance) that is reported (in the edit script) as
7082 /// deleted at a given iterator.
7083 ///
7084 /// @param i the iterator of an element of the first scope that has
7085 /// been reported as being delete.
7086 ///
7087 /// @return the scope member of the first scope of this diff that has
7088 /// been reported by the edit script as being deleted at iterator i.
7089 const decl_base_sptr
7090 scope_diff::deleted_member_at(vector<deletion>::const_iterator i) const
7091 {return deleted_member_at(i->index());}
7092 
7093 /// Accessor that eases the manipulation of the edit script associated
7094 /// to this instance. It returns the scope member (of the second
7095 /// scope of this diff instance) that is reported as being inserted
7096 /// from a given index.
7097 ///
7098 /// @param i the index of an element of the second scope this diff
7099 /// that has been reported by the edit script as being inserted.
7100 ///
7101 /// @return the scope member of the second scope of this diff that has
7102 /// been reported as being inserted from index i.
7103 const decl_base_sptr
7105 {
7106  scope_decl_sptr scope = dynamic_pointer_cast<scope_decl>(second_subject());
7107  return scope->get_member_decls()[i];
7108 }
7109 
7110 /// Accessor that eases the manipulation of the edit script associated
7111 /// to this instance. It returns the scope member (of the second
7112 /// scope of this diff instance) that is reported as being inserted
7113 /// from a given iterator.
7114 ///
7115 /// @param i the iterator of an element of the second scope this diff
7116 /// that has been reported by the edit script as being inserted.
7117 ///
7118 /// @return the scope member of the second scope of this diff that has
7119 /// been reported as being inserted from iterator i.
7120 const decl_base_sptr
7121 scope_diff::inserted_member_at(vector<unsigned>::const_iterator i)
7122 {return inserted_member_at(*i);}
7123 
7124 /// @return a sorted vector of the types which content has changed
7125 /// from the first scope to the other.
7126 const diff_sptrs_type&
7128 {return priv_->sorted_changed_types_;}
7129 
7130 /// @return a sorted vector of the decls which content has changed
7131 /// from the first scope to the other.
7132 const diff_sptrs_type&
7134 {return priv_->sorted_changed_decls_;}
7135 
7137 scope_diff::removed_types() const
7138 {return priv_->removed_types_;}
7139 
7141 scope_diff::removed_decls() const
7142 {return priv_->removed_decls_;}
7143 
7145 scope_diff::added_types() const
7146 {return priv_->added_types_;}
7147 
7149 scope_diff::added_decls() const
7150 {return priv_->added_decls_;}
7151 
7152 /// @return the pretty representation for the current instance of @ref
7153 /// scope_diff.
7154 const string&
7156 {
7157  if (diff::priv_->pretty_representation_.empty())
7158  {
7159  std::ostringstream o;
7160  o << "scope_diff["
7161  << first_subject()->get_pretty_representation()
7162  << ", "
7163  << second_subject()->get_pretty_representation()
7164  << "]";
7165  diff::priv_->pretty_representation_ = o.str();
7166  }
7167  return diff::priv_->pretty_representation_;
7168 }
7169 
7170 /// Return true iff the current diff node carries a change.
7171 ///
7172 /// Return true iff the current diff node carries a change.
7173 bool
7175 {
7176  // TODO: add the number of really removed/added stuff.
7177  return changed_types().size() + changed_decls().size();
7178 }
7179 
7180 /// @return the kind of local change carried by the current diff node.
7181 /// The value returned is zero if the current node carries no local
7182 /// change.
7183 enum change_kind
7185 {
7186  ir::change_kind k = ir::NO_CHANGE_KIND;
7187  if (!equals(*first_scope(), *second_scope(), &k))
7188  return k & ir::ALL_LOCAL_CHANGES_MASK;
7189  return ir::NO_CHANGE_KIND;
7190 }
7191 
7192 /// Report the changes of one scope against another.
7193 ///
7194 /// @param out the out stream to report the changes to.
7195 ///
7196 /// @param indent the string to use for indentation.
7197 void
7198 scope_diff::report(ostream& out, const string& indent) const
7199 {
7200  context()->get_reporter()->report(*this, out, indent);
7201 }
7202 
7203 /// Compute the diff between two scopes.
7204 ///
7205 /// Note that the two decls must have been created in the same @ref
7206 /// environment, otherwise, this function aborts.
7207 ///
7208 /// @param first the first scope to consider in computing the diff.
7209 ///
7210 /// @param second the second scope to consider in the diff
7211 /// computation. The second scope is diffed against the first scope.
7212 ///
7213 /// @param d a pointer to the diff object to populate with the
7214 /// computed diff.
7215 ///
7216 /// @return return the populated \a d parameter passed to this
7217 /// function.
7218 ///
7219 /// @param ctxt the diff context to use.
7222  const scope_decl_sptr second,
7223  scope_diff_sptr d,
7224  diff_context_sptr ctxt)
7225 {
7226  ABG_ASSERT(d->first_scope() == first && d->second_scope() == second);
7227 
7228  compute_diff(first->get_member_decls().begin(),
7229  first->get_member_decls().end(),
7230  second->get_member_decls().begin(),
7231  second->get_member_decls().end(),
7232  d->member_changes());
7233 
7234  d->ensure_lookup_tables_populated();
7235  d->context(ctxt);
7236 
7237  return d;
7238 }
7239 
7240 /// Compute the diff between two scopes.
7241 ///
7242 /// Note that the two decls must have been created in the same @ref
7243 /// environment, otherwise, this function aborts.
7244 ///
7245 /// @param first_scope the first scope to consider in computing the diff.
7246 ///
7247 /// @param second_scope the second scope to consider in the diff
7248 /// computation. The second scope is diffed against the first scope.
7249 ///
7250 /// @param ctxt the diff context to use.
7251 ///
7252 /// @return return the resulting diff
7254 compute_diff(const scope_decl_sptr first_scope,
7255  const scope_decl_sptr second_scope,
7256  diff_context_sptr ctxt)
7257 {
7258  scope_diff_sptr d(new scope_diff(first_scope, second_scope, ctxt));
7259  d = compute_diff(first_scope, second_scope, d, ctxt);
7260  ctxt->initialize_canonical_diff(d);
7261  return d;
7262 }
7263 
7264 //</scope_diff stuff>
7265 
7266 // <fn_parm_diff stuff>
7267 
7268 /// Constructor for the fn_parm_diff type.
7269 ///
7270 /// @param first the first subject of the diff.
7271 ///
7272 /// @param second the second subject of the diff.
7273 ///
7274 /// @param ctxt the context of the diff. Note that this context
7275 /// object must stay alive at least during the life time of the
7276 /// current instance of @ref fn_parm_diff. Otherwise memory
7277 /// corruption issues occur.
7278 fn_parm_diff::fn_parm_diff(const function_decl::parameter_sptr first,
7279  const function_decl::parameter_sptr second,
7280  diff_context_sptr ctxt)
7281  : decl_diff_base(first, second, ctxt),
7282  priv_(new priv)
7283 {
7284  ABG_ASSERT(first->get_index() == second->get_index());
7285  priv_->type_diff = compute_diff(first->get_type(),
7286  second->get_type(),
7287  ctxt);
7288  ABG_ASSERT(priv_->type_diff);
7289 }
7290 
7291 /// Getter for the first subject of this diff node.
7292 ///
7293 /// @return the first function_decl::parameter_sptr subject of this
7294 /// diff node.
7297 {return dynamic_pointer_cast<function_decl::parameter>(first_subject());}
7298 
7299 /// Getter for the second subject of this diff node.
7300 ///
7301 /// @return the second function_decl::parameter_sptr subject of this
7302 /// diff node.
7305 {return dynamic_pointer_cast<function_decl::parameter>(second_subject());}
7306 
7307 /// Getter for the diff representing the changes on the type of the
7308 /// function parameter involved in the current instance of @ref
7309 /// fn_parm_diff.
7310 ///
7311 /// @return a diff_sptr representing the changes on the type of the
7312 /// function parameter we are interested in.
7313 diff_sptr
7315 {return priv_->type_diff;}
7316 
7317 /// Build and return a textual representation of the current instance
7318 /// of @ref fn_parm_diff.
7319 ///
7320 /// @return the string representing the current instance of
7321 /// fn_parm_diff.
7322 const string&
7324 {
7325  if (diff::priv_->pretty_representation_.empty())
7326  {
7327  std::ostringstream o;
7328  o << "function_parameter_diff["
7329  << first_subject()->get_pretty_representation()
7330  << ", "
7331  << second_subject()->get_pretty_representation()
7332  << "]";
7333  diff::priv_->pretty_representation_ = o.str();
7334  }
7335  return diff::priv_->pretty_representation_;
7336 }
7337 
7338 /// Return true iff the current diff node carries a change.
7339 ///
7340 /// @return true iff the current diff node carries a change.
7341 bool
7343 {return *first_parameter() != *second_parameter();}
7344 
7345 /// Check if the current diff node carries a local change.
7346 ///
7347 /// @return the kind of local change carried by the current diff node.
7348 /// The value returned is zero if the current node carries no local
7349 /// change.
7350 enum change_kind
7352 {
7353  ir::change_kind k = ir::NO_CHANGE_KIND;
7354  if (!equals(*first_parameter(), *second_parameter(), &k))
7355  return k & ir::ALL_LOCAL_CHANGES_MASK;
7356  return ir::NO_CHANGE_KIND;
7357 }
7358 
7359 /// Emit a textual report about the current fn_parm_diff instance.
7360 ///
7361 /// @param out the output stream to emit the textual report to.
7362 ///
7363 /// @param indent the indentation string to use in the report.
7364 void
7365 fn_parm_diff::report(ostream& out, const string& indent) const
7366 {
7367  context()->get_reporter()->report(*this, out, indent);
7368 }
7369 
7370 /// Populate the vector of children nodes of the @ref diff base type
7371 /// sub-object of this instance of @ref fn_parm_diff.
7372 ///
7373 /// The children nodes can then later be retrieved using
7374 /// diff::children_nodes()
7375 void
7377 {
7378  if (type_diff())
7380 }
7381 
7382 /// Compute the difference between two function_decl::parameter_sptr;
7383 /// that is, between two function parameters. Return a resulting
7384 /// fn_parm_diff_sptr that represents the changes.
7385 ///
7386 /// Note that the two decls must have been created in the same @ref
7387 /// environment, otherwise, this function aborts.
7388 ///
7389 /// @param first the first subject of the diff.
7390 ///
7391 /// @param second the second subject of the diff.
7392 ///
7393 /// @param ctxt the context of the diff.
7394 ///
7395 /// @return fn_parm_diff_sptr the resulting diff node.
7398  const function_decl::parameter_sptr second,
7399  diff_context_sptr ctxt)
7400 {
7401  if (!first || !second)
7402  return fn_parm_diff_sptr();
7403 
7404  fn_parm_diff_sptr result(new fn_parm_diff(first, second, ctxt));
7405  ctxt->initialize_canonical_diff(result);
7406 
7407  return result;
7408 }
7409 // </fn_parm_diff stuff>
7410 
7411 // <function_type_diff stuff>
7412 
7413 void
7414 function_type_diff::ensure_lookup_tables_populated()
7415 {
7416  priv_->return_type_diff_ =
7417  compute_diff(first_function_type()->get_return_type(),
7418  second_function_type()->get_return_type(),
7419  context());
7420 
7421  string parm_name;
7423  for (vector<deletion>::const_iterator i =
7424  priv_->parm_changes_.deletions().begin();
7425  i != priv_->parm_changes_.deletions().end();
7426  ++i)
7427  {
7428  parm = *(first_function_type()->get_first_parm()
7429  + i->index());
7430  parm_name = parm->get_name_id();
7431  // If for a reason the type name is empty we want to know and
7432  // fix that.
7433  ABG_ASSERT(!parm_name.empty());
7434  priv_->deleted_parms_[parm_name] = parm;
7435  priv_->deleted_parms_by_id_[parm->get_index()] = parm;
7436  }
7437 
7438  for (vector<insertion>::const_iterator i =
7439  priv_->parm_changes_.insertions().begin();
7440  i != priv_->parm_changes_.insertions().end();
7441  ++i)
7442  {
7443  for (vector<unsigned>::const_iterator j =
7444  i->inserted_indexes().begin();
7445  j != i->inserted_indexes().end();
7446  ++j)
7447  {
7448  parm = *(second_function_type()->get_first_parm() + *j);
7449  parm_name = parm->get_name_id();
7450  // If for a reason the type name is empty we want to know and
7451  // fix that.
7452  ABG_ASSERT(!parm_name.empty());
7453  {
7454  string_parm_map::const_iterator k =
7455  priv_->deleted_parms_.find(parm_name);
7456  if (k != priv_->deleted_parms_.end())
7457  {
7458  if (*k->second != *parm)
7459  priv_->subtype_changed_parms_[parm_name] =
7460  compute_diff(k->second, parm, context());
7461  priv_->deleted_parms_.erase(parm_name);
7462  }
7463  else
7464  priv_->added_parms_[parm_name] = parm;
7465  }
7466  {
7467  unsigned_parm_map::const_iterator k =
7468  priv_->deleted_parms_by_id_.find(parm->get_index());
7469  if (k != priv_->deleted_parms_by_id_.end())
7470  {
7471  if (*k->second != *parm
7472  && (k->second->get_name_id() != parm_name))
7473  priv_->changed_parms_by_id_[parm->get_index()] =
7474  compute_diff(k->second, parm, context());
7475  priv_->added_parms_.erase(parm_name);
7476  priv_->deleted_parms_.erase(k->second->get_name_id());
7477  priv_->deleted_parms_by_id_.erase(parm->get_index());
7478  }
7479  else
7480  priv_->added_parms_by_id_[parm->get_index()] = parm;
7481  }
7482  }
7483  }
7484 
7485  sort_string_fn_parm_diff_sptr_map(priv_->subtype_changed_parms_,
7486  priv_->sorted_subtype_changed_parms_);
7487  sort_string_fn_parm_diff_sptr_map(priv_->changed_parms_by_id_,
7488  priv_->sorted_changed_parms_by_id_);
7489  sort_string_parm_map(priv_->deleted_parms_,
7490  priv_->sorted_deleted_parms_);
7491 
7492  sort_string_parm_map(priv_->added_parms_,
7493  priv_->sorted_added_parms_);
7494 }
7495 
7496 /// In the vector of deleted parameters, get the one that is at a given
7497 /// index.
7498 ///
7499 /// @param i the index of the deleted parameter to get.
7500 ///
7501 /// @return the parameter returned.
7503 function_type_diff::deleted_parameter_at(int i) const
7504 {return first_function_type()->get_parameters()[i];}
7505 
7506 /// Getter for the sorted vector of deleted parameters.
7507 ///
7508 /// @return the sorted vector of deleted parameters.
7509 const vector<function_decl::parameter_sptr>&
7511 {return priv_->sorted_deleted_parms_;}
7512 
7513 /// Getter for the sorted vector of added parameters .
7514 ///
7515 /// @return the sorted vector of added parameters.
7516 const vector<function_decl::parameter_sptr>&
7518 {return priv_->sorted_added_parms_;}
7519 
7520 /// In the vector of inserted parameters, get the one that is at a
7521 /// given index.
7522 ///
7523 /// @param i the index of the inserted parameter to get.
7524 ///
7525 /// @return the parameter returned.
7527 function_type_diff::inserted_parameter_at(int i) const
7528 {return second_function_type()->get_parameters()[i];}
7529 
7530 /// Consutrctor of the @ref function_type type.
7531 ///
7532 /// @param first the first @ref function_type subject of the diff to
7533 /// create.
7534 ///
7535 /// @param second the second @ref function_type subject of the diff to
7536 /// create.
7537 ///
7538 /// @param ctxt the diff context to be used by the newly created
7539 /// instance of function_type_diff. Note that this context object
7540 /// must stay alive at least during the life time of the current
7541 /// instance of @ref function_type_diff. Otherwise memory corruption
7542 /// issues occur.
7544  const function_type_sptr second,
7545  diff_context_sptr ctxt)
7546  : type_diff_base(first, second, ctxt),
7547  priv_(new priv)
7548 {}
7549 
7550 /// Getter for the first subject of the diff.
7551 ///
7552 /// @return the first function type involved in the diff.
7553 const function_type_sptr
7555 {return dynamic_pointer_cast<function_type>(first_subject());}
7556 
7557 /// Getter for the second subject of the diff.
7558 ///
7559 /// @return the second function type involved in the diff.
7560 const function_type_sptr
7562 {return dynamic_pointer_cast<function_type>(second_subject());}
7563 
7564 /// Getter for the diff of the return types of the two function types
7565 /// of the current diff.
7566 ///
7567 /// @return the diff of the return types of the two function types of
7568 /// the current diff.
7569 const diff_sptr
7571 {return priv_->return_type_diff_;}
7572 
7573 /// Getter for the map of function parameter changes of the current diff.
7574 ///
7575 /// @return a map of function parameter changes of the current diff.
7578 {return priv_->subtype_changed_parms_;}
7579 
7580 /// Getter for the map of parameters that got removed.
7581 ///
7582 /// @return the map of parameters that got removed.
7583 const string_parm_map&
7585 {return priv_->deleted_parms_;}
7586 
7587 /// Getter for the map of parameters that got added.
7588 ///
7589 /// @return the map of parameters that got added.
7590 const string_parm_map&
7592 {return priv_->added_parms_;}
7593 
7594 /// Build and return a copy of a pretty representation of the current
7595 /// instance of @ref function_type_diff.
7596 ///
7597 /// @return a copy of the pretty representation of the current
7598 /// instance of @ref function_type_diff.
7599 const string&
7601 {
7602  if (diff::priv_->pretty_representation_.empty())
7603  {
7604  std::ostringstream o;
7605  o << "function_type_diff["
7607  << ", "
7609  << "]";
7610  diff::priv_->pretty_representation_ = o.str();
7611  }
7612  return diff::priv_->pretty_representation_;
7613 }
7614 
7615 /// Test if the current diff node carries changes.
7616 ///
7617 /// @return true iff the current diff node carries changes.
7618 bool
7620 {return *first_function_type() != *second_function_type();}
7621 
7622 /// Test if the current diff node carries local changes.
7623 ///
7624 /// A local change is a change that is carried by this diff node, not
7625 /// by any of its children nodes.
7626 ///
7627 /// @return the kind of local change carried by the current diff node.
7628 /// The value returned is zero if the current node carries no local
7629 /// change.
7630 enum change_kind
7632 {
7633  ir::change_kind k = ir::NO_CHANGE_KIND;
7635  return k & ir::ALL_LOCAL_CHANGES_MASK;
7636  return ir::NO_CHANGE_KIND;
7637 }
7638 
7639 /// Build and emit a textual report about the current @ref
7640 /// function_type_diff instance.
7641 ///
7642 /// @param out the output stream.
7643 ///
7644 /// @param indent the indentation string to use.
7645 void
7646 function_type_diff::report(ostream& out, const string& indent) const
7647 {
7648  context()->get_reporter()->report(*this, out, indent);
7649 }
7650 
7651 /// Populate the vector of children node of the @ref diff base type
7652 /// sub-object of this instance of @ref function_type_diff.
7653 ///
7654 /// The children node can then later be retrieved using
7655 /// diff::children_node().
7656 void
7658 {
7659  if (diff_sptr d = return_type_diff())
7660  append_child_node(d);
7661 
7662  for (vector<fn_parm_diff_sptr>::const_iterator i =
7663  priv_->sorted_subtype_changed_parms_.begin();
7664  i != priv_->sorted_subtype_changed_parms_.end();
7665  ++i)
7666  if (diff_sptr d = *i)
7667  append_child_node(d);
7668 
7669  for (vector<fn_parm_diff_sptr>::const_iterator i =
7670  priv_->sorted_changed_parms_by_id_.begin();
7671  i != priv_->sorted_changed_parms_by_id_.end();
7672  ++i)
7673  if (diff_sptr d = *i)
7674  append_child_node(d);
7675 }
7676 
7677 /// Compute the diff between two instances of @ref function_type.
7678 ///
7679 /// Note that the two types must have been created in the same @ref
7680 /// environment, otherwise, this function aborts.
7681 ///
7682 /// @param first the first @ref function_type to consider for the diff.
7683 ///
7684 /// @param second the second @ref function_type to consider for the diff.
7685 ///
7686 /// @param ctxt the diff context to use.
7687 ///
7688 /// @return the resulting diff between the two @ref function_type.
7691  const function_type_sptr second,
7692  diff_context_sptr ctxt)
7693 {
7694  if (!first || !second)
7695  {
7696  // TODO: implement this for either first or second being NULL.
7697  return function_type_diff_sptr();
7698  }
7699 
7700  function_type_diff_sptr result(new function_type_diff(first, second, ctxt));
7701 
7702  diff_utils::compute_diff(first->get_first_parm(),
7703  first->get_parameters().end(),
7704  second->get_first_parm(),
7705  second->get_parameters().end(),
7706  result->priv_->parm_changes_);
7707 
7708  result->ensure_lookup_tables_populated();
7709 
7710  ctxt->initialize_canonical_diff(result);
7711 
7712  return result;
7713 }
7714 // </function_type_diff stuff>
7715 
7716 // <function_decl_diff stuff>
7717 
7718 /// Build the lookup tables of the diff, if necessary.
7719 void
7720 function_decl_diff::ensure_lookup_tables_populated()
7721 {
7722 }
7723 
7724 /// Populate the vector of children node of the @ref diff base type
7725 /// sub-object of this instance of @ref function_decl_diff.
7726 ///
7727 /// The children node can then later be retrieved using
7728 /// diff::children_node().
7729 void
7731 {
7732  if (diff_sptr d = type_diff())
7733  append_child_node(d);
7734 }
7735 
7736 /// Constructor for function_decl_diff
7737 ///
7738 /// @param first the first function considered by the diff.
7739 ///
7740 /// @param second the second function considered by the diff.
7741 ///
7742 /// @param ctxt the context of the diff. Note that this context
7743 /// object must stay alive at least during the life time of the
7744 /// current instance of @ref function_decl_diff. Otherwise memory
7745 /// corruption issues occur.
7747  const function_decl_sptr second,
7748  diff_context_sptr ctxt)
7749  : decl_diff_base(first, second, ctxt),
7750  priv_(new priv)
7751 {
7752 }
7753 
7754 /// @return the first function considered by the diff.
7755 const function_decl_sptr
7757 {return dynamic_pointer_cast<function_decl>(first_subject());}
7758 
7759 /// @return the second function considered by the diff.
7760 const function_decl_sptr
7762 {return dynamic_pointer_cast<function_decl>(second_subject());}
7763 
7765 function_decl_diff::type_diff() const
7766 {return priv_->type_diff_;}
7767 
7768 /// @return the pretty representation for the current instance of @ref
7769 /// function_decl_diff.
7770 const string&
7772 {
7773  if (diff::priv_->pretty_representation_.empty())
7774  {
7775  std::ostringstream o;
7776  o << "function_diff["
7777  << first_subject()->get_pretty_representation()
7778  << ", "
7779  << second_subject()->get_pretty_representation()
7780  << "]";
7781  diff::priv_->pretty_representation_ = o.str();
7782  }
7783  return diff::priv_->pretty_representation_;
7784 }
7785 
7786 /// Return true iff the current diff node carries a change.
7787 ///
7788 /// @return true iff the current diff node carries a change.
7789 bool
7791 {return *first_function_decl() != *second_function_decl();}
7792 
7793 /// @return the kind of local change carried by the current diff node.
7794 /// The value returned is zero if the current node carries no local
7795 /// change.
7796 enum change_kind
7798 {
7799  ir::change_kind k = ir::NO_CHANGE_KIND;
7801  return k & ir::ALL_LOCAL_CHANGES_MASK;
7802  return ir::NO_CHANGE_KIND;
7803 }
7804 
7805 /// Serialize a report of the changes encapsulated in the current
7806 /// instance of @ref function_decl_diff over to an output stream.
7807 ///
7808 /// @param out the output stream to serialize the report to.
7809 ///
7810 /// @param indent the string to use an an indentation prefix.
7811 void
7812 function_decl_diff::report(ostream& out, const string& indent) const
7813 {
7814  context()->get_reporter()->report(*this, out, indent);
7815 }
7816 
7817 /// Compute the diff between two function_decl.
7818 ///
7819 /// Note that the two decls must have been created in the same @ref
7820 /// environment, otherwise, this function aborts.
7821 ///
7822 /// @param first the first function_decl to consider for the diff
7823 ///
7824 /// @param second the second function_decl to consider for the diff
7825 ///
7826 /// @param ctxt the diff context to use.
7827 ///
7828 /// @return the computed diff
7831  const function_decl_sptr second,
7832  diff_context_sptr ctxt)
7833 {
7834  if (!first || !second)
7835  {
7836  // TODO: implement this for either first or second being NULL.
7837  return function_decl_diff_sptr();
7838  }
7839 
7840  function_type_diff_sptr type_diff = compute_diff(first->get_type(),
7841  second->get_type(),
7842  ctxt);
7843 
7844  function_decl_diff_sptr result(new function_decl_diff(first, second,
7845  ctxt));
7846  result->priv_->type_diff_ = type_diff;
7847 
7848  result->ensure_lookup_tables_populated();
7849 
7850  ctxt->initialize_canonical_diff(result);
7851 
7852  return result;
7853 }
7854 
7855 // </function_decl_diff stuff>
7856 
7857 // <type_decl_diff stuff>
7858 
7859 /// Constructor for type_decl_diff.
7860 ///
7861 /// @param first the first subject of the diff.
7862 ///
7863 /// @param second the second subject of the diff.
7864 ///
7865 /// @param ctxt the context of the diff. Note that this context
7866 /// object must stay alive at least during the life time of the
7867 /// current instance of @ref type_decl_diff. Otherwise memory
7868 /// corruption issues occur.
7869 type_decl_diff::type_decl_diff(const type_decl_sptr first,
7870  const type_decl_sptr second,
7871  diff_context_sptr ctxt)
7872  : type_diff_base(first, second, ctxt)
7873 {}
7874 
7875 /// Getter for the first subject of the type_decl_diff.
7876 ///
7877 /// @return the first type_decl involved in the diff.
7878 const type_decl_sptr
7880 {return dynamic_pointer_cast<type_decl>(first_subject());}
7881 
7882 /// Getter for the second subject of the type_decl_diff.
7883 ///
7884 /// @return the second type_decl involved in the diff.
7885 const type_decl_sptr
7887 {return dynamic_pointer_cast<type_decl>(second_subject());}
7888 
7889 /// @return the pretty representation for the current instance of @ref
7890 /// type_decl_diff.
7891 const string&
7893 {
7894  if (diff::priv_->pretty_representation_.empty())
7895  {
7896  std::ostringstream o;
7897  o << "type_decl_diff["
7898  << first_subject()->get_pretty_representation()
7899  << ", "
7900  << second_subject()->get_pretty_representation()
7901  << "]";
7902  diff::priv_->pretty_representation_ = o.str();
7903  }
7904  return diff::priv_->pretty_representation_;
7905 }
7906 /// Return true iff the current diff node carries a change.
7907 ///
7908 /// @return true iff the current diff node carries a change.
7909 bool
7911 {return first_type_decl() != second_type_decl();}
7912 
7913 /// @return the kind of local change carried by the current diff node.
7914 /// The value returned is zero if the current node carries no local
7915 /// change.
7916 enum change_kind
7918 {
7919  ir::change_kind k = ir::NO_CHANGE_KIND;
7920  if (!equals(*first_type_decl(), *second_type_decl(), &k))
7921  return k & ir::ALL_LOCAL_CHANGES_MASK;
7922  return ir::NO_CHANGE_KIND;
7923 }
7924 /// Ouputs a report of the differences between of the two type_decl
7925 /// involved in the type_decl_diff.
7926 ///
7927 /// @param out the output stream to emit the report to.
7928 ///
7929 /// @param indent the string to use for indentatino indent.
7930 void
7931 type_decl_diff::report(ostream& out, const string& indent) const
7932 {
7933  context()->get_reporter()->report(*this, out, indent);
7934 }
7935 
7936 /// Compute a diff between two type_decl.
7937 ///
7938 /// Note that the two types must have been created in the same @ref
7939 /// environment, otherwise, this function aborts.
7940 ///
7941 /// This function doesn't actually compute a diff. As a type_decl is
7942 /// very simple (unlike compound constructs like function_decl or
7943 /// class_decl) it's easy to just compare the components of the
7944 /// type_decl to know what has changed. Thus this function just
7945 /// builds and return a type_decl_diff object. The
7946 /// type_decl_diff::report function will just compare the components
7947 /// of the the two type_decl and display where and how they differ.
7948 ///
7949 /// @param first a pointer to the first type_decl to
7950 /// consider.
7951 ///
7952 /// @param second a pointer to the second type_decl to consider.
7953 ///
7954 /// @param ctxt the diff context to use.
7955 ///
7956 /// @return a pointer to the resulting type_decl_diff.
7959  const type_decl_sptr second,
7960  diff_context_sptr ctxt)
7961 {
7962  type_decl_diff_sptr result(new type_decl_diff(first, second, ctxt));
7963 
7964  // We don't need to actually compute a diff here as a type_decl
7965  // doesn't have complicated sub-components. type_decl_diff::report
7966  // just walks the members of the type_decls and display information
7967  // about the ones that have changed. On a similar note,
7968  // type_decl_diff::length returns 0 if the two type_decls are equal,
7969  // and 1 otherwise.
7970 
7971  ctxt->initialize_canonical_diff(result);
7972 
7973  return result;
7974 }
7975 
7976 // </type_decl_diff stuff>
7977 
7978 // <typedef_diff stuff>
7979 
7980 /// Populate the vector of children node of the @ref diff base type
7981 /// sub-object of this instance of @ref typedef_diff.
7982 ///
7983 /// The children node can then later be retrieved using
7984 /// diff::children_node().
7985 void
7988 
7989 /// Constructor for typedef_diff.
7990 ///
7991 /// @param first the first subject of the diff.
7992 ///
7993 /// @param second the second subject of the diff.
7994 ///
7995 /// @param underlying the underlying diff of the @ref typedef_diff.
7996 /// That is the diff between the underlying types of @p first and @p
7997 /// second.
7998 ///
7999 /// @param ctxt the context of the diff. Note that this context
8000 /// object must stay alive at least during the life time of the
8001 /// current instance of @ref typedef_diff. Otherwise memory
8002 /// corruption issues occur.
8003 typedef_diff::typedef_diff(const typedef_decl_sptr first,
8004  const typedef_decl_sptr second,
8005  const diff_sptr underlying,
8006  diff_context_sptr ctxt)
8007  : type_diff_base(first, second, ctxt),
8008  priv_(new priv(underlying))
8009 {}
8010 
8011 /// Getter for the firt typedef_decl involved in the diff.
8012 ///
8013 /// @return the first subject of the diff.
8014 const typedef_decl_sptr
8016 {return dynamic_pointer_cast<typedef_decl>(first_subject());}
8017 
8018 /// Getter for the second typedef_decl involved in the diff.
8019 ///
8020 /// @return the second subject of the diff.
8021 const typedef_decl_sptr
8023 {return dynamic_pointer_cast<typedef_decl>(second_subject());}
8024 
8025 /// Getter for the diff between the two underlying types of the
8026 /// typedefs.
8027 ///
8028 /// @return the diff object reprensenting the difference between the
8029 /// two underlying types of the typedefs.
8030 const diff_sptr
8032 {return priv_->underlying_type_diff_;}
8033 
8034 /// Setter for the diff between the two underlying types of the
8035 /// typedefs.
8036 ///
8037 /// @param d the new diff object reprensenting the difference between
8038 /// the two underlying types of the typedefs.
8039 void
8041 {priv_->underlying_type_diff_ = d;}
8042 
8043 /// @return the pretty representation for the current instance of @ref
8044 /// typedef_diff.
8045 const string&
8047 {
8048  if (diff::priv_->pretty_representation_.empty())
8049  {
8050  std::ostringstream o;
8051  o << "typedef_diff["
8052  << first_subject()->get_pretty_representation()
8053  << ", "
8054  << second_subject()->get_pretty_representation()
8055  << "]";
8056  diff::priv_->pretty_representation_ = o.str();
8057  }
8058  return diff::priv_->pretty_representation_;
8059 }
8060 
8061 /// Return true iff the current diff node carries a change.
8062 ///
8063 /// @return true iff the current diff node carries a change.
8064 bool
8066 {
8067  decl_base_sptr second = second_typedef_decl();
8068  return !(*first_typedef_decl() == *second);
8069 }
8070 
8071 /// @return the kind of local change carried by the current diff node.
8072 /// The value returned is zero if the current node carries no local
8073 /// change.
8074 enum change_kind
8076 {
8077  ir::change_kind k = ir::NO_CHANGE_KIND;
8079  return k & ir::ALL_LOCAL_CHANGES_MASK;
8080  return ir::NO_CHANGE_KIND;
8081 }
8082 
8083 /// Reports the difference between the two subjects of the diff in a
8084 /// serialized form.
8085 ///
8086 /// @param out the output stream to emit the report to.
8087 ///
8088 /// @param indent the indentation string to use.
8089 void
8090 typedef_diff::report(ostream& out, const string& indent) const
8091 {
8092  context()->get_reporter()->report(*this, out, indent);
8093 }
8094 
8095 /// Compute a diff between two typedef_decl.
8096 ///
8097 /// Note that the two types must have been created in the same @ref
8098 /// environment, otherwise, this function aborts.
8099 ///
8100 /// @param first a pointer to the first typedef_decl to consider.
8101 ///
8102 /// @param second a pointer to the second typedef_decl to consider.
8103 ///
8104 /// @param ctxt the diff context to use.
8105 ///
8106 /// @return a pointer to the the resulting typedef_diff.
8109  const typedef_decl_sptr second,
8110  diff_context_sptr ctxt)
8111 {
8112  diff_sptr d = compute_diff_for_types(first->get_underlying_type(),
8113  second->get_underlying_type(),
8114  ctxt);
8115  typedef_diff_sptr result(new typedef_diff(first, second, d, ctxt));
8116 
8117  ctxt->initialize_canonical_diff(result);
8118 
8119  return result;
8120 }
8121 
8122 /// Return the leaf underlying diff node of a @ref typedef_diff node.
8123 ///
8124 /// If the underlying diff node of a @ref typedef_diff node is itself
8125 /// a @ref typedef_diff node, then recursively look at the underlying
8126 /// diff nodes to get the first one that is not a a @ref typedef_diff
8127 /// node. This is what a leaf underlying diff node means.
8128 ///
8129 /// Otherwise, if the underlying diff node of @ref typedef_diff is
8130 /// *NOT* a @ref typedef_diff node, then just return the underlying
8131 /// diff node.
8132 ///
8133 /// And if the diff node considered is not a @ref typedef_diff node,
8134 /// then just return it.
8135 ///
8136 /// @return the leaf underlying diff node of a @p diff.
8137 const diff*
8139 {
8140  const typedef_diff* d = dynamic_cast<const typedef_diff*>(diff);
8141  if (!d)
8142  return diff;
8143 
8144  if (const typedef_diff* deef =
8145  dynamic_cast<const typedef_diff*>(d->underlying_type_diff().get()))
8147 
8148  return d->underlying_type_diff().get();
8149 }
8150 
8151 // </typedef_diff stuff>
8152 
8153 // <translation_unit_diff stuff>
8154 
8155 /// Constructor for translation_unit_diff.
8156 ///
8157 /// @param first the first translation unit to consider for this diff.
8158 ///
8159 /// @param second the second translation unit to consider for this diff.
8160 ///
8161 /// @param ctxt the context of the diff. Note that this context
8162 /// object must stay alive at least during the life time of the
8163 /// current instance of @ref translation_unit_diff. Otherwise memory
8164 /// corruption issues occur.
8166  translation_unit_sptr second,
8167  diff_context_sptr ctxt)
8168  : scope_diff(first->get_global_scope(), second->get_global_scope(), ctxt),
8169  priv_(new priv(first, second))
8170 {
8171 }
8172 
8173 /// Getter for the first translation unit of this diff.
8174 ///
8175 /// @return the first translation unit of this diff.
8178 {return priv_->first_;}
8179 
8180 /// Getter for the second translation unit of this diff.
8181 ///
8182 /// @return the second translation unit of this diff.
8185 {return priv_->second_;}
8186 
8187 /// Return true iff the current diff node carries a change.
8188 ///
8189 /// @return true iff the current diff node carries a change.
8190 bool
8192 {return scope_diff::has_changes();}
8193 
8194 /// @return the kind of local change carried by the current diff node.
8195 /// The value returned is zero if the current node carries no local
8196 /// change.
8197 enum change_kind
8199 {return ir::NO_CHANGE_KIND;}
8200 
8201 /// Report the diff in a serialized form.
8202 ///
8203 /// @param out the output stream to serialize the report to.
8204 ///
8205 /// @param indent the prefix to use as indentation for the report.
8206 void
8207 translation_unit_diff::report(ostream& out, const string& indent) const
8208 {scope_diff::report(out, indent);}
8209 
8210 /// Compute the diff between two translation_units.
8211 ///
8212 /// Note that the two translation units must have been created in the
8213 /// same @ref environment, otherwise, this function aborts.
8214 ///
8215 /// @param first the first translation_unit to consider.
8216 ///
8217 /// @param second the second translation_unit to consider.
8218 ///
8219 /// @param ctxt the diff context to use. If null, this function will
8220 /// create a new context and set to the diff object returned.
8221 ///
8222 /// @return the newly created diff object.
8225  const translation_unit_sptr second,
8226  diff_context_sptr ctxt)
8227 {
8228  ABG_ASSERT(first && second);
8229 
8230  if (!ctxt)
8231  ctxt.reset(new diff_context);
8232 
8233  // TODO: handle first or second having empty contents.
8234  translation_unit_diff_sptr tu_diff(new translation_unit_diff(first, second,
8235  ctxt));
8236  scope_diff_sptr sc_diff = dynamic_pointer_cast<scope_diff>(tu_diff);
8237 
8238  compute_diff(static_pointer_cast<scope_decl>(first->get_global_scope()),
8239  static_pointer_cast<scope_decl>(second->get_global_scope()),
8240  sc_diff,
8241  ctxt);
8242 
8243  ctxt->initialize_canonical_diff(tu_diff);
8244 
8245  return tu_diff;
8246 }
8247 
8248 // </translation_unit_diff stuff>
8249 
8250 // <diff_maps stuff>
8251 
8252 /// The private data of the @ref diff_maps type.
8253 struct diff_maps::priv
8254 {
8255  string_diff_ptr_map type_decl_diff_map_;
8256  string_diff_ptr_map enum_diff_map_;
8257  string_diff_ptr_map class_diff_map_;
8258  string_diff_ptr_map union_diff_map_;
8259  string_diff_ptr_map typedef_diff_map_;
8260  string_diff_ptr_map subrange_diff_map_;
8261  string_diff_ptr_map array_diff_map_;
8262  string_diff_ptr_map reference_diff_map_;
8263  string_diff_ptr_map function_type_diff_map_;
8264  string_diff_ptr_map function_decl_diff_map_;
8265  string_diff_ptr_map var_decl_diff_map_;
8266  string_diff_ptr_map distinct_diff_map_;
8267  string_diff_ptr_map fn_parm_diff_map_;
8268  diff_artifact_set_map_type impacted_artifacts_map_;
8269 }; // end struct diff_maps::priv
8270 
8271 /// Default constructor of the @ref diff_maps type.
8273  : priv_(new diff_maps::priv())
8274 {}
8275 
8276 diff_maps::~diff_maps() = default;
8277 
8278 /// Getter of the map that contains basic type diffs.
8279 ///
8280 /// @return the map that contains basic type diffs.
8281 const string_diff_ptr_map&
8283 {return priv_->type_decl_diff_map_;}
8284 
8285 /// Getter of the map that contains basic type diffs.
8286 ///
8287 /// @return the map that contains basic type diffs.
8290 {return priv_->type_decl_diff_map_;}
8291 
8292 /// Getter of the map that contains enum type diffs.
8293 ///
8294 /// @return the map that contains enum type diffs.
8295 const string_diff_ptr_map&
8297 {return priv_->enum_diff_map_;}
8298 
8299 /// Getter of the map that contains enum type diffs.
8300 ///
8301 /// @return the map that contains enum type diffs.
8304 {return priv_->enum_diff_map_;}
8305 
8306 /// Getter of the map that contains class type diffs.
8307 ///
8308 /// @return the map that contains class type diffs.
8309 const string_diff_ptr_map&
8311 {return priv_->class_diff_map_;}
8312 
8313 /// Getter of the map that contains class type diffs.
8314 ///
8315 /// @return the map that contains class type diffs.
8318 {return priv_->class_diff_map_;}
8319 
8320 /// Getter of the map that contains union type diffs.
8321 ///
8322 /// @return the map that contains union type diffs.
8323 const string_diff_ptr_map&
8325 {return priv_->union_diff_map_;}
8326 
8327 /// Getter of the map that contains union type diffs.
8328 ///
8329 /// @return the map that contains union type diffs.
8332 {return priv_->union_diff_map_;}
8333 
8334 /// Getter of the map that contains typedef type diffs.
8335 ///
8336 /// @return the map that contains typedef type diffs.
8337 const string_diff_ptr_map&
8339 {return priv_->typedef_diff_map_;}
8340 
8341 /// Getter of the map that contains typedef type diffs.
8342 ///
8343 /// @return the map that contains typedef type diffs.
8346 {return priv_->typedef_diff_map_;}
8347 
8348 /// Getter of the map that contains subrange type diffs.
8349 ///
8350 /// @return the map that contains subrange type diffs.
8351 const string_diff_ptr_map&
8353 {return priv_->subrange_diff_map_;}
8354 
8355 /// Getter of the map that contains subrange type diffs.
8356 ///
8357 /// @return the map that contains subrange type diffs.
8360 {return priv_->subrange_diff_map_;}
8361 
8362 /// Getter of the map that contains array type diffs.
8363 ///
8364 /// @return the map that contains array type diffs.
8365 const string_diff_ptr_map&
8367 {return priv_->array_diff_map_;}
8368 
8369 /// Getter of the map that contains array type diffs.
8370 ///
8371 /// @return the map that contains array type diffs.
8374 {return priv_->array_diff_map_;}
8375 
8376 /// Getter of the map that contains reference type diffs.
8377 ///
8378 /// @return the map that contains reference type diffs.
8379 const string_diff_ptr_map&
8381 {return priv_->reference_diff_map_;}
8382 
8383 /// Getter of the map that contains reference type diffs.
8384 ///
8385 /// @return the map that contains reference type diffs.
8388 {{return priv_->reference_diff_map_;}}
8389 
8390 /// Getter of the map that contains function parameter diffs.
8391 ///
8392 /// @return the map that contains function parameter diffs.
8393 const string_diff_ptr_map&
8395 {return priv_->fn_parm_diff_map_;}
8396 
8397 /// Getter of the map that contains function parameter diffs.
8398 ///
8399 /// @return the map that contains function parameter diffs.
8402 {return priv_->fn_parm_diff_map_;}
8403 
8404 /// Getter of the map that contains function type diffs.
8405 ///
8406 /// @return the map that contains function type diffs.
8407 const string_diff_ptr_map&
8409 {return priv_->function_type_diff_map_;}
8410 
8411 /// Getter of the map that contains function type diffs.
8412 ///
8413 /// @return the map that contains function type diffs.
8416 {return priv_->function_type_diff_map_;}
8417 
8418 /// Getter of the map that contains function decl diffs.
8419 ///
8420 /// @return the map that contains function decl diffs.
8421 const string_diff_ptr_map&
8423 {return priv_->function_decl_diff_map_;}
8424 
8425 /// Getter of the map that contains function decl diffs.
8426 ///
8427 /// @return the map that contains function decl diffs.
8430 {return priv_->function_decl_diff_map_;}
8431 
8432 /// Getter of the map that contains var decl diffs.
8433 ///
8434 /// @return the map that contains var decl diffs.
8435 const string_diff_ptr_map&
8437 {return priv_->var_decl_diff_map_;}
8438 
8439 /// Getter of the map that contains var decl diffs.
8440 ///
8441 /// @return the map that contains var decl diffs.
8444 {return priv_->var_decl_diff_map_;}
8445 
8446 /// Getter of the map that contains distinct diffs.
8447 ///
8448 /// @return the map that contains distinct diffs.
8449 const string_diff_ptr_map&
8451 {return priv_->distinct_diff_map_;}
8452 
8453 /// Getter of the map that contains distinct diffs.
8454 ///
8455 /// @return the map that contains distinct diffs.
8458 {return priv_->distinct_diff_map_;}
8459 
8460 /// Insert a new diff node into the current instance of @ref diff_maps.
8461 ///
8462 /// @param dif the new diff node to insert into the @ref diff_maps.
8463 ///
8464 /// @param impacted_iface the interface (global function or variable)
8465 /// currently being analysed that led to analysing the diff node @p
8466 /// dif. In other words, this is the interface impacted by the diff
8467 /// node @p dif. Note that this can be nil in cases where we are
8468 /// directly analysing changes to a type that is not reachable from
8469 /// any global function or variable.
8470 ///
8471 /// @return true iff the diff node could be added to the current
8472 /// instance of @ref diff_maps.
8473 bool
8475  const type_or_decl_base_sptr& impacted_iface)
8476 {
8477  string n = get_pretty_representation(dif->first_subject(),
8478  /*internal=*/true);
8479  if (const type_decl_diff *d = is_diff_of_basic_type(dif))
8480  get_type_decl_diff_map()[n] = const_cast<type_decl_diff*>(d);
8481  else if (const enum_diff *d = is_enum_diff(dif))
8482  get_enum_diff_map()[n] = const_cast<enum_diff*>(d);
8483  else if (const class_diff *d = is_class_diff(dif))
8484  get_class_diff_map()[n] = const_cast<class_diff*>(d);
8485  else if (const union_diff *d = is_union_diff(dif))
8486  get_union_diff_map()[n] = const_cast<union_diff*>(d);
8487  else if (const typedef_diff *d = is_typedef_diff(dif))
8488  get_typedef_diff_map()[n] = const_cast<typedef_diff*>(d);
8489  else if (const subrange_diff *d = is_subrange_diff(dif))
8490  get_subrange_diff_map()[n] = const_cast<subrange_diff*>(d);
8491  else if (const array_diff *d = is_array_diff(dif))
8492  get_array_diff_map()[n] = const_cast<array_diff*>(d);
8493  else if (const reference_diff *d = is_reference_diff(dif))
8494  get_reference_diff_map()[n] = const_cast<reference_diff*>(d);
8495  else if (const fn_parm_diff *d = is_fn_parm_diff(dif))
8496  get_fn_parm_diff_map()[n] = const_cast<fn_parm_diff*>(d);
8497  else if (const function_type_diff *d = is_function_type_diff(dif))
8498  get_function_type_diff_map()[n] = const_cast<function_type_diff*>(d);
8499  else if (const var_diff *d = is_var_diff(dif))
8500  get_var_decl_diff_map()[n] = const_cast<var_diff*>(d);
8501  else if (const function_decl_diff *d = is_function_decl_diff(dif))
8502  get_function_decl_diff_map()[n] = const_cast<function_decl_diff*>(d);
8503  else if (const distinct_diff *d = is_distinct_diff(dif))
8504  get_distinct_diff_map()[n] = const_cast<distinct_diff*>(d);
8505  else if (is_base_diff(dif))
8506  // we silently drop this case.
8507  return true;
8508  else
8510 
8511  // Update the map that associates this diff node to the set of
8512  // interfaces it impacts.
8513 
8514  if (impacted_iface)
8515  {
8516  diff_artifact_set_map_type::iterator i =
8517  priv_->impacted_artifacts_map_.find(dif);
8518 
8519  if (i == priv_->impacted_artifacts_map_.end())
8520  {
8522  set.insert(impacted_iface);
8523  priv_->impacted_artifacts_map_[dif] = set;
8524  }
8525  else
8526  i->second.insert(impacted_iface);
8527  }
8528 
8529  return true;
8530 }
8531 
8532 /// Lookup the interfaces that are impacted by a given leaf diff node.
8533 ///
8534 /// @param d the diff node to consider.
8535 ///
8536 /// @return the set of artifacts impacted by @p d.
8539 {
8540  diff_artifact_set_map_type::iterator i =
8541  priv_->impacted_artifacts_map_.find(d);
8542 
8543  if (i == priv_->impacted_artifacts_map_.end())
8544  return 0;
8545 
8546  return &i->second;
8547 }
8548 
8549 //
8550 // </diff_maps stuff>
8551 
8552 /// Constructor for the @ref diff_stat type.
8553 ///
8554 /// @param ctxt the context of the corpus diff. Note that this
8555 /// context object must stay alive at least during the life time of
8556 /// the current instance of @ref corpus_diff::diff_stats. Otherwise
8557 /// memory corruption issues occur.
8558 corpus_diff::diff_stats::diff_stats(diff_context_sptr ctxt)
8559  : priv_(new priv(ctxt))
8560 {}
8561 
8562 /// Getter for the number of functions removed.
8563 ///
8564 /// @return the number of functions removed.
8565 size_t
8567 {return priv_->num_func_removed;}
8568 
8569 /// Setter for the number of functions removed.
8570 ///
8571 /// @param n the new number of functions removed.
8572 void
8574 {priv_->num_func_removed = n;}
8575 
8576 /// Getter for the number of removed functions that have been filtered
8577 /// out.
8578 ///
8579 /// @return the number of removed functions that have been filtered
8580 /// out.
8581 size_t
8583 {
8584  if (priv_->ctxt() && !priv_->ctxt()->show_deleted_fns())
8585  return num_func_removed();
8586  return priv_->num_removed_func_filtered_out;
8587 }
8588 
8589 /// Setter for the number of removed functions that have been filtered
8590 /// out.
8591 ///
8592 /// @param t the new value.
8593 void
8595 {priv_->num_removed_func_filtered_out = t;}
8596 
8597 /// Getter for the net number of function removed.
8598 ///
8599 /// This is the difference between the number of functions removed and
8600 /// the number of functons removed that have been filtered out.
8601 ///
8602 /// @return the net number of function removed.
8603 size_t
8605 {
8606  ABG_ASSERT(num_func_removed() >= num_removed_func_filtered_out());
8607  return num_func_removed() - num_removed_func_filtered_out();
8608 }
8609 
8610 /// Getter for the number of functions added.
8611 ///
8612 /// @return the number of functions added.
8613 size_t
8615 {return priv_->num_func_added;}
8616 
8617 /// Setter for the number of functions added.
8618 ///
8619 /// @param n the new number of functions added.
8620 void
8622 {priv_->num_func_added = n;}
8623 
8624 /// Getter for the number of added function that have been filtered out.
8625 ///
8626 /// @return the number of added function that have been filtered out.
8627 size_t
8629 {
8630  if (priv_->ctxt() && !priv_->ctxt()->show_added_fns())
8631  return num_func_added();
8632  return priv_->num_added_func_filtered_out;
8633 }
8634 
8635 /// Setter for the number of added function that have been filtered
8636 /// out.
8637 ///
8638 /// @param n the new value.
8639 void
8641 {priv_->num_added_func_filtered_out = n;}
8642 
8643 /// Getter for the net number of added functions.
8644 ///
8645 /// The net number of added functions is the difference between the
8646 /// number of added functions and the number of added functions that
8647 /// have been filtered out.
8648 ///
8649 /// @return the net number of added functions.
8650 size_t
8652 {
8653  ABG_ASSERT(num_func_added() >= num_added_func_filtered_out());
8654  return num_func_added() - num_added_func_filtered_out();
8655 }
8656 
8657 /// Getter for the number of functions that have a change in one of
8658 /// their sub-types.
8659 ///
8660 /// @return the number of functions that have a change in one of their
8661 /// sub-types.
8662 size_t
8664 {return priv_->num_func_changed;}
8665 
8666 /// Setter for the number of functions that have a change in one of
8667 /// their sub-types.
8668 ///
8669 /// @@param n the new number of functions that have a change in one of
8670 /// their sub-types.
8671 void
8673 {priv_->num_func_changed = n;}
8674 
8675 /// Getter for the number of functions that have a change in one of
8676 /// their sub-types, and that have been filtered out.
8677 ///
8678 /// @return the number of functions that have a change in one of their
8679 /// sub-types, and that have been filtered out.
8680 size_t
8682 {return priv_->num_changed_func_filtered_out;}
8683 
8684 /// Setter for the number of functions that have a change in one of
8685 /// their sub-types, and that have been filtered out.
8686 ///
8687 /// @param n the new number of functions that have a change in one of their
8688 /// sub-types, and that have been filtered out.
8689 void
8691 {priv_->num_changed_func_filtered_out = n;}
8692 
8693 /// Getter for the number of functions that carry virtual member
8694 /// offset changes.
8695 ///
8696 /// @return the number of functions that carry virtual member changes.
8697 size_t
8699 {return priv_->num_func_with_virt_offset_changes;}
8700 
8701 /// Setter for the number of functions that carry virtual member
8702 /// offset changes.
8703 ///
8704 /// @param n the new number of functions that carry virtual member
8705 /// offset. changes.
8706 void
8708 {priv_->num_func_with_virt_offset_changes = n;}
8709 
8710 /// Getter for the number of functions that have a change in their
8711 /// sub-types, minus the number of these functions that got filtered
8712 /// out from the diff.
8713 ///
8714 /// @return for the the number of functions that have a change in
8715 /// their sub-types, minus the number of these functions that got
8716 /// filtered out from the diff.
8717 size_t
8719 {return num_func_changed() - num_changed_func_filtered_out();}
8720 
8721 /// Getter for the number of variables removed.
8722 ///
8723 /// @return the number of variables removed.
8724 size_t
8726 {return priv_->num_vars_removed;}
8727 
8728 /// Setter for the number of variables removed.
8729 ///
8730 /// @param n the new number of variables removed.
8731 void
8733 {priv_->num_vars_removed = n;}
8734 
8735 /// Getter for the number removed variables that have been filtered
8736 /// out.
8737 ///
8738 /// @return the number removed variables that have been filtered out.
8739 size_t
8741 {
8742  if (priv_->ctxt() && !priv_->ctxt()->show_deleted_vars())
8743  return num_vars_removed();
8744  return priv_->num_removed_vars_filtered_out;
8745 }
8746 
8747 /// Setter for the number of removed variables that have been filtered
8748 /// out.
8749 ///
8750 /// @param n the new value.
8751 void
8753 {priv_->num_removed_vars_filtered_out = n;}
8754 
8755 /// Getter for the net number of removed variables.
8756 ///
8757 /// The net number of removed variables is the difference between the
8758 /// number of removed variables and the number of removed variables
8759 /// that have been filtered out.
8760 ///
8761 /// @return the net number of removed variables.
8762 size_t
8764 {
8765  ABG_ASSERT(num_vars_removed() >= num_removed_vars_filtered_out());
8766  return num_vars_removed() - num_removed_vars_filtered_out();
8767 }
8768 
8769 /// Getter for the number of variables added.
8770 ///
8771 /// @return the number of variables added.
8772 size_t
8774 {return priv_->num_vars_added;}
8775 
8776 /// Setter for the number of variables added.
8777 ///
8778 /// @param n the new number of variables added.
8779 void
8781 {priv_->num_vars_added = n;}
8782 
8783 /// Getter for the number of added variables that have been filtered
8784 /// out.
8785 ///
8786 /// @return the number of added variables that have been filtered out.
8787 size_t
8789 {
8790  if (priv_->ctxt() && !priv_->ctxt()->show_added_vars())
8791  return num_vars_added();
8792  return priv_->num_added_vars_filtered_out;
8793 }
8794 
8795 /// Setter for the number of added variables that have been filtered
8796 /// out.
8797 ///
8798 /// @param n the new value.
8799 void
8801 {priv_->num_added_vars_filtered_out = n;}
8802 
8803 /// Getter for the net number of added variables.
8804 ///
8805 /// The net number of added variables is the difference between the
8806 /// number of added variables and the number of added variables that
8807 /// have been filetered out.
8808 ///
8809 /// @return the net number of added variables.
8810 size_t
8812 {
8813  ABG_ASSERT(num_vars_added() >= num_added_vars_filtered_out());
8814  return num_vars_added() - num_added_vars_filtered_out();
8815 }
8816 
8817 /// Getter for the number of variables that have a change in one of
8818 /// their sub-types.
8819 ///
8820 /// @return the number of variables that have a change in one of their
8821 /// sub-types.
8822 size_t
8824 {return priv_->num_vars_changed;}
8825 
8826 /// Setter for the number of variables that have a change in one of
8827 /// their sub-types.
8828 ///
8829 /// @param n the new number of variables that have a change in one of
8830 /// their sub-types.
8831 void
8833 {priv_->num_vars_changed = n;}
8834 
8835 /// Getter for the number of variables that have a change in one of
8836 /// their sub-types, and that have been filtered out.
8837 ///
8838 /// @return the number of functions that have a change in one of their
8839 /// sub-types, and that have been filtered out.
8840 size_t
8842 {return priv_->num_changed_vars_filtered_out;}
8843 
8844 /// Setter for the number of variables that have a change in one of
8845 /// their sub-types, and that have been filtered out.
8846 ///
8847 /// @param n the new number of variables that have a change in one of their
8848 /// sub-types, and that have been filtered out.
8849 void
8851 {priv_->num_changed_vars_filtered_out = n;}
8852 
8853 /// Getter for the number of variables that have a change in their
8854 /// sub-types, minus the number of these variables that got filtered
8855 /// out from the diff.
8856 ///
8857 /// @return for the the number of variables that have a change in
8858 /// their sub-types, minus the number of these variables that got
8859 /// filtered out from the diff.
8860 size_t
8862 {return num_vars_changed() - num_changed_vars_filtered_out();}
8863 
8864 /// Getter for the number of function symbols (not referenced by any
8865 /// debug info) that got removed.
8866 ///
8867 /// @return the number of function symbols (not referenced by any
8868 /// debug info) that got removed.
8869 size_t
8871 {return priv_->num_func_syms_removed;}
8872 
8873 /// Setter for the number of function symbols (not referenced by any
8874 /// debug info) that got removed.
8875 ///
8876 /// @param n the number of function symbols (not referenced by any
8877 /// debug info) that got removed.
8878 void
8880 {priv_->num_func_syms_removed = n;}
8881 
8882 /// Getter for the number of removed function symbols, not referenced
8883 /// by debug info, that have been filtered out.
8884 ///
8885 /// @return the number of removed function symbols, not referenced by
8886 /// debug info, that have been filtered out.
8887 size_t
8889 {
8890  if (priv_->ctxt()
8891  && !priv_->ctxt()->show_symbols_unreferenced_by_debug_info())
8892  return num_func_syms_removed();
8893  return priv_->num_removed_func_syms_filtered_out;
8894 }
8895 
8896 /// Setter for the number of removed function symbols, not referenced
8897 /// by debug info, that have been filtered out.
8898 ///
8899 /// @param n the new the number of removed function symbols, not
8900 /// referenced by debug info, that have been filtered out.
8901 void
8903 {priv_->num_removed_func_syms_filtered_out = n;}
8904 
8905 /// Getter of the net number of removed function symbols that are not
8906 /// referenced by any debug info.
8907 ///
8908 /// This is the difference between the total number of removed
8909 /// function symbols and the number of removed function symbols that
8910 /// have been filteted out. Both numbers are for symbols not
8911 /// referenced by debug info.
8912 ///
8913 /// return the net number of removed function symbols that are not
8914 /// referenced by any debug info.
8915 size_t
8917 {
8918  ABG_ASSERT(num_func_syms_removed() >= num_removed_func_syms_filtered_out());
8919  return num_func_syms_removed() - num_removed_func_syms_filtered_out();
8920 }
8921 
8922 /// Getter for the number of function symbols (not referenced by any
8923 /// debug info) that got added.
8924 ///
8925 /// @return the number of function symbols (not referenced by any
8926 /// debug info) that got added.
8927 size_t
8929 {return priv_->num_func_syms_added;}
8930 
8931 /// Setter for the number of function symbols (not referenced by any
8932 /// debug info) that got added.
8933 ///
8934 /// @param n the new number of function symbols (not referenced by any
8935 /// debug info) that got added.
8936 void
8938 {priv_->num_func_syms_added = n;}
8939 
8940 /// Getter for the number of added function symbols, not referenced by
8941 /// any debug info, that have been filtered out.
8942 ///
8943 /// @return the number of added function symbols, not referenced by
8944 /// any debug info, that have been filtered out.
8945 size_t
8947 {
8948  if (priv_->ctxt()
8949  && !(priv_->ctxt()->show_added_symbols_unreferenced_by_debug_info()
8950  && priv_->ctxt()->show_symbols_unreferenced_by_debug_info()))
8951  return num_func_syms_added();
8952  return priv_->num_added_func_syms_filtered_out;
8953 }
8954 
8955 /// Setter for the number of added function symbols, not referenced by
8956 /// any debug info, that have been filtered out.
8957 ///
8958 /// @param n the new number of added function symbols, not referenced
8959 /// by any debug info, that have been filtered out.
8960 void
8962 {priv_->num_added_func_syms_filtered_out = n;}
8963 
8964 /// Getter of the net number of added function symbols that are not
8965 /// referenced by any debug info.
8966 ///
8967 /// This is the difference between the total number of added
8968 /// function symbols and the number of added function symbols that
8969 /// have been filteted out. Both numbers are for symbols not
8970 /// referenced by debug info.
8971 ///
8972 /// return the net number of added function symbols that are not
8973 /// referenced by any debug info.
8974 size_t
8976 {
8977  ABG_ASSERT(num_func_syms_added() >= num_added_func_syms_filtered_out());
8978  return num_func_syms_added()- num_added_func_syms_filtered_out();
8979 }
8980 
8981 /// Getter for the number of variable symbols (not referenced by any
8982 /// debug info) that got removed.
8983 ///
8984 /// @return the number of variable symbols (not referenced by any
8985 /// debug info) that got removed.
8986 size_t
8988 {return priv_->num_var_syms_removed;}
8989 
8990 /// Setter for the number of variable symbols (not referenced by any
8991 /// debug info) that got removed.
8992 ///
8993 /// @param n the number of variable symbols (not referenced by any
8994 /// debug info) that got removed.
8995 void
8997 {priv_->num_var_syms_removed = n;}
8998 
8999 /// Getter for the number of removed variable symbols, not referenced
9000 /// by any debug info, that have been filtered out.
9001 ///
9002 /// @return the number of removed variable symbols, not referenced
9003 /// by any debug info, that have been filtered out.
9004 size_t
9006 {
9007  if (priv_->ctxt()
9008  && !priv_->ctxt()->show_symbols_unreferenced_by_debug_info())
9009  return num_var_syms_removed();
9010  return priv_->num_removed_var_syms_filtered_out;
9011 }
9012 
9013 /// Setter for the number of removed variable symbols, not referenced
9014 /// by any debug info, that have been filtered out.
9015 ///
9016 /// @param n the number of removed variable symbols, not referenced by
9017 /// any debug info, that have been filtered out.
9018 void
9020 {priv_->num_removed_var_syms_filtered_out = n;}
9021 
9022 /// Getter of the net number of removed variable symbols that are not
9023 /// referenced by any debug info.
9024 ///
9025 /// This is the difference between the total number of removed
9026 /// variable symbols and the number of removed variable symbols that
9027 /// have been filteted out. Both numbers are for symbols not
9028 /// referenced by debug info.
9029 ///
9030 /// return the net number of removed variable symbols that are not
9031 /// referenced by any debug info.
9032 size_t
9034 {
9035  ABG_ASSERT(num_var_syms_removed() >= num_removed_var_syms_filtered_out());
9036  return num_var_syms_removed() - num_removed_var_syms_filtered_out();
9037 }
9038 
9039 /// Getter for the number of variable symbols (not referenced by any
9040 /// debug info) that got added.
9041 ///
9042 /// @return the number of variable symbols (not referenced by any
9043 /// debug info) that got added.
9044 size_t
9046 {return priv_->num_var_syms_added;}
9047 
9048 /// Setter for the number of variable symbols (not referenced by any
9049 /// debug info) that got added.
9050 ///
9051 /// @param n the new number of variable symbols (not referenced by any
9052 /// debug info) that got added.
9053 void
9055 {priv_->num_var_syms_added = n;}
9056 
9057 /// Getter for the number of added variable symbols, not referenced by
9058 /// any debug info, that have been filtered out.
9059 ///
9060 /// @return the number of added variable symbols, not referenced by
9061 /// any debug info, that have been filtered out.
9062 size_t
9064 {
9065  if (priv_->ctxt()
9066  && !(priv_->ctxt()->show_added_symbols_unreferenced_by_debug_info()
9067  && priv_->ctxt()->show_symbols_unreferenced_by_debug_info()))
9068  return num_var_syms_added();
9069  return priv_->num_added_var_syms_filtered_out;
9070 }
9071 
9072 /// Setter for the number of added variable symbols, not referenced by
9073 /// any debug info, that have been filtered out.
9074 ///
9075 /// @param n the new number of added variable symbols, not referenced
9076 /// by any debug info, that have been filtered out.
9077 void
9079 {priv_->num_added_var_syms_filtered_out = n;}
9080 
9081 /// Getter of the net number of added variable symbols that are not
9082 /// referenced by any debug info.
9083 ///
9084 /// This is the difference between the total number of added
9085 /// variable symbols and the number of added variable symbols that
9086 /// have been filteted out. Both numbers are for symbols not
9087 /// referenced by debug info.
9088 ///
9089 /// return the net number of added variable symbols that are not
9090 /// referenced by any debug info.
9091 size_t
9093 {
9094  ABG_ASSERT(num_var_syms_added() >= num_added_var_syms_filtered_out());
9095  return num_var_syms_added() - num_added_var_syms_filtered_out();
9096 }
9097 
9098 /// Getter of the number of leaf type change diff nodes.
9099 ///
9100 /// @return the number of leaf type change diff nodes.
9101 size_t
9103 {return priv_->num_leaf_changes;}
9104 
9105 /// Setter of the number of leaf type change diff nodes.
9106 ///
9107 /// @param n the new number of leaf type change diff nodes.
9108 void
9110 {priv_->num_leaf_changes = n;}
9111 
9112 /// Getter of the number of leaf type change diff nodes that have been
9113 /// filtered out.
9114 ///
9115 /// @return the number of leaf type change diff nodes that have been
9116 size_t
9118 {return priv_->num_leaf_changes_filtered_out;}
9119 
9120 /// Setter of the number of leaf type change diff nodes that have been
9121 /// filtered out.
9122 ///
9123 /// @param n the new number of leaf type change diff nodes that have
9124 /// been filtered out.
9125 void
9127 {priv_->num_leaf_changes_filtered_out = n;}
9128 
9129 /// Getter of the net number of leaf change diff nodes.
9130 ///
9131 /// This is the difference between the total number of leaf change
9132 /// diff nodes, and the number of the leaf change diff nodes that have
9133 /// been filtered out.
9134 ///
9135 /// A leaf change is either a type change, a function change or a
9136 /// variable change.
9137 size_t
9139 {
9140  ABG_ASSERT(num_leaf_changes() >= num_leaf_changes_filtered_out());
9141  return num_leaf_changes() - num_leaf_changes_filtered_out();
9142 }
9143 
9144 /// Getter for the number of leaf type change diff nodes.
9145 ///
9146 /// @return the number of leaf type changes diff nodes.
9147 size_t
9149 {return priv_->num_leaf_type_changes;}
9150 
9151 /// Setter for the number of leaf type change diff nodes.
9152 ///
9153 /// @param n the new number of leaf type change diff nodes.
9154 void
9156 {priv_->num_leaf_type_changes = n;}
9157 
9158 /// Getter for the number of filtered out leaf type change diff nodes.
9159 ///
9160 /// @return the number of filtered out leaf type change diff nodes.
9161 size_t
9163 {return priv_->num_leaf_type_changes_filtered_out;}
9164 
9165 /// Setter for the number of filtered out leaf type change diff nodes.
9166 /// @param n the new number of filtered out leaf type change diff nodes.
9167 void
9169 {priv_->num_leaf_type_changes_filtered_out = n;}
9170 
9171 /// Getter for the net number of leaf type change diff nodes.
9172 ///
9173 /// This is the difference between the number of leaf type changes and
9174 /// the number of filtered out leaf type changes.
9175 ///
9176 /// @return the net number of leaf type change diff nodes.
9177 size_t
9179 {return num_leaf_type_changes() - num_leaf_type_changes_filtered_out();}
9180 
9181 /// Getter for the number of leaf function change diff nodes.
9182 ///
9183 /// @return the number of leaf function change diff nodes.
9184 size_t
9186 {return priv_->num_leaf_func_changes;}
9187 
9188 /// Setter for the number of leaf function change diff nodes.
9189 ///
9190 /// @param n the new number of leaf function change diff nodes.
9191 void
9193 {priv_->num_leaf_func_changes = n;}
9194 
9195 /// Getter for the number of leaf function change diff nodes that were
9196 /// filtered out.
9197 ///
9198 /// @return the number of leaf function change diff nodes that were
9199 /// filtered out.
9200 size_t
9202 {return priv_->num_leaf_func_changes_filtered_out;}
9203 
9204 /// Setter for the number of leaf function change diff nodes that were
9205 /// filtered out.
9206 ///
9207 /// @param n the new number of leaf function change diff nodes that
9208 /// were filtered out.
9209 void
9211 {priv_->num_leaf_func_changes_filtered_out = n;}
9212 
9213 /// Getter for the net number of leaf function change diff nodes.
9214 ///
9215 /// This is the difference between the number of leaf function change
9216 /// diff nodes and the number of filtered out leaf function change
9217 /// diff nodes.
9218 ///
9219 /// @return the net number of leaf function change diff nodes.
9220 size_t
9222 {return num_leaf_func_changes() - num_leaf_func_changes_filtered_out();}
9223 
9224 /// Getter for the number of leaf variable change diff nodes.
9225 ///
9226 /// @return the number of leaf variable change diff nodes.
9227 size_t
9229 {return priv_->num_leaf_var_changes;}
9230 
9231 /// Setter for the number of leaf variable change diff nodes.
9232 ///
9233 /// @param n the number of leaf variable change diff nodes.
9234 void
9236 {priv_->num_leaf_var_changes = n;}
9237 
9238 /// Getter of the number of added types that are unreachable from the
9239 /// public interface of the ABI corpus.
9240 ///
9241 /// Public interface means the set of defined and publicly exported
9242 /// functions and variables of the ABI corpus.
9243 ///
9244 /// @return the number of added types that are unreachable from the
9245 /// public interface of the ABI corpus.
9246 size_t
9248 {return priv_->num_added_unreachable_types;}
9249 
9250 /// Setter of the number of added types that are unreachable from the
9251 /// public interface (global functions or variables) of the ABI
9252 /// corpus.
9253 ///
9254 /// Public interface means the set of defined and publicly exported
9255 /// functions and variables of the ABI corpus.
9256 ///
9257 /// @param n the new number of added types that are unreachable from
9258 /// the public interface of the ABI corpus.
9259 void
9261 {priv_->num_added_unreachable_types = n;}
9262 
9263 /// Getter of the number of added types that are unreachable from
9264 /// public interfaces and that are filtered out by suppression
9265 /// specifications.
9266 ///
9267 /// @return the number of added types that are unreachable from public
9268 /// interfaces and that are filtered out by suppression
9269 /// specifications.
9270 size_t
9272 {return priv_->num_added_unreachable_types_filtered_out;}
9273 
9274 /// Setter of the number of added types that are unreachable from
9275 /// public interfaces and that are filtered out by suppression
9276 /// specifications.
9277 ///
9278 /// @param n the new number of added types that are unreachable from
9279 /// public interfaces and that are filtered out by suppression
9280 /// specifications.
9281 void
9283 {priv_->num_added_unreachable_types_filtered_out = n;}
9284 
9285 /// Getter of the number of added types that are unreachable from
9286 /// public interfaces and that are *NOT* filtered out by suppression
9287 /// specifications.
9288 ///
9289 /// @return the number of added types that are unreachable from public
9290 /// interfaces and that are *NOT* filtered out by suppression
9291 /// specifications.
9292 size_t
9294 {
9295  ABG_ASSERT(num_added_unreachable_types()
9296  >=
9297  num_added_unreachable_types_filtered_out());
9298 
9299  return (num_added_unreachable_types()
9300  -
9301  num_added_unreachable_types_filtered_out());
9302 }
9303 
9304 /// Getter of the number of removed types that are unreachable from
9305 /// the public interface of the ABI corpus.
9306 ///
9307 /// Public interface means the set of defined and publicly exported
9308 /// functions and variables of the ABI corpus.
9309 ///
9310 /// @return the number of removed types that are unreachable from
9311 /// the public interface of the ABI corpus.
9312 size_t
9314 {return priv_->num_removed_unreachable_types;}
9315 
9316 /// Setter of the number of removed types that are unreachable from
9317 /// the public interface of the ABI corpus.
9318 ///
9319 /// Public interface means the set of defined and publicly exported
9320 /// functions and variables of the ABI corpus.
9321 ///
9322 ///@param n the new number of removed types that are unreachable from
9323 /// the public interface of the ABI corpus.
9324 void
9326 {priv_->num_removed_unreachable_types = n;}
9327 
9328 /// Getter of the number of removed types that are not reachable from
9329 /// public interfaces and that have been filtered out by suppression
9330 /// specifications.
9331 ///
9332 /// @return the number of removed types that are not reachable from
9333 /// public interfaces and that have been filtered out by suppression
9334 /// specifications.
9335 size_t
9337 {return priv_->num_removed_unreachable_types_filtered_out;}
9338 
9339 /// Setter of the number of removed types that are not reachable from
9340 /// public interfaces and that have been filtered out by suppression
9341 /// specifications.
9342 ///
9343 /// @param n the new number of removed types that are not reachable
9344 /// from public interfaces and that have been filtered out by
9345 /// suppression specifications.
9346 void
9348 {priv_->num_removed_unreachable_types_filtered_out = n;}
9349 
9350 /// Getter of the number of removed types that are not reachable from
9351 /// public interfaces and that have *NOT* been filtered out by
9352 /// suppression specifications.
9353 ///
9354 /// @return the number of removed types that are not reachable from
9355 /// public interfaces and that have *NOT* been filtered out by
9356 /// suppression specifications.
9357 size_t
9359 {
9360  ABG_ASSERT(num_removed_unreachable_types()
9361  >=
9362  num_removed_unreachable_types_filtered_out());
9363 
9364  return (num_removed_unreachable_types()
9365  -
9366  num_removed_unreachable_types_filtered_out());
9367 }
9368 
9369 /// Getter of the number of changed types that are unreachable from
9370 /// the public interface of the ABI corpus.
9371 ///
9372 /// Public interface means the set of defined and publicly exported
9373 /// functions and variables of the ABI corpus.
9374 ///
9375 /// @return the number of changed types that are unreachable from the
9376 /// public interface of the ABI corpus.
9377 size_t
9379 {return priv_->num_changed_unreachable_types;}
9380 
9381 /// Setter of the number of changed types that are unreachable from
9382 /// the public interface of the ABI corpus.
9383 ///
9384 /// Public interface means the set of defined and publicly exported
9385 /// functions and variables of the ABI corpus.
9386 ///
9387 ///@param n the new number of changed types that are unreachable from
9388 /// the public interface of the ABI corpus.
9389 void
9391 {priv_->num_changed_unreachable_types = n;}
9392 
9393 /// Getter of the number of changed types that are unreachable from
9394 /// public interfaces and that have been filtered out by suppression
9395 /// specifications.
9396 ///
9397 /// @return the number of changed types that are unreachable from
9398 /// public interfaces and that have been filtered out by suppression
9399 /// specifications.
9400 size_t
9402 {return priv_->num_changed_unreachable_types_filtered_out;}
9403 
9404 /// Setter of the number of changed types that are unreachable from
9405 /// public interfaces and that have been filtered out by suppression
9406 /// specifications.
9407 ///
9408 /// @param n the new number of changed types that are unreachable from
9409 /// public interfaces and that have been filtered out by suppression
9410 /// specifications.
9411 void
9413 {priv_->num_changed_unreachable_types_filtered_out = n;}
9414 
9415 /// Getter of the number of changed types that are unreachable from
9416 /// public interfaces and that have *NOT* been filtered out by
9417 /// suppression specifications.
9418 ///
9419 /// @return the number of changed types that are unreachable from
9420 /// public interfaces and that have *NOT* been filtered out by
9421 /// suppression specifications.
9422 size_t
9424 {
9425  ABG_ASSERT(num_changed_unreachable_types()
9426  >=
9427  num_changed_unreachable_types_filtered_out());
9428 
9429  return (num_changed_unreachable_types()
9430  -
9431  num_changed_unreachable_types_filtered_out());
9432 }
9433 
9434 /// Getter for the number of leaf variable changes diff nodes that
9435 /// have been filtered out.
9436 ///
9437 /// @return the number of leaf variable changes diff nodes that have
9438 /// been filtered out.
9439 size_t
9441 {return priv_->num_leaf_var_changes_filtered_out;}
9442 
9443 /// Setter for the number of leaf variable changes diff nodes that
9444 /// have been filtered out.
9445 ///
9446 /// @param n the number of leaf variable changes diff nodes that have
9447 /// been filtered out.
9448 void
9450 {priv_->num_leaf_var_changes_filtered_out = n;}
9451 
9452 /// Getter for the net number of leaf variable change diff nodes.
9453 ///
9454 /// This the difference between the number of leaf variable change
9455 /// diff nodes and the number of filtered out leaf variable change
9456 /// diff nodes.
9457 ///
9458 /// @return the net number of leaf variable change diff nodes.
9459 size_t
9461 {return num_leaf_var_changes() - num_leaf_var_changes_filtered_out();}
9462 
9463 
9464 // <corpus_diff stuff>
9465 
9466 /// Getter of the context associated with this corpus.
9467 ///
9468 /// @return a smart pointer to the context associate with the corpus.
9471 {return ctxt_.lock();}
9472 
9473 /// Tests if the lookup tables are empty.
9474 ///
9475 /// @return true if the lookup tables are empty, false otherwise.
9476 bool
9478 {
9479  return (deleted_fns_.empty()
9480  && added_fns_.empty()
9481  && changed_fns_map_.empty()
9482  && deleted_vars_.empty()
9483  && added_vars_.empty()
9484  && changed_vars_map_.empty());
9485 }
9486 
9487 /// Clear the lookup tables useful for reporting an enum_diff.
9488 void
9490 {
9491  deleted_fns_.clear();
9492  added_fns_.clear();
9493  changed_fns_map_.clear();
9494  deleted_vars_.clear();
9495  added_vars_.clear();
9496  changed_vars_map_.clear();
9497 }
9498 
9499 /// If the lookup tables are not yet built, walk the differences and
9500 /// fill the lookup tables.
9501 void
9503 {
9504  if (!lookup_tables_empty())
9505  return;
9506 
9507  diff_context_sptr ctxt = get_context();
9508 
9509  {
9510  edit_script& e = fns_edit_script_;
9511 
9512  for (vector<deletion>::const_iterator it = e.deletions().begin();
9513  it != e.deletions().end();
9514  ++it)
9515  {
9516  unsigned i = it->index();
9517  ABG_ASSERT(i < first_->get_functions().size());
9518 
9519  const function_decl* deleted_fn = first_->get_functions()[i];
9520  string n = get_function_id_or_pretty_representation(deleted_fn);
9521  ABG_ASSERT(!n.empty());
9522  // The below is commented out because there can be several
9523  // functions with the same ID in the corpus. So several
9524  // functions with the same ID can be deleted.
9525  // ABG_ASSERT(deleted_fns_.find(n) == deleted_fns_.end());
9526  deleted_fns_[n] = deleted_fn;
9527  }
9528 
9529  for (vector<insertion>::const_iterator it = e.insertions().begin();
9530  it != e.insertions().end();
9531  ++it)
9532  {
9533  for (vector<unsigned>::const_iterator iit =
9534  it->inserted_indexes().begin();
9535  iit != it->inserted_indexes().end();
9536  ++iit)
9537  {
9538  unsigned i = *iit;
9539  const function_decl* added_fn = second_->get_functions()[i];
9540  string n = get_function_id_or_pretty_representation(added_fn);
9541  ABG_ASSERT(!n.empty());
9542  // The below is commented out because there can be several
9543  // functions with the same ID in the corpus. So several
9544  // functions with the same ID can be added.
9545  // ABG_ASSERT(added_fns_.find(n) == added_fns_.end());
9546  string_function_ptr_map::const_iterator j =
9547  deleted_fns_.find(n);
9548  if (j != deleted_fns_.end())
9549  {
9550  function_decl_sptr f(const_cast<function_decl*>(j->second),
9551  noop_deleter());
9552  function_decl_sptr s(const_cast<function_decl*>(added_fn),
9553  noop_deleter());
9554  function_decl_diff_sptr d = compute_diff(f, s, ctxt);
9555  if (*j->second != *added_fn)
9556  changed_fns_map_[j->first] = d;
9557  deleted_fns_.erase(j);
9558  }
9559  else
9560  added_fns_[n] = added_fn;
9561  }
9562  }
9563  sort_string_function_decl_diff_sptr_map(changed_fns_map_, changed_fns_);
9564 
9565  // Now walk the allegedly deleted functions; check if their
9566  // underlying symbols are deleted as well; otherwise, consider
9567  // that the function in question hasn't been deleted.
9568 
9569  vector<string> to_delete;
9570  for (string_function_ptr_map::const_iterator i = deleted_fns_.begin();
9571  i != deleted_fns_.end();
9572  ++i)
9573  if (second_->lookup_function_symbol(*i->second->get_symbol()))
9574  to_delete.push_back(i->first);
9575 
9576  for (vector<string>::const_iterator i = to_delete.begin();
9577  i != to_delete.end();
9578  ++i)
9579  deleted_fns_.erase(*i);
9580 
9581  // Do something similar for added functions.
9582 
9583  to_delete.clear();
9584  for (string_function_ptr_map::const_iterator i = added_fns_.begin();
9585  i != added_fns_.end();
9586  ++i)
9587  {
9588  if (first_->lookup_function_symbol(*i->second->get_symbol()))
9589  to_delete.push_back(i->first);
9590  else if (! i->second->get_symbol()->get_version().is_empty()
9591  && i->second->get_symbol()->get_version().is_default())
9592  // We are looking for a symbol that has a default version,
9593  // and which seems to be newly added. Let's see if the same
9594  // symbol with *no* version was already present in the
9595  // former corpus. If yes, then the symbol shouldn't be
9596  // considered as 'added'.
9597  {
9598  elf_symbol::version empty_version;
9599  if (first_->lookup_function_symbol(i->second->get_symbol()->get_name(),
9600  empty_version))
9601  to_delete.push_back(i->first);
9602  }
9603  }
9604 
9605  for (vector<string>::const_iterator i = to_delete.begin();
9606  i != to_delete.end();
9607  ++i)
9608  added_fns_.erase(*i);
9609  }
9610 
9611  {
9612  edit_script& e = vars_edit_script_;
9613 
9614  for (vector<deletion>::const_iterator it = e.deletions().begin();
9615  it != e.deletions().end();
9616  ++it)
9617  {
9618  unsigned i = it->index();
9619  ABG_ASSERT(i < first_->get_variables().size());
9620 
9621  const var_decl* deleted_var = first_->get_variables()[i];
9622  string n = deleted_var->get_id();
9623  ABG_ASSERT(!n.empty());
9624  ABG_ASSERT(deleted_vars_.find(n) == deleted_vars_.end());
9625  deleted_vars_[n] = deleted_var;
9626  }
9627 
9628  for (vector<insertion>::const_iterator it = e.insertions().begin();
9629  it != e.insertions().end();
9630  ++it)
9631  {
9632  for (vector<unsigned>::const_iterator iit =
9633  it->inserted_indexes().begin();
9634  iit != it->inserted_indexes().end();
9635  ++iit)
9636  {
9637  unsigned i = *iit;
9638  const var_decl* added_var = second_->get_variables()[i];
9639  string n = added_var->get_id();
9640  ABG_ASSERT(!n.empty());
9641  {
9642  string_var_ptr_map::const_iterator k = added_vars_.find(n);
9643  if ( k != added_vars_.end())
9644  {
9645  ABG_ASSERT(is_member_decl(k->second)
9646  && get_member_is_static(k->second));
9647  continue;
9648  }
9649  }
9650  string_var_ptr_map::const_iterator j =
9651  deleted_vars_.find(n);
9652  if (j != deleted_vars_.end())
9653  {
9654  if (*j->second != *added_var)
9655  {
9656  var_decl_sptr f(const_cast<var_decl*>(j->second),
9657  noop_deleter());
9658  var_decl_sptr s(const_cast<var_decl*>(added_var),
9659  noop_deleter());
9660  changed_vars_map_[n] = compute_diff(f, s, ctxt);
9661  }
9662  deleted_vars_.erase(j);
9663  }
9664  else
9665  added_vars_[n] = added_var;
9666  }
9667  }
9668  sort_string_var_diff_sptr_map(changed_vars_map_,
9669  sorted_changed_vars_);
9670 
9671  // Now walk the allegedly deleted variables; check if their
9672  // underlying symbols are deleted as well; otherwise consider
9673  // that the variable in question hasn't been deleted.
9674 
9675  vector<string> to_delete;
9676  for (string_var_ptr_map::const_iterator i = deleted_vars_.begin();
9677  i != deleted_vars_.end();
9678  ++i)
9679  if (second_->lookup_variable_symbol(*i->second->get_symbol()))
9680  to_delete.push_back(i->first);
9681 
9682  for (vector<string>::const_iterator i = to_delete.begin();
9683  i != to_delete.end();
9684  ++i)
9685  deleted_vars_.erase(*i);
9686 
9687  // Do something similar for added variables.
9688 
9689  to_delete.clear();
9690  for (string_var_ptr_map::const_iterator i = added_vars_.begin();
9691  i != added_vars_.end();
9692  ++i)
9693  if (first_->lookup_variable_symbol(*i->second->get_symbol()))
9694  to_delete.push_back(i->first);
9695  else if (! i->second->get_symbol()->get_version().is_empty()
9696  && i->second->get_symbol()->get_version().is_default())
9697  // We are looking for a symbol that has a default version,
9698  // and which seems to be newly added. Let's see if the same
9699  // symbol with *no* version was already present in the
9700  // former corpus. If yes, then the symbol shouldn't be
9701  // considered as 'added'.
9702  {
9703  elf_symbol::version empty_version;
9704  if (first_->lookup_variable_symbol(i->second->get_symbol()->get_name(),
9705  empty_version))
9706  to_delete.push_back(i->first);
9707  }
9708 
9709  for (vector<string>::const_iterator i = to_delete.begin();
9710  i != to_delete.end();
9711  ++i)
9712  added_vars_.erase(*i);
9713  }
9714 
9715  // Massage the edit script for added/removed function symbols that
9716  // were not referenced by any debug info and turn them into maps of
9717  // {symbol_name, symbol}.
9718  {
9719  edit_script& e = unrefed_fn_syms_edit_script_;
9720  for (vector<deletion>::const_iterator it = e.deletions().begin();
9721  it != e.deletions().end();
9722  ++it)
9723  {
9724  unsigned i = it->index();
9725  ABG_ASSERT(i < first_->get_unreferenced_function_symbols().size());
9726  elf_symbol_sptr deleted_sym =
9727  first_->get_unreferenced_function_symbols()[i];
9728  if (!second_->lookup_function_symbol(*deleted_sym))
9729  deleted_unrefed_fn_syms_[deleted_sym->get_id_string()] = deleted_sym;
9730  }
9731 
9732  for (vector<insertion>::const_iterator it = e.insertions().begin();
9733  it != e.insertions().end();
9734  ++it)
9735  {
9736  for (vector<unsigned>::const_iterator iit =
9737  it->inserted_indexes().begin();
9738  iit != it->inserted_indexes().end();
9739  ++iit)
9740  {
9741  unsigned i = *iit;
9742  ABG_ASSERT(i < second_->get_unreferenced_function_symbols().size());
9743  elf_symbol_sptr added_sym =
9744  second_->get_unreferenced_function_symbols()[i];
9745  if ((deleted_unrefed_fn_syms_.find(added_sym->get_id_string())
9746  == deleted_unrefed_fn_syms_.end()))
9747  {
9748  if (!first_->lookup_function_symbol(*added_sym))
9749  {
9750  bool do_add = true;
9751  if (! added_sym->get_version().is_empty()
9752  && added_sym->get_version().is_default())
9753  {
9754  // So added_seem has a default version. If
9755  // the former corpus had a symbol with the
9756  // same name as added_sym but with *no*
9757  // version, then added_sym shouldn't be
9758  // considered as a newly added symbol.
9759  elf_symbol::version empty_version;
9760  if (first_->lookup_function_symbol(added_sym->get_name(),
9761  empty_version))
9762  do_add = false;
9763  }
9764 
9765  if (do_add)
9766  added_unrefed_fn_syms_[added_sym->get_id_string()] =
9767  added_sym;
9768  }
9769  }
9770  else
9771  deleted_unrefed_fn_syms_.erase(added_sym->get_id_string());
9772  }
9773  }
9774  }
9775 
9776  // Massage the edit script for added/removed variable symbols that
9777  // were not referenced by any debug info and turn them into maps of
9778  // {symbol_name, symbol}.
9779  {
9780  edit_script& e = unrefed_var_syms_edit_script_;
9781  for (vector<deletion>::const_iterator it = e.deletions().begin();
9782  it != e.deletions().end();
9783  ++it)
9784  {
9785  unsigned i = it->index();
9786  ABG_ASSERT(i < first_->get_unreferenced_variable_symbols().size());
9787  elf_symbol_sptr deleted_sym =
9788  first_->get_unreferenced_variable_symbols()[i];
9789  if (!second_->lookup_variable_symbol(*deleted_sym))
9790  deleted_unrefed_var_syms_[deleted_sym->get_id_string()] = deleted_sym;
9791  }
9792 
9793  for (vector<insertion>::const_iterator it = e.insertions().begin();
9794  it != e.insertions().end();
9795  ++it)
9796  {
9797  for (vector<unsigned>::const_iterator iit =
9798  it->inserted_indexes().begin();
9799  iit != it->inserted_indexes().end();
9800  ++iit)
9801  {
9802  unsigned i = *iit;
9803  ABG_ASSERT(i < second_->get_unreferenced_variable_symbols().size());
9804  elf_symbol_sptr added_sym =
9805  second_->get_unreferenced_variable_symbols()[i];
9806  if (deleted_unrefed_var_syms_.find(added_sym->get_id_string())
9807  == deleted_unrefed_var_syms_.end())
9808  {
9809  if (!first_->lookup_variable_symbol(*added_sym))
9810  {
9811  bool do_add = true;
9812  if (! added_sym->get_version().is_empty()
9813  && added_sym->get_version().is_default())
9814  {
9815  // So added_seem has a default version. If
9816  // the former corpus had a symbol with the
9817  // same name as added_sym but with *no*
9818  // version, then added_sym shouldn't be
9819  // considered as a newly added symbol.
9820  elf_symbol::version empty_version;
9821  if (first_->lookup_variable_symbol(added_sym->get_name(),
9822  empty_version))
9823  do_add = false;
9824  }
9825 
9826  if (do_add)
9827  added_unrefed_var_syms_[added_sym->get_id_string()] =
9828  added_sym;
9829  }
9830  }
9831  else
9832  deleted_unrefed_var_syms_.erase(added_sym->get_id_string());
9833  }
9834  }
9835  }
9836 
9837  // Handle the unreachable_types_edit_script_
9838  {
9839  edit_script& e = unreachable_types_edit_script_;
9840 
9841  // Populate the map of deleted unreachable types from the
9842  // deletions of the edit script.
9843  for (vector<deletion>::const_iterator it = e.deletions().begin();
9844  it != e.deletions().end();
9845  ++it)
9846  {
9847  unsigned i = it->index();
9848  type_base_sptr t
9849  (first_->get_types_not_reachable_from_public_interfaces()[i]);
9850 
9851  if (!is_user_defined_type(t))
9852  continue;
9853 
9854  string repr =
9855  abigail::ir::get_pretty_representation(t, /*internal=*/false);
9856  deleted_unreachable_types_[repr] = t;
9857  }
9858 
9859  // Populate the map of added and change unreachable types from the
9860  // insertions of the edit script.
9861  for (vector<insertion>::const_iterator it = e.insertions().begin();
9862  it != e.insertions().end();
9863  ++it)
9864  {
9865  for (vector<unsigned>::const_iterator iit =
9866  it->inserted_indexes().begin();
9867  iit != it->inserted_indexes().end();
9868  ++iit)
9869  {
9870  unsigned i = *iit;
9871  type_base_sptr t
9872  (second_->get_types_not_reachable_from_public_interfaces()[i]);
9873 
9874  if (!is_user_defined_type(t))
9875  continue;
9876 
9877  string repr =
9878  abigail::ir::get_pretty_representation(t, /*internal=*/false);
9879 
9880  // Let's see if the inserted type we are looking at was
9881  // reported as deleted as well.
9882  //
9883  // If it's been deleted and a different version of it has
9884  // now been added, it means it's been *changed*. In that
9885  // case we'll compute the diff of that change and store it
9886  // in the map of changed unreachable types.
9887  //
9888  // Otherwise, it means the type's been added so we'll add
9889  // it to the set of added unreachable types.
9890 
9891  string_type_base_sptr_map::const_iterator j =
9892  deleted_unreachable_types_.find(repr);
9893  if (j != deleted_unreachable_types_.end())
9894  {
9895  // So there was another type of the same pretty
9896  // representation which was reported as deleted.
9897  // Let's see if they are different or not ...
9898  decl_base_sptr old_type = is_decl(j->second);
9899  decl_base_sptr new_type = is_decl(t);
9900  if (old_type != new_type)
9901  {
9902  // The previously added type is different from this
9903  // one that is added. That means the initial type
9904  // was changed. Let's compute its diff and store it
9905  // as a changed type.
9906  diff_sptr d = compute_diff(old_type, new_type, ctxt);
9907  ABG_ASSERT(d->has_changes());
9908  changed_unreachable_types_[repr]= d;
9909  }
9910 
9911  // In any case, the type was both deleted and added,
9912  // so we cannot have it marked as being deleted. So
9913  // let's remove it from the deleted types.
9914  deleted_unreachable_types_.erase(j);
9915  }
9916  else
9917  // The type wasn't previously reported as deleted, so
9918  // it's really added.
9919  added_unreachable_types_[repr] = t;
9920  }
9921  }
9922 
9923  // Handle anonymous enums that got changed. An anonymous enum is
9924  // designated by its flat textual representation. So a change to
9925  // any of its enumerators results in a different enum. That is
9926  // represented by a deletion of the previous anonymous enum, and
9927  // the addition of a new one. For the user however, it's the same
9928  // enum that changed. Let's massage this "added/removed" pattern
9929  // to show what the user expects, namely, a changed anonymous
9930  // enum.
9931  {
9932  std::set<type_base_sptr> deleted_anon_types;
9933  std::set<type_base_sptr> added_anon_types;
9934 
9935  for (auto entry : deleted_unreachable_types_)
9936  {
9937  if ((is_enum_type(entry.second)
9938  && is_enum_type(entry.second)->get_is_anonymous())
9939  || (is_class_or_union_type(entry.second)
9940  && is_class_or_union_type(entry.second)->get_is_anonymous()))
9941  deleted_anon_types.insert(entry.second);
9942  }
9943 
9944 
9945  for (auto entry : added_unreachable_types_)
9946  if ((is_enum_type(entry.second)
9947  && is_enum_type(entry.second)->get_is_anonymous())
9948  || (is_class_or_union_type(entry.second)
9949  && is_class_or_union_type(entry.second)->get_is_anonymous()))
9950  added_anon_types.insert(entry.second);
9951 
9952  string_type_base_sptr_map added_anon_types_to_erase;
9953  string_type_base_sptr_map removed_anon_types_to_erase;
9954  enum_type_decl_sptr deleted_enum;
9955  class_or_union_sptr deleted_class;
9956 
9957  // Look for deleted anonymous types (enums, unions, structs &
9958  // classes) which have enumerators or data members present in an
9959  // added anonymous type ...
9960  for (auto deleted: deleted_anon_types)
9961  {
9962  deleted_enum = is_enum_type(deleted);
9963  deleted_class = is_class_or_union_type(deleted);
9964 
9965  // For enums, look for any enumerator of 'deleted_enum' that
9966  // is also present in an added anonymous enum.
9967  if (deleted_enum)
9968  {
9969  for (auto enr : deleted_enum->get_enumerators())
9970  {
9971  bool this_enum_got_changed = false;
9972  for (auto t : added_anon_types)
9973  {
9974  if (enum_type_decl_sptr added_enum = is_enum_type(t))
9975  if (is_enumerator_present_in_enum(enr, *added_enum))
9976  {
9977  // So the enumerator 'enr' from the
9978  // 'deleted_enum' enum is also present in the
9979  // 'added_enum' enum so we assume that
9980  // 'deleted_enum' and 'added_enum' are the same
9981  // enum that got changed. Let's represent it
9982  // using a diff node.
9983  diff_sptr d = compute_diff(deleted_enum,
9984  added_enum, ctxt);
9985  ABG_ASSERT(d->has_changes());
9986  string repr =
9988  /*internal=*/false);
9989  changed_unreachable_types_[repr]= d;
9990  this_enum_got_changed = true;
9991  string r1 =
9993  /*internal=*/false);
9994  string r2 =
9996  /*internal=*/false);
9997  removed_anon_types_to_erase[r1] = deleted_enum;
9998  added_anon_types_to_erase[r2] = added_enum;
9999  break;
10000  }
10001  }
10002  if (this_enum_got_changed)
10003  break;
10004  }
10005  }
10006  else if (deleted_class)
10007  {
10008  // For unions, structs & classes, look for any data
10009  // member of 'deleted_class' that is also present in an
10010  // added anonymous class.
10011  for (auto dm : deleted_class->get_data_members())
10012  {
10013  bool this_class_got_changed = false;
10014  for (auto klass : added_anon_types)
10015  {
10016  if (class_or_union_sptr added_class =
10017  is_class_or_union_type(klass))
10018  if (class_or_union_types_of_same_kind(deleted_class,
10019  added_class)
10020  && lookup_data_member(added_class, dm))
10021  {
10022  // So the data member 'dm' from the
10023  // 'deleted_class' class is also present in
10024  // the 'added_class' class so we assume that
10025  // 'deleted_class' and 'added_class' are the
10026  // same anonymous class that got changed.
10027  // Let's represent it using a diff node.
10028  diff_sptr d = compute_diff(is_type(deleted_class),
10029  is_type(added_class),
10030  ctxt);
10031  ABG_ASSERT(d->has_changes());
10032  string repr =
10034  /*internal=*/false);
10035  changed_unreachable_types_[repr]= d;
10036  this_class_got_changed = true;
10037  string r1 =
10039  /*internal=*/false);
10040  string r2 =
10042  /*internal=*/false);
10043  removed_anon_types_to_erase[r1] = deleted_class;
10044  added_anon_types_to_erase[r2] = added_class;
10045  break;
10046  }
10047  }
10048  if (this_class_got_changed)
10049  break;
10050  }
10051  }
10052  }
10053 
10054  // Now remove the added/removed anonymous types from their maps,
10055  // as they are now represented as a changed type, not an added
10056  // and removed anonymous type.
10057  for (auto entry : added_anon_types_to_erase)
10058  added_unreachable_types_.erase(entry.first);
10059 
10060  for (auto entry : removed_anon_types_to_erase)
10061  deleted_unreachable_types_.erase(entry.first);
10062  }
10063  }
10064 }
10065 
10066 /// Test if a change reports about a given @ref function_decl that is
10067 /// changed in a certain way is suppressed by a given suppression
10068 /// specifiation
10069 ///
10070 /// @param fn the @ref function_decl to consider.
10071 ///
10072 /// @param suppr the suppression specification to consider.
10073 ///
10074 /// @param k the kind of change that happened to @p fn.
10075 ///
10076 /// @param ctxt the context of the current diff.
10077 ///
10078 /// @return true iff the suppression specification @p suppr suppresses
10079 /// change reports about function @p fn, if that function changes in
10080 /// the way expressed by @p k.
10081 static bool
10082 function_is_suppressed(const function_decl* fn,
10083  const suppression_sptr suppr,
10085  const diff_context_sptr ctxt)
10086 {
10088  if (!fn_suppr)
10089  return false;
10090  return fn_suppr->suppresses_function(fn, k, ctxt);
10091 }
10092 
10093 /// Test if a change reports about a given @ref var_decl that is
10094 /// changed in a certain way is suppressed by a given suppression
10095 /// specifiation
10096 ///
10097 /// @param fn the @ref var_decl to consider.
10098 ///
10099 /// @param suppr the suppression specification to consider.
10100 ///
10101 /// @param k the kind of change that happened to @p fn.
10102 ///
10103 /// @param ctxt the context of the current diff.
10104 ///
10105 /// @return true iff the suppression specification @p suppr suppresses
10106 /// change reports about variable @p fn, if that variable changes in
10107 /// the way expressed by @p k.
10108 static bool
10109 variable_is_suppressed(const var_decl* var,
10110  const suppression_sptr suppr,
10112  const diff_context_sptr ctxt)
10113 {
10115  if (!var_suppr)
10116  return false;
10117  return var_suppr->suppresses_variable(var, k, ctxt);
10118 }
10119 
10120 /// Apply suppression specifications for this corpus diff to the set
10121 /// of added/removed functions/variables, as well as to types not
10122 /// reachable from global functions/variables.
10123 void
10125 {
10126  diff_context_sptr ctxt = get_context();
10127 
10128  const suppressions_type& suppressions = ctxt->suppressions();
10129  for (suppressions_type::const_iterator i = suppressions.begin();
10130  i != suppressions.end();
10131  ++i)
10132  {
10133  // Added/Deleted functions.
10135  {
10136  // Added functions
10137  for (string_function_ptr_map::const_iterator e = added_fns_.begin();
10138  e != added_fns_.end();
10139  ++e)
10140  if (function_is_suppressed(e->second, fn_suppr,
10142  ctxt))
10143  suppressed_added_fns_[e->first] = e->second;
10144 
10145  // Deleted functions.
10146  for (string_function_ptr_map::const_iterator e = deleted_fns_.begin();
10147  e != deleted_fns_.end();
10148  ++e)
10149  if (function_is_suppressed(e->second, fn_suppr,
10151  ctxt))
10152  suppressed_deleted_fns_[e->first] = e->second;
10153 
10154  // Added function symbols not referenced by any debug info
10155  for (string_elf_symbol_map::const_iterator e =
10156  added_unrefed_fn_syms_.begin();
10157  e != added_unrefed_fn_syms_.end();
10158  ++e)
10159  if (fn_suppr->suppresses_function_symbol(e->second,
10161  ctxt))
10162  suppressed_added_unrefed_fn_syms_[e->first] = e->second;
10163 
10164  // Removed function symbols not referenced by any debug info
10165  for (string_elf_symbol_map::const_iterator e =
10166  deleted_unrefed_fn_syms_.begin();
10167  e != deleted_unrefed_fn_syms_.end();
10168  ++e)
10169  if (fn_suppr->suppresses_function_symbol(e->second,
10171  ctxt))
10172  suppressed_deleted_unrefed_fn_syms_[e->first] = e->second;
10173  }
10174  // Added/Delete virtual member functions changes that might be
10175  // suppressed by a type_suppression that matches the enclosing
10176  // class of the virtual member function.
10177  else if (type_suppression_sptr type_suppr = is_type_suppression(*i))
10178  {
10179  // Added virtual functions
10180  for (string_function_ptr_map::const_iterator e = added_fns_.begin();
10181  e != added_fns_.end();
10182  ++e)
10183  if (is_member_function(e->second)
10184  && get_member_function_is_virtual(e->second))
10185  {
10186  const function_decl *f = e->second;
10187  class_decl_sptr c =
10188  is_class_type(is_method_type(f->get_type())->get_class_type());
10189  ABG_ASSERT(c);
10190  if (type_suppr->suppresses_type(c, ctxt))
10191  suppressed_added_fns_[e->first] = e->second;
10192  }
10193  // Deleted virtual functions
10194  for (string_function_ptr_map::const_iterator e = deleted_fns_.begin();
10195  e != deleted_fns_.end();
10196  ++e)
10197  if (is_member_function(e->second)
10198  && get_member_function_is_virtual(e->second))
10199  {
10200  const function_decl *f = e->second;
10201  class_decl_sptr c =
10202  is_class_type(is_method_type(f->get_type())->get_class_type());
10203  ABG_ASSERT(c);
10204  if (type_suppr->suppresses_type(c, ctxt))
10205  suppressed_deleted_fns_[e->first] = e->second;
10206  }
10207 
10208  // Apply this type suppression to deleted types
10209  // non-reachable from a public interface.
10210  for (string_type_base_sptr_map::const_iterator e =
10211  deleted_unreachable_types_.begin();
10212  e != deleted_unreachable_types_.end();
10213  ++e)
10214  if (type_suppr->suppresses_type(e->second, ctxt))
10215  suppressed_deleted_unreachable_types_[e->first] = e->second;
10216 
10217  // Apply this type suppression to added types
10218  // non-reachable from a public interface.
10219  for (string_type_base_sptr_map::const_iterator e =
10220  added_unreachable_types_.begin();
10221  e != added_unreachable_types_.end();
10222  ++e)
10223  if (type_suppr->suppresses_type(e->second, ctxt))
10224  suppressed_added_unreachable_types_[e->first] = e->second;
10225  }
10226  // Added/Deleted variables
10227  else if (variable_suppression_sptr var_suppr =
10229  {
10230  // Added variables
10231  for (string_var_ptr_map::const_iterator e = added_vars_.begin();
10232  e != added_vars_.end();
10233  ++e)
10234  if (variable_is_suppressed(e->second, var_suppr,
10236  ctxt))
10237  suppressed_added_vars_[e->first] = e->second;
10238 
10239  //Deleted variables
10240  for (string_var_ptr_map::const_iterator e = deleted_vars_.begin();
10241  e != deleted_vars_.end();
10242  ++e)
10243  if (variable_is_suppressed(e->second, var_suppr,
10245  ctxt))
10246  suppressed_deleted_vars_[e->first] = e->second;
10247 
10248  // Added variable symbols not referenced by any debug info
10249  for (string_elf_symbol_map::const_iterator e =
10250  added_unrefed_var_syms_.begin();
10251  e != added_unrefed_var_syms_.end();
10252  ++e)
10253  if (var_suppr->suppresses_variable_symbol(e->second,
10255  ctxt))
10256  suppressed_added_unrefed_var_syms_[e->first] = e->second;
10257 
10258  // Removed variable symbols not referenced by any debug info
10259  for (string_elf_symbol_map::const_iterator e =
10260  deleted_unrefed_var_syms_.begin();
10261  e != deleted_unrefed_var_syms_.end();
10262  ++e)
10263  if (var_suppr->suppresses_variable_symbol(e->second,
10265  ctxt))
10266  suppressed_deleted_unrefed_var_syms_[e->first] = e->second;
10267  }
10268  }
10269 }
10270 
10271 /// Test if the change reports for a given deleted function have
10272 /// been deleted.
10273 ///
10274 /// @param fn the function to consider.
10275 ///
10276 /// @return true iff the change reports for a give given deleted
10277 /// function have been deleted.
10278 bool
10280 {
10281  if (!fn)
10282  return false;
10283 
10284  string_function_ptr_map::const_iterator i =
10285  suppressed_deleted_fns_.find(fn->get_id());
10286 
10287  return (i != suppressed_deleted_fns_.end());
10288 }
10289 
10290 /// Test if an added type that is unreachable from public interface
10291 /// has been suppressed by a suppression specification.
10292 ///
10293 /// @param t the added unreachable type to be considered.
10294 ///
10295 /// @return true iff @p t has been suppressed by a suppression
10296 /// specification.
10297 bool
10299 {
10300  if (!t)
10301  return false;
10302 
10303  string repr = abigail::ir::get_pretty_representation(t, /*internal=*/false);
10304  string_type_base_sptr_map::const_iterator i =
10305  suppressed_added_unreachable_types_.find(repr);
10306  if (i == suppressed_added_unreachable_types_.end())
10307  return false;
10308 
10309  return true;
10310 }
10311 
10312 /// Test if a deleted type that is unreachable from public interface
10313 /// has been suppressed by a suppression specification.
10314 ///
10315 /// @param t the deleted unreachable type to be considered.
10316 ///
10317 /// @return true iff @p t has been suppressed by a suppression
10318 /// specification.
10319 bool
10321 {
10322  if (!t)
10323  return false;
10324 
10325  string repr = abigail::ir::get_pretty_representation(t, /*internal=*/false);
10326  string_type_base_sptr_map::const_iterator i =
10327  suppressed_deleted_unreachable_types_.find(repr);
10328  if (i == suppressed_deleted_unreachable_types_.end())
10329  return false;
10330 
10331  return true;
10332 }
10333 
10334 /// Test if the change reports for a give given added function has
10335 /// been deleted.
10336 ///
10337 /// @param fn the function to consider.
10338 ///
10339 /// @return true iff the change reports for a give given added
10340 /// function has been deleted.
10341 bool
10343 {
10344  if (!fn)
10345  return false;
10346 
10347  string_function_ptr_map::const_iterator i =
10348  suppressed_added_fns_.find(fn->get_id());
10349 
10350  return (i != suppressed_added_fns_.end());
10351 }
10352 
10353 /// Test if the change reports for a give given deleted variable has
10354 /// been deleted.
10355 ///
10356 /// @param var the variable to consider.
10357 ///
10358 /// @return true iff the change reports for a give given deleted
10359 /// variable has been deleted.
10360 bool
10362 {
10363  if (!var)
10364  return false;
10365 
10366  string_var_ptr_map::const_iterator i =
10367  suppressed_deleted_vars_.find(var->get_id());
10368 
10369  return (i != suppressed_deleted_vars_.end());
10370 }
10371 
10372 /// Test if the change reports for a given added variable have been
10373 /// suppressed.
10374 ///
10375 /// @param var the variable to consider.
10376 ///
10377 /// @return true iff the change reports for a given deleted
10378 /// variable has been deleted.
10379 bool
10381 {
10382  if (!var)
10383  return false;
10384 
10385  string_var_ptr_map::const_iterator i =
10386  suppressed_added_vars_.find(var->get_id());
10387 
10388  return (i != suppressed_added_vars_.end());
10389 }
10390 
10391 /// Test if the change reports for a given deleted function symbol
10392 /// (that is not referenced by any debug info) has been suppressed.
10393 ///
10394 /// @param var the function to consider.
10395 ///
10396 /// @return true iff the change reports for a given deleted function
10397 /// symbol has been suppressed.
10398 bool
10400 {
10401  if (!s)
10402  return false;
10403 
10404  string_elf_symbol_map::const_iterator i =
10405  suppressed_deleted_unrefed_fn_syms_.find(s->get_id_string());
10406 
10407  return (i != suppressed_deleted_unrefed_fn_syms_.end());
10408 }
10409 
10410 /// Test if the change reports for a given added function symbol
10411 /// (that is not referenced by any debug info) has been suppressed.
10412 ///
10413 /// @param var the function to consider.
10414 ///
10415 /// @return true iff the change reports for a given added function
10416 /// symbol has been suppressed.
10417 bool
10419 {
10420  if (!s)
10421  return false;
10422 
10423  string_elf_symbol_map::const_iterator i =
10424  suppressed_added_unrefed_fn_syms_.find(s->get_id_string());
10425 
10426  return (i != suppressed_added_unrefed_fn_syms_.end());
10427 }
10428 
10429 /// Test if the change reports for a given deleted variable symbol
10430 /// (that is not referenced by any debug info) has been suppressed.
10431 ///
10432 /// @param var the variable to consider.
10433 ///
10434 /// @return true iff the change reports for a given deleted variable
10435 /// symbol has been suppressed.
10436 bool
10438 {
10439  if (!s)
10440  return false;
10441 
10442  string_elf_symbol_map::const_iterator i =
10443  suppressed_deleted_unrefed_var_syms_.find(s->get_id_string());
10444 
10445  return (i != suppressed_deleted_unrefed_var_syms_.end());
10446 }
10447 
10448 /// Test if the change reports for a given added variable symbol
10449 /// (that is not referenced by any debug info) has been suppressed.
10450 ///
10451 /// @param var the variable to consider.
10452 ///
10453 /// @return true iff the change reports for a given added variable
10454 /// symbol has been suppressed.
10455 bool
10457 {
10458  if (!s)
10459  return false;
10460 
10461  string_elf_symbol_map::const_iterator i =
10462  suppressed_added_unrefed_var_syms_.find(s->get_id_string());
10463 
10464  return (i != suppressed_added_unrefed_var_syms_.end());
10465 }
10466 
10467 #ifdef do_count_diff_map_changes
10468 #undef do_count_diff_map_changes
10469 #endif
10470 #define do_count_diff_map_changes(diff_map, n_changes, n_filtered) \
10471  { \
10472  string_diff_ptr_map::const_iterator i; \
10473  for (i = diff_map.begin(); \
10474  i != diff_map.end(); \
10475  ++i) \
10476  { \
10477  if (const var_diff* d = is_var_diff(i->second)) \
10478  if (is_data_member(d->first_var())) \
10479  continue; \
10480  \
10481  if (i->second->has_local_changes()) \
10482  ++n_changes; \
10483  if (!i->second->get_canonical_diff()->to_be_reported()) \
10484  ++n_filtered; \
10485  } \
10486  }
10487 
10488 /// Count the number of leaf changes as well as the number of the
10489 /// changes that have been filtered out.
10490 ///
10491 /// @param num_changes out parameter. This is set to the total number
10492 /// of leaf changes.
10493 ///
10494 /// @param num_filtered out parameter. This is set to the number of
10495 /// leaf changes that have been filtered out.
10496 void
10497 corpus_diff::priv::count_leaf_changes(size_t &num_changes, size_t &num_filtered)
10498 {
10499  count_leaf_type_changes(num_changes, num_filtered);
10500 
10501  // Now count the non-type changes.
10502  do_count_diff_map_changes(leaf_diffs_.get_function_decl_diff_map(),
10503  num_changes, num_filtered);
10504  do_count_diff_map_changes(leaf_diffs_.get_var_decl_diff_map(),
10505  num_changes, num_filtered);
10506 }
10507 
10508 /// Count the number of leaf *type* changes as well as the number of
10509 /// the leaf type changes that have been filtered out.
10510 ///
10511 /// @param num_changes out parameter. This is set to the total number
10512 /// of leaf type changes.
10513 ///
10514 /// @param num_filtered out parameter. This is set to the number of
10515 /// leaf type changes that have been filtered out.
10516 void
10518  size_t &num_filtered)
10519 {
10520  do_count_diff_map_changes(leaf_diffs_.get_type_decl_diff_map(),
10521  num_changes, num_filtered);
10522  do_count_diff_map_changes(leaf_diffs_.get_enum_diff_map(),
10523  num_changes, num_filtered);
10524  do_count_diff_map_changes(leaf_diffs_.get_class_diff_map(),
10525  num_changes, num_filtered);
10526  do_count_diff_map_changes(leaf_diffs_.get_union_diff_map(),
10527  num_changes, num_filtered);
10528  do_count_diff_map_changes(leaf_diffs_.get_typedef_diff_map(),
10529  num_changes, num_filtered);
10530  do_count_diff_map_changes(leaf_diffs_.get_subrange_diff_map(),
10531  num_changes, num_filtered);
10532  do_count_diff_map_changes(leaf_diffs_.get_array_diff_map(),
10533  num_changes, num_filtered);
10534  do_count_diff_map_changes(leaf_diffs_.get_distinct_diff_map(),
10535  num_changes, num_filtered);
10536  do_count_diff_map_changes(leaf_diffs_.get_fn_parm_diff_map(),
10537  num_changes, num_filtered);
10538 }
10539 
10540 /// Count the number of types not reachable from the interface (i.e,
10541 /// not reachable from global functions or variables).
10542 ///
10543 /// @param num_added this is set to the number of added types not
10544 /// reachable from the interface.
10545 ///
10546 /// @param num_deleted this is set to the number of deleted types not
10547 /// reachable from the interface.
10548 ///
10549 /// @param num_changed this is set to the number of changed types not
10550 /// reachable from the interface.
10551 ///
10552 /// @param num_filtered_added this is set to the number of added types
10553 /// not reachable from the interface and that have been filtered out
10554 /// by suppression specifications.
10555 ///
10556 /// @param num_filtered_deleted this is set to the number of deleted
10557 /// types not reachable from the interface and that have been filtered
10558 /// out by suppression specifications.
10559 ///
10560 /// @param num_filtered_changed this is set to the number of changed
10561 /// types not reachable from the interface and that have been filtered
10562 /// out by suppression specifications.
10563 void
10565  size_t &num_deleted,
10566  size_t &num_changed,
10567  size_t &num_filtered_added,
10568  size_t &num_filtered_deleted,
10569  size_t &num_filtered_changed)
10570 {
10571  num_added = added_unreachable_types_.size();
10572  num_deleted = deleted_unreachable_types_.size();
10573  num_changed = changed_unreachable_types_.size();
10574  num_filtered_added = suppressed_added_unreachable_types_.size();
10575  num_filtered_deleted = suppressed_deleted_unreachable_types_.size();
10576 
10577  for (vector<diff_sptr>::const_iterator i =
10579  i != changed_unreachable_types_sorted().end();
10580  ++i)
10581  if (!(*i)->to_be_reported())
10582  ++num_filtered_changed;
10583 }
10584 
10585 /// Get the map of diff nodes representing changed unreachable types.
10586 ///
10587 /// @return the map of diff nodes representing changed unreachable
10588 /// types.
10589 const string_diff_sptr_map&
10591 {return changed_unreachable_types_;}
10592 
10593 /// Get the sorted vector of diff nodes representing changed
10594 /// unreachable types.
10595 ///
10596 /// Upon the first invocation of this method, if the vector is empty,
10597 /// this function gets the diff nodes representing changed
10598 /// unreachable, sort them, and return the sorted vector.
10599 ///
10600 /// @return the sorted vector of diff nodes representing changed
10601 /// unreachable types.
10602 const vector<diff_sptr>&
10604 {
10605 if (changed_unreachable_types_sorted_.empty())
10606  if (!changed_unreachable_types_.empty())
10607  sort_string_diff_sptr_map(changed_unreachable_types_,
10608  changed_unreachable_types_sorted_);
10609 
10610  return changed_unreachable_types_sorted_;
10611 }
10612 
10613 /// Compute the diff stats.
10614 ///
10615 /// To know the number of functions that got filtered out, this
10616 /// function applies the categorizing filters to the diff sub-trees of
10617 /// each function changes diff, prior to calculating the stats.
10618 ///
10619 /// @param num_removed the number of removed functions.
10620 ///
10621 /// @param num_added the number of added functions.
10622 ///
10623 /// @param num_changed the number of changed functions.
10624 ///
10625 /// @param num_filtered_out the number of changed functions that are
10626 /// got filtered out from the report
10627 void
10629 {
10630  stat.num_func_removed(deleted_fns_.size());
10631  stat.num_removed_func_filtered_out(suppressed_deleted_fns_.size());
10632  stat.num_func_added(added_fns_.size());
10633  stat.num_added_func_filtered_out(suppressed_added_fns_.size());
10634  stat.num_func_changed(changed_fns_map_.size());
10635 
10636  stat.num_vars_removed(deleted_vars_.size());
10637  stat.num_removed_vars_filtered_out(suppressed_deleted_vars_.size());
10638  stat.num_vars_added(added_vars_.size());
10639  stat.num_added_vars_filtered_out(suppressed_added_vars_.size());
10640  stat.num_vars_changed(changed_vars_map_.size());
10641 
10642  diff_context_sptr ctxt = get_context();
10643 
10645  if (ctxt->perform_change_categorization())
10646  {
10647  if (get_context()->do_log())
10648  {
10649  std::cerr << "in apply_filters_and_compute_diff_stats:"
10650  << "applying filters to "
10651  << changed_fns_.size()
10652  << " changed fns ...\n";
10653  t.start();
10654  }
10655  // Walk the changed function diff nodes to apply the categorization
10656  // filters.
10657  diff_sptr diff;
10658  for (function_decl_diff_sptrs_type::const_iterator i =
10659  changed_fns_.begin();
10660  i != changed_fns_.end();
10661  ++i)
10662  {
10663  diff_sptr diff = *i;
10664  ctxt->maybe_apply_filters(diff);
10665  }
10666 
10667  if (get_context()->do_log())
10668  {
10669  t.stop();
10670  std::cerr << "in apply_filters_and_compute_diff_stats:"
10671  << "filters to changed fn applied!:" << t << "\n";
10672 
10673  std::cerr << "in apply_filters_and_compute_diff_stats:"
10674  << "applying filters to "
10675  << sorted_changed_vars_.size()
10676  << " changed vars ...\n";
10677  t.start();
10678  }
10679 
10680  // Walk the changed variable diff nodes to apply the categorization
10681  // filters.
10682  for (var_diff_sptrs_type::const_iterator i = sorted_changed_vars_.begin();
10683  i != sorted_changed_vars_.end();
10684  ++i)
10685  {
10686  diff_sptr diff = *i;
10687  ctxt->maybe_apply_filters(diff);
10688  }
10689 
10690  if (get_context()->do_log())
10691  {
10692  t.stop();
10693  std::cerr << "in apply_filters_and_compute_diff_stats:"
10694  << "filters to changed vars applied!:" << t << "\n";
10695 
10696  std::cerr << "in apply_filters_and_compute_diff_stats:"
10697  << "applying filters to unreachable types ...\n";
10698  t.start();
10699  }
10700 
10701  // walk the changed unreachable types to apply categorization
10702  // filters
10703  for (auto& diff : changed_unreachable_types_sorted())
10704  ctxt->maybe_apply_filters(diff);
10705 
10706  for (auto& entry : changed_unreachable_types())
10707  ctxt->maybe_apply_filters(entry.second);
10708 
10709  if (get_context()->do_log())
10710  {
10711  t.stop();
10712  std::cerr << "in apply_filters_and_compute_diff_stats:"
10713  << "filters to unreachable types applied!:" << t << "\n";
10714 
10715  std::cerr << "in apply_filters_and_compute_diff_stats:"
10716  << "categorizing redundant changed sub nodes ...\n";
10717  t.start();
10718  }
10719 
10720  categorize_redundant_changed_sub_nodes();
10721 
10722  if (get_context()->do_log())
10723  {
10724  t.stop();
10725  std::cerr << "in apply_filters_and_compute_diff_stats:"
10726  << "redundant changed sub nodes categorized!:" << t << "\n";
10727 
10728  std::cerr << "in apply_filters_and_compute_diff_stats:"
10729  << "count changed fns ...\n";
10730  t.start();
10731  }
10732  }
10733 
10734  // Walk the changed function diff nodes to count the number of
10735  // filtered-out functions and the number of functions with virtual
10736  // offset changes.
10737  for (function_decl_diff_sptrs_type::const_iterator i =
10738  changed_fns_.begin();
10739  i != changed_fns_.end();
10740  ++i)
10741  {
10742  if ((*i)->is_filtered_out())
10743  {
10745  (stat.num_changed_func_filtered_out() + 1);
10746 
10747  if ((*i)->has_local_changes())
10750  }
10751  else
10752  {
10753  if ((*i)->get_category() & VIRTUAL_MEMBER_CHANGE_CATEGORY)
10756  }
10757 
10758  if ((*i)->has_local_changes())
10760  (stat.num_leaf_func_changes() + 1);
10761  }
10762 
10763  if (get_context()->do_log())
10764  {
10765  t.stop();
10766  std::cerr << "in apply_filters_and_compute_diff_stats:"
10767  << "changed fn counted!:" << t << "\n";
10768 
10769  std::cerr << "in apply_filters_and_compute_diff_stats:"
10770  << "count changed vars ...\n";
10771  t.start();
10772  }
10773 
10774  // Walk the changed variables diff nodes to count the number of
10775  // filtered-out variables.
10776  for (var_diff_sptrs_type ::const_iterator i = sorted_changed_vars_.begin();
10777  i != sorted_changed_vars_.end();
10778  ++i)
10779  {
10780  if ((*i)->is_filtered_out())
10781  {
10783  (stat.num_changed_vars_filtered_out() + 1);
10784 
10785  if ((*i)->has_local_changes())
10787  (stat.num_leaf_var_changes_filtered_out() + 1);
10788  }
10789  if ((*i)->has_local_changes())
10791  (stat.num_leaf_var_changes() + 1);
10792  }
10793 
10794  if (get_context()->do_log())
10795  {
10796  t.stop();
10797  std::cerr << "in apply_filters_and_compute_diff_stats:"
10798  << "changed vars counted!:" << t << "\n";
10799 
10800  std::cerr << "in apply_filters_and_compute_diff_stats:"
10801  << "count leaf changed types ...\n";
10802  t.start();
10803  }
10804 
10805  stat.num_func_syms_added(added_unrefed_fn_syms_.size());
10806  stat.num_added_func_syms_filtered_out(suppressed_added_unrefed_fn_syms_.size());
10807  stat.num_func_syms_removed(deleted_unrefed_fn_syms_.size());
10808  stat.num_removed_func_syms_filtered_out(suppressed_deleted_unrefed_fn_syms_.size());
10809  stat.num_var_syms_added(added_unrefed_var_syms_.size());
10810  stat.num_added_var_syms_filtered_out(suppressed_added_unrefed_var_syms_.size());
10811  stat.num_var_syms_removed(deleted_unrefed_var_syms_.size());
10812  stat.num_removed_var_syms_filtered_out(suppressed_deleted_unrefed_var_syms_.size());
10813 
10814  // Walk the general leaf type diff nodes to count them
10815  {
10816  size_t num_type_changes = 0, num_type_filtered = 0;
10817  count_leaf_type_changes(num_type_changes, num_type_filtered);
10818 
10819  stat.num_leaf_type_changes(num_type_changes);
10820  stat.num_leaf_type_changes_filtered_out(num_type_filtered);
10821  }
10822 
10823  if (get_context()->do_log())
10824  {
10825  t.stop();
10826  std::cerr << "in apply_filters_and_compute_diff_stats:"
10827  << "changed leaf types counted!:" << t << "\n";
10828 
10829  std::cerr << "in apply_filters_and_compute_diff_stats:"
10830  << "count leaf changed artefacts ...\n";
10831  t.start();
10832  }
10833 
10834  // Walk the general leaf artefacts diff nodes to count them
10835  {
10836  size_t num_changes = 0, num_filtered = 0;
10837  count_leaf_changes(num_changes, num_filtered);
10838 
10839  stat.num_leaf_changes(num_changes);
10840  stat.num_leaf_changes_filtered_out(num_filtered);
10841  }
10842 
10843  if (get_context()->do_log())
10844  {
10845  t.stop();
10846  std::cerr << "in apply_filters_and_compute_diff_stats:"
10847  << "changed leaf artefacts counted!:" << t << "\n";
10848 
10849  std::cerr << "in apply_filters_and_compute_diff_stats:"
10850  << "count unreachable types ...\n";
10851  t.start();
10852  }
10853 
10854  // Walk the unreachable types to count them
10855  {
10856  size_t num_added_unreachable_types = 0,
10857  num_changed_unreachable_types = 0,
10858  num_deleted_unreachable_types = 0,
10859  num_added_unreachable_types_filtered = 0,
10860  num_changed_unreachable_types_filtered = 0,
10861  num_deleted_unreachable_types_filtered = 0;
10862 
10863  count_unreachable_types(num_added_unreachable_types,
10864  num_deleted_unreachable_types,
10865  num_changed_unreachable_types,
10866  num_added_unreachable_types_filtered,
10867  num_deleted_unreachable_types_filtered,
10868  num_changed_unreachable_types_filtered);
10869 
10870  if (get_context()->do_log())
10871  {
10872  t.stop();
10873  std::cerr << "in apply_filters_and_compute_diff_stats:"
10874  << "unreachable types counted!:" << t << "\n";
10875  }
10876 
10877  stat.num_added_unreachable_types(num_added_unreachable_types);
10878  stat.num_removed_unreachable_types(num_deleted_unreachable_types);
10879  stat.num_changed_unreachable_types(num_changed_unreachable_types);
10881  (num_added_unreachable_types_filtered);
10883  (num_deleted_unreachable_types_filtered);
10885  (num_changed_unreachable_types_filtered);
10886  }
10887 }
10888 
10889 /// Emit the summary of the functions & variables that got
10890 /// removed/changed/added.
10891 ///
10892 /// TODO: This should be handled by the reporters, just like what is
10893 /// done for reporter_base::diff_to_be_reported.
10894 ///
10895 /// @param out the output stream to emit the stats to.
10896 ///
10897 /// @param indent the indentation string to use in the summary.
10898 void
10900  ostream& out,
10901  const string& indent)
10902 {
10903  /// Report added/removed/changed functions.
10904  size_t net_num_leaf_changes =
10905  s.net_num_func_removed() +
10906  s.net_num_func_added() +
10908  s.net_num_vars_removed() +
10909  s.net_num_vars_added() +
10916 
10917  if (!sonames_equal_)
10918  out << indent << "ELF SONAME changed\n";
10919 
10920  if (!architectures_equal_)
10921  out << indent << "ELF architecture changed\n";
10922 
10923  diff_context_sptr ctxt = get_context();
10924 
10925  if (ctxt->show_leaf_changes_only())
10926  {
10927  out << "Leaf changes summary: ";
10928  out << net_num_leaf_changes << " artifact";
10929  if (net_num_leaf_changes > 1)
10930  out << "s";
10931  out << " changed";
10932 
10933  if (size_t num_filtered = s.num_leaf_changes_filtered_out())
10934  out << " (" << num_filtered << " filtered out)";
10935  out << "\n";
10936 
10937  out << indent << "Changed leaf types summary: "
10940  out << " (" << s.num_leaf_type_changes_filtered_out()
10941  << " filtered out)";
10942  out << " leaf type";
10943  if (s.num_leaf_type_changes() > 1)
10944  out << "s";
10945  out << " changed\n";
10946 
10947  // function changes summary
10948  out << indent << "Removed/Changed/Added functions summary: ";
10949  out << s.net_num_func_removed() << " Removed";
10951  out << " ("
10953  << " filtered out)";
10954  out << ", ";
10955 
10956  out << s.net_num_leaf_func_changes() << " Changed";
10958  out << " ("
10960  << " filtered out)";
10961  out << ", ";
10962 
10963  out << s.net_num_func_added()<< " Added ";
10964  if (s.net_num_func_added() <= 1)
10965  out << "function";
10966  else
10967  out << "functions";
10969  out << " (" << s.num_added_func_filtered_out() << " filtered out)";
10970  out << "\n";
10971 
10972  // variables changes summary
10973  out << indent << "Removed/Changed/Added variables summary: ";
10974  out << s.net_num_vars_removed() << " Removed";
10976  out << " (" << s.num_removed_vars_filtered_out()
10977  << " filtered out)";
10978  out << ", ";
10979 
10980  out << s.net_num_leaf_var_changes() << " Changed";
10982  out << " ("
10984  << " filtered out)";
10985  out << ", ";
10986 
10987  out << s.net_num_vars_added() << " Added ";
10988  if (s.net_num_vars_added() <= 1)
10989  out << "variable";
10990  else
10991  out << "variables";
10993  out << " (" << s.num_added_vars_filtered_out()
10994  << " filtered out)";
10995  out << "\n";
10996  }
10997  else // if (ctxt->show_leaf_changes_only())
10998  {
10999  size_t total_nb_function_changes = s.num_func_removed()
11000  + s.num_func_changed() + s.num_func_added();
11001 
11002  // function changes summary
11003  out << indent << "Functions changes summary: ";
11004  out << s.net_num_func_removed() << " Removed";
11006  out << " ("
11008  << " filtered out)";
11009  out << ", ";
11010 
11011  out << s.net_num_func_changed() << " Changed";
11013  out << " (" << s.num_changed_func_filtered_out() << " filtered out)";
11014  out << ", ";
11015 
11016  out << s.net_num_func_added() << " Added";
11018  out << " (" << s.num_added_func_filtered_out() << " filtered out)";
11019  if (total_nb_function_changes <= 1)
11020  out << " function";
11021  else
11022  out << " functions";
11023  out << "\n";
11024 
11025  // variables changes summary
11026  size_t total_nb_variable_changes = s.num_vars_removed()
11027  + s.num_vars_changed() + s.num_vars_added();
11028 
11029  out << indent << "Variables changes summary: ";
11030  out << s.net_num_vars_removed() << " Removed";
11032  out << " (" << s.num_removed_vars_filtered_out()
11033  << " filtered out)";
11034  out << ", ";
11035 
11036  out << s.num_vars_changed() - s.num_changed_vars_filtered_out() << " Changed";
11038  out << " (" << s.num_changed_vars_filtered_out() << " filtered out)";
11039  out << ", ";
11040 
11041  out << s.net_num_vars_added() << " Added";
11043  out << " (" << s.num_added_vars_filtered_out()
11044  << " filtered out)";
11045  if (total_nb_variable_changes <= 1)
11046  out << " variable";
11047  else
11048  out << " variables";
11049  out << "\n";
11050  }
11051 
11052  // Show statistics about types not reachable from global
11053  // functions/variables.
11054  if (ctxt->show_unreachable_types())
11055  {
11056  size_t total_nb_unreachable_type_changes =
11060 
11061  // Show summary of unreachable types
11062  out << indent << "Unreachable types summary: "
11064  << " removed";
11067  << " filtered out)";
11068  out << ", ";
11069 
11071  << " changed";
11074  << " filtered out)";
11075  out << ", ";
11076 
11078  << " added";
11080  out << " (" << s.num_added_unreachable_types_filtered_out()
11081  << " filtered out)";
11082  if (total_nb_unreachable_type_changes <= 1)
11083  out << " type";
11084  else
11085  out << " types";
11086  out << "\n";
11087  }
11088 
11089  if (ctxt->show_symbols_unreferenced_by_debug_info()
11090  && (s.num_func_syms_removed()
11091  || s.num_func_syms_added()
11092  || s.num_var_syms_removed()
11093  || s.num_var_syms_added()))
11094  {
11095  // function symbols changes summary.
11096 
11097  if (!ctxt->show_added_symbols_unreferenced_by_debug_info()
11098  && s.num_func_syms_removed() == 0
11099  && s.num_func_syms_added() != 0)
11100  // If the only unreferenced function symbol change is function
11101  // syms that got added, but we were forbidden to show function
11102  // syms being added, do nothing.
11103  ;
11104  else
11105  {
11106  out << indent
11107  << "Function symbols changes summary: "
11108  << s.net_num_removed_func_syms() << " Removed";
11110  out << " (" << s.num_removed_func_syms_filtered_out()
11111  << " filtered out)";
11112  out << ", ";
11113  out << s.net_num_added_func_syms() << " Added";
11115  out << " (" << s.num_added_func_syms_filtered_out()
11116  << " filtered out)";
11117  out << " function symbol";
11118  if (s.num_func_syms_added() + s.num_func_syms_removed() > 1)
11119  out << "s";
11120  out << " not referenced by debug info\n";
11121  }
11122 
11123  // variable symbol changes summary.
11124 
11125  if (!ctxt->show_added_symbols_unreferenced_by_debug_info()
11126  && s.num_var_syms_removed() == 0
11127  && s.num_var_syms_added() != 0)
11128  // If the only unreferenced variable symbol change is variable
11129  // syms that got added, but we were forbidden to show variable
11130  // syms being added, do nothing.
11131  ;
11132  else
11133  {
11134  out << indent
11135  << "Variable symbols changes summary: "
11136  << s.net_num_removed_var_syms() << " Removed";
11138  out << " (" << s.num_removed_var_syms_filtered_out()
11139  << " filtered out)";
11140  out << ", ";
11141  out << s.net_num_added_var_syms() << " Added";
11143  out << " (" << s.num_added_var_syms_filtered_out()
11144  << " filtered out)";
11145  out << " variable symbol";
11146  if (s.num_var_syms_added() + s.num_var_syms_removed() > 1)
11147  out << "s";
11148  out << " not referenced by debug info\n";
11149  }
11150  }
11151 }
11152 
11153 /// Walk the changed functions and variables diff nodes to categorize
11154 /// redundant nodes.
11155 void
11157 {
11158  diff_sptr diff;
11159 
11160  diff_context_sptr ctxt = get_context();
11161 
11162  ctxt->forget_visited_diffs();
11163  for (function_decl_diff_sptrs_type::const_iterator i =
11164  changed_fns_.begin();
11165  i!= changed_fns_.end();
11166  ++i)
11167  {
11168  diff = *i;
11170  }
11171 
11172  for (var_diff_sptrs_type::const_iterator i = sorted_changed_vars_.begin();
11173  i!= sorted_changed_vars_.end();
11174  ++i)
11175  {
11176  diff_sptr diff = *i;
11178  }
11179 
11180  for (diff_sptrs_type::const_iterator i =
11183  ++i)
11184  {
11185  diff_sptr diff = *i;
11187  }
11188 }
11189 
11190 /// Walk the changed functions and variables diff nodes and clear the
11191 /// redundancy categorization they might carry.
11192 void
11194 {
11195  diff_sptr diff;
11196  for (function_decl_diff_sptrs_type::const_iterator i = changed_fns_.begin();
11197  i!= changed_fns_.end();
11198  ++i)
11199  {
11200  diff = *i;
11202  }
11203 
11204  for (var_diff_sptrs_type::const_iterator i = sorted_changed_vars_.begin();
11205  i!= sorted_changed_vars_.end();
11206  ++i)
11207  {
11208  diff = *i;
11210  }
11211 }
11212 
11213 /// If the user asked to dump the diff tree node (for changed
11214 /// variables and functions) on the error output stream, then just do
11215 /// that.
11216 ///
11217 /// This function is used for debugging purposes.
11218 void
11220 {
11221  diff_context_sptr ctxt = get_context();
11222 
11223  if (!ctxt->dump_diff_tree()
11224  || ctxt->error_output_stream() == 0)
11225  return;
11226 
11227  if (!changed_fns_.empty())
11228  {
11229  *ctxt->error_output_stream() << "changed functions diff tree: \n\n";
11230  for (function_decl_diff_sptrs_type::const_iterator i =
11231  changed_fns_.begin();
11232  i != changed_fns_.end();
11233  ++i)
11234  {
11235  diff_sptr d = *i;
11236  print_diff_tree(d, *ctxt->error_output_stream());
11237  }
11238  }
11239 
11240  if (!sorted_changed_vars_.empty())
11241  {
11242  *ctxt->error_output_stream() << "\nchanged variables diff tree: \n\n";
11243  for (var_diff_sptrs_type::const_iterator i =
11244  sorted_changed_vars_.begin();
11245  i != sorted_changed_vars_.end();
11246  ++i)
11247  {
11248  diff_sptr d = *i;
11249  print_diff_tree(d, *ctxt->error_output_stream());
11250  }
11251  }
11252 
11253  if (!changed_unreachable_types_sorted().empty())
11254  {
11255  *ctxt->error_output_stream() << "\nchanged unreachable "
11256  "types diff tree: \n\n";
11257  for (vector<diff_sptr>::const_iterator i =
11259  i != changed_unreachable_types_sorted().end();
11260  ++i)
11261  {
11262  diff_sptr d = *i;
11263  print_diff_tree(d, *ctxt->error_output_stream());
11264  }
11265  }
11266 }
11267 
11268 /// Populate the vector of children node of the @ref corpus_diff type.
11269 ///
11270 /// The children node can then later be retrieved using
11271 /// corpus_diff::children_node().
11272 void
11274 {
11275  for (function_decl_diff_sptrs_type::const_iterator i =
11276  changed_functions_sorted().begin();
11277  i != changed_functions_sorted().end();
11278  ++i)
11279  if (diff_sptr d = *i)
11280  append_child_node(d);
11281 }
11282 
11283 /// Constructor for @ref corpus_diff.
11284 ///
11285 /// @param first the first corpus of the diff.
11286 ///
11287 /// @param second the second corpus of the diff.
11288 ///
11289 /// @param ctxt the diff context to use. Note that this context
11290 /// object must stay alive at least during the life time of the
11291 /// current instance of @ref corpus_diff. Otherwise memory corruption
11292 /// issues occur.
11293 corpus_diff::corpus_diff(corpus_sptr first,
11294  corpus_sptr second,
11295  diff_context_sptr ctxt)
11296  : priv_(new priv(first, second, ctxt))
11297 {}
11298 
11299 corpus_diff::~corpus_diff() = default;
11300 
11301 /// Finish building the current instance of @ref corpus_diff.
11302 void
11304 {
11305  if (priv_->finished_)
11306  return;
11308  priv_->finished_ = true;
11309 }
11310 
11311 /// Test if logging was requested.
11312 ///
11313 /// @return true iff logging was requested.
11314 bool
11316 {return context()->do_log();}
11317 
11318 /// Request logging, or not.
11319 ///
11320 /// @param f true iff logging is requested.
11321 void
11323 {context()->do_log(f);}
11324 
11325 /// @return the first corpus of the diff.
11326 corpus_sptr
11328 {return priv_->first_;}
11329 
11330 /// @return the second corpus of the diff.
11331 corpus_sptr
11333 {return priv_->second_;}
11334 
11335 /// @return the children nodes of the current instance of corpus_diff.
11336 const vector<diff*>&
11338 {return priv_->children_;}
11339 
11340 /// Append a new child node to the vector of children nodes for the
11341 /// current instance of @ref corpus_diff node.
11342 ///
11343 /// Note that the vector of children nodes for the current instance of
11344 /// @ref corpus_diff node must remain sorted, using
11345 /// diff_less_than_functor.
11346 ///
11347 /// @param d the new child node. Note that the life time of the
11348 /// object held by @p d will thus equal the life time of the current
11349 /// instance of @ref corpus_diff.
11350 void
11352 {
11353  ABG_ASSERT(d);
11354 
11356  bool inserted = false;
11357  for (vector<diff*>::iterator i = priv_->children_.begin();
11358  i != priv_->children_.end();
11359  ++i)
11360  // Look for the point where to insert the diff child node.
11361  if (!is_less_than(d.get(), *i))
11362  {
11363  context()->keep_diff_alive(d);
11364  priv_->children_.insert(i, d.get());
11365  // As we have just inserted 'd' into the vector, the iterator
11366  // 'i' is invalidated. We must *NOT* use it anymore.
11367  inserted = true;
11368  break;
11369  }
11370 
11371  if (!inserted)
11372  {
11373  context()->keep_diff_alive(d);
11374  // We didn't insert anything to the vector, presumably b/c it was
11375  // empty or had one element that was "less than" 'd'. We can thus
11376  // just append 'd' to the end of the vector.
11377  priv_->children_.push_back(d.get());
11378  }
11379 }
11380 
11381 /// @return the bare edit script of the functions changed as recorded
11382 /// by the diff.
11383 edit_script&
11385 {return priv_->fns_edit_script_;}
11386 
11387 /// @return the bare edit script of the variables changed as recorded
11388 /// by the diff.
11389 edit_script&
11391 {return priv_->vars_edit_script_;}
11392 
11393 /// Test if the soname of the underlying corpus has changed.
11394 ///
11395 /// @return true iff the soname has changed.
11396 bool
11398 {return !priv_->sonames_equal_;}
11399 
11400 /// Test if the architecture of the underlying corpus has changed.
11401 ///
11402 /// @return true iff the architecture has changed.
11403 bool
11405 {return !priv_->architectures_equal_;}
11406 
11407 /// Getter for the deleted functions of the diff.
11408 ///
11409 /// @return the the deleted functions of the diff.
11412 {return priv_->deleted_fns_;}
11413 
11414 /// Getter for the added functions of the diff.
11415 ///
11416 /// @return the added functions of the diff.
11419 {return priv_->added_fns_;}
11420 
11421 /// Getter for the functions which signature didn't change, but which
11422 /// do have some indirect changes in their parms.
11423 ///
11424 /// @return a non-sorted map of functions which signature didn't
11425 /// change, but which do have some indirect changes in their parms.
11426 /// The key of the map is a unique identifier for the function; it's
11427 /// usually made of the name and version of the underlying ELF symbol
11428 /// of the function for corpora that were built from ELF files.
11431 {return priv_->changed_fns_map_;}
11432 
11433 /// Getter for a sorted vector of functions which signature didn't
11434 /// change, but which do have some indirect changes in their parms.
11435 ///
11436 /// @return a sorted vector of functions which signature didn't
11437 /// change, but which do have some indirect changes in their parms.
11440 {return priv_->changed_fns_;}
11441 
11442 /// Getter for the variables that got deleted from the first subject
11443 /// of the diff.
11444 ///
11445 /// @return the map of deleted variable.
11446 const string_var_ptr_map&
11448 {return priv_->deleted_vars_;}
11449 
11450 /// Getter for the added variables of the diff.
11451 ///
11452 /// @return the map of added variable.
11453 const string_var_ptr_map&
11455 {return priv_->added_vars_;}
11456 
11457 /// Getter for the non-sorted map of variables which signature didn't
11458 /// change but which do have some indirect changes in some sub-types.
11459 ///
11460 /// @return the non-sorted map of changed variables.
11463 {return priv_->changed_vars_map_;}
11464 
11465 /// Getter for the sorted vector of variables which signature didn't
11466 /// change but which do have some indirect changes in some sub-types.
11467 ///
11468 /// @return a sorted vector of changed variables.
11469 const var_diff_sptrs_type&
11471 {return priv_->sorted_changed_vars_;}
11472 
11473 /// Getter for function symbols not referenced by any debug info and
11474 /// that got deleted.
11475 ///
11476 /// @return a map of elf function symbols not referenced by any debug
11477 /// info and that got deleted.
11478 const string_elf_symbol_map&
11480 {return priv_->deleted_unrefed_fn_syms_;}
11481 
11482 /// Getter for function symbols not referenced by any debug info and
11483 /// that got added.
11484 ///
11485 /// @return a map of elf function symbols not referenced by any debug
11486 /// info and that got added.
11487 const string_elf_symbol_map&
11489 {return priv_->added_unrefed_fn_syms_;}
11490 
11491 /// Getter for variable symbols not referenced by any debug info and
11492 /// that got deleted.
11493 ///
11494 /// @return a map of elf variable symbols not referenced by any debug
11495 /// info and that got deleted.
11496 const string_elf_symbol_map&
11498 {return priv_->deleted_unrefed_var_syms_;}
11499 
11500 /// Getter for variable symbols not referenced by any debug info and
11501 /// that got added.
11502 ///
11503 /// @return a map of elf variable symbols not referenced by any debug
11504 /// info and that got added.
11505 const string_elf_symbol_map&
11507 {return priv_->added_unrefed_var_syms_;}
11508 
11509 /// Getter for a map of deleted types that are not reachable from
11510 /// global functions/variables.
11511 ///
11512 /// @return a map that associates pretty representation of deleted
11513 /// unreachable types and said types.
11516 {return priv_->deleted_unreachable_types_;}
11517 
11518 /// Getter of a sorted vector of deleted types that are not reachable
11519 /// from global functions/variables.
11520 ///
11521 /// @return a sorted vector of deleted types that are not reachable
11522 /// from global functions/variables. The types are lexicographically
11523 /// sorted by considering their pretty representation.
11524 const vector<type_base_sptr>&
11526 {
11527  if (priv_->deleted_unreachable_types_sorted_.empty())
11528  if (!priv_->deleted_unreachable_types_.empty())
11529  sort_string_type_base_sptr_map(priv_->deleted_unreachable_types_,
11530  priv_->deleted_unreachable_types_sorted_);
11531 
11532  return priv_->deleted_unreachable_types_sorted_;
11533 }
11534 
11535 /// Getter for a map of added types that are not reachable from global
11536 /// functions/variables.
11537 ///
11538 /// @return a map that associates pretty representation of added
11539 /// unreachable types and said types.
11542 {return priv_->added_unreachable_types_;}
11543 
11544 /// Getter of a sorted vector of added types that are not reachable
11545 /// from global functions/variables.
11546 ///
11547 /// @return a sorted vector of added types that are not reachable from
11548 /// global functions/variables. The types are lexicographically
11549 /// sorted by considering their pretty representation.
11550 const vector<type_base_sptr>&
11552 {
11553  if (priv_->added_unreachable_types_sorted_.empty())
11554  if (!priv_->added_unreachable_types_.empty())
11555  sort_string_type_base_sptr_map(priv_->added_unreachable_types_,
11556  priv_->added_unreachable_types_sorted_);
11557 
11558  return priv_->added_unreachable_types_sorted_;
11559 }
11560 
11561 /// Getter for a map of changed types that are not reachable from
11562 /// global functions/variables.
11563 ///
11564 /// @return a map that associates pretty representation of changed
11565 /// unreachable types and said types.
11566 const string_diff_sptr_map&
11568 {return priv_->changed_unreachable_types_;}
11569 
11570 /// Getter of a sorted vector of changed types that are not reachable
11571 /// from global functions/variables.
11572 ///
11573 /// @return a sorted vector of changed types that are not reachable
11574 /// from global functions/variables. The diffs are lexicographically
11575 /// sorted by considering their pretty representation.
11576 const vector<diff_sptr>&
11578 {return priv_->changed_unreachable_types_sorted();}
11579 
11580 /// Getter of the diff context of this diff
11581 ///
11582 /// @return the diff context for this diff.
11583 const diff_context_sptr
11585 {return priv_->get_context();}
11586 
11587 /// @return the pretty representation for the current instance of @ref
11588 /// corpus_diff
11589 const string&
11591 {
11592  if (priv_->pretty_representation_.empty())
11593  {
11594  std::ostringstream o;
11595  o << "corpus_diff["
11596  << first_corpus()->get_path()
11597  << ", "
11598  << second_corpus()->get_path()
11599  << "]";
11600  priv_->pretty_representation_ = o.str();
11601  }
11602  return priv_->pretty_representation_;
11603 }
11604 /// Return true iff the current @ref corpus_diff node carries a
11605 /// change.
11606 ///
11607 /// @return true iff the current diff node carries a change.
11608 bool
11610 {
11611  return (soname_changed()
11613  || !(priv_->deleted_fns_.empty()
11614  && priv_->added_fns_.empty()
11615  && priv_->changed_fns_map_.empty()
11616  && priv_->deleted_vars_.empty()
11617  && priv_->added_vars_.empty()
11618  && priv_->changed_vars_map_.empty()
11619  && priv_->added_unrefed_fn_syms_.empty()
11620  && priv_->deleted_unrefed_fn_syms_.empty()
11621  && priv_->added_unrefed_var_syms_.empty()
11622  && priv_->deleted_unrefed_var_syms_.empty()
11623  && priv_->deleted_unreachable_types_.empty()
11624  && priv_->added_unreachable_types_.empty()
11625  && priv_->changed_unreachable_types_.empty()));
11626 }
11627 
11628 /// Test if the current instance of @ref corpus_diff carries changes
11629 /// that we are sure are incompatible. By incompatible change we mean
11630 /// a change that "breaks" the ABI of the corpus we are looking at.
11631 ///
11632 /// In concrete terms, this function considers the following changes
11633 /// as being ABI incompatible for sure:
11634 ///
11635 /// - a soname change
11636 /// - if exported functions or variables got removed
11637 ///
11638 /// Note that subtype changes *can* represent changes that break ABI
11639 /// too. But they also can be changes that are OK, ABI-wise.
11640 ///
11641 /// It's up to the user to provide suppression specifications to say
11642 /// explicitely which subtype change is OK. The remaining sub-type
11643 /// changes are then considered to be ABI incompatible. But to test
11644 /// if such ABI incompatible subtype changes are present you need to
11645 /// use the function @ref corpus_diff::has_net_subtype_changes()
11646 ///
11647 /// @return true iff the current instance of @ref corpus_diff carries
11648 /// changes that we are sure are ABI incompatible.
11649 bool
11651 {
11652  const diff_stats& stats = const_cast<corpus_diff*>(this)->
11654 
11657  || stats.net_num_func_removed() != 0
11658  || (stats.num_func_with_virtual_offset_changes() != 0
11659  // If all reports about functions with sub-type changes
11660  // have been suppressed, then even those about functions
11661  // that are virtual don't matter anymore because the
11662  // user willingly requested to shut them down
11663  && stats.net_num_func_changed() != 0)
11664  || stats.net_num_vars_removed() != 0
11665  || stats.net_num_removed_func_syms() != 0
11666  || stats.net_num_removed_var_syms() != 0
11667  || stats.net_num_removed_unreachable_types() != 0);
11668 
11669  // If stats.net_num_changed_unreachable_types() != 0 then walk the
11670  // corpus_diff::priv::changed_unreachable_types_, and see if there
11671  // is one that is harmful by bitwise and-ing their category with
11672  // abigail::comparison::get_default_harmful_categories_bitmap().
11675  {
11676  // The changed unreachable types can carry harmful changes.
11677  // Let's figure if they actually do.
11678 
11679  diff_context_sptr ctxt = context();
11680  for (auto &entry : priv_->changed_unreachable_types())
11681  {
11682  diff_sptr dif = entry.second;
11683 
11684  // Let's see if any of the categories of this diff node
11685  // belong to the "harmful" ones.
11686  if (dif->get_category() & get_default_harmful_categories_bitmap())
11687  {
11688  has_incompatible_changes |= true;
11689  break;
11690  }
11691  }
11692  }
11693 
11694  return has_incompatible_changes;
11695 }
11696 
11697 /// Test if the current instance of @ref corpus_diff carries subtype
11698 /// changes whose reports are not suppressed by any suppression
11699 /// specification. In effect, these are deemed incompatible ABI
11700 /// changes.
11701 ///
11702 /// @return true iff the the current instance of @ref corpus_diff
11703 /// carries subtype changes that are deemed incompatible ABI changes.
11704 bool
11706 {
11707  const diff_stats& stats = const_cast<corpus_diff*>(this)->
11709 
11710  return (stats.net_num_func_changed() != 0
11711  || stats.net_num_vars_changed() != 0
11712  || stats.net_num_removed_unreachable_types() != 0
11713  || stats.net_num_changed_unreachable_types() != 0);
11714 }
11715 
11716 /// Test if the current instance of @ref corpus_diff carries changes
11717 /// whose reports are not suppressed by any suppression specification.
11718 /// In effect, these are deemed incompatible ABI changes.
11719 ///
11720 /// @return true iff the the current instance of @ref corpus_diff
11721 /// carries subtype changes that are deemed incompatible ABI changes.
11722 bool
11724 {return context()->get_reporter()->diff_has_net_changes(this);}
11725 
11726 /// Apply the different filters that are registered to be applied to
11727 /// the diff tree; that includes the categorization filters. Also,
11728 /// apply the suppression interpretation filters.
11729 ///
11730 /// After the filters are applied, this function calculates some
11731 /// statistics about the changes carried by the current instance of
11732 /// @ref corpus_diff. These statistics are represented by an instance
11733 /// of @ref corpus_diff::diff_stats.
11734 ///
11735 /// This member function is called by the reporting function
11736 /// corpus_diff::report().
11737 ///
11738 /// Note that for a given instance of corpus_diff, this function
11739 /// applies the filters and suppressions only the first time it is
11740 /// invoked. Subsequent invocations just return the instance of
11741 /// corpus_diff::diff_stats that was cached after the first
11742 /// invocation.
11743 ///
11744 /// @return a reference to the statistics about the changes carried by
11745 /// the current instance of @ref corpus_diff.
11748 {
11749  if (priv_->diff_stats_)
11750  return *priv_->diff_stats_;
11751 
11753  if (do_log())
11754  {
11755  std::cerr << "Applying suppressions ...\n";
11756  t.start();
11757  }
11758 
11759  apply_suppressions(this);
11760 
11761  if (do_log())
11762  {
11763  t.stop();
11764  std::cerr << "suppressions applied!:" << t << "\n";
11765  }
11766 
11767  priv_->diff_stats_.reset(new diff_stats(context()));
11768 
11769  if (do_log())
11770  {
11771  std::cerr << "Marking leaf nodes ...\n";
11772  t.start();
11773  }
11774 
11776 
11777  if (do_log())
11778  {
11779  t.stop();
11780  std::cerr << "leaf nodes marked!:" << t << "\n";
11781  std::cerr << "Applying filters and computing diff stats ...\n";
11782  t.start();
11783  }
11784 
11785  priv_->apply_filters_and_compute_diff_stats(*priv_->diff_stats_);
11786 
11787  if (do_log())
11788  {
11789  t.stop();
11790  std::cerr << "Filters applied and diff stats computed!: " << t << "\n";
11791  }
11792 
11793  return *priv_->diff_stats_;
11794 }
11795 
11796 /// A visitor that marks leaf diff nodes by storing them in the
11797 /// instance of @ref diff_maps returned by
11798 /// corpus_diff::get_leaf_diffs() invoked on the current instance of
11799 /// corpus_diff.
11800 struct leaf_diff_node_marker_visitor : public diff_node_visitor
11801 {
11802  /// This is called when the visitor visits a diff node.
11803  ///
11804  /// It basically tests if the diff node being visited is a leaf diff
11805  /// node - that is, it contains local changes. If it does, then the
11806  /// node is added to the set of maps that hold leaf diffs in the
11807  /// current corpus_diff.
11808  ///
11809  /// Note that only leaf nodes that are reachable from public
11810  /// interfaces (global functions or variables) are collected by this
11811  /// visitor.
11812  ///
11813  /// @param d the diff node being visited.
11814  virtual void
11815  visit_begin(diff *d)
11816  {
11817  if (d->has_local_changes()
11818  // A leaf basic (or class/union) type name change makes no
11819  // sense when showing just leaf changes. It only makes sense
11820  // when it can explain the details about a non-leaf change.
11821  // In other words, it doesn't make sense to say that an "int"
11822  // became "unsigned int". But it does make sense to say that
11823  // a typedef changed because its underlying type was 'int' and
11824  // is now an "unsigned int".
11826  // Similarly, a *local* change describing a type that changed
11827  // its nature doesn't make sense.
11828  && !is_distinct_diff(d)
11829  // Similarly, a pointer (or reference or array), a typedef or
11830  // qualified type change in itself doesn't make sense. It
11831  // would rather make sense to show that pointer change as part
11832  // of the variable change whose pointer type changed, for
11833  // instance.
11834  && !is_pointer_diff(d)
11835  && !is_reference_diff(d)
11836  && !is_qualified_type_diff(d)
11837  && !is_typedef_diff(d)
11838  && !is_array_diff(d)
11839  // Similarly a parameter change in itself doesn't make sense.
11840  // It should have already been reported as part of the change
11841  // of the function it belongs to.
11842  && !is_fn_parm_diff(d)
11843  // An anonymous class or union diff doesn't make sense on its
11844  // own. It must have been described already by the diff of
11845  // the enclosing struct or union if 'd' is from an anonymous
11846  // data member, or from a typedef change if 'd' is from a
11847  // typedef change which underlying type is an anonymous
11848  // struct/union.
11850  // Don't show decl-only-ness changes either.
11852  // Sometime, we can encounter artifacts of bogus DWARF that
11853  // yield a diff node for a decl-only class (and empty class
11854  // with the is_declaration flag set) that carries a non-zero
11855  // size! And of course at some point that non-zero size
11856  // changes. We need to be able to detect that.
11858  {
11859  diff_context_sptr ctxt = d->context();
11860  const corpus_diff *corpus_diff_node = ctxt->get_corpus_diff().get();
11861  ABG_ASSERT(corpus_diff_node);
11862 
11863  if (diff *iface_diff = get_current_topmost_iface_diff())
11864  {
11865  type_or_decl_base_sptr iface = iface_diff->first_subject();
11866  // So, this diff node that is reachable from a global
11867  // function or variable carries a leaf change. Let's add
11868  // it to the set of of leaf diffs of corpus_diff_node.
11869  const_cast<corpus_diff*>(corpus_diff_node)->
11870  get_leaf_diffs().insert_diff_node(d, iface);
11871  }
11872  }
11873  }
11874 }; // end struct leaf_diff_node_marker_visitor
11875 
11876 /// Walks the diff nodes associated to the current corpus diff and
11877 /// mark those that carry local changes. They are said to be leaf
11878 /// diff nodes.
11879 ///
11880 /// The marked nodes are available from the
11881 /// corpus_diff::get_leaf_diffs() function.
11882 void
11884 {
11885  if (!has_changes())
11886  return;
11887 
11888  if (!context()->show_leaf_changes_only())
11889  return;
11890 
11891  leaf_diff_node_marker_visitor v;
11892  context()->forget_visited_diffs();
11893  bool s = context()->visiting_a_node_twice_is_forbidden();
11894  context()->forbid_visiting_a_node_twice(true);
11895  if (context()->show_impacted_interfaces())
11896  context()->forbid_visiting_a_node_twice_per_interface(true);
11897  traverse(v);
11898  context()->forbid_visiting_a_node_twice(s);
11899  context()->forbid_visiting_a_node_twice_per_interface(false);
11900 }
11901 
11902 /// Get the set of maps that contain leaf nodes. A leaf node being a
11903 /// node with a local change.
11904 ///
11905 /// @return the set of maps that contain leaf nodes. A leaf node
11906 /// being a node with a local change.
11907 diff_maps&
11909 {return priv_->leaf_diffs_;}
11910 
11911 /// Get the set of maps that contain leaf nodes. A leaf node being a
11912 /// node with a local change.
11913 ///
11914 /// @return the set of maps that contain leaf nodes. A leaf node
11915 /// being a node with a local change.
11916 const diff_maps&
11918 {return priv_->leaf_diffs_;}
11919 
11920 /// Report the diff in a serialized form.
11921 ///
11922 /// @param out the stream to serialize the diff to.
11923 ///
11924 /// @param indent the prefix to use for the indentation of this
11925 /// serialization.
11926 void
11927 corpus_diff::report(ostream& out, const string& indent) const
11928 {
11929  context()->get_reporter()->report(*this, out, indent);
11930 }
11931 
11932 /// Traverse the diff sub-tree under the current instance corpus_diff.
11933 ///
11934 /// @param v the visitor to invoke on each diff node of the sub-tree.
11935 ///
11936 /// @return true if the traversing has to keep going on, false otherwise.
11937 bool
11939 {
11940  finish_diff_type();
11941 
11942  v.visit_begin(this);
11943 
11944  if (!v.visit(this, true))
11945  {
11946  v.visit_end(this);
11947  return false;
11948  }
11949 
11950  for (function_decl_diff_sptrs_type::const_iterator i =
11951  changed_functions_sorted().begin();
11952  i != changed_functions_sorted().end();
11953  ++i)
11954  {
11955  if (diff_sptr d = *i)
11956  {
11957  const diff_context_sptr &ctxt = context();
11958  if (ctxt->visiting_a_node_twice_is_forbidden_per_interface())
11959  ctxt->forget_visited_diffs();
11960 
11961  v.set_current_topmost_iface_diff(d.get());
11962 
11963  if (!d->traverse(v))
11964  {
11965  v.visit_end(this);
11967  return false;
11968  }
11969  }
11970  }
11971 
11972  for (var_diff_sptrs_type::const_iterator i =
11973  changed_variables_sorted().begin();
11974  i != changed_variables_sorted().end();
11975  ++i)
11976  {
11977  if (diff_sptr d = *i)
11978  {
11979  const diff_context_sptr &ctxt = context();
11980  if (ctxt->visiting_a_node_twice_is_forbidden_per_interface())
11981  ctxt->forget_visited_diffs();
11982 
11983  v.set_current_topmost_iface_diff(d.get());
11984 
11985  if (!d->traverse(v))
11986  {
11987  v.visit_end(this);
11989  return false;
11990  }
11991  }
11992  }
11993 
11995 
11996  // Traverse the changed unreachable type diffs. These diffs are on
11997  // types that are not reachable from global functions or variables.
11998  for (vector<diff_sptr>::const_iterator i =
12000  i != changed_unreachable_types_sorted().end();
12001  ++i)
12002  {
12003  if (diff_sptr d = *i)
12004  {
12005  const diff_context_sptr &ctxt = context();
12006  if (ctxt->visiting_a_node_twice_is_forbidden_per_interface())
12007  ctxt->forget_visited_diffs();
12008 
12009  if (!d->traverse(v))
12010  {
12011  v.visit_end(this);
12012  return false;
12013  }
12014  }
12015  }
12016 
12017  v.visit_end(this);
12018  return true;
12019 }
12020 
12021 /// Compute the diff between two instances of @ref corpus.
12022 ///
12023 /// Note that the two corpora must have been created in the same @ref
12024 /// environment, otherwise, this function aborts.
12025 ///
12026 /// @param f the first @ref corpus to consider for the diff.
12027 ///
12028 /// @param s the second @ref corpus to consider for the diff.
12029 ///
12030 /// @param ctxt the diff context to use.
12031 ///
12032 /// @return the resulting diff between the two @ref corpus.
12034 compute_diff(const corpus_sptr f,
12035  const corpus_sptr s,
12036  diff_context_sptr ctxt)
12037 {
12038  typedef corpus::functions::const_iterator fns_it_type;
12039  typedef corpus::variables::const_iterator vars_it_type;
12040  typedef elf_symbols::const_iterator symbols_it_type;
12041  typedef diff_utils::deep_ptr_eq_functor eq_type;
12042  typedef vector<type_base_wptr>::const_iterator type_base_wptr_it_type;
12043 
12044  ABG_ASSERT(f && s);
12045 
12046  if (!ctxt)
12047  ctxt.reset(new diff_context);
12048 
12049  corpus_diff_sptr r(new corpus_diff(f, s, ctxt));
12050 
12051  ctxt->set_corpus_diff(r);
12052 
12053  if(ctxt->show_soname_change())
12054  r->priv_->sonames_equal_ = f->get_soname() == s->get_soname();
12055  else
12056  r->priv_->sonames_equal_ = true;
12057 
12058  r->priv_->architectures_equal_ =
12059  f->get_architecture_name() == s->get_architecture_name();
12060 
12061  // Compute the diff of publicly defined and exported functions
12062  diff_utils::compute_diff<fns_it_type, eq_type>(f->get_functions().begin(),
12063  f->get_functions().end(),
12064  s->get_functions().begin(),
12065  s->get_functions().end(),
12066  r->priv_->fns_edit_script_);
12067 
12068  // Compute the diff of publicly defined and exported variables.
12069  diff_utils::compute_diff<vars_it_type, eq_type>
12070  (f->get_variables().begin(), f->get_variables().end(),
12071  s->get_variables().begin(), s->get_variables().end(),
12072  r->priv_->vars_edit_script_);
12073 
12074  // Compute the diff of function elf symbols not referenced by debug
12075  // info.
12076  diff_utils::compute_diff<symbols_it_type, eq_type>
12077  (f->get_unreferenced_function_symbols().begin(),
12078  f->get_unreferenced_function_symbols().end(),
12079  s->get_unreferenced_function_symbols().begin(),
12080  s->get_unreferenced_function_symbols().end(),
12081  r->priv_->unrefed_fn_syms_edit_script_);
12082 
12083  // Compute the diff of variable elf symbols not referenced by debug
12084  // info.
12085  diff_utils::compute_diff<symbols_it_type, eq_type>
12086  (f->get_unreferenced_variable_symbols().begin(),
12087  f->get_unreferenced_variable_symbols().end(),
12088  s->get_unreferenced_variable_symbols().begin(),
12089  s->get_unreferenced_variable_symbols().end(),
12090  r->priv_->unrefed_var_syms_edit_script_);
12091 
12092  if (ctxt->show_unreachable_types())
12093  // Compute the diff of types not reachable from public functions
12094  // or global variables that are exported.
12095  diff_utils::compute_diff<type_base_wptr_it_type, eq_type>
12096  (f->get_types_not_reachable_from_public_interfaces().begin(),
12097  f->get_types_not_reachable_from_public_interfaces().end(),
12098  s->get_types_not_reachable_from_public_interfaces().begin(),
12099  s->get_types_not_reachable_from_public_interfaces().end(),
12100  r->priv_->unreachable_types_edit_script_);
12101 
12102  r->priv_->ensure_lookup_tables_populated();
12103 
12104  return r;
12105 }
12106 
12107 // </corpus stuff>
12108 
12109 /// Compute the diff between two instances of @ref corpus_group.
12110 ///
12111 /// Note that the two corpus_diff must have been created in the same
12112 /// @ref environment, otherwise, this function aborts.
12113 ///
12114 /// @param f the first @ref corpus_group to consider for the diff.
12115 ///
12116 /// @param s the second @ref corpus_group to consider for the diff.
12117 ///
12118 /// @param ctxt the diff context to use.
12119 ///
12120 /// @return the resulting diff between the two @ref corpus_group.
12122 compute_diff(const corpus_group_sptr& f,
12123  const corpus_group_sptr& s,
12124  diff_context_sptr ctxt)
12125 {
12126 
12127  corpus_sptr c1 = f;
12128  corpus_sptr c2 = s;
12129 
12130  return compute_diff(c1, c2, ctxt);
12131 }
12132 
12133 // <corpus_group stuff>
12134 
12135 // </corpus_group stuff>
12136 // <diff_node_visitor stuff>
12137 
12138 /// The private data of the @diff_node_visitor type.
12139 struct diff_node_visitor::priv
12140 {
12141  diff* topmost_interface_diff;
12142  visiting_kind kind;
12143 
12144  priv()
12145  : topmost_interface_diff(),
12146  kind()
12147  {}
12148 
12149  priv(visiting_kind k)
12150  : topmost_interface_diff(),
12151  kind(k)
12152  {}
12153 }; // end struct diff_node_visitor
12154 
12155 /// Default constructor of the @ref diff_node_visitor type.
12157  : priv_(new priv)
12158 {}
12159 
12160 diff_node_visitor::~diff_node_visitor() = default;
12161 
12162 /// Constructor of the @ref diff_node_visitor type.
12163 ///
12164 /// @param k how the visiting has to be performed.
12166  : priv_(new priv(k))
12167 {}
12168 
12169 /// Getter for the visiting policy of the traversing code while
12170 /// invoking this visitor.
12171 ///
12172 /// @return the visiting policy used by the traversing code when
12173 /// invoking this visitor.
12176 {return priv_->kind;}
12177 
12178 /// Setter for the visiting policy of the traversing code while
12179 /// invoking this visitor.
12180 ///
12181 /// @param v a bit map representing the new visiting policy used by
12182 /// the traversing code when invoking this visitor.
12183 void
12185 {priv_->kind = v;}
12186 
12187 /// Setter for the visiting policy of the traversing code while
12188 /// invoking this visitor. This one makes a logical or between the
12189 /// current policy and the bitmap given in argument and assigns the
12190 /// current policy to the result.
12191 ///
12192 /// @param v a bitmap representing the visiting policy to or with
12193 /// the current policy.
12194 void
12196 {priv_->kind = priv_->kind | v;}
12197 
12198 /// Setter of the diff current topmost interface which is impacted by
12199 /// the current diff node being visited.
12200 ///
12201 /// @param d the current topmost interface diff impacted.
12202 void
12204 {priv_->topmost_interface_diff = d;}
12205 
12206 /// Getter of the diff current topmost interface which is impacted by
12207 /// the current diff node being visited.
12208 ///
12209 /// @return the current topmost interface diff impacted.
12210 diff*
12212 {return priv_->topmost_interface_diff;}
12213 
12214 /// This is called by the traversing code on a @ref diff node just
12215 /// before visiting it. That is, before visiting it and its children
12216 /// node.
12217 ///
12218 /// @param d the diff node to visit.
12219 void
12221 {}
12222 
12223 /// This is called by the traversing code on a @ref diff node just
12224 /// after visiting it. That is after visiting it and its children
12225 /// nodes.
12226 ///
12227 /// @param d the diff node that got visited.
12228 void
12230 {}
12231 
12232 /// This is called by the traversing code on a @ref corpus_diff node
12233 /// just before visiting it. That is, before visiting it and its
12234 /// children node.
12235 ///
12236 /// @param p the corpus_diff node to visit.
12237 ///
12238 void
12240 {}
12241 
12242 /// This is called by the traversing code on a @ref corpus_diff node
12243 /// just after visiting it. That is after visiting it and its children
12244 /// nodes.
12245 ///
12246 /// @param d the diff node that got visited.
12247 void
12249 {}
12250 
12251 /// Default visitor implementation
12252 ///
12253 /// @return true
12254 bool
12256 {return true;}
12257 
12258 /// Default visitor implementation.
12259 ///
12260 /// @return true
12261 bool
12263 {
12264  diff* d = dif;
12265  visit(d, pre);
12266 
12267  return true;
12268 }
12269 
12270 /// Default visitor implementation.
12271 ///
12272 /// @return true
12273 bool
12275 {
12276  diff* d = dif;
12277  visit(d, pre);
12278 
12279  return true;
12280 }
12281 
12282 /// Default visitor implementation.
12283 ///
12284 /// @return true
12285 bool
12287 {
12288  diff* d = dif;
12289  visit(d, pre);
12290 
12291  return true;
12292 }
12293 
12294 /// Default visitor implementation.
12295 ///
12296 /// @return true
12297 bool
12299 {
12300  diff* d = dif;
12301  visit(d, pre);
12302 
12303  return true;
12304 }
12305 
12306 /// Default visitor implementation.
12307 ///
12308 /// @return true
12309 bool
12311 {
12312  diff* d = dif;
12313  visit(d, pre);
12314 
12315  return true;
12316 }
12317 
12318 /// Default visitor implementation.
12319 ///
12320 /// @return true
12321 bool
12323 {
12324  diff* d = dif;
12325  visit(d, pre);
12326 
12327  return true;
12328 }
12329 
12330 /// Default visitor implementation.
12331 ///
12332 /// @return true
12333 bool
12335 {
12336  diff* d = dif;
12337  visit(d, pre);
12338 
12339  return true;
12340 }
12341 
12342 /// Default visitor implementation.
12343 ///
12344 /// @return true
12345 bool
12347 {
12348  diff* d = dif;
12349  visit(d, pre);
12350 
12351  return true;
12352 }
12353 
12354 /// Default visitor implementation.
12355 ///
12356 /// @return true
12357 bool
12359 {
12360  diff* d = dif;
12361  visit(d, pre);
12362 
12363  return true;
12364 }
12365 
12366 /// Default visitor implementation.
12367 ///
12368 /// @return true
12369 bool
12371 {
12372  diff* d = dif;
12373  visit(d, pre);
12374 
12375  return true;
12376 }
12377 
12378 /// Default visitor implementation.
12379 ///
12380 /// @return true
12381 bool
12383 {
12384  diff* d = dif;
12385  visit(d, pre);
12386 
12387  return true;
12388 }
12389 
12390 /// Default visitor implementation.
12391 ///
12392 /// @return true
12393 bool
12395 {
12396  diff* d = dif;
12397  visit(d, pre);
12398 
12399  return true;
12400 }
12401 
12402 /// Default visitor implementation.
12403 ///
12404 /// @return true
12405 bool
12407 {
12408  diff* d = dif;
12409  visit(d, pre);
12410 
12411  return true;
12412 }
12413 
12414 /// Default visitor implementation.
12415 ///
12416 /// @return true
12417 bool
12419 {return true;}
12420 
12421 // </diff_node_visitor stuff>
12422 
12423 // <redundant diff node marking>
12424 
12425 // </redundant diff node marking>
12426 
12427 // <diff tree category propagation>
12428 
12429 /// A visitor to propagate the category of a node up to its parent
12430 /// nodes. This visitor doesn't touch the REDUNDANT_CATEGORY or the
12431 /// SUPPRESSED_CATEGORY because those are propagated using other
12432 /// specific visitors.
12433 struct category_propagation_visitor : public diff_node_visitor
12434 {
12435  virtual void
12436  visit_end(diff* d)
12437  {
12438  // Has this diff node 'd' been already visited ?
12439  bool already_visited = d->context()->diff_has_been_visited(d);
12440 
12441  // The canonical diff node of the class of equivalence of the diff
12442  // node 'd'.
12443  diff* canonical = d->get_canonical_diff();
12444 
12445  // If this class of equivalence of diff node is being visited for
12446  // the first time, then update its canonical node's category too.
12447  bool update_canonical = !already_visited && canonical;
12448 
12449  for (vector<diff*>::const_iterator i = d->children_nodes().begin();
12450  i != d->children_nodes().end();
12451  ++i)
12452  {
12453  // If we are visiting the class of equivalence of 'd' for the
12454  // first time, then let's look at the children of 'd' and
12455  // propagate their categories to 'd'.
12456  //
12457  // If the class of equivalence of 'd' has already been
12458  // visited, then let's look at the canonical diff nodes of the
12459  // children of 'd' and propagate their categories to 'd'.
12460  diff* diff = already_visited
12461  ? (*i)->get_canonical_diff()
12462  : *i;
12463 
12464  ABG_ASSERT(diff);
12465 
12467  // Do not propagate redundant and suppressed categories. Those
12468  // are propagated in a specific pass elsewhere.
12469  c &= ~(REDUNDANT_CATEGORY
12475  // Also, if a (class) type has got a harmful name change, do not
12476  // propagate harmless name changes coming from its sub-types
12477  // (i.e, data members) to the class itself.
12480 
12481  d->add_to_category(c);
12482  if (!already_visited && canonical)
12483  if (update_canonical)
12484  canonical->add_to_category(c);
12485  }
12486  }
12487 };// end struct category_propagation_visitor
12488 
12489 /// Visit all the nodes of a given sub-tree. For each node that has a
12490 /// particular category set, propagate that category set up to its
12491 /// parent nodes.
12492 ///
12493 /// @param diff_tree the diff sub-tree to walk for categorization
12494 /// purpose;
12495 void
12497 {
12498  category_propagation_visitor v;
12499  bool s = diff_tree->context()->visiting_a_node_twice_is_forbidden();
12500  diff_tree->context()->forbid_visiting_a_node_twice(true);
12501  diff_tree->context()->forget_visited_diffs();
12502  diff_tree->traverse(v);
12503  diff_tree->context()->forbid_visiting_a_node_twice(s);
12504 }
12505 
12506 /// Visit all the nodes of a given sub-tree. For each node that has a
12507 /// particular category set, propagate that category set up to its
12508 /// parent nodes.
12509 ///
12510 /// @param diff_tree the diff sub-tree to walk for categorization
12511 /// purpose;
12512 void
12514 {propagate_categories(diff_tree.get());}
12515 
12516 /// Visit all the nodes of a given corpus tree. For each node that
12517 /// has a particular category set, propagate that category set up to
12518 /// its parent nodes.
12519 ///
12520 /// @param diff_tree the corpus_diff tree to walk for categorization
12521 /// purpose;
12522 void
12524 {
12525  category_propagation_visitor v;
12526  bool s = diff_tree->context()->visiting_a_node_twice_is_forbidden();
12527  diff_tree->context()->forbid_visiting_a_node_twice(false);
12528  diff_tree->traverse(v);
12529  diff_tree->context()->forbid_visiting_a_node_twice(s);
12530 }
12531 
12532 /// Visit all the nodes of a given corpus tree. For each node that
12533 /// has a particular category set, propagate that category set up to
12534 /// its parent nodes.
12535 ///
12536 /// @param diff_tree the corpus_diff tree to walk for categorization
12537 /// purpose;
12538 void
12540 {propagate_categories(diff_tree.get());}
12541 
12542 /// A tree node visitor that knows how to categorizes a given diff
12543 /// node in the SUPPRESSED_CATEGORY category and how to propagate that
12544 /// categorization.
12545 struct suppression_categorization_visitor : public diff_node_visitor
12546 {
12547 
12548  /// Before visiting the children of the diff node, check if the node
12549  /// is suppressed by a suppression specification. If it is, mark
12550  /// the node as belonging to the SUPPRESSED_CATEGORY category.
12551  ///
12552  /// @param p the diff node to visit.
12553  virtual void
12554  visit_begin(diff* d)
12555  {
12556  bool is_private_type = false;
12557  if (d->is_suppressed(is_private_type))
12558  {
12559  diff_category c = is_private_type
12563 
12564  // If a node was suppressed, all the other nodes of its class
12565  // of equivalence are suppressed too.
12566  diff *canonical_diff = d->get_canonical_diff();
12567  if (canonical_diff != d)
12568  canonical_diff->add_to_category(c);
12569  }
12571  {
12572  // This diff node is specifically allowed by a
12573  // negated_suppression, then mark it as being in the
12574  // HAS_ALLOWED_CHANGE_CATEGORY.
12576  d->add_to_local_category(c);
12577  diff *canonical_diff = d->get_canonical_diff();
12578  canonical_diff->add_to_category(c);
12579 
12580  // Note that some complementary code later down below does
12581  // categorize the descendants and parents nodes of this node
12582  // as HAS_PARENT_WITH_ALLOWED_CHANGE_CATEGORY and
12583  // HAS_DESCENDANT_WITH_ALLOWED_CHANGE_CATEGORY, repectively.
12584  }
12585 
12586  // If a parent node has been allowed by a negated suppression
12587  // specification, then categorize the current node as
12588  // HAS_PARENT_WITH_ALLOWED_CHANGE_CATEGORY.
12589  if (d->parent_node())
12590  {
12595  else
12596  {
12597  c = d->parent_node()->get_category();
12601  }
12602  }
12603 
12604  }
12605 
12606  /// After visiting the children nodes of a given diff node,
12607  /// propagate the SUPPRESSED_CATEGORY from the children nodes to the
12608  /// diff node, if need be.
12609  ///
12610  /// That is, if all children nodes carry a suppressed change the
12611  /// current node should be marked as suppressed as well.
12612  ///
12613  /// In practice, this might be too strong of a condition. If the
12614  /// current node carries a local change (i.e, a change not carried
12615  /// by any of its children node) and if that change is not
12616  /// suppressed, then the current node should *NOT* be suppressed.
12617  ///
12618  /// But right now, the IR doesn't let us know about local vs
12619  /// children-carried changes. So we cannot be that precise yet.
12620  virtual void
12621  visit_end(diff* d)
12622  {
12623  bool has_non_suppressed_child = false;
12624  bool has_non_empty_child = false;
12625  bool has_suppressed_child = false;
12626  bool has_non_private_child = false;
12627  bool has_private_child = false;
12628  bool has_descendant_with_allowed_change = false;
12629 
12630  if (// A node to which we can propagate the "SUPPRESSED_CATEGORY"
12631  // (or the PRIVATE_TYPE_CATEGORY for the same matter)
12632  // category from its children is a node which:
12633  //
12634  // 1/ hasn't been suppressed already
12635  //
12636  // 2/ and has no local change (unless it's a pointer,
12637  // reference or qualified diff node).
12638  //
12639  // Note that qualified type and typedef diff nodes are a bit
12640  // special. The local changes of the underlying type are
12641  // considered local for the qualified/typedef type, just like
12642  // for pointer/reference types. But then the qualified or
12643  // typedef type itself can have local changes of its own, and
12644  // those changes are of the kind LOCAL_NON_TYPE_CHANGE_KIND.
12645  // So a qualified type which have local changes that are
12646  // *NOT* of LOCAL_NON_TYPE_CHANGE_KIND (or that has no local
12647  // changes at all) and which is in the PRIVATE_TYPE_CATEGORY
12648  // or SUPPRESSED_CATEGORY can see these categories be
12649  // propagated.
12650  //
12651  // Note that all pointer/reference diff node changes are
12652  // potentially considered local, i.e, local changes of the
12653  // pointed-to-type are considered local to the pointer itself.
12654  //
12655  // Similarly, changes local to the type of function parameters,
12656  // variables (and data members) and classes (that are not of
12657  // LOCAL_NON_TYPE_CHANGE_KIND kind) and that have been
12658  // suppressed can propagate their SUPPRESSED_CATEGORY-ness to
12659  // those kinds of diff node.
12660  !(d->get_category() & SUPPRESSED_CATEGORY)
12661  && (!d->has_local_changes()
12662  || is_pointer_diff(d)
12663  || is_reference_diff(d)
12664  || (is_qualified_type_diff(d)
12665  && (!(d->has_local_changes() & LOCAL_NON_TYPE_CHANGE_KIND)))
12666  || (is_typedef_diff(d)
12667  && (!(d->has_local_changes() & LOCAL_NON_TYPE_CHANGE_KIND)))
12668  || (is_function_decl_diff(d)
12669  && (!(d->has_local_changes() & LOCAL_NON_TYPE_CHANGE_KIND)))
12670  || (is_fn_parm_diff(d)
12671  && (!(d->has_local_changes() & LOCAL_NON_TYPE_CHANGE_KIND)))
12672  || (is_function_type_diff(d)
12673  && (!(d->has_local_changes() & LOCAL_NON_TYPE_CHANGE_KIND)))
12674  || (is_var_diff(d)
12675  && (!(d->has_local_changes() & LOCAL_NON_TYPE_CHANGE_KIND)))
12676  || (is_class_diff(d)
12677  && (!(d->has_local_changes() & LOCAL_NON_TYPE_CHANGE_KIND)))))
12678  {
12679  // Note that we handle private diff nodes differently from
12680  // generally suppressed diff nodes. E.g, it's not because a
12681  // type is private (and suppressed because of that; i.e, in
12682  // the category PRIVATE_TYPE_CATEGORY) that a typedef to that
12683  // type should also be private and so suppressed. Private
12684  // diff nodes thus have different propagation rules than
12685  // generally suppressed rules.
12686  for (vector<diff*>::const_iterator i = d->children_nodes().begin();
12687  i != d->children_nodes().end();
12688  ++i)
12689  {
12690  diff* child = *i;
12691  if (child->has_changes())
12692  {
12693  has_non_empty_child = true;
12694  if (child->get_class_of_equiv_category() & SUPPRESSED_CATEGORY)
12695  has_suppressed_child = true;
12696  else if (child->get_class_of_equiv_category()
12698  // Propagation of the PRIVATE_TYPE_CATEGORY is going
12699  // to be handled later below.
12700  ;
12701  else
12702  has_non_suppressed_child = true;
12703 
12704  if (child->get_class_of_equiv_category()
12706  has_private_child = true;
12707  else if (child->get_class_of_equiv_category()
12709  // Propagation of the SUPPRESSED_CATEGORY has been
12710  // handled above already.
12711  ;
12712  else
12713  has_non_private_child = true;
12714  }
12715  }
12716 
12717  if (has_non_empty_child
12718  && has_suppressed_child
12719  && !has_non_suppressed_child)
12720  {
12722  // If a node was suppressed, all the other nodes of its class
12723  // of equivalence are suppressed too.
12724  diff *canonical_diff = d->get_canonical_diff();
12725  if (canonical_diff != d)
12726  canonical_diff->add_to_category(SUPPRESSED_CATEGORY);
12727  }
12728 
12729  // Note that the private-ness of a an underlying type won't be
12730  // propagated to its parent typedef, by virtue of the big "if"
12731  // clause at the beginning of this function. So we don't have
12732  // to handle that case here. So the idiom of defining
12733  // typedefs of private (opaque) types will be respected;
12734  // meaning that changes to opaque underlying type will be
12735  // flagged as private and the typedef will be flagged private
12736  // as well, unless the typedef itself has local non-type
12737  // changes. In the later case, changes to the typedef will be
12738  // emitted because the typedef won't inherit the privateness
12739  // of its underlying type. So in practise, the typedef
12740  // remains public for the purpose of change reporting.
12741  if (has_non_empty_child
12742  && has_private_child
12743  && !has_non_private_child)
12744  {
12745  d->add_to_category(PRIVATE_TYPE_CATEGORY);
12746  // If a node was suppressed, all the other nodes of its class
12747  // of equivalence are suppressed too.
12748  diff *canonical_diff = d->get_canonical_diff();
12749  if (canonical_diff != d)
12750  canonical_diff->add_to_category(PRIVATE_TYPE_CATEGORY);
12751  }
12752 
12753  // If the underlying type of a typedef is private and carries
12754  // changes (that are implicitely suppressed because it's
12755  // private) then the typedef must be suppressed too, so that
12756  // those changes to the underlying type are not seen.
12757  if (is_typedef_diff(d)
12758  && !d->has_local_changes()
12759  && has_private_child
12760  && has_non_empty_child)
12761  {
12762  d->add_to_category(SUPPRESSED_CATEGORY|PRIVATE_TYPE_CATEGORY);
12763  // If a node was suppressed, all the other nodes of its class
12764  // of equivalence are suppressed too.
12765  diff *canonical_diff = d->get_canonical_diff();
12766  if (canonical_diff != d)
12767  canonical_diff->add_to_category
12769  }
12770 
12771  if (const function_decl_diff *fn_diff = is_function_decl_diff(d))
12772  if (!(d->has_local_changes() & LOCAL_NON_TYPE_CHANGE_KIND))
12773  {
12774  // d is a function diff that carries a local *type*
12775  // change (that means it's a change to the function
12776  // type). Let's see if the child function type diff
12777  // node is suppressed. That would mean that we are
12778  // instructed to show details of a diff that is deemed
12779  // suppressed; this means the suppression conflicts with
12780  // a local type change. In that case, let's follow what
12781  // the user asked and suppress the function altogether,
12782  if (function_type_diff_sptr fn_type_diff = fn_diff->type_diff())
12783  if (fn_type_diff->is_suppressed())
12784  {
12785  d->add_to_category(SUPPRESSED_CATEGORY);
12786  // If a node was suppressed, all the other nodes
12787  // of its class of equivalence are suppressed too.
12788  diff *canonical_diff = d->get_canonical_diff();
12789  if (canonical_diff != d)
12790  canonical_diff->add_to_category(SUPPRESSED_CATEGORY);
12791  }
12792  }
12793  }
12794 
12795  // If any descendant node was selected by a negated suppression
12796  // specification then categorize the current one as
12797  // HAS_DESCENDANT_WITH_ALLOWED_CHANGE_CATEGORY.
12798  for (auto child_node : d->children_nodes())
12799  {
12800  diff *canonical_diff = child_node->get_canonical_diff();
12801  diff_category c = canonical_diff->get_category();
12804  has_descendant_with_allowed_change = true;
12805  }
12806  if (has_descendant_with_allowed_change)
12807  {
12809  d->add_to_category(c);
12810  d->get_canonical_diff()->add_to_category(c);
12811  }
12812  }
12813 }; //end struct suppression_categorization_visitor
12814 
12815 /// Walk a given diff-sub tree and appply the suppressions carried by
12816 /// the context. If the suppression applies to a given node than
12817 /// categorize the node into the SUPPRESSED_CATEGORY category and
12818 /// propagate that categorization.
12819 ///
12820 /// @param diff_tree the diff-sub tree to apply the suppressions to.
12821 void
12823 {
12824  if (diff_tree && !diff_tree->context()->suppressions().empty())
12825  {
12826  // Apply suppressions to functions and variables that have
12827  // changed sub-types.
12828  suppression_categorization_visitor v;
12829  diff_tree->context()->forget_visited_diffs();
12830  bool s = diff_tree->context()->visiting_a_node_twice_is_forbidden();
12831  diff_tree->context()->forbid_visiting_a_node_twice(true);
12832  diff_tree->traverse(v);
12833  diff_tree->context()->forbid_visiting_a_node_twice(s);
12834  }
12835 }
12836 
12837 /// Walk a given diff-sub tree and appply the suppressions carried by
12838 /// the context. If the suppression applies to a given node than
12839 /// categorize the node into the SUPPRESSED_CATEGORY category and
12840 /// propagate that categorization.
12841 ///
12842 /// @param diff_tree the diff-sub tree to apply the suppressions to.
12843 void
12845 {apply_suppressions(diff_tree.get());}
12846 
12847 /// Walk a @ref corpus_diff tree and appply the suppressions carried
12848 /// by the context. If the suppression applies to a given node then
12849 /// categorize the node into the SUPPRESSED_CATEGORY category and
12850 /// propagate that categorization.
12851 ///
12852 /// @param diff_tree the diff tree to apply the suppressions to.
12853 void
12855 {
12856  if (diff_tree && !diff_tree->context()->suppressions().empty())
12857  {
12858  // First, visit the children trees of changed constructs:
12859  // changed functions, variables, as well as sub-types of these,
12860  // and apply suppression specifications to these ...
12861  suppression_categorization_visitor v;
12862  diff_tree->context()->forget_visited_diffs();
12863  bool s = diff_tree->context()->visiting_a_node_twice_is_forbidden();
12864  diff_tree->context()->forbid_visiting_a_node_twice(true);
12865  const_cast<corpus_diff*>(diff_tree)->traverse(v);
12866  diff_tree->context()->forbid_visiting_a_node_twice(s);
12867 
12868  // ... then also visit the set of added and removed functions,
12869  // variables, symbols, and types not reachable from global
12870  // functions and variables.
12871  diff_tree->priv_->
12872  apply_supprs_to_added_removed_fns_vars_unreachable_types();
12873  }
12874 }
12875 
12876 /// Walk a diff tree and appply the suppressions carried by the
12877 /// context. If the suppression applies to a given node than
12878 /// categorize the node into the SUPPRESSED_CATEGORY category and
12879 /// propagate that categorization.
12880 ///
12881 /// @param diff_tree the diff tree to apply the suppressions to.
12882 void
12884 {apply_suppressions(diff_tree.get());}
12885 
12886 // </diff tree category propagation>
12887 
12888 // <diff tree printing stuff>
12889 
12890 /// A visitor to print (to an output stream) a pretty representation
12891 /// of a @ref diff sub-tree or of a complete @ref corpus_diff tree.
12892 struct diff_node_printer : public diff_node_visitor
12893 {
12894  ostream& out_;
12895  unsigned level_;
12896 
12897  /// Emit a certain number of spaces to the output stream associated
12898  /// to this diff_node_printer.
12899  ///
12900  /// @param level half of the numver of spaces to emit.
12901  void
12902  do_indent(unsigned level)
12903  {
12904  for (unsigned i = 0; i < level; ++i)
12905  out_ << " ";
12906  }
12907 
12908  diff_node_printer(ostream& out)
12909  : diff_node_visitor(DO_NOT_MARK_VISITED_NODES_AS_VISITED),
12910  out_(out),
12911  level_(0)
12912  {}
12913 
12914  virtual void
12915  visit_begin(diff*)
12916  {
12917  ++level_;
12918  }
12919 
12920  virtual void
12921  visit_end(diff*)
12922  {
12923  --level_;
12924  }
12925 
12926  virtual void
12927  visit_begin(corpus_diff*)
12928  {
12929  ++level_;
12930  }
12931 
12932  virtual void
12933  visit_end(corpus_diff*)
12934  {
12935  --level_;
12936  }
12937 
12938  virtual bool
12939  visit(diff* d, bool pre)
12940  {
12941  if (!pre)
12942  // We are post-visiting the diff node D. Which means, we have
12943  // printed a pretty representation for it already. So do
12944  // nothing now.
12945  return true;
12946 
12947  do_indent(level_);
12948  out_ << d->get_pretty_representation();
12949  out_ << "\n";
12950  do_indent(level_);
12951  out_ << "{\n";
12952  do_indent(level_ + 1);
12953  out_ << "category: "<< d->get_category() << "\n";
12954  do_indent(level_ + 1);
12955  out_ << "@: " << std::hex << d << std::dec << "\n";
12956  do_indent(level_ + 1);
12957  out_ << "@-canonical: " << std::hex
12958  << d->get_canonical_diff()
12959  << std::dec << "\n";
12960  do_indent(level_);
12961  out_ << "}\n";
12962 
12963  return true;
12964  }
12965 
12966  virtual bool
12967  visit(corpus_diff* d, bool pre)
12968  {
12969  if (!pre)
12970  // We are post-visiting the diff node D. Which means, we have
12971  // printed a pretty representation for it already. So do
12972  // nothing now.
12973  return true;
12974 
12975  // indent
12976  for (unsigned i = 0; i < level_; ++i)
12977  out_ << ' ';
12978  out_ << d->get_pretty_representation();
12979  out_ << '\n';
12980  return true;
12981  }
12982 }; // end struct diff_printer_visitor
12983 
12984 // </ diff tree printing stuff>
12985 
12986 /// Emit a textual representation of a @ref diff sub-tree to an
12987 /// output stream.
12988 ///
12989 /// @param diff_tree the sub-tree to emit the textual representation
12990 /// for.
12991 ///
12992 /// @param out the output stream to emit the textual representation
12993 /// for @p diff_tree to.
12994 void
12995 print_diff_tree(diff* diff_tree, ostream& out)
12996 {
12997  diff_node_printer p(out);
12998  bool s = diff_tree->context()->visiting_a_node_twice_is_forbidden();
12999  diff_tree->context()->forbid_visiting_a_node_twice(false);
13000  diff_tree->traverse(p);
13001  diff_tree->context()->forbid_visiting_a_node_twice(s);
13002 }
13003 
13004 /// Emit a textual representation of a @ref corpus_diff tree to an
13005 /// output stream.
13006 ///
13007 /// @param diff_tree the @ref corpus_diff tree to emit the textual
13008 /// representation for.
13009 ///
13010 /// @param out the output stream to emit the textual representation
13011 /// for @p diff_tree to.
13012 void
13013 print_diff_tree(corpus_diff* diff_tree, std::ostream& out)
13014 {
13015  diff_node_printer p(out);
13016  bool s = diff_tree->context()->visiting_a_node_twice_is_forbidden();
13017  diff_tree->context()->forbid_visiting_a_node_twice(false);
13018  diff_tree->traverse(p);
13019  diff_tree->context()->forbid_visiting_a_node_twice(s);
13020 }
13021 
13022 /// Emit a textual representation of a @ref diff sub-tree to an
13023 /// output stream.
13024 ///
13025 /// @param diff_tree the sub-tree to emit the textual representation
13026 /// for.
13027 ///
13028 /// @param out the output stream to emit the textual representation
13029 /// for @p diff_tree to.
13030 void
13032  std::ostream& o)
13033 {print_diff_tree(diff_tree.get(), o);}
13034 
13035 /// Emit a textual representation of a @ref corpus_diff tree to an
13036 /// output stream.
13037 ///
13038 /// @param diff_tree the @ref corpus_diff tree to emit the textual
13039 /// representation for.
13040 ///
13041 /// @param out the output stream to emit the textual representation
13042 /// for @p diff_tree to.
13043 void
13045  std::ostream& o)
13046 {print_diff_tree(diff_tree.get(), o);}
13047 
13048 // <redundancy_marking_visitor>
13049 
13050 /// A tree visitor to categorize nodes with respect to the
13051 /// REDUNDANT_CATEGORY. That is, detect if a node is redundant (is
13052 /// present on several spots of the tree) and mark such nodes
13053 /// appropriatly. This visitor also takes care of propagating the
13054 /// REDUNDANT_CATEGORY of a given node to its parent nodes as
13055 /// appropriate.
13056 struct redundancy_marking_visitor : public diff_node_visitor
13057 {
13058  bool skip_children_nodes_;
13059 
13060  redundancy_marking_visitor()
13061  : skip_children_nodes_()
13062  {}
13063 
13064  virtual void
13065  visit_begin(diff* d)
13066  {
13067  if (d->to_be_reported())
13068  {
13069  // A diff node that carries a change and that has been already
13070  // traversed elsewhere is considered redundant. So let's mark
13071  // it as such and let's not traverse it; that is, let's not
13072  // visit its children.
13073  if ((d->context()->diff_has_been_visited(d)
13074  || d->get_canonical_diff()->is_traversing())
13075  && d->has_changes())
13076  {
13077  // But if two diff nodes are redundant sibbling that carry
13078  // changes of base types, do not mark them as being
13079  // redundant. This is to avoid marking nodes as redundant
13080  // in this case:
13081  //
13082  // int foo(int a, int b);
13083  // compared with:
13084  // float foo(float a, float b); (in C).
13085  //
13086  // In this case, we want to report all the occurences of
13087  // the int->float change because logically, they are at
13088  // the same level in the diff tree.
13089 
13090  bool redundant_with_sibling_node = false;
13091  const diff* p = d->parent_node();
13092 
13093  // If this is a child node of a fn_parm_diff, look through
13094  // the fn_parm_diff node to get the function diff node.
13095  if (p && dynamic_cast<const fn_parm_diff*>(p))
13096  p = p->parent_node();
13097 
13098  if (p)
13099  for (vector<diff*>::const_iterator s =
13100  p->children_nodes().begin();
13101  s != p->children_nodes().end();
13102  ++s)
13103  {
13104  if (*s == d)
13105  continue;
13106  diff* sib = *s;
13107  // If this is a fn_parm_diff, look through the
13108  // fn_parm_diff node to get at the real type node.
13109  if (fn_parm_diff* f = dynamic_cast<fn_parm_diff*>(*s))
13110  sib = f->type_diff().get();
13111  if (sib == d)
13112  continue;
13113  if (sib->get_canonical_diff() == d->get_canonical_diff()
13114  // Sibbling diff nodes that carry base type
13115  // changes ar to be marked as redundant.
13116  && (is_base_diff(sib) || is_distinct_diff(sib)))
13117  {
13118  redundant_with_sibling_node = true;
13119  break;
13120  }
13121  }
13122  if (!redundant_with_sibling_node
13123  // Changes to basic types should never be considered
13124  // redundant. For instance, if a member of integer
13125  // type is changed into a char type in both a struct A
13126  // and a struct B, we want to see both changes.
13128  // The same goes for distinct type changes
13130  // Functions with similar *local* changes are never marked
13131  // redundant because otherwise one could miss important
13132  // similar local changes that are applied to different
13133  // functions.
13135  // Changes involving variadic parameters of functions
13136  // should never be marked redundant because we want to see
13137  // them all.
13140  // If the canonical diff itself has been filtered out,
13141  // then this one is not marked redundant, unless the
13142  // canonical diff was already redundant.
13143  && (!d->get_canonical_diff()->is_filtered_out()
13144  || (d->get_canonical_diff()->get_category()
13145  & REDUNDANT_CATEGORY))
13146  // If the *same* diff node (not one that is merely
13147  // equivalent to this one) has already been visited
13148  // the do not mark it as beind redundant. It's only
13149  // the other nodes that are equivalent to this one
13150  // that must be marked redundant.
13151  && d->context()->diff_has_been_visited(d) != d
13152  // If the diff node is a function parameter and is not
13153  // a reference/pointer (to a non basic or a non
13154  // distinct type diff) then do not mark it as
13155  // redundant.
13156  //
13157  // Children nodes of base class diff nodes are never
13158  // redundant either, we want to see them all.
13161  && !is_child_node_of_base_diff(d))))
13162  {
13164  // As we said in preamble, as this node is marked as
13165  // being redundant, let's not visit its children.
13166  // This is not an optimization; it's needed for
13167  // correctness. In the case of a diff node involving
13168  // a class type that refers to himself, visiting the
13169  // children nodes might cause them to be wrongly
13170  // marked as redundant.
13173  skip_children_nodes_ = true;
13174  }
13175  }
13176  }
13177  else
13178  {
13179  // If the node is not to be reported, do not look at it children.
13181  skip_children_nodes_ = true;
13182  }
13183  }
13184 
13185  virtual void
13186  visit_begin(corpus_diff*)
13187  {
13188  }
13189 
13190  virtual void
13191  visit_end(diff* d)
13192  {
13193  if (skip_children_nodes_)
13194  // When visiting this node, we decided to skip its children
13195  // node. Now that we are done visiting the node, lets stop
13196  // avoiding the children nodes visiting for the other tree
13197  // nodes.
13198  {
13200  skip_children_nodes_ = false;
13201  }
13202  else
13203  {
13204  // Propagate the redundancy categorization of the children nodes
13205  // to this node. But if this node has local changes, then it
13206  // doesn't inherit redundancy from its children nodes.
13207  if (!(d->get_category() & REDUNDANT_CATEGORY)
13208  && (!d->has_local_changes_to_be_reported()
13209  // By default, pointer, reference and qualified types
13210  // consider that a local changes to their underlying
13211  // type is always a local change for themselves.
13212  //
13213  // This is as if those types don't have local changes
13214  // in the same sense as other types. So we always
13215  // propagate redundancy to them, regardless of if they
13216  // have local changes or not.
13217  //
13218  // We also propagate redundancy to typedef types if
13219  // these /only/ carry changes to their underlying
13220  // type.
13221  //
13222  // Note that changes to the underlying type of a
13223  // typedef is considered local of
13224  // LOCAL_TYPE_CHANGE_KIND kind. The other changes to the
13225  // typedef itself are considered local of
13226  // LOCAL_NON_TYPE_CHANGE_KIND kind.
13227  || is_pointer_diff(d)
13229  // A typedef with local non-type changes should not
13230  // see redundancy propagation from its underlying
13231  // type, otherwise, the non-type change might be
13232  // "suppressed" away.
13233  || (is_typedef_diff(d)
13234  && (!(d->has_local_changes()
13236  // A (member) variable with non-type local changes
13237  // should not see redundacy propagation from its type.
13238  // If redundant local-type changes are carried by its
13239  // type however, then that redundancy is propagated to
13240  // the variable. This is key to keep the redundancy
13241  // consistency in the system; otherwise, a type change
13242  // would be rightfully considered redundant at some
13243  // places but not at others.
13244  || (is_var_diff(d)
13245  && (!(d->has_local_changes()
13247  // A function parameter with non-type local changes
13248  // should not see redundancy propagation either. But
13249  // a function parameter with local type changes can
13250  // definitely be redundant.
13251  || (is_fn_parm_diff(d)
13252  && (!(d->has_local_changes()
13254  ))
13255  {
13256  bool has_non_redundant_child = false;
13257  bool has_non_empty_child = false;
13258  for (vector<diff*>::const_iterator i =
13259  d->children_nodes().begin();
13260  i != d->children_nodes().end();
13261  ++i)
13262  {
13263  if ((*i)->has_changes())
13264  {
13265  has_non_empty_child = true;
13266  // Let's see if the current child node '*i' is
13267  // "non-redundant".
13268  //
13269  // A non-redundant node would be a node that
13270  // carries a change to be reported and has not
13271  // been marked as being redundant.
13272  if ((*i)->to_be_reported()
13273  && ((*i)->get_category() & REDUNDANT_CATEGORY) == 0)
13274  has_non_redundant_child = true;
13275  }
13276  if (has_non_redundant_child)
13277  break;
13278  }
13279 
13280  // A diff node for which at least a child node carries a
13281  // change, and for which all the children are redundant is
13282  // deemed redundant too, unless it has local changes.
13283  if (has_non_empty_child
13284  && !has_non_redundant_child)
13285  d->add_to_category(REDUNDANT_CATEGORY);
13286  }
13287  }
13288  }
13289 
13290  virtual void
13291  visit_end(corpus_diff*)
13292  {
13293  }
13294 
13295  virtual bool
13296  visit(diff*, bool)
13297  {return true;}
13298 
13299  virtual bool
13300  visit(corpus_diff*, bool)
13301  {
13302  return true;
13303  }
13304 };// end struct redundancy_marking_visitor
13305 
13306 /// A visitor of @ref diff nodes that clears the REDUNDANT_CATEGORY
13307 /// category out of the nodes.
13308 struct redundancy_clearing_visitor : public diff_node_visitor
13309 {
13310  bool
13311  visit(corpus_diff*, bool)
13312  {return true;}
13313 
13314  bool
13315  visit(diff* d, bool)
13316  {
13317  // clear the REDUNDANT_CATEGORY out of the current node.
13318  diff_category c = d->get_category();
13319  c &= ~REDUNDANT_CATEGORY;
13320  d->set_category(c);
13321  return true;
13322  }
13323 }; // end struct redundancy_clearing_visitor
13324 
13325 /// Walk a given @ref diff sub-tree to categorize each of the nodes
13326 /// with respect to the REDUNDANT_CATEGORY.
13327 ///
13328 /// @param diff_tree the @ref diff sub-tree to walk.
13329 void
13331 {
13332  if (diff_tree->context()->show_redundant_changes())
13333  return;
13334  redundancy_marking_visitor v;
13335  bool s = diff_tree->context()->visiting_a_node_twice_is_forbidden();
13336  diff_tree->context()->forbid_visiting_a_node_twice(false);
13337  diff_tree->traverse(v);
13338  diff_tree->context()->forbid_visiting_a_node_twice(s);
13339 }
13340 
13341 /// Walk a given @ref diff sub-tree to categorize each of the nodes
13342 /// with respect to the REDUNDANT_CATEGORY.
13343 ///
13344 /// @param diff_tree the @ref diff sub-tree to walk.
13345 void
13347 {categorize_redundancy(diff_tree.get());}
13348 
13349 /// Walk a given @ref corpus_diff tree to categorize each of the nodes
13350 /// with respect to the REDUNDANT_CATEGORY.
13351 ///
13352 /// @param diff_tree the @ref corpus_diff tree to walk.
13353 void
13355 {
13356  redundancy_marking_visitor v;
13357  diff_tree->context()->forget_visited_diffs();
13358  bool s = diff_tree->context()->visiting_a_node_twice_is_forbidden();
13359  diff_tree->context()->forbid_visiting_a_node_twice(false);
13360  diff_tree->traverse(v);
13361  diff_tree->context()->forbid_visiting_a_node_twice(s);
13362 }
13363 
13364 /// Walk a given @ref corpus_diff tree to categorize each of the nodes
13365 /// with respect to the REDUNDANT_CATEGORY.
13366 ///
13367 /// @param diff_tree the @ref corpus_diff tree to walk.
13368 void
13370 {categorize_redundancy(diff_tree.get());}
13371 
13372 // </redundancy_marking_visitor>
13373 
13374 /// Walk a given @ref diff sub-tree to clear the REDUNDANT_CATEGORY
13375 /// out of the category of the nodes.
13376 ///
13377 /// @param diff_tree the @ref diff sub-tree to walk.
13378 void
13380 {
13381  redundancy_clearing_visitor v;
13382  bool s = diff_tree->context()->visiting_a_node_twice_is_forbidden();
13383  diff_tree->context()->forbid_visiting_a_node_twice(false);
13384  diff_tree->traverse(v);
13385  diff_tree->context()->forbid_visiting_a_node_twice(s);
13386  diff_tree->context()->forget_visited_diffs();
13387 }
13388 
13389 /// Walk a given @ref diff sub-tree to clear the REDUNDANT_CATEGORY
13390 /// out of the category of the nodes.
13391 ///
13392 /// @param diff_tree the @ref diff sub-tree to walk.
13393 void
13395 {clear_redundancy_categorization(diff_tree.get());}
13396 
13397 /// Walk a given @ref corpus_diff tree to clear the REDUNDANT_CATEGORY
13398 /// out of the category of the nodes.
13399 ///
13400 /// @param diff_tree the @ref corpus_diff tree to walk.
13401 void
13403 {
13404  redundancy_clearing_visitor v;
13405  bool s = diff_tree->context()->visiting_a_node_twice_is_forbidden();
13406  diff_tree->context()->forbid_visiting_a_node_twice(false);
13407  diff_tree->traverse(v);
13408  diff_tree->context()->forbid_visiting_a_node_twice(s);
13409  diff_tree->context()->forget_visited_diffs();
13410 }
13411 
13412 /// Walk a given @ref corpus_diff tree to clear the REDUNDANT_CATEGORY
13413 /// out of the category of the nodes.
13414 ///
13415 /// @param diff_tree the @ref corpus_diff tree to walk.
13416 void
13418 {clear_redundancy_categorization(diff_tree.get());}
13419 
13420 /// Apply the @ref diff tree filters that have been associated to the
13421 /// context of the a given @ref corpus_diff tree. As a result, the
13422 /// nodes of the @diff tree are going to be categorized into one of
13423 /// several of the categories of @ref diff_category.
13424 ///
13425 /// @param diff_tree the @ref corpus_diff instance which @ref diff are
13426 /// to be categorized.
13427 void
13429 {
13430  diff_tree->context()->maybe_apply_filters(diff_tree);
13431  propagate_categories(diff_tree);
13432 }
13433 
13434 /// Test if a diff node represents the difference between a variadic
13435 /// parameter type and something else.
13436 ///
13437 /// @param d the diff node to consider.
13438 ///
13439 /// @return true iff @p d is a diff node that represents the
13440 /// difference between a variadic parameter type and something else.
13441 bool
13443 {
13444  if (!d)
13445  return false;
13446 
13447  type_base_sptr t = is_type(d->first_subject());
13448  if (t && t->get_environment().is_variadic_parameter_type(t))
13449  return true;
13450 
13451  t = is_type(d->second_subject());
13452  if (t && t->get_environment().is_variadic_parameter_type(t))
13453  return true;
13454 
13455  return false;
13456 }
13457 
13458 /// Test if a diff node represents the difference between a variadic
13459 /// parameter type and something else.
13460 ///
13461 /// @param d the diff node to consider.
13462 ///
13463 /// @return true iff @p d is a diff node that represents the
13464 /// difference between a variadic parameter type and something else.
13465 bool
13467 {return is_diff_of_variadic_parameter_type(d.get());}
13468 
13469 /// Test if a diff node represents the difference between a variadic
13470 /// parameter and something else.
13471 ///
13472 /// @param d the diff node to consider.
13473 ///
13474 /// @return true iff @p d is a diff node that represents the
13475 /// difference between a variadic parameter and something else.
13476 bool
13478 {
13479  fn_parm_diff* diff =
13480  dynamic_cast<fn_parm_diff*>(const_cast<abigail::comparison::diff*>(d));
13481  return (diff && is_diff_of_variadic_parameter_type(diff->type_diff()));
13482 }
13483 
13484 /// Test if a diff node represents the difference between a variadic
13485 /// parameter and something else.
13486 ///
13487 /// @param d the diff node to consider.
13488 ///
13489 /// @return true iff @p d is a diff node that represents the
13490 /// difference between a variadic parameter and something else.
13491 bool
13493 {return is_diff_of_variadic_parameter(d.get());}
13494 
13495 /// Test if a diff node represents a diff between two basic types.
13496 ///
13497 /// @param d the diff node to consider.
13498 ///
13499 /// @return true iff @p d is a diff between two basic types.
13500 const type_decl_diff*
13502 {return dynamic_cast<const type_decl_diff*>(d);}
13503 
13504 /// Test if a diff node represents a diff between two basic types, or
13505 /// between pointers, references or qualified type to basic types.
13506 ///
13507 /// @param diff the diff node to consider.
13508 ///
13509 /// @param allow_indirect_type if true, then this function looks into
13510 /// pointer, reference or qualified diff types to see if they "point
13511 /// to" basic types.
13512 ///
13513 /// @return true iff @p d is a diff between two basic types.
13514 const type_decl_diff*
13515 is_diff_of_basic_type(const diff* diff, bool allow_indirect_type)
13516 {
13517  if (allow_indirect_type)
13519  return is_diff_of_basic_type(diff);
13520 }
13521 
13522 /// If a diff node is about changes between two typedef types, get the
13523 /// diff node about changes between the underlying types.
13524 ///
13525 /// Note that this function walks the tree of underlying diff nodes
13526 /// returns the first diff node about types that are not typedefs.
13527 ///
13528 /// @param dif the dif node to consider.
13529 ///
13530 /// @return the underlying diff node of @p dif, or just return @p dif
13531 /// if it's not a typedef diff node.
13532 const diff*
13534 {
13535  const typedef_diff *d = 0;
13536  while ((d = is_typedef_diff(dif)))
13537  dif = d->underlying_type_diff().get();
13538  return dif;
13539 }
13540 
13541 /// If a diff node is about changes between two pointer types, get the
13542 /// diff node about changes between the underlying (pointed-to) types.
13543 ///
13544 /// Note that this function walks the tree of underlying diff nodes
13545 /// returns the first diff node about types that are not pointers.
13546 ///
13547 /// @param dif the dif node to consider.
13548 ///
13549 /// @return the underlying diff node of @p dif, or just return @p dif
13550 /// if it's not a pointer diff node.
13551 const diff*
13553 {
13554  const pointer_diff *d = 0;
13555  while ((d = is_pointer_diff(dif)))
13556  dif = d->underlying_type_diff().get();
13557  return dif;
13558 }
13559 
13560 /// If a diff node is about changes between two reference types, get
13561 /// the diff node about changes between the underlying (pointed-to)
13562 /// types.
13563 ///
13564 /// Note that this function walks the tree of underlying diff nodes
13565 /// returns the first diff node about types that are not references.
13566 ///
13567 /// @param dif the dif node to consider.
13568 ///
13569 /// @return the underlying diff node of @p dif, or just return @p dif
13570 /// if it's not a reference diff node.
13571 const diff*
13573 {
13574  const reference_diff *d = 0;
13575  while ((d = is_reference_diff(dif)))
13576  dif = d->underlying_type_diff().get();
13577  return dif;
13578 }
13579 
13580 /// If a diff node is about changes between two qualified types, get
13581 /// the diff node about changes between the underlying (non-qualified)
13582 /// types.
13583 ///
13584 /// Note that this function walks the tree of underlying diff nodes
13585 /// returns the first diff node about types that are not qualified.
13586 ///
13587 /// @param dif the dif node to consider.
13588 ///
13589 /// @return the underlying diff node of @p dif, or just return @p dif
13590 /// if it's not a qualified diff node.
13591 const diff*
13593 {
13594  const qualified_type_diff *d = 0;
13595  while ((d = is_qualified_type_diff(dif)))
13596  dif = d->underlying_type_diff().get();
13597  return dif;
13598 }
13599 
13600 /// If a diff node is about changes between two function parameters
13601 /// get the diff node about changes between the types of the parameters.
13602 ///
13603 /// @param dif the dif node to consider.
13604 ///
13605 /// @return the diff of the types of the parameters.
13606 const diff*
13608 {
13609  const fn_parm_diff *d = 0;
13610  while ((d = is_fn_parm_diff(dif)))
13611  dif = d->type_diff().get();
13612  return dif;
13613 }
13614 
13615 /// If a diff node is about changes between two pointer, reference or
13616 /// qualified types, get the diff node about changes between the
13617 /// underlying types.
13618 ///
13619 /// Note that this function walks the tree of underlying diff nodes
13620 /// returns the first diff node about types that are not pointer,
13621 /// reference or qualified.
13622 ///
13623 /// @param dif the dif node to consider.
13624 ///
13625 /// @return the underlying diff node of @p dif, or just return @p dif
13626 /// if it's not a pointer, reference or qualified diff node.
13627 const diff*
13629 {
13630  while (true)
13631  {
13632  if (const pointer_diff *d = is_pointer_diff(dif))
13633  dif = peel_pointer_diff(d);
13634  else if (const reference_diff *d = is_reference_diff(dif))
13635  dif = peel_reference_diff(d);
13636  else if (const qualified_type_diff *d = is_qualified_type_diff(dif))
13637  dif = peel_qualified_diff(d);
13638  else
13639  break;
13640  }
13641  return dif;
13642 }
13643 
13644 /// If a diff node is about changes between two typedefs or qualified
13645 /// types, get the diff node about changes between the underlying
13646 /// types.
13647 ///
13648 /// Note that this function walks the tree of underlying diff nodes
13649 /// returns the first diff node about types that are not typedef or
13650 /// qualified types.
13651 ///
13652 /// @param dif the dif node to consider.
13653 ///
13654 /// @return the underlying diff node of @p dif, or just return @p dif
13655 /// if it's not typedef or qualified diff node.
13656 const diff*
13658 {
13659  while (true)
13660  {
13661  if (const typedef_diff *d = is_typedef_diff(dif))
13662  dif = peel_typedef_diff(d);
13663  else if (const qualified_type_diff *d = is_qualified_type_diff(dif))
13664  dif = peel_qualified_diff(d);
13665  else
13666  break;
13667  }
13668  return dif;
13669 }
13670 
13671 /// If a diff node is about changes between two typedefs or qualified
13672 /// types, get the diff node about changes between the underlying
13673 /// types.
13674 ///
13675 /// Note that this function walks the tree of underlying diff nodes
13676 /// returns the first diff node about types that are neither typedef,
13677 /// qualified type nor parameters.
13678 ///
13679 /// @param dif the dif node to consider.
13680 ///
13681 /// @return the diff node about changes between the underlying types.
13682 const diff*
13684 {
13685  while (true)
13686  {
13687  if (const typedef_diff *d = is_typedef_diff(dif))
13688  dif = peel_typedef_diff(d);
13689  else if (const qualified_type_diff *d = is_qualified_type_diff(dif))
13690  dif = peel_qualified_diff(d);
13691  else if (const fn_parm_diff *d = is_fn_parm_diff(dif))
13692  dif = peel_fn_parm_diff(d);
13693  else
13694  break;
13695  }
13696  return dif;
13697 }
13698 
13699 /// Test if a diff node represents a diff between two class or union
13700 /// types.
13701 ///
13702 /// @param d the diff node to consider.
13703 ///
13704 /// @return iff @p is a diff between two class or union types then
13705 /// return the instance of @ref class_or_union_diff that @p derives
13706 /// from. Otherwise, return nil.
13707 const class_or_union_diff*
13709 {return dynamic_cast<const class_or_union_diff*>(d);}
13710 
13711 /// Test if a given diff node carries *only* a local type change.
13712 ///
13713 /// @param d the diff node to consider.
13714 ///
13715 /// @return true iff @p has a change and that change is a local type
13716 /// change.
13717 static bool
13718 has_local_type_change_only(const diff *d)
13719 {
13720  if (enum change_kind k = d->has_local_changes())
13721  if ((k & LOCAL_NON_TYPE_CHANGE_KIND) == 0
13722  && (k & LOCAL_TYPE_CHANGE_KIND) != 0)
13723  return true;
13724 
13725  return false;
13726 }
13727 
13728 /// Test if a diff node is a decl diff that only carries a basic type
13729 /// change on its type diff sub-node.
13730 ///
13731 ///Note that that pointers/references/qualified types diffs to basic
13732 /// type diffs are considered as having basic type change only.
13733 ///
13734 /// @param d the diff node to consider.
13735 ///
13736 /// @return true iff @p d is a decl diff that only carries a basic
13737 /// type change on its type diff sub-node.
13738 bool
13740 {
13742 
13743  if (is_diff_of_basic_type(d, true) && d->has_changes())
13744  return true;
13745  else if (const var_diff * v = dynamic_cast<const var_diff*>(d))
13746  return (has_local_type_change_only(v)
13747  && is_diff_of_basic_type(v->type_diff().get(), true));
13748  else if (const fn_parm_diff * p = dynamic_cast<const fn_parm_diff*>(d))
13749  return (has_local_type_change_only(p)
13750  && is_diff_of_basic_type(p->type_diff().get(), true));
13751  else if (const function_decl_diff* f =
13752  dynamic_cast<const function_decl_diff*>(d))
13753  return (has_local_type_change_only(f)
13754  && f->type_diff()
13755  && is_diff_of_basic_type(f->type_diff()->return_type_diff().get(),
13756  true));
13757  return false;
13758 }
13759 }// end namespace comparison
13760 } // 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:1714
#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 unsigned_var_diff_sptr_map & changed_data_members() const
Getter of the map of data members that got replaced by another data member. The key of the map is the...
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:159
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:281
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.
The abstraction of a diff between two ptr_to_mbr_type.
virtual bool has_changes() const
Test whether the current 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 ptr_to_mbr_...
virtual ~ptr_to_mbr_diff()
Destructor of ptr_to_mbr_diff.
ptr_to_mbr_type_sptr first_ptr_to_mbr_type() const
Getter of the first pointer-to-member subject of the current diff node.
const diff_sptr containing_type_diff() const
Getter of the diff node carrying changes to the containing type of first subject of the current diff ...
const diff_sptr member_type_diff() const
Getter of the diff node carrying changes to the member type of first subject of the current diff node...
ptr_to_mbr_type_sptr second_ptr_to_mbr_type() const
Getter of the second pointer-to-member subject of the current diff node.
virtual enum change_kind has_local_changes() const
Test whether the current diff node carries any local change.
virtual const string & get_pretty_representation() const
Get the pretty representation of the current ptr_to_mbr_diff node.
virtual void report(ostream &, const string &indent="") const
Pure interface to report the diff in a serialized form that is legible for the user.
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:2533
shared_ptr< base_spec > base_spec_sptr
Convenience typedef.
Definition: abg-ir.h:4245
vector< base_spec_sptr > base_specs
Convenience typedef.
Definition: abg-ir.h:4250
vector< method_decl_sptr > member_functions
Convenience typedef.
Definition: abg-ir.h:4060
bool get_is_anonymous() const
Test if the current declaration is anonymous.
Definition: abg-ir.cc:4908
The abstraction of the version of an ELF symbol.
Definition: abg-ir.h:1194
Abstraction of an elf symbol.
Definition: abg-ir.h:923
const string & get_id_string() const
Get a string that is representative of a given elf_symbol.
Definition: abg-ir.cc:2528
std::vector< enumerator > enumerators
Convenience typedef for a list of enumerator.
Definition: abg-ir.h:2763
Abstraction for a function declaration.
Definition: abg-ir.h:3111
shared_ptr< parameter > parameter_sptr
Convenience typedef for a shared pointer on a function_decl::parameter.
Definition: abg-ir.h:3131
const function_type_sptr get_type() const
Return the type of the current instance of function_decl.
Definition: abg-ir.cc:22264
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:22612
An abstraction helper for type declarations.
Definition: abg-ir.h:1973
The base class of both types and declarations.
Definition: abg-ir.h:1368
Abstracts a variable declaration.
Definition: abg-ir.h:3008
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:21036
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_UNION_OR_CLASS_CHANGE_CATEGORY
This means that a diff node in the sub-tree carries a harmless union or class change.
@ HARMLESS_DECL_NAME_CHANGE_CATEGORY
This means that a diff node in the sub-tree carries a harmless declaration name change....
@ NO_CHANGE_CATEGORY
This means the diff node does not carry any (meaningful) change, or that it carries changes that have...
@ 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:50
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.
void sort_string_function_ptr_map(const string_function_ptr_map &map, vector< const function_decl * > &sorted)
Sort an instance of string_function_ptr_map map and stuff a resulting sorted vector of pointers to fu...
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_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.
shared_ptr< function_decl_diff > function_decl_diff_sptr
Convenience typedef for a shared pointer to a function_decl type.
shared_ptr< ptr_to_mbr_diff > ptr_to_mbr_diff_sptr
Typedef of a shared_ptr to ptr_to_mbr_diff.
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.
unordered_map< string, const 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.
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.
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.
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...
bool is_less_than(const function_decl_diff &first, const function_decl_diff &second)
Compare two function_decl_diff for the purpose of sorting.
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.
void sort_string_var_ptr_map(const string_var_ptr_map &map, vector< const var_decl * > &sorted)
Sort a map of string -> pointer to var_decl.
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.
unordered_map< string, const 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.
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 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:233
bool get_member_function_is_dtor(const function_decl &f)
Test whether a member function is a destructor.
Definition: abg-ir.cc:6695
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:5816
shared_ptr< function_decl > function_decl_sptr
Convenience typedef for a shared pointer on a function_decl.
Definition: abg-fwd.h:267
unordered_set< type_or_decl_base_sptr, type_or_decl_hash, type_or_decl_equal > artifact_sptr_set_type
A convenience typedef for a hash set of type_or_decl_base_sptr.
Definition: abg-ir.h:550
bool is_type(const type_or_decl_base &tod)
Test whether a declaration is a type.
Definition: abg-ir.cc:10665
bool is_anonymous_data_member(const decl_base &d)
Test if a decl is an anonymous data member.
Definition: abg-ir.cc:6113
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:11997
shared_ptr< elf_symbol > elf_symbol_sptr
A convenience typedef for a shared pointer to elf_symbol.
Definition: abg-ir.h:886
change_kind
A bitfield that gives callers of abigail::ir::equals() some insight about how different two internal ...
Definition: abg-ir.h:1323
@ LOCAL_TYPE_CHANGE_KIND
This means that a given IR artifact has a local type change.
Definition: abg-ir.h:1327
@ ALL_LOCAL_CHANGES_MASK
Testing (anding) against this mask means that a given IR artifact has local differences,...
Definition: abg-ir.h:1338
@ 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:1332
bool is_user_defined_type(const type_base *t)
Test if a type is user-defined.
Definition: abg-ir.cc:5720
bool collect_non_anonymous_data_members(const class_or_union *cou, string_decl_base_sptr_map &dms)
Collect all the non-anonymous data members of a class or union type.
Definition: abg-ir.cc:6056
bool is_class_type(const type_or_decl_base &t)
Test whether a type is a class.
Definition: abg-ir.cc:10947
shared_ptr< array_type_def > array_type_def_sptr
Convenience typedef for a shared pointer on a array_type_def.
Definition: abg-fwd.h:242
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:9456
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:11178
shared_ptr< class_decl > class_decl_sptr
Convenience typedef for a shared pointer on a class_decl.
Definition: abg-fwd.h:191
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:5983
shared_ptr< function_type > function_type_sptr
Convenience typedef for a shared pointer on a function_type.
Definition: abg-fwd.h:209
shared_ptr< typedef_decl > typedef_decl_sptr
Convenience typedef for a shared pointer on a typedef_decl.
Definition: abg-fwd.h:165
const enum_type_decl * is_enum_type(const type_or_decl_base *d)
Test if a decl is an enum_type_decl.
Definition: abg-ir.cc:10897
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:10508
const global_scope * get_global_scope(const decl_base &decl)
return the global scope as seen by a given declaration.
Definition: abg-ir.cc:8717
shared_ptr< var_decl > var_decl_sptr
Convenience typedef for a shared pointer on a var_decl.
Definition: abg-fwd.h:254
shared_ptr< ptr_to_mbr_type > ptr_to_mbr_type_sptr
Convenience typedef for a shared pointer to a ptr_to_mbr_type.
Definition: abg-fwd.h:238
shared_ptr< scope_decl > scope_decl_sptr
Convenience typedef for a shared pointer on a scope_decl.
Definition: abg-fwd.h:262
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
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.
Definition: abg-fwd.h:158
bool equals(const decl_base &l, const decl_base &r, change_kind *k)
Compares two instances of decl_base.
Definition: abg-ir.cc:5367
shared_ptr< pointer_type_def > pointer_type_def_sptr
Convenience typedef for a shared pointer on a pointer_type_def.
Definition: abg-fwd.h:224
bool is_enumerator_present_in_enum(const enum_type_decl::enumerator &enr, const enum_type_decl &enom)
Test if a given enumerator is found present in an enum.
Definition: abg-ir.cc:19932
uint64_t get_absolute_data_member_offset(const var_decl &m)
Get the absolute offset of a data member.
Definition: abg-ir.cc:6514
bool is_member_function(const function_decl &f)
Test whether a function_decl is a member function.
Definition: abg-ir.cc:6609
var_decl * is_var_decl(const type_or_decl_base *tod)
Tests if a declaration is a variable declaration.
Definition: abg-ir.cc:11841
decl_base * is_decl(const type_or_decl_base *d)
Test if an ABI artifact is a declaration.
Definition: abg-ir.cc:10605
shared_ptr< enum_type_decl > enum_type_decl_sptr
Convenience typedef for shared pointer to a enum_type_decl.
Definition: abg-fwd.h:173
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:6972
uint64_t get_data_member_offset(const var_decl &m)
Get the offset of a data member.
Definition: abg-ir.cc:6425
bool get_member_function_is_virtual(const function_decl &f)
Test if a given member function is virtual.
Definition: abg-ir.cc:6882
class_or_union * anonymous_data_member_to_class_or_union(const var_decl *d)
Get the class_or_union type of a given anonymous data member.
Definition: abg-ir.cc:6271
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:11700
bool is_union_type(const type_or_decl_base &t)
Test if a type is a union_decl.
Definition: abg-ir.cc:11227
bool is_data_member(const var_decl &v)
Test if a var_decl is a data member.
Definition: abg-ir.cc:5854
const decl_base * get_type_declaration(const type_base *t)
Get the declaration for a given type.
Definition: abg-ir.cc:10298
const var_decl * lookup_data_member(const type_base *type, const char *dm_name)
Look for a data member of a given class, struct or union type and return it.
Definition: abg-ir.cc:28388
interned_string get_function_id_or_pretty_representation(const function_decl *fn)
Get the ID of a function, or, if the ID can designate several different functions,...
Definition: abg-ir.cc:9348
shared_ptr< type_decl > type_decl_sptr
Convenience typedef for a shared pointer on a type_decl.
Definition: abg-fwd.h:160
bool is_unique_type(const type_base_sptr &t)
Test if a type is unique in the entire environment.
Definition: abg-ir.cc:27983
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:11670
bool class_or_union_types_of_same_kind(const class_or_union *first, const class_or_union *second)
Test if two class or union types are of the same kind.
Definition: abg-ir.cc:11199
bool is_at_global_scope(const decl_base &decl)
Tests whether a given declaration is at global scope.
Definition: abg-ir.cc:10438
bool is_member_decl(const decl_base_sptr d)
Tests if a declaration is a class member.
Definition: abg-ir.cc:5658
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:1658
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_opaque_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:1652
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.
const string_diff_sptr_map & changed_unreachable_types() const
Get the map of diff nodes representing changed unreachable types.
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 private data of the ptr_to_mbr_diff type.
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:3245
A deleter for shared pointers that ... doesn't delete the object managed by the shared pointer.