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-2025 Red Hat, Inc.
5 //
6 // Author: Dodji Seketeli
7 
8 /// @file
9 ///
10 /// This contains the implementation of the comparison engine of
11 /// libabigail.
12 
13 #include <ctype.h>
14 #include <libgen.h>
15 #include <algorithm>
16 #include <sstream>
17 #include <set>
18 
19 #include "abg-comparison-priv.h"
20 #include "abg-reporter-priv.h"
21 #include "abg-tools-utils.h"
22 
23 namespace abigail
24 {
25 
26 namespace comparison
27 {
28 
29 ///
30 ///
31 ///@defgroup DiffNode Internal Representation of the comparison engine
32 /// @{
33 ///
34 /// @brief How changes are represented in libabigail's comparison engine.
35 ///
36 ///@par diff nodes
37 ///
38 /// The internal representation of the comparison engine is basically
39 /// a graph of @ref instances of @ref diff node. We refer to these
40 /// just as <em>diff nodes</em>. A diff node represents a change
41 /// between two ABI artifacts represented by instances of types of the
42 /// abigail::ir namespace. These two artifacts that are being
43 /// compared are called the <em>subjects of the diff</em>.
44 ///
45 /// The types of that IR are in the abigail::comparison namespace.
46 ///
47 ///@par comparing diff nodes
48 ///
49 /// Comparing two instances of @ref diff nodes amounts to comparing
50 /// the subject of the diff. In other words, two @ref diff nodes are
51 /// equal if and only if their subjects are equal. Thus, two @ref
52 /// diff nodes can have different memory addresses and yet be equal.
53 ///
54 ///@par diff reporting and context
55 ///
56 /// A diff node can be serialized to an output stream to express, in
57 /// a human-readable textual form, the different changes that exist
58 /// between its two subjects. This is done by invoking the
59 /// diff::report() method. That reporting is controlled by several
60 /// parameters that are conceptually part of the context of the diff.
61 /// That context is materialized by an instance of the @ref
62 /// diff_context type.
63 ///
64 /// Please note that the role of the instance(s) of @ref diff_context
65 /// is boreader than just controlling the reporting of @ref diff
66 /// nodes. Basically, a @ref diff node itself is created following
67 /// behaviours that are controlled by a particular instance of
68 /// diff_context. A diff node is created in a particular diff
69 /// context, so to speak.
70 ///
71 /// @}
72 ///
73 
74 ///
75 ///@defgroup CanonicalDiff Canonical diff tree nodes
76 /// @{
77 ///
78 /// @brief How equivalent diff nodes are quickly spotted.
79 ///
80 /// @par Equivalence of diff nodes.
81 ///
82 /// Each @ref diff node has a property named <em>Canonical Diff
83 /// Node</em>. If \c D is a diff node, the canonical diff node of @c
84 /// D, noted @c C(D) is a particular diff node that is equal to @c D.
85 /// Thus, a fast way to compare two @ref diff node is to perform a
86 /// pointer comparison of their canonical diff nodes.
87 ///
88 /// A set of equivalent @ref diff nodes is a set of diff nodes that
89 /// all have the same canonical node. All the nodes of that set are
90 /// equal.
91 ///
92 /// A canonical node is registereded for a given diff node by invoking
93 /// the method diff_context::initialize_canonical_diff().
94 ///
95 /// Please note that the diff_context holds all the canonical diffs
96 /// that got registered through it. Thus, the life time of all of
97 /// canonical diff objects is the same as the life time of the @ref
98 /// diff_context they relate to.
99 ///
100 /// @}
101 ///
102 
103 // -----------------------------------------
104 // <private functions re-usable elsewhere>
105 // -----------------------------------------
106 /// Sort a map of enumerators by their value.
107 ///
108 /// @param enumerators_map the map to sort.
109 ///
110 /// @param sorted the resulting vector of sorted enumerators.
111 void
114 {
115  for (string_enumerator_map::const_iterator i = enumerators_map.begin();
116  i != enumerators_map.end();
117  ++i)
118  sorted.push_back(i->second);
120  std::sort(sorted.begin(), sorted.end(), comp);
121 }
122 
123 /// Sort a map of changed enumerators.
124 ///
125 /// @param enumerators_map the map to sort.
126 ///
127 ///@param output parameter. The resulting sorted enumerators.
128 void
130  changed_enumerators_type& sorted)
131 {
132  for (string_changed_enumerator_map::const_iterator i =
133  enumerators_map.begin();
134  i != enumerators_map.end();
135  ++i)
136  sorted.push_back(i->second);
137 
139  std::sort(sorted.begin(), sorted.end(), comp);
140 }
141 
142 /// Sort a map of data members by the offset of their initial value.
143 ///
144 /// @param data_members the map of changed data members to sort.
145 ///
146 /// @param sorted the resulting vector of sorted changed data members.
147 void
149  vector<decl_base_sptr>& sorted)
150 {
151  sorted.reserve(data_members.size());
152  for (string_decl_base_sptr_map::const_iterator i = data_members.begin();
153  i != data_members.end();
154  ++i)
155  sorted.push_back(i->second);
156 
157  data_member_comp comp;
158  std::sort(sorted.begin(), sorted.end(), comp);
159 }
160 
161 /// Sort (in place) a vector of changed data members.
162 ///
163 /// @param to_sort the vector to sort.
164 void
166 {
167  data_member_comp comp;
168  std::sort(to_sort.begin(), to_sort.end(), comp);
169 }
170 
171 /// Get the ELF symbol associated to a decl.
172 ///
173 /// Please note that ELF symbol are only associated to function or
174 /// global variable decls. So for any other kind of decl, this
175 /// function returns nullptr.
176 ///
177 /// @param d the decl to consider.
178 ///
179 /// @return the ELF symbol associated to @p if any or nullptr.
180 static elf_symbol_sptr
181 get_symbol(const decl_base_sptr& d)
182 {
184  return fn->get_symbol();
185  else if (var_decl_sptr var = is_var_decl(d))
186  return var->get_symbol();
187 
188  return elf_symbol_sptr();
189 }
190 
191 /// Compare two decl diff nodes (@ref decl_diff_base) for the purpose
192 /// of sorting.
193 ///
194 /// @param first the first @ref decl_diff to consider.
195 ///
196 /// @param second the second @ref function_decl_diff to consider.
197 ///
198 /// @return true iff @p first compares less than @p second.
199 bool
200 is_less_than(const decl_diff_base& first, const decl_diff_base& second)
201 {
202  decl_base_sptr f = is_decl(first.first_subject()),
203  s = is_decl(second.first_subject());
204 
205  string fr = f->get_qualified_name(), sr = s->get_qualified_name();
206 
207  if (fr != sr)
208  return fr < sr;
209 
210  if (!f->get_linkage_name().empty()
211  && !s->get_linkage_name().empty())
212  {
213  fr = f->get_linkage_name();
214  sr = s->get_linkage_name();
215  if (fr != sr)
216  return fr < sr;
217  }
218 
219  if (get_symbol(f) && get_symbol(s))
220  {
221  fr = get_symbol(f)->get_id_string();
222  sr = get_symbol(s)->get_id_string();
223  if (fr != sr)
224  return fr < sr;
225  }
226 
227  fr = f->get_pretty_representation(true, true);
228  sr = s->get_pretty_representation(true, true);
229 
230  return fr < sr;
231 }
232 
233 /// Compare two decl diff nodes (@ref decl_diff_base) for the purpose
234 /// of sorting.
235 ///
236 /// @param first the first @ref decl_diff to consider.
237 ///
238 /// @param second the second @ref function_decl_diff to consider.
239 ///
240 /// @return true iff @p first compares less than @p second.
241 bool
243  const decl_diff_base_sptr& second)
244 {
245  if (!first || !second)
246  return false;
247 
248  return is_less_than(*first, *second);
249 }
250 
251 /// Sort an instance of @ref string_function_ptr_map map and stuff a
252 /// resulting sorted vector of pointers to function_decl.
253 ///
254 /// @param map the map to sort.
255 ///
256 /// @param sorted the resulting sorted vector.
257 void
259  vector<const function_decl*>& sorted)
260 {
261  sorted.reserve(map.size());
262  for (string_function_ptr_map::const_iterator i = map.begin();
263  i != map.end();
264  ++i)
265  sorted.push_back(i->second);
266 
267  function_comp comp;
268  std::sort(sorted.begin(), sorted.end(), comp);
269 }
270 
271 /// Sort a map that's an instance of @ref
272 /// string_member_function_sptr_map and fill a vector of member
273 /// functions with the sorted result.
274 ///
275 /// @param map the map to sort.
276 ///
277 /// @param sorted the resulting sorted vector.
278 void
281 {
282  sorted.reserve(map.size());
283  for (string_member_function_sptr_map::const_iterator i = map.begin();
284  i != map.end();
285  ++i)
286  sorted.push_back(i->second);
287 
288  function_comp comp;
289  std::sort(sorted.begin(), sorted.end(), comp);
290 }
291 
292 /// Sort the values of a @ref string_function_decl_diff_sptr_map map
293 /// and store the result in a vector of @ref function_decl_diff_sptr
294 /// objects.
295 ///
296 /// @param map the map whose values to store.
297 ///
298 /// @param sorted the vector of function_decl_diff_sptr to store the
299 /// result of the sort into.
300 void
304 {
305  sorted.reserve(map.size());
306  for (string_function_decl_diff_sptr_map::const_iterator i = map.begin();
307  i != map.end();
308  ++i)
309  sorted.push_back(i->second);
311  std::sort(sorted.begin(), sorted.end(), comp);
312 }
313 
314 /// Sort a vector of @ref function_decl_diff_sptr.
315 ///
316 /// The comparison functor used is function_decl_diff_comp.
317 ///
318 /// @param fn_diffs in/out parameter. The vector of @ref
319 /// function_decl_diff_sptr to sort.
320 void
322 {
324  std::sort(fn_diffs.begin(), fn_diffs.end(), comp);
325 }
326 
327 /// Sort of an instance of @ref string_var_diff_sptr_map map.
328 ///
329 /// @param map the input map to sort.
330 ///
331 /// @param sorted the ouptut sorted vector of @ref var_diff_sptr.
332 /// It's populated with the sorted content.
333 void
335  var_diff_sptrs_type& sorted)
336 {
337  sorted.reserve(map.size());
338  for (string_var_diff_sptr_map::const_iterator i = map.begin();
339  i != map.end();
340  ++i)
341  sorted.push_back(i->second);
342 
343  var_diff_sptr_comp comp;
344  std::sort(sorted.begin(), sorted.end(), comp);
345 }
346 
347 /// Sort a vector of @ref var_diff_sptr.
348 ///
349 /// The comparison functor used is @ref var_diff_sptr_comp.
350 ///
351 /// @param var_diffs in/out parameter the vector of @ref var_diff_sptr
352 /// to sort.
353 void
355 {
356  var_diff_sptr_comp comp;
357  std::sort(var_diffs.begin(), var_diffs.end(), comp);
358 }
359 
360 /// Sort a map of string -> pointer to @ref elf_symbol.
361 ///
362 /// The result is a vector of @ref elf_symbol_sptr sorted by the
363 /// name of the symbol.
364 ///
365 /// @param map the map to sort.
366 ///
367 /// @param sorted out parameter; the sorted vector of @ref
368 /// elf_symbol_sptr.
369 void
371  vector<elf_symbol_sptr>& sorted)
372 {
373  for (string_elf_symbol_map::const_iterator i = map.begin();
374  i!= map.end();
375  ++i)
376  sorted.push_back(i->second);
377 
378  elf_symbol_comp comp;
379  std::sort(sorted.begin(), sorted.end(), comp);
380 }
381 
382 /// Sort a map of string -> pointer to @ref var_decl.
383 ///
384 /// The result is a vector of var_decl* sorted by the qualified name
385 /// of the variables.
386 ///
387 /// @param map the map to sort.
388 ///
389 /// @param sorted out parameter; the sorted vector of @ref var_decl.
390 void
392  vector<var_decl_sptr>& sorted)
393 {
394  for (string_var_ptr_map::const_iterator i = map.begin();
395  i != map.end();
396  ++i)
397  sorted.push_back(i->second);
398 
399  var_comp comp;
400  std::sort(sorted.begin(), sorted.end(), comp);
401 }
402 
403 /// Sort the values of a string_var_diff_sptr_map and store the result
404 /// in a vector of var_diff_sptr.
405 ///
406 /// @param map the map of changed data members to sort.
407 ///
408 /// @param sorted the resulting vector of var_diff_sptr.
409 void
411  var_diff_sptrs_type& sorted)
412 {
413  sorted.reserve(map.size());
414  for (string_var_diff_sptr_map::const_iterator i = map.begin();
415  i != map.end();
416  ++i)
417  sorted.push_back(i->second);
419  std::sort(sorted.begin(), sorted.end(), comp);
420 }
421 
422 /// Sort the values of a unsigned_var_diff_sptr_map map and store the
423 /// result into a vector of var_diff_sptr.
424 ///
425 /// @param map the map of changed data members to sort.
426 ///
427 /// @param sorted the resulting vector of sorted var_diff_sptr.
428 void
430  var_diff_sptrs_type& sorted)
431 {
432  sorted.reserve(map.size());
433  for (unsigned_var_diff_sptr_map::const_iterator i = map.begin();
434  i != map.end();
435  ++i)
436  sorted.push_back(i->second);
438  std::sort(sorted.begin(), sorted.end(), comp);
439 }
440 
441 /// Sort an map of string -> virtual member function into a vector of
442 /// virtual member functions. The virtual member functions are sorted
443 /// by increasing order of their virtual index.
444 ///
445 /// @param map the input map.
446 ///
447 /// @param sorted the resulting sorted vector of virtual function
448 /// member.
449 void
453 {
454  sorted.reserve(map.size());
455  for (string_function_decl_diff_sptr_map::const_iterator i = map.begin();
456  i != map.end();
457  ++i)
458  sorted.push_back(i->second);
459 
461  sort(sorted.begin(), sorted.end(), comp);
462 }
463 
464 /// Sort a map ofg string -> @ref diff_sptr into a vector of @ref
465 /// diff_sptr. The diff_sptr are sorted lexicographically wrt
466 /// qualified names of their first subjects.
467 ///
468 /// @param map the map to sort.
469 ///
470 /// @param sorted the resulting sorted vector.
471 void
473  diff_sptrs_type& sorted)
474 {
475  sorted.reserve(map.size());
476  for (string_diff_sptr_map::const_iterator i = map.begin();
477  i != map.end();
478  ++i)
479  sorted.push_back(i->second);
480 
481  diff_comp comp;
482  sort(sorted.begin(), sorted.end(), comp);
483 }
484 
485 /// Sort a map ofg string -> @ref diff* into a vector of @ref
486 /// diff_ptr. The diff_ptr are sorted lexicographically wrt
487 /// qualified names of their first subjects.
488 ///
489 /// @param map the map to sort.
490 ///
491 /// @param sorted the resulting sorted vector.
492 void
494  diff_ptrs_type& sorted)
495 {
496  sorted.reserve(map.size());
497  for (string_diff_ptr_map::const_iterator i = map.begin();
498  i != map.end();
499  ++i)
500  sorted.push_back(i->second);
501 
502  diff_comp comp;
503  sort(sorted.begin(), sorted.end(), comp);
504 }
505 
506 /// Sort a map of string -> base_diff_sptr into a sorted vector of
507 /// base_diff_sptr. The base_diff_sptr are sorted by increasing value
508 /// of their offset in their containing type.
509 ///
510 /// @param map the input map to sort.
511 ///
512 /// @param sorted the resulting sorted vector.
513 void
515  base_diff_sptrs_type& sorted)
516 {
517  for (string_base_diff_sptr_map::const_iterator i = map.begin();
518  i != map.end();
519  ++i)
520  sorted.push_back(i->second);
521  base_diff_comp comp;
522  sort(sorted.begin(), sorted.end(), comp);
523 }
524 
525 /// Lexicographically sort base specifications found
526 /// in instances of string_base_sptr_map.
527 void
529  class_decl::base_specs& sorted)
530 {
531  for (string_base_sptr_map::const_iterator i = m.begin();
532  i != m.end();
533  ++i)
534  sorted.push_back(i->second);
535 
536  base_spec_comp comp;
537  std::sort(sorted.begin(), sorted.end(), comp);
538 }
539 
540 /// Sort a map of @ref fn_parm_diff by the indexes of the function
541 /// parameters.
542 ///
543 /// @param map the map to sort.
544 ///
545 /// @param sorted the resulting sorted vector of changed function
546 /// parms.
547 void
549  vector<fn_parm_diff_sptr>& sorted)
550 {
551  sorted.reserve(map.size());
552  for (unsigned_fn_parm_diff_sptr_map::const_iterator i = map.begin();
553  i != map.end();
554  ++i)
555  sorted.push_back(i->second);
556 
557  fn_parm_diff_comp comp;
558  std::sort(sorted.begin(), sorted.end(), comp);
559 }
560 
561 /// Sort a map of changed function parameters by the indexes of the
562 /// function parameters.
563 ///
564 /// @param map the map to sort.
565 ///
566 /// @param sorted the resulting sorted vector of instances of @ref
567 /// fn_parm_diff_sptr
568 void
570  vector<fn_parm_diff_sptr>& sorted)
571 {
572  sorted.reserve(map.size());
573  for (string_fn_parm_diff_sptr_map::const_iterator i = map.begin();
574  i != map.end();
575  ++i)
576  sorted.push_back(i->second);
577 
578  fn_parm_diff_comp comp;
579  std::sort(sorted.begin(), sorted.end(), comp);
580 }
581 
582 /// Sort a map of string -> function parameters.
583 ///
584 /// @param map the map to sort.
585 ///
586 /// @param sorted the resulting sorted vector of
587 /// @ref vector<function_decl::parameter_sptr>
588 void
590  vector<function_decl::parameter_sptr>& sorted)
591 {
592  for (string_parm_map::const_iterator i = map.begin();
593  i != map.end();
594  ++i)
595  sorted.push_back(i->second);
596 
597  parm_comp comp;
598  std::sort(sorted.begin(), sorted.end(), comp);
599 }
600 
601 /// Sort the set of ABI artifacts contained in a @ref
602 /// artifact_sptr_set_type.
603 ///
604 /// @param set the set of ABI artifacts to sort.
605 ///
606 /// @param output parameter the vector containing the sorted ABI
607 /// artifacts.
608 void
610  vector<type_or_decl_base_sptr>& sorted)
611 {
612 
613  for (artifact_sptr_set_type::const_iterator it = set.begin();
614  it != set.end();
615  ++it)
616  sorted.push_back(*it);
617 
619  std::sort(sorted.begin(), sorted.end(), comp);
620 }
621 
622 /// Sort a map of string to type_base_sptr entities.
623 ///
624 /// The entries are sorted based on the lexicographic order of the
625 /// pretty representation of the type_sptr_sptr. The sorted result is
626 /// put in a vector of type_base_sptr.
627 ///
628 /// @param map the map to sort.
629 ///
630 /// @param sorted the resulting vector of type_base_sptr
631 /// lexicographically sorted using their pretty representation.
632 void
634  vector<type_base_sptr>& sorted)
635 {
636  for (string_type_base_sptr_map::const_iterator i = map.begin();
637  i != map.end();
638  ++i)
639  sorted.push_back(i->second);
640 
642  std::sort(sorted.begin(), sorted.end(), comp);
643 }
644 
645 /// Return the first underlying type that is not a qualified type.
646 /// @param t the qualified type to consider.
647 ///
648 /// @return the first underlying type that is not a qualified type, or
649 /// NULL if t is NULL.
650 type_base_sptr
651 get_leaf_type(qualified_type_def_sptr t)
652 {
653  if (!t)
654  return type_base_sptr();
655 
656  type_base_sptr ut = t->get_underlying_type();
657  qualified_type_def_sptr qut = dynamic_pointer_cast<qualified_type_def>(ut);
658 
659  if (!qut)
660  return ut;
661  return get_leaf_type(qut);
662 }
663 
664 /// Tests if a given diff node is to represent the changes between two
665 /// gobal decls.
666 ///
667 /// @param d the diff node to consider.
668 ///
669 /// @return true iff @p d represents the changes between two global
670 /// decls.
671 bool
673 {
674  ABG_ASSERT(d != 0);
675 
676  if (d == 0)
677  return false;
678 
680  ABG_ASSERT(first);
681 
683  ABG_ASSERT(second);
684 
685  if (decl_base_sptr decl = is_decl(first))
686  if (is_at_global_scope(decl))
687  if ((decl = is_decl(second)))
688  if (is_at_global_scope(decl))
689  return true;
690 
691  return false;
692 }
693 
694 // -----------------------------------------
695 // </private functions re-usable elsewhere>
696 // -----------------------------------------
697 
698 /// The overloaded or operator for @ref visiting_kind.
701 {return static_cast<visiting_kind>(static_cast<unsigned>(l)
702  | static_cast<unsigned>(r));}
703 
704 /// The overloaded and operator for @ref visiting_kind.
707 {
708  return static_cast<visiting_kind>(static_cast<unsigned>(l)
709  & static_cast<unsigned>(r));
710 }
711 
712 /// The overloaded 'bit inversion' operator for @ref visiting_kind.
715 {return static_cast<visiting_kind>(~static_cast<unsigned>(l));}
716 
717 /// Test if a diff node is about differences between types.
718 ///
719 /// @param diff the diff node to test.
720 ///
721 /// @return a pointer to the actual type_diff_base* that @p diff
722 /// extends, iff it is about differences between types.
723 const type_diff_base*
725 {return dynamic_cast<const type_diff_base*>(diff);}
726 
727 /// Test if a diff node is about differences between declarations.
728 ///
729 /// @param diff the diff node to test.
730 ///
731 /// @return a pointer to the actual decl_diff_base @p diff extends,
732 /// iff it is about differences between declarations.
733 const decl_diff_base*
735 {return dynamic_cast<const decl_diff_base*>(diff);}
736 
737 /// Test if a diff node is a @ref class_diff node.
738 ///
739 /// @param diff the diff node to consider.
740 ///
741 /// @return a non-nil pointer to a @ref class_diff iff @p diff is a
742 /// @ref class_diff node.
743 const class_diff*
745 {return dynamic_cast<const class_diff*>(diff);}
746 
747 /// Test if a diff node is a @ref enum_diff node.
748 ///
749 /// @param diff the diff node to consider.
750 ///
751 /// @return a non-nil pointer to ad @ref enum_diff node iff @p diff is
752 /// a @ref enum_diff node.
753 const enum_diff*
755 {return dynamic_cast<const enum_diff*>(diff);}
756 
757 /// Test if a diff node is a @ref union_diff node.
758 ///
759 /// @param diff the diff node to consider.
760 ///
761 /// @return a non-nil pointer to a @ref union_diff iff @p diff is a
762 /// @ref union_diff node.
763 const union_diff*
765 {return dynamic_cast<const union_diff*>(diff);}
766 
767 /// Test if a diff node is a @ref class_or_union_diff node.
768 ///
769 /// @param d the diff node to consider.
770 ///
771 /// @return a non-nil pointer to the @ref class_or_union_diff denoted
772 /// by @p d iff @p d is a @ref class_or_union_diff.
773 const class_or_union_diff*
775 {return dynamic_cast<const class_or_union_diff*>(d);}
776 
777 /// Test if a diff node is a @ref class_or_union_diff between two
778 /// anonymous classes or unions.
779 ///
780 /// @param d the diff node to consider.
781 ///
782 /// @return a non-nil pointer to the @ref class_or_union_diff denoted
783 /// by @p d iff @p is a pointer to an anonymous class or union diff.
784 const class_or_union_diff*
786 {
787  if (const class_or_union_diff *dif = is_class_or_union_diff(d))
788  if (dif->first_class_or_union()->get_is_anonymous())
789  return dif;
790  return 0;
791 }
792 
793 /// Test if a diff node is a @ref typedef_diff node.
794 ///
795 /// @param diff the diff node to consider.
796 ///
797 /// @return a non-nil pointer to a @ref typedef_diff iff @p diff is a
798 /// @ref typedef_diff node.
799 const typedef_diff*
801 {return dynamic_cast<const typedef_diff*>(diff);}
802 
803 /// Test if a diff node is a @ref subrange_diff node.
804 ///
805 /// @param diff the diff node to consider.
806 ///
807 /// @return a non-nil pointer to a @ref subrange_diff iff @p diff is a
808 /// @ref subrange_diff node.
809 const subrange_diff*
811 {return dynamic_cast<const subrange_diff*>(diff);}
812 
813 /// Test if a diff node is a @ref subrange_diff between two anonymous
814 /// subranges.
815 ///
816 /// @param d the diff node to consider.
817 ///
818 /// @return a non-nil pointer to the @ref subrange_diff denoted by @p
819 /// d iff @p d is a pointer to an anonymous @ref subrange_diff.
820 const subrange_diff*
822 {
823  if (const subrange_diff* dif = is_subrange_diff(d))
824  if (dif->first_subrange()->get_is_anonymous())
825  return dif;
826 
827  return nullptr;
828 }
829 
830 /// Test if a diff node is a @ref array_diff node.
831 ///
832 /// @param diff the diff node to consider.
833 ///
834 /// @return a non-nil pointer to a @ref array_diff iff @p diff is a
835 /// @ref array_diff node.
836 const array_diff*
838 {return dynamic_cast<const array_diff*>(diff);}
839 
840 /// Test if a diff node is a @ref function_type_diff node.
841 ///
842 /// @param diff the diff node to consider.
843 ///
844 /// @return a non-nil pointer to a @ref function_type_diff iff @p diff is a
845 /// @ref function_type_diff node.
846 const function_type_diff*
848 {return dynamic_cast<const function_type_diff*>(diff);}
849 
850 /// Test if a given diff node carries a function type change with
851 /// local changes.
852 ///
853 /// @param diff the diff node to consider.
854 ///
855 /// @return a non-nil pointer to a @ref function_type_diff iff @p diff
856 /// is a function_type_diff node that carries a local change.
857 const function_type_diff*
859 {
860  if (const function_type_diff* d = is_function_type_diff(diff))
861  if (d->has_local_changes())
862  return d;
863 
864  return 0;
865 }
866 
867 /// Test if a diff node is about differences between variables.
868 ///
869 /// @param diff the diff node to test.
870 ///
871 /// @return a pointer to the actual var_diff that @p diff is a type
872 /// of, iff it is about differences between variables.
873 const var_diff*
875 {
876  const var_diff* d = dynamic_cast<const var_diff*>(diff);
877  if (d)
878  ABG_ASSERT(is_decl_diff(diff));
879  return d;
880 }
881 
882 /// Test if a diff node is about differences between functions.
883 ///
884 /// @param diff the diff node to test.
885 ///
886 /// @return a pointer to the actual var_diff that @p diff is a type
887 /// of, iff it is about differences between variables.
888 const function_decl_diff*
890 {
891  const function_decl_diff *d = dynamic_cast<const function_decl_diff*>(diff);
892  if (d)
893  ABG_ASSERT(is_decl_diff(diff));
894  return d;
895 }
896 
897 /// Test if a diff node is about differences between two pointers.
898 ///
899 /// @param diff the diff node to consider.
900 ///
901 /// @return the @p diff converted into an instance of @ref
902 /// pointer_diff iff @p diff is about differences between two
903 /// pointers.
904 const pointer_diff*
906 {return dynamic_cast<const pointer_diff*>(diff);}
907 
908 /// Test if a diff node is about differences between two references.
909 ///
910 /// @param diff the diff node to consider.
911 ///
912 /// @return the @p diff converted into an instance of @ref
913 /// reference_diff iff @p diff is about differences between two
914 /// references.
915 const reference_diff*
917 {return dynamic_cast<const reference_diff*>(diff);}
918 
919 /// Test if a diff node is about differences between two qualified
920 /// types.
921 ///
922 /// @param diff the diff node to consider.
923 ///
924 /// @return @p diff converted into an instance of @ref
925 /// qualified_type_diff iff @p diff is about differences between two
926 /// qualified types.
927 const qualified_type_diff*
929 {return dynamic_cast<const qualified_type_diff*>(diff);}
930 
931 /// Test if a diff node is a reference or pointer diff node to a
932 /// change that is neither basic type change nor distinct type change.
933 ///
934 /// Note that this function also works on diffs of typedefs of
935 /// reference or pointer.
936 ///
937 /// @param diff the diff node to consider.
938 ///
939 /// @return true iff @p diff is a eference or pointer diff node to a
940 /// change that is neither basic type change nor distinct type change.
941 bool
943 {
944  diff = peel_typedef_diff(diff);
945  if (const reference_diff* d = is_reference_diff(diff))
946  {
947  diff = peel_reference_diff(d);
948  if (is_diff_of_basic_type(diff) || is_distinct_diff(diff))
949  return false;
950  return true;
951  }
952  else if (const pointer_diff *d = is_pointer_diff(diff))
953  {
954  diff = peel_pointer_diff(d);
955  if (is_diff_of_basic_type(diff) || is_distinct_diff(diff))
956  return false;
957  return true;
958  }
959 
960  return false;
961 }
962 
963 /// Test if a diff node is about differences between two function
964 /// parameters.
965 ///
966 /// @param diff the diff node to consider.
967 ///
968 /// @return the @p diff converted into an instance of @ref
969 /// reference_diff iff @p diff is about differences between two
970 /// function parameters.
971 const fn_parm_diff*
973 {return dynamic_cast<const fn_parm_diff*>(diff);}
974 
975 /// Test if a diff node is about differences between two base class
976 /// specifiers.
977 ///
978 /// @param diff the diff node to consider.
979 ///
980 /// @return the @p diff converted into an instance of @ref base_diff
981 /// iff @p diff is about differences between two base class
982 /// specifiers.
983 const base_diff*
985 {return dynamic_cast<const base_diff*>(diff);}
986 
987 /// Test if a diff node is about differences between two diff nodes of
988 /// different kinds.
989 ///
990 /// @param diff the diff node to consider.
991 ///
992 /// @return the @p diff converted into an instance of @ref
993 /// distintc_diff iff @p diff is about differences between two diff
994 /// nodes of different kinds.
995 const distinct_diff*
997 {return dynamic_cast<const distinct_diff*>(diff);}
998 
999 /// Test if a diff node is a @ref corpus_diff node.
1000 ///
1001 /// @param diff the diff node to consider.
1002 ///
1003 /// @return a non-nil pointer to a @ref corpus_diff iff @p diff is a
1004 /// @ref corpus_diff node.
1005 const corpus_diff*
1007 {return dynamic_cast<const corpus_diff*>(diff);}
1008 
1009 /// Test if a diff node is a child node of a function parameter diff node.
1010 ///
1011 /// @param diff the diff node to test.
1012 ///
1013 /// @return true iff @p diff is a child node of a function parameter
1014 /// diff node.
1015 bool
1017 {return diff && is_fn_parm_diff(diff->parent_node());}
1018 
1019 /// Test if a diff node is a child node of a base diff node.
1020 ///
1021 /// @param diff the diff node to test.
1022 ///
1023 /// @return true iff @p diff is a child node of a base diff node.
1024 bool
1026 {return diff && is_base_diff(diff->parent_node());}
1027 
1028 /// The default traverse function.
1029 ///
1030 /// @return true.
1031 bool
1033 {return true;}
1034 
1035 diff_context::diff_context()
1036  : priv_(new diff_context::priv)
1037 {
1038  // Setup all the diff output filters we have.
1040 
1042  add_diff_filter(f);
1043 
1044  // f.reset(new filtering::harmless_filter);
1045  // add_diff_filter(f);
1046 
1047  // f.reset(new filtering::harmful_filter);
1048  // add_diff_filter(f);
1049 }
1050 
1051 diff_context::~diff_context() = default;
1052 
1053 /// Test if logging was requested.
1054 ///
1055 /// @return true iff logging was requested.
1056 bool
1058 {return priv_->do_log_;}
1059 
1060 /// Set logging as requested.
1061 ///
1062 /// @param f the flag
1063 void
1065 {priv_->do_log_ = f;}
1066 
1067 /// Set the corpus diff relevant to this context.
1068 ///
1069 /// @param d the corpus_diff we are interested in.
1070 void
1072 {priv_->corpus_diff_ = d;}
1073 
1074 /// Get the corpus diff for the current context.
1075 ///
1076 /// @return the corpus diff of this context.
1077 const corpus_diff_sptr&
1079 {return priv_->corpus_diff_;}
1080 
1081 /// Getter for the first corpus of the corpus diff of the current context.
1082 ///
1083 /// @return the first corpus of the corpus diff of the current
1084 /// context, if no corpus diff is associated to the context.
1085 corpus_sptr
1087 {
1088  if (priv_->corpus_diff_)
1089  return priv_->corpus_diff_->first_corpus();
1090  return corpus_sptr();
1091 }
1092 
1093 /// Getter for the second corpus of the corpus diff of the current
1094 /// context.
1095 ///
1096 /// @return the second corpus of the corpus diff of the current
1097 /// context, if no corpus diff is associated to the context.
1098 corpus_sptr
1100 {
1101  if (priv_->corpus_diff_)
1102  return priv_->corpus_diff_->second_corpus();
1103  return corpus_sptr();
1104 }
1105 
1106 /// Getter of the reporter to be used in this context.
1107 ///
1108 /// @return the reporter to be used in this context.
1111 {
1112  if (!priv_->reporter_)
1113  {
1114  if (show_leaf_changes_only())
1115  priv_->reporter_.reset(new leaf_reporter);
1116  else
1117  priv_->reporter_.reset(new default_reporter);
1118  }
1119  ABG_ASSERT(priv_->reporter_);
1120  return priv_->reporter_;
1121 }
1122 
1123 /// Setter of the reporter to be used in this context.
1124 ///
1125 /// @param r the reporter to be used in this context.
1126 void
1128 {priv_->reporter_ = r;}
1129 
1130 /// Tests if the current diff context already has a diff for two decls.
1131 ///
1132 /// @param first the first decl to consider.
1133 ///
1134 /// @param second the second decl to consider.
1135 ///
1136 /// @return a pointer to the diff for @p first @p second if found,
1137 /// null otherwise.
1138 diff_sptr
1139 diff_context::has_diff_for(const type_or_decl_base_sptr first,
1140  const type_or_decl_base_sptr second) const
1141 {
1142  types_or_decls_diff_map_type::const_iterator i =
1143  priv_->types_or_decls_diff_map.find(std::make_pair(first, second));
1144  if (i != priv_->types_or_decls_diff_map.end())
1145  return i->second;
1146  return diff_sptr();
1147 }
1148 
1149 /// Tests if the current diff context already has a diff for two types.
1150 ///
1151 /// @param first the first type to consider.
1152 ///
1153 /// @param second the second type to consider.
1154 ///
1155 /// @return a pointer to the diff for @p first @p second if found,
1156 /// null otherwise.
1157 diff_sptr
1158 diff_context::has_diff_for_types(const type_base_sptr first,
1159  const type_base_sptr second) const
1160 {return has_diff_for(first, second);}
1161 
1162 /// Tests if the current diff context already has a given diff.
1163 ///
1164 ///@param d the diff to consider.
1165 ///
1166 /// @return a pointer to the diff found for @p d
1167 const diff*
1168 diff_context::has_diff_for(const diff* d) const
1169 {return has_diff_for(d->first_subject(), d->second_subject()).get();}
1170 
1171 /// Tests if the current diff context already has a given diff.
1172 ///
1173 ///@param d the diff to consider.
1174 ///
1175 /// @return a pointer to the diff found for @p d
1176 diff_sptr
1177 diff_context::has_diff_for(const diff_sptr d) const
1178 {return has_diff_for(d->first_subject(), d->second_subject());}
1179 
1180 /// Getter for the bitmap that represents the set of categories that
1181 /// the user wants to see reported.
1182 ///
1183 /// @return a bitmap that represents the set of categories that the
1184 /// user wants to see reported.
1187 {return priv_->allowed_category_;}
1188 
1189 /// Setter for the bitmap that represents the set of categories that
1190 /// the user wants to see reported.
1191 ///
1192 /// @param c a bitmap that represents the set of categories that the
1193 /// user wants to see represented.
1194 void
1196 {priv_->allowed_category_ = c;}
1197 
1198 /// Setter for the bitmap that represents the set of categories that
1199 /// the user wants to see reported
1200 ///
1201 /// This function perform a bitwise or between the new set of
1202 /// categories and the current ones, and then sets the current
1203 /// categories to the result of the or.
1204 ///
1205 /// @param c a bitmap that represents the set of categories that the
1206 /// user wants to see represented.
1207 void
1209 {priv_->allowed_category_ = priv_->allowed_category_ | c;}
1210 
1211 /// Setter for the bitmap that represents the set of categories that
1212 /// the user wants to see reported
1213 ///
1214 /// This function actually unsets bits from the current categories.
1215 ///
1216 /// @param c a bitmap that represents the set of categories to unset
1217 /// from the current categories.
1218 void
1220 {priv_->allowed_category_ = priv_->allowed_category_ & ~c;}
1221 
1222 /// Add a diff for two decls to the cache of the current diff_context.
1223 ///
1224 /// Doing this allows to later find the added diff from its two
1225 /// subject decls.
1226 ///
1227 /// @param first the first decl to consider.
1228 ///
1229 /// @param second the second decl to consider.
1230 ///
1231 /// @param the diff to add.
1232 void
1233 diff_context::add_diff(type_or_decl_base_sptr first,
1234  type_or_decl_base_sptr second,
1235  const diff_sptr d)
1236 {priv_->types_or_decls_diff_map[std::make_pair(first, second)] = d;}
1237 
1238 /// Add a diff tree node to the cache of the current diff_context
1239 ///
1240 /// @param d the diff tree node to add.
1241 void
1242 diff_context::add_diff(const diff* d)
1243 {
1244  if (d)
1245  {
1246  diff_sptr dif(const_cast<diff*>(d), noop_deleter());
1247  add_diff(d->first_subject(), d->second_subject(), dif);
1248  }
1249 }
1250 
1251 /// Add a diff tree node to the cache of the current diff_context
1252 ///
1253 /// @param d the diff tree node to add.
1254 void
1255 diff_context::add_diff(const diff_sptr d)
1256 {
1257  if (d)
1258  add_diff(d->first_subject(), d->second_subject(), d);
1259 }
1260 
1261 /// Getter for the @ref CanonicalDiff "canonical diff node" for the
1262 /// @ref diff represented by their two subjects.
1263 ///
1264 /// @param first the first subject of the diff.
1265 ///
1266 /// @param second the second subject of the diff.
1267 ///
1268 /// @return the canonical diff for the diff node represented by the
1269 /// two diff subjects @p first and @p second. If no canonical diff
1270 /// node was registered for these subjects, then a nil node is
1271 /// returned.
1272 diff_sptr
1274  const type_or_decl_base_sptr second) const
1275 {return has_diff_for(first, second);}
1276 
1277 /// Getter for the @ref CanonicalDiff "canonical diff node" for the
1278 /// @ref diff represented by the two subjects of a given diff node.
1279 ///
1280 /// @param d the diff node to get the canonical node for.
1281 ///
1282 /// @return the canonical diff for the diff node represented by the
1283 /// two diff subjects of @p d. If no canonical diff node was
1284 /// registered for these subjects, then a nil node is returned.
1285 diff_sptr
1287 {return has_diff_for(d);}
1288 
1289 /// Setter for the @ref CanonicalDiff "canonical diff node" for the
1290 /// @ref diff represented by their two subjects.
1291 ///
1292 /// @param first the first subject of the diff.
1293 ///
1294 /// @param second the second subject of the diff.
1295 ///
1296 /// @param d the new canonical diff.
1297 void
1298 diff_context::set_canonical_diff_for(const type_or_decl_base_sptr first,
1299  const type_or_decl_base_sptr second,
1300  const diff_sptr d)
1301 {
1302  ABG_ASSERT(d);
1303  if (!has_diff_for(first, second))
1304  {
1305  add_diff(first, second, d);
1306  priv_->canonical_diffs.push_back(d);
1307  }
1308 }
1309 
1310 /// If there is is a @ref CanonicalDiff "canonical diff node"
1311 /// registered for two diff subjects, return it. Otherwise, register
1312 /// a canonical diff node for these two diff subjects and return it.
1313 ///
1314 /// @param first the first subject of the diff.
1315 ///
1316 /// @param second the second subject of the diff.
1317 ///
1318 /// @param d the new canonical diff node.
1319 ///
1320 /// @return the canonical diff node.
1321 diff_sptr
1322 diff_context::set_or_get_canonical_diff_for(const type_or_decl_base_sptr first,
1323  const type_or_decl_base_sptr second,
1324  const diff_sptr canonical_diff)
1325 {
1326  ABG_ASSERT(canonical_diff);
1327 
1328  diff_sptr canonical = get_canonical_diff_for(first, second);
1329  if (!canonical)
1330  {
1331  canonical = canonical_diff;
1332  set_canonical_diff_for(first, second, canonical);
1333  }
1334  return canonical;
1335 }
1336 
1337 /// Set the canonical diff node property of a given diff node
1338 /// appropriately.
1339 ///
1340 /// For a given diff node that has no canonical diff node, retrieve
1341 /// the canonical diff node (by looking at its diff subjects and at
1342 /// the current context) and set the canonical diff node property of
1343 /// the diff node to that canonical diff node. If no canonical diff
1344 /// node has been registered to the diff context for the subjects of
1345 /// the diff node then, register the canonical diff node as being the
1346 /// diff node itself; and set its canonical diff node property as
1347 /// such. Otherwise, if the diff node already has a canonical diff
1348 /// node, do nothing.
1349 ///
1350 /// @param diff the diff node to initialize the canonical diff node
1351 /// property for.
1352 void
1354 {
1355  if (diff->get_canonical_diff() == 0)
1356  {
1357  diff_sptr canonical =
1358  set_or_get_canonical_diff_for(diff->first_subject(),
1359  diff->second_subject(),
1360  diff);
1361  diff->set_canonical_diff(canonical.get());
1362  }
1363 }
1364 
1365 /// Add a diff node to the set of diff nodes that are kept alive for
1366 /// the life time of the current instance of diff_context.
1367 ///
1368 /// Note that diff added to the diff cache are kept alive as well, and
1369 /// don't need to be passed to this function to be kept alive.
1370 ///
1371 /// @param d the diff node to be kept alive during the life time of
1372 /// the current instance of @ref diff_context.
1373 void
1375 {priv_->live_diffs_.insert(d);}
1376 
1377 /// Test if a diff node has been traversed.
1378 ///
1379 /// @param d the diff node to consider.
1380 ///
1381 /// @return the first diff node against which @p d is redundant.
1382 diff*
1384 {
1385  const diff* canonical = d->get_canonical_diff();
1386  ABG_ASSERT(canonical);
1387 
1388  size_t ptr_value = reinterpret_cast<size_t>(canonical);
1389  pointer_map::iterator it = priv_->visited_diff_nodes_.find(ptr_value);
1390  if (it != priv_->visited_diff_nodes_.end())
1391  return reinterpret_cast<diff*>(it->second);
1392  else
1393  return 0;
1394 }
1395 
1396 /// Test if a diff node has been traversed.
1397 ///
1398 /// @param d the diff node to consider.
1399 ///
1400 /// @return the first diff node against which @p d is redundant.
1401 diff_sptr
1403 {
1405  return diff;
1406 }
1407 
1408 /// Mark a diff node as traversed by a traversing algorithm.
1409 ///
1410 /// Actually, it's the @ref CanonicalDiff "canonical diff" of this
1411 /// node that is marked as traversed.
1412 ///
1413 /// Subsequent invocations of diff_has_been_visited() on the diff node
1414 /// will yield true.
1415 void
1417 {
1418  if (diff_has_been_visited(d))
1419  return;
1420 
1421  const diff* canonical = d->get_canonical_diff();
1422  ABG_ASSERT(canonical);
1423 
1424  size_t canonical_ptr_value = reinterpret_cast<size_t>(canonical);
1425  size_t diff_ptr_value = reinterpret_cast<size_t>(d);
1426  priv_->visited_diff_nodes_[canonical_ptr_value] = diff_ptr_value;
1427 }
1428 
1429 /// Unmark all the diff nodes that were marked as being traversed.
1430 void
1432 {priv_->visited_diff_nodes_.clear();}
1433 
1434 /// This sets a flag that, if it's true, then during the traversing of
1435 /// a diff nodes tree each node is visited at most once.
1436 ///
1437 /// @param f if true then during the traversing of a diff nodes tree
1438 /// each node is visited at most once.
1439 ///
1440 void
1442 {priv_->forbid_visiting_a_node_twice_ = f;}
1443 
1444 /// This function sets a flag os that if @ref
1445 /// forbid_visiting_a_node_twice() returns true, then each time the
1446 /// node visitor starts visiting a new interface, it resets the
1447 /// memory the systems has about already visited node.
1448 ///
1449 /// @param f the flag to set.
1450 void
1452 {priv_->reset_visited_diffs_for_each_interface_ = f;}
1453 
1454 /// Return a flag that, if true, then during the traversing of a diff
1455 /// nodes tree each node is visited at most once.
1456 ///
1457 /// @return the boolean flag.
1458 bool
1460 {return priv_->forbid_visiting_a_node_twice_;}
1461 
1462 /// Return a flag that, if true, then during the traversing of a diff
1463 /// nodes tree each node is visited at most once, while visiting the
1464 /// diff tree underneath a given interface (public function or
1465 /// variable). Each time a new interface is visited, the nodes
1466 /// visited while visiting previous interfaces can be visited again.
1467 ///
1468 /// @return the boolean flag.
1469 ///
1470 /// @return the boolean flag.
1471 bool
1473 {
1474  return (priv_->forbid_visiting_a_node_twice_
1475  && priv_->reset_visited_diffs_for_each_interface_);
1476 }
1477 
1478 /// Getter for the diff tree nodes filters to apply to diff sub-trees.
1479 ///
1480 /// @return the vector of tree filters to apply to diff sub-trees.
1481 const filtering::filters&
1483 {return priv_->filters_;}
1484 
1485 /// Setter for the diff filters to apply to a given diff sub-tree.
1486 ///
1487 /// @param f the new diff filter to add to the vector of diff filters
1488 /// to apply to diff sub-trees.
1489 void
1491 {priv_->filters_.push_back(f);}
1492 
1493 /// Apply the diff filters to a given diff sub-tree.
1494 ///
1495 /// If the current context is instructed to filter out some categories
1496 /// then this function walks the given sub-tree and categorizes its
1497 /// nodes by using the filters held by the context.
1498 ///
1499 /// @param diff the diff sub-tree to apply the filters to.
1500 void
1502 {
1503  if (!diff)
1504  return;
1505 
1506  if (!diff->has_changes())
1507  return;
1508 
1509  for (filtering::filters::const_iterator i = diff_filters().begin();
1510  i != diff_filters().end();
1511  ++i)
1512  {
1514  if (do_log())
1515  {
1516  std::cerr << "applying a filter to diff '"
1517  << diff->get_pretty_representation()
1518  << "'...\n";
1519  t.start();
1520  }
1521 
1522  filtering::apply_filter(*i, diff);
1523 
1524  if (do_log())
1525  {
1526  t.stop();
1527  std::cerr << "filter applied!:" << t << "\n";
1528 
1529  std::cerr << "propagating categories for the same diff node ... \n";
1530  t.start();
1531  }
1532 
1533  propagate_categories(diff);
1534 
1535  if (do_log())
1536  {
1537  t.stop();
1538  std::cerr << "category propagated!: " << t << "\n";
1539  }
1540  }
1541 
1542  }
1543 
1544 /// Apply the diff filters to the diff nodes of a @ref corpus_diff
1545 /// instance.
1546 ///
1547 /// If the current context is instructed to filter out some categories
1548 /// then this function walks the diff tree and categorizes its nodes
1549 /// by using the filters held by the context.
1550 ///
1551 /// @param diff the corpus diff to apply the filters to.
1552 void
1554 {
1555 
1556  if (!diff || !diff->has_changes())
1557  return;
1558 
1559  for (filtering::filters::const_iterator i = diff_filters().begin();
1560  i != diff_filters().end();
1561  ++i)
1562  {
1563  filtering::apply_filter(**i, diff);
1564  propagate_categories(diff);
1565  }
1566 }
1567 
1568 /// Getter for the vector of suppressions that specify which diff node
1569 /// reports should be dropped on the floor.
1570 ///
1571 /// @return the set of suppressions.
1572 const suppressions_type&
1574 {return priv_->suppressions_;}
1575 
1576 /// Getter for the vector of suppressions that specify which diff node
1577 /// reports should be dropped on the floor.
1578 ///
1579 /// @return the set of suppressions.
1582 {
1583  // Invalidate negated and direct suppressions caches that are built
1584  // from priv_->suppressions_;
1585  priv_->negated_suppressions_.clear();
1586  priv_->direct_suppressions_.clear();
1587  return priv_->suppressions_;
1588 }
1589 
1590 /// Getter of the negated suppression specifications that are
1591 /// comprised in the general vector of suppression specifications
1592 /// returned by diff_context::suppressions().
1593 ///
1594 /// Note that the first invocation of this function scans the vector
1595 /// returned by diff_context::suppressions() and caches the negated
1596 /// suppressions from there.
1597 ///
1598 /// Subsequent invocations of this function just return the cached
1599 /// negated suppressions.
1600 ///
1601 /// @return the negated suppression specifications stored in this diff
1602 /// context.
1605 {
1606  if (priv_->negated_suppressions_.empty())
1607  for (auto s : suppressions())
1608  if (is_negated_suppression(s))
1609  priv_->negated_suppressions_.push_back(s);
1610 
1611  return priv_->negated_suppressions_;
1612 }
1613 
1614 /// Getter of the direct suppression specification (those that are
1615 /// not negated) comprised in the general vector of suppression
1616 /// specifications returned by diff_context::suppression().
1617 ///
1618 /// Note that the first invocation of this function scans the vector
1619 /// returned by diff_context::suppressions() and caches the direct
1620 /// suppressions from there.
1621 ///
1622 /// Subsequent invocations of this function just return the cached
1623 /// direct suppressions.
1624 ///
1625 /// @return the direct suppression specifications.
1628 {
1629  if (priv_->direct_suppressions_.empty())
1630  {
1631  for (auto s : suppressions())
1632  if (!is_negated_suppression(s))
1633  priv_->direct_suppressions_.push_back(s);
1634  }
1635  return priv_->direct_suppressions_;
1636 }
1637 
1638 /// Add a new suppression specification that specifies which diff node
1639 /// reports should be dropped on the floor.
1640 ///
1641 /// @param suppr the new suppression specification to add to the
1642 /// existing set of suppressions specifications of the diff context.
1643 void
1645 {
1646  priv_->suppressions_.push_back(suppr);
1647  // Invalidate negated and direct suppressions caches that are built
1648  // from priv_->suppressions_;
1649  priv_->negated_suppressions_.clear();
1650  priv_->direct_suppressions_.clear();
1651 }
1652 
1653 /// Add new suppression specifications that specify which diff node
1654 /// reports should be dropped on the floor.
1655 ///
1656 /// @param supprs the new suppression specifications to add to the
1657 /// existing set of suppression specifications of the diff context.
1658 void
1660 {
1661  priv_->suppressions_.insert(priv_->suppressions_.end(),
1662  supprs.begin(), supprs.end());
1663 }
1664 
1665 /// Test if it's requested to perform diff node categorization.
1666 ///
1667 /// @return true iff it's requested to perform diff node
1668 /// categorization.
1669 bool
1671 {return priv_->perform_change_categorization_;}
1672 
1673 /// Request change categorization or not.
1674 ///
1675 /// @param f true iff change categorization is requested.
1676 void
1678 {priv_->perform_change_categorization_ = f;}
1679 
1680 /// Set the flag that indicates if the diff using this context should
1681 /// show only leaf changes or not.
1682 ///
1683 /// @param f the new value of the flag that indicates if the diff
1684 /// using this context should show only leaf changes or not.
1685 void
1687 {
1688  // This function can be called only if the reporter hasn't yet been
1689  // created. Once it's been created, we are supposed to live with
1690  // it.
1691  ABG_ASSERT(priv_->reporter_ == 0);
1692  priv_->leaf_changes_only_ = f;
1693 }
1694 
1695 /// Get the flag that indicates if the diff using this context should
1696 /// show only leaf changes or not.
1697 ///
1698 /// @return the value of the flag that indicates if the diff using
1699 /// this context should show only leaf changes or not.
1700 bool
1702 {return priv_->leaf_changes_only_;}
1703 
1704 /// Get the flag that indicates if the diff reports using this context
1705 /// should show sizes and offsets in an hexadecimal base or not. If
1706 /// not, then they are to be shown in a decimal base.
1707 ///
1708 /// @return true iff sizes and offsets are to be shown in an
1709 /// hexadecimal base.
1710 bool
1712 {return priv_->hex_values_;}
1713 
1714 /// Set the flag that indicates if diff reports using this context
1715 /// should show sizes and offsets in an hexadecimal base or not. If
1716 /// not, then they are to be shown in a decimal base.
1717 ///
1718 /// @param f if true then sizes and offsets are to be shown in an
1719 /// hexadecimal base.
1720 void
1722 {priv_->hex_values_ = f;}
1723 
1724 /// Get the flag that indicates if diff reports using this context
1725 /// should show sizes and offsets in bits, rather than bytes.
1726 ///
1727 /// @return true iff sizes and offsets are to be shown in bits.
1728 /// Otherwise they are to be shown in bytes.
1729 bool
1731 {return priv_->show_offsets_sizes_in_bits_;}
1732 
1733 /// Set the flag that indicates if diff reports using this context
1734 /// should show sizes and offsets in bits, rather than bytes.
1735 ///
1736 /// @param f if true then sizes and offsets are to be shown in bits.
1737 /// Otherwise they are to be shown in bytes.
1738 void
1740 {priv_->show_offsets_sizes_in_bits_ = f;}
1741 
1742 /// Set a flag saying if offset changes should be reported in a
1743 /// relative way. That is, if the report should say how of many bits
1744 /// a class/struct data member did move.
1745 ///
1746 /// @param f the new boolean value of the flag.
1747 void
1749 {priv_->show_relative_offset_changes_ = f;}
1750 
1751 /// Get the flag saying if offset changes should be reported in a
1752 /// relative way. That is, if the report should say how of many bits
1753 /// a class/struct data member did move.
1754 ///
1755 /// @return the boolean value of the flag.
1756 bool
1758 {return priv_->show_relative_offset_changes_;}
1759 
1760 /// Set a flag saying if the comparison module should only show the
1761 /// diff stats.
1762 ///
1763 /// @param f the flag to set.
1764 void
1766 {priv_->show_stats_only_ = f;}
1767 
1768 /// Test if the comparison module should only show the diff stats.
1769 ///
1770 /// @return true if the comparison module should only show the diff
1771 /// stats, false otherwise.
1772 bool
1774 {return priv_->show_stats_only_;}
1775 
1776 /// Setter for the property that says if the comparison module should
1777 /// show the soname changes in its report.
1778 ///
1779 /// @param f the new value of the property.
1780 void
1782 {priv_->show_soname_change_ = f;}
1783 
1784 /// Getter for the property that says if the comparison module should
1785 /// show the soname changes in its report.
1786 ///
1787 /// @return the value of the property.
1788 bool
1790 {return priv_->show_soname_change_;}
1791 
1792 /// Setter for the property that says if the comparison module should
1793 /// show the architecture changes in its report.
1794 ///
1795 /// @param f the new value of the property.
1796 void
1798 {priv_->show_architecture_change_ = f;}
1799 
1800 /// Getter for the property that says if the comparison module should
1801 /// show the architecture changes in its report.
1802 ///
1803 /// @return the value of the property.
1804 bool
1806 {return priv_->show_architecture_change_;}
1807 
1808 /// Set a flag saying to show the deleted functions.
1809 ///
1810 /// @param f true to show deleted functions.
1811 void
1813 {priv_->show_deleted_fns_ = f;}
1814 
1815 /// @return true if we want to show the deleted functions, false
1816 /// otherwise.
1817 bool
1819 {return priv_->show_deleted_fns_;}
1820 
1821 /// Set a flag saying to show the changed functions.
1822 ///
1823 /// @param f true to show the changed functions.
1824 void
1826 {priv_->show_changed_fns_ = f;}
1827 
1828 /// @return true if we want to show the changed functions, false otherwise.
1829 bool
1831 {return priv_->show_changed_fns_;}
1832 
1833 /// Set a flag saying to show the added functions.
1834 ///
1835 /// @param f true to show the added functions.
1836 void
1838 {priv_->show_added_fns_ = f;}
1839 
1840 /// @return true if we want to show the added functions, false
1841 /// otherwise.
1842 bool
1844 {return priv_->show_added_fns_;}
1845 
1846 /// Set a flag saying to show the deleted variables.
1847 ///
1848 /// @param f true to show the deleted variables.
1849 void
1851 {priv_->show_deleted_vars_ = f;}
1852 
1853 /// @return true if we want to show the deleted variables, false
1854 /// otherwise.
1855 bool
1857 {return priv_->show_deleted_vars_;}
1858 
1859 /// Set a flag saying to show the changed variables.
1860 ///
1861 /// @param f true to show the changed variables.
1862 void
1864 {priv_->show_changed_vars_ = f;}
1865 
1866 /// @return true if we want to show the changed variables, false otherwise.
1867 bool
1869 {return priv_->show_changed_vars_;}
1870 
1871 /// Set a flag saying to show the added variables.
1872 ///
1873 /// @param f true to show the added variables.
1874 void
1876 {priv_->show_added_vars_ = f;}
1877 
1878 /// @return true if we want to show the added variables, false
1879 /// otherwise.
1880 bool
1882 {return priv_->show_added_vars_;}
1883 
1884 bool
1885 diff_context::show_linkage_names() const
1886 {return priv_->show_linkage_names_;}
1887 
1888 void
1889 diff_context::show_linkage_names(bool f)
1890 {priv_->show_linkage_names_= f;}
1891 
1892 /// Set a flag saying to show location information.
1893 ///
1894 /// @param f true to show location information.
1895 void
1897 {priv_->show_locs_= f;}
1898 
1899 /// @return true if we want to show location information, false
1900 /// otherwise.
1901 bool
1903 {return priv_->show_locs_;}
1904 
1905 /// A getter for the flag that says if we should report about
1906 /// functions or variables diff nodes that have *exclusively*
1907 /// redundant diff tree children nodes.
1908 ///
1909 /// @return the flag.
1910 bool
1912 {return priv_->show_redundant_changes_;}
1913 
1914 /// A setter for the flag that says if we should report about
1915 /// functions or variables diff nodes that have *exclusively*
1916 /// redundant diff tree children nodes.
1917 ///
1918 /// @param f the flag to set.
1919 void
1921 {priv_->show_redundant_changes_ = f;}
1922 
1923 /// Getter for the flag that indicates if symbols not referenced by
1924 /// any debug info are to be compared and reported about.
1925 ///
1926 /// @return the boolean flag.
1927 bool
1929 {return priv_->show_syms_unreferenced_by_di_;}
1930 
1931 /// Setter for the flag that indicates if symbols not referenced by
1932 /// any debug info are to be compared and reported about.
1933 ///
1934 /// @param f the new flag to set.
1935 void
1937 {priv_->show_syms_unreferenced_by_di_ = f;}
1938 
1939 /// Getter for the flag that indicates if symbols not referenced by
1940 /// any debug info and that got added are to be reported about.
1941 ///
1942 /// @return true iff symbols not referenced by any debug info and that
1943 /// got added are to be reported about.
1944 bool
1946 {return priv_->show_added_syms_unreferenced_by_di_;}
1947 
1948 /// Setter for the flag that indicates if symbols not referenced by
1949 /// any debug info and that got added are to be reported about.
1950 ///
1951 /// @param f the new flag that says if symbols not referenced by any
1952 /// debug info and that got added are to be reported about.
1953 void
1955 {priv_->show_added_syms_unreferenced_by_di_ = f;}
1956 
1957 /// Setter for the flag that indicates if changes on types unreachable
1958 /// from global functions and variables are to be reported.
1959 ///
1960 /// @param f if true, then changes on types unreachable from global
1961 /// functions and variables are to be reported.
1962 void
1964 {priv_->show_unreachable_types_ = f;}
1965 
1966 /// Getter for the flag that indicates if changes on types unreachable
1967 /// from global functions and variables are to be reported.
1968 ///
1969 /// @return true iff changes on types unreachable from global
1970 /// functions and variables are to be reported.
1971 bool
1973 {return priv_->show_unreachable_types_;}
1974 
1975 /// Getter of the flag that indicates if the leaf reporter should
1976 /// display a summary of the interfaces impacted by a given leaf
1977 /// change or not.
1978 ///
1979 /// @return the flag that indicates if the leaf reporter should
1980 /// display a summary of the interfaces impacted by a given leaf
1981 /// change or not.
1982 bool
1984 {return priv_->show_impacted_interfaces_;}
1985 
1986 /// Setter of the flag that indicates if the leaf reporter should
1987 /// display a summary of the interfaces impacted by a given leaf
1988 /// change or not.
1989 ///
1990 /// @param f the new value of the flag that indicates if the leaf
1991 /// reporter should display a summary of the interfaces impacted by a
1992 /// given leaf change or not.
1993 void
1995 {priv_->show_impacted_interfaces_ = f;}
1996 
1997 /// Setter for the default output stream used by code of the
1998 /// comparison engine. By default the default output stream is a NULL
1999 /// pointer.
2000 ///
2001 /// @param o a pointer to the default output stream.
2002 void
2004 {priv_->default_output_stream_ = o;}
2005 
2006 /// Getter for the default output stream used by code of the
2007 /// comparison engine. By default the default output stream is a NULL
2008 /// pointer.
2009 ///
2010 /// @return a pointer to the default output stream.
2011 ostream*
2013 {return priv_->default_output_stream_;}
2014 
2015 /// Setter for the errror output stream used by code of the comparison
2016 /// engine. By default the error output stream is a NULL pointer.
2017 ///
2018 /// @param o a pointer to the error output stream.
2019 void
2021 {priv_->error_output_stream_ = o;}
2022 
2023 /// Getter for the errror output stream used by code of the comparison
2024 /// engine. By default the error output stream is a NULL pointer.
2025 ///
2026 /// @return a pointer to the error output stream.
2027 ostream*
2029 {return priv_->error_output_stream_;}
2030 
2031 /// Test if the comparison engine should dump the diff tree for the
2032 /// changed functions and variables it has.
2033 ///
2034 /// @return true if after the comparison, the engine should dump the
2035 /// diff tree for the changed functions and variables it has.
2036 bool
2038 {return priv_->dump_diff_tree_;}
2039 
2040 /// Set if the comparison engine should dump the diff tree for the
2041 /// changed functions and variables it has.
2042 ///
2043 /// @param f true if after the comparison, the engine should dump the
2044 /// diff tree for the changed functions and variables it has.
2045 void
2047 {priv_->dump_diff_tree_ = f;}
2048 
2049 /// Emit a textual representation of a diff tree to the error output
2050 /// stream of the current context, for debugging purposes.
2051 ///
2052 /// @param d the diff tree to serialize to the error output associated
2053 /// to the current instance of @ref diff_context.
2054 void
2056 {
2057  if (error_output_stream())
2059 }
2060 
2061 /// Emit a textual representation of a @ref corpus_diff tree to the error
2062 /// output stream of the current context, for debugging purposes.
2063 ///
2064 /// @param d the @ref corpus_diff tree to serialize to the error
2065 /// output associated to the current instance of @ref diff_context.
2066 void
2068 {
2069  if (error_output_stream())
2071 }
2072 // </diff_context stuff>
2073 
2074 // <diff stuff>
2075 
2076 /// Constructor for the @ref diff type.
2077 ///
2078 /// This constructs a diff between two subjects that are actually
2079 /// declarations; the first and the second one.
2080 ///
2081 /// @param first_subject the first decl (subject) of the diff.
2082 ///
2083 /// @param second_subject the second decl (subject) of the diff.
2084 diff::diff(type_or_decl_base_sptr first_subject,
2085  type_or_decl_base_sptr second_subject)
2086  : priv_(new priv(first_subject, second_subject,
2089  /*reported_once=*/false,
2090  /*currently_reporting=*/false))
2091 {}
2092 
2093 /// Constructor for the @ref diff type.
2094 ///
2095 /// This constructs a diff between two subjects that are actually
2096 /// declarations; the first and the second one.
2097 ///
2098 /// @param first_subject the first decl (subject) of the diff.
2099 ///
2100 /// @param second_subject the second decl (subject) of the diff.
2101 ///
2102 /// @param ctxt the context of the diff. Note that this context
2103 /// object must stay alive during the entire life time of the current
2104 /// instance of @ref diff. Otherwise, memory corruption issues occur.
2105 diff::diff(type_or_decl_base_sptr first_subject,
2106  type_or_decl_base_sptr second_subject,
2107  diff_context_sptr ctxt)
2108  : priv_(new priv(first_subject, second_subject,
2109  ctxt, NO_CHANGE_CATEGORY,
2110  /*reported_once=*/false,
2111  /*currently_reporting=*/false))
2112 {}
2113 
2114 /// Test if logging was requested
2115 ///
2116 /// @return true iff logging was requested.
2117 bool
2119 {return context()->do_log();}
2120 
2121 /// Request logging (or not)
2122 ///
2123 /// @param f true iff logging is to be requested.
2124 void
2126 {context()->do_log(f);}
2127 
2128 /// Flag a given diff node as being traversed.
2129 ///
2130 /// For certain diff nodes like @ref class_diff, it's important to
2131 /// avoid traversing the node again while it's already being
2132 /// traversed; otherwise this leads to infinite loops. So the
2133 /// diff::begin_traversing() and diff::end_traversing() methods flag a
2134 /// given node as being traversed (or not), so that
2135 /// diff::is_traversing() can tell if the node is being traversed.
2136 ///
2137 /// Note that traversing a node means visiting it *and* visiting its
2138 /// children nodes.
2139 ///
2140 /// The canonical node is marked as being traversed too.
2141 ///
2142 /// These functions are called by the traversing code.
2143 void
2145 {
2147  if (priv_->canonical_diff_)
2148  priv_->canonical_diff_->priv_->traversing_ = true;
2149  priv_->traversing_ = true;
2150 }
2151 
2152 /// Tell if a given node is being traversed or not.
2153 ///
2154 /// Note that traversing a node means visiting it *and* visiting its
2155 /// children nodes.
2156 ///
2157 /// It's the canonical node which is looked at, actually.
2158 ///
2159 /// Please read the comments for the diff::begin_traversing() for mode
2160 /// context.
2161 ///
2162 /// @return true if the current instance of @diff is being traversed.
2163 bool
2165 {
2166  if (priv_->canonical_diff_)
2167  return priv_->canonical_diff_->priv_->traversing_;
2168  return priv_->traversing_;
2169 }
2170 
2171 /// Flag a given diff node as not being traversed anymore.
2172 ///
2173 /// Note that traversing a node means visiting it *and* visiting its
2174 /// children nodes.
2175 ///
2176 /// Please read the comments of the function diff::begin_traversing()
2177 /// for mode context.
2178 void
2180 {
2182  if (priv_->canonical_diff_)
2183  priv_->canonical_diff_->priv_->traversing_ = false;
2184  priv_->traversing_ = false;
2185 }
2186 
2187 /// Finish the insertion of a diff tree node into the diff graph.
2188 ///
2189 /// This function might be called several times. It must perform the
2190 /// insertion only once.
2191 ///
2192 /// For instance, certain kinds of diff tree node have specific
2193 /// children nodes that are populated after the constructor of the
2194 /// diff tree node has been called. In that case, calling overloads
2195 /// of this method ensures that these children nodes are properly
2196 /// gathered and setup.
2197 void
2199 {
2200  if (diff::priv_->finished_)
2201  return;
2203  diff::priv_->finished_ = true;
2204 }
2205 
2206 /// Getter of the first subject of the diff.
2207 ///
2208 /// @return the first subject of the diff.
2211 {return dynamic_pointer_cast<type_or_decl_base>(priv_->first_subject_);}
2212 
2213 /// Getter of the second subject of the diff.
2214 ///
2215 /// @return the second subject of the diff.
2218 {return dynamic_pointer_cast<type_or_decl_base>(priv_->second_subject_);}
2219 
2220 /// Getter for the children nodes of the current @ref diff node.
2221 ///
2222 /// @return a vector of the children nodes.
2223 const vector<diff*>&
2225 {return priv_->children_;}
2226 
2227 /// Getter for the parent node of the current @ref diff node.
2228 ///
2229 /// @return the parent node of the current @ref diff node.
2230 const diff*
2232 {return priv_->parent_;}
2233 
2234 /// Getter for the canonical diff of the current instance of @ref
2235 /// diff.
2236 ///
2237 /// Note that the canonical diff node for the current instanc eof diff
2238 /// node must have been set by invoking
2239 /// class_diff::initialize_canonical_diff() on the current instance of
2240 /// diff node.
2241 ///
2242 /// @return the canonical diff node or null if none was set.
2243 diff*
2245 {return priv_->canonical_diff_;}
2246 
2247 /// Setter for the canonical diff of the current instance of @ref
2248 /// diff.
2249 ///
2250 /// @param d the new canonical node to set.
2251 void
2253 {priv_->canonical_diff_ = d;}
2254 
2255 /// Add a new child node to the vector of children nodes for the
2256 /// current @ref diff node.
2257 ///
2258 /// @param d the new child node to add to the children nodes.
2259 void
2261 {
2262  ABG_ASSERT(d);
2263 
2264  // Ensure 'd' is kept alive for the life time of the context of this
2265  // diff.
2266  context()->keep_diff_alive(d);
2267 
2268  // Add the underlying pointer of 'd' to the vector of children.
2269  // Note that this vector holds no reference to 'd'. This is to avoid
2270  // reference cycles. The reference to 'd' is held by the context of
2271  // this diff, thanks to the call to context()->keep_diff_alive(d)
2272  // above.
2273  priv_->children_.push_back(d.get());
2274 
2275  d->priv_->parent_ = this;
2276 }
2277 
2278 /// Getter of the context of the current diff.
2279 ///
2280 /// @return the context of the current diff.
2281 const diff_context_sptr
2283 {return priv_->get_context();}
2284 
2285 /// Setter of the context of the current diff.
2286 ///
2287 /// @param c the new context to set.
2288 void
2290 {priv_->ctxt_ = c;}
2291 
2292 /// Tests if we are currently in the middle of emitting a report for
2293 /// this diff.
2294 ///
2295 /// @return true if we are currently emitting a report for the
2296 /// current diff, false otherwise.
2297 bool
2299 {
2300  if (priv_->canonical_diff_)
2301  return priv_->canonical_diff_->priv_->currently_reporting_;
2302  return priv_->currently_reporting_;
2303 }
2304 
2305 /// Sets a flag saying if we are currently in the middle of emitting
2306 /// a report for this diff.
2307 ///
2308 /// @param f true if we are currently emitting a report for the
2309 /// current diff, false otherwise.
2310 void
2312 {
2313  if (priv_->canonical_diff_)
2314  priv_->canonical_diff_->priv_->currently_reporting_ = f;
2315  priv_->currently_reporting_ = f;
2316 }
2317 
2318 /// Tests if a report has already been emitted for the current diff.
2319 ///
2320 /// @return true if a report has already been emitted for the
2321 /// current diff, false otherwise.
2322 bool
2324 {
2325  ABG_ASSERT(priv_->canonical_diff_);
2326  return priv_->canonical_diff_->priv_->reported_once_;
2327 }
2328 
2329 /// The generic traversing code that walks a given diff sub-tree.
2330 ///
2331 /// Note that there is a difference between traversing a diff node and
2332 /// visiting it. Basically, traversing a diff node means visiting it
2333 /// and visiting its children nodes too. So one can visit a node
2334 /// without traversing it. But traversing a node without visiting it
2335 /// is not possible.
2336 ///
2337 /// Note that the insertion of the "generic view" of the diff node
2338 /// into the graph being traversed is done "on the fly". The
2339 /// insertion of the "typed view" of the diff node into the graph is
2340 /// done implicitely. To learn more about the generic and typed view
2341 /// of the diff node, please read the introductory comments of the
2342 /// @ref diff class.
2343 ///
2344 /// Note that by default this traversing code visits a given class of
2345 /// equivalence of a diff node only once. This behaviour can been
2346 /// changed by calling
2347 /// diff_context::visiting_a_node_twice_is_forbidden(), but this is
2348 /// very risky as it might create endless loops while visiting a diff
2349 /// tree graph that has changes that refer to themselves; that is,
2350 /// diff tree graphs with cycles.
2351 ///
2352 /// When a diff node is encountered, the
2353 /// diff_node_visitor::visit_begin() method is invoked on the diff
2354 /// node first.
2355 ///
2356 /// If the diff node has already been visited, then
2357 /// node_visitor::visit_end() is called on it and the node traversing
2358 /// is done; the children of the diff node are not visited in this
2359 /// case.
2360 ///
2361 /// If the diff node has *NOT* been visited yet, then the
2362 /// diff_node_visitor::visit() method is invoked with it's 'pre'
2363 /// argument set to true. Then if the diff_node_visitor::visit()
2364 /// returns true, then the children nodes of the diff node are
2365 /// visited. Otherwise, no children nodes of the diff node is
2366 /// visited and the diff_node_visitor::visit_end() is called.
2367 
2368 /// After the children nodes are visited (and only if they are
2369 /// visited) the diff_node_visitor::visit() method is invoked with
2370 /// it's 'pre' argument set to false. And then the
2371 /// diff_node_visitor::visit_end() is called.
2372 ///
2373 /// @param v the entity that visits each node of the diff sub-tree.
2374 ///
2375 /// @return true to tell the caller that all of the sub-tree could be
2376 /// walked. This instructs the caller to keep walking the rest of the
2377 /// tree. Return false otherwise.
2378 bool
2380 {
2381  // Insert the "generic view" of the diff node into its graph.
2382  finish_diff_type();
2383 
2384  v.visit_begin(this);
2385 
2386  bool already_visited = false;
2387  if (context()->visiting_a_node_twice_is_forbidden()
2388  && context()->diff_has_been_visited(this))
2389  already_visited = true;
2390 
2391  bool mark_visited_nodes_as_traversed =
2393 
2394  if (!already_visited && !v.visit(this, /*pre=*/true))
2395  {
2396  v.visit_end(this);
2397  if (mark_visited_nodes_as_traversed)
2398  context()->mark_diff_as_visited(this);
2399  return false;
2400  }
2401 
2403  && !is_traversing()
2404  && !already_visited)
2405  {
2406  begin_traversing();
2407  for (vector<diff*>::const_iterator i = children_nodes().begin();
2408  i != children_nodes().end();
2409  ++i)
2410  {
2411  if (!(*i)->traverse(v))
2412  {
2413  v.visit_end(this);
2414  if (mark_visited_nodes_as_traversed)
2415  context()->mark_diff_as_visited(this);
2416  end_traversing();
2417  return false;
2418  }
2419  }
2420  end_traversing();
2421  }
2422 
2423  if (!v.visit(this, /*pref=*/false))
2424  {
2425  v.visit_end(this);
2426  if (mark_visited_nodes_as_traversed)
2427  context()->mark_diff_as_visited(this);
2428  return false;
2429  }
2430 
2431  v.visit_end(this);
2432  if (!already_visited && mark_visited_nodes_as_traversed)
2433  context()->mark_diff_as_visited(this);
2434 
2435  return true;
2436 }
2437 
2438 /// Sets a flag saying if a report has already been emitted for the
2439 /// current diff.
2440 ///
2441 /// @param f true if a report has already been emitted for the
2442 /// current diff, false otherwise.
2443 void
2444 diff::reported_once(bool f) const
2445 {
2446  ABG_ASSERT(priv_->canonical_diff_);
2447  priv_->canonical_diff_->priv_->reported_once_ = f;
2448  priv_->reported_once_ = f;
2449 }
2450 
2451 /// Getter for the local category of the current diff tree node.
2452 ///
2453 /// The local category represents the set of categories of a diff
2454 /// node, not taking in account the categories inherited from its
2455 /// children nodes.
2456 ///
2457 /// @return the local category of the current diff tree node.
2460 {return priv_->local_category_;}
2461 
2462 /// Getter of the category of the class of equivalence of the current
2463 /// diff tree node.
2464 ///
2465 /// That is, if the current diff tree node has a canonical node,
2466 /// return the category of that canonical node. Otherwise, return the
2467 /// category of the current node.
2468 ///
2469 /// @return the category of the class of equivalence of the current
2470 /// tree node.
2473 {
2474  diff* canonical = get_canonical_diff();
2475  return canonical ? canonical->get_category() : get_category();
2476 }
2477 
2478 /// Getter for the category of the current diff tree node.
2479 ///
2480 /// This category represents the union of the local category and the
2481 /// categories inherited from the children diff nodes.
2482 ///
2483 /// @return the category of the current diff tree node.
2486 {return priv_->category_;}
2487 
2488 /// Adds the current diff tree node to an additional set of
2489 /// categories. Note that the categories include thoses inherited
2490 /// from the children nodes of this diff node.
2491 ///
2492 /// @param c a bit-map representing the set of categories to add the
2493 /// current diff tree node to.
2494 ///
2495 /// @return the resulting bit-map representing the categories this
2496 /// current diff tree node belongs to, including those inherited from
2497 /// its children nodes.
2500 {
2501  priv_->category_ = priv_->category_ | c;
2502  return priv_->category_;
2503 }
2504 
2505 /// Adds the current diff tree node to the categories resulting from
2506 /// the local changes of the current diff node.
2507 ///
2508 /// @param c a bit-map representing the set of categories to add the
2509 /// current diff tree node to.
2510 ///
2511 /// @return the resulting bit-map representing the categories this
2512 /// current diff tree node belongs to.
2515 {
2516  priv_->local_category_ = priv_->local_category_ | c;
2517  return priv_->local_category_;
2518 }
2519 
2520 /// Adds the current diff tree node to the categories resulting from
2521 /// the local and inherited changes of the current diff node.
2522 ///
2523 /// @param c a bit-map representing the set of categories to add the
2524 /// current diff tree node to.
2525 void
2527 {
2529  add_to_category(c);
2530 }
2531 
2532 /// Remove the current diff tree node from an a existing sef of
2533 /// categories. The categories include those inherited from the
2534 /// children nodes of the current diff node.
2535 ///
2536 /// @param c a bit-map representing the set of categories to add the
2537 /// current diff tree node to.
2538 ///
2539 /// @return the resulting bit-map representing the categories this
2540 /// current diff tree onde belongs to, including the categories
2541 /// inherited from the children nodes of the current diff node.
2544 {
2545  priv_->category_ = priv_->category_ & ~c;
2546  return priv_->category_;
2547 }
2548 
2549 /// Remove the current diff tree node from the categories resulting
2550 /// from the local changes.
2551 ///
2552 /// @param c a bit-map representing the set of categories to add the
2553 /// current diff tree node to.
2554 ///
2555 /// @return the resulting bit-map representing the categories this
2556 /// current diff tree onde belongs to.
2559 {
2560  priv_->local_category_ = priv_->local_category_ & ~c;
2561  return priv_->local_category_;
2562 }
2563 
2564 /// Set the category of the current @ref diff node. This category
2565 /// includes the categories inherited from the children nodes of the
2566 /// current diff node.
2567 ///
2568 /// @param c the new category for the current diff node.
2569 void
2571 {priv_->category_ = c;}
2572 
2573 /// Set the local category of the current @ref diff node.
2574 ///
2575 /// @param c the new category for the current diff node.
2576 void
2578 {priv_->local_category_ = c;}
2579 
2580 /// Test if this diff tree node is to be filtered out for reporting
2581 /// purposes.
2582 ///
2583 /// There is a difference between a diff node being filtered out and
2584 /// being suppressed. Being suppressed means that there is a
2585 /// suppression specification that suppresses the diff node
2586 /// specifically. Being filtered out mean the node is either
2587 /// suppressed, or it's filtered out because the suppression of a set
2588 /// of (children) nodes caused this node to be filtered out as well.
2589 /// For instance, if a function diff has all its children diff nodes
2590 /// suppressed and if the function diff node carries no local change,
2591 /// then the function diff node itself is going to be filtered out.
2592 ///
2593 /// The function tests if the categories of the diff tree node are
2594 /// "forbidden" by the context or not.
2595 ///
2596 /// @return true iff the current diff node should NOT be reported.
2597 bool
2599 {
2600  if (diff * canonical = get_canonical_diff())
2601  if ((canonical->get_category() & SUPPRESSED_CATEGORY
2602  || canonical->get_category() & PRIVATE_TYPE_CATEGORY)
2603  && !canonical->is_allowed_by_specific_negated_suppression()
2604  && !canonical->has_descendant_allowed_by_specific_negated_suppression()
2605  && !canonical->has_parent_allowed_by_specific_negated_suppression())
2606  // The canonical type was suppressed either by a user-provided
2607  // suppression specification or by a "private-type" suppression
2608  // specification.. This means all the classes of equivalence of
2609  // that canonical type were suppressed. So this node should be
2610  // filtered out.
2611  return true;
2612  return priv_->is_filtered_out(get_category());
2613 }
2614 
2615 /// Test if this diff tree node is to be filtered out for reporting
2616 /// purposes, but by considering only the categories that were *NOT*
2617 /// inherited from its children nodes.
2618 ///
2619 /// The function tests if the local categories of the diff tree node
2620 /// are "forbidden" by the context or not.
2621 ///
2622 /// @return true iff the current diff node should NOT be reported,
2623 /// with respect to its local categories.
2624 bool
2626 {return priv_->is_filtered_out(get_local_category());}
2627 
2628 /// Test if this diff tree node is to be filtered out for reporting
2629 /// purposes, but without considering the categories that can /force/
2630 /// the node to be unfiltered.
2631 ///
2632 /// The function tests if the categories of the diff tree node are
2633 /// "forbidden" by the context or not.
2634 ///
2635 /// @return true iff the current diff node should should NOT be
2636 /// reported, with respect to the categories that might filter it out
2637 /// only.
2638 bool
2640 {
2645 
2646  return priv_->is_filtered_out(c);
2647 }
2648 
2649 /// Test if the current diff node has been suppressed by a
2650 /// user-provided suppression specification.
2651 ///
2652 /// @return true if the current diff node has been suppressed by a
2653 /// user-provided suppression list.
2654 bool
2656 {
2657  bool is_private = false;
2658  return is_suppressed(is_private);
2659 }
2660 
2661 /// Test if the current diff node has been suppressed by a
2662 /// user-provided suppression specification or by an auto-generated
2663 /// "private type" suppression specification.
2664 ///
2665 /// Note that private type suppressions are auto-generated from the
2666 /// path to where public headers are, as given by the user.
2667 ///
2668 /// Here is the current algorithm:
2669 ///
2670 /// First, suppress this diff node if it's not matched by any
2671 /// negated suppression specifications. If it's not
2672 /// suppressed, then suppress it if it's matched by direct
2673 /// suppression specifications.
2674 ///
2675 /// @param is_private_type out parameter if the current diff node was
2676 /// suppressed because it's a private type then this parameter is set
2677 /// to true.
2678 ///
2679 /// @return true if the current diff node has been suppressed by a
2680 /// user-provided suppression list.
2681 bool
2682 diff::is_suppressed(bool &is_private_type) const
2683 {
2684  // If there is at least one negated suppression, then suppress the
2685  // current diff node by default ...
2686  bool do_suppress = !context()->negated_suppressions().empty();
2687 
2688  // ... unless there is at least one negated suppression that
2689  // specifically asks to keep this diff node around (un-suppressed).
2690  for (auto n : context()->negated_suppressions())
2691  if (!n->suppresses_diff(this))
2692  {
2693  do_suppress = false;
2694  break;
2695  }
2696 
2697  // Then walk the set of non-negated, AKA direct, suppressions. If at
2698  // least one suppression suppresses the current diff node then the
2699  // diff node must be suppressed.
2700  for (auto d : context()->direct_suppressions())
2701  if (d->suppresses_diff(this))
2702  {
2703  do_suppress = true;
2705  is_private_type = true;
2706  break;
2707  }
2708 
2709  return do_suppress;
2710 }
2711 
2712 /// Test if the current diff node has been suppressed by a suppression
2713 /// specification or it has been categorized as suppressed due to
2714 /// category propagation.
2715 ///
2716 /// @return true iff the current diff node has been suppressed by a
2717 /// suppression specification or it has been categorized as suppressed
2718 /// due to category propagation.
2719 bool
2721 {
2722  return (get_category() & SUPPRESSED_CATEGORY
2724 }
2725 
2726 /// Test if this diff tree node should be reported.
2727 ///
2728 /// @return true iff the current node should be reported.
2729 bool
2731 {
2732  if (has_changes() && !is_filtered_out())
2733  return true;
2734  return false;
2735 }
2736 
2737 /// Test if this diff tree node should be reported when considering
2738 /// the categories that were *NOT* inherited from its children nodes.
2739 ///
2740 /// @return true iff the current node should be reported.
2741 bool
2743 {
2744  if (has_local_changes()
2746  return true;
2747  return false;
2748 }
2749 
2750 /// Test if this diff node is allowed (prevented from being
2751 /// suppressed) by at least one negated suppression specification.
2752 ///
2753 /// @return true if this diff node is meant to be allowed by at least
2754 /// one negated suppression specification.
2755 bool
2757 {
2758  const suppressions_type& suppressions = context()->suppressions();
2759  for (suppressions_type::const_iterator i = suppressions.begin();
2760  i != suppressions.end();
2761  ++i)
2762  {
2763  if (is_negated_suppression(*i)
2764  && !(*i)->suppresses_diff(this))
2765  return true;
2766  }
2767  return false;
2768 }
2769 
2770 /// Test if the current diff node has a descendant node which is
2771 /// specifically allowed by a negated suppression specification.
2772 ///
2773 /// @return true iff the current diff node has a descendant node
2774 /// which is specifically allowed by a negated suppression
2775 /// specification.
2776 bool
2778 {
2780  return result;
2781 }
2782 
2783 /// Test if the current diff node has a parent node which is
2784 /// specifically allowed by a negated suppression specification.
2785 ///
2786 /// @return true iff the current diff node has a parent node which is
2787 /// specifically allowed by a negated suppression specification.
2788 bool
2790 {
2792  return result;
2793 }
2794 
2795 /// Get a pretty representation of the current @ref diff node.
2796 ///
2797 /// This is suitable for e.g. emitting debugging traces for the diff
2798 /// tree nodes.
2799 ///
2800 /// @return the pretty representation of the diff node.
2801 const string&
2803 {
2804  if (priv_->pretty_representation_.empty())
2805  priv_->pretty_representation_ = "empty_diff";
2806  return priv_->pretty_representation_;
2807 }
2808 
2809 /// Default implementation of the hierachy chaining virtual function.
2810 ///
2811 /// There are several types of diff nodes that have logical children
2812 /// nodes; for instance, a typedef_diff has the diff of the underlying
2813 /// type as a child node. A var_diff has the diff of the types of the
2814 /// variables as a child node, etc.
2815 ///
2816 /// But because the @ref diff base has a generic representation for
2817 /// children nodes of the all the types of @ref diff nodes (regardless
2818 /// of the specific most-derived type of diff node) that one can get
2819 /// using the method diff::children_nodes(), one need to populate that
2820 /// vector of children node.
2821 ///
2822 /// Populating that vector of children node is done by this function;
2823 /// it must be overloaded by each most-derived type of diff node that
2824 /// extends the @ref diff type.
2825 void
2827 {}
2828 
2829 // </diff stuff>
2830 
2831 // <type_diff_base stuff>
2832 
2833 type_diff_base::type_diff_base(type_base_sptr first_subject,
2834  type_base_sptr second_subject,
2835  diff_context_sptr ctxt)
2836  : diff(first_subject, second_subject, ctxt),
2837  priv_(new priv)
2838 {}
2839 
2840 type_diff_base::~type_diff_base()
2841 {}
2842 // </type_diff_base stuff>
2843 
2844 // <decl_diff_base stuff>
2845 
2846 /// Constructor of @ref decl_diff_base.
2847 ///
2848 /// @param first_subject the first subject of the diff.
2849 ///
2850 /// @param second_subject the second subject of the diff.
2851 ///
2852 /// @param ctxt the context of the diff. This object must stay alive
2853 /// at least during the life time of the current instance of @ref
2854 /// decl_diff_base, otherwise, memory corruption issues occur.
2855 decl_diff_base::decl_diff_base(decl_base_sptr first_subject,
2856  decl_base_sptr second_subject,
2857  diff_context_sptr ctxt)
2858  : diff(first_subject, second_subject, ctxt),
2859  priv_(new priv)
2860 {}
2861 
2862 decl_diff_base::~decl_diff_base()
2863 {}
2864 
2865 // </decl_diff_base stuff>
2866 
2867 // <distinct_diff stuff>
2868 
2869 /// @return a pretty representation for the @ref distinct_diff node.
2870 const string&
2872 {
2873  if (diff::priv_->pretty_representation_.empty())
2874  {
2875  std::ostringstream o;
2876  o << "distinct_diff[";
2877  if (first_subject())
2878  o << first_subject()->get_pretty_representation();
2879  else
2880  o << "null";
2881  o << ", ";
2882  if (second_subject())
2883  o << second_subject()->get_pretty_representation() ;
2884  else
2885  o << "null";
2886  o << "]" ;
2887  diff::priv_->pretty_representation_ = o.str();
2888  }
2889  return diff::priv_->pretty_representation_;
2890 }
2891 
2892 /// Populate the vector of children node of the @ref diff base type
2893 /// sub-object of this instance of @distinct_diff.
2894 ///
2895 /// The children nodes can then later be retrieved using
2896 /// diff::children_nodes().
2897 void
2899 {
2901 
2902  if (diff_sptr d = compatible_child_diff())
2903  append_child_node(d);
2904 }
2905 
2906 /// Constructor for @ref distinct_diff.
2907 ///
2908 /// Note that the two entities considered for the diff (and passed in
2909 /// parameter) must be of different kinds.
2910 ///
2911 /// @param first the first entity to consider for the diff.
2912 ///
2913 /// @param second the second entity to consider for the diff.
2914 ///
2915 /// @param ctxt the context of the diff. Note that this context
2916 /// object must stay alive at least during the life time of the
2917 /// current instance of @ref distinct_diff. Otherwise memory
2918 /// corruption issues occur.
2920  type_or_decl_base_sptr second,
2921  diff_context_sptr ctxt)
2922  : diff(first, second, ctxt),
2923  priv_(new priv)
2924 {ABG_ASSERT(entities_are_of_distinct_kinds(first, second));}
2925 
2926 /// Getter for the first subject of the diff.
2927 ///
2928 /// @return the first subject of the diff.
2931 {return first_subject();}
2932 
2933 /// Getter for the second subject of the diff.
2934 ///
2935 /// @return the second subject of the diff.
2938 {return second_subject();}
2939 
2940 /// Getter for the child diff of this distinct_diff instance.
2941 ///
2942 /// When a distinct_diff has two subjects that are different but
2943 /// compatible, then the distinct_diff instance has a child diff node
2944 /// (named the compatible child diff) that is the diff between the two
2945 /// subjects stripped from their typedefs. Otherwise, the compatible
2946 /// child diff is nul.
2947 ///
2948 /// Note that two diff subjects (that compare different) are
2949 /// considered compatible if stripping typedefs out of them makes them
2950 /// comparing equal.
2951 ///
2952 /// @return the compatible child diff node, if any. Otherwise, null.
2953 const diff_sptr
2955 {
2956  if (!priv_->compatible_child_diff)
2957  {
2960  {
2961  type_base_sptr fs = peel_qualified_or_typedef_type(is_type(first())),
2963 
2964  priv_->compatible_child_diff =
2967  context());
2968  }
2969  }
2970  return priv_->compatible_child_diff;
2971 }
2972 
2973 /// Test if the two arguments are of different kind, or that are both
2974 /// NULL.
2975 ///
2976 /// @param first the first argument to test for similarity in kind.
2977 ///
2978 /// @param second the second argument to test for similarity in kind.
2979 ///
2980 /// @return true iff the two arguments are of different kind.
2981 bool
2983  type_or_decl_base_sptr second)
2984 {
2985  if (!!first != !!second)
2986  return true;
2987  if (!first && !second)
2988  // We do consider diffs of two empty decls as a diff of distinct
2989  // kinds, for now.
2990  return true;
2991  if (first == second)
2992  return false;
2993 
2994  const type_or_decl_base &f = *first, &s = *second;
2995  return typeid(f) != typeid(s);
2996 }
2997 
2998 /// @return true if the two subjects of the diff are different, false
2999 /// otherwise.
3000 bool
3002 {return first() != second();}
3003 
3004 /// @return the kind of local change carried by the current diff node.
3005 /// The value returned is zero if the current node carries no local
3006 /// change.
3007 enum change_kind
3009 {
3010  // Changes on a distinct_diff are all local.
3011  if (has_changes())
3012  return LOCAL_TYPE_CHANGE_KIND;
3013  return NO_CHANGE_KIND;
3014 }
3015 
3016 /// Emit a report about the current diff instance.
3017 ///
3018 /// @param out the output stream to send the diff report to.
3019 ///
3020 /// @param indent the indentation string to use in the report.
3021 void
3022 distinct_diff::report(ostream& out, const string& indent) const
3023 {
3024  context()->get_reporter()->report(*this, out, indent);
3025 }
3026 
3027 /// Try to diff entities that are of distinct kinds.
3028 ///
3029 /// @param first the first entity to consider for the diff.
3030 ///
3031 /// @param second the second entity to consider for the diff.
3032 ///
3033 /// @param ctxt the context of the diff.
3034 ///
3035 /// @return a non-null diff if a diff object could be built, null
3036 /// otherwise.
3039  const type_or_decl_base_sptr second,
3040  diff_context_sptr ctxt)
3041 {
3043  return distinct_diff_sptr();
3044 
3045  distinct_diff_sptr result(new distinct_diff(first, second, ctxt));
3046 
3047  ctxt->initialize_canonical_diff(result);
3048 
3049  return result;
3050 }
3051 
3052 /// </distinct_diff stuff>
3053 
3054 /// Try to compute a diff on two instances of DiffType representation.
3055 ///
3056 /// The function template performs the diff if and only if the decl
3057 /// representations are of a DiffType.
3058 ///
3059 /// @tparm DiffType the type of instances to diff.
3060 ///
3061 /// @param first the first representation of decl to consider in the
3062 /// diff computation.
3063 ///
3064 /// @param second the second representation of decl to consider in the
3065 /// diff computation.
3066 ///
3067 /// @param ctxt the diff context to use.
3068 ///
3069 ///@return the diff of the two types @p first and @p second if and
3070 ///only if they represent the parametrized type DiffType. Otherwise,
3071 ///returns a NULL pointer value.
3072 template<typename DiffType>
3073 diff_sptr
3075  const type_or_decl_base_sptr second,
3076  diff_context_sptr ctxt)
3077 {
3078  if (shared_ptr<DiffType> f =
3079  dynamic_pointer_cast<DiffType>(first))
3080  {
3081  shared_ptr<DiffType> s =
3082  dynamic_pointer_cast<DiffType>(second);
3083  if (!s)
3084  return diff_sptr();
3085  return compute_diff(f, s, ctxt);
3086  }
3087  return diff_sptr();
3088 }
3089 
3090 
3091 /// This is a specialization of @ref try_to_diff() template to diff
3092 /// instances of @ref class_decl.
3093 ///
3094 /// @param first the first representation of decl to consider in the
3095 /// diff computation.
3096 ///
3097 /// @param second the second representation of decl to consider in the
3098 /// diff computation.
3099 ///
3100 /// @param ctxt the diff context to use.
3101 template<>
3102 diff_sptr
3104  const type_or_decl_base_sptr second,
3105  diff_context_sptr ctxt)
3106 {
3107  if (class_decl_sptr f =
3108  dynamic_pointer_cast<class_decl>(first))
3109  {
3110  class_decl_sptr s = dynamic_pointer_cast<class_decl>(second);
3111  if (!s)
3112  return diff_sptr();
3113 
3114  if (f->get_is_declaration_only())
3115  {
3116  class_decl_sptr f2 =
3117  is_class_type (f->get_definition_of_declaration());
3118  if (f2)
3119  f = f2;
3120  }
3121  if (s->get_is_declaration_only())
3122  {
3123  class_decl_sptr s2 =
3124  is_class_type(s->get_definition_of_declaration());
3125  if (s2)
3126  s = s2;
3127  }
3128  return compute_diff(f, s, ctxt);
3129  }
3130  return diff_sptr();
3131 }
3132 
3133 /// Try to diff entities that are of distinct kinds.
3134 ///
3135 /// @param first the first entity to consider for the diff.
3136 ///
3137 /// @param second the second entity to consider for the diff.
3138 ///
3139 /// @param ctxt the context of the diff.
3140 ///
3141 /// @return a non-null diff if a diff object could be built, null
3142 /// otherwise.
3143 static diff_sptr
3144 try_to_diff_distinct_kinds(const type_or_decl_base_sptr first,
3145  const type_or_decl_base_sptr second,
3146  diff_context_sptr ctxt)
3147 {return compute_diff_for_distinct_kinds(first, second, ctxt);}
3148 
3149 /// Compute the difference between two types.
3150 ///
3151 /// The function considers every possible types known to libabigail
3152 /// and runs the appropriate diff function on them.
3153 ///
3154 /// Whenever a new kind of type decl is supported by abigail, if we
3155 /// want to be able to diff two instances of it, we need to update
3156 /// this function to support it.
3157 ///
3158 /// @param first the first type decl to consider for the diff
3159 ///
3160 /// @param second the second type decl to consider for the diff.
3161 ///
3162 /// @param ctxt the diff context to use.
3163 ///
3164 /// @return the resulting diff. It's a pointer to a descendent of
3165 /// abigail::comparison::diff.
3166 static diff_sptr
3167 compute_diff_for_types(const type_or_decl_base_sptr& first,
3168  const type_or_decl_base_sptr& second,
3169  const diff_context_sptr& ctxt)
3170 {
3171  type_or_decl_base_sptr f = first;
3172  type_or_decl_base_sptr s = second;
3173 
3174  diff_sptr d;
3175 
3176  ((d = try_to_diff<type_decl>(f, s, ctxt))
3177  ||(d = try_to_diff<enum_type_decl>(f, s, ctxt))
3178  ||(d = try_to_diff<union_decl>(f, s,ctxt))
3179  ||(d = try_to_diff<class_decl>(f, s,ctxt))
3180  ||(d = try_to_diff<pointer_type_def>(f, s, ctxt))
3181  ||(d = try_to_diff<reference_type_def>(f, s, ctxt))
3182  ||(d = try_to_diff<ptr_to_mbr_type>(f, s, ctxt))
3183  ||(d = try_to_diff<array_type_def::subrange_type>(f, s, ctxt))
3184  ||(d = try_to_diff<array_type_def>(f, s, ctxt))
3185  ||(d = try_to_diff<qualified_type_def>(f, s, ctxt))
3186  ||(d = try_to_diff<typedef_decl>(f, s, ctxt))
3187  ||(d = try_to_diff<function_type>(f, s, ctxt))
3188  ||(d = try_to_diff_distinct_kinds(f, s, ctxt)));
3189 
3190  ABG_ASSERT(d);
3191 
3192  return d;
3193 }
3194 
3197 {return static_cast<diff_category>(static_cast<unsigned>(c1)
3198  | static_cast<unsigned>(c2));}
3199 
3201 operator|=(diff_category& c1, diff_category c2)
3202 {
3203  c1 = c1 | c2;
3204  return c1;
3205 }
3206 
3208 operator&=(diff_category& c1, diff_category c2)
3209 {
3210  c1 = c1 & c2;
3211  return c1;
3212 }
3213 
3215 operator^(diff_category c1, diff_category c2)
3216 {return static_cast<diff_category>(static_cast<unsigned>(c1)
3217  ^ static_cast<unsigned>(c2));}
3218 
3221 {return static_cast<diff_category>(static_cast<unsigned>(c1)
3222  & static_cast<unsigned>(c2));}
3223 
3226 {return static_cast<diff_category>(~static_cast<unsigned>(c));}
3227 
3228 
3229 /// Getter of a bitmap made of the set of change categories that are
3230 /// considered harmless.
3231 ///
3232 /// @return the bitmap made of the set of change categories that are
3233 /// considered harmless.
3236 {
3253 }
3254 
3255 /// Getter of a bitmap made of the set of change categories that are
3256 /// considered harmful.
3257 ///
3258 /// @return the bitmap made of the set of change categories that are
3259 /// considered harmful.
3262 {
3265  | abigail::comparison::REFERENCE_LVALUENESS_CHANGE_CATEGORY
3269 }
3270 
3271 /// Test if an instance of @ref diff_category (a category bit-field)
3272 /// is harmful or not.
3273 ///
3274 /// A harmful change is a change that is not harmless. OK, that
3275 /// smells bit like a tasteless tautology, but bear with me please.
3276 ///
3277 /// A harmless change is a change that should be filtered out by
3278 /// default to avoid unnecessarily cluttering the change report.
3279 ///
3280 /// A harmful change is thus a change that SHOULD NOT be filtered out
3281 /// by default because it CAN represent an incompatible ABI change.
3282 ///
3283 /// An incompatbile ABI change is a harmful change that makes the new
3284 /// ABI incompatible with the previous one.
3285 ///
3286 /// @param c the instance of @ref diff_category to consider. It is a
3287 /// bit-field of the categories of a given diff node.
3288 ///
3289 /// @return true
3290 bool
3292 {
3294  return c & dc;
3295 }
3296 
3297 /// Serialize an instance of @ref diff_category to an output stream.
3298 ///
3299 /// @param o the output stream to serialize @p c to.
3300 ///
3301 /// @param c the instance of diff_category to serialize.
3302 ///
3303 /// @return the output stream to serialize @p c to.
3304 ostream&
3306 {
3307  bool emitted_a_category = false;
3308 
3309  if (c == NO_CHANGE_CATEGORY)
3310  {
3311  o << "NO_CHANGE_CATEGORY";
3312  emitted_a_category = true;
3313  }
3314 
3315  if (c & ACCESS_CHANGE_CATEGORY)
3316  {
3317  if (emitted_a_category)
3318  o << "|";
3319  o << "ACCESS_CHANGE_CATEGORY";
3320  emitted_a_category |= true;
3321  }
3322 
3324  {
3325  if (emitted_a_category)
3326  o << "|";
3327  o << "COMPATIBLE_TYPE_CHANGE_CATEGORY";
3328  emitted_a_category |= true;
3329  }
3330 
3332  {
3333  if (emitted_a_category)
3334  o << "|";
3335  o << "HARMLESS_DECL_NAME_CHANGE_CATEGORY";
3336  emitted_a_category |= true;
3337  }
3338 
3340  {
3341  if (emitted_a_category)
3342  o << "|";
3343  o << "NON_VIRT_MEM_FUN_CHANGE_CATEGORY";
3344  emitted_a_category |= true;
3345  }
3346 
3348  {
3349  if (emitted_a_category)
3350  o << "|";
3351  o << "STATIC_DATA_MEMBER_CHANGE_CATEGORY";
3352  emitted_a_category |= true;
3353  }
3354 
3356  {
3357  if (emitted_a_category)
3358  o << "|";
3359  o << "HARMLESS_ENUM_CHANGE_CATEGORY";
3360  emitted_a_category |= true;
3361  }
3362 
3364  {
3365  if (emitted_a_category)
3366  o << "|";
3367  o << "HARMLESS_DATA_MEMBER_CHANGE_CATEGORY";
3368  emitted_a_category |= true;
3369  }
3370 
3372  {
3373  if (emitted_a_category)
3374  o << "|";
3375  o << "HARMLESS_SYMBOL_ALIAS_CHANGE_CATEGORY";
3376  emitted_a_category |= true;
3377  }
3378 
3380  {
3381  if (emitted_a_category)
3382  o << "|";
3383  o << "HARMLESS_UNION_OR_CLASS_CHANGE_CATEGORY";
3384  emitted_a_category |= true;
3385  }
3386 
3387  if (c & SUPPRESSED_CATEGORY)
3388  {
3389  if (emitted_a_category)
3390  o << "|";
3391  o << "SUPPRESSED_CATEGORY";
3392  emitted_a_category |= true;
3393  }
3394 
3395  if (c & PRIVATE_TYPE_CATEGORY)
3396  {
3397  if (emitted_a_category)
3398  o << "|";
3399  o << "PRIVATE_TYPE_CATEGORY";
3400  emitted_a_category |= true;
3401  }
3402 
3404  {
3405  if (emitted_a_category)
3406  o << "|";
3407  o << "SIZE_OR_OFFSET_CHANGE_CATEGORY";
3408  emitted_a_category |= true;
3409  }
3410 
3412  {
3413  if (emitted_a_category)
3414  o << "|";
3415  o << "VIRTUAL_MEMBER_CHANGE_CATEGORY";
3416  emitted_a_category |= true;
3417  }
3418 
3419  if (c & REFERENCE_LVALUENESS_CHANGE_CATEGORY)
3420  {
3421  if (emitted_a_category)
3422  o << "|";
3423  o << "REFERENCE_LVALUENESS_CHANGE_CATEGORY";
3424  emitted_a_category |= true;
3425  }
3426 
3428  {
3429  if (emitted_a_category)
3430  o << "|";
3431  o << "NON_COMPATIBLE_DISTINCT_CHANGE_CATEGORY";
3432  emitted_a_category |= true;
3433  }
3434 
3436  {
3437  if (emitted_a_category)
3438  o << "|";
3439  o << "NON_COMPATIBLE_NAME_CHANGE_CATEGORY";
3440  emitted_a_category |= true;
3441  }
3442 
3443  if (c & REDUNDANT_CATEGORY)
3444  {
3445  if (emitted_a_category)
3446  o << "|";
3447  o << "REDUNDANT_CATEGORY";
3448  emitted_a_category |= true;
3449  }
3450 
3452  {
3453  if (emitted_a_category)
3454  o << "|";
3455  o << "TYPE_DECL_ONLY_DEF_CHANGE_CATEGORY";
3456  emitted_a_category |= true;
3457  }
3458 
3460  {
3461  if (emitted_a_category)
3462  o << "|";
3463  o << "FN_PARM_TYPE_TOP_CV_CHANGE_CATEGORY";
3464  emitted_a_category |= true;
3465  }
3466 
3468  {
3469  if (emitted_a_category)
3470  o << "|";
3471  o << "FN_PARM_TYPE_CV_CHANGE_CATEGORY";
3472  emitted_a_category |= true;
3473  }
3474 
3476  {
3477  if (emitted_a_category)
3478  o << "|";
3479  o << "FN_RETURN_TYPE_CV_CHANGE_CATEGORY";
3480  emitted_a_category |= true;
3481  }
3482 
3484  {
3485  if (emitted_a_category)
3486  o << "|";
3487  o << "FN_PARM_ADD_REMOVE_CHANGE_CATEGORY";
3488  emitted_a_category |= true;
3489  }
3490 
3492  {
3493  if (emitted_a_category)
3494  o << "|";
3495  o << "VAR_TYPE_CV_CHANGE_CATEGORY";
3496  emitted_a_category |= true;
3497  }
3498 
3500  {
3501  if (emitted_a_category)
3502  o << "|";
3503  o << "VOID_PTR_TO_PTR_CHANGE_CATEGORY";
3504  emitted_a_category |= true;
3505  }
3506 
3508  {
3509  if (emitted_a_category)
3510  o << "|";
3511  o << "BENIGN_INFINITE_ARRAY_CHANGE_CATEGORY";
3512  emitted_a_category |= true;
3513  }
3514 
3516  {
3517  if (emitted_a_category)
3518  o << "|";
3519  o << "HAS_ALLOWED_CHANGE_CATEGORY";
3520  emitted_a_category |= true;
3521  }
3522 
3524  {
3525  if (emitted_a_category)
3526  o << "|";
3527  o << "HAS_DESCENDANT_WITH_ALLOWED_CHANGE_CATEGORY";
3528  emitted_a_category |= true;
3529  }
3530 
3532  {
3533  if (emitted_a_category)
3534  o << "|";
3535  o << "HAS_PARENT_WITH_ALLOWED_CHANGE_CATEGORY";
3536  emitted_a_category |= true;
3537  }
3538 
3539  return o;
3540 }
3541 
3542 /// Compute the difference between two decls.
3543 ///
3544 /// The function consider every possible decls known to libabigail and
3545 /// runs the appropriate diff function on them.
3546 ///
3547 /// Whenever a new kind of non-type decl is supported by abigail, if
3548 /// we want to be able to diff two instances of it, we need to update
3549 /// this function to support it.
3550 ///
3551 /// @param first the first decl to consider for the diff
3552 ///
3553 /// @param second the second decl to consider for the diff.
3554 ///
3555 /// @param ctxt the diff context to use.
3556 ///
3557 /// @return the resulting diff.
3558 static diff_sptr
3559 compute_diff_for_decls(const decl_base_sptr first,
3560  const decl_base_sptr second,
3561  diff_context_sptr ctxt)
3562 {
3563 
3564  diff_sptr d;
3565 
3566  ((d = try_to_diff<function_decl>(first, second, ctxt))
3567  || (d = try_to_diff<var_decl>(first, second, ctxt))
3568  || (d = try_to_diff_distinct_kinds(first, second, ctxt)));
3569 
3570  ABG_ASSERT(d);
3571 
3572  return d;
3573 }
3574 
3575 /// Compute the difference between two decls. The decls can represent
3576 /// either type declarations, or non-type declaration.
3577 ///
3578 /// Note that the two decls must have been created in the same @ref
3579 /// environment, otherwise, this function aborts.
3580 ///
3581 /// @param first the first decl to consider.
3582 ///
3583 /// @param second the second decl to consider.
3584 ///
3585 /// @param ctxt the diff context to use.
3586 ///
3587 /// @return the resulting diff, or NULL if the diff could not be
3588 /// computed.
3589 diff_sptr
3590 compute_diff(const decl_base_sptr first,
3591  const decl_base_sptr second,
3592  diff_context_sptr ctxt)
3593 {
3594  if (!first || !second)
3595  return diff_sptr();
3596 
3597  diff_sptr d;
3598  if (is_type(first) && is_type(second))
3599  d = compute_diff_for_types(first, second, ctxt);
3600  else
3601  d = compute_diff_for_decls(first, second, ctxt);
3602  ABG_ASSERT(d);
3603  return d;
3604 }
3605 
3606 /// Compute the difference between two types.
3607 ///
3608 /// Note that the two types must have been created in the same @ref
3609 /// environment, otherwise, this function aborts.
3610 ///
3611 /// @param first the first type to consider.
3612 ///
3613 /// @param second the second type to consider.
3614 ///
3615 /// @param ctxt the diff context to use.
3616 ///
3617 /// @return the resulting diff, or NULL if the diff couldn't be
3618 /// computed.
3619 diff_sptr
3620 compute_diff(const type_base_sptr first,
3621  const type_base_sptr second,
3622  diff_context_sptr ctxt)
3623 {
3624  decl_base_sptr f = get_type_declaration(first),
3625  s = get_type_declaration(second);
3626 
3627  diff_sptr d = compute_diff_for_types(f,s, ctxt);
3628  ABG_ASSERT(d);
3629  return d;
3630 }
3631 
3632 /// Get a copy of the pretty representation of a diff node.
3633 ///
3634 /// @param d the diff node to consider.
3635 ///
3636 /// @return the pretty representation string.
3637 string
3639 {
3640  if (!d)
3641  return "";
3642  string prefix= "diff of ";
3643  return prefix + get_pretty_representation(d->first_subject());
3644 }
3645 
3646 // <var_diff stuff>
3647 
3648 /// Populate the vector of children node of the @ref diff base type
3649 /// sub-object of this instance of @ref var_diff.
3650 ///
3651 /// The children node can then later be retrieved using
3652 /// diff::children_node().
3653 void
3656 
3657 /// @return the pretty representation for this current instance of
3658 /// @ref var_diff.
3659 const string&
3661 {
3662  if (diff::priv_->pretty_representation_.empty())
3663  {
3664  std::ostringstream o;
3665  o << "var_diff["
3666  << first_subject()->get_pretty_representation()
3667  << ", "
3668  << second_subject()->get_pretty_representation()
3669  << "]";
3670  diff::priv_->pretty_representation_ = o.str();
3671  }
3672  return diff::priv_->pretty_representation_;
3673 }
3674 /// Constructor for @ref var_diff.
3675 ///
3676 /// @param first the first instance of @ref var_decl to consider in
3677 /// the diff.
3678 ///
3679 /// @param second the second instance of @ref var_decl to consider in
3680 /// the diff.
3681 ///
3682 /// @param type_diff the diff between types of the instances of
3683 /// var_decl.
3684 ///
3685 /// @param ctxt the diff context to use.
3687  var_decl_sptr second,
3688  diff_sptr type_diff,
3689  diff_context_sptr ctxt)
3690  : decl_diff_base(first, second, ctxt),
3691  priv_(new priv)
3692 {priv_->type_diff_ = type_diff;}
3693 
3694 /// Getter for the first @ref var_decl of the diff.
3695 ///
3696 /// @return the first @ref var_decl of the diff.
3699 {return dynamic_pointer_cast<var_decl>(first_subject());}
3700 
3701 /// Getter for the second @ref var_decl of the diff.
3702 ///
3703 /// @return the second @ref var_decl of the diff.
3706 {return dynamic_pointer_cast<var_decl>(second_subject());}
3707 
3708 /// Getter for the diff of the types of the instances of @ref
3709 /// var_decl.
3710 ///
3711 /// @return the diff of the types of the instances of @ref var_decl.
3712 diff_sptr
3714 {
3715  if (diff_sptr result = priv_->type_diff_.lock())
3716  return result;
3717  else
3718  {
3719  result = compute_diff(first_var()->get_type(),
3720  second_var()->get_type(),
3721  context());
3722  context()->keep_diff_alive(result);
3723  priv_->type_diff_ = result;
3724  return result;
3725  }
3726 }
3727 
3728 /// Return true iff the diff node has a change.
3729 ///
3730 /// @return true iff the diff node has a change.
3731 bool
3733 {return *first_var() != *second_var();}
3734 
3735 /// @return the kind of local change carried by the current diff node.
3736 /// The value returned is zero if the current node carries no local
3737 /// change.
3738 enum change_kind
3740 {
3741  ir::change_kind k = ir::NO_CHANGE_KIND;
3742  if (!equals(*first_var(), *second_var(), &k))
3743  return k & ir::ALL_LOCAL_CHANGES_MASK;
3744  return ir::NO_CHANGE_KIND;
3745 }
3746 
3747 /// Report the diff in a serialized form.
3748 ///
3749 /// @param out the stream to serialize the diff to.
3750 ///
3751 /// @param indent the prefix to use for the indentation of this
3752 /// serialization.
3753 void
3754 var_diff::report(ostream& out, const string& indent) const
3755 {
3756  context()->get_reporter()->report(*this, out, indent);
3757 }
3758 
3759 /// Compute the diff between two instances of @ref var_decl.
3760 ///
3761 /// Note that the two decls must have been created in the same @ref
3762 /// environment, otherwise, this function aborts.
3763 ///
3764 /// @param first the first @ref var_decl to consider for the diff.
3765 ///
3766 /// @param second the second @ref var_decl to consider for the diff.
3767 ///
3768 /// @param ctxt the diff context to use.
3769 ///
3770 /// @return the resulting diff between the two @ref var_decl.
3773  const var_decl_sptr second,
3774  diff_context_sptr ctxt)
3775 {
3776  var_diff_sptr d(new var_diff(first, second, diff_sptr(), ctxt));
3777  ctxt->initialize_canonical_diff(d);
3778 
3779  return d;
3780 }
3781 
3782 // </var_diff stuff>
3783 
3784 // <pointer_type_def stuff>
3785 
3786 /// Populate the vector of children node of the @ref diff base type
3787 /// sub-object of this instance of @ref pointer_diff.
3788 ///
3789 /// The children node can then later be retrieved using
3790 /// diff::children_node().
3791 void
3794 
3795 /// Constructor for a pointer_diff.
3796 ///
3797 /// @param first the first pointer to consider for the diff.
3798 ///
3799 /// @param second the secon pointer to consider for the diff.
3800 ///
3801 /// @param ctxt the diff context to use.
3803  pointer_type_def_sptr second,
3804  diff_sptr underlying,
3805  diff_context_sptr ctxt)
3806  : type_diff_base(first, second, ctxt),
3807  priv_(new priv(underlying))
3808 {}
3809 
3810 /// Getter for the first subject of a pointer diff
3811 ///
3812 /// @return the first pointer considered in this pointer diff.
3815 {return dynamic_pointer_cast<pointer_type_def>(first_subject());}
3816 
3817 /// Getter for the second subject of a pointer diff
3818 ///
3819 /// @return the second pointer considered in this pointer diff.
3822 {return dynamic_pointer_cast<pointer_type_def>(second_subject());}
3823 
3824 /// @return the pretty represenation for the current instance of @ref
3825 /// pointer_diff.
3826 const string&
3828 {
3829  if (diff::priv_->pretty_representation_.empty())
3830  {
3831  std::ostringstream o;
3832  o << "pointer_diff["
3833  << first_subject()->get_pretty_representation()
3834  << ", "
3835  << second_subject()->get_pretty_representation()
3836  << "]";
3837  diff::priv_->pretty_representation_ = o.str();
3838  }
3839  return diff::priv_->pretty_representation_;
3840 }
3841 
3842 /// Return true iff the current diff node carries a change.
3843 ///
3844 /// @return true iff the current diff node carries a change.
3845 bool
3847 {return first_pointer() != second_pointer();}
3848 
3849 /// @return the kind of local change carried by the current diff node.
3850 /// The value returned is zero if the current node carries no local
3851 /// change.
3852 enum change_kind
3854 {
3855  ir::change_kind k = ir::NO_CHANGE_KIND;
3856  if (!equals(*first_pointer(), *second_pointer(), &k))
3857  return k & ir::ALL_LOCAL_CHANGES_MASK;
3858  return ir::NO_CHANGE_KIND;
3859 }
3860 
3861 /// Getter for the diff between the pointed-to types of the pointers
3862 /// of this diff.
3863 ///
3864 /// @return the diff between the pointed-to types.
3865 diff_sptr
3867 {return priv_->underlying_type_diff_;}
3868 
3869 /// Setter for the diff between the pointed-to types of the pointers
3870 /// of this diff.
3871 ///
3872 /// @param d the new diff between the pointed-to types of the pointers
3873 /// of this diff.
3874 void
3876 {priv_->underlying_type_diff_ = d;}
3877 
3878 /// Report the diff in a serialized form.
3879 ///
3880 /// @param out the stream to serialize the diff to.
3881 ///
3882 /// @param indent the prefix to use for the indentation of this
3883 /// serialization.
3884 void
3885 pointer_diff::report(ostream& out, const string& indent) const
3886 {
3887  context()->get_reporter()->report(*this, out, indent);
3888 }
3889 
3890 /// Compute the diff between between two pointers.
3891 ///
3892 /// Note that the two types must have been created in the same @ref
3893 /// environment, otherwise, this function aborts.
3894 ///
3895 /// @param first the pointer to consider for the diff.
3896 ///
3897 /// @param second the pointer to consider for the diff.
3898 ///
3899 /// @return the resulting diff between the two pointers.
3900 ///
3901 /// @param ctxt the diff context to use.
3904  pointer_type_def_sptr second,
3905  diff_context_sptr ctxt)
3906 {
3907  diff_sptr d = compute_diff_for_types(first->get_pointed_to_type(),
3908  second->get_pointed_to_type(),
3909  ctxt);
3910  pointer_diff_sptr result(new pointer_diff(first, second, d, ctxt));
3911  ctxt->initialize_canonical_diff(result);
3912 
3913  return result;
3914 }
3915 
3916 // </pointer_type_def>
3917 
3918 // <subrange_diff >
3919 
3920 /// Constructor of the @ref subrange_diff diff node type.
3921 ///
3922 /// @param first the first subrange type to consider for the diff.
3923 ///
3924 /// @param second the second subrange type to consider for the diff.
3925 ///
3926 /// @param underlying_type_diff the underlying type diff between @p
3927 /// first and @p second.
3928 ///
3929 /// @param ctxt the diff context to use.
3932  const array_type_def::subrange_sptr& second,
3933  const diff_sptr& underlying_type_diff,
3934  const diff_context_sptr ctxt)
3935  : type_diff_base(first, second, ctxt),
3936  priv_(new priv(underlying_type_diff))
3937 {}
3938 
3939 
3940 /// Getter of the first subrange of the current instance @ref
3941 /// subrange_diff.
3942 ///
3943 /// @return The first subrange of the current instance @ref subrange_diff.
3946 {return is_subrange_type(first_subject());}
3947 
3948 /// Getter of the second subrange of the current instance @ref
3949 /// subrange_diff.
3950 ///
3951 /// @return The second subrange of the current instance @ref
3952 /// subrange_diff.
3955 {return is_subrange_type(second_subject());}
3956 
3957 /// Getter of the diff node of the underlying types of the current
3958 /// @ref subrange_diff diff node.
3959 ///
3960 /// @return The diff node of the underlying types of the current @ref
3961 /// subrange_diff diff node.
3962 const diff_sptr
3964 {return priv_->underlying_type_diff_;}
3965 
3966 /// Getter the pretty representation of the @ref subrange_diff diff
3967 /// node.
3968 ///
3969 /// @return The pretty representation of the @ref subrange_diff diff node.
3970 const string&
3972 {
3973  if (diff::priv_->pretty_representation_.empty())
3974  {
3975  std::ostringstream o;
3976  o << "subrange_diff["
3977  << first_subject()->get_pretty_representation()
3978  << ","
3979  << second_subject()->get_pretty_representation()
3980  << "]";
3981  diff::priv_->pretty_representation_ = o.str();
3982  }
3983  return diff::priv_->pretty_representation_;
3984 }
3985 
3986 /// Test if the current @ref subrange_diff node carries any change.
3987 ///
3988 /// @return true iff the current @ref subrange_diff node carries any
3989 /// change.
3990 bool
3992 {return *first_subrange() != *second_subrange();}
3993 
3994 /// Test if the current @ref subrange_diff node carries any local
3995 /// change.
3996 ///
3997 /// @return true iff the current @ref subrange_diff node carries any
3998 /// local change.
3999 enum change_kind
4001 {
4002  ir::change_kind k = ir::NO_CHANGE_KIND;
4003  if (!equals(*first_subrange(), *second_subrange(), &k))
4004  return k & ir::ALL_LOCAL_CHANGES_MASK;
4005  return ir::NO_CHANGE_KIND;
4006 }
4007 
4008 /// Report about the changes carried by this node.
4009 ///
4010 /// @param out the output stream to send the report to.
4011 ///
4012 /// @param indent the indentation string to use.
4013 void
4014 subrange_diff::report(ostream& out, const string& indent) const
4015 {context()->get_reporter()->report(*this, out, indent);}
4016 
4017 /// Populate the vector of children node of the @ref diff base type
4018 /// sub-object of this instance of @ref subrange_diff.
4019 ///
4020 /// The children node can then later be retrieved using
4021 /// diff::children_node().
4022 void
4025 
4026 /// Compute the diff between two instances of @ref subrange_diff.
4027 ///
4028 /// Note that the two decls must have been created in the same @ref
4029 /// environment, otherwise, this function aborts.
4030 ///
4031 /// @param first the first @ref subrange_diff to consider for the diff.
4032 ///
4033 /// @param second the second @ref subrange_diff to consider for the diff.
4034 ///
4035 /// @param ctxt the diff context to use.
4036 ///
4037 /// @return the resulting diff between the two @ref subrange_diff.
4041  diff_context_sptr ctxt)
4042 {
4043  diff_sptr d = compute_diff_for_types(first->get_underlying_type(),
4044  second->get_underlying_type(),
4045  ctxt);
4046 
4047  subrange_diff_sptr result(new subrange_diff(first, second, d, ctxt));
4048  ctxt->initialize_canonical_diff(result);
4049  return result;
4050 }
4051 
4052 //</subrange_diff >
4053 
4054 
4055 // <array_type_def>
4056 
4057 /// Populate the vector of children node of the @ref diff base type
4058 /// sub-object of this instance of @ref array_diff.
4059 ///
4060 /// The children node can then later be retrieved using
4061 /// diff::children_node().
4062 void
4064 {
4066  for (const auto& subrange_diff : subrange_diffs())
4068 }
4069 
4070 /// Constructor for array_diff
4071 ///
4072 /// @param first the first array_type of the diff.
4073 ///
4074 /// @param second the second array_type of the diff.
4075 ///
4076 /// @param element_type_diff the diff between the two array element
4077 /// types.
4078 ///
4079 /// @param ctxt the diff context to use.
4081  const array_type_def_sptr second,
4082  diff_sptr element_type_diff,
4083  vector<subrange_diff_sptr>& subrange_diffs,
4084  diff_context_sptr ctxt)
4085  : type_diff_base(first, second, ctxt),
4086  priv_(new priv(element_type_diff, subrange_diffs))
4087 {}
4088 
4089 /// Getter for the first array of the diff.
4090 ///
4091 /// @return the first array of the diff.
4092 const array_type_def_sptr
4094 {return dynamic_pointer_cast<array_type_def>(first_subject());}
4095 
4096 /// Getter for the second array of the diff.
4097 ///
4098 /// @return for the second array of the diff.
4099 const array_type_def_sptr
4101 {return dynamic_pointer_cast<array_type_def>(second_subject());}
4102 
4103 /// Getter for the diff between the two types of array elements.
4104 ///
4105 /// @return the diff between the two types of array elements.
4106 const diff_sptr&
4108 {return priv_->element_type_diff_;}
4109 
4110 /// Getter for the diffs between the array subranges.
4111 ///
4112 /// @return the diffs between the array subranges.
4113 const vector<subrange_diff_sptr>&
4115 {return priv_->subrange_diffs_;}
4116 
4117 /// Test if any subrange diff is to be reported.
4118 ///
4119 /// @return true if any subrange diff is to be reported, false
4120 /// otherwise.
4121 bool
4123 {
4124  for (const auto& diff: subrange_diffs())
4125  if (diff->to_be_reported())
4126  return true;
4127 
4128  return false;
4129 }
4130 
4131 /// Setter for the diff between the two array element types.
4132 ///
4133 /// @param d the new diff between the two array element types.
4134 void
4136 {priv_->element_type_diff_ = d;}
4137 
4138 /// Setter for the diff between the two sets of array sub-ranges.
4139 ///
4140 /// @param d the new diff between the two sets of array sub-ranges.
4141 void
4142 array_diff::subrange_diffs(const vector<subrange_diff_sptr>& d)
4143 {priv_->subrange_diffs_ = d;}
4144 
4145 /// @return the pretty representation for the current instance of @ref
4146 /// array_diff.
4147 const string&
4149 {
4150  if (diff::priv_->pretty_representation_.empty())
4151  {
4152  std::ostringstream o;
4153  o << "array_diff["
4154  << first_subject()->get_pretty_representation()
4155  << ", "
4156  << second_subject()->get_pretty_representation()
4157  << "]";
4158  diff::priv_->pretty_representation_ = o.str();
4159  }
4160  return diff::priv_->pretty_representation_;
4161 }
4162 
4163 /// Return true iff the current diff node carries a change.
4164 ///
4165 /// @return true iff the current diff node carries a change.
4166 bool
4168 {
4169  bool l = false;
4170 
4171  // the array element types match check for differing dimensions
4172  // etc...
4174  f = dynamic_pointer_cast<array_type_def>(first_subject()),
4175  s = dynamic_pointer_cast<array_type_def>(second_subject());
4176 
4177  if (f->get_name() != s->get_name())
4178  l |= true;
4179  if (f->get_size_in_bits() != s->get_size_in_bits())
4180  l |= true;
4181  if (f->get_alignment_in_bits() != s->get_alignment_in_bits())
4182  l |= true;
4183 
4184  l |= element_type_diff()
4185  ? element_type_diff()->has_changes()
4186  : false;
4187 
4188  for (const auto& subrange_diff : subrange_diffs())
4189  l |= subrange_diff->has_changes();
4190 
4191  return l;
4192 }
4193 
4194 
4195 /// @return the kind of local change carried by the current diff node.
4196 /// The value returned is zero if the current node carries no local
4197 /// change.
4198 enum change_kind
4200 {
4201  ir::change_kind k = ir::NO_CHANGE_KIND;
4202  if (!equals(*first_array(), *second_array(), &k))
4203  return k & ir::ALL_LOCAL_CHANGES_MASK;
4204  return ir::NO_CHANGE_KIND;
4205 }
4206 
4207 /// Report the diff in a serialized form.
4208 ///
4209 /// @param out the output stream to serialize the dif to.
4210 ///
4211 /// @param indent the string to use for indenting the report.
4212 void
4213 array_diff::report(ostream& out, const string& indent) const
4214 {
4215  context()->get_reporter()->report(*this, out, indent);
4216 }
4217 
4218 /// Compute the diff between two arrays.
4219 ///
4220 /// Note that the two types must have been created in the same @ref
4221 /// environment, otherwise, this function aborts.
4222 ///
4223 /// @param first the first array to consider for the diff.
4224 ///
4225 /// @param second the second array to consider for the diff.
4226 ///
4227 /// @param ctxt the diff context to use.
4230  array_type_def_sptr second,
4231  diff_context_sptr ctxt)
4232 {
4233  diff_sptr element_diff = compute_diff_for_types(first->get_element_type(),
4234  second->get_element_type(),
4235  ctxt);
4236  vector<subrange_diff_sptr> subrange_diffs;
4237  if (first->get_subranges().size() == first->get_subranges().size())
4238  {
4239  for (unsigned i = 0; i < first->get_subranges().size(); ++i)
4240  {
4242  compute_diff(first->get_subranges()[i],
4243  second->get_subranges()[i],
4244  ctxt);
4245  subrange_diffs.push_back(subrange_diff);
4246  }
4247  }
4248  array_diff_sptr result(new array_diff(first, second,
4249  element_diff,
4250  subrange_diffs,
4251  ctxt));
4252  ctxt->initialize_canonical_diff(result);
4253  return result;
4254 }
4255 // </array_type_def>
4256 
4257 // <reference_type_def>
4258 
4259 /// Populate the vector of children node of the @ref diff base type
4260 /// sub-object of this instance of @ref reference_diff.
4261 ///
4262 /// The children node can then later be retrieved using
4263 /// diff::children_node().
4264 void
4267 
4268 /// Constructor for reference_diff
4269 ///
4270 /// @param first the first reference_type of the diff.
4271 ///
4272 /// @param second the second reference_type of the diff.
4273 ///
4274 /// @param ctxt the diff context to use.
4276  const reference_type_def_sptr second,
4277  diff_sptr underlying,
4278  diff_context_sptr ctxt)
4279  : type_diff_base(first, second, ctxt),
4280  priv_(new priv(underlying))
4281 {}
4282 
4283 /// Getter for the first reference of the diff.
4284 ///
4285 /// @return the first reference of the diff.
4288 {return dynamic_pointer_cast<reference_type_def>(first_subject());}
4289 
4290 /// Getter for the second reference of the diff.
4291 ///
4292 /// @return for the second reference of the diff.
4295 {return dynamic_pointer_cast<reference_type_def>(second_subject());}
4296 
4297 
4298 /// Getter for the diff between the two referred-to types.
4299 ///
4300 /// @return the diff between the two referred-to types.
4301 const diff_sptr&
4303 {return priv_->underlying_type_diff_;}
4304 
4305 /// Setter for the diff between the two referred-to types.
4306 ///
4307 /// @param d the new diff betweend the two referred-to types.
4308 diff_sptr&
4310 {
4311  priv_->underlying_type_diff_ = d;
4312  return priv_->underlying_type_diff_;
4313 }
4314 
4315 /// @return the pretty representation for the current instance of @ref
4316 /// reference_diff.
4317 const string&
4319 {
4320  if (diff::priv_->pretty_representation_.empty())
4321  {
4322  std::ostringstream o;
4323  o << "reference_diff["
4324  << first_subject()->get_pretty_representation()
4325  << ", "
4326  << second_subject()->get_pretty_representation()
4327  << "]";
4328  diff::priv_->pretty_representation_ = o.str();
4329  }
4330  return diff::priv_->pretty_representation_;
4331 }
4332 
4333 /// Return true iff the current diff node carries a change.
4334 ///
4335 /// @return true iff the current diff node carries a change.
4336 bool
4338 {
4339  return first_reference() != second_reference();
4340 }
4341 
4342 /// @return the kind of local change carried by the current diff node.
4343 /// The value returned is zero if the current node carries no local
4344 /// change.
4345 enum change_kind
4347 {
4348  ir::change_kind k = ir::NO_CHANGE_KIND;
4349  if (!equals(*first_reference(), *second_reference(), &k))
4350  return k & ir::ALL_LOCAL_CHANGES_MASK;
4351  return ir::NO_CHANGE_KIND;
4352 }
4353 
4354 /// Report the diff in a serialized form.
4355 ///
4356 /// @param out the output stream to serialize the dif to.
4357 ///
4358 /// @param indent the string to use for indenting the report.
4359 void
4360 reference_diff::report(ostream& out, const string& indent) const
4361 {
4362  context()->get_reporter()->report(*this, out, indent);
4363 }
4364 
4365 /// Compute the diff between two references.
4366 ///
4367 /// Note that the two types must have been created in the same @ref
4368 /// environment, otherwise, this function aborts.
4369 ///
4370 /// @param first the first reference to consider for the diff.
4371 ///
4372 /// @param second the second reference to consider for the diff.
4373 ///
4374 /// @param ctxt the diff context to use.
4377  reference_type_def_sptr second,
4378  diff_context_sptr ctxt)
4379 {
4380  diff_sptr d = compute_diff_for_types(first->get_pointed_to_type(),
4381  second->get_pointed_to_type(),
4382  ctxt);
4383  reference_diff_sptr result(new reference_diff(first, second, d, ctxt));
4384  ctxt->initialize_canonical_diff(result);
4385  return result;
4386 }
4387 // </reference_type_def>
4388 
4389 // <ptr_to_mbr_diff stuff>
4390 
4391 
4392 /// Constructor of @ref ptr_to_mbr_diff.
4393 ///
4394 /// @param first the first pointer-to-member subject of the diff.
4395 ///
4396 /// @param second the second pointer-to-member subject of the diff.
4397 ///
4398 /// @param member_type_diff the diff node carrying changes to the
4399 /// member type of the pointer-to-member we are considering.
4400 ///
4401 /// @param containing_type_diff the diff node carrying changes to the
4402 /// containing type of the pointer-to-member we are considering.
4403 ///
4404 /// @param ctxt the context of the diff we are considering.
4405 ptr_to_mbr_diff::ptr_to_mbr_diff(const ptr_to_mbr_type_sptr& first,
4406  const ptr_to_mbr_type_sptr& second,
4407  const diff_sptr& member_type_diff,
4408  const diff_sptr& containing_type_diff,
4409  diff_context_sptr ctxt)
4410  : type_diff_base(first, second, ctxt),
4411  priv_(new priv(member_type_diff, containing_type_diff))
4412 {}
4413 
4414 /// Getter of the first pointer-to-member subject of the current diff
4415 /// node.
4416 ///
4417 /// @return the first pointer-to-member subject of the current diff
4418 /// node.
4421 {return dynamic_pointer_cast<ptr_to_mbr_type>(first_subject());}
4422 
4423 /// Getter of the second pointer-to-member subject of the current diff
4424 /// node.
4425 ///
4426 /// @return the second pointer-to-member subject of the current diff
4427 /// node.
4430 {return dynamic_pointer_cast<ptr_to_mbr_type>(second_subject());}
4431 
4432 /// Getter of the diff node carrying changes to the member type of
4433 /// first subject of the current diff node.
4434 ///
4435 /// @return The diff node carrying changes to the member type of first
4436 /// subject of the current diff node.
4437 const diff_sptr
4439 {return priv_->member_type_diff_;}
4440 
4441 /// Getter of the diff node carrying changes to the containing type of
4442 /// first subject of the current diff node.
4443 ///
4444 /// @return The diff node carrying changes to the containing type of
4445 /// first subject of the current diff node.
4446 const diff_sptr
4448 {return priv_->containing_type_diff_;}
4449 
4450 /// Test whether the current diff node carries any change.
4451 ///
4452 /// @return true iff the current diff node carries any change.
4453 bool
4455 {
4457 }
4458 
4459 /// Test whether the current diff node carries any local change.
4460 ///
4461 /// @return true iff the current diff node carries any local change.
4462 enum change_kind
4464 {
4465  ir::change_kind k = ir::NO_CHANGE_KIND;
4467  return k & ir::ALL_LOCAL_CHANGES_MASK;
4468  return ir::NO_CHANGE_KIND;
4469 }
4470 
4471 /// Get the pretty representation of the current @ref ptr_to_mbr_diff
4472 /// node.
4473 ///
4474 /// @return the pretty representation of the current diff node.
4475 const string&
4477 {
4478  if (diff::priv_->pretty_representation_.empty())
4479  {
4480  std::ostringstream o;
4481  o << "ptr_to_mbr_diff["
4482  << first_subject()->get_pretty_representation()
4483  << ", "
4484  << second_subject()->get_pretty_representation()
4485  << "]";
4486  diff::priv_->pretty_representation_ = o.str();
4487  }
4488  return diff::priv_->pretty_representation_;
4489 }
4490 
4491 void
4492 ptr_to_mbr_diff::report(ostream& out, const string& indent) const
4493 {
4494  context()->get_reporter()->report(*this, out, indent);
4495 }
4496 
4497 /// Populate the vector of children node of the @ref diff base type
4498 /// sub-object of this instance of @ref ptr_to_mbr_diff.
4499 ///
4500 /// The children node can then later be retrieved using
4501 /// diff::children_node().
4502 void
4504 {
4507 }
4508 
4509 /// Destructor of @ref ptr_to_mbr_diff.
4511 {
4512 }
4513 
4514 /// Compute the diff between two @ref ptr_to_mbr_type types.
4515 ///
4516 /// Note that the two types must have been created in the same @ref
4517 /// environment, otherwise, this function aborts.
4518 ///
4519 /// @param first the first pointer-to-member type to consider for the diff.
4520 ///
4521 /// @param second the second pointer-to-member type to consider for the diff.
4522 ///
4523 /// @param ctxt the diff context to use.
4526  const ptr_to_mbr_type_sptr& second,
4527  diff_context_sptr& ctxt)
4528 {
4529  diff_sptr member_type_diff =
4530  compute_diff(is_type(first->get_member_type()),
4531  is_type(second->get_member_type()),
4532  ctxt);
4533 
4534  diff_sptr containing_type_diff =
4535  compute_diff(is_type(first->get_containing_type()),
4536  is_type(second->get_containing_type()),
4537  ctxt);
4538 
4539  ptr_to_mbr_diff_sptr result(new ptr_to_mbr_diff(first, second,
4540  member_type_diff,
4541  containing_type_diff,
4542  ctxt));
4543  ctxt->initialize_canonical_diff(result);
4544  return result;
4545 }
4546 
4547 // </ptr_to_mbr_diff stuff>
4548 
4549 // <qualified_type_diff stuff>
4550 
4551 /// Populate the vector of children node of the @ref diff base type
4552 /// sub-object of this instance of @ref qualified_type_diff.
4553 ///
4554 /// The children node can then later be retrieved using
4555 /// diff::children_node().
4556 void
4559 
4560 /// Constructor for qualified_type_diff.
4561 ///
4562 /// @param first the first qualified type of the diff.
4563 ///
4564 /// @param second the second qualified type of the diff.
4565 ///
4566 /// @param ctxt the diff context to use.
4567 qualified_type_diff::qualified_type_diff(qualified_type_def_sptr first,
4568  qualified_type_def_sptr second,
4569  diff_sptr under,
4570  diff_context_sptr ctxt)
4571  : type_diff_base(first, second, ctxt),
4572  priv_(new priv(under))
4573 {}
4574 
4575 /// Getter for the first qualified type of the diff.
4576 ///
4577 /// @return the first qualified type of the diff.
4578 const qualified_type_def_sptr
4580 {return dynamic_pointer_cast<qualified_type_def>(first_subject());}
4581 
4582 /// Getter for the second qualified type of the diff.
4583 ///
4584 /// @return the second qualified type of the diff.
4585 const qualified_type_def_sptr
4587 {return dynamic_pointer_cast<qualified_type_def>(second_subject());}
4588 
4589 /// Getter for the diff between the underlying types of the two
4590 /// qualified types.
4591 ///
4592 /// @return the diff between the underlying types of the two qualified
4593 /// types.
4594 diff_sptr
4596 {return priv_->underlying_type_diff;}
4597 
4598 /// Getter for the diff between the most underlying non-qualified
4599 /// types of two qualified types.
4600 ///
4601 /// @return the diff between the most underlying non-qualified types
4602 /// of two qualified types.
4603 diff_sptr
4605 {
4606  if (!priv_->leaf_underlying_type_diff)
4607  priv_->leaf_underlying_type_diff
4608  = compute_diff_for_types(get_leaf_type(first_qualified_type()),
4610  context());
4611 
4612  return priv_->leaf_underlying_type_diff;
4613 }
4614 
4615 /// Setter for the diff between the underlying types of the two
4616 /// qualified types.
4617 ///
4618 /// @return the diff between the underlying types of the two qualified
4619 /// types.
4620 void
4622 {priv_->underlying_type_diff = d;}
4623 
4624 /// @return the pretty representation of the current instance of @ref
4625 /// qualified_type_diff.
4626 const string&
4628 {
4629  if (diff::priv_->pretty_representation_.empty())
4630  {
4631  std::ostringstream o;
4632  o << "qualified_type_diff["
4633  << first_subject()->get_pretty_representation()
4634  << ", "
4635  << second_subject()->get_pretty_representation()
4636  << "]";
4637  diff::priv_->pretty_representation_ = o.str();
4638  }
4639  return diff::priv_->pretty_representation_;
4640 }
4641 
4642 /// Return true iff the current diff node carries a change.
4643 ///
4644 /// @return true iff the current diff node carries a change.
4645 bool
4648 
4649 /// @return the kind of local change carried by the current diff node.
4650 /// The value returned is zero if the current node carries no local
4651 /// change.
4652 enum change_kind
4654 {
4655  ir::change_kind k = ir::NO_CHANGE_KIND;
4657  return k & ir::ALL_LOCAL_CHANGES_MASK;
4658  return ir::NO_CHANGE_KIND;
4659 }
4660 
4661 /// Report the diff in a serialized form.
4662 ///
4663 /// @param out the output stream to serialize to.
4664 ///
4665 /// @param indent the string to use to indent the lines of the report.
4666 void
4667 qualified_type_diff::report(ostream& out, const string& indent) const
4668 {
4669  context()->get_reporter()->report(*this, out, indent);
4670 }
4671 
4672 /// Compute the diff between two qualified types.
4673 ///
4674 /// Note that the two types must have been created in the same @ref
4675 /// environment, otherwise, this function aborts.
4676 ///
4677 /// @param first the first qualified type to consider for the diff.
4678 ///
4679 /// @param second the second qualified type to consider for the diff.
4680 ///
4681 /// @param ctxt the diff context to use.
4682 qualified_type_diff_sptr
4683 compute_diff(const qualified_type_def_sptr first,
4684  const qualified_type_def_sptr second,
4685  diff_context_sptr ctxt)
4686 {
4687  diff_sptr d = compute_diff_for_types(first->get_underlying_type(),
4688  second->get_underlying_type(),
4689  ctxt);
4690  qualified_type_diff_sptr result(new qualified_type_diff(first, second,
4691  d, ctxt));
4692  ctxt->initialize_canonical_diff(result);
4693  return result;
4694 }
4695 
4696 // </qualified_type_diff stuff>
4697 
4698 // <enum_diff stuff>
4699 
4700 /// Clear the lookup tables useful for reporting an enum_diff.
4701 ///
4702 /// This function must be updated each time a lookup table is added or
4703 /// removed from the class_diff::priv.
4704 void
4705 enum_diff::clear_lookup_tables()
4706 {
4707  priv_->deleted_enumerators_.clear();
4708  priv_->inserted_enumerators_.clear();
4709  priv_->changed_enumerators_.clear();
4710 }
4711 
4712 /// Tests if the lookup tables are empty.
4713 ///
4714 /// @return true if the lookup tables are empty, false otherwise.
4715 bool
4716 enum_diff::lookup_tables_empty() const
4717 {
4718  return (priv_->deleted_enumerators_.empty()
4719  && priv_->inserted_enumerators_.empty()
4720  && priv_->changed_enumerators_.empty());
4721 }
4722 
4723 /// If the lookup tables are not yet built, walk the differences and
4724 /// fill the lookup tables.
4725 void
4726 enum_diff::ensure_lookup_tables_populated()
4727 {
4728  if (!lookup_tables_empty())
4729  return;
4730 
4731  {
4732  edit_script e = priv_->enumerators_changes_;
4733 
4734  for (vector<deletion>::const_iterator it = e.deletions().begin();
4735  it != e.deletions().end();
4736  ++it)
4737  {
4738  unsigned i = it->index();
4739  const enum_type_decl::enumerator& n =
4740  first_enum()->get_enumerators()[i];
4741  const string& name = n.get_name();
4742  ABG_ASSERT(priv_->deleted_enumerators_.find(n.get_name())
4743  == priv_->deleted_enumerators_.end());
4744  priv_->deleted_enumerators_[name] = n;
4745  }
4746 
4747  for (vector<insertion>::const_iterator it = e.insertions().begin();
4748  it != e.insertions().end();
4749  ++it)
4750  {
4751  for (vector<unsigned>::const_iterator iit =
4752  it->inserted_indexes().begin();
4753  iit != it->inserted_indexes().end();
4754  ++iit)
4755  {
4756  unsigned i = *iit;
4757  const enum_type_decl::enumerator& n =
4758  second_enum()->get_enumerators()[i];
4759  const string& name = n.get_name();
4760  ABG_ASSERT(priv_->inserted_enumerators_.find(n.get_name())
4761  == priv_->inserted_enumerators_.end());
4762  string_enumerator_map::const_iterator j =
4763  priv_->deleted_enumerators_.find(name);
4764  if (j == priv_->deleted_enumerators_.end())
4765  priv_->inserted_enumerators_[name] = n;
4766  else
4767  {
4768  if (j->second != n)
4769  priv_->changed_enumerators_[j->first] =
4770  std::make_pair(j->second, n);
4771  priv_->deleted_enumerators_.erase(j);
4772  }
4773  }
4774  }
4775 
4776  // If a new enumerator is added with a value that already existed
4777  // in the old enum but with a new name, then populate the
4778  // enum_diff::priv_::changed_enumerators_ data member with a
4779  // change that represents a change to an enumerator name. The
4780  // enum_diff::priv_::inserted_enumerators_ is adjusted accordingly
4781  // an the 'new' enumerator is removed in this case.
4782 
4783  enum_type_decl::enumerators enums_to_erase;
4784  for (auto& entry : priv_->inserted_enumerators_)
4785  {
4786  enum_type_decl::enumerator& final_enumerator = entry.second;
4787  enum_type_decl::enumerator initial_enumerator;
4788  if (first_enum()->find_enumerator_by_value(entry.second.get_value(),
4789  initial_enumerator))
4790  {
4791  enum_type_decl::enumerator foo;
4792  if (!second_enum()->
4793  find_enumerator_by_name(initial_enumerator.get_name(),
4794  foo))
4795  {
4796  priv_->changed_enumerators_[initial_enumerator.get_name()] =
4797  std::make_pair(initial_enumerator, final_enumerator);
4798  enums_to_erase.push_back(final_enumerator);
4799  }
4800  }
4801  }
4802 
4803  for (auto& enomerator : enums_to_erase)
4804  priv_->inserted_enumerators_.erase(enomerator.get_name());
4805 
4806  // If an enumerator is deleted yet its value (with a new name) is
4807  // still present among enumerators of the newer enum then populate
4808  // the enum_diff::priv_::changed_enumerators_ data member with a
4809  // change that represents a change to an enumerator name. The
4810  // enum_diff::priv_::deleted_enumerators_ is adjusted accordingly
4811  // an the 'new' enumerator is removed in this case.
4812 
4813  enums_to_erase.clear();
4814  for (auto& entry : priv_->deleted_enumerators_)
4815  {
4816  enum_type_decl::enumerator& initial_enumerator = entry.second;
4817  enum_type_decl::enumerator final_enumerator;
4818  if (second_enum()->find_enumerator_by_value(entry.second.get_value(),
4819  final_enumerator))
4820  {
4821  enum_type_decl::enumerator foo;
4822  if (!first_enum()->
4823  find_enumerator_by_name(final_enumerator.get_name(),
4824  foo))
4825  {
4826  priv_->changed_enumerators_[initial_enumerator.get_name()] =
4827  std::make_pair(initial_enumerator, final_enumerator);
4828  enums_to_erase.push_back(initial_enumerator);
4829  }
4830  }
4831  }
4832 
4833  for (auto& enomerator : enums_to_erase)
4834  priv_->deleted_enumerators_.erase(enomerator.get_name());
4835  }
4836 }
4837 
4838 /// Populate the vector of children node of the @ref diff base type
4839 /// sub-object of this instance of @ref enum_diff.
4840 ///
4841 /// The children node can then later be retrieved using
4842 /// diff::children_node().
4843 void
4846 
4847 /// Constructor for enum_diff.
4848 ///
4849 /// @param first the first enum type of the diff.
4850 ///
4851 /// @param second the second enum type of the diff.
4852 ///
4853 /// @param underlying_type_diff the diff of the two underlying types
4854 /// of the two enum types.
4855 ///
4856 /// @param ctxt the diff context to use.
4858  const enum_type_decl_sptr second,
4859  const diff_sptr underlying_type_diff,
4860  const diff_context_sptr ctxt)
4861  : type_diff_base(first, second, ctxt),
4862  priv_(new priv(underlying_type_diff))
4863 {}
4864 
4865 /// @return the first enum of the diff.
4866 const enum_type_decl_sptr
4868 {return dynamic_pointer_cast<enum_type_decl>(first_subject());}
4869 
4870 /// @return the second enum of the diff.
4871 const enum_type_decl_sptr
4873 {return dynamic_pointer_cast<enum_type_decl>(second_subject());}
4874 
4875 /// @return the diff of the two underlying enum types.
4876 diff_sptr
4878 {return priv_->underlying_type_diff_;}
4879 
4880 /// @return a map of the enumerators that were deleted.
4881 const string_enumerator_map&
4883 {return priv_->deleted_enumerators_;}
4884 
4885 /// @return a map of the enumerators that were inserted
4886 const string_enumerator_map&
4888 {return priv_->inserted_enumerators_;}
4889 
4890 /// @return a map of the enumerators that were changed
4893 {return priv_->changed_enumerators_;}
4894 
4895 /// @return the pretty representation of the current instance of @ref
4896 /// enum_diff.
4897 const string&
4899 {
4900  if (diff::priv_->pretty_representation_.empty())
4901  {
4902  std::ostringstream o;
4903  o << "enum_diff["
4904  << first_subject()->get_pretty_representation()
4905  << ", "
4906  << second_subject()->get_pretty_representation()
4907  << "]";
4908  diff::priv_->pretty_representation_ = o.str();
4909  }
4910  return diff::priv_->pretty_representation_;
4911 }
4912 
4913 /// Return true iff the current diff node carries a change.
4914 ///
4915 /// @return true iff the current diff node carries a change.
4916 bool
4918 {return first_enum() != second_enum();}
4919 
4920 /// @return the kind of local change carried by the current diff node.
4921 /// The value returned is zero if the current node carries no local
4922 /// change.
4923 enum change_kind
4925 {
4926  ir::change_kind k = ir::NO_CHANGE_KIND;
4927  if (!equals(*first_enum(), *second_enum(), &k))
4928  return k & ir::ALL_LOCAL_CHANGES_MASK;
4929  return ir::NO_CHANGE_KIND;
4930 }
4931 
4932 /// Report the differences between the two enums.
4933 ///
4934 /// @param out the output stream to send the report to.
4935 ///
4936 /// @param indent the string to use for indentation.
4937 void
4938 enum_diff::report(ostream& out, const string& indent) const
4939 {
4940  context()->get_reporter()->report(*this, out, indent);
4941 }
4942 
4943 /// Compute the set of changes between two instances of @ref
4944 /// enum_type_decl.
4945 ///
4946 /// Note that the two types must have been created in the same @ref
4947 /// environment, otherwise, this function aborts.
4948 ///
4949 /// @param first a pointer to the first enum_type_decl to consider.
4950 ///
4951 /// @param second a pointer to the second enum_type_decl to consider.
4952 ///
4953 /// @return the resulting diff of the two enums @p first and @p
4954 /// second.
4955 ///
4956 /// @param ctxt the diff context to use.
4957 enum_diff_sptr
4959  const enum_type_decl_sptr second,
4960  diff_context_sptr ctxt)
4961 {
4962  diff_sptr ud = compute_diff_for_types(first->get_underlying_type(),
4963  second->get_underlying_type(),
4964  ctxt);
4965  enum_diff_sptr d(new enum_diff(first, second, ud, ctxt));
4966  if (first != second)
4967  {
4968  compute_diff(first->get_enumerators().begin(),
4969  first->get_enumerators().end(),
4970  second->get_enumerators().begin(),
4971  second->get_enumerators().end(),
4972  d->priv_->enumerators_changes_);
4973  d->ensure_lookup_tables_populated();
4974  }
4975  ctxt->initialize_canonical_diff(d);
4976 
4977  return d;
4978 }
4979 // </enum_diff stuff>
4980 
4981 // <class_or_union_diff stuff>
4982 
4983 /// Test if the current diff node carries a member type change for a
4984 /// member type which name is the same as the name of a given type
4985 /// declaration.
4986 ///
4987 /// @param d the type declaration which name should be equal to the
4988 /// name of the member type that might have changed.
4989 ///
4990 /// @return the member type that has changed, iff there were a member
4991 /// type (which name is the same as the name of @p d) that changed.
4992 /// Note that the member type that is returned is the new value of the
4993 /// member type that changed.
4996 {
4997  string qname = d->get_qualified_name();
4998  string_diff_sptr_map::const_iterator it =
4999  changed_member_types_.find(qname);
5000 
5001  return ((it == changed_member_types_.end())
5003  : it->second->second_subject());
5004 }
5005 
5006 /// Test if the current diff node carries a data member change for a
5007 /// data member which name is the same as the name of a given type
5008 /// declaration.
5009 ///
5010 /// @param d the type declaration which name should be equal to the
5011 /// name of the data member that might have changed.
5012 ///
5013 /// @return the data member that has changed, iff there were a data
5014 /// member type (which name is the same as the name of @p d) that
5015 /// changed. Note that the data member that is returned is the new
5016 /// value of the data member that changed.
5017 decl_base_sptr
5019 {
5020  string qname = d->get_qualified_name();
5021  string_var_diff_sptr_map::const_iterator it =
5022  subtype_changed_dm_.find(qname);
5023 
5024  if (it == subtype_changed_dm_.end())
5025  return decl_base_sptr();
5026  return it->second->second_var();
5027 }
5028 
5029 /// Test if the current diff node carries a member class template
5030 /// change for a member class template which name is the same as the
5031 /// name of a given type declaration.
5032 ///
5033 /// @param d the type declaration which name should be equal to the
5034 /// name of the member class template that might have changed.
5035 ///
5036 /// @return the member class template that has changed, iff there were
5037 /// a member class template (which name is the same as the name of @p
5038 /// d) that changed. Note that the member class template that is
5039 /// returned is the new value of the member class template that
5040 /// changed.
5041 decl_base_sptr
5043 {
5044  string qname = d->get_qualified_name();
5045  string_diff_sptr_map::const_iterator it =
5046  changed_member_class_tmpls_.find(qname);
5047 
5048  return ((it == changed_member_class_tmpls_.end())
5049  ? decl_base_sptr()
5050  : dynamic_pointer_cast<decl_base>(it->second->second_subject()));
5051 }
5052 
5053 /// Get the number of non static data members that were deleted.
5054 ///
5055 /// @return the number of non static data members that were deleted.
5056 size_t
5058 {
5059  size_t result = 0;
5060 
5061  for (string_decl_base_sptr_map::const_iterator i =
5062  deleted_data_members_.begin();
5063  i != deleted_data_members_.end();
5064  ++i)
5065  if (is_member_decl(i->second)
5066  && !get_member_is_static(i->second))
5067  ++result;
5068 
5069  return result;
5070 }
5071 
5072 /// Get the number of non static data members that were inserted.
5073 ///
5074 /// @return the number of non static data members that were inserted.
5075 size_t
5077 {
5078  size_t result = 0;
5079 
5080  for (string_decl_base_sptr_map::const_iterator i =
5081  inserted_data_members_.begin();
5082  i != inserted_data_members_.end();
5083  ++i)
5084  if (is_member_decl(i->second)
5085  && !get_member_is_static(i->second))
5086  ++result;
5087 
5088  return result;
5089 }
5090 
5091 /// Get the number of data member sub-type changes carried by the
5092 /// current diff node that were filtered out.
5093 ///
5094 /// @param local_only if true, it means that only (filtered) local
5095 /// changes are considered.
5096 ///
5097 /// @return the number of data member sub-type changes carried by the
5098 /// current diff node that were filtered out.
5099 size_t
5101 {
5102  size_t num_filtered= 0;
5103  for (var_diff_sptrs_type::const_iterator i =
5104  sorted_subtype_changed_dm_.begin();
5105  i != sorted_subtype_changed_dm_.end();
5106  ++i)
5107  {
5108  if (local_only)
5109  {
5110  if ((*i)->has_local_changes() && (*i)->is_filtered_out())
5111  ++num_filtered;
5112  }
5113  else
5114  {
5115  if ((*i)->is_filtered_out())
5116  ++num_filtered;
5117  }
5118  }
5119  return num_filtered;
5120 }
5121 
5122 /// Get the number of data member changes carried by the current diff
5123 /// node that were filtered out.
5124 ///
5125 /// @param local_only if true, it means that only (filtered) local
5126 /// changes are considered.
5127 ///
5128 /// @return the number of data member changes carried by the current
5129 /// diff node that were filtered out.
5130 size_t
5132 {
5133  size_t num_filtered= 0;
5134 
5135  for (unsigned_var_diff_sptr_map::const_iterator i = changed_dm_.begin();
5136  i != changed_dm_.end();
5137  ++i)
5138  {
5139  diff_sptr diff = i->second;
5140  if (local_only)
5141  {
5142  if (diff->has_changes() && diff->is_filtered_out())
5143  ++num_filtered;
5144  }
5145  else
5146  {
5147  if (diff->is_filtered_out())
5148  ++num_filtered;
5149  }
5150  }
5151  return num_filtered;
5152 }
5153 
5154 /// Skip the processing of the current member function if its
5155 /// virtual-ness is disallowed by the user.
5156 ///
5157 /// This is to be used in the member functions below that are used to
5158 /// count the number of filtered inserted, deleted and changed member
5159 /// functions.
5160 #define SKIP_MEM_FN_IF_VIRTUALITY_DISALLOWED \
5161  do { \
5162  if (get_member_function_is_virtual(f) \
5163  || get_member_function_is_virtual(s)) \
5164  { \
5165  if (!(allowed_category | VIRTUAL_MEMBER_CHANGE_CATEGORY)) \
5166  continue; \
5167  } \
5168  else \
5169  { \
5170  if (!(allowed_category | NON_VIRT_MEM_FUN_CHANGE_CATEGORY)) \
5171  continue; \
5172  } \
5173  } while (false)
5174 
5175 /// Get the number of member functions changes carried by the current
5176 /// diff node that were filtered out.
5177 ///
5178 /// @return the number of member functions changes carried by the
5179 /// current diff node that were filtered out.
5180 size_t
5182 (const diff_context_sptr& ctxt)
5183 {
5184  size_t count = 0;
5185  diff_category allowed_category = ctxt->get_allowed_category();
5186 
5187  for (function_decl_diff_sptrs_type::const_iterator i =
5188  sorted_changed_member_functions_.begin();
5189  i != sorted_changed_member_functions_.end();
5190  ++i)
5191  {
5192  method_decl_sptr f =
5193  dynamic_pointer_cast<method_decl>
5194  ((*i)->first_function_decl());
5195  ABG_ASSERT(f);
5196 
5197  method_decl_sptr s =
5198  dynamic_pointer_cast<method_decl>
5199  ((*i)->second_function_decl());
5200  ABG_ASSERT(s);
5201 
5203 
5204  diff_sptr diff = *i;
5205  ctxt->maybe_apply_filters(diff);
5206 
5207  if (diff->is_filtered_out())
5208  ++count;
5209  }
5210 
5211  return count;
5212 }
5213 
5214 /// Get the number of member functions insertions carried by the current
5215 /// diff node that were filtered out.
5216 ///
5217 /// @return the number of member functions insertions carried by the
5218 /// current diff node that were filtered out.
5219 size_t
5221 (const diff_context_sptr& ctxt)
5222 {
5223  size_t count = 0;
5224  diff_category allowed_category = ctxt->get_allowed_category();
5225 
5226  for (string_member_function_sptr_map::const_iterator i =
5227  inserted_member_functions_.begin();
5228  i != inserted_member_functions_.end();
5229  ++i)
5230  {
5231  method_decl_sptr f = i->second,
5232  s = i->second;
5233 
5235 
5236  diff_sptr diff = compute_diff_for_decls(f, s, ctxt);
5237  ctxt->maybe_apply_filters(diff);
5238 
5239  if (diff->get_category() != NO_CHANGE_CATEGORY
5240  && diff->is_filtered_out())
5241  ++count;
5242  }
5243 
5244  return count;
5245 }
5246 
5247 /// Get the number of member functions deletions carried by the current
5248 /// diff node that were filtered out.
5249 ///
5250 /// @return the number of member functions deletions carried by the
5251 /// current diff node that were filtered out.
5252 size_t
5254 (const diff_context_sptr& ctxt)
5255 {
5256  size_t count = 0;
5257  diff_category allowed_category = ctxt->get_allowed_category();
5258 
5259  for (string_member_function_sptr_map::const_iterator i =
5260  deleted_member_functions_.begin();
5261  i != deleted_member_functions_.end();
5262  ++i)
5263  {
5264  method_decl_sptr f = i->second,
5265  s = i->second;
5266 
5268 
5269  diff_sptr diff = compute_diff_for_decls(f, s, ctxt);
5270  ctxt->maybe_apply_filters(diff);
5271 
5272  if (diff->get_category() != NO_CHANGE_CATEGORY
5273  && diff->is_filtered_out())
5274  ++count;
5275  }
5276 
5277  return count;
5278 }
5279 
5280 /// Clear the lookup tables useful for reporting.
5281 ///
5282 /// This function must be updated each time a lookup table is added or
5283 /// removed from the class_or_union_diff::priv.
5284 void
5286 {
5287  priv_->deleted_member_types_.clear();
5288  priv_->inserted_member_types_.clear();
5289  priv_->changed_member_types_.clear();
5290  priv_->deleted_data_members_.clear();
5291  priv_->inserted_data_members_.clear();
5292  priv_->subtype_changed_dm_.clear();
5293  priv_->deleted_member_functions_.clear();
5294  priv_->inserted_member_functions_.clear();
5295  priv_->changed_member_functions_.clear();
5296  priv_->deleted_member_class_tmpls_.clear();
5297  priv_->inserted_member_class_tmpls_.clear();
5298  priv_->changed_member_class_tmpls_.clear();
5299 }
5300 
5301 /// Tests if the lookup tables are empty.
5302 ///
5303 /// @return true if the lookup tables are empty, false otherwise.
5304 bool
5306 {
5307  return (priv_->deleted_member_types_.empty()
5308  && priv_->inserted_member_types_.empty()
5309  && priv_->changed_member_types_.empty()
5310  && priv_->deleted_data_members_.empty()
5311  && priv_->inserted_data_members_.empty()
5312  && priv_->subtype_changed_dm_.empty()
5313  && priv_->inserted_member_functions_.empty()
5314  && priv_->deleted_member_functions_.empty()
5315  && priv_->changed_member_functions_.empty()
5316  && priv_->deleted_member_class_tmpls_.empty()
5317  && priv_->inserted_member_class_tmpls_.empty()
5318  && priv_->changed_member_class_tmpls_.empty());
5319 }
5320 
5321 /// If the lookup tables are not yet built, walk the differences and
5322 /// fill them.
5323 void
5325 {
5326  {
5327  edit_script& e = priv_->member_types_changes_;
5328 
5329  for (vector<deletion>::const_iterator it = e.deletions().begin();
5330  it != e.deletions().end();
5331  ++it)
5332  {
5333  unsigned i = it->index();
5334  decl_base_sptr d =
5335  get_type_declaration(first_class_or_union()->get_member_types()[i]);
5336  class_or_union_sptr record_type = is_class_or_union_type(d);
5337  if (record_type && record_type->get_is_declaration_only())
5338  continue;
5339  string name = d->get_name();
5340  priv_->deleted_member_types_[name] = d;
5341  }
5342 
5343  for (vector<insertion>::const_iterator it = e.insertions().begin();
5344  it != e.insertions().end();
5345  ++it)
5346  {
5347  for (vector<unsigned>::const_iterator iit =
5348  it->inserted_indexes().begin();
5349  iit != it->inserted_indexes().end();
5350  ++iit)
5351  {
5352  unsigned i = *iit;
5353  decl_base_sptr d =
5354  get_type_declaration(second_class_or_union()->get_member_types()[i]);
5355  class_or_union_sptr record_type = is_class_or_union_type(d);
5356  if (record_type && record_type->get_is_declaration_only())
5357  continue;
5358  string name = d->get_name();
5359  string_decl_base_sptr_map::const_iterator j =
5360  priv_->deleted_member_types_.find(name);
5361  if (j != priv_->deleted_member_types_.end())
5362  {
5363  if (*j->second != *d)
5364  priv_->changed_member_types_[name] =
5365  compute_diff(j->second, d, context());
5366 
5367  priv_->deleted_member_types_.erase(j);
5368  }
5369  else
5370  priv_->inserted_member_types_[name] = d;
5371  }
5372  }
5373  }
5374 
5375  {
5376  edit_script& e = priv_->data_members_changes_;
5377 
5378  for (vector<deletion>::const_iterator it = e.deletions().begin();
5379  it != e.deletions().end();
5380  ++it)
5381  {
5382  unsigned i = it->index();
5383  var_decl_sptr data_member =
5384  is_var_decl(first_class_or_union()->get_non_static_data_members()[i]);
5385  string name = data_member->get_anon_dm_reliable_name();
5386 
5387  ABG_ASSERT(priv_->deleted_data_members_.find(name)
5388  == priv_->deleted_data_members_.end());
5389  priv_->deleted_data_members_[name] = data_member;
5390  }
5391 
5392  for (vector<insertion>::const_iterator it = e.insertions().begin();
5393  it != e.insertions().end();
5394  ++it)
5395  {
5396  for (vector<unsigned>::const_iterator iit =
5397  it->inserted_indexes().begin();
5398  iit != it->inserted_indexes().end();
5399  ++iit)
5400  {
5401  unsigned i = *iit;
5402  decl_base_sptr d =
5403  second_class_or_union()->get_non_static_data_members()[i];
5404  var_decl_sptr added_dm = is_var_decl(d);
5405  string name = added_dm->get_anon_dm_reliable_name();
5406  ABG_ASSERT(priv_->inserted_data_members_.find(name)
5407  == priv_->inserted_data_members_.end());
5408 
5409  bool ignore_added_anonymous_data_member = false;
5410  if (is_anonymous_data_member(added_dm))
5411  {
5412  //
5413  // Handle insertion of anonymous data member to
5414  // replace existing data members.
5415  //
5416  // For instance consider this:
5417  // struct S
5418  // {
5419  // int a;
5420  // int b;
5421  // int c;
5422  // };// end struct S
5423  //
5424  // Where the data members 'a' and 'b' are replaced
5425  // by an anonymous data member without changing the
5426  // effective bit layout of the structure:
5427  //
5428  // struct S
5429  // {
5430  // struct
5431  // {
5432  // union
5433  // {
5434  // int a;
5435  // char a_1;
5436  // };
5437  // union
5438  // {
5439  // int b;
5440  // char b_1;
5441  // };
5442  // };
5443  // int c;
5444  // }; // end struct S
5445  //
5446  var_decl_sptr replaced_dm, replacing_dm;
5447  bool added_anon_dm_changes_dm = false;
5448  // The vector of data members replaced by anonymous
5449  // data members.
5450  vector<var_decl_sptr> dms_replaced_by_anon_dm;
5451 
5452  //
5453  // Let's start collecting the set of data members
5454  // which have been replaced by anonymous types in a
5455  // harmless way. These are going to be collected into
5456  // dms_replaced_by_anon_dm and, ultimately, into
5457  // priv_->dms_replaced_by_adms_
5458  //
5459  for (string_decl_base_sptr_map::const_iterator it =
5460  priv_->deleted_data_members_.begin();
5461  it != priv_->deleted_data_members_.end();
5462  ++it)
5463  {
5464  // We don't support this pattern for anonymous
5465  // data members themselves being replaced. If
5466  // that occurs then we'll just report it verbatim.
5467  if (is_anonymous_data_member(it->second))
5468  continue;
5469 
5470  string deleted_dm_name = it->second->get_name();
5471  if ((replacing_dm =
5473  deleted_dm_name)))
5474  {
5475  // So it looks like replacing_dm might have
5476  // replaced the data member which name is
5477  // 'deleted_dm_name'. Let's look deeper to be
5478  // sure.
5479  //
5480  // Note that replacing_dm is part (member) of
5481  // an anonymous data member that might replace
5482  // replaced_dm.
5483 
5484  // So let's get that replaced data member.
5485  replaced_dm = is_var_decl(it->second);
5486  size_t replaced_dm_offset =
5487  get_data_member_offset(replaced_dm),
5488  replacing_dm_offset =
5489  get_absolute_data_member_offset(replacing_dm);
5490 
5491  if (replaced_dm_offset != replacing_dm_offset)
5492  {
5493  // So the replacing data member and the
5494  // replaced data member don't have the
5495  // same offset. This is not the pattern we
5496  // are looking for. Rather, it looks like
5497  // the anonymous data member has *changed*
5498  // the data member.
5499  added_anon_dm_changes_dm = true;
5500  break;
5501  }
5502 
5503  if (replaced_dm->get_type()->get_size_in_bits()
5504  == replaced_dm->get_type()->get_size_in_bits())
5505  dms_replaced_by_anon_dm.push_back(replaced_dm);
5506  else
5507  {
5508  added_anon_dm_changes_dm = true;
5509  break;
5510  }
5511  }
5512  }
5513 
5514  // Now walk dms_replaced_by_anon_dm to fill up
5515  // priv_->dms_replaced_by_adms_ with the set of data
5516  // members replaced by anonymous data members.
5517  if (!added_anon_dm_changes_dm
5518  && !dms_replaced_by_anon_dm.empty())
5519  {
5520  // See if the added data member isn't too big.
5521  type_base_sptr added_dm_type = added_dm->get_type();
5522  ABG_ASSERT(added_dm_type);
5523  var_decl_sptr new_next_dm =
5525  added_dm);
5526  var_decl_sptr old_next_dm =
5527  first_class_or_union()->find_data_member(new_next_dm);
5528 
5529  if (!old_next_dm
5530  || (old_next_dm
5531  && (get_absolute_data_member_offset(old_next_dm)
5532  == get_absolute_data_member_offset(new_next_dm))))
5533  {
5534  // None of the data members that are replaced
5535  // by the added union should be considered as
5536  // having been deleted.
5537  ignore_added_anonymous_data_member = true;
5538  for (vector<var_decl_sptr>::const_iterator i =
5539  dms_replaced_by_anon_dm.begin();
5540  i != dms_replaced_by_anon_dm.end();
5541  ++i)
5542  {
5543  string n = (*i)->get_name();
5544  priv_->dms_replaced_by_adms_[n] =
5545  added_dm;
5546  priv_->deleted_data_members_.erase(n);
5547  }
5548  }
5549  }
5550  }
5551 
5552  if (!ignore_added_anonymous_data_member)
5553  {
5554  // Detect changed data members.
5555  //
5556  // A changed data member (that we shall name D) is a data
5557  // member that satisfies the conditions below:
5558  //
5559  // 1/ It must have been added.
5560  //
5561  // 2/ It must have been deleted as well.
5562  //
5563  // 3/ There must be a non-empty difference between the
5564  // deleted D and the added D.
5565  string_decl_base_sptr_map::const_iterator j =
5566  priv_->deleted_data_members_.find(name);
5567  if (j != priv_->deleted_data_members_.end())
5568  {
5569  if (*j->second != *d)
5570  {
5571  var_decl_sptr old_dm = is_var_decl(j->second);
5572  priv_->subtype_changed_dm_[name]=
5573  compute_diff(old_dm, added_dm, context());
5574  }
5575  priv_->deleted_data_members_.erase(j);
5576  }
5577  else
5578  priv_->inserted_data_members_[name] = d;
5579  }
5580  }
5581  }
5582 
5583  // Now detect when a data member is deleted from offset N and
5584  // another one is added to offset N. In that case, we want to be
5585  // able to say that the data member at offset N changed.
5586  for (string_decl_base_sptr_map::const_iterator i =
5587  priv_->deleted_data_members_.begin();
5588  i != priv_->deleted_data_members_.end();
5589  ++i)
5590  {
5591  unsigned offset = get_data_member_offset(i->second);
5592  priv_->deleted_dm_by_offset_[offset] = i->second;
5593  }
5594 
5595  for (string_decl_base_sptr_map::const_iterator i =
5596  priv_->inserted_data_members_.begin();
5597  i != priv_->inserted_data_members_.end();
5598  ++i)
5599  {
5600  unsigned offset = get_data_member_offset(i->second);
5601  priv_->inserted_dm_by_offset_[offset] = i->second;
5602  }
5603 
5604  for (unsigned_decl_base_sptr_map::const_iterator i =
5605  priv_->inserted_dm_by_offset_.begin();
5606  i != priv_->inserted_dm_by_offset_.end();
5607  ++i)
5608  {
5609  unsigned_decl_base_sptr_map::const_iterator j =
5610  priv_->deleted_dm_by_offset_.find(i->first);
5611  if (j != priv_->deleted_dm_by_offset_.end())
5612  {
5613  var_decl_sptr old_dm = is_var_decl(j->second);
5614  var_decl_sptr new_dm = is_var_decl(i->second);
5615  priv_->changed_dm_[i->first] =
5616  compute_diff(old_dm, new_dm, context());
5617  }
5618  }
5619 
5620  for (unsigned_var_diff_sptr_map::const_iterator i =
5621  priv_->changed_dm_.begin();
5622  i != priv_->changed_dm_.end();
5623  ++i)
5624  {
5625  priv_->deleted_dm_by_offset_.erase(i->first);
5626  priv_->inserted_dm_by_offset_.erase(i->first);
5627  priv_->deleted_data_members_.erase
5628  (i->second->first_var()->get_anon_dm_reliable_name());
5629  priv_->inserted_data_members_.erase
5630  (i->second->second_var()->get_anon_dm_reliable_name());
5631  }
5632 
5633  // Now detect anonymous data members that might appear as deleted
5634  // even though all their data members are still present. Consider
5635  // these as being non-deleted.
5636  string_decl_base_sptr_map non_anonymous_dms_in_second_class;
5638  non_anonymous_dms_in_second_class);
5639  vector<string> deleted_data_members_to_delete;
5640  // Walk data members considered deleted ...
5641  for (auto& entry : priv_->deleted_data_members_)
5642  {
5643  var_decl_sptr data_member = is_var_decl(entry.second);
5644  ABG_ASSERT(data_member);
5645  if (is_anonymous_data_member(data_member))
5646  {
5647  // Let's look at this anonymous data member that is
5648  // considered deleted because it's moved from where it was
5649  // initially, at very least. If its leaf data members are
5650  // still present in the second class then, we won't
5651  // consider it as deleted.
5652  class_or_union_sptr cou = anonymous_data_member_to_class_or_union(data_member);
5653  ABG_ASSERT(cou);
5654  string_decl_base_sptr_map non_anonymous_data_members;
5655  // Lets collect the leaf data members of the anonymous
5656  // data member.
5657  collect_non_anonymous_data_members(cou, non_anonymous_data_members);
5658  bool anonymous_dm_members_present = true;
5659  // Let's see if at least one of the leaf members of the
5660  // anonymous data member is NOT present in the second
5661  // version of the class.
5662  for (auto& e : non_anonymous_data_members)
5663  {
5664  if (non_anonymous_dms_in_second_class.find(e.first)
5665  == non_anonymous_dms_in_second_class.end())
5666  // Grrr, OK, it looks like at least one leaf data
5667  // member of the original anonymous data member was
5668  // removed from the class, so yeah, the anonymous
5669  // data member might have been removed after all.
5670  anonymous_dm_members_present = false;
5671  }
5672  if (anonymous_dm_members_present)
5673  // All leaf data members of the anonymous data member
5674  // are still present in the second version of the class.
5675  // So let's mark that anonymous data member as NOT being
5676  // deleted.
5677  deleted_data_members_to_delete.push_back(data_member->get_anon_dm_reliable_name());
5678  }
5679  }
5680  // All anonymous data members that were recognized as being NOT
5681  // deleted should be removed from the set of deleted data members
5682  // now.
5683  for (string& name_of_dm_to_delete: deleted_data_members_to_delete)
5684  priv_->deleted_data_members_.erase(name_of_dm_to_delete);
5685  }
5686  sort_string_data_member_diff_sptr_map(priv_->subtype_changed_dm_,
5687  priv_->sorted_subtype_changed_dm_);
5688  sort_unsigned_data_member_diff_sptr_map(priv_->changed_dm_,
5689  priv_->sorted_changed_dm_);
5690 
5691  {
5692  edit_script& e = priv_->member_class_tmpls_changes_;
5693 
5694  for (vector<deletion>::const_iterator it = e.deletions().begin();
5695  it != e.deletions().end();
5696  ++it)
5697  {
5698  unsigned i = it->index();
5699  decl_base_sptr d =
5700  first_class_or_union()->get_member_class_templates()[i]->
5701  as_class_tdecl();
5702  string name = d->get_name();
5703  ABG_ASSERT(priv_->deleted_member_class_tmpls_.find(name)
5704  == priv_->deleted_member_class_tmpls_.end());
5705  priv_->deleted_member_class_tmpls_[name] = d;
5706  }
5707 
5708  for (vector<insertion>::const_iterator it = e.insertions().begin();
5709  it != e.insertions().end();
5710  ++it)
5711  {
5712  for (vector<unsigned>::const_iterator iit =
5713  it->inserted_indexes().begin();
5714  iit != it->inserted_indexes().end();
5715  ++iit)
5716  {
5717  unsigned i = *iit;
5718  decl_base_sptr d =
5719  second_class_or_union()->get_member_class_templates()[i]->
5720  as_class_tdecl();
5721  string name = d->get_name();
5722  ABG_ASSERT(priv_->inserted_member_class_tmpls_.find(name)
5723  == priv_->inserted_member_class_tmpls_.end());
5724  string_decl_base_sptr_map::const_iterator j =
5725  priv_->deleted_member_class_tmpls_.find(name);
5726  if (j != priv_->deleted_member_class_tmpls_.end())
5727  {
5728  if (*j->second != *d)
5729  priv_->changed_member_types_[name]=
5730  compute_diff(j->second, d, context());
5731  priv_->deleted_member_class_tmpls_.erase(j);
5732  }
5733  else
5734  priv_->inserted_member_class_tmpls_[name] = d;
5735  }
5736  }
5737  }
5738  sort_string_diff_sptr_map(priv_->changed_member_types_,
5739  priv_->sorted_changed_member_types_);
5740 }
5741 
5742 /// Allocate the memory for the priv_ pimpl data member of the @ref
5743 /// class_or_union_diff class.
5744 void
5746 {
5747  if (!priv_)
5748  priv_.reset(new priv);
5749 }
5750 
5751 /// Constructor for the @ref class_or_union_diff class.
5752 ///
5753 /// @param first_scope the first @ref class_or_union of the diff node.
5754 ///
5755 /// @param second_scope the second @ref class_or_union of the diff node.
5756 ///
5757 /// @param ctxt the context of the diff.
5758 class_or_union_diff::class_or_union_diff(class_or_union_sptr first_scope,
5759  class_or_union_sptr second_scope,
5760  diff_context_sptr ctxt)
5761  : type_diff_base(first_scope, second_scope, ctxt)
5762  //priv_(new priv)
5763 {}
5764 
5765 /// Getter of the private data of the @ref class_or_union_diff type.
5766 ///
5767 /// Note that due to an optimization, the private data of @ref
5768 /// class_or_union_diff can be shared among several instances of
5769 /// class_or_union_diff, so you should never try to access
5770 /// class_or_union_diff::priv directly.
5771 ///
5772 /// When class_or_union_diff::priv is shared, this function returns
5773 /// the correct shared one.
5774 ///
5775 /// @return the (possibly) shared private data of the current instance
5776 /// of @ref class_or_union_diff.
5777 const class_or_union_diff::priv_ptr&
5779 {
5780  if (priv_)
5781  return priv_;
5782 
5783  // If the current class_or_union_diff::priv member is empty, then look for
5784  // the shared one, from the canonical type.
5785  class_or_union_diff *canonical =
5786  dynamic_cast<class_or_union_diff*>(get_canonical_diff());
5787  ABG_ASSERT(canonical);
5788  ABG_ASSERT(canonical->priv_);
5789 
5790  return canonical->priv_;
5791 }
5792 
5793 /// Destructor of class_or_union_diff.
5795 {
5796 }
5797 
5798 /// @return the first @ref class_or_union involved in the diff.
5799 class_or_union_sptr
5802 
5803 /// @return the second @ref class_or_union involved in the diff.
5804 class_or_union_sptr
5807 
5808 /// @return the edit script of the member types of the two @ref
5809 /// class_or_union.
5810 const edit_script&
5812 {return get_priv()->member_types_changes_;}
5813 
5814 /// @return the edit script of the member types of the two @ref
5815 /// class_or_union.
5816 edit_script&
5818 {return get_priv()->member_types_changes_;}
5819 
5820 /// @return the edit script of the data members of the two @ref
5821 /// class_or_union.
5822 const edit_script&
5824 {return get_priv()->data_members_changes_;}
5825 
5826 /// @return the edit script of the data members of the two @ref
5827 /// class_or_union.
5828 edit_script&
5830 {return get_priv()->data_members_changes_;}
5831 
5832 /// Getter for the data members that got inserted.
5833 ///
5834 /// @return a map of data members that got inserted.
5837 {return get_priv()->inserted_data_members_;}
5838 
5839 /// Getter for the data members that got deleted.
5840 ///
5841 /// @return a map of data members that got deleted.
5844 {return get_priv()->deleted_data_members_;}
5845 
5846 /// @return the edit script of the member functions of the two @ref
5847 /// class_or_union.
5848 const edit_script&
5850 {return get_priv()->member_fns_changes_;}
5851 
5852 /// Getter for the virtual members functions that have had a change in
5853 /// a sub-type, without having a change in their symbol name.
5854 ///
5855 /// @return a sorted vector of virtual member functions that have a
5856 /// sub-type change.
5859 {return get_priv()->sorted_changed_member_functions_;}
5860 
5861 /// @return the edit script of the member functions of the two
5862 /// classes.
5863 edit_script&
5865 {return get_priv()->member_fns_changes_;}
5866 
5867 /// @return a map of member functions that got deleted.
5870 {return get_priv()->deleted_member_functions_;}
5871 
5872 /// @return a map of member functions that got inserted.
5875 {return get_priv()->inserted_member_functions_;}
5876 
5877 /// Getter of the map of data members that got replaced by another
5878 /// data member. The key of the map is the offset at which the
5879 /// element got replaced and the value is a pointer to the @ref
5880 /// var_diff representing the replacement of the data member.
5881 ///
5882 /// @return sorted vector of changed data member.
5885 {return get_priv()->changed_dm_;}
5886 
5887 /// Getter of the sorted vector of data members that got replaced by
5888 /// another data member.
5889 ///
5890 /// @return sorted vector of changed data member.
5891 const var_diff_sptrs_type&
5893 {return get_priv()->sorted_changed_dm_;}
5894 
5895 /// Count the number of /filtered/ data members that got replaced by
5896 /// another data member.
5897 ///
5898 /// @return the number of changed data member that got filtered out.
5899 size_t
5901 {return get_priv()->count_filtered_changed_dm(local);}
5902 
5903 /// Getter of the sorted vector of data members with a (sub-)type change.
5904 ///
5905 /// @return sorted vector of changed data member.
5906 const var_diff_sptrs_type&
5908 {return get_priv()->sorted_subtype_changed_dm_;}
5909 
5910 /// Count the number of /filtered/ data members with a sub-type change.
5911 ///
5912 /// @return the number of changed data member that got filtered out.
5913 size_t
5915 {return get_priv()->count_filtered_subtype_changed_dm(local);}
5916 
5917 /// Get the map of data members that got replaced by anonymous data
5918 /// members.
5919 ///
5920 /// The key of a map entry is the name of the replaced data member and
5921 /// the value is the anonymous data member that replaces it.
5922 ///
5923 /// @return the map of data members replaced by anonymous data
5924 /// members.
5927 {return get_priv()->dms_replaced_by_adms_;}
5928 
5929 /// Get an ordered vector of of data members that got replaced by
5930 /// anonymous data members.
5931 ///
5932 /// This returns a vector of pair of two data members: the one that
5933 /// was replaced, and the anonymous data member that replaced it.
5934 ///
5935 /// @return the sorted vector data members replaced by anonymous data members.
5938 {
5939  if (priv_->dms_replaced_by_adms_ordered_.empty())
5940  {
5941  for (string_decl_base_sptr_map::const_iterator it =
5942  priv_->dms_replaced_by_adms_.begin();
5943  it != priv_->dms_replaced_by_adms_.end();
5944  ++it)
5945  {
5946  const var_decl_sptr dm =
5947  first_class_or_union()->find_data_member(it->first);
5948  ABG_ASSERT(dm);
5949  changed_var_sptr changed_dm(dm, is_data_member(it->second));
5950  priv_->dms_replaced_by_adms_ordered_.push_back(changed_dm);
5951  }
5952  sort_changed_data_members(priv_->dms_replaced_by_adms_ordered_);
5953  }
5954 
5955  return priv_->dms_replaced_by_adms_ordered_;
5956 }
5957 
5958 /// @return the edit script of the member function templates of the two
5959 /// @ref class_or_union.
5960 const edit_script&
5962 {return get_priv()->member_fn_tmpls_changes_;}
5963 
5964 /// @return the edit script of the member function templates of the
5965 /// two @ref class_or_union.
5966 edit_script&
5968 {return get_priv()->member_fn_tmpls_changes_;}
5969 
5970 /// @return the edit script of the member class templates of the two
5971 /// @ref class_or_union.
5972 const edit_script&
5974 {return get_priv()->member_class_tmpls_changes_;}
5975 
5976 /// @return the edit script of the member class templates of the two
5977 /// @ref class_or_union.
5978 edit_script&
5980 {return get_priv()->member_class_tmpls_changes_;}
5981 
5982 /// Test if the current diff node carries a change.
5983 bool
5986 
5987 /// @return the kind of local change carried by the current diff node.
5988 /// The value returned is zero if the current node carries no local
5989 /// change.
5990 enum change_kind
5992 {
5993  ir::change_kind k = ir::NO_CHANGE_KIND;
5995  return k & ir::ALL_LOCAL_CHANGES_MASK;
5996  return ir::NO_CHANGE_KIND;
5997 }
5998 
5999 
6000 /// Report the changes carried by the current @ref class_or_union_diff
6001 /// node in a textual format.
6002 ///
6003 /// @param out the output stream to write the textual report to.
6004 ///
6005 /// @param indent the number of white space to use as indentation.
6006 void
6007 class_or_union_diff::report(ostream& out, const string& indent) const
6008 {
6009  context()->get_reporter()->report(*this, out, indent);
6010 }
6011 
6012 /// Populate the vector of children node of the @ref diff base type
6013 /// sub-object of this instance of @ref class_or_union_diff.
6014 ///
6015 /// The children node can then later be retrieved using
6016 /// diff::children_node().
6017 void
6019 {
6020  // data member changes
6021  for (var_diff_sptrs_type::const_iterator i =
6022  get_priv()->sorted_subtype_changed_dm_.begin();
6023  i != get_priv()->sorted_subtype_changed_dm_.end();
6024  ++i)
6025  if (diff_sptr d = *i)
6026  append_child_node(d);
6027 
6028  for (var_diff_sptrs_type::const_iterator i =
6029  get_priv()->sorted_changed_dm_.begin();
6030  i != get_priv()->sorted_changed_dm_.end();
6031  ++i)
6032  if (diff_sptr d = *i)
6033  append_child_node(d);
6034 
6035  // member types changes
6036  for (diff_sptrs_type::const_iterator i =
6037  get_priv()->sorted_changed_member_types_.begin();
6038  i != get_priv()->sorted_changed_member_types_.end();
6039  ++i)
6040  if (diff_sptr d = *i)
6041  append_child_node(d);
6042 
6043  // member function changes
6044  for (function_decl_diff_sptrs_type::const_iterator i =
6045  get_priv()->sorted_changed_member_functions_.begin();
6046  i != get_priv()->sorted_changed_member_functions_.end();
6047  ++i)
6048  if (diff_sptr d = *i)
6049  append_child_node(d);
6050 }
6051 
6052 // </class_or_union_diff stuff>
6053 
6054 //<class_diff stuff>
6055 
6056 /// Clear the lookup tables useful for reporting.
6057 ///
6058 /// This function must be updated each time a lookup table is added or
6059 /// removed from the class_diff::priv.
6060 void
6061 class_diff::clear_lookup_tables(void)
6062 {
6063  priv_->deleted_bases_.clear();
6064  priv_->inserted_bases_.clear();
6065  priv_->changed_bases_.clear();
6066 }
6067 
6068 /// Tests if the lookup tables are empty.
6069 ///
6070 /// @return true if the lookup tables are empty, false otherwise.
6071 bool
6072 class_diff::lookup_tables_empty(void) const
6073 {
6074  return (priv_->deleted_bases_.empty()
6075  && priv_->inserted_bases_.empty()
6076  && priv_->changed_bases_.empty());
6077 }
6078 
6079 /// Find a virtual destructor in a map of member functions
6080 ///
6081 /// @param map the map of member functions. Note that the key of the
6082 /// map is the member function name. The key is the member function.
6083 ///
6084 /// @return an iterator to the destructor found or, if no virtual destructor
6085 /// was found, return map.end()
6086 static string_member_function_sptr_map::const_iterator
6087 find_virtual_dtor_in_map(const string_member_function_sptr_map& map)
6088 {
6089  for (string_member_function_sptr_map::const_iterator i = map.begin();
6090  i !=map.end();
6091  ++i)
6092  {
6093  if (get_member_function_is_dtor(i->second)
6094  && get_member_function_is_virtual(i->second))
6095  return i;
6096  }
6097  return map.end();
6098 }
6099 
6100 /// If the lookup tables are not yet built, walk the differences and
6101 /// fill them.
6102 void
6103 class_diff::ensure_lookup_tables_populated(void) const
6104 {
6106 
6107  if (!lookup_tables_empty())
6108  return;
6109 
6110  {
6111  edit_script& e = get_priv()->base_changes_;
6112 
6113  for (vector<deletion>::const_iterator it = e.deletions().begin();
6114  it != e.deletions().end();
6115  ++it)
6116  {
6117  unsigned i = it->index();
6119  first_class_decl()->get_base_specifiers()[i];
6120  string name = b->get_base_class()->get_qualified_name();
6121  ABG_ASSERT(get_priv()->deleted_bases_.find(name)
6122  == get_priv()->deleted_bases_.end());
6123  get_priv()->deleted_bases_[name] = b;
6124  }
6125 
6126  for (vector<insertion>::const_iterator it = e.insertions().begin();
6127  it != e.insertions().end();
6128  ++it)
6129  {
6130  for (vector<unsigned>::const_iterator iit =
6131  it->inserted_indexes().begin();
6132  iit != it->inserted_indexes().end();
6133  ++iit)
6134  {
6135  unsigned i = *iit;
6137  second_class_decl()->get_base_specifiers()[i];
6138  string name = b->get_base_class()->get_qualified_name();
6139  ABG_ASSERT(get_priv()->inserted_bases_.find(name)
6140  == get_priv()->inserted_bases_.end());
6141  string_base_sptr_map::const_iterator j =
6142  get_priv()->deleted_bases_.find(name);
6143  if (j != get_priv()->deleted_bases_.end())
6144  {
6145  if (j->second != b)
6146  get_priv()->changed_bases_[name] =
6147  compute_diff(j->second, b, context());
6148  else
6149  // The base class changed place. IOW, the base
6150  // classes got re-arranged. Let's keep track of the
6151  // base classes that moved.
6152  get_priv()->moved_bases_.push_back(b);
6153  get_priv()->deleted_bases_.erase(j);
6154  }
6155  else
6156  get_priv()->inserted_bases_[name] = b;
6157  }
6158  }
6159 
6160  // ===============================================================
6161  // Detect when a data member is deleted from the class but is now
6162  // present in one of the bases at the same offset. In that case,
6163  // the data member should not be considered as removed.
6164  // ===============================================================
6166  class_or_union_diff::priv_->deleted_data_members_;
6167 
6168  vector<var_decl_sptr> deleted_data_members_present_in_bases;
6169  for (auto entry : deleted_data_members)
6170  {
6171  var_decl_sptr deleted_member = is_var_decl(entry.second);
6172  ABG_ASSERT(deleted_member);
6173  for (class_decl::base_spec_sptr base : second_class_decl()->get_base_specifiers())
6174  {
6175  class_decl_sptr klass = base->get_base_class();
6176  var_decl_sptr member = klass->find_data_member(deleted_member->get_name());
6177  if (member)
6178  deleted_data_members_present_in_bases.push_back(member);
6179  }
6180  }
6181  // Walk the deleted data members that are now in one of the bases,
6182  // of the new type, at the same offset, and let's see if they have
6183  // sub-type changes. In any cases, these should not be considered
6184  // as being deleted.
6185  for (var_decl_sptr m : deleted_data_members_present_in_bases)
6186  {
6187  string name = m->get_name();
6188  auto it = deleted_data_members.find(name);
6189  ABG_ASSERT(it != deleted_data_members.end());
6190  var_decl_sptr deleted_member = is_var_decl(it->second);
6191  if (*deleted_member != *m)
6192  {
6193  var_diff_sptr dif = compute_diff(deleted_member, m, context());
6194  ABG_ASSERT(dif);
6195  class_or_union_diff::priv_->subtype_changed_dm_[name]= dif;
6196  }
6197  deleted_data_members.erase(name);
6198  }
6199  }
6200 
6201  sort_string_base_sptr_map(get_priv()->deleted_bases_,
6202  get_priv()->sorted_deleted_bases_);
6203  sort_string_base_sptr_map(get_priv()->inserted_bases_,
6204  get_priv()->sorted_inserted_bases_);
6205  sort_string_base_diff_sptr_map(get_priv()->changed_bases_,
6206  get_priv()->sorted_changed_bases_);
6207 
6208  {
6209  const class_or_union_diff::priv_ptr &p = class_or_union_diff::get_priv();
6210 
6211  edit_script& e = p->member_fns_changes_;
6212 
6213  for (vector<deletion>::const_iterator it = e.deletions().begin();
6214  it != e.deletions().end();
6215  ++it)
6216  {
6217  unsigned i = it->index();
6218  method_decl_sptr mem_fn =
6219  first_class_decl()->get_virtual_mem_fns()[i];
6220  string name = mem_fn->get_linkage_name();
6221  if (name.empty())
6222  name = mem_fn->get_pretty_representation();
6223  ABG_ASSERT(!name.empty());
6224  if (p->deleted_member_functions_.find(name)
6225  != p->deleted_member_functions_.end())
6226  continue;
6227  p->deleted_member_functions_[name] = mem_fn;
6228  }
6229 
6230  for (vector<insertion>::const_iterator it = e.insertions().begin();
6231  it != e.insertions().end();
6232  ++it)
6233  {
6234  for (vector<unsigned>::const_iterator iit =
6235  it->inserted_indexes().begin();
6236  iit != it->inserted_indexes().end();
6237  ++iit)
6238  {
6239  unsigned i = *iit;
6240 
6241  method_decl_sptr mem_fn =
6242  second_class_decl()->get_virtual_mem_fns()[i];
6243  string name = mem_fn->get_linkage_name();
6244  if (name.empty())
6245  name = mem_fn->get_pretty_representation();
6246  ABG_ASSERT(!name.empty());
6247  if (p->inserted_member_functions_.find(name)
6248  != p->inserted_member_functions_.end())
6249  continue;
6250  string_member_function_sptr_map::const_iterator j =
6251  p->deleted_member_functions_.find(name);
6252 
6253  if (j != p->deleted_member_functions_.end())
6254  {
6255  if (*j->second != *mem_fn)
6256  p->changed_member_functions_[name] =
6257  compute_diff(static_pointer_cast<function_decl>(j->second),
6258  static_pointer_cast<function_decl>(mem_fn),
6259  context());
6260  p->deleted_member_functions_.erase(j);
6261  }
6262  else
6263  p->inserted_member_functions_[name] = mem_fn;
6264  }
6265  }
6266 
6267  // Now walk the allegedly deleted member functions; check if their
6268  // underlying symbols are deleted as well; otherwise, consider
6269  // that the member function in question hasn't been deleted.
6270 
6271  // Also, while walking the deleted member functions, we attend at
6272  // a particular cleanup business related to (virtual) C++
6273  // destructors:
6274  //
6275  // In the binary, there can be at least three types of
6276  // destructors, defined in the document
6277  // https://itanium-cxx-abi.github.io/cxx-abi/abi.html#definitions:
6278  //
6279  // 1/ Base object destructor (aka D2 destructor):
6280  //
6281  // "A function that runs the destructors for non-static data
6282  // members of T and non-virtual direct base classes of T. "
6283  //
6284  // 2/ Complete object destructor (aka D1 destructor):
6285  //
6286  // "A function that, in addition to the actions required of a
6287  // base object destructor, runs the destructors for the
6288  // virtual base classes of T."
6289  //
6290  // 3/ Deleting destructor (aka D0 destructor):
6291  //
6292  // "A function that, in addition to the actions required of a
6293  // complete object destructor, calls the appropriate
6294  // deallocation function (i.e,. operator delete) for T."
6295  //
6296  // With binaries generated by GCC, these destructors might be ELF
6297  // clones of each others, meaning, their ELF symbols can be
6298  // aliases.
6299  //
6300  // Also, note that because the actual destructor invoked by user
6301  // code is virtual, it's invoked through the vtable. So the
6302  // presence of the underlying D0, D1, D2 in the binary might vary
6303  // without that variation being an ABI issue, provided that the
6304  // destructor invoked through the vtable is present.
6305  //
6306  // So, a particular virtual destructor implementation for a class
6307  // might disapear and be replaced by another one in a subsequent
6308  // version of the binary. If all versions of the binary have an
6309  // actual virtual destructor, things might be considered fine.
6310  vector<string> to_delete;
6311  corpus_sptr f = context()->get_first_corpus(),
6312  s = context()->get_second_corpus();
6313  if (s)
6314  for (string_member_function_sptr_map::const_iterator i =
6315  deleted_member_fns().begin();
6316  i != deleted_member_fns().end();
6317  ++i)
6318  {
6319  if (get_member_function_is_virtual(i->second))
6320  {
6321  if (get_member_function_is_dtor(i->second))
6322  {
6323  // If a particular virtual destructor is deleted,
6324  // but the new binary still have a virtual
6325  // destructor for that class we consider that things
6326  // are fine. For instance, in the
6327  // tests/data/test-diff-pkg/tbb-4.1-9.20130314.fc22.x86_64--tbb-4.3-3.20141204.fc23.x86_64-report-0.txt
6328  // test, a new D4 destructor replaces the old ones.
6329  // But because the virtual destructor is still
6330  // there, this is not an ABI issue. So let's detect
6331  // this case.
6332  auto it =
6333  find_virtual_dtor_in_map(p->inserted_member_functions_);
6334  if (it != p->inserted_member_functions_.end())
6335  {
6336  // So the deleted virtual destructor is not
6337  // really deleted, because a proper virtual
6338  // destructor was added to the new version.
6339  // Let's remove the deleted/added virtual
6340  // destructor then.
6341  string name =
6342  (!i->second->get_linkage_name().empty())
6343  ? i->second->get_linkage_name()
6344  : i->second->get_pretty_representation();
6345  to_delete.push_back(name);
6346  p->inserted_member_functions_.erase(it);
6347  }
6348  }
6349  continue;
6350  }
6351  // We assume that all non-virtual member functions functions
6352  // we look at here have ELF symbols.
6353  if (!i->second->get_symbol()
6354  || s->lookup_function_symbol(*i->second->get_symbol()))
6355  to_delete.push_back(i->first);
6356  }
6357 
6358 
6359  for (vector<string>::const_iterator i = to_delete.begin();
6360  i != to_delete.end();
6361  ++i)
6362  p->deleted_member_functions_.erase(*i);
6363 
6364  // Do something similar for added functions.
6365  to_delete.clear();
6366  if (f)
6367  for (string_member_function_sptr_map::const_iterator i =
6368  inserted_member_fns().begin();
6369  i != inserted_member_fns().end();
6370  ++i)
6371  {
6372  if (get_member_function_is_virtual(i->second))
6373  continue;
6374  // We assume that all non-virtual member functions functions
6375  // we look at here have ELF symbols.
6376  if (!i->second->get_symbol()
6377  || f->lookup_function_symbol(*i->second->get_symbol()))
6378  to_delete.push_back(i->first);
6379  }
6380 
6381  for (vector<string>::const_iterator i = to_delete.begin();
6382  i != to_delete.end();
6383  ++i)
6384  p->inserted_member_functions_.erase(*i);
6385 
6386  sort_string_member_function_sptr_map(p->deleted_member_functions_,
6387  p->sorted_deleted_member_functions_);
6388 
6389  sort_string_member_function_sptr_map(p->inserted_member_functions_,
6390  p->sorted_inserted_member_functions_);
6391 
6393  (p->changed_member_functions_,
6394  p->sorted_changed_member_functions_);
6395  }
6396 }
6397 
6398 /// Allocate the memory for the priv_ pimpl data member of the @ref
6399 /// class_diff class.
6400 void
6401 class_diff::allocate_priv_data()
6402 {
6404  if (!priv_)
6405  priv_.reset(new priv);
6406 }
6407 
6408 /// Test whether a given base class has changed. A base class has
6409 /// changed if it's in both in deleted *and* inserted bases.
6410 ///
6411 ///@param d the declaration for the base class to consider.
6412 ///
6413 /// @return the new base class if the given base class has changed, or
6414 /// NULL if it hasn't.
6417 {
6418  string qname = d->get_base_class()->get_qualified_name();
6419  string_base_diff_sptr_map::const_iterator it =
6420  changed_bases_.find(qname);
6421 
6422  return (it == changed_bases_.end())
6424  : it->second->second_base();
6425 
6426 }
6427 
6428 /// Count the number of bases classes whose changes got filtered out.
6429 ///
6430 /// @return the number of bases classes whose changes got filtered
6431 /// out.
6432 size_t
6434 {
6435  size_t num_filtered = 0;
6436  for (base_diff_sptrs_type::const_iterator i = sorted_changed_bases_.begin();
6437  i != sorted_changed_bases_.end();
6438  ++i)
6439  {
6440  diff_sptr diff = *i;
6441  if (diff && diff->is_filtered_out())
6442  ++num_filtered;
6443  }
6444  return num_filtered;
6445 }
6446 
6447 /// Populate the vector of children node of the @ref diff base type
6448 /// sub-object of this instance of @ref class_diff.
6449 ///
6450 /// The children node can then later be retrieved using
6451 /// diff::children_node().
6452 void
6454 {
6456 
6457  // base class changes.
6458  for (base_diff_sptrs_type::const_iterator i =
6459  get_priv()->sorted_changed_bases_.begin();
6460  i != get_priv()->sorted_changed_bases_.end();
6461  ++i)
6462  if (diff_sptr d = *i)
6463  append_child_node(d);
6464 }
6465 
6466 /// Constructor of class_diff
6467 ///
6468 /// @param first_scope the first class of the diff.
6469 ///
6470 /// @param second_scope the second class of the diff.
6471 ///
6472 /// @param ctxt the diff context to use.
6474  class_decl_sptr second_scope,
6475  diff_context_sptr ctxt)
6476  : class_or_union_diff(first_scope, second_scope, ctxt)
6477  // We don't initialize the priv_ data member here. This is an
6478  // optimization to reduce memory consumption (and also execution
6479  // time) for cases where there are a lot of instances of
6480  // class_diff in the same equivalence class. In compute_diff(),
6481  // the priv_ is set to the priv_ of the canonical diff node.
6482  // See PR libabigail/17948.
6483 {}
6484 
6485 class_diff::~class_diff()
6486 {}
6487 
6488 /// Getter of the private data of the @ref class_diff type.
6489 ///
6490 /// Note that due to an optimization, the private data of @ref
6491 /// class_diff can be shared among several instances of class_diff, so
6492 /// you should never try to access class_diff::priv directly.
6493 ///
6494 /// When class_diff::priv is shared, this function returns the correct
6495 /// shared one.
6496 ///
6497 /// @return the (possibly) shared private data of the current instance
6498 /// of class_diff.
6499 const class_diff::priv_ptr&
6500 class_diff::get_priv() const
6501 {
6502  if (priv_)
6503  return priv_;
6504 
6505  // If the current class_diff::priv member is empty, then look for
6506  // the shared one, from the canonical type.
6507  class_diff *canonical =
6508  dynamic_cast<class_diff*>(get_canonical_diff());
6509  ABG_ASSERT(canonical);
6510  ABG_ASSERT(canonical->priv_);
6511 
6512  return canonical->priv_;
6513 }
6514 
6515 /// @return the pretty representation of the current instance of @ref
6516 /// class_diff.
6517 const string&
6519 {
6520  if (diff::priv_->pretty_representation_.empty())
6521  {
6522  std::ostringstream o;
6523  o << "class_diff["
6524  << first_subject()->get_pretty_representation()
6525  << ", "
6526  << second_subject()->get_pretty_representation()
6527  << "]";
6528  diff::priv_->pretty_representation_ = o.str();
6529  }
6530  return diff::priv_->pretty_representation_;
6531 }
6532 
6533 /// Return true iff the current diff node carries a change.
6534 ///
6535 /// @return true iff the current diff node carries a change.
6536 bool
6538 {return (first_class_decl() != second_class_decl());}
6539 
6540 /// @return the kind of local change carried by the current diff node.
6541 /// The value returned is zero if the current node carries no local
6542 /// change.
6543 enum change_kind
6545 {
6546  ir::change_kind k = ir::NO_CHANGE_KIND;
6547  if (!equals(*first_class_decl(), *second_class_decl(), &k))
6548  return k & ir::ALL_LOCAL_CHANGES_MASK;
6549  return ir::NO_CHANGE_KIND;
6550 }
6551 
6552 /// @return the first class invoveld in the diff.
6553 shared_ptr<class_decl>
6555 {return dynamic_pointer_cast<class_decl>(first_subject());}
6556 
6557 /// Getter of the second class involved in the diff.
6558 ///
6559 /// @return the second class invoveld in the diff
6560 shared_ptr<class_decl>
6562 {return dynamic_pointer_cast<class_decl>(second_subject());}
6563 
6564 /// @return the edit script of the bases of the two classes.
6565 const edit_script&
6567 {return get_priv()->base_changes_;}
6568 
6569 /// Getter for the deleted base classes of the diff.
6570 ///
6571 /// @return a map containing the deleted base classes, keyed with
6572 /// their pretty representation.
6573 const string_base_sptr_map&
6575 {return get_priv()->deleted_bases_;}
6576 
6577 /// Getter for the inserted base classes of the diff.
6578 ///
6579 /// @return a map containing the inserted base classes, keyed with
6580 /// their pretty representation.
6581 const string_base_sptr_map&
6583 {return get_priv()->inserted_bases_;}
6584 
6585 /// Getter for the changed base classes of the diff.
6586 ///
6587 /// @return a sorted vector containing the changed base classes
6588 const base_diff_sptrs_type&
6590 {return get_priv()->sorted_changed_bases_;}
6591 
6592 /// Getter for the vector of bases that "moved".
6593 /// That is, the vector of base types which position changed. If this
6594 /// vector is not empty, it means the bases of the underlying class
6595 /// type got re-ordered.
6596 ///
6597 /// @return the vector of bases that moved.
6598 const vector<class_decl::base_spec_sptr>&
6600 {return get_priv()->moved_bases_;}
6601 
6602 /// @return the edit script of the bases of the two classes.
6603 edit_script&
6605 {return get_priv()->base_changes_;}
6606 
6607 /// Produce a basic report about the changes between two class_decl.
6608 ///
6609 /// @param out the output stream to report the changes to.
6610 ///
6611 /// @param indent the string to use as an indentation prefix in the
6612 /// report.
6613 void
6614 class_diff::report(ostream& out, const string& indent) const
6615 {
6616  context()->get_reporter()->report(*this, out, indent);
6617 }
6618 
6619 /// Compute the set of changes between two instances of class_decl.
6620 ///
6621 /// Note that the two types must have been created in the same @ref
6622 /// environment, otherwise, this function aborts.
6623 ///
6624 /// @param first the first class_decl to consider.
6625 ///
6626 /// @param second the second class_decl to consider.
6627 ///
6628 /// @return changes the resulting changes.
6629 ///
6630 /// @param ctxt the diff context to use.
6633  const class_decl_sptr second,
6634  diff_context_sptr ctxt)
6635 {
6638 
6639  class_diff_sptr changes(new class_diff(f, s, ctxt));
6640 
6641  ctxt->initialize_canonical_diff(changes);
6642  ABG_ASSERT(changes->get_canonical_diff());
6643 
6644  if (!ctxt->get_canonical_diff_for(first, second))
6645  {
6646  // Either first or second is a decl-only class; let's set the
6647  // canonical diff here in that case.
6648  diff_sptr canonical_diff = ctxt->get_canonical_diff_for(changes);
6649  ABG_ASSERT(canonical_diff);
6650  ctxt->set_canonical_diff_for(first, second, canonical_diff);
6651  }
6652 
6653  // Ok, so this is an optimization. Do not freak out if it looks
6654  // weird, because, well, it does look weird. This speeds up
6655  // greatly, for instance, the test case given at PR
6656  // libabigail/17948.
6657  //
6658  // We are setting the private data of the new instance of class_diff
6659  // (which is 'changes') to the private data of its canonical
6660  // instance. That is, we are sharing the private data of 'changes'
6661  // with the private data of its canonical instance to consume less
6662  // memory in cases where the equivalence class of 'changes' is huge.
6663  //
6664  // But if changes is its own canonical instance, then we initialize
6665  // its private data properly
6666  if (is_class_diff(changes->get_canonical_diff()) == changes.get())
6667  // changes is its own canonical instance, so it gets a brand new
6668  // private data.
6669  changes->allocate_priv_data();
6670  else
6671  {
6672  // changes has a non-empty equivalence class so it's going to
6673  // share its private data with its canonical instance. Next
6674  // time class_diff::get_priv() is invoked, it's going to return
6675  // the shared private data of the canonical instance.
6676  return changes;
6677  }
6678 
6679  // Compare base specs
6680  compute_diff(f->get_base_specifiers().begin(),
6681  f->get_base_specifiers().end(),
6682  s->get_base_specifiers().begin(),
6683  s->get_base_specifiers().end(),
6684  changes->base_changes());
6685 
6686  // Do *not* compare member types because it generates lots of noise
6687  // and I doubt it's really useful.
6688 #if 0
6689  compute_diff(f->get_member_types().begin(),
6690  f->get_member_types().end(),
6691  s->get_member_types().begin(),
6692  s->get_member_types().end(),
6693  changes->member_types_changes());
6694 #endif
6695 
6696  // Compare data member
6697  compute_diff(f->get_non_static_data_members().begin(),
6698  f->get_non_static_data_members().end(),
6699  s->get_non_static_data_members().begin(),
6700  s->get_non_static_data_members().end(),
6701  changes->data_members_changes());
6702 
6703  // Compare virtual member functions
6704  compute_diff(f->get_virtual_mem_fns().begin(),
6705  f->get_virtual_mem_fns().end(),
6706  s->get_virtual_mem_fns().begin(),
6707  s->get_virtual_mem_fns().end(),
6708  changes->member_fns_changes());
6709 
6710  // Compare member function templates
6711  compute_diff(f->get_member_function_templates().begin(),
6712  f->get_member_function_templates().end(),
6713  s->get_member_function_templates().begin(),
6714  s->get_member_function_templates().end(),
6715  changes->member_fn_tmpls_changes());
6716 
6717  // Likewise, do not compare member class templates
6718 #if 0
6719  compute_diff(f->get_member_class_templates().begin(),
6720  f->get_member_class_templates().end(),
6721  s->get_member_class_templates().begin(),
6722  s->get_member_class_templates().end(),
6723  changes->member_class_tmpls_changes());
6724 #endif
6725 
6726  changes->ensure_lookup_tables_populated();
6727 
6728  return changes;
6729 }
6730 
6731 //</class_diff stuff>
6732 
6733 // <base_diff stuff>
6734 
6735 /// Populate the vector of children node of the @ref diff base type
6736 /// sub-object of this instance of @ref base_diff.
6737 ///
6738 /// The children node can then later be retrieved using
6739 /// diff::children_node().
6740 void
6743 
6744 /// @param first the first base spec to consider.
6745 ///
6746 /// @param second the second base spec to consider.
6747 ///
6748 /// @param ctxt the context of the diff. Note that this context
6749 /// object must stay alive at least during the life time of the
6750 /// current instance of @ref base_diff. Otherwise memory corruption
6751 /// issues occur.
6754  class_diff_sptr underlying,
6755  diff_context_sptr ctxt)
6756  : diff(first, second, ctxt),
6757  priv_(new priv(underlying))
6758 {}
6759 
6760 /// Getter for the first base spec of the diff object.
6761 ///
6762 /// @return the first base specifier for the diff object.
6765 {return dynamic_pointer_cast<class_decl::base_spec>(first_subject());}
6766 
6767 /// Getter for the second base spec of the diff object.
6768 ///
6769 /// @return the second base specifier for the diff object.
6772 {return dynamic_pointer_cast<class_decl::base_spec>(second_subject());}
6773 
6774 /// Getter for the diff object for the diff of the underlying base
6775 /// classes.
6776 ///
6777 /// @return the diff object for the diff of the underlying base
6778 /// classes.
6779 const class_diff_sptr
6781 {return priv_->underlying_class_diff_;}
6782 
6783 /// Setter for the diff object for the diff of the underlyng base
6784 /// classes.
6785 ///
6786 /// @param d the new diff object for the diff of the underlying base
6787 /// classes.
6788 void
6790 {priv_->underlying_class_diff_ = d;}
6791 
6792 /// @return the pretty representation for the current instance of @ref
6793 /// base_diff.
6794 const string&
6796 {
6797  if (diff::priv_->pretty_representation_.empty())
6798  {
6799  std::ostringstream o;
6800  o << "base_diff["
6801  << first_subject()->get_pretty_representation()
6802  << ", "
6803  << second_subject()->get_pretty_representation()
6804  << "]";
6805  diff::priv_->pretty_representation_ = o.str();
6806  }
6807  return diff::priv_->pretty_representation_;
6808 }
6809 
6810 /// Return true iff the current diff node carries a change.
6811 ///
6812 /// Return true iff the current diff node carries a change.
6813 bool
6815 {return first_base() != second_base();}
6816 
6817 /// @return the kind of local change carried by the current diff node.
6818 /// The value returned is zero if the current node carries no local
6819 /// change.
6820 enum change_kind
6822 {
6823  ir::change_kind k = ir::NO_CHANGE_KIND;
6824  if (!equals(*first_base(), *second_base(), &k))
6825  return k & ir::ALL_LOCAL_CHANGES_MASK;
6826  return ir::NO_CHANGE_KIND;
6827 }
6828 
6829 /// Generates a report for the current instance of base_diff.
6830 ///
6831 /// @param out the output stream to send the report to.
6832 ///
6833 /// @param indent the string to use for indentation.
6834 void
6835 base_diff::report(ostream& out, const string& indent) const
6836 {
6837  context()->get_reporter()->report(*this, out, indent);
6838 }
6839 
6840 /// Constructs the diff object representing a diff between two base
6841 /// class specifications.
6842 ///
6843 /// Note that the two artifacts must have been created in the same
6844 /// @ref environment, otherwise, this function aborts.
6845 ///
6846 /// @param first the first base class specification.
6847 ///
6848 /// @param second the second base class specification.
6849 ///
6850 /// @param ctxt the content of the diff.
6851 ///
6852 /// @return the resulting diff object.
6855  const class_decl::base_spec_sptr second,
6856  diff_context_sptr ctxt)
6857 {
6858  class_diff_sptr cl = compute_diff(first->get_base_class(),
6859  second->get_base_class(),
6860  ctxt);
6861  base_diff_sptr changes(new base_diff(first, second, cl, ctxt));
6862 
6863  ctxt->initialize_canonical_diff(changes);
6864 
6865  return changes;
6866 }
6867 
6868 // </base_diff stuff>
6869 
6870 
6871 // <union_diff stuff>
6872 
6873 /// Clear the lookup tables useful for reporting.
6874 ///
6875 /// This function must be updated each time a lookup table is added or
6876 /// removed from the union_diff::priv.
6877 void
6878 union_diff::clear_lookup_tables(void)
6880 
6881 /// Tests if the lookup tables are empty.
6882 ///
6883 /// @return true if the lookup tables are empty, false otherwise.
6884 bool
6885 union_diff::lookup_tables_empty(void) const
6887 
6888 /// If the lookup tables are not yet built, walk the differences and
6889 /// fill them.
6890 void
6891 union_diff::ensure_lookup_tables_populated(void) const
6893 
6894 /// Allocate the memory for the priv_ pimpl data member of the @ref
6895 /// union_diff class.
6896 void
6897 union_diff::allocate_priv_data()
6898 {
6900 }
6901 
6902 /// Constructor for the @ref union_diff type.
6903 ///
6904 /// @param first_union the first object of the comparison.
6905 ///
6906 /// @param second_union the second object of the comparison.
6907 ///
6908 /// @param ctxt the context of the comparison.
6909 union_diff::union_diff(union_decl_sptr first_union,
6910  union_decl_sptr second_union,
6911  diff_context_sptr ctxt)
6912  : class_or_union_diff(first_union, second_union, ctxt)
6913 {}
6914 
6915 /// Destructor of the union_diff node.
6917 {}
6918 
6919 /// @return the first object of the comparison.
6920 union_decl_sptr
6922 {return is_union_type(first_subject());}
6923 
6924 /// @return the second object of the comparison.
6925 union_decl_sptr
6927 {return is_union_type(second_subject());}
6928 
6929 /// @return the pretty representation of the current diff node.
6930 const string&
6932 {
6933  if (diff::priv_->pretty_representation_.empty())
6934  {
6935  std::ostringstream o;
6936  o << "union_diff["
6937  << first_subject()->get_pretty_representation()
6938  << ", "
6939  << second_subject()->get_pretty_representation()
6940  << "]";
6941  diff::priv_->pretty_representation_ = o.str();
6942  }
6943  return diff::priv_->pretty_representation_;
6944 }
6945 
6946 /// Report the changes carried by the current @ref union_diff node in
6947 /// a textual format.
6948 ///
6949 /// @param out the output stream to write the textual report to.
6950 ///
6951 /// @param indent the number of white space to use as indentation.
6952 void
6953 union_diff::report(ostream& out, const string& indent) const
6954 {
6955  context()->get_reporter()->report(*this, out, indent);
6956 }
6957 
6958 /// Compute the difference between two @ref union_decl types.
6959 ///
6960 /// Note that the two types must hav been created in the same
6961 /// environment, otherwise, this function aborts.
6962 ///
6963 /// @param first the first @ref union_decl to consider.
6964 ///
6965 /// @param second the second @ref union_decl to consider.
6966 ///
6967 /// @param ctxt the context of the diff to use.
6968 union_diff_sptr
6969 compute_diff(const union_decl_sptr first,
6970  const union_decl_sptr second,
6971  diff_context_sptr ctxt)
6972 {
6973  union_diff_sptr changes(new union_diff(first, second, ctxt));
6974 
6975  ctxt->initialize_canonical_diff(changes);
6976  ABG_ASSERT(changes->get_canonical_diff());
6977 
6978  // Ok, so this is an optimization. Do not freak out if it looks
6979  // weird, because, well, it does look weird. This speeds up
6980  // greatly, for instance, the test case given at PR
6981  // libabigail/17948.
6982  //
6983  // We are setting the private data of the new instance of class_diff
6984  // (which is 'changes') to the private data of its canonical
6985  // instance. That is, we are sharing the private data of 'changes'
6986  // with the private data of its canonical instance to consume less
6987  // memory in cases where the equivalence class of 'changes' is huge.
6988  //
6989  // But if changes is its own canonical instance, then we initialize
6990  // its private data properly.
6991  if (is_union_diff(changes->get_canonical_diff()) == changes.get())
6992  // changes is its own canonical instance, so it gets a brand new
6993  // private data.
6994  changes->allocate_priv_data();
6995  else
6996  {
6997  // changes has a non-empty equivalence class so it's going to
6998  // share its private data with its canonical instance. Next
6999  // time class_diff::get_priv() is invoked, it's going to return
7000  // the shared private data of the canonical instance.
7001  return changes;
7002  }
7003 
7004  // Compare data member
7005  compute_diff(first->get_non_static_data_members().begin(),
7006  first->get_non_static_data_members().end(),
7007  second->get_non_static_data_members().begin(),
7008  second->get_non_static_data_members().end(),
7009  changes->data_members_changes());
7010 
7011 #if 0
7012  // Compare member functions
7013  compute_diff(first->get_mem_fns().begin(),
7014  first->get_mem_fns().end(),
7015  second->get_mem_fns().begin(),
7016  second->get_mem_fns().end(),
7017  changes->member_fns_changes());
7018 
7019  // Compare member function templates
7020  compute_diff(first->get_member_function_templates().begin(),
7021  first->get_member_function_templates().end(),
7022  second->get_member_function_templates().begin(),
7023  second->get_member_function_templates().end(),
7024  changes->member_fn_tmpls_changes());
7025 #endif
7026 
7027  changes->ensure_lookup_tables_populated();
7028 
7029  return changes;
7030 }
7031 
7032 // </union_diff stuff>
7033 
7034 //<scope_diff stuff>
7035 
7036 /// Clear the lookup tables that are useful for reporting.
7037 ///
7038 /// This function must be updated each time a lookup table is added or
7039 /// removed.
7040 void
7041 scope_diff::clear_lookup_tables()
7042 {
7043  priv_->deleted_types_.clear();
7044  priv_->deleted_decls_.clear();
7045  priv_->inserted_types_.clear();
7046  priv_->inserted_decls_.clear();
7047  priv_->changed_types_.clear();
7048  priv_->changed_decls_.clear();
7049  priv_->removed_types_.clear();
7050  priv_->removed_decls_.clear();
7051  priv_->added_types_.clear();
7052  priv_->added_decls_.clear();
7053 }
7054 
7055 /// Tests if the lookup tables are empty.
7056 ///
7057 /// This function must be updated each time a lookup table is added or
7058 /// removed.
7059 ///
7060 /// @return true iff all the lookup tables are empty.
7061 bool
7062 scope_diff::lookup_tables_empty() const
7063 {
7064  return (priv_->deleted_types_.empty()
7065  && priv_->deleted_decls_.empty()
7066  && priv_->inserted_types_.empty()
7067  && priv_->inserted_decls_.empty()
7068  && priv_->changed_types_.empty()
7069  && priv_->changed_decls_.empty()
7070  && priv_->removed_types_.empty()
7071  && priv_->removed_decls_.empty()
7072  && priv_->added_types_.empty()
7073  && priv_->added_decls_.empty());
7074 }
7075 
7076 /// If the lookup tables are not yet built, walk the member_changes_
7077 /// member and fill the lookup tables.
7078 void
7079 scope_diff::ensure_lookup_tables_populated()
7080 {
7081  if (!lookup_tables_empty())
7082  return;
7083 
7084  edit_script& e = priv_->member_changes_;
7085 
7086  // Populate deleted types & decls lookup tables.
7087  for (const auto& deletion : e.deletions())
7088  {
7089  unsigned i = deletion.index();
7090  decl_base_sptr decl = deleted_member_at(i);
7091  string qname = decl->get_qualified_name();
7092  if (is_type(decl))
7093  {
7094  class_decl_sptr klass_decl = dynamic_pointer_cast<class_decl>(decl);
7095  if (klass_decl && klass_decl->get_is_declaration_only())
7096  continue;
7097 
7098  // Unique types are artifically put in a scope because they
7099  // have to belong somewhere, but they should not be
7100  // considered added/removed from any scope because they are
7101  // artificial and always present in the system.
7102  if (is_unique_type(is_type(decl)))
7103  continue;
7104 
7105  ABG_ASSERT(priv_->deleted_types_.find(qname)
7106  == priv_->deleted_types_.end());
7107  priv_->deleted_types_[qname] = decl;
7108  }
7109  else
7110  {
7111  ABG_ASSERT(priv_->deleted_decls_.find(qname)
7112  == priv_->deleted_decls_.end());
7113  priv_->deleted_decls_[qname] = decl;
7114  }
7115  }
7116 
7117  // Populate inserted types & decls as well as chagned types & decls
7118  // lookup tables.
7119  for (vector<insertion>::const_iterator it = e.insertions().begin();
7120  it != e.insertions().end();
7121  ++it)
7122  {
7123  for (vector<unsigned>::const_iterator i = it->inserted_indexes().begin();
7124  i != it->inserted_indexes().end();
7125  ++i)
7126  {
7127  decl_base_sptr decl = inserted_member_at(i);
7128  string qname = decl->get_qualified_name();
7129  if (is_type(decl))
7130  {
7131  class_decl_sptr klass_decl =
7132  dynamic_pointer_cast<class_decl>(decl);
7133  if (klass_decl && klass_decl->get_is_declaration_only())
7134  continue;
7135 
7136  // Unique types are artifically put in a scope because they
7137  // have to belong somewhere, but they should not be
7138  // considered added/removed from any scope because they are
7139  // artificial and always present in the system.
7140  if (is_unique_type(is_type(decl)))
7141  continue;
7142 
7143  ABG_ASSERT(priv_->inserted_types_.find(qname)
7144  == priv_->inserted_types_.end());
7145  string_decl_base_sptr_map::const_iterator j =
7146  priv_->deleted_types_.find(qname);
7147  if (j != priv_->deleted_types_.end())
7148  {
7149  if (*j->second != *decl)
7150  priv_->changed_types_[qname] =
7151  compute_diff(j->second, decl, context());
7152  priv_->deleted_types_.erase(j);
7153  }
7154  else
7155  priv_->inserted_types_[qname] = decl;
7156  }
7157  else
7158  {
7159  ABG_ASSERT(priv_->inserted_decls_.find(qname)
7160  == priv_->inserted_decls_.end());
7161  string_decl_base_sptr_map::const_iterator j =
7162  priv_->deleted_decls_.find(qname);
7163  if (j != priv_->deleted_decls_.end())
7164  {
7165  if (*j->second != *decl)
7166  priv_->changed_decls_[qname] =
7167  compute_diff(j->second, decl, context());
7168  priv_->deleted_decls_.erase(j);
7169  }
7170  else
7171  priv_->inserted_decls_[qname] = decl;
7172  }
7173  }
7174  }
7175 
7176  sort_string_diff_sptr_map(priv_->changed_decls_,
7177  priv_->sorted_changed_decls_);
7178  sort_string_diff_sptr_map(priv_->changed_types_,
7179  priv_->sorted_changed_types_);
7180 
7181  // Populate removed types/decls lookup tables
7182  for (string_decl_base_sptr_map::const_iterator i =
7183  priv_->deleted_types_.begin();
7184  i != priv_->deleted_types_.end();
7185  ++i)
7186  {
7187  string_decl_base_sptr_map::const_iterator r =
7188  priv_->inserted_types_.find(i->first);
7189  if (r == priv_->inserted_types_.end())
7190  priv_->removed_types_[i->first] = i->second;
7191  }
7192  for (string_decl_base_sptr_map::const_iterator i =
7193  priv_->deleted_decls_.begin();
7194  i != priv_->deleted_decls_.end();
7195  ++i)
7196  {
7197  string_decl_base_sptr_map::const_iterator r =
7198  priv_->inserted_decls_.find(i->first);
7199  if (r == priv_->inserted_decls_.end())
7200  priv_->removed_decls_[i->first] = i->second;
7201  }
7202 
7203  // Populate added types/decls.
7204  for (string_decl_base_sptr_map::const_iterator i =
7205  priv_->inserted_types_.begin();
7206  i != priv_->inserted_types_.end();
7207  ++i)
7208  {
7209  string_decl_base_sptr_map::const_iterator r =
7210  priv_->deleted_types_.find(i->first);
7211  if (r == priv_->deleted_types_.end())
7212  priv_->added_types_[i->first] = i->second;
7213  }
7214  for (string_decl_base_sptr_map::const_iterator i =
7215  priv_->inserted_decls_.begin();
7216  i != priv_->inserted_decls_.end();
7217  ++i)
7218  {
7219  string_decl_base_sptr_map::const_iterator r =
7220  priv_->deleted_decls_.find(i->first);
7221  if (r == priv_->deleted_decls_.end())
7222  priv_->added_decls_[i->first] = i->second;
7223  }
7224 }
7225 
7226 /// Populate the vector of children node of the @ref diff base type
7227 /// sub-object of this instance of @ref scope_diff.
7228 ///
7229 /// The children node can then later be retrieved using
7230 /// diff::children_node().
7231 void
7233 {
7234  for (diff_sptrs_type::const_iterator i = changed_types().begin();
7235  i != changed_types().end();
7236  ++i)
7237  if (*i)
7238  append_child_node(*i);
7239 
7240  for (diff_sptrs_type::const_iterator i = changed_decls().begin();
7241  i != changed_decls().end();
7242  ++i)
7243  if (*i)
7244  append_child_node(*i);
7245 }
7246 
7247 /// Constructor for scope_diff
7248 ///
7249 /// @param first_scope the first scope to consider for the diff.
7250 ///
7251 /// @param second_scope the second scope to consider for the diff.
7252 ///
7253 /// @param ctxt the diff context to use. Note that this context
7254 /// object must stay alive at least during the life time of the
7255 /// current instance of @ref scope_diff. Otherwise memory corruption
7256 /// issues occur.
7258  scope_decl_sptr second_scope,
7259  diff_context_sptr ctxt)
7260  : diff(first_scope, second_scope, ctxt),
7261  priv_(new priv)
7262 {}
7263 
7264 /// Getter for the first scope of the diff.
7265 ///
7266 /// @return the first scope of the diff.
7267 const scope_decl_sptr
7269 {return dynamic_pointer_cast<scope_decl>(first_subject());}
7270 
7271 /// Getter for the second scope of the diff.
7272 ///
7273 /// @return the second scope of the diff.
7274 const scope_decl_sptr
7276 {return dynamic_pointer_cast<scope_decl>(second_subject());}
7277 
7278 /// Accessor of the edit script of the members of a scope.
7279 ///
7280 /// This edit script is computed using the equality operator that
7281 /// applies to shared_ptr<decl_base>.
7282 ///
7283 /// That has interesting consequences. For instance, consider two
7284 /// scopes S0 and S1. S0 contains a class C0 and S1 contains a class
7285 /// S0'. C0 and C0' have the same qualified name, but have different
7286 /// members. The edit script will consider that C0 has been deleted
7287 /// from S0 and that S0' has been inserted. This is a low level
7288 /// canonical representation of the changes; a higher level
7289 /// representation would give us a simpler way to say "the class C0
7290 /// has been modified into C0'". But worry not. We do have such
7291 /// higher representation as well; that is what changed_types() and
7292 /// changed_decls() is for.
7293 ///
7294 /// @return the edit script of the changes encapsulatd in this
7295 /// instance of scope_diff.
7296 const edit_script&
7298 {return priv_->member_changes_;}
7299 
7300 /// Accessor of the edit script of the members of a scope.
7301 ///
7302 /// This edit script is computed using the equality operator that
7303 /// applies to shared_ptr<decl_base>.
7304 ///
7305 /// That has interesting consequences. For instance, consider two
7306 /// scopes S0 and S1. S0 contains a class C0 and S1 contains a class
7307 /// S0'. C0 and C0' have the same qualified name, but have different
7308 /// members. The edit script will consider that C0 has been deleted
7309 /// from S0 and that S0' has been inserted. This is a low level
7310 /// canonical representation of the changes; a higher level
7311 /// representation would give us a simpler way to say "the class C0
7312 /// has been modified into C0'". But worry not. We do have such
7313 /// higher representation as well; that is what changed_types() and
7314 /// changed_decls() is for.
7315 ///
7316 /// @return the edit script of the changes encapsulatd in this
7317 /// instance of scope_diff.
7318 edit_script&
7320 {return priv_->member_changes_;}
7321 
7322 /// Accessor that eases the manipulation of the edit script associated
7323 /// to this instance. It returns the scope member that is reported
7324 /// (in the edit script) as deleted at a given index.
7325 ///
7326 /// @param i the index (in the edit script) of an element of the first
7327 /// scope that has been reported as being delete.
7328 ///
7329 /// @return the scope member that has been reported by the edit script
7330 /// as being deleted at index i.
7331 const decl_base_sptr
7333 {
7334  scope_decl_sptr scope = dynamic_pointer_cast<scope_decl>(first_subject());
7335  return scope->get_member_decls()[i];
7336 }
7337 
7338 /// Accessor that eases the manipulation of the edit script associated
7339 /// to this instance. It returns the scope member (of the first scope
7340 /// of this diff instance) that is reported (in the edit script) as
7341 /// deleted at a given iterator.
7342 ///
7343 /// @param i the iterator of an element of the first scope that has
7344 /// been reported as being delete.
7345 ///
7346 /// @return the scope member of the first scope of this diff that has
7347 /// been reported by the edit script as being deleted at iterator i.
7348 const decl_base_sptr
7349 scope_diff::deleted_member_at(vector<deletion>::const_iterator i) const
7350 {return deleted_member_at(i->index());}
7351 
7352 /// Accessor that eases the manipulation of the edit script associated
7353 /// to this instance. It returns the scope member (of the second
7354 /// scope of this diff instance) that is reported as being inserted
7355 /// from a given index.
7356 ///
7357 /// @param i the index of an element of the second scope this diff
7358 /// that has been reported by the edit script as being inserted.
7359 ///
7360 /// @return the scope member of the second scope of this diff that has
7361 /// been reported as being inserted from index i.
7362 const decl_base_sptr
7364 {
7365  scope_decl_sptr scope = dynamic_pointer_cast<scope_decl>(second_subject());
7366  return scope->get_member_decls()[i];
7367 }
7368 
7369 /// Accessor that eases the manipulation of the edit script associated
7370 /// to this instance. It returns the scope member (of the second
7371 /// scope of this diff instance) that is reported as being inserted
7372 /// from a given iterator.
7373 ///
7374 /// @param i the iterator of an element of the second scope this diff
7375 /// that has been reported by the edit script as being inserted.
7376 ///
7377 /// @return the scope member of the second scope of this diff that has
7378 /// been reported as being inserted from iterator i.
7379 const decl_base_sptr
7380 scope_diff::inserted_member_at(vector<unsigned>::const_iterator i)
7381 {return inserted_member_at(*i);}
7382 
7383 /// @return a sorted vector of the types which content has changed
7384 /// from the first scope to the other.
7385 const diff_sptrs_type&
7387 {return priv_->sorted_changed_types_;}
7388 
7389 /// @return a sorted vector of the decls which content has changed
7390 /// from the first scope to the other.
7391 const diff_sptrs_type&
7393 {return priv_->sorted_changed_decls_;}
7394 
7396 scope_diff::removed_types() const
7397 {return priv_->removed_types_;}
7398 
7400 scope_diff::removed_decls() const
7401 {return priv_->removed_decls_;}
7402 
7404 scope_diff::added_types() const
7405 {return priv_->added_types_;}
7406 
7408 scope_diff::added_decls() const
7409 {return priv_->added_decls_;}
7410 
7411 /// @return the pretty representation for the current instance of @ref
7412 /// scope_diff.
7413 const string&
7415 {
7416  if (diff::priv_->pretty_representation_.empty())
7417  {
7418  std::ostringstream o;
7419  o << "scope_diff["
7420  << first_subject()->get_pretty_representation()
7421  << ", "
7422  << second_subject()->get_pretty_representation()
7423  << "]";
7424  diff::priv_->pretty_representation_ = o.str();
7425  }
7426  return diff::priv_->pretty_representation_;
7427 }
7428 
7429 /// Return true iff the current diff node carries a change.
7430 ///
7431 /// Return true iff the current diff node carries a change.
7432 bool
7434 {
7435  // TODO: add the number of really removed/added stuff.
7436  return changed_types().size() + changed_decls().size();
7437 }
7438 
7439 /// @return the kind of local change carried by the current diff node.
7440 /// The value returned is zero if the current node carries no local
7441 /// change.
7442 enum change_kind
7444 {
7445  ir::change_kind k = ir::NO_CHANGE_KIND;
7446  if (!equals(*first_scope(), *second_scope(), &k))
7447  return k & ir::ALL_LOCAL_CHANGES_MASK;
7448  return ir::NO_CHANGE_KIND;
7449 }
7450 
7451 /// Report the changes of one scope against another.
7452 ///
7453 /// @param out the out stream to report the changes to.
7454 ///
7455 /// @param indent the string to use for indentation.
7456 void
7457 scope_diff::report(ostream& out, const string& indent) const
7458 {
7459  context()->get_reporter()->report(*this, out, indent);
7460 }
7461 
7462 /// Compute the diff between two scopes.
7463 ///
7464 /// Note that the two decls must have been created in the same @ref
7465 /// environment, otherwise, this function aborts.
7466 ///
7467 /// @param first the first scope to consider in computing the diff.
7468 ///
7469 /// @param second the second scope to consider in the diff
7470 /// computation. The second scope is diffed against the first scope.
7471 ///
7472 /// @param d a pointer to the diff object to populate with the
7473 /// computed diff.
7474 ///
7475 /// @return return the populated \a d parameter passed to this
7476 /// function.
7477 ///
7478 /// @param ctxt the diff context to use.
7481  const scope_decl_sptr second,
7482  scope_diff_sptr d,
7483  diff_context_sptr ctxt)
7484 {
7485  ABG_ASSERT(d->first_scope() == first && d->second_scope() == second);
7486 
7487  compute_diff(first->get_member_decls().begin(),
7488  first->get_member_decls().end(),
7489  second->get_member_decls().begin(),
7490  second->get_member_decls().end(),
7491  d->member_changes());
7492 
7493  d->ensure_lookup_tables_populated();
7494  d->context(ctxt);
7495 
7496  return d;
7497 }
7498 
7499 /// Compute the diff between two scopes.
7500 ///
7501 /// Note that the two decls must have been created in the same @ref
7502 /// environment, otherwise, this function aborts.
7503 ///
7504 /// @param first_scope the first scope to consider in computing the diff.
7505 ///
7506 /// @param second_scope the second scope to consider in the diff
7507 /// computation. The second scope is diffed against the first scope.
7508 ///
7509 /// @param ctxt the diff context to use.
7510 ///
7511 /// @return return the resulting diff
7513 compute_diff(const scope_decl_sptr first_scope,
7514  const scope_decl_sptr second_scope,
7515  diff_context_sptr ctxt)
7516 {
7517  scope_diff_sptr d(new scope_diff(first_scope, second_scope, ctxt));
7518  d = compute_diff(first_scope, second_scope, d, ctxt);
7519  ctxt->initialize_canonical_diff(d);
7520  return d;
7521 }
7522 
7523 //</scope_diff stuff>
7524 
7525 // <fn_parm_diff stuff>
7526 
7527 /// Constructor for the fn_parm_diff type.
7528 ///
7529 /// @param first the first subject of the diff.
7530 ///
7531 /// @param second the second subject of the diff.
7532 ///
7533 /// @param ctxt the context of the diff. Note that this context
7534 /// object must stay alive at least during the life time of the
7535 /// current instance of @ref fn_parm_diff. Otherwise memory
7536 /// corruption issues occur.
7537 fn_parm_diff::fn_parm_diff(const function_decl::parameter_sptr first,
7538  const function_decl::parameter_sptr second,
7539  diff_context_sptr ctxt)
7540  : decl_diff_base(first, second, ctxt),
7541  priv_(new priv)
7542 {
7543  ABG_ASSERT(first->get_index() == second->get_index());
7544  priv_->type_diff = compute_diff(first->get_type(),
7545  second->get_type(),
7546  ctxt);
7547  ABG_ASSERT(priv_->type_diff);
7548 }
7549 
7550 /// Getter for the first subject of this diff node.
7551 ///
7552 /// @return the first function_decl::parameter_sptr subject of this
7553 /// diff node.
7556 {return dynamic_pointer_cast<function_decl::parameter>(first_subject());}
7557 
7558 /// Getter for the second subject of this diff node.
7559 ///
7560 /// @return the second function_decl::parameter_sptr subject of this
7561 /// diff node.
7564 {return dynamic_pointer_cast<function_decl::parameter>(second_subject());}
7565 
7566 /// Getter for the diff representing the changes on the type of the
7567 /// function parameter involved in the current instance of @ref
7568 /// fn_parm_diff.
7569 ///
7570 /// @return a diff_sptr representing the changes on the type of the
7571 /// function parameter we are interested in.
7572 diff_sptr
7574 {return priv_->type_diff;}
7575 
7576 /// Build and return a textual representation of the current instance
7577 /// of @ref fn_parm_diff.
7578 ///
7579 /// @return the string representing the current instance of
7580 /// fn_parm_diff.
7581 const string&
7583 {
7584  if (diff::priv_->pretty_representation_.empty())
7585  {
7586  std::ostringstream o;
7587  o << "function_parameter_diff["
7588  << first_subject()->get_pretty_representation()
7589  << ", "
7590  << second_subject()->get_pretty_representation()
7591  << "]";
7592  diff::priv_->pretty_representation_ = o.str();
7593  }
7594  return diff::priv_->pretty_representation_;
7595 }
7596 
7597 /// Return true iff the current diff node carries a change.
7598 ///
7599 /// @return true iff the current diff node carries a change.
7600 bool
7602 {return *first_parameter() != *second_parameter();}
7603 
7604 /// Check if the current diff node carries a local change.
7605 ///
7606 /// @return the kind of local change carried by the current diff node.
7607 /// The value returned is zero if the current node carries no local
7608 /// change.
7609 enum change_kind
7611 {
7612  ir::change_kind k = ir::NO_CHANGE_KIND;
7613  if (!equals(*first_parameter(), *second_parameter(), &k))
7614  return k & ir::ALL_LOCAL_CHANGES_MASK;
7615  return ir::NO_CHANGE_KIND;
7616 }
7617 
7618 /// Emit a textual report about the current fn_parm_diff instance.
7619 ///
7620 /// @param out the output stream to emit the textual report to.
7621 ///
7622 /// @param indent the indentation string to use in the report.
7623 void
7624 fn_parm_diff::report(ostream& out, const string& indent) const
7625 {
7626  context()->get_reporter()->report(*this, out, indent);
7627 }
7628 
7629 /// Populate the vector of children nodes of the @ref diff base type
7630 /// sub-object of this instance of @ref fn_parm_diff.
7631 ///
7632 /// The children nodes can then later be retrieved using
7633 /// diff::children_nodes()
7634 void
7636 {
7637  if (type_diff())
7639 }
7640 
7641 /// Compute the difference between two function_decl::parameter_sptr;
7642 /// that is, between two function parameters. Return a resulting
7643 /// fn_parm_diff_sptr that represents the changes.
7644 ///
7645 /// Note that the two decls must have been created in the same @ref
7646 /// environment, otherwise, this function aborts.
7647 ///
7648 /// @param first the first subject of the diff.
7649 ///
7650 /// @param second the second subject of the diff.
7651 ///
7652 /// @param ctxt the context of the diff.
7653 ///
7654 /// @return fn_parm_diff_sptr the resulting diff node.
7657  const function_decl::parameter_sptr second,
7658  diff_context_sptr ctxt)
7659 {
7660  if (!first || !second)
7661  return fn_parm_diff_sptr();
7662 
7663  fn_parm_diff_sptr result(new fn_parm_diff(first, second, ctxt));
7664  ctxt->initialize_canonical_diff(result);
7665 
7666  return result;
7667 }
7668 // </fn_parm_diff stuff>
7669 
7670 // <function_type_diff stuff>
7671 
7672 void
7673 function_type_diff::ensure_lookup_tables_populated()
7674 {
7675  priv_->return_type_diff_ =
7676  compute_diff(first_function_type()->get_return_type(),
7677  second_function_type()->get_return_type(),
7678  context());
7679 
7680  string parm_name;
7682  for (vector<deletion>::const_iterator i =
7683  priv_->parm_changes_.deletions().begin();
7684  i != priv_->parm_changes_.deletions().end();
7685  ++i)
7686  {
7687  parm = *(first_function_type()->get_first_parm()
7688  + i->index());
7689  parm_name = parm->get_name_id();
7690  // If for a reason the type name is empty we want to know and
7691  // fix that.
7692  ABG_ASSERT(!parm_name.empty());
7693  priv_->deleted_parms_[parm_name] = parm;
7694  priv_->deleted_parms_by_id_[parm->get_index()] = parm;
7695  }
7696 
7697  for (vector<insertion>::const_iterator i =
7698  priv_->parm_changes_.insertions().begin();
7699  i != priv_->parm_changes_.insertions().end();
7700  ++i)
7701  {
7702  for (vector<unsigned>::const_iterator j =
7703  i->inserted_indexes().begin();
7704  j != i->inserted_indexes().end();
7705  ++j)
7706  {
7707  parm = *(second_function_type()->get_first_parm() + *j);
7708  parm_name = parm->get_name_id();
7709  // If for a reason the type name is empty we want to know and
7710  // fix that.
7711  ABG_ASSERT(!parm_name.empty());
7712  {
7713  string_parm_map::const_iterator k =
7714  priv_->deleted_parms_.find(parm_name);
7715  if (k != priv_->deleted_parms_.end())
7716  {
7717  if (*k->second != *parm)
7718  priv_->subtype_changed_parms_[parm_name] =
7719  compute_diff(k->second, parm, context());
7720  priv_->deleted_parms_.erase(parm_name);
7721  }
7722  else
7723  priv_->added_parms_[parm_name] = parm;
7724  }
7725  {
7726  unsigned_parm_map::const_iterator k =
7727  priv_->deleted_parms_by_id_.find(parm->get_index());
7728  if (k != priv_->deleted_parms_by_id_.end())
7729  {
7730  if (*k->second != *parm
7731  && (k->second->get_name_id() != parm_name))
7732  priv_->changed_parms_by_id_[parm->get_index()] =
7733  compute_diff(k->second, parm, context());
7734  priv_->added_parms_.erase(parm_name);
7735  priv_->deleted_parms_.erase(k->second->get_name_id());
7736  priv_->deleted_parms_by_id_.erase(parm->get_index());
7737  }
7738  else
7739  priv_->added_parms_by_id_[parm->get_index()] = parm;
7740  }
7741  }
7742  }
7743 
7744  sort_string_fn_parm_diff_sptr_map(priv_->subtype_changed_parms_,
7745  priv_->sorted_subtype_changed_parms_);
7746  sort_string_fn_parm_diff_sptr_map(priv_->changed_parms_by_id_,
7747  priv_->sorted_changed_parms_by_id_);
7748  sort_string_parm_map(priv_->deleted_parms_,
7749  priv_->sorted_deleted_parms_);
7750 
7751  sort_string_parm_map(priv_->added_parms_,
7752  priv_->sorted_added_parms_);
7753 }
7754 
7755 /// In the vector of deleted parameters, get the one that is at a given
7756 /// index.
7757 ///
7758 /// @param i the index of the deleted parameter to get.
7759 ///
7760 /// @return the parameter returned.
7762 function_type_diff::deleted_parameter_at(int i) const
7763 {return first_function_type()->get_parameters()[i];}
7764 
7765 /// Getter for the sorted vector of deleted parameters.
7766 ///
7767 /// @return the sorted vector of deleted parameters.
7768 const vector<function_decl::parameter_sptr>&
7770 {return priv_->sorted_deleted_parms_;}
7771 
7772 /// Getter for the sorted vector of added parameters .
7773 ///
7774 /// @return the sorted vector of added parameters.
7775 const vector<function_decl::parameter_sptr>&
7777 {return priv_->sorted_added_parms_;}
7778 
7779 /// In the vector of inserted parameters, get the one that is at a
7780 /// given index.
7781 ///
7782 /// @param i the index of the inserted parameter to get.
7783 ///
7784 /// @return the parameter returned.
7786 function_type_diff::inserted_parameter_at(int i) const
7787 {return second_function_type()->get_parameters()[i];}
7788 
7789 /// Consutrctor of the @ref function_type type.
7790 ///
7791 /// @param first the first @ref function_type subject of the diff to
7792 /// create.
7793 ///
7794 /// @param second the second @ref function_type subject of the diff to
7795 /// create.
7796 ///
7797 /// @param ctxt the diff context to be used by the newly created
7798 /// instance of function_type_diff. Note that this context object
7799 /// must stay alive at least during the life time of the current
7800 /// instance of @ref function_type_diff. Otherwise memory corruption
7801 /// issues occur.
7803  const function_type_sptr second,
7804  diff_context_sptr ctxt)
7805  : type_diff_base(first, second, ctxt),
7806  priv_(new priv)
7807 {}
7808 
7809 /// Getter for the first subject of the diff.
7810 ///
7811 /// @return the first function type involved in the diff.
7812 const function_type_sptr
7814 {return dynamic_pointer_cast<function_type>(first_subject());}
7815 
7816 /// Getter for the second subject of the diff.
7817 ///
7818 /// @return the second function type involved in the diff.
7819 const function_type_sptr
7821 {return dynamic_pointer_cast<function_type>(second_subject());}
7822 
7823 /// Getter for the diff of the return types of the two function types
7824 /// of the current diff.
7825 ///
7826 /// @return the diff of the return types of the two function types of
7827 /// the current diff.
7828 const diff_sptr
7830 {return priv_->return_type_diff_;}
7831 
7832 /// Getter for the map of function parameter changes of the current diff.
7833 ///
7834 /// @return a map of function parameter changes of the current diff.
7837 {return priv_->subtype_changed_parms_;}
7838 
7839 /// Getter for the map of parameters that got removed.
7840 ///
7841 /// @return the map of parameters that got removed.
7842 const string_parm_map&
7844 {return priv_->deleted_parms_;}
7845 
7846 /// Getter for the map of parameters that got added.
7847 ///
7848 /// @return the map of parameters that got added.
7849 const string_parm_map&
7851 {return priv_->added_parms_;}
7852 
7853 /// Build and return a copy of a pretty representation of the current
7854 /// instance of @ref function_type_diff.
7855 ///
7856 /// @return a copy of the pretty representation of the current
7857 /// instance of @ref function_type_diff.
7858 const string&
7860 {
7861  if (diff::priv_->pretty_representation_.empty())
7862  {
7863  std::ostringstream o;
7864  o << "function_type_diff["
7866  << ", "
7868  << "]";
7869  diff::priv_->pretty_representation_ = o.str();
7870  }
7871  return diff::priv_->pretty_representation_;
7872 }
7873 
7874 /// Test if the current diff node carries changes.
7875 ///
7876 /// @return true iff the current diff node carries changes.
7877 bool
7879 {return *first_function_type() != *second_function_type();}
7880 
7881 /// Test if the current diff node carries local changes.
7882 ///
7883 /// A local change is a change that is carried by this diff node, not
7884 /// by any of its children nodes.
7885 ///
7886 /// @return the kind of local change carried by the current diff node.
7887 /// The value returned is zero if the current node carries no local
7888 /// change.
7889 enum change_kind
7891 {
7892  ir::change_kind k = ir::NO_CHANGE_KIND;
7894  return k & ir::ALL_LOCAL_CHANGES_MASK;
7895  return ir::NO_CHANGE_KIND;
7896 }
7897 
7898 /// Build and emit a textual report about the current @ref
7899 /// function_type_diff instance.
7900 ///
7901 /// @param out the output stream.
7902 ///
7903 /// @param indent the indentation string to use.
7904 void
7905 function_type_diff::report(ostream& out, const string& indent) const
7906 {
7907  context()->get_reporter()->report(*this, out, indent);
7908 }
7909 
7910 /// Populate the vector of children node of the @ref diff base type
7911 /// sub-object of this instance of @ref function_type_diff.
7912 ///
7913 /// The children node can then later be retrieved using
7914 /// diff::children_node().
7915 void
7917 {
7918  if (diff_sptr d = return_type_diff())
7919  append_child_node(d);
7920 
7921  for (vector<fn_parm_diff_sptr>::const_iterator i =
7922  priv_->sorted_subtype_changed_parms_.begin();
7923  i != priv_->sorted_subtype_changed_parms_.end();
7924  ++i)
7925  if (diff_sptr d = *i)
7926  append_child_node(d);
7927 
7928  for (vector<fn_parm_diff_sptr>::const_iterator i =
7929  priv_->sorted_changed_parms_by_id_.begin();
7930  i != priv_->sorted_changed_parms_by_id_.end();
7931  ++i)
7932  if (diff_sptr d = *i)
7933  append_child_node(d);
7934 }
7935 
7936 /// Compute the diff between two instances of @ref function_type.
7937 ///
7938 /// Note that the two types must have been created in the same @ref
7939 /// environment, otherwise, this function aborts.
7940 ///
7941 /// @param first the first @ref function_type to consider for the diff.
7942 ///
7943 /// @param second the second @ref function_type to consider for the diff.
7944 ///
7945 /// @param ctxt the diff context to use.
7946 ///
7947 /// @return the resulting diff between the two @ref function_type.
7950  const function_type_sptr second,
7951  diff_context_sptr ctxt)
7952 {
7953  if (!first || !second)
7954  {
7955  // TODO: implement this for either first or second being NULL.
7956  return function_type_diff_sptr();
7957  }
7958 
7959  function_type_diff_sptr result(new function_type_diff(first, second, ctxt));
7960 
7961  diff_utils::compute_diff(first->get_first_parm(),
7962  first->get_parameters().end(),
7963  second->get_first_parm(),
7964  second->get_parameters().end(),
7965  result->priv_->parm_changes_);
7966 
7967  result->ensure_lookup_tables_populated();
7968 
7969  ctxt->initialize_canonical_diff(result);
7970 
7971  return result;
7972 }
7973 // </function_type_diff stuff>
7974 
7975 // <function_decl_diff stuff>
7976 
7977 /// Build the lookup tables of the diff, if necessary.
7978 void
7979 function_decl_diff::ensure_lookup_tables_populated()
7980 {
7981 }
7982 
7983 /// Populate the vector of children node of the @ref diff base type
7984 /// sub-object of this instance of @ref function_decl_diff.
7985 ///
7986 /// The children node can then later be retrieved using
7987 /// diff::children_node().
7988 void
7990 {
7991  if (diff_sptr d = type_diff())
7992  append_child_node(d);
7993 }
7994 
7995 /// Constructor for function_decl_diff
7996 ///
7997 /// @param first the first function considered by the diff.
7998 ///
7999 /// @param second the second function considered by the diff.
8000 ///
8001 /// @param ctxt the context of the diff. Note that this context
8002 /// object must stay alive at least during the life time of the
8003 /// current instance of @ref function_decl_diff. Otherwise memory
8004 /// corruption issues occur.
8006  const function_decl_sptr second,
8007  diff_context_sptr ctxt)
8008  : decl_diff_base(first, second, ctxt),
8009  priv_(new priv)
8010 {
8011 }
8012 
8013 /// @return the first function considered by the diff.
8014 const function_decl_sptr
8016 {return dynamic_pointer_cast<function_decl>(first_subject());}
8017 
8018 /// @return the second function considered by the diff.
8019 const function_decl_sptr
8021 {return dynamic_pointer_cast<function_decl>(second_subject());}
8022 
8024 function_decl_diff::type_diff() const
8025 {return priv_->type_diff_;}
8026 
8027 /// @return the pretty representation for the current instance of @ref
8028 /// function_decl_diff.
8029 const string&
8031 {
8032  if (diff::priv_->pretty_representation_.empty())
8033  {
8034  std::ostringstream o;
8035  o << "function_diff["
8036  << first_subject()->get_pretty_representation()
8037  << ", "
8038  << second_subject()->get_pretty_representation()
8039  << "]";
8040  diff::priv_->pretty_representation_ = o.str();
8041  }
8042  return diff::priv_->pretty_representation_;
8043 }
8044 
8045 /// Return true iff the current diff node carries a change.
8046 ///
8047 /// @return true iff the current diff node carries a change.
8048 bool
8050 {return *first_function_decl() != *second_function_decl();}
8051 
8052 /// @return the kind of local change carried by the current diff node.
8053 /// The value returned is zero if the current node carries no local
8054 /// change.
8055 enum change_kind
8057 {
8058  ir::change_kind k = ir::NO_CHANGE_KIND;
8060  return k & ir::ALL_LOCAL_CHANGES_MASK;
8061  return ir::NO_CHANGE_KIND;
8062 }
8063 
8064 /// Serialize a report of the changes encapsulated in the current
8065 /// instance of @ref function_decl_diff over to an output stream.
8066 ///
8067 /// @param out the output stream to serialize the report to.
8068 ///
8069 /// @param indent the string to use an an indentation prefix.
8070 void
8071 function_decl_diff::report(ostream& out, const string& indent) const
8072 {
8073  context()->get_reporter()->report(*this, out, indent);
8074 }
8075 
8076 /// Compute the diff between two function_decl.
8077 ///
8078 /// Note that the two decls must have been created in the same @ref
8079 /// environment, otherwise, this function aborts.
8080 ///
8081 /// @param first the first function_decl to consider for the diff
8082 ///
8083 /// @param second the second function_decl to consider for the diff
8084 ///
8085 /// @param ctxt the diff context to use.
8086 ///
8087 /// @return the computed diff
8090  const function_decl_sptr second,
8091  diff_context_sptr ctxt)
8092 {
8093  if (!first || !second)
8094  {
8095  // TODO: implement this for either first or second being NULL.
8096  return function_decl_diff_sptr();
8097  }
8098 
8099  function_type_diff_sptr type_diff = compute_diff(first->get_type(),
8100  second->get_type(),
8101  ctxt);
8102 
8103  function_decl_diff_sptr result(new function_decl_diff(first, second,
8104  ctxt));
8105  result->priv_->type_diff_ = type_diff;
8106 
8107  result->ensure_lookup_tables_populated();
8108 
8109  ctxt->initialize_canonical_diff(result);
8110 
8111  return result;
8112 }
8113 
8114 // </function_decl_diff stuff>
8115 
8116 // <type_decl_diff stuff>
8117 
8118 /// Constructor for type_decl_diff.
8119 ///
8120 /// @param first the first subject of the diff.
8121 ///
8122 /// @param second the second subject of the diff.
8123 ///
8124 /// @param ctxt the context of the diff. Note that this context
8125 /// object must stay alive at least during the life time of the
8126 /// current instance of @ref type_decl_diff. Otherwise memory
8127 /// corruption issues occur.
8128 type_decl_diff::type_decl_diff(const type_decl_sptr first,
8129  const type_decl_sptr second,
8130  diff_context_sptr ctxt)
8131  : type_diff_base(first, second, ctxt)
8132 {}
8133 
8134 /// Getter for the first subject of the type_decl_diff.
8135 ///
8136 /// @return the first type_decl involved in the diff.
8137 const type_decl_sptr
8139 {return dynamic_pointer_cast<type_decl>(first_subject());}
8140 
8141 /// Getter for the second subject of the type_decl_diff.
8142 ///
8143 /// @return the second type_decl involved in the diff.
8144 const type_decl_sptr
8146 {return dynamic_pointer_cast<type_decl>(second_subject());}
8147 
8148 /// @return the pretty representation for the current instance of @ref
8149 /// type_decl_diff.
8150 const string&
8152 {
8153  if (diff::priv_->pretty_representation_.empty())
8154  {
8155  std::ostringstream o;
8156  o << "type_decl_diff["
8157  << first_subject()->get_pretty_representation()
8158  << ", "
8159  << second_subject()->get_pretty_representation()
8160  << "]";
8161  diff::priv_->pretty_representation_ = o.str();
8162  }
8163  return diff::priv_->pretty_representation_;
8164 }
8165 /// Return true iff the current diff node carries a change.
8166 ///
8167 /// @return true iff the current diff node carries a change.
8168 bool
8170 {return first_type_decl() != second_type_decl();}
8171 
8172 /// @return the kind of local change carried by the current diff node.
8173 /// The value returned is zero if the current node carries no local
8174 /// change.
8175 enum change_kind
8177 {
8178  ir::change_kind k = ir::NO_CHANGE_KIND;
8179  if (!equals(*first_type_decl(), *second_type_decl(), &k))
8180  return k & ir::ALL_LOCAL_CHANGES_MASK;
8181  return ir::NO_CHANGE_KIND;
8182 }
8183 /// Ouputs a report of the differences between of the two type_decl
8184 /// involved in the type_decl_diff.
8185 ///
8186 /// @param out the output stream to emit the report to.
8187 ///
8188 /// @param indent the string to use for indentatino indent.
8189 void
8190 type_decl_diff::report(ostream& out, const string& indent) const
8191 {
8192  context()->get_reporter()->report(*this, out, indent);
8193 }
8194 
8195 /// Compute a diff between two type_decl.
8196 ///
8197 /// Note that the two types must have been created in the same @ref
8198 /// environment, otherwise, this function aborts.
8199 ///
8200 /// This function doesn't actually compute a diff. As a type_decl is
8201 /// very simple (unlike compound constructs like function_decl or
8202 /// class_decl) it's easy to just compare the components of the
8203 /// type_decl to know what has changed. Thus this function just
8204 /// builds and return a type_decl_diff object. The
8205 /// type_decl_diff::report function will just compare the components
8206 /// of the the two type_decl and display where and how they differ.
8207 ///
8208 /// @param first a pointer to the first type_decl to
8209 /// consider.
8210 ///
8211 /// @param second a pointer to the second type_decl to consider.
8212 ///
8213 /// @param ctxt the diff context to use.
8214 ///
8215 /// @return a pointer to the resulting type_decl_diff.
8218  const type_decl_sptr second,
8219  diff_context_sptr ctxt)
8220 {
8221  type_decl_diff_sptr result(new type_decl_diff(first, second, ctxt));
8222 
8223  // We don't need to actually compute a diff here as a type_decl
8224  // doesn't have complicated sub-components. type_decl_diff::report
8225  // just walks the members of the type_decls and display information
8226  // about the ones that have changed. On a similar note,
8227  // type_decl_diff::length returns 0 if the two type_decls are equal,
8228  // and 1 otherwise.
8229 
8230  ctxt->initialize_canonical_diff(result);
8231 
8232  return result;
8233 }
8234 
8235 // </type_decl_diff stuff>
8236 
8237 // <typedef_diff stuff>
8238 
8239 /// Populate the vector of children node of the @ref diff base type
8240 /// sub-object of this instance of @ref typedef_diff.
8241 ///
8242 /// The children node can then later be retrieved using
8243 /// diff::children_node().
8244 void
8247 
8248 /// Constructor for typedef_diff.
8249 ///
8250 /// @param first the first subject of the diff.
8251 ///
8252 /// @param second the second subject of the diff.
8253 ///
8254 /// @param underlying the underlying diff of the @ref typedef_diff.
8255 /// That is the diff between the underlying types of @p first and @p
8256 /// second.
8257 ///
8258 /// @param ctxt the context of the diff. Note that this context
8259 /// object must stay alive at least during the life time of the
8260 /// current instance of @ref typedef_diff. Otherwise memory
8261 /// corruption issues occur.
8262 typedef_diff::typedef_diff(const typedef_decl_sptr first,
8263  const typedef_decl_sptr second,
8264  const diff_sptr underlying,
8265  diff_context_sptr ctxt)
8266  : type_diff_base(first, second, ctxt),
8267  priv_(new priv(underlying))
8268 {}
8269 
8270 /// Getter for the firt typedef_decl involved in the diff.
8271 ///
8272 /// @return the first subject of the diff.
8273 const typedef_decl_sptr
8275 {return dynamic_pointer_cast<typedef_decl>(first_subject());}
8276 
8277 /// Getter for the second typedef_decl involved in the diff.
8278 ///
8279 /// @return the second subject of the diff.
8280 const typedef_decl_sptr
8282 {return dynamic_pointer_cast<typedef_decl>(second_subject());}
8283 
8284 /// Getter for the diff between the two underlying types of the
8285 /// typedefs.
8286 ///
8287 /// @return the diff object reprensenting the difference between the
8288 /// two underlying types of the typedefs.
8289 const diff_sptr
8291 {return priv_->underlying_type_diff_;}
8292 
8293 /// Setter for the diff between the two underlying types of the
8294 /// typedefs.
8295 ///
8296 /// @param d the new diff object reprensenting the difference between
8297 /// the two underlying types of the typedefs.
8298 void
8300 {priv_->underlying_type_diff_ = d;}
8301 
8302 /// @return the pretty representation for the current instance of @ref
8303 /// typedef_diff.
8304 const string&
8306 {
8307  if (diff::priv_->pretty_representation_.empty())
8308  {
8309  std::ostringstream o;
8310  o << "typedef_diff["
8311  << first_subject()->get_pretty_representation()
8312  << ", "
8313  << second_subject()->get_pretty_representation()
8314  << "]";
8315  diff::priv_->pretty_representation_ = o.str();
8316  }
8317  return diff::priv_->pretty_representation_;
8318 }
8319 
8320 /// Return true iff the current diff node carries a change.
8321 ///
8322 /// @return true iff the current diff node carries a change.
8323 bool
8325 {
8326  decl_base_sptr second = second_typedef_decl();
8327  return !(*first_typedef_decl() == *second);
8328 }
8329 
8330 /// @return the kind of local change carried by the current diff node.
8331 /// The value returned is zero if the current node carries no local
8332 /// change.
8333 enum change_kind
8335 {
8336  ir::change_kind k = ir::NO_CHANGE_KIND;
8338  return k & ir::ALL_LOCAL_CHANGES_MASK;
8339  return ir::NO_CHANGE_KIND;
8340 }
8341 
8342 /// Reports the difference between the two subjects of the diff in a
8343 /// serialized form.
8344 ///
8345 /// @param out the output stream to emit the report to.
8346 ///
8347 /// @param indent the indentation string to use.
8348 void
8349 typedef_diff::report(ostream& out, const string& indent) const
8350 {
8351  context()->get_reporter()->report(*this, out, indent);
8352 }
8353 
8354 /// Compute a diff between two typedef_decl.
8355 ///
8356 /// Note that the two types must have been created in the same @ref
8357 /// environment, otherwise, this function aborts.
8358 ///
8359 /// @param first a pointer to the first typedef_decl to consider.
8360 ///
8361 /// @param second a pointer to the second typedef_decl to consider.
8362 ///
8363 /// @param ctxt the diff context to use.
8364 ///
8365 /// @return a pointer to the the resulting typedef_diff.
8368  const typedef_decl_sptr second,
8369  diff_context_sptr ctxt)
8370 {
8371  diff_sptr d = compute_diff_for_types(first->get_underlying_type(),
8372  second->get_underlying_type(),
8373  ctxt);
8374  typedef_diff_sptr result(new typedef_diff(first, second, d, ctxt));
8375 
8376  ctxt->initialize_canonical_diff(result);
8377 
8378  return result;
8379 }
8380 
8381 /// Return the leaf underlying diff node of a @ref typedef_diff node.
8382 ///
8383 /// If the underlying diff node of a @ref typedef_diff node is itself
8384 /// a @ref typedef_diff node, then recursively look at the underlying
8385 /// diff nodes to get the first one that is not a a @ref typedef_diff
8386 /// node. This is what a leaf underlying diff node means.
8387 ///
8388 /// Otherwise, if the underlying diff node of @ref typedef_diff is
8389 /// *NOT* a @ref typedef_diff node, then just return the underlying
8390 /// diff node.
8391 ///
8392 /// And if the diff node considered is not a @ref typedef_diff node,
8393 /// then just return it.
8394 ///
8395 /// @return the leaf underlying diff node of a @p diff.
8396 const diff*
8398 {
8399  const typedef_diff* d = dynamic_cast<const typedef_diff*>(diff);
8400  if (!d)
8401  return diff;
8402 
8403  if (const typedef_diff* deef =
8404  dynamic_cast<const typedef_diff*>(d->underlying_type_diff().get()))
8406 
8407  return d->underlying_type_diff().get();
8408 }
8409 
8410 // </typedef_diff stuff>
8411 
8412 // <translation_unit_diff stuff>
8413 
8414 /// Constructor for translation_unit_diff.
8415 ///
8416 /// @param first the first translation unit to consider for this diff.
8417 ///
8418 /// @param second the second translation unit to consider for this diff.
8419 ///
8420 /// @param ctxt the context of the diff. Note that this context
8421 /// object must stay alive at least during the life time of the
8422 /// current instance of @ref translation_unit_diff. Otherwise memory
8423 /// corruption issues occur.
8425  translation_unit_sptr second,
8426  diff_context_sptr ctxt)
8427  : scope_diff(first->get_global_scope(), second->get_global_scope(), ctxt),
8428  priv_(new priv(first, second))
8429 {
8430 }
8431 
8432 /// Getter for the first translation unit of this diff.
8433 ///
8434 /// @return the first translation unit of this diff.
8437 {return priv_->first_;}
8438 
8439 /// Getter for the second translation unit of this diff.
8440 ///
8441 /// @return the second translation unit of this diff.
8444 {return priv_->second_;}
8445 
8446 /// Return true iff the current diff node carries a change.
8447 ///
8448 /// @return true iff the current diff node carries a change.
8449 bool
8451 {return scope_diff::has_changes();}
8452 
8453 /// @return the kind of local change carried by the current diff node.
8454 /// The value returned is zero if the current node carries no local
8455 /// change.
8456 enum change_kind
8458 {return ir::NO_CHANGE_KIND;}
8459 
8460 /// Report the diff in a serialized form.
8461 ///
8462 /// @param out the output stream to serialize the report to.
8463 ///
8464 /// @param indent the prefix to use as indentation for the report.
8465 void
8466 translation_unit_diff::report(ostream& out, const string& indent) const
8467 {scope_diff::report(out, indent);}
8468 
8469 /// Compute the diff between two translation_units.
8470 ///
8471 /// Note that the two translation units must have been created in the
8472 /// same @ref environment, otherwise, this function aborts.
8473 ///
8474 /// @param first the first translation_unit to consider.
8475 ///
8476 /// @param second the second translation_unit to consider.
8477 ///
8478 /// @param ctxt the diff context to use. If null, this function will
8479 /// create a new context and set to the diff object returned.
8480 ///
8481 /// @return the newly created diff object.
8484  const translation_unit_sptr second,
8485  diff_context_sptr ctxt)
8486 {
8487  ABG_ASSERT(first && second);
8488 
8489  if (!ctxt)
8490  ctxt.reset(new diff_context);
8491 
8492  // TODO: handle first or second having empty contents.
8493  translation_unit_diff_sptr tu_diff(new translation_unit_diff(first, second,
8494  ctxt));
8495  scope_diff_sptr sc_diff = dynamic_pointer_cast<scope_diff>(tu_diff);
8496 
8497  compute_diff(static_pointer_cast<scope_decl>(first->get_global_scope()),
8498  static_pointer_cast<scope_decl>(second->get_global_scope()),
8499  sc_diff,
8500  ctxt);
8501 
8502  ctxt->initialize_canonical_diff(tu_diff);
8503 
8504  return tu_diff;
8505 }
8506 
8507 // </translation_unit_diff stuff>
8508 
8509 // <diff_maps stuff>
8510 
8511 /// The private data of the @ref diff_maps type.
8512 struct diff_maps::priv
8513 {
8514  string_diff_ptr_map type_decl_diff_map_;
8515  string_diff_ptr_map enum_diff_map_;
8516  string_diff_ptr_map class_diff_map_;
8517  string_diff_ptr_map union_diff_map_;
8518  string_diff_ptr_map typedef_diff_map_;
8519  string_diff_ptr_map subrange_diff_map_;
8520  string_diff_ptr_map array_diff_map_;
8521  string_diff_ptr_map reference_diff_map_;
8522  string_diff_ptr_map function_type_diff_map_;
8523  string_diff_ptr_map function_decl_diff_map_;
8524  string_diff_ptr_map var_decl_diff_map_;
8525  string_diff_ptr_map distinct_diff_map_;
8526  string_diff_ptr_map fn_parm_diff_map_;
8527  diff_artifact_set_map_type impacted_artifacts_map_;
8528 }; // end struct diff_maps::priv
8529 
8530 /// Default constructor of the @ref diff_maps type.
8532  : priv_(new diff_maps::priv())
8533 {}
8534 
8535 diff_maps::~diff_maps() = default;
8536 
8537 /// Getter of the map that contains basic type diffs.
8538 ///
8539 /// @return the map that contains basic type diffs.
8540 const string_diff_ptr_map&
8542 {return priv_->type_decl_diff_map_;}
8543 
8544 /// Getter of the map that contains basic type diffs.
8545 ///
8546 /// @return the map that contains basic type diffs.
8549 {return priv_->type_decl_diff_map_;}
8550 
8551 /// Getter of the map that contains enum type diffs.
8552 ///
8553 /// @return the map that contains enum type diffs.
8554 const string_diff_ptr_map&
8556 {return priv_->enum_diff_map_;}
8557 
8558 /// Getter of the map that contains enum type diffs.
8559 ///
8560 /// @return the map that contains enum type diffs.
8563 {return priv_->enum_diff_map_;}
8564 
8565 /// Getter of the map that contains class type diffs.
8566 ///
8567 /// @return the map that contains class type diffs.
8568 const string_diff_ptr_map&
8570 {return priv_->class_diff_map_;}
8571 
8572 /// Getter of the map that contains class type diffs.
8573 ///
8574 /// @return the map that contains class type diffs.
8577 {return priv_->class_diff_map_;}
8578 
8579 /// Getter of the map that contains union type diffs.
8580 ///
8581 /// @return the map that contains union type diffs.
8582 const string_diff_ptr_map&
8584 {return priv_->union_diff_map_;}
8585 
8586 /// Getter of the map that contains union type diffs.
8587 ///
8588 /// @return the map that contains union type diffs.
8591 {return priv_->union_diff_map_;}
8592 
8593 /// Getter of the map that contains typedef type diffs.
8594 ///
8595 /// @return the map that contains typedef type diffs.
8596 const string_diff_ptr_map&
8598 {return priv_->typedef_diff_map_;}
8599 
8600 /// Getter of the map that contains typedef type diffs.
8601 ///
8602 /// @return the map that contains typedef type diffs.
8605 {return priv_->typedef_diff_map_;}
8606 
8607 /// Getter of the map that contains subrange type diffs.
8608 ///
8609 /// @return the map that contains subrange type diffs.
8610 const string_diff_ptr_map&
8612 {return priv_->subrange_diff_map_;}
8613 
8614 /// Getter of the map that contains subrange type diffs.
8615 ///
8616 /// @return the map that contains subrange type diffs.
8619 {return priv_->subrange_diff_map_;}
8620 
8621 /// Getter of the map that contains array type diffs.
8622 ///
8623 /// @return the map that contains array type diffs.
8624 const string_diff_ptr_map&
8626 {return priv_->array_diff_map_;}
8627 
8628 /// Getter of the map that contains array type diffs.
8629 ///
8630 /// @return the map that contains array type diffs.
8633 {return priv_->array_diff_map_;}
8634 
8635 /// Getter of the map that contains reference type diffs.
8636 ///
8637 /// @return the map that contains reference type diffs.
8638 const string_diff_ptr_map&
8640 {return priv_->reference_diff_map_;}
8641 
8642 /// Getter of the map that contains reference type diffs.
8643 ///
8644 /// @return the map that contains reference type diffs.
8647 {{return priv_->reference_diff_map_;}}
8648 
8649 /// Getter of the map that contains function parameter diffs.
8650 ///
8651 /// @return the map that contains function parameter diffs.
8652 const string_diff_ptr_map&
8654 {return priv_->fn_parm_diff_map_;}
8655 
8656 /// Getter of the map that contains function parameter diffs.
8657 ///
8658 /// @return the map that contains function parameter diffs.
8661 {return priv_->fn_parm_diff_map_;}
8662 
8663 /// Getter of the map that contains function type diffs.
8664 ///
8665 /// @return the map that contains function type diffs.
8666 const string_diff_ptr_map&
8668 {return priv_->function_type_diff_map_;}
8669 
8670 /// Getter of the map that contains function type diffs.
8671 ///
8672 /// @return the map that contains function type diffs.
8675 {return priv_->function_type_diff_map_;}
8676 
8677 /// Getter of the map that contains function decl diffs.
8678 ///
8679 /// @return the map that contains function decl diffs.
8680 const string_diff_ptr_map&
8682 {return priv_->function_decl_diff_map_;}
8683 
8684 /// Getter of the map that contains function decl diffs.
8685 ///
8686 /// @return the map that contains function decl diffs.
8689 {return priv_->function_decl_diff_map_;}
8690 
8691 /// Getter of the map that contains var decl diffs.
8692 ///
8693 /// @return the map that contains var decl diffs.
8694 const string_diff_ptr_map&
8696 {return priv_->var_decl_diff_map_;}
8697 
8698 /// Getter of the map that contains var decl diffs.
8699 ///
8700 /// @return the map that contains var decl diffs.
8703 {return priv_->var_decl_diff_map_;}
8704 
8705 /// Getter of the map that contains distinct diffs.
8706 ///
8707 /// @return the map that contains distinct diffs.
8708 const string_diff_ptr_map&
8710 {return priv_->distinct_diff_map_;}
8711 
8712 /// Getter of the map that contains distinct diffs.
8713 ///
8714 /// @return the map that contains distinct diffs.
8717 {return priv_->distinct_diff_map_;}
8718 
8719 /// Insert a new diff node into the current instance of @ref diff_maps.
8720 ///
8721 /// @param dif the new diff node to insert into the @ref diff_maps.
8722 ///
8723 /// @param impacted_iface the interface (global function or variable)
8724 /// currently being analysed that led to analysing the diff node @p
8725 /// dif. In other words, this is the interface impacted by the diff
8726 /// node @p dif. Note that this can be nil in cases where we are
8727 /// directly analysing changes to a type that is not reachable from
8728 /// any global function or variable.
8729 ///
8730 /// @return true iff the diff node could be added to the current
8731 /// instance of @ref diff_maps.
8732 bool
8734  const type_or_decl_base_sptr& impacted_iface)
8735 {
8736  string n = get_pretty_representation(dif->first_subject(),
8737  /*internal=*/true);
8738  if (const type_decl_diff *d = is_diff_of_basic_type(dif))
8739  get_type_decl_diff_map()[n] = const_cast<type_decl_diff*>(d);
8740  else if (const enum_diff *d = is_enum_diff(dif))
8741  get_enum_diff_map()[n] = const_cast<enum_diff*>(d);
8742  else if (const class_diff *d = is_class_diff(dif))
8743  get_class_diff_map()[n] = const_cast<class_diff*>(d);
8744  else if (const union_diff *d = is_union_diff(dif))
8745  get_union_diff_map()[n] = const_cast<union_diff*>(d);
8746  else if (const typedef_diff *d = is_typedef_diff(dif))
8747  get_typedef_diff_map()[n] = const_cast<typedef_diff*>(d);
8748  else if (const subrange_diff *d = is_subrange_diff(dif))
8749  get_subrange_diff_map()[n] = const_cast<subrange_diff*>(d);
8750  else if (const array_diff *d = is_array_diff(dif))
8751  get_array_diff_map()[n] = const_cast<array_diff*>(d);
8752  else if (const reference_diff *d = is_reference_diff(dif))
8753  get_reference_diff_map()[n] = const_cast<reference_diff*>(d);
8754  else if (const fn_parm_diff *d = is_fn_parm_diff(dif))
8755  get_fn_parm_diff_map()[n] = const_cast<fn_parm_diff*>(d);
8756  else if (const function_type_diff *d = is_function_type_diff(dif))
8757  get_function_type_diff_map()[n] = const_cast<function_type_diff*>(d);
8758  else if (const var_diff *d = is_var_diff(dif))
8759  get_var_decl_diff_map()[n] = const_cast<var_diff*>(d);
8760  else if (const function_decl_diff *d = is_function_decl_diff(dif))
8761  get_function_decl_diff_map()[n] = const_cast<function_decl_diff*>(d);
8762  else if (const distinct_diff *d = is_distinct_diff(dif))
8763  get_distinct_diff_map()[n] = const_cast<distinct_diff*>(d);
8764  else if (is_base_diff(dif))
8765  // we silently drop this case.
8766  return true;
8767  else
8769 
8770  // Update the map that associates this diff node to the set of
8771  // interfaces it impacts.
8772 
8773  if (impacted_iface)
8774  {
8775  diff_artifact_set_map_type::iterator i =
8776  priv_->impacted_artifacts_map_.find(dif);
8777 
8778  if (i == priv_->impacted_artifacts_map_.end())
8779  {
8781  set.insert(impacted_iface);
8782  priv_->impacted_artifacts_map_[dif] = set;
8783  }
8784  else
8785  i->second.insert(impacted_iface);
8786  }
8787 
8788  return true;
8789 }
8790 
8791 /// Lookup the interfaces that are impacted by a given leaf diff node.
8792 ///
8793 /// @param d the diff node to consider.
8794 ///
8795 /// @return the set of artifacts impacted by @p d.
8798 {
8799  diff_artifact_set_map_type::iterator i =
8800  priv_->impacted_artifacts_map_.find(d);
8801 
8802  if (i == priv_->impacted_artifacts_map_.end())
8803  return 0;
8804 
8805  return &i->second;
8806 }
8807 
8808 //
8809 // </diff_maps stuff>
8810 
8811 /// Constructor for the @ref diff_stat type.
8812 ///
8813 /// @param ctxt the context of the corpus diff. Note that this
8814 /// context object must stay alive at least during the life time of
8815 /// the current instance of @ref corpus_diff::diff_stats. Otherwise
8816 /// memory corruption issues occur.
8817 corpus_diff::diff_stats::diff_stats(diff_context_sptr ctxt)
8818  : priv_(new priv(ctxt))
8819 {}
8820 
8821 /// Getter for the number of functions removed.
8822 ///
8823 /// @return the number of functions removed.
8824 size_t
8826 {return priv_->num_func_removed;}
8827 
8828 /// Setter for the number of functions removed.
8829 ///
8830 /// @param n the new number of functions removed.
8831 void
8833 {priv_->num_func_removed = n;}
8834 
8835 /// Getter for the number of removed functions that have been filtered
8836 /// out.
8837 ///
8838 /// @return the number of removed functions that have been filtered
8839 /// out.
8840 size_t
8842 {
8843  if (priv_->ctxt() && !priv_->ctxt()->show_deleted_fns())
8844  return num_func_removed();
8845  return priv_->num_removed_func_filtered_out;
8846 }
8847 
8848 /// Setter for the number of removed functions that have been filtered
8849 /// out.
8850 ///
8851 /// @param t the new value.
8852 void
8854 {priv_->num_removed_func_filtered_out = t;}
8855 
8856 /// Getter for the net number of function removed.
8857 ///
8858 /// This is the difference between the number of functions removed and
8859 /// the number of functons removed that have been filtered out.
8860 ///
8861 /// @return the net number of function removed.
8862 size_t
8864 {
8865  ABG_ASSERT(num_func_removed() >= num_removed_func_filtered_out());
8866  return num_func_removed() - num_removed_func_filtered_out();
8867 }
8868 
8869 /// Getter for the number of functions added.
8870 ///
8871 /// @return the number of functions added.
8872 size_t
8874 {return priv_->num_func_added;}
8875 
8876 /// Setter for the number of functions added.
8877 ///
8878 /// @param n the new number of functions added.
8879 void
8881 {priv_->num_func_added = n;}
8882 
8883 /// Getter for the number of added function that have been filtered out.
8884 ///
8885 /// @return the number of added function that have been filtered out.
8886 size_t
8888 {
8889  if (priv_->ctxt() && !priv_->ctxt()->show_added_fns())
8890  return num_func_added();
8891  return priv_->num_added_func_filtered_out;
8892 }
8893 
8894 /// Setter for the number of added function that have been filtered
8895 /// out.
8896 ///
8897 /// @param n the new value.
8898 void
8900 {priv_->num_added_func_filtered_out = n;}
8901 
8902 /// Getter for the net number of added functions.
8903 ///
8904 /// The net number of added functions is the difference between the
8905 /// number of added functions and the number of added functions that
8906 /// have been filtered out.
8907 ///
8908 /// @return the net number of added functions.
8909 size_t
8911 {
8912  ABG_ASSERT(num_func_added() >= num_added_func_filtered_out());
8913  return num_func_added() - num_added_func_filtered_out();
8914 }
8915 
8916 /// Getter for the number of functions that have a change in one of
8917 /// their sub-types.
8918 ///
8919 /// @return the number of functions that have a change in one of their
8920 /// sub-types.
8921 size_t
8923 {return priv_->num_func_changed;}
8924 
8925 /// Setter for the number of functions that have a change in one of
8926 /// their sub-types.
8927 ///
8928 /// @@param n the new number of functions that have a change in one of
8929 /// their sub-types.
8930 void
8932 {priv_->num_func_changed = n;}
8933 
8934 /// Getter for the number of functions that have a change in one of
8935 /// their sub-types, and that have been filtered out.
8936 ///
8937 /// @return the number of functions that have a change in one of their
8938 /// sub-types, and that have been filtered out.
8939 size_t
8941 {return priv_->num_changed_func_filtered_out;}
8942 
8943 /// Setter for the number of functions that have a change in one of
8944 /// their sub-types, and that have been filtered out.
8945 ///
8946 /// @param n the new number of functions that have a change in one of their
8947 /// sub-types, and that have been filtered out.
8948 void
8950 {priv_->num_changed_func_filtered_out = n;}
8951 
8952 /// Getter for the number of functions that carry virtual member
8953 /// offset changes.
8954 ///
8955 /// @return the number of functions that carry virtual member changes.
8956 size_t
8958 {return priv_->num_func_with_virt_offset_changes;}
8959 
8960 /// Setter for the number of functions that carry virtual member
8961 /// offset changes.
8962 ///
8963 /// @param n the new number of functions that carry virtual member
8964 /// offset. changes.
8965 void
8967 {priv_->num_func_with_virt_offset_changes = n;}
8968 
8969 /// Getter for the number of functions with local harmful changes.
8970 ///
8971 /// A local harmful change is a harmful change that is local to the
8972 /// function itself or is local to a return or parameter type.
8973 ///
8974 /// @return the number of functions with local harmful changes.
8975 size_t
8977 {return priv_->num_func_with_local_harmful_changes;}
8978 
8979 /// Setter for the number of functions with local harmful changes.
8980 ///
8981 /// A local harmful change is a harmful change that is local to the
8982 /// function itself or is local to a return or parameter type.
8983 ///
8984 /// @param n the number of functions with local harmful changes.
8985 void
8987 {priv_->num_func_with_local_harmful_changes = n;}
8988 
8989 /// Getter for the number of variables with local harmful changes.
8990 ///
8991 /// A local harmful change is a harmful change that is local to the
8992 /// variable itself or is local to its type.
8993 ///
8994 /// @return the number of variables with local harmful changes.
8995 size_t
8997 {return priv_->num_var_with_local_harmful_changes;}
8998 
8999 /// Setter for the number of variables with local harmful changes.
9000 ///
9001 /// A local harmful change is a harmful change that is local to the
9002 /// variable itself or is local to its type.
9003 ///
9004 /// @param n the number of variables with local harmful changes.
9005 void
9007 {priv_->num_var_with_local_harmful_changes = n;}
9008 
9009 /// Getter for the number of functions with incompatible changes.
9010 ///
9011 /// @return the number of functions with incompatible changes.
9012 size_t
9014 {return priv_->num_func_with_incompatible_changes;}
9015 
9016 /// Setter for the number of functions with incompatible changes.
9017 ///
9018 /// @param n the number of functions with incompatible changes.
9019 void
9021 {priv_->num_func_with_incompatible_changes = n;}
9022 
9023 /// Getter for the number of variables with incompatible changes.
9024 ///
9025 /// @return the number of variables with incompatible changes.
9026 size_t
9028 {return priv_->num_var_with_incompatible_changes;}
9029 
9030 /// Setter for the number of variables with incompatible changes.
9031 ///
9032 /// @param n the number of variables with incompatible changes.
9033 void
9035 {priv_->num_var_with_incompatible_changes = n;}
9036 
9037 /// Getter for the number of functions that have a change in their
9038 /// sub-types, minus the number of these functions that got filtered
9039 /// out from the diff.
9040 ///
9041 /// @return for the the number of functions that have a change in
9042 /// their sub-types, minus the number of these functions that got
9043 /// filtered out from the diff.
9044 size_t
9046 {return num_func_changed() - num_changed_func_filtered_out();}
9047 
9048 /// Getter of the net number of functions with changes that are not
9049 /// incompatible.
9050 ///
9051 /// @return net number of functions with changes that are not
9052 /// incompatible.
9053 size_t
9055 {return net_num_func_changed() - num_func_with_incompatible_changes();}
9056 
9057 /// Getter for the number of variables removed.
9058 ///
9059 /// @return the number of variables removed.
9060 size_t
9062 {return priv_->num_vars_removed;}
9063 
9064 /// Setter for the number of variables removed.
9065 ///
9066 /// @param n the new number of variables removed.
9067 void
9069 {priv_->num_vars_removed = n;}
9070 
9071 /// Getter for the number removed variables that have been filtered
9072 /// out.
9073 ///
9074 /// @return the number removed variables that have been filtered out.
9075 size_t
9077 {
9078  if (priv_->ctxt() && !priv_->ctxt()->show_deleted_vars())
9079  return num_vars_removed();
9080  return priv_->num_removed_vars_filtered_out;
9081 }
9082 
9083 /// Setter for the number of removed variables that have been filtered
9084 /// out.
9085 ///
9086 /// @param n the new value.
9087 void
9089 {priv_->num_removed_vars_filtered_out = n;}
9090 
9091 /// Getter for the net number of removed variables.
9092 ///
9093 /// The net number of removed variables is the difference between the
9094 /// number of removed variables and the number of removed variables
9095 /// that have been filtered out.
9096 ///
9097 /// @return the net number of removed variables.
9098 size_t
9100 {
9101  ABG_ASSERT(num_vars_removed() >= num_removed_vars_filtered_out());
9102  return num_vars_removed() - num_removed_vars_filtered_out();
9103 }
9104 
9105 /// Getter for the number of variables added.
9106 ///
9107 /// @return the number of variables added.
9108 size_t
9110 {return priv_->num_vars_added;}
9111 
9112 /// Setter for the number of variables added.
9113 ///
9114 /// @param n the new number of variables added.
9115 void
9117 {priv_->num_vars_added = n;}
9118 
9119 /// Getter for the number of added variables that have been filtered
9120 /// out.
9121 ///
9122 /// @return the number of added variables that have been filtered out.
9123 size_t
9125 {
9126  if (priv_->ctxt() && !priv_->ctxt()->show_added_vars())
9127  return num_vars_added();
9128  return priv_->num_added_vars_filtered_out;
9129 }
9130 
9131 /// Setter for the number of added variables that have been filtered
9132 /// out.
9133 ///
9134 /// @param n the new value.
9135 void
9137 {priv_->num_added_vars_filtered_out = n;}
9138 
9139 /// Getter for the net number of added variables.
9140 ///
9141 /// The net number of added variables is the difference between the
9142 /// number of added variables and the number of added variables that
9143 /// have been filetered out.
9144 ///
9145 /// @return the net number of added variables.
9146 size_t
9148 {
9149  ABG_ASSERT(num_vars_added() >= num_added_vars_filtered_out());
9150  return num_vars_added() - num_added_vars_filtered_out();
9151 }
9152 
9153 /// Getter for the number of variables that have a change in one of
9154 /// their sub-types.
9155 ///
9156 /// @return the number of variables that have a change in one of their
9157 /// sub-types.
9158 size_t
9160 {return priv_->num_vars_changed;}
9161 
9162 /// Setter for the number of variables that have a change in one of
9163 /// their sub-types.
9164 ///
9165 /// @param n the new number of variables that have a change in one of
9166 /// their sub-types.
9167 void
9169 {priv_->num_vars_changed = n;}
9170 
9171 /// Getter for the number of variables that have a change in one of
9172 /// their sub-types, and that have been filtered out.
9173 ///
9174 /// @return the number of functions that have a change in one of their
9175 /// sub-types, and that have been filtered out.
9176 size_t
9178 {return priv_->num_changed_vars_filtered_out;}
9179 
9180 /// Setter for the number of variables that have a change in one of
9181 /// their sub-types, and that have been filtered out.
9182 ///
9183 /// @param n the new number of variables that have a change in one of their
9184 /// sub-types, and that have been filtered out.
9185 void
9187 {priv_->num_changed_vars_filtered_out = n;}
9188 
9189 /// Getter for the number of variables that have a change in their
9190 /// sub-types, minus the number of these variables that got filtered
9191 /// out from the diff.
9192 ///
9193 /// @return for the the number of variables that have a change in
9194 /// their sub-types, minus the number of these variables that got
9195 /// filtered out from the diff.
9196 size_t
9198 {return num_vars_changed() - num_changed_vars_filtered_out();}
9199 
9200 /// Getter of the net number of variables with changes that are not
9201 /// incompatible.
9202 ///
9203 /// @return net number of variables with changes that are not
9204 /// incompatible.
9205 size_t
9207 {return net_num_vars_changed() - num_var_with_incompatible_changes();}
9208 
9209 /// Getter for the number of function symbols (not referenced by any
9210 /// debug info) that got removed.
9211 ///
9212 /// @return the number of function symbols (not referenced by any
9213 /// debug info) that got removed.
9214 size_t
9216 {return priv_->num_func_syms_removed;}
9217 
9218 /// Setter for the number of function symbols (not referenced by any
9219 /// debug info) that got removed.
9220 ///
9221 /// @param n the number of function symbols (not referenced by any
9222 /// debug info) that got removed.
9223 void
9225 {priv_->num_func_syms_removed = n;}
9226 
9227 /// Getter for the number of removed function symbols, not referenced
9228 /// by debug info, that have been filtered out.
9229 ///
9230 /// @return the number of removed function symbols, not referenced by
9231 /// debug info, that have been filtered out.
9232 size_t
9234 {
9235  if (priv_->ctxt()
9236  && !priv_->ctxt()->show_symbols_unreferenced_by_debug_info())
9237  return num_func_syms_removed();
9238  return priv_->num_removed_func_syms_filtered_out;
9239 }
9240 
9241 /// Setter for the number of removed function symbols, not referenced
9242 /// by debug info, that have been filtered out.
9243 ///
9244 /// @param n the new the number of removed function symbols, not
9245 /// referenced by debug info, that have been filtered out.
9246 void
9248 {priv_->num_removed_func_syms_filtered_out = n;}
9249 
9250 /// Getter of the net number of removed function symbols that are not
9251 /// referenced by any debug info.
9252 ///
9253 /// This is the difference between the total number of removed
9254 /// function symbols and the number of removed function symbols that
9255 /// have been filteted out. Both numbers are for symbols not
9256 /// referenced by debug info.
9257 ///
9258 /// return the net number of removed function symbols that are not
9259 /// referenced by any debug info.
9260 size_t
9262 {
9263  ABG_ASSERT(num_func_syms_removed() >= num_removed_func_syms_filtered_out());
9264  return num_func_syms_removed() - num_removed_func_syms_filtered_out();
9265 }
9266 
9267 /// Getter for the number of function symbols (not referenced by any
9268 /// debug info) that got added.
9269 ///
9270 /// @return the number of function symbols (not referenced by any
9271 /// debug info) that got added.
9272 size_t
9274 {return priv_->num_func_syms_added;}
9275 
9276 /// Setter for the number of function symbols (not referenced by any
9277 /// debug info) that got added.
9278 ///
9279 /// @param n the new number of function symbols (not referenced by any
9280 /// debug info) that got added.
9281 void
9283 {priv_->num_func_syms_added = n;}
9284 
9285 /// Getter for the number of added function symbols, not referenced by
9286 /// any debug info, that have been filtered out.
9287 ///
9288 /// @return the number of added function symbols, not referenced by
9289 /// any debug info, that have been filtered out.
9290 size_t
9292 {
9293  if (priv_->ctxt()
9294  && !(priv_->ctxt()->show_added_symbols_unreferenced_by_debug_info()
9295  && priv_->ctxt()->show_symbols_unreferenced_by_debug_info()))
9296  return num_func_syms_added();
9297  return priv_->num_added_func_syms_filtered_out;
9298 }
9299 
9300 /// Setter for the number of added function symbols, not referenced by
9301 /// any debug info, that have been filtered out.
9302 ///
9303 /// @param n the new number of added function symbols, not referenced
9304 /// by any debug info, that have been filtered out.
9305 void
9307 {priv_->num_added_func_syms_filtered_out = n;}
9308 
9309 /// Getter of the net number of added function symbols that are not
9310 /// referenced by any debug info.
9311 ///
9312 /// This is the difference between the total number of added
9313 /// function symbols and the number of added function symbols that
9314 /// have been filteted out. Both numbers are for symbols not
9315 /// referenced by debug info.
9316 ///
9317 /// return the net number of added function symbols that are not
9318 /// referenced by any debug info.
9319 size_t
9321 {
9322  ABG_ASSERT(num_func_syms_added() >= num_added_func_syms_filtered_out());
9323  return num_func_syms_added()- num_added_func_syms_filtered_out();
9324 }
9325 
9326 /// Getter for the number of variable symbols (not referenced by any
9327 /// debug info) that got removed.
9328 ///
9329 /// @return the number of variable symbols (not referenced by any
9330 /// debug info) that got removed.
9331 size_t
9333 {return priv_->num_var_syms_removed;}
9334 
9335 /// Setter for the number of variable symbols (not referenced by any
9336 /// debug info) that got removed.
9337 ///
9338 /// @param n the number of variable symbols (not referenced by any
9339 /// debug info) that got removed.
9340 void
9342 {priv_->num_var_syms_removed = n;}
9343 
9344 /// Getter for the number of removed variable symbols, not referenced
9345 /// by any debug info, that have been filtered out.
9346 ///
9347 /// @return the number of removed variable symbols, not referenced
9348 /// by any debug info, that have been filtered out.
9349 size_t
9351 {
9352  if (priv_->ctxt()
9353  && !priv_->ctxt()->show_symbols_unreferenced_by_debug_info())
9354  return num_var_syms_removed();
9355  return priv_->num_removed_var_syms_filtered_out;
9356 }
9357 
9358 /// Setter for the number of removed variable symbols, not referenced
9359 /// by any debug info, that have been filtered out.
9360 ///
9361 /// @param n the number of removed variable symbols, not referenced by
9362 /// any debug info, that have been filtered out.
9363 void
9365 {priv_->num_removed_var_syms_filtered_out = n;}
9366 
9367 /// Getter of the net number of removed variable symbols that are not
9368 /// referenced by any debug info.
9369 ///
9370 /// This is the difference between the total number of removed
9371 /// variable symbols and the number of removed variable symbols that
9372 /// have been filteted out. Both numbers are for symbols not
9373 /// referenced by debug info.
9374 ///
9375 /// return the net number of removed variable symbols that are not
9376 /// referenced by any debug info.
9377 size_t
9379 {
9380  ABG_ASSERT(num_var_syms_removed() >= num_removed_var_syms_filtered_out());
9381  return num_var_syms_removed() - num_removed_var_syms_filtered_out();
9382 }
9383 
9384 /// Getter for the number of variable symbols (not referenced by any
9385 /// debug info) that got added.
9386 ///
9387 /// @return the number of variable symbols (not referenced by any
9388 /// debug info) that got added.
9389 size_t
9391 {return priv_->num_var_syms_added;}
9392 
9393 /// Setter for the number of variable symbols (not referenced by any
9394 /// debug info) that got added.
9395 ///
9396 /// @param n the new number of variable symbols (not referenced by any
9397 /// debug info) that got added.
9398 void
9400 {priv_->num_var_syms_added = n;}
9401 
9402 /// Getter for the number of added variable symbols, not referenced by
9403 /// any debug info, that have been filtered out.
9404 ///
9405 /// @return the number of added variable symbols, not referenced by
9406 /// any debug info, that have been filtered out.
9407 size_t
9409 {
9410  if (priv_->ctxt()
9411  && !(priv_->ctxt()->show_added_symbols_unreferenced_by_debug_info()
9412  && priv_->ctxt()->show_symbols_unreferenced_by_debug_info()))
9413  return num_var_syms_added();
9414  return priv_->num_added_var_syms_filtered_out;
9415 }
9416 
9417 /// Setter for the number of added variable symbols, not referenced by
9418 /// any debug info, that have been filtered out.
9419 ///
9420 /// @param n the new number of added variable symbols, not referenced
9421 /// by any debug info, that have been filtered out.
9422 void
9424 {priv_->num_added_var_syms_filtered_out = n;}
9425 
9426 /// Getter of the net number of added variable symbols that are not
9427 /// referenced by any debug info.
9428 ///
9429 /// This is the difference between the total number of added
9430 /// variable symbols and the number of added variable symbols that
9431 /// have been filteted out. Both numbers are for symbols not
9432 /// referenced by debug info.
9433 ///
9434 /// return the net number of added variable symbols that are not
9435 /// referenced by any debug info.
9436 size_t
9438 {
9439  ABG_ASSERT(num_var_syms_added() >= num_added_var_syms_filtered_out());
9440  return num_var_syms_added() - num_added_var_syms_filtered_out();
9441 }
9442 
9443 /// Getter of the number of leaf type change diff nodes.
9444 ///
9445 /// @return the number of leaf type change diff nodes.
9446 size_t
9448 {return priv_->num_leaf_changes;}
9449 
9450 /// Setter of the number of leaf type change diff nodes.
9451 ///
9452 /// @param n the new number of leaf type change diff nodes.
9453 void
9455 {priv_->num_leaf_changes = n;}
9456 
9457 /// Getter of the number of leaf type change diff nodes that have been
9458 /// filtered out.
9459 ///
9460 /// @return the number of leaf type change diff nodes that have been
9461 size_t
9463 {return priv_->num_leaf_changes_filtered_out;}
9464 
9465 /// Setter of the number of leaf type change diff nodes that have been
9466 /// filtered out.
9467 ///
9468 /// @param n the new number of leaf type change diff nodes that have
9469 /// been filtered out.
9470 void
9472 {priv_->num_leaf_changes_filtered_out = n;}
9473 
9474 /// Getter of the net number of leaf change diff nodes.
9475 ///
9476 /// This is the difference between the total number of leaf change
9477 /// diff nodes, and the number of the leaf change diff nodes that have
9478 /// been filtered out.
9479 ///
9480 /// A leaf change is either a type change, a function change or a
9481 /// variable change.
9482 size_t
9484 {
9485  ABG_ASSERT(num_leaf_changes() >= num_leaf_changes_filtered_out());
9486  return num_leaf_changes() - num_leaf_changes_filtered_out();
9487 }
9488 
9489 /// Getter for the number of leaf type change diff nodes.
9490 ///
9491 /// @return the number of leaf type changes diff nodes.
9492 size_t
9494 {return priv_->num_leaf_type_changes;}
9495 
9496 /// Setter for the number of leaf type change diff nodes.
9497 ///
9498 /// @param n the new number of leaf type change diff nodes.
9499 void
9501 {priv_->num_leaf_type_changes = n;}
9502 
9503 /// Getter for the number of filtered out leaf type change diff nodes.
9504 ///
9505 /// @return the number of filtered out leaf type change diff nodes.
9506 size_t
9508 {return priv_->num_leaf_type_changes_filtered_out;}
9509 
9510 /// Setter for the number of filtered out leaf type change diff nodes.
9511 /// @param n the new number of filtered out leaf type change diff nodes.
9512 void
9514 {priv_->num_leaf_type_changes_filtered_out = n;}
9515 
9516 /// Getter for the net number of leaf type change diff nodes.
9517 ///
9518 /// This is the difference between the number of leaf type changes and
9519 /// the number of filtered out leaf type changes.
9520 ///
9521 /// @return the net number of leaf type change diff nodes.
9522 size_t
9524 {return num_leaf_type_changes() - num_leaf_type_changes_filtered_out();}
9525 
9526 /// Getter for the number of leaf function change diff nodes.
9527 ///
9528 /// @return the number of leaf function change diff nodes.
9529 size_t
9531 {return priv_->num_leaf_func_changes;}
9532 
9533 /// Setter for the number of leaf function change diff nodes.
9534 ///
9535 /// @param n the new number of leaf function change diff nodes.
9536 void
9538 {priv_->num_leaf_func_changes = n;}
9539 
9540 /// Getter for the number of leaf function diff nodes that carry
9541 /// incompatible changes.
9542 ///
9543 /// @return the number of leaf function diff nodes that carry
9544 /// incompatible changes.
9545 size_t
9547 {return priv_->num_leaf_func_with_incompatible_changes;}
9548 
9549 /// Setter for the number of leaf function diff nodes that carry
9550 /// incompatible changes.
9551 ///
9552 /// @param n the new number of leaf function diff nodes that carry
9553 /// incompatible changes.
9554 void
9556 {priv_->num_leaf_func_with_incompatible_changes = n;}
9557 
9558 /// Getter for the number of leaf function change diff nodes that were
9559 /// filtered out.
9560 ///
9561 /// @return the number of leaf function change diff nodes that were
9562 /// filtered out.
9563 size_t
9565 {return priv_->num_leaf_func_changes_filtered_out;}
9566 
9567 /// Setter for the number of leaf function change diff nodes that were
9568 /// filtered out.
9569 ///
9570 /// @param n the new number of leaf function change diff nodes that
9571 /// were filtered out.
9572 void
9574 {priv_->num_leaf_func_changes_filtered_out = n;}
9575 
9576 /// Getter for the net number of leaf function change diff nodes.
9577 ///
9578 /// This is the difference between the number of leaf function change
9579 /// diff nodes and the number of filtered out leaf function change
9580 /// diff nodes.
9581 ///
9582 /// @return the net number of leaf function change diff nodes.
9583 size_t
9585 {return num_leaf_func_changes() - num_leaf_func_changes_filtered_out();}
9586 
9587 /// Getter for the net number of leaf function diff nodes that carry
9588 /// changes that are NOT incompatible.
9589 ///
9590 /// @return net number of leaf function diff nodes that carry changes
9591 /// that are NOT incompatible.
9592 size_t
9594 {
9595  return (net_num_leaf_func_changes()
9596  - num_leaf_func_with_incompatible_changes());
9597 }
9598 
9599 /// Getter for the number of leaf variable change diff nodes.
9600 ///
9601 /// @return the number of leaf variable change diff nodes.
9602 size_t
9604 {return priv_->num_leaf_var_changes;}
9605 
9606 /// Setter for the number of leaf variable change diff nodes.
9607 ///
9608 /// @param n the number of leaf variable change diff nodes.
9609 void
9611 {priv_->num_leaf_var_changes = n;}
9612 
9613 /// Getter for the number of leaf variable diff nodes that carry
9614 /// incompatible changes.
9615 ///
9616 /// @return the number of leaf variable diff nodes that carry
9617 /// incompatible changes.
9618 size_t
9620 {return priv_->num_leaf_var_with_incompatible_changes;}
9621 
9622 /// Setter for the number of leaf variable diff nodes that carry
9623 /// incompatible changes.
9624 ///
9625 /// @param n the new number of leaf variable diff nodes that carry
9626 /// incompatible changes.
9627 void
9629 {priv_->num_leaf_var_with_incompatible_changes = n;}
9630 
9631 /// Getter of the number of added types that are unreachable from the
9632 /// public interface of the ABI corpus.
9633 ///
9634 /// Public interface means the set of defined and publicly exported
9635 /// functions and variables of the ABI corpus.
9636 ///
9637 /// @return the number of added types that are unreachable from the
9638 /// public interface of the ABI corpus.
9639 size_t
9641 {return priv_->num_added_unreachable_types;}
9642 
9643 /// Setter of the number of added types that are unreachable from the
9644 /// public interface (global functions or variables) of the ABI
9645 /// corpus.
9646 ///
9647 /// Public interface means the set of defined and publicly exported
9648 /// functions and variables of the ABI corpus.
9649 ///
9650 /// @param n the new number of added types that are unreachable from
9651 /// the public interface of the ABI corpus.
9652 void
9654 {priv_->num_added_unreachable_types = n;}
9655 
9656 /// Getter of the number of added types that are unreachable from
9657 /// public interfaces and that are filtered out by suppression
9658 /// specifications.
9659 ///
9660 /// @return the number of added types that are unreachable from public
9661 /// interfaces and that are filtered out by suppression
9662 /// specifications.
9663 size_t
9665 {return priv_->num_added_unreachable_types_filtered_out;}
9666 
9667 /// Setter of the number of added types that are unreachable from
9668 /// public interfaces and that are filtered out by suppression
9669 /// specifications.
9670 ///
9671 /// @param n the new number of added types that are unreachable from
9672 /// public interfaces and that are filtered out by suppression
9673 /// specifications.
9674 void
9676 {priv_->num_added_unreachable_types_filtered_out = n;}
9677 
9678 /// Getter of the number of added types that are unreachable from
9679 /// public interfaces and that are *NOT* filtered out by suppression
9680 /// specifications.
9681 ///
9682 /// @return the number of added types that are unreachable from public
9683 /// interfaces and that are *NOT* filtered out by suppression
9684 /// specifications.
9685 size_t
9687 {
9688  ABG_ASSERT(num_added_unreachable_types()
9689  >=
9690  num_added_unreachable_types_filtered_out());
9691 
9692  return (num_added_unreachable_types()
9693  -
9694  num_added_unreachable_types_filtered_out());
9695 }
9696 
9697 /// Getter of the number of removed types that are unreachable from
9698 /// the public interface of the ABI corpus.
9699 ///
9700 /// Public interface means the set of defined and publicly exported
9701 /// functions and variables of the ABI corpus.
9702 ///
9703 /// @return the number of removed types that are unreachable from
9704 /// the public interface of the ABI corpus.
9705 size_t
9707 {return priv_->num_removed_unreachable_types;}
9708 
9709 /// Setter of the number of removed types that are unreachable from
9710 /// the public interface of the ABI corpus.
9711 ///
9712 /// Public interface means the set of defined and publicly exported
9713 /// functions and variables of the ABI corpus.
9714 ///
9715 ///@param n the new number of removed types that are unreachable from
9716 /// the public interface of the ABI corpus.
9717 void
9719 {priv_->num_removed_unreachable_types = n;}
9720 
9721 /// Getter of the number of removed types that are not reachable from
9722 /// public interfaces and that have been filtered out by suppression
9723 /// specifications.
9724 ///
9725 /// @return the number of removed types that are not reachable from
9726 /// public interfaces and that have been filtered out by suppression
9727 /// specifications.
9728 size_t
9730 {return priv_->num_removed_unreachable_types_filtered_out;}
9731 
9732 /// Setter of the number of removed types that are not reachable from
9733 /// public interfaces and that have been filtered out by suppression
9734 /// specifications.
9735 ///
9736 /// @param n the new number of removed types that are not reachable
9737 /// from public interfaces and that have been filtered out by
9738 /// suppression specifications.
9739 void
9741 {priv_->num_removed_unreachable_types_filtered_out = n;}
9742 
9743 /// Getter of the number of removed types that are not reachable from
9744 /// public interfaces and that have *NOT* been filtered out by
9745 /// suppression specifications.
9746 ///
9747 /// @return the number of removed types that are not reachable from
9748 /// public interfaces and that have *NOT* been filtered out by
9749 /// suppression specifications.
9750 size_t
9752 {
9753  ABG_ASSERT(num_removed_unreachable_types()
9754  >=
9755  num_removed_unreachable_types_filtered_out());
9756 
9757  return (num_removed_unreachable_types()
9758  -
9759  num_removed_unreachable_types_filtered_out());
9760 }
9761 
9762 /// Getter of the number of changed types that are unreachable from
9763 /// the public interface of the ABI corpus.
9764 ///
9765 /// Public interface means the set of defined and publicly exported
9766 /// functions and variables of the ABI corpus.
9767 ///
9768 /// @return the number of changed types that are unreachable from the
9769 /// public interface of the ABI corpus.
9770 size_t
9772 {return priv_->num_changed_unreachable_types;}
9773 
9774 /// Setter of the number of changed types that are unreachable from
9775 /// the public interface of the ABI corpus.
9776 ///
9777 /// Public interface means the set of defined and publicly exported
9778 /// functions and variables of the ABI corpus.
9779 ///
9780 ///@param n the new number of changed types that are unreachable from
9781 /// the public interface of the ABI corpus.
9782 void
9784 {priv_->num_changed_unreachable_types = n;}
9785 
9786 /// Getter of the number of changed types that are unreachable from
9787 /// public interfaces and that have been filtered out by suppression
9788 /// specifications.
9789 ///
9790 /// @return the number of changed types that are unreachable from
9791 /// public interfaces and that have been filtered out by suppression
9792 /// specifications.
9793 size_t
9795 {return priv_->num_changed_unreachable_types_filtered_out;}
9796 
9797 /// Setter of the number of changed types that are unreachable from
9798 /// public interfaces and that have been filtered out by suppression
9799 /// specifications.
9800 ///
9801 /// @param n the new number of changed types that are unreachable from
9802 /// public interfaces and that have been filtered out by suppression
9803 /// specifications.
9804 void
9806 {priv_->num_changed_unreachable_types_filtered_out = n;}
9807 
9808 /// Getter of the number of changed types that are unreachable from
9809 /// public interfaces and that have *NOT* been filtered out by
9810 /// suppression specifications.
9811 ///
9812 /// @return the number of changed types that are unreachable from
9813 /// public interfaces and that have *NOT* been filtered out by
9814 /// suppression specifications.
9815 size_t
9817 {
9818  ABG_ASSERT(num_changed_unreachable_types()
9819  >=
9820  num_changed_unreachable_types_filtered_out());
9821 
9822  return (num_changed_unreachable_types()
9823  -
9824  num_changed_unreachable_types_filtered_out());
9825 }
9826 
9827 /// Getter for the number of leaf variable changes diff nodes that
9828 /// have been filtered out.
9829 ///
9830 /// @return the number of leaf variable changes diff nodes that have
9831 /// been filtered out.
9832 size_t
9834 {return priv_->num_leaf_var_changes_filtered_out;}
9835 
9836 /// Setter for the number of leaf variable changes diff nodes that
9837 /// have been filtered out.
9838 ///
9839 /// @param n the number of leaf variable changes diff nodes that have
9840 /// been filtered out.
9841 void
9843 {priv_->num_leaf_var_changes_filtered_out = n;}
9844 
9845 /// Getter for the net number of leaf variable change diff nodes.
9846 ///
9847 /// This the difference between the number of leaf variable change
9848 /// diff nodes and the number of filtered out leaf variable change
9849 /// diff nodes.
9850 ///
9851 /// @return the net number of leaf variable change diff nodes.
9852 size_t
9854 {return num_leaf_var_changes() - num_leaf_var_changes_filtered_out();}
9855 
9856 /// Getter for the net number of leaf variable diff nodes that carry
9857 /// changes that are NOT incompatible.
9858 ///
9859 /// @return the net number of leaf variable diff nodes that carry
9860 /// changes that are NOT incompatible.
9861 size_t
9863 {return net_num_leaf_var_changes() - num_leaf_var_with_incompatible_changes();}
9864 // <corpus_diff stuff>
9865 
9866 /// Getter of the context associated with this corpus.
9867 ///
9868 /// @return a smart pointer to the context associate with the corpus.
9871 {return ctxt_.lock();}
9872 
9873 /// Tests if the lookup tables are empty.
9874 ///
9875 /// @return true if the lookup tables are empty, false otherwise.
9876 bool
9878 {
9879  return (deleted_fns_.empty()
9880  && added_fns_.empty()
9881  && changed_fns_map_.empty()
9882  && deleted_vars_.empty()
9883  && added_vars_.empty()
9884  && changed_vars_map_.empty());
9885 }
9886 
9887 /// Clear the lookup tables useful for reporting an enum_diff.
9888 void
9890 {
9891  deleted_fns_.clear();
9892  added_fns_.clear();
9893  changed_fns_map_.clear();
9894  deleted_vars_.clear();
9895  added_vars_.clear();
9896  changed_vars_map_.clear();
9897 }
9898 
9899 /// If the lookup tables are not yet built, walk the differences and
9900 /// fill the lookup tables.
9901 void
9903 {
9904  if (!lookup_tables_empty())
9905  return;
9906 
9907  diff_context_sptr ctxt = get_context();
9908 
9909  {
9910  edit_script& e = fns_edit_script_;
9911 
9912  for (vector<deletion>::const_iterator it = e.deletions().begin();
9913  it != e.deletions().end();
9914  ++it)
9915  {
9916  unsigned i = it->index();
9917  ABG_ASSERT(i < first_->get_functions().size());
9918 
9919  const function_decl* deleted_fn = first_->get_functions()[i];
9920  string n = get_function_id_or_pretty_representation(deleted_fn);
9921  ABG_ASSERT(!n.empty());
9922  // The below is commented out because there can be several
9923  // functions with the same ID in the corpus. So several
9924  // functions with the same ID can be deleted.
9925  // ABG_ASSERT(deleted_fns_.find(n) == deleted_fns_.end());
9926  deleted_fns_[n] = deleted_fn;
9927  }
9928 
9929  for (vector<insertion>::const_iterator it = e.insertions().begin();
9930  it != e.insertions().end();
9931  ++it)
9932  {
9933  for (vector<unsigned>::const_iterator iit =
9934  it->inserted_indexes().begin();
9935  iit != it->inserted_indexes().end();
9936  ++iit)
9937  {
9938  unsigned i = *iit;
9939  const function_decl* added_fn = second_->get_functions()[i];
9940  string n = get_function_id_or_pretty_representation(added_fn);
9941  ABG_ASSERT(!n.empty());
9942  // The below is commented out because there can be several
9943  // functions with the same ID in the corpus. So several
9944  // functions with the same ID can be added.
9945  // ABG_ASSERT(added_fns_.find(n) == added_fns_.end());
9946  string_function_ptr_map::const_iterator j =
9947  deleted_fns_.find(n);
9948  if (j != deleted_fns_.end())
9949  {
9950  function_decl_sptr f(const_cast<function_decl*>(j->second),
9951  noop_deleter());
9952  function_decl_sptr s(const_cast<function_decl*>(added_fn),
9953  noop_deleter());
9954  function_decl_diff_sptr d = compute_diff(f, s, ctxt);
9955  if (*j->second != *added_fn)
9956  changed_fns_map_[j->first] = d;
9957  deleted_fns_.erase(j);
9958  }
9959  else
9960  added_fns_[n] = added_fn;
9961  }
9962  }
9963  sort_string_function_decl_diff_sptr_map(changed_fns_map_, changed_fns_);
9964 
9965  // Now walk the allegedly deleted functions; check if their
9966  // underlying symbols are deleted as well; otherwise, consider
9967  // that the function in question hasn't been deleted.
9968 
9969  vector<string> to_delete;
9970  for (string_function_ptr_map::const_iterator i = deleted_fns_.begin();
9971  i != deleted_fns_.end();
9972  ++i)
9973  if (second_->lookup_function_symbol(*i->second->get_symbol()))
9974  to_delete.push_back(i->first);
9975 
9976  for (vector<string>::const_iterator i = to_delete.begin();
9977  i != to_delete.end();
9978  ++i)
9979  deleted_fns_.erase(*i);
9980 
9981  // Do something similar for added functions.
9982 
9983  to_delete.clear();
9984  for (string_function_ptr_map::const_iterator i = added_fns_.begin();
9985  i != added_fns_.end();
9986  ++i)
9987  {
9988  if (first_->lookup_function_symbol(*i->second->get_symbol()))
9989  to_delete.push_back(i->first);
9990  else if (! i->second->get_symbol()->get_version().is_empty()
9991  && i->second->get_symbol()->get_version().is_default())
9992  // We are looking for a symbol that has a default version,
9993  // and which seems to be newly added. Let's see if the same
9994  // symbol with *no* version was already present in the
9995  // former corpus. If yes, then the symbol shouldn't be
9996  // considered as 'added'.
9997  {
9998  elf_symbol::version empty_version;
9999  if (first_->lookup_function_symbol(i->second->get_symbol()->get_name(),
10000  empty_version))
10001  to_delete.push_back(i->first);
10002  }
10003  }
10004 
10005  for (vector<string>::const_iterator i = to_delete.begin();
10006  i != to_delete.end();
10007  ++i)
10008  added_fns_.erase(*i);
10009  }
10010 
10011  {
10012  edit_script& e = vars_edit_script_;
10013 
10014  for (vector<deletion>::const_iterator it = e.deletions().begin();
10015  it != e.deletions().end();
10016  ++it)
10017  {
10018  unsigned i = it->index();
10019  ABG_ASSERT(i < first_->get_variables().size());
10020 
10021  const var_decl_sptr deleted_var = first_->get_variables()[i];
10022  string n = deleted_var->get_id();
10023  ABG_ASSERT(!n.empty());
10024  // The below is commented out because there can be several
10025  // global variables with the same ID in the corpus. So
10026  // several global variables with the same ID can be deleted.
10027  //
10028  // In general these are static member variables. There can be
10029  // multiple instances of these (one per translation unit) that
10030  // appear to be different, but they are put into a COMDAT
10031  // section (with CLOOS ELF binding in modern toolchains) in
10032  // the end.
10033  //
10034  // In that case, let's keep track of the first global variable
10035  // removed and let's ignore the subsequent ones as they should
10036  // all be "merged" into one by the linker.
10037  //
10038  // ABG_ASSERT(deleted_vars_.find(n) == deleted_vars_.end());
10039  string_var_ptr_map::const_iterator j = deleted_vars_.find(n);
10040  if (j != deleted_vars_.end())
10041  {
10042  ABG_ASSERT(is_member_decl(j->second)
10043  && get_member_is_static(j->second));
10044  continue;
10045  }
10046  else
10047  deleted_vars_[n] = deleted_var;
10048  }
10049 
10050  for (vector<insertion>::const_iterator it = e.insertions().begin();
10051  it != e.insertions().end();
10052  ++it)
10053  {
10054  for (vector<unsigned>::const_iterator iit =
10055  it->inserted_indexes().begin();
10056  iit != it->inserted_indexes().end();
10057  ++iit)
10058  {
10059  unsigned i = *iit;
10060  const var_decl_sptr added_var = second_->get_variables()[i];
10061  string n = added_var->get_id();
10062  ABG_ASSERT(!n.empty());
10063  {
10064  string_var_ptr_map::const_iterator k = added_vars_.find(n);
10065  if ( k != added_vars_.end())
10066  {
10067  ABG_ASSERT(is_member_decl(k->second)
10068  && get_member_is_static(k->second));
10069  continue;
10070  }
10071  }
10072  string_var_ptr_map::const_iterator j =
10073  deleted_vars_.find(n);
10074  if (j != deleted_vars_.end())
10075  {
10076  if (*j->second != *added_var)
10077  {
10078  var_decl_sptr f = j->second;
10079  var_decl_sptr s = added_var;
10080  changed_vars_map_[n] = compute_diff(f, s, ctxt);
10081  }
10082  deleted_vars_.erase(j);
10083  }
10084  else
10085  added_vars_[n] = added_var;
10086  }
10087  }
10088  sort_string_var_diff_sptr_map(changed_vars_map_,
10089  sorted_changed_vars_);
10090 
10091  // Now walk the allegedly deleted variables; check if their
10092  // underlying symbols are deleted as well; otherwise consider
10093  // that the variable in question hasn't been deleted.
10094 
10095  vector<string> to_delete;
10096  for (string_var_ptr_map::const_iterator i = deleted_vars_.begin();
10097  i != deleted_vars_.end();
10098  ++i)
10099  if (second_->lookup_variable_symbol(*i->second->get_symbol()))
10100  to_delete.push_back(i->first);
10101 
10102  for (vector<string>::const_iterator i = to_delete.begin();
10103  i != to_delete.end();
10104  ++i)
10105  deleted_vars_.erase(*i);
10106 
10107  // Do something similar for added variables.
10108 
10109  to_delete.clear();
10110  for (string_var_ptr_map::const_iterator i = added_vars_.begin();
10111  i != added_vars_.end();
10112  ++i)
10113  if (first_->lookup_variable_symbol(*i->second->get_symbol()))
10114  to_delete.push_back(i->first);
10115  else if (! i->second->get_symbol()->get_version().is_empty()
10116  && i->second->get_symbol()->get_version().is_default())
10117  // We are looking for a symbol that has a default version,
10118  // and which seems to be newly added. Let's see if the same
10119  // symbol with *no* version was already present in the
10120  // former corpus. If yes, then the symbol shouldn't be
10121  // considered as 'added'.
10122  {
10123  elf_symbol::version empty_version;
10124  if (first_->lookup_variable_symbol(i->second->get_symbol()->get_name(),
10125  empty_version))
10126  to_delete.push_back(i->first);
10127  }
10128 
10129  for (vector<string>::const_iterator i = to_delete.begin();
10130  i != to_delete.end();
10131  ++i)
10132  added_vars_.erase(*i);
10133  }
10134 
10135  // Massage the edit script for added/removed function symbols that
10136  // were not referenced by any debug info and turn them into maps of
10137  // {symbol_name, symbol}.
10138  {
10139  edit_script& e = unrefed_fn_syms_edit_script_;
10140  for (vector<deletion>::const_iterator it = e.deletions().begin();
10141  it != e.deletions().end();
10142  ++it)
10143  {
10144  unsigned i = it->index();
10145  ABG_ASSERT(i < first_->get_unreferenced_function_symbols().size());
10146  elf_symbol_sptr deleted_sym =
10147  first_->get_unreferenced_function_symbols()[i];
10148  if (!second_->lookup_function_symbol(*deleted_sym))
10149  deleted_unrefed_fn_syms_[deleted_sym->get_id_string()] = deleted_sym;
10150  }
10151 
10152  for (vector<insertion>::const_iterator it = e.insertions().begin();
10153  it != e.insertions().end();
10154  ++it)
10155  {
10156  for (vector<unsigned>::const_iterator iit =
10157  it->inserted_indexes().begin();
10158  iit != it->inserted_indexes().end();
10159  ++iit)
10160  {
10161  unsigned i = *iit;
10162  ABG_ASSERT(i < second_->get_unreferenced_function_symbols().size());
10163  elf_symbol_sptr added_sym =
10164  second_->get_unreferenced_function_symbols()[i];
10165  if ((deleted_unrefed_fn_syms_.find(added_sym->get_id_string())
10166  == deleted_unrefed_fn_syms_.end()))
10167  {
10168  if (!first_->lookup_function_symbol(*added_sym))
10169  {
10170  bool do_add = true;
10171  if (! added_sym->get_version().is_empty()
10172  && added_sym->get_version().is_default())
10173  {
10174  // So added_seem has a default version. If
10175  // the former corpus had a symbol with the
10176  // same name as added_sym but with *no*
10177  // version, then added_sym shouldn't be
10178  // considered as a newly added symbol.
10179  elf_symbol::version empty_version;
10180  if (first_->lookup_function_symbol(added_sym->get_name(),
10181  empty_version))
10182  do_add = false;
10183  }
10184 
10185  if (do_add)
10186  added_unrefed_fn_syms_[added_sym->get_id_string()] =
10187  added_sym;
10188  }
10189  }
10190  else
10191  deleted_unrefed_fn_syms_.erase(added_sym->get_id_string());
10192  }
10193  }
10194  }
10195 
10196  // Massage the edit script for added/removed variable symbols that
10197  // were not referenced by any debug info and turn them into maps of
10198  // {symbol_name, symbol}.
10199  {
10200  edit_script& e = unrefed_var_syms_edit_script_;
10201  for (vector<deletion>::const_iterator it = e.deletions().begin();
10202  it != e.deletions().end();
10203  ++it)
10204  {
10205  unsigned i = it->index();
10206  ABG_ASSERT(i < first_->get_unreferenced_variable_symbols().size());
10207  elf_symbol_sptr deleted_sym =
10208  first_->get_unreferenced_variable_symbols()[i];
10209  if (!second_->lookup_variable_symbol(*deleted_sym))
10210  deleted_unrefed_var_syms_[deleted_sym->get_id_string()] = deleted_sym;
10211  }
10212 
10213  for (vector<insertion>::const_iterator it = e.insertions().begin();
10214  it != e.insertions().end();
10215  ++it)
10216  {
10217  for (vector<unsigned>::const_iterator iit =
10218  it->inserted_indexes().begin();
10219  iit != it->inserted_indexes().end();
10220  ++iit)
10221  {
10222  unsigned i = *iit;
10223  ABG_ASSERT(i < second_->get_unreferenced_variable_symbols().size());
10224  elf_symbol_sptr added_sym =
10225  second_->get_unreferenced_variable_symbols()[i];
10226  if (deleted_unrefed_var_syms_.find(added_sym->get_id_string())
10227  == deleted_unrefed_var_syms_.end())
10228  {
10229  if (!first_->lookup_variable_symbol(*added_sym))
10230  {
10231  bool do_add = true;
10232  if (! added_sym->get_version().is_empty()
10233  && added_sym->get_version().is_default())
10234  {
10235  // So added_seem has a default version. If
10236  // the former corpus had a symbol with the
10237  // same name as added_sym but with *no*
10238  // version, then added_sym shouldn't be
10239  // considered as a newly added symbol.
10240  elf_symbol::version empty_version;
10241  if (first_->lookup_variable_symbol(added_sym->get_name(),
10242  empty_version))
10243  do_add = false;
10244  }
10245 
10246  if (do_add)
10247  added_unrefed_var_syms_[added_sym->get_id_string()] =
10248  added_sym;
10249  }
10250  }
10251  else
10252  deleted_unrefed_var_syms_.erase(added_sym->get_id_string());
10253  }
10254  }
10255  }
10256 
10257  // Handle the unreachable_types_edit_script_
10258  {
10259  edit_script& e = unreachable_types_edit_script_;
10260 
10261  // Populate the map of deleted unreachable types from the
10262  // deletions of the edit script.
10263  for (vector<deletion>::const_iterator it = e.deletions().begin();
10264  it != e.deletions().end();
10265  ++it)
10266  {
10267  unsigned i = it->index();
10268  type_base_sptr t
10269  (first_->get_types_not_reachable_from_public_interfaces()[i]);
10270 
10271  if (!is_user_defined_type(t))
10272  continue;
10273 
10274  string repr =
10275  abigail::ir::get_pretty_representation(t, /*internal=*/false);
10276  deleted_unreachable_types_[repr] = t;
10277  }
10278 
10279  // Populate the map of added and change unreachable types from the
10280  // insertions of the edit script.
10281  for (vector<insertion>::const_iterator it = e.insertions().begin();
10282  it != e.insertions().end();
10283  ++it)
10284  {
10285  for (vector<unsigned>::const_iterator iit =
10286  it->inserted_indexes().begin();
10287  iit != it->inserted_indexes().end();
10288  ++iit)
10289  {
10290  unsigned i = *iit;
10291  type_base_sptr t
10292  (second_->get_types_not_reachable_from_public_interfaces()[i]);
10293 
10294  if (!is_user_defined_type(t))
10295  continue;
10296 
10297  string repr =
10298  abigail::ir::get_pretty_representation(t, /*internal=*/false);
10299 
10300  // Let's see if the inserted type we are looking at was
10301  // reported as deleted as well.
10302  //
10303  // If it's been deleted and a different version of it has
10304  // now been added, it means it's been *changed*. In that
10305  // case we'll compute the diff of that change and store it
10306  // in the map of changed unreachable types.
10307  //
10308  // Otherwise, it means the type's been added so we'll add
10309  // it to the set of added unreachable types.
10310 
10311  string_type_base_sptr_map::const_iterator j =
10312  deleted_unreachable_types_.find(repr);
10313  if (j != deleted_unreachable_types_.end())
10314  {
10315  // So there was another type of the same pretty
10316  // representation which was reported as deleted.
10317  // Let's see if they are different or not ...
10318  decl_base_sptr old_type = is_decl(j->second);
10319  decl_base_sptr new_type = is_decl(t);
10320  if (old_type != new_type)
10321  {
10322  // The previously added type is different from this
10323  // one that is added. That means the initial type
10324  // was changed. Let's compute its diff and store it
10325  // as a changed type.
10326  diff_sptr d = compute_diff(old_type, new_type, ctxt);
10327  ABG_ASSERT(d->has_changes());
10328  changed_unreachable_types_[repr]= d;
10329  }
10330 
10331  // In any case, the type was both deleted and added,
10332  // so we cannot have it marked as being deleted. So
10333  // let's remove it from the deleted types.
10334  deleted_unreachable_types_.erase(j);
10335  }
10336  else
10337  // The type wasn't previously reported as deleted, so
10338  // it's really added.
10339  added_unreachable_types_[repr] = t;
10340  }
10341  }
10342 
10343  // Handle anonymous enums that got changed. An anonymous enum is
10344  // designated by its flat textual representation. So a change to
10345  // any of its enumerators results in a different enum. That is
10346  // represented by a deletion of the previous anonymous enum, and
10347  // the addition of a new one. For the user however, it's the same
10348  // enum that changed. Let's massage this "added/removed" pattern
10349  // to show what the user expects, namely, a changed anonymous
10350  // enum.
10351  {
10352  std::set<type_base_sptr> deleted_anon_types;
10353  std::set<type_base_sptr> added_anon_types;
10354 
10355  for (auto entry : deleted_unreachable_types_)
10356  {
10357  if ((is_enum_type(entry.second)
10358  && is_enum_type(entry.second)->get_is_anonymous())
10359  || (is_class_or_union_type(entry.second)
10360  && is_class_or_union_type(entry.second)->get_is_anonymous()))
10361  deleted_anon_types.insert(entry.second);
10362  }
10363 
10364 
10365  for (auto entry : added_unreachable_types_)
10366  if ((is_enum_type(entry.second)
10367  && is_enum_type(entry.second)->get_is_anonymous())
10368  || (is_class_or_union_type(entry.second)
10369  && is_class_or_union_type(entry.second)->get_is_anonymous()))
10370  added_anon_types.insert(entry.second);
10371 
10372  string_type_base_sptr_map added_anon_types_to_erase;
10373  string_type_base_sptr_map removed_anon_types_to_erase;
10374  enum_type_decl_sptr deleted_enum;
10375  class_or_union_sptr deleted_class;
10376 
10377  // Look for deleted anonymous types (enums, unions, structs &
10378  // classes) which have enumerators or data members present in an
10379  // added anonymous type ...
10380  for (auto deleted: deleted_anon_types)
10381  {
10382  deleted_enum = is_enum_type(deleted);
10383  deleted_class = is_class_or_union_type(deleted);
10384 
10385  // For enums, look for any enumerator of 'deleted_enum' that
10386  // is also present in an added anonymous enum.
10387  if (deleted_enum)
10388  {
10389  for (auto enr : deleted_enum->get_enumerators())
10390  {
10391  bool this_enum_got_changed = false;
10392  for (auto t : added_anon_types)
10393  {
10394  if (enum_type_decl_sptr added_enum = is_enum_type(t))
10395  if (is_enumerator_present_in_enum(enr, *added_enum))
10396  {
10397  // So the enumerator 'enr' from the
10398  // 'deleted_enum' enum is also present in the
10399  // 'added_enum' enum so we assume that
10400  // 'deleted_enum' and 'added_enum' are the same
10401  // enum that got changed. Let's represent it
10402  // using a diff node.
10403  diff_sptr d = compute_diff(deleted_enum,
10404  added_enum, ctxt);
10405  ABG_ASSERT(d->has_changes());
10406  string repr =
10408  /*internal=*/false);
10409  changed_unreachable_types_[repr]= d;
10410  this_enum_got_changed = true;
10411  string r1 =
10413  /*internal=*/false);
10414  string r2 =
10416  /*internal=*/false);
10417  removed_anon_types_to_erase[r1] = deleted_enum;
10418  added_anon_types_to_erase[r2] = added_enum;
10419  break;
10420  }
10421  }
10422  if (this_enum_got_changed)
10423  break;
10424  }
10425  }
10426  else if (deleted_class)
10427  {
10428  // For unions, structs & classes, look for any data
10429  // member of 'deleted_class' that is also present in an
10430  // added anonymous class.
10431  for (auto dm : deleted_class->get_data_members())
10432  {
10433  bool this_class_got_changed = false;
10434  for (auto klass : added_anon_types)
10435  {
10436  if (class_or_union_sptr added_class =
10437  is_class_or_union_type(klass))
10438  if (class_or_union_types_of_same_kind(deleted_class,
10439  added_class)
10440  && lookup_data_member(added_class, dm))
10441  {
10442  // So the data member 'dm' from the
10443  // 'deleted_class' class is also present in
10444  // the 'added_class' class so we assume that
10445  // 'deleted_class' and 'added_class' are the
10446  // same anonymous class that got changed.
10447  // Let's represent it using a diff node.
10448  diff_sptr d = compute_diff(is_type(deleted_class),
10449  is_type(added_class),
10450  ctxt);
10451  ABG_ASSERT(d->has_changes());
10452  string repr =
10454  /*internal=*/false);
10455  changed_unreachable_types_[repr]= d;
10456  this_class_got_changed = true;
10457  string r1 =
10459  /*internal=*/false);
10460  string r2 =
10462  /*internal=*/false);
10463  removed_anon_types_to_erase[r1] = deleted_class;
10464  added_anon_types_to_erase[r2] = added_class;
10465  break;
10466  }
10467  }
10468  if (this_class_got_changed)
10469  break;
10470  }
10471  }
10472  }
10473 
10474  // Now remove the added/removed anonymous types from their maps,
10475  // as they are now represented as a changed type, not an added
10476  // and removed anonymous type.
10477  for (auto entry : added_anon_types_to_erase)
10478  added_unreachable_types_.erase(entry.first);
10479 
10480  for (auto entry : removed_anon_types_to_erase)
10481  deleted_unreachable_types_.erase(entry.first);
10482  }
10483  }
10484 }
10485 
10486 /// Test if a change reports about a given @ref function_decl that is
10487 /// changed in a certain way is suppressed by a given suppression
10488 /// specifiation
10489 ///
10490 /// @param fn the @ref function_decl to consider.
10491 ///
10492 /// @param suppr the suppression specification to consider.
10493 ///
10494 /// @param k the kind of change that happened to @p fn.
10495 ///
10496 /// @param ctxt the context of the current diff.
10497 ///
10498 /// @return true iff the suppression specification @p suppr suppresses
10499 /// change reports about function @p fn, if that function changes in
10500 /// the way expressed by @p k.
10501 static bool
10502 function_is_suppressed(const function_decl* fn,
10503  const suppression_sptr suppr,
10505  const diff_context_sptr ctxt)
10506 {
10508  if (!fn_suppr)
10509  return false;
10510  return fn_suppr->suppresses_function(fn, k, ctxt);
10511 }
10512 
10513 /// Test if a change reports about a given @ref var_decl that is
10514 /// changed in a certain way is suppressed by a given suppression
10515 /// specifiation
10516 ///
10517 /// @param fn the @ref var_decl to consider.
10518 ///
10519 /// @param suppr the suppression specification to consider.
10520 ///
10521 /// @param k the kind of change that happened to @p fn.
10522 ///
10523 /// @param ctxt the context of the current diff.
10524 ///
10525 /// @return true iff the suppression specification @p suppr suppresses
10526 /// change reports about variable @p fn, if that variable changes in
10527 /// the way expressed by @p k.
10528 static bool
10529 variable_is_suppressed(const var_decl_sptr& var,
10530  const suppression_sptr suppr,
10532  const diff_context_sptr ctxt)
10533 {
10535  if (!var_suppr)
10536  return false;
10537  return var_suppr->suppresses_variable(var, k, ctxt);
10538 }
10539 
10540 /// Apply suppression specifications for this corpus diff to the set
10541 /// of added/removed functions/variables, as well as to types not
10542 /// reachable from global functions/variables.
10543 void
10545 {
10546  diff_context_sptr ctxt = get_context();
10547 
10548  const suppressions_type& suppressions = ctxt->suppressions();
10549  for (suppressions_type::const_iterator i = suppressions.begin();
10550  i != suppressions.end();
10551  ++i)
10552  {
10553  // Added/Deleted functions.
10555  {
10556  // Added functions
10557  for (string_function_ptr_map::const_iterator e = added_fns_.begin();
10558  e != added_fns_.end();
10559  ++e)
10560  if (function_is_suppressed(e->second, fn_suppr,
10562  ctxt))
10563  suppressed_added_fns_[e->first] = e->second;
10564 
10565  // Deleted functions.
10566  for (string_function_ptr_map::const_iterator e = deleted_fns_.begin();
10567  e != deleted_fns_.end();
10568  ++e)
10569  if (function_is_suppressed(e->second, fn_suppr,
10571  ctxt))
10572  suppressed_deleted_fns_[e->first] = e->second;
10573 
10574  // Added function symbols not referenced by any debug info
10575  for (string_elf_symbol_map::const_iterator e =
10576  added_unrefed_fn_syms_.begin();
10577  e != added_unrefed_fn_syms_.end();
10578  ++e)
10579  if (fn_suppr->suppresses_function_symbol(e->second,
10581  ctxt))
10582  suppressed_added_unrefed_fn_syms_[e->first] = e->second;
10583 
10584  // Removed function symbols not referenced by any debug info
10585  for (string_elf_symbol_map::const_iterator e =
10586  deleted_unrefed_fn_syms_.begin();
10587  e != deleted_unrefed_fn_syms_.end();
10588  ++e)
10589  if (fn_suppr->suppresses_function_symbol(e->second,
10591  ctxt))
10592  suppressed_deleted_unrefed_fn_syms_[e->first] = e->second;
10593  }
10594  // Added/Delete virtual member functions changes that might be
10595  // suppressed by a type_suppression that matches the enclosing
10596  // class of the virtual member function.
10597  else if (type_suppression_sptr type_suppr = is_type_suppression(*i))
10598  {
10599  // Added virtual functions
10600  for (string_function_ptr_map::const_iterator e = added_fns_.begin();
10601  e != added_fns_.end();
10602  ++e)
10603  if (is_member_function(e->second)
10604  && get_member_function_is_virtual(e->second))
10605  {
10606  const function_decl *f = e->second;
10607  class_decl_sptr c =
10608  is_class_type(is_method_type(f->get_type())->get_class_type());
10609  ABG_ASSERT(c);
10610  if (type_suppr->suppresses_type(c, ctxt))
10611  suppressed_added_fns_[e->first] = e->second;
10612  }
10613  // Deleted virtual functions
10614  for (string_function_ptr_map::const_iterator e = deleted_fns_.begin();
10615  e != deleted_fns_.end();
10616  ++e)
10617  if (is_member_function(e->second)
10618  && get_member_function_is_virtual(e->second))
10619  {
10620  const function_decl *f = e->second;
10621  class_decl_sptr c =
10622  is_class_type(is_method_type(f->get_type())->get_class_type());
10623  ABG_ASSERT(c);
10624  if (type_suppr->suppresses_type(c, ctxt))
10625  suppressed_deleted_fns_[e->first] = e->second;
10626  }
10627 
10628  // Apply this type suppression to deleted types
10629  // non-reachable from a public interface.
10630  for (string_type_base_sptr_map::const_iterator e =
10631  deleted_unreachable_types_.begin();
10632  e != deleted_unreachable_types_.end();
10633  ++e)
10634  if (type_suppr->suppresses_type(e->second, ctxt))
10635  suppressed_deleted_unreachable_types_[e->first] = e->second;
10636 
10637  // Apply this type suppression to added types
10638  // non-reachable from a public interface.
10639  for (string_type_base_sptr_map::const_iterator e =
10640  added_unreachable_types_.begin();
10641  e != added_unreachable_types_.end();
10642  ++e)
10643  if (type_suppr->suppresses_type(e->second, ctxt))
10644  suppressed_added_unreachable_types_[e->first] = e->second;
10645  }
10646  // Added/Deleted variables
10647  else if (variable_suppression_sptr var_suppr =
10649  {
10650  // Added variables
10651  for (string_var_ptr_map::const_iterator e = added_vars_.begin();
10652  e != added_vars_.end();
10653  ++e)
10654  if (variable_is_suppressed(e->second, var_suppr,
10656  ctxt))
10657  suppressed_added_vars_[e->first] = e->second;
10658 
10659  //Deleted variables
10660  for (string_var_ptr_map::const_iterator e = deleted_vars_.begin();
10661  e != deleted_vars_.end();
10662  ++e)
10663  if (variable_is_suppressed(e->second, var_suppr,
10665  ctxt))
10666  suppressed_deleted_vars_[e->first] = e->second;
10667 
10668  // Added variable symbols not referenced by any debug info
10669  for (string_elf_symbol_map::const_iterator e =
10670  added_unrefed_var_syms_.begin();
10671  e != added_unrefed_var_syms_.end();
10672  ++e)
10673  if (var_suppr->suppresses_variable_symbol(e->second,
10675  ctxt))
10676  suppressed_added_unrefed_var_syms_[e->first] = e->second;
10677 
10678  // Removed variable symbols not referenced by any debug info
10679  for (string_elf_symbol_map::const_iterator e =
10680  deleted_unrefed_var_syms_.begin();
10681  e != deleted_unrefed_var_syms_.end();
10682  ++e)
10683  if (var_suppr->suppresses_variable_symbol(e->second,
10685  ctxt))
10686  suppressed_deleted_unrefed_var_syms_[e->first] = e->second;
10687  }
10688  }
10689 }
10690 
10691 /// Test if the change reports for a given deleted function have
10692 /// been deleted.
10693 ///
10694 /// @param fn the function to consider.
10695 ///
10696 /// @return true iff the change reports for a give given deleted
10697 /// function have been deleted.
10698 bool
10700 {
10701  if (!fn)
10702  return false;
10703 
10704  string_function_ptr_map::const_iterator i =
10705  suppressed_deleted_fns_.find(fn->get_id());
10706 
10707  return (i != suppressed_deleted_fns_.end());
10708 }
10709 
10710 /// Test if an added type that is unreachable from public interface
10711 /// has been suppressed by a suppression specification.
10712 ///
10713 /// @param t the added unreachable type to be considered.
10714 ///
10715 /// @return true iff @p t has been suppressed by a suppression
10716 /// specification.
10717 bool
10719 {
10720  if (!t)
10721  return false;
10722 
10723  string repr = abigail::ir::get_pretty_representation(t, /*internal=*/false);
10724  string_type_base_sptr_map::const_iterator i =
10725  suppressed_added_unreachable_types_.find(repr);
10726  if (i == suppressed_added_unreachable_types_.end())
10727  return false;
10728 
10729  return true;
10730 }
10731 
10732 /// Test if a deleted type that is unreachable from public interface
10733 /// has been suppressed by a suppression specification.
10734 ///
10735 /// @param t the deleted unreachable type to be considered.
10736 ///
10737 /// @return true iff @p t has been suppressed by a suppression
10738 /// specification.
10739 bool
10741 {
10742  if (!t)
10743  return false;
10744 
10745  string repr = abigail::ir::get_pretty_representation(t, /*internal=*/false);
10746  string_type_base_sptr_map::const_iterator i =
10747  suppressed_deleted_unreachable_types_.find(repr);
10748  if (i == suppressed_deleted_unreachable_types_.end())
10749  return false;
10750 
10751  return true;
10752 }
10753 
10754 /// Test if the change reports for a give given added function has
10755 /// been deleted.
10756 ///
10757 /// @param fn the function to consider.
10758 ///
10759 /// @return true iff the change reports for a give given added
10760 /// function has been deleted.
10761 bool
10763 {
10764  if (!fn)
10765  return false;
10766 
10767  string_function_ptr_map::const_iterator i =
10768  suppressed_added_fns_.find(fn->get_id());
10769 
10770  return (i != suppressed_added_fns_.end());
10771 }
10772 
10773 /// Test if the change reports for a give given deleted variable has
10774 /// been deleted.
10775 ///
10776 /// @param var the variable to consider.
10777 ///
10778 /// @return true iff the change reports for a give given deleted
10779 /// variable has been deleted.
10780 bool
10782 {
10783  if (!var)
10784  return false;
10785 
10786  string_var_ptr_map::const_iterator i =
10787  suppressed_deleted_vars_.find(var->get_id());
10788 
10789  return (i != suppressed_deleted_vars_.end());
10790 }
10791 
10792 /// Test if the change reports for a given added variable have been
10793 /// suppressed.
10794 ///
10795 /// @param var the variable to consider.
10796 ///
10797 /// @return true iff the change reports for a given deleted
10798 /// variable has been deleted.
10799 bool
10801 {
10802  if (!var)
10803  return false;
10804 
10805  string_var_ptr_map::const_iterator i =
10806  suppressed_added_vars_.find(var->get_id());
10807 
10808  return (i != suppressed_added_vars_.end());
10809 }
10810 
10811 /// Test if the change reports for a given deleted function symbol
10812 /// (that is not referenced by any debug info) has been suppressed.
10813 ///
10814 /// @param var the function to consider.
10815 ///
10816 /// @return true iff the change reports for a given deleted function
10817 /// symbol has been suppressed.
10818 bool
10820 {
10821  if (!s)
10822  return false;
10823 
10824  string_elf_symbol_map::const_iterator i =
10825  suppressed_deleted_unrefed_fn_syms_.find(s->get_id_string());
10826 
10827  return (i != suppressed_deleted_unrefed_fn_syms_.end());
10828 }
10829 
10830 /// Test if the change reports for a given added function symbol
10831 /// (that is not referenced by any debug info) has been suppressed.
10832 ///
10833 /// @param var the function to consider.
10834 ///
10835 /// @return true iff the change reports for a given added function
10836 /// symbol has been suppressed.
10837 bool
10839 {
10840  if (!s)
10841  return false;
10842 
10843  string_elf_symbol_map::const_iterator i =
10844  suppressed_added_unrefed_fn_syms_.find(s->get_id_string());
10845 
10846  return (i != suppressed_added_unrefed_fn_syms_.end());
10847 }
10848 
10849 /// Test if the change reports for a given deleted variable symbol
10850 /// (that is not referenced by any debug info) has been suppressed.
10851 ///
10852 /// @param var the variable to consider.
10853 ///
10854 /// @return true iff the change reports for a given deleted variable
10855 /// symbol has been suppressed.
10856 bool
10858 {
10859  if (!s)
10860  return false;
10861 
10862  string_elf_symbol_map::const_iterator i =
10863  suppressed_deleted_unrefed_var_syms_.find(s->get_id_string());
10864 
10865  return (i != suppressed_deleted_unrefed_var_syms_.end());
10866 }
10867 
10868 /// Test if the change reports for a given added variable symbol
10869 /// (that is not referenced by any debug info) has been suppressed.
10870 ///
10871 /// @param var the variable to consider.
10872 ///
10873 /// @return true iff the change reports for a given added variable
10874 /// symbol has been suppressed.
10875 bool
10877 {
10878  if (!s)
10879  return false;
10880 
10881  string_elf_symbol_map::const_iterator i =
10882  suppressed_added_unrefed_var_syms_.find(s->get_id_string());
10883 
10884  return (i != suppressed_added_unrefed_var_syms_.end());
10885 }
10886 
10887 #ifdef do_count_diff_map_changes
10888 #undef do_count_diff_map_changes
10889 #endif
10890 #define do_count_diff_map_changes(diff_map, n_changes, n_filtered) \
10891  { \
10892  string_diff_ptr_map::const_iterator i; \
10893  for (i = diff_map.begin(); \
10894  i != diff_map.end(); \
10895  ++i) \
10896  { \
10897  if (const var_diff* d = is_var_diff(i->second)) \
10898  if (is_data_member(d->first_var())) \
10899  continue; \
10900  \
10901  if (i->second->has_local_changes()) \
10902  ++n_changes; \
10903  if (!i->second->get_canonical_diff()->to_be_reported()) \
10904  ++n_filtered; \
10905  } \
10906  }
10907 
10908 /// Count the number of leaf changes as well as the number of the
10909 /// changes that have been filtered out.
10910 ///
10911 /// @param num_changes out parameter. This is set to the total number
10912 /// of leaf changes.
10913 ///
10914 /// @param num_filtered out parameter. This is set to the number of
10915 /// leaf changes that have been filtered out.
10916 void
10917 corpus_diff::priv::count_leaf_changes(size_t &num_changes, size_t &num_filtered)
10918 {
10919  count_leaf_type_changes(num_changes, num_filtered);
10920 
10921  // Now count the non-type changes.
10922  do_count_diff_map_changes(leaf_diffs_.get_function_decl_diff_map(),
10923  num_changes, num_filtered);
10924  do_count_diff_map_changes(leaf_diffs_.get_var_decl_diff_map(),
10925  num_changes, num_filtered);
10926 }
10927 
10928 /// Count the number of leaf *type* changes as well as the number of
10929 /// the leaf type changes that have been filtered out.
10930 ///
10931 /// @param num_changes out parameter. This is set to the total number
10932 /// of leaf type changes.
10933 ///
10934 /// @param num_filtered out parameter. This is set to the number of
10935 /// leaf type changes that have been filtered out.
10936 void
10938  size_t &num_filtered)
10939 {
10940  do_count_diff_map_changes(leaf_diffs_.get_type_decl_diff_map(),
10941  num_changes, num_filtered);
10942  do_count_diff_map_changes(leaf_diffs_.get_enum_diff_map(),
10943  num_changes, num_filtered);
10944  do_count_diff_map_changes(leaf_diffs_.get_class_diff_map(),
10945  num_changes, num_filtered);
10946  do_count_diff_map_changes(leaf_diffs_.get_union_diff_map(),
10947  num_changes, num_filtered);
10948  do_count_diff_map_changes(leaf_diffs_.get_typedef_diff_map(),
10949  num_changes, num_filtered);
10950  do_count_diff_map_changes(leaf_diffs_.get_subrange_diff_map(),
10951  num_changes, num_filtered);
10952  do_count_diff_map_changes(leaf_diffs_.get_array_diff_map(),
10953  num_changes, num_filtered);
10954  do_count_diff_map_changes(leaf_diffs_.get_distinct_diff_map(),
10955  num_changes, num_filtered);
10956  do_count_diff_map_changes(leaf_diffs_.get_fn_parm_diff_map(),
10957  num_changes, num_filtered);
10958 }
10959 
10960 /// Count the number of types not reachable from the interface (i.e,
10961 /// not reachable from global functions or variables).
10962 ///
10963 /// @param num_added this is set to the number of added types not
10964 /// reachable from the interface.
10965 ///
10966 /// @param num_deleted this is set to the number of deleted types not
10967 /// reachable from the interface.
10968 ///
10969 /// @param num_changed this is set to the number of changed types not
10970 /// reachable from the interface.
10971 ///
10972 /// @param num_filtered_added this is set to the number of added types
10973 /// not reachable from the interface and that have been filtered out
10974 /// by suppression specifications.
10975 ///
10976 /// @param num_filtered_deleted this is set to the number of deleted
10977 /// types not reachable from the interface and that have been filtered
10978 /// out by suppression specifications.
10979 ///
10980 /// @param num_filtered_changed this is set to the number of changed
10981 /// types not reachable from the interface and that have been filtered
10982 /// out by suppression specifications.
10983 void
10985  size_t &num_deleted,
10986  size_t &num_changed,
10987  size_t &num_filtered_added,
10988  size_t &num_filtered_deleted,
10989  size_t &num_filtered_changed)
10990 {
10991  num_added = added_unreachable_types_.size();
10992  num_deleted = deleted_unreachable_types_.size();
10993  num_changed = changed_unreachable_types_.size();
10994  num_filtered_added = suppressed_added_unreachable_types_.size();
10995  num_filtered_deleted = suppressed_deleted_unreachable_types_.size();
10996 
10997  for (vector<diff_sptr>::const_iterator i =
10999  i != changed_unreachable_types_sorted().end();
11000  ++i)
11001  if (!(*i)->to_be_reported())
11002  ++num_filtered_changed;
11003 }
11004 
11005 /// Get the map of diff nodes representing changed unreachable types.
11006 ///
11007 /// @return the map of diff nodes representing changed unreachable
11008 /// types.
11009 const string_diff_sptr_map&
11011 {return changed_unreachable_types_;}
11012 
11013 /// Get the sorted vector of diff nodes representing changed
11014 /// unreachable types.
11015 ///
11016 /// Upon the first invocation of this method, if the vector is empty,
11017 /// this function gets the diff nodes representing changed
11018 /// unreachable, sort them, and return the sorted vector.
11019 ///
11020 /// @return the sorted vector of diff nodes representing changed
11021 /// unreachable types.
11022 const vector<diff_sptr>&
11024 {
11025 if (changed_unreachable_types_sorted_.empty())
11026  if (!changed_unreachable_types_.empty())
11027  sort_string_diff_sptr_map(changed_unreachable_types_,
11028  changed_unreachable_types_sorted_);
11029 
11030  return changed_unreachable_types_sorted_;
11031 }
11032 
11033 /// Compute the diff stats.
11034 ///
11035 /// To know the number of functions that got filtered out, this
11036 /// function applies the categorizing filters to the diff sub-trees of
11037 /// each function changes diff, prior to calculating the stats.
11038 ///
11039 /// @param num_removed the number of removed functions.
11040 ///
11041 /// @param num_added the number of added functions.
11042 ///
11043 /// @param num_changed the number of changed functions.
11044 ///
11045 /// @param num_filtered_out the number of changed functions that are
11046 /// got filtered out from the report
11047 void
11049 {
11050  stat.num_func_removed(deleted_fns_.size());
11051  stat.num_removed_func_filtered_out(suppressed_deleted_fns_.size());
11052  stat.num_func_added(added_fns_.size());
11053  stat.num_added_func_filtered_out(suppressed_added_fns_.size());
11054  stat.num_func_changed(changed_fns_map_.size());
11055 
11056  stat.num_vars_removed(deleted_vars_.size());
11057  stat.num_removed_vars_filtered_out(suppressed_deleted_vars_.size());
11058  stat.num_vars_added(added_vars_.size());
11059  stat.num_added_vars_filtered_out(suppressed_added_vars_.size());
11060  stat.num_vars_changed(changed_vars_map_.size());
11061 
11062  diff_context_sptr ctxt = get_context();
11063 
11065  if (ctxt->perform_change_categorization())
11066  {
11067  if (get_context()->do_log())
11068  {
11069  std::cerr << "in apply_filters_and_compute_diff_stats:"
11070  << "applying filters to "
11071  << changed_fns_.size()
11072  << " changed fns ...\n";
11073  t.start();
11074  }
11075  // Walk the changed function diff nodes to apply the categorization
11076  // filters.
11077  diff_sptr diff;
11078  for (function_decl_diff_sptrs_type::const_iterator i =
11079  changed_fns_.begin();
11080  i != changed_fns_.end();
11081  ++i)
11082  {
11083  diff_sptr diff = *i;
11084  ctxt->maybe_apply_filters(diff);
11085  }
11086 
11087  if (get_context()->do_log())
11088  {
11089  t.stop();
11090  std::cerr << "in apply_filters_and_compute_diff_stats:"
11091  << "filters to changed fn applied!:" << t << "\n";
11092 
11093  std::cerr << "in apply_filters_and_compute_diff_stats:"
11094  << "applying filters to "
11095  << sorted_changed_vars_.size()
11096  << " changed vars ...\n";
11097  t.start();
11098  }
11099 
11100  // Walk the changed variable diff nodes to apply the categorization
11101  // filters.
11102  for (var_diff_sptrs_type::const_iterator i = sorted_changed_vars_.begin();
11103  i != sorted_changed_vars_.end();
11104  ++i)
11105  {
11106  diff_sptr diff = *i;
11107  ctxt->maybe_apply_filters(diff);
11108  }
11109 
11110  if (get_context()->do_log())
11111  {
11112  t.stop();
11113  std::cerr << "in apply_filters_and_compute_diff_stats:"
11114  << "filters to changed vars applied!:" << t << "\n";
11115 
11116  std::cerr << "in apply_filters_and_compute_diff_stats:"
11117  << "applying filters to unreachable types ...\n";
11118  t.start();
11119  }
11120 
11121  // walk the changed unreachable types to apply categorization
11122  // filters
11123  for (auto& diff : changed_unreachable_types_sorted())
11124  ctxt->maybe_apply_filters(diff);
11125 
11126  for (auto& entry : changed_unreachable_types())
11127  ctxt->maybe_apply_filters(entry.second);
11128 
11129  if (get_context()->do_log())
11130  {
11131  t.stop();
11132  std::cerr << "in apply_filters_and_compute_diff_stats:"
11133  << "filters to unreachable types applied!:" << t << "\n";
11134 
11135  std::cerr << "in apply_filters_and_compute_diff_stats:"
11136  << "categorizing redundant changed sub nodes ...\n";
11137  t.start();
11138  }
11139 
11140  categorize_redundant_changed_sub_nodes();
11141 
11142  if (get_context()->do_log())
11143  {
11144  t.stop();
11145  std::cerr << "in apply_filters_and_compute_diff_stats:"
11146  << "redundant changed sub nodes categorized!:" << t << "\n";
11147 
11148  std::cerr << "in apply_filters_and_compute_diff_stats:"
11149  << "count changed fns ...\n";
11150  t.start();
11151  }
11152  }
11153 
11154  // Walk the changed function diff nodes to count the number of
11155  // filtered-out functions and the number of functions with virtual
11156  // offset changes.
11157  for (function_decl_diff_sptrs_type::const_iterator i =
11158  changed_fns_.begin();
11159  i != changed_fns_.end();
11160  ++i)
11161  {
11162  bool incompatible_change = false;
11163  if ((*i)->is_filtered_out())
11164  {
11166  (stat.num_changed_func_filtered_out() + 1);
11167 
11168  if ((*i)->has_local_changes())
11171  }
11172 
11173  // Now let's detect functions with incompatible changes.
11174  if (!(*i)->is_categorized_as_suppressed())
11175  {
11176  // Note that a filtered-out function diff (because of
11177  // redundancy) can still carry an incompatible change. In
11178  // that case, the diff will later be removed from the
11179  // account of filtered diff nodes.
11180  //
11181  // Also note that such a filtered-out function was *NOT*
11182  // suppressed by a user-provided suppression specification.
11183 
11185  {
11188  incompatible_change = true;
11189  }
11190 
11191  // Are any of the local changes of the function_diff harmful?
11192  // If yes, then set stat.num_func_with_local_harmful_changes()
11193  // and stat.num_var_with_local_harmful_changes().
11195  {
11198  incompatible_change = true;
11199  }
11200  }
11201 
11202  if ((*i)->has_local_changes())
11204  (stat.num_leaf_func_changes() + 1);
11205 
11206  if (incompatible_change)
11207  {
11208  incompatible_changed_fns_.push_back(*i);
11211 
11212  if ((*i)->has_local_changes())
11213  // The function is a leaf node.
11216 
11217  if ((*i)->is_filtered_out())
11218  {
11219  // If the incompatible change was filtered-out (possibly
11220  // b/c of redundancy) consider it as not being filtered
11221  // out anymore.
11223  (stat.num_changed_func_filtered_out() - 1);
11224 
11225  if ((*i)->has_local_changes())
11228  }
11229  }
11230  }
11231 
11232  if (get_context()->do_log())
11233  {
11234  t.stop();
11235  std::cerr << "in apply_filters_and_compute_diff_stats:"
11236  << "changed fn counted!:" << t << "\n";
11237 
11238  std::cerr << "in apply_filters_and_compute_diff_stats:"
11239  << "count changed vars ...\n";
11240  t.start();
11241  }
11242 
11243  // Similarly to function diff nodes above, walk the changed
11244  // variables diff nodes to count the number of filtered-out,
11245  // suppressed and incompatible variable diff nodes.
11246  for (var_diff_sptrs_type ::const_iterator i = sorted_changed_vars_.begin();
11247  i != sorted_changed_vars_.end();
11248  ++i)
11249  {
11250  bool incompatible_change = false;
11251  if ((*i)->is_filtered_out())
11252  {
11254  (stat.num_changed_vars_filtered_out() + 1);
11255 
11256  if ((*i)->has_local_changes())
11258  (stat.num_leaf_var_changes_filtered_out() + 1);
11259  }
11260 
11261  if (!(*i)->is_categorized_as_suppressed())
11262  {
11264  {
11265  incompatible_change = true;
11266  incompatible_changed_vars_.push_back(*i);
11270  (stat.num_var_with_incompatible_changes() + 1);
11271 
11272  if ((*i)->is_filtered_out())
11273  {
11275  (stat.num_changed_vars_filtered_out() - 1);
11276 
11277  if ((*i)->has_local_changes())
11279  (stat.num_leaf_var_changes_filtered_out() - 1);
11280  }
11281  }
11282  }
11283 
11284  if ((*i)->has_local_changes())
11285  {
11287  (stat.num_leaf_var_changes() + 1);
11288 
11289  if (incompatible_change)
11292  }
11293  }
11294 
11295  if (get_context()->do_log())
11296  {
11297  t.stop();
11298  std::cerr << "in apply_filters_and_compute_diff_stats:"
11299  << "changed vars counted!:" << t << "\n";
11300 
11301  std::cerr << "in apply_filters_and_compute_diff_stats:"
11302  << "count leaf changed types ...\n";
11303  t.start();
11304  }
11305 
11306  stat.num_func_syms_added(added_unrefed_fn_syms_.size());
11307  stat.num_added_func_syms_filtered_out(suppressed_added_unrefed_fn_syms_.size());
11308  stat.num_func_syms_removed(deleted_unrefed_fn_syms_.size());
11309  stat.num_removed_func_syms_filtered_out(suppressed_deleted_unrefed_fn_syms_.size());
11310  stat.num_var_syms_added(added_unrefed_var_syms_.size());
11311  stat.num_added_var_syms_filtered_out(suppressed_added_unrefed_var_syms_.size());
11312  stat.num_var_syms_removed(deleted_unrefed_var_syms_.size());
11313  stat.num_removed_var_syms_filtered_out(suppressed_deleted_unrefed_var_syms_.size());
11314 
11315  // Walk the general leaf type diff nodes to count them
11316  {
11317  size_t num_type_changes = 0, num_type_filtered = 0;
11318  count_leaf_type_changes(num_type_changes, num_type_filtered);
11319 
11320  stat.num_leaf_type_changes(num_type_changes);
11321  stat.num_leaf_type_changes_filtered_out(num_type_filtered);
11322  }
11323 
11324  if (get_context()->do_log())
11325  {
11326  t.stop();
11327  std::cerr << "in apply_filters_and_compute_diff_stats:"
11328  << "changed leaf types counted!:" << t << "\n";
11329 
11330  std::cerr << "in apply_filters_and_compute_diff_stats:"
11331  << "count leaf changed artefacts ...\n";
11332  t.start();
11333  }
11334 
11335  // Walk the general leaf artefacts diff nodes to count them
11336  {
11337  size_t num_changes = 0, num_filtered = 0;
11338  count_leaf_changes(num_changes, num_filtered);
11339 
11340  stat.num_leaf_changes(num_changes);
11341  stat.num_leaf_changes_filtered_out(num_filtered);
11342  }
11343 
11344  if (get_context()->do_log())
11345  {
11346  t.stop();
11347  std::cerr << "in apply_filters_and_compute_diff_stats:"
11348  << "changed leaf artefacts counted!:" << t << "\n";
11349 
11350  std::cerr << "in apply_filters_and_compute_diff_stats:"
11351  << "count unreachable types ...\n";
11352  t.start();
11353  }
11354 
11355  // Walk the unreachable types to count them
11356  {
11357  size_t num_added_unreachable_types = 0,
11358  num_changed_unreachable_types = 0,
11359  num_deleted_unreachable_types = 0,
11360  num_added_unreachable_types_filtered = 0,
11361  num_changed_unreachable_types_filtered = 0,
11362  num_deleted_unreachable_types_filtered = 0;
11363 
11364  count_unreachable_types(num_added_unreachable_types,
11365  num_deleted_unreachable_types,
11366  num_changed_unreachable_types,
11367  num_added_unreachable_types_filtered,
11368  num_deleted_unreachable_types_filtered,
11369  num_changed_unreachable_types_filtered);
11370 
11371  if (get_context()->do_log())
11372  {
11373  t.stop();
11374  std::cerr << "in apply_filters_and_compute_diff_stats:"
11375  << "unreachable types counted!:" << t << "\n";
11376  }
11377 
11378  stat.num_added_unreachable_types(num_added_unreachable_types);
11379  stat.num_removed_unreachable_types(num_deleted_unreachable_types);
11380  stat.num_changed_unreachable_types(num_changed_unreachable_types);
11382  (num_added_unreachable_types_filtered);
11384  (num_deleted_unreachable_types_filtered);
11386  (num_changed_unreachable_types_filtered);
11387  }
11388 }
11389 
11390 /// Emit the summary of the functions & variables that got
11391 /// removed/changed/added.
11392 ///
11393 /// TODO: This should be handled by the reporters, just like what is
11394 /// done for reporter_base::diff_to_be_reported.
11395 ///
11396 /// @param out the output stream to emit the stats to.
11397 ///
11398 /// @param indent the indentation string to use in the summary.
11399 void
11401  ostream& out,
11402  const string& indent)
11403 {
11404  /// Report added/removed/changed functions.
11405  size_t net_num_leaf_changes =
11406  s.net_num_func_removed() +
11407  s.net_num_func_added() +
11409  s.net_num_vars_removed() +
11410  s.net_num_vars_added() +
11417 
11418  if (!sonames_equal_)
11419  out << indent << "ELF SONAME changed\n";
11420 
11421  if (!architectures_equal_)
11422  out << indent << "ELF architecture changed\n";
11423 
11424  diff_context_sptr ctxt = get_context();
11425 
11426  if (ctxt->show_leaf_changes_only())
11427  {
11428  out << "Leaf changes summary: ";
11429  out << net_num_leaf_changes << " artifact";
11430  if (net_num_leaf_changes > 1)
11431  out << "s";
11432  out << " changed";
11433 
11434  if (size_t num_filtered = s.num_leaf_changes_filtered_out())
11435  out << " (" << num_filtered << " filtered out)";
11436  out << "\n";
11437 
11438  out << indent << "Changed leaf types summary: "
11441  out << " (" << s.num_leaf_type_changes_filtered_out()
11442  << " filtered out)";
11443  out << " leaf type";
11444  if (s.num_leaf_type_changes() > 1)
11445  out << "s";
11446  out << " changed\n";
11447 
11448  // function changes summary
11449  out << indent << "Removed/Changed/Added functions summary: ";
11450  out << s.net_num_func_removed() << " Removed";
11452  out << " ("
11454  << " filtered out)";
11455  out << ", ";
11456 
11457  out << s.net_num_leaf_func_changes() << " Changed";
11459  out << " ("
11461  << " filtered out)";
11462  out << ", ";
11463 
11464  out << s.net_num_func_added()<< " Added ";
11465  if (s.net_num_func_added() <= 1)
11466  out << "function";
11467  else
11468  out << "functions";
11470  out << " (" << s.num_added_func_filtered_out() << " filtered out)";
11471  out << "\n";
11472 
11473  // variables changes summary
11474  out << indent << "Removed/Changed/Added variables summary: ";
11475  out << s.net_num_vars_removed() << " Removed";
11477  out << " (" << s.num_removed_vars_filtered_out()
11478  << " filtered out)";
11479  out << ", ";
11480 
11481  out << s.net_num_leaf_var_changes() << " Changed";
11483  out << " ("
11485  << " filtered out)";
11486  out << ", ";
11487 
11488  out << s.net_num_vars_added() << " Added ";
11489  if (s.net_num_vars_added() <= 1)
11490  out << "variable";
11491  else
11492  out << "variables";
11494  out << " (" << s.num_added_vars_filtered_out()
11495  << " filtered out)";
11496  out << "\n";
11497  }
11498  else // if (ctxt->show_leaf_changes_only())
11499  {
11500  size_t total_nb_function_changes = s.num_func_removed()
11501  + s.num_func_changed() + s.num_func_added();
11502 
11503  // function changes summary
11504  out << indent << "Functions changes summary: ";
11505  out << s.net_num_func_removed() << " Removed";
11507  out << " ("
11509  << " filtered out)";
11510  out << ", ";
11511 
11512  out << s.net_num_func_changed() << " Changed";
11514  out << " (" << s.num_changed_func_filtered_out() << " filtered out)";
11515  out << ", ";
11516 
11517  out << s.net_num_func_added() << " Added";
11519  out << " (" << s.num_added_func_filtered_out() << " filtered out)";
11520  if (total_nb_function_changes <= 1)
11521  out << " function";
11522  else
11523  out << " functions";
11524  out << "\n";
11525 
11526  // variables changes summary
11527  size_t total_nb_variable_changes = s.num_vars_removed()
11528  + s.num_vars_changed() + s.num_vars_added();
11529 
11530  out << indent << "Variables changes summary: ";
11531  out << s.net_num_vars_removed() << " Removed";
11533  out << " (" << s.num_removed_vars_filtered_out()
11534  << " filtered out)";
11535  out << ", ";
11536 
11537  out << s.num_vars_changed() - s.num_changed_vars_filtered_out() << " Changed";
11539  out << " (" << s.num_changed_vars_filtered_out() << " filtered out)";
11540  out << ", ";
11541 
11542  out << s.net_num_vars_added() << " Added";
11544  out << " (" << s.num_added_vars_filtered_out()
11545  << " filtered out)";
11546  if (total_nb_variable_changes <= 1)
11547  out << " variable";
11548  else
11549  out << " variables";
11550  out << "\n";
11551  }
11552 
11553  // Show statistics about types not reachable from global
11554  // functions/variables.
11555  if (ctxt->show_unreachable_types())
11556  {
11557  size_t total_nb_unreachable_type_changes =
11561 
11562  // Show summary of unreachable types
11563  out << indent << "Unreachable types summary: "
11565  << " removed";
11568  << " filtered out)";
11569  out << ", ";
11570 
11572  << " changed";
11575  << " filtered out)";
11576  out << ", ";
11577 
11579  << " added";
11581  out << " (" << s.num_added_unreachable_types_filtered_out()
11582  << " filtered out)";
11583  if (total_nb_unreachable_type_changes <= 1)
11584  out << " type";
11585  else
11586  out << " types";
11587  out << "\n";
11588  }
11589 
11590  if (ctxt->show_symbols_unreferenced_by_debug_info()
11591  && (s.num_func_syms_removed()
11592  || s.num_func_syms_added()
11593  || s.num_var_syms_removed()
11594  || s.num_var_syms_added()))
11595  {
11596  // function symbols changes summary.
11597 
11598  if (!ctxt->show_added_symbols_unreferenced_by_debug_info()
11599  && s.num_func_syms_removed() == 0
11600  && s.num_func_syms_added() != 0)
11601  // If the only unreferenced function symbol change is function
11602  // syms that got added, but we were forbidden to show function
11603  // syms being added, do nothing.
11604  ;
11605  else
11606  {
11607  out << indent
11608  << "Function symbols changes summary: "
11609  << s.net_num_removed_func_syms() << " Removed";
11611  out << " (" << s.num_removed_func_syms_filtered_out()
11612  << " filtered out)";
11613  out << ", ";
11614  out << s.net_num_added_func_syms() << " Added";
11616  out << " (" << s.num_added_func_syms_filtered_out()
11617  << " filtered out)";
11618  out << " function symbol";
11619  if (s.num_func_syms_added() + s.num_func_syms_removed() > 1)
11620  out << "s";
11621  out << " not referenced by debug info\n";
11622  }
11623 
11624  // variable symbol changes summary.
11625 
11626  if (!ctxt->show_added_symbols_unreferenced_by_debug_info()
11627  && s.num_var_syms_removed() == 0
11628  && s.num_var_syms_added() != 0)
11629  // If the only unreferenced variable symbol change is variable
11630  // syms that got added, but we were forbidden to show variable
11631  // syms being added, do nothing.
11632  ;
11633  else
11634  {
11635  out << indent
11636  << "Variable symbols changes summary: "
11637  << s.net_num_removed_var_syms() << " Removed";
11639  out << " (" << s.num_removed_var_syms_filtered_out()
11640  << " filtered out)";
11641  out << ", ";
11642  out << s.net_num_added_var_syms() << " Added";
11644  out << " (" << s.num_added_var_syms_filtered_out()
11645  << " filtered out)";
11646  out << " variable symbol";
11647  if (s.num_var_syms_added() + s.num_var_syms_removed() > 1)
11648  out << "s";
11649  out << " not referenced by debug info\n";
11650  }
11651  }
11652 }
11653 
11654 /// Walk the changed functions and variables diff nodes to categorize
11655 /// redundant nodes.
11656 void
11658 {
11659  diff_sptr diff;
11660 
11661  diff_context_sptr ctxt = get_context();
11662 
11663  ctxt->forget_visited_diffs();
11664  for (function_decl_diff_sptrs_type::const_iterator i =
11665  changed_fns_.begin();
11666  i!= changed_fns_.end();
11667  ++i)
11668  {
11669  diff = *i;
11670  categorize_redundancy(diff);
11671  }
11672 
11673  for (var_diff_sptrs_type::const_iterator i = sorted_changed_vars_.begin();
11674  i!= sorted_changed_vars_.end();
11675  ++i)
11676  {
11677  diff_sptr diff = *i;
11678  categorize_redundancy(diff);
11679  }
11680 
11681  for (diff_sptrs_type::const_iterator i =
11684  ++i)
11685  {
11686  diff_sptr diff = *i;
11687  categorize_redundancy(diff);
11688  }
11689 }
11690 
11691 /// Walk the changed functions and variables diff nodes and clear the
11692 /// redundancy categorization they might carry.
11693 void
11695 {
11696  diff_sptr diff;
11697  for (function_decl_diff_sptrs_type::const_iterator i = changed_fns_.begin();
11698  i!= changed_fns_.end();
11699  ++i)
11700  {
11701  diff = *i;
11703  }
11704 
11705  for (var_diff_sptrs_type::const_iterator i = sorted_changed_vars_.begin();
11706  i!= sorted_changed_vars_.end();
11707  ++i)
11708  {
11709  diff = *i;
11711  }
11712 }
11713 
11714 /// If the user asked to dump the diff tree node (for changed
11715 /// variables and functions) on the error output stream, then just do
11716 /// that.
11717 ///
11718 /// This function is used for debugging purposes.
11719 void
11721 {
11722  diff_context_sptr ctxt = get_context();
11723 
11724  if (!ctxt->dump_diff_tree()
11725  || ctxt->error_output_stream() == 0)
11726  return;
11727 
11728  if (!changed_fns_.empty())
11729  {
11730  *ctxt->error_output_stream() << "changed functions diff tree: \n\n";
11731  for (function_decl_diff_sptrs_type::const_iterator i =
11732  changed_fns_.begin();
11733  i != changed_fns_.end();
11734  ++i)
11735  {
11736  diff_sptr d = *i;
11737  print_diff_tree(d, *ctxt->error_output_stream());
11738  }
11739  }
11740 
11741  if (!sorted_changed_vars_.empty())
11742  {
11743  *ctxt->error_output_stream() << "\nchanged variables diff tree: \n\n";
11744  for (var_diff_sptrs_type::const_iterator i =
11745  sorted_changed_vars_.begin();
11746  i != sorted_changed_vars_.end();
11747  ++i)
11748  {
11749  diff_sptr d = *i;
11750  print_diff_tree(d, *ctxt->error_output_stream());
11751  }
11752  }
11753 
11754  if (!changed_unreachable_types_sorted().empty())
11755  {
11756  *ctxt->error_output_stream() << "\nchanged unreachable "
11757  "types diff tree: \n\n";
11758  for (vector<diff_sptr>::const_iterator i =
11760  i != changed_unreachable_types_sorted().end();
11761  ++i)
11762  {
11763  diff_sptr d = *i;
11764  print_diff_tree(d, *ctxt->error_output_stream());
11765  }
11766  }
11767 }
11768 
11769 /// Populate the vector of children node of the @ref corpus_diff type.
11770 ///
11771 /// The children node can then later be retrieved using
11772 /// corpus_diff::children_node().
11773 void
11775 {
11776  for (function_decl_diff_sptrs_type::const_iterator i =
11777  changed_functions_sorted().begin();
11778  i != changed_functions_sorted().end();
11779  ++i)
11780  if (diff_sptr d = *i)
11781  append_child_node(d);
11782 }
11783 
11784 /// Constructor for @ref corpus_diff.
11785 ///
11786 /// @param first the first corpus of the diff.
11787 ///
11788 /// @param second the second corpus of the diff.
11789 ///
11790 /// @param ctxt the diff context to use. Note that this context
11791 /// object must stay alive at least during the life time of the
11792 /// current instance of @ref corpus_diff. Otherwise memory corruption
11793 /// issues occur.
11794 corpus_diff::corpus_diff(corpus_sptr first,
11795  corpus_sptr second,
11796  diff_context_sptr ctxt)
11797  : priv_(new priv(first, second, ctxt))
11798 {}
11799 
11800 corpus_diff::~corpus_diff() = default;
11801 
11802 /// Finish building the current instance of @ref corpus_diff.
11803 void
11805 {
11806  if (priv_->finished_)
11807  return;
11809  priv_->finished_ = true;
11810 }
11811 
11812 /// Test if logging was requested.
11813 ///
11814 /// @return true iff logging was requested.
11815 bool
11817 {return context()->do_log();}
11818 
11819 /// Request logging, or not.
11820 ///
11821 /// @param f true iff logging is requested.
11822 void
11824 {context()->do_log(f);}
11825 
11826 /// @return the first corpus of the diff.
11827 corpus_sptr
11829 {return priv_->first_;}
11830 
11831 /// @return the second corpus of the diff.
11832 corpus_sptr
11834 {return priv_->second_;}
11835 
11836 /// @return the children nodes of the current instance of corpus_diff.
11837 const vector<diff*>&
11839 {return priv_->children_;}
11840 
11841 /// Append a new child node to the vector of children nodes for the
11842 /// current instance of @ref corpus_diff node.
11843 ///
11844 /// Note that the vector of children nodes for the current instance of
11845 /// @ref corpus_diff node must remain sorted, using
11846 /// diff_less_than_functor.
11847 ///
11848 /// @param d the new child node. Note that the life time of the
11849 /// object held by @p d will thus equal the life time of the current
11850 /// instance of @ref corpus_diff.
11851 void
11853 {
11854  ABG_ASSERT(d);
11855 
11857  bool inserted = false;
11858  for (vector<diff*>::iterator i = priv_->children_.begin();
11859  i != priv_->children_.end();
11860  ++i)
11861  // Look for the point where to insert the diff child node.
11862  if (!is_less_than(d.get(), *i))
11863  {
11864  context()->keep_diff_alive(d);
11865  priv_->children_.insert(i, d.get());
11866  // As we have just inserted 'd' into the vector, the iterator
11867  // 'i' is invalidated. We must *NOT* use it anymore.
11868  inserted = true;
11869  break;
11870  }
11871 
11872  if (!inserted)
11873  {
11874  context()->keep_diff_alive(d);
11875  // We didn't insert anything to the vector, presumably b/c it was
11876  // empty or had one element that was "less than" 'd'. We can thus
11877  // just append 'd' to the end of the vector.
11878  priv_->children_.push_back(d.get());
11879  }
11880 }
11881 
11882 /// @return the bare edit script of the functions changed as recorded
11883 /// by the diff.
11884 edit_script&
11886 {return priv_->fns_edit_script_;}
11887 
11888 /// @return the bare edit script of the variables changed as recorded
11889 /// by the diff.
11890 edit_script&
11892 {return priv_->vars_edit_script_;}
11893 
11894 /// Test if the soname of the underlying corpus has changed.
11895 ///
11896 /// @return true iff the soname has changed.
11897 bool
11899 {return !priv_->sonames_equal_;}
11900 
11901 /// Test if the architecture of the underlying corpus has changed.
11902 ///
11903 /// @return true iff the architecture has changed.
11904 bool
11906 {return !priv_->architectures_equal_;}
11907 
11908 /// Getter for the deleted functions of the diff.
11909 ///
11910 /// @return the the deleted functions of the diff.
11913 {return priv_->deleted_fns_;}
11914 
11915 /// Getter for the added functions of the diff.
11916 ///
11917 /// @return the added functions of the diff.
11920 {return priv_->added_fns_;}
11921 
11922 /// Getter for the functions which signature didn't change, but which
11923 /// do have some indirect changes in their parms.
11924 ///
11925 /// @return a non-sorted map of functions which signature didn't
11926 /// change, but which do have some indirect changes in their parms.
11927 /// The key of the map is a unique identifier for the function; it's
11928 /// usually made of the name and version of the underlying ELF symbol
11929 /// of the function for corpora that were built from ELF files.
11932 {return priv_->changed_fns_map_;}
11933 
11934 /// Getter for a sorted vector of functions which signature didn't
11935 /// change, but which do have some indirect changes in their parms.
11936 ///
11937 /// @return a sorted vector of functions which signature didn't
11938 /// change, but which do have some indirect changes in their parms.
11941 {return priv_->changed_fns_;}
11942 
11943 /// Getter of the set of diff nodes representing incompatibly changed
11944 /// functions
11945 ///
11946 /// @return the set of diff nodes representing incompatibly changed
11947 /// functions
11950 {return priv_->incompatible_changed_fns_;}
11951 
11952 /// Getter of the set of diff nodes representing incompatibly changed
11953 /// functions
11954 ///
11955 /// @return the set of diff nodes representing incompatibly changed
11956 /// functions
11959 {return priv_->incompatible_changed_fns_;}
11960 
11961 /// Getter for the variables that got deleted from the first subject
11962 /// of the diff.
11963 ///
11964 /// @return the map of deleted variable.
11965 const string_var_ptr_map&
11967 {return priv_->deleted_vars_;}
11968 
11969 /// Getter for the added variables of the diff.
11970 ///
11971 /// @return the map of added variable.
11972 const string_var_ptr_map&
11974 {return priv_->added_vars_;}
11975 
11976 /// Getter for the non-sorted map of variables which signature didn't
11977 /// change but which do have some indirect changes in some sub-types.
11978 ///
11979 /// @return the non-sorted map of changed variables.
11982 {return priv_->changed_vars_map_;}
11983 
11984 /// Getter for the sorted vector of variables which signature didn't
11985 /// change but which do have some indirect changes in some sub-types.
11986 ///
11987 /// @return a sorted vector of changed variables.
11988 const var_diff_sptrs_type&
11990 {return priv_->sorted_changed_vars_;}
11991 
11992 /// Getter of the set of diff nodes representing incompatibly changed
11993 /// global variables.
11994 ///
11995 /// @return the set of diff nodes representing incompatibly changed
11996 /// global variables.
11997 const var_diff_sptrs_type&
11999 {return priv_->incompatible_changed_vars_;}
12000 
12001 /// Getter of the set of diff nodes representing incompatibly changed
12002 /// global variables.
12003 ///
12004 /// @return the set of diff nodes representing incompatibly changed
12005 /// global variables.
12008 {return priv_->incompatible_changed_vars_;}
12009 
12010 /// Getter for function symbols not referenced by any debug info and
12011 /// that got deleted.
12012 ///
12013 /// @return a map of elf function symbols not referenced by any debug
12014 /// info and that got deleted.
12015 const string_elf_symbol_map&
12017 {return priv_->deleted_unrefed_fn_syms_;}
12018 
12019 /// Getter for function symbols not referenced by any debug info and
12020 /// that got added.
12021 ///
12022 /// @return a map of elf function symbols not referenced by any debug
12023 /// info and that got added.
12024 const string_elf_symbol_map&
12026 {return priv_->added_unrefed_fn_syms_;}
12027 
12028 /// Getter for variable symbols not referenced by any debug info and
12029 /// that got deleted.
12030 ///
12031 /// @return a map of elf variable symbols not referenced by any debug
12032 /// info and that got deleted.
12033 const string_elf_symbol_map&
12035 {return priv_->deleted_unrefed_var_syms_;}
12036 
12037 /// Getter for variable symbols not referenced by any debug info and
12038 /// that got added.
12039 ///
12040 /// @return a map of elf variable symbols not referenced by any debug
12041 /// info and that got added.
12042 const string_elf_symbol_map&
12044 {return priv_->added_unrefed_var_syms_;}
12045 
12046 /// Getter for a map of deleted types that are not reachable from
12047 /// global functions/variables.
12048 ///
12049 /// @return a map that associates pretty representation of deleted
12050 /// unreachable types and said types.
12053 {return priv_->deleted_unreachable_types_;}
12054 
12055 /// Getter of a sorted vector of deleted types that are not reachable
12056 /// from global functions/variables.
12057 ///
12058 /// @return a sorted vector of deleted types that are not reachable
12059 /// from global functions/variables. The types are lexicographically
12060 /// sorted by considering their pretty representation.
12061 const vector<type_base_sptr>&
12063 {
12064  if (priv_->deleted_unreachable_types_sorted_.empty())
12065  if (!priv_->deleted_unreachable_types_.empty())
12066  sort_string_type_base_sptr_map(priv_->deleted_unreachable_types_,
12067  priv_->deleted_unreachable_types_sorted_);
12068 
12069  return priv_->deleted_unreachable_types_sorted_;
12070 }
12071 
12072 /// Getter for a map of added types that are not reachable from global
12073 /// functions/variables.
12074 ///
12075 /// @return a map that associates pretty representation of added
12076 /// unreachable types and said types.
12079 {return priv_->added_unreachable_types_;}
12080 
12081 /// Getter of a sorted vector of added types that are not reachable
12082 /// from global functions/variables.
12083 ///
12084 /// @return a sorted vector of added types that are not reachable from
12085 /// global functions/variables. The types are lexicographically
12086 /// sorted by considering their pretty representation.
12087 const vector<type_base_sptr>&
12089 {
12090  if (priv_->added_unreachable_types_sorted_.empty())
12091  if (!priv_->added_unreachable_types_.empty())
12092  sort_string_type_base_sptr_map(priv_->added_unreachable_types_,
12093  priv_->added_unreachable_types_sorted_);
12094 
12095  return priv_->added_unreachable_types_sorted_;
12096 }
12097 
12098 /// Getter for a map of changed types that are not reachable from
12099 /// global functions/variables.
12100 ///
12101 /// @return a map that associates pretty representation of changed
12102 /// unreachable types and said types.
12103 const string_diff_sptr_map&
12105 {return priv_->changed_unreachable_types_;}
12106 
12107 /// Getter of a sorted vector of changed types that are not reachable
12108 /// from global functions/variables.
12109 ///
12110 /// @return a sorted vector of changed types that are not reachable
12111 /// from global functions/variables. The diffs are lexicographically
12112 /// sorted by considering their pretty representation.
12113 const vector<diff_sptr>&
12115 {return priv_->changed_unreachable_types_sorted();}
12116 
12117 /// Getter of the diff context of this diff
12118 ///
12119 /// @return the diff context for this diff.
12120 const diff_context_sptr
12122 {return priv_->get_context();}
12123 
12124 /// @return the pretty representation for the current instance of @ref
12125 /// corpus_diff
12126 const string&
12128 {
12129  if (priv_->pretty_representation_.empty())
12130  {
12131  std::ostringstream o;
12132  o << "corpus_diff["
12133  << first_corpus()->get_path()
12134  << ", "
12135  << second_corpus()->get_path()
12136  << "]";
12137  priv_->pretty_representation_ = o.str();
12138  }
12139  return priv_->pretty_representation_;
12140 }
12141 /// Return true iff the current @ref corpus_diff node carries a
12142 /// change.
12143 ///
12144 /// @return true iff the current diff node carries a change.
12145 bool
12147 {
12148  return (soname_changed()
12150  || !(priv_->deleted_fns_.empty()
12151  && priv_->added_fns_.empty()
12152  && priv_->changed_fns_map_.empty()
12153  && priv_->deleted_vars_.empty()
12154  && priv_->added_vars_.empty()
12155  && priv_->changed_vars_map_.empty()
12156  && priv_->added_unrefed_fn_syms_.empty()
12157  && priv_->deleted_unrefed_fn_syms_.empty()
12158  && priv_->added_unrefed_var_syms_.empty()
12159  && priv_->deleted_unrefed_var_syms_.empty()
12160  && priv_->deleted_unreachable_types_.empty()
12161  && priv_->added_unreachable_types_.empty()
12162  && priv_->changed_unreachable_types_.empty()));
12163 }
12164 
12165 /// Test if the current instance of @ref corpus_diff carries changes
12166 /// that we are sure are incompatible. By incompatible change we mean
12167 /// a change that "breaks" the ABI of the corpus we are looking at.
12168 ///
12169 /// In concrete terms, this function considers the following changes
12170 /// as being ABI incompatible for sure:
12171 ///
12172 /// - a soname change
12173 /// - if exported functions or variables got removed
12174 ///
12175 /// Note that subtype changes *can* represent changes that break ABI
12176 /// too. But they also can be changes that are OK, ABI-wise.
12177 ///
12178 /// It's up to the user to provide suppression specifications to say
12179 /// explicitely which subtype change is OK. The remaining sub-type
12180 /// changes are then considered to be ABI incompatible. But to test
12181 /// if such ABI incompatible subtype changes are present you need to
12182 /// use the function @ref corpus_diff::has_net_subtype_changes()
12183 ///
12184 /// @return true iff the current instance of @ref corpus_diff carries
12185 /// changes that we are sure are ABI incompatible.
12186 bool
12188 {
12189  const diff_stats& stats = const_cast<corpus_diff*>(this)->
12191 
12193  (soname_changed()
12195  || stats.net_num_func_removed() != 0
12197  // If all reports about functions changes have been
12198  // suppressed, then even those about incompatible changes
12199  // don't matter anymore because the user willingly requested
12200  // to shut them down.
12201  && stats.net_num_func_changed() != 0)
12202  || stats.net_num_vars_removed() != 0
12204  && stats.net_num_vars_changed() != 0)
12205  || stats.net_num_removed_func_syms() != 0
12206  || stats.net_num_removed_var_syms() != 0
12207  || stats.net_num_removed_unreachable_types() != 0);
12208 
12209  // If stats.net_num_changed_unreachable_types() != 0 then walk the
12210  // corpus_diff::priv::changed_unreachable_types_, and see if there
12211  // is one that is harmful by bitwise and-ing their category with
12212  // abigail::comparison::get_default_harmful_categories_bitmap().
12213  if (!has_incompatible_changes
12215  {
12216  // The changed unreachable types can carry harmful changes.
12217  // Let's figure if they actually do.
12218 
12219  diff_context_sptr ctxt = context();
12220  for (auto &entry : priv_->changed_unreachable_types())
12221  {
12222  diff_sptr dif = entry.second;
12223 
12224  // Let's see if any of the categories of this diff node
12225  // belong to the "harmful" ones.
12226  if (dif->get_category() & get_default_harmful_categories_bitmap())
12227  {
12228  has_incompatible_changes |= true;
12229  break;
12230  }
12231  }
12232  }
12233 
12234  return has_incompatible_changes;
12235 }
12236 
12237 /// Test if the current instance of @ref corpus_diff carries subtype
12238 /// changes whose reports are not suppressed by any suppression
12239 /// specification. In effect, these are deemed incompatible ABI
12240 /// changes.
12241 ///
12242 /// @return true iff the the current instance of @ref corpus_diff
12243 /// carries subtype changes that are deemed incompatible ABI changes.
12244 bool
12246 {
12247  const diff_stats& stats = const_cast<corpus_diff*>(this)->
12249 
12250  return (stats.net_num_func_changed() != 0
12251  || stats.net_num_vars_changed() != 0
12252  || stats.net_num_removed_unreachable_types() != 0
12253  || stats.net_num_changed_unreachable_types() != 0);
12254 }
12255 
12256 /// Test if the current instance of @ref corpus_diff carries changes
12257 /// whose reports are not suppressed by any suppression specification.
12258 /// In effect, these are deemed incompatible ABI changes.
12259 ///
12260 /// @return true iff the the current instance of @ref corpus_diff
12261 /// carries subtype changes that are deemed incompatible ABI changes.
12262 bool
12264 {return context()->get_reporter()->diff_has_net_changes(this);}
12265 
12266 /// Apply the different filters that are registered to be applied to
12267 /// the diff tree; that includes the categorization filters. Also,
12268 /// apply the suppression interpretation filters.
12269 ///
12270 /// After the filters are applied, this function calculates some
12271 /// statistics about the changes carried by the current instance of
12272 /// @ref corpus_diff. These statistics are represented by an instance
12273 /// of @ref corpus_diff::diff_stats.
12274 ///
12275 /// This member function is called by the reporting function
12276 /// corpus_diff::report().
12277 ///
12278 /// Note that for a given instance of corpus_diff, this function
12279 /// applies the filters and suppressions only the first time it is
12280 /// invoked. Subsequent invocations just return the instance of
12281 /// corpus_diff::diff_stats that was cached after the first
12282 /// invocation.
12283 ///
12284 /// @return a reference to the statistics about the changes carried by
12285 /// the current instance of @ref corpus_diff.
12288 {
12289  if (priv_->diff_stats_)
12290  return *priv_->diff_stats_;
12291 
12293  if (do_log())
12294  {
12295  std::cerr << "Applying suppressions ...\n";
12296  t.start();
12297  }
12298 
12299  apply_suppressions(this);
12300 
12301  if (do_log())
12302  {
12303  t.stop();
12304  std::cerr << "suppressions applied!:" << t << "\n";
12305  }
12306 
12307  priv_->diff_stats_.reset(new diff_stats(context()));
12308 
12309  if (do_log())
12310  {
12311  std::cerr << "Marking leaf nodes ...\n";
12312  t.start();
12313  }
12314 
12316 
12317  if (do_log())
12318  {
12319  t.stop();
12320  std::cerr << "leaf nodes marked!:" << t << "\n";
12321  std::cerr << "Applying filters and computing diff stats ...\n";
12322  t.start();
12323  }
12324 
12325  priv_->apply_filters_and_compute_diff_stats(*priv_->diff_stats_);
12326 
12327  if (do_log())
12328  {
12329  t.stop();
12330  std::cerr << "Filters applied and diff stats computed!: " << t << "\n";
12331  }
12332 
12333  return *priv_->diff_stats_;
12334 }
12335 
12336 /// A visitor that marks leaf diff nodes by storing them in the
12337 /// instance of @ref diff_maps returned by
12338 /// corpus_diff::get_leaf_diffs() invoked on the current instance of
12339 /// corpus_diff.
12340 struct leaf_diff_node_marker_visitor : public diff_node_visitor
12341 {
12342  /// This is called when the visitor visits a diff node.
12343  ///
12344  /// It basically tests if the diff node being visited is a leaf diff
12345  /// node - that is, it contains local changes. If it does, then the
12346  /// node is added to the set of maps that hold leaf diffs in the
12347  /// current corpus_diff.
12348  ///
12349  /// Note that only leaf nodes that are reachable from public
12350  /// interfaces (global functions or variables) are collected by this
12351  /// visitor.
12352  ///
12353  /// @param d the diff node being visited.
12354  virtual void
12355  visit_begin(diff *d)
12356  {
12357  if (d->has_local_changes()
12358  // A leaf basic (or class/union) type name change makes no
12359  // sense when showing just leaf changes. It only makes sense
12360  // when it can explain the details about a non-leaf change.
12361  // In other words, it doesn't make sense to say that an "int"
12362  // became "unsigned int". But it does make sense to say that
12363  // a typedef changed because its underlying type was 'int' and
12364  // is now an "unsigned int".
12366  // Similarly, a *local* change describing a type that changed
12367  // its nature doesn't make sense.
12368  && !is_distinct_diff(d)
12369  // Similarly, a pointer (or reference or array), a typedef or
12370  // qualified type change in itself doesn't make sense. It
12371  // would rather make sense to show that pointer change as part
12372  // of the variable change whose pointer type changed, for
12373  // instance.
12374  && !is_pointer_diff(d)
12375  && !is_reference_diff(d)
12376  && !is_qualified_type_diff(d)
12377  && !is_typedef_diff(d)
12378  && !is_array_diff(d)
12379  // Similarly a parameter change in itself doesn't make sense.
12380  // It should have already been reported as part of the change
12381  // of the function it belongs to.
12382  && !is_fn_parm_diff(d)
12383  // An anonymous class or union diff doesn't make sense on its
12384  // own. It must have been described already by the diff of
12385  // the enclosing struct or union if 'd' is from an anonymous
12386  // data member, or from a typedef change if 'd' is from a
12387  // typedef change which underlying type is an anonymous
12388  // struct/union.
12390  // An anonymous subrange doesn't make sense either.
12392  // Don't show decl-only-ness changes either.
12394  // Sometime, we can encounter artifacts of bogus DWARF that
12395  // yield a diff node for a decl-only class (and empty class
12396  // with the is_declaration flag set) that carries a non-zero
12397  // size! And of course at some point that non-zero size
12398  // changes. We need to be able to detect that.
12400  {
12401  diff_context_sptr ctxt = d->context();
12402  const corpus_diff *corpus_diff_node = ctxt->get_corpus_diff().get();
12403  ABG_ASSERT(corpus_diff_node);
12404 
12405  if (diff *iface_diff = get_current_topmost_iface_diff())
12406  {
12407  type_or_decl_base_sptr iface = iface_diff->first_subject();
12408  // So, this diff node that is reachable from a global
12409  // function or variable carries a leaf change. Let's add
12410  // it to the set of of leaf diffs of corpus_diff_node.
12411  const_cast<corpus_diff*>(corpus_diff_node)->
12412  get_leaf_diffs().insert_diff_node(d, iface);
12413  }
12414  }
12415  }
12416 }; // end struct leaf_diff_node_marker_visitor
12417 
12418 /// Walks the diff nodes associated to the current corpus diff and
12419 /// mark those that carry local changes. They are said to be leaf
12420 /// diff nodes.
12421 ///
12422 /// The marked nodes are available from the
12423 /// corpus_diff::get_leaf_diffs() function.
12424 void
12426 {
12427  if (!has_changes())
12428  return;
12429 
12430  if (!context()->show_leaf_changes_only())
12431  return;
12432 
12433  leaf_diff_node_marker_visitor v;
12434  context()->forget_visited_diffs();
12435  bool s = context()->visiting_a_node_twice_is_forbidden();
12436  context()->forbid_visiting_a_node_twice(true);
12437  if (context()->show_impacted_interfaces())
12438  context()->forbid_visiting_a_node_twice_per_interface(true);
12439  traverse(v);
12440  context()->forbid_visiting_a_node_twice(s);
12441  context()->forbid_visiting_a_node_twice_per_interface(false);
12442 }
12443 
12444 /// Get the set of maps that contain leaf nodes. A leaf node being a
12445 /// node with a local change.
12446 ///
12447 /// @return the set of maps that contain leaf nodes. A leaf node
12448 /// being a node with a local change.
12449 diff_maps&
12451 {return priv_->leaf_diffs_;}
12452 
12453 /// Get the set of maps that contain leaf nodes. A leaf node being a
12454 /// node with a local change.
12455 ///
12456 /// @return the set of maps that contain leaf nodes. A leaf node
12457 /// being a node with a local change.
12458 const diff_maps&
12460 {return priv_->leaf_diffs_;}
12461 
12462 /// Report the diff in a serialized form.
12463 ///
12464 /// @param out the stream to serialize the diff to.
12465 ///
12466 /// @param indent the prefix to use for the indentation of this
12467 /// serialization.
12468 void
12469 corpus_diff::report(ostream& out, const string& indent) const
12470 {
12471  context()->get_reporter()->report(*this, out, indent);
12472 }
12473 
12474 /// Traverse the diff sub-tree under the current instance corpus_diff.
12475 ///
12476 /// @param v the visitor to invoke on each diff node of the sub-tree.
12477 ///
12478 /// @return true if the traversing has to keep going on, false otherwise.
12479 bool
12481 {
12482  finish_diff_type();
12483 
12484  v.visit_begin(this);
12485 
12486  if (!v.visit(this, true))
12487  {
12488  v.visit_end(this);
12489  return false;
12490  }
12491 
12492  for (function_decl_diff_sptrs_type::const_iterator i =
12493  changed_functions_sorted().begin();
12494  i != changed_functions_sorted().end();
12495  ++i)
12496  {
12497  if (diff_sptr d = *i)
12498  {
12499  const diff_context_sptr &ctxt = context();
12500  if (ctxt->visiting_a_node_twice_is_forbidden_per_interface())
12501  ctxt->forget_visited_diffs();
12502 
12503  v.set_current_topmost_iface_diff(d.get());
12504 
12505  if (!d->traverse(v))
12506  {
12507  v.visit_end(this);
12509  return false;
12510  }
12511  }
12512  }
12513 
12514  for (var_diff_sptrs_type::const_iterator i =
12515  changed_variables_sorted().begin();
12516  i != changed_variables_sorted().end();
12517  ++i)
12518  {
12519  if (diff_sptr d = *i)
12520  {
12521  const diff_context_sptr &ctxt = context();
12522  if (ctxt->visiting_a_node_twice_is_forbidden_per_interface())
12523  ctxt->forget_visited_diffs();
12524 
12525  v.set_current_topmost_iface_diff(d.get());
12526 
12527  if (!d->traverse(v))
12528  {
12529  v.visit_end(this);
12531  return false;
12532  }
12533  }
12534  }
12535 
12537 
12538  // Traverse the changed unreachable type diffs. These diffs are on
12539  // types that are not reachable from global functions or variables.
12540  for (vector<diff_sptr>::const_iterator i =
12542  i != changed_unreachable_types_sorted().end();
12543  ++i)
12544  {
12545  if (diff_sptr d = *i)
12546  {
12547  const diff_context_sptr &ctxt = context();
12548  if (ctxt->visiting_a_node_twice_is_forbidden_per_interface())
12549  ctxt->forget_visited_diffs();
12550 
12551  if (!d->traverse(v))
12552  {
12553  v.visit_end(this);
12554  return false;
12555  }
12556  }
12557  }
12558 
12559  v.visit_end(this);
12560  return true;
12561 }
12562 
12563 /// Compute the diff between two instances of @ref corpus.
12564 ///
12565 /// Note that the two corpora must have been created in the same @ref
12566 /// environment, otherwise, this function aborts.
12567 ///
12568 /// @param f the first @ref corpus to consider for the diff.
12569 ///
12570 /// @param s the second @ref corpus to consider for the diff.
12571 ///
12572 /// @param ctxt the diff context to use.
12573 ///
12574 /// @return the resulting diff between the two @ref corpus.
12576 compute_diff(const corpus_sptr f,
12577  const corpus_sptr s,
12578  diff_context_sptr ctxt)
12579 {
12580  typedef corpus::functions::const_iterator fns_it_type;
12581  typedef corpus::variables::const_iterator vars_it_type;
12582  typedef elf_symbols::const_iterator symbols_it_type;
12583  typedef diff_utils::deep_ptr_eq_functor eq_type;
12584  typedef vector<type_base_wptr>::const_iterator type_base_wptr_it_type;
12585 
12586  ABG_ASSERT(f && s);
12587 
12588  if (!ctxt)
12589  ctxt.reset(new diff_context);
12590 
12591  corpus_diff_sptr r(new corpus_diff(f, s, ctxt));
12592 
12593  ctxt->set_corpus_diff(r);
12594 
12595  if(ctxt->show_soname_change())
12596  r->priv_->sonames_equal_ = f->get_soname() == s->get_soname();
12597  else
12598  r->priv_->sonames_equal_ = true;
12599 
12600  r->priv_->architectures_equal_ =
12601  f->get_architecture_name() == s->get_architecture_name();
12602 
12603  // Compute the diff of publicly defined and exported functions
12604  diff_utils::compute_diff<fns_it_type, eq_type>(f->get_functions().begin(),
12605  f->get_functions().end(),
12606  s->get_functions().begin(),
12607  s->get_functions().end(),
12608  r->priv_->fns_edit_script_);
12609 
12610  // Compute the diff of publicly defined and exported variables.
12611  diff_utils::compute_diff<vars_it_type, eq_type>
12612  (f->get_variables().begin(), f->get_variables().end(),
12613  s->get_variables().begin(), s->get_variables().end(),
12614  r->priv_->vars_edit_script_);
12615 
12616  // Compute the diff of function elf symbols not referenced by debug
12617  // info.
12618  diff_utils::compute_diff<symbols_it_type, eq_type>
12619  (f->get_unreferenced_function_symbols().begin(),
12620  f->get_unreferenced_function_symbols().end(),
12621  s->get_unreferenced_function_symbols().begin(),
12622  s->get_unreferenced_function_symbols().end(),
12623  r->priv_->unrefed_fn_syms_edit_script_);
12624 
12625  // Compute the diff of variable elf symbols not referenced by debug
12626  // info.
12627  diff_utils::compute_diff<symbols_it_type, eq_type>
12628  (f->get_unreferenced_variable_symbols().begin(),
12629  f->get_unreferenced_variable_symbols().end(),
12630  s->get_unreferenced_variable_symbols().begin(),
12631  s->get_unreferenced_variable_symbols().end(),
12632  r->priv_->unrefed_var_syms_edit_script_);
12633 
12634  if (ctxt->show_unreachable_types())
12635  // Compute the diff of types not reachable from public functions
12636  // or global variables that are exported.
12637  diff_utils::compute_diff<type_base_wptr_it_type, eq_type>
12638  (f->get_types_not_reachable_from_public_interfaces().begin(),
12639  f->get_types_not_reachable_from_public_interfaces().end(),
12640  s->get_types_not_reachable_from_public_interfaces().begin(),
12641  s->get_types_not_reachable_from_public_interfaces().end(),
12642  r->priv_->unreachable_types_edit_script_);
12643 
12644  r->priv_->ensure_lookup_tables_populated();
12645 
12646  return r;
12647 }
12648 
12649 // </corpus stuff>
12650 
12651 /// Compute the diff between two instances of @ref corpus_group.
12652 ///
12653 /// Note that the two corpus_diff must have been created in the same
12654 /// @ref environment, otherwise, this function aborts.
12655 ///
12656 /// @param f the first @ref corpus_group to consider for the diff.
12657 ///
12658 /// @param s the second @ref corpus_group to consider for the diff.
12659 ///
12660 /// @param ctxt the diff context to use.
12661 ///
12662 /// @return the resulting diff between the two @ref corpus_group.
12664 compute_diff(const corpus_group_sptr& f,
12665  const corpus_group_sptr& s,
12666  diff_context_sptr ctxt)
12667 {
12668 
12669  corpus_sptr c1 = f;
12670  corpus_sptr c2 = s;
12671 
12672  return compute_diff(c1, c2, ctxt);
12673 }
12674 
12675 // <corpus_group stuff>
12676 
12677 // </corpus_group stuff>
12678 // <diff_node_visitor stuff>
12679 
12680 /// The private data of the @diff_node_visitor type.
12681 struct diff_node_visitor::priv
12682 {
12683  diff* topmost_interface_diff;
12684  visiting_kind kind;
12685 
12686  priv()
12687  : topmost_interface_diff(),
12688  kind()
12689  {}
12690 
12691  priv(visiting_kind k)
12692  : topmost_interface_diff(),
12693  kind(k)
12694  {}
12695 }; // end struct diff_node_visitor
12696 
12697 /// Default constructor of the @ref diff_node_visitor type.
12699  : priv_(new priv)
12700 {}
12701 
12702 diff_node_visitor::~diff_node_visitor() = default;
12703 
12704 /// Constructor of the @ref diff_node_visitor type.
12705 ///
12706 /// @param k how the visiting has to be performed.
12708  : priv_(new priv(k))
12709 {}
12710 
12711 /// Getter for the visiting policy of the traversing code while
12712 /// invoking this visitor.
12713 ///
12714 /// @return the visiting policy used by the traversing code when
12715 /// invoking this visitor.
12718 {return priv_->kind;}
12719 
12720 /// Setter for the visiting policy of the traversing code while
12721 /// invoking this visitor.
12722 ///
12723 /// @param v a bit map representing the new visiting policy used by
12724 /// the traversing code when invoking this visitor.
12725 void
12727 {priv_->kind = v;}
12728 
12729 /// Setter for the visiting policy of the traversing code while
12730 /// invoking this visitor. This one makes a logical or between the
12731 /// current policy and the bitmap given in argument and assigns the
12732 /// current policy to the result.
12733 ///
12734 /// @param v a bitmap representing the visiting policy to or with
12735 /// the current policy.
12736 void
12738 {priv_->kind = priv_->kind | v;}
12739 
12740 /// Setter of the diff current topmost interface which is impacted by
12741 /// the current diff node being visited.
12742 ///
12743 /// @param d the current topmost interface diff impacted.
12744 void
12746 {priv_->topmost_interface_diff = d;}
12747 
12748 /// Getter of the diff current topmost interface which is impacted by
12749 /// the current diff node being visited.
12750 ///
12751 /// @return the current topmost interface diff impacted.
12752 diff*
12754 {return priv_->topmost_interface_diff;}
12755 
12756 /// This is called by the traversing code on a @ref diff node just
12757 /// before visiting it. That is, before visiting it and its children
12758 /// node.
12759 ///
12760 /// @param d the diff node to visit.
12761 void
12763 {}
12764 
12765 /// This is called by the traversing code on a @ref diff node just
12766 /// after visiting it. That is after visiting it and its children
12767 /// nodes.
12768 ///
12769 /// @param d the diff node that got visited.
12770 void
12772 {}
12773 
12774 /// This is called by the traversing code on a @ref corpus_diff node
12775 /// just before visiting it. That is, before visiting it and its
12776 /// children node.
12777 ///
12778 /// @param p the corpus_diff node to visit.
12779 ///
12780 void
12782 {}
12783 
12784 /// This is called by the traversing code on a @ref corpus_diff node
12785 /// just after visiting it. That is after visiting it and its children
12786 /// nodes.
12787 ///
12788 /// @param d the diff node that got visited.
12789 void
12791 {}
12792 
12793 /// Default visitor implementation
12794 ///
12795 /// @return true
12796 bool
12798 {return true;}
12799 
12800 /// Default visitor implementation.
12801 ///
12802 /// @return true
12803 bool
12805 {
12806  diff* d = dif;
12807  visit(d, pre);
12808 
12809  return true;
12810 }
12811 
12812 /// Default visitor implementation.
12813 ///
12814 /// @return true
12815 bool
12817 {
12818  diff* d = dif;
12819  visit(d, pre);
12820 
12821  return true;
12822 }
12823 
12824 /// Default visitor implementation.
12825 ///
12826 /// @return true
12827 bool
12829 {
12830  diff* d = dif;
12831  visit(d, pre);
12832 
12833  return true;
12834 }
12835 
12836 /// Default visitor implementation.
12837 ///
12838 /// @return true
12839 bool
12841 {
12842  diff* d = dif;
12843  visit(d, pre);
12844 
12845  return true;
12846 }
12847 
12848 /// Default visitor implementation.
12849 ///
12850 /// @return true
12851 bool
12853 {
12854  diff* d = dif;
12855  visit(d, pre);
12856 
12857  return true;
12858 }
12859 
12860 /// Default visitor implementation.
12861 ///
12862 /// @return true
12863 bool
12865 {
12866  diff* d = dif;
12867  visit(d, pre);
12868 
12869  return true;
12870 }
12871 
12872 /// Default visitor implementation.
12873 ///
12874 /// @return true
12875 bool
12877 {
12878  diff* d = dif;
12879  visit(d, pre);
12880 
12881  return true;
12882 }
12883 
12884 /// Default visitor implementation.
12885 ///
12886 /// @return true
12887 bool
12889 {
12890  diff* d = dif;
12891  visit(d, pre);
12892 
12893  return true;
12894 }
12895 
12896 /// Default visitor implementation.
12897 ///
12898 /// @return true
12899 bool
12901 {
12902  diff* d = dif;
12903  visit(d, pre);
12904 
12905  return true;
12906 }
12907 
12908 /// Default visitor implementation.
12909 ///
12910 /// @return true
12911 bool
12913 {
12914  diff* d = dif;
12915  visit(d, pre);
12916 
12917  return true;
12918 }
12919 
12920 /// Default visitor implementation.
12921 ///
12922 /// @return true
12923 bool
12925 {
12926  diff* d = dif;
12927  visit(d, pre);
12928 
12929  return true;
12930 }
12931 
12932 /// Default visitor implementation.
12933 ///
12934 /// @return true
12935 bool
12937 {
12938  diff* d = dif;
12939  visit(d, pre);
12940 
12941  return true;
12942 }
12943 
12944 /// Default visitor implementation.
12945 ///
12946 /// @return true
12947 bool
12949 {
12950  diff* d = dif;
12951  visit(d, pre);
12952 
12953  return true;
12954 }
12955 
12956 /// Default visitor implementation.
12957 ///
12958 /// @return true
12959 bool
12961 {return true;}
12962 
12963 // </diff_node_visitor stuff>
12964 
12965 // <redundant diff node marking>
12966 
12967 // </redundant diff node marking>
12968 
12969 // <diff tree category propagation>
12970 
12971 /// A visitor to propagate the category of a node up to its parent
12972 /// nodes. This visitor doesn't touch the REDUNDANT_CATEGORY or the
12973 /// SUPPRESSED_CATEGORY because those are propagated using other
12974 /// specific visitors.
12975 struct category_propagation_visitor : public diff_node_visitor
12976 {
12977  virtual void
12978  visit_end(diff* d)
12979  {
12980  // Has this diff node 'd' been already visited ?
12981  bool already_visited = d->context()->diff_has_been_visited(d);
12982 
12983  // The canonical diff node of the class of equivalence of the diff
12984  // node 'd'.
12985  diff* canonical = d->get_canonical_diff();
12986 
12987  // If this class of equivalence of diff node is being visited for
12988  // the first time, then update its canonical node's category too.
12989  bool update_canonical = !already_visited && canonical;
12990 
12991  for (vector<diff*>::const_iterator i = d->children_nodes().begin();
12992  i != d->children_nodes().end();
12993  ++i)
12994  {
12995  // If we are visiting the class of equivalence of 'd' for the
12996  // first time, then let's look at the children of 'd' and
12997  // propagate their categories to 'd'.
12998  //
12999  // If the class of equivalence of 'd' has already been
13000  // visited, then let's look at the canonical diff nodes of the
13001  // children of 'd' and propagate their categories to 'd'.
13002  diff* diff = already_visited
13003  ? (*i)->get_canonical_diff()
13004  : *i;
13005 
13006  ABG_ASSERT(diff);
13007 
13008  diff_category c = diff->get_category();
13009  // Do not propagate redundant and suppressed categories. Those
13010  // are propagated in a specific pass elsewhere.
13011  c &= ~(REDUNDANT_CATEGORY
13017  // Also, if a (class) type has got a harmful name change, do not
13018  // propagate harmless name changes coming from its sub-types
13019  // (i.e, data members) to the class itself.
13022 
13023  d->add_to_category(c);
13024  if (!already_visited && canonical)
13025  if (update_canonical)
13026  canonical->add_to_category(c);
13027  }
13028 
13031  {
13032  // The current diff node has either:
13033  //
13034  // 1/ a harmless "void pointer to pointer" change
13035  //
13036  // or:
13037  //
13038  // 2/ a harmless "enum to int" change.
13039  //
13040  // The change 1/ was most likely flagged locally as a
13041  // non-compatible distinct change, aka, a non-compatible
13042  // change between two types of different kinds. At a higher
13043  // level however, as we see that it's just a void pointer to
13044  // pointer change, we should unset the
13045  // NON_COMPATIBLE_DISTINCT_CHANGE_CATEGORY categorization.
13046  //
13047  // The change 2/ was most likely flagged locally (in the
13048  // children nodes of the current diff node) as a
13049  // non-compatible name change. At a higher level however, as
13050  // we see that it's just a harmless "enum to int" change,
13051  // let's unset the NON_COMPATIBLE_NAME_CHANGE_CATEGORY
13052  // categorization as well.
13053  diff_category c = d->get_category();
13056  d->set_category(c);
13057  if (is_pointer_diff(d) || is_reference_diff(d))
13058  {
13059  // For pointers and references, changes to
13060  // pointed-to-types are considered local. So, if some
13061  // pointed-to-types have non-compatible name or distinct
13062  // change, then the local category of the
13063  // pointer/reference will reflect that. Let's thus clear
13064  // those NON_COMPATIBLE_DISTINCT_CHANGE_CATEGORY and
13065  // NON_COMPATIBLE_NAME_CHANGE_CATEGORY bits from the local
13066  // category as well.
13067  c = d->get_local_category();
13070  d->set_local_category(c);
13071  }
13072  }
13073 
13075  {
13076  diff_category c = d->get_category();
13078  d->set_category(c);
13079  }
13080  }
13081 };// end struct category_propagation_visitor
13082 
13083 /// Visit all the nodes of a given sub-tree. For each node that has a
13084 /// particular category set, propagate that category set up to its
13085 /// parent nodes.
13086 ///
13087 /// @param diff_tree the diff sub-tree to walk for categorization
13088 /// purpose;
13089 void
13090 propagate_categories(diff* diff_tree)
13091 {
13092  category_propagation_visitor v;
13093  bool s = diff_tree->context()->visiting_a_node_twice_is_forbidden();
13094  diff_tree->context()->forbid_visiting_a_node_twice(true);
13095  diff_tree->context()->forget_visited_diffs();
13096  diff_tree->traverse(v);
13097  diff_tree->context()->forbid_visiting_a_node_twice(s);
13098 }
13099 
13100 /// Visit all the nodes of a given sub-tree. For each node that has a
13101 /// particular category set, propagate that category set up to its
13102 /// parent nodes.
13103 ///
13104 /// @param diff_tree the diff sub-tree to walk for categorization
13105 /// purpose;
13106 void
13108 {propagate_categories(diff_tree.get());}
13109 
13110 /// Visit all the nodes of a given corpus tree. For each node that
13111 /// has a particular category set, propagate that category set up to
13112 /// its parent nodes.
13113 ///
13114 /// @param diff_tree the corpus_diff tree to walk for categorization
13115 /// purpose;
13116 void
13118 {
13119  category_propagation_visitor v;
13120  bool s = diff_tree->context()->visiting_a_node_twice_is_forbidden();
13121  diff_tree->context()->forbid_visiting_a_node_twice(false);
13122  diff_tree->traverse(v);
13123  diff_tree->context()->forbid_visiting_a_node_twice(s);
13124 }
13125 
13126 /// Visit all the nodes of a given corpus tree. For each node that
13127 /// has a particular category set, propagate that category set up to
13128 /// its parent nodes.
13129 ///
13130 /// @param diff_tree the corpus_diff tree to walk for categorization
13131 /// purpose;
13132 void
13134 {propagate_categories(diff_tree.get());}
13135 
13136 /// A tree node visitor that knows how to categorizes a given diff
13137 /// node in the SUPPRESSED_CATEGORY category and how to propagate that
13138 /// categorization.
13139 struct suppression_categorization_visitor : public diff_node_visitor
13140 {
13141 
13142  /// Before visiting the children of the diff node, check if the node
13143  /// is suppressed by a suppression specification. If it is, mark
13144  /// the node as belonging to the SUPPRESSED_CATEGORY category.
13145  ///
13146  /// @param p the diff node to visit.
13147  virtual void
13148  visit_begin(diff* d)
13149  {
13150  bool is_private_type = false;
13151  if (d->is_suppressed(is_private_type))
13152  {
13153  diff_category c = is_private_type
13157 
13158  // If a node was suppressed, all the other nodes of its class
13159  // of equivalence are suppressed too.
13160  diff *canonical_diff = d->get_canonical_diff();
13161  if (canonical_diff != d)
13162  canonical_diff->add_to_category(c);
13163  }
13165  {
13166  // This diff node is specifically allowed by a
13167  // negated_suppression, then mark it as being in the
13168  // HAS_ALLOWED_CHANGE_CATEGORY.
13170  d->add_to_local_category(c);
13171  diff *canonical_diff = d->get_canonical_diff();
13172  canonical_diff->add_to_category(c);
13173 
13174  // Note that some complementary code later down below does
13175  // categorize the descendants and parents nodes of this node
13176  // as HAS_PARENT_WITH_ALLOWED_CHANGE_CATEGORY and
13177  // HAS_DESCENDANT_WITH_ALLOWED_CHANGE_CATEGORY, repectively.
13178  }
13179 
13180  // If a parent node has been allowed by a negated suppression
13181  // specification, then categorize the current node as
13182  // HAS_PARENT_WITH_ALLOWED_CHANGE_CATEGORY.
13183  if (d->parent_node())
13184  {
13189  else
13190  {
13191  c = d->parent_node()->get_category();
13195  }
13196  }
13197 
13198  }
13199 
13200  /// After visiting the children nodes of a given diff node,
13201  /// propagate the SUPPRESSED_CATEGORY from the children nodes to the
13202  /// diff node, if need be.
13203  ///
13204  /// That is, if all children nodes carry a suppressed change the
13205  /// current node should be marked as suppressed as well.
13206  ///
13207  /// In practice, this might be too strong of a condition. If the
13208  /// current node carries a local change (i.e, a change not carried
13209  /// by any of its children node) and if that change is not
13210  /// suppressed, then the current node should *NOT* be suppressed.
13211  ///
13212  /// But right now, the IR doesn't let us know about local vs
13213  /// children-carried changes. So we cannot be that precise yet.
13214  virtual void
13215  visit_end(diff* d)
13216  {
13217  bool has_non_suppressed_child = false;
13218  bool has_non_empty_child = false;
13219  bool has_suppressed_child = false;
13220  bool has_non_private_child = false;
13221  bool has_private_child = false;
13222  bool has_descendant_with_allowed_change = false;
13223 
13224  if (// A node to which we can propagate the "SUPPRESSED_CATEGORY"
13225  // (or the PRIVATE_TYPE_CATEGORY for the same matter)
13226  // category from its children is a node which:
13227  //
13228  // 1/ hasn't been suppressed already
13229  //
13230  // 2/ and has no local change (unless it's a pointer,
13231  // reference or qualified diff node).
13232  //
13233  // Note that qualified type and typedef diff nodes are a bit
13234  // special. The local changes of the underlying type are
13235  // considered local for the qualified/typedef type, just like
13236  // for pointer/reference types. But then the qualified or
13237  // typedef type itself can have local changes of its own, and
13238  // those changes are of the kind LOCAL_NON_TYPE_CHANGE_KIND.
13239  // So a qualified type which have local changes that are
13240  // *NOT* of LOCAL_NON_TYPE_CHANGE_KIND (or that has no local
13241  // changes at all) and which is in the PRIVATE_TYPE_CATEGORY
13242  // or SUPPRESSED_CATEGORY can see these categories be
13243  // propagated.
13244  //
13245  // Note that all pointer/reference diff node changes are
13246  // potentially considered local, i.e, local changes of the
13247  // pointed-to-type are considered local to the pointer itself.
13248  //
13249  // Similarly, changes local to the type of function parameters,
13250  // variables (and data members) and classes (that are not of
13251  // LOCAL_NON_TYPE_CHANGE_KIND kind) and that have been
13252  // suppressed can propagate their SUPPRESSED_CATEGORY-ness to
13253  // those kinds of diff node.
13254  !(d->get_category() & SUPPRESSED_CATEGORY)
13255  && (!d->has_local_changes()
13256  || is_pointer_diff(d)
13257  || is_reference_diff(d)
13258  || (is_qualified_type_diff(d)
13259  && (!(d->has_local_changes() & LOCAL_NON_TYPE_CHANGE_KIND)))
13260  || (is_typedef_diff(d)
13261  && (!(d->has_local_changes() & LOCAL_NON_TYPE_CHANGE_KIND)))
13262  || (is_function_decl_diff(d)
13263  && (!(d->has_local_changes() & LOCAL_NON_TYPE_CHANGE_KIND)))
13264  || (is_fn_parm_diff(d)
13265  && (!(d->has_local_changes() & LOCAL_NON_TYPE_CHANGE_KIND)))
13266  || (is_function_type_diff(d)
13267  && (!(d->has_local_changes() & LOCAL_NON_TYPE_CHANGE_KIND)))
13268  || (is_var_diff(d)
13269  && (!(d->has_local_changes() & LOCAL_NON_TYPE_CHANGE_KIND)))
13270  || (is_class_diff(d)
13271  && (!(d->has_local_changes() & LOCAL_NON_TYPE_CHANGE_KIND)))))
13272  {
13273  // Note that we handle private diff nodes differently from
13274  // generally suppressed diff nodes. E.g, it's not because a
13275  // type is private (and suppressed because of that; i.e, in
13276  // the category PRIVATE_TYPE_CATEGORY) that a typedef to that
13277  // type should also be private and so suppressed. Private
13278  // diff nodes thus have different propagation rules than
13279  // generally suppressed rules.
13280  for (vector<diff*>::const_iterator i = d->children_nodes().begin();
13281  i != d->children_nodes().end();
13282  ++i)
13283  {
13284  diff* child = *i;
13285  if (child->has_changes())
13286  {
13287  has_non_empty_child = true;
13288  if (child->get_class_of_equiv_category() & SUPPRESSED_CATEGORY)
13289  has_suppressed_child = true;
13290  else if (child->get_class_of_equiv_category()
13292  // Propagation of the PRIVATE_TYPE_CATEGORY is going
13293  // to be handled later below.
13294  ;
13295  else
13296  has_non_suppressed_child = true;
13297 
13298  if (child->get_class_of_equiv_category()
13300  has_private_child = true;
13301  else if (child->get_class_of_equiv_category()
13303  // Propagation of the SUPPRESSED_CATEGORY has been
13304  // handled above already.
13305  ;
13306  else
13307  has_non_private_child = true;
13308  }
13309  }
13310 
13311  if (has_non_empty_child
13312  && has_suppressed_child
13313  && !has_non_suppressed_child)
13314  {
13316  // If a node was suppressed, all the other nodes of its class
13317  // of equivalence are suppressed too.
13318  diff *canonical_diff = d->get_canonical_diff();
13319  if (canonical_diff != d)
13320  canonical_diff->add_to_category(SUPPRESSED_CATEGORY);
13321  }
13322 
13323  // Note that the private-ness of a an underlying type won't be
13324  // propagated to its parent typedef, by virtue of the big "if"
13325  // clause at the beginning of this function. So we don't have
13326  // to handle that case here. So the idiom of defining
13327  // typedefs of private (opaque) types will be respected;
13328  // meaning that changes to opaque underlying type will be
13329  // flagged as private and the typedef will be flagged private
13330  // as well, unless the typedef itself has local non-type
13331  // changes. In the later case, changes to the typedef will be
13332  // emitted because the typedef won't inherit the privateness
13333  // of its underlying type. So in practise, the typedef
13334  // remains public for the purpose of change reporting.
13335  if (has_non_empty_child
13336  && has_private_child
13337  && !has_non_private_child)
13338  {
13339  d->add_to_category(PRIVATE_TYPE_CATEGORY);
13340  // If a node was suppressed, all the other nodes of its class
13341  // of equivalence are suppressed too.
13342  diff *canonical_diff = d->get_canonical_diff();
13343  if (canonical_diff != d)
13344  canonical_diff->add_to_category(PRIVATE_TYPE_CATEGORY);
13345  }
13346 
13347  // If the underlying type of a typedef is private and carries
13348  // changes (that are implicitely suppressed because it's
13349  // private) then the typedef must be suppressed too, so that
13350  // those changes to the underlying type are not seen.
13351  if (is_typedef_diff(d)
13352  && !d->has_local_changes()
13353  && has_private_child
13354  && has_non_empty_child)
13355  {
13356  d->add_to_category(SUPPRESSED_CATEGORY|PRIVATE_TYPE_CATEGORY);
13357  // If a node was suppressed, all the other nodes of its class
13358  // of equivalence are suppressed too.
13359  diff *canonical_diff = d->get_canonical_diff();
13360  if (canonical_diff != d)
13361  canonical_diff->add_to_category
13363  }
13364 
13365  if (const function_decl_diff *fn_diff = is_function_decl_diff(d))
13366  if (!(d->has_local_changes() & LOCAL_NON_TYPE_CHANGE_KIND))
13367  {
13368  // d is a function diff that carries a local *type*
13369  // change (that means it's a change to the function
13370  // type). Let's see if the child function type diff
13371  // node is suppressed. That would mean that we are
13372  // instructed to show details of a diff that is deemed
13373  // suppressed; this means the suppression conflicts with
13374  // a local type change. In that case, let's follow what
13375  // the user asked and suppress the function altogether,
13376  if (function_type_diff_sptr fn_type_diff = fn_diff->type_diff())
13377  if (fn_type_diff->is_suppressed())
13378  {
13379  d->add_to_category(SUPPRESSED_CATEGORY);
13380  // If a node was suppressed, all the other nodes
13381  // of its class of equivalence are suppressed too.
13382  diff *canonical_diff = d->get_canonical_diff();
13383  if (canonical_diff != d)
13384  canonical_diff->add_to_category(SUPPRESSED_CATEGORY);
13385  }
13386  }
13387  }
13388 
13389  // If any descendant node was selected by a negated suppression
13390  // specification then categorize the current one as
13391  // HAS_DESCENDANT_WITH_ALLOWED_CHANGE_CATEGORY.
13392  for (auto child_node : d->children_nodes())
13393  {
13394  diff *canonical_diff = child_node->get_canonical_diff();
13395  diff_category c = canonical_diff->get_category();
13398  has_descendant_with_allowed_change = true;
13399  }
13400  if (has_descendant_with_allowed_change)
13401  {
13403  d->add_to_category(c);
13404  d->get_canonical_diff()->add_to_category(c);
13405  }
13406  }
13407 }; //end struct suppression_categorization_visitor
13408 
13409 /// Walk a given diff-sub tree and appply the suppressions carried by
13410 /// the context. If the suppression applies to a given node than
13411 /// categorize the node into the SUPPRESSED_CATEGORY category and
13412 /// propagate that categorization.
13413 ///
13414 /// @param diff_tree the diff-sub tree to apply the suppressions to.
13415 void
13416 apply_suppressions(diff* diff_tree)
13417 {
13418  if (diff_tree && !diff_tree->context()->suppressions().empty())
13419  {
13420  // Apply suppressions to functions and variables that have
13421  // changed sub-types.
13422  suppression_categorization_visitor v;
13423  diff_tree->context()->forget_visited_diffs();
13424  bool s = diff_tree->context()->visiting_a_node_twice_is_forbidden();
13425  diff_tree->context()->forbid_visiting_a_node_twice(true);
13426  diff_tree->traverse(v);
13427  diff_tree->context()->forbid_visiting_a_node_twice(s);
13428  }
13429 }
13430 
13431 /// Walk a given diff-sub tree and appply the suppressions carried by
13432 /// the context. If the suppression applies to a given node than
13433 /// categorize the node into the SUPPRESSED_CATEGORY category and
13434 /// propagate that categorization.
13435 ///
13436 /// @param diff_tree the diff-sub tree to apply the suppressions to.
13437 void
13439 {apply_suppressions(diff_tree.get());}
13440 
13441 /// Walk a @ref corpus_diff tree and appply the suppressions carried
13442 /// by the context. If the suppression applies to a given node then
13443 /// categorize the node into the SUPPRESSED_CATEGORY category and
13444 /// propagate that categorization.
13445 ///
13446 /// @param diff_tree the diff tree to apply the suppressions to.
13447 void
13449 {
13450  if (diff_tree && !diff_tree->context()->suppressions().empty())
13451  {
13452  // First, visit the children trees of changed constructs:
13453  // changed functions, variables, as well as sub-types of these,
13454  // and apply suppression specifications to these ...
13455  suppression_categorization_visitor v;
13456  diff_tree->context()->forget_visited_diffs();
13457  bool s = diff_tree->context()->visiting_a_node_twice_is_forbidden();
13458  diff_tree->context()->forbid_visiting_a_node_twice(true);
13459  const_cast<corpus_diff*>(diff_tree)->traverse(v);
13460  diff_tree->context()->forbid_visiting_a_node_twice(s);
13461 
13462  // ... then also visit the set of added and removed functions,
13463  // variables, symbols, and types not reachable from global
13464  // functions and variables.
13465  diff_tree->priv_->
13466  apply_supprs_to_added_removed_fns_vars_unreachable_types();
13467  }
13468 }
13469 
13470 /// Walk a diff tree and appply the suppressions carried by the
13471 /// context. If the suppression applies to a given node than
13472 /// categorize the node into the SUPPRESSED_CATEGORY category and
13473 /// propagate that categorization.
13474 ///
13475 /// @param diff_tree the diff tree to apply the suppressions to.
13476 void
13478 {apply_suppressions(diff_tree.get());}
13479 
13480 // </diff tree category propagation>
13481 
13482 // <diff tree printing stuff>
13483 
13484 /// A visitor to print (to an output stream) a pretty representation
13485 /// of a @ref diff sub-tree or of a complete @ref corpus_diff tree.
13486 struct diff_node_printer : public diff_node_visitor
13487 {
13488  ostream& out_;
13489  unsigned level_;
13490 
13491  /// Emit a certain number of spaces to the output stream associated
13492  /// to this diff_node_printer.
13493  ///
13494  /// @param level half of the numver of spaces to emit.
13495  void
13496  do_indent(unsigned level)
13497  {
13498  for (unsigned i = 0; i < level; ++i)
13499  out_ << " ";
13500  }
13501 
13502  diff_node_printer(ostream& out)
13503  : diff_node_visitor(DO_NOT_MARK_VISITED_NODES_AS_VISITED),
13504  out_(out),
13505  level_(0)
13506  {}
13507 
13508  virtual void
13509  visit_begin(diff*)
13510  {
13511  ++level_;
13512  }
13513 
13514  virtual void
13515  visit_end(diff*)
13516  {
13517  --level_;
13518  }
13519 
13520  virtual void
13521  visit_begin(corpus_diff*)
13522  {
13523  ++level_;
13524  }
13525 
13526  virtual void
13527  visit_end(corpus_diff*)
13528  {
13529  --level_;
13530  }
13531 
13532  virtual bool
13533  visit(diff* d, bool pre)
13534  {
13535  if (!pre)
13536  // We are post-visiting the diff node D. Which means, we have
13537  // printed a pretty representation for it already. So do
13538  // nothing now.
13539  return true;
13540 
13541  do_indent(level_);
13542  out_ << d->get_pretty_representation();
13543  out_ << "\n";
13544  do_indent(level_);
13545  out_ << "{\n";
13546  do_indent(level_ + 1);
13547  out_ << "category: "<< d->get_category() << "\n";
13548  do_indent(level_ + 1);
13549  out_ << "local category: "<< d->get_local_category() << "\n";
13550  do_indent(level_ + 1);
13551  out_ << "@: " << std::hex << d << std::dec << "\n";
13552  do_indent(level_ + 1);
13553  out_ << "@-canonical: " << std::hex
13554  << d->get_canonical_diff()
13555  << std::dec << "\n";
13556  do_indent(level_);
13557  out_ << "}\n";
13558 
13559  return true;
13560  }
13561 
13562  virtual bool
13563  visit(corpus_diff* d, bool pre)
13564  {
13565  if (!pre)
13566  // We are post-visiting the diff node D. Which means, we have
13567  // printed a pretty representation for it already. So do
13568  // nothing now.
13569  return true;
13570 
13571  // indent
13572  for (unsigned i = 0; i < level_; ++i)
13573  out_ << ' ';
13574  out_ << d->get_pretty_representation();
13575  out_ << '\n';
13576  return true;
13577  }
13578 }; // end struct diff_printer_visitor
13579 
13580 // </ diff tree printing stuff>
13581 
13582 /// Emit a textual representation of a @ref diff sub-tree to an
13583 /// output stream.
13584 ///
13585 /// @param diff_tree the sub-tree to emit the textual representation
13586 /// for.
13587 ///
13588 /// @param out the output stream to emit the textual representation
13589 /// for @p diff_tree to.
13590 void
13591 print_diff_tree(diff* diff_tree, ostream& out)
13592 {
13593  diff_node_printer p(out);
13594  bool s = diff_tree->context()->visiting_a_node_twice_is_forbidden();
13595  diff_tree->context()->forbid_visiting_a_node_twice(false);
13596  diff_tree->traverse(p);
13597  diff_tree->context()->forbid_visiting_a_node_twice(s);
13598 }
13599 
13600 /// Emit a textual representation of a @ref corpus_diff tree to an
13601 /// output stream.
13602 ///
13603 /// @param diff_tree the @ref corpus_diff tree to emit the textual
13604 /// representation for.
13605 ///
13606 /// @param out the output stream to emit the textual representation
13607 /// for @p diff_tree to.
13608 void
13609 print_diff_tree(corpus_diff* diff_tree, std::ostream& out)
13610 {
13611  diff_node_printer p(out);
13612  bool s = diff_tree->context()->visiting_a_node_twice_is_forbidden();
13613  diff_tree->context()->forbid_visiting_a_node_twice(false);
13614  diff_tree->traverse(p);
13615  diff_tree->context()->forbid_visiting_a_node_twice(s);
13616 }
13617 
13618 /// Emit a textual representation of a @ref diff sub-tree to an
13619 /// output stream.
13620 ///
13621 /// @param diff_tree the sub-tree to emit the textual representation
13622 /// for.
13623 ///
13624 /// @param out the output stream to emit the textual representation
13625 /// for @p diff_tree to.
13626 void
13628  std::ostream& o)
13629 {print_diff_tree(diff_tree.get(), o);}
13630 
13631 /// Emit a textual representation of a @ref corpus_diff tree to an
13632 /// output stream.
13633 ///
13634 /// @param diff_tree the @ref corpus_diff tree to emit the textual
13635 /// representation for.
13636 ///
13637 /// @param out the output stream to emit the textual representation
13638 /// for @p diff_tree to.
13639 void
13641  std::ostream& o)
13642 {print_diff_tree(diff_tree.get(), o);}
13643 
13644 /// Print a given category out to stdout for debuging purposes
13645 ///
13646 /// @param c the category to print to stdout.
13647 void
13649 {
13650  std::cout << c << std::endl;
13651 }
13652 
13653 // <redundancy_marking_visitor>
13654 
13655 /// A tree visitor to categorize nodes with respect to the
13656 /// REDUNDANT_CATEGORY. That is, detect if a node is redundant (is
13657 /// present on several spots of the tree) and mark such nodes
13658 /// appropriatly. This visitor also takes care of propagating the
13659 /// REDUNDANT_CATEGORY of a given node to its parent nodes as
13660 /// appropriate.
13661 struct redundancy_marking_visitor : public diff_node_visitor
13662 {
13663  bool skip_children_nodes_;
13664 
13665  redundancy_marking_visitor()
13666  : skip_children_nodes_()
13667  {}
13668 
13669  virtual void
13670  visit_begin(diff* d)
13671  {
13672  if (d->to_be_reported())
13673  {
13674  // A diff node that carries a change and that has been already
13675  // traversed elsewhere is considered redundant. So let's mark
13676  // it as such and let's not traverse it; that is, let's not
13677  // visit its children.
13678  if ((d->context()->diff_has_been_visited(d)
13679  || d->get_canonical_diff()->is_traversing())
13680  && d->has_changes())
13681  {
13682  // But if two diff nodes are redundant sibbling that carry
13683  // changes of base types, do not mark them as being
13684  // redundant. This is to avoid marking nodes as redundant
13685  // in this case:
13686  //
13687  // int foo(int a, int b);
13688  // compared with:
13689  // float foo(float a, float b); (in C).
13690  //
13691  // In this case, we want to report all the occurences of
13692  // the int->float change because logically, they are at
13693  // the same level in the diff tree.
13694 
13695  bool redundant_with_sibling_node = false;
13696  const diff* p = d->parent_node();
13697 
13698  // If this is a child node of a fn_parm_diff, look through
13699  // the fn_parm_diff node to get the function diff node.
13700  if (p && dynamic_cast<const fn_parm_diff*>(p))
13701  p = p->parent_node();
13702 
13703  if (p)
13704  for (vector<diff*>::const_iterator s =
13705  p->children_nodes().begin();
13706  s != p->children_nodes().end();
13707  ++s)
13708  {
13709  if (*s == d)
13710  continue;
13711  diff* sib = *s;
13712  // If this is a fn_parm_diff, look through the
13713  // fn_parm_diff node to get at the real type node.
13714  if (fn_parm_diff* f = dynamic_cast<fn_parm_diff*>(*s))
13715  sib = f->type_diff().get();
13716  if (sib == d)
13717  continue;
13718  if (sib->get_canonical_diff() == d->get_canonical_diff()
13719  // Sibbling diff nodes that carry base type
13720  // changes are to be marked as redundant.
13721  && (is_base_diff(sib) || is_distinct_diff(sib)))
13722  {
13723  redundant_with_sibling_node = true;
13724  break;
13725  }
13726  }
13727  if (!redundant_with_sibling_node
13728  // Changes to basic types should never be considered
13729  // redundant. For instance, if a member of integer
13730  // type is changed into a char type in both a struct A
13731  // and a struct B, we want to see both changes.
13733  // The same goes for distinct type changes
13735  // Functions with similar *local* changes are never marked
13736  // redundant because otherwise one could miss important
13737  // similar local changes that are applied to different
13738  // functions.
13740  // Changes involving variadic parameters of functions
13741  // should never be marked redundant because we want to see
13742  // them all.
13745  // If the canonical diff itself has been filtered out,
13746  // then this one is not marked redundant, unless the
13747  // canonical diff was already redundant.
13748  && (!d->get_canonical_diff()->is_filtered_out()
13749  || (d->get_canonical_diff()->get_category()
13750  & REDUNDANT_CATEGORY))
13751  // If the *same* diff node (not one that is merely
13752  // equivalent to this one) has already been visited
13753  // the do not mark it as beind redundant. It's only
13754  // the other nodes that are equivalent to this one
13755  // that must be marked redundant.
13756  && d->context()->diff_has_been_visited(d) != d
13757  // If the diff node is a function parameter and is not
13758  // a reference/pointer (to a non basic or a non
13759  // distinct type diff) then do not mark it as
13760  // redundant.
13761  //
13762  // Children nodes of base class diff nodes are never
13763  // redundant either, we want to see them all.
13766  && !is_child_node_of_base_diff(d))))
13767  {
13769  // As we said in preamble, as this node is marked as
13770  // being redundant, let's not visit its children.
13771  // This is not an optimization; it's needed for
13772  // correctness. In the case of a diff node involving
13773  // a class type that refers to himself, visiting the
13774  // children nodes might cause them to be wrongly
13775  // marked as redundant.
13778  skip_children_nodes_ = true;
13779  }
13780  }
13781  }
13782  else
13783  {
13784  // If the node is not to be reported, do not look at it children.
13786  skip_children_nodes_ = true;
13787  }
13788  }
13789 
13790  virtual void
13791  visit_begin(corpus_diff*)
13792  {
13793  }
13794 
13795  virtual void
13796  visit_end(diff* d)
13797  {
13798  if (skip_children_nodes_)
13799  // When visiting this node, we decided to skip its children
13800  // node. Now that we are done visiting the node, lets stop
13801  // avoiding the children nodes visiting for the other tree
13802  // nodes.
13803  {
13805  skip_children_nodes_ = false;
13806  }
13807  else
13808  {
13809  // Propagate the redundancy categorization of the children
13810  // nodes to this node. But if this node has local harmful
13811  // changes then it doesn't inherit redundancy from its
13812  // children nodes.
13813  if (!(d->get_category() & REDUNDANT_CATEGORY)
13814  && ((!d->has_local_changes_to_be_reported()
13815  || !is_harmful_category(d->get_local_category()))
13816  // By default, pointer, reference, array and qualified
13817  // types consider that a local changes to their
13818  // underlying type is always a local change for
13819  // themselves.
13820  //
13821  // This is as if those types don't have local changes
13822  // in the same sense as other types. So we always
13823  // propagate redundancy to them, regardless of if they
13824  // have local changes or not.
13825  //
13826  // We also propagate redundancy to typedef types if
13827  // these /only/ carry changes to their underlying
13828  // type.
13829  //
13830  // Note that changes to the underlying type of a
13831  // typedef is considered local of
13832  // LOCAL_TYPE_CHANGE_KIND kind. The other changes to the
13833  // typedef itself are considered local of
13834  // LOCAL_NON_TYPE_CHANGE_KIND kind.
13835  || is_pointer_diff(d)
13836  || is_array_diff(d)
13838  // A typedef with local non-type changes should not
13839  // see redundancy propagation from its underlying
13840  // type, otherwise, the non-type change might be
13841  // "suppressed" away.
13842  || (is_typedef_diff(d)
13843  && (!(d->has_local_changes()
13845  // A (member) variable with non-type local changes
13846  // should not see redundacy propagation from its type.
13847  // If redundant local-type changes are carried by its
13848  // type however, then that redundancy is propagated to
13849  // the variable. This is key to keep the redundancy
13850  // consistency in the system; otherwise, a type change
13851  // would be rightfully considered redundant at some
13852  // places but not at others.
13853  || (is_var_diff(d)
13854  && (!(d->has_local_changes()
13856  // A function parameter with non-type local changes
13857  // should not see redundancy propagation either. But
13858  // a function parameter with local type changes can
13859  // definitely be redundant.
13860  || (is_fn_parm_diff(d)
13861  && (!(d->has_local_changes()
13863  ))
13864  {
13865  bool has_non_redundant_child = false;
13866  bool has_non_empty_child = false;
13867  bool is_array_diff_node = is_array_diff(d);
13868  for (vector<diff*>::const_iterator i =
13869  d->children_nodes().begin();
13870  i != d->children_nodes().end();
13871  ++i)
13872  {
13873  if ((*i)->has_changes())
13874  {
13875  // If we are looking at a child node of an array,
13876  // do not take a subrange diff node change into
13877  // account when considering redundancy. In other
13878  // words, a subrange diff node that carries a
13879  // change should not be considered as a non-empty
13880  // child node. This is because we want to report
13881  // all subrange diff node changes and not consider
13882  // them as redundant.
13883  if (!is_array_diff_node || !is_subrange_diff(*i))
13884  has_non_empty_child = true;
13885  // Let's see if the current child node '*i' is
13886  // "non-redundant".
13887  //
13888  // A non-redundant node would be a node that
13889  // carries a change to be reported and has not
13890  // been marked as being redundant.
13891  if ((*i)->to_be_reported()
13892  && ((*i)->get_category() & REDUNDANT_CATEGORY) == 0)
13893  has_non_redundant_child = true;
13894  }
13895  if (has_non_redundant_child)
13896  break;
13897  }
13898 
13899  // A diff node for which at least a child node carries a
13900  // change, and for which all the children are redundant is
13901  // deemed redundant too, unless it has local changes.
13902  if (has_non_empty_child
13903  && !has_non_redundant_child)
13904  d->add_to_category(REDUNDANT_CATEGORY);
13905  }
13906  }
13907  }
13908 
13909  virtual void
13910  visit_end(corpus_diff*)
13911  {
13912  }
13913 
13914  virtual bool
13915  visit(diff*, bool)
13916  {return true;}
13917 
13918  virtual bool
13919  visit(corpus_diff*, bool)
13920  {
13921  return true;
13922  }
13923 };// end struct redundancy_marking_visitor
13924 
13925 /// A visitor of @ref diff nodes that clears the REDUNDANT_CATEGORY
13926 /// category out of the nodes.
13927 struct redundancy_clearing_visitor : public diff_node_visitor
13928 {
13929  bool
13930  visit(corpus_diff*, bool)
13931  {return true;}
13932 
13933  bool
13934  visit(diff* d, bool)
13935  {
13936  // clear the REDUNDANT_CATEGORY out of the current node.
13937  diff_category c = d->get_category();
13938  c &= ~REDUNDANT_CATEGORY;
13939  d->set_category(c);
13940  return true;
13941  }
13942 }; // end struct redundancy_clearing_visitor
13943 
13944 /// Walk a given @ref diff sub-tree to categorize each of the nodes
13945 /// with respect to the REDUNDANT_CATEGORY.
13946 ///
13947 /// @param diff_tree the @ref diff sub-tree to walk.
13948 void
13949 categorize_redundancy(diff* diff_tree)
13950 {
13951  if (diff_tree->context()->show_redundant_changes())
13952  return;
13953  redundancy_marking_visitor v;
13954  bool s = diff_tree->context()->visiting_a_node_twice_is_forbidden();
13955  diff_tree->context()->forbid_visiting_a_node_twice(false);
13956  diff_tree->traverse(v);
13957  diff_tree->context()->forbid_visiting_a_node_twice(s);
13958 }
13959 
13960 /// Walk a given @ref diff sub-tree to categorize each of the nodes
13961 /// with respect to the REDUNDANT_CATEGORY.
13962 ///
13963 /// @param diff_tree the @ref diff sub-tree to walk.
13964 void
13966 {categorize_redundancy(diff_tree.get());}
13967 
13968 /// Walk a given @ref corpus_diff tree to categorize each of the nodes
13969 /// with respect to the REDUNDANT_CATEGORY.
13970 ///
13971 /// @param diff_tree the @ref corpus_diff tree to walk.
13972 void
13974 {
13975  redundancy_marking_visitor v;
13976  diff_tree->context()->forget_visited_diffs();
13977  bool s = diff_tree->context()->visiting_a_node_twice_is_forbidden();
13978  diff_tree->context()->forbid_visiting_a_node_twice(false);
13979  diff_tree->traverse(v);
13980  diff_tree->context()->forbid_visiting_a_node_twice(s);
13981 }
13982 
13983 /// Walk a given @ref corpus_diff tree to categorize each of the nodes
13984 /// with respect to the REDUNDANT_CATEGORY.
13985 ///
13986 /// @param diff_tree the @ref corpus_diff tree to walk.
13987 void
13989 {categorize_redundancy(diff_tree.get());}
13990 
13991 // </redundancy_marking_visitor>
13992 
13993 /// Walk a given @ref diff sub-tree to clear the REDUNDANT_CATEGORY
13994 /// out of the category of the nodes.
13995 ///
13996 /// @param diff_tree the @ref diff sub-tree to walk.
13997 void
13999 {
14000  redundancy_clearing_visitor v;
14001  bool s = diff_tree->context()->visiting_a_node_twice_is_forbidden();
14002  diff_tree->context()->forbid_visiting_a_node_twice(false);
14003  diff_tree->traverse(v);
14004  diff_tree->context()->forbid_visiting_a_node_twice(s);
14005  diff_tree->context()->forget_visited_diffs();
14006 }
14007 
14008 /// Walk a given @ref diff sub-tree to clear the REDUNDANT_CATEGORY
14009 /// out of the category of the nodes.
14010 ///
14011 /// @param diff_tree the @ref diff sub-tree to walk.
14012 void
14014 {clear_redundancy_categorization(diff_tree.get());}
14015 
14016 /// Walk a given @ref corpus_diff tree to clear the REDUNDANT_CATEGORY
14017 /// out of the category of the nodes.
14018 ///
14019 /// @param diff_tree the @ref corpus_diff tree to walk.
14020 void
14022 {
14023  redundancy_clearing_visitor v;
14024  bool s = diff_tree->context()->visiting_a_node_twice_is_forbidden();
14025  diff_tree->context()->forbid_visiting_a_node_twice(false);
14026  diff_tree->traverse(v);
14027  diff_tree->context()->forbid_visiting_a_node_twice(s);
14028  diff_tree->context()->forget_visited_diffs();
14029 }
14030 
14031 /// Walk a given @ref corpus_diff tree to clear the REDUNDANT_CATEGORY
14032 /// out of the category of the nodes.
14033 ///
14034 /// @param diff_tree the @ref corpus_diff tree to walk.
14035 void
14037 {clear_redundancy_categorization(diff_tree.get());}
14038 
14039 /// Apply the @ref diff tree filters that have been associated with
14040 /// the context of the a given @ref diff, categorize the diff nodes
14041 /// subsequently. As a result, the nodes of the @p diff_tree tree are
14042 /// going to be properly filtered out at reporting time.
14043 ///
14044 /// @param diff_tree the @ref diff instance to consider.
14045 void
14047 {
14048  if (!diff_tree)
14049  return;
14050 
14051  diff_context_sptr ctxt = diff_tree->context();
14052  ABG_ASSERT(ctxt);
14053 
14054  if (!ctxt->perform_change_categorization())
14055  return;
14056 
14057  apply_suppressions(diff_tree);
14058  ctxt->maybe_apply_filters(diff_tree);
14059  categorize_redundancy(diff_tree);
14060 }
14061 
14062 /// Apply the @ref diff tree filters that have been associated with
14063 /// the context of the a given @ref corpus_diff, categorize the diff
14064 /// nodes subsequently. As a result, the nodes of the @p c tree are
14065 /// going to be properly filtered out at reporting time.
14066 ///
14067 /// @param c the @ref corpus_diff instance to consider.
14068 void
14070 {
14071  if (c)
14072  c->apply_filters_and_suppressions_before_reporting();
14073 }
14074 
14075 /// Test if a diff node represents the difference between a variadic
14076 /// parameter type and something else.
14077 ///
14078 /// @param d the diff node to consider.
14079 ///
14080 /// @return true iff @p d is a diff node that represents the
14081 /// difference between a variadic parameter type and something else.
14082 bool
14084 {
14085  if (!d)
14086  return false;
14087 
14088  type_base_sptr t = is_type(d->first_subject());
14089  if (t && t->get_environment().is_variadic_parameter_type(t))
14090  return true;
14091 
14092  t = is_type(d->second_subject());
14093  if (t && t->get_environment().is_variadic_parameter_type(t))
14094  return true;
14095 
14096  return false;
14097 }
14098 
14099 /// Test if a diff node represents the difference between a variadic
14100 /// parameter type and something else.
14101 ///
14102 /// @param d the diff node to consider.
14103 ///
14104 /// @return true iff @p d is a diff node that represents the
14105 /// difference between a variadic parameter type and something else.
14106 bool
14108 {return is_diff_of_variadic_parameter_type(d.get());}
14109 
14110 /// Test if a diff node represents the difference between a variadic
14111 /// parameter and something else.
14112 ///
14113 /// @param d the diff node to consider.
14114 ///
14115 /// @return true iff @p d is a diff node that represents the
14116 /// difference between a variadic parameter and something else.
14117 bool
14119 {
14120  fn_parm_diff* diff =
14121  dynamic_cast<fn_parm_diff*>(const_cast<abigail::comparison::diff*>(d));
14122  return (diff && is_diff_of_variadic_parameter_type(diff->type_diff()));
14123 }
14124 
14125 /// Test if a diff node represents the difference between a variadic
14126 /// parameter and something else.
14127 ///
14128 /// @param d the diff node to consider.
14129 ///
14130 /// @return true iff @p d is a diff node that represents the
14131 /// difference between a variadic parameter and something else.
14132 bool
14134 {return is_diff_of_variadic_parameter(d.get());}
14135 
14136 /// Test if a diff node represents a diff between two basic types.
14137 ///
14138 /// @param d the diff node to consider.
14139 ///
14140 /// @return true iff @p d is a diff between two basic types.
14141 const type_decl_diff*
14143 {return dynamic_cast<const type_decl_diff*>(d);}
14144 
14145 /// Test if a diff node represents a diff between two basic types, or
14146 /// between pointers, references or qualified type to basic types.
14147 ///
14148 /// @param diff the diff node to consider.
14149 ///
14150 /// @param allow_indirect_type if true, then this function looks into
14151 /// pointer, reference or qualified diff types to see if they "point
14152 /// to" basic types.
14153 ///
14154 /// @return true iff @p d is a diff between two basic types.
14155 const type_decl_diff*
14156 is_diff_of_basic_type(const diff* diff, bool allow_indirect_type)
14157 {
14158  if (allow_indirect_type)
14160  return is_diff_of_basic_type(diff);
14161 }
14162 
14163 /// If a diff node is about changes between two typedef types, get the
14164 /// diff node about changes between the underlying types.
14165 ///
14166 /// Note that this function walks the tree of underlying diff nodes
14167 /// returns the first diff node about types that are not typedefs.
14168 ///
14169 /// @param dif the dif node to consider.
14170 ///
14171 /// @return the underlying diff node of @p dif, or just return @p dif
14172 /// if it's not a typedef diff node.
14173 const diff*
14174 peel_typedef_diff(const diff* dif)
14175 {
14176  const typedef_diff *d = 0;
14177  while ((d = is_typedef_diff(dif)))
14178  dif = d->underlying_type_diff().get();
14179  return dif;
14180 }
14181 
14182 /// If a diff node is about changes between two pointer types, get the
14183 /// diff node about changes between the underlying (pointed-to) types.
14184 ///
14185 /// Note that this function walks the tree of underlying diff nodes
14186 /// returns the first diff node about types that are not pointers.
14187 ///
14188 /// @param dif the dif node to consider.
14189 ///
14190 /// @return the underlying diff node of @p dif, or just return @p dif
14191 /// if it's not a pointer diff node.
14192 const diff*
14193 peel_pointer_diff(const diff* dif)
14194 {
14195  const pointer_diff *d = 0;
14196  while ((d = is_pointer_diff(dif)))
14197  dif = d->underlying_type_diff().get();
14198  return dif;
14199 }
14200 
14201 /// If a diff node is about changes between two reference types, get
14202 /// the diff node about changes between the underlying (pointed-to)
14203 /// types.
14204 ///
14205 /// Note that this function walks the tree of underlying diff nodes
14206 /// returns the first diff node about types that are not references.
14207 ///
14208 /// @param dif the dif node to consider.
14209 ///
14210 /// @return the underlying diff node of @p dif, or just return @p dif
14211 /// if it's not a reference diff node.
14212 const diff*
14213 peel_reference_diff(const diff* dif)
14214 {
14215  const reference_diff *d = 0;
14216  while ((d = is_reference_diff(dif)))
14217  dif = d->underlying_type_diff().get();
14218  return dif;
14219 }
14220 
14221 /// If a diff node is about changes between two qualified types, get
14222 /// the diff node about changes between the underlying (non-qualified)
14223 /// types.
14224 ///
14225 /// Note that this function walks the tree of underlying diff nodes
14226 /// returns the first diff node about types that are not qualified.
14227 ///
14228 /// @param dif the dif node to consider.
14229 ///
14230 /// @return the underlying diff node of @p dif, or just return @p dif
14231 /// if it's not a qualified diff node.
14232 const diff*
14233 peel_qualified_diff(const diff* dif)
14234 {
14235  const qualified_type_diff *d = 0;
14236  while ((d = is_qualified_type_diff(dif)))
14237  dif = d->underlying_type_diff().get();
14238  return dif;
14239 }
14240 
14241 /// If a diff node is about changes between two function parameters
14242 /// get the diff node about changes between the types of the parameters.
14243 ///
14244 /// @param dif the dif node to consider.
14245 ///
14246 /// @return the diff of the types of the parameters.
14247 const diff*
14248 peel_fn_parm_diff(const diff* dif)
14249 {
14250  const fn_parm_diff *d = 0;
14251  while ((d = is_fn_parm_diff(dif)))
14252  dif = d->type_diff().get();
14253  return dif;
14254 }
14255 
14256 /// If a diff node is about changes between two pointer, reference or
14257 /// qualified types, get the diff node about changes between the
14258 /// underlying types.
14259 ///
14260 /// Note that this function walks the tree of underlying diff nodes
14261 /// returns the first diff node about types that are not pointer,
14262 /// reference or qualified.
14263 ///
14264 /// @param dif the dif node to consider.
14265 ///
14266 /// @return the underlying diff node of @p dif, or just return @p dif
14267 /// if it's not a pointer, reference or qualified diff node.
14268 const diff*
14270 {
14271  while (true)
14272  {
14273  if (const pointer_diff *d = is_pointer_diff(dif))
14274  dif = peel_pointer_diff(d);
14275  else if (const reference_diff *d = is_reference_diff(dif))
14276  dif = peel_reference_diff(d);
14277  else if (const qualified_type_diff *d = is_qualified_type_diff(dif))
14278  dif = peel_qualified_diff(d);
14279  else
14280  break;
14281  }
14282  return dif;
14283 }
14284 
14285 /// If a diff node is about changes between two typedefs or qualified
14286 /// types, get the diff node about changes between the underlying
14287 /// types.
14288 ///
14289 /// Note that this function walks the tree of underlying diff nodes
14290 /// returns the first diff node about types that are not typedef or
14291 /// qualified types.
14292 ///
14293 /// @param dif the dif node to consider.
14294 ///
14295 /// @return the underlying diff node of @p dif, or just return @p dif
14296 /// if it's not typedef or qualified diff node.
14297 const diff*
14299 {
14300  while (true)
14301  {
14302  if (const typedef_diff *d = is_typedef_diff(dif))
14303  dif = peel_typedef_diff(d);
14304  else if (const qualified_type_diff *d = is_qualified_type_diff(dif))
14305  dif = peel_qualified_diff(d);
14306  else
14307  break;
14308  }
14309  return dif;
14310 }
14311 
14312 /// If a diff node is about changes between two typedefs or qualified
14313 /// types, get the diff node about changes between the underlying
14314 /// types.
14315 ///
14316 /// Note that this function walks the tree of underlying diff nodes
14317 /// returns the first diff node about types that are neither typedef,
14318 /// qualified type nor parameters.
14319 ///
14320 /// @param dif the dif node to consider.
14321 ///
14322 /// @return the diff node about changes between the underlying types.
14323 const diff*
14325 {
14326  while (true)
14327  {
14328  if (const typedef_diff *d = is_typedef_diff(dif))
14329  dif = peel_typedef_diff(d);
14330  else if (const qualified_type_diff *d = is_qualified_type_diff(dif))
14331  dif = peel_qualified_diff(d);
14332  else if (const fn_parm_diff *d = is_fn_parm_diff(dif))
14333  dif = peel_fn_parm_diff(d);
14334  else
14335  break;
14336  }
14337  return dif;
14338 }
14339 
14340 /// Test if a diff node represents a diff between two class or union
14341 /// types.
14342 ///
14343 /// @param d the diff node to consider.
14344 ///
14345 /// @return iff @p is a diff between two class or union types then
14346 /// return the instance of @ref class_or_union_diff that @p derives
14347 /// from. Otherwise, return nil.
14348 const class_or_union_diff*
14350 {return dynamic_cast<const class_or_union_diff*>(d);}
14351 
14352 /// Test if a given diff node carries *only* a local type change.
14353 ///
14354 /// @param d the diff node to consider.
14355 ///
14356 /// @return true iff @p has a change and that change is a local type
14357 /// change.
14358 static bool
14359 has_local_type_change_only(const diff *d)
14360 {
14361  if (enum change_kind k = d->has_local_changes())
14362  if ((k & LOCAL_NON_TYPE_CHANGE_KIND) == 0
14363  && (k & LOCAL_TYPE_CHANGE_KIND) != 0)
14364  return true;
14365 
14366  return false;
14367 }
14368 
14369 /// Test if a diff node is a decl diff that only carries a basic type
14370 /// change on its type diff sub-node.
14371 ///
14372 ///Note that that pointers/references/qualified types diffs to basic
14373 /// type diffs are considered as having basic type change only.
14374 ///
14375 /// @param d the diff node to consider.
14376 ///
14377 /// @return true iff @p d is a decl diff that only carries a basic
14378 /// type change on its type diff sub-node.
14379 bool
14381 {
14383 
14384  if (is_diff_of_basic_type(d, true) && d->has_changes())
14385  return true;
14386  else if (const var_diff * v = dynamic_cast<const var_diff*>(d))
14387  return (has_local_type_change_only(v)
14388  && is_diff_of_basic_type(v->type_diff().get(), true));
14389  else if (const fn_parm_diff * p = dynamic_cast<const fn_parm_diff*>(d))
14390  return (has_local_type_change_only(p)
14391  && is_diff_of_basic_type(p->type_diff().get(), true));
14392  else if (const function_decl_diff* f =
14393  dynamic_cast<const function_decl_diff*>(d))
14394  return (has_local_type_change_only(f)
14395  && f->type_diff()
14396  && is_diff_of_basic_type(f->type_diff()->return_type_diff().get(),
14397  true));
14398  return false;
14399 }
14400 }// end namespace comparison
14401 } // end namespace abigail
Testing (anding) against this mask means that a given IR artifact has local differences, with respect to the other artifact it was compared against. A local change is a change that is carried by the artifact itself (or its type), rather than by one off its sub-types.
Definition: abg-ir.h:1376
qualified_type_diff(qualified_type_def_sptr first, qualified_type_def_sptr second, diff_sptr underling, diff_context_sptr ctxt=diff_context_sptr())
Constructor for qualified_type_diff.
void set_allowed_category(diff_category c)
Setter for the bitmap that represents the set of categories that the user wants to see reported...
bool is_filtered_out_without_looking_at_allowed_changes() const
Test if this diff tree node is to be filtered out for reporting purposes, but without considering the...
bool is_child_node_of_function_parm_diff(const diff *diff)
Test if a diff node is a child node of a function parameter diff node.
A type used to time various part of the libabigail system.
vector< diff * > diff_ptrs_type
Convenience typedef for a vector of diff*.
const string_diff_ptr_map & get_class_diff_map() const
Getter of the map that contains class type diffs.
std::pair< var_decl_sptr, var_decl_sptr > changed_var_sptr
Convenience typedef for a pair of var_decl_sptr representing a var_decl change. The first member of t...
bool has_harmless_enum_to_int_change(const diff *diff)
Test if a diff node carries a harmless change of an enum into an integer (or vice-versa).
const string_var_ptr_map & added_variables() const
Getter for the added variables of the diff.
void set_reporter(reporter_base_sptr &)
Setter of the reporter to be used in this context.
size_t net_num_added_unreachable_types() const
Getter of the number of added types that are unreachable from public interfaces and that are *NOT* fi...
A comparison function for instances of base_diff.
const diff * peel_typedef_qualified_type_or_parameter_diff(const diff *dif)
If a diff node is about changes between two typedefs or qualified types, get the diff node about chan...
const string_decl_base_sptr_map & inserted_data_members() const
Getter for the data members that got inserted.
bool is_type(const type_or_decl_base &tod)
Test whether a declaration is a type.
Definition: abg-ir.cc:10807
bool show_offsets_sizes_in_bits() const
Get the flag that indicates if diff reports using this context should show sizes and offsets in bits...
The abstraction of an array type.
Definition: abg-ir.h:2547
bool get_member_function_is_virtual(const function_decl &f)
Test if a given member function is virtual.
Definition: abg-ir.cc:6641
bool has_parent_allowed_by_specific_negated_suppression() const
Test if the current diff node has a parent node which is specifically allowed by a negated suppressio...
This means the diff node (or at least one of its descendant nodes) carries a change involving two com...
void sort_enumerators(const string_enumerator_map &enumerators_map, enum_type_decl::enumerators &sorted)
Sort a map of enumerators by their value.
shared_ptr< function_type_diff > function_type_diff_sptr
A convenience typedef for a shared pointer to function_type_type_diff.
size_t net_num_leaf_var_changes() const
Getter for the net number of leaf variable change diff nodes.
The base type of all declarations.
Definition: abg-ir.h:1584
size_t num_leaf_var_changes_filtered_out() const
Getter for the number of leaf variable changes diff nodes that have been filtered out...
A comparison functor for instances of diff.
virtual void report(ostream &, const string &indent="") const
Report the differences between the two enums.
type_suppression_sptr is_type_suppression(suppression_sptr suppr)
Test if an instance of suppression is an instance of type_suppression.
const string_diff_sptr_map & changed_unreachable_types() const
Getter for a map of changed types that are not reachable from global functions/variables.
const string_member_function_sptr_map & deleted_member_fns() const
ptr_to_mbr_type_sptr second_ptr_to_mbr_type() const
Getter of the second pointer-to-member subject of the current diff node.
virtual void chain_into_hierarchy()
Populate the vector of children node of the diff base type sub-object of this instance of subrange_di...
shared_ptr< decl_diff_base > decl_diff_base_sptr
Convenience typedef for a shared_ptr of decl_diff_base.
function_suppression_sptr is_function_suppression(const suppression_sptr suppr)
Test if an instance of suppression is an instance of function_suppression.
vector< function_decl_diff_sptr > function_decl_diff_sptrs_type
Convenience typedef for a vector of function_decl_diff_sptr.
The private data of the ptr_to_mbr_diff type.
size_t num_changed_unreachable_types_filtered_out() const
Getter of the number of changed types that are unreachable from public interfaces and that have been ...
distinct_diff(type_or_decl_base_sptr first, type_or_decl_base_sptr second, diff_context_sptr ctxt=diff_context_sptr())
Constructor for distinct_diff.
A "Less Than" functor to compare instance of function_decl_diff.
diff_category remove_from_category(diff_category c)
Remove the current diff tree node from an a existing sef of categories. The categories include those ...
void sort_string_member_function_sptr_map(const string_member_function_sptr_map &map, class_or_union::member_functions &sorted)
Sort a map that's an instance of string_member_function_sptr_map and fill a vector of member function...
size_t num_leaf_type_changes_filtered_out() const
Getter for the number of filtered out leaf type change diff nodes.
The abstraction of a change between two ABI artifacts, a.k.a an artifact change.
const pointer_diff * is_pointer_diff(const diff *diff)
Test if a diff node is about differences between two pointers.
diff_category has_fn_return_or_parm_harmful_change(const diff *d)
Test if a diff node is a function diff node that carries either a return or a parameter type change t...
virtual ~class_or_union_diff()
Destructor of class_or_union_diff.
virtual void chain_into_hierarchy()
Populate the vector of children node of the diff base type sub-object of this instance of class_or_un...
const edit_script & member_fn_tmpls_changes() const
const string_diff_ptr_map & get_function_decl_diff_map() const
Getter of the map that contains function decl diffs.
const edit_script & member_fns_changes() const
Abstraction of a diff between two qualified types.
virtual enum change_kind has_local_changes() const
size_t net_num_func_removed() const
Getter for the net number of function removed.
virtual enum change_kind has_local_changes() const
shared_ptr< class_diff > class_diff_sptr
Convenience typedef for a shared pointer on a class_diff type.
virtual void chain_into_hierarchy()
Populate the vector of children node of the diff base type sub-object of this instance of enum_diff...
const changed_var_sptrs_type & ordered_data_members_replaced_by_adms() const
Get an ordered vector of of data members that got replaced by anonymous data members.
size_t net_num_vars_changed() const
Getter for the number of variables that have a change in their sub-types, minus the number of these v...
vector< var_diff_sptr > var_diff_sptrs_type
Convenience typedef for a vector of var_diff_sptr.
const edit_script & base_changes() const
class_decl_sptr second_class_decl() const
Getter of the second class involved in the diff.
shared_ptr< typedef_diff > typedef_diff_sptr
Convenience typedef for a shared pointer on a typedef_diff type.
const string_parm_map & removed_parms() const
Getter for the map of parameters that got removed.
const function_decl_sptr first_function_decl() const
const string_diff_ptr_map & get_function_type_diff_map() const
Getter of the map that contains function type diffs.
const vector< diff * > & children_nodes() const
Getter for the children nodes of the current diff node.
const diff_sptrs_type & changed_decls() const
virtual void report(ostream &out, const string &indent="") const
Report the diff in a serialized form.
size_t net_num_changed_unreachable_types() const
Getter of the number of changed types that are unreachable from public interfaces and that have *NOT*...
The internal type for the impl idiom implementation of pointer_diff.
bool added_function_is_suppressed(const function_decl *fn) const
Test if the change reports for a give given added function has been deleted.
const function_decl_diff_sptrs_type & incompatible_changed_functions() const
Getter of the set of diff nodes representing incompatibly changed functions.
size_t num_func_with_incompatible_changes() const
Getter for the number of functions with incompatible changes.
const string_var_ptr_map & deleted_variables() const
Getter for the variables that got deleted from the first subject of the diff.
const string_fn_parm_diff_sptr_map & subtype_changed_parms() const
Getter for the map of function parameter changes of the current diff.
virtual bool has_changes() const
Return true iff the diff node has a change.
bool has_net_subtype_changes() const
Test if the current instance of corpus_diff carries subtype changes whose reports are not suppressed ...
diff_sptr underlying_type_diff() const
Getter for the diff between the underlying types of the two qualified types.
shared_ptr< pointer_diff > pointer_diff_sptr
Convenience typedef for a shared pointer on a pointer_diff type.
virtual void report(ostream &, const string &indent="") const
Produce a basic report about the changes between two class_decl.
virtual const string & get_pretty_representation() const
Build and return a textual representation of the current instance of fn_parm_diff.
var_decl_sptr first_var() const
Getter for the first var_decl of the diff.
shared_ptr< suppression_base > suppression_sptr
Convenience typedef for a shared pointer to a suppression.
Definition: abg-fwd.h:1681
const edit_script & data_members_changes() const
void finish_diff_type()
Finish building the current instance of corpus_diff.
size_t num_func_with_virtual_offset_changes() const
Getter for the number of functions that carry virtual member offset changes.
diff_category add_to_category(diff_category c)
Adds the current diff tree node to an additional set of categories. Note that the categories include ...
bool deleted_function_is_suppressed(const function_decl *fn) const
Test if the change reports for a given deleted function have been deleted.
An abstractions of the changes between two scopes.
diff_category get_local_category() const
Getter for the local category of the current diff tree node.
bool is_data_member(const var_decl &v)
Test if a var_decl is a data member.
Definition: abg-ir.cc:5613
An abstraction of a diff between entities that are of a different kind (disctinct).
diff_context_sptr get_context()
Getter of the context associated with this corpus.
bool is_class_type(const type_or_decl_base &t)
Test whether a type is a class.
Definition: abg-ir.cc:11165
virtual void chain_into_hierarchy()
Populate the vector of children node of the diff base type sub-object of this instance of pointer_dif...
virtual void chain_into_hierarchy()
Populate the vector of children node of the diff base type sub-object of this instance of qualified_t...
bool has_incompatible_changes() const
Test if the current instance of corpus_diff carries changes that we are sure are incompatible. By incompatible change we mean a change that "breaks" the ABI of the corpus we are looking at.
bool start()
Start the timer.
const qualified_type_diff * is_qualified_type_diff(const diff *diff)
Test if a diff node is about differences between two qualified types.
bool class_or_union_types_of_same_kind(const class_or_union *first, const class_or_union *second)
Test if two class or union types are of the same kind.
Definition: abg-ir.cc:11417
const corpus_diff * is_corpus_diff(const diff *diff)
Test if a diff node is a corpus_diff node.
virtual enum change_kind has_local_changes() const
const vector< subrange_diff_sptr > & subrange_diffs() const
Getter for the diffs between the array subranges.
virtual const string & get_pretty_representation() const
Getter the pretty representation of the subrange_diff diff node.
interned_string get_id() const
Return an ID that tries to uniquely identify the function inside a program or a library.
Definition: abg-ir.cc:23310
shared_ptr< function_type > function_type_sptr
Convenience typedef for a shared pointer on a function_type.
Definition: abg-fwd.h:208
bool show_impacted_interfaces() const
Getter of the flag that indicates if the leaf reporter should display a summary of the interfaces imp...
void sort_string_var_diff_sptr_map(const string_var_diff_sptr_map &map, var_diff_sptrs_type &sorted)
Sort of an instance of string_var_diff_sptr_map map.
virtual void visit_begin(diff *)
This is called by the traversing code on a diff node just before visiting it. That is...
void append_child_node(diff_sptr)
Add a new child node to the vector of children nodes for the current diff node.
vector< changed_var_sptr > changed_var_sptrs_type
Convenience typedef for a vector of .gg381.
bool is_member_function(const function_decl &f)
Test whether a function_decl is a member function.
Definition: abg-ir.cc:6368
scope_diff(scope_decl_sptr first_scope, scope_decl_sptr second_scope, diff_context_sptr ctxt=diff_context_sptr())
Constructor for scope_diff.
void mark_diff_as_visited(const diff *)
Mark a diff node as traversed by a traversing algorithm.
void sort_var_diffs(var_diff_sptrs_type &var_diffs)
Sort a vector of var_diff_sptr.
diff_sptr try_to_diff< class_decl >(const type_or_decl_base_sptr first, const type_or_decl_base_sptr second, diff_context_sptr ctxt)
This is a specialization of try_to_diff() template to diff instances of class_decl.
An abstraction helper for type declarations.
Definition: abg-ir.h:2002
A diff node in this category is a function (or function type) with at least one parameter added or re...
A functor to compare instances of elf_symbol base on their names.
This means the diff node (or at least one of its descendant nodes) carries a change that modifies the...
const qualified_type_def_sptr first_qualified_type() const
Getter for the first qualified type of the diff.
#define ABG_ASSERT_NOT_REACHED
A macro that expands to aborting the program when executed.
size_t num_leaf_changes_filtered_out() const
Getter of the number of leaf type change diff nodes that have been filtered out.
bool do_log() const
Test if logging was requested.
size_t count_filtered_subtype_changed_data_members(bool local_only=false) const
Count the number of /filtered/ data members with a sub-type change.
const function_type_sptr get_type() const
Return the type of the current instance of function_decl.
Definition: abg-ir.cc:22974
The base class of both types and declarations.
Definition: abg-ir.h:1405
bool insert_diff_node(const diff *d, const type_or_decl_base_sptr &impacted_iface)
Insert a new diff node into the current instance of diff_maps.
const string_var_diff_sptr_map & changed_variables()
Getter for the non-sorted map of variables which signature didn't change but which do have some indir...
A declaration that introduces a scope.
Definition: abg-ir.h:1852
virtual void chain_into_hierarchy()
This constructs the relation between this diff node and its detail diff nodes, in the generic view of...
bool is_negated_suppression(const suppression_base &s)
Test if a suppression specification is a negated suppression.
virtual bool has_changes() const
Return true iff the current diff node carries a change.
bool is_reference_or_ptr_diff_to_non_basic_nor_distinct_types(const diff *diff)
Test if a diff node is a reference or pointer diff node to a change that is neither basic type change...
var_decl_sptr find_data_member_from_anonymous_data_member(const var_decl_sptr &anon_dm, const string &name)
Find a data member inside an anonymous data member.
Definition: abg-ir.cc:10650
const function_decl::parameter_sptr second_parameter() const
Getter for the second subject of this diff node.
edit_script & function_changes() const
Abstracts a reference type.
Definition: abg-ir.h:2415
void sort_function_decl_diffs(function_decl_diff_sptrs_type &fn_diffs)
Sort a vector of function_decl_diff_sptr.
This type abstracts changes for a class_decl.
void clear_redundancy_categorization(diff *diff_tree)
Walk a given diff sub-tree to clear the REDUNDANT_CATEGORY out of the category of the nodes...
const array_type_def_sptr second_array() const
Getter for the second array of the diff.
size_t num_removed_var_syms_filtered_out() const
Getter for the number of removed variable symbols, not referenced by any debug info, that have been filtered out.
const function_type_diff * is_function_type_diff_with_local_changes(const diff *diff)
Test if a given diff node carries a function type change with local changes.
The abstraction of a qualified type.
Definition: abg-ir.h:2235
This means that a diff node was marked as suppressed by a user-provided suppression specification...
void sort_string_data_member_diff_sptr_map(const string_var_diff_sptr_map &map, var_diff_sptrs_type &sorted)
Sort the values of a string_var_diff_sptr_map and store the result in a vector of var_diff_sptr...
size_t count_filtered_changed_dm(bool local_only=false)
Get the number of data member changes carried by the current diff node that were filtered out...
const typedef_decl_sptr first_typedef_decl() const
Getter for the firt typedef_decl involved in the diff.
type_or_decl_base_sptr first_subject() const
Getter of the first subject of the diff.
This means the diff node does not carry any (meaningful) change, or that it carries changes that have...
bool show_added_symbols_unreferenced_by_debug_info() const
Getter for the flag that indicates if symbols not referenced by any debug info and that got added are...
const diff * parent_node() const
Getter for the parent node of the current diff node.
const base_diff * is_base_diff(const diff *diff)
Test if a diff node is about differences between two base class specifiers.
Abstraction of a base specifier in a class declaration.
Definition: abg-ir.h:4362
diff_sptr get_canonical_diff_for(const type_or_decl_base_sptr first, const type_or_decl_base_sptr second) const
Getter for the canonical diff node for the diff represented by their two subjects.
const diff_stats & apply_filters_and_suppressions_before_reporting()
Apply the different filters that are registered to be applied to the diff tree; that includes the cat...
size_t net_num_vars_added() const
Getter for the net number of added variables.
const suppr::suppressions_type & suppressions() const
Getter for the vector of suppressions that specify which diff node reports should be dropped on the f...
size_t num_removed_unreachable_types() const
Getter of the number of removed types that are unreachable from the public interface of the ABI corpu...
virtual const string & get_pretty_representation() const
Get the pretty representation of the current ptr_to_mbr_diff node.
bool is_filtered_out_wrt_non_inherited_categories() const
Test if this diff tree node is to be filtered out for reporting purposes, but by considering only the...
void forbid_visiting_a_node_twice_per_interface(bool)
This function sets a flag os that if forbid_visiting_a_node_twice() returns true, then each time the ...
unordered_map< string, class_decl::base_spec_sptr > string_base_sptr_map
Convenience typedef for a map of string and class_decl::basse_spec_sptr.
shared_ptr< diff_context > diff_context_sptr
Convenience typedef for a shared pointer of diff_context.
Definition: abg-fwd.h:67
const corpus_diff_sptr & get_corpus_diff() const
Get the corpus diff for the current context.
Abstraction of a diff between two typedef_decl.
const scope_decl_sptr first_scope() const
Getter for the first scope of the diff.
virtual enum change_kind has_local_changes() const
diff_node_visitor()
Default constructor of the diff_node_visitor type.
bool deleted_unrefed_fn_sym_is_suppressed(const elf_symbol *) const
Test if the change reports for a given deleted function symbol (that is not referenced by any debug i...
const var_diff * is_var_diff(const diff *diff)
Test if a diff node is about differences between variables.
virtual const string & get_pretty_representation() const
virtual void report(ostream &, const string &indent="") const
Report the changes carried by the current class_or_union_diff node in a textual format.
size_t net_num_leaf_func_non_incompatible_changes() const
Getter for the net number of leaf function diff nodes that carry changes that are NOT incompatible...
diff_category get_default_harmful_categories_bitmap()
Getter of a bitmap made of the set of change categories that are considered harmful.
size_t num_leaf_var_changes() const
Getter for the number of leaf variable change diff nodes.
A non-compatible name change between two types.
This means that a diff node in the sub-tree carries an addition of enumerator to an enum type...
bool is_mostly_distinct_diff(const diff *d)
Test if a diff node carries a distinct type change or a pointer/reference/typedef to distinct type ch...
virtual const string & get_pretty_representation() const
const diff * peel_typedef_diff(const diff *dif)
If a diff node is about changes between two typedef types, get the diff node about changes between th...
This means the diff node (or at least one of its descendant nodes) carries access related changes...
void sort_data_members(const string_decl_base_sptr_map &data_members, vector< decl_base_sptr > &sorted)
Sort a map of data members by the offset of their initial value.
shared_ptr< reference_diff > reference_diff_sptr
Convenience typedef for a shared pointer on a reference_diff type.
bool is_user_defined_type(const type_base *t)
Test if a type is user-defined.
Definition: abg-ir.cc:5479
The variable was deleted from the second subject of the diff.
const type_decl_sptr first_type_decl() const
Getter for the first subject of the type_decl_diff.
diff * diff_has_been_visited(const diff *) const
Test if a diff node has been traversed.
virtual void report(ostream &, const string &indent="") const
Generates a report for the current instance of base_diff.
const var_diff_sptrs_type & incompatible_changed_variables() const
Getter of the set of diff nodes representing incompatibly changed global variables.
class_decl::base_spec_sptr second_base() const
Getter for the second base spec of the diff object.
A diff node in this category carries a change from void pointer to non-void pointer.
diff * get_current_topmost_iface_diff() const
Getter of the diff current topmost interface which is impacted by the current diff node being visited...
virtual enum change_kind has_local_changes() const
Test whether the current diff node carries any local change.
virtual enum change_kind has_local_changes() const
void print_category(diff_category c)
Print a given category out to stdout for debuging purposes.
shared_ptr< var_decl > var_decl_sptr
Convenience typedef for a shared pointer on a var_decl.
Definition: abg-fwd.h:253
class_or_union_sptr first_class_or_union() const
A diff node in this category has a parent node that is in the HAS_ALLOWED_CHANGE_CATEGORY category...
bool is_member_decl(const decl_base_sptr d)
Tests if a declaration is a class member.
Definition: abg-ir.cc:5417
void maybe_apply_filters(diff_sptr diff)
Apply the diff filters to a given diff sub-tree.
const global_scope * get_global_scope(const decl_base &decl)
return the global scope as seen by a given declaration.
Definition: abg-ir.cc:8543
void sort_string_var_ptr_map(const string_var_ptr_map &map, vector< var_decl_sptr > &sorted)
Sort a map of string -> pointer to var_decl.
The abstraction of a diff between two arrays.
const string_enumerator_map & deleted_enumerators() const
diff_maps()
Default constructor of the diff_maps type.
size_t num_removed_vars_filtered_out() const
Getter for the number removed variables that have been filtered out.
const string_diff_ptr_map & get_distinct_diff_map() const
Getter of the map that contains distinct diffs.
uint64_t get_absolute_data_member_offset(const var_decl &m)
Get the absolute offset of a data member.
Definition: abg-ir.cc:6273
size_t num_added_var_syms_filtered_out() const
Getter for the number of added variable symbols, not referenced by any debug info, that have been filtered out.
Abstraction of the declaration of a method.
Definition: abg-ir.h:3886
bool has_decl_only_def_change(const decl_base_sptr &first, const decl_base_sptr &second)
Test if two decl_base_sptr are different just by the fact that one is decl-only and the other one is ...
size_t net_num_added_func_syms() const
Getter of the net number of added function symbols that are not referenced by any debug info...
This says that the traversing code should not mark visited nodes as having been traversed. This is useful, for instance, for visitors which have debugging purposes.
void categorize_redundant_changed_sub_nodes()
Walk the changed functions and variables diff nodes to categorize redundant nodes.
size_t net_num_func_added() const
Getter for the net number of added functions.
shared_ptr< distinct_diff > distinct_diff_sptr
Convenience typedef for a shared pointer to distinct_types_diff.
ostream & operator<<(ostream &o, diff_category c)
Serialize an instance of diff_category to an output stream.
const fn_parm_diff * is_fn_parm_diff(const diff *diff)
Test if a diff node is about differences between two function parameters.
class_decl::base_spec_sptr first_base() const
Getter for the first base spec of the diff object.
virtual bool traverse(diff_node_visitor &v)
Traverse the diff sub-tree under the current instance corpus_diff.
class_or_union * is_class_or_union_type(const type_or_decl_base *t)
Test if a type is a class_or_union.
Definition: abg-ir.cc:11396
bool added_unreachable_type_is_suppressed(const type_base *t) const
Test if an added type that is unreachable from public interface has been suppressed by a suppression ...
const declarations & get_member_decls() const
Getter for the member declarations carried by the current scope_decl.
Definition: abg-ir.cc:7881
const type_decl_diff * is_diff_of_basic_type(const diff *d)
Test if a diff node represents a diff between two basic types.
virtual enum change_kind has_local_changes() const
Check if the current diff node carries a local change.
shared_ptr< translation_unit > translation_unit_sptr
Convenience typedef for a shared pointer on a translation_unit type.
Definition: abg-fwd.h:133
Abstracts a class declaration.
Definition: abg-ir.h:4173
Abstraction of a diff between two function_decl.
A diff node in this category is a function parameter type which top cv-qualifiers change...
shared_ptr< typedef_decl > typedef_decl_sptr
Convenience typedef for a shared pointer on a typedef_decl.
Definition: abg-fwd.h:164
virtual void report(ostream &out, const string &indent="") const
Report the diff in a serialized form.
void sort_string_diff_sptr_map(const string_diff_sptr_map &map, diff_sptrs_type &sorted)
Sort a map ofg string -> diff_sptr into a vector of diff_sptr. The diff_sptr are sorted lexicographic...
change_kind
A bitfield that gives callers of abigail::ir::equals() some insight about how different two internal ...
Definition: abg-ir.h:1360
bool is_at_global_scope(const decl_base &decl)
Tests whether a given declaration is at global scope.
Definition: abg-ir.cc:10580
void propagate_categories(diff *diff_tree)
Visit all the nodes of a given sub-tree. For each node that has a particular category set...
This means that a diff node in the sub-tree carries an incompatible change to a vtable.
unordered_map< string, diff * > string_diff_ptr_map
Convenience typedef for a map which value is a diff*. The key of the map is the qualified name of the...
function_type_diff(const function_type_sptr first, const function_type_sptr second, diff_context_sptr ctxt)
Consutrctor of the function_type type.
bool currently_reporting() const
Tests if we are currently in the middle of emitting a report for this diff.
corpus_diff(corpus_sptr first, corpus_sptr second, diff_context_sptr ctxt=diff_context_sptr())
Constructor for corpus_diff.
size_t count_filtered_subtype_changed_dm(bool local_only=false)
Get the number of data member sub-type changes carried by the current diff node that were filtered ou...
const string_diff_ptr_map & get_enum_diff_map() const
Getter of the map that contains enum type diffs.
void switch_categories_on(diff_category c)
Setter for the bitmap that represents the set of categories that the user wants to see reported...
diff_category get_allowed_category() const
Getter for the bitmap that represents the set of categories that the user wants to see reported...
void apply_suppressions(diff *diff_tree)
Walk a given diff-sub tree and appply the suppressions carried by the context. If the suppression app...
size_t count_filtered_changed_mem_fns(const diff_context_sptr &)
Get the number of member functions changes carried by the current diff node that were filtered out...
const enum_type_decl_sptr first_enum() const
const string_diff_ptr_map & get_reference_diff_map() const
Getter of the map that contains reference type diffs.
virtual void report(ostream &, const string &indent="") const
Report the diff in a serialized form.
shared_ptr< subrange_diff > subrange_diff_sptr
A convenience typedef for a shared pointer to subrange_diff type.
const class_diff * is_class_diff(const diff *diff)
Test if a diff node is a class_diff node.
bool has_void_ptr_to_ptr_change(const diff *dif)
Test if a diff node carries a void* to pointer type change.
class_or_union * anonymous_data_member_to_class_or_union(const var_decl *d)
Get the class_or_union type of a given anonymous data member.
Definition: abg-ir.cc:6030
const edit_script & member_types_changes() const
shared_ptr< type_suppression > type_suppression_sptr
Convenience typedef for a shared pointer to type_suppression.
shared_ptr< scope_diff > scope_diff_sptr
Convenience typedef for a shared pointer on a scope_diff.
base_diff(class_decl::base_spec_sptr first, class_decl::base_spec_sptr second, class_diff_sptr underlying, diff_context_sptr ctxt=diff_context_sptr())
bool show_unreachable_types()
Getter for the flag that indicates if changes on types unreachable from global functions and variable...
Abstraction of a diff between two enums.
virtual void report(ostream &out, const string &indent="") const
Ouputs a report of the differences between of the two type_decl involved in the type_decl_diff.
The default, initial, reporter of the libabigail comparison engine.
Definition: abg-reporter.h:158
unordered_map< string, decl_base_sptr > string_decl_base_sptr_map
Convenience typedef for a map which key is a string and which value is a decl_base_sptr.
Definition: abg-fwd.h:157
virtual enum change_kind has_local_changes() const
Abstracts a variable declaration.
Definition: abg-ir.h:3067
void sort_string_elf_symbol_map(const string_elf_symbol_map &map, vector< elf_symbol_sptr > &sorted)
Sort a map of string -> pointer to elf_symbol.
The private data structure for distinct_diff.
void set_category(diff_category c)
Set the category of the current diff node. This category includes the categories inherited from the c...
virtual void report(ostream &, const string &indent="") const
Serialize a report of the changes encapsulated in the current instance of function_decl_diff over to ...
void sort_string_parm_map(const string_parm_map &map, vector< function_decl::parameter_sptr > &sorted)
Sort a map of string -> function parameters.
edit_script & variable_changes() const
diff_category has_var_harmful_local_change(const diff *d)
Test if a diff node carries a harmful local change to a variable.
A functor to compare instances of var_decl base on their qualified names.
void switch_categories_off(diff_category c)
Setter for the bitmap that represents the set of categories that the user wants to see reported...
bool is_diff_of_global_decls(const diff *)
Tests if a given diff node is to represent the changes between two gobal decls.
bool get_member_function_is_dtor(const function_decl &f)
Test whether a member function is a destructor.
Definition: abg-ir.cc:6454
Abstraction of a function parameter.
Definition: abg-ir.h:3334
bool is_categorized_as_suppressed() const
Test if the current diff node has been suppressed by a suppression specification or it has been categ...
The base class of diff between decls.
The base class of diff between types.
A reporter that only reports leaf changes.
Definition: abg-reporter.h:280
Abstraction of a diff between two basic type declarations.
const function_decl_sptr second_function_decl() const
unordered_map< string, var_diff_sptr > string_var_diff_sptr_map
Convenience typedef for a map whose key is a string and whose value is a changed variable of type var...
unordered_map< string, base_diff_sptr > string_base_diff_sptr_map
Convenience typedef for a map of string and base_diff_sptr.
void initialize_canonical_diff(const diff_sptr diff)
Set the canonical diff node property of a given diff node appropriately.
void allocate_priv_data()
Allocate the memory for the priv_ pimpl data member of the class_or_union_diff class.
virtual bool has_changes() const
Return true iff the current diff node carries a change.
bool soname_changed() const
Test if the soname of the underlying corpus has changed.
size_t net_num_removed_func_syms() const
Getter of the net number of removed function symbols that are not referenced by any debug info...
diff_sptr try_to_diff(const type_or_decl_base_sptr first, const type_or_decl_base_sptr second, diff_context_sptr ctxt)
bool is_suppressed() const
Test if the current diff node has been suppressed by a user-provided suppression specification.
decl_base_sptr subtype_changed_dm(decl_base_sptr) const
Test if the current diff node carries a data member change for a data member which name is the same a...
var_decl * is_var_decl(const type_or_decl_base *tod)
Tests if a declaration is a variable declaration.
Definition: abg-ir.cc:12059
bool has_net_changes() const
Test if the current instance of corpus_diff carries changes whose reports are not suppressed by any s...
const type_or_decl_base_sptr first() const
Getter for the first subject of the diff.
visiting_kind get_visiting_kind() const
Getter for the visiting policy of the traversing code while invoking this visitor.
unordered_map< string, elf_symbol_sptr > string_elf_symbol_map
Convenience typedef for a map whose key is a string and whose value is an elf_symbol_sptr.
This is the base class of class_diff and union_diff.
const string_decl_base_sptr_map & deleted_data_members() const
Getter for the data members that got deleted.
The internal type for the impl idiom implementation of subrange_diff.
bool has_changes() const
Return true iff the current corpus_diff node carries a change.
std::vector< enumerator > enumerators
Convenience typedef for a list of enumerator.
Definition: abg-ir.h:2798
size_t num_var_syms_removed() const
Getter for the number of variable symbols (not referenced by any debug info) that got removed...
The abstraction of the diff between two subrange types.
const string_diff_ptr_map & get_type_decl_diff_map() const
Getter of the map that contains basic type diffs.
unordered_map< unsigned, fn_parm_diff_sptr > unsigned_fn_parm_diff_sptr_map
Convenience typedef for a map which key is an integer and which value is a changed parameter...
A functor to compare instances of class_decl::base_spec.
void sort_string_base_diff_sptr_map(const string_base_diff_sptr_map &map, base_diff_sptrs_type &sorted)
Sort a map of string -> base_diff_sptr into a sorted vector of base_diff_sptr. The base_diff_sptr are...
An abstraction of a diff between between two abi corpus.
A functor to compare two instances of diff_sptr.
void sort_unsigned_data_member_diff_sptr_map(const unsigned_var_diff_sptr_map map, var_diff_sptrs_type &sorted)
Sort the values of a unsigned_var_diff_sptr_map map and store the result into a vector of var_diff_sp...
virtual bool traverse(diff_node_visitor &v)
The default traverse function.
virtual void chain_into_hierarchy()
Populate the vector of children node of the diff base type sub-object of this instance of base_diff...
virtual void chain_into_hierarchy()
Populate the vector of children node of the diff base type sub-object of this instance of reference_d...
function_decl_diff(const function_decl_sptr first, const function_decl_sptr second, diff_context_sptr ctxt)
Constructor for function_decl_diff.
const var_decl_sptr get_next_data_member(const class_or_union *klass, const var_decl_sptr &data_member)
In the context of a given class or union, this function returns the data member that is located after...
Definition: abg-ir.cc:5742
void set_canonical_diff(diff *)
Setter for the canonical diff of the current instance of diff.
size_t net_num_leaf_var_non_incompatible_changes() const
Getter for the net number of leaf variable diff nodes that carry changes that are NOT incompatible...
bool is_unique_type(const type_base_sptr &t)
Test if a type is unique in the entire environment.
Definition: abg-ir.cc:28670
vector< changed_enumerator > changed_enumerators_type
Convenience typedef for a vector of changed enumerators.
void ensure_lookup_tables_populated()
If the lookup tables are not yet built, walk the differences and fill the lookup tables.
Abstracts a declaration for an enum type.
Definition: abg-ir.h:2784
class_or_union_sptr second_class_or_union() const
bool is_traversing() const
Tell if a given node is being traversed or not.
size_t num_added_unreachable_types_filtered_out() const
Getter of the number of added types that are unreachable from public interfaces and that are filtered...
uint64_t get_data_member_offset(const var_decl &m)
Get the offset of a data member.
Definition: abg-ir.cc:6184
translation_unit_diff(translation_unit_sptr first, translation_unit_sptr second, diff_context_sptr ctxt=diff_context_sptr())
Constructor for translation_unit_diff.
const type_or_decl_base_sptr second() const
Getter for the second subject of the diff.
bool show_stats_only() const
Test if the comparison module should only show the diff stats.
diff_category
An enum for the different categories that a diff tree node falls into, regarding the kind of changes ...
ostream * default_output_stream()
Getter for the default output stream used by code of the comparison engine. By default the default ou...
Toplevel namespace for libabigail.
The variable was added to the second second subject of the diff.
bool do_log() const
Test if logging was requested.
shared_ptr< ptr_to_mbr_type > ptr_to_mbr_type_sptr
Convenience typedef for a shared pointer to a ptr_to_mbr_type.
Definition: abg-fwd.h:237
virtual bool has_changes() const
Test if the current diff node carries a change.
bool show_leaf_changes_only() const
Get the flag that indicates if the diff using this context should show only leaf changes or not...
size_t num_changed_vars_filtered_out() const
Getter for the number of variables that have a change in one of their sub-types, and that have been f...
unordered_set< type_or_decl_base_sptr, type_or_decl_hash, type_or_decl_equal > artifact_sptr_set_type
A convenience typedef for a hash set of type_or_decl_base_sptr.
Definition: abg-ir.h:559
shared_ptr< scope_decl > scope_decl_sptr
Convenience typedef for a shared pointer on a scope_decl.
Definition: abg-fwd.h:261
virtual void visit_end(corpus_diff *)
This is called by the traversing code on a corpus_diff node just after visiting it. That is after visiting it and its children nodes.
bool added_unrefed_var_sym_is_suppressed(const elf_symbol *) const
Test if the change reports for a given added variable symbol (that is not referenced by any debug inf...
const diff * peel_typedef_or_qualified_type_diff(const diff *dif)
If a diff node is about changes between two typedefs or qualified types, get the diff node about chan...
bool has_benign_array_of_unknown_size_change(const diff *dif)
Test if a diff node carries a benign change to the size of a variable of type array.
unordered_map< string, changed_enumerator > string_changed_enumerator_map
Convenience typedef for a map which value is a changed enumerator. The key is the name of the changed...
An abstraction of a diff between two instances of class_decl::base_spec.
#define SKIP_MEM_FN_IF_VIRTUALITY_DISALLOWED
Skip the processing of the current member function if its virtual-ness is disallowed by the user...
visiting_kind operator&(visiting_kind l, visiting_kind r)
The overloaded and operator for visiting_kind.
const string_base_sptr_map & inserted_bases() const
Getter for the inserted base classes of the diff.
size_t count_filtered_deleted_mem_fns(const diff_context_sptr &)
Get the number of member functions deletions carried by the current diff node that were filtered out...
virtual const string & get_pretty_representation() const
shared_ptr< function_decl > function_decl_sptr
Convenience typedef for a shared pointer on a function_decl.
Definition: abg-fwd.h:266
decl_base * is_decl(const type_or_decl_base *d)
Test if an ABI artifact is a declaration.
Definition: abg-ir.cc:10747
virtual const string & get_pretty_representation() const
virtual const string & get_pretty_representation() const
const string_diff_ptr_map & get_typedef_diff_map() const
Getter of the map that contains typedef type diffs.
bool reported_once() const
Tests if a report has already been emitted for the current diff.
virtual bool has_changes() const
Test if the current subrange_diff node carries any change.
void set_current_topmost_iface_diff(diff *)
Setter of the diff current topmost interface which is impacted by the current diff node being visited...
const diff * peel_pointer_or_qualified_type_diff(const diff *dif)
If a diff node is about changes between two pointer, reference or qualified types, get the diff node about changes between the underlying types.
bool is_enumerator_present_in_enum(const enum_type_decl::enumerator &enr, const enum_type_decl &enom)
Test if a given enumerator is found present in an enum.
Definition: abg-ir.cc:20556
const string_function_ptr_map & added_functions()
Getter for the added functions of the diff.
type_base_sptr get_leaf_type(qualified_type_def_sptr t)
Return the first underlying type that is not a qualified type.
decl_diff_base(decl_base_sptr first_subject, decl_base_sptr second_subject, diff_context_sptr ctxt)
Constructor of decl_diff_base.
const enum_type_decl * is_enum_type(const type_or_decl_base *d)
Test if a decl is an enum_type_decl.
Definition: abg-ir.cc:11100
const string_function_ptr_map & deleted_functions() const
Getter for the deleted functions of the diff.
friend corpus_diff_sptr compute_diff(const corpus_sptr f, const corpus_sptr s, diff_context_sptr ctxt)
Compute the diff between two instances of corpus.
void sort_string_base_sptr_map(const string_base_sptr_map &m, class_decl::base_specs &sorted)
Lexicographically sort base specifications found in instances of string_base_sptr_map.
virtual bool has_changes() const
Test if the current diff node carries changes.
virtual bool has_changes() const
Return true iff the current diff node carries a change.
void set_corpus_diff(const corpus_diff_sptr &)
Set the corpus diff relevant to this context.
bool show_redundant_changes() const
A getter for the flag that says if we should report about functions or variables diff nodes that have...
const string_enumerator_map & inserted_enumerators() const
virtual void report(ostream &out, const string &indent="") const
Emit a report about the current diff instance.
shared_ptr< ptr_to_mbr_diff > ptr_to_mbr_diff_sptr
Typedef of a shared_ptr to ptr_to_mbr_diff.
bool perform_change_categorization() const
Test if it's requested to perform diff node categorization.
shared_ptr< parameter > parameter_sptr
Convenience typedef for a shared pointer on a function_decl::parameter.
Definition: abg-ir.h:3183
The abstraction of a pointer-to-member type.
Definition: abg-ir.h:2483
const diff_sptrs_type & changed_types() const
size_t num_leaf_changes() const
Getter of the number of leaf type change diff nodes.
The type of the private data of corpus_diff::diff_stats.
size_t net_num_vars_removed() const
Getter for the net number of removed variables.
size_t num_leaf_type_changes() const
Getter for the number of leaf type change diff nodes.
const edit_script & member_changes() const
Accessor of the edit script of the members of a scope.
virtual bool has_changes() const
Return true iff the current diff node carries a change.
shared_ptr< base_spec > base_spec_sptr
Convenience typedef.
Definition: abg-ir.h:4188
diff_category remove_from_local_category(diff_category c)
Remove the current diff tree node from the categories resulting from the local changes.
const string_elf_symbol_map & added_unrefed_function_symbols() const
Getter for function symbols not referenced by any debug info and that got added.
unordered_map< string, type_base_sptr > string_type_base_sptr_map
Convenience typedef for a map which key is a string and which value is a type_base_sptr.
var_decl_sptr second_var() const
Getter for the second var_decl of the diff.
This means that a diff node was warked as being for a private type. That is, the diff node is meant t...
Abstraction of a diff between two function parameters.
virtual enum change_kind has_local_changes() const
const function_decl::parameter_sptr first_parameter() const
Getter for the first subject of this diff node.
size_t num_added_unreachable_types() const
Getter of the number of added types that are unreachable from the public interface of the ABI corpus...
Abstraction for a function declaration.
Definition: abg-ir.h:3164
virtual const string & get_pretty_representation() const
virtual void chain_into_hierarchy()
Populate the vector of children node of the diff base type sub-object of this instance of class_diff...
size_t num_var_with_incompatible_changes() const
Getter for the number of variables with incompatible changes.
size_t num_added_func_filtered_out() const
Getter for the number of added function that have been filtered out.
void forget_visited_diffs()
Unmark all the diff nodes that were marked as being traversed.
const string_type_base_sptr_map & added_unreachable_types() const
Getter for a map of added types that are not reachable from global functions/variables.
virtual enum change_kind has_local_changes() const
size_t num_removed_func_syms_filtered_out() const
Getter for the number of removed function symbols, not referenced by debug info, that have been filte...
virtual const string & get_pretty_representation() const
Get a pretty representation of the current diff node.
This means that a diff node in the sub-tree carries a harmless declaration name change. This is set only for name changes for data members and typedefs.
virtual void chain_into_hierarchy()
Populate the vector of children node of the diff base type sub-object of this instance of function_ty...
bool added_variable_is_suppressed(const var_decl_sptr &var) const
Test if the change reports for a given added variable have been suppressed.
unordered_map< string, diff_sptr > string_diff_sptr_map
Convenience typedef for a map which value is a diff_sptr. The key of the map is the qualified name of...
const array_type_def::subrange_sptr first_subrange() const
Getter of the first subrange of the current instance subrange_diff.
This means that a diff node in the sub-tree carries a harmless data member change. An example of harmless data member change is an anonymous data member that replaces a given data member without locally changing the layout.
unordered_map< string, function_decl_diff_sptr > string_function_decl_diff_sptr_map
Convenience typedef for a map which key is a string and which value is a function_decl_diff_sptr.
void apply_supprs_to_added_removed_fns_vars_unreachable_types()
Apply suppression specifications for this corpus diff to the set of added/removed functions/variables...
diff_sptr leaf_underlying_type_diff() const
Getter for the diff between the most underlying non-qualified types of two qualified types...
diff_sptr compute_diff(const decl_base_sptr first, const decl_base_sptr second, diff_context_sptr ctxt)
Compute the difference between two decls. The decls can represent either type declarations, or non-type declaration.
virtual enum change_kind has_local_changes() const
size_t num_func_removed() const
Getter for the number of functions removed.
diff_category get_category() const
Getter for the category of the current diff tree node.
void clear_redundancy_categorization()
Walk the changed functions and variables diff nodes and clear the redundancy categorization they migh...
void end_traversing()
Flag a given diff node as not being traversed anymore.
class_decl_sptr first_class_decl() const
The context of the diff. This type holds various bits of information that is going to be used through...
size_t net_num_removed_var_syms() const
Getter of the net number of removed variable symbols that are not referenced by any debug info...
unordered_map< string, var_decl_sptr > string_var_ptr_map
Convenience typedef for a map which key is a string and which value is a point to var_decl...
const diff_sptr underlying_type_diff() const
Getter of the diff node of the underlying types of the current subrange_diff diff node...
The abstraction of a diff between two ptr_to_mbr_type.
A diff node in this category is redundant. That means it's present as a child of a other nodes in the...
The abstraction of a diff between two references.
const decl_base * get_type_declaration(const type_base *t)
Get the declaration for a given type.
Definition: abg-ir.cc:10229
shared_ptr< function_decl_diff > function_decl_diff_sptr
Convenience typedef for a shared pointer to a function_decl type.
This means that a diff node in the sub-tree carries a type that was declaration-only and that is now ...
Functor to sort instances of var_diff_sptr.
size_t num_vars_changed() const
Getter for the number of variables that have a change in one of their sub-types.
virtual ~union_diff()
Destructor of the union_diff node.
void emit_diff_stats(const diff_stats &stats, ostream &out, const string &indent)
Emit the summary of the functions & variables that got removed/changed/added.
diff * get_canonical_diff() const
Getter for the canonical diff of the current instance of diff.
bool has_descendant_allowed_by_specific_negated_suppression() const
Test if the current diff node has a descendant node which is specifically allowed by a negated suppre...
unordered_map< const diff *, artifact_sptr_set_type, diff_hash, diff_equal > diff_artifact_set_map_type
A convenience typedef for an unordered_map which key is a diff* and which value is a artifact_sptr_se...
friend var_diff_sptr compute_diff(const var_decl_sptr first, const var_decl_sptr second, diff_context_sptr ctxt)
Compute the diff between two instances of var_decl.
shared_ptr< type_or_decl_base > type_or_decl_base_sptr
A convenience typedef for a shared_ptr to type_or_decl_base.
Definition: abg-fwd.h:118
virtual const string & get_pretty_representation() const
Build and return a copy of a pretty representation of the current instance of function_type_diff.
size_t net_num_leaf_changes() const
Getter of the net number of leaf change diff nodes.
const string_diff_ptr_map & get_var_decl_diff_map() const
Getter of the map that contains var decl diffs.
virtual bool has_changes() const
Return true iff the current diff node carries a change.
shared_ptr< type_decl > type_decl_sptr
Convenience typedef for a shared pointer on a type_decl.
Definition: abg-fwd.h:159
shared_ptr< type_decl_diff > type_decl_diff_sptr
Convenience typedef for a shared pointer on a type_decl_diff type.
void keep_diff_alive(diff_sptr &)
Add a diff node to the set of diff nodes that are kept alive for the life time of the current instanc...
bool is_filtered_out() const
Test if this diff tree node is to be filtered out for reporting purposes.
void add_suppressions(const suppr::suppressions_type &supprs)
Add new suppression specifications that specify which diff node reports should be dropped on the floo...
virtual enum change_kind has_local_changes() const =0
Pure interface to know if the current instance of carries a local change. A local change is a change...
virtual bool has_changes() const
Return true iff the current diff node carries a change.
virtual void chain_into_hierarchy()
Populate the vector of children node of the corpus_diff type.
const vector< function_decl::parameter_sptr > & sorted_added_parms() const
Getter for the sorted vector of added parameters .
void apply_filters_and_categorize_diff_node_tree(diff_sptr &diff_tree)
Apply the diff tree filters that have been associated with the context of the a given diff...
ptr_to_mbr_type_sptr first_ptr_to_mbr_type() const
Getter of the first pointer-to-member subject of the current diff node.
The abstraction of a diff between two pointers.
Abstraction of an elf symbol.
Definition: abg-ir.h:960
virtual void report(ostream &, const string &indent="") const
Report the changes carried by the current union_diff node in a textual format.
const string_elf_symbol_map & deleted_unrefed_function_symbols() const
Getter for function symbols not referenced by any debug info and that got deleted.
virtual void report(ostream &out, const string &indent="") const
Report the changes of one scope against another.
const var_diff_sptrs_type & changed_variables_sorted()
Getter for the sorted vector of variables which signature didn't change but which do have some indire...
unordered_map< string, const function_decl * > string_function_ptr_map
Convenience typedef for a map which key is a string and which value is a pointer to decl_base...
virtual bool has_changes() const
Return true iff the current diff node carries a change.
size_t count_filtered_inserted_mem_fns(const diff_context_sptr &)
Get the number of member functions insertions carried by the current diff node that were filtered out...
size_t count_filtered_bases()
Count the number of bases classes whose changes got filtered out.
virtual const string & get_pretty_representation() const
The function was deleted from the second subject of the diff.
void forbid_visiting_a_node_twice(bool f)
This sets a flag that, if it's true, then during the traversing of a diff nodes tree each node is vis...
void apply_filter(filter_base &filter, corpus_diff_sptr d)
Walk the diff sub-trees of a a corpus_diff and apply a filter to the nodes visted. The filter categorizes each node, assigning it into one or several categories.
vector< method_decl_sptr > member_functions
Convenience typedef.
Definition: abg-ir.h:4008
size_t net_num_added_var_syms() const
Getter of the net number of added variable symbols that are not referenced by any debug info...
const typedef_diff * is_typedef_diff(const diff *diff)
Test if a diff node is a typedef_diff node.
const function_decl_diff * is_function_decl_diff(const diff *diff)
Test if a diff node is about differences between functions.
virtual bool has_changes() const
Return true iff the current diff node carries a change.
const diff * peel_fn_parm_diff(const diff *dif)
If a diff node is about changes between two function parameters get the diff node about changes betwe...
diff_category get_default_harmless_categories_bitmap()
Getter of a bitmap made of the set of change categories that are considered harmless.
const diff_sptr containing_type_diff() const
Getter of the diff node carrying changes to the containing type of first subject of the current diff ...
friend scope_diff_sptr compute_diff(const scope_decl_sptr first, const scope_decl_sptr second, scope_diff_sptr d, diff_context_sptr ctxt)
Compute the diff between two scopes.
void mark_leaf_diff_nodes()
Walks the diff nodes associated to the current corpus diff and mark those that carry local changes...
void set_local_category(diff_category c)
Set the local category of the current diff node.
virtual bool visit(diff *, bool)
Default visitor implementation.
shared_ptr< translation_unit_diff > translation_unit_diff_sptr
Convenience typedef for a shared pointer on a translation_unit_diff type.
size_t num_vars_removed() const
Getter for the number of variables removed.
A diff node in this category is for a variable which type holds a cv-qualifier change.
void add_suppression(const suppr::suppression_sptr suppr)
Add a new suppression specification that specifies which diff node reports should be dropped on the f...
void clear_lookup_tables()
Clear the lookup tables useful for reporting an enum_diff.
shared_ptr< reference_type_def > reference_type_def_sptr
Convenience typedef for a shared pointer on a reference_type_def.
Definition: abg-fwd.h:232
virtual bool traverse(diff_node_visitor &v)
The generic traversing code that walks a given diff sub-tree.
virtual const string & get_pretty_representation() const
pointer_diff(pointer_type_def_sptr first, pointer_type_def_sptr second, diff_sptr underlying_type_diff, diff_context_sptr ctxt=diff_context_sptr())
Constructor for a pointer_diff.
size_t count_filtered_changed_data_members(bool local_only=false) const
Count the number of /filtered/ data members that got replaced by another data member.
visiting_kind operator|(visiting_kind l, visiting_kind r)
The overloaded or operator for visiting_kind.
diff_sptr underlying_type_diff() const
virtual bool has_changes() const
Return true iff the current diff node carries a change.
shared_ptr< var_diff > var_diff_sptr
Convenience typedef for a shared pointer to a var_diff type.
void count_leaf_changes(size_t &num_changes, size_t &num_filtered)
Count the number of leaf changes as well as the number of the changes that have been filtered out...
shared_ptr< elf_symbol > elf_symbol_sptr
A convenience typedef for a shared pointer to elf_symbol.
Definition: abg-ir.h:924
const pointer_type_def_sptr second_pointer() const
Getter for the second subject of a pointer diff.
diff_category get_class_of_equiv_category() const
Getter of the category of the class of equivalence of the current diff tree node. ...
bool do_log() const
Test if logging was requested.
class_or_union_diff(class_or_union_sptr first_scope, class_or_union_sptr second_scope, diff_context_sptr ctxt=diff_context_sptr())
Constructor for the class_or_union_diff class.
const string_elf_symbol_map & added_unrefed_variable_symbols() const
Getter for variable symbols not referenced by any debug info and that got added.
#define ABG_ASSERT(cond)
This is a wrapper around the 'assert' glibc call. It allows for its argument to have side effects...
Definition: abg-fwd.h:1743
virtual enum change_kind has_local_changes() const
virtual void chain_into_hierarchy()
Populate the vector of children nodes of the diff base type sub-object of this instance of fn_parm_di...
size_t num_func_with_local_harmful_changes() const
Getter for the number of functions with local harmful changes.
virtual bool has_changes() const
Return true iff the current diff node carries a change.
bool is_opaque_type_suppr_spec(const type_suppression &s)
Test if a type suppression specification represents a private type suppression automatically generate...
size_t num_leaf_func_changes() const
Getter for the number of leaf function change diff nodes.
bool has_local_changes_to_be_reported() const
Test if this diff tree node should be reported when considering the categories that were *NOT* inheri...
virtual void visit_end(diff *)
This is called by the traversing code on a diff node just after visiting it. That is after visiting i...
virtual void report(ostream &, const string &indent="") const
Reports the difference between the two subjects of the diff in a serialized form. ...
size_t num_leaf_var_with_incompatible_changes() const
Getter for the number of leaf variable diff nodes that carry incompatible changes.
const diff * peel_qualified_diff(const diff *dif)
If a diff node is about changes between two qualified types, get the diff node about changes between ...
size_t num_func_added() const
Getter for the number of functions added.
change_kind
The kind of change the current function suppression should apply to.
An abstraction of a diff between two translation units.
A diff node in this category has a function parameter type with a cv-qualifiers change.
type_base * peel_qualified_or_typedef_type(const type_base *type)
Return the leaf underlying type of a qualified or typedef type.
Definition: abg-ir.cc:7358
vector< suppression_sptr > suppressions_type
Convenience typedef for a vector of suppression_sptr.
Definition: abg-fwd.h:1687
virtual void report(ostream &, const string &indent="") const
Build and emit a textual report about the current function_type_diff instance.
bool show_architecture_change() const
Getter for the property that says if the comparison module should show the architecture changes in it...
variable_suppression_sptr is_variable_suppression(const suppression_sptr s)
Test if an instance of suppression is an instance of variable_suppression.
visiting_kind
An enum for the different ways to visit a diff tree node.
interned_string get_function_id_or_pretty_representation(const function_decl *fn)
Get the ID of a function, or, if the ID can designate several different functions, get its pretty representation.
Definition: abg-ir.cc:9180
A diff node in this category has a descendant node that is in the HAS_ALLOWED_CHANGE_CATEGORY categor...
A functor to compare two enumerators based on their value. This implements the "less than" operator...
size_t num_var_with_local_harmful_changes() const
Getter for the number of variables with local harmful changes.
bool is_union_type(const type_or_decl_base &t)
Test if a type is a union_decl.
Definition: abg-ir.cc:11445
virtual void chain_into_hierarchy()
Populate the vector of children node of the diff base type sub-object of this instance of array_diff...
const string_diff_sptr_map & changed_unreachable_types() const
Get the map of diff nodes representing changed unreachable types.
virtual void chain_into_hierarchy()
Populate the vector of children node of the diff base type sub-object of this instance of var_diff...
const edit_script & member_class_tmpls_changes() const
A comparison functor to compare two instances of fn_parm_diff based on their indexes.
virtual const string & get_pretty_representation() const
virtual void report(ostream &, const string &indent="") const
Pure interface to report the diff in a serialized form that is legible for the user.
function_decl * is_function_decl(const type_or_decl_base *d)
Test whether a declaration is a function_decl.
Definition: abg-ir.cc:10695
void begin_traversing()
Flag a given diff node as being traversed.
virtual void chain_into_hierarchy()
Populate the vector of children node of the diff base type sub-object of this instance of function_de...
const decl_diff_base * is_decl_diff(const diff *diff)
Test if a diff node is about differences between declarations.
size_t num_changed_func_filtered_out() const
Getter for the number of functions that have a change in one of their sub-types, and that have been f...
virtual void chain_into_hierarchy()
Populate the vector of children node of the diff base type sub-object of this instance of scope_diff...
const string_member_function_sptr_map & inserted_member_fns() const
diff_sptr underlying_type_diff() const
Getter for the diff between the pointed-to types of the pointers of this diff.
const string_parm_map & added_parms() const
Getter for the map of parameters that got added.
const vector< diff * > & children_nodes() const
virtual void report(ostream &, const string &indent="") const
Report the diff in a serialized form.
size_t net_num_non_incompatible_var_changed() const
Getter of the net number of variables with changes that are not incompatible.
const decl_base_sptr inserted_member_at(unsigned i)
Accessor that eases the manipulation of the edit script associated to this instance. It returns the scope member (of the second scope of this diff instance) that is reported as being inserted from a given index.
const array_diff * is_array_diff(const diff *diff)
Test if a diff node is a array_diff node.
bool has_basic_type_change_only(const diff *d)
Test if a diff node is a decl diff that only carries a basic type change on its type diff sub-node...
const string_function_decl_diff_sptr_map & changed_functions() const
Getter for the functions which signature didn't change, but which do have some indirect changes in th...
bool lookup_tables_empty() const
Tests if the lookup tables are empty.
diff_sptr type_diff() const
Getter for the diff representing the changes on the type of the function parameter involved in the cu...
size_t num_removed_unreachable_types_filtered_out() const
Getter of the number of removed types that are not reachable from public interfaces and that have bee...
bool has_fn_with_virtual_offset_change(const diff *d)
Test if a diff node carries a change to the offset of a virtual function.
A comparison functor to compare two instances of var_diff that represent changed data members based o...
change_kind
The kind of change the current variable suppression should apply to.
size_t net_num_func_changed() const
Getter for the number of functions that have a change in their sub-types, minus the number of these f...
const filtering::filters & diff_filters() const
Getter for the diff tree nodes filters to apply to diff sub-trees.
The abstraction of a pointer type.
Definition: abg-ir.h:2349
bool lookup_tables_empty(void) const
Tests if the lookup tables are empty.
bool added_unrefed_fn_sym_is_suppressed(const elf_symbol *) const
Test if the change reports for a given added function symbol (that is not referenced by any debug inf...
virtual bool has_changes() const
Test whether the current diff node carries any change.
const string_diff_ptr_map & get_array_diff_map() const
Getter of the map that contains array type diffs.
This type contains maps. Each map associates a type name to a diff of that type. Not all kinds of dif...
virtual bool visit(distinct_diff *, bool)
Default visitor implementation.
unordered_map< unsigned, var_diff_sptr > unsigned_var_diff_sptr_map
Convenience typedef for a map whose key is an unsigned int and whose value is a changed variable of t...
size_t num_added_func_syms_filtered_out() const
Getter for the number of added function symbols, not referenced by any debug info, that have been filtered out.
const diff_sptr & element_type_diff() const
Getter for the diff between the two types of array elements.
const string & get_pretty_representation() const
virtual enum change_kind has_local_changes() const
Test if the current subrange_diff node carries any local change.
friend class_diff_sptr compute_diff(const class_decl_sptr first, const class_decl_sptr second, diff_context_sptr ctxt)
Compute the set of changes between two instances of class_decl.
const type_decl_sptr second_type_decl() const
Getter for the second subject of the type_decl_diff.
The function was added to the second subject of the diff.
bool show_symbols_unreferenced_by_debug_info() const
Getter for the flag that indicates if symbols not referenced by any debug info are to be compared and...
size_t num_var_syms_added() const
Getter for the number of variable symbols (not referenced by any debug info) that got added...
const array_type_def::subrange_sptr second_subrange() const
Getter of the second subrange of the current instance subrange_diff.
const vector< class_decl::base_spec_sptr > & moved_bases() const
Getter for the vector of bases that "moved". That is, the vector of base types which position changed...
bool is_less_than(const decl_diff_base &first, const decl_diff_base &second)
Compare two decl diff nodes (decl_diff_base) for the purpose of sorting.
const string_diff_ptr_map & get_subrange_diff_map() const
Getter of the map that contains subrange type diffs.
const string_diff_ptr_map & get_union_diff_map() const
Getter of the map that contains union type diffs.
const enum_diff * is_enum_diff(const diff *diff)
Test if a diff node is a enum_diff node.
virtual void report(ostream &, const string &indent="") const
Report the diff in a serialized form.
The base class for the node visitors. These are the types used to visit each node traversed by the di...
bool dump_diff_tree() const
Test if the comparison engine should dump the diff tree for the changed functions and variables it ha...
bool collect_non_anonymous_data_members(const class_or_union *cou, string_decl_base_sptr_map &dms)
Collect all the non-anonymous data members of a class or union type.
Definition: abg-ir.cc:5815
A filter that walks the diff nodes tree and tags relevant diff nodes into categories considered to re...
const function_type_sptr second_function_type() const
Getter for the second subject of the diff.
void append_child_node(diff_sptr)
Append a new child node to the vector of children nodes for the current instance of corpus_diff node...
A basic type declaration that introduces no scope.
Definition: abg-ir.h:2117
void sort_changed_data_members(changed_var_sptrs_type &input)
Sort (in place) a vector of changed data members.
shared_ptr< enum_type_decl > enum_type_decl_sptr
Convenience typedef for shared pointer to a enum_type_decl.
Definition: abg-fwd.h:172
shared_ptr< base_diff > base_diff_sptr
Convenience typedef for a shared pointer to a base_diff type.
virtual void chain_into_hierarchy()
Populate the vector of children node of the diff base type sub-object of this instance of ...
void sort_changed_enumerators(const string_changed_enumerator_map &enumerators_map, changed_enumerators_type &sorted)
Sort a map of changed enumerators.
const subrange_diff * is_subrange_diff(const diff *diff)
Test if a diff node is a subrange_diff node.
shared_ptr< class_decl > class_decl_sptr
Convenience typedef for a shared pointer on a class_decl.
Definition: abg-fwd.h:190
virtual void get_qualified_name(interned_string &qualified_name, bool internal=false) const
Compute the qualified name of the decl.
Definition: abg-ir.cc:4823
const decl_base_sptr deleted_member_at(unsigned index) const
Accessor that eases the manipulation of the edit script associated to this instance. It returns the scope member that is reported (in the edit script) as deleted at a given index.
const string_changed_enumerator_map & changed_enumerators() const
shared_ptr< array_diff > array_diff_sptr
Convenience typedef for a shared pointer on a array_diff type.
size_t num_func_syms_added() const
Getter for the number of function symbols (not referenced by any debug info) that got added...
ostream * error_output_stream() const
Getter for the errror output stream used by code of the comparison engine. By default the error outpu...
size_t num_vars_added() const
Getter for the number of variables added.
virtual ~ptr_to_mbr_diff()
Destructor of ptr_to_mbr_diff.
virtual enum change_kind has_local_changes() const
bool show_soname_change() const
Getter for the property that says if the comparison module should show the soname changes in its repo...
An equality functor to deeply compare pointers.
A comparison functor to compare two data members based on their offset.
bool deleted_unrefed_var_sym_is_suppressed(const elf_symbol *) const
Test if the change reports for a given deleted variable symbol (that is not referenced by any debug i...
static bool entities_are_of_distinct_kinds(type_or_decl_base_sptr first, type_or_decl_base_sptr second)
Test if the two arguments are of different kind, or that are both NULL.
shared_ptr< fn_parm_diff > fn_parm_diff_sptr
Convenience typedef for a shared pointer to a fn_parm_diff type.
unordered_map< string, method_decl_sptr > string_member_function_sptr_map
Convenience typedef for a hash map of strings and member functions.
bool is_harmful_category(diff_category c)
Test if an instance of diff_category (a category bit-field) is harmful or not.
virtual bool has_changes() const
Return true iff the current diff node carries a change.
const class_or_union_diff * is_anonymous_class_or_union_diff(const diff *d)
Test if a diff node is a class_or_union_diff between two anonymous classes or unions.
const string_decl_base_sptr_map & data_members_replaced_by_adms() const
Get the map of data members that got replaced by anonymous data members.
bool is_diff_of_variadic_parameter(const diff *d)
Test if a diff node represents the difference between a variadic parameter and something else...
union_decl_sptr second_union_decl() const
const var_decl * lookup_data_member(const type_base *type, const char *dm_name)
Look for a data member of a given class, struct or union type and return it.
Definition: abg-ir.cc:29100
void count_leaf_type_changes(size_t &num_type_changes, size_t &num_type_changes_filtered)
Count the number of leaf *type* changes as well as the number of the leaf type changes that have been...
bool show_relative_offset_changes(void)
Get the flag saying if offset changes should be reported in a relative way. That is, if the report should say how of many bits a class/struct data member did move.
The type of private data of class_or_union_diff.
void set_underlying_class_diff(class_diff_sptr d)
Setter for the diff object for the diff of the underlyng base classes.
A deleter for shared pointers that ... doesn't delete the object managed by the shared pointer...
const translation_unit_sptr first_translation_unit() const
Getter for the first translation unit of this diff.
bool to_be_reported() const
Test if this diff tree node should be reported.
void clear_lookup_tables(void)
Clear the lookup tables useful for reporting.
virtual const string & get_pretty_representation() const
void or_visiting_kind(visiting_kind v)
Setter for the visiting policy of the traversing code while invoking this visitor. This one makes a logical or between the current policy and the bitmap given in argument and assigns the current policy to the result.
const function_type_sptr first_function_type() const
Getter for the first subject of the diff.
virtual enum change_kind has_local_changes() const
Test if the current diff node carries local changes.
This means that a given IR artifact has a local type change.
Definition: abg-ir.h:1365
Abstracts a diff between two instances of var_decl.
const pointer_type_def_sptr first_pointer() const
Getter for the first subject of a pointer diff.
diff_sptr type_diff() const
Getter for the diff of the types of the instances of var_decl.
array_type_def::subrange_type * is_subrange_type(const type_or_decl_base *type)
Test if a type is an array_type_def::subrange_type.
Definition: abg-ir.cc:12215
corpus_sptr get_second_corpus() const
Getter for the second corpus of the corpus diff of the current context.
const typedef_decl_sptr second_typedef_decl() const
Getter for the second typedef_decl involved in the diff.
bool get_member_is_static(const decl_base &d)
Gets a flag saying if a class member is static or not.
Definition: abg-ir.cc:5575
const vector< function_decl::parameter_sptr > & sorted_deleted_parms() const
Getter for the sorted vector of deleted parameters.
void maybe_dump_diff_tree()
If the user asked to dump the diff tree node (for changed variables and functions) on the error outpu...
const class_or_union_diff * is_class_or_union_diff(const diff *d)
Test if a diff node is a class_or_union_diff node.
const var_diff_sptrs_type & sorted_subtype_changed_data_members() const
Getter of the sorted vector of data members with a (sub-)type change.
corpus_sptr get_first_corpus() const
Getter for the first corpus of the corpus diff of the current context.
type_or_decl_base_sptr member_type_has_changed(decl_base_sptr) const
Test if the current diff node carries a member type change for a member type which name is the same a...
bool has_harmful_name_change(const decl_base_sptr &f, const decl_base_sptr &s, const diff_context_sptr &ctxt)
Test if two decls represent a harmful name change.
A comparison functor to compare pointer to instances of type_or_decl_base.
Definition: abg-ir.h:3293
bool get_is_anonymous() const
Test if the current declaration is anonymous.
Definition: abg-ir.cc:4668
This means that a diff node in the sub-tree carries an addition or removal of a non-virtual member fu...
bool is_child_node_of_base_diff(const diff *diff)
Test if a diff node is a child node of a base diff node.
unordered_map< string, fn_parm_diff_sptr > string_fn_parm_diff_sptr_map
Convenience typedef for a map which value is a changed function parameter and which key is the name o...
reference_type_def_sptr second_reference() const
Getter for the second reference of the diff.
void sort_string_fn_parm_diff_sptr_map(const unsigned_fn_parm_diff_sptr_map &map, vector< fn_parm_diff_sptr > &sorted)
Sort a map of fn_parm_diff by the indexes of the function parameters.
The private data and functions of the abigail::ir::comparison types.
void sort_string_virtual_member_function_diff_sptr_map(const string_function_decl_diff_sptr_map &map, function_decl_diff_sptrs_type &sorted)
Sort an map of string -> virtual member function into a vector of virtual member functions. The virtual member functions are sorted by increasing order of their virtual index.
The abstraction of the version of an ELF symbol.
Definition: abg-ir.h:1231
void sort_string_function_decl_diff_sptr_map(const string_function_decl_diff_sptr_map &map, function_decl_diff_sptrs_type &sorted)
Sort the values of a string_function_decl_diff_sptr_map map and store the result in a vector of funct...
const reference_diff * is_reference_diff(const diff *diff)
Test if a diff node is about differences between two references.
size_t net_num_removed_unreachable_types() const
Getter of the number of removed types that are not reachable from public interfaces and that have *NO...
This means that a diff node in the sub-tree carries an a symbol alias change that is harmless...
virtual void report(ostream &, const string &indent="") const
Report the diff in a serialized form.
A diff node in this category carries a change that must be reported, even if the diff node is also in...
vector< diff_sptr > diff_sptrs_type
Convenience typedef for a vector of diff_sptr.
const qualified_type_def_sptr second_qualified_type() const
Getter for the second qualified type of the diff.
bool show_hex_values() const
Get the flag that indicates if the diff reports using this context should show sizes and offsets in a...
const scope_decl_sptr second_scope() const
Getter for the second scope of the diff.
const diff * peel_reference_diff(const diff *dif)
If a diff node is about changes between two reference types, get the diff node about changes between ...
A functor to compare two changed enumerators, based on their initial value.
const diff * get_typedef_diff_underlying_type_diff(const diff *diff)
Return the leaf underlying diff node of a typedef_diff node.
size_t num_func_changed() const
Getter for the number of functions that have a change in one of their sub-types.
union_diff(union_decl_sptr first_union, union_decl_sptr second_union, diff_context_sptr ctxt=diff_context_sptr())
Constructor for the union_diff type.
const type_diff_base * is_type_diff(const diff *diff)
Test if a diff node is about differences between types.
size_t num_leaf_func_changes_filtered_out() const
Getter for the number of leaf function change diff nodes that were filtered out.
shared_ptr< corpus_diff > corpus_diff_sptr
A convenience typedef for a shared pointer to corpus_diff.
size_t get_deleted_non_static_data_members_number() const
Get the number of non static data members that were deleted.
size_t net_num_leaf_type_changes() const
Getter for the net number of leaf type change diff nodes.
const diff_context_sptr context() const
Getter of the diff context of this diff.
const string_elf_symbol_map & deleted_unrefed_variable_symbols() const
Getter for variable symbols not referenced by any debug info and that got deleted.
bool types_are_compatible(const type_base_sptr type1, const type_base_sptr type2)
Test if two types are equal modulo a typedef or CV qualifiers.
Definition: abg-ir.cc:10397
class_or_union * look_through_decl_only_class(class_or_union *the_class)
If a class (or union) is a decl-only class, get its definition. Otherwise, just return the initial cl...
Definition: abg-ir.cc:11918
subrange_diff(const array_type_def::subrange_sptr &first, const array_type_def::subrange_sptr &second, const diff_sptr &underlying_type_diff, const diff_context_sptr ctxt=diff_context_sptr())
Constructor of the subrange_diff diff node type.
void do_dump_diff_tree(const diff_sptr) const
Emit a textual representation of a diff tree to the error output stream of the current context...
shared_ptr< variable_suppression > variable_suppression_sptr
A convenience typedef for a shared pointer to variable_suppression.
const suppr::suppressions_type & direct_suppressions() const
Getter of the direct suppression specification (those that are not negated) comprised in the general ...
virtual enum change_kind has_local_changes() const
const class_or_union_diff * is_diff_of_class_or_union_type(const diff *d)
Test if a diff node represents a diff between two class or union types.
This means that a given IR artifact has a local non-type change. That is a change that is carried by ...
Definition: abg-ir.h:1370
const suppr::suppressions_type & negated_suppressions() const
Getter of the negated suppression specifications that are comprised in the general vector of suppress...
bool visiting_a_node_twice_is_forbidden_per_interface() const
Return a flag that, if true, then during the traversing of a diff nodes tree each node is visited at ...
const subrange_diff * is_anonymous_subrange_diff(const diff *d)
Test if a diff node is a subrange_diff between two anonymous subranges.
reference_type_def_sptr first_reference() const
Getter for the first reference of the diff.
vector< base_diff_sptr > base_diff_sptrs_type
Convenience typedef for a vector of base_diff_sptr.
unordered_map< string, function_decl::parameter_sptr > string_parm_map
Convenience typedef for a map which value is a function parameter. The key is the name of the functio...
const diff_sptr compatible_child_diff() const
Getter for the child diff of this distinct_diff instance.
bool is_anonymous_data_member(const decl_base &d)
Test if a decl is an anonymous data member.
Definition: abg-ir.cc:5872
virtual void report(ostream &, const string &indent="") const
Report about the changes carried by this node.
"Less than" functor to compare instances of function_decl.
void add_to_local_and_inherited_categories(diff_category c)
Adds the current diff tree node to the categories resulting from the local and inherited changes of t...
void sort_string_type_base_sptr_map(string_type_base_sptr_map &map, vector< type_base_sptr > &sorted)
Sort a map of string to type_base_sptr entities.
virtual bool has_changes() const
Return true iff the current diff node carries a change.
Functor that compares two function parameters for the purpose of sorting them.
const function_type_diff * is_function_type_diff(const diff *diff)
Test if a diff node is a function_type_diff node.
const function_decl_diff_sptrs_type & changed_member_fns() const
Getter for the virtual members functions that have had a change in a sub-type, without having a chang...
string get_pretty_representation(const type_or_decl_base *tod, bool internal)
Build and return a copy of the pretty representation of an ABI artifact that could be either a type o...
Definition: abg-ir.cc:9286
void compute_diff(RandomAccessOutputIterator a_base, RandomAccessOutputIterator a_begin, RandomAccessOutputIterator a_end, RandomAccessOutputIterator b_base, RandomAccessOutputIterator b_begin, RandomAccessOutputIterator b_end, vector< point > &lcs, edit_script &ses, int &ses_len)
Compute the longest common subsequence of two (sub-regions of) sequences as well as the shortest edit...
virtual enum change_kind has_local_changes() const
virtual bool has_changes() const =0
Pure interface to get the length of the changes encapsulated by this diff. A length of zero means tha...
This says that the traversing code should avoid visiting the children nodes of the current node being...
decl_base_sptr member_class_tmpl_has_changed(decl_base_sptr) const
Test if the current diff node carries a member class template change for a member class template whic...
shared_ptr< function_suppression > function_suppression_sptr
Convenience typedef for a shared pointer to function_suppression.
friend void apply_suppressions(const corpus_diff *diff_tree)
Walk a corpus_diff tree and appply the suppressions carried by the context. If the suppression applie...
virtual const string & get_pretty_representation() const
virtual enum change_kind has_local_changes() const
void sort_string_diff_ptr_map(const string_diff_ptr_map &map, diff_ptrs_type &sorted)
Sort a map ofg string -> diff* into a vector of diff_ptr. The diff_ptr are sorted lexicographically w...
A diff node in this category carries a change in the size of the array type of a global variable...
const translation_unit_sptr second_translation_unit() const
Getter for the second translation unit of this diff.
const vector< diff_sptr > & changed_unreachable_types_sorted() const
Getter of a sorted vector of changed types that are not reachable from global functions/variables.
virtual void chain_into_hierarchy()
Populate the vector of children node of the diff base type sub-object of this instance of ptr_to_mbr_...
size_t get_inserted_non_static_data_members_number() const
Get the number of non static data members that were inserted.
This means that a diff node in the sub-tree carries a harmless union or class change.
const string_base_sptr_map & deleted_bases() const
Getter for the deleted base classes of the diff.
type_or_decl_base_sptr second_subject() const
Getter of the second subject of the diff.
const var_diff_sptrs_type & sorted_changed_data_members() const
Getter of the sorted vector of data members that got replaced by another data member.
size_t num_added_vars_filtered_out() const
Getter for the number of added variables that have been filtered out.
bool deleted_unreachable_type_is_suppressed(const type_base *t) const
Test if a deleted type that is unreachable from public interface has been suppressed by a suppression...
unordered_map< string, enum_type_decl::enumerator > string_enumerator_map
Convenience typedef for a map which value is an enumerator. The key is the name of the enumerator...
const diff_sptr & underlying_type_diff() const
Getter for the diff between the two referred-to types.
bool is_allowed_by_specific_negated_suppression() const
Test if this diff node is allowed (prevented from being suppressed) by at least one negated suppressi...
bool equals(const decl_base &l, const decl_base &r, change_kind *k)
Compares two instances of decl_base.
Definition: abg-ir.cc:5138
bool has_basic_or_class_type_name_change(const diff *d)
Test if a diff node carries a basic or class type name change.
virtual void report(ostream &out, const string &indent="") const
Report the diff in a serialized form.
union_decl_sptr first_union_decl() const
void categorize_redundancy(diff *diff_tree)
Walk a given diff sub-tree to categorize each of the nodes with respect to the REDUNDANT_CATEGORY.
virtual void chain_into_hierarchy()
Populate the vector of children node of the diff base type sub-object of this instance of typedef_dif...
void apply_filters_and_compute_diff_stats(corpus_diff::diff_stats &)
Compute the diff stats.
size_t num_changed_unreachable_types() const
Getter of the number of changed types that are unreachable from the public interface of the ABI corpu...
The abstraction of a typedef declaration.
Definition: abg-ir.h:2934
std::vector< filter_base_sptr > filters
Convenience typedef for a vector of filter_base_sptr.
const diff_sptr underlying_type_diff() const
Getter for the diff between the two underlying types of the typedefs.
const vector< type_base_sptr > & added_unreachable_types_sorted() const
Getter of a sorted vector of added types that are not reachable from global functions/variables.
const string & get_id_string() const
Get a string that is representative of a given elf_symbol.
Definition: abg-ir.cc:2616
void set_visiting_kind(visiting_kind v)
Setter for the visiting policy of the traversing code while invoking this visitor.
artifact_sptr_set_type * lookup_impacted_interfaces(const diff *d) const
Lookup the interfaces that are impacted by a given leaf diff node.
vector< base_spec_sptr > base_specs
Convenience typedef.
Definition: abg-ir.h:4193
void count_unreachable_types(size_t &num_added, size_t &num_removed, size_t &num_changed, size_t &num_filtered_added, size_t &num_filtered_removed, size_t &num_filtered_changed)
Count the number of types not reachable from the interface (i.e, not reachable from global functions ...
This is a document class that aims to capture statistics about the changes carried by a corpus_diff t...
void sort_string_function_ptr_map(const string_function_ptr_map &map, vector< const function_decl * > &sorted)
Sort an instance of string_function_ptr_map map and stuff a resulting sorted vector of pointers to fu...
virtual bool has_changes() const
Return true iff the current diff node carries a change.
bool visiting_a_node_twice_is_forbidden() const
Return a flag that, if true, then during the traversing of a diff nodes tree each node is visited at ...
const union_diff * is_union_diff(const diff *diff)
Test if a diff node is a union_diff node.
virtual const string & get_pretty_representation() const
void print_diff_tree(diff *diff_tree, ostream &out)
Emit a textual representation of a diff sub-tree to an output stream.
const function_decl_diff_sptrs_type & changed_functions_sorted() const
Getter for a sorted vector of functions which signature didn't change, but which do have some indirec...
diff_maps & get_leaf_diffs()
Get the set of maps that contain leaf nodes. A leaf node being a node with a local change...
The internal type for the impl idiom implementation of var_diff.
A diff node in this category is a function return type with a cv-qualifier change.
const string_diff_ptr_map & get_fn_parm_diff_map() const
Getter of the map that contains function parameter diffs.
reference_diff(const reference_type_def_sptr first, const reference_type_def_sptr second, diff_sptr underlying, diff_context_sptr ctxt=diff_context_sptr())
Constructor for reference_diff.
shared_ptr< diff > diff_sptr
Convenience typedef for a shared_ptr for the diff class.
Definition: abg-fwd.h:75
shared_ptr< reporter_base > reporter_base_sptr
A convenience typedef for a shared pointer to a reporter_base.
Definition: abg-reporter.h:50
enum_diff(const enum_type_decl_sptr, const enum_type_decl_sptr, const diff_sptr, diff_context_sptr ctxt=diff_context_sptr())
Constructor for enum_diff.
friend function_type_diff_sptr compute_diff(const function_type_sptr first, const function_type_sptr second, diff_context_sptr ctxt)
Compute the diff between two instances of function_type.
const vector< type_base_sptr > & deleted_unreachable_types_sorted() const
Getter of a sorted vector of deleted types that are not reachable from global functions/variables.
const distinct_diff * is_distinct_diff(const diff *diff)
Test if a diff node is about differences between two diff nodes of different kinds.
distinct_diff_sptr compute_diff_for_distinct_kinds(const type_or_decl_base_sptr first, const type_or_decl_base_sptr second, diff_context_sptr ctxt)
Try to diff entities that are of distinct kinds.
size_t num_leaf_func_with_incompatible_changes() const
Getter for the number of leaf function diff nodes that carry incompatible changes.
const diff * peel_pointer_diff(const diff *dif)
If a diff node is about changes between two pointer types, get the diff node about changes between th...
reporter_base_sptr get_reporter() const
Getter of the reporter to be used in this context.
size_t net_num_leaf_func_changes() const
Getter for the net number of leaf function change diff nodes.
class_decl::base_spec_sptr base_has_changed(class_decl::base_spec_sptr) const
Test whether a given base class has changed. A base class has changed if it's in both in deleted *and...
var_diff(var_decl_sptr first, var_decl_sptr second, diff_sptr type_diff, diff_context_sptr ctxt=diff_context_sptr())
Constructor for var_diff.
bool any_subrange_diff_to_be_reported() const
Test if any subrange diff is to be reported.
void sort_artifacts_set(const artifact_sptr_set_type &set, vector< type_or_decl_base_sptr > &sorted)
Sort the set of ABI artifacts contained in a artifact_sptr_set_type.
shared_ptr< subrange_type > subrange_sptr
Convenience typedef for a shared pointer on a function_decl::subrange.
Definition: abg-ir.h:2562
virtual void report(ostream &, const string &indent="") const
Emit a textual report about the current fn_parm_diff instance.
A change between two non-compatible types of different kinds.
shared_ptr< array_type_def > array_type_def_sptr
Convenience typedef for a shared pointer on a array_type_def.
Definition: abg-fwd.h:241
bool is_diff_of_variadic_parameter_type(const diff *d)
Test if a diff node represents the difference between a variadic parameter type and something else...
shared_ptr< pointer_type_def > pointer_type_def_sptr
Convenience typedef for a shared pointer on a pointer_type_def.
Definition: abg-fwd.h:223
visiting_kind operator~(visiting_kind l)
The overloaded 'bit inversion' operator for visiting_kind.
virtual const string & get_pretty_representation() const
bool architecture_changed() const
Test if the architecture of the underlying corpus has changed.
method_type_sptr is_method_type(const type_or_decl_base_sptr &t)
Test whether a type is a method_type.
Definition: abg-ir.cc:11888
bool is_decl_only_class_with_size_change(const class_or_union &first, const class_or_union &second)
Test if two classes that are decl-only (have the decl-only flag and carry no data members) but are di...
Abstraction of a diff between two function types.
virtual enum change_kind has_local_changes() const
class_diff(class_decl_sptr first_scope, class_decl_sptr second_scope, diff_context_sptr ctxt=diff_context_sptr())
Constructor of class_diff.
const class_diff_sptr get_underlying_class_diff() const
Getter for the diff object for the diff of the underlying base classes.
string get_pretty_representation(diff *d)
Get a copy of the pretty representation of a diff node.
shared_ptr< filter_base > filter_base_sptr
Convenience typedef for a shared pointer to filter_base.
const array_type_def_sptr first_array() const
Getter for the first array of the diff.
virtual const string & get_pretty_representation() const
const base_diff_sptrs_type & changed_bases()
Getter for the changed base classes of the diff.
const diff_sptr return_type_diff() const
Getter for the diff of the return types of the two function types of the current diff.
array_diff(const array_type_def_sptr first, const array_type_def_sptr second, diff_sptr element_type_diff, vector< subrange_diff_sptr > &subrange_diffs, diff_context_sptr ctxt=diff_context_sptr())
Constructor for array_diff.
void ensure_lookup_tables_populated(void) const
If the lookup tables are not yet built, walk the differences and fill them.
A comparison functor for instances of function_decl_diff that represent changes between two virtual m...
const string_type_base_sptr_map & deleted_unreachable_types() const
Getter for a map of deleted types that are not reachable from global functions/variables.
const diff_context_sptr context() const
Getter of the context of the current diff.
Abstraction of a function type.
Definition: abg-ir.h:3419
virtual void finish_diff_type()
Finish the insertion of a diff tree node into the diff graph.
const enum_type_decl_sptr second_enum() const
size_t num_removed_func_filtered_out() const
Getter for the number of removed functions that have been filtered out.
const class_or_union_diff::priv_ptr & get_priv() const
Getter of the private data of the class_or_union_diff type.
bool deleted_variable_is_suppressed(const var_decl_sptr &var) const
Test if the change reports for a give given deleted variable has been deleted.
size_t net_num_non_incompatible_func_changed() const
Getter of the net number of functions with changes that are not incompatible.
void add_diff_filter(filtering::filter_base_sptr)
Setter for the diff filters to apply to a given diff sub-tree.
bool stop()
Stop the timer.
const diff_sptr member_type_diff() const
Getter of the diff node carrying changes to the member type of first subject of the current diff node...
const vector< diff_sptr > & changed_unreachable_types_sorted() const
Get the sorted vector of diff nodes representing changed unreachable types.
size_t num_func_syms_removed() const
Getter for the number of function symbols (not referenced by any debug info) that got removed...
const unsigned_var_diff_sptr_map & changed_data_members() const
Getter of the map of data members that got replaced by another data member. The key of the map is the...
diff_category add_to_local_category(diff_category c)
Adds the current diff tree node to the categories resulting from the local changes of the current dif...
This means that a diff node in the sub-tree carries an addition or removal of a static data member...