libabigail
abg-comparison.cc
Go to the documentation of this file.
1 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
2 // -*- Mode: C++ -*-
3 //
4 // Copyright (C) 2013-2023 Red Hat, Inc.
5 //
6 // Author: Dodji Seketeli
7 
8 /// @file
9 ///
10 /// This contains the implementation of the comparison engine of
11 /// libabigail.
12 
13 #include <ctype.h>
14 #include <libgen.h>
15 #include <algorithm>
16 #include <sstream>
17 
18 #include "abg-comparison-priv.h"
19 #include "abg-reporter-priv.h"
20 #include "abg-tools-utils.h"
21 
22 namespace abigail
23 {
24 
25 namespace comparison
26 {
27 
28 ///
29 ///
30 ///@defgroup DiffNode Internal Representation of the comparison engine
31 /// @{
32 ///
33 /// @brief How changes are represented in libabigail's comparison engine.
34 ///
35 ///@par diff nodes
36 ///
37 /// The internal representation of the comparison engine is basically
38 /// a graph of @ref instances of @ref diff node. We refer to these
39 /// just as <em>diff nodes</em>. A diff node represents a change
40 /// between two ABI artifacts represented by instances of types of the
41 /// abigail::ir namespace. These two artifacts that are being
42 /// compared are called the <em>subjects of the diff</em>.
43 ///
44 /// The types of that IR are in the abigail::comparison namespace.
45 ///
46 ///@par comparing diff nodes
47 ///
48 /// Comparing two instances of @ref diff nodes amounts to comparing
49 /// the subject of the diff. In other words, two @ref diff nodes are
50 /// equal if and only if their subjects are equal. Thus, two @ref
51 /// diff nodes can have different memory addresses and yet be equal.
52 ///
53 ///@par diff reporting and context
54 ///
55 /// A diff node can be serialized to an output stream to express, in
56 /// a human-readable textual form, the different changes that exist
57 /// between its two subjects. This is done by invoking the
58 /// diff::report() method. That reporting is controlled by several
59 /// parameters that are conceptually part of the context of the diff.
60 /// That context is materialized by an instance of the @ref
61 /// diff_context type.
62 ///
63 /// Please note that the role of the instance(s) of @ref diff_context
64 /// is boreader than just controlling the reporting of @ref diff
65 /// nodes. Basically, a @ref diff node itself is created following
66 /// behaviours that are controlled by a particular instance of
67 /// diff_context. A diff node is created in a particular diff
68 /// context, so to speak.
69 ///
70 /// @}
71 ///
72 
73 ///
74 ///@defgroup CanonicalDiff Canonical diff tree nodes
75 /// @{
76 ///
77 /// @brief How equivalent diff nodes are quickly spotted.
78 ///
79 /// @par Equivalence of diff nodes.
80 ///
81 /// Each @ref diff node has a property named <em>Canonical Diff
82 /// Node</em>. If \c D is a diff node, the canonical diff node of @c
83 /// D, noted @c C(D) is a particular diff node that is equal to @c D.
84 /// Thus, a fast way to compare two @ref diff node is to perform a
85 /// pointer comparison of their canonical diff nodes.
86 ///
87 /// A set of equivalent @ref diff nodes is a set of diff nodes that
88 /// all have the same canonical node. All the nodes of that set are
89 /// equal.
90 ///
91 /// A canonical node is registereded for a given diff node by invoking
92 /// the method diff_context::initialize_canonical_diff().
93 ///
94 /// Please note that the diff_context holds all the canonical diffs
95 /// that got registered through it. Thus, the life time of all of
96 /// canonical diff objects is the same as the life time of the @ref
97 /// diff_context they relate to.
98 ///
99 /// @}
100 ///
101 
102 // -----------------------------------------
103 // <private functions re-usable elsewhere>
104 // -----------------------------------------
105 /// Sort a map of enumerators by their value.
106 ///
107 /// @param enumerators_map the map to sort.
108 ///
109 /// @param sorted the resulting vector of sorted enumerators.
110 void
113 {
114  for (string_enumerator_map::const_iterator i = enumerators_map.begin();
115  i != enumerators_map.end();
116  ++i)
117  sorted.push_back(i->second);
119  std::sort(sorted.begin(), sorted.end(), comp);
120 }
121 
122 /// Sort a map of changed enumerators.
123 ///
124 /// @param enumerators_map the map to sort.
125 ///
126 ///@param output parameter. The resulting sorted enumerators.
127 void
129  changed_enumerators_type& sorted)
130 {
131  for (string_changed_enumerator_map::const_iterator i =
132  enumerators_map.begin();
133  i != enumerators_map.end();
134  ++i)
135  sorted.push_back(i->second);
136 
138  std::sort(sorted.begin(), sorted.end(), comp);
139 }
140 
141 /// Sort a map of data members by the offset of their initial value.
142 ///
143 /// @param data_members the map of changed data members to sort.
144 ///
145 /// @param sorted the resulting vector of sorted changed data members.
146 void
148  vector<decl_base_sptr>& sorted)
149 {
150  sorted.reserve(data_members.size());
151  for (string_decl_base_sptr_map::const_iterator i = data_members.begin();
152  i != data_members.end();
153  ++i)
154  sorted.push_back(i->second);
155 
156  data_member_comp comp;
157  std::sort(sorted.begin(), sorted.end(), comp);
158 }
159 
160 /// Sort (in place) a vector of changed data members.
161 ///
162 /// @param to_sort the vector to sort.
163 void
165 {
166  data_member_comp comp;
167  std::sort(to_sort.begin(), to_sort.end(), comp);
168 }
169 
170 /// Sort an instance of @ref string_function_ptr_map map and stuff a
171 /// resulting sorted vector of pointers to function_decl.
172 ///
173 /// @param map the map to sort.
174 ///
175 /// @param sorted the resulting sorted vector.
176 void
178  vector<function_decl*>& sorted)
179 {
180  sorted.reserve(map.size());
181  for (string_function_ptr_map::const_iterator i = map.begin();
182  i != map.end();
183  ++i)
184  sorted.push_back(i->second);
185 
186  function_comp comp;
187  std::sort(sorted.begin(), sorted.end(), comp);
188 }
189 
190 /// Sort a map that's an instance of @ref
191 /// string_member_function_sptr_map and fill a vector of member
192 /// functions with the sorted result.
193 ///
194 /// @param map the map to sort.
195 ///
196 /// @param sorted the resulting sorted vector.
197 void
200 {
201  sorted.reserve(map.size());
202  for (string_member_function_sptr_map::const_iterator i = map.begin();
203  i != map.end();
204  ++i)
205  sorted.push_back(i->second);
206 
207  function_comp comp;
208  std::sort(sorted.begin(), sorted.end(), comp);
209 }
210 
211 /// Sort the values of a @ref string_function_decl_diff_sptr_map map
212 /// and store the result in a vector of @ref function_decl_diff_sptr
213 /// objects.
214 ///
215 /// @param map the map whose values to store.
216 ///
217 /// @param sorted the vector of function_decl_diff_sptr to store the
218 /// result of the sort into.
219 void
223 {
224  sorted.reserve(map.size());
225  for (string_function_decl_diff_sptr_map::const_iterator i = map.begin();
226  i != map.end();
227  ++i)
228  sorted.push_back(i->second);
230  std::sort(sorted.begin(), sorted.end(), comp);
231 }
232 
233 /// Sort of an instance of @ref string_var_diff_sptr_map map.
234 ///
235 /// @param map the input map to sort.
236 ///
237 /// @param sorted the ouptut sorted vector of @ref var_diff_sptr.
238 /// It's populated with the sorted content.
239 void
241  var_diff_sptrs_type& sorted)
242 {
243  sorted.reserve(map.size());
244  for (string_var_diff_sptr_map::const_iterator i = map.begin();
245  i != map.end();
246  ++i)
247  sorted.push_back(i->second);
248 
249  var_diff_sptr_comp comp;
250  std::sort(sorted.begin(), sorted.end(), comp);
251 }
252 
253 /// Sort a map of string -> pointer to @ref elf_symbol.
254 ///
255 /// The result is a vector of @ref elf_symbol_sptr sorted by the
256 /// name of the symbol.
257 ///
258 /// @param map the map to sort.
259 ///
260 /// @param sorted out parameter; the sorted vector of @ref
261 /// elf_symbol_sptr.
262 void
264  vector<elf_symbol_sptr>& sorted)
265 {
266  for (string_elf_symbol_map::const_iterator i = map.begin();
267  i!= map.end();
268  ++i)
269  sorted.push_back(i->second);
270 
271  elf_symbol_comp comp;
272  std::sort(sorted.begin(), sorted.end(), comp);
273 }
274 
275 /// Sort a map of string -> pointer to @ref var_decl.
276 ///
277 /// The result is a vector of var_decl* sorted by the qualified name
278 /// of the variables.
279 ///
280 /// @param map the map to sort.
281 ///
282 /// @param sorted out parameter; the sorted vector of @ref var_decl.
283 void
285  vector<var_decl*>& sorted)
286 {
287  for (string_var_ptr_map::const_iterator i = map.begin();
288  i != map.end();
289  ++i)
290  sorted.push_back(i->second);
291 
292  var_comp comp;
293  std::sort(sorted.begin(), sorted.end(), comp);
294 }
295 
296 /// Sort the values of a string_var_diff_sptr_map and store the result
297 /// in a vector of var_diff_sptr.
298 ///
299 /// @param map the map of changed data members to sort.
300 ///
301 /// @param sorted the resulting vector of var_diff_sptr.
302 void
304  var_diff_sptrs_type& sorted)
305 {
306  sorted.reserve(map.size());
307  for (string_var_diff_sptr_map::const_iterator i = map.begin();
308  i != map.end();
309  ++i)
310  sorted.push_back(i->second);
312  std::sort(sorted.begin(), sorted.end(), comp);
313 }
314 
315 /// Sort the values of a unsigned_var_diff_sptr_map map and store the
316 /// result into a vector of var_diff_sptr.
317 ///
318 /// @param map the map of changed data members to sort.
319 ///
320 /// @param sorted the resulting vector of sorted var_diff_sptr.
321 void
323  var_diff_sptrs_type& sorted)
324 {
325  sorted.reserve(map.size());
326  for (unsigned_var_diff_sptr_map::const_iterator i = map.begin();
327  i != map.end();
328  ++i)
329  sorted.push_back(i->second);
331  std::sort(sorted.begin(), sorted.end(), comp);
332 }
333 
334 /// Sort an map of string -> virtual member function into a vector of
335 /// virtual member functions. The virtual member functions are sorted
336 /// by increasing order of their virtual index.
337 ///
338 /// @param map the input map.
339 ///
340 /// @param sorted the resulting sorted vector of virtual function
341 /// member.
342 void
346 {
347  sorted.reserve(map.size());
348  for (string_function_decl_diff_sptr_map::const_iterator i = map.begin();
349  i != map.end();
350  ++i)
351  sorted.push_back(i->second);
352 
354  sort(sorted.begin(), sorted.end(), comp);
355 }
356 
357 /// Sort a map ofg string -> @ref diff_sptr into a vector of @ref
358 /// diff_sptr. The diff_sptr are sorted lexicographically wrt
359 /// qualified names of their first subjects.
360 ///
361 /// @param map the map to sort.
362 ///
363 /// @param sorted the resulting sorted vector.
364 void
366  diff_sptrs_type& sorted)
367 {
368  sorted.reserve(map.size());
369  for (string_diff_sptr_map::const_iterator i = map.begin();
370  i != map.end();
371  ++i)
372  sorted.push_back(i->second);
373 
374  diff_comp comp;
375  sort(sorted.begin(), sorted.end(), comp);
376 }
377 
378 /// Sort a map ofg string -> @ref diff* into a vector of @ref
379 /// diff_ptr. The diff_ptr are sorted lexicographically wrt
380 /// qualified names of their first subjects.
381 ///
382 /// @param map the map to sort.
383 ///
384 /// @param sorted the resulting sorted vector.
385 void
387  diff_ptrs_type& sorted)
388 {
389  sorted.reserve(map.size());
390  for (string_diff_ptr_map::const_iterator i = map.begin();
391  i != map.end();
392  ++i)
393  sorted.push_back(i->second);
394 
395  diff_comp comp;
396  sort(sorted.begin(), sorted.end(), comp);
397 }
398 
399 /// Sort a map of string -> base_diff_sptr into a sorted vector of
400 /// base_diff_sptr. The base_diff_sptr are sorted by increasing value
401 /// of their offset in their containing type.
402 ///
403 /// @param map the input map to sort.
404 ///
405 /// @param sorted the resulting sorted vector.
406 void
408  base_diff_sptrs_type& sorted)
409 {
410  for (string_base_diff_sptr_map::const_iterator i = map.begin();
411  i != map.end();
412  ++i)
413  sorted.push_back(i->second);
414  base_diff_comp comp;
415  sort(sorted.begin(), sorted.end(), comp);
416 }
417 
418 /// Lexicographically sort base specifications found
419 /// in instances of string_base_sptr_map.
420 void
422  class_decl::base_specs& sorted)
423 {
424  for (string_base_sptr_map::const_iterator i = m.begin();
425  i != m.end();
426  ++i)
427  sorted.push_back(i->second);
428 
429  base_spec_comp comp;
430  std::sort(sorted.begin(), sorted.end(), comp);
431 }
432 
433 /// Sort a map of @ref fn_parm_diff by the indexes of the function
434 /// parameters.
435 ///
436 /// @param map the map to sort.
437 ///
438 /// @param sorted the resulting sorted vector of changed function
439 /// parms.
440 void
442  vector<fn_parm_diff_sptr>& sorted)
443 {
444  sorted.reserve(map.size());
445  for (unsigned_fn_parm_diff_sptr_map::const_iterator i = map.begin();
446  i != map.end();
447  ++i)
448  sorted.push_back(i->second);
449 
450  fn_parm_diff_comp comp;
451  std::sort(sorted.begin(), sorted.end(), comp);
452 }
453 
454 /// Sort a map of changed function parameters by the indexes of the
455 /// function parameters.
456 ///
457 /// @param map the map to sort.
458 ///
459 /// @param sorted the resulting sorted vector of instances of @ref
460 /// fn_parm_diff_sptr
461 void
463  vector<fn_parm_diff_sptr>& sorted)
464 {
465  sorted.reserve(map.size());
466  for (string_fn_parm_diff_sptr_map::const_iterator i = map.begin();
467  i != map.end();
468  ++i)
469  sorted.push_back(i->second);
470 
471  fn_parm_diff_comp comp;
472  std::sort(sorted.begin(), sorted.end(), comp);
473 }
474 
475 /// Sort a map of string -> function parameters.
476 ///
477 /// @param map the map to sort.
478 ///
479 /// @param sorted the resulting sorted vector of
480 /// @ref vector<function_decl::parameter_sptr>
481 void
483  vector<function_decl::parameter_sptr>& sorted)
484 {
485  for (string_parm_map::const_iterator i = map.begin();
486  i != map.end();
487  ++i)
488  sorted.push_back(i->second);
489 
490  parm_comp comp;
491  std::sort(sorted.begin(), sorted.end(), comp);
492 }
493 
494 /// Sort the set of ABI artifacts contained in a @ref
495 /// artifact_sptr_set_type.
496 ///
497 /// @param set the set of ABI artifacts to sort.
498 ///
499 /// @param output parameter the vector containing the sorted ABI
500 /// artifacts.
501 void
503  vector<type_or_decl_base_sptr>& sorted)
504 {
505 
506  for (artifact_sptr_set_type::const_iterator it = set.begin();
507  it != set.end();
508  ++it)
509  sorted.push_back(*it);
510 
512  std::sort(sorted.begin(), sorted.end(), comp);
513 }
514 
515 /// Sort a map of string to type_base_sptr entities.
516 ///
517 /// The entries are sorted based on the lexicographic order of the
518 /// pretty representation of the type_sptr_sptr. The sorted result is
519 /// put in a vector of type_base_sptr.
520 ///
521 /// @param map the map to sort.
522 ///
523 /// @param sorted the resulting vector of type_base_sptr
524 /// lexicographically sorted using their pretty representation.
525 void
527  vector<type_base_sptr>& sorted)
528 {
529  for (string_type_base_sptr_map::const_iterator i = map.begin();
530  i != map.end();
531  ++i)
532  sorted.push_back(i->second);
533 
535  std::sort(sorted.begin(), sorted.end(), comp);
536 }
537 
538 /// Return the first underlying type that is not a qualified type.
539 /// @param t the qualified type to consider.
540 ///
541 /// @return the first underlying type that is not a qualified type, or
542 /// NULL if t is NULL.
543 type_base_sptr
544 get_leaf_type(qualified_type_def_sptr t)
545 {
546  if (!t)
547  return type_base_sptr();
548 
549  type_base_sptr ut = t->get_underlying_type();
550  qualified_type_def_sptr qut = dynamic_pointer_cast<qualified_type_def>(ut);
551 
552  if (!qut)
553  return ut;
554  return get_leaf_type(qut);
555 }
556 
557 /// Tests if a given diff node is to represent the changes between two
558 /// gobal decls.
559 ///
560 /// @param d the diff node to consider.
561 ///
562 /// @return true iff @p d represents the changes between two global
563 /// decls.
564 bool
566 {
567  ABG_ASSERT(d != 0);
568 
569  if (d == 0)
570  return false;
571 
573  ABG_ASSERT(first);
574 
576  ABG_ASSERT(second);
577 
578  if (decl_base_sptr decl = is_decl(first))
579  if (is_at_global_scope(decl))
580  if ((decl = is_decl(second)))
581  if (is_at_global_scope(decl))
582  return true;
583 
584  return false;
585 }
586 
587 // -----------------------------------------
588 // </private functions re-usable elsewhere>
589 // -----------------------------------------
590 
591 /// The overloaded or operator for @ref visiting_kind.
594 {return static_cast<visiting_kind>(static_cast<unsigned>(l)
595  | static_cast<unsigned>(r));}
596 
597 /// The overloaded and operator for @ref visiting_kind.
600 {
601  return static_cast<visiting_kind>(static_cast<unsigned>(l)
602  & static_cast<unsigned>(r));
603 }
604 
605 /// The overloaded 'bit inversion' operator for @ref visiting_kind.
608 {return static_cast<visiting_kind>(~static_cast<unsigned>(l));}
609 
610 /// Test if a diff node is about differences between types.
611 ///
612 /// @param diff the diff node to test.
613 ///
614 /// @return a pointer to the actual type_diff_base* that @p diff
615 /// extends, iff it is about differences between types.
616 const type_diff_base*
618 {return dynamic_cast<const type_diff_base*>(diff);}
619 
620 /// Test if a diff node is about differences between declarations.
621 ///
622 /// @param diff the diff node to test.
623 ///
624 /// @return a pointer to the actual decl_diff_base @p diff extends,
625 /// iff it is about differences between declarations.
626 const decl_diff_base*
628 {return dynamic_cast<const decl_diff_base*>(diff);}
629 
630 /// Test if a diff node is a @ref class_diff node.
631 ///
632 /// @param diff the diff node to consider.
633 ///
634 /// @return a non-nil pointer to a @ref class_diff iff @p diff is a
635 /// @ref class_diff node.
636 const class_diff*
638 {return dynamic_cast<const class_diff*>(diff);}
639 
640 /// Test if a diff node is a @ref enum_diff node.
641 ///
642 /// @param diff the diff node to consider.
643 ///
644 /// @return a non-nil pointer to ad @ref enum_diff node iff @p diff is
645 /// a @ref enum_diff node.
646 const enum_diff*
648 {return dynamic_cast<const enum_diff*>(diff);}
649 
650 /// Test if a diff node is a @ref union_diff node.
651 ///
652 /// @param diff the diff node to consider.
653 ///
654 /// @return a non-nil pointer to a @ref union_diff iff @p diff is a
655 /// @ref union_diff node.
656 const union_diff*
658 {return dynamic_cast<const union_diff*>(diff);}
659 
660 /// Test if a diff node is a @ref class_or_union_diff node.
661 ///
662 /// @param d the diff node to consider.
663 ///
664 /// @return a non-nil pointer to the @ref class_or_union_diff denoted
665 /// by @p d iff @p d is a @ref class_or_union_diff.
666 const class_or_union_diff*
668 {return dynamic_cast<const class_or_union_diff*>(d);}
669 
670 /// Test if a diff node is a @ref class_or_union_diff between two
671 /// anonymous classes or unions.
672 ///
673 /// @param d the diff node to consider.
674 ///
675 /// @return a non-nil pointer to the @ref class_or_union_diff iff @p
676 /// denoted by @p d iff @p is pointer to an anonymous class or union
677 /// diff.
678 const class_or_union_diff*
680 {
681  if (const class_or_union_diff *dif = is_class_or_union_diff(d))
682  if (dif->first_class_or_union()->get_is_anonymous())
683  return dif;
684  return 0;
685 }
686 
687 /// Test if a diff node is a @ref typedef_diff node.
688 ///
689 /// @param diff the diff node to consider.
690 ///
691 /// @return a non-nil pointer to a @ref typedef_diff iff @p diff is a
692 /// @ref typedef_diff node.
693 const typedef_diff*
695 {return dynamic_cast<const typedef_diff*>(diff);}
696 
697 /// Test if a diff node is a @ref subrange_diff node.
698 ///
699 /// @param diff the diff node to consider.
700 ///
701 /// @return a non-nil pointer to a @ref subrange_diff iff @p diff is a
702 /// @ref subrange_diff node.
703 const subrange_diff*
705 {return dynamic_cast<const subrange_diff*>(diff);}
706 
707 /// Test if a diff node is a @ref array_diff node.
708 ///
709 /// @param diff the diff node to consider.
710 ///
711 /// @return a non-nil pointer to a @ref array_diff iff @p diff is a
712 /// @ref array_diff node.
713 const array_diff*
715 {return dynamic_cast<const array_diff*>(diff);}
716 
717 /// Test if a diff node is a @ref function_type_diff node.
718 ///
719 /// @param diff the diff node to consider.
720 ///
721 /// @return a non-nil pointer to a @ref function_type_diff iff @p diff is a
722 /// @ref function_type_diff node.
723 const function_type_diff*
725 {return dynamic_cast<const function_type_diff*>(diff);}
726 
727 /// Test if a given diff node carries a function type change with
728 /// local changes.
729 ///
730 /// @param diff the diff node to consider.
731 ///
732 /// @return a non-nil pointer to a @ref function_type_diff iff @p diff
733 /// is a function_type_diff node that carries a local change.
734 const function_type_diff*
736 {
738  if (d->has_local_changes())
739  return d;
740 
741  return 0;
742 }
743 
744 /// Test if a diff node is about differences between variables.
745 ///
746 /// @param diff the diff node to test.
747 ///
748 /// @return a pointer to the actual var_diff that @p diff is a type
749 /// of, iff it is about differences between variables.
750 const var_diff*
752 {
753  const var_diff* d = dynamic_cast<const var_diff*>(diff);
754  if (d)
756  return d;
757 }
758 
759 /// Test if a diff node is about differences between functions.
760 ///
761 /// @param diff the diff node to test.
762 ///
763 /// @return a pointer to the actual var_diff that @p diff is a type
764 /// of, iff it is about differences between variables.
765 const function_decl_diff*
767 {
768  const function_decl_diff *d = dynamic_cast<const function_decl_diff*>(diff);
769  if (d)
771  return d;
772 }
773 
774 /// Test if a diff node is about differences between two pointers.
775 ///
776 /// @param diff the diff node to consider.
777 ///
778 /// @return the @p diff converted into an instance of @ref
779 /// pointer_diff iff @p diff is about differences between two
780 /// pointers.
781 const pointer_diff*
783 {return dynamic_cast<const pointer_diff*>(diff);}
784 
785 /// Test if a diff node is about differences between two references.
786 ///
787 /// @param diff the diff node to consider.
788 ///
789 /// @return the @p diff converted into an instance of @ref
790 /// reference_diff iff @p diff is about differences between two
791 /// references.
792 const reference_diff*
794 {return dynamic_cast<const reference_diff*>(diff);}
795 
796 /// Test if a diff node is about differences between two qualified
797 /// types.
798 ///
799 /// @param diff the diff node to consider.
800 ///
801 /// @return @p diff converted into an instance of @ref
802 /// qualified_type_diff iff @p diff is about differences between two
803 /// qualified types.
804 const qualified_type_diff*
806 {return dynamic_cast<const qualified_type_diff*>(diff);}
807 
808 /// Test if a diff node is a reference or pointer diff node to a
809 /// change that is neither basic type change nor distinct type change.
810 ///
811 /// Note that this function also works on diffs of typedefs of
812 /// reference or pointer.
813 ///
814 /// @param diff the diff node to consider.
815 ///
816 /// @return true iff @p diff is a eference or pointer diff node to a
817 /// change that is neither basic type change nor distinct type change.
818 bool
820 {
822  if (const reference_diff* d = is_reference_diff(diff))
823  {
826  return false;
827  return true;
828  }
829  else if (const pointer_diff *d = is_pointer_diff(diff))
830  {
831  diff = peel_pointer_diff(d);
833  return false;
834  return true;
835  }
836 
837  return false;
838 }
839 
840 /// Test if a diff node is about differences between two function
841 /// parameters.
842 ///
843 /// @param diff the diff node to consider.
844 ///
845 /// @return the @p diff converted into an instance of @ref
846 /// reference_diff iff @p diff is about differences between two
847 /// function parameters.
848 const fn_parm_diff*
850 {return dynamic_cast<const fn_parm_diff*>(diff);}
851 
852 /// Test if a diff node is about differences between two base class
853 /// specifiers.
854 ///
855 /// @param diff the diff node to consider.
856 ///
857 /// @return the @p diff converted into an instance of @ref base_diff
858 /// iff @p diff is about differences between two base class
859 /// specifiers.
860 const base_diff*
862 {return dynamic_cast<const base_diff*>(diff);}
863 
864 /// Test if a diff node is about differences between two diff nodes of
865 /// different kinds.
866 ///
867 /// @param diff the diff node to consider.
868 ///
869 /// @return the @p diff converted into an instance of @ref
870 /// distintc_diff iff @p diff is about differences between two diff
871 /// nodes of different kinds.
872 const distinct_diff*
874 {return dynamic_cast<const distinct_diff*>(diff);}
875 
876 /// Test if a diff node is a @ref corpus_diff node.
877 ///
878 /// @param diff the diff node to consider.
879 ///
880 /// @return a non-nil pointer to a @ref corpus_diff iff @p diff is a
881 /// @ref corpus_diff node.
882 const corpus_diff*
884 {return dynamic_cast<const corpus_diff*>(diff);}
885 
886 /// Test if a diff node is a child node of a function parameter diff node.
887 ///
888 /// @param diff the diff node to test.
889 ///
890 /// @return true iff @p diff is a child node of a function parameter
891 /// diff node.
892 bool
894 {return diff && is_fn_parm_diff(diff->parent_node());}
895 
896 /// Test if a diff node is a child node of a base diff node.
897 ///
898 /// @param diff the diff node to test.
899 ///
900 /// @return true iff @p diff is a child node of a base diff node.
901 bool
903 {return diff && is_base_diff(diff->parent_node());}
904 
905 /// The default traverse function.
906 ///
907 /// @return true.
908 bool
910 {return true;}
911 
912 diff_context::diff_context()
913  : priv_(new diff_context::priv)
914 {
915  // Setup all the diff output filters we have.
917 
919  add_diff_filter(f);
920 
921  // f.reset(new filtering::harmless_filter);
922  // add_diff_filter(f);
923 
924  // f.reset(new filtering::harmful_filter);
925  // add_diff_filter(f);
926 }
927 
928 diff_context::~diff_context() = default;
929 
930 /// Test if logging was requested.
931 ///
932 /// @return true iff logging was requested.
933 bool
935 {return priv_->do_log_;}
936 
937 /// Set logging as requested.
938 ///
939 /// @param f the flag
940 void
942 {priv_->do_log_ = f;}
943 
944 /// Set the corpus diff relevant to this context.
945 ///
946 /// @param d the corpus_diff we are interested in.
947 void
949 {priv_->corpus_diff_ = d;}
950 
951 /// Get the corpus diff for the current context.
952 ///
953 /// @return the corpus diff of this context.
954 const corpus_diff_sptr&
956 {return priv_->corpus_diff_;}
957 
958 /// Getter for the first corpus of the corpus diff of the current context.
959 ///
960 /// @return the first corpus of the corpus diff of the current
961 /// context, if no corpus diff is associated to the context.
962 corpus_sptr
964 {
965  if (priv_->corpus_diff_)
966  return priv_->corpus_diff_->first_corpus();
967  return corpus_sptr();
968 }
969 
970 /// Getter for the second corpus of the corpus diff of the current
971 /// context.
972 ///
973 /// @return the second corpus of the corpus diff of the current
974 /// context, if no corpus diff is associated to the context.
975 corpus_sptr
977 {
978  if (priv_->corpus_diff_)
979  return priv_->corpus_diff_->second_corpus();
980  return corpus_sptr();
981 }
982 
983 /// Getter of the reporter to be used in this context.
984 ///
985 /// @return the reporter to be used in this context.
988 {
989  if (!priv_->reporter_)
990  {
992  priv_->reporter_.reset(new leaf_reporter);
993  else
994  priv_->reporter_.reset(new default_reporter);
995  }
996  ABG_ASSERT(priv_->reporter_);
997  return priv_->reporter_;
998 }
999 
1000 /// Setter of the reporter to be used in this context.
1001 ///
1002 /// @param r the reporter to be used in this context.
1003 void
1005 {priv_->reporter_ = r;}
1006 
1007 /// Tests if the current diff context already has a diff for two decls.
1008 ///
1009 /// @param first the first decl to consider.
1010 ///
1011 /// @param second the second decl to consider.
1012 ///
1013 /// @return a pointer to the diff for @p first @p second if found,
1014 /// null otherwise.
1015 diff_sptr
1016 diff_context::has_diff_for(const type_or_decl_base_sptr first,
1017  const type_or_decl_base_sptr second) const
1018 {
1019  types_or_decls_diff_map_type::const_iterator i =
1020  priv_->types_or_decls_diff_map.find(std::make_pair(first, second));
1021  if (i != priv_->types_or_decls_diff_map.end())
1022  return i->second;
1023  return diff_sptr();
1024 }
1025 
1026 /// Tests if the current diff context already has a diff for two types.
1027 ///
1028 /// @param first the first type to consider.
1029 ///
1030 /// @param second the second type to consider.
1031 ///
1032 /// @return a pointer to the diff for @p first @p second if found,
1033 /// null otherwise.
1034 diff_sptr
1035 diff_context::has_diff_for_types(const type_base_sptr first,
1036  const type_base_sptr second) const
1037 {return has_diff_for(first, second);}
1038 
1039 /// Tests if the current diff context already has a given diff.
1040 ///
1041 ///@param d the diff to consider.
1042 ///
1043 /// @return a pointer to the diff found for @p d
1044 const diff*
1045 diff_context::has_diff_for(const diff* d) const
1046 {return has_diff_for(d->first_subject(), d->second_subject()).get();}
1047 
1048 /// Tests if the current diff context already has a given diff.
1049 ///
1050 ///@param d the diff to consider.
1051 ///
1052 /// @return a pointer to the diff found for @p d
1053 diff_sptr
1054 diff_context::has_diff_for(const diff_sptr d) const
1055 {return has_diff_for(d->first_subject(), d->second_subject());}
1056 
1057 /// Getter for the bitmap that represents the set of categories that
1058 /// the user wants to see reported.
1059 ///
1060 /// @return a bitmap that represents the set of categories that the
1061 /// user wants to see reported.
1064 {return priv_->allowed_category_;}
1065 
1066 /// Setter for the bitmap that represents the set of categories that
1067 /// the user wants to see reported.
1068 ///
1069 /// @param c a bitmap that represents the set of categories that the
1070 /// user wants to see represented.
1071 void
1073 {priv_->allowed_category_ = c;}
1074 
1075 /// Setter for the bitmap that represents the set of categories that
1076 /// the user wants to see reported
1077 ///
1078 /// This function perform a bitwise or between the new set of
1079 /// categories and the current ones, and then sets the current
1080 /// categories to the result of the or.
1081 ///
1082 /// @param c a bitmap that represents the set of categories that the
1083 /// user wants to see represented.
1084 void
1086 {priv_->allowed_category_ = priv_->allowed_category_ | c;}
1087 
1088 /// Setter for the bitmap that represents the set of categories that
1089 /// the user wants to see reported
1090 ///
1091 /// This function actually unsets bits from the current categories.
1092 ///
1093 /// @param c a bitmap that represents the set of categories to unset
1094 /// from the current categories.
1095 void
1097 {priv_->allowed_category_ = priv_->allowed_category_ & ~c;}
1098 
1099 /// Add a diff for two decls to the cache of the current diff_context.
1100 ///
1101 /// Doing this allows to later find the added diff from its two
1102 /// subject decls.
1103 ///
1104 /// @param first the first decl to consider.
1105 ///
1106 /// @param second the second decl to consider.
1107 ///
1108 /// @param the diff to add.
1109 void
1110 diff_context::add_diff(type_or_decl_base_sptr first,
1111  type_or_decl_base_sptr second,
1112  const diff_sptr d)
1113 {priv_->types_or_decls_diff_map[std::make_pair(first, second)] = d;}
1114 
1115 /// Add a diff tree node to the cache of the current diff_context
1116 ///
1117 /// @param d the diff tree node to add.
1118 void
1119 diff_context::add_diff(const diff* d)
1120 {
1121  if (d)
1122  {
1123  diff_sptr dif(const_cast<diff*>(d), noop_deleter());
1124  add_diff(d->first_subject(), d->second_subject(), dif);
1125  }
1126 }
1127 
1128 /// Add a diff tree node to the cache of the current diff_context
1129 ///
1130 /// @param d the diff tree node to add.
1131 void
1132 diff_context::add_diff(const diff_sptr d)
1133 {
1134  if (d)
1135  add_diff(d->first_subject(), d->second_subject(), d);
1136 }
1137 
1138 /// Getter for the @ref CanonicalDiff "canonical diff node" for the
1139 /// @ref diff represented by their two subjects.
1140 ///
1141 /// @param first the first subject of the diff.
1142 ///
1143 /// @param second the second subject of the diff.
1144 ///
1145 /// @return the canonical diff for the diff node represented by the
1146 /// two diff subjects @p first and @p second. If no canonical diff
1147 /// node was registered for these subjects, then a nil node is
1148 /// returned.
1149 diff_sptr
1151  const type_or_decl_base_sptr second) const
1152 {return has_diff_for(first, second);}
1153 
1154 /// Getter for the @ref CanonicalDiff "canonical diff node" for the
1155 /// @ref diff represented by the two subjects of a given diff node.
1156 ///
1157 /// @param d the diff node to get the canonical node for.
1158 ///
1159 /// @return the canonical diff for the diff node represented by the
1160 /// two diff subjects of @p d. If no canonical diff node was
1161 /// registered for these subjects, then a nil node is returned.
1162 diff_sptr
1164 {return has_diff_for(d);}
1165 
1166 /// Setter for the @ref CanonicalDiff "canonical diff node" for the
1167 /// @ref diff represented by their two subjects.
1168 ///
1169 /// @param first the first subject of the diff.
1170 ///
1171 /// @param second the second subject of the diff.
1172 ///
1173 /// @param d the new canonical diff.
1174 void
1175 diff_context::set_canonical_diff_for(const type_or_decl_base_sptr first,
1176  const type_or_decl_base_sptr second,
1177  const diff_sptr d)
1178 {
1179  ABG_ASSERT(d);
1180  if (!has_diff_for(first, second))
1181  {
1182  add_diff(first, second, d);
1183  priv_->canonical_diffs.push_back(d);
1184  }
1185 }
1186 
1187 /// If there is is a @ref CanonicalDiff "canonical diff node"
1188 /// registered for two diff subjects, return it. Otherwise, register
1189 /// a canonical diff node for these two diff subjects and return it.
1190 ///
1191 /// @param first the first subject of the diff.
1192 ///
1193 /// @param second the second subject of the diff.
1194 ///
1195 /// @param d the new canonical diff node.
1196 ///
1197 /// @return the canonical diff node.
1198 diff_sptr
1199 diff_context::set_or_get_canonical_diff_for(const type_or_decl_base_sptr first,
1200  const type_or_decl_base_sptr second,
1201  const diff_sptr canonical_diff)
1202 {
1203  ABG_ASSERT(canonical_diff);
1204 
1205  diff_sptr canonical = get_canonical_diff_for(first, second);
1206  if (!canonical)
1207  {
1208  canonical = canonical_diff;
1209  set_canonical_diff_for(first, second, canonical);
1210  }
1211  return canonical;
1212 }
1213 
1214 /// Set the canonical diff node property of a given diff node
1215 /// appropriately.
1216 ///
1217 /// For a given diff node that has no canonical diff node, retrieve
1218 /// the canonical diff node (by looking at its diff subjects and at
1219 /// the current context) and set the canonical diff node property of
1220 /// the diff node to that canonical diff node. If no canonical diff
1221 /// node has been registered to the diff context for the subjects of
1222 /// the diff node then, register the canonical diff node as being the
1223 /// diff node itself; and set its canonical diff node property as
1224 /// such. Otherwise, if the diff node already has a canonical diff
1225 /// node, do nothing.
1226 ///
1227 /// @param diff the diff node to initialize the canonical diff node
1228 /// property for.
1229 void
1231 {
1232  if (diff->get_canonical_diff() == 0)
1233  {
1234  diff_sptr canonical =
1235  set_or_get_canonical_diff_for(diff->first_subject(),
1236  diff->second_subject(),
1237  diff);
1238  diff->set_canonical_diff(canonical.get());
1239  }
1240 }
1241 
1242 /// Add a diff node to the set of diff nodes that are kept alive for
1243 /// the life time of the current instance of diff_context.
1244 ///
1245 /// Note that diff added to the diff cache are kept alive as well, and
1246 /// don't need to be passed to this function to be kept alive.
1247 ///
1248 /// @param d the diff node to be kept alive during the life time of
1249 /// the current instance of @ref diff_context.
1250 void
1252 {priv_->live_diffs_.insert(d);}
1253 
1254 /// Test if a diff node has been traversed.
1255 ///
1256 /// @param d the diff node to consider.
1257 ///
1258 /// @return the first diff node against which @p d is redundant.
1259 diff*
1261 {
1262  const diff* canonical = d->get_canonical_diff();
1263  ABG_ASSERT(canonical);
1264 
1265  size_t ptr_value = reinterpret_cast<size_t>(canonical);
1266  pointer_map::iterator it = priv_->visited_diff_nodes_.find(ptr_value);
1267  if (it != priv_->visited_diff_nodes_.end())
1268  return reinterpret_cast<diff*>(it->second);
1269  else
1270  return 0;
1271 }
1272 
1273 /// Test if a diff node has been traversed.
1274 ///
1275 /// @param d the diff node to consider.
1276 ///
1277 /// @return the first diff node against which @p d is redundant.
1278 diff_sptr
1280 {
1282  return diff;
1283 }
1284 
1285 /// Mark a diff node as traversed by a traversing algorithm.
1286 ///
1287 /// Actually, it's the @ref CanonicalDiff "canonical diff" of this
1288 /// node that is marked as traversed.
1289 ///
1290 /// Subsequent invocations of diff_has_been_visited() on the diff node
1291 /// will yield true.
1292 void
1294 {
1295  if (diff_has_been_visited(d))
1296  return;
1297 
1298  const diff* canonical = d->get_canonical_diff();
1299  ABG_ASSERT(canonical);
1300 
1301  size_t canonical_ptr_value = reinterpret_cast<size_t>(canonical);
1302  size_t diff_ptr_value = reinterpret_cast<size_t>(d);
1303  priv_->visited_diff_nodes_[canonical_ptr_value] = diff_ptr_value;
1304 }
1305 
1306 /// Unmark all the diff nodes that were marked as being traversed.
1307 void
1309 {priv_->visited_diff_nodes_.clear();}
1310 
1311 /// This sets a flag that, if it's true, then during the traversing of
1312 /// a diff nodes tree each node is visited at most once.
1313 ///
1314 /// @param f if true then during the traversing of a diff nodes tree
1315 /// each node is visited at most once.
1316 ///
1317 void
1319 {priv_->forbid_visiting_a_node_twice_ = f;}
1320 
1321 /// This function sets a flag os that if @ref
1322 /// forbid_visiting_a_node_twice() returns true, then each time the
1323 /// node visitor starts visiting a new interface, it resets the
1324 /// memory the systems has about already visited node.
1325 ///
1326 /// @param f the flag to set.
1327 void
1329 {priv_->reset_visited_diffs_for_each_interface_ = f;}
1330 
1331 /// Return a flag that, if true, then during the traversing of a diff
1332 /// nodes tree each node is visited at most once.
1333 ///
1334 /// @return the boolean flag.
1335 bool
1337 {return priv_->forbid_visiting_a_node_twice_;}
1338 
1339 /// Return a flag that, if true, then during the traversing of a diff
1340 /// nodes tree each node is visited at most once, while visiting the
1341 /// diff tree underneath a given interface (public function or
1342 /// variable). Each time a new interface is visited, the nodes
1343 /// visited while visiting previous interfaces can be visited again.
1344 ///
1345 /// @return the boolean flag.
1346 ///
1347 /// @return the boolean flag.
1348 bool
1350 {
1351  return (priv_->forbid_visiting_a_node_twice_
1352  && priv_->reset_visited_diffs_for_each_interface_);
1353 }
1354 
1355 /// Getter for the diff tree nodes filters to apply to diff sub-trees.
1356 ///
1357 /// @return the vector of tree filters to apply to diff sub-trees.
1358 const filtering::filters&
1360 {return priv_->filters_;}
1361 
1362 /// Setter for the diff filters to apply to a given diff sub-tree.
1363 ///
1364 /// @param f the new diff filter to add to the vector of diff filters
1365 /// to apply to diff sub-trees.
1366 void
1368 {priv_->filters_.push_back(f);}
1369 
1370 /// Apply the diff filters to a given diff sub-tree.
1371 ///
1372 /// If the current context is instructed to filter out some categories
1373 /// then this function walks the given sub-tree and categorizes its
1374 /// nodes by using the filters held by the context.
1375 ///
1376 /// @param diff the diff sub-tree to apply the filters to.
1377 void
1379 {
1380  if (!diff)
1381  return;
1382 
1384  return;
1385 
1386  if (!diff->has_changes())
1387  return;
1388 
1389  for (filtering::filters::const_iterator i = diff_filters().begin();
1390  i != diff_filters().end();
1391  ++i)
1392  {
1394  if (do_log())
1395  {
1396  std::cerr << "applying a filter to diff '"
1398  << "'...\n";
1399  t.start();
1400  }
1401 
1403 
1404  if (do_log())
1405  {
1406  t.stop();
1407  std::cerr << "filter applied!:" << t << "\n";
1408 
1409  std::cerr << "propagating categories for the same diff node ... \n";
1410  t.start();
1411  }
1412 
1414 
1415  if (do_log())
1416  {
1417  t.stop();
1418  std::cerr << "category propagated!: " << t << "\n";
1419  }
1420  }
1421 
1422  }
1423 
1424 /// Apply the diff filters to the diff nodes of a @ref corpus_diff
1425 /// instance.
1426 ///
1427 /// If the current context is instructed to filter out some categories
1428 /// then this function walks the diff tree and categorizes its nodes
1429 /// by using the filters held by the context.
1430 ///
1431 /// @param diff the corpus diff to apply the filters to.
1432 void
1434 {
1435 
1436  if (!diff || !diff->has_changes())
1437  return;
1438 
1439  for (filtering::filters::const_iterator i = diff_filters().begin();
1440  i != diff_filters().end();
1441  ++i)
1442  {
1445  }
1446 }
1447 
1448 /// Getter for the vector of suppressions that specify which diff node
1449 /// reports should be dropped on the floor.
1450 ///
1451 /// @return the set of suppressions.
1452 const suppressions_type&
1454 {return priv_->suppressions_;}
1455 
1456 /// Getter for the vector of suppressions that specify which diff node
1457 /// reports should be dropped on the floor.
1458 ///
1459 /// @return the set of suppressions.
1462 {
1463  // Invalidate negated and direct suppressions caches that are built
1464  // from priv_->suppressions_;
1465  priv_->negated_suppressions_.clear();
1466  priv_->direct_suppressions_.clear();
1467  return priv_->suppressions_;
1468 }
1469 
1470 /// Getter of the negated suppression specifications that are
1471 /// comprised in the general vector of suppression specifications
1472 /// returned by diff_context::suppressions().
1473 ///
1474 /// Note that the first invocation of this function scans the vector
1475 /// returned by diff_context::suppressions() and caches the negated
1476 /// suppressions from there.
1477 ///
1478 /// Subsequent invocations of this function just return the cached
1479 /// negated suppressions.
1480 ///
1481 /// @return the negated suppression specifications stored in this diff
1482 /// context.
1485 {
1486  if (priv_->negated_suppressions_.empty())
1487  for (auto s : suppressions())
1488  if (is_negated_suppression(s))
1489  priv_->negated_suppressions_.push_back(s);
1490 
1491  return priv_->negated_suppressions_;
1492 }
1493 
1494 /// Getter of the direct suppression specification (those that are
1495 /// not negated) comprised in the general vector of suppression
1496 /// specifications returned by diff_context::suppression().
1497 ///
1498 /// Note that the first invocation of this function scans the vector
1499 /// returned by diff_context::suppressions() and caches the direct
1500 /// suppressions from there.
1501 ///
1502 /// Subsequent invocations of this function just return the cached
1503 /// direct suppressions.
1504 ///
1505 /// @return the direct suppression specifications.
1508 {
1509  if (priv_->direct_suppressions_.empty())
1510  {
1511  for (auto s : suppressions())
1512  if (!is_negated_suppression(s))
1513  priv_->direct_suppressions_.push_back(s);
1514  }
1515  return priv_->direct_suppressions_;
1516 }
1517 
1518 /// Add a new suppression specification that specifies which diff node
1519 /// reports should be dropped on the floor.
1520 ///
1521 /// @param suppr the new suppression specification to add to the
1522 /// existing set of suppressions specifications of the diff context.
1523 void
1525 {
1526  priv_->suppressions_.push_back(suppr);
1527  // Invalidate negated and direct suppressions caches that are built
1528  // from priv_->suppressions_;
1529  priv_->negated_suppressions_.clear();
1530  priv_->direct_suppressions_.clear();
1531 }
1532 
1533 /// Add new suppression specifications that specify which diff node
1534 /// reports should be dropped on the floor.
1535 ///
1536 /// @param supprs the new suppression specifications to add to the
1537 /// existing set of suppression specifications of the diff context.
1538 void
1540 {
1541  priv_->suppressions_.insert(priv_->suppressions_.end(),
1542  supprs.begin(), supprs.end());
1543 }
1544 
1545 /// Test if it's requested to perform diff node categorization.
1546 ///
1547 /// @return true iff it's requested to perform diff node
1548 /// categorization.
1549 bool
1551 {return priv_->perform_change_categorization_;}
1552 
1553 /// Request change categorization or not.
1554 ///
1555 /// @param f true iff change categorization is requested.
1556 void
1558 {priv_->perform_change_categorization_ = f;}
1559 
1560 /// Set the flag that indicates if the diff using this context should
1561 /// show only leaf changes or not.
1562 ///
1563 /// @param f the new value of the flag that indicates if the diff
1564 /// using this context should show only leaf changes or not.
1565 void
1567 {
1568  // This function can be called only if the reporter hasn't yet been
1569  // created. Once it's been created, we are supposed to live with
1570  // it.
1571  ABG_ASSERT(priv_->reporter_ == 0);
1572  priv_->leaf_changes_only_ = f;
1573 }
1574 
1575 /// Get the flag that indicates if the diff using this context should
1576 /// show only leaf changes or not.
1577 ///
1578 /// @return the value of the flag that indicates if the diff using
1579 /// this context should show only leaf changes or not.
1580 bool
1582 {return priv_->leaf_changes_only_;}
1583 
1584 /// Get the flag that indicates if the diff reports using this context
1585 /// should show sizes and offsets in an hexadecimal base or not. If
1586 /// not, then they are to be shown in a decimal base.
1587 ///
1588 /// @return true iff sizes and offsets are to be shown in an
1589 /// hexadecimal base.
1590 bool
1592 {return priv_->hex_values_;}
1593 
1594 /// Set the flag that indicates if diff reports using this context
1595 /// should show sizes and offsets in an hexadecimal base or not. If
1596 /// not, then they are to be shown in a decimal base.
1597 ///
1598 /// @param f if true then sizes and offsets are to be shown in an
1599 /// hexadecimal base.
1600 void
1602 {priv_->hex_values_ = f;}
1603 
1604 /// Get the flag that indicates if diff reports using this context
1605 /// should show sizes and offsets in bits, rather than bytes.
1606 ///
1607 /// @return true iff sizes and offsets are to be shown in bits.
1608 /// Otherwise they are to be shown in bytes.
1609 bool
1611 {return priv_->show_offsets_sizes_in_bits_;}
1612 
1613 /// Set the flag that indicates if diff reports using this context
1614 /// should show sizes and offsets in bits, rather than bytes.
1615 ///
1616 /// @param f if true then sizes and offsets are to be shown in bits.
1617 /// Otherwise they are to be shown in bytes.
1618 void
1620 {priv_->show_offsets_sizes_in_bits_ = f;}
1621 
1622 /// Set a flag saying if offset changes should be reported in a
1623 /// relative way. That is, if the report should say how of many bits
1624 /// a class/struct data member did move.
1625 ///
1626 /// @param f the new boolean value of the flag.
1627 void
1629 {priv_->show_relative_offset_changes_ = f;}
1630 
1631 /// Get the flag saying if offset changes should be reported in a
1632 /// relative way. That is, if the report should say how of many bits
1633 /// a class/struct data member did move.
1634 ///
1635 /// @return the boolean value of the flag.
1636 bool
1638 {return priv_->show_relative_offset_changes_;}
1639 
1640 /// Set a flag saying if the comparison module should only show the
1641 /// diff stats.
1642 ///
1643 /// @param f the flag to set.
1644 void
1646 {priv_->show_stats_only_ = f;}
1647 
1648 /// Test if the comparison module should only show the diff stats.
1649 ///
1650 /// @return true if the comparison module should only show the diff
1651 /// stats, false otherwise.
1652 bool
1654 {return priv_->show_stats_only_;}
1655 
1656 /// Setter for the property that says if the comparison module should
1657 /// show the soname changes in its report.
1658 ///
1659 /// @param f the new value of the property.
1660 void
1662 {priv_->show_soname_change_ = f;}
1663 
1664 /// Getter for the property that says if the comparison module should
1665 /// show the soname changes in its report.
1666 ///
1667 /// @return the value of the property.
1668 bool
1670 {return priv_->show_soname_change_;}
1671 
1672 /// Setter for the property that says if the comparison module should
1673 /// show the architecture changes in its report.
1674 ///
1675 /// @param f the new value of the property.
1676 void
1678 {priv_->show_architecture_change_ = f;}
1679 
1680 /// Getter for the property that says if the comparison module should
1681 /// show the architecture changes in its report.
1682 ///
1683 /// @return the value of the property.
1684 bool
1686 {return priv_->show_architecture_change_;}
1687 
1688 /// Set a flag saying to show the deleted functions.
1689 ///
1690 /// @param f true to show deleted functions.
1691 void
1693 {priv_->show_deleted_fns_ = f;}
1694 
1695 /// @return true if we want to show the deleted functions, false
1696 /// otherwise.
1697 bool
1699 {return priv_->show_deleted_fns_;}
1700 
1701 /// Set a flag saying to show the changed functions.
1702 ///
1703 /// @param f true to show the changed functions.
1704 void
1706 {priv_->show_changed_fns_ = f;}
1707 
1708 /// @return true if we want to show the changed functions, false otherwise.
1709 bool
1711 {return priv_->show_changed_fns_;}
1712 
1713 /// Set a flag saying to show the added functions.
1714 ///
1715 /// @param f true to show the added functions.
1716 void
1718 {priv_->show_added_fns_ = f;}
1719 
1720 /// @return true if we want to show the added functions, false
1721 /// otherwise.
1722 bool
1724 {return priv_->show_added_fns_;}
1725 
1726 /// Set a flag saying to show the deleted variables.
1727 ///
1728 /// @param f true to show the deleted variables.
1729 void
1731 {priv_->show_deleted_vars_ = f;}
1732 
1733 /// @return true if we want to show the deleted variables, false
1734 /// otherwise.
1735 bool
1737 {return priv_->show_deleted_vars_;}
1738 
1739 /// Set a flag saying to show the changed variables.
1740 ///
1741 /// @param f true to show the changed variables.
1742 void
1744 {priv_->show_changed_vars_ = f;}
1745 
1746 /// @return true if we want to show the changed variables, false otherwise.
1747 bool
1749 {return priv_->show_changed_vars_;}
1750 
1751 /// Set a flag saying to show the added variables.
1752 ///
1753 /// @param f true to show the added variables.
1754 void
1756 {priv_->show_added_vars_ = f;}
1757 
1758 /// @return true if we want to show the added variables, false
1759 /// otherwise.
1760 bool
1762 {return priv_->show_added_vars_;}
1763 
1764 bool
1765 diff_context::show_linkage_names() const
1766 {return priv_->show_linkage_names_;}
1767 
1768 void
1769 diff_context::show_linkage_names(bool f)
1770 {priv_->show_linkage_names_= f;}
1771 
1772 /// Set a flag saying to show location information.
1773 ///
1774 /// @param f true to show location information.
1775 void
1777 {priv_->show_locs_= f;}
1778 
1779 /// @return true if we want to show location information, false
1780 /// otherwise.
1781 bool
1783 {return priv_->show_locs_;}
1784 
1785 /// A getter for the flag that says if we should report about
1786 /// functions or variables diff nodes that have *exclusively*
1787 /// redundant diff tree children nodes.
1788 ///
1789 /// @return the flag.
1790 bool
1792 {return priv_->show_redundant_changes_;}
1793 
1794 /// A setter for the flag that says if we should report about
1795 /// functions or variables diff nodes that have *exclusively*
1796 /// redundant diff tree children nodes.
1797 ///
1798 /// @param f the flag to set.
1799 void
1801 {priv_->show_redundant_changes_ = f;}
1802 
1803 /// Getter for the flag that indicates if symbols not referenced by
1804 /// any debug info are to be compared and reported about.
1805 ///
1806 /// @return the boolean flag.
1807 bool
1809 {return priv_->show_syms_unreferenced_by_di_;}
1810 
1811 /// Setter for the flag that indicates if symbols not referenced by
1812 /// any debug info are to be compared and reported about.
1813 ///
1814 /// @param f the new flag to set.
1815 void
1817 {priv_->show_syms_unreferenced_by_di_ = f;}
1818 
1819 /// Getter for the flag that indicates if symbols not referenced by
1820 /// any debug info and that got added are to be reported about.
1821 ///
1822 /// @return true iff symbols not referenced by any debug info and that
1823 /// got added are to be reported about.
1824 bool
1826 {return priv_->show_added_syms_unreferenced_by_di_;}
1827 
1828 /// Setter for the flag that indicates if symbols not referenced by
1829 /// any debug info and that got added are to be reported about.
1830 ///
1831 /// @param f the new flag that says if symbols not referenced by any
1832 /// debug info and that got added are to be reported about.
1833 void
1835 {priv_->show_added_syms_unreferenced_by_di_ = f;}
1836 
1837 /// Setter for the flag that indicates if changes on types unreachable
1838 /// from global functions and variables are to be reported.
1839 ///
1840 /// @param f if true, then changes on types unreachable from global
1841 /// functions and variables are to be reported.
1842 void
1844 {priv_->show_unreachable_types_ = f;}
1845 
1846 /// Getter for the flag that indicates if changes on types unreachable
1847 /// from global functions and variables are to be reported.
1848 ///
1849 /// @return true iff changes on types unreachable from global
1850 /// functions and variables are to be reported.
1851 bool
1853 {return priv_->show_unreachable_types_;}
1854 
1855 /// Getter of the flag that indicates if the leaf reporter should
1856 /// display a summary of the interfaces impacted by a given leaf
1857 /// change or not.
1858 ///
1859 /// @return the flag that indicates if the leaf reporter should
1860 /// display a summary of the interfaces impacted by a given leaf
1861 /// change or not.
1862 bool
1864 {return priv_->show_impacted_interfaces_;}
1865 
1866 /// Setter of the flag that indicates if the leaf reporter should
1867 /// display a summary of the interfaces impacted by a given leaf
1868 /// change or not.
1869 ///
1870 /// @param f the new value of the flag that indicates if the leaf
1871 /// reporter should display a summary of the interfaces impacted by a
1872 /// given leaf change or not.
1873 void
1875 {priv_->show_impacted_interfaces_ = f;}
1876 
1877 /// Setter for the default output stream used by code of the
1878 /// comparison engine. By default the default output stream is a NULL
1879 /// pointer.
1880 ///
1881 /// @param o a pointer to the default output stream.
1882 void
1884 {priv_->default_output_stream_ = o;}
1885 
1886 /// Getter for the default output stream used by code of the
1887 /// comparison engine. By default the default output stream is a NULL
1888 /// pointer.
1889 ///
1890 /// @return a pointer to the default output stream.
1891 ostream*
1893 {return priv_->default_output_stream_;}
1894 
1895 /// Setter for the errror output stream used by code of the comparison
1896 /// engine. By default the error output stream is a NULL pointer.
1897 ///
1898 /// @param o a pointer to the error output stream.
1899 void
1901 {priv_->error_output_stream_ = o;}
1902 
1903 /// Getter for the errror output stream used by code of the comparison
1904 /// engine. By default the error output stream is a NULL pointer.
1905 ///
1906 /// @return a pointer to the error output stream.
1907 ostream*
1909 {return priv_->error_output_stream_;}
1910 
1911 /// Test if the comparison engine should dump the diff tree for the
1912 /// changed functions and variables it has.
1913 ///
1914 /// @return true if after the comparison, the engine should dump the
1915 /// diff tree for the changed functions and variables it has.
1916 bool
1918 {return priv_->dump_diff_tree_;}
1919 
1920 /// Set if the comparison engine should dump the diff tree for the
1921 /// changed functions and variables it has.
1922 ///
1923 /// @param f true if after the comparison, the engine should dump the
1924 /// diff tree for the changed functions and variables it has.
1925 void
1927 {priv_->dump_diff_tree_ = f;}
1928 
1929 /// Emit a textual representation of a diff tree to the error output
1930 /// stream of the current context, for debugging purposes.
1931 ///
1932 /// @param d the diff tree to serialize to the error output associated
1933 /// to the current instance of @ref diff_context.
1934 void
1936 {
1937  if (error_output_stream())
1939 }
1940 
1941 /// Emit a textual representation of a @ref corpus_diff tree to the error
1942 /// output stream of the current context, for debugging purposes.
1943 ///
1944 /// @param d the @ref corpus_diff tree to serialize to the error
1945 /// output associated to the current instance of @ref diff_context.
1946 void
1948 {
1949  if (error_output_stream())
1951 }
1952 // </diff_context stuff>
1953 
1954 // <diff stuff>
1955 
1956 /// Constructor for the @ref diff type.
1957 ///
1958 /// This constructs a diff between two subjects that are actually
1959 /// declarations; the first and the second one.
1960 ///
1961 /// @param first_subject the first decl (subject) of the diff.
1962 ///
1963 /// @param second_subject the second decl (subject) of the diff.
1964 diff::diff(type_or_decl_base_sptr first_subject,
1965  type_or_decl_base_sptr second_subject)
1966  : priv_(new priv(first_subject, second_subject,
1969  /*reported_once=*/false,
1970  /*currently_reporting=*/false))
1971 {}
1972 
1973 /// Constructor for the @ref diff type.
1974 ///
1975 /// This constructs a diff between two subjects that are actually
1976 /// declarations; the first and the second one.
1977 ///
1978 /// @param first_subject the first decl (subject) of the diff.
1979 ///
1980 /// @param second_subject the second decl (subject) of the diff.
1981 ///
1982 /// @param ctxt the context of the diff. Note that this context
1983 /// object must stay alive during the entire life time of the current
1984 /// instance of @ref diff. Otherwise, memory corruption issues occur.
1985 diff::diff(type_or_decl_base_sptr first_subject,
1986  type_or_decl_base_sptr second_subject,
1987  diff_context_sptr ctxt)
1988  : priv_(new priv(first_subject, second_subject,
1989  ctxt, NO_CHANGE_CATEGORY,
1990  /*reported_once=*/false,
1991  /*currently_reporting=*/false))
1992 {}
1993 
1994 /// Test if logging was requested
1995 ///
1996 /// @return true iff logging was requested.
1997 bool
1999 {return context()->do_log();}
2000 
2001 /// Request logging (or not)
2002 ///
2003 /// @param f true iff logging is to be requested.
2004 void
2006 {context()->do_log(f);}
2007 
2008 /// Flag a given diff node as being traversed.
2009 ///
2010 /// For certain diff nodes like @ref class_diff, it's important to
2011 /// avoid traversing the node again while it's already being
2012 /// traversed; otherwise this leads to infinite loops. So the
2013 /// diff::begin_traversing() and diff::end_traversing() methods flag a
2014 /// given node as being traversed (or not), so that
2015 /// diff::is_traversing() can tell if the node is being traversed.
2016 ///
2017 /// Note that traversing a node means visiting it *and* visiting its
2018 /// children nodes.
2019 ///
2020 /// The canonical node is marked as being traversed too.
2021 ///
2022 /// These functions are called by the traversing code.
2023 void
2025 {
2027  if (priv_->canonical_diff_)
2028  priv_->canonical_diff_->priv_->traversing_ = true;
2029  priv_->traversing_ = true;
2030 }
2031 
2032 /// Tell if a given node is being traversed or not.
2033 ///
2034 /// Note that traversing a node means visiting it *and* visiting its
2035 /// children nodes.
2036 ///
2037 /// It's the canonical node which is looked at, actually.
2038 ///
2039 /// Please read the comments for the diff::begin_traversing() for mode
2040 /// context.
2041 ///
2042 /// @return true if the current instance of @diff is being traversed.
2043 bool
2045 {
2046  if (priv_->canonical_diff_)
2047  return priv_->canonical_diff_->priv_->traversing_;
2048  return priv_->traversing_;
2049 }
2050 
2051 /// Flag a given diff node as not being traversed anymore.
2052 ///
2053 /// Note that traversing a node means visiting it *and* visiting its
2054 /// children nodes.
2055 ///
2056 /// Please read the comments of the function diff::begin_traversing()
2057 /// for mode context.
2058 void
2060 {
2062  if (priv_->canonical_diff_)
2063  priv_->canonical_diff_->priv_->traversing_ = false;
2064  priv_->traversing_ = false;
2065 }
2066 
2067 /// Finish the insertion of a diff tree node into the diff graph.
2068 ///
2069 /// This function might be called several times. It must perform the
2070 /// insertion only once.
2071 ///
2072 /// For instance, certain kinds of diff tree node have specific
2073 /// children nodes that are populated after the constructor of the
2074 /// diff tree node has been called. In that case, calling overloads
2075 /// of this method ensures that these children nodes are properly
2076 /// gathered and setup.
2077 void
2079 {
2080  if (diff::priv_->finished_)
2081  return;
2083  diff::priv_->finished_ = true;
2084 }
2085 
2086 /// Getter of the first subject of the diff.
2087 ///
2088 /// @return the first subject of the diff.
2091 {return dynamic_pointer_cast<type_or_decl_base>(priv_->first_subject_);}
2092 
2093 /// Getter of the second subject of the diff.
2094 ///
2095 /// @return the second subject of the diff.
2098 {return dynamic_pointer_cast<type_or_decl_base>(priv_->second_subject_);}
2099 
2100 /// Getter for the children nodes of the current @ref diff node.
2101 ///
2102 /// @return a vector of the children nodes.
2103 const vector<diff*>&
2105 {return priv_->children_;}
2106 
2107 /// Getter for the parent node of the current @ref diff node.
2108 ///
2109 /// @return the parent node of the current @ref diff node.
2110 const diff*
2112 {return priv_->parent_;}
2113 
2114 /// Getter for the canonical diff of the current instance of @ref
2115 /// diff.
2116 ///
2117 /// Note that the canonical diff node for the current instanc eof diff
2118 /// node must have been set by invoking
2119 /// class_diff::initialize_canonical_diff() on the current instance of
2120 /// diff node.
2121 ///
2122 /// @return the canonical diff node or null if none was set.
2123 diff*
2125 {return priv_->canonical_diff_;}
2126 
2127 /// Setter for the canonical diff of the current instance of @ref
2128 /// diff.
2129 ///
2130 /// @param d the new canonical node to set.
2131 void
2133 {priv_->canonical_diff_ = d;}
2134 
2135 /// Add a new child node to the vector of children nodes for the
2136 /// current @ref diff node.
2137 ///
2138 /// @param d the new child node to add to the children nodes.
2139 void
2141 {
2142  ABG_ASSERT(d);
2143 
2144  // Ensure 'd' is kept alive for the life time of the context of this
2145  // diff.
2146  context()->keep_diff_alive(d);
2147 
2148  // Add the underlying pointer of 'd' to the vector of children.
2149  // Note that this vector holds no reference to 'd'. This is to avoid
2150  // reference cycles. The reference to 'd' is held by the context of
2151  // this diff, thanks to the call to context()->keep_diff_alive(d)
2152  // above.
2153  priv_->children_.push_back(d.get());
2154 
2155  d->priv_->parent_ = this;
2156 }
2157 
2158 /// Getter of the context of the current diff.
2159 ///
2160 /// @return the context of the current diff.
2161 const diff_context_sptr
2163 {return priv_->get_context();}
2164 
2165 /// Setter of the context of the current diff.
2166 ///
2167 /// @param c the new context to set.
2168 void
2170 {priv_->ctxt_ = c;}
2171 
2172 /// Tests if we are currently in the middle of emitting a report for
2173 /// this diff.
2174 ///
2175 /// @return true if we are currently emitting a report for the
2176 /// current diff, false otherwise.
2177 bool
2179 {
2180  if (priv_->canonical_diff_)
2181  return priv_->canonical_diff_->priv_->currently_reporting_;
2182  return priv_->currently_reporting_;
2183 }
2184 
2185 /// Sets a flag saying if we are currently in the middle of emitting
2186 /// a report for this diff.
2187 ///
2188 /// @param f true if we are currently emitting a report for the
2189 /// current diff, false otherwise.
2190 void
2192 {
2193  if (priv_->canonical_diff_)
2194  priv_->canonical_diff_->priv_->currently_reporting_ = f;
2195  priv_->currently_reporting_ = f;
2196 }
2197 
2198 /// Tests if a report has already been emitted for the current diff.
2199 ///
2200 /// @return true if a report has already been emitted for the
2201 /// current diff, false otherwise.
2202 bool
2204 {
2205  ABG_ASSERT(priv_->canonical_diff_);
2206  return priv_->canonical_diff_->priv_->reported_once_;
2207 }
2208 
2209 /// The generic traversing code that walks a given diff sub-tree.
2210 ///
2211 /// Note that there is a difference between traversing a diff node and
2212 /// visiting it. Basically, traversing a diff node means visiting it
2213 /// and visiting its children nodes too. So one can visit a node
2214 /// without traversing it. But traversing a node without visiting it
2215 /// is not possible.
2216 ///
2217 /// Note that the insertion of the "generic view" of the diff node
2218 /// into the graph being traversed is done "on the fly". The
2219 /// insertion of the "typed view" of the diff node into the graph is
2220 /// done implicitely. To learn more about the generic and typed view
2221 /// of the diff node, please read the introductory comments of the
2222 /// @ref diff class.
2223 ///
2224 /// Note that by default this traversing code visits a given class of
2225 /// equivalence of a diff node only once. This behaviour can been
2226 /// changed by calling
2227 /// diff_context::visiting_a_node_twice_is_forbidden(), but this is
2228 /// very risky as it might create endless loops while visiting a diff
2229 /// tree graph that has changes that refer to themselves; that is,
2230 /// diff tree graphs with cycles.
2231 ///
2232 /// When a diff node is encountered, the
2233 /// diff_node_visitor::visit_begin() method is invoked on the diff
2234 /// node first.
2235 ///
2236 /// If the diff node has already been visited, then
2237 /// node_visitor::visit_end() is called on it and the node traversing
2238 /// is done; the children of the diff node are not visited in this
2239 /// case.
2240 ///
2241 /// If the diff node has *NOT* been visited yet, then the
2242 /// diff_node_visitor::visit() method is invoked with it's 'pre'
2243 /// argument set to true. Then if the diff_node_visitor::visit()
2244 /// returns true, then the children nodes of the diff node are
2245 /// visited. Otherwise, no children nodes of the diff node is
2246 /// visited and the diff_node_visitor::visit_end() is called.
2247 
2248 /// After the children nodes are visited (and only if they are
2249 /// visited) the diff_node_visitor::visit() method is invoked with
2250 /// it's 'pre' argument set to false. And then the
2251 /// diff_node_visitor::visit_end() is called.
2252 ///
2253 /// @param v the entity that visits each node of the diff sub-tree.
2254 ///
2255 /// @return true to tell the caller that all of the sub-tree could be
2256 /// walked. This instructs the caller to keep walking the rest of the
2257 /// tree. Return false otherwise.
2258 bool
2260 {
2261  // Insert the "generic view" of the diff node into its graph.
2262  finish_diff_type();
2263 
2264  v.visit_begin(this);
2265 
2266  bool already_visited = false;
2267  if (context()->visiting_a_node_twice_is_forbidden()
2268  && context()->diff_has_been_visited(this))
2269  already_visited = true;
2270 
2271  bool mark_visited_nodes_as_traversed =
2273 
2274  if (!already_visited && !v.visit(this, /*pre=*/true))
2275  {
2276  v.visit_end(this);
2277  if (mark_visited_nodes_as_traversed)
2278  context()->mark_diff_as_visited(this);
2279  return false;
2280  }
2281 
2283  && !is_traversing()
2284  && !already_visited)
2285  {
2286  begin_traversing();
2287  for (vector<diff*>::const_iterator i = children_nodes().begin();
2288  i != children_nodes().end();
2289  ++i)
2290  {
2291  if (!(*i)->traverse(v))
2292  {
2293  v.visit_end(this);
2294  if (mark_visited_nodes_as_traversed)
2295  context()->mark_diff_as_visited(this);
2296  end_traversing();
2297  return false;
2298  }
2299  }
2300  end_traversing();
2301  }
2302 
2303  if (!v.visit(this, /*pref=*/false))
2304  {
2305  v.visit_end(this);
2306  if (mark_visited_nodes_as_traversed)
2307  context()->mark_diff_as_visited(this);
2308  return false;
2309  }
2310 
2311  v.visit_end(this);
2312  if (!already_visited && mark_visited_nodes_as_traversed)
2313  context()->mark_diff_as_visited(this);
2314 
2315  return true;
2316 }
2317 
2318 /// Sets a flag saying if a report has already been emitted for the
2319 /// current diff.
2320 ///
2321 /// @param f true if a report has already been emitted for the
2322 /// current diff, false otherwise.
2323 void
2324 diff::reported_once(bool f) const
2325 {
2326  ABG_ASSERT(priv_->canonical_diff_);
2327  priv_->canonical_diff_->priv_->reported_once_ = f;
2328  priv_->reported_once_ = f;
2329 }
2330 
2331 /// Getter for the local category of the current diff tree node.
2332 ///
2333 /// The local category represents the set of categories of a diff
2334 /// node, not taking in account the categories inherited from its
2335 /// children nodes.
2336 ///
2337 /// @return the local category of the current diff tree node.
2340 {return priv_->local_category_;}
2341 
2342 /// Getter of the category of the class of equivalence of the current
2343 /// diff tree node.
2344 ///
2345 /// That is, if the current diff tree node has a canonical node,
2346 /// return the category of that canonical node. Otherwise, return the
2347 /// category of the current node.
2348 ///
2349 /// @return the category of the class of equivalence of the current
2350 /// tree node.
2353 {
2354  diff* canonical = get_canonical_diff();
2355  return canonical ? canonical->get_category() : get_category();
2356 }
2357 
2358 /// Getter for the category of the current diff tree node.
2359 ///
2360 /// This category represents the union of the local category and the
2361 /// categories inherited from the children diff nodes.
2362 ///
2363 /// @return the category of the current diff tree node.
2366 {return priv_->category_;}
2367 
2368 /// Adds the current diff tree node to an additional set of
2369 /// categories. Note that the categories include thoses inherited
2370 /// from the children nodes of this diff node.
2371 ///
2372 /// @param c a bit-map representing the set of categories to add the
2373 /// current diff tree node to.
2374 ///
2375 /// @return the resulting bit-map representing the categories this
2376 /// current diff tree node belongs to, including those inherited from
2377 /// its children nodes.
2380 {
2381  priv_->category_ = priv_->category_ | c;
2382  return priv_->category_;
2383 }
2384 
2385 /// Adds the current diff tree node to the categories resulting from
2386 /// the local changes of the current diff node.
2387 ///
2388 /// @param c a bit-map representing the set of categories to add the
2389 /// current diff tree node to.
2390 ///
2391 /// @return the resulting bit-map representing the categories this
2392 /// current diff tree node belongs to.
2395 {
2396  priv_->local_category_ = priv_->local_category_ | c;
2397  return priv_->local_category_;
2398 }
2399 
2400 /// Adds the current diff tree node to the categories resulting from
2401 /// the local and inherited changes of the current diff node.
2402 ///
2403 /// @param c a bit-map representing the set of categories to add the
2404 /// current diff tree node to.
2405 void
2407 {
2409  add_to_category(c);
2410 }
2411 
2412 /// Remove the current diff tree node from an a existing sef of
2413 /// categories. The categories include those inherited from the
2414 /// children nodes of the current diff node.
2415 ///
2416 /// @param c a bit-map representing the set of categories to add the
2417 /// current diff tree node to.
2418 ///
2419 /// @return the resulting bit-map representing the categories this
2420 /// current diff tree onde belongs to, including the categories
2421 /// inherited from the children nodes of the current diff node.
2424 {
2425  priv_->category_ = priv_->category_ & ~c;
2426  return priv_->category_;
2427 }
2428 
2429 /// Remove the current diff tree node from the categories resulting
2430 /// from the local changes.
2431 ///
2432 /// @param c a bit-map representing the set of categories to add the
2433 /// current diff tree node to.
2434 ///
2435 /// @return the resulting bit-map representing the categories this
2436 /// current diff tree onde belongs to.
2439 {
2440  priv_->local_category_ = priv_->local_category_ & ~c;
2441  return priv_->local_category_;
2442 }
2443 
2444 /// Set the category of the current @ref diff node. This category
2445 /// includes the categories inherited from the children nodes of the
2446 /// current diff node.
2447 ///
2448 /// @param c the new category for the current diff node.
2449 void
2451 {priv_->category_ = c;}
2452 
2453 /// Set the local category of the current @ref diff node.
2454 ///
2455 /// @param c the new category for the current diff node.
2456 void
2458 {priv_->local_category_ = c;}
2459 
2460 /// Test if this diff tree node is to be filtered out for reporting
2461 /// purposes.
2462 ///
2463 /// There is a difference between a diff node being filtered out and
2464 /// being suppressed. Being suppressed means that there is a
2465 /// suppression specification that suppresses the diff node
2466 /// specifically. Being filtered out mean the node is either
2467 /// suppressed, or it's filtered out because the suppression of a set
2468 /// of (children) nodes caused this node to be filtered out as well.
2469 /// For instance, if a function diff has all its children diff nodes
2470 /// suppressed and if the function diff node carries no local change,
2471 /// then the function diff node itself is going to be filtered out.
2472 ///
2473 /// The function tests if the categories of the diff tree node are
2474 /// "forbidden" by the context or not.
2475 ///
2476 /// @return true iff the current diff node should NOT be reported.
2477 bool
2479 {
2480  if (diff * canonical = get_canonical_diff())
2481  if ((canonical->get_category() & SUPPRESSED_CATEGORY
2482  || canonical->get_category() & PRIVATE_TYPE_CATEGORY)
2483  && !canonical->is_allowed_by_specific_negated_suppression()
2484  && !canonical->has_descendant_allowed_by_specific_negated_suppression()
2485  && !canonical->has_parent_allowed_by_specific_negated_suppression())
2486  // The canonical type was suppressed either by a user-provided
2487  // suppression specification or by a "private-type" suppression
2488  // specification.. This means all the classes of equivalence of
2489  // that canonical type were suppressed. So this node should be
2490  // filtered out.
2491  return true;
2492  return priv_->is_filtered_out(get_category());
2493 }
2494 
2495 /// Test if this diff tree node is to be filtered out for reporting
2496 /// purposes, but by considering only the categories that were *NOT*
2497 /// inherited from its children nodes.
2498 ///
2499 /// The function tests if the local categories of the diff tree node
2500 /// are "forbidden" by the context or not.
2501 ///
2502 /// @return true iff the current diff node should NOT be reported,
2503 /// with respect to its local categories.
2504 bool
2506 {return priv_->is_filtered_out(get_local_category());}
2507 
2508 /// Test if this diff tree node is to be filtered out for reporting
2509 /// purposes, but without considering the categories that can /force/
2510 /// the node to be unfiltered.
2511 ///
2512 /// The function tests if the categories of the diff tree node are
2513 /// "forbidden" by the context or not.
2514 ///
2515 /// @return true iff the current diff node should should NOT be
2516 /// reported, with respect to the categories that might filter it out
2517 /// only.
2518 bool
2520 {
2525 
2526  return priv_->is_filtered_out(c);
2527 }
2528 
2529 /// Test if the current diff node has been suppressed by a
2530 /// user-provided suppression specification.
2531 ///
2532 /// @return true if the current diff node has been suppressed by a
2533 /// user-provided suppression list.
2534 bool
2536 {
2537  bool is_private = false;
2538  return is_suppressed(is_private);
2539 }
2540 
2541 /// Test if the current diff node has been suppressed by a
2542 /// user-provided suppression specification or by an auto-generated
2543 /// "private type" suppression specification.
2544 ///
2545 /// Note that private type suppressions are auto-generated from the
2546 /// path to where public headers are, as given by the user.
2547 ///
2548 /// Here is the current algorithm:
2549 ///
2550 /// First, suppress this diff node if it's not matched by any
2551 /// negated suppression specifications. If it's not
2552 /// suppressed, then suppress it if it's matched by direct
2553 /// suppression specifications.
2554 ///
2555 /// @param is_private_type out parameter if the current diff node was
2556 /// suppressed because it's a private type then this parameter is set
2557 /// to true.
2558 ///
2559 /// @return true if the current diff node has been suppressed by a
2560 /// user-provided suppression list.
2561 bool
2562 diff::is_suppressed(bool &is_private_type) const
2563 {
2564  // If there is at least one negated suppression, then suppress the
2565  // current diff node by default ...
2566  bool do_suppress = !context()->negated_suppressions().empty();
2567 
2568  // ... unless there is at least one negated suppression that
2569  // specifically asks to keep this diff node around (un-suppressed).
2570  for (auto n : context()->negated_suppressions())
2571  if (!n->suppresses_diff(this))
2572  {
2573  do_suppress = false;
2574  break;
2575  }
2576 
2577  // Then walk the set of non-negated, AKA direct, suppressions. If at
2578  // least one suppression suppresses the current diff node then the
2579  // diff node must be suppressed.
2580  for (auto d : context()->direct_suppressions())
2581  if (d->suppresses_diff(this))
2582  {
2583  do_suppress = true;
2585  is_private_type = true;
2586  break;
2587  }
2588 
2589  return do_suppress;
2590 }
2591 
2592 /// Test if this diff tree node should be reported.
2593 ///
2594 /// @return true iff the current node should be reported.
2595 bool
2597 {
2598  if (has_changes() && !is_filtered_out())
2599  return true;
2600  return false;
2601 }
2602 
2603 /// Test if this diff tree node should be reported when considering
2604 /// the categories that were *NOT* inherited from its children nodes.
2605 ///
2606 /// @return true iff the current node should be reported.
2607 bool
2609 {
2610  if (has_local_changes()
2612  return true;
2613  return false;
2614 }
2615 
2616 /// Test if this diff node is allowed (prevented from being
2617 /// suppressed) by at least one negated suppression specification.
2618 ///
2619 /// @return true if this diff node is meant to be allowed by at least
2620 /// one negated suppression specification.
2621 bool
2623 {
2624  const suppressions_type& suppressions = context()->suppressions();
2625  for (suppressions_type::const_iterator i = suppressions.begin();
2626  i != suppressions.end();
2627  ++i)
2628  {
2629  if (is_negated_suppression(*i)
2630  && !(*i)->suppresses_diff(this))
2631  return true;
2632  }
2633  return false;
2634 }
2635 
2636 /// Test if the current diff node has a descendant node which is
2637 /// specifically allowed by a negated suppression specification.
2638 ///
2639 /// @return true iff the current diff node has a descendant node
2640 /// which is specifically allowed by a negated suppression
2641 /// specification.
2642 bool
2644 {
2646  return result;
2647 }
2648 
2649 /// Test if the current diff node has a parent node which is
2650 /// specifically allowed by a negated suppression specification.
2651 ///
2652 /// @return true iff the current diff node has a parent node which is
2653 /// specifically allowed by a negated suppression specification.
2654 bool
2656 {
2658  return result;
2659 }
2660 
2661 /// Get a pretty representation of the current @ref diff node.
2662 ///
2663 /// This is suitable for e.g. emitting debugging traces for the diff
2664 /// tree nodes.
2665 ///
2666 /// @return the pretty representation of the diff node.
2667 const string&
2669 {
2670  if (priv_->pretty_representation_.empty())
2671  priv_->pretty_representation_ = "empty_diff";
2672  return priv_->pretty_representation_;
2673 }
2674 
2675 /// Default implementation of the hierachy chaining virtual function.
2676 ///
2677 /// There are several types of diff nodes that have logical children
2678 /// nodes; for instance, a typedef_diff has the diff of the underlying
2679 /// type as a child node. A var_diff has the diff of the types of the
2680 /// variables as a child node, etc.
2681 ///
2682 /// But because the @ref diff base has a generic representation for
2683 /// children nodes of the all the types of @ref diff nodes (regardless
2684 /// of the specific most-derived type of diff node) that one can get
2685 /// using the method diff::children_nodes(), one need to populate that
2686 /// vector of children node.
2687 ///
2688 /// Populating that vector of children node is done by this function;
2689 /// it must be overloaded by each most-derived type of diff node that
2690 /// extends the @ref diff type.
2691 void
2693 {}
2694 
2695 // </diff stuff>
2696 
2697 // <type_diff_base stuff>
2698 
2699 type_diff_base::type_diff_base(type_base_sptr first_subject,
2700  type_base_sptr second_subject,
2701  diff_context_sptr ctxt)
2702  : diff(first_subject, second_subject, ctxt),
2703  priv_(new priv)
2704 {}
2705 
2706 type_diff_base::~type_diff_base()
2707 {}
2708 // </type_diff_base stuff>
2709 
2710 // <decl_diff_base stuff>
2711 
2712 /// Constructor of @ref decl_diff_base.
2713 ///
2714 /// @param first_subject the first subject of the diff.
2715 ///
2716 /// @param second_subject the second subject of the diff.
2717 ///
2718 /// @param ctxt the context of the diff. This object must stay alive
2719 /// at least during the life time of the current instance of @ref
2720 /// decl_diff_base, otherwise, memory corruption issues occur.
2721 decl_diff_base::decl_diff_base(decl_base_sptr first_subject,
2722  decl_base_sptr second_subject,
2723  diff_context_sptr ctxt)
2724  : diff(first_subject, second_subject, ctxt),
2725  priv_(new priv)
2726 {}
2727 
2728 decl_diff_base::~decl_diff_base()
2729 {}
2730 
2731 // </decl_diff_base stuff>
2732 
2733 // <distinct_diff stuff>
2734 
2735 /// @return a pretty representation for the @ref distinct_diff node.
2736 const string&
2738 {
2739  if (diff::priv_->pretty_representation_.empty())
2740  {
2741  std::ostringstream o;
2742  o << "distinct_diff[";
2743  if (first_subject())
2744  o << first_subject()->get_pretty_representation();
2745  else
2746  o << "null";
2747  o << ", ";
2748  if (second_subject())
2749  o << second_subject()->get_pretty_representation() ;
2750  else
2751  o << "null";
2752  o << "]" ;
2753  diff::priv_->pretty_representation_ = o.str();
2754  }
2755  return diff::priv_->pretty_representation_;
2756 }
2757 
2758 /// Populate the vector of children node of the @ref diff base type
2759 /// sub-object of this instance of @distinct_diff.
2760 ///
2761 /// The children nodes can then later be retrieved using
2762 /// diff::children_nodes().
2763 void
2765 {
2767 
2768  if (diff_sptr d = compatible_child_diff())
2769  append_child_node(d);
2770 }
2771 
2772 /// Constructor for @ref distinct_diff.
2773 ///
2774 /// Note that the two entities considered for the diff (and passed in
2775 /// parameter) must be of different kinds.
2776 ///
2777 /// @param first the first entity to consider for the diff.
2778 ///
2779 /// @param second the second entity to consider for the diff.
2780 ///
2781 /// @param ctxt the context of the diff. Note that this context
2782 /// object must stay alive at least during the life time of the
2783 /// current instance of @ref distinct_diff. Otherwise memory
2784 /// corruption issues occur.
2786  type_or_decl_base_sptr second,
2787  diff_context_sptr ctxt)
2788  : diff(first, second, ctxt),
2789  priv_(new priv)
2791 
2792 /// Getter for the first subject of the diff.
2793 ///
2794 /// @return the first subject of the diff.
2797 {return first_subject();}
2798 
2799 /// Getter for the second subject of the diff.
2800 ///
2801 /// @return the second subject of the diff.
2804 {return second_subject();}
2805 
2806 /// Getter for the child diff of this distinct_diff instance.
2807 ///
2808 /// When a distinct_diff has two subjects that are different but
2809 /// compatible, then the distinct_diff instance has a child diff node
2810 /// (named the compatible child diff) that is the diff between the two
2811 /// subjects stripped from their typedefs. Otherwise, the compatible
2812 /// child diff is nul.
2813 ///
2814 /// Note that two diff subjects (that compare different) are
2815 /// considered compatible if stripping typedefs out of them makes them
2816 /// comparing equal.
2817 ///
2818 /// @return the compatible child diff node, if any. Otherwise, null.
2819 const diff_sptr
2821 {
2822  if (!priv_->compatible_child_diff)
2823  {
2824  type_base_sptr fs = strip_typedef(is_type(first())),
2825  ss = strip_typedef(is_type(second()));
2826 
2827  if (fs && ss
2829  get_type_declaration(ss)))
2830  priv_->compatible_child_diff = compute_diff(get_type_declaration(fs),
2832  context());
2833  }
2834  return priv_->compatible_child_diff;
2835 }
2836 
2837 /// Test if the two arguments are of different kind, or that are both
2838 /// NULL.
2839 ///
2840 /// @param first the first argument to test for similarity in kind.
2841 ///
2842 /// @param second the second argument to test for similarity in kind.
2843 ///
2844 /// @return true iff the two arguments are of different kind.
2845 bool
2847  type_or_decl_base_sptr second)
2848 {
2849  if (!!first != !!second)
2850  return true;
2851  if (!first && !second)
2852  // We do consider diffs of two empty decls as a diff of distinct
2853  // kinds, for now.
2854  return true;
2855  if (first == second)
2856  return false;
2857 
2858  const type_or_decl_base &f = *first, &s = *second;
2859  return typeid(f) != typeid(s);
2860 }
2861 
2862 /// @return true if the two subjects of the diff are different, false
2863 /// otherwise.
2864 bool
2866 {return first() != second();}
2867 
2868 /// @return the kind of local change carried by the current diff node.
2869 /// The value returned is zero if the current node carries no local
2870 /// change.
2871 enum change_kind
2873 {
2874  // Changes on a distinct_diff are all local.
2875  if (has_changes())
2876  return LOCAL_TYPE_CHANGE_KIND;
2877  return NO_CHANGE_KIND;
2878 }
2879 
2880 /// Emit a report about the current diff instance.
2881 ///
2882 /// @param out the output stream to send the diff report to.
2883 ///
2884 /// @param indent the indentation string to use in the report.
2885 void
2886 distinct_diff::report(ostream& out, const string& indent) const
2887 {
2888  context()->get_reporter()->report(*this, out, indent);
2889 }
2890 
2891 /// Try to diff entities that are of distinct kinds.
2892 ///
2893 /// @param first the first entity to consider for the diff.
2894 ///
2895 /// @param second the second entity to consider for the diff.
2896 ///
2897 /// @param ctxt the context of the diff.
2898 ///
2899 /// @return a non-null diff if a diff object could be built, null
2900 /// otherwise.
2903  const type_or_decl_base_sptr second,
2904  diff_context_sptr ctxt)
2905 {
2907  return distinct_diff_sptr();
2908 
2909  distinct_diff_sptr result(new distinct_diff(first, second, ctxt));
2910 
2911  ctxt->initialize_canonical_diff(result);
2912 
2913  return result;
2914 }
2915 
2916 /// </distinct_diff stuff>
2917 
2918 /// Try to compute a diff on two instances of DiffType representation.
2919 ///
2920 /// The function template performs the diff if and only if the decl
2921 /// representations are of a DiffType.
2922 ///
2923 /// @tparm DiffType the type of instances to diff.
2924 ///
2925 /// @param first the first representation of decl to consider in the
2926 /// diff computation.
2927 ///
2928 /// @param second the second representation of decl to consider in the
2929 /// diff computation.
2930 ///
2931 /// @param ctxt the diff context to use.
2932 ///
2933 ///@return the diff of the two types @p first and @p second if and
2934 ///only if they represent the parametrized type DiffType. Otherwise,
2935 ///returns a NULL pointer value.
2936 template<typename DiffType>
2937 diff_sptr
2939  const type_or_decl_base_sptr second,
2940  diff_context_sptr ctxt)
2941 {
2942  if (shared_ptr<DiffType> f =
2943  dynamic_pointer_cast<DiffType>(first))
2944  {
2945  shared_ptr<DiffType> s =
2946  dynamic_pointer_cast<DiffType>(second);
2947  if (!s)
2948  return diff_sptr();
2949  return compute_diff(f, s, ctxt);
2950  }
2951  return diff_sptr();
2952 }
2953 
2954 
2955 /// This is a specialization of @ref try_to_diff() template to diff
2956 /// instances of @ref class_decl.
2957 ///
2958 /// @param first the first representation of decl to consider in the
2959 /// diff computation.
2960 ///
2961 /// @param second the second representation of decl to consider in the
2962 /// diff computation.
2963 ///
2964 /// @param ctxt the diff context to use.
2965 template<>
2968  const type_or_decl_base_sptr second,
2969  diff_context_sptr ctxt)
2970 {
2971  if (class_decl_sptr f =
2972  dynamic_pointer_cast<class_decl>(first))
2973  {
2974  class_decl_sptr s = dynamic_pointer_cast<class_decl>(second);
2975  if (!s)
2976  return diff_sptr();
2977 
2978  if (f->get_is_declaration_only())
2979  {
2980  class_decl_sptr f2 =
2981  is_class_type (f->get_definition_of_declaration());
2982  if (f2)
2983  f = f2;
2984  }
2985  if (s->get_is_declaration_only())
2986  {
2987  class_decl_sptr s2 =
2988  is_class_type(s->get_definition_of_declaration());
2989  if (s2)
2990  s = s2;
2991  }
2992  return compute_diff(f, s, ctxt);
2993  }
2994  return diff_sptr();
2995 }
2996 
2997 /// Try to diff entities that are of distinct kinds.
2998 ///
2999 /// @param first the first entity to consider for the diff.
3000 ///
3001 /// @param second the second entity to consider for the diff.
3002 ///
3003 /// @param ctxt the context of the diff.
3004 ///
3005 /// @return a non-null diff if a diff object could be built, null
3006 /// otherwise.
3007 static diff_sptr
3008 try_to_diff_distinct_kinds(const type_or_decl_base_sptr first,
3009  const type_or_decl_base_sptr second,
3010  diff_context_sptr ctxt)
3011 {return compute_diff_for_distinct_kinds(first, second, ctxt);}
3012 
3013 /// Compute the difference between two types.
3014 ///
3015 /// The function considers every possible types known to libabigail
3016 /// and runs the appropriate diff function on them.
3017 ///
3018 /// Whenever a new kind of type decl is supported by abigail, if we
3019 /// want to be able to diff two instances of it, we need to update
3020 /// this function to support it.
3021 ///
3022 /// @param first the first type decl to consider for the diff
3023 ///
3024 /// @param second the second type decl to consider for the diff.
3025 ///
3026 /// @param ctxt the diff context to use.
3027 ///
3028 /// @return the resulting diff. It's a pointer to a descendent of
3029 /// abigail::comparison::diff.
3030 static diff_sptr
3031 compute_diff_for_types(const type_or_decl_base_sptr& first,
3032  const type_or_decl_base_sptr& second,
3033  const diff_context_sptr& ctxt)
3034 {
3035  type_or_decl_base_sptr f = first;
3036  type_or_decl_base_sptr s = second;
3037 
3038  diff_sptr d;
3039 
3040  ((d = try_to_diff<type_decl>(f, s, ctxt))
3041  ||(d = try_to_diff<enum_type_decl>(f, s, ctxt))
3042  ||(d = try_to_diff<union_decl>(f, s,ctxt))
3043  ||(d = try_to_diff<class_decl>(f, s,ctxt))
3044  ||(d = try_to_diff<pointer_type_def>(f, s, ctxt))
3045  ||(d = try_to_diff<reference_type_def>(f, s, ctxt))
3046  ||(d = try_to_diff<array_type_def::subrange_type>(f, s, ctxt))
3047  ||(d = try_to_diff<array_type_def>(f, s, ctxt))
3048  ||(d = try_to_diff<qualified_type_def>(f, s, ctxt))
3049  ||(d = try_to_diff<typedef_decl>(f, s, ctxt))
3050  ||(d = try_to_diff<function_type>(f, s, ctxt))
3051  ||(d = try_to_diff_distinct_kinds(f, s, ctxt)));
3052 
3053  ABG_ASSERT(d);
3054 
3055  return d;
3056 }
3057 
3060 {return static_cast<diff_category>(static_cast<unsigned>(c1)
3061  | static_cast<unsigned>(c2));}
3062 
3064 operator|=(diff_category& c1, diff_category c2)
3065 {
3066  c1 = c1 | c2;
3067  return c1;
3068 }
3069 
3071 operator&=(diff_category& c1, diff_category c2)
3072 {
3073  c1 = c1 & c2;
3074  return c1;
3075 }
3076 
3078 operator^(diff_category c1, diff_category c2)
3079 {return static_cast<diff_category>(static_cast<unsigned>(c1)
3080  ^ static_cast<unsigned>(c2));}
3081 
3084 {return static_cast<diff_category>(static_cast<unsigned>(c1)
3085  & static_cast<unsigned>(c2));}
3086 
3089 {return static_cast<diff_category>(~static_cast<unsigned>(c));}
3090 
3091 
3092 /// Getter of a bitmap made of the set of change categories that are
3093 /// considered harmless.
3094 ///
3095 /// @return the bitmap made of the set of change categories that are
3096 /// considered harmless.
3099 {
3116 }
3117 
3118 /// Getter of a bitmap made of the set of change categories that are
3119 /// considered harmful.
3120 ///
3121 /// @return the bitmap made of the set of change categories that are
3122 /// considered harmful.
3125 {
3129 }
3130 
3131 /// Serialize an instance of @ref diff_category to an output stream.
3132 ///
3133 /// @param o the output stream to serialize @p c to.
3134 ///
3135 /// @param c the instance of diff_category to serialize.
3136 ///
3137 /// @return the output stream to serialize @p c to.
3138 ostream&
3139 operator<<(ostream& o, diff_category c)
3140 {
3141  bool emitted_a_category = false;
3142 
3143  if (c == NO_CHANGE_CATEGORY)
3144  {
3145  o << "NO_CHANGE_CATEGORY";
3146  emitted_a_category = true;
3147  }
3148 
3149  if (c & ACCESS_CHANGE_CATEGORY)
3150  {
3151  if (emitted_a_category)
3152  o << "|";
3153  o << "ACCESS_CHANGE_CATEGORY";
3154  emitted_a_category |= true;
3155  }
3156 
3158  {
3159  if (emitted_a_category)
3160  o << "|";
3161  o << "COMPATIBLE_TYPE_CHANGE_CATEGORY";
3162  emitted_a_category |= true;
3163  }
3164 
3166  {
3167  if (emitted_a_category)
3168  o << "|";
3169  o << "HARMLESS_DECL_NAME_CHANGE_CATEGORY";
3170  emitted_a_category |= true;
3171  }
3172 
3174  {
3175  if (emitted_a_category)
3176  o << "|";
3177  o << "NON_VIRT_MEM_FUN_CHANGE_CATEGORY";
3178  emitted_a_category |= true;
3179  }
3180 
3182  {
3183  if (emitted_a_category)
3184  o << "|";
3185  o << "STATIC_DATA_MEMBER_CHANGE_CATEGORY";
3186  emitted_a_category |= true;
3187  }
3188 
3190  {
3191  if (emitted_a_category)
3192  o << "|";
3193  o << "HARMLESS_ENUM_CHANGE_CATEGORY";
3194  emitted_a_category |= true;
3195  }
3196 
3198  {
3199  if (emitted_a_category)
3200  o << "|";
3201  o << "HARMLESS_DATA_MEMBER_CHANGE_CATEGORY";
3202  emitted_a_category |= true;
3203  }
3204 
3206  {
3207  if (emitted_a_category)
3208  o << "|";
3209  o << "HARMLESS_SYMBOL_ALIAS_CHANGE_CATEGORY";
3210  emitted_a_category |= true;
3211  }
3212 
3214  {
3215  if (emitted_a_category)
3216  o << "|";
3217  o << "HARMLESS_UNION_CHANGE_CATEGORY";
3218  emitted_a_category |= true;
3219  }
3220 
3221  if (c & SUPPRESSED_CATEGORY)
3222  {
3223  if (emitted_a_category)
3224  o << "|";
3225  o << "SUPPRESSED_CATEGORY";
3226  emitted_a_category |= true;
3227  }
3228 
3229  if (c & PRIVATE_TYPE_CATEGORY)
3230  {
3231  if (emitted_a_category)
3232  o << "|";
3233  o << "PRIVATE_TYPE_CATEGORY";
3234  emitted_a_category |= true;
3235  }
3236 
3238  {
3239  if (emitted_a_category)
3240  o << "|";
3241  o << "SIZE_OR_OFFSET_CHANGE_CATEGORY";
3242  emitted_a_category |= true;
3243  }
3244 
3246  {
3247  if (emitted_a_category)
3248  o << "|";
3249  o << "VIRTUAL_MEMBER_CHANGE_CATEGORY";
3250  emitted_a_category |= true;
3251  }
3252 
3253  if (c & REDUNDANT_CATEGORY)
3254  {
3255  if (emitted_a_category)
3256  o << "|";
3257  o << "REDUNDANT_CATEGORY";
3258  emitted_a_category |= true;
3259  }
3260 
3262  {
3263  if (emitted_a_category)
3264  o << "|";
3265  o << "TYPE_DECL_ONLY_DEF_CHANGE_CATEGORY";
3266  emitted_a_category |= true;
3267  }
3268 
3270  {
3271  if (emitted_a_category)
3272  o << "|";
3273  o << "FN_PARM_TYPE_TOP_CV_CHANGE_CATEGORY";
3274  emitted_a_category |= true;
3275  }
3276 
3278  {
3279  if (emitted_a_category)
3280  o << "|";
3281  o << "FN_PARM_TYPE_CV_CHANGE_CATEGORY";
3282  emitted_a_category |= true;
3283  }
3284 
3286  {
3287  if (emitted_a_category)
3288  o << "|";
3289  o << "FN_RETURN_TYPE_CV_CHANGE_CATEGORY";
3290  emitted_a_category |= true;
3291  }
3292 
3294  {
3295  if (emitted_a_category)
3296  o << "|";
3297  o << "FN_PARM_ADD_REMOVE_CHANGE_CATEGORY";
3298  emitted_a_category |= true;
3299  }
3300 
3302  {
3303  if (emitted_a_category)
3304  o << "|";
3305  o << "VAR_TYPE_CV_CHANGE_CATEGORY";
3306  emitted_a_category |= true;
3307  }
3308 
3310  {
3311  if (emitted_a_category)
3312  o << "|";
3313  o << "VOID_PTR_TO_PTR_CHANGE_CATEGORY";
3314  emitted_a_category |= true;
3315  }
3316 
3318  {
3319  if (emitted_a_category)
3320  o << "|";
3321  o << "BENIGN_INFINITE_ARRAY_CHANGE_CATEGORY";
3322  emitted_a_category |= true;
3323  }
3324 
3326  {
3327  if (emitted_a_category)
3328  o << "|";
3329  o << "HAS_ALLOWED_CHANGE_CATEGORY";
3330  emitted_a_category |= true;
3331  }
3332 
3334  {
3335  if (emitted_a_category)
3336  o << "|";
3337  o << "HAS_DESCENDANT_WITH_ALLOWED_CHANGE_CATEGORY";
3338  emitted_a_category |= true;
3339  }
3340 
3342  {
3343  if (emitted_a_category)
3344  o << "|";
3345  o << "HAS_PARENT_WITH_ALLOWED_CHANGE_CATEGORY";
3346  emitted_a_category |= true;
3347  }
3348 
3349  return o;
3350 }
3351 
3352 /// Compute the difference between two decls.
3353 ///
3354 /// The function consider every possible decls known to libabigail and
3355 /// runs the appropriate diff function on them.
3356 ///
3357 /// Whenever a new kind of non-type decl is supported by abigail, if
3358 /// we want to be able to diff two instances of it, we need to update
3359 /// this function to support it.
3360 ///
3361 /// @param first the first decl to consider for the diff
3362 ///
3363 /// @param second the second decl to consider for the diff.
3364 ///
3365 /// @param ctxt the diff context to use.
3366 ///
3367 /// @return the resulting diff.
3368 static diff_sptr
3369 compute_diff_for_decls(const decl_base_sptr first,
3370  const decl_base_sptr second,
3371  diff_context_sptr ctxt)
3372 {
3373 
3374  diff_sptr d;
3375 
3376  ((d = try_to_diff<function_decl>(first, second, ctxt))
3377  || (d = try_to_diff<var_decl>(first, second, ctxt))
3378  || (d = try_to_diff_distinct_kinds(first, second, ctxt)));
3379 
3380  ABG_ASSERT(d);
3381 
3382  return d;
3383 }
3384 
3385 /// Compute the difference between two decls. The decls can represent
3386 /// either type declarations, or non-type declaration.
3387 ///
3388 /// Note that the two decls must have been created in the same @ref
3389 /// environment, otherwise, this function aborts.
3390 ///
3391 /// @param first the first decl to consider.
3392 ///
3393 /// @param second the second decl to consider.
3394 ///
3395 /// @param ctxt the diff context to use.
3396 ///
3397 /// @return the resulting diff, or NULL if the diff could not be
3398 /// computed.
3399 diff_sptr
3400 compute_diff(const decl_base_sptr first,
3401  const decl_base_sptr second,
3402  diff_context_sptr ctxt)
3403 {
3404  if (!first || !second)
3405  return diff_sptr();
3406 
3407  diff_sptr d;
3408  if (is_type(first) && is_type(second))
3409  d = compute_diff_for_types(first, second, ctxt);
3410  else
3411  d = compute_diff_for_decls(first, second, ctxt);
3412  ABG_ASSERT(d);
3413  return d;
3414 }
3415 
3416 /// Compute the difference between two types.
3417 ///
3418 /// Note that the two types must have been created in the same @ref
3419 /// environment, otherwise, this function aborts.
3420 ///
3421 /// @param first the first type to consider.
3422 ///
3423 /// @param second the second type to consider.
3424 ///
3425 /// @param ctxt the diff context to use.
3426 ///
3427 /// @return the resulting diff, or NULL if the diff couldn't be
3428 /// computed.
3429 diff_sptr
3430 compute_diff(const type_base_sptr first,
3431  const type_base_sptr second,
3432  diff_context_sptr ctxt)
3433 {
3434  decl_base_sptr f = get_type_declaration(first),
3435  s = get_type_declaration(second);
3436 
3437  diff_sptr d = compute_diff_for_types(f,s, ctxt);
3438  ABG_ASSERT(d);
3439  return d;
3440 }
3441 
3442 /// Get a copy of the pretty representation of a diff node.
3443 ///
3444 /// @param d the diff node to consider.
3445 ///
3446 /// @return the pretty representation string.
3447 string
3449 {
3450  if (!d)
3451  return "";
3452  string prefix= "diff of ";
3453  return prefix + get_pretty_representation(d->first_subject());
3454 }
3455 
3456 // <var_diff stuff>
3457 
3458 /// Populate the vector of children node of the @ref diff base type
3459 /// sub-object of this instance of @ref var_diff.
3460 ///
3461 /// The children node can then later be retrieved using
3462 /// diff::children_node().
3463 void
3466 
3467 /// @return the pretty representation for this current instance of
3468 /// @ref var_diff.
3469 const string&
3471 {
3472  if (diff::priv_->pretty_representation_.empty())
3473  {
3474  std::ostringstream o;
3475  o << "var_diff["
3476  << first_subject()->get_pretty_representation()
3477  << ", "
3478  << second_subject()->get_pretty_representation()
3479  << "]";
3480  diff::priv_->pretty_representation_ = o.str();
3481  }
3482  return diff::priv_->pretty_representation_;
3483 }
3484 /// Constructor for @ref var_diff.
3485 ///
3486 /// @param first the first instance of @ref var_decl to consider in
3487 /// the diff.
3488 ///
3489 /// @param second the second instance of @ref var_decl to consider in
3490 /// the diff.
3491 ///
3492 /// @param type_diff the diff between types of the instances of
3493 /// var_decl.
3494 ///
3495 /// @param ctxt the diff context to use.
3497  var_decl_sptr second,
3498  diff_sptr type_diff,
3499  diff_context_sptr ctxt)
3500  : decl_diff_base(first, second, ctxt),
3501  priv_(new priv)
3502 {priv_->type_diff_ = type_diff;}
3503 
3504 /// Getter for the first @ref var_decl of the diff.
3505 ///
3506 /// @return the first @ref var_decl of the diff.
3509 {return dynamic_pointer_cast<var_decl>(first_subject());}
3510 
3511 /// Getter for the second @ref var_decl of the diff.
3512 ///
3513 /// @return the second @ref var_decl of the diff.
3516 {return dynamic_pointer_cast<var_decl>(second_subject());}
3517 
3518 /// Getter for the diff of the types of the instances of @ref
3519 /// var_decl.
3520 ///
3521 /// @return the diff of the types of the instances of @ref var_decl.
3522 diff_sptr
3524 {
3525  if (diff_sptr result = priv_->type_diff_.lock())
3526  return result;
3527  else
3528  {
3529  result = compute_diff(first_var()->get_type(),
3530  second_var()->get_type(),
3531  context());
3532  context()->keep_diff_alive(result);
3533  priv_->type_diff_ = result;
3534  return result;
3535  }
3536 }
3537 
3538 /// Return true iff the diff node has a change.
3539 ///
3540 /// @return true iff the diff node has a change.
3541 bool
3543 {return *first_var() != *second_var();}
3544 
3545 /// @return the kind of local change carried by the current diff node.
3546 /// The value returned is zero if the current node carries no local
3547 /// change.
3548 enum change_kind
3550 {
3551  ir::change_kind k = ir::NO_CHANGE_KIND;
3552  if (!equals(*first_var(), *second_var(), &k))
3553  return k & ir::ALL_LOCAL_CHANGES_MASK;
3554  return ir::NO_CHANGE_KIND;
3555 }
3556 
3557 /// Report the diff in a serialized form.
3558 ///
3559 /// @param out the stream to serialize the diff to.
3560 ///
3561 /// @param indent the prefix to use for the indentation of this
3562 /// serialization.
3563 void
3564 var_diff::report(ostream& out, const string& indent) const
3565 {
3566  context()->get_reporter()->report(*this, out, indent);
3567 }
3568 
3569 /// Compute the diff between two instances of @ref var_decl.
3570 ///
3571 /// Note that the two decls must have been created in the same @ref
3572 /// environment, otherwise, this function aborts.
3573 ///
3574 /// @param first the first @ref var_decl to consider for the diff.
3575 ///
3576 /// @param second the second @ref var_decl to consider for the diff.
3577 ///
3578 /// @param ctxt the diff context to use.
3579 ///
3580 /// @return the resulting diff between the two @ref var_decl.
3583  const var_decl_sptr second,
3584  diff_context_sptr ctxt)
3585 {
3586  var_diff_sptr d(new var_diff(first, second, diff_sptr(), ctxt));
3587  ctxt->initialize_canonical_diff(d);
3588 
3589  return d;
3590 }
3591 
3592 // </var_diff stuff>
3593 
3594 // <pointer_type_def stuff>
3595 
3596 /// Populate the vector of children node of the @ref diff base type
3597 /// sub-object of this instance of @ref pointer_diff.
3598 ///
3599 /// The children node can then later be retrieved using
3600 /// diff::children_node().
3601 void
3604 
3605 /// Constructor for a pointer_diff.
3606 ///
3607 /// @param first the first pointer to consider for the diff.
3608 ///
3609 /// @param second the secon pointer to consider for the diff.
3610 ///
3611 /// @param ctxt the diff context to use.
3613  pointer_type_def_sptr second,
3614  diff_sptr underlying,
3615  diff_context_sptr ctxt)
3616  : type_diff_base(first, second, ctxt),
3617  priv_(new priv(underlying))
3618 {}
3619 
3620 /// Getter for the first subject of a pointer diff
3621 ///
3622 /// @return the first pointer considered in this pointer diff.
3625 {return dynamic_pointer_cast<pointer_type_def>(first_subject());}
3626 
3627 /// Getter for the second subject of a pointer diff
3628 ///
3629 /// @return the second pointer considered in this pointer diff.
3632 {return dynamic_pointer_cast<pointer_type_def>(second_subject());}
3633 
3634 /// @return the pretty represenation for the current instance of @ref
3635 /// pointer_diff.
3636 const string&
3638 {
3639  if (diff::priv_->pretty_representation_.empty())
3640  {
3641  std::ostringstream o;
3642  o << "pointer_diff["
3643  << first_subject()->get_pretty_representation()
3644  << ", "
3645  << second_subject()->get_pretty_representation()
3646  << "]";
3647  diff::priv_->pretty_representation_ = o.str();
3648  }
3649  return diff::priv_->pretty_representation_;
3650 }
3651 
3652 /// Return true iff the current diff node carries a change.
3653 ///
3654 /// @return true iff the current diff node carries a change.
3655 bool
3657 {return first_pointer() != second_pointer();}
3658 
3659 /// @return the kind of local change carried by the current diff node.
3660 /// The value returned is zero if the current node carries no local
3661 /// change.
3662 enum change_kind
3664 {
3665  ir::change_kind k = ir::NO_CHANGE_KIND;
3666  if (!equals(*first_pointer(), *second_pointer(), &k))
3667  return k & ir::ALL_LOCAL_CHANGES_MASK;
3668  return ir::NO_CHANGE_KIND;
3669 }
3670 
3671 /// Getter for the diff between the pointed-to types of the pointers
3672 /// of this diff.
3673 ///
3674 /// @return the diff between the pointed-to types.
3675 diff_sptr
3677 {return priv_->underlying_type_diff_;}
3678 
3679 /// Setter for the diff between the pointed-to types of the pointers
3680 /// of this diff.
3681 ///
3682 /// @param d the new diff between the pointed-to types of the pointers
3683 /// of this diff.
3684 void
3686 {priv_->underlying_type_diff_ = d;}
3687 
3688 /// Report the diff in a serialized form.
3689 ///
3690 /// @param out the stream to serialize the diff to.
3691 ///
3692 /// @param indent the prefix to use for the indentation of this
3693 /// serialization.
3694 void
3695 pointer_diff::report(ostream& out, const string& indent) const
3696 {
3697  context()->get_reporter()->report(*this, out, indent);
3698 }
3699 
3700 /// Compute the diff between between two pointers.
3701 ///
3702 /// Note that the two types must have been created in the same @ref
3703 /// environment, otherwise, this function aborts.
3704 ///
3705 /// @param first the pointer to consider for the diff.
3706 ///
3707 /// @param second the pointer to consider for the diff.
3708 ///
3709 /// @return the resulting diff between the two pointers.
3710 ///
3711 /// @param ctxt the diff context to use.
3714  pointer_type_def_sptr second,
3715  diff_context_sptr ctxt)
3716 {
3717  diff_sptr d = compute_diff_for_types(first->get_pointed_to_type(),
3718  second->get_pointed_to_type(),
3719  ctxt);
3720  pointer_diff_sptr result(new pointer_diff(first, second, d, ctxt));
3721  ctxt->initialize_canonical_diff(result);
3722 
3723  return result;
3724 }
3725 
3726 // </pointer_type_def>
3727 
3728 // <subrange_diff >
3729 
3730 /// Constructor of the @ref subrange_diff diff node type.
3731 ///
3732 /// @param first the first subrange type to consider for the diff.
3733 ///
3734 /// @param second the second subrange type to consider for the diff.
3735 ///
3736 /// @param underlying_type_diff the underlying type diff between @p
3737 /// first and @p second.
3738 ///
3739 /// @param ctxt the diff context to use.
3741 (const array_type_def::subrange_sptr& first,
3742  const array_type_def::subrange_sptr& second,
3743  const diff_sptr& underlying_type_diff,
3744  const diff_context_sptr ctxt)
3745  : type_diff_base(first, second, ctxt),
3746  priv_(new priv(underlying_type_diff))
3747 {}
3748 
3749 
3750 /// Getter of the first subrange of the current instance @ref
3751 /// subrange_diff.
3752 ///
3753 /// @return The first subrange of the current instance @ref subrange_diff.
3756 {return is_subrange_type(first_subject());}
3757 
3758 /// Getter of the second subrange of the current instance @ref
3759 /// subrange_diff.
3760 ///
3761 /// @return The second subrange of the current instance @ref
3762 /// subrange_diff.
3765 {return is_subrange_type(second_subject());}
3766 
3767 /// Getter of the diff node of the underlying types of the current
3768 /// @ref subrange_diff diff node.
3769 ///
3770 /// @return The diff node of the underlying types of the current @ref
3771 /// subrange_diff diff node.
3772 const diff_sptr
3774 {return priv_->underlying_type_diff_;}
3775 
3776 /// Getter the pretty representation of the @ref subrange_diff diff
3777 /// node.
3778 ///
3779 /// @return The pretty representation of the @ref subrange_diff diff node.
3780 const string&
3782 {
3783  if (diff::priv_->pretty_representation_.empty())
3784  {
3785  std::ostringstream o;
3786  o << "subrange_diff["
3787  << first_subject()->get_pretty_representation()
3788  << ","
3789  << second_subject()->get_pretty_representation()
3790  << "]";
3791  diff::priv_->pretty_representation_ = o.str();
3792  }
3793  return diff::priv_->pretty_representation_;
3794 }
3795 
3796 /// Test if the current @ref subrange_diff node carries any change.
3797 ///
3798 /// @return true iff the current @ref subrange_diff node carries any
3799 /// change.
3800 bool
3802 {return *first_subrange() != *second_subrange();}
3803 
3804 /// Test if the current @ref subrange_diff node carries any local
3805 /// change.
3806 ///
3807 /// @return true iff the current @ref subrange_diff node carries any
3808 /// local change.
3809 enum change_kind
3811 {
3812  ir::change_kind k = ir::NO_CHANGE_KIND;
3813  if (!equals(*first_subrange(), *second_subrange(), &k))
3814  return k & ir::ALL_LOCAL_CHANGES_MASK;
3815  return ir::NO_CHANGE_KIND;
3816 }
3817 
3818 /// Report about the changes carried by this node.
3819 ///
3820 /// @param out the output stream to send the report to.
3821 ///
3822 /// @param indent the indentation string to use.
3823 void
3824 subrange_diff::report(ostream& out, const string& indent) const
3825 {context()->get_reporter()->report(*this, out, indent);}
3826 
3827 /// Populate the vector of children node of the @ref diff base type
3828 /// sub-object of this instance of @ref subrange_diff.
3829 ///
3830 /// The children node can then later be retrieved using
3831 /// diff::children_node().
3832 void
3835 
3836 /// Compute the diff between two instances of @ref subrange_diff.
3837 ///
3838 /// Note that the two decls must have been created in the same @ref
3839 /// environment, otherwise, this function aborts.
3840 ///
3841 /// @param first the first @ref subrange_diff to consider for the diff.
3842 ///
3843 /// @param second the second @ref subrange_diff to consider for the diff.
3844 ///
3845 /// @param ctxt the diff context to use.
3846 ///
3847 /// @return the resulting diff between the two @ref subrange_diff.
3851  diff_context_sptr ctxt)
3852 {
3853  diff_sptr d = compute_diff_for_types(first->get_underlying_type(),
3854  second->get_underlying_type(),
3855  ctxt);
3856 
3857  subrange_diff_sptr result(new subrange_diff(first, second, d, ctxt));
3858  ctxt->initialize_canonical_diff(result);
3859  return result;
3860 }
3861 
3862 //</subrange_diff >
3863 
3864 
3865 // <array_type_def>
3866 
3867 /// Populate the vector of children node of the @ref diff base type
3868 /// sub-object of this instance of @ref array_diff.
3869 ///
3870 /// The children node can then later be retrieved using
3871 /// diff::children_node().
3872 void
3875 
3876 /// Constructor for array_diff
3877 ///
3878 /// @param first the first array_type of the diff.
3879 ///
3880 /// @param second the second array_type of the diff.
3881 ///
3882 /// @param element_type_diff the diff between the two array element
3883 /// types.
3884 ///
3885 /// @param ctxt the diff context to use.
3887  const array_type_def_sptr second,
3888  diff_sptr element_type_diff,
3889  diff_context_sptr ctxt)
3890  : type_diff_base(first, second, ctxt),
3891  priv_(new priv(element_type_diff))
3892 {}
3893 
3894 /// Getter for the first array of the diff.
3895 ///
3896 /// @return the first array of the diff.
3897 const array_type_def_sptr
3899 {return dynamic_pointer_cast<array_type_def>(first_subject());}
3900 
3901 /// Getter for the second array of the diff.
3902 ///
3903 /// @return for the second array of the diff.
3904 const array_type_def_sptr
3906 {return dynamic_pointer_cast<array_type_def>(second_subject());}
3907 
3908 /// Getter for the diff between the two types of array elements.
3909 ///
3910 /// @return the diff between the two types of array elements.
3911 const diff_sptr&
3913 {return priv_->element_type_diff_;}
3914 
3915 /// Setter for the diff between the two array element types.
3916 ///
3917 /// @param d the new diff betweend the two array element types.
3918 void
3920 {priv_->element_type_diff_ = d;}
3921 
3922 /// @return the pretty representation for the current instance of @ref
3923 /// array_diff.
3924 const string&
3926 {
3927  if (diff::priv_->pretty_representation_.empty())
3928  {
3929  std::ostringstream o;
3930  o << "array_diff["
3931  << first_subject()->get_pretty_representation()
3932  << ", "
3933  << second_subject()->get_pretty_representation()
3934  << "]";
3935  diff::priv_->pretty_representation_ = o.str();
3936  }
3937  return diff::priv_->pretty_representation_;
3938 }
3939 
3940 /// Return true iff the current diff node carries a change.
3941 ///
3942 /// @return true iff the current diff node carries a change.
3943 bool
3945 {
3946  bool l = false;
3947 
3948  // the array element types match check for differing dimensions
3949  // etc...
3951  f = dynamic_pointer_cast<array_type_def>(first_subject()),
3952  s = dynamic_pointer_cast<array_type_def>(second_subject());
3953 
3954  if (f->get_name() != s->get_name())
3955  l |= true;
3956  if (f->get_size_in_bits() != s->get_size_in_bits())
3957  l |= true;
3958  if (f->get_alignment_in_bits() != s->get_alignment_in_bits())
3959  l |= true;
3960 
3961  l |= element_type_diff()
3962  ? element_type_diff()->has_changes()
3963  : false;
3964 
3965  return l;
3966 }
3967 
3968 
3969 /// @return the kind of local change carried by the current diff node.
3970 /// The value returned is zero if the current node carries no local
3971 /// change.
3972 enum change_kind
3974 {
3975  ir::change_kind k = ir::NO_CHANGE_KIND;
3976  if (!equals(*first_array(), *second_array(), &k))
3977  return k & ir::ALL_LOCAL_CHANGES_MASK;
3978  return ir::NO_CHANGE_KIND;
3979 }
3980 
3981 /// Report the diff in a serialized form.
3982 ///
3983 /// @param out the output stream to serialize the dif to.
3984 ///
3985 /// @param indent the string to use for indenting the report.
3986 void
3987 array_diff::report(ostream& out, const string& indent) const
3988 {
3989  context()->get_reporter()->report(*this, out, indent);
3990 }
3991 
3992 /// Compute the diff between two arrays.
3993 ///
3994 /// Note that the two types must have been created in the same @ref
3995 /// environment, otherwise, this function aborts.
3996 ///
3997 /// @param first the first array to consider for the diff.
3998 ///
3999 /// @param second the second array to consider for the diff.
4000 ///
4001 /// @param ctxt the diff context to use.
4004  array_type_def_sptr second,
4005  diff_context_sptr ctxt)
4006 {
4007  diff_sptr d = compute_diff_for_types(first->get_element_type(),
4008  second->get_element_type(),
4009  ctxt);
4010  array_diff_sptr result(new array_diff(first, second, d, ctxt));
4011  ctxt->initialize_canonical_diff(result);
4012  return result;
4013 }
4014 // </array_type_def>
4015 
4016 // <reference_type_def>
4017 
4018 /// Populate the vector of children node of the @ref diff base type
4019 /// sub-object of this instance of @ref reference_diff.
4020 ///
4021 /// The children node can then later be retrieved using
4022 /// diff::children_node().
4023 void
4026 
4027 /// Constructor for reference_diff
4028 ///
4029 /// @param first the first reference_type of the diff.
4030 ///
4031 /// @param second the second reference_type of the diff.
4032 ///
4033 /// @param ctxt the diff context to use.
4035  const reference_type_def_sptr second,
4036  diff_sptr underlying,
4037  diff_context_sptr ctxt)
4038  : type_diff_base(first, second, ctxt),
4039  priv_(new priv(underlying))
4040 {}
4041 
4042 /// Getter for the first reference of the diff.
4043 ///
4044 /// @return the first reference of the diff.
4047 {return dynamic_pointer_cast<reference_type_def>(first_subject());}
4048 
4049 /// Getter for the second reference of the diff.
4050 ///
4051 /// @return for the second reference of the diff.
4054 {return dynamic_pointer_cast<reference_type_def>(second_subject());}
4055 
4056 
4057 /// Getter for the diff between the two referred-to types.
4058 ///
4059 /// @return the diff between the two referred-to types.
4060 const diff_sptr&
4062 {return priv_->underlying_type_diff_;}
4063 
4064 /// Setter for the diff between the two referred-to types.
4065 ///
4066 /// @param d the new diff betweend the two referred-to types.
4067 diff_sptr&
4069 {
4070  priv_->underlying_type_diff_ = d;
4071  return priv_->underlying_type_diff_;
4072 }
4073 
4074 /// @return the pretty representation for the current instance of @ref
4075 /// reference_diff.
4076 const string&
4078 {
4079  if (diff::priv_->pretty_representation_.empty())
4080  {
4081  std::ostringstream o;
4082  o << "reference_diff["
4083  << first_subject()->get_pretty_representation()
4084  << ", "
4085  << second_subject()->get_pretty_representation()
4086  << "]";
4087  diff::priv_->pretty_representation_ = o.str();
4088  }
4089  return diff::priv_->pretty_representation_;
4090 }
4091 
4092 /// Return true iff the current diff node carries a change.
4093 ///
4094 /// @return true iff the current diff node carries a change.
4095 bool
4097 {
4098  return first_reference() != second_reference();
4099 }
4100 
4101 /// @return the kind of local change carried by the current diff node.
4102 /// The value returned is zero if the current node carries no local
4103 /// change.
4104 enum change_kind
4106 {
4107  ir::change_kind k = ir::NO_CHANGE_KIND;
4108  if (!equals(*first_reference(), *second_reference(), &k))
4109  return k & ir::ALL_LOCAL_CHANGES_MASK;
4110  return ir::NO_CHANGE_KIND;
4111 }
4112 
4113 /// Report the diff in a serialized form.
4114 ///
4115 /// @param out the output stream to serialize the dif to.
4116 ///
4117 /// @param indent the string to use for indenting the report.
4118 void
4119 reference_diff::report(ostream& out, const string& indent) const
4120 {
4121  context()->get_reporter()->report(*this, out, indent);
4122 }
4123 
4124 /// Compute the diff between two references.
4125 ///
4126 /// Note that the two types must have been created in the same @ref
4127 /// environment, otherwise, this function aborts.
4128 ///
4129 /// @param first the first reference to consider for the diff.
4130 ///
4131 /// @param second the second reference to consider for the diff.
4132 ///
4133 /// @param ctxt the diff context to use.
4136  reference_type_def_sptr second,
4137  diff_context_sptr ctxt)
4138 {
4139  diff_sptr d = compute_diff_for_types(first->get_pointed_to_type(),
4140  second->get_pointed_to_type(),
4141  ctxt);
4142  reference_diff_sptr result(new reference_diff(first, second, d, ctxt));
4143  ctxt->initialize_canonical_diff(result);
4144  return result;
4145 }
4146 // </reference_type_def>
4147 
4148 // <qualified_type_diff stuff>
4149 
4150 /// Populate the vector of children node of the @ref diff base type
4151 /// sub-object of this instance of @ref qualified_type_diff.
4152 ///
4153 /// The children node can then later be retrieved using
4154 /// diff::children_node().
4155 void
4158 
4159 /// Constructor for qualified_type_diff.
4160 ///
4161 /// @param first the first qualified type of the diff.
4162 ///
4163 /// @param second the second qualified type of the diff.
4164 ///
4165 /// @param ctxt the diff context to use.
4166 qualified_type_diff::qualified_type_diff(qualified_type_def_sptr first,
4167  qualified_type_def_sptr second,
4168  diff_sptr under,
4169  diff_context_sptr ctxt)
4170  : type_diff_base(first, second, ctxt),
4171  priv_(new priv(under))
4172 {}
4173 
4174 /// Getter for the first qualified type of the diff.
4175 ///
4176 /// @return the first qualified type of the diff.
4177 const qualified_type_def_sptr
4179 {return dynamic_pointer_cast<qualified_type_def>(first_subject());}
4180 
4181 /// Getter for the second qualified type of the diff.
4182 ///
4183 /// @return the second qualified type of the diff.
4184 const qualified_type_def_sptr
4186 {return dynamic_pointer_cast<qualified_type_def>(second_subject());}
4187 
4188 /// Getter for the diff between the underlying types of the two
4189 /// qualified types.
4190 ///
4191 /// @return the diff between the underlying types of the two qualified
4192 /// types.
4193 diff_sptr
4195 {return priv_->underlying_type_diff;}
4196 
4197 /// Getter for the diff between the most underlying non-qualified
4198 /// types of two qualified types.
4199 ///
4200 /// @return the diff between the most underlying non-qualified types
4201 /// of two qualified types.
4202 diff_sptr
4204 {
4205  if (!priv_->leaf_underlying_type_diff)
4206  priv_->leaf_underlying_type_diff
4207  = compute_diff_for_types(get_leaf_type(first_qualified_type()),
4209  context());
4210 
4211  return priv_->leaf_underlying_type_diff;
4212 }
4213 
4214 /// Setter for the diff between the underlying types of the two
4215 /// qualified types.
4216 ///
4217 /// @return the diff between the underlying types of the two qualified
4218 /// types.
4219 void
4221 {priv_->underlying_type_diff = d;}
4222 
4223 /// @return the pretty representation of the current instance of @ref
4224 /// qualified_type_diff.
4225 const string&
4227 {
4228  if (diff::priv_->pretty_representation_.empty())
4229  {
4230  std::ostringstream o;
4231  o << "qualified_type_diff["
4232  << first_subject()->get_pretty_representation()
4233  << ", "
4234  << second_subject()->get_pretty_representation()
4235  << "]";
4236  diff::priv_->pretty_representation_ = o.str();
4237  }
4238  return diff::priv_->pretty_representation_;
4239 }
4240 
4241 /// Return true iff the current diff node carries a change.
4242 ///
4243 /// @return true iff the current diff node carries a change.
4244 bool
4247 
4248 /// @return the kind of local change carried by the current diff node.
4249 /// The value returned is zero if the current node carries no local
4250 /// change.
4251 enum change_kind
4253 {
4254  ir::change_kind k = ir::NO_CHANGE_KIND;
4256  return k & ir::ALL_LOCAL_CHANGES_MASK;
4257  return ir::NO_CHANGE_KIND;
4258 }
4259 
4260 /// Report the diff in a serialized form.
4261 ///
4262 /// @param out the output stream to serialize to.
4263 ///
4264 /// @param indent the string to use to indent the lines of the report.
4265 void
4266 qualified_type_diff::report(ostream& out, const string& indent) const
4267 {
4268  context()->get_reporter()->report(*this, out, indent);
4269 }
4270 
4271 /// Compute the diff between two qualified types.
4272 ///
4273 /// Note that the two types must have been created in the same @ref
4274 /// environment, otherwise, this function aborts.
4275 ///
4276 /// @param first the first qualified type to consider for the diff.
4277 ///
4278 /// @param second the second qualified type to consider for the diff.
4279 ///
4280 /// @param ctxt the diff context to use.
4281 qualified_type_diff_sptr
4282 compute_diff(const qualified_type_def_sptr first,
4283  const qualified_type_def_sptr second,
4284  diff_context_sptr ctxt)
4285 {
4286  diff_sptr d = compute_diff_for_types(first->get_underlying_type(),
4287  second->get_underlying_type(),
4288  ctxt);
4289  qualified_type_diff_sptr result(new qualified_type_diff(first, second,
4290  d, ctxt));
4291  ctxt->initialize_canonical_diff(result);
4292  return result;
4293 }
4294 
4295 // </qualified_type_diff stuff>
4296 
4297 // <enum_diff stuff>
4298 
4299 /// Clear the lookup tables useful for reporting an enum_diff.
4300 ///
4301 /// This function must be updated each time a lookup table is added or
4302 /// removed from the class_diff::priv.
4303 void
4304 enum_diff::clear_lookup_tables()
4305 {
4306  priv_->deleted_enumerators_.clear();
4307  priv_->inserted_enumerators_.clear();
4308  priv_->changed_enumerators_.clear();
4309 }
4310 
4311 /// Tests if the lookup tables are empty.
4312 ///
4313 /// @return true if the lookup tables are empty, false otherwise.
4314 bool
4315 enum_diff::lookup_tables_empty() const
4316 {
4317  return (priv_->deleted_enumerators_.empty()
4318  && priv_->inserted_enumerators_.empty()
4319  && priv_->changed_enumerators_.empty());
4320 }
4321 
4322 /// If the lookup tables are not yet built, walk the differences and
4323 /// fill the lookup tables.
4324 void
4325 enum_diff::ensure_lookup_tables_populated()
4326 {
4327  if (!lookup_tables_empty())
4328  return;
4329 
4330  {
4331  edit_script e = priv_->enumerators_changes_;
4332 
4333  for (vector<deletion>::const_iterator it = e.deletions().begin();
4334  it != e.deletions().end();
4335  ++it)
4336  {
4337  unsigned i = it->index();
4338  const enum_type_decl::enumerator& n =
4339  first_enum()->get_enumerators()[i];
4340  const string& name = n.get_name();
4341  ABG_ASSERT(priv_->deleted_enumerators_.find(n.get_name())
4342  == priv_->deleted_enumerators_.end());
4343  priv_->deleted_enumerators_[name] = n;
4344  }
4345 
4346  for (vector<insertion>::const_iterator it = e.insertions().begin();
4347  it != e.insertions().end();
4348  ++it)
4349  {
4350  for (vector<unsigned>::const_iterator iit =
4351  it->inserted_indexes().begin();
4352  iit != it->inserted_indexes().end();
4353  ++iit)
4354  {
4355  unsigned i = *iit;
4356  const enum_type_decl::enumerator& n =
4357  second_enum()->get_enumerators()[i];
4358  const string& name = n.get_name();
4359  ABG_ASSERT(priv_->inserted_enumerators_.find(n.get_name())
4360  == priv_->inserted_enumerators_.end());
4361  string_enumerator_map::const_iterator j =
4362  priv_->deleted_enumerators_.find(name);
4363  if (j == priv_->deleted_enumerators_.end())
4364  priv_->inserted_enumerators_[name] = n;
4365  else
4366  {
4367  if (j->second != n)
4368  priv_->changed_enumerators_[j->first] =
4369  std::make_pair(j->second, n);
4370  priv_->deleted_enumerators_.erase(j);
4371  }
4372  }
4373  }
4374  }
4375 }
4376 
4377 /// Populate the vector of children node of the @ref diff base type
4378 /// sub-object of this instance of @ref enum_diff.
4379 ///
4380 /// The children node can then later be retrieved using
4381 /// diff::children_node().
4382 void
4385 
4386 /// Constructor for enum_diff.
4387 ///
4388 /// @param first the first enum type of the diff.
4389 ///
4390 /// @param second the second enum type of the diff.
4391 ///
4392 /// @param underlying_type_diff the diff of the two underlying types
4393 /// of the two enum types.
4394 ///
4395 /// @param ctxt the diff context to use.
4397  const enum_type_decl_sptr second,
4398  const diff_sptr underlying_type_diff,
4399  const diff_context_sptr ctxt)
4400  : type_diff_base(first, second, ctxt),
4401  priv_(new priv(underlying_type_diff))
4402 {}
4403 
4404 /// @return the first enum of the diff.
4405 const enum_type_decl_sptr
4407 {return dynamic_pointer_cast<enum_type_decl>(first_subject());}
4408 
4409 /// @return the second enum of the diff.
4410 const enum_type_decl_sptr
4412 {return dynamic_pointer_cast<enum_type_decl>(second_subject());}
4413 
4414 /// @return the diff of the two underlying enum types.
4415 diff_sptr
4417 {return priv_->underlying_type_diff_;}
4418 
4419 /// @return a map of the enumerators that were deleted.
4420 const string_enumerator_map&
4422 {return priv_->deleted_enumerators_;}
4423 
4424 /// @return a map of the enumerators that were inserted
4425 const string_enumerator_map&
4427 {return priv_->inserted_enumerators_;}
4428 
4429 /// @return a map of the enumerators that were changed
4432 {return priv_->changed_enumerators_;}
4433 
4434 /// @return the pretty representation of the current instance of @ref
4435 /// enum_diff.
4436 const string&
4438 {
4439  if (diff::priv_->pretty_representation_.empty())
4440  {
4441  std::ostringstream o;
4442  o << "enum_diff["
4443  << first_subject()->get_pretty_representation()
4444  << ", "
4445  << second_subject()->get_pretty_representation()
4446  << "]";
4447  diff::priv_->pretty_representation_ = o.str();
4448  }
4449  return diff::priv_->pretty_representation_;
4450 }
4451 
4452 /// Return true iff the current diff node carries a change.
4453 ///
4454 /// @return true iff the current diff node carries a change.
4455 bool
4457 {return first_enum() != second_enum();}
4458 
4459 /// @return the kind of local change carried by the current diff node.
4460 /// The value returned is zero if the current node carries no local
4461 /// change.
4462 enum change_kind
4464 {
4465  ir::change_kind k = ir::NO_CHANGE_KIND;
4466  if (!equals(*first_enum(), *second_enum(), &k))
4467  return k & ir::ALL_LOCAL_CHANGES_MASK;
4468  return ir::NO_CHANGE_KIND;
4469 }
4470 
4471 /// Report the differences between the two enums.
4472 ///
4473 /// @param out the output stream to send the report to.
4474 ///
4475 /// @param indent the string to use for indentation.
4476 void
4477 enum_diff::report(ostream& out, const string& indent) const
4478 {
4479  context()->get_reporter()->report(*this, out, indent);
4480 }
4481 
4482 /// Compute the set of changes between two instances of @ref
4483 /// enum_type_decl.
4484 ///
4485 /// Note that the two types must have been created in the same @ref
4486 /// environment, otherwise, this function aborts.
4487 ///
4488 /// @param first a pointer to the first enum_type_decl to consider.
4489 ///
4490 /// @param second a pointer to the second enum_type_decl to consider.
4491 ///
4492 /// @return the resulting diff of the two enums @p first and @p
4493 /// second.
4494 ///
4495 /// @param ctxt the diff context to use.
4496 enum_diff_sptr
4498  const enum_type_decl_sptr second,
4499  diff_context_sptr ctxt)
4500 {
4501  diff_sptr ud = compute_diff_for_types(first->get_underlying_type(),
4502  second->get_underlying_type(),
4503  ctxt);
4504  enum_diff_sptr d(new enum_diff(first, second, ud, ctxt));
4505  if (first != second)
4506  {
4507  compute_diff(first->get_enumerators().begin(),
4508  first->get_enumerators().end(),
4509  second->get_enumerators().begin(),
4510  second->get_enumerators().end(),
4511  d->priv_->enumerators_changes_);
4512  d->ensure_lookup_tables_populated();
4513  }
4514  ctxt->initialize_canonical_diff(d);
4515 
4516  return d;
4517 }
4518 // </enum_diff stuff>
4519 
4520 // <class_or_union_diff stuff>
4521 
4522 /// Test if the current diff node carries a member type change for a
4523 /// member type which name is the same as the name of a given type
4524 /// declaration.
4525 ///
4526 /// @param d the type declaration which name should be equal to the
4527 /// name of the member type that might have changed.
4528 ///
4529 /// @return the member type that has changed, iff there were a member
4530 /// type (which name is the same as the name of @p d) that changed.
4531 /// Note that the member type that is returned is the new value of the
4532 /// member type that changed.
4535 {
4536  string qname = d->get_qualified_name();
4537  string_diff_sptr_map::const_iterator it =
4538  changed_member_types_.find(qname);
4539 
4540  return ((it == changed_member_types_.end())
4542  : it->second->second_subject());
4543 }
4544 
4545 /// Test if the current diff node carries a data member change for a
4546 /// data member which name is the same as the name of a given type
4547 /// declaration.
4548 ///
4549 /// @param d the type declaration which name should be equal to the
4550 /// name of the data member that might have changed.
4551 ///
4552 /// @return the data member that has changed, iff there were a data
4553 /// member type (which name is the same as the name of @p d) that
4554 /// changed. Note that the data member that is returned is the new
4555 /// value of the data member that changed.
4556 decl_base_sptr
4558 {
4559  string qname = d->get_qualified_name();
4560  string_var_diff_sptr_map::const_iterator it =
4561  subtype_changed_dm_.find(qname);
4562 
4563  if (it == subtype_changed_dm_.end())
4564  return decl_base_sptr();
4565  return it->second->second_var();
4566 }
4567 
4568 /// Test if the current diff node carries a member class template
4569 /// change for a member class template which name is the same as the
4570 /// name of a given type declaration.
4571 ///
4572 /// @param d the type declaration which name should be equal to the
4573 /// name of the member class template that might have changed.
4574 ///
4575 /// @return the member class template that has changed, iff there were
4576 /// a member class template (which name is the same as the name of @p
4577 /// d) that changed. Note that the member class template that is
4578 /// returned is the new value of the member class template that
4579 /// changed.
4580 decl_base_sptr
4582 {
4583  string qname = d->get_qualified_name();
4584  string_diff_sptr_map::const_iterator it =
4585  changed_member_class_tmpls_.find(qname);
4586 
4587  return ((it == changed_member_class_tmpls_.end())
4588  ? decl_base_sptr()
4589  : dynamic_pointer_cast<decl_base>(it->second->second_subject()));
4590 }
4591 
4592 /// Get the number of non static data members that were deleted.
4593 ///
4594 /// @return the number of non static data members that were deleted.
4595 size_t
4597 {
4598  size_t result = 0;
4599 
4600  for (string_decl_base_sptr_map::const_iterator i =
4601  deleted_data_members_.begin();
4602  i != deleted_data_members_.end();
4603  ++i)
4604  if (is_member_decl(i->second)
4605  && !get_member_is_static(i->second))
4606  ++result;
4607 
4608  return result;
4609 }
4610 
4611 /// Get the number of non static data members that were inserted.
4612 ///
4613 /// @return the number of non static data members that were inserted.
4614 size_t
4616 {
4617  size_t result = 0;
4618 
4619  for (string_decl_base_sptr_map::const_iterator i =
4620  inserted_data_members_.begin();
4621  i != inserted_data_members_.end();
4622  ++i)
4623  if (is_member_decl(i->second)
4624  && !get_member_is_static(i->second))
4625  ++result;
4626 
4627  return result;
4628 }
4629 
4630 /// Get the number of data member sub-type changes carried by the
4631 /// current diff node that were filtered out.
4632 ///
4633 /// @param local_only if true, it means that only (filtered) local
4634 /// changes are considered.
4635 ///
4636 /// @return the number of data member sub-type changes carried by the
4637 /// current diff node that were filtered out.
4638 size_t
4640 {
4641  size_t num_filtered= 0;
4642  for (var_diff_sptrs_type::const_iterator i =
4643  sorted_subtype_changed_dm_.begin();
4644  i != sorted_subtype_changed_dm_.end();
4645  ++i)
4646  {
4647  if (local_only)
4648  {
4649  if ((*i)->has_changes()
4650  && !(*i)->has_local_changes_to_be_reported())
4651  ++num_filtered;
4652  }
4653  else
4654  {
4655  if ((*i)->is_filtered_out())
4656  ++num_filtered;
4657  }
4658  }
4659  return num_filtered;
4660 }
4661 
4662 /// Get the number of data member changes carried by the current diff
4663 /// node that were filtered out.
4664 ///
4665 /// @param local_only if true, it means that only (filtered) local
4666 /// changes are considered.
4667 ///
4668 /// @return the number of data member changes carried by the current
4669 /// diff node that were filtered out.
4670 size_t
4672 {
4673  size_t num_filtered= 0;
4674 
4675  for (unsigned_var_diff_sptr_map::const_iterator i = changed_dm_.begin();
4676  i != changed_dm_.end();
4677  ++i)
4678  {
4679  diff_sptr diff = i->second;
4680  if (local_only)
4681  {
4683  || diff->is_filtered_out())
4684  ++num_filtered;
4685  }
4686  else
4687  {
4688  if (diff->is_filtered_out())
4689  ++num_filtered;
4690  }
4691  }
4692  return num_filtered;
4693 }
4694 
4695 /// Skip the processing of the current member function if its
4696 /// virtual-ness is disallowed by the user.
4697 ///
4698 /// This is to be used in the member functions below that are used to
4699 /// count the number of filtered inserted, deleted and changed member
4700 /// functions.
4701 #define SKIP_MEM_FN_IF_VIRTUALITY_DISALLOWED \
4702  do { \
4703  if (get_member_function_is_virtual(f) \
4704  || get_member_function_is_virtual(s)) \
4705  { \
4706  if (!(allowed_category | VIRTUAL_MEMBER_CHANGE_CATEGORY)) \
4707  continue; \
4708  } \
4709  else \
4710  { \
4711  if (!(allowed_category | NON_VIRT_MEM_FUN_CHANGE_CATEGORY)) \
4712  continue; \
4713  } \
4714  } while (false)
4715 
4716 /// Get the number of member functions changes carried by the current
4717 /// diff node that were filtered out.
4718 ///
4719 /// @return the number of member functions changes carried by the
4720 /// current diff node that were filtered out.
4721 size_t
4723 (const diff_context_sptr& ctxt)
4724 {
4725  size_t count = 0;
4726  diff_category allowed_category = ctxt->get_allowed_category();
4727 
4728  for (function_decl_diff_sptrs_type::const_iterator i =
4729  sorted_changed_member_functions_.begin();
4730  i != sorted_changed_member_functions_.end();
4731  ++i)
4732  {
4733  method_decl_sptr f =
4734  dynamic_pointer_cast<method_decl>
4735  ((*i)->first_function_decl());
4736  ABG_ASSERT(f);
4737 
4738  method_decl_sptr s =
4739  dynamic_pointer_cast<method_decl>
4740  ((*i)->second_function_decl());
4741  ABG_ASSERT(s);
4742 
4744 
4745  diff_sptr diff = *i;
4746  ctxt->maybe_apply_filters(diff);
4747 
4748  if (diff->is_filtered_out())
4749  ++count;
4750  }
4751 
4752  return count;
4753 }
4754 
4755 /// Get the number of member functions insertions carried by the current
4756 /// diff node that were filtered out.
4757 ///
4758 /// @return the number of member functions insertions carried by the
4759 /// current diff node that were filtered out.
4760 size_t
4762 (const diff_context_sptr& ctxt)
4763 {
4764  size_t count = 0;
4765  diff_category allowed_category = ctxt->get_allowed_category();
4766 
4767  for (string_member_function_sptr_map::const_iterator i =
4768  inserted_member_functions_.begin();
4769  i != inserted_member_functions_.end();
4770  ++i)
4771  {
4772  method_decl_sptr f = i->second,
4773  s = i->second;
4774 
4776 
4777  diff_sptr diff = compute_diff_for_decls(f, s, ctxt);
4778  ctxt->maybe_apply_filters(diff);
4779 
4781  && diff->is_filtered_out())
4782  ++count;
4783  }
4784 
4785  return count;
4786 }
4787 
4788 /// Get the number of member functions deletions carried by the current
4789 /// diff node that were filtered out.
4790 ///
4791 /// @return the number of member functions deletions carried by the
4792 /// current diff node that were filtered out.
4793 size_t
4795 (const diff_context_sptr& ctxt)
4796 {
4797  size_t count = 0;
4798  diff_category allowed_category = ctxt->get_allowed_category();
4799 
4800  for (string_member_function_sptr_map::const_iterator i =
4801  deleted_member_functions_.begin();
4802  i != deleted_member_functions_.end();
4803  ++i)
4804  {
4805  method_decl_sptr f = i->second,
4806  s = i->second;
4807 
4809 
4810  diff_sptr diff = compute_diff_for_decls(f, s, ctxt);
4811  ctxt->maybe_apply_filters(diff);
4812 
4814  && diff->is_filtered_out())
4815  ++count;
4816  }
4817 
4818  return count;
4819 }
4820 
4821 /// Clear the lookup tables useful for reporting.
4822 ///
4823 /// This function must be updated each time a lookup table is added or
4824 /// removed from the class_or_union_diff::priv.
4825 void
4827 {
4828  priv_->deleted_member_types_.clear();
4829  priv_->inserted_member_types_.clear();
4830  priv_->changed_member_types_.clear();
4831  priv_->deleted_data_members_.clear();
4832  priv_->inserted_data_members_.clear();
4833  priv_->subtype_changed_dm_.clear();
4834  priv_->deleted_member_functions_.clear();
4835  priv_->inserted_member_functions_.clear();
4836  priv_->changed_member_functions_.clear();
4837  priv_->deleted_member_class_tmpls_.clear();
4838  priv_->inserted_member_class_tmpls_.clear();
4839  priv_->changed_member_class_tmpls_.clear();
4840 }
4841 
4842 /// Tests if the lookup tables are empty.
4843 ///
4844 /// @return true if the lookup tables are empty, false otherwise.
4845 bool
4847 {
4848  return (priv_->deleted_member_types_.empty()
4849  && priv_->inserted_member_types_.empty()
4850  && priv_->changed_member_types_.empty()
4851  && priv_->deleted_data_members_.empty()
4852  && priv_->inserted_data_members_.empty()
4853  && priv_->subtype_changed_dm_.empty()
4854  && priv_->inserted_member_functions_.empty()
4855  && priv_->deleted_member_functions_.empty()
4856  && priv_->changed_member_functions_.empty()
4857  && priv_->deleted_member_class_tmpls_.empty()
4858  && priv_->inserted_member_class_tmpls_.empty()
4859  && priv_->changed_member_class_tmpls_.empty());
4860 }
4861 
4862 /// If the lookup tables are not yet built, walk the differences and
4863 /// fill them.
4864 void
4866 {
4867  {
4868  edit_script& e = priv_->member_types_changes_;
4869 
4870  for (vector<deletion>::const_iterator it = e.deletions().begin();
4871  it != e.deletions().end();
4872  ++it)
4873  {
4874  unsigned i = it->index();
4875  decl_base_sptr d =
4876  get_type_declaration(first_class_or_union()->get_member_types()[i]);
4877  class_or_union_sptr record_type = is_class_or_union_type(d);
4878  if (record_type && record_type->get_is_declaration_only())
4879  continue;
4880  string name = d->get_name();
4881  priv_->deleted_member_types_[name] = d;
4882  }
4883 
4884  for (vector<insertion>::const_iterator it = e.insertions().begin();
4885  it != e.insertions().end();
4886  ++it)
4887  {
4888  for (vector<unsigned>::const_iterator iit =
4889  it->inserted_indexes().begin();
4890  iit != it->inserted_indexes().end();
4891  ++iit)
4892  {
4893  unsigned i = *iit;
4894  decl_base_sptr d =
4895  get_type_declaration(second_class_or_union()->get_member_types()[i]);
4896  class_or_union_sptr record_type = is_class_or_union_type(d);
4897  if (record_type && record_type->get_is_declaration_only())
4898  continue;
4899  string name = d->get_name();
4900  string_decl_base_sptr_map::const_iterator j =
4901  priv_->deleted_member_types_.find(name);
4902  if (j != priv_->deleted_member_types_.end())
4903  {
4904  if (*j->second != *d)
4905  priv_->changed_member_types_[name] =
4906  compute_diff(j->second, d, context());
4907 
4908  priv_->deleted_member_types_.erase(j);
4909  }
4910  else
4911  priv_->inserted_member_types_[name] = d;
4912  }
4913  }
4914  }
4915 
4916  {
4917  edit_script& e = priv_->data_members_changes_;
4918 
4919  for (vector<deletion>::const_iterator it = e.deletions().begin();
4920  it != e.deletions().end();
4921  ++it)
4922  {
4923  unsigned i = it->index();
4924  var_decl_sptr data_member =
4925  is_var_decl(first_class_or_union()->get_non_static_data_members()[i]);
4926  string name = data_member->get_anon_dm_reliable_name();
4927 
4928  ABG_ASSERT(priv_->deleted_data_members_.find(name)
4929  == priv_->deleted_data_members_.end());
4930  priv_->deleted_data_members_[name] = data_member;
4931  }
4932 
4933  for (vector<insertion>::const_iterator it = e.insertions().begin();
4934  it != e.insertions().end();
4935  ++it)
4936  {
4937  for (vector<unsigned>::const_iterator iit =
4938  it->inserted_indexes().begin();
4939  iit != it->inserted_indexes().end();
4940  ++iit)
4941  {
4942  unsigned i = *iit;
4943  decl_base_sptr d =
4944  second_class_or_union()->get_non_static_data_members()[i];
4945  var_decl_sptr added_dm = is_var_decl(d);
4946  string name = added_dm->get_anon_dm_reliable_name();
4947  ABG_ASSERT(priv_->inserted_data_members_.find(name)
4948  == priv_->inserted_data_members_.end());
4949 
4950  bool ignore_added_anonymous_data_member = false;
4951  if (is_anonymous_data_member(added_dm))
4952  {
4953  //
4954  // Handle insertion of anonymous data member to
4955  // replace existing data members.
4956  //
4957  // For instance consider this:
4958  // struct S
4959  // {
4960  // int a;
4961  // int b;
4962  // int c;
4963  // };// end struct S
4964  //
4965  // Where the data members 'a' and 'b' are replaced
4966  // by an anonymous data member without changing the
4967  // effective bit layout of the structure:
4968  //
4969  // struct S
4970  // {
4971  // struct
4972  // {
4973  // union
4974  // {
4975  // int a;
4976  // char a_1;
4977  // };
4978  // union
4979  // {
4980  // int b;
4981  // char b_1;
4982  // };
4983  // };
4984  // int c;
4985  // }; // end struct S
4986  //
4987  var_decl_sptr replaced_dm, replacing_dm;
4988  bool added_anon_dm_changes_dm = false;
4989  // The vector of data members replaced by anonymous
4990  // data members.
4991  vector<var_decl_sptr> dms_replaced_by_anon_dm;
4992 
4993  //
4994  // Let's start collecting the set of data members
4995  // which have been replaced by anonymous types in a
4996  // harmless way. These are going to be collected into
4997  // dms_replaced_by_anon_dm and, ultimately, into
4998  // priv_->dms_replaced_by_adms_
4999  //
5000  for (string_decl_base_sptr_map::const_iterator it =
5001  priv_->deleted_data_members_.begin();
5002  it != priv_->deleted_data_members_.end();
5003  ++it)
5004  {
5005  // We don't support this pattern for anonymous
5006  // data members themselves being replaced. If
5007  // that occurs then we'll just report it verbatim.
5008  if (is_anonymous_data_member(it->second))
5009  continue;
5010 
5011  string deleted_dm_name = it->second->get_name();
5012  if ((replacing_dm =
5014  deleted_dm_name)))
5015  {
5016  // So it looks like replacing_dm might have
5017  // replaced the data member which name is
5018  // 'deleted_dm_name'. Let's look deeper to be
5019  // sure.
5020  //
5021  // Note that replacing_dm is part (member) of
5022  // an anonymous data member that might replace
5023  // replaced_dm.
5024 
5025  // So let's get that replaced data member.
5026  replaced_dm = is_var_decl(it->second);
5027  size_t replaced_dm_offset =
5028  get_data_member_offset(replaced_dm),
5029  replacing_dm_offset =
5030  get_absolute_data_member_offset(replacing_dm);
5031 
5032  if (replaced_dm_offset != replacing_dm_offset)
5033  {
5034  // So the replacing data member and the
5035  // replaced data member don't have the
5036  // same offset. This is not the pattern we
5037  // are looking for. Rather, it looks like
5038  // the anonymous data member has *changed*
5039  // the data member.
5040  added_anon_dm_changes_dm = true;
5041  break;
5042  }
5043 
5044  if (replaced_dm->get_type()->get_size_in_bits()
5045  == replaced_dm->get_type()->get_size_in_bits())
5046  dms_replaced_by_anon_dm.push_back(replaced_dm);
5047  else
5048  {
5049  added_anon_dm_changes_dm = true;
5050  break;
5051  }
5052  }
5053  }
5054 
5055  // Now walk dms_replaced_by_anon_dm to fill up
5056  // priv_->dms_replaced_by_adms_ with the set of data
5057  // members replaced by anonymous data members.
5058  if (!added_anon_dm_changes_dm
5059  && !dms_replaced_by_anon_dm.empty())
5060  {
5061  // See if the added data member isn't too big.
5062  type_base_sptr added_dm_type = added_dm->get_type();
5063  ABG_ASSERT(added_dm_type);
5064  var_decl_sptr new_next_dm =
5066  added_dm);
5067  var_decl_sptr old_next_dm =
5068  first_class_or_union()->find_data_member(new_next_dm);
5069 
5070  if (!old_next_dm
5071  || (old_next_dm
5072  && (get_absolute_data_member_offset(old_next_dm)
5073  == get_absolute_data_member_offset(new_next_dm))))
5074  {
5075  // None of the data members that are replaced
5076  // by the added union should be considered as
5077  // having been deleted.
5078  ignore_added_anonymous_data_member = true;
5079  for (vector<var_decl_sptr>::const_iterator i =
5080  dms_replaced_by_anon_dm.begin();
5081  i != dms_replaced_by_anon_dm.end();
5082  ++i)
5083  {
5084  string n = (*i)->get_name();
5085  priv_->dms_replaced_by_adms_[n] =
5086  added_dm;
5087  priv_->deleted_data_members_.erase(n);
5088  }
5089  }
5090  }
5091  }
5092 
5093  if (!ignore_added_anonymous_data_member)
5094  {
5095  // Detect changed data members.
5096  //
5097  // A changed data member (that we shall name D) is a data
5098  // member that satisfies the conditions below:
5099  //
5100  // 1/ It must have been added.
5101  //
5102  // 2/ It must have been deleted as well.
5103  //
5104  // 3/ It there must be a non-empty difference between the
5105  // deleted D and the added D.
5106  string_decl_base_sptr_map::const_iterator j =
5107  priv_->deleted_data_members_.find(name);
5108  if (j != priv_->deleted_data_members_.end())
5109  {
5110  if (*j->second != *d)
5111  {
5112  var_decl_sptr old_dm = is_var_decl(j->second);
5113  priv_->subtype_changed_dm_[name]=
5114  compute_diff(old_dm, added_dm, context());
5115  }
5116  priv_->deleted_data_members_.erase(j);
5117  }
5118  else
5119  priv_->inserted_data_members_[name] = d;
5120  }
5121  }
5122  }
5123 
5124  // Now detect when a data member is deleted from offset N and
5125  // another one is added to offset N. In that case, we want to be
5126  // able to say that the data member at offset N changed.
5127  for (string_decl_base_sptr_map::const_iterator i =
5128  priv_->deleted_data_members_.begin();
5129  i != priv_->deleted_data_members_.end();
5130  ++i)
5131  {
5132  unsigned offset = get_data_member_offset(i->second);
5133  priv_->deleted_dm_by_offset_[offset] = i->second;
5134  }
5135 
5136  for (string_decl_base_sptr_map::const_iterator i =
5137  priv_->inserted_data_members_.begin();
5138  i != priv_->inserted_data_members_.end();
5139  ++i)
5140  {
5141  unsigned offset = get_data_member_offset(i->second);
5142  priv_->inserted_dm_by_offset_[offset] = i->second;
5143  }
5144 
5145  for (unsigned_decl_base_sptr_map::const_iterator i =
5146  priv_->inserted_dm_by_offset_.begin();
5147  i != priv_->inserted_dm_by_offset_.end();
5148  ++i)
5149  {
5150  unsigned_decl_base_sptr_map::const_iterator j =
5151  priv_->deleted_dm_by_offset_.find(i->first);
5152  if (j != priv_->deleted_dm_by_offset_.end())
5153  {
5154  var_decl_sptr old_dm = is_var_decl(j->second);
5155  var_decl_sptr new_dm = is_var_decl(i->second);
5156  priv_->changed_dm_[i->first] =
5157  compute_diff(old_dm, new_dm, context());
5158  }
5159  }
5160 
5161  for (unsigned_var_diff_sptr_map::const_iterator i =
5162  priv_->changed_dm_.begin();
5163  i != priv_->changed_dm_.end();
5164  ++i)
5165  {
5166  priv_->deleted_dm_by_offset_.erase(i->first);
5167  priv_->inserted_dm_by_offset_.erase(i->first);
5168  priv_->deleted_data_members_.erase
5169  (i->second->first_var()->get_anon_dm_reliable_name());
5170  priv_->inserted_data_members_.erase
5171  (i->second->second_var()->get_anon_dm_reliable_name());
5172  }
5173  }
5174  sort_string_data_member_diff_sptr_map(priv_->subtype_changed_dm_,
5175  priv_->sorted_subtype_changed_dm_);
5176  sort_unsigned_data_member_diff_sptr_map(priv_->changed_dm_,
5177  priv_->sorted_changed_dm_);
5178 
5179  {
5180  edit_script& e = priv_->member_class_tmpls_changes_;
5181 
5182  for (vector<deletion>::const_iterator it = e.deletions().begin();
5183  it != e.deletions().end();
5184  ++it)
5185  {
5186  unsigned i = it->index();
5187  decl_base_sptr d =
5188  first_class_or_union()->get_member_class_templates()[i]->
5189  as_class_tdecl();
5190  string name = d->get_name();
5191  ABG_ASSERT(priv_->deleted_member_class_tmpls_.find(name)
5192  == priv_->deleted_member_class_tmpls_.end());
5193  priv_->deleted_member_class_tmpls_[name] = d;
5194  }
5195 
5196  for (vector<insertion>::const_iterator it = e.insertions().begin();
5197  it != e.insertions().end();
5198  ++it)
5199  {
5200  for (vector<unsigned>::const_iterator iit =
5201  it->inserted_indexes().begin();
5202  iit != it->inserted_indexes().end();
5203  ++iit)
5204  {
5205  unsigned i = *iit;
5206  decl_base_sptr d =
5207  second_class_or_union()->get_member_class_templates()[i]->
5208  as_class_tdecl();
5209  string name = d->get_name();
5210  ABG_ASSERT(priv_->inserted_member_class_tmpls_.find(name)
5211  == priv_->inserted_member_class_tmpls_.end());
5212  string_decl_base_sptr_map::const_iterator j =
5213  priv_->deleted_member_class_tmpls_.find(name);
5214  if (j != priv_->deleted_member_class_tmpls_.end())
5215  {
5216  if (*j->second != *d)
5217  priv_->changed_member_types_[name]=
5218  compute_diff(j->second, d, context());
5219  priv_->deleted_member_class_tmpls_.erase(j);
5220  }
5221  else
5222  priv_->inserted_member_class_tmpls_[name] = d;
5223  }
5224  }
5225  }
5226  sort_string_diff_sptr_map(priv_->changed_member_types_,
5227  priv_->sorted_changed_member_types_);
5228 }
5229 
5230 /// Allocate the memory for the priv_ pimpl data member of the @ref
5231 /// class_or_union_diff class.
5232 void
5234 {
5235  if (!priv_)
5236  priv_.reset(new priv);
5237 }
5238 
5239 /// Constructor for the @ref class_or_union_diff class.
5240 ///
5241 /// @param first_scope the first @ref class_or_union of the diff node.
5242 ///
5243 /// @param second_scope the second @ref class_or_union of the diff node.
5244 ///
5245 /// @param ctxt the context of the diff.
5246 class_or_union_diff::class_or_union_diff(class_or_union_sptr first_scope,
5247  class_or_union_sptr second_scope,
5248  diff_context_sptr ctxt)
5249  : type_diff_base(first_scope, second_scope, ctxt)
5250  //priv_(new priv)
5251 {}
5252 
5253 /// Getter of the private data of the @ref class_or_union_diff type.
5254 ///
5255 /// Note that due to an optimization, the private data of @ref
5256 /// class_or_union_diff can be shared among several instances of
5257 /// class_or_union_diff, so you should never try to access
5258 /// class_or_union_diff::priv directly.
5259 ///
5260 /// When class_or_union_diff::priv is shared, this function returns
5261 /// the correct shared one.
5262 ///
5263 /// @return the (possibly) shared private data of the current instance
5264 /// of @ref class_or_union_diff.
5265 const class_or_union_diff::priv_ptr&
5267 {
5268  if (priv_)
5269  return priv_;
5270 
5271  // If the current class_or_union_diff::priv member is empty, then look for
5272  // the shared one, from the canonical type.
5273  class_or_union_diff *canonical =
5274  dynamic_cast<class_or_union_diff*>(get_canonical_diff());
5275  ABG_ASSERT(canonical);
5276  ABG_ASSERT(canonical->priv_);
5277 
5278  return canonical->priv_;
5279 }
5280 
5281 /// Destructor of class_or_union_diff.
5283 {
5284 }
5285 
5286 /// @return the first @ref class_or_union involved in the diff.
5287 class_or_union_sptr
5290 
5291 /// @return the second @ref class_or_union involved in the diff.
5292 class_or_union_sptr
5295 
5296 /// @return the edit script of the member types of the two @ref
5297 /// class_or_union.
5298 const edit_script&
5300 {return get_priv()->member_types_changes_;}
5301 
5302 /// @return the edit script of the member types of the two @ref
5303 /// class_or_union.
5304 edit_script&
5306 {return get_priv()->member_types_changes_;}
5307 
5308 /// @return the edit script of the data members of the two @ref
5309 /// class_or_union.
5310 const edit_script&
5312 {return get_priv()->data_members_changes_;}
5313 
5314 /// @return the edit script of the data members of the two @ref
5315 /// class_or_union.
5316 edit_script&
5318 {return get_priv()->data_members_changes_;}
5319 
5320 /// Getter for the data members that got inserted.
5321 ///
5322 /// @return a map of data members that got inserted.
5325 {return get_priv()->inserted_data_members_;}
5326 
5327 /// Getter for the data members that got deleted.
5328 ///
5329 /// @return a map of data members that got deleted.
5332 {return get_priv()->deleted_data_members_;}
5333 
5334 /// @return the edit script of the member functions of the two @ref
5335 /// class_or_union.
5336 const edit_script&
5338 {return get_priv()->member_fns_changes_;}
5339 
5340 /// Getter for the virtual members functions that have had a change in
5341 /// a sub-type, without having a change in their symbol name.
5342 ///
5343 /// @return a sorted vector of virtual member functions that have a
5344 /// sub-type change.
5347 {return get_priv()->sorted_changed_member_functions_;}
5348 
5349 /// @return the edit script of the member functions of the two
5350 /// classes.
5351 edit_script&
5353 {return get_priv()->member_fns_changes_;}
5354 
5355 /// @return a map of member functions that got deleted.
5358 {return get_priv()->deleted_member_functions_;}
5359 
5360 /// @return a map of member functions that got inserted.
5363 {return get_priv()->inserted_member_functions_;}
5364 
5365 /// Getter of the sorted vector of data members that got replaced by
5366 /// another data member.
5367 ///
5368 /// @return sorted vector of changed data member.
5369 const var_diff_sptrs_type&
5371 {return get_priv()->sorted_changed_dm_;}
5372 
5373 /// Count the number of /filtered/ data members that got replaced by
5374 /// another data member.
5375 ///
5376 /// @return the number of changed data member that got filtered out.
5377 size_t
5379 {return get_priv()->count_filtered_changed_dm(local);}
5380 
5381 /// Getter of the sorted vector of data members with a (sub-)type change.
5382 ///
5383 /// @return sorted vector of changed data member.
5384 const var_diff_sptrs_type&
5386 {return get_priv()->sorted_subtype_changed_dm_;}
5387 
5388 /// Count the number of /filtered/ data members with a sub-type change.
5389 ///
5390 /// @return the number of changed data member that got filtered out.
5391 size_t
5393 {return get_priv()->count_filtered_subtype_changed_dm(local);}
5394 
5395 /// Get the map of data members that got replaced by anonymous data
5396 /// members.
5397 ///
5398 /// The key of a map entry is the name of the replaced data member and
5399 /// the value is the anonymous data member that replaces it.
5400 ///
5401 /// @return the map of data members replaced by anonymous data
5402 /// members.
5405 {return get_priv()->dms_replaced_by_adms_;}
5406 
5407 /// Get an ordered vector of of data members that got replaced by
5408 /// anonymous data members.
5409 ///
5410 /// This returns a vector of pair of two data members: the one that
5411 /// was replaced, and the anonymous data member that replaced it.
5412 ///
5413 /// @return the sorted vector data members replaced by anonymous data members.
5416 {
5417  if (priv_->dms_replaced_by_adms_ordered_.empty())
5418  {
5419  for (string_decl_base_sptr_map::const_iterator it =
5420  priv_->dms_replaced_by_adms_.begin();
5421  it != priv_->dms_replaced_by_adms_.end();
5422  ++it)
5423  {
5424  const var_decl_sptr dm =
5425  first_class_or_union()->find_data_member(it->first);
5426  ABG_ASSERT(dm);
5427  changed_var_sptr changed_dm(dm, is_data_member(it->second));
5428  priv_->dms_replaced_by_adms_ordered_.push_back(changed_dm);
5429  }
5430  sort_changed_data_members(priv_->dms_replaced_by_adms_ordered_);
5431  }
5432 
5433  return priv_->dms_replaced_by_adms_ordered_;
5434 }
5435 
5436 /// @return the edit script of the member function templates of the two
5437 /// @ref class_or_union.
5438 const edit_script&
5440 {return get_priv()->member_fn_tmpls_changes_;}
5441 
5442 /// @return the edit script of the member function templates of the
5443 /// two @ref class_or_union.
5444 edit_script&
5446 {return get_priv()->member_fn_tmpls_changes_;}
5447 
5448 /// @return the edit script of the member class templates of the two
5449 /// @ref class_or_union.
5450 const edit_script&
5452 {return get_priv()->member_class_tmpls_changes_;}
5453 
5454 /// @return the edit script of the member class templates of the two
5455 /// @ref class_or_union.
5456 edit_script&
5458 {return get_priv()->member_class_tmpls_changes_;}
5459 
5460 /// Test if the current diff node carries a change.
5461 bool
5464 
5465 /// @return the kind of local change carried by the current diff node.
5466 /// The value returned is zero if the current node carries no local
5467 /// change.
5468 enum change_kind
5470 {
5471  ir::change_kind k = ir::NO_CHANGE_KIND;
5473  return k & ir::ALL_LOCAL_CHANGES_MASK;
5474  return ir::NO_CHANGE_KIND;
5475 }
5476 
5477 
5478 /// Report the changes carried by the current @ref class_or_union_diff
5479 /// node in a textual format.
5480 ///
5481 /// @param out the output stream to write the textual report to.
5482 ///
5483 /// @param indent the number of white space to use as indentation.
5484 void
5485 class_or_union_diff::report(ostream& out, const string& indent) const
5486 {
5487  context()->get_reporter()->report(*this, out, indent);
5488 }
5489 
5490 /// Populate the vector of children node of the @ref diff base type
5491 /// sub-object of this instance of @ref class_or_union_diff.
5492 ///
5493 /// The children node can then later be retrieved using
5494 /// diff::children_node().
5495 void
5497 {
5498  // data member changes
5499  for (var_diff_sptrs_type::const_iterator i =
5500  get_priv()->sorted_subtype_changed_dm_.begin();
5501  i != get_priv()->sorted_subtype_changed_dm_.end();
5502  ++i)
5503  if (diff_sptr d = *i)
5504  append_child_node(d);
5505 
5506  for (var_diff_sptrs_type::const_iterator i =
5507  get_priv()->sorted_changed_dm_.begin();
5508  i != get_priv()->sorted_changed_dm_.end();
5509  ++i)
5510  if (diff_sptr d = *i)
5511  append_child_node(d);
5512 
5513  // member types changes
5514  for (diff_sptrs_type::const_iterator i =
5515  get_priv()->sorted_changed_member_types_.begin();
5516  i != get_priv()->sorted_changed_member_types_.end();
5517  ++i)
5518  if (diff_sptr d = *i)
5519  append_child_node(d);
5520 
5521  // member function changes
5522  for (function_decl_diff_sptrs_type::const_iterator i =
5523  get_priv()->sorted_changed_member_functions_.begin();
5524  i != get_priv()->sorted_changed_member_functions_.end();
5525  ++i)
5526  if (diff_sptr d = *i)
5527  append_child_node(d);
5528 }
5529 
5530 // </class_or_union_diff stuff>
5531 
5532 //<class_diff stuff>
5533 
5534 /// Clear the lookup tables useful for reporting.
5535 ///
5536 /// This function must be updated each time a lookup table is added or
5537 /// removed from the class_diff::priv.
5538 void
5539 class_diff::clear_lookup_tables(void)
5540 {
5541  priv_->deleted_bases_.clear();
5542  priv_->inserted_bases_.clear();
5543  priv_->changed_bases_.clear();
5544 }
5545 
5546 /// Tests if the lookup tables are empty.
5547 ///
5548 /// @return true if the lookup tables are empty, false otherwise.
5549 bool
5550 class_diff::lookup_tables_empty(void) const
5551 {
5552  return (priv_->deleted_bases_.empty()
5553  && priv_->inserted_bases_.empty()
5554  && priv_->changed_bases_.empty());
5555 }
5556 
5557 /// Find a virtual destructor in a map of member functions
5558 ///
5559 /// @param map the map of member functions. Note that the key of the
5560 /// map is the member function name. The key is the member function.
5561 ///
5562 /// @return an iterator to the destructor found or, if no virtual destructor
5563 /// was found, return map.end()
5564 static string_member_function_sptr_map::const_iterator
5565 find_virtual_dtor_in_map(const string_member_function_sptr_map& map)
5566 {
5567  for (string_member_function_sptr_map::const_iterator i = map.begin();
5568  i !=map.end();
5569  ++i)
5570  {
5571  if (get_member_function_is_dtor(i->second)
5572  && get_member_function_is_virtual(i->second))
5573  return i;
5574  }
5575  return map.end();
5576 }
5577 
5578 /// If the lookup tables are not yet built, walk the differences and
5579 /// fill them.
5580 void
5581 class_diff::ensure_lookup_tables_populated(void) const
5582 {
5584 
5585  if (!lookup_tables_empty())
5586  return;
5587 
5588  {
5589  edit_script& e = get_priv()->base_changes_;
5590 
5591  for (vector<deletion>::const_iterator it = e.deletions().begin();
5592  it != e.deletions().end();
5593  ++it)
5594  {
5595  unsigned i = it->index();
5597  first_class_decl()->get_base_specifiers()[i];
5598  string name = b->get_base_class()->get_qualified_name();
5599  ABG_ASSERT(get_priv()->deleted_bases_.find(name)
5600  == get_priv()->deleted_bases_.end());
5601  get_priv()->deleted_bases_[name] = b;
5602  }
5603 
5604  for (vector<insertion>::const_iterator it = e.insertions().begin();
5605  it != e.insertions().end();
5606  ++it)
5607  {
5608  for (vector<unsigned>::const_iterator iit =
5609  it->inserted_indexes().begin();
5610  iit != it->inserted_indexes().end();
5611  ++iit)
5612  {
5613  unsigned i = *iit;
5615  second_class_decl()->get_base_specifiers()[i];
5616  string name = b->get_base_class()->get_qualified_name();
5617  ABG_ASSERT(get_priv()->inserted_bases_.find(name)
5618  == get_priv()->inserted_bases_.end());
5619  string_base_sptr_map::const_iterator j =
5620  get_priv()->deleted_bases_.find(name);
5621  if (j != get_priv()->deleted_bases_.end())
5622  {
5623  if (j->second != b)
5624  get_priv()->changed_bases_[name] =
5625  compute_diff(j->second, b, context());
5626  else
5627  // The base class changed place. IOW, the base
5628  // classes got re-arranged. Let's keep track of the
5629  // base classes that moved.
5630  get_priv()->moved_bases_.push_back(b);
5631  get_priv()->deleted_bases_.erase(j);
5632  }
5633  else
5634  get_priv()->inserted_bases_[name] = b;
5635  }
5636  }
5637  }
5638 
5639  sort_string_base_sptr_map(get_priv()->deleted_bases_,
5640  get_priv()->sorted_deleted_bases_);
5641  sort_string_base_sptr_map(get_priv()->inserted_bases_,
5642  get_priv()->sorted_inserted_bases_);
5643  sort_string_base_diff_sptr_map(get_priv()->changed_bases_,
5644  get_priv()->sorted_changed_bases_);
5645 
5646  {
5647  const class_or_union_diff::priv_ptr &p = class_or_union_diff::get_priv();
5648 
5649  edit_script& e = p->member_fns_changes_;
5650 
5651  for (vector<deletion>::const_iterator it = e.deletions().begin();
5652  it != e.deletions().end();
5653  ++it)
5654  {
5655  unsigned i = it->index();
5656  method_decl_sptr mem_fn =
5657  first_class_decl()->get_virtual_mem_fns()[i];
5658  string name = mem_fn->get_linkage_name();
5659  if (name.empty())
5660  name = mem_fn->get_pretty_representation();
5661  ABG_ASSERT(!name.empty());
5662  if (p->deleted_member_functions_.find(name)
5663  != p->deleted_member_functions_.end())
5664  continue;
5665  p->deleted_member_functions_[name] = mem_fn;
5666  }
5667 
5668  for (vector<insertion>::const_iterator it = e.insertions().begin();
5669  it != e.insertions().end();
5670  ++it)
5671  {
5672  for (vector<unsigned>::const_iterator iit =
5673  it->inserted_indexes().begin();
5674  iit != it->inserted_indexes().end();
5675  ++iit)
5676  {
5677  unsigned i = *iit;
5678 
5679  method_decl_sptr mem_fn =
5680  second_class_decl()->get_virtual_mem_fns()[i];
5681  string name = mem_fn->get_linkage_name();
5682  if (name.empty())
5683  name = mem_fn->get_pretty_representation();
5684  ABG_ASSERT(!name.empty());
5685  if (p->inserted_member_functions_.find(name)
5686  != p->inserted_member_functions_.end())
5687  continue;
5688  string_member_function_sptr_map::const_iterator j =
5689  p->deleted_member_functions_.find(name);
5690 
5691  if (j != p->deleted_member_functions_.end())
5692  {
5693  if (*j->second != *mem_fn)
5694  p->changed_member_functions_[name] =
5695  compute_diff(static_pointer_cast<function_decl>(j->second),
5696  static_pointer_cast<function_decl>(mem_fn),
5697  context());
5698  p->deleted_member_functions_.erase(j);
5699  }
5700  else
5701  p->inserted_member_functions_[name] = mem_fn;
5702  }
5703  }
5704 
5705  // Now walk the allegedly deleted member functions; check if their
5706  // underlying symbols are deleted as well; otherwise, consider
5707  // that the member function in question hasn't been deleted.
5708 
5709  // Also, while walking the deleted member functions, we attend at
5710  // a particular cleanup business related to (virtual) C++
5711  // destructors:
5712  //
5713  // In the binary, there can be at least three types of
5714  // destructors, defined in the document
5715  // https://itanium-cxx-abi.github.io/cxx-abi/abi.html#definitions:
5716  //
5717  // 1/ Base object destructor (aka D2 destructor):
5718  //
5719  // "A function that runs the destructors for non-static data
5720  // members of T and non-virtual direct base classes of T. "
5721  //
5722  // 2/ Complete object destructor (aka D1 destructor):
5723  //
5724  // "A function that, in addition to the actions required of a
5725  // base object destructor, runs the destructors for the
5726  // virtual base classes of T."
5727  //
5728  // 3/ Deleting destructor (aka D0 destructor):
5729  //
5730  // "A function that, in addition to the actions required of a
5731  // complete object destructor, calls the appropriate
5732  // deallocation function (i.e,. operator delete) for T."
5733  //
5734  // With binaries generated by GCC, these destructors might be ELF
5735  // clones of each others, meaning, their ELF symbols can be
5736  // aliases.
5737  //
5738  // Also, note that because the actual destructor invoked by user
5739  // code is virtual, it's invoked through the vtable. So the
5740  // presence of the underlying D0, D1, D2 in the binary might vary
5741  // without that variation being an ABI issue, provided that the
5742  // destructor invoked through the vtable is present.
5743  //
5744  // So, a particular virtual destructor implementation for a class
5745  // might disapear and be replaced by another one in a subsequent
5746  // version of the binary. If all versions of the binary have an
5747  // actual virtual destructor, things might be considered fine.
5748  vector<string> to_delete;
5749  corpus_sptr f = context()->get_first_corpus(),
5750  s = context()->get_second_corpus();
5751  if (s)
5752  for (string_member_function_sptr_map::const_iterator i =
5753  deleted_member_fns().begin();
5754  i != deleted_member_fns().end();
5755  ++i)
5756  {
5757  if (get_member_function_is_virtual(i->second))
5758  {
5759  if (get_member_function_is_dtor(i->second))
5760  {
5761  // If a particular virtual destructor is deleted,
5762  // but the new binary still have a virtual
5763  // destructor for that class we consider that things
5764  // are fine. For instance, in the
5765  // tests/data/test-diff-pkg/tbb-4.1-9.20130314.fc22.x86_64--tbb-4.3-3.20141204.fc23.x86_64-report-0.txt
5766  // test, a new D4 destructor replaces the old ones.
5767  // But because the virtual destructor is still
5768  // there, this is not an ABI issue. So let's detect
5769  // this case.
5770  auto it =
5771  find_virtual_dtor_in_map(p->inserted_member_functions_);
5772  if (it != p->inserted_member_functions_.end())
5773  {
5774  // So the deleted virtual destructor is not
5775  // really deleted, because a proper virtual
5776  // destructor was added to the new version.
5777  // Let's remove the deleted/added virtual
5778  // destructor then.
5779  string name =
5780  (!i->second->get_linkage_name().empty())
5781  ? i->second->get_linkage_name()
5782  : i->second->get_pretty_representation();
5783  to_delete.push_back(name);
5784  p->inserted_member_functions_.erase(it);
5785  }
5786  }
5787  continue;
5788  }
5789  // We assume that all non-virtual member functions functions
5790  // we look at here have ELF symbols.
5791  if (!i->second->get_symbol()
5792  || s->lookup_function_symbol(*i->second->get_symbol()))
5793  to_delete.push_back(i->first);
5794  }
5795 
5796 
5797  for (vector<string>::const_iterator i = to_delete.begin();
5798  i != to_delete.end();
5799  ++i)
5800  p->deleted_member_functions_.erase(*i);
5801 
5802  // Do something similar for added functions.
5803  to_delete.clear();
5804  if (f)
5805  for (string_member_function_sptr_map::const_iterator i =
5806  inserted_member_fns().begin();
5807  i != inserted_member_fns().end();
5808  ++i)
5809  {
5810  if (get_member_function_is_virtual(i->second))
5811  continue;
5812  // We assume that all non-virtual member functions functions
5813  // we look at here have ELF symbols.
5814  if (!i->second->get_symbol()
5815  || f->lookup_function_symbol(*i->second->get_symbol()))
5816  to_delete.push_back(i->first);
5817  }
5818 
5819  for (vector<string>::const_iterator i = to_delete.begin();
5820  i != to_delete.end();
5821  ++i)
5822  p->inserted_member_functions_.erase(*i);
5823 
5824  sort_string_member_function_sptr_map(p->deleted_member_functions_,
5825  p->sorted_deleted_member_functions_);
5826 
5827  sort_string_member_function_sptr_map(p->inserted_member_functions_,
5828  p->sorted_inserted_member_functions_);
5829 
5831  (p->changed_member_functions_,
5832  p->sorted_changed_member_functions_);
5833  }
5834 }
5835 
5836 /// Allocate the memory for the priv_ pimpl data member of the @ref
5837 /// class_diff class.
5838 void
5839 class_diff::allocate_priv_data()
5840 {
5842  if (!priv_)
5843  priv_.reset(new priv);
5844 }
5845 
5846 /// Test whether a given base class has changed. A base class has
5847 /// changed if it's in both in deleted *and* inserted bases.
5848 ///
5849 ///@param d the declaration for the base class to consider.
5850 ///
5851 /// @return the new base class if the given base class has changed, or
5852 /// NULL if it hasn't.
5855 {
5856  string qname = d->get_base_class()->get_qualified_name();
5857  string_base_diff_sptr_map::const_iterator it =
5858  changed_bases_.find(qname);
5859 
5860  return (it == changed_bases_.end())
5862  : it->second->second_base();
5863 
5864 }
5865 
5866 /// Count the number of bases classes whose changes got filtered out.
5867 ///
5868 /// @return the number of bases classes whose changes got filtered
5869 /// out.
5870 size_t
5872 {
5873  size_t num_filtered = 0;
5874  for (base_diff_sptrs_type::const_iterator i = sorted_changed_bases_.begin();
5875  i != sorted_changed_bases_.end();
5876  ++i)
5877  {
5878  diff_sptr diff = *i;
5879  if (diff && diff->is_filtered_out())
5880  ++num_filtered;
5881  }
5882  return num_filtered;
5883 }
5884 
5885 /// Populate the vector of children node of the @ref diff base type
5886 /// sub-object of this instance of @ref class_diff.
5887 ///
5888 /// The children node can then later be retrieved using
5889 /// diff::children_node().
5890 void
5892 {
5894 
5895  // base class changes.
5896  for (base_diff_sptrs_type::const_iterator i =
5897  get_priv()->sorted_changed_bases_.begin();
5898  i != get_priv()->sorted_changed_bases_.end();
5899  ++i)
5900  if (diff_sptr d = *i)
5901  append_child_node(d);
5902 }
5903 
5904 /// Constructor of class_diff
5905 ///
5906 /// @param first_scope the first class of the diff.
5907 ///
5908 /// @param second_scope the second class of the diff.
5909 ///
5910 /// @param ctxt the diff context to use.
5912  class_decl_sptr second_scope,
5913  diff_context_sptr ctxt)
5914  : class_or_union_diff(first_scope, second_scope, ctxt)
5915  // We don't initialize the priv_ data member here. This is an
5916  // optimization to reduce memory consumption (and also execution
5917  // time) for cases where there are a lot of instances of
5918  // class_diff in the same equivalence class. In compute_diff(),
5919  // the priv_ is set to the priv_ of the canonical diff node.
5920  // See PR libabigail/17948.
5921 {}
5922 
5923 class_diff::~class_diff()
5924 {}
5925 
5926 /// Getter of the private data of the @ref class_diff type.
5927 ///
5928 /// Note that due to an optimization, the private data of @ref
5929 /// class_diff can be shared among several instances of class_diff, so
5930 /// you should never try to access class_diff::priv directly.
5931 ///
5932 /// When class_diff::priv is shared, this function returns the correct
5933 /// shared one.
5934 ///
5935 /// @return the (possibly) shared private data of the current instance
5936 /// of class_diff.
5937 const class_diff::priv_ptr&
5938 class_diff::get_priv() const
5939 {
5940  if (priv_)
5941  return priv_;
5942 
5943  // If the current class_diff::priv member is empty, then look for
5944  // the shared one, from the canonical type.
5945  class_diff *canonical =
5946  dynamic_cast<class_diff*>(get_canonical_diff());
5947  ABG_ASSERT(canonical);
5948  ABG_ASSERT(canonical->priv_);
5949 
5950  return canonical->priv_;
5951 }
5952 
5953 /// @return the pretty representation of the current instance of @ref
5954 /// class_diff.
5955 const string&
5957 {
5958  if (diff::priv_->pretty_representation_.empty())
5959  {
5960  std::ostringstream o;
5961  o << "class_diff["
5962  << first_subject()->get_pretty_representation()
5963  << ", "
5964  << second_subject()->get_pretty_representation()
5965  << "]";
5966  diff::priv_->pretty_representation_ = o.str();
5967  }
5968  return diff::priv_->pretty_representation_;
5969 }
5970 
5971 /// Return true iff the current diff node carries a change.
5972 ///
5973 /// @return true iff the current diff node carries a change.
5974 bool
5976 {return (first_class_decl() != second_class_decl());}
5977 
5978 /// @return the kind of local change carried by the current diff node.
5979 /// The value returned is zero if the current node carries no local
5980 /// change.
5981 enum change_kind
5983 {
5984  ir::change_kind k = ir::NO_CHANGE_KIND;
5985  if (!equals(*first_class_decl(), *second_class_decl(), &k))
5986  return k & ir::ALL_LOCAL_CHANGES_MASK;
5987  return ir::NO_CHANGE_KIND;
5988 }
5989 
5990 /// @return the first class invoveld in the diff.
5991 shared_ptr<class_decl>
5993 {return dynamic_pointer_cast<class_decl>(first_subject());}
5994 
5995 /// Getter of the second class involved in the diff.
5996 ///
5997 /// @return the second class invoveld in the diff
5998 shared_ptr<class_decl>
6000 {return dynamic_pointer_cast<class_decl>(second_subject());}
6001 
6002 /// @return the edit script of the bases of the two classes.
6003 const edit_script&
6005 {return get_priv()->base_changes_;}
6006 
6007 /// Getter for the deleted base classes of the diff.
6008 ///
6009 /// @return a map containing the deleted base classes, keyed with
6010 /// their pretty representation.
6011 const string_base_sptr_map&
6013 {return get_priv()->deleted_bases_;}
6014 
6015 /// Getter for the inserted base classes of the diff.
6016 ///
6017 /// @return a map containing the inserted base classes, keyed with
6018 /// their pretty representation.
6019 const string_base_sptr_map&
6021 {return get_priv()->inserted_bases_;}
6022 
6023 /// Getter for the changed base classes of the diff.
6024 ///
6025 /// @return a sorted vector containing the changed base classes
6026 const base_diff_sptrs_type&
6028 {return get_priv()->sorted_changed_bases_;}
6029 
6030 /// Getter for the vector of bases that "moved".
6031 /// That is, the vector of base types which position changed. If this
6032 /// vector is not empty, it means the bases of the underlying class
6033 /// type got re-ordered.
6034 ///
6035 /// @return the vector of bases that moved.
6036 const vector<class_decl::base_spec_sptr>&
6038 {return get_priv()->moved_bases_;}
6039 
6040 /// @return the edit script of the bases of the two classes.
6041 edit_script&
6043 {return get_priv()->base_changes_;}
6044 
6045 /// Produce a basic report about the changes between two class_decl.
6046 ///
6047 /// @param out the output stream to report the changes to.
6048 ///
6049 /// @param indent the string to use as an indentation prefix in the
6050 /// report.
6051 void
6052 class_diff::report(ostream& out, const string& indent) const
6053 {
6054  context()->get_reporter()->report(*this, out, indent);
6055 }
6056 
6057 /// Compute the set of changes between two instances of class_decl.
6058 ///
6059 /// Note that the two types must have been created in the same @ref
6060 /// environment, otherwise, this function aborts.
6061 ///
6062 /// @param first the first class_decl to consider.
6063 ///
6064 /// @param second the second class_decl to consider.
6065 ///
6066 /// @return changes the resulting changes.
6067 ///
6068 /// @param ctxt the diff context to use.
6071  const class_decl_sptr second,
6072  diff_context_sptr ctxt)
6073 {
6076 
6077  class_diff_sptr changes(new class_diff(f, s, ctxt));
6078 
6079  ctxt->initialize_canonical_diff(changes);
6080  ABG_ASSERT(changes->get_canonical_diff());
6081 
6082  if (!ctxt->get_canonical_diff_for(first, second))
6083  {
6084  // Either first or second is a decl-only class; let's set the
6085  // canonical diff here in that case.
6086  diff_sptr canonical_diff = ctxt->get_canonical_diff_for(changes);
6087  ABG_ASSERT(canonical_diff);
6088  ctxt->set_canonical_diff_for(first, second, canonical_diff);
6089  }
6090 
6091  // Ok, so this is an optimization. Do not freak out if it looks
6092  // weird, because, well, it does look weird. This speeds up
6093  // greatly, for instance, the test case given at PR
6094  // libabigail/17948.
6095  //
6096  // We are setting the private data of the new instance of class_diff
6097  // (which is 'changes') to the private data of its canonical
6098  // instance. That is, we are sharing the private data of 'changes'
6099  // with the private data of its canonical instance to consume less
6100  // memory in cases where the equivalence class of 'changes' is huge.
6101  //
6102  // But if changes is its own canonical instance, then we initialize
6103  // its private data properly
6104  if (is_class_diff(changes->get_canonical_diff()) == changes.get())
6105  // changes is its own canonical instance, so it gets a brand new
6106  // private data.
6107  changes->allocate_priv_data();
6108  else
6109  {
6110  // changes has a non-empty equivalence class so it's going to
6111  // share its private data with its canonical instance. Next
6112  // time class_diff::get_priv() is invoked, it's going to return
6113  // the shared private data of the canonical instance.
6114  return changes;
6115  }
6116 
6117  // Compare base specs
6118  compute_diff(f->get_base_specifiers().begin(),
6119  f->get_base_specifiers().end(),
6120  s->get_base_specifiers().begin(),
6121  s->get_base_specifiers().end(),
6122  changes->base_changes());
6123 
6124  // Do *not* compare member types because it generates lots of noise
6125  // and I doubt it's really useful.
6126 #if 0
6127  compute_diff(f->get_member_types().begin(),
6128  f->get_member_types().end(),
6129  s->get_member_types().begin(),
6130  s->get_member_types().end(),
6131  changes->member_types_changes());
6132 #endif
6133 
6134  // Compare data member
6135  compute_diff(f->get_non_static_data_members().begin(),
6136  f->get_non_static_data_members().end(),
6137  s->get_non_static_data_members().begin(),
6138  s->get_non_static_data_members().end(),
6139  changes->data_members_changes());
6140 
6141  // Compare virtual member functions
6142  compute_diff(f->get_virtual_mem_fns().begin(),
6143  f->get_virtual_mem_fns().end(),
6144  s->get_virtual_mem_fns().begin(),
6145  s->get_virtual_mem_fns().end(),
6146  changes->member_fns_changes());
6147 
6148  // Compare member function templates
6149  compute_diff(f->get_member_function_templates().begin(),
6150  f->get_member_function_templates().end(),
6151  s->get_member_function_templates().begin(),
6152  s->get_member_function_templates().end(),
6153  changes->member_fn_tmpls_changes());
6154 
6155  <