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