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  // Use hash-based set difference to classify functions as
9910  // added/deleted/changed, avoiding the quadratic Myers diff.
9911  {
9912  // Build a map of function ID -> function_decl* for each corpus.
9913  unordered_map<string, const function_decl*> first_fns_map;
9914  first_fns_map.reserve(first_->get_functions().size());
9915  for (const auto* fn : first_->get_functions())
9916  {
9918  ABG_ASSERT(!n.empty());
9919  first_fns_map[n] = fn;
9920  }
9921 
9922  for (const auto* fn : second_->get_functions())
9923  {
9925  ABG_ASSERT(!n.empty());
9926  auto j = first_fns_map.find(n);
9927  if (j != first_fns_map.end())
9928  {
9929  // Function exists in both corpora -- check if changed.
9930  if (*j->second != *fn)
9931  {
9932  function_decl_sptr f(const_cast<function_decl*>(j->second),
9933  noop_deleter());
9934  function_decl_sptr s(const_cast<function_decl*>(fn),
9935  noop_deleter());
9936  function_decl_diff_sptr d = compute_diff(f, s, ctxt);
9937  changed_fns_map_[j->first] = d;
9938  }
9939  first_fns_map.erase(j);
9940  }
9941  else
9942  added_fns_[n] = fn;
9943  }
9944 
9945  // Remaining entries in first_fns_map are deleted functions.
9946  for (const auto& entry : first_fns_map)
9947  deleted_fns_[entry.first] = entry.second;
9948 
9949  sort_string_function_decl_diff_sptr_map(changed_fns_map_, changed_fns_);
9950 
9951  // Now walk the allegedly deleted functions; check if their
9952  // underlying symbols are deleted as well; otherwise, consider
9953  // that the function in question hasn't been deleted.
9954 
9955  vector<string> to_delete;
9956  for (string_function_ptr_map::const_iterator i = deleted_fns_.begin();
9957  i != deleted_fns_.end();
9958  ++i)
9959  if (second_->lookup_function_symbol(*i->second->get_symbol()))
9960  to_delete.push_back(i->first);
9961 
9962  for (vector<string>::const_iterator i = to_delete.begin();
9963  i != to_delete.end();
9964  ++i)
9965  deleted_fns_.erase(*i);
9966 
9967  // Do something similar for added functions.
9968 
9969  to_delete.clear();
9970  for (string_function_ptr_map::const_iterator i = added_fns_.begin();
9971  i != added_fns_.end();
9972  ++i)
9973  {
9974  if (first_->lookup_function_symbol(*i->second->get_symbol()))
9975  to_delete.push_back(i->first);
9976  else if (! i->second->get_symbol()->get_version().is_empty()
9977  && i->second->get_symbol()->get_version().is_default())
9978  // We are looking for a symbol that has a default version,
9979  // and which seems to be newly added. Let's see if the same
9980  // symbol with *no* version was already present in the
9981  // former corpus. If yes, then the symbol shouldn't be
9982  // considered as 'added'.
9983  {
9984  elf_symbol::version empty_version;
9985  if (first_->lookup_function_symbol(i->second->get_symbol()->get_name(),
9986  empty_version))
9987  to_delete.push_back(i->first);
9988  }
9989  }
9990 
9991  for (vector<string>::const_iterator i = to_delete.begin();
9992  i != to_delete.end();
9993  ++i)
9994  added_fns_.erase(*i);
9995  }
9996 
9997  // Use hash-based set difference to classify variables as
9998  // added/deleted/changed, avoiding the quadratic Myers diff.
9999  {
10000  // Build a map of variable ID -> var_decl_sptr for the first corpus.
10001  unordered_map<string, var_decl_sptr> first_vars_map;
10002  first_vars_map.reserve(first_->get_variables().size());
10003  for (const auto& var : first_->get_variables())
10004  {
10005  string n = var->get_id();
10006  ABG_ASSERT(!n.empty());
10007  // Keep only the first instance of duplicate IDs (static
10008  // member variables from multiple translation units).
10009  if (first_vars_map.find(n) == first_vars_map.end())
10010  first_vars_map[n] = var;
10011  else
10013  }
10014 
10015  for (const auto& var : second_->get_variables())
10016  {
10017  string n = var->get_id();
10018  ABG_ASSERT(!n.empty());
10019  auto j = first_vars_map.find(n);
10020  if (j != first_vars_map.end())
10021  {
10022  // Variable exists in both corpora -- check if changed.
10023  if (*j->second != *var)
10024  {
10025  var_decl_sptr f = j->second;
10026  var_decl_sptr s = var;
10027  changed_vars_map_[n] = compute_diff(f, s, ctxt);
10028  }
10029  first_vars_map.erase(j);
10030  }
10031  else if (added_vars_.find(n) == added_vars_.end())
10032  added_vars_[n] = var;
10033  else
10035  }
10036 
10037  // Remaining entries in first_vars_map are deleted variables.
10038  for (const auto& entry : first_vars_map)
10039  deleted_vars_[entry.first] = entry.second;
10040 
10041  sort_string_var_diff_sptr_map(changed_vars_map_,
10042  sorted_changed_vars_);
10043 
10044  // Now walk the allegedly deleted variables; check if their
10045  // underlying symbols are deleted as well; otherwise consider
10046  // that the variable in question hasn't been deleted.
10047 
10048  vector<string> to_delete;
10049  for (string_var_ptr_map::const_iterator i = deleted_vars_.begin();
10050  i != deleted_vars_.end();
10051  ++i)
10052  if (second_->lookup_variable_symbol(*i->second->get_symbol()))
10053  to_delete.push_back(i->first);
10054 
10055  for (vector<string>::const_iterator i = to_delete.begin();
10056  i != to_delete.end();
10057  ++i)
10058  deleted_vars_.erase(*i);
10059 
10060  // Do something similar for added variables.
10061 
10062  to_delete.clear();
10063  for (string_var_ptr_map::const_iterator i = added_vars_.begin();
10064  i != added_vars_.end();
10065  ++i)
10066  if (first_->lookup_variable_symbol(*i->second->get_symbol()))
10067  to_delete.push_back(i->first);
10068  else if (! i->second->get_symbol()->get_version().is_empty()
10069  && i->second->get_symbol()->get_version().is_default())
10070  // We are looking for a symbol that has a default version,
10071  // and which seems to be newly added. Let's see if the same
10072  // symbol with *no* version was already present in the
10073  // former corpus. If yes, then the symbol shouldn't be
10074  // considered as 'added'.
10075  {
10076  elf_symbol::version empty_version;
10077  if (first_->lookup_variable_symbol(i->second->get_symbol()->get_name(),
10078  empty_version))
10079  to_delete.push_back(i->first);
10080  }
10081 
10082  for (vector<string>::const_iterator i = to_delete.begin();
10083  i != to_delete.end();
10084  ++i)
10085  added_vars_.erase(*i);
10086  }
10087 
10088  // Handle the unreachable_types_edit_script_
10089  {
10090  edit_script& e = unreachable_types_edit_script_;
10091 
10092  // Populate the map of deleted unreachable types from the
10093  // deletions of the edit script.
10094  for (vector<deletion>::const_iterator it = e.deletions().begin();
10095  it != e.deletions().end();
10096  ++it)
10097  {
10098  unsigned i = it->index();
10099  type_base_sptr t
10100  (first_->get_types_not_reachable_from_public_interfaces()[i]);
10101 
10102  if (!is_user_defined_type(t))
10103  continue;
10104 
10105  string repr =
10106  abigail::ir::get_pretty_representation(t, /*internal=*/false);
10107  deleted_unreachable_types_[repr] = t;
10108  }
10109 
10110  // Populate the map of added and change unreachable types from the
10111  // insertions of the edit script.
10112  for (vector<insertion>::const_iterator it = e.insertions().begin();
10113  it != e.insertions().end();
10114  ++it)
10115  {
10116  for (vector<unsigned>::const_iterator iit =
10117  it->inserted_indexes().begin();
10118  iit != it->inserted_indexes().end();
10119  ++iit)
10120  {
10121  unsigned i = *iit;
10122  type_base_sptr t
10123  (second_->get_types_not_reachable_from_public_interfaces()[i]);
10124 
10125  if (!is_user_defined_type(t))
10126  continue;
10127 
10128  string repr =
10129  abigail::ir::get_pretty_representation(t, /*internal=*/false);
10130 
10131  // Let's see if the inserted type we are looking at was
10132  // reported as deleted as well.
10133  //
10134  // If it's been deleted and a different version of it has
10135  // now been added, it means it's been *changed*. In that
10136  // case we'll compute the diff of that change and store it
10137  // in the map of changed unreachable types.
10138  //
10139  // Otherwise, it means the type's been added so we'll add
10140  // it to the set of added unreachable types.
10141 
10142  string_type_base_sptr_map::const_iterator j =
10143  deleted_unreachable_types_.find(repr);
10144  if (j != deleted_unreachable_types_.end())
10145  {
10146  // So there was another type of the same pretty
10147  // representation which was reported as deleted.
10148  // Let's see if they are different or not ...
10149  decl_base_sptr old_type = is_decl(j->second);
10150  decl_base_sptr new_type = is_decl(t);
10151  if (old_type != new_type)
10152  {
10153  // The previously added type is different from this
10154  // one that is added. That means the initial type
10155  // was changed. Let's compute its diff and store it
10156  // as a changed type.
10157  diff_sptr d = compute_diff(old_type, new_type, ctxt);
10158  ABG_ASSERT(d->has_changes());
10159  changed_unreachable_types_[repr]= d;
10160  }
10161 
10162  // In any case, the type was both deleted and added,
10163  // so we cannot have it marked as being deleted. So
10164  // let's remove it from the deleted types.
10165  deleted_unreachable_types_.erase(j);
10166  }
10167  else
10168  // The type wasn't previously reported as deleted, so
10169  // it's really added.
10170  added_unreachable_types_[repr] = t;
10171  }
10172  }
10173 
10174  // Handle anonymous enums that got changed. An anonymous enum is
10175  // designated by its flat textual representation. So a change to
10176  // any of its enumerators results in a different enum. That is
10177  // represented by a deletion of the previous anonymous enum, and
10178  // the addition of a new one. For the user however, it's the same
10179  // enum that changed. Let's massage this "added/removed" pattern
10180  // to show what the user expects, namely, a changed anonymous
10181  // enum.
10182  {
10183  std::set<type_base_sptr> deleted_anon_types;
10184  std::set<type_base_sptr> added_anon_types;
10185 
10186  for (auto entry : deleted_unreachable_types_)
10187  {
10188  if ((is_enum_type(entry.second)
10189  && is_enum_type(entry.second)->get_is_anonymous())
10190  || (is_class_or_union_type(entry.second)
10191  && is_class_or_union_type(entry.second)->get_is_anonymous()))
10192  deleted_anon_types.insert(entry.second);
10193  }
10194 
10195 
10196  for (auto entry : added_unreachable_types_)
10197  if ((is_enum_type(entry.second)
10198  && is_enum_type(entry.second)->get_is_anonymous())
10199  || (is_class_or_union_type(entry.second)
10200  && is_class_or_union_type(entry.second)->get_is_anonymous()))
10201  added_anon_types.insert(entry.second);
10202 
10203  string_type_base_sptr_map added_anon_types_to_erase;
10204  string_type_base_sptr_map removed_anon_types_to_erase;
10205  enum_type_decl_sptr deleted_enum;
10206  class_or_union_sptr deleted_class;
10207 
10208  // Look for deleted anonymous types (enums, unions, structs &
10209  // classes) which have enumerators or data members present in an
10210  // added anonymous type ...
10211  for (auto deleted: deleted_anon_types)
10212  {
10213  deleted_enum = is_enum_type(deleted);
10214  deleted_class = is_class_or_union_type(deleted);
10215 
10216  // For enums, look for any enumerator of 'deleted_enum' that
10217  // is also present in an added anonymous enum.
10218  if (deleted_enum)
10219  {
10220  for (auto enr : deleted_enum->get_enumerators())
10221  {
10222  bool this_enum_got_changed = false;
10223  for (auto t : added_anon_types)
10224  {
10225  if (enum_type_decl_sptr added_enum = is_enum_type(t))
10226  if (is_enumerator_present_in_enum(enr, *added_enum))
10227  {
10228  // So the enumerator 'enr' from the
10229  // 'deleted_enum' enum is also present in the
10230  // 'added_enum' enum so we assume that
10231  // 'deleted_enum' and 'added_enum' are the same
10232  // enum that got changed. Let's represent it
10233  // using a diff node.
10234  diff_sptr d = compute_diff(deleted_enum,
10235  added_enum, ctxt);
10236  ABG_ASSERT(d->has_changes());
10237  string repr =
10239  /*internal=*/false);
10240  changed_unreachable_types_[repr]= d;
10241  this_enum_got_changed = true;
10242  string r1 =
10244  /*internal=*/false);
10245  string r2 =
10247  /*internal=*/false);
10248  removed_anon_types_to_erase[r1] = deleted_enum;
10249  added_anon_types_to_erase[r2] = added_enum;
10250  break;
10251  }
10252  }
10253  if (this_enum_got_changed)
10254  break;
10255  }
10256  }
10257  else if (deleted_class)
10258  {
10259  // For unions, structs & classes, look for any data
10260  // member of 'deleted_class' that is also present in an
10261  // added anonymous class.
10262  for (auto dm : deleted_class->get_data_members())
10263  {
10264  bool this_class_got_changed = false;
10265  for (auto klass : added_anon_types)
10266  {
10267  if (class_or_union_sptr added_class =
10268  is_class_or_union_type(klass))
10269  if (class_or_union_types_of_same_kind(deleted_class,
10270  added_class)
10271  && lookup_data_member(added_class, dm))
10272  {
10273  // So the data member 'dm' from the
10274  // 'deleted_class' class is also present in
10275  // the 'added_class' class so we assume that
10276  // 'deleted_class' and 'added_class' are the
10277  // same anonymous class that got changed.
10278  // Let's represent it using a diff node.
10279  diff_sptr d = compute_diff(is_type(deleted_class),
10280  is_type(added_class),
10281  ctxt);
10282  ABG_ASSERT(d->has_changes());
10283  string repr =
10285  /*internal=*/false);
10286  changed_unreachable_types_[repr]= d;
10287  this_class_got_changed = true;
10288  string r1 =
10290  /*internal=*/false);
10291  string r2 =
10293  /*internal=*/false);
10294  removed_anon_types_to_erase[r1] = deleted_class;
10295  added_anon_types_to_erase[r2] = added_class;
10296  break;
10297  }
10298  }
10299  if (this_class_got_changed)
10300  break;
10301  }
10302  }
10303  }
10304 
10305  // Now remove the added/removed anonymous types from their maps,
10306  // as they are now represented as a changed type, not an added
10307  // and removed anonymous type.
10308  for (auto entry : added_anon_types_to_erase)
10309  added_unreachable_types_.erase(entry.first);
10310 
10311  for (auto entry : removed_anon_types_to_erase)
10312  deleted_unreachable_types_.erase(entry.first);
10313  }
10314  }
10315 }
10316 
10317 /// Test if a change reports about a given @ref function_decl that is
10318 /// changed in a certain way is suppressed by a given suppression
10319 /// specifiation
10320 ///
10321 /// @param fn the @ref function_decl to consider.
10322 ///
10323 /// @param suppr the suppression specification to consider.
10324 ///
10325 /// @param k the kind of change that happened to @p fn.
10326 ///
10327 /// @param ctxt the context of the current diff.
10328 ///
10329 /// @return true iff the suppression specification @p suppr suppresses
10330 /// change reports about function @p fn, if that function changes in
10331 /// the way expressed by @p k.
10332 static bool
10333 function_is_suppressed(const function_decl* fn,
10334  const suppression_sptr suppr,
10336  const diff_context_sptr ctxt)
10337 {
10339  if (!fn_suppr)
10340  return false;
10341  return fn_suppr->suppresses_function(fn, k, ctxt);
10342 }
10343 
10344 /// Test if a change reports about a given @ref var_decl that is
10345 /// changed in a certain way is suppressed by a given suppression
10346 /// specifiation
10347 ///
10348 /// @param fn the @ref var_decl to consider.
10349 ///
10350 /// @param suppr the suppression specification to consider.
10351 ///
10352 /// @param k the kind of change that happened to @p fn.
10353 ///
10354 /// @param ctxt the context of the current diff.
10355 ///
10356 /// @return true iff the suppression specification @p suppr suppresses
10357 /// change reports about variable @p fn, if that variable changes in
10358 /// the way expressed by @p k.
10359 static bool
10360 variable_is_suppressed(const var_decl_sptr& var,
10361  const suppression_sptr suppr,
10363  const diff_context_sptr ctxt)
10364 {
10366  if (!var_suppr)
10367  return false;
10368  return var_suppr->suppresses_variable(var, k, ctxt);
10369 }
10370 
10371 /// Apply suppression specifications for this corpus diff to the set
10372 /// of added/removed functions/variables, as well as to types not
10373 /// reachable from global functions/variables.
10374 void
10376 {
10377  diff_context_sptr ctxt = get_context();
10378 
10379  const suppressions_type& suppressions = ctxt->suppressions();
10380  for (suppressions_type::const_iterator i = suppressions.begin();
10381  i != suppressions.end();
10382  ++i)
10383  {
10384  // Added/Deleted functions.
10386  {
10387  // Added functions
10388  for (string_function_ptr_map::const_iterator e = added_fns_.begin();
10389  e != added_fns_.end();
10390  ++e)
10391  if (function_is_suppressed(e->second, fn_suppr,
10393  ctxt))
10394  suppressed_added_fns_[e->first] = e->second;
10395 
10396  // Deleted functions.
10397  for (string_function_ptr_map::const_iterator e = deleted_fns_.begin();
10398  e != deleted_fns_.end();
10399  ++e)
10400  if (function_is_suppressed(e->second, fn_suppr,
10402  ctxt))
10403  suppressed_deleted_fns_[e->first] = e->second;
10404 
10405  // Added function symbols not referenced by any debug info
10406  for (string_elf_symbol_map::const_iterator e =
10407  added_unrefed_fn_syms_.begin();
10408  e != added_unrefed_fn_syms_.end();
10409  ++e)
10410  if (fn_suppr->suppresses_function_symbol(e->second,
10412  ctxt))
10413  suppressed_added_unrefed_fn_syms_[e->first] = e->second;
10414 
10415  // Removed function symbols not referenced by any debug info
10416  for (string_elf_symbol_map::const_iterator e =
10417  deleted_unrefed_fn_syms_.begin();
10418  e != deleted_unrefed_fn_syms_.end();
10419  ++e)
10420  if (fn_suppr->suppresses_function_symbol(e->second,
10422  ctxt))
10423  suppressed_deleted_unrefed_fn_syms_[e->first] = e->second;
10424  }
10425  // Added/Delete virtual member functions changes that might be
10426  // suppressed by a type_suppression that matches the enclosing
10427  // class of the virtual member function.
10428  else if (type_suppression_sptr type_suppr = is_type_suppression(*i))
10429  {
10430  // Added virtual functions
10431  for (string_function_ptr_map::const_iterator e = added_fns_.begin();
10432  e != added_fns_.end();
10433  ++e)
10434  if (is_member_function(e->second)
10435  && get_member_function_is_virtual(e->second))
10436  {
10437  const function_decl *f = e->second;
10438  class_decl_sptr c =
10439  is_class_type(is_method_type(f->get_type())->get_class_type());
10440  ABG_ASSERT(c);
10441  if (type_suppr->suppresses_type(c, ctxt))
10442  suppressed_added_fns_[e->first] = e->second;
10443  }
10444  // Deleted virtual functions
10445  for (string_function_ptr_map::const_iterator e = deleted_fns_.begin();
10446  e != deleted_fns_.end();
10447  ++e)
10448  if (is_member_function(e->second)
10449  && get_member_function_is_virtual(e->second))
10450  {
10451  const function_decl *f = e->second;
10452  class_decl_sptr c =
10453  is_class_type(is_method_type(f->get_type())->get_class_type());
10454  ABG_ASSERT(c);
10455  if (type_suppr->suppresses_type(c, ctxt))
10456  suppressed_deleted_fns_[e->first] = e->second;
10457  }
10458 
10459  // Apply this type suppression to deleted types
10460  // non-reachable from a public interface.
10461  for (string_type_base_sptr_map::const_iterator e =
10462  deleted_unreachable_types_.begin();
10463  e != deleted_unreachable_types_.end();
10464  ++e)
10465  if (type_suppr->suppresses_type(e->second, ctxt))
10466  suppressed_deleted_unreachable_types_[e->first] = e->second;
10467 
10468  // Apply this type suppression to added types
10469  // non-reachable from a public interface.
10470  for (string_type_base_sptr_map::const_iterator e =
10471  added_unreachable_types_.begin();
10472  e != added_unreachable_types_.end();
10473  ++e)
10474  if (type_suppr->suppresses_type(e->second, ctxt))
10475  suppressed_added_unreachable_types_[e->first] = e->second;
10476  }
10477  // Added/Deleted variables
10478  else if (variable_suppression_sptr var_suppr =
10480  {
10481  // Added variables
10482  for (string_var_ptr_map::const_iterator e = added_vars_.begin();
10483  e != added_vars_.end();
10484  ++e)
10485  if (variable_is_suppressed(e->second, var_suppr,
10487  ctxt))
10488  suppressed_added_vars_[e->first] = e->second;
10489 
10490  //Deleted variables
10491  for (string_var_ptr_map::const_iterator e = deleted_vars_.begin();
10492  e != deleted_vars_.end();
10493  ++e)
10494  if (variable_is_suppressed(e->second, var_suppr,
10496  ctxt))
10497  suppressed_deleted_vars_[e->first] = e->second;
10498 
10499  // Added variable symbols not referenced by any debug info
10500  for (string_elf_symbol_map::const_iterator e =
10501  added_unrefed_var_syms_.begin();
10502  e != added_unrefed_var_syms_.end();
10503  ++e)
10504  if (var_suppr->suppresses_variable_symbol(e->second,
10506  ctxt))
10507  suppressed_added_unrefed_var_syms_[e->first] = e->second;
10508 
10509  // Removed variable symbols not referenced by any debug info
10510  for (string_elf_symbol_map::const_iterator e =
10511  deleted_unrefed_var_syms_.begin();
10512  e != deleted_unrefed_var_syms_.end();
10513  ++e)
10514  if (var_suppr->suppresses_variable_symbol(e->second,
10516  ctxt))
10517  suppressed_deleted_unrefed_var_syms_[e->first] = e->second;
10518  }
10519  }
10520 }
10521 
10522 /// Test if the change reports for a given deleted function have
10523 /// been deleted.
10524 ///
10525 /// @param fn the function to consider.
10526 ///
10527 /// @return true iff the change reports for a give given deleted
10528 /// function have been deleted.
10529 bool
10531 {
10532  if (!fn)
10533  return false;
10534 
10535  string_function_ptr_map::const_iterator i =
10536  suppressed_deleted_fns_.find(fn->get_id());
10537 
10538  return (i != suppressed_deleted_fns_.end());
10539 }
10540 
10541 /// Test if an added type that is unreachable from public interface
10542 /// has been suppressed by a suppression specification.
10543 ///
10544 /// @param t the added unreachable type to be considered.
10545 ///
10546 /// @return true iff @p t has been suppressed by a suppression
10547 /// specification.
10548 bool
10550 {
10551  if (!t)
10552  return false;
10553 
10554  string repr = abigail::ir::get_pretty_representation(t, /*internal=*/false);
10555  string_type_base_sptr_map::const_iterator i =
10556  suppressed_added_unreachable_types_.find(repr);
10557  if (i == suppressed_added_unreachable_types_.end())
10558  return false;
10559 
10560  return true;
10561 }
10562 
10563 /// Test if a deleted type that is unreachable from public interface
10564 /// has been suppressed by a suppression specification.
10565 ///
10566 /// @param t the deleted unreachable type to be considered.
10567 ///
10568 /// @return true iff @p t has been suppressed by a suppression
10569 /// specification.
10570 bool
10572 {
10573  if (!t)
10574  return false;
10575 
10576  string repr = abigail::ir::get_pretty_representation(t, /*internal=*/false);
10577  string_type_base_sptr_map::const_iterator i =
10578  suppressed_deleted_unreachable_types_.find(repr);
10579  if (i == suppressed_deleted_unreachable_types_.end())
10580  return false;
10581 
10582  return true;
10583 }
10584 
10585 /// Test if the change reports for a give given added function has
10586 /// been deleted.
10587 ///
10588 /// @param fn the function to consider.
10589 ///
10590 /// @return true iff the change reports for a give given added
10591 /// function has been deleted.
10592 bool
10594 {
10595  if (!fn)
10596  return false;
10597 
10598  string_function_ptr_map::const_iterator i =
10599  suppressed_added_fns_.find(fn->get_id());
10600 
10601  return (i != suppressed_added_fns_.end());
10602 }
10603 
10604 /// Test if the change reports for a give given deleted variable has
10605 /// been deleted.
10606 ///
10607 /// @param var the variable to consider.
10608 ///
10609 /// @return true iff the change reports for a give given deleted
10610 /// variable has been deleted.
10611 bool
10613 {
10614  if (!var)
10615  return false;
10616 
10617  string_var_ptr_map::const_iterator i =
10618  suppressed_deleted_vars_.find(var->get_id());
10619 
10620  return (i != suppressed_deleted_vars_.end());
10621 }
10622 
10623 /// Test if the change reports for a given added variable have been
10624 /// suppressed.
10625 ///
10626 /// @param var the variable to consider.
10627 ///
10628 /// @return true iff the change reports for a given deleted
10629 /// variable has been deleted.
10630 bool
10632 {
10633  if (!var)
10634  return false;
10635 
10636  string_var_ptr_map::const_iterator i =
10637  suppressed_added_vars_.find(var->get_id());
10638 
10639  return (i != suppressed_added_vars_.end());
10640 }
10641 
10642 /// Test if the change reports for a given deleted function symbol
10643 /// (that is not referenced by any debug info) has been suppressed.
10644 ///
10645 /// @param var the function to consider.
10646 ///
10647 /// @return true iff the change reports for a given deleted function
10648 /// symbol has been suppressed.
10649 bool
10651 {
10652  if (!s)
10653  return false;
10654 
10655  string_elf_symbol_map::const_iterator i =
10656  suppressed_deleted_unrefed_fn_syms_.find(s->get_id_string());
10657 
10658  return (i != suppressed_deleted_unrefed_fn_syms_.end());
10659 }
10660 
10661 /// Test if the change reports for a given added function symbol
10662 /// (that is not referenced by any debug info) has been suppressed.
10663 ///
10664 /// @param var the function to consider.
10665 ///
10666 /// @return true iff the change reports for a given added function
10667 /// symbol has been suppressed.
10668 bool
10670 {
10671  if (!s)
10672  return false;
10673 
10674  string_elf_symbol_map::const_iterator i =
10675  suppressed_added_unrefed_fn_syms_.find(s->get_id_string());
10676 
10677  return (i != suppressed_added_unrefed_fn_syms_.end());
10678 }
10679 
10680 /// Test if the change reports for a given deleted variable symbol
10681 /// (that is not referenced by any debug info) has been suppressed.
10682 ///
10683 /// @param var the variable to consider.
10684 ///
10685 /// @return true iff the change reports for a given deleted variable
10686 /// symbol has been suppressed.
10687 bool
10689 {
10690  if (!s)
10691  return false;
10692 
10693  string_elf_symbol_map::const_iterator i =
10694  suppressed_deleted_unrefed_var_syms_.find(s->get_id_string());
10695 
10696  return (i != suppressed_deleted_unrefed_var_syms_.end());
10697 }
10698 
10699 /// Test if the change reports for a given added variable symbol
10700 /// (that is not referenced by any debug info) has been suppressed.
10701 ///
10702 /// @param var the variable to consider.
10703 ///
10704 /// @return true iff the change reports for a given added variable
10705 /// symbol has been suppressed.
10706 bool
10708 {
10709  if (!s)
10710  return false;
10711 
10712  string_elf_symbol_map::const_iterator i =
10713  suppressed_added_unrefed_var_syms_.find(s->get_id_string());
10714 
10715  return (i != suppressed_added_unrefed_var_syms_.end());
10716 }
10717 
10718 #ifdef do_count_diff_map_changes
10719 #undef do_count_diff_map_changes
10720 #endif
10721 #define do_count_diff_map_changes(diff_map, n_changes, n_filtered) \
10722  { \
10723  string_diff_ptr_map::const_iterator i; \
10724  for (i = diff_map.begin(); \
10725  i != diff_map.end(); \
10726  ++i) \
10727  { \
10728  if (const var_diff* d = is_var_diff(i->second)) \
10729  if (is_data_member(d->first_var())) \
10730  continue; \
10731  \
10732  if (i->second->has_local_changes()) \
10733  ++n_changes; \
10734  if (!i->second->get_canonical_diff()->to_be_reported()) \
10735  ++n_filtered; \
10736  } \
10737  }
10738 
10739 /// Count the number of leaf changes as well as the number of the
10740 /// changes that have been filtered out.
10741 ///
10742 /// @param num_changes out parameter. This is set to the total number
10743 /// of leaf changes.
10744 ///
10745 /// @param num_filtered out parameter. This is set to the number of
10746 /// leaf changes that have been filtered out.
10747 void
10748 corpus_diff::priv::count_leaf_changes(size_t &num_changes, size_t &num_filtered)
10749 {
10750  count_leaf_type_changes(num_changes, num_filtered);
10751 
10752  // Now count the non-type changes.
10753  do_count_diff_map_changes(leaf_diffs_.get_function_decl_diff_map(),
10754  num_changes, num_filtered);
10755  do_count_diff_map_changes(leaf_diffs_.get_var_decl_diff_map(),
10756  num_changes, num_filtered);
10757 }
10758 
10759 /// Count the number of leaf *type* changes as well as the number of
10760 /// the leaf type changes that have been filtered out.
10761 ///
10762 /// @param num_changes out parameter. This is set to the total number
10763 /// of leaf type changes.
10764 ///
10765 /// @param num_filtered out parameter. This is set to the number of
10766 /// leaf type changes that have been filtered out.
10767 void
10769  size_t &num_filtered)
10770 {
10771  do_count_diff_map_changes(leaf_diffs_.get_type_decl_diff_map(),
10772  num_changes, num_filtered);
10773  do_count_diff_map_changes(leaf_diffs_.get_enum_diff_map(),
10774  num_changes, num_filtered);
10775  do_count_diff_map_changes(leaf_diffs_.get_class_diff_map(),
10776  num_changes, num_filtered);
10777  do_count_diff_map_changes(leaf_diffs_.get_union_diff_map(),
10778  num_changes, num_filtered);
10779  do_count_diff_map_changes(leaf_diffs_.get_typedef_diff_map(),
10780  num_changes, num_filtered);
10781  do_count_diff_map_changes(leaf_diffs_.get_subrange_diff_map(),
10782  num_changes, num_filtered);
10783  do_count_diff_map_changes(leaf_diffs_.get_array_diff_map(),
10784  num_changes, num_filtered);
10785  do_count_diff_map_changes(leaf_diffs_.get_distinct_diff_map(),
10786  num_changes, num_filtered);
10787  do_count_diff_map_changes(leaf_diffs_.get_fn_parm_diff_map(),
10788  num_changes, num_filtered);
10789 }
10790 
10791 /// Count the number of types not reachable from the interface (i.e,
10792 /// not reachable from global functions or variables).
10793 ///
10794 /// @param num_added this is set to the number of added types not
10795 /// reachable from the interface.
10796 ///
10797 /// @param num_deleted this is set to the number of deleted types not
10798 /// reachable from the interface.
10799 ///
10800 /// @param num_changed this is set to the number of changed types not
10801 /// reachable from the interface.
10802 ///
10803 /// @param num_filtered_added this is set to the number of added types
10804 /// not reachable from the interface and that have been filtered out
10805 /// by suppression specifications.
10806 ///
10807 /// @param num_filtered_deleted this is set to the number of deleted
10808 /// types not reachable from the interface and that have been filtered
10809 /// out by suppression specifications.
10810 ///
10811 /// @param num_filtered_changed this is set to the number of changed
10812 /// types not reachable from the interface and that have been filtered
10813 /// out by suppression specifications.
10814 void
10816  size_t &num_deleted,
10817  size_t &num_changed,
10818  size_t &num_filtered_added,
10819  size_t &num_filtered_deleted,
10820  size_t &num_filtered_changed)
10821 {
10822  num_added = added_unreachable_types_.size();
10823  num_deleted = deleted_unreachable_types_.size();
10824  num_changed = changed_unreachable_types_.size();
10825  num_filtered_added = suppressed_added_unreachable_types_.size();
10826  num_filtered_deleted = suppressed_deleted_unreachable_types_.size();
10827 
10828  for (vector<diff_sptr>::const_iterator i =
10830  i != changed_unreachable_types_sorted().end();
10831  ++i)
10832  if (!(*i)->to_be_reported())
10833  ++num_filtered_changed;
10834 }
10835 
10836 /// Get the map of diff nodes representing changed unreachable types.
10837 ///
10838 /// @return the map of diff nodes representing changed unreachable
10839 /// types.
10840 const string_diff_sptr_map&
10842 {return changed_unreachable_types_;}
10843 
10844 /// Get the sorted vector of diff nodes representing changed
10845 /// unreachable types.
10846 ///
10847 /// Upon the first invocation of this method, if the vector is empty,
10848 /// this function gets the diff nodes representing changed
10849 /// unreachable, sort them, and return the sorted vector.
10850 ///
10851 /// @return the sorted vector of diff nodes representing changed
10852 /// unreachable types.
10853 const vector<diff_sptr>&
10855 {
10856 if (changed_unreachable_types_sorted_.empty())
10857  if (!changed_unreachable_types_.empty())
10858  sort_string_diff_sptr_map(changed_unreachable_types_,
10859  changed_unreachable_types_sorted_);
10860 
10861  return changed_unreachable_types_sorted_;
10862 }
10863 
10864 /// Compute the diff stats.
10865 ///
10866 /// To know the number of functions that got filtered out, this
10867 /// function applies the categorizing filters to the diff sub-trees of
10868 /// each function changes diff, prior to calculating the stats.
10869 ///
10870 /// @param num_removed the number of removed functions.
10871 ///
10872 /// @param num_added the number of added functions.
10873 ///
10874 /// @param num_changed the number of changed functions.
10875 ///
10876 /// @param num_filtered_out the number of changed functions that are
10877 /// got filtered out from the report
10878 void
10880 {
10881  stat.num_func_removed(deleted_fns_.size());
10882  stat.num_removed_func_filtered_out(suppressed_deleted_fns_.size());
10883  stat.num_func_added(added_fns_.size());
10884  stat.num_added_func_filtered_out(suppressed_added_fns_.size());
10885  stat.num_func_changed(changed_fns_map_.size());
10886 
10887  stat.num_vars_removed(deleted_vars_.size());
10888  stat.num_removed_vars_filtered_out(suppressed_deleted_vars_.size());
10889  stat.num_vars_added(added_vars_.size());
10890  stat.num_added_vars_filtered_out(suppressed_added_vars_.size());
10891  stat.num_vars_changed(changed_vars_map_.size());
10892 
10893  diff_context_sptr ctxt = get_context();
10894 
10896  if (ctxt->perform_change_categorization())
10897  {
10898  if (get_context()->do_log())
10899  {
10900  std::cerr << "in apply_filters_and_compute_diff_stats:"
10901  << "applying filters to "
10902  << changed_fns_.size()
10903  << " changed fns ...\n";
10904  t.start();
10905  }
10906  // Walk the changed function diff nodes to apply the categorization
10907  // filters.
10908  diff_sptr diff;
10909  for (function_decl_diff_sptrs_type::const_iterator i =
10910  changed_fns_.begin();
10911  i != changed_fns_.end();
10912  ++i)
10913  {
10914  diff_sptr diff = *i;
10915  ctxt->maybe_apply_filters(diff);
10916  }
10917 
10918  if (get_context()->do_log())
10919  {
10920  t.stop();
10921  std::cerr << "in apply_filters_and_compute_diff_stats:"
10922  << "filters to changed fn applied!:" << t << "\n";
10923 
10924  std::cerr << "in apply_filters_and_compute_diff_stats:"
10925  << "applying filters to "
10926  << sorted_changed_vars_.size()
10927  << " changed vars ...\n";
10928  t.start();
10929  }
10930 
10931  // Walk the changed variable diff nodes to apply the categorization
10932  // filters.
10933  for (var_diff_sptrs_type::const_iterator i = sorted_changed_vars_.begin();
10934  i != sorted_changed_vars_.end();
10935  ++i)
10936  {
10937  diff_sptr diff = *i;
10938  ctxt->maybe_apply_filters(diff);
10939  }
10940 
10941  if (get_context()->do_log())
10942  {
10943  t.stop();
10944  std::cerr << "in apply_filters_and_compute_diff_stats:"
10945  << "filters to changed vars applied!:" << t << "\n";
10946 
10947  std::cerr << "in apply_filters_and_compute_diff_stats:"
10948  << "applying filters to unreachable types ...\n";
10949  t.start();
10950  }
10951 
10952  // walk the changed unreachable types to apply categorization
10953  // filters
10954  for (auto& diff : changed_unreachable_types_sorted())
10955  ctxt->maybe_apply_filters(diff);
10956 
10957  for (auto& entry : changed_unreachable_types())
10958  ctxt->maybe_apply_filters(entry.second);
10959 
10960  if (get_context()->do_log())
10961  {
10962  t.stop();
10963  std::cerr << "in apply_filters_and_compute_diff_stats:"
10964  << "filters to unreachable types applied!:" << t << "\n";
10965 
10966  std::cerr << "in apply_filters_and_compute_diff_stats:"
10967  << "categorizing redundant changed sub nodes ...\n";
10968  t.start();
10969  }
10970 
10971  categorize_redundant_changed_sub_nodes();
10972 
10973  if (get_context()->do_log())
10974  {
10975  t.stop();
10976  std::cerr << "in apply_filters_and_compute_diff_stats:"
10977  << "redundant changed sub nodes categorized!:" << t << "\n";
10978 
10979  std::cerr << "in apply_filters_and_compute_diff_stats:"
10980  << "count changed fns ...\n";
10981  t.start();
10982  }
10983  }
10984 
10985  // Walk the changed function diff nodes to count the number of
10986  // filtered-out functions and the number of functions with virtual
10987  // offset changes.
10988  for (function_decl_diff_sptrs_type::const_iterator i =
10989  changed_fns_.begin();
10990  i != changed_fns_.end();
10991  ++i)
10992  {
10993  bool incompatible_change = false;
10994  if ((*i)->is_filtered_out())
10995  {
10997  (stat.num_changed_func_filtered_out() + 1);
10998 
10999  if ((*i)->has_local_changes())
11002  }
11003 
11004  // Now let's detect functions with incompatible changes.
11005  if (!(*i)->is_categorized_as_suppressed())
11006  {
11007  // Note that a filtered-out function diff (because of
11008  // redundancy) can still carry an incompatible change. In
11009  // that case, the diff will later be removed from the
11010  // account of filtered diff nodes.
11011  //
11012  // Also note that such a filtered-out function was *NOT*
11013  // suppressed by a user-provided suppression specification.
11014 
11016  {
11019  incompatible_change = true;
11020  }
11021 
11022  // Are any of the local changes of the function_diff harmful?
11023  // If yes, then set stat.num_func_with_local_harmful_changes()
11024  // and stat.num_var_with_local_harmful_changes().
11026  {
11029  incompatible_change = true;
11030  }
11031  }
11032 
11033  if ((*i)->has_local_changes())
11035  (stat.num_leaf_func_changes() + 1);
11036 
11037  if (incompatible_change)
11038  {
11039  incompatible_changed_fns_.push_back(*i);
11042 
11043  if ((*i)->has_local_changes())
11044  // The function is a leaf node.
11047 
11048  if ((*i)->is_filtered_out())
11049  {
11050  // If the incompatible change was filtered-out (possibly
11051  // b/c of redundancy) consider it as not being filtered
11052  // out anymore.
11054  (stat.num_changed_func_filtered_out() - 1);
11055 
11056  if ((*i)->has_local_changes())
11059  }
11060  }
11061  }
11062 
11063  if (get_context()->do_log())
11064  {
11065  t.stop();
11066  std::cerr << "in apply_filters_and_compute_diff_stats:"
11067  << "changed fn counted!:" << t << "\n";
11068 
11069  std::cerr << "in apply_filters_and_compute_diff_stats:"
11070  << "count changed vars ...\n";
11071  t.start();
11072  }
11073 
11074  // Similarly to function diff nodes above, walk the changed
11075  // variables diff nodes to count the number of filtered-out,
11076  // suppressed and incompatible variable diff nodes.
11077  for (var_diff_sptrs_type ::const_iterator i = sorted_changed_vars_.begin();
11078  i != sorted_changed_vars_.end();
11079  ++i)
11080  {
11081  bool incompatible_change = false;
11082  if ((*i)->is_filtered_out())
11083  {
11085  (stat.num_changed_vars_filtered_out() + 1);
11086 
11087  if ((*i)->has_local_changes())
11089  (stat.num_leaf_var_changes_filtered_out() + 1);
11090  }
11091 
11092  if (!(*i)->is_categorized_as_suppressed())
11093  {
11095  {
11096  incompatible_change = true;
11097  incompatible_changed_vars_.push_back(*i);
11101  (stat.num_var_with_incompatible_changes() + 1);
11102 
11103  if ((*i)->is_filtered_out())
11104  {
11106  (stat.num_changed_vars_filtered_out() - 1);
11107 
11108  if ((*i)->has_local_changes())
11110  (stat.num_leaf_var_changes_filtered_out() - 1);
11111  }
11112  }
11113  }
11114 
11115  if ((*i)->has_local_changes())
11116  {
11118  (stat.num_leaf_var_changes() + 1);
11119 
11120  if (incompatible_change)
11123  }
11124  }
11125 
11126  if (get_context()->do_log())
11127  {
11128  t.stop();
11129  std::cerr << "in apply_filters_and_compute_diff_stats:"
11130  << "changed vars counted!:" << t << "\n";
11131 
11132  std::cerr << "in apply_filters_and_compute_diff_stats:"
11133  << "count leaf changed types ...\n";
11134  t.start();
11135  }
11136 
11137  stat.num_func_syms_added(added_unrefed_fn_syms_.size());
11138  stat.num_added_func_syms_filtered_out(suppressed_added_unrefed_fn_syms_.size());
11139  stat.num_func_syms_removed(deleted_unrefed_fn_syms_.size());
11140  stat.num_removed_func_syms_filtered_out(suppressed_deleted_unrefed_fn_syms_.size());
11141  stat.num_var_syms_added(added_unrefed_var_syms_.size());
11142  stat.num_added_var_syms_filtered_out(suppressed_added_unrefed_var_syms_.size());
11143  stat.num_var_syms_removed(deleted_unrefed_var_syms_.size());
11144  stat.num_removed_var_syms_filtered_out(suppressed_deleted_unrefed_var_syms_.size());
11145 
11146  // Walk the general leaf type diff nodes to count them
11147  {
11148  size_t num_type_changes = 0, num_type_filtered = 0;
11149  count_leaf_type_changes(num_type_changes, num_type_filtered);
11150 
11151  stat.num_leaf_type_changes(num_type_changes);
11152  stat.num_leaf_type_changes_filtered_out(num_type_filtered);
11153  }
11154 
11155  if (get_context()->do_log())
11156  {
11157  t.stop();
11158  std::cerr << "in apply_filters_and_compute_diff_stats:"
11159  << "changed leaf types counted!:" << t << "\n";
11160 
11161  std::cerr << "in apply_filters_and_compute_diff_stats:"
11162  << "count leaf changed artefacts ...\n";
11163  t.start();
11164  }
11165 
11166  // Walk the general leaf artefacts diff nodes to count them
11167  {
11168  size_t num_changes = 0, num_filtered = 0;
11169  count_leaf_changes(num_changes, num_filtered);
11170 
11171  stat.num_leaf_changes(num_changes);
11172  stat.num_leaf_changes_filtered_out(num_filtered);
11173  }
11174 
11175  if (get_context()->do_log())
11176  {
11177  t.stop();
11178  std::cerr << "in apply_filters_and_compute_diff_stats:"
11179  << "changed leaf artefacts counted!:" << t << "\n";
11180 
11181  std::cerr << "in apply_filters_and_compute_diff_stats:"
11182  << "count unreachable types ...\n";
11183  t.start();
11184  }
11185 
11186  // Walk the unreachable types to count them
11187  {
11188  size_t num_added_unreachable_types = 0,
11189  num_changed_unreachable_types = 0,
11190  num_deleted_unreachable_types = 0,
11191  num_added_unreachable_types_filtered = 0,
11192  num_changed_unreachable_types_filtered = 0,
11193  num_deleted_unreachable_types_filtered = 0;
11194 
11195  count_unreachable_types(num_added_unreachable_types,
11196  num_deleted_unreachable_types,
11197  num_changed_unreachable_types,
11198  num_added_unreachable_types_filtered,
11199  num_deleted_unreachable_types_filtered,
11200  num_changed_unreachable_types_filtered);
11201 
11202  if (get_context()->do_log())
11203  {
11204  t.stop();
11205  std::cerr << "in apply_filters_and_compute_diff_stats:"
11206  << "unreachable types counted!:" << t << "\n";
11207  }
11208 
11209  stat.num_added_unreachable_types(num_added_unreachable_types);
11210  stat.num_removed_unreachable_types(num_deleted_unreachable_types);
11211  stat.num_changed_unreachable_types(num_changed_unreachable_types);
11213  (num_added_unreachable_types_filtered);
11215  (num_deleted_unreachable_types_filtered);
11217  (num_changed_unreachable_types_filtered);
11218  }
11219 }
11220 
11221 /// Emit the summary of the functions & variables that got
11222 /// removed/changed/added.
11223 ///
11224 /// TODO: This should be handled by the reporters, just like what is
11225 /// done for reporter_base::diff_to_be_reported.
11226 ///
11227 /// @param out the output stream to emit the stats to.
11228 ///
11229 /// @param indent the indentation string to use in the summary.
11230 void
11232  ostream& out,
11233  const string& indent)
11234 {
11235  /// Report added/removed/changed functions.
11236  size_t net_num_leaf_changes =
11237  s.net_num_func_removed() +
11238  s.net_num_func_added() +
11240  s.net_num_vars_removed() +
11241  s.net_num_vars_added() +
11248 
11249  if (!sonames_equal_)
11250  out << indent << "ELF SONAME changed\n";
11251 
11252  if (!architectures_equal_)
11253  out << indent << "ELF architecture changed\n";
11254 
11255  diff_context_sptr ctxt = get_context();
11256 
11257  if (ctxt->show_leaf_changes_only())
11258  {
11259  out << "Leaf changes summary: ";
11260  out << net_num_leaf_changes << " artifact";
11261  if (net_num_leaf_changes > 1)
11262  out << "s";
11263  out << " changed";
11264 
11265  if (size_t num_filtered = s.num_leaf_changes_filtered_out())
11266  out << " (" << num_filtered << " filtered out)";
11267  out << "\n";
11268 
11269  out << indent << "Changed leaf types summary: "
11272  out << " (" << s.num_leaf_type_changes_filtered_out()
11273  << " filtered out)";
11274  out << " leaf type";
11275  if (s.num_leaf_type_changes() > 1)
11276  out << "s";
11277  out << " changed\n";
11278 
11279  // function changes summary
11280  out << indent << "Removed/Changed/Added functions summary: ";
11281  out << s.net_num_func_removed() << " Removed";
11283  out << " ("
11285  << " filtered out)";
11286  out << ", ";
11287 
11288  out << s.net_num_leaf_func_changes() << " Changed";
11290  out << " ("
11292  << " filtered out)";
11293  out << ", ";
11294 
11295  out << s.net_num_func_added()<< " Added ";
11296  if (s.net_num_func_added() <= 1)
11297  out << "function";
11298  else
11299  out << "functions";
11301  out << " (" << s.num_added_func_filtered_out() << " filtered out)";
11302  out << "\n";
11303 
11304  // variables changes summary
11305  out << indent << "Removed/Changed/Added variables summary: ";
11306  out << s.net_num_vars_removed() << " Removed";
11308  out << " (" << s.num_removed_vars_filtered_out()
11309  << " filtered out)";
11310  out << ", ";
11311 
11312  out << s.net_num_leaf_var_changes() << " Changed";
11314  out << " ("
11316  << " filtered out)";
11317  out << ", ";
11318 
11319  out << s.net_num_vars_added() << " Added ";
11320  if (s.net_num_vars_added() <= 1)
11321  out << "variable";
11322  else
11323  out << "variables";
11325  out << " (" << s.num_added_vars_filtered_out()
11326  << " filtered out)";
11327  out << "\n";
11328  }
11329  else // if (ctxt->show_leaf_changes_only())
11330  {
11331  size_t total_nb_function_changes = s.num_func_removed()
11332  + s.num_func_changed() + s.num_func_added();
11333 
11334  // function changes summary
11335  out << indent << "Functions changes summary: ";
11336  out << s.net_num_func_removed() << " Removed";
11338  out << " ("
11340  << " filtered out)";
11341  out << ", ";
11342 
11343  out << s.net_num_func_changed() << " Changed";
11345  out << " (" << s.num_changed_func_filtered_out() << " filtered out)";
11346  out << ", ";
11347 
11348  out << s.net_num_func_added() << " Added";
11350  out << " (" << s.num_added_func_filtered_out() << " filtered out)";
11351  if (total_nb_function_changes <= 1)
11352  out << " function";
11353  else
11354  out << " functions";
11355  out << "\n";
11356 
11357  // variables changes summary
11358  size_t total_nb_variable_changes = s.num_vars_removed()
11359  + s.num_vars_changed() + s.num_vars_added();
11360 
11361  out << indent << "Variables changes summary: ";
11362  out << s.net_num_vars_removed() << " Removed";
11364  out << " (" << s.num_removed_vars_filtered_out()
11365  << " filtered out)";
11366  out << ", ";
11367 
11368  out << s.num_vars_changed() - s.num_changed_vars_filtered_out() << " Changed";
11370  out << " (" << s.num_changed_vars_filtered_out() << " filtered out)";
11371  out << ", ";
11372 
11373  out << s.net_num_vars_added() << " Added";
11375  out << " (" << s.num_added_vars_filtered_out()
11376  << " filtered out)";
11377  if (total_nb_variable_changes <= 1)
11378  out << " variable";
11379  else
11380  out << " variables";
11381  out << "\n";
11382  }
11383 
11384  // Show statistics about types not reachable from global
11385  // functions/variables.
11386  if (ctxt->show_unreachable_types())
11387  {
11388  size_t total_nb_unreachable_type_changes =
11392 
11393  // Show summary of unreachable types
11394  out << indent << "Unreachable types summary: "
11396  << " removed";
11399  << " filtered out)";
11400  out << ", ";
11401 
11403  << " changed";
11406  << " filtered out)";
11407  out << ", ";
11408 
11410  << " added";
11412  out << " (" << s.num_added_unreachable_types_filtered_out()
11413  << " filtered out)";
11414  if (total_nb_unreachable_type_changes <= 1)
11415  out << " type";
11416  else
11417  out << " types";
11418  out << "\n";
11419  }
11420 
11421  if (ctxt->show_symbols_unreferenced_by_debug_info()
11422  && (s.num_func_syms_removed()
11423  || s.num_func_syms_added()
11424  || s.num_var_syms_removed()
11425  || s.num_var_syms_added()))
11426  {
11427  // function symbols changes summary.
11428 
11429  if (!ctxt->show_added_symbols_unreferenced_by_debug_info()
11430  && s.num_func_syms_removed() == 0
11431  && s.num_func_syms_added() != 0)
11432  // If the only unreferenced function symbol change is function
11433  // syms that got added, but we were forbidden to show function
11434  // syms being added, do nothing.
11435  ;
11436  else
11437  {
11438  out << indent
11439  << "Function symbols changes summary: "
11440  << s.net_num_removed_func_syms() << " Removed";
11442  out << " (" << s.num_removed_func_syms_filtered_out()
11443  << " filtered out)";
11444  out << ", ";
11445  out << s.net_num_added_func_syms() << " Added";
11447  out << " (" << s.num_added_func_syms_filtered_out()
11448  << " filtered out)";
11449  out << " function symbol";
11450  if (s.num_func_syms_added() + s.num_func_syms_removed() > 1)
11451  out << "s";
11452  out << " not referenced by debug info\n";
11453  }
11454 
11455  // variable symbol changes summary.
11456 
11457  if (!ctxt->show_added_symbols_unreferenced_by_debug_info()
11458  && s.num_var_syms_removed() == 0
11459  && s.num_var_syms_added() != 0)
11460  // If the only unreferenced variable symbol change is variable
11461  // syms that got added, but we were forbidden to show variable
11462  // syms being added, do nothing.
11463  ;
11464  else
11465  {
11466  out << indent
11467  << "Variable symbols changes summary: "
11468  << s.net_num_removed_var_syms() << " Removed";
11470  out << " (" << s.num_removed_var_syms_filtered_out()
11471  << " filtered out)";
11472  out << ", ";
11473  out << s.net_num_added_var_syms() << " Added";
11475  out << " (" << s.num_added_var_syms_filtered_out()
11476  << " filtered out)";
11477  out << " variable symbol";
11478  if (s.num_var_syms_added() + s.num_var_syms_removed() > 1)
11479  out << "s";
11480  out << " not referenced by debug info\n";
11481  }
11482  }
11483 }
11484 
11485 /// Walk the changed functions and variables diff nodes to categorize
11486 /// redundant nodes.
11487 void
11489 {
11490  diff_sptr diff;
11491 
11492  diff_context_sptr ctxt = get_context();
11493 
11494  ctxt->forget_visited_diffs();
11495  for (function_decl_diff_sptrs_type::const_iterator i =
11496  changed_fns_.begin();
11497  i!= changed_fns_.end();
11498  ++i)
11499  {
11500  diff = *i;
11501  categorize_redundancy(diff);
11502  }
11503 
11504  for (var_diff_sptrs_type::const_iterator i = sorted_changed_vars_.begin();
11505  i!= sorted_changed_vars_.end();
11506  ++i)
11507  {
11508  diff_sptr diff = *i;
11509  categorize_redundancy(diff);
11510  }
11511 
11512  for (diff_sptrs_type::const_iterator i =
11515  ++i)
11516  {
11517  diff_sptr diff = *i;
11518  categorize_redundancy(diff);
11519  }
11520 }
11521 
11522 /// Walk the changed functions and variables diff nodes and clear the
11523 /// redundancy categorization they might carry.
11524 void
11526 {
11527  diff_sptr diff;
11528  for (function_decl_diff_sptrs_type::const_iterator i = changed_fns_.begin();
11529  i!= changed_fns_.end();
11530  ++i)
11531  {
11532  diff = *i;
11534  }
11535 
11536  for (var_diff_sptrs_type::const_iterator i = sorted_changed_vars_.begin();
11537  i!= sorted_changed_vars_.end();
11538  ++i)
11539  {
11540  diff = *i;
11542  }
11543 }
11544 
11545 /// If the user asked to dump the diff tree node (for changed
11546 /// variables and functions) on the error output stream, then just do
11547 /// that.
11548 ///
11549 /// This function is used for debugging purposes.
11550 void
11552 {
11553  diff_context_sptr ctxt = get_context();
11554 
11555  if (!ctxt->dump_diff_tree()
11556  || ctxt->error_output_stream() == 0)
11557  return;
11558 
11559  if (!changed_fns_.empty())
11560  {
11561  *ctxt->error_output_stream() << "changed functions diff tree: \n\n";
11562  for (function_decl_diff_sptrs_type::const_iterator i =
11563  changed_fns_.begin();
11564  i != changed_fns_.end();
11565  ++i)
11566  {
11567  diff_sptr d = *i;
11568  print_diff_tree(d, *ctxt->error_output_stream());
11569  }
11570  }
11571 
11572  if (!sorted_changed_vars_.empty())
11573  {
11574  *ctxt->error_output_stream() << "\nchanged variables diff tree: \n\n";
11575  for (var_diff_sptrs_type::const_iterator i =
11576  sorted_changed_vars_.begin();
11577  i != sorted_changed_vars_.end();
11578  ++i)
11579  {
11580  diff_sptr d = *i;
11581  print_diff_tree(d, *ctxt->error_output_stream());
11582  }
11583  }
11584 
11585  if (!changed_unreachable_types_sorted().empty())
11586  {
11587  *ctxt->error_output_stream() << "\nchanged unreachable "
11588  "types diff tree: \n\n";
11589  for (vector<diff_sptr>::const_iterator i =
11591  i != changed_unreachable_types_sorted().end();
11592  ++i)
11593  {
11594  diff_sptr d = *i;
11595  print_diff_tree(d, *ctxt->error_output_stream());
11596  }
11597  }
11598 }
11599 
11600 /// Populate the vector of children node of the @ref corpus_diff type.
11601 ///
11602 /// The children node can then later be retrieved using
11603 /// corpus_diff::children_node().
11604 void
11606 {
11607  for (function_decl_diff_sptrs_type::const_iterator i =
11608  changed_functions_sorted().begin();
11609  i != changed_functions_sorted().end();
11610  ++i)
11611  if (diff_sptr d = *i)
11612  append_child_node(d);
11613 }
11614 
11615 /// Constructor for @ref corpus_diff.
11616 ///
11617 /// @param first the first corpus of the diff.
11618 ///
11619 /// @param second the second corpus of the diff.
11620 ///
11621 /// @param ctxt the diff context to use. Note that this context
11622 /// object must stay alive at least during the life time of the
11623 /// current instance of @ref corpus_diff. Otherwise memory corruption
11624 /// issues occur.
11625 corpus_diff::corpus_diff(corpus_sptr first,
11626  corpus_sptr second,
11627  diff_context_sptr ctxt)
11628  : priv_(new priv(first, second, ctxt))
11629 {}
11630 
11631 corpus_diff::~corpus_diff() = default;
11632 
11633 /// Finish building the current instance of @ref corpus_diff.
11634 void
11636 {
11637  if (priv_->finished_)
11638  return;
11640  priv_->finished_ = true;
11641 }
11642 
11643 /// Test if logging was requested.
11644 ///
11645 /// @return true iff logging was requested.
11646 bool
11648 {return context()->do_log();}
11649 
11650 /// Request logging, or not.
11651 ///
11652 /// @param f true iff logging is requested.
11653 void
11655 {context()->do_log(f);}
11656 
11657 /// @return the first corpus of the diff.
11658 corpus_sptr
11660 {return priv_->first_;}
11661 
11662 /// @return the second corpus of the diff.
11663 corpus_sptr
11665 {return priv_->second_;}
11666 
11667 /// @return the children nodes of the current instance of corpus_diff.
11668 const vector<diff*>&
11670 {return priv_->children_;}
11671 
11672 /// Append a new child node to the vector of children nodes for the
11673 /// current instance of @ref corpus_diff node.
11674 ///
11675 /// Note that the vector of children nodes for the current instance of
11676 /// @ref corpus_diff node must remain sorted, using
11677 /// diff_less_than_functor.
11678 ///
11679 /// @param d the new child node. Note that the life time of the
11680 /// object held by @p d will thus equal the life time of the current
11681 /// instance of @ref corpus_diff.
11682 void
11684 {
11685  ABG_ASSERT(d);
11686 
11688  bool inserted = false;
11689  for (vector<diff*>::iterator i = priv_->children_.begin();
11690  i != priv_->children_.end();
11691  ++i)
11692  // Look for the point where to insert the diff child node.
11693  if (!is_less_than(d.get(), *i))
11694  {
11695  context()->keep_diff_alive(d);
11696  priv_->children_.insert(i, d.get());
11697  // As we have just inserted 'd' into the vector, the iterator
11698  // 'i' is invalidated. We must *NOT* use it anymore.
11699  inserted = true;
11700  break;
11701  }
11702 
11703  if (!inserted)
11704  {
11705  context()->keep_diff_alive(d);
11706  // We didn't insert anything to the vector, presumably b/c it was
11707  // empty or had one element that was "less than" 'd'. We can thus
11708  // just append 'd' to the end of the vector.
11709  priv_->children_.push_back(d.get());
11710  }
11711 }
11712 
11713 /// Test if the soname of the underlying corpus has changed.
11714 ///
11715 /// @return true iff the soname has changed.
11716 bool
11718 {return !priv_->sonames_equal_;}
11719 
11720 /// Test if the architecture of the underlying corpus has changed.
11721 ///
11722 /// @return true iff the architecture has changed.
11723 bool
11725 {return !priv_->architectures_equal_;}
11726 
11727 /// Getter for the deleted functions of the diff.
11728 ///
11729 /// @return the the deleted functions of the diff.
11732 {return priv_->deleted_fns_;}
11733 
11734 /// Getter for the added functions of the diff.
11735 ///
11736 /// @return the added functions of the diff.
11739 {return priv_->added_fns_;}
11740 
11741 /// Getter for the functions which signature didn't change, but which
11742 /// do have some indirect changes in their parms.
11743 ///
11744 /// @return a non-sorted map of functions which signature didn't
11745 /// change, but which do have some indirect changes in their parms.
11746 /// The key of the map is a unique identifier for the function; it's
11747 /// usually made of the name and version of the underlying ELF symbol
11748 /// of the function for corpora that were built from ELF files.
11751 {return priv_->changed_fns_map_;}
11752 
11753 /// Getter for a sorted vector of functions which signature didn't
11754 /// change, but which do have some indirect changes in their parms.
11755 ///
11756 /// @return a sorted vector of functions which signature didn't
11757 /// change, but which do have some indirect changes in their parms.
11760 {return priv_->changed_fns_;}
11761 
11762 /// Getter of the set of diff nodes representing incompatibly changed
11763 /// functions
11764 ///
11765 /// @return the set of diff nodes representing incompatibly changed
11766 /// functions
11769 {return priv_->incompatible_changed_fns_;}
11770 
11771 /// Getter of the set of diff nodes representing incompatibly changed
11772 /// functions
11773 ///
11774 /// @return the set of diff nodes representing incompatibly changed
11775 /// functions
11778 {return priv_->incompatible_changed_fns_;}
11779 
11780 /// Getter for the variables that got deleted from the first subject
11781 /// of the diff.
11782 ///
11783 /// @return the map of deleted variable.
11784 const string_var_ptr_map&
11786 {return priv_->deleted_vars_;}
11787 
11788 /// Getter for the added variables of the diff.
11789 ///
11790 /// @return the map of added variable.
11791 const string_var_ptr_map&
11793 {return priv_->added_vars_;}
11794 
11795 /// Getter for the non-sorted map of variables which signature didn't
11796 /// change but which do have some indirect changes in some sub-types.
11797 ///
11798 /// @return the non-sorted map of changed variables.
11801 {return priv_->changed_vars_map_;}
11802 
11803 /// Getter for the sorted vector of variables which signature didn't
11804 /// change but which do have some indirect changes in some sub-types.
11805 ///
11806 /// @return a sorted vector of changed variables.
11807 const var_diff_sptrs_type&
11809 {return priv_->sorted_changed_vars_;}
11810 
11811 /// Getter of the set of diff nodes representing incompatibly changed
11812 /// global variables.
11813 ///
11814 /// @return the set of diff nodes representing incompatibly changed
11815 /// global variables.
11816 const var_diff_sptrs_type&
11818 {return priv_->incompatible_changed_vars_;}
11819 
11820 /// Getter of the set of diff nodes representing incompatibly changed
11821 /// global variables.
11822 ///
11823 /// @return the set of diff nodes representing incompatibly changed
11824 /// global variables.
11827 {return priv_->incompatible_changed_vars_;}
11828 
11829 /// Getter for function symbols not referenced by any debug info and
11830 /// that got deleted.
11831 ///
11832 /// @return a map of elf function symbols not referenced by any debug
11833 /// info and that got deleted.
11834 const string_elf_symbol_map&
11836 {return priv_->deleted_unrefed_fn_syms_;}
11837 
11838 /// Getter for function symbols not referenced by any debug info and
11839 /// that got added.
11840 ///
11841 /// @return a map of elf function symbols not referenced by any debug
11842 /// info and that got added.
11843 const string_elf_symbol_map&
11845 {return priv_->added_unrefed_fn_syms_;}
11846 
11847 /// Getter for variable symbols not referenced by any debug info and
11848 /// that got deleted.
11849 ///
11850 /// @return a map of elf variable symbols not referenced by any debug
11851 /// info and that got deleted.
11852 const string_elf_symbol_map&
11854 {return priv_->deleted_unrefed_var_syms_;}
11855 
11856 /// Getter for variable symbols not referenced by any debug info and
11857 /// that got added.
11858 ///
11859 /// @return a map of elf variable symbols not referenced by any debug
11860 /// info and that got added.
11861 const string_elf_symbol_map&
11863 {return priv_->added_unrefed_var_syms_;}
11864 
11865 /// Getter for a map of deleted types that are not reachable from
11866 /// global functions/variables.
11867 ///
11868 /// @return a map that associates pretty representation of deleted
11869 /// unreachable types and said types.
11872 {return priv_->deleted_unreachable_types_;}
11873 
11874 /// Getter of a sorted vector of deleted types that are not reachable
11875 /// from global functions/variables.
11876 ///
11877 /// @return a sorted vector of deleted types that are not reachable
11878 /// from global functions/variables. The types are lexicographically
11879 /// sorted by considering their pretty representation.
11880 const vector<type_base_sptr>&
11882 {
11883  if (priv_->deleted_unreachable_types_sorted_.empty())
11884  if (!priv_->deleted_unreachable_types_.empty())
11885  sort_string_type_base_sptr_map(priv_->deleted_unreachable_types_,
11886  priv_->deleted_unreachable_types_sorted_);
11887 
11888  return priv_->deleted_unreachable_types_sorted_;
11889 }
11890 
11891 /// Getter for a map of added types that are not reachable from global
11892 /// functions/variables.
11893 ///
11894 /// @return a map that associates pretty representation of added
11895 /// unreachable types and said types.
11898 {return priv_->added_unreachable_types_;}
11899 
11900 /// Getter of a sorted vector of added types that are not reachable
11901 /// from global functions/variables.
11902 ///
11903 /// @return a sorted vector of added types that are not reachable from
11904 /// global functions/variables. The types are lexicographically
11905 /// sorted by considering their pretty representation.
11906 const vector<type_base_sptr>&
11908 {
11909  if (priv_->added_unreachable_types_sorted_.empty())
11910  if (!priv_->added_unreachable_types_.empty())
11911  sort_string_type_base_sptr_map(priv_->added_unreachable_types_,
11912  priv_->added_unreachable_types_sorted_);
11913 
11914  return priv_->added_unreachable_types_sorted_;
11915 }
11916 
11917 /// Getter for a map of changed types that are not reachable from
11918 /// global functions/variables.
11919 ///
11920 /// @return a map that associates pretty representation of changed
11921 /// unreachable types and said types.
11922 const string_diff_sptr_map&
11924 {return priv_->changed_unreachable_types_;}
11925 
11926 /// Getter of a sorted vector of changed types that are not reachable
11927 /// from global functions/variables.
11928 ///
11929 /// @return a sorted vector of changed types that are not reachable
11930 /// from global functions/variables. The diffs are lexicographically
11931 /// sorted by considering their pretty representation.
11932 const vector<diff_sptr>&
11934 {return priv_->changed_unreachable_types_sorted();}
11935 
11936 /// Getter of the diff context of this diff
11937 ///
11938 /// @return the diff context for this diff.
11939 const diff_context_sptr
11941 {return priv_->get_context();}
11942 
11943 /// @return the pretty representation for the current instance of @ref
11944 /// corpus_diff
11945 const string&
11947 {
11948  if (priv_->pretty_representation_.empty())
11949  {
11950  std::ostringstream o;
11951  o << "corpus_diff["
11952  << first_corpus()->get_path()
11953  << ", "
11954  << second_corpus()->get_path()
11955  << "]";
11956  priv_->pretty_representation_ = o.str();
11957  }
11958  return priv_->pretty_representation_;
11959 }
11960 /// Return true iff the current @ref corpus_diff node carries a
11961 /// change.
11962 ///
11963 /// @return true iff the current diff node carries a change.
11964 bool
11966 {
11967  return (soname_changed()
11969  || !(priv_->deleted_fns_.empty()
11970  && priv_->added_fns_.empty()
11971  && priv_->changed_fns_map_.empty()
11972  && priv_->deleted_vars_.empty()
11973  && priv_->added_vars_.empty()
11974  && priv_->changed_vars_map_.empty()
11975  && priv_->added_unrefed_fn_syms_.empty()
11976  && priv_->deleted_unrefed_fn_syms_.empty()
11977  && priv_->added_unrefed_var_syms_.empty()
11978  && priv_->deleted_unrefed_var_syms_.empty()
11979  && priv_->deleted_unreachable_types_.empty()
11980  && priv_->added_unreachable_types_.empty()
11981  && priv_->changed_unreachable_types_.empty()));
11982 }
11983 
11984 /// Test if the current instance of @ref corpus_diff carries changes
11985 /// that we are sure are incompatible. By incompatible change we mean
11986 /// a change that "breaks" the ABI of the corpus we are looking at.
11987 ///
11988 /// In concrete terms, this function considers the following changes
11989 /// as being ABI incompatible for sure:
11990 ///
11991 /// - a soname change
11992 /// - if exported functions or variables got removed
11993 ///
11994 /// Note that subtype changes *can* represent changes that break ABI
11995 /// too. But they also can be changes that are OK, ABI-wise.
11996 ///
11997 /// It's up to the user to provide suppression specifications to say
11998 /// explicitely which subtype change is OK. The remaining sub-type
11999 /// changes are then considered to be ABI incompatible. But to test
12000 /// if such ABI incompatible subtype changes are present you need to
12001 /// use the function @ref corpus_diff::has_net_subtype_changes()
12002 ///
12003 /// @return true iff the current instance of @ref corpus_diff carries
12004 /// changes that we are sure are ABI incompatible.
12005 bool
12007 {
12008  const diff_stats& stats = const_cast<corpus_diff*>(this)->
12010 
12012  (soname_changed()
12014  || stats.net_num_func_removed() != 0
12016  // If all reports about functions changes have been
12017  // suppressed, then even those about incompatible changes
12018  // don't matter anymore because the user willingly requested
12019  // to shut them down.
12020  && stats.net_num_func_changed() != 0)
12021  || stats.net_num_vars_removed() != 0
12023  && stats.net_num_vars_changed() != 0)
12024  || stats.net_num_removed_func_syms() != 0
12025  || stats.net_num_removed_var_syms() != 0
12026  || stats.net_num_removed_unreachable_types() != 0);
12027 
12028  // If stats.net_num_changed_unreachable_types() != 0 then walk the
12029  // corpus_diff::priv::changed_unreachable_types_, and see if there
12030  // is one that is harmful by bitwise and-ing their category with
12031  // abigail::comparison::get_default_harmful_categories_bitmap().
12032  if (!has_incompatible_changes
12034  {
12035  // The changed unreachable types can carry harmful changes.
12036  // Let's figure if they actually do.
12037 
12038  diff_context_sptr ctxt = context();
12039  for (auto &entry : priv_->changed_unreachable_types())
12040  {
12041  diff_sptr dif = entry.second;
12042 
12043  // Let's see if any of the categories of this diff node
12044  // belong to the "harmful" ones.
12045  if (dif->get_category() & get_default_harmful_categories_bitmap())
12046  {
12047  has_incompatible_changes |= true;
12048  break;
12049  }
12050  }
12051  }
12052 
12053  return has_incompatible_changes;
12054 }
12055 
12056 /// Test if the current instance of @ref corpus_diff carries subtype
12057 /// changes whose reports are not suppressed by any suppression
12058 /// specification. In effect, these are deemed incompatible ABI
12059 /// changes.
12060 ///
12061 /// @return true iff the the current instance of @ref corpus_diff
12062 /// carries subtype changes that are deemed incompatible ABI changes.
12063 bool
12065 {
12066  const diff_stats& stats = const_cast<corpus_diff*>(this)->
12068 
12069  return (stats.net_num_func_changed() != 0
12070  || stats.net_num_vars_changed() != 0
12071  || stats.net_num_removed_unreachable_types() != 0
12072  || stats.net_num_changed_unreachable_types() != 0);
12073 }
12074 
12075 /// Test if the current instance of @ref corpus_diff carries changes
12076 /// whose reports are not suppressed by any suppression specification.
12077 /// In effect, these are deemed incompatible ABI changes.
12078 ///
12079 /// @return true iff the the current instance of @ref corpus_diff
12080 /// carries subtype changes that are deemed incompatible ABI changes.
12081 bool
12083 {return context()->get_reporter()->diff_has_net_changes(this);}
12084 
12085 /// Apply the different filters that are registered to be applied to
12086 /// the diff tree; that includes the categorization filters. Also,
12087 /// apply the suppression interpretation filters.
12088 ///
12089 /// After the filters are applied, this function calculates some
12090 /// statistics about the changes carried by the current instance of
12091 /// @ref corpus_diff. These statistics are represented by an instance
12092 /// of @ref corpus_diff::diff_stats.
12093 ///
12094 /// This member function is called by the reporting function
12095 /// corpus_diff::report().
12096 ///
12097 /// Note that for a given instance of corpus_diff, this function
12098 /// applies the filters and suppressions only the first time it is
12099 /// invoked. Subsequent invocations just return the instance of
12100 /// corpus_diff::diff_stats that was cached after the first
12101 /// invocation.
12102 ///
12103 /// @return a reference to the statistics about the changes carried by
12104 /// the current instance of @ref corpus_diff.
12107 {
12108  if (priv_->diff_stats_)
12109  return *priv_->diff_stats_;
12110 
12112  if (do_log())
12113  {
12114  std::cerr << "Applying suppressions ...\n";
12115  t.start();
12116  }
12117 
12118  apply_suppressions(this);
12119 
12120  if (do_log())
12121  {
12122  t.stop();
12123  std::cerr << "suppressions applied!:" << t << "\n";
12124  }
12125 
12126  priv_->diff_stats_.reset(new diff_stats(context()));
12127 
12128  if (do_log())
12129  {
12130  std::cerr << "Marking leaf nodes ...\n";
12131  t.start();
12132  }
12133 
12135 
12136  if (do_log())
12137  {
12138  t.stop();
12139  std::cerr << "leaf nodes marked!:" << t << "\n";
12140  std::cerr << "Applying filters and computing diff stats ...\n";
12141  t.start();
12142  }
12143 
12144  priv_->apply_filters_and_compute_diff_stats(*priv_->diff_stats_);
12145 
12146  if (do_log())
12147  {
12148  t.stop();
12149  std::cerr << "Filters applied and diff stats computed!: " << t << "\n";
12150  }
12151 
12152  return *priv_->diff_stats_;
12153 }
12154 
12155 /// A visitor that marks leaf diff nodes by storing them in the
12156 /// instance of @ref diff_maps returned by
12157 /// corpus_diff::get_leaf_diffs() invoked on the current instance of
12158 /// corpus_diff.
12159 struct leaf_diff_node_marker_visitor : public diff_node_visitor
12160 {
12161  /// This is called when the visitor visits a diff node.
12162  ///
12163  /// It basically tests if the diff node being visited is a leaf diff
12164  /// node - that is, it contains local changes. If it does, then the
12165  /// node is added to the set of maps that hold leaf diffs in the
12166  /// current corpus_diff.
12167  ///
12168  /// Note that only leaf nodes that are reachable from public
12169  /// interfaces (global functions or variables) are collected by this
12170  /// visitor.
12171  ///
12172  /// @param d the diff node being visited.
12173  virtual void
12174  visit_begin(diff *d)
12175  {
12176  if (d->has_local_changes()
12177  // A leaf basic (or class/union) type name change makes no
12178  // sense when showing just leaf changes. It only makes sense
12179  // when it can explain the details about a non-leaf change.
12180  // In other words, it doesn't make sense to say that an "int"
12181  // became "unsigned int". But it does make sense to say that
12182  // a typedef changed because its underlying type was 'int' and
12183  // is now an "unsigned int".
12185  // Similarly, a *local* change describing a type that changed
12186  // its nature doesn't make sense.
12187  && !is_distinct_diff(d)
12188  // Similarly, a pointer (or reference or array), a typedef or
12189  // qualified type change in itself doesn't make sense. It
12190  // would rather make sense to show that pointer change as part
12191  // of the variable change whose pointer type changed, for
12192  // instance.
12193  && !is_pointer_diff(d)
12194  && !is_reference_diff(d)
12195  && !is_qualified_type_diff(d)
12196  && !is_typedef_diff(d)
12197  && !is_array_diff(d)
12198  // Similarly a parameter change in itself doesn't make sense.
12199  // It should have already been reported as part of the change
12200  // of the function it belongs to.
12201  && !is_fn_parm_diff(d)
12202  // An anonymous class or union diff doesn't make sense on its
12203  // own. It must have been described already by the diff of
12204  // the enclosing struct or union if 'd' is from an anonymous
12205  // data member, or from a typedef change if 'd' is from a
12206  // typedef change which underlying type is an anonymous
12207  // struct/union.
12209  // An anonymous subrange doesn't make sense either.
12211  // Don't show decl-only-ness changes either.
12213  // Sometime, we can encounter artifacts of bogus DWARF that
12214  // yield a diff node for a decl-only class (and empty class
12215  // with the is_declaration flag set) that carries a non-zero
12216  // size! And of course at some point that non-zero size
12217  // changes. We need to be able to detect that.
12219  {
12220  diff_context_sptr ctxt = d->context();
12221  const corpus_diff *corpus_diff_node = ctxt->get_corpus_diff().get();
12222  ABG_ASSERT(corpus_diff_node);
12223 
12224  if (diff *iface_diff = get_current_topmost_iface_diff())
12225  {
12226  type_or_decl_base_sptr iface = iface_diff->first_subject();
12227  // So, this diff node that is reachable from a global
12228  // function or variable carries a leaf change. Let's add
12229  // it to the set of of leaf diffs of corpus_diff_node.
12230  const_cast<corpus_diff*>(corpus_diff_node)->
12231  get_leaf_diffs().insert_diff_node(d, iface);
12232  }
12233  }
12234  }
12235 }; // end struct leaf_diff_node_marker_visitor
12236 
12237 /// Walks the diff nodes associated to the current corpus diff and
12238 /// mark those that carry local changes. They are said to be leaf
12239 /// diff nodes.
12240 ///
12241 /// The marked nodes are available from the
12242 /// corpus_diff::get_leaf_diffs() function.
12243 void
12245 {
12246  if (!has_changes())
12247  return;
12248 
12249  if (!context()->show_leaf_changes_only())
12250  return;
12251 
12252  leaf_diff_node_marker_visitor v;
12253  context()->forget_visited_diffs();
12254  bool s = context()->visiting_a_node_twice_is_forbidden();
12255  context()->forbid_visiting_a_node_twice(true);
12256  if (context()->show_impacted_interfaces())
12257  context()->forbid_visiting_a_node_twice_per_interface(true);
12258  traverse(v);
12259  context()->forbid_visiting_a_node_twice(s);
12260  context()->forbid_visiting_a_node_twice_per_interface(false);
12261 }
12262 
12263 /// Get the set of maps that contain leaf nodes. A leaf node being a
12264 /// node with a local change.
12265 ///
12266 /// @return the set of maps that contain leaf nodes. A leaf node
12267 /// being a node with a local change.
12268 diff_maps&
12270 {return priv_->leaf_diffs_;}
12271 
12272 /// Get the set of maps that contain leaf nodes. A leaf node being a
12273 /// node with a local change.
12274 ///
12275 /// @return the set of maps that contain leaf nodes. A leaf node
12276 /// being a node with a local change.
12277 const diff_maps&
12279 {return priv_->leaf_diffs_;}
12280 
12281 /// Report the diff in a serialized form.
12282 ///
12283 /// @param out the stream to serialize the diff to.
12284 ///
12285 /// @param indent the prefix to use for the indentation of this
12286 /// serialization.
12287 void
12288 corpus_diff::report(ostream& out, const string& indent) const
12289 {
12290  context()->get_reporter()->report(*this, out, indent);
12291 }
12292 
12293 /// Traverse the diff sub-tree under the current instance corpus_diff.
12294 ///
12295 /// @param v the visitor to invoke on each diff node of the sub-tree.
12296 ///
12297 /// @return true if the traversing has to keep going on, false otherwise.
12298 bool
12300 {
12301  finish_diff_type();
12302 
12303  v.visit_begin(this);
12304 
12305  if (!v.visit(this, true))
12306  {
12307  v.visit_end(this);
12308  return false;
12309  }
12310 
12311  for (function_decl_diff_sptrs_type::const_iterator i =
12312  changed_functions_sorted().begin();
12313  i != changed_functions_sorted().end();
12314  ++i)
12315  {
12316  if (diff_sptr d = *i)
12317  {
12318  const diff_context_sptr &ctxt = context();
12319  if (ctxt->visiting_a_node_twice_is_forbidden_per_interface())
12320  ctxt->forget_visited_diffs();
12321 
12322  v.set_current_topmost_iface_diff(d.get());
12323 
12324  if (!d->traverse(v))
12325  {
12326  v.visit_end(this);
12328  return false;
12329  }
12330  }
12331  }
12332 
12333  for (var_diff_sptrs_type::const_iterator i =
12334  changed_variables_sorted().begin();
12335  i != changed_variables_sorted().end();
12336  ++i)
12337  {
12338  if (diff_sptr d = *i)
12339  {
12340  const diff_context_sptr &ctxt = context();
12341  if (ctxt->visiting_a_node_twice_is_forbidden_per_interface())
12342  ctxt->forget_visited_diffs();
12343 
12344  v.set_current_topmost_iface_diff(d.get());
12345 
12346  if (!d->traverse(v))
12347  {
12348  v.visit_end(this);
12350  return false;
12351  }
12352  }
12353  }
12354 
12356 
12357  // Traverse the changed unreachable type diffs. These diffs are on
12358  // types that are not reachable from global functions or variables.
12359  for (vector<diff_sptr>::const_iterator i =
12361  i != changed_unreachable_types_sorted().end();
12362  ++i)
12363  {
12364  if (diff_sptr d = *i)
12365  {
12366  const diff_context_sptr &ctxt = context();
12367  if (ctxt->visiting_a_node_twice_is_forbidden_per_interface())
12368  ctxt->forget_visited_diffs();
12369 
12370  if (!d->traverse(v))
12371  {
12372  v.visit_end(this);
12373  return false;
12374  }
12375  }
12376  }
12377 
12378  v.visit_end(this);
12379  return true;
12380 }
12381 
12382 /// Use a hash-based set difference to compute added/deleted
12383 /// unreferenced symbols between two corpora. This replaces the
12384 /// previous Myers diff approach which was O(N*D) and became quadratic
12385 /// when most symbols differ. The downstream consumer only needs
12386 /// unordered maps keyed by symbol id_string, so ordering is not
12387 /// required.
12388 ///
12389 /// @param first the first corpus.
12390 ///
12391 /// @param second the second corpus.
12392 ///
12393 /// @param first_syms unreferenced symbols from the first corpus.
12394 ///
12395 /// @param second_syms unreferenced symbols from the second corpus.
12396 ///
12397 /// @param deleted_syms output map of deleted symbols (in first but
12398 /// not second), keyed by id_string.
12399 ///
12400 /// @param added_syms output map of added symbols (in second but not
12401 /// first), keyed by id_string.
12402 ///
12403 /// @param lookup_in_corpus a function that looks up whether a symbol
12404 /// exists in a given corpus.
12405 template<typename lookup_fn>
12406 static void
12407 compute_unreferenced_symbol_set_diff(const corpus_sptr& first,
12408  const corpus_sptr& second,
12409  const elf_symbols& first_syms,
12410  const elf_symbols& second_syms,
12411  string_elf_symbol_map& deleted_syms,
12412  string_elf_symbol_map& added_syms,
12413  lookup_fn lookup_in_corpus)
12414 {
12415  // Build a map of id_string -> symbol for each side.
12416  unordered_map<string, elf_symbol_sptr> first_map, second_map;
12417  first_map.reserve(first_syms.size());
12418  second_map.reserve(second_syms.size());
12419 
12420  for (const auto& sym : first_syms)
12421  first_map[sym->get_id_string()] = sym;
12422 
12423  for (const auto& sym : second_syms)
12424  second_map[sym->get_id_string()] = sym;
12425 
12426  // Symbols in first but not in second are candidate deletions.
12427  for (const auto& entry : first_map)
12428  {
12429  if (second_map.find(entry.first) == second_map.end())
12430  {
12431  if (!lookup_in_corpus(second, *entry.second))
12432  deleted_syms[entry.first] = entry.second;
12433  }
12434  }
12435 
12436  // Symbols in second but not in first are candidate additions.
12437  for (const auto& entry : second_map)
12438  {
12439  if (first_map.find(entry.first) != first_map.end())
12440  continue;
12441 
12442  if (!lookup_in_corpus(first, *entry.second))
12443  {
12444  bool do_add = true;
12445  if (!entry.second->get_version().is_empty()
12446  && entry.second->get_version().is_default())
12447  {
12448  // added_sym has a default version. If the former
12449  // corpus had a symbol with the same name but with
12450  // *no* version, then it shouldn't be considered as
12451  // newly added.
12452  elf_symbol::version empty_version;
12453  if (lookup_in_corpus(first, entry.second->get_name(),
12454  empty_version))
12455  do_add = false;
12456  }
12457  if (do_add)
12458  added_syms[entry.first] = entry.second;
12459  }
12460  }
12461 }
12462 
12463 /// Compute the diff between two instances of @ref corpus.
12464 ///
12465 /// Note that the two corpora must have been created in the same @ref
12466 /// environment, otherwise, this function aborts.
12467 ///
12468 /// @param f the first @ref corpus to consider for the diff.
12469 ///
12470 /// @param s the second @ref corpus to consider for the diff.
12471 ///
12472 /// @param ctxt the diff context to use.
12473 ///
12474 /// @return the resulting diff between the two @ref corpus.
12476 compute_diff(const corpus_sptr f,
12477  const corpus_sptr s,
12478  diff_context_sptr ctxt)
12479 {
12480  typedef diff_utils::deep_ptr_eq_functor eq_type;
12481  typedef vector<type_base_wptr>::const_iterator type_base_wptr_it_type;
12482 
12483  ABG_ASSERT(f && s);
12484 
12485  if (!ctxt)
12486  ctxt.reset(new diff_context);
12487 
12488  corpus_diff_sptr r(new corpus_diff(f, s, ctxt));
12489 
12490  ctxt->set_corpus_diff(r);
12491 
12492  if(ctxt->show_soname_change())
12493  r->priv_->sonames_equal_ = f->get_soname() == s->get_soname();
12494  else
12495  r->priv_->sonames_equal_ = true;
12496 
12497  r->priv_->architectures_equal_ =
12498  f->get_architecture_name() == s->get_architecture_name();
12499 
12500  // Note: the diff of functions, variables, and unreferenced symbols
12501  // is computed by
12502  // compare_fns_vars_and_ensure_lookup_tables_populated() below using
12503  // hash-based set difference, which avoids the quadratic behavior of
12504  // Myers diff when most entries differ between large corpora.
12505 
12506  // Compute the diff of function elf symbols not referenced by debug
12507  // info. Use hash-based set difference instead of Myers diff to
12508  // avoid quadratic behavior when most symbols differ.
12509  compute_unreferenced_symbol_set_diff
12510  (f, s,
12511  f->get_unreferenced_function_symbols(),
12512  s->get_unreferenced_function_symbols(),
12513  r->priv_->deleted_unrefed_fn_syms_,
12514  r->priv_->added_unrefed_fn_syms_,
12515  [](const auto& c, auto&&... args)
12516  {return c->lookup_function_symbol(std::forward<decltype(args)>(args)...);});
12517 
12518  // Compute the diff of variable elf symbols not referenced by debug
12519  // info. Use hash-based set difference instead of Myers diff to
12520  // avoid quadratic behavior when most symbols differ.
12521  compute_unreferenced_symbol_set_diff
12522  (f, s,
12523  f->get_unreferenced_variable_symbols(),
12524  s->get_unreferenced_variable_symbols(),
12525  r->priv_->deleted_unrefed_var_syms_,
12526  r->priv_->added_unrefed_var_syms_,
12527  [](const auto& c, auto&&... args)
12528  {return c->lookup_variable_symbol(std::forward<decltype(args)>(args)...);});
12529 
12530  if (ctxt->show_unreachable_types())
12531  // Compute the diff of types not reachable from public functions
12532  // or global variables that are exported.
12533  diff_utils::compute_diff<type_base_wptr_it_type, eq_type>
12534  (f->get_types_not_reachable_from_public_interfaces().begin(),
12535  f->get_types_not_reachable_from_public_interfaces().end(),
12536  s->get_types_not_reachable_from_public_interfaces().begin(),
12537  s->get_types_not_reachable_from_public_interfaces().end(),
12538  r->priv_->unreachable_types_edit_script_);
12539 
12540  r->priv_->compare_fns_vars_and_ensure_lookup_tables_populated();
12541 
12542  return r;
12543 }
12544 
12545 // </corpus stuff>
12546 
12547 /// Compute the diff between two instances of @ref corpus_group.
12548 ///
12549 /// Note that the two corpus_diff must have been created in the same
12550 /// @ref environment, otherwise, this function aborts.
12551 ///
12552 /// @param f the first @ref corpus_group to consider for the diff.
12553 ///
12554 /// @param s the second @ref corpus_group to consider for the diff.
12555 ///
12556 /// @param ctxt the diff context to use.
12557 ///
12558 /// @return the resulting diff between the two @ref corpus_group.
12560 compute_diff(const corpus_group_sptr& f,
12561  const corpus_group_sptr& s,
12562  diff_context_sptr ctxt)
12563 {
12564 
12565  corpus_sptr c1 = f;
12566  corpus_sptr c2 = s;
12567 
12568  return compute_diff(c1, c2, ctxt);
12569 }
12570 
12571 // <corpus_group stuff>
12572 
12573 // </corpus_group stuff>
12574 // <diff_node_visitor stuff>
12575 
12576 /// The private data of the @diff_node_visitor type.
12577 struct diff_node_visitor::priv
12578 {
12579  diff* topmost_interface_diff;
12580  visiting_kind kind;
12581 
12582  priv()
12583  : topmost_interface_diff(),
12584  kind()
12585  {}
12586 
12587  priv(visiting_kind k)
12588  : topmost_interface_diff(),
12589  kind(k)
12590  {}
12591 }; // end struct diff_node_visitor
12592 
12593 /// Default constructor of the @ref diff_node_visitor type.
12595  : priv_(new priv)
12596 {}
12597 
12598 diff_node_visitor::~diff_node_visitor() = default;
12599 
12600 /// Constructor of the @ref diff_node_visitor type.
12601 ///
12602 /// @param k how the visiting has to be performed.
12604  : priv_(new priv(k))
12605 {}
12606 
12607 /// Getter for the visiting policy of the traversing code while
12608 /// invoking this visitor.
12609 ///
12610 /// @return the visiting policy used by the traversing code when
12611 /// invoking this visitor.
12614 {return priv_->kind;}
12615 
12616 /// Setter for the visiting policy of the traversing code while
12617 /// invoking this visitor.
12618 ///
12619 /// @param v a bit map representing the new visiting policy used by
12620 /// the traversing code when invoking this visitor.
12621 void
12623 {priv_->kind = v;}
12624 
12625 /// Setter for the visiting policy of the traversing code while
12626 /// invoking this visitor. This one makes a logical or between the
12627 /// current policy and the bitmap given in argument and assigns the
12628 /// current policy to the result.
12629 ///
12630 /// @param v a bitmap representing the visiting policy to or with
12631 /// the current policy.
12632 void
12634 {priv_->kind = priv_->kind | v;}
12635 
12636 /// Setter of the diff current topmost interface which is impacted by
12637 /// the current diff node being visited.
12638 ///
12639 /// @param d the current topmost interface diff impacted.
12640 void
12642 {priv_->topmost_interface_diff = d;}
12643 
12644 /// Getter of the diff current topmost interface which is impacted by
12645 /// the current diff node being visited.
12646 ///
12647 /// @return the current topmost interface diff impacted.
12648 diff*
12650 {return priv_->topmost_interface_diff;}
12651 
12652 /// This is called by the traversing code on a @ref diff node just
12653 /// before visiting it. That is, before visiting it and its children
12654 /// node.
12655 ///
12656 /// @param d the diff node to visit.
12657 void
12659 {}
12660 
12661 /// This is called by the traversing code on a @ref diff node just
12662 /// after visiting it. That is after visiting it and its children
12663 /// nodes.
12664 ///
12665 /// @param d the diff node that got visited.
12666 void
12668 {}
12669 
12670 /// This is called by the traversing code on a @ref corpus_diff node
12671 /// just before visiting it. That is, before visiting it and its
12672 /// children node.
12673 ///
12674 /// @param p the corpus_diff node to visit.
12675 ///
12676 void
12678 {}
12679 
12680 /// This is called by the traversing code on a @ref corpus_diff node
12681 /// just after visiting it. That is after visiting it and its children
12682 /// nodes.
12683 ///
12684 /// @param d the diff node that got visited.
12685 void
12687 {}
12688 
12689 /// Default visitor implementation
12690 ///
12691 /// @return true
12692 bool
12694 {return true;}
12695 
12696 /// Default visitor implementation.
12697 ///
12698 /// @return true
12699 bool
12701 {
12702  diff* d = dif;
12703  visit(d, pre);
12704 
12705  return true;
12706 }
12707 
12708 /// Default visitor implementation.
12709 ///
12710 /// @return true
12711 bool
12713 {
12714  diff* d = dif;
12715  visit(d, pre);
12716 
12717  return true;
12718 }
12719 
12720 /// Default visitor implementation.
12721 ///
12722 /// @return true
12723 bool
12725 {
12726  diff* d = dif;
12727  visit(d, pre);
12728 
12729  return true;
12730 }
12731 
12732 /// Default visitor implementation.
12733 ///
12734 /// @return true
12735 bool
12737 {
12738  diff* d = dif;
12739  visit(d, pre);
12740 
12741  return true;
12742 }
12743 
12744 /// Default visitor implementation.
12745 ///
12746 /// @return true
12747 bool
12749 {
12750  diff* d = dif;
12751  visit(d, pre);
12752 
12753  return true;
12754 }
12755 
12756 /// Default visitor implementation.
12757 ///
12758 /// @return true
12759 bool
12761 {
12762  diff* d = dif;
12763  visit(d, pre);
12764 
12765  return true;
12766 }
12767 
12768 /// Default visitor implementation.
12769 ///
12770 /// @return true
12771 bool
12773 {
12774  diff* d = dif;
12775  visit(d, pre);
12776 
12777  return true;
12778 }
12779 
12780 /// Default visitor implementation.
12781 ///
12782 /// @return true
12783 bool
12785 {
12786  diff* d = dif;
12787  visit(d, pre);
12788 
12789  return true;
12790 }
12791 
12792 /// Default visitor implementation.
12793 ///
12794 /// @return true
12795 bool
12797 {
12798  diff* d = dif;
12799  visit(d, pre);
12800 
12801  return true;
12802 }
12803 
12804 /// Default visitor implementation.
12805 ///
12806 /// @return true
12807 bool
12809 {
12810  diff* d = dif;
12811  visit(d, pre);
12812 
12813  return true;
12814 }
12815 
12816 /// Default visitor implementation.
12817 ///
12818 /// @return true
12819 bool
12821 {
12822  diff* d = dif;
12823  visit(d, pre);
12824 
12825  return true;
12826 }
12827 
12828 /// Default visitor implementation.
12829 ///
12830 /// @return true
12831 bool
12833 {
12834  diff* d = dif;
12835  visit(d, pre);
12836 
12837  return true;
12838 }
12839 
12840 /// Default visitor implementation.
12841 ///
12842 /// @return true
12843 bool
12845 {
12846  diff* d = dif;
12847  visit(d, pre);
12848 
12849  return true;
12850 }
12851 
12852 /// Default visitor implementation.
12853 ///
12854 /// @return true
12855 bool
12857 {return true;}
12858 
12859 // </diff_node_visitor stuff>
12860 
12861 // <redundant diff node marking>
12862 
12863 // </redundant diff node marking>
12864 
12865 // <diff tree category propagation>
12866 
12867 /// A visitor to propagate the category of a node up to its parent
12868 /// nodes. This visitor doesn't touch the REDUNDANT_CATEGORY or the
12869 /// SUPPRESSED_CATEGORY because those are propagated using other
12870 /// specific visitors.
12871 struct category_propagation_visitor : public diff_node_visitor
12872 {
12873  virtual void
12874  visit_end(diff* d)
12875  {
12876  // Has this diff node 'd' been already visited ?
12877  bool already_visited = d->context()->diff_has_been_visited(d);
12878 
12879  // The canonical diff node of the class of equivalence of the diff
12880  // node 'd'.
12881  diff* canonical = d->get_canonical_diff();
12882 
12883  // If this class of equivalence of diff node is being visited for
12884  // the first time, then update its canonical node's category too.
12885  bool update_canonical = !already_visited && canonical;
12886 
12887  for (vector<diff*>::const_iterator i = d->children_nodes().begin();
12888  i != d->children_nodes().end();
12889  ++i)
12890  {
12891  // If we are visiting the class of equivalence of 'd' for the
12892  // first time, then let's look at the children of 'd' and
12893  // propagate their categories to 'd'.
12894  //
12895  // If the class of equivalence of 'd' has already been
12896  // visited, then let's look at the canonical diff nodes of the
12897  // children of 'd' and propagate their categories to 'd'.
12898  diff* diff = already_visited
12899  ? (*i)->get_canonical_diff()
12900  : *i;
12901 
12902  ABG_ASSERT(diff);
12903 
12904  diff_category c = diff->get_category();
12905  // Do not propagate redundant and suppressed categories. Those
12906  // are propagated in a specific pass elsewhere.
12907  c &= ~(REDUNDANT_CATEGORY
12913  // Also, if a (class) type has got a harmful name change, do not
12914  // propagate harmless name changes coming from its sub-types
12915  // (i.e, data members) to the class itself.
12918 
12919  d->add_to_category(c);
12920  if (!already_visited && canonical)
12921  if (update_canonical)
12922  canonical->add_to_category(c);
12923  }
12924 
12927  {
12928  // The current diff node has either:
12929  //
12930  // 1/ a harmless "void pointer to pointer" change
12931  //
12932  // or:
12933  //
12934  // 2/ a harmless "enum to int" change.
12935  //
12936  // The change 1/ was most likely flagged locally as a
12937  // non-compatible distinct change, aka, a non-compatible
12938  // change between two types of different kinds. At a higher
12939  // level however, as we see that it's just a void pointer to
12940  // pointer change, we should unset the
12941  // NON_COMPATIBLE_DISTINCT_CHANGE_CATEGORY categorization.
12942  //
12943  // The change 2/ was most likely flagged locally (in the
12944  // children nodes of the current diff node) as a
12945  // non-compatible name change. At a higher level however, as
12946  // we see that it's just a harmless "enum to int" change,
12947  // let's unset the NON_COMPATIBLE_NAME_CHANGE_CATEGORY
12948  // categorization as well.
12949  diff_category c = d->get_category();
12952  d->set_category(c);
12953  if (is_pointer_diff(d) || is_reference_diff(d))
12954  {
12955  // For pointers and references, changes to
12956  // pointed-to-types are considered local. So, if some
12957  // pointed-to-types have non-compatible name or distinct
12958  // change, then the local category of the
12959  // pointer/reference will reflect that. Let's thus clear
12960  // those NON_COMPATIBLE_DISTINCT_CHANGE_CATEGORY and
12961  // NON_COMPATIBLE_NAME_CHANGE_CATEGORY bits from the local
12962  // category as well.
12963  c = d->get_local_category();
12966  d->set_local_category(c);
12967  }
12968  }
12969 
12971  {
12972  diff_category c = d->get_category();
12974  d->set_category(c);
12975  }
12976  }
12977 };// end struct category_propagation_visitor
12978 
12979 /// Visit all the nodes of a given sub-tree. For each node that has a
12980 /// particular category set, propagate that category set up to its
12981 /// parent nodes.
12982 ///
12983 /// @param diff_tree the diff sub-tree to walk for categorization
12984 /// purpose;
12985 void
12986 propagate_categories(diff* diff_tree)
12987 {
12988  category_propagation_visitor v;
12989  bool s = diff_tree->context()->visiting_a_node_twice_is_forbidden();
12990  diff_tree->context()->forbid_visiting_a_node_twice(true);
12991  diff_tree->context()->forget_visited_diffs();
12992  diff_tree->traverse(v);
12993  diff_tree->context()->forbid_visiting_a_node_twice(s);
12994 }
12995 
12996 /// Visit all the nodes of a given sub-tree. For each node that has a
12997 /// particular category set, propagate that category set up to its
12998 /// parent nodes.
12999 ///
13000 /// @param diff_tree the diff sub-tree to walk for categorization
13001 /// purpose;
13002 void
13004 {propagate_categories(diff_tree.get());}
13005 
13006 /// Visit all the nodes of a given corpus tree. For each node that
13007 /// has a particular category set, propagate that category set up to
13008 /// its parent nodes.
13009 ///
13010 /// @param diff_tree the corpus_diff tree to walk for categorization
13011 /// purpose;
13012 void
13014 {
13015  category_propagation_visitor v;
13016  bool s = diff_tree->context()->visiting_a_node_twice_is_forbidden();
13017  diff_tree->context()->forbid_visiting_a_node_twice(false);
13018  diff_tree->traverse(v);
13019  diff_tree->context()->forbid_visiting_a_node_twice(s);
13020 }
13021 
13022 /// Visit all the nodes of a given corpus tree. For each node that
13023 /// has a particular category set, propagate that category set up to
13024 /// its parent nodes.
13025 ///
13026 /// @param diff_tree the corpus_diff tree to walk for categorization
13027 /// purpose;
13028 void
13030 {propagate_categories(diff_tree.get());}
13031 
13032 /// A tree node visitor that knows how to categorizes a given diff
13033 /// node in the SUPPRESSED_CATEGORY category and how to propagate that
13034 /// categorization.
13035 struct suppression_categorization_visitor : public diff_node_visitor
13036 {
13037 
13038  /// Before visiting the children of the diff node, check if the node
13039  /// is suppressed by a suppression specification. If it is, mark
13040  /// the node as belonging to the SUPPRESSED_CATEGORY category.
13041  ///
13042  /// @param p the diff node to visit.
13043  virtual void
13044  visit_begin(diff* d)
13045  {
13046  bool is_private_type = false;
13047  if (d->is_suppressed(is_private_type))
13048  {
13049  diff_category c = is_private_type
13053 
13054  // If a node was suppressed, all the other nodes of its class
13055  // of equivalence are suppressed too.
13056  diff *canonical_diff = d->get_canonical_diff();
13057  if (canonical_diff != d)
13058  canonical_diff->add_to_category(c);
13059  }
13061  {
13062  // This diff node is specifically allowed by a
13063  // negated_suppression, then mark it as being in the
13064  // HAS_ALLOWED_CHANGE_CATEGORY.
13066  d->add_to_local_category(c);
13067  diff *canonical_diff = d->get_canonical_diff();
13068  canonical_diff->add_to_category(c);
13069 
13070  // Note that some complementary code later down below does
13071  // categorize the descendants and parents nodes of this node
13072  // as HAS_PARENT_WITH_ALLOWED_CHANGE_CATEGORY and
13073  // HAS_DESCENDANT_WITH_ALLOWED_CHANGE_CATEGORY, repectively.
13074  }
13075 
13076  // If a parent node has been allowed by a negated suppression
13077  // specification, then categorize the current node as
13078  // HAS_PARENT_WITH_ALLOWED_CHANGE_CATEGORY.
13079  if (d->parent_node())
13080  {
13085  else
13086  {
13087  c = d->parent_node()->get_category();
13091  }
13092  }
13093 
13094  }
13095 
13096  /// After visiting the children nodes of a given diff node,
13097  /// propagate the SUPPRESSED_CATEGORY from the children nodes to the
13098  /// diff node, if need be.
13099  ///
13100  /// That is, if all children nodes carry a suppressed change the
13101  /// current node should be marked as suppressed as well.
13102  ///
13103  /// In practice, this might be too strong of a condition. If the
13104  /// current node carries a local change (i.e, a change not carried
13105  /// by any of its children node) and if that change is not
13106  /// suppressed, then the current node should *NOT* be suppressed.
13107  ///
13108  /// But right now, the IR doesn't let us know about local vs
13109  /// children-carried changes. So we cannot be that precise yet.
13110  virtual void
13111  visit_end(diff* d)
13112  {
13113  bool has_non_suppressed_child = false;
13114  bool has_non_empty_child = false;
13115  bool has_suppressed_child = false;
13116  bool has_non_private_child = false;
13117  bool has_private_child = false;
13118  bool has_descendant_with_allowed_change = false;
13119 
13120  if (// A node to which we can propagate the "SUPPRESSED_CATEGORY"
13121  // (or the PRIVATE_TYPE_CATEGORY for the same matter)
13122  // category from its children is a node which:
13123  //
13124  // 1/ hasn't been suppressed already
13125  //
13126  // 2/ and has no local change (unless it's a pointer,
13127  // reference or qualified diff node).
13128  //
13129  // Note that qualified type and typedef diff nodes are a bit
13130  // special. The local changes of the underlying type are
13131  // considered local for the qualified/typedef type, just like
13132  // for pointer/reference types. But then the qualified or
13133  // typedef type itself can have local changes of its own, and
13134  // those changes are of the kind LOCAL_NON_TYPE_CHANGE_KIND.
13135  // So a qualified type which have local changes that are
13136  // *NOT* of LOCAL_NON_TYPE_CHANGE_KIND (or that has no local
13137  // changes at all) and which is in the PRIVATE_TYPE_CATEGORY
13138  // or SUPPRESSED_CATEGORY can see these categories be
13139  // propagated.
13140  //
13141  // Note that all pointer/reference diff node changes are
13142  // potentially considered local, i.e, local changes of the
13143  // pointed-to-type are considered local to the pointer itself.
13144  //
13145  // Similarly, changes local to the type of function parameters,
13146  // variables (and data members) and classes (that are not of
13147  // LOCAL_NON_TYPE_CHANGE_KIND kind) and that have been
13148  // suppressed can propagate their SUPPRESSED_CATEGORY-ness to
13149  // those kinds of diff node.
13150  !(d->get_category() & SUPPRESSED_CATEGORY)
13151  && (!d->has_local_changes()
13152  || is_pointer_diff(d)
13153  || is_reference_diff(d)
13154  || (is_qualified_type_diff(d)
13155  && (!(d->has_local_changes() & LOCAL_NON_TYPE_CHANGE_KIND)))
13156  || (is_typedef_diff(d)
13157  && (!(d->has_local_changes() & LOCAL_NON_TYPE_CHANGE_KIND)))
13158  || (is_function_decl_diff(d)
13159  && (!(d->has_local_changes() & LOCAL_NON_TYPE_CHANGE_KIND)))
13160  || (is_fn_parm_diff(d)
13161  && (!(d->has_local_changes() & LOCAL_NON_TYPE_CHANGE_KIND)))
13162  || (is_function_type_diff(d)
13163  && (!(d->has_local_changes() & LOCAL_NON_TYPE_CHANGE_KIND)))
13164  || (is_var_diff(d)
13165  && (!(d->has_local_changes() & LOCAL_NON_TYPE_CHANGE_KIND)))
13166  || (is_class_diff(d)
13167  && (!(d->has_local_changes() & LOCAL_NON_TYPE_CHANGE_KIND)))))
13168  {
13169  // Note that we handle private diff nodes differently from
13170  // generally suppressed diff nodes. E.g, it's not because a
13171  // type is private (and suppressed because of that; i.e, in
13172  // the category PRIVATE_TYPE_CATEGORY) that a typedef to that
13173  // type should also be private and so suppressed. Private
13174  // diff nodes thus have different propagation rules than
13175  // generally suppressed rules.
13176  for (vector<diff*>::const_iterator i = d->children_nodes().begin();
13177  i != d->children_nodes().end();
13178  ++i)
13179  {
13180  diff* child = *i;
13181  if (child->has_changes())
13182  {
13183  has_non_empty_child = true;
13184  if (child->get_class_of_equiv_category() & SUPPRESSED_CATEGORY)
13185  has_suppressed_child = true;
13186  else if (child->get_class_of_equiv_category()
13188  // Propagation of the PRIVATE_TYPE_CATEGORY is going
13189  // to be handled later below.
13190  ;
13191  else
13192  has_non_suppressed_child = true;
13193 
13194  if (child->get_class_of_equiv_category()
13196  has_private_child = true;
13197  else if (child->get_class_of_equiv_category()
13199  // Propagation of the SUPPRESSED_CATEGORY has been
13200  // handled above already.
13201  ;
13202  else
13203  has_non_private_child = true;
13204  }
13205  }
13206 
13207  if (has_non_empty_child
13208  && has_suppressed_child
13209  && !has_non_suppressed_child)
13210  {
13212  // If a node was suppressed, all the other nodes of its class
13213  // of equivalence are suppressed too.
13214  diff *canonical_diff = d->get_canonical_diff();
13215  if (canonical_diff != d)
13216  canonical_diff->add_to_category(SUPPRESSED_CATEGORY);
13217  }
13218 
13219  // Note that the private-ness of a an underlying type won't be
13220  // propagated to its parent typedef, by virtue of the big "if"
13221  // clause at the beginning of this function. So we don't have
13222  // to handle that case here. So the idiom of defining
13223  // typedefs of private (opaque) types will be respected;
13224  // meaning that changes to opaque underlying type will be
13225  // flagged as private and the typedef will be flagged private
13226  // as well, unless the typedef itself has local non-type
13227  // changes. In the later case, changes to the typedef will be
13228  // emitted because the typedef won't inherit the privateness
13229  // of its underlying type. So in practise, the typedef
13230  // remains public for the purpose of change reporting.
13231  if (has_non_empty_child
13232  && has_private_child
13233  && !has_non_private_child)
13234  {
13235  d->add_to_category(PRIVATE_TYPE_CATEGORY);
13236  // If a node was suppressed, all the other nodes of its class
13237  // of equivalence are suppressed too.
13238  diff *canonical_diff = d->get_canonical_diff();
13239  if (canonical_diff != d)
13240  canonical_diff->add_to_category(PRIVATE_TYPE_CATEGORY);
13241  }
13242 
13243  // If the underlying type of a typedef is private and carries
13244  // changes (that are implicitely suppressed because it's
13245  // private) then the typedef must be suppressed too, so that
13246  // those changes to the underlying type are not seen.
13247  if (is_typedef_diff(d)
13248  && !d->has_local_changes()
13249  && has_private_child
13250  && has_non_empty_child)
13251  {
13252  d->add_to_category(SUPPRESSED_CATEGORY|PRIVATE_TYPE_CATEGORY);
13253  // If a node was suppressed, all the other nodes of its class
13254  // of equivalence are suppressed too.
13255  diff *canonical_diff = d->get_canonical_diff();
13256  if (canonical_diff != d)
13257  canonical_diff->add_to_category
13259  }
13260 
13261  if (const function_decl_diff *fn_diff = is_function_decl_diff(d))
13262  if (!(d->has_local_changes() & LOCAL_NON_TYPE_CHANGE_KIND))
13263  {
13264  // d is a function diff that carries a local *type*
13265  // change (that means it's a change to the function
13266  // type). Let's see if the child function type diff
13267  // node is suppressed. That would mean that we are
13268  // instructed to show details of a diff that is deemed
13269  // suppressed; this means the suppression conflicts with
13270  // a local type change. In that case, let's follow what
13271  // the user asked and suppress the function altogether,
13272  if (function_type_diff_sptr fn_type_diff = fn_diff->type_diff())
13273  if (fn_type_diff->is_suppressed())
13274  {
13275  d->add_to_category(SUPPRESSED_CATEGORY);
13276  // If a node was suppressed, all the other nodes
13277  // of its class of equivalence are suppressed too.
13278  diff *canonical_diff = d->get_canonical_diff();
13279  if (canonical_diff != d)
13280  canonical_diff->add_to_category(SUPPRESSED_CATEGORY);
13281  }
13282  }
13283  }
13284 
13285  // If any descendant node was selected by a negated suppression
13286  // specification then categorize the current one as
13287  // HAS_DESCENDANT_WITH_ALLOWED_CHANGE_CATEGORY.
13288  for (auto child_node : d->children_nodes())
13289  {
13290  diff *canonical_diff = child_node->get_canonical_diff();
13291  diff_category c = canonical_diff->get_category();
13294  has_descendant_with_allowed_change = true;
13295  }
13296  if (has_descendant_with_allowed_change)
13297  {
13299  d->add_to_category(c);
13300  d->get_canonical_diff()->add_to_category(c);
13301  }
13302  }
13303 }; //end struct suppression_categorization_visitor
13304 
13305 /// Walk a given diff-sub tree and appply the suppressions carried by
13306 /// the context. If the suppression applies to a given node than
13307 /// categorize the node into the SUPPRESSED_CATEGORY category and
13308 /// propagate that categorization.
13309 ///
13310 /// @param diff_tree the diff-sub tree to apply the suppressions to.
13311 void
13312 apply_suppressions(diff* diff_tree)
13313 {
13314  if (diff_tree && !diff_tree->context()->suppressions().empty())
13315  {
13316  // Apply suppressions to functions and variables that have
13317  // changed sub-types.
13318  suppression_categorization_visitor v;
13319  diff_tree->context()->forget_visited_diffs();
13320  bool s = diff_tree->context()->visiting_a_node_twice_is_forbidden();
13321  diff_tree->context()->forbid_visiting_a_node_twice(true);
13322  diff_tree->traverse(v);
13323  diff_tree->context()->forbid_visiting_a_node_twice(s);
13324  }
13325 }
13326 
13327 /// Walk a given diff-sub tree and appply the suppressions carried by
13328 /// the context. If the suppression applies to a given node than
13329 /// categorize the node into the SUPPRESSED_CATEGORY category and
13330 /// propagate that categorization.
13331 ///
13332 /// @param diff_tree the diff-sub tree to apply the suppressions to.
13333 void
13335 {apply_suppressions(diff_tree.get());}
13336 
13337 /// Walk a @ref corpus_diff tree and appply the suppressions carried
13338 /// by the context. If the suppression applies to a given node then
13339 /// categorize the node into the SUPPRESSED_CATEGORY category and
13340 /// propagate that categorization.
13341 ///
13342 /// @param diff_tree the diff tree to apply the suppressions to.
13343 void
13345 {
13346  if (diff_tree && !diff_tree->context()->suppressions().empty())
13347  {
13348  // First, visit the children trees of changed constructs:
13349  // changed functions, variables, as well as sub-types of these,
13350  // and apply suppression specifications to these ...
13351  suppression_categorization_visitor v;
13352  diff_tree->context()->forget_visited_diffs();
13353  bool s = diff_tree->context()->visiting_a_node_twice_is_forbidden();
13354  diff_tree->context()->forbid_visiting_a_node_twice(true);
13355  const_cast<corpus_diff*>(diff_tree)->traverse(v);
13356  diff_tree->context()->forbid_visiting_a_node_twice(s);
13357 
13358  // ... then also visit the set of added and removed functions,
13359  // variables, symbols, and types not reachable from global
13360  // functions and variables.
13361  diff_tree->priv_->
13362  apply_supprs_to_added_removed_fns_vars_unreachable_types();
13363  }
13364 }
13365 
13366 /// Walk a diff tree and appply the suppressions carried by the
13367 /// context. If the suppression applies to a given node than
13368 /// categorize the node into the SUPPRESSED_CATEGORY category and
13369 /// propagate that categorization.
13370 ///
13371 /// @param diff_tree the diff tree to apply the suppressions to.
13372 void
13374 {apply_suppressions(diff_tree.get());}
13375 
13376 // </diff tree category propagation>
13377 
13378 // <diff tree printing stuff>
13379 
13380 /// A visitor to print (to an output stream) a pretty representation
13381 /// of a @ref diff sub-tree or of a complete @ref corpus_diff tree.
13382 struct diff_node_printer : public diff_node_visitor
13383 {
13384  ostream& out_;
13385  unsigned level_;
13386 
13387  /// Emit a certain number of spaces to the output stream associated
13388  /// to this diff_node_printer.
13389  ///
13390  /// @param level half of the numver of spaces to emit.
13391  void
13392  do_indent(unsigned level)
13393  {
13394  for (unsigned i = 0; i < level; ++i)
13395  out_ << " ";
13396  }
13397 
13398  diff_node_printer(ostream& out)
13399  : diff_node_visitor(DO_NOT_MARK_VISITED_NODES_AS_VISITED),
13400  out_(out),
13401  level_(0)
13402  {}
13403 
13404  virtual void
13405  visit_begin(diff*)
13406  {
13407  ++level_;
13408  }
13409 
13410  virtual void
13411  visit_end(diff*)
13412  {
13413  --level_;
13414  }
13415 
13416  virtual void
13417  visit_begin(corpus_diff*)
13418  {
13419  ++level_;
13420  }
13421 
13422  virtual void
13423  visit_end(corpus_diff*)
13424  {
13425  --level_;
13426  }
13427 
13428  virtual bool
13429  visit(diff* d, bool pre)
13430  {
13431  if (!pre)
13432  // We are post-visiting the diff node D. Which means, we have
13433  // printed a pretty representation for it already. So do
13434  // nothing now.
13435  return true;
13436 
13437  do_indent(level_);
13438  out_ << d->get_pretty_representation();
13439  out_ << "\n";
13440  do_indent(level_);
13441  out_ << "{\n";
13442  do_indent(level_ + 1);
13443  out_ << "category: "<< d->get_category() << "\n";
13444  do_indent(level_ + 1);
13445  out_ << "local category: "<< d->get_local_category() << "\n";
13446  do_indent(level_ + 1);
13447  out_ << "@: " << std::hex << d << std::dec << "\n";
13448  do_indent(level_ + 1);
13449  out_ << "@-canonical: " << std::hex
13450  << d->get_canonical_diff()
13451  << std::dec << "\n";
13452  do_indent(level_);
13453  out_ << "}\n";
13454 
13455  return true;
13456  }
13457 
13458  virtual bool
13459  visit(corpus_diff* d, bool pre)
13460  {
13461  if (!pre)
13462  // We are post-visiting the diff node D. Which means, we have
13463  // printed a pretty representation for it already. So do
13464  // nothing now.
13465  return true;
13466 
13467  // indent
13468  for (unsigned i = 0; i < level_; ++i)
13469  out_ << ' ';
13470  out_ << d->get_pretty_representation();
13471  out_ << '\n';
13472  return true;
13473  }
13474 }; // end struct diff_printer_visitor
13475 
13476 // </ diff tree printing stuff>
13477 
13478 /// Emit a textual representation of a @ref diff sub-tree to an
13479 /// output stream.
13480 ///
13481 /// @param diff_tree the sub-tree to emit the textual representation
13482 /// for.
13483 ///
13484 /// @param out the output stream to emit the textual representation
13485 /// for @p diff_tree to.
13486 void
13487 print_diff_tree(diff* diff_tree, ostream& out)
13488 {
13489  diff_node_printer p(out);
13490  bool s = diff_tree->context()->visiting_a_node_twice_is_forbidden();
13491  diff_tree->context()->forbid_visiting_a_node_twice(false);
13492  diff_tree->traverse(p);
13493  diff_tree->context()->forbid_visiting_a_node_twice(s);
13494 }
13495 
13496 /// Emit a textual representation of a @ref corpus_diff tree to an
13497 /// output stream.
13498 ///
13499 /// @param diff_tree the @ref corpus_diff tree to emit the textual
13500 /// representation for.
13501 ///
13502 /// @param out the output stream to emit the textual representation
13503 /// for @p diff_tree to.
13504 void
13505 print_diff_tree(corpus_diff* diff_tree, std::ostream& out)
13506 {
13507  diff_node_printer p(out);
13508  bool s = diff_tree->context()->visiting_a_node_twice_is_forbidden();
13509  diff_tree->context()->forbid_visiting_a_node_twice(false);
13510  diff_tree->traverse(p);
13511  diff_tree->context()->forbid_visiting_a_node_twice(s);
13512 }
13513 
13514 /// Emit a textual representation of a @ref diff sub-tree to an
13515 /// output stream.
13516 ///
13517 /// @param diff_tree the sub-tree to emit the textual representation
13518 /// for.
13519 ///
13520 /// @param out the output stream to emit the textual representation
13521 /// for @p diff_tree to.
13522 void
13524  std::ostream& o)
13525 {print_diff_tree(diff_tree.get(), o);}
13526 
13527 /// Emit a textual representation of a @ref corpus_diff tree to an
13528 /// output stream.
13529 ///
13530 /// @param diff_tree the @ref corpus_diff tree to emit the textual
13531 /// representation for.
13532 ///
13533 /// @param out the output stream to emit the textual representation
13534 /// for @p diff_tree to.
13535 void
13537  std::ostream& o)
13538 {print_diff_tree(diff_tree.get(), o);}
13539 
13540 /// Print a given category out to stdout for debuging purposes
13541 ///
13542 /// @param c the category to print to stdout.
13543 void
13545 {
13546  std::cout << c << std::endl;
13547 }
13548 
13549 // <redundancy_marking_visitor>
13550 
13551 /// A tree visitor to categorize nodes with respect to the
13552 /// REDUNDANT_CATEGORY. That is, detect if a node is redundant (is
13553 /// present on several spots of the tree) and mark such nodes
13554 /// appropriatly. This visitor also takes care of propagating the
13555 /// REDUNDANT_CATEGORY of a given node to its parent nodes as
13556 /// appropriate.
13557 struct redundancy_marking_visitor : public diff_node_visitor
13558 {
13559  bool skip_children_nodes_;
13560 
13561  redundancy_marking_visitor()
13562  : skip_children_nodes_()
13563  {}
13564 
13565  virtual void
13566  visit_begin(diff* d)
13567  {
13568  if (d->to_be_reported())
13569  {
13570  // A diff node that carries a change and that has been already
13571  // traversed elsewhere is considered redundant. So let's mark
13572  // it as such and let's not traverse it; that is, let's not
13573  // visit its children.
13574  if ((d->context()->diff_has_been_visited(d)
13575  || d->get_canonical_diff()->is_traversing())
13576  && d->has_changes())
13577  {
13578  // But if two diff nodes are redundant sibbling that carry
13579  // changes of base types, do not mark them as being
13580  // redundant. This is to avoid marking nodes as redundant
13581  // in this case:
13582  //
13583  // int foo(int a, int b);
13584  // compared with:
13585  // float foo(float a, float b); (in C).
13586  //
13587  // In this case, we want to report all the occurences of
13588  // the int->float change because logically, they are at
13589  // the same level in the diff tree.
13590 
13591  bool redundant_with_sibling_node = false;
13592  const diff* p = d->parent_node();
13593 
13594  // If this is a child node of a fn_parm_diff, look through
13595  // the fn_parm_diff node to get the function diff node.
13596  if (p && dynamic_cast<const fn_parm_diff*>(p))
13597  p = p->parent_node();
13598 
13599  if (p)
13600  for (vector<diff*>::const_iterator s =
13601  p->children_nodes().begin();
13602  s != p->children_nodes().end();
13603  ++s)
13604  {
13605  if (*s == d)
13606  continue;
13607  diff* sib = *s;
13608  // If this is a fn_parm_diff, look through the
13609  // fn_parm_diff node to get at the real type node.
13610  if (fn_parm_diff* f = dynamic_cast<fn_parm_diff*>(*s))
13611  sib = f->type_diff().get();
13612  if (sib == d)
13613  continue;
13614  if (sib->get_canonical_diff() == d->get_canonical_diff()
13615  // Sibbling diff nodes that carry base type
13616  // changes are to be marked as redundant.
13617  && (is_base_diff(sib) || is_distinct_diff(sib)))
13618  {
13619  redundant_with_sibling_node = true;
13620  break;
13621  }
13622  }
13623  if (!redundant_with_sibling_node
13624  // Changes to basic types should never be considered
13625  // redundant. For instance, if a member of integer
13626  // type is changed into a char type in both a struct A
13627  // and a struct B, we want to see both changes.
13629  // The same goes for distinct type changes
13631  // Functions with similar *local* changes are never marked
13632  // redundant because otherwise one could miss important
13633  // similar local changes that are applied to different
13634  // functions.
13636  // Changes involving variadic parameters of functions
13637  // should never be marked redundant because we want to see
13638  // them all.
13641  // If the canonical diff itself has been filtered out,
13642  // then this one is not marked redundant, unless the
13643  // canonical diff was already redundant.
13644  && (!d->get_canonical_diff()->is_filtered_out()
13645  || (d->get_canonical_diff()->get_category()
13646  & REDUNDANT_CATEGORY))
13647  // If the *same* diff node (not one that is merely
13648  // equivalent to this one) has already been visited
13649  // the do not mark it as beind redundant. It's only
13650  // the other nodes that are equivalent to this one
13651  // that must be marked redundant.
13652  && d->context()->diff_has_been_visited(d) != d
13653  // If the diff node is a function parameter and is not
13654  // a reference/pointer (to a non basic or a non
13655  // distinct type diff) then do not mark it as
13656  // redundant.
13657  //
13658  // Children nodes of base class diff nodes are never
13659  // redundant either, we want to see them all.
13662  && !is_child_node_of_base_diff(d))))
13663  {
13665  // As we said in preamble, as this node is marked as
13666  // being redundant, let's not visit its children.
13667  // This is not an optimization; it's needed for
13668  // correctness. In the case of a diff node involving
13669  // a class type that refers to himself, visiting the
13670  // children nodes might cause them to be wrongly
13671  // marked as redundant.
13674  skip_children_nodes_ = true;
13675  }
13676  }
13677  }
13678  else
13679  {
13680  // If the node is not to be reported, do not look at it children.
13682  skip_children_nodes_ = true;
13683  }
13684  }
13685 
13686  virtual void
13687  visit_begin(corpus_diff*)
13688  {
13689  }
13690 
13691  virtual void
13692  visit_end(diff* d)
13693  {
13694  if (skip_children_nodes_)
13695  // When visiting this node, we decided to skip its children
13696  // node. Now that we are done visiting the node, lets stop
13697  // avoiding the children nodes visiting for the other tree
13698  // nodes.
13699  {
13701  skip_children_nodes_ = false;
13702  }
13703  else
13704  {
13705  // Propagate the redundancy categorization of the children
13706  // nodes to this node. But if this node has local harmful
13707  // changes then it doesn't inherit redundancy from its
13708  // children nodes.
13709  if (!(d->get_category() & REDUNDANT_CATEGORY)
13710  && ((!d->has_local_changes_to_be_reported()
13711  || !is_harmful_category(d->get_local_category()))
13712  // By default, pointer, reference, array and qualified
13713  // types consider that a local changes to their
13714  // underlying type is always a local change for
13715  // themselves.
13716  //
13717  // This is as if those types don't have local changes
13718  // in the same sense as other types. So we always
13719  // propagate redundancy to them, regardless of if they
13720  // have local changes or not.
13721  //
13722  // We also propagate redundancy to typedef types if
13723  // these /only/ carry changes to their underlying
13724  // type.
13725  //
13726  // Note that changes to the underlying type of a
13727  // typedef is considered local of
13728  // LOCAL_TYPE_CHANGE_KIND kind. The other changes to the
13729  // typedef itself are considered local of
13730  // LOCAL_NON_TYPE_CHANGE_KIND kind.
13731  || is_pointer_diff(d)
13732  || is_array_diff(d)
13734  // A typedef with local non-type changes should not
13735  // see redundancy propagation from its underlying
13736  // type, otherwise, the non-type change might be
13737  // "suppressed" away.
13738  || (is_typedef_diff(d)
13739  && (!(d->has_local_changes()
13741  // A (member) variable with non-type local changes
13742  // should not see redundacy propagation from its type.
13743  // If redundant local-type changes are carried by its
13744  // type however, then that redundancy is propagated to
13745  // the variable. This is key to keep the redundancy
13746  // consistency in the system; otherwise, a type change
13747  // would be rightfully considered redundant at some
13748  // places but not at others.
13749  || (is_var_diff(d)
13750  && (!(d->has_local_changes()
13752  // A function parameter with non-type local changes
13753  // should not see redundancy propagation either. But
13754  // a function parameter with local type changes can
13755  // definitely be redundant.
13756  || (is_fn_parm_diff(d)
13757  && (!(d->has_local_changes()
13759  ))
13760  {
13761  bool has_non_redundant_child = false;
13762  bool has_non_empty_child = false;
13763  bool is_array_diff_node = is_array_diff(d);
13764  for (vector<diff*>::const_iterator i =
13765  d->children_nodes().begin();
13766  i != d->children_nodes().end();
13767  ++i)
13768  {
13769  if ((*i)->has_changes())
13770  {
13771  // If we are looking at a child node of an array,
13772  // do not take a subrange diff node change into
13773  // account when considering redundancy. In other
13774  // words, a subrange diff node that carries a
13775  // change should not be considered as a non-empty
13776  // child node. This is because we want to report
13777  // all subrange diff node changes and not consider
13778  // them as redundant.
13779  if (!is_array_diff_node || !is_subrange_diff(*i))
13780  has_non_empty_child = true;
13781  // Let's see if the current child node '*i' is
13782  // "non-redundant".
13783  //
13784  // A non-redundant node would be a node that
13785  // carries a change to be reported and has not
13786  // been marked as being redundant.
13787  if ((*i)->to_be_reported()
13788  && ((*i)->get_category() & REDUNDANT_CATEGORY) == 0)
13789  has_non_redundant_child = true;
13790  }
13791  if (has_non_redundant_child)
13792  break;
13793  }
13794 
13795  // A diff node for which at least a child node carries a
13796  // change, and for which all the children are redundant is
13797  // deemed redundant too, unless it has local changes.
13798  if (has_non_empty_child
13799  && !has_non_redundant_child)
13800  d->add_to_category(REDUNDANT_CATEGORY);
13801  }
13802  }
13803  }
13804 
13805  virtual void
13806  visit_end(corpus_diff*)
13807  {
13808  }
13809 
13810  virtual bool
13811  visit(diff*, bool)
13812  {return true;}
13813 
13814  virtual bool
13815  visit(corpus_diff*, bool)
13816  {
13817  return true;
13818  }
13819 };// end struct redundancy_marking_visitor
13820 
13821 /// A visitor of @ref diff nodes that clears the REDUNDANT_CATEGORY
13822 /// category out of the nodes.
13823 struct redundancy_clearing_visitor : public diff_node_visitor
13824 {
13825  bool
13826  visit(corpus_diff*, bool)
13827  {return true;}
13828 
13829  bool
13830  visit(diff* d, bool)
13831  {
13832  // clear the REDUNDANT_CATEGORY out of the current node.
13833  diff_category c = d->get_category();
13834  c &= ~REDUNDANT_CATEGORY;
13835  d->set_category(c);
13836  return true;
13837  }
13838 }; // end struct redundancy_clearing_visitor
13839 
13840 /// Walk a given @ref diff sub-tree to categorize each of the nodes
13841 /// with respect to the REDUNDANT_CATEGORY.
13842 ///
13843 /// @param diff_tree the @ref diff sub-tree to walk.
13844 void
13845 categorize_redundancy(diff* diff_tree)
13846 {
13847  if (diff_tree->context()->show_redundant_changes())
13848  return;
13849  redundancy_marking_visitor v;
13850  bool s = diff_tree->context()->visiting_a_node_twice_is_forbidden();
13851  diff_tree->context()->forbid_visiting_a_node_twice(false);
13852  diff_tree->traverse(v);
13853  diff_tree->context()->forbid_visiting_a_node_twice(s);
13854 }
13855 
13856 /// Walk a given @ref diff sub-tree to categorize each of the nodes
13857 /// with respect to the REDUNDANT_CATEGORY.
13858 ///
13859 /// @param diff_tree the @ref diff sub-tree to walk.
13860 void
13862 {categorize_redundancy(diff_tree.get());}
13863 
13864 /// Walk a given @ref corpus_diff tree to categorize each of the nodes
13865 /// with respect to the REDUNDANT_CATEGORY.
13866 ///
13867 /// @param diff_tree the @ref corpus_diff tree to walk.
13868 void
13870 {
13871  redundancy_marking_visitor v;
13872  diff_tree->context()->forget_visited_diffs();
13873  bool s = diff_tree->context()->visiting_a_node_twice_is_forbidden();
13874  diff_tree->context()->forbid_visiting_a_node_twice(false);
13875  diff_tree->traverse(v);
13876  diff_tree->context()->forbid_visiting_a_node_twice(s);
13877 }
13878 
13879 /// Walk a given @ref corpus_diff tree to categorize each of the nodes
13880 /// with respect to the REDUNDANT_CATEGORY.
13881 ///
13882 /// @param diff_tree the @ref corpus_diff tree to walk.
13883 void
13885 {categorize_redundancy(diff_tree.get());}
13886 
13887 // </redundancy_marking_visitor>
13888 
13889 /// Walk a given @ref diff sub-tree to clear the REDUNDANT_CATEGORY
13890 /// out of the category of the nodes.
13891 ///
13892 /// @param diff_tree the @ref diff sub-tree to walk.
13893 void
13895 {
13896  redundancy_clearing_visitor v;
13897  bool s = diff_tree->context()->visiting_a_node_twice_is_forbidden();
13898  diff_tree->context()->forbid_visiting_a_node_twice(false);
13899  diff_tree->traverse(v);
13900  diff_tree->context()->forbid_visiting_a_node_twice(s);
13901  diff_tree->context()->forget_visited_diffs();
13902 }
13903 
13904 /// Walk a given @ref diff sub-tree to clear the REDUNDANT_CATEGORY
13905 /// out of the category of the nodes.
13906 ///
13907 /// @param diff_tree the @ref diff sub-tree to walk.
13908 void
13910 {clear_redundancy_categorization(diff_tree.get());}
13911 
13912 /// Walk a given @ref corpus_diff tree to clear the REDUNDANT_CATEGORY
13913 /// out of the category of the nodes.
13914 ///
13915 /// @param diff_tree the @ref corpus_diff tree to walk.
13916 void
13918 {
13919  redundancy_clearing_visitor v;
13920  bool s = diff_tree->context()->visiting_a_node_twice_is_forbidden();
13921  diff_tree->context()->forbid_visiting_a_node_twice(false);
13922  diff_tree->traverse(v);
13923  diff_tree->context()->forbid_visiting_a_node_twice(s);
13924  diff_tree->context()->forget_visited_diffs();
13925 }
13926 
13927 /// Walk a given @ref corpus_diff tree to clear the REDUNDANT_CATEGORY
13928 /// out of the category of the nodes.
13929 ///
13930 /// @param diff_tree the @ref corpus_diff tree to walk.
13931 void
13933 {clear_redundancy_categorization(diff_tree.get());}
13934 
13935 /// Apply the @ref diff tree filters that have been associated with
13936 /// the context of the a given @ref diff, categorize the diff nodes
13937 /// subsequently. As a result, the nodes of the @p diff_tree tree are
13938 /// going to be properly filtered out at reporting time.
13939 ///
13940 /// @param diff_tree the @ref diff instance to consider.
13941 void
13943 {
13944  if (!diff_tree)
13945  return;
13946 
13947  diff_context_sptr ctxt = diff_tree->context();
13948  ABG_ASSERT(ctxt);
13949 
13950  if (!ctxt->perform_change_categorization())
13951  return;
13952 
13953  apply_suppressions(diff_tree);
13954  ctxt->maybe_apply_filters(diff_tree);
13955  categorize_redundancy(diff_tree);
13956 }
13957 
13958 /// Apply the @ref diff tree filters that have been associated with
13959 /// the context of the a given @ref corpus_diff, categorize the diff
13960 /// nodes subsequently. As a result, the nodes of the @p c tree are
13961 /// going to be properly filtered out at reporting time.
13962 ///
13963 /// @param c the @ref corpus_diff instance to consider.
13964 void
13966 {
13967  if (c)
13968  c->apply_filters_and_suppressions_before_reporting();
13969 }
13970 
13971 /// Test if a diff node represents the difference between a variadic
13972 /// parameter type and something else.
13973 ///
13974 /// @param d the diff node to consider.
13975 ///
13976 /// @return true iff @p d is a diff node that represents the
13977 /// difference between a variadic parameter type and something else.
13978 bool
13980 {
13981  if (!d)
13982  return false;
13983 
13984  type_base_sptr t = is_type(d->first_subject());
13985  if (t && t->get_environment().is_variadic_parameter_type(t))
13986  return true;
13987 
13988  t = is_type(d->second_subject());
13989  if (t && t->get_environment().is_variadic_parameter_type(t))
13990  return true;
13991 
13992  return false;
13993 }
13994 
13995 /// Test if a diff node represents the difference between a variadic
13996 /// parameter type and something else.
13997 ///
13998 /// @param d the diff node to consider.
13999 ///
14000 /// @return true iff @p d is a diff node that represents the
14001 /// difference between a variadic parameter type and something else.
14002 bool
14004 {return is_diff_of_variadic_parameter_type(d.get());}
14005 
14006 /// Test if a diff node represents the difference between a variadic
14007 /// parameter and something else.
14008 ///
14009 /// @param d the diff node to consider.
14010 ///
14011 /// @return true iff @p d is a diff node that represents the
14012 /// difference between a variadic parameter and something else.
14013 bool
14015 {
14016  fn_parm_diff* diff =
14017  dynamic_cast<fn_parm_diff*>(const_cast<abigail::comparison::diff*>(d));
14018  return (diff && is_diff_of_variadic_parameter_type(diff->type_diff()));
14019 }
14020 
14021 /// Test if a diff node represents the difference between a variadic
14022 /// parameter and something else.
14023 ///
14024 /// @param d the diff node to consider.
14025 ///
14026 /// @return true iff @p d is a diff node that represents the
14027 /// difference between a variadic parameter and something else.
14028 bool
14030 {return is_diff_of_variadic_parameter(d.get());}
14031 
14032 /// Test if a diff node represents a diff between two basic types.
14033 ///
14034 /// @param d the diff node to consider.
14035 ///
14036 /// @return true iff @p d is a diff between two basic types.
14037 const type_decl_diff*
14039 {return dynamic_cast<const type_decl_diff*>(d);}
14040 
14041 /// Test if a diff node represents a diff between two basic types, or
14042 /// between pointers, references or qualified type to basic types.
14043 ///
14044 /// @param diff the diff node to consider.
14045 ///
14046 /// @param allow_indirect_type if true, then this function looks into
14047 /// pointer, reference or qualified diff types to see if they "point
14048 /// to" basic types.
14049 ///
14050 /// @return true iff @p d is a diff between two basic types.
14051 const type_decl_diff*
14052 is_diff_of_basic_type(const diff* diff, bool allow_indirect_type)
14053 {
14054  if (allow_indirect_type)
14056  return is_diff_of_basic_type(diff);
14057 }
14058 
14059 /// If a diff node is about changes between two typedef types, get the
14060 /// diff node about changes between the underlying types.
14061 ///
14062 /// Note that this function walks the tree of underlying diff nodes
14063 /// returns the first diff node about types that are not typedefs.
14064 ///
14065 /// @param dif the dif node to consider.
14066 ///
14067 /// @return the underlying diff node of @p dif, or just return @p dif
14068 /// if it's not a typedef diff node.
14069 const diff*
14070 peel_typedef_diff(const diff* dif)
14071 {
14072  const typedef_diff *d = 0;
14073  while ((d = is_typedef_diff(dif)))
14074  dif = d->underlying_type_diff().get();
14075  return dif;
14076 }
14077 
14078 /// If a diff node is about changes between two pointer types, get the
14079 /// diff node about changes between the underlying (pointed-to) types.
14080 ///
14081 /// Note that this function walks the tree of underlying diff nodes
14082 /// returns the first diff node about types that are not pointers.
14083 ///
14084 /// @param dif the dif node to consider.
14085 ///
14086 /// @return the underlying diff node of @p dif, or just return @p dif
14087 /// if it's not a pointer diff node.
14088 const diff*
14089 peel_pointer_diff(const diff* dif)
14090 {
14091  const pointer_diff *d = 0;
14092  while ((d = is_pointer_diff(dif)))
14093  dif = d->underlying_type_diff().get();
14094  return dif;
14095 }
14096 
14097 /// If a diff node is about changes between two reference types, get
14098 /// the diff node about changes between the underlying (pointed-to)
14099 /// types.
14100 ///
14101 /// Note that this function walks the tree of underlying diff nodes
14102 /// returns the first diff node about types that are not references.
14103 ///
14104 /// @param dif the dif node to consider.
14105 ///
14106 /// @return the underlying diff node of @p dif, or just return @p dif
14107 /// if it's not a reference diff node.
14108 const diff*
14109 peel_reference_diff(const diff* dif)
14110 {
14111  const reference_diff *d = 0;
14112  while ((d = is_reference_diff(dif)))
14113  dif = d->underlying_type_diff().get();
14114  return dif;
14115 }
14116 
14117 /// If a diff node is about changes between two qualified types, get
14118 /// the diff node about changes between the underlying (non-qualified)
14119 /// types.
14120 ///
14121 /// Note that this function walks the tree of underlying diff nodes
14122 /// returns the first diff node about types that are not qualified.
14123 ///
14124 /// @param dif the dif node to consider.
14125 ///
14126 /// @return the underlying diff node of @p dif, or just return @p dif
14127 /// if it's not a qualified diff node.
14128 const diff*
14129 peel_qualified_diff(const diff* dif)
14130 {
14131  const qualified_type_diff *d = 0;
14132  while ((d = is_qualified_type_diff(dif)))
14133  dif = d->underlying_type_diff().get();
14134  return dif;
14135 }
14136 
14137 /// If a diff node is about changes between two function parameters
14138 /// get the diff node about changes between the types of the parameters.
14139 ///
14140 /// @param dif the dif node to consider.
14141 ///
14142 /// @return the diff of the types of the parameters.
14143 const diff*
14144 peel_fn_parm_diff(const diff* dif)
14145 {
14146  const fn_parm_diff *d = 0;
14147  while ((d = is_fn_parm_diff(dif)))
14148  dif = d->type_diff().get();
14149  return dif;
14150 }
14151 
14152 /// If a diff node is about changes between two pointer, reference or
14153 /// qualified types, get the diff node about changes between the
14154 /// underlying types.
14155 ///
14156 /// Note that this function walks the tree of underlying diff nodes
14157 /// returns the first diff node about types that are not pointer,
14158 /// reference or qualified.
14159 ///
14160 /// @param dif the dif node to consider.
14161 ///
14162 /// @return the underlying diff node of @p dif, or just return @p dif
14163 /// if it's not a pointer, reference or qualified diff node.
14164 const diff*
14166 {
14167  while (true)
14168  {
14169  if (const pointer_diff *d = is_pointer_diff(dif))
14170  dif = peel_pointer_diff(d);
14171  else if (const reference_diff *d = is_reference_diff(dif))
14172  dif = peel_reference_diff(d);
14173  else if (const qualified_type_diff *d = is_qualified_type_diff(dif))
14174  dif = peel_qualified_diff(d);
14175  else
14176  break;
14177  }
14178  return dif;
14179 }
14180 
14181 /// If a diff node is about changes between two typedefs or qualified
14182 /// types, get the diff node about changes between the underlying
14183 /// 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 typedef or
14187 /// qualified types.
14188 ///
14189 /// @param dif the dif node to consider.
14190 ///
14191 /// @return the underlying diff node of @p dif, or just return @p dif
14192 /// if it's not typedef or qualified diff node.
14193 const diff*
14195 {
14196  while (true)
14197  {
14198  if (const typedef_diff *d = is_typedef_diff(dif))
14199  dif = peel_typedef_diff(d);
14200  else if (const qualified_type_diff *d = is_qualified_type_diff(dif))
14201  dif = peel_qualified_diff(d);
14202  else
14203  break;
14204  }
14205  return dif;
14206 }
14207 
14208 /// If a diff node is about changes between two typedefs or qualified
14209 /// types, get the diff node about changes between the underlying
14210 /// types.
14211 ///
14212 /// Note that this function walks the tree of underlying diff nodes
14213 /// returns the first diff node about types that are neither typedef,
14214 /// qualified type nor parameters.
14215 ///
14216 /// @param dif the dif node to consider.
14217 ///
14218 /// @return the diff node about changes between the underlying types.
14219 const diff*
14221 {
14222  while (true)
14223  {
14224  if (const typedef_diff *d = is_typedef_diff(dif))
14225  dif = peel_typedef_diff(d);
14226  else if (const qualified_type_diff *d = is_qualified_type_diff(dif))
14227  dif = peel_qualified_diff(d);
14228  else if (const fn_parm_diff *d = is_fn_parm_diff(dif))
14229  dif = peel_fn_parm_diff(d);
14230  else
14231  break;
14232  }
14233  return dif;
14234 }
14235 
14236 /// Test if a diff node represents a diff between two class or union
14237 /// types.
14238 ///
14239 /// @param d the diff node to consider.
14240 ///
14241 /// @return iff @p is a diff between two class or union types then
14242 /// return the instance of @ref class_or_union_diff that @p derives
14243 /// from. Otherwise, return nil.
14244 const class_or_union_diff*
14246 {return dynamic_cast<const class_or_union_diff*>(d);}
14247 
14248 /// Test if a given diff node carries *only* a local type change.
14249 ///
14250 /// @param d the diff node to consider.
14251 ///
14252 /// @return true iff @p has a change and that change is a local type
14253 /// change.
14254 static bool
14255 has_local_type_change_only(const diff *d)
14256 {
14257  if (enum change_kind k = d->has_local_changes())
14258  if ((k & LOCAL_NON_TYPE_CHANGE_KIND) == 0
14259  && (k & LOCAL_TYPE_CHANGE_KIND) != 0)
14260  return true;
14261 
14262  return false;
14263 }
14264 
14265 /// Test if a diff node is a decl diff that only carries a basic type
14266 /// change on its type diff sub-node.
14267 ///
14268 ///Note that that pointers/references/qualified types diffs to basic
14269 /// type diffs are considered as having basic type change only.
14270 ///
14271 /// @param d the diff node to consider.
14272 ///
14273 /// @return true iff @p d is a decl diff that only carries a basic
14274 /// type change on its type diff sub-node.
14275 bool
14277 {
14279 
14280  if (is_diff_of_basic_type(d, true) && d->has_changes())
14281  return true;
14282  else if (const var_diff * v = dynamic_cast<const var_diff*>(d))
14283  return (has_local_type_change_only(v)
14284  && is_diff_of_basic_type(v->type_diff().get(), true));
14285  else if (const fn_parm_diff * p = dynamic_cast<const fn_parm_diff*>(d))
14286  return (has_local_type_change_only(p)
14287  && is_diff_of_basic_type(p->type_diff().get(), true));
14288  else if (const function_decl_diff* f =
14289  dynamic_cast<const function_decl_diff*>(d))
14290  return (has_local_type_change_only(f)
14291  && f->type_diff()
14292  && is_diff_of_basic_type(f->type_diff()->return_type_diff().get(),
14293  true));
14294  return false;
14295 }
14296 }// end namespace comparison
14297 } // 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:10814
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:6648
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:5620
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:11172
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:11424
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:23317
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:6375
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:22981
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:10657
const function_decl::parameter_sptr second_parameter() const
Getter for the second subject of this diff node.
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:5486
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:5424
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:8550
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:6280
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:11403
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:7888
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:10587
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:6037
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.
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:6461
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.
std::vector< elf_symbol_sptr > elf_symbols
Convenience typedef for a vector of elf_symbol.
Definition: abg-ir.h:942
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:12066
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:5749
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:28677
vector< changed_enumerator > changed_enumerators_type
Convenience typedef for a vector of changed enumerators.
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:6191
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:10754
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:20563
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:11107
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:10236
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:7365
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:9187
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:11452
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:10702
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:5822
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:4830
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:29107
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:12222
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:5582
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:4675
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.
void compare_fns_vars_and_ensure_lookup_tables_populated()
If the lookup tables are not yet built, walk the differences and fill the lookup tables.
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:10404
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:11925
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:5879
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:9293
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:5145
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:11895
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...