Bug 24731 - Wrongly reporting union members order change
[platform/upstream/libabigail.git] / src / abg-comparison.cc
1 // -*- Mode: C++ -*-
2 //
3 // Copyright (C) 2013-2019 Red Hat, Inc.
4 //
5 // This file is part of the GNU Application Binary Interface Generic
6 // Analysis and Instrumentation Library (libabigail).  This library is
7 // free software; you can redistribute it and/or modify it under the
8 // terms of the GNU Lesser General Public License as published by the
9 // Free Software Foundation; either version 3, or (at your option) any
10 // later version.
11
12 // This library is distributed in the hope that it will be useful, but
13 // WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15 // General Lesser Public License for more details.
16
17 // You should have received a copy of the GNU Lesser General Public
18 // License along with this program; see the file COPYING-LGPLV3.  If
19 // not, see <http://www.gnu.org/licenses/>.
20 //
21 // Author: Dodji Seketeli
22
23 /// @file
24 ///
25 /// This contains the implementation of the comparison engine of
26 /// libabigail.
27
28 #include <ctype.h>
29 #include <libgen.h>
30 #include <algorithm>
31 #include <sstream>
32
33 #include "abg-comparison-priv.h"
34 #include "abg-reporter-priv.h"
35
36 namespace abigail
37 {
38
39 namespace comparison
40 {
41
42 ///
43 ///
44 ///@defgroup DiffNode Internal Representation of the comparison engine
45 /// @{
46 ///
47 /// @brief How changes are represented in libabigail's comparison engine.
48 ///
49 ///@par diff nodes
50 ///
51 /// The internal representation of the comparison engine is basically
52 /// a graph of @ref instances of @ref diff node.  We refer to these
53 /// just as <em>diff nodes</em>.  A diff node represents a change
54 /// between two ABI artifacts represented by instances of types of the
55 /// abigail::ir namespace.  These two artifacts that are being
56 /// compared are called the <em>subjects of the diff</em>.
57 ///
58 /// The types of that IR are in the abigail::comparison namespace.
59 ///
60 ///@par comparing diff nodes
61 ///
62 /// Comparing two instances of @ref diff nodes amounts to comparing
63 /// the subject of the diff.  In other words, two @ref diff nodes are
64 /// equal if and only if their subjects are equal.  Thus, two @ref
65 /// diff nodes can have different memory addresses and yet be equal.
66 ///
67 ///@par diff reporting and context
68 ///
69 /// A diff node can be serialized to an output stream to express, in
70 /// a human-readable textual form, the different changes that exist
71 /// between its two subjects.  This is done by invoking the
72 /// diff::report() method.  That reporting is controlled by several
73 /// parameters that are conceptually part of the context of the diff.
74 /// That context is materialized by an instance of the @ref
75 /// diff_context type.
76 ///
77 /// Please note that the role of the instance(s) of @ref diff_context
78 /// is boreader than just controlling the reporting of @ref diff
79 /// nodes.  Basically, a @ref diff node itself is created following
80 /// behaviours that are controlled by a particular instance of
81 /// diff_context.  A diff node is created in a particular diff
82 /// context, so to speak.
83 ///
84 /// @}
85 ///
86
87 ///
88 ///@defgroup CanonicalDiff Canonical diff tree nodes
89 /// @{
90 ///
91 /// @brief How equivalent diff nodes are quickly spotted.
92 ///
93 /// @par Equivalence of diff nodes.
94 ///
95 /// Each @ref diff node has a property named <em>Canonical Diff
96 /// Node</em>.  If \c D is a diff node, the canonical diff node of @c
97 /// D, noted @c C(D) is a particular diff node that is equal to @c D.
98 /// Thus, a fast way to compare two @ref diff node is to perform a
99 /// pointer comparison of their canonical diff nodes.
100 ///
101 /// A set of equivalent @ref diff nodes is a set of diff nodes that
102 /// all have the same canonical node.  All the nodes of that set are
103 /// equal.
104 ///
105 /// A canonical node is registereded for a given diff node by invoking
106 /// the method diff_context::initialize_canonical_diff().
107 ///
108 /// Please note that the diff_context holds all the canonical diffs
109 /// that got registered through it.  Thus, the life time of all of
110 /// canonical diff objects is the same as the life time of the @ref
111 /// diff_context they relate to.
112 ///
113 /// @}
114 ///
115
116 // -----------------------------------------
117 // <private functions re-usable elsewhere>
118 // -----------------------------------------
119 /// Sort a map of enumerators by their value.
120 ///
121 /// @param enumerators_map the map to sort.
122 ///
123 /// @param sorted the resulting vector of sorted enumerators.
124 void
125 sort_enumerators(const string_enumerator_map& enumerators_map,
126                  enum_type_decl::enumerators& sorted)
127 {
128   for (string_enumerator_map::const_iterator i = enumerators_map.begin();
129        i != enumerators_map.end();
130        ++i)
131     sorted.push_back(i->second);
132   enumerator_value_comp comp;
133   std::sort(sorted.begin(), sorted.end(), comp);
134 }
135
136 /// Sort a map of changed enumerators.
137 ///
138 /// @param enumerators_map the map to sort.
139 ///
140 ///@param output parameter.  The resulting sorted enumerators.
141 void
142 sort_changed_enumerators(const string_changed_enumerator_map& enumerators_map,
143                          changed_enumerators_type& sorted)
144 {
145   for (string_changed_enumerator_map::const_iterator i =
146          enumerators_map.begin();
147        i != enumerators_map.end();
148        ++i)
149     sorted.push_back(i->second);
150
151   changed_enumerator_comp comp;
152   std::sort(sorted.begin(), sorted.end(), comp);
153 }
154
155 /// Sort a map of data members by the offset of their initial value.
156 ///
157 /// @param data_members the map of changed data members to sort.
158 ///
159 /// @param sorted the resulting vector of sorted changed data members.
160 void
161 sort_data_members(const string_decl_base_sptr_map &data_members,
162                   vector<decl_base_sptr>& sorted)
163 {
164   sorted.reserve(data_members.size());
165   for (string_decl_base_sptr_map::const_iterator i = data_members.begin();
166        i != data_members.end();
167        ++i)
168     sorted.push_back(i->second);
169
170   data_member_comp comp;
171   std::sort(sorted.begin(), sorted.end(), comp);
172 }
173
174 /// Sort a an instance of @ref string_function_ptr_map map and stuff
175 /// a resulting sorted vector of pointers to function_decl.
176 ///
177 /// @param map the map to sort.
178 ///
179 /// @param sorted the resulting sorted vector.
180 void
181 sort_string_function_ptr_map(const string_function_ptr_map& map,
182                              vector<function_decl*>& sorted)
183 {
184   sorted.reserve(map.size());
185   for (string_function_ptr_map::const_iterator i = map.begin();
186        i != map.end();
187        ++i)
188     sorted.push_back(i->second);
189
190   function_comp comp;
191   std::sort(sorted.begin(), sorted.end(), comp);
192 }
193
194 /// Sort the values of a @ref string_function_decl_diff_sptr_map map
195 /// and store the result in a vector of @ref function_decl_diff_sptr
196 /// objects.
197 ///
198 /// @param map the map whose values to store.
199 ///
200 /// @param sorted the vector of function_decl_diff_sptr to store the
201 /// result of the sort into.
202 void
203 sort_string_function_decl_diff_sptr_map
204 (const string_function_decl_diff_sptr_map& map,
205  function_decl_diff_sptrs_type& sorted)
206 {
207   sorted.reserve(map.size());
208   for (string_function_decl_diff_sptr_map::const_iterator i = map.begin();
209        i != map.end();
210        ++i)
211     sorted.push_back(i->second);
212   function_decl_diff_comp comp;
213   std::sort(sorted.begin(), sorted.end(), comp);
214 }
215
216 /// Sort of an instance of @ref string_var_diff_sptr_map map.
217 ///
218 /// @param map the input map to sort.
219 ///
220 /// @param sorted the ouptut sorted vector of @ref var_diff_sptr.
221 /// It's populated with the sorted content.
222 void
223 sort_string_var_diff_sptr_map(const string_var_diff_sptr_map& map,
224                               var_diff_sptrs_type& sorted)
225 {
226   sorted.reserve(map.size());
227   for (string_var_diff_sptr_map::const_iterator i = map.begin();
228        i != map.end();
229        ++i)
230     sorted.push_back(i->second);
231
232   var_diff_sptr_comp comp;
233   std::sort(sorted.begin(), sorted.end(), comp);
234 }
235
236 /// Sort a map of string -> pointer to @ref elf_symbol.
237 ///
238 /// The result is a vector of @ref elf_symbol_sptr sorted by the
239 /// name of the symbol.
240 ///
241 /// @param map the map to sort.
242 ///
243 /// @param sorted out parameter; the sorted vector of @ref
244 /// elf_symbol_sptr.
245 void
246 sort_string_elf_symbol_map(const string_elf_symbol_map& map,
247                            vector<elf_symbol_sptr>& sorted)
248 {
249   for (string_elf_symbol_map::const_iterator i = map.begin();
250        i!= map.end();
251        ++i)
252     sorted.push_back(i->second);
253
254   elf_symbol_comp comp;
255   std::sort(sorted.begin(), sorted.end(), comp);
256 }
257
258 /// Sort a map of string -> pointer to @ref var_decl.
259 ///
260 /// The result is a vector of var_decl* sorted by the qualified name
261 /// of the variables.
262 ///
263 /// @param map the map to sort.
264 ///
265 /// @param sorted out parameter; the sorted vector of @ref var_decl.
266 void
267 sort_string_var_ptr_map(const string_var_ptr_map& map,
268                         vector<var_decl*>& sorted)
269 {
270   for (string_var_ptr_map::const_iterator i = map.begin();
271        i != map.end();
272        ++i)
273     sorted.push_back(i->second);
274
275   var_comp comp;
276   std::sort(sorted.begin(), sorted.end(), comp);
277 }
278
279 /// Sort the values of a string_var_diff_sptr_map and store the result
280 /// in a vector of var_diff_sptr.
281 ///
282 /// @param map the map of changed data members to sort.
283 ///
284 /// @param sorted the resulting vector of var_diff_sptr.
285 void
286 sort_string_data_member_diff_sptr_map(const string_var_diff_sptr_map& map,
287                                       var_diff_sptrs_type& sorted)
288 {
289   sorted.reserve(map.size());
290   for (string_var_diff_sptr_map::const_iterator i = map.begin();
291        i != map.end();
292        ++i)
293     sorted.push_back(i->second);
294   data_member_diff_comp comp;
295   std::sort(sorted.begin(), sorted.end(), comp);
296 }
297
298 /// Sort the values of a unsigned_var_diff_sptr_map map and store the
299 /// result into a vector of var_diff_sptr.
300 ///
301 /// @param map the map of changed data members to sort.
302 ///
303 /// @param sorted the resulting vector of sorted var_diff_sptr.
304 void
305 sort_unsigned_data_member_diff_sptr_map(const unsigned_var_diff_sptr_map map,
306                                         var_diff_sptrs_type& sorted)
307 {
308   sorted.reserve(map.size());
309   for (unsigned_var_diff_sptr_map::const_iterator i = map.begin();
310        i != map.end();
311        ++i)
312     sorted.push_back(i->second);
313   data_member_diff_comp comp;
314   std::sort(sorted.begin(), sorted.end(), comp);
315 }
316
317 /// Sort an map of string -> virtual member function into a vector of
318 /// virtual member functions.  The virtual member functions are sorted
319 /// by increasing order of their virtual index.
320 ///
321 /// @param map the input map.
322 ///
323 /// @param sorted the resulting sorted vector of virtual function
324 /// member.
325 void
326 sort_string_virtual_member_function_diff_sptr_map
327 (const string_function_decl_diff_sptr_map& map,
328  function_decl_diff_sptrs_type& sorted)
329 {
330   sorted.reserve(map.size());
331   for (string_function_decl_diff_sptr_map::const_iterator i = map.begin();
332        i != map.end();
333        ++i)
334     sorted.push_back(i->second);
335
336   virtual_member_function_diff_comp comp;
337   sort(sorted.begin(), sorted.end(), comp);
338 }
339
340 /// Sort a map ofg string -> @ref diff_sptr into a vector of @ref
341 /// diff_sptr.  The diff_sptr are sorted lexicographically wrt
342 /// qualified names of their first subjects.
343 ///
344 /// @param map the map to sort.
345 ///
346 /// @param sorted the resulting sorted vector.
347 void
348 sort_string_diff_sptr_map(const string_diff_sptr_map& map,
349                           diff_sptrs_type& sorted)
350 {
351   sorted.reserve(map.size());
352   for (string_diff_sptr_map::const_iterator i = map.begin();
353        i != map.end();
354        ++i)
355     sorted.push_back(i->second);
356
357   diff_comp comp;
358   sort(sorted.begin(), sorted.end(), comp);
359 }
360
361 /// Sort a map ofg string -> @ref diff* into a vector of @ref
362 /// diff_ptr.  The diff_ptr are sorted lexicographically wrt
363 /// qualified names of their first subjects.
364 ///
365 /// @param map the map to sort.
366 ///
367 /// @param sorted the resulting sorted vector.
368 void
369 sort_string_diff_ptr_map(const string_diff_ptr_map& map,
370                           diff_ptrs_type& sorted)
371 {
372   sorted.reserve(map.size());
373   for (string_diff_ptr_map::const_iterator i = map.begin();
374        i != map.end();
375        ++i)
376     sorted.push_back(i->second);
377
378   diff_comp comp;
379   sort(sorted.begin(), sorted.end(), comp);
380 }
381
382 /// Sort a map of string -> base_diff_sptr into a sorted vector of
383 /// base_diff_sptr.  The base_diff_sptr are sorted by increasing value
384 /// of their offset in their containing type.
385 ///
386 /// @param map the input map to sort.
387 ///
388 /// @param sorted the resulting sorted vector.
389 void
390 sort_string_base_diff_sptr_map(const string_base_diff_sptr_map& map,
391                                base_diff_sptrs_type& sorted)
392 {
393   for (string_base_diff_sptr_map::const_iterator i = map.begin();
394        i != map.end();
395        ++i)
396     sorted.push_back(i->second);
397   base_diff_comp comp;
398   sort(sorted.begin(), sorted.end(), comp);
399 }
400
401 /// Lexicographically sort base specifications found
402 /// in instances of string_base_sptr_map.
403 void
404 sort_string_base_sptr_map(const string_base_sptr_map& m,
405                           class_decl::base_specs& sorted)
406 {
407   for (string_base_sptr_map::const_iterator i = m.begin();
408        i != m.end();
409        ++i)
410     sorted.push_back(i->second);
411
412   base_spec_comp comp;
413   std::sort(sorted.begin(), sorted.end(), comp);
414 }
415
416 /// Sort a map of @ref fn_parm_diff by the indexes of the function
417 /// parameters.
418 ///
419 /// @param map the map to sort.
420 ///
421 /// @param sorted the resulting sorted vector of changed function
422 /// parms.
423 void
424 sort_string_fn_parm_diff_sptr_map(const unsigned_fn_parm_diff_sptr_map& map,
425                                   vector<fn_parm_diff_sptr>&            sorted)
426 {
427   sorted.reserve(map.size());
428   for (unsigned_fn_parm_diff_sptr_map::const_iterator i = map.begin();
429        i != map.end();
430        ++i)
431     sorted.push_back(i->second);
432
433   fn_parm_diff_comp comp;
434   std::sort(sorted.begin(), sorted.end(), comp);
435 }
436
437 /// Sort a map of changed function parameters by the indexes of the
438 /// function parameters.
439 ///
440 /// @param map the map to sort.
441 ///
442 /// @param sorted the resulting sorted vector of instances of @ref
443 /// fn_parm_diff_sptr
444 void
445 sort_string_fn_parm_diff_sptr_map(const string_fn_parm_diff_sptr_map&   map,
446                                   vector<fn_parm_diff_sptr>&            sorted)
447 {
448   sorted.reserve(map.size());
449   for (string_fn_parm_diff_sptr_map::const_iterator i = map.begin();
450        i != map.end();
451        ++i)
452     sorted.push_back(i->second);
453
454   fn_parm_diff_comp comp;
455   std::sort(sorted.begin(), sorted.end(), comp);
456 }
457
458 /// Sort a map of string -> function parameters.
459 ///
460 /// @param map the map to sort.
461 ///
462 /// @param sorted the resulting sorted vector of
463 /// @ref vector<function_decl::parameter_sptr>
464 void
465 sort_string_parm_map(const string_parm_map& map,
466                      vector<function_decl::parameter_sptr>& sorted)
467 {
468   for (string_parm_map::const_iterator i = map.begin();
469        i != map.end();
470        ++i)
471     sorted.push_back(i->second);
472
473   // TODO: finish this.
474   parm_comp comp;
475   std::sort(sorted.begin(), sorted.end(), comp);
476 }
477
478 /// Sort the set of ABI artifacts contained in a @ref
479 /// artifact_sptr_set_type.
480 ///
481 /// @param set the set of ABI artifacts to sort.
482 ///
483 /// @param output parameter the vector containing the sorted ABI
484 /// artifacts.
485 void
486 sort_artifacts_set(const artifact_sptr_set_type& set,
487                    vector<type_or_decl_base_sptr>& sorted)
488 {
489
490   for (artifact_sptr_set_type::const_iterator it = set.begin();
491        it != set.end();
492        ++it)
493     sorted.push_back(*it);
494
495   type_or_decl_base_comp comp;
496   std::sort(sorted.begin(), sorted.end(), comp);
497 }
498
499 /// Return the first underlying type that is not a qualified type.
500 /// @param t the qualified type to consider.
501 ///
502 /// @return the first underlying type that is not a qualified type, or
503 /// NULL if t is NULL.
504 type_base_sptr
505 get_leaf_type(qualified_type_def_sptr t)
506 {
507   if (!t)
508     return type_base_sptr();
509
510   type_base_sptr ut = t->get_underlying_type();
511   qualified_type_def_sptr qut = dynamic_pointer_cast<qualified_type_def>(ut);
512
513   if (!qut)
514     return ut;
515   return get_leaf_type(qut);
516 }
517
518 /// Tests if a given diff node is to represent the changes between two
519 /// gobal decls.
520 ///
521 /// @param d the diff node to consider.
522 ///
523 /// @return true iff @p d represents the changes between two global
524 /// decls.
525 bool
526 is_diff_of_global_decls(const diff* d)
527 {
528   ABG_ASSERT(d != 0);
529
530   if (d == 0)
531     return false;
532
533   type_or_decl_base_sptr first = d->first_subject();
534   ABG_ASSERT(first);
535
536   type_or_decl_base_sptr second = d->first_subject();
537   ABG_ASSERT(second);
538
539   if (decl_base_sptr decl = is_decl(first))
540     if (is_at_global_scope(decl))
541       if ((decl = is_decl(second)))
542         if (is_at_global_scope(decl))
543           return true;
544
545   return false;
546 }
547
548 // -----------------------------------------
549 // </private functions re-usable elsewhere>
550 // -----------------------------------------
551
552 /// The overloaded or operator for @ref visiting_kind.
553 visiting_kind
554 operator|(visiting_kind l, visiting_kind r)
555 {return static_cast<visiting_kind>(static_cast<unsigned>(l)
556                                    | static_cast<unsigned>(r));}
557
558 /// The overloaded and operator for @ref visiting_kind.
559 visiting_kind
560 operator&(visiting_kind l, visiting_kind r)
561 {
562   return static_cast<visiting_kind>(static_cast<unsigned>(l)
563                                     & static_cast<unsigned>(r));
564 }
565
566 /// The overloaded 'bit inversion' operator for @ref visiting_kind.
567 visiting_kind
568 operator~(visiting_kind l)
569 {return static_cast<visiting_kind>(~static_cast<unsigned>(l));}
570
571 /// Test if a diff node is about differences between types.
572 ///
573 /// @param diff the diff node to test.
574 ///
575 /// @return a pointer to the actual type_diff_base* that @p diff
576 /// extends, iff it is about differences between types.
577 const type_diff_base*
578 is_type_diff(const diff* diff)
579 {return dynamic_cast<const type_diff_base*>(diff);}
580
581 /// Test if a diff node is about differences between declarations.
582 ///
583 /// @param diff the diff node to test.
584 ///
585 /// @return a pointer to the actual decl_diff_base @p diff extends,
586 /// iff it is about differences between declarations.
587 const decl_diff_base*
588 is_decl_diff(const diff* diff)
589 {return dynamic_cast<const decl_diff_base*>(diff);}
590
591 /// Test if a diff node is a @ref class_diff node.
592 ///
593 /// @param diff the diff node to consider.
594 ///
595 /// @return a non-nil pointer to a @ref class_diff iff @p diff is a
596 /// @ref class_diff node.
597 const class_diff*
598 is_class_diff(const diff* diff)
599 {return dynamic_cast<const class_diff*>(diff);}
600
601 /// Test if a diff node is a @ref enum_diff node.
602 ///
603 /// @param diff the diff node to consider.
604 ///
605 /// @return a non-nil pointer to ad @ref enum_diff node iff @p diff is
606 /// a @ref enum_diff node.
607 const enum_diff*
608 is_enum_diff(const diff *diff)
609 {return dynamic_cast<const enum_diff*>(diff);}
610
611 /// Test if a diff node is a @ref union_diff node.
612 ///
613 /// @param diff the diff node to consider.
614 ///
615 /// @return a non-nil pointer to a @ref union_diff iff @p diff is a
616 /// @ref union_diff node.
617 const union_diff*
618 is_union_diff(const diff* diff)
619 {return dynamic_cast<const union_diff*>(diff);}
620
621 /// Test if a diff node is a @ref class_or_union_diff node.
622 ///
623 /// @param d the diff node to consider.
624 ///
625 /// @return a non-nil pointer to the @ref class_or_union_diff denoted
626 /// by @p d iff @p d is a @ref class_or_union_diff.
627 const class_or_union_diff*
628 is_class_or_union_diff(const diff* d)
629 {return dynamic_cast<const class_or_union_diff*>(d);}
630
631 /// Test if a diff node is a @ref class_or_union_diff between two
632 /// anonymous classes or unions.
633 ///
634 /// @param d the diff node to consider.
635 ///
636 /// @return a non-nil pointer to the @ref class_or_union_diff iff @p
637 /// denoted by @p d iff @p is pointer to an anonymous class or union
638 /// diff.
639 const class_or_union_diff*
640 is_anonymous_class_or_union_diff(const diff* d)
641 {
642   if (const class_or_union_diff *dif = is_class_or_union_diff(d))
643     if (dif->first_class_or_union()->get_is_anonymous())
644       return dif;
645   return 0;
646 }
647
648 /// Test if a diff node is a @ref typedef_diff node.
649 ///
650 /// @param diff the diff node to consider.
651 ///
652 /// @return a non-nil pointer to a @ref typedef_diff iff @p diff is a
653 /// @ref typedef_diff node.
654 const typedef_diff*
655 is_typedef_diff(const diff *diff)
656 {return dynamic_cast<const typedef_diff*>(diff);}
657
658 /// Test if a diff node is a @ref array_diff node.
659 ///
660 /// @param diff the diff node to consider.
661 ///
662 /// @return a non-nil pointer to a @ref array_diff iff @p diff is a
663 /// @ref array_diff node.
664 const array_diff*
665 is_array_diff(const diff* diff)
666 {return dynamic_cast<const array_diff*>(diff);}
667
668 /// Test if a diff node is a @ref function_type_diff node.
669 ///
670 /// @param diff the diff node to consider.
671 ///
672 /// @return a non-nil pointer to a @ref function_type_diff iff @p diff is a
673 /// @ref function_type_diff node.
674 const function_type_diff*
675 is_function_type_diff(const diff* diff)
676 {return dynamic_cast<const function_type_diff*>(diff);}
677
678 /// Test if a given diff node carries a function type change with
679 /// local changes.
680 ///
681 /// @param diff the diff node to consider.
682 ///
683 /// @return a non-nil pointer to a @ref function_type_diff iff @p diff
684 /// is a function_type_diff node that carries a local change.
685 const function_type_diff*
686 is_function_type_diff_with_local_changes(const diff* diff)
687 {
688   if (const function_type_diff* d = is_function_type_diff(diff))
689     if (d->has_local_changes())
690       return d;
691
692   return 0;
693 }
694
695 /// Test if a diff node is about differences between variables.
696 ///
697 /// @param diff the diff node to test.
698 ///
699 /// @return a pointer to the actual var_diff that @p diff is a type
700 /// of, iff it is about differences between variables.
701 const var_diff*
702 is_var_diff(const diff* diff)
703 {
704   const var_diff* d = dynamic_cast<const var_diff*>(diff);
705   if (d)
706     ABG_ASSERT(is_decl_diff(diff));
707   return d;
708 }
709
710 /// Test if a diff node is about differences between functions.
711 ///
712 /// @param diff the diff node to test.
713 ///
714 /// @return a pointer to the actual var_diff that @p diff is a type
715 /// of, iff it is about differences between variables.
716 const function_decl_diff*
717 is_function_decl_diff(const diff* diff)
718 {
719   const function_decl_diff *d = dynamic_cast<const function_decl_diff*>(diff);
720   if (d)
721     ABG_ASSERT(is_decl_diff(diff));
722   return d;
723 }
724
725 /// Test if a diff node is about differences between two pointers.
726 ///
727 /// @param diff the diff node to consider.
728 ///
729 /// @return the @p diff converted into an instance of @ref
730 /// pointer_diff iff @p diff is about differences between two
731 /// pointers.
732 const pointer_diff*
733 is_pointer_diff(const diff* diff)
734 {return dynamic_cast<const pointer_diff*>(diff);}
735
736 /// Test if a diff node is about differences between two references.
737 ///
738 /// @param diff the diff node to consider.
739 ///
740 /// @return the @p diff converted into an instance of @ref
741 /// reference_diff iff @p diff is about differences between two
742 /// references.
743 const reference_diff*
744 is_reference_diff(const diff* diff)
745 {return dynamic_cast<const reference_diff*>(diff);}
746
747 /// Test if a diff node is about differences between two qualified
748 /// types.
749 ///
750 /// @param diff the diff node to consider.
751 ///
752 /// @return @p diff converted into an instance of @ref
753 /// qualified_type_diff iff @p diff is about differences between two
754 /// qualified types.
755 const qualified_type_diff*
756 is_qualified_type_diff(const diff* diff)
757 {return dynamic_cast<const qualified_type_diff*>(diff);}
758
759 /// Test if a diff node is either a reference diff node or a pointer
760 /// diff node.  Note that this function also works on diffs of
761 /// typedefs of reference or pointer.
762 ///
763 /// @param diff the diff node to test.
764 ///
765 /// @return true iff @p diff is either reference diff node or a
766 /// pointer diff node.
767 bool
768 is_reference_or_pointer_diff(const diff* diff)
769 {
770   diff = peel_typedef_diff(diff);
771   return is_reference_diff(diff) || is_pointer_diff(diff);
772 }
773
774 /// Test if a diff node is a reference or pointer diff node to a
775 /// change that is neither basic type change nor distinct type change.
776 ///
777 /// Note that this function also works on diffs of typedefs of
778 /// reference or pointer.
779 ///
780 /// @param diff the diff node to consider.
781 ///
782 /// @return true iff @p diff is a eference or pointer diff node to a
783 /// change that is neither basic type change nor distinct type change.
784 bool
785 is_reference_or_ptr_diff_to_non_basic_nor_distinct_types(const diff* diff)
786 {
787   diff = peel_typedef_diff(diff);
788   if (const reference_diff* d = is_reference_diff(diff))
789     {
790       diff = peel_reference_diff(d);
791       if (is_diff_of_basic_type(diff) || is_distinct_diff(diff))
792         return false;
793       return true;
794     }
795   else if (const pointer_diff *d = is_pointer_diff(diff))
796     {
797       diff = peel_pointer_diff(d);
798       if (is_diff_of_basic_type(diff) || is_distinct_diff(diff))
799         return false;
800       return true;
801     }
802
803   return false;
804 }
805
806 /// Test if a diff node is about differences between two function
807 /// parameters.
808 ///
809 /// @param diff the diff node to consider.
810 ///
811 /// @return the @p diff converted into an instance of @ref
812 /// reference_diff iff @p diff is about differences between two
813 /// function parameters.
814 const fn_parm_diff*
815 is_fn_parm_diff(const diff* diff)
816 {return dynamic_cast<const fn_parm_diff*>(diff);}
817
818 /// Test if a diff node is about differences between two base class
819 /// specifiers.
820 ///
821 /// @param diff the diff node to consider.
822 ///
823 /// @return the @p diff converted into an instance of @ref base_diff
824 /// iff @p diff is about differences between two base class
825 /// specifiers.
826 const base_diff*
827 is_base_diff(const diff* diff)
828 {return dynamic_cast<const base_diff*>(diff);}
829
830 /// Test if a diff node is about differences between two diff nodes of
831 /// different kinds.
832 ///
833 /// @param diff the diff node to consider.
834 ///
835 /// @return the @p diff converted into an instance of @ref
836 /// distintc_diff iff @p diff is about differences between two diff
837 /// nodes of different kinds.
838 const distinct_diff*
839 is_distinct_diff(const diff *diff)
840 {return dynamic_cast<const distinct_diff*>(diff);}
841
842 /// Test if a diff node is a @ref corpus_diff node.
843 ///
844 /// @param diff the diff node to consider.
845 ///
846 /// @return a non-nil pointer to a @ref corpus_diff iff @p diff is a
847 /// @ref corpus_diff node.
848 const corpus_diff*
849 is_corpus_diff(const diff* diff)
850 {return dynamic_cast<const corpus_diff*>(diff);}
851
852 /// Test if a diff node is a child node of a function parameter diff node.
853 ///
854 /// @param diff the diff node to test.
855 ///
856 /// @return true iff @p diff is a child node of a function parameter
857 /// diff node.
858 bool
859 is_child_node_of_function_parm_diff(const diff* diff)
860 {return diff && is_fn_parm_diff(diff->parent_node());}
861
862 /// Test if a diff node is a child node of a base diff node.
863 ///
864 /// @param diff the diff node to test.
865 ///
866 /// @return true iff @p diff is a child node of a base diff node.
867 bool
868 is_child_node_of_base_diff(const diff* diff)
869 {return diff && is_base_diff(diff->parent_node());}
870
871 /// Test if the current diff node has an ancestor node that has been
872 /// filtered out.
873 ///
874 /// This function detects cycles when walking through the "parent"
875 /// path.
876 ///
877 /// @param diff the diff node to take into account.
878 ///
879 /// @param ancestor this is a hash map of the pointers of the parents
880 /// that are visited.  It's used to detect cycles while visiting
881 /// parents of this diff tree node.
882 ///
883 /// @return true iff the current diff node has an ancestor node that
884 /// has been filtered out.
885 static bool
886 diff_has_ancestor_filtered_out(const diff* d,
887                                unordered_map<size_t, bool>& ancestors)
888 {
889   if (!d || !d->parent_node())
890     return false;
891   if (d->parent_node()->is_filtered_out())
892     return true;
893
894   const diff* parent = d->parent_node();
895   unordered_map<size_t, bool>::const_iterator i =
896     ancestors.find(reinterpret_cast<size_t>(parent));
897   if (i != ancestors.end())
898     // We've just detected a cycle in the path made of the parents
899     // that we are visiting.
900     return false;
901   ancestors[reinterpret_cast<size_t>(parent)] = true;
902
903   return diff_has_ancestor_filtered_out(parent, ancestors);
904 }
905
906 /// Test if the current diff node has an ancestor node that has been
907 /// filtered out.
908 ///
909 /// @param diff the diff node to take into account.
910 ///
911 /// @return true iff the current diff node has an ancestor node that
912 /// has been filtered out.
913 static bool
914 diff_has_ancestor_filtered_out(const diff* diff)
915 {
916   unordered_map<size_t, bool> ancestors_trace;
917   return diff_has_ancestor_filtered_out(diff, ancestors_trace);
918 }
919
920 /// The default traverse function.
921 ///
922 /// @return true.
923 bool
924 diff_traversable_base::traverse(diff_node_visitor&)
925 {return true;}
926
927 diff_context::diff_context()
928   : priv_(new diff_context::priv)
929 {
930   // Setup all the diff output filters we have.
931   filtering::filter_base_sptr f;
932
933   f.reset(new filtering::harmless_harmful_filter);
934   add_diff_filter(f);
935
936   // f.reset(new filtering::harmless_filter);
937   // add_diff_filter(f);
938
939   // f.reset(new filtering::harmful_filter);
940   // add_diff_filter(f);
941 }
942
943 /// Set the corpus diff relevant to this context.
944 ///
945 /// @param d the corpus_diff we are interested in.
946 void
947 diff_context::set_corpus_diff(const corpus_diff_sptr& d)
948 {priv_->corpus_diff_ = d;}
949
950 /// Get the corpus diff for the current context.
951 ///
952 /// @return the corpus diff of this context.
953 const corpus_diff_sptr&
954 diff_context::get_corpus_diff() const
955 {return priv_->corpus_diff_;}
956
957 /// Getter for the first corpus of the corpus diff of the current context.
958 ///
959 /// @return the first corpus of the corpus diff of the current
960 /// context, if no corpus diff is associated to the context.
961 corpus_sptr
962 diff_context::get_first_corpus() const
963 {
964   if (priv_->corpus_diff_)
965     return priv_->corpus_diff_->first_corpus();
966   return corpus_sptr();
967 }
968
969 /// Getter for the second corpus of the corpus diff of the current
970 /// context.
971 ///
972 /// @return the second corpus of the corpus diff of the current
973 /// context, if no corpus diff is associated to the context.
974 corpus_sptr
975 diff_context::get_second_corpus() const
976 {
977   if (priv_->corpus_diff_)
978     return priv_->corpus_diff_->second_corpus();
979   return corpus_sptr();
980 }
981
982 /// Getter of the reporter to be used in this context.
983 ///
984 /// @return the reporter to be used in this context.
985 reporter_base_sptr
986 diff_context::get_reporter() const
987 {
988   if (!priv_->reporter_)
989     {
990       if (show_leaf_changes_only())
991         priv_->reporter_.reset(new leaf_reporter);
992       else
993         priv_->reporter_.reset(new default_reporter);
994     }
995   ABG_ASSERT(priv_->reporter_);
996   return priv_->reporter_;
997 }
998
999 /// Setter of the reporter to be used in this context.
1000 ///
1001 /// @param r the reporter to be used in this context.
1002 void
1003 diff_context::set_reporter(reporter_base_sptr& r)
1004 {priv_->reporter_ = r;}
1005
1006 /// Tests if the current diff context already has a diff for two decls.
1007 ///
1008 /// @param first the first decl to consider.
1009 ///
1010 /// @param second the second decl to consider.
1011 ///
1012 /// @return a pointer to the diff for @p first @p second if found,
1013 /// null otherwise.
1014 diff_sptr
1015 diff_context::has_diff_for(const type_or_decl_base_sptr first,
1016                            const type_or_decl_base_sptr second) const
1017 {
1018   types_or_decls_diff_map_type::const_iterator i =
1019     priv_->types_or_decls_diff_map.find(std::make_pair(first, second));
1020   if (i != priv_->types_or_decls_diff_map.end())
1021     return i->second;
1022   return diff_sptr();
1023 }
1024
1025 /// Tests if the current diff context already has a diff for two types.
1026 ///
1027 /// @param first the first type to consider.
1028 ///
1029 /// @param second the second type to consider.
1030 ///
1031 /// @return a pointer to the diff for @p first @p second if found,
1032 /// null otherwise.
1033 diff_sptr
1034 diff_context::has_diff_for_types(const type_base_sptr first,
1035                                   const type_base_sptr second) const
1036 {return has_diff_for(first, second);}
1037
1038 /// Tests if the current diff context already has a given diff.
1039 ///
1040 ///@param d the diff to consider.
1041 ///
1042 /// @return a pointer to the diff found for @p d
1043 const diff*
1044 diff_context::has_diff_for(const diff* d) const
1045 {return has_diff_for(d->first_subject(), d->second_subject()).get();}
1046
1047 /// Tests if the current diff context already has a given diff.
1048 ///
1049 ///@param d the diff to consider.
1050 ///
1051 /// @return a pointer to the diff found for @p d
1052 diff_sptr
1053 diff_context::has_diff_for(const diff_sptr d) const
1054 {return has_diff_for(d->first_subject(), d->second_subject());}
1055
1056 /// Getter for the bitmap that represents the set of categories that
1057 /// the user wants to see reported.
1058 ///
1059 /// @return a bitmap that represents the set of categories that the
1060 /// user wants to see reported.
1061 diff_category
1062 diff_context::get_allowed_category() const
1063 {return priv_->allowed_category_;}
1064
1065 /// Setter for the bitmap that represents the set of categories that
1066 /// the user wants to see reported.
1067 ///
1068 /// @param c a bitmap that represents the set of categories that the
1069 /// user wants to see represented.
1070 void
1071 diff_context::set_allowed_category(diff_category c)
1072 {priv_->allowed_category_ = c;}
1073
1074 /// Setter for the bitmap that represents the set of categories that
1075 /// the user wants to see reported
1076 ///
1077 /// This function perform a bitwise or between the new set of
1078 /// categories and the current ones, and then sets the current
1079 /// categories to the result of the or.
1080 ///
1081 /// @param c a bitmap that represents the set of categories that the
1082 /// user wants to see represented.
1083 void
1084 diff_context::switch_categories_on(diff_category c)
1085 {priv_->allowed_category_ = priv_->allowed_category_ | c;}
1086
1087 /// Setter for the bitmap that represents the set of categories that
1088 /// the user wants to see reported
1089 ///
1090 /// This function actually unsets bits from the current categories.
1091 ///
1092 /// @param c a bitmap that represents the set of categories to unset
1093 /// from the current categories.
1094 void
1095 diff_context::switch_categories_off(diff_category c)
1096 {priv_->allowed_category_ = priv_->allowed_category_ & ~c;}
1097
1098 /// Add a diff for two decls to the cache of the current diff_context.
1099 ///
1100 /// Doing this allows to later find the added diff from its two
1101 /// subject decls.
1102 ///
1103 /// @param first the first decl to consider.
1104 ///
1105 /// @param second the second decl to consider.
1106 ///
1107 /// @param the diff to add.
1108 void
1109 diff_context::add_diff(type_or_decl_base_sptr first,
1110                        type_or_decl_base_sptr second,
1111                        const diff_sptr d)
1112 {priv_->types_or_decls_diff_map[std::make_pair(first, second)] = d;}
1113
1114 /// Add a diff tree node to the cache of the current diff_context
1115 ///
1116 /// @param d the diff tree node to add.
1117 void
1118 diff_context::add_diff(const diff* d)
1119 {
1120   if (d)
1121     {
1122       diff_sptr dif(const_cast<diff*>(d), noop_deleter());
1123       add_diff(d->first_subject(), d->second_subject(), dif);
1124     }
1125 }
1126
1127 /// Add a diff tree node to the cache of the current diff_context
1128 ///
1129 /// @param d the diff tree node to add.
1130 void
1131 diff_context::add_diff(const diff_sptr d)
1132 {
1133   if (d)
1134       add_diff(d->first_subject(), d->second_subject(), d);
1135 }
1136
1137 /// Getter for the @ref CanonicalDiff "canonical diff node" for the
1138 /// @ref diff represented by their two subjects.
1139 ///
1140 /// @param first the first subject of the diff.
1141 ///
1142 /// @param second the second subject of the diff.
1143 ///
1144 /// @return the canonical diff for the diff node represented by the
1145 /// two diff subjects @p first and @p second.  If no canonical diff
1146 /// node was registered for these subjects, then a nil node is
1147 /// returned.
1148 diff_sptr
1149 diff_context::get_canonical_diff_for(const type_or_decl_base_sptr first,
1150                                      const type_or_decl_base_sptr second) const
1151 {return has_diff_for(first, second);}
1152
1153 /// Getter for the @ref CanonicalDiff "canonical diff node" for the
1154 /// @ref diff represented by the two subjects of a given diff node.
1155 ///
1156 /// @param d the diff node to get the canonical node for.
1157 ///
1158 /// @return the canonical diff for the diff node represented by the
1159 /// two diff subjects of @p d.  If no canonical diff node was
1160 /// registered for these subjects, then a nil node is returned.
1161 diff_sptr
1162 diff_context::get_canonical_diff_for(const diff_sptr d) const
1163 {return has_diff_for(d);}
1164
1165 /// Setter for the @ref CanonicalDiff "canonical diff node" for the
1166 /// @ref diff represented by their two subjects.
1167 ///
1168 /// @param first the first subject of the diff.
1169 ///
1170 /// @param second the second subject of the diff.
1171 ///
1172 /// @param d the new canonical diff.
1173 void
1174 diff_context::set_canonical_diff_for(const type_or_decl_base_sptr first,
1175                                      const type_or_decl_base_sptr second,
1176                                      const diff_sptr d)
1177 {
1178   ABG_ASSERT(d);
1179   if (!has_diff_for(first, second))
1180     {
1181       add_diff(first, second, d);
1182       priv_->canonical_diffs.push_back(d);
1183     }
1184 }
1185
1186 /// If there is is a @ref CanonicalDiff "canonical diff node"
1187 /// registered for two diff subjects, return it.  Otherwise, register
1188 /// a canonical diff node for these two diff subjects and return it.
1189 ///
1190 /// @param first the first subject of the diff.
1191 ///
1192 /// @param second the second subject of the diff.
1193 ///
1194 /// @param d the new canonical diff node.
1195 ///
1196 /// @return the canonical diff node.
1197 diff_sptr
1198 diff_context::set_or_get_canonical_diff_for(const type_or_decl_base_sptr first,
1199                                             const type_or_decl_base_sptr second,
1200                                             const diff_sptr canonical_diff)
1201 {
1202   ABG_ASSERT(canonical_diff);
1203
1204   diff_sptr canonical = get_canonical_diff_for(first, second);
1205   if (!canonical)
1206     {
1207       canonical = canonical_diff;
1208       set_canonical_diff_for(first, second, canonical);
1209     }
1210   return canonical;
1211 }
1212
1213 /// Set the canonical diff node property of a given diff node
1214 /// appropriately.
1215 ///
1216 /// For a given diff node that has no canonical diff node, retrieve
1217 /// the canonical diff node (by looking at its diff subjects and at
1218 /// the current context) and set the canonical diff node property of
1219 /// the diff node to that canonical diff node.  If no canonical diff
1220 /// node has been registered to the diff context for the subjects of
1221 /// the diff node then, register the canonical diff node as being the
1222 /// diff node itself; and set its canonical diff node property as
1223 /// such.  Otherwise, if the diff node already has a canonical diff
1224 /// node, do nothing.
1225 ///
1226 /// @param diff the diff node to initialize the canonical diff node
1227 /// property for.
1228 void
1229 diff_context::initialize_canonical_diff(const diff_sptr diff)
1230 {
1231   if (diff->get_canonical_diff() == 0)
1232     {
1233       diff_sptr canonical =
1234         set_or_get_canonical_diff_for(diff->first_subject(),
1235                                       diff->second_subject(),
1236                                       diff);
1237       diff->set_canonical_diff(canonical.get());
1238     }
1239 }
1240
1241 /// Add a diff node to the set of diff nodes that are kept alive for
1242 /// the life time of the current instance of diff_context.
1243 ///
1244 /// Note that diff added to the diff cache are kept alive as well, and
1245 /// don't need to be passed to this function to be kept alive.
1246 ///
1247 /// @param d the diff node to be kept alive during the life time of
1248 /// the current instance of @ref diff_context.
1249 void
1250 diff_context::keep_diff_alive(diff_sptr& d)
1251 {priv_->live_diffs_.insert(d);}
1252
1253 /// Test if a diff node has been traversed.
1254 ///
1255 /// @param d the diff node to consider.
1256 ///
1257 /// @return the first diff node against which @p d is redundant.
1258 diff*
1259 diff_context::diff_has_been_visited(const diff* d) const
1260 {
1261   const diff* canonical = d->get_canonical_diff();
1262   ABG_ASSERT(canonical);
1263
1264   size_t ptr_value = reinterpret_cast<size_t>(canonical);
1265   pointer_map::iterator it = priv_->visited_diff_nodes_.find(ptr_value);
1266   if (it != priv_->visited_diff_nodes_.end())
1267     return reinterpret_cast<diff*>(it->second);
1268   else
1269     return 0;
1270 }
1271
1272 /// Test if a diff node has been traversed.
1273 ///
1274 /// @param d the diff node to consider.
1275 ///
1276 /// @return the first diff node against which @p d is redundant.
1277 diff_sptr
1278 diff_context::diff_has_been_visited(const diff_sptr d) const
1279 {
1280   diff_sptr diff(diff_has_been_visited(d.get()));
1281   return diff;
1282 }
1283
1284 /// Mark a diff node as traversed by a traversing algorithm.
1285 ///
1286 /// Actually, it's the @ref CanonicalDiff "canonical diff" of this
1287 /// node that is marked as traversed.
1288 ///
1289 /// Subsequent invocations of diff_has_been_visited() on the diff node
1290 /// will yield true.
1291 void
1292 diff_context::mark_diff_as_visited(const diff* d)
1293 {
1294   if (diff_has_been_visited(d))
1295     return;
1296
1297   const diff* canonical = d->get_canonical_diff();
1298   ABG_ASSERT(canonical);
1299
1300    size_t canonical_ptr_value = reinterpret_cast<size_t>(canonical);
1301    size_t diff_ptr_value = reinterpret_cast<size_t>(d);;
1302    priv_->visited_diff_nodes_[canonical_ptr_value] = diff_ptr_value;
1303 }
1304
1305 /// Unmark all the diff nodes that were marked as being traversed.
1306 void
1307 diff_context::forget_visited_diffs()
1308 {priv_->visited_diff_nodes_.clear();}
1309
1310 /// Mark a given diff node as being the last one that has been visited
1311 /// in its class of equivalence.
1312 ///
1313 /// @param d the diff node to mark.
1314 void
1315 diff_context::mark_last_diff_visited_per_class_of_equivalence(const diff* d)
1316 {
1317   if (!d->get_canonical_diff())
1318     return;
1319
1320   size_t v0 = reinterpret_cast<size_t>(d->get_canonical_diff());
1321   size_t v1 = reinterpret_cast<size_t>(d);
1322   priv_->last_visited_diff_node_[v0]= v1;
1323 }
1324
1325 /// Clear the marking about the diff diff nodes in a given class of
1326 /// equivalence.
1327 void
1328 diff_context::clear_last_diffs_visited_per_class_of_equivalence()
1329 {priv_->last_visited_diff_node_.clear();}
1330
1331 /// Return the last diff node visited in the class of equivalence of
1332 /// a given diff node.
1333 ///
1334 /// @param d the diff node which class of equivalence to consider.
1335 ///
1336 /// @return the last diff node visited in the class of equivalence of
1337 /// the diff node @p d.
1338 const diff*
1339 diff_context::get_last_visited_diff_of_class_of_equivalence(const diff* d)
1340 {
1341   size_t v0 = reinterpret_cast<size_t>(d);
1342
1343   pointer_map::const_iterator it = priv_->last_visited_diff_node_.find(v0);
1344   if (it != priv_->last_visited_diff_node_.end())
1345     return reinterpret_cast<const diff*>(it->second);
1346   return 0;
1347 }
1348
1349 /// This sets a flag that, if it's true, then during the traversing of
1350 /// a diff nodes tree each node is visited at most once.
1351 ///
1352 /// @param f if true then during the traversing of a diff nodes tree
1353 /// each node is visited at most once.
1354 ///
1355 void
1356 diff_context::forbid_visiting_a_node_twice(bool f)
1357 {priv_->forbid_visiting_a_node_twice_ = f;}
1358
1359 /// This function sets a flag os that if @ref
1360 ///  forbid_visiting_a_node_twice() returns true, then each time the
1361 ///  node visitor starts visiting a new interface, it resets the
1362 ///  memory the systems has about already visited node.
1363 ///
1364 ///  @param f the flag to set.
1365 void
1366 diff_context::forbid_visiting_a_node_twice_per_interface(bool f)
1367 {priv_->reset_visited_diffs_for_each_interface_ = f;}
1368
1369 /// Return a flag that, if true, then during the traversing of a diff
1370 /// nodes tree each node is visited at most once.
1371 ///
1372 /// @return the boolean flag.
1373 bool
1374 diff_context::visiting_a_node_twice_is_forbidden() const
1375 {return priv_->forbid_visiting_a_node_twice_;}
1376
1377 /// Return a flag that, if true, then during the traversing of a diff
1378 /// nodes tree each node is visited at most once, while visiting the
1379 /// diff tree underneath a given interface (public function or
1380 /// variable).  Each time a new interface is visited, the nodes
1381 /// visited while visiting previous interfaces can be visited again.
1382 ///
1383 /// @return the boolean flag.
1384 ///
1385 /// @return the boolean flag.
1386 bool
1387 diff_context::visiting_a_node_twice_is_forbidden_per_interface() const
1388 {
1389   return (priv_->forbid_visiting_a_node_twice_
1390           && priv_->reset_visited_diffs_for_each_interface_);
1391 }
1392
1393 /// Getter for the diff tree nodes filters to apply to diff sub-trees.
1394 ///
1395 /// @return the vector of tree filters to apply to diff sub-trees.
1396 const filtering::filters&
1397 diff_context::diff_filters() const
1398 {return priv_->filters_;}
1399
1400 /// Setter for the diff filters to apply to a given diff sub-tree.
1401 ///
1402 /// @param f the new diff filter to add to the vector of diff filters
1403 /// to apply to diff sub-trees.
1404 void
1405 diff_context::add_diff_filter(filtering::filter_base_sptr f)
1406 {priv_->filters_.push_back(f);}
1407
1408 /// Apply the diff filters to a given diff sub-tree.
1409 ///
1410 /// If the current context is instructed to filter out some categories
1411 /// then this function walks the given sub-tree and categorizes its
1412 /// nodes by using the filters held by the context.
1413 ///
1414 /// @param diff the diff sub-tree to apply the filters to.
1415 void
1416 diff_context::maybe_apply_filters(diff_sptr diff)
1417 {
1418   if (!diff)
1419     return;
1420
1421   if (get_allowed_category() == EVERYTHING_CATEGORY)
1422     return;
1423
1424   if (!diff->has_changes())
1425     return;
1426
1427   for (filtering::filters::const_iterator i = diff_filters().begin();
1428        i != diff_filters().end();
1429        ++i)
1430     {
1431       filtering::apply_filter(*i, diff);
1432       propagate_categories(diff);
1433     }
1434
1435  }
1436
1437 /// Apply the diff filters to the diff nodes of a @ref corpus_diff
1438 /// instance.
1439 ///
1440 /// If the current context is instructed to filter out some categories
1441 /// then this function walks the diff tree and categorizes its nodes
1442 /// by using the filters held by the context.
1443 ///
1444 /// @param diff the corpus diff to apply the filters to.
1445 void
1446 diff_context::maybe_apply_filters(corpus_diff_sptr diff)
1447 {
1448
1449   if (!diff || !diff->has_changes())
1450     return;
1451
1452   for (filtering::filters::const_iterator i = diff_filters().begin();
1453        i != diff_filters().end();
1454        ++i)
1455     {
1456       filtering::apply_filter(**i, diff);
1457       propagate_categories(diff);
1458     }
1459 }
1460
1461 /// Getter for the vector of suppressions that specify which diff node
1462 /// reports should be dropped on the floor.
1463 ///
1464 /// @return the set of suppressions.
1465 suppressions_type&
1466 diff_context::suppressions() const
1467 {return priv_->suppressions_;}
1468
1469 /// Add a new suppression specification that specifies which diff node
1470 /// reports should be dropped on the floor.
1471 ///
1472 /// @param suppr the new suppression specification to add to the
1473 /// existing set of suppressions specifications of the diff context.
1474 void
1475 diff_context::add_suppression(const suppression_sptr suppr)
1476 {priv_->suppressions_.push_back(suppr);}
1477
1478 /// Add new suppression specifications that specify which diff node
1479 /// reports should be dropped on the floor.
1480 ///
1481 /// @param supprs the new suppression specifications to add to the
1482 /// existing set of suppression specifications of the diff context.
1483 void
1484 diff_context::add_suppressions(const suppressions_type& supprs)
1485 {
1486   priv_->suppressions_.insert(priv_->suppressions_.end(),
1487                               supprs.begin(), supprs.end());
1488 }
1489
1490 /// Set the flag that indicates if the diff using this context should
1491 /// show only leaf changes or not.
1492 ///
1493 /// @param f the new value of the flag that indicates if the diff
1494 /// using this context should show only leaf changes or not.
1495 void
1496 diff_context::show_leaf_changes_only(bool f)
1497 {
1498   // This function can be called only if the reporter hasn't yet been
1499   // created.  Once it's been created, we are supposed to live with
1500   // it.
1501   ABG_ASSERT(priv_->reporter_ == 0);
1502
1503   priv_->leaf_changes_only_ = f;
1504   // So when we are showing only leaf changes, we want to show
1505   // redundant changes because of this: Suppose several functions have
1506   // their return type changed from void* to int*.  We want them all
1507   // to be reported.  In that case the change is not redundant.  As
1508   // far as user-defined type changes (like struct/class) they are
1509   // already put inside a map which makes them be non-redundant, so we
1510   // don't have to worry about that case.
1511   //
1512   // TODO: maybe that in this case we should avoid firing the
1513   // redundancy analysis pass altogether.  That could help save a
1514   // couple of CPU cycle here and there!
1515   priv_->show_redundant_changes_ = f;
1516 }
1517
1518 /// Get the flag that indicates if the diff using this context should
1519 /// show only leaf changes or not.
1520 ///
1521 /// @return the value of the flag that indicates if the diff using
1522 /// this context should show only leaf changes or not.
1523 bool
1524 diff_context::show_leaf_changes_only() const
1525 {return priv_->leaf_changes_only_;}
1526
1527 /// Get the flag that indicates if the diff reports using this context
1528 /// should show sizes and offsets in an hexadecimal base or not.  If
1529 /// not, then they are to be shown in a decimal base.
1530 ///
1531 /// @return true iff sizes and offsets are to be shown in an
1532 /// hexadecimal base.
1533 bool
1534 diff_context::show_hex_values() const
1535 {return priv_->hex_values_;}
1536
1537 /// Set the flag that indicates if diff reports using this context
1538 /// should show sizes and offsets in an hexadecimal base or not.  If
1539 /// not, then they are to be shown in a decimal base.
1540 ///
1541 /// @param f if true then sizes and offsets are to be shown in an
1542 /// hexadecimal base.
1543 void
1544 diff_context::show_hex_values(bool f)
1545 {priv_->hex_values_ = f;}
1546
1547 /// Get the flag that indicates if diff reports using this context
1548 /// should show sizes and offsets in bits, rather than bytes.
1549 ///
1550 /// @return true iff sizes and offsets are to be shown in bits.
1551 /// Otherwise they are to be shown in bytes.
1552 bool
1553 diff_context::show_offsets_sizes_in_bits() const
1554 {return priv_->show_offsets_sizes_in_bits_;}
1555
1556 /// Set the flag that indicates if diff reports using this context
1557 /// should show sizes and offsets in bits, rather than bytes.
1558 ///
1559 /// @param f if true then sizes and offsets are to be shown in bits.
1560 /// Otherwise they are to be shown in bytes.
1561 void
1562 diff_context::show_offsets_sizes_in_bits(bool f)
1563 {priv_->show_offsets_sizes_in_bits_ = f;}
1564
1565 /// Set a flag saying if offset changes should be reported in a
1566 /// relative way.  That is, if the report should say how of many bits
1567 /// a class/struct data member did move.
1568 ///
1569 /// @param f the new boolean value of the flag.
1570 void
1571 diff_context::show_relative_offset_changes(bool f)
1572 {priv_->show_relative_offset_changes_ = f;}
1573
1574 /// Get the flag saying if offset changes should be reported in a
1575 /// relative way.  That is, if the report should say how of many bits
1576 /// a class/struct data member did move.
1577 ///
1578 /// @return the boolean value of the flag.
1579 bool
1580 diff_context::show_relative_offset_changes(void)
1581 {return priv_->show_relative_offset_changes_;}
1582
1583   bool
1584   show_relative_offset_changes(void);
1585
1586 /// Set a flag saying if the comparison module should only show the
1587 /// diff stats.
1588 ///
1589 /// @param f the flag to set.
1590 void
1591 diff_context::show_stats_only(bool f)
1592 {priv_->show_stats_only_ = f;}
1593
1594 /// Test if the comparison module should only show the diff stats.
1595 ///
1596 /// @return true if the comparison module should only show the diff
1597 /// stats, false otherwise.
1598 bool
1599 diff_context::show_stats_only() const
1600 {return priv_->show_stats_only_;}
1601
1602 /// Setter for the property that says if the comparison module should
1603 /// show the soname changes in its report.
1604 ///
1605 /// @param f the new value of the property.
1606 void
1607 diff_context::show_soname_change(bool f)
1608 {priv_->show_soname_change_ = f;}
1609
1610 /// Getter for the property that says if the comparison module should
1611 /// show the soname changes in its report.
1612 ///
1613 /// @return the value of the property.
1614 bool
1615 diff_context::show_soname_change() const
1616 {return priv_->show_soname_change_;}
1617
1618 /// Setter for the property that says if the comparison module should
1619 /// show the architecture changes in its report.
1620 ///
1621 /// @param f the new value of the property.
1622 void
1623 diff_context::show_architecture_change(bool f)
1624 {priv_->show_architecture_change_ = f;}
1625
1626 /// Getter for the property that says if the comparison module should
1627 /// show the architecture changes in its report.
1628 ///
1629 /// @return the value of the property.
1630 bool
1631 diff_context::show_architecture_change() const
1632 {return priv_->show_architecture_change_;}
1633
1634 /// Set a flag saying to show the deleted functions.
1635 ///
1636 /// @param f true to show deleted functions.
1637 void
1638 diff_context::show_deleted_fns(bool f)
1639 {priv_->show_deleted_fns_ = f;}
1640
1641 /// @return true if we want to show the deleted functions, false
1642 /// otherwise.
1643 bool
1644 diff_context::show_deleted_fns() const
1645 {return priv_->show_deleted_fns_;}
1646
1647 /// Set a flag saying to show the changed functions.
1648 ///
1649 /// @param f true to show the changed functions.
1650 void
1651 diff_context::show_changed_fns(bool f)
1652 {priv_->show_changed_fns_ = f;}
1653
1654 /// @return true if we want to show the changed functions, false otherwise.
1655 bool
1656 diff_context::show_changed_fns() const
1657 {return priv_->show_changed_fns_;}
1658
1659 /// Set a flag saying to show the added functions.
1660 ///
1661 /// @param f true to show the added functions.
1662 void
1663 diff_context::show_added_fns(bool f)
1664 {priv_->show_added_fns_ = f;}
1665
1666 /// @return true if we want to show the added functions, false
1667 /// otherwise.
1668 bool
1669 diff_context::show_added_fns() const
1670 {return priv_->show_added_fns_;}
1671
1672 /// Set a flag saying to show the deleted variables.
1673 ///
1674 /// @param f true to show the deleted variables.
1675 void
1676 diff_context::show_deleted_vars(bool f)
1677 {priv_->show_deleted_vars_ = f;}
1678
1679 /// @return true if we want to show the deleted variables, false
1680 /// otherwise.
1681 bool
1682 diff_context::show_deleted_vars() const
1683 {return priv_->show_deleted_vars_;}
1684
1685 /// Set a flag saying to show the changed variables.
1686 ///
1687 /// @param f true to show the changed variables.
1688 void
1689 diff_context::show_changed_vars(bool f)
1690 {priv_->show_changed_vars_ = f;}
1691
1692 /// @return true if we want to show the changed variables, false otherwise.
1693 bool
1694 diff_context::show_changed_vars() const
1695 {return priv_->show_changed_vars_;}
1696
1697 /// Set a flag saying to show the added variables.
1698 ///
1699 /// @param f true to show the added variables.
1700 void
1701 diff_context::show_added_vars(bool f)
1702 {priv_->show_added_vars_ = f;}
1703
1704 /// @return true if we want to show the added variables, false
1705 /// otherwise.
1706 bool
1707 diff_context::show_added_vars() const
1708 {return priv_->show_added_vars_;}
1709
1710 bool
1711 diff_context::show_linkage_names() const
1712 {return priv_->show_linkage_names_;}
1713
1714 void
1715 diff_context::show_linkage_names(bool f)
1716 {priv_->show_linkage_names_= f;}
1717
1718 /// Set a flag saying to show location information.
1719 ///
1720 /// @param f true to show location information.
1721 void
1722 diff_context::show_locs(bool f)
1723 {priv_->show_locs_= f;}
1724
1725 /// @return true if we want to show location information, false
1726 /// otherwise.
1727 bool
1728 diff_context::show_locs() const
1729 {return priv_->show_locs_;}
1730
1731 /// A getter for the flag that says if we should report about
1732 /// functions or variables diff nodes that have *exclusively*
1733 /// redundant diff tree children nodes.
1734 ///
1735 /// @return the flag.
1736 bool
1737 diff_context::show_redundant_changes() const
1738 {return priv_->show_redundant_changes_;}
1739
1740 /// A setter for the flag that says if we should report about
1741 /// functions or variables diff nodes that have *exclusively*
1742 /// redundant diff tree children nodes.
1743 ///
1744 /// @param f the flag to set.
1745 void
1746 diff_context::show_redundant_changes(bool f)
1747 {priv_->show_redundant_changes_ = f;}
1748
1749 /// Getter for the flag that indicates if symbols not referenced by
1750 /// any debug info are to be compared and reported about.
1751 ///
1752 /// @return the boolean flag.
1753 bool
1754 diff_context::show_symbols_unreferenced_by_debug_info() const
1755 {return priv_->show_syms_unreferenced_by_di_;}
1756
1757 /// Setter for the flag that indicates if symbols not referenced by
1758 /// any debug info are to be compared and reported about.
1759 ///
1760 /// @param f the new flag to set.
1761 void
1762 diff_context::show_symbols_unreferenced_by_debug_info(bool f)
1763 {priv_->show_syms_unreferenced_by_di_ = f;}
1764
1765 /// Getter for the flag that indicates if symbols not referenced by
1766 /// any debug info and that got added are to be reported about.
1767 ///
1768 /// @return true iff symbols not referenced by any debug info and that
1769 /// got added are to be reported about.
1770 bool
1771 diff_context::show_added_symbols_unreferenced_by_debug_info() const
1772 {return priv_->show_added_syms_unreferenced_by_di_;}
1773
1774 /// Setter for the flag that indicates if symbols not referenced by
1775 /// any debug info and that got added are to be reported about.
1776 ///
1777 /// @param f the new flag that says if symbols not referenced by any
1778 /// debug info and that got added are to be reported about.
1779 void
1780 diff_context::show_added_symbols_unreferenced_by_debug_info(bool f)
1781 {priv_->show_added_syms_unreferenced_by_di_ = f;}
1782
1783 /// Getter of the flag that indicates if the leaf reporter should
1784 /// display a summary of the interfaces impacted by a given leaf
1785 /// change or not.
1786 ///
1787 /// @return the flag that indicates if the leaf reporter should
1788 /// display a summary of the interfaces impacted by a given leaf
1789 /// change or not.
1790 bool
1791 diff_context::show_impacted_interfaces() const
1792 {return priv_->show_impacted_interfaces_;}
1793
1794 /// Setter of the flag that indicates if the leaf reporter should
1795 /// display a summary of the interfaces impacted by a given leaf
1796 /// change or not.
1797 ///
1798 /// @param f the new value of the flag that indicates if the leaf
1799 /// reporter should display a summary of the interfaces impacted by a
1800 /// given leaf change or not.
1801 void
1802 diff_context::show_impacted_interfaces(bool f)
1803 {priv_->show_impacted_interfaces_ = f;}
1804
1805 /// Setter for the default output stream used by code of the
1806 /// comparison engine.  By default the default output stream is a NULL
1807 /// pointer.
1808 ///
1809 /// @param o a pointer to the default output stream.
1810 void
1811 diff_context::default_output_stream(ostream* o)
1812 {priv_->default_output_stream_ = o;}
1813
1814 /// Getter for the default output stream used by code of the
1815 /// comparison engine.  By default the default output stream is a NULL
1816 /// pointer.
1817 ///
1818 /// @return a pointer to the default output stream.
1819 ostream*
1820 diff_context::default_output_stream()
1821 {return priv_->default_output_stream_;}
1822
1823 /// Setter for the errror output stream used by code of the comparison
1824 /// engine.  By default the error output stream is a NULL pointer.
1825 ///
1826 /// @param o a pointer to the error output stream.
1827 void
1828 diff_context::error_output_stream(ostream* o)
1829 {priv_->error_output_stream_ = o;}
1830
1831 /// Getter for the errror output stream used by code of the comparison
1832 /// engine.  By default the error output stream is a NULL pointer.
1833 ///
1834 /// @return a pointer to the error output stream.
1835 ostream*
1836 diff_context::error_output_stream() const
1837 {return priv_->error_output_stream_;}
1838
1839 /// Test if the comparison engine should dump the diff tree for the
1840 /// changed functions and variables it has.
1841 ///
1842 /// @return true if after the comparison, the engine should dump the
1843 /// diff tree for the changed functions and variables it has.
1844 bool
1845 diff_context::dump_diff_tree() const
1846 {return priv_->dump_diff_tree_;}
1847
1848 /// Set if the comparison engine should dump the diff tree for the
1849 /// changed functions and variables it has.
1850 ///
1851 /// @param f true if after the comparison, the engine should dump the
1852 /// diff tree for the changed functions and variables it has.
1853 void
1854 diff_context::dump_diff_tree(bool f)
1855 {priv_->dump_diff_tree_ = f;}
1856
1857 /// Emit a textual representation of a diff tree to the error output
1858 /// stream of the current context, for debugging purposes.
1859 ///
1860 /// @param d the diff tree to serialize to the error output associated
1861 /// to the current instance of @ref diff_context.
1862 void
1863 diff_context::do_dump_diff_tree(const diff_sptr d) const
1864 {
1865   if (error_output_stream())
1866     print_diff_tree(d, *error_output_stream());
1867 }
1868
1869 /// Emit a textual representation of a @ref corpus_diff tree to the error
1870 /// output stream of the current context, for debugging purposes.
1871 ///
1872 /// @param d the @ref corpus_diff tree to serialize to the error
1873 /// output associated to the current instance of @ref diff_context.
1874 void
1875 diff_context::do_dump_diff_tree(const corpus_diff_sptr d) const
1876 {
1877   if (error_output_stream())
1878     print_diff_tree(d, *error_output_stream());
1879 }
1880 // </diff_context stuff>
1881
1882 // <diff stuff>
1883
1884 /// Constructor for the @ref diff type.
1885 ///
1886 /// This constructs a diff between two subjects that are actually
1887 /// declarations; the first and the second one.
1888 ///
1889 /// @param first_subject the first decl (subject) of the diff.
1890 ///
1891 /// @param second_subject the second decl (subject) of the diff.
1892 diff::diff(type_or_decl_base_sptr first_subject,
1893            type_or_decl_base_sptr second_subject)
1894   : priv_(new priv(first_subject, second_subject,
1895                    diff_context_sptr(),
1896                    NO_CHANGE_CATEGORY,
1897                    /*reported_once=*/false,
1898                    /*currently_reporting=*/false))
1899 {}
1900
1901 /// Constructor for the @ref diff type.
1902 ///
1903 /// This constructs a diff between two subjects that are actually
1904 /// declarations; the first and the second one.
1905 ///
1906 /// @param first_subject the first decl (subject) of the diff.
1907 ///
1908 /// @param second_subject the second decl (subject) of the diff.
1909 ///
1910 /// @param ctxt the context of the diff.  Note that this context
1911 /// object must stay alive during the entire life time of the current
1912 /// instance of @ref diff.  Otherwise, memory corruption issues occur.
1913 diff::diff(type_or_decl_base_sptr       first_subject,
1914            type_or_decl_base_sptr       second_subject,
1915            diff_context_sptr    ctxt)
1916   : priv_(new priv(first_subject, second_subject,
1917                    ctxt, NO_CHANGE_CATEGORY,
1918                    /*reported_once=*/false,
1919                    /*currently_reporting=*/false))
1920 {}
1921
1922 /// Flag a given diff node as being traversed.
1923 ///
1924 /// For certain diff nodes like @ref class_diff, it's important to
1925 /// avoid traversing the node again while it's already being
1926 /// traversed; otherwise this leads to infinite loops.  So the
1927 /// diff::begin_traversing() and diff::end_traversing() methods flag a
1928 /// given node as being traversed (or not), so that
1929 /// diff::is_traversing() can tell if the node is being traversed.
1930 ///
1931 /// Note that traversing a node means visiting it *and* visiting its
1932 /// children nodes.
1933 ///
1934 /// The canonical node is marked as being traversed too.
1935 ///
1936 /// These functions are called by the traversing code.
1937 void
1938 diff::begin_traversing()
1939 {
1940   ABG_ASSERT(!is_traversing());
1941   if (priv_->canonical_diff_)
1942     priv_->canonical_diff_->priv_->traversing_ = true;
1943   priv_->traversing_ = true;
1944 }
1945
1946 /// Tell if a given node is being traversed or not.
1947 ///
1948 /// Note that traversing a node means visiting it *and* visiting its
1949 /// children nodes.
1950 ///
1951 /// It's the canonical node which is looked at, actually.
1952 ///
1953 /// Please read the comments for the diff::begin_traversing() for mode
1954 /// context.
1955 ///
1956 /// @return true if the current instance of @diff is being traversed.
1957 bool
1958 diff::is_traversing() const
1959 {
1960   if (priv_->canonical_diff_)
1961     return priv_->canonical_diff_->priv_->traversing_;
1962   return priv_->traversing_;
1963 }
1964
1965 /// Flag a given diff node as not being traversed anymore.
1966 ///
1967 /// Note that traversing a node means visiting it *and* visiting its
1968 /// children nodes.
1969 ///
1970 /// Please read the comments of the function diff::begin_traversing()
1971 /// for mode context.
1972 void
1973 diff::end_traversing()
1974 {
1975   ABG_ASSERT(is_traversing());
1976   if (priv_->canonical_diff_)
1977     priv_->canonical_diff_->priv_->traversing_ = false;
1978   priv_->traversing_ = false;
1979 }
1980
1981 /// Finish the building of a given kind of a diff tree node.
1982 ///
1983 /// For instance, certain kinds of diff tree node have specific
1984 /// children nodes that are populated after the constructor of the
1985 /// diff tree node has been called.  In that case, calling overloads
1986 /// of this method ensures that these children nodes are properly
1987 /// gathered and setup.
1988 void
1989 diff::finish_diff_type()
1990 {
1991 }
1992
1993 /// Getter of the first subject of the diff.
1994 ///
1995 /// @return the first subject of the diff.
1996 type_or_decl_base_sptr
1997 diff::first_subject() const
1998 {return dynamic_pointer_cast<type_or_decl_base>(priv_->first_subject_);}
1999
2000 /// Getter of the second subject of the diff.
2001 ///
2002 /// @return the second subject of the diff.
2003 type_or_decl_base_sptr
2004 diff::second_subject() const
2005 {return dynamic_pointer_cast<type_or_decl_base>(priv_->second_subject_);}
2006
2007 /// Getter for the children nodes of the current @ref diff node.
2008 ///
2009 /// @return a vector of the children nodes.
2010 const vector<diff*>&
2011 diff::children_nodes() const
2012 {return priv_->children_;}
2013
2014 /// Getter for the parent node of the current @ref diff node.
2015 ///
2016 /// @return the parent node of the current @ref diff node.
2017 const diff*
2018 diff::parent_node() const
2019 {return priv_->parent_;}
2020
2021 /// Getter for the canonical diff of the current instance of @ref
2022 /// diff.
2023 ///
2024 /// Note that the canonical diff node for the current instanc eof diff
2025 /// node must have been set by invoking
2026 /// class_diff::initialize_canonical_diff() on the current instance of
2027 /// diff node.
2028 ///
2029 /// @return the canonical diff node or null if none was set.
2030 diff*
2031 diff::get_canonical_diff() const
2032 {return priv_->canonical_diff_;}
2033
2034 /// Setter for the canonical diff of the current instance of @ref
2035 /// diff.
2036 ///
2037 /// @param d the new canonical node to set.
2038 void
2039 diff::set_canonical_diff(diff * d)
2040 {priv_->canonical_diff_ = d;}
2041
2042 /// Add a new child node to the vector of children nodes for the
2043 /// current @ref diff node.
2044 ///
2045 /// @param d the new child node to add to the children nodes.
2046 void
2047 diff::append_child_node(diff_sptr d)
2048 {
2049   ABG_ASSERT(d);
2050
2051   // Ensure 'd' is kept alive for the life time of the context of this
2052   // diff.
2053   context()->keep_diff_alive(d);
2054
2055   // Add the underlying pointer of 'd' to the vector of children.
2056   // Note that this vector holds no reference to 'd'. This is to avoid
2057   // reference cycles.  The reference to 'd' is held by the context of
2058   // this diff, thanks to the call to context()->keep_diff_alive(d)
2059   // above.
2060   priv_->children_.push_back(d.get());
2061
2062   diff_less_than_functor comp;
2063   std::sort(priv_->children_.begin(),
2064             priv_->children_.end(),
2065             comp);
2066
2067   d->priv_->parent_ = this;
2068 }
2069
2070 /// Getter of the context of the current diff.
2071 ///
2072 /// @return the context of the current diff.
2073 const diff_context_sptr
2074 diff::context() const
2075 {return priv_->get_context();}
2076
2077 /// Setter of the context of the current diff.
2078 ///
2079 /// @param c the new context to set.
2080 void
2081 diff::context(diff_context_sptr c)
2082 {priv_->ctxt_ = c;}
2083
2084 /// Tests if we are currently in the middle of emitting a report for
2085 /// this diff.
2086 ///
2087 /// @return true if we are currently emitting a report for the
2088 /// current diff, false otherwise.
2089 bool
2090 diff::currently_reporting() const
2091 {
2092   if (priv_->canonical_diff_)
2093     return priv_->canonical_diff_->priv_->currently_reporting_;
2094   return priv_->currently_reporting_;
2095 }
2096
2097 /// Sets a flag saying if we are currently in the middle of emitting
2098 /// a report for this diff.
2099 ///
2100 /// @param f true if we are currently emitting a report for the
2101 /// current diff, false otherwise.
2102 void
2103 diff::currently_reporting(bool f) const
2104 {
2105   if (priv_->canonical_diff_)
2106     priv_->canonical_diff_->priv_->currently_reporting_ = f;
2107   priv_->currently_reporting_ = f;
2108 }
2109
2110 /// Tests if a report has already been emitted for the current diff.
2111 ///
2112 /// @return true if a report has already been emitted for the
2113 /// current diff, false otherwise.
2114 bool
2115 diff::reported_once() const
2116 {
2117   ABG_ASSERT(priv_->canonical_diff_);
2118   return priv_->canonical_diff_->priv_->reported_once_;
2119 }
2120
2121 /// The generic traversing code that walks a given diff sub-tree.
2122 ///
2123 /// Note that there is a difference between traversing a diff node and
2124 /// visiting it.  Basically, traversing a diff node means visiting it
2125 /// and visiting its children nodes too.  So one can visit a node
2126 /// without traversing it.  But traversing a node without visiting it
2127 /// is not possible.
2128 ///
2129 /// Note that by default this traversing code visits a given class of
2130 /// equivalence of a diff node only once.  This behaviour can been
2131 /// changed by calling
2132 /// diff_context::visiting_a_node_twice_is_forbidden(), but this is
2133 /// very risky as it might create endless loops while visiting a diff
2134 /// tree graph that has changes that refer to themselves; that is,
2135 /// diff tree graphs with cycles.
2136 ///
2137 /// When a diff node is encountered, the
2138 /// diff_node_visitor::visit_begin() method is invoked on the diff
2139 /// node first.
2140 ///
2141 /// If the diff node has already been visited, then
2142 /// node_visitor::visit_end() is called on it and the node traversing
2143 /// is done; the children of the diff node are not visited in this
2144 /// case.
2145 ///
2146 /// If the diff node has *NOT* been visited yet, then the
2147 /// diff_node_visitor::visit() method is invoked with it's 'pre'
2148 /// argument set to true.  Then if the diff_node_visitor::visit()
2149 /// returns true, then the children nodes of the diff node are
2150 /// visited.  Otherwise, no children nodes of the diff node is
2151 /// visited and the diff_node_visitor::visit_end() is called.
2152
2153 /// After the children nodes are visited (and only if they are
2154 /// visited) the diff_node_visitor::visit() method is invoked with
2155 /// it's 'pre' argument set to false.  And then the
2156 /// diff_node_visitor::visit_end() is called.
2157 ///
2158 /// @param v the entity that visits each node of the diff sub-tree.
2159 ///
2160 /// @return true to tell the caller that all of the sub-tree could be
2161 /// walked.  This instructs the caller to keep walking the rest of the
2162 /// tree.  Return false otherwise.
2163 bool
2164 diff::traverse(diff_node_visitor& v)
2165 {
2166   finish_diff_type();
2167
2168   v.visit_begin(this);
2169
2170   bool already_visited = false;
2171   if (context()->visiting_a_node_twice_is_forbidden()
2172       && context()->diff_has_been_visited(this))
2173     already_visited = true;
2174
2175   bool mark_visited_nodes_as_traversed =
2176     !(v.get_visiting_kind() & DO_NOT_MARK_VISITED_NODES_AS_VISITED);
2177
2178   if (!already_visited && !v.visit(this, /*pre=*/true))
2179     {
2180       v.visit_end(this);
2181       if (mark_visited_nodes_as_traversed)
2182         context()->mark_diff_as_visited(this);
2183       return false;
2184     }
2185
2186   if (!(v.get_visiting_kind() & SKIP_CHILDREN_VISITING_KIND)
2187       && !is_traversing()
2188       && !already_visited)
2189     {
2190       begin_traversing();
2191       for (vector<diff*>::const_iterator i = children_nodes().begin();
2192            i != children_nodes().end();
2193            ++i)
2194         {
2195           if (!(*i)->traverse(v))
2196             {
2197               v.visit_end(this);
2198               if (mark_visited_nodes_as_traversed)
2199                 context()->mark_diff_as_visited(this);
2200               end_traversing();
2201               return false;
2202             }
2203         }
2204       end_traversing();
2205     }
2206
2207   if (!v.visit(this, /*pref=*/false))
2208     {
2209       v.visit_end(this);
2210       if (mark_visited_nodes_as_traversed)
2211         context()->mark_diff_as_visited(this);
2212       return false;
2213     }
2214
2215   v.visit_end(this);
2216   if (!already_visited && mark_visited_nodes_as_traversed)
2217     context()->mark_diff_as_visited(this);
2218
2219   return true;
2220 }
2221
2222 /// Sets a flag saying if a report has already been emitted for the
2223 /// current diff.
2224 ///
2225 /// @param f true if a report has already been emitted for the
2226 /// current diff, false otherwise.
2227 void
2228 diff::reported_once(bool f) const
2229 {
2230   ABG_ASSERT(priv_->canonical_diff_);
2231   priv_->canonical_diff_->priv_->reported_once_ = f;
2232   priv_->reported_once_ = f;
2233 }
2234
2235 /// Getter for the local category of the current diff tree node.
2236 ///
2237 /// The local category represents the set of categories of a diff
2238 /// node, not taking in account the categories inherited from its
2239 /// children nodes.
2240 ///
2241 /// @return the local category of the current diff tree node.
2242 diff_category
2243 diff::get_local_category() const
2244 {return priv_->local_category_;}
2245
2246 /// Getter of the category of the class of equivalence of the current
2247 /// diff tree node.
2248 ///
2249 /// That is, if the current diff tree node has a canonical node,
2250 /// return the category of that canonical node.  Otherwise, return the
2251 /// category of the current node.
2252 ///
2253 /// @return the category of the class of equivalence of the current
2254 /// tree node.
2255 diff_category
2256 diff::get_class_of_equiv_category() const
2257 {
2258   diff* canonical = get_canonical_diff();
2259   return canonical ? canonical->get_category() : get_category();
2260 }
2261
2262 /// Getter for the category of the current diff tree node.
2263 ///
2264 /// This category represents the union of the local category and the
2265 /// categories inherited from the children diff nodes.
2266 ///
2267 /// @return the category of the current diff tree node.
2268 diff_category
2269 diff::get_category() const
2270 {return priv_->category_;}
2271
2272 /// Adds the current diff tree node to an additional set of
2273 /// categories.  Note that the categories include thoses inherited
2274 /// from the children nodes of this diff node.
2275 ///
2276 /// @param c a bit-map representing the set of categories to add the
2277 /// current diff tree node to.
2278 ///
2279 /// @return the resulting bit-map representing the categories this
2280 /// current diff tree node belongs to, including those inherited from
2281 /// its children nodes.
2282 diff_category
2283 diff::add_to_category(diff_category c)
2284 {
2285   priv_->category_ = priv_->category_ | c;
2286   return priv_->category_;
2287 }
2288
2289 /// Adds the current diff tree node to the categories resulting from
2290 /// the local changes of the current diff node.
2291 ///
2292 /// @param c a bit-map representing the set of categories to add the
2293 /// current diff tree node to.
2294 ///
2295 /// @return the resulting bit-map representing the categories this
2296 /// current diff tree node belongs to.
2297 diff_category
2298 diff::add_to_local_category(diff_category c)
2299 {
2300   priv_->local_category_ = priv_->local_category_ | c;
2301   return priv_->local_category_;
2302 }
2303
2304 /// Adds the current diff tree node to the categories resulting from
2305 /// the local and inherited changes of the current diff node.
2306 ///
2307 /// @param c a bit-map representing the set of categories to add the
2308 /// current diff tree node to.
2309 void
2310 diff::add_to_local_and_inherited_categories(diff_category c)
2311 {
2312   add_to_local_category(c);
2313   add_to_category(c);
2314 }
2315
2316 /// Remove the current diff tree node from an a existing sef of
2317 /// categories.  The categories include those inherited from the
2318 /// children nodes of the current diff node.
2319 ///
2320 /// @param c a bit-map representing the set of categories to add the
2321 /// current diff tree node to.
2322 ///
2323 /// @return the resulting bit-map representing the categories this
2324 /// current diff tree onde belongs to, including the categories
2325 /// inherited from the children nodes of the current diff node.
2326 diff_category
2327 diff::remove_from_category(diff_category c)
2328 {
2329   priv_->category_ = priv_->category_ & ~c;
2330   return priv_->category_;
2331 }
2332
2333 /// Remove the current diff tree node from the categories resulting
2334 /// from the local changes.
2335 ///
2336 /// @param c a bit-map representing the set of categories to add the
2337 /// current diff tree node to.
2338 ///
2339 /// @return the resulting bit-map representing the categories this
2340 /// current diff tree onde belongs to.
2341 diff_category
2342 diff::remove_from_local_category(diff_category c)
2343 {
2344   priv_->local_category_ = priv_->local_category_ & ~c;
2345   return priv_->local_category_;
2346 }
2347
2348 /// Set the category of the current @ref diff node.  This category
2349 /// includes the categories inherited from the children nodes of the
2350 /// current diff node.
2351 ///
2352 /// @param c the new category for the current diff node.
2353 void
2354 diff::set_category(diff_category c)
2355 {priv_->category_ = c;}
2356
2357 /// Set the local category of the current @ref diff node.
2358 ///
2359 /// @param c the new category for the current diff node.
2360 void
2361 diff::set_local_category(diff_category c)
2362 {priv_->local_category_ = c;}
2363
2364 /// Test if this diff tree node is to be filtered out for reporting
2365 /// purposes.
2366 ///
2367 /// The function tests if the categories of the diff tree node are
2368 /// "forbidden" by the context or not.
2369 ///
2370 /// @return true iff the current diff node should NOT be reported.
2371 bool
2372 diff::is_filtered_out() const
2373 {
2374   if (diff * canonical = get_canonical_diff())
2375     if (canonical->get_category() & SUPPRESSED_CATEGORY
2376         || canonical->get_category() & PRIVATE_TYPE_CATEGORY)
2377       // The canonical type was suppressed either by a user-provided
2378       // suppression specification or by a "private-type" suppression
2379       // specification..  This means all the class of equivalence of
2380       // that canonical type was suppressed.  So this node should be
2381       // suppressed too.
2382       return true;
2383   return priv_->is_filtered_out(get_category());
2384 }
2385
2386 /// Test if this diff tree node is to be filtered out for reporting
2387 /// purposes, but by considering only the categories that were *NOT*
2388 /// inherited from its children nodes.
2389 ///
2390 /// The function tests if the local categories of the diff tree node
2391 /// are "forbidden" by the context or not.
2392 ///
2393 /// @return true iff the current diff node should NOT be reported,
2394 /// with respect to its local categories.
2395 bool
2396 diff::is_filtered_out_wrt_non_inherited_categories() const
2397 {return priv_->is_filtered_out(get_local_category());}
2398
2399 /// Test if the current diff node has been suppressed by a
2400 /// user-provided suppression specification.
2401 ///
2402 /// @return true if the current diff node has been suppressed by a
2403 /// user-provided suppression list.
2404 bool
2405 diff::is_suppressed() const
2406 {
2407   bool is_private = false;
2408   return is_suppressed(is_private);
2409 }
2410
2411 /// Test if the current diff node has been suppressed by a
2412 /// user-provided suppression specification or by an auto-generated
2413 /// "private type" suppression specification.
2414 ///
2415 /// Note that private type suppressions are auto-generated from the
2416 /// path to where public headers are, as given by the user.
2417 ///
2418 /// @param is_private_type out parameter if the current diff node was
2419 /// suppressed because it's a private type then this parameter is set
2420 /// to true.
2421 ///
2422 /// @return true if the current diff node has been suppressed by a
2423 /// user-provided suppression list.
2424 bool
2425 diff::is_suppressed(bool &is_private_type) const
2426 {
2427   const suppressions_type& suppressions = context()->suppressions();
2428   for (suppressions_type::const_iterator i = suppressions.begin();
2429        i != suppressions.end();
2430        ++i)
2431     {
2432       if ((*i)->suppresses_diff(this))
2433         {
2434           if (is_private_type_suppr_spec(*i))
2435             is_private_type = true;
2436           return true;
2437         }
2438     }
2439   return false;
2440 }
2441
2442 /// Test if this diff tree node should be reported.
2443 ///
2444 /// @return true iff the current node should be reported.
2445 bool
2446 diff::to_be_reported() const
2447 {
2448   if (has_changes() && !is_filtered_out())
2449     return true;
2450   return false;
2451 }
2452
2453 /// Test if this diff tree node should be reported when considering
2454 /// the categories that were *NOT* inherited from its children nodes.
2455 ///
2456 /// @return true iff the current node should be reported.
2457 bool
2458 diff::has_local_changes_to_be_reported() const
2459 {
2460   if (has_local_changes()
2461       && !is_filtered_out_wrt_non_inherited_categories())
2462     return true;
2463   return false;
2464 }
2465
2466 /// Get a pretty representation of the current @ref diff node.
2467 ///
2468 /// This is suitable for e.g. emitting debugging traces for the diff
2469 /// tree nodes.
2470 ///
2471 /// @return the pretty representation of the diff node.
2472 const string&
2473 diff::get_pretty_representation() const
2474 {
2475   if (priv_->pretty_representation_.empty())
2476     priv_->pretty_representation_ = "empty_diff";
2477   return priv_->pretty_representation_;
2478 }
2479
2480 /// Default implementation of the hierachy chaining virtual function.
2481 ///
2482 /// There are several types of diff nodes that have logical children
2483 /// nodes; for instance, a typedef_diff has the diff of the underlying
2484 /// type as a child node.  A var_diff has the diff of the types of the
2485 /// variables as a child node, etc.
2486 ///
2487 /// But because the @ref diff base has a generic representation for
2488 /// children nodes of the all the types of @ref diff nodes (regardless
2489 /// of the specific most-derived type of diff node) that one can get
2490 /// using the method diff::children_nodes(), one need to populate that
2491 /// vector of children node.
2492 ///
2493 /// Populating that vector of children node is done by this function;
2494 /// it must be overloaded by each most-derived type of diff node that
2495 /// extends the @ref diff type.
2496 void
2497 diff::chain_into_hierarchy()
2498 {}
2499
2500 // </diff stuff>
2501
2502 // <type_diff_base stuff>
2503
2504 type_diff_base::type_diff_base(type_base_sptr   first_subject,
2505                                type_base_sptr   second_subject,
2506                                diff_context_sptr        ctxt)
2507   : diff(first_subject, second_subject, ctxt),
2508     priv_(new priv)
2509 {}
2510
2511 type_diff_base::~type_diff_base()
2512 {}
2513 // </type_diff_base stuff>
2514
2515 // <decl_diff_base stuff>
2516
2517 /// Constructor of @ref decl_diff_base.
2518 ///
2519 /// @param first_subject the first subject of the diff.
2520 ///
2521 /// @param second_subject the second subject of the diff.
2522 ///
2523 /// @param ctxt the context of the diff.  This object must stay alive
2524 /// at least during the life time of the current instance of @ref
2525 /// decl_diff_base, otherwise, memory corruption issues occur.
2526 decl_diff_base::decl_diff_base(decl_base_sptr   first_subject,
2527                                decl_base_sptr   second_subject,
2528                                diff_context_sptr        ctxt)
2529   : diff(first_subject, second_subject, ctxt),
2530     priv_(new priv)
2531 {}
2532
2533 decl_diff_base::~decl_diff_base()
2534 {}
2535
2536 // </decl_diff_base stuff>
2537
2538 // <distinct_diff stuff>
2539
2540 /// @return a pretty representation for the @ref distinct_diff node.
2541 const string&
2542 distinct_diff::get_pretty_representation() const
2543 {
2544   if (diff::priv_->pretty_representation_.empty())
2545     {
2546       std::ostringstream o;
2547       o << "distinct_diff[";
2548       if (first_subject())
2549         o << first_subject()->get_pretty_representation();
2550       else
2551         o << "null";
2552       o << ", ";
2553       if (second_subject())
2554         o << second_subject()->get_pretty_representation() ;
2555       else
2556         o << "null";
2557       o << "]" ;
2558       diff::priv_->pretty_representation_ = o.str();
2559     }
2560   return diff::priv_->pretty_representation_;
2561 }
2562
2563 /// Populate the vector of children node of the @ref diff base type
2564 /// sub-object of this instance of @distinct_diff.
2565 ///
2566 /// The children nodes can then later be retrieved using
2567 /// diff::children_nodes().
2568 void
2569 distinct_diff::chain_into_hierarchy()
2570 {
2571   ABG_ASSERT(entities_are_of_distinct_kinds(first(), second()));
2572
2573   if (diff_sptr d = compatible_child_diff())
2574     append_child_node(d);
2575 }
2576
2577 /// Constructor for @ref distinct_diff.
2578 ///
2579 /// Note that the two entities considered for the diff (and passed in
2580 /// parameter) must be of different kinds.
2581 ///
2582 /// @param first the first entity to consider for the diff.
2583 ///
2584 /// @param second the second entity to consider for the diff.
2585 ///
2586 /// @param ctxt the context of the diff.  Note that this context
2587 /// object must stay alive at least during the life time of the
2588 /// current instance of @ref distinct_diff.  Otherwise memory
2589 /// corruption issues occur.
2590 distinct_diff::distinct_diff(type_or_decl_base_sptr first,
2591                              type_or_decl_base_sptr second,
2592                              diff_context_sptr ctxt)
2593   : diff(first, second, ctxt),
2594     priv_(new priv)
2595 {ABG_ASSERT(entities_are_of_distinct_kinds(first, second));}
2596
2597 /// Finish building the current instance of @ref distinct_diff.
2598 void
2599 distinct_diff::finish_diff_type()
2600 {
2601   if (diff::priv_->finished_)
2602     return;
2603
2604   chain_into_hierarchy();
2605   diff::priv_->finished_ = true;
2606 }
2607
2608 /// Getter for the first subject of the diff.
2609 ///
2610 /// @return the first subject of the diff.
2611 const type_or_decl_base_sptr
2612 distinct_diff::first() const
2613 {return first_subject();}
2614
2615 /// Getter for the second subject of the diff.
2616 ///
2617 /// @return the second subject of the diff.
2618 const type_or_decl_base_sptr
2619 distinct_diff::second() const
2620 {return second_subject();}
2621
2622 /// Getter for the child diff of this distinct_diff instance.
2623 ///
2624 /// When a distinct_diff has two subjects that are different but
2625 /// compatible, then the distinct_diff instance has a child diff node
2626 /// (named the compatible child diff) that is the diff between the two
2627 /// subjects stripped from their typedefs.  Otherwise, the compatible
2628 /// child diff is nul.
2629 ///
2630 /// Note that two diff subjects (that compare different) are
2631 /// considered compatible if stripping typedefs out of them makes them
2632 /// comparing equal.
2633 ///
2634 /// @return the compatible child diff node, if any.  Otherwise, null.
2635 const diff_sptr
2636 distinct_diff::compatible_child_diff() const
2637 {
2638   if (!priv_->compatible_child_diff)
2639     {
2640       type_base_sptr fs = strip_typedef(is_type(first())),
2641         ss = strip_typedef(is_type(second()));
2642
2643       if (fs && ss
2644           && !entities_are_of_distinct_kinds(get_type_declaration(fs),
2645                                              get_type_declaration(ss)))
2646         priv_->compatible_child_diff = compute_diff(get_type_declaration(fs),
2647                                                     get_type_declaration(ss),
2648                                                     context());
2649     }
2650   return priv_->compatible_child_diff;
2651 }
2652
2653 /// Test if the two arguments are of different kind, or that are both
2654 /// NULL.
2655 ///
2656 /// @param first the first argument to test for similarity in kind.
2657 ///
2658 /// @param second the second argument to test for similarity in kind.
2659 ///
2660 /// @return true iff the two arguments are of different kind.
2661 bool
2662 distinct_diff::entities_are_of_distinct_kinds(type_or_decl_base_sptr first,
2663                                               type_or_decl_base_sptr second)
2664 {
2665   if (!!first != !!second)
2666     return true;
2667   if (!first && !second)
2668     // We do consider diffs of two empty decls as a diff of distinct
2669     // kinds, for now.
2670     return true;
2671   if (first == second)
2672     return false;
2673
2674   const type_or_decl_base &f = *first, &s = *second;
2675   return typeid(f) != typeid(s);
2676 }
2677
2678 /// @return true if the two subjects of the diff are different, false
2679 /// otherwise.
2680 bool
2681 distinct_diff::has_changes() const
2682 {return first() != second();}
2683
2684 /// @return the kind of local change carried by the current diff node.
2685 /// The value returned is zero if the current node carries no local
2686 /// change.
2687 enum change_kind
2688 distinct_diff::has_local_changes() const
2689 {
2690   // Changes on a distinct_diff are all local.
2691   if (has_changes())
2692     return (LOCAL_CHANGE_KIND | LOCAL_TYPE_CHANGE_KIND);
2693   return NO_CHANGE_KIND;
2694 }
2695
2696 /// Emit a report about the current diff instance.
2697 ///
2698 /// @param out the output stream to send the diff report to.
2699 ///
2700 /// @param indent the indentation string to use in the report.
2701 void
2702 distinct_diff::report(ostream& out, const string& indent) const
2703 {
2704   context()->get_reporter()->report(*this, out, indent);
2705 }
2706
2707 /// Try to diff entities that are of distinct kinds.
2708 ///
2709 /// @param first the first entity to consider for the diff.
2710 ///
2711 /// @param second the second entity to consider for the diff.
2712 ///
2713 /// @param ctxt the context of the diff.
2714 ///
2715 /// @return a non-null diff if a diff object could be built, null
2716 /// otherwise.
2717 distinct_diff_sptr
2718 compute_diff_for_distinct_kinds(const type_or_decl_base_sptr first,
2719                                 const type_or_decl_base_sptr second,
2720                                 diff_context_sptr ctxt)
2721 {
2722   if (!distinct_diff::entities_are_of_distinct_kinds(first, second))
2723     return distinct_diff_sptr();
2724
2725   distinct_diff_sptr result(new distinct_diff(first, second, ctxt));
2726
2727   ctxt->initialize_canonical_diff(result);
2728
2729   return result;
2730 }
2731
2732 /// </distinct_diff stuff>
2733
2734 /// Try to compute a diff on two instances of DiffType representation.
2735 ///
2736 /// The function template performs the diff if and only if the decl
2737 /// representations are of a DiffType.
2738 ///
2739 /// @tparm DiffType the type of instances to diff.
2740 ///
2741 /// @param first the first representation of decl to consider in the
2742 /// diff computation.
2743 ///
2744 /// @param second the second representation of decl to consider in the
2745 /// diff computation.
2746 ///
2747 /// @param ctxt the diff context to use.
2748 ///
2749 ///@return the diff of the two types @p first and @p second if and
2750 ///only if they represent the parametrized type DiffType.  Otherwise,
2751 ///returns a NULL pointer value.
2752 template<typename DiffType>
2753 diff_sptr
2754 try_to_diff(const type_or_decl_base_sptr first,
2755             const type_or_decl_base_sptr second,
2756             diff_context_sptr ctxt)
2757 {
2758   if (shared_ptr<DiffType> f =
2759       dynamic_pointer_cast<DiffType>(first))
2760     {
2761       shared_ptr<DiffType> s =
2762         dynamic_pointer_cast<DiffType>(second);
2763       if (!s)
2764         return diff_sptr();
2765       return compute_diff(f, s, ctxt);
2766     }
2767   return diff_sptr();
2768 }
2769
2770
2771 /// This is a specialization of @ref try_to_diff() template to diff
2772 /// instances of @ref class_decl.
2773 ///
2774 /// @param first the first representation of decl to consider in the
2775 /// diff computation.
2776 ///
2777 /// @param second the second representation of decl to consider in the
2778 /// diff computation.
2779 ///
2780 /// @param ctxt the diff context to use.
2781 template<>
2782 diff_sptr
2783 try_to_diff<class_decl>(const type_or_decl_base_sptr first,
2784                         const type_or_decl_base_sptr second,
2785                         diff_context_sptr ctxt)
2786 {
2787   if (class_decl_sptr f =
2788       dynamic_pointer_cast<class_decl>(first))
2789     {
2790       class_decl_sptr s = dynamic_pointer_cast<class_decl>(second);
2791       if (!s)
2792         return diff_sptr();
2793
2794       if (f->get_is_declaration_only())
2795         {
2796           class_decl_sptr f2 = f->get_definition_of_declaration();
2797           if (f2)
2798             f = f2;
2799         }
2800       if (s->get_is_declaration_only())
2801         {
2802           class_decl_sptr s2 = s->get_definition_of_declaration();
2803           if (s2)
2804             s = s2;
2805         }
2806       return compute_diff(f, s, ctxt);
2807     }
2808   return diff_sptr();
2809 }
2810
2811 /// Try to diff entities that are of distinct kinds.
2812 ///
2813 /// @param first the first entity to consider for the diff.
2814 ///
2815 /// @param second the second entity to consider for the diff.
2816 ///
2817 /// @param ctxt the context of the diff.
2818 ///
2819 /// @return a non-null diff if a diff object could be built, null
2820 /// otherwise.
2821 static diff_sptr
2822 try_to_diff_distinct_kinds(const type_or_decl_base_sptr first,
2823                            const type_or_decl_base_sptr second,
2824                            diff_context_sptr ctxt)
2825 {return compute_diff_for_distinct_kinds(first, second, ctxt);}
2826
2827 /// Compute the difference between two types.
2828 ///
2829 /// The function considers every possible types known to libabigail
2830 /// and runs the appropriate diff function on them.
2831 ///
2832 /// Whenever a new kind of type decl is supported by abigail, if we
2833 /// want to be able to diff two instances of it, we need to update
2834 /// this function to support it.
2835 ///
2836 /// @param first the first type decl to consider for the diff
2837 ///
2838 /// @param second the second type decl to consider for the diff.
2839 ///
2840 /// @param ctxt the diff context to use.
2841 ///
2842 /// @return the resulting diff.  It's a pointer to a descendent of
2843 /// abigail::comparison::diff.
2844 static diff_sptr
2845 compute_diff_for_types(const type_or_decl_base_sptr& first,
2846                        const type_or_decl_base_sptr& second,
2847                        const diff_context_sptr& ctxt)
2848 {
2849   type_or_decl_base_sptr f = first;
2850   type_or_decl_base_sptr s = second;
2851
2852   // Look through no-op qualified types.
2853   f = look_through_no_op_qualified_type(is_type(f));
2854   s = look_through_no_op_qualified_type(is_type(s));
2855
2856   diff_sptr d;
2857
2858   ((d = try_to_diff<type_decl>(f, s, ctxt))
2859    ||(d = try_to_diff<enum_type_decl>(f, s, ctxt))
2860    ||(d = try_to_diff<union_decl>(f, s,ctxt))
2861    ||(d = try_to_diff<class_decl>(f, s,ctxt))
2862    ||(d = try_to_diff<pointer_type_def>(f, s, ctxt))
2863    ||(d = try_to_diff<reference_type_def>(f, s, ctxt))
2864    ||(d = try_to_diff<array_type_def>(f, s, ctxt))
2865    ||(d = try_to_diff<qualified_type_def>(f, s, ctxt))
2866    ||(d = try_to_diff<typedef_decl>(f, s, ctxt))
2867    ||(d = try_to_diff<function_type>(f, s, ctxt))
2868    ||(d = try_to_diff_distinct_kinds(f, s, ctxt)));
2869
2870   ABG_ASSERT(d);
2871
2872   return d;
2873 }
2874
2875 diff_category
2876 operator|(diff_category c1, diff_category c2)
2877 {return static_cast<diff_category>(static_cast<unsigned>(c1)
2878                                    | static_cast<unsigned>(c2));}
2879
2880 diff_category&
2881 operator|=(diff_category& c1, diff_category c2)
2882 {
2883   c1 = c1 | c2;
2884   return c1;
2885 }
2886
2887 diff_category&
2888 operator&=(diff_category& c1, diff_category c2)
2889 {
2890   c1 = c1 & c2;
2891   return c1;
2892 }
2893
2894 diff_category
2895 operator^(diff_category c1, diff_category c2)
2896 {return static_cast<diff_category>(static_cast<unsigned>(c1)
2897                                    ^ static_cast<unsigned>(c2));}
2898
2899 diff_category
2900 operator&(diff_category c1, diff_category c2)
2901 {return static_cast<diff_category>(static_cast<unsigned>(c1)
2902                                    & static_cast<unsigned>(c2));}
2903
2904 diff_category
2905 operator~(diff_category c)
2906 {return static_cast<diff_category>(~static_cast<unsigned>(c));}
2907
2908
2909 /// Getter of a bitmap made of the set of change categories that are
2910 /// considered harmless.
2911 ///
2912 /// @return the bitmap made of the set of change categories that are
2913 /// considered harmless.
2914 diff_category
2915 get_default_harmless_categories_bitmap()
2916 {
2917   return (abigail::comparison::ACCESS_CHANGE_CATEGORY
2918           | abigail::comparison::COMPATIBLE_TYPE_CHANGE_CATEGORY
2919           | abigail::comparison::HARMLESS_DECL_NAME_CHANGE_CATEGORY
2920           | abigail::comparison::NON_VIRT_MEM_FUN_CHANGE_CATEGORY
2921           | abigail::comparison::STATIC_DATA_MEMBER_CHANGE_CATEGORY
2922           | abigail::comparison::HARMLESS_ENUM_CHANGE_CATEGORY
2923           | abigail::comparison::HARMLESS_SYMBOL_ALIAS_CHANGE_CATEORY
2924           | abigail::comparison::HARMLESS_UNION_CHANGE_CATEGORY
2925           | abigail::comparison::CLASS_DECL_ONLY_DEF_CHANGE_CATEGORY
2926           | abigail::comparison::FN_PARM_TYPE_TOP_CV_CHANGE_CATEGORY
2927           | abigail::comparison::FN_PARM_TYPE_CV_CHANGE_CATEGORY
2928           | abigail::comparison::FN_RETURN_TYPE_CV_CHANGE_CATEGORY
2929           | abigail::comparison::VAR_TYPE_CV_CHANGE_CATEGORY
2930           | abigail::comparison::VOID_PTR_TO_PTR_CHANGE_CATEGORY
2931           | abigail::comparison::BENIGN_INFINITE_ARRAY_CHANGE_CATEGORY);
2932 }
2933
2934 /// Getter of a bitmap made of the set of change categories that are
2935 /// considered harmful.
2936 ///
2937 /// @return the bitmap made of the set of change categories that are
2938 /// considered harmful.
2939 diff_category
2940 get_default_harmful_categories_bitmap()
2941 {
2942   return (abigail::comparison::SIZE_OR_OFFSET_CHANGE_CATEGORY
2943           | abigail::comparison::VIRTUAL_MEMBER_CHANGE_CATEGORY);
2944 }
2945
2946 /// Serialize an instance of @ref diff_category to an output stream.
2947 ///
2948 /// @param o the output stream to serialize @p c to.
2949 ///
2950 /// @param c the instance of diff_category to serialize.
2951 ///
2952 /// @return the output stream to serialize @p c to.
2953 ostream&
2954 operator<<(ostream& o, diff_category c)
2955 {
2956   bool emitted_a_category = false;
2957
2958   if (c == NO_CHANGE_CATEGORY)
2959     {
2960       o << "NO_CHANGE_CATEGORY";
2961       emitted_a_category = true;
2962     }
2963
2964   if (c & ACCESS_CHANGE_CATEGORY)
2965     {
2966       if (emitted_a_category)
2967         o << "|";
2968       o << "ACCESS_CHANGE_CATEGORY";
2969       emitted_a_category |= true;
2970     }
2971
2972   if (c & COMPATIBLE_TYPE_CHANGE_CATEGORY)
2973     {
2974       if (emitted_a_category)
2975         o << "|";
2976       o << "COMPATIBLE_TYPE_CHANGE_CATEGORY";
2977       emitted_a_category |= true;
2978     }
2979
2980   if (c & HARMLESS_DECL_NAME_CHANGE_CATEGORY)
2981     {
2982       if (emitted_a_category)
2983         o << "|";
2984       o << "HARMLESS_DECL_NAME_CHANGE_CATEGORY";
2985       emitted_a_category |= true;
2986     }
2987
2988   if (c & NON_VIRT_MEM_FUN_CHANGE_CATEGORY)
2989     {
2990       if (emitted_a_category)
2991         o << "|";
2992       o << "NON_VIRT_MEM_FUN_CHANGE_CATEGORY";
2993       emitted_a_category |= true;
2994     }
2995
2996   if (c & STATIC_DATA_MEMBER_CHANGE_CATEGORY)
2997     {
2998       if (emitted_a_category)
2999         o << "|";
3000       o << "STATIC_DATA_MEMBER_CHANGE_CATEGORY";
3001       emitted_a_category |= true;
3002     }
3003
3004   if (c & HARMLESS_ENUM_CHANGE_CATEGORY)
3005     {
3006       if (emitted_a_category)
3007         o << "|";
3008       o << "HARMLESS_ENUM_CHANGE_CATEGORY";
3009       emitted_a_category |= true;
3010     }
3011
3012   if (c & HARMLESS_SYMBOL_ALIAS_CHANGE_CATEORY)
3013     {
3014       if (emitted_a_category)
3015         o << "|";
3016       o << "HARMLESS_SYMBOL_ALIAS_CHANGE_CATEORY";
3017       emitted_a_category |= true;
3018     }
3019
3020   if (c & HARMLESS_UNION_CHANGE_CATEGORY)
3021     {
3022       if (emitted_a_category)
3023         o << "|";
3024       o << "HARMLESS_UNION_CHANGE_CATEORY";
3025       emitted_a_category |= true;
3026     }
3027
3028   if (c & SUPPRESSED_CATEGORY)
3029     {
3030       if (emitted_a_category)
3031         o << "|";
3032       o << "SUPPRESSED_CATEGORY";
3033       emitted_a_category |= true;
3034     }
3035
3036   if (c & PRIVATE_TYPE_CATEGORY)
3037     {
3038       if (emitted_a_category)
3039         o << "|";
3040       o << "PRIVATE_TYPE_CATEGORY";
3041       emitted_a_category |= true;
3042     }
3043
3044   if (c & SIZE_OR_OFFSET_CHANGE_CATEGORY)
3045     {
3046       if (emitted_a_category)
3047         o << "|";
3048       o << "SIZE_OR_OFFSET_CHANGE_CATEGORY";
3049       emitted_a_category |= true;
3050     }
3051
3052   if (c & VIRTUAL_MEMBER_CHANGE_CATEGORY)
3053     {
3054       if (emitted_a_category)
3055         o << "|";
3056       o << "VIRTUAL_MEMBER_CHANGE_CATEGORY";
3057       emitted_a_category |= true;
3058     }
3059
3060   if (c & REDUNDANT_CATEGORY)
3061     {
3062       if (emitted_a_category)
3063         o << "|";
3064       o << "REDUNDANT_CATEGORY";
3065       emitted_a_category |= true;
3066     }
3067
3068   if (c & CLASS_DECL_ONLY_DEF_CHANGE_CATEGORY)
3069     {
3070       if (emitted_a_category)
3071         o << "|";
3072       o << "CLASS_DECL_ONLY_DEF_CHANGE_CATEGORY";
3073       emitted_a_category |= true;
3074     }
3075
3076   if (c & FN_PARM_TYPE_TOP_CV_CHANGE_CATEGORY)
3077     {
3078       if (emitted_a_category)
3079         o << "|";
3080       o << "FN_PARM_TYPE_TOP_CV_CHANGE_CATEGORY";
3081       emitted_a_category |= true;
3082     }
3083
3084   if (c & FN_PARM_TYPE_CV_CHANGE_CATEGORY)
3085     {
3086       if (emitted_a_category)
3087         o << "|";
3088       o << "FN_PARM_TYPE_CV_CHANGE_CATEGORY";
3089       emitted_a_category |= true;
3090     }
3091
3092     if (c & FN_RETURN_TYPE_CV_CHANGE_CATEGORY)
3093     {
3094       if (emitted_a_category)
3095         o << "|";
3096       o << "FN_RETURN_TYPE_CV_CHANGE_CATEGORY";
3097       emitted_a_category |= true;
3098     }
3099
3100    if (c & VAR_TYPE_CV_CHANGE_CATEGORY)
3101     {
3102       if (emitted_a_category)
3103         o << "|";
3104       o << "VAR_TYPE_CV_CHANGE_CATEGORY";
3105       emitted_a_category |= true;
3106     }
3107
3108     if (c & VOID_PTR_TO_PTR_CHANGE_CATEGORY)
3109     {
3110       if (emitted_a_category)
3111         o << "|";
3112       o << "VOID_PTR_TO_PTR_CHANGE_CATEGORY";
3113       emitted_a_category |= true;
3114     }
3115
3116     if (c & BENIGN_INFINITE_ARRAY_CHANGE_CATEGORY)
3117     {
3118       if (emitted_a_category)
3119         o << "|";
3120       o << "BENIGN_INFINITE_ARRAY_CHANGE_CATEGORY";
3121       emitted_a_category |= true;
3122     }
3123
3124   return o;
3125 }
3126
3127 /// Compute the difference between two decls.
3128 ///
3129 /// The function consider every possible decls known to libabigail and
3130 /// runs the appropriate diff function on them.
3131 ///
3132 /// Whenever a new kind of non-type decl is supported by abigail, if
3133 /// we want to be able to diff two instances of it, we need to update
3134 /// this function to support it.
3135 ///
3136 /// @param first the first decl to consider for the diff
3137 ///
3138 /// @param second the second decl to consider for the diff.
3139 ///
3140 /// @param ctxt the diff context to use.
3141 ///
3142 /// @return the resulting diff.
3143 static diff_sptr
3144 compute_diff_for_decls(const decl_base_sptr first,
3145                        const decl_base_sptr second,
3146                        diff_context_sptr ctxt)
3147 {
3148
3149   diff_sptr d;
3150
3151   ((d = try_to_diff<function_decl>(first, second, ctxt))
3152    || (d = try_to_diff<var_decl>(first, second, ctxt))
3153    || (d = try_to_diff_distinct_kinds(first, second, ctxt)));
3154
3155    ABG_ASSERT(d);
3156
3157   return d;
3158 }
3159
3160 /// Compute the difference between two decls.  The decls can represent
3161 /// either type declarations, or non-type declaration.
3162 ///
3163 /// Note that the two decls must have been created in the same @ref
3164 /// environment, otherwise, this function aborts.
3165 ///
3166 /// @param first the first decl to consider.
3167 ///
3168 /// @param second the second decl to consider.
3169 ///
3170 /// @param ctxt the diff context to use.
3171 ///
3172 /// @return the resulting diff, or NULL if the diff could not be
3173 /// computed.
3174 diff_sptr
3175 compute_diff(const decl_base_sptr       first,
3176              const decl_base_sptr       second,
3177              diff_context_sptr          ctxt)
3178 {
3179   if (!first || !second)
3180     return diff_sptr();
3181
3182   ABG_ASSERT(first->get_environment() == second->get_environment());
3183
3184   diff_sptr d;
3185   if (is_type(first) && is_type(second))
3186     d = compute_diff_for_types(first, second, ctxt);
3187   else
3188     d = compute_diff_for_decls(first, second, ctxt);
3189   ABG_ASSERT(d);
3190   return d;
3191 }
3192
3193 /// Compute the difference between two types.
3194 ///
3195 /// Note that the two types must have been created in the same @ref
3196 /// environment, otherwise, this function aborts.
3197 ///
3198 /// @param first the first type to consider.
3199 ///
3200 /// @param second the second type to consider.
3201 ///
3202 /// @param ctxt the diff context to use.
3203 ///
3204 /// @return the resulting diff, or NULL if the diff couldn't be
3205 /// computed.
3206 diff_sptr
3207 compute_diff(const type_base_sptr       first,
3208              const type_base_sptr       second,
3209              diff_context_sptr          ctxt)
3210 {
3211   decl_base_sptr f = get_type_declaration(first),
3212     s = get_type_declaration(second);
3213
3214   if (first && second)
3215     ABG_ASSERT(first->get_environment() == second->get_environment());
3216
3217   diff_sptr d = compute_diff_for_types(f,s, ctxt);
3218   ABG_ASSERT(d);
3219   return d;
3220 }
3221
3222 /// Get a copy of the pretty representation of a diff node.
3223 ///
3224 /// @param d the diff node to consider.
3225 ///
3226 /// @return the pretty representation string.
3227 string
3228 get_pretty_representation(diff* d)
3229 {
3230   if (!d)
3231     return "";
3232   string prefix= "diff of ";
3233   return prefix + get_pretty_representation(d->first_subject());
3234 }
3235
3236 // <var_diff stuff>
3237
3238 /// Populate the vector of children node of the @ref diff base type
3239 /// sub-object of this instance of @ref var_diff.
3240 ///
3241 /// The children node can then later be retrieved using
3242 /// diff::children_node().
3243 void
3244 var_diff::chain_into_hierarchy()
3245 {append_child_node(type_diff());}
3246
3247 /// @return the pretty representation for this current instance of
3248 /// @ref var_diff.
3249 const string&
3250 var_diff::get_pretty_representation() const
3251 {
3252   if (diff::priv_->pretty_representation_.empty())
3253     {
3254       std::ostringstream o;
3255       o << "var_diff["
3256         << first_subject()->get_pretty_representation()
3257         << ", "
3258         << second_subject()->get_pretty_representation()
3259         << "]";
3260       diff::priv_->pretty_representation_ = o.str();
3261     }
3262   return diff::priv_->pretty_representation_;
3263 }
3264 /// Constructor for @ref var_diff.
3265 ///
3266 /// @param first the first instance of @ref var_decl to consider in
3267 /// the diff.
3268 ///
3269 /// @param second the second instance of @ref var_decl to consider in
3270 /// the diff.
3271 ///
3272 /// @param type_diff the diff between types of the instances of
3273 /// var_decl.
3274 ///
3275 /// @param ctxt the diff context to use.
3276 var_diff::var_diff(var_decl_sptr        first,
3277                    var_decl_sptr        second,
3278                    diff_sptr            type_diff,
3279                    diff_context_sptr    ctxt)
3280   : decl_diff_base(first, second, ctxt),
3281     priv_(new priv)
3282 {priv_->type_diff_ = type_diff;}
3283
3284 /// Finish building the current instance of @ref var_diff.
3285 void
3286 var_diff::finish_diff_type()
3287 {
3288   if (diff::priv_->finished_)
3289     return;
3290   chain_into_hierarchy();
3291   diff::priv_->finished_ = true;
3292 }
3293
3294 /// Getter for the first @ref var_decl of the diff.
3295 ///
3296 /// @return the first @ref var_decl of the diff.
3297 var_decl_sptr
3298 var_diff::first_var() const
3299 {return dynamic_pointer_cast<var_decl>(first_subject());}
3300
3301 /// Getter for the second @ref var_decl of the diff.
3302 ///
3303 /// @return the second @ref var_decl of the diff.
3304 var_decl_sptr
3305 var_diff::second_var() const
3306 {return dynamic_pointer_cast<var_decl>(second_subject());}
3307
3308 /// Getter for the diff of the types of the instances of @ref
3309 /// var_decl.
3310 ///
3311 /// @return the diff of the types of the instances of @ref var_decl.
3312 diff_sptr
3313 var_diff::type_diff() const
3314 {
3315   if (priv_->type_diff_.expired())
3316     {
3317       diff_sptr d = compute_diff(first_var()->get_type(),
3318                                        second_var()->get_type(),
3319                                        context());
3320       context()->keep_diff_alive(d);
3321       priv_->type_diff_ = d;
3322     }
3323   return diff_sptr(priv_->type_diff_);
3324 }
3325
3326 /// Return true iff the diff node has a change.
3327 ///
3328 /// @return true iff the diff node has a change.
3329 bool
3330 var_diff::has_changes() const
3331 {return *first_var() != *second_var();}
3332
3333 /// @return the kind of local change carried by the current diff node.
3334 /// The value returned is zero if the current node carries no local
3335 /// change.
3336 enum change_kind
3337 var_diff::has_local_changes() const
3338 {
3339   ir::change_kind k = ir::NO_CHANGE_KIND;
3340   if (!equals(*first_var(), *second_var(), &k))
3341     return k & ir::ALL_LOCAL_CHANGES_MASK;
3342   return ir::NO_CHANGE_KIND;
3343 }
3344
3345 /// Report the diff in a serialized form.
3346 ///
3347 /// @param out the stream to serialize the diff to.
3348 ///
3349 /// @param indent the prefix to use for the indentation of this
3350 /// serialization.
3351 void
3352 var_diff::report(ostream& out, const string& indent) const
3353 {
3354   context()->get_reporter()->report(*this, out, indent);
3355 }
3356
3357 /// Compute the diff between two instances of @ref var_decl.
3358 ///
3359 /// Note that the two decls must have been created in the same @ref
3360 /// environment, otherwise, this function aborts.
3361 ///
3362 /// @param first the first @ref var_decl to consider for the diff.
3363 ///
3364 /// @param second the second @ref var_decl to consider for the diff.
3365 ///
3366 /// @param ctxt the diff context to use.
3367 ///
3368 /// @return the resulting diff between the two @ref var_decl.
3369 var_diff_sptr
3370 compute_diff(const var_decl_sptr        first,
3371              const var_decl_sptr        second,
3372              diff_context_sptr          ctxt)
3373 {
3374   if (first && second)
3375     ABG_ASSERT(first->get_environment() == second->get_environment());
3376
3377   var_diff_sptr d(new var_diff(first, second, diff_sptr(), ctxt));
3378   ctxt->initialize_canonical_diff(d);
3379
3380   return d;
3381 }
3382
3383 // </var_diff stuff>
3384
3385 // <pointer_type_def stuff>
3386
3387 /// Populate the vector of children node of the @ref diff base type
3388 /// sub-object of this instance of @ref pointer_diff.
3389 ///
3390 /// The children node can then later be retrieved using
3391 /// diff::children_node().
3392 void
3393 pointer_diff::chain_into_hierarchy()
3394 {append_child_node(underlying_type_diff());}
3395
3396 /// Constructor for a pointer_diff.
3397 ///
3398 /// @param first the first pointer to consider for the diff.
3399 ///
3400 /// @param second the secon pointer to consider for the diff.
3401 ///
3402 /// @param ctxt the diff context to use.
3403 pointer_diff::pointer_diff(pointer_type_def_sptr        first,
3404                            pointer_type_def_sptr        second,
3405                            diff_sptr                    underlying,
3406                            diff_context_sptr            ctxt)
3407   : type_diff_base(first, second, ctxt),
3408     priv_(new priv(underlying))
3409 {}
3410
3411 /// Finish building the current instance of @ref pointer_diff.
3412 void
3413 pointer_diff::finish_diff_type()
3414 {
3415   if (diff::priv_->finished_)
3416     return;
3417   chain_into_hierarchy();
3418   diff::priv_->finished_ = true;
3419 }
3420
3421 /// Getter for the first subject of a pointer diff
3422 ///
3423 /// @return the first pointer considered in this pointer diff.
3424 const pointer_type_def_sptr
3425 pointer_diff::first_pointer() const
3426 {return dynamic_pointer_cast<pointer_type_def>(first_subject());}
3427
3428 /// Getter for the second subject of a pointer diff
3429 ///
3430 /// @return the second pointer considered in this pointer diff.
3431 const pointer_type_def_sptr
3432 pointer_diff::second_pointer() const
3433 {return dynamic_pointer_cast<pointer_type_def>(second_subject());}
3434
3435 /// @return the pretty represenation for the current instance of @ref
3436 /// pointer_diff.
3437 const string&
3438 pointer_diff::get_pretty_representation() const
3439 {
3440   if (diff::priv_->pretty_representation_.empty())
3441     {
3442       std::ostringstream o;
3443       o << "pointer_diff["
3444         << first_subject()->get_pretty_representation()
3445         << ", "
3446         << second_subject()->get_pretty_representation()
3447         << "]";
3448       diff::priv_->pretty_representation_ = o.str();
3449     }
3450   return diff::priv_->pretty_representation_;
3451 }
3452
3453 /// Return true iff the current diff node carries a change.
3454 ///
3455 /// @return true iff the current diff node carries a change.
3456 bool
3457 pointer_diff::has_changes() const
3458 {return first_pointer() != second_pointer();}
3459
3460 /// @return the kind of local change carried by the current diff node.
3461 /// The value returned is zero if the current node carries no local
3462 /// change.
3463 enum change_kind
3464 pointer_diff::has_local_changes() const
3465 {
3466   ir::change_kind k = ir::NO_CHANGE_KIND;
3467   if (!equals(*first_pointer(), *second_pointer(), &k))
3468     return k & ir::ALL_LOCAL_CHANGES_MASK;
3469   return ir::NO_CHANGE_KIND;
3470 }
3471
3472 /// Getter for the diff between the pointed-to types of the pointers
3473 /// of this diff.
3474 ///
3475 /// @return the diff between the pointed-to types.
3476 diff_sptr
3477 pointer_diff::underlying_type_diff() const
3478 {return priv_->underlying_type_diff_;}
3479
3480 /// Setter for the diff between the pointed-to types of the pointers
3481 /// of this diff.
3482 ///
3483 /// @param d the new diff between the pointed-to types of the pointers
3484 /// of this diff.
3485 void
3486 pointer_diff::underlying_type_diff(const diff_sptr d)
3487 {priv_->underlying_type_diff_ = d;}
3488
3489 /// Report the diff in a serialized form.
3490 ///
3491 /// @param out the stream to serialize the diff to.
3492 ///
3493 /// @param indent the prefix to use for the indentation of this
3494 /// serialization.
3495 void
3496 pointer_diff::report(ostream& out, const string& indent) const
3497 {
3498   context()->get_reporter()->report(*this, out, indent);
3499 }
3500
3501 /// Compute the diff between between two pointers.
3502 ///
3503 /// Note that the two types must have been created in the same @ref
3504 /// environment, otherwise, this function aborts.
3505 ///
3506 /// @param first the pointer to consider for the diff.
3507 ///
3508 /// @param second the pointer to consider for the diff.
3509 ///
3510 /// @return the resulting diff between the two pointers.
3511 ///
3512 /// @param ctxt the diff context to use.
3513 pointer_diff_sptr
3514 compute_diff(pointer_type_def_sptr      first,
3515              pointer_type_def_sptr      second,
3516              diff_context_sptr          ctxt)
3517 {
3518   if (first && second)
3519     ABG_ASSERT(first->get_environment() == second->get_environment());
3520
3521   diff_sptr d = compute_diff_for_types(first->get_pointed_to_type(),
3522                                        second->get_pointed_to_type(),
3523                                        ctxt);
3524   pointer_diff_sptr result(new pointer_diff(first, second, d, ctxt));
3525   ctxt->initialize_canonical_diff(result);
3526
3527   return result;
3528 }
3529
3530 // </pointer_type_def>
3531
3532 // <array_type_def>
3533
3534 /// Populate the vector of children node of the @ref diff base type
3535 /// sub-object of this instance of @ref array_diff.
3536 ///
3537 /// The children node can then later be retrieved using
3538 /// diff::children_node().
3539 void
3540 array_diff::chain_into_hierarchy()
3541 {append_child_node(element_type_diff());}
3542
3543 /// Constructor for array_diff
3544 ///
3545 /// @param first the first array_type of the diff.
3546 ///
3547 /// @param second the second array_type of the diff.
3548 ///
3549 /// @param element_type_diff the diff between the two array element
3550 /// types.
3551 ///
3552 /// @param ctxt the diff context to use.
3553 array_diff::array_diff(const array_type_def_sptr        first,
3554                        const array_type_def_sptr        second,
3555                        diff_sptr                        element_type_diff,
3556                        diff_context_sptr                ctxt)
3557   : type_diff_base(first, second, ctxt),
3558     priv_(new priv(element_type_diff))
3559 {}
3560
3561 /// Finish building the current instance of @ref array_diff.
3562 void
3563 array_diff::finish_diff_type()
3564 {
3565   if (diff::priv_->finished_)
3566     return;
3567   chain_into_hierarchy();
3568   diff::priv_->finished_ = true;
3569 }
3570
3571 /// Getter for the first array of the diff.
3572 ///
3573 /// @return the first array of the diff.
3574 const array_type_def_sptr
3575 array_diff::first_array() const
3576 {return dynamic_pointer_cast<array_type_def>(first_subject());}
3577
3578 /// Getter for the second array of the diff.
3579 ///
3580 /// @return for the second array of the diff.
3581 const array_type_def_sptr
3582 array_diff::second_array() const
3583 {return dynamic_pointer_cast<array_type_def>(second_subject());}
3584
3585 /// Getter for the diff between the two types of array elements.
3586 ///
3587 /// @return the diff between the two types of array elements.
3588 const diff_sptr&
3589 array_diff::element_type_diff() const
3590 {return priv_->element_type_diff_;}
3591
3592 /// Setter for the diff between the two array element types.
3593 ///
3594 /// @param d the new diff betweend the two array element types.
3595 void
3596 array_diff::element_type_diff(diff_sptr d)
3597 {priv_->element_type_diff_ = d;}
3598
3599 /// @return the pretty representation for the current instance of @ref
3600 /// array_diff.
3601 const string&
3602 array_diff::get_pretty_representation() const
3603 {
3604   if (diff::priv_->pretty_representation_.empty())
3605     {
3606       std::ostringstream o;
3607       o << "array_diff["
3608         << first_subject()->get_pretty_representation()
3609         << ", "
3610         << second_subject()->get_pretty_representation()
3611         << "]";
3612       diff::priv_->pretty_representation_ = o.str();
3613     }
3614   return diff::priv_->pretty_representation_;
3615 }
3616
3617 /// Return true iff the current diff node carries a change.
3618 ///
3619 /// @return true iff the current diff node carries a change.
3620 bool
3621 array_diff::has_changes() const
3622 {
3623   bool l = false;
3624
3625   //  the array element types match check for differing dimensions
3626   //  etc...
3627   array_type_def_sptr
3628     f = dynamic_pointer_cast<array_type_def>(first_subject()),
3629     s = dynamic_pointer_cast<array_type_def>(second_subject());
3630
3631   if (f->get_name() != s->get_name())
3632     l |= true;
3633   if (f->get_size_in_bits() != s->get_size_in_bits())
3634     l |= true;
3635   if (f->get_alignment_in_bits() != s->get_alignment_in_bits())
3636     l |= true;
3637
3638   l |=  element_type_diff()
3639     ? element_type_diff()->has_changes()
3640     : false;
3641
3642   return l;
3643 }
3644
3645
3646 /// @return the kind of local change carried by the current diff node.
3647 /// The value returned is zero if the current node carries no local
3648 /// change.
3649 enum change_kind
3650 array_diff::has_local_changes() const
3651 {
3652   ir::change_kind k = ir::NO_CHANGE_KIND;
3653   if (!equals(*first_array(), *second_array(), &k))
3654     return k & ir::ALL_LOCAL_CHANGES_MASK;
3655   return ir::NO_CHANGE_KIND;;
3656 }
3657
3658 /// Report the diff in a serialized form.
3659 ///
3660 /// @param out the output stream to serialize the dif to.
3661 ///
3662 /// @param indent the string to use for indenting the report.
3663 void
3664 array_diff::report(ostream& out, const string& indent) const
3665 {
3666   context()->get_reporter()->report(*this, out, indent);
3667 }
3668
3669 /// Compute the diff between two arrays.
3670 ///
3671 /// Note that the two types must have been created in the same @ref
3672 /// environment, otherwise, this function aborts.
3673 ///
3674 /// @param first the first array to consider for the diff.
3675 ///
3676 /// @param second the second array to consider for the diff.
3677 ///
3678 /// @param ctxt the diff context to use.
3679 array_diff_sptr
3680 compute_diff(array_type_def_sptr        first,
3681              array_type_def_sptr        second,
3682              diff_context_sptr          ctxt)
3683 {
3684   if (first && second)
3685     ABG_ASSERT(first->get_environment() == second->get_environment());
3686
3687   diff_sptr d = compute_diff_for_types(first->get_element_type(),
3688                                        second->get_element_type(),
3689                                        ctxt);
3690   array_diff_sptr result(new array_diff(first, second, d, ctxt));
3691   ctxt->initialize_canonical_diff(result);
3692   return result;
3693 }
3694 // </array_type_def>
3695
3696 // <reference_type_def>
3697
3698 /// Populate the vector of children node of the @ref diff base type
3699 /// sub-object of this instance of @ref reference_diff.
3700 ///
3701 /// The children node can then later be retrieved using
3702 /// diff::children_node().
3703 void
3704 reference_diff::chain_into_hierarchy()
3705 {append_child_node(underlying_type_diff());}
3706
3707 /// Constructor for reference_diff
3708 ///
3709 /// @param first the first reference_type of the diff.
3710 ///
3711 /// @param second the second reference_type of the diff.
3712 ///
3713 /// @param ctxt the diff context to use.
3714 reference_diff::reference_diff(const reference_type_def_sptr    first,
3715                                const reference_type_def_sptr    second,
3716                                diff_sptr                        underlying,
3717                                diff_context_sptr                ctxt)
3718   : type_diff_base(first, second, ctxt),
3719         priv_(new priv(underlying))
3720 {}
3721
3722 /// Finish building the current instance of @ref reference_diff.
3723 void
3724 reference_diff::finish_diff_type()
3725 {
3726   if (diff::priv_->finished_)
3727     return;
3728   chain_into_hierarchy();
3729   diff::priv_->finished_ = true;
3730 }
3731
3732 /// Getter for the first reference of the diff.
3733 ///
3734 /// @return the first reference of the diff.
3735 reference_type_def_sptr
3736 reference_diff::first_reference() const
3737 {return dynamic_pointer_cast<reference_type_def>(first_subject());}
3738
3739 /// Getter for the second reference of the diff.
3740 ///
3741 /// @return for the second reference of the diff.
3742 reference_type_def_sptr
3743 reference_diff::second_reference() const
3744 {return dynamic_pointer_cast<reference_type_def>(second_subject());}
3745
3746
3747 /// Getter for the diff between the two referred-to types.
3748 ///
3749 /// @return the diff between the two referred-to types.
3750 const diff_sptr&
3751 reference_diff::underlying_type_diff() const
3752 {return priv_->underlying_type_diff_;}
3753
3754 /// Setter for the diff between the two referred-to types.
3755 ///
3756 /// @param d the new diff betweend the two referred-to types.
3757 diff_sptr&
3758 reference_diff::underlying_type_diff(diff_sptr d)
3759 {
3760   priv_->underlying_type_diff_ = d;
3761   return priv_->underlying_type_diff_;
3762 }
3763
3764 /// @return the pretty representation for the current instance of @ref
3765 /// reference_diff.
3766 const string&
3767 reference_diff::get_pretty_representation() const
3768 {
3769   if (diff::priv_->pretty_representation_.empty())
3770     {
3771       std::ostringstream o;
3772       o << "reference_diff["
3773         << first_subject()->get_pretty_representation()
3774         << ", "
3775         << second_subject()->get_pretty_representation()
3776         << "]";
3777       diff::priv_->pretty_representation_ = o.str();
3778     }
3779   return diff::priv_->pretty_representation_;
3780 }
3781
3782 /// Return true iff the current diff node carries a change.
3783 ///
3784 /// @return true iff the current diff node carries a change.
3785 bool
3786 reference_diff::has_changes() const
3787 {
3788   return first_reference() != second_reference();
3789 }
3790
3791 /// @return the kind of local change carried by the current diff node.
3792 /// The value returned is zero if the current node carries no local
3793 /// change.
3794 enum change_kind
3795 reference_diff::has_local_changes() const
3796 {
3797   ir::change_kind k = ir::NO_CHANGE_KIND;
3798   if (!equals(*first_reference(), *second_reference(), &k))
3799     return k & ir::ALL_LOCAL_CHANGES_MASK;
3800   return ir::NO_CHANGE_KIND;
3801 }
3802
3803 /// Report the diff in a serialized form.
3804 ///
3805 /// @param out the output stream to serialize the dif to.
3806 ///
3807 /// @param indent the string to use for indenting the report.
3808 void
3809 reference_diff::report(ostream& out, const string& indent) const
3810 {
3811   context()->get_reporter()->report(*this, out, indent);
3812 }
3813
3814 /// Compute the diff between two references.
3815 ///
3816 /// Note that the two types must have been created in the same @ref
3817 /// environment, otherwise, this function aborts.
3818 ///
3819 /// @param first the first reference to consider for the diff.
3820 ///
3821 /// @param second the second reference to consider for the diff.
3822 ///
3823 /// @param ctxt the diff context to use.
3824 reference_diff_sptr
3825 compute_diff(reference_type_def_sptr    first,
3826              reference_type_def_sptr    second,
3827              diff_context_sptr          ctxt)
3828 {
3829   if (first && second)
3830     ABG_ASSERT(first->get_environment() == second->get_environment());
3831
3832   diff_sptr d = compute_diff_for_types(first->get_pointed_to_type(),
3833                                        second->get_pointed_to_type(),
3834                                        ctxt);
3835   reference_diff_sptr result(new reference_diff(first, second, d, ctxt));
3836   ctxt->initialize_canonical_diff(result);
3837   return result;
3838 }
3839 // </reference_type_def>
3840
3841 // <qualified_type_diff stuff>
3842
3843 /// Populate the vector of children node of the @ref diff base type
3844 /// sub-object of this instance of @ref qualified_type_diff.
3845 ///
3846 /// The children node can then later be retrieved using
3847 /// diff::children_node().
3848 void
3849 qualified_type_diff::chain_into_hierarchy()
3850 {append_child_node(leaf_underlying_type_diff());}
3851
3852 /// Constructor for qualified_type_diff.
3853 ///
3854 /// @param first the first qualified type of the diff.
3855 ///
3856 /// @param second the second qualified type of the diff.
3857 ///
3858 /// @param ctxt the diff context to use.
3859 qualified_type_diff::qualified_type_diff(qualified_type_def_sptr        first,
3860                                          qualified_type_def_sptr        second,
3861                                          diff_sptr                      under,
3862                                          diff_context_sptr              ctxt)
3863   : type_diff_base(first, second, ctxt),
3864     priv_(new priv(under))
3865 {}
3866
3867 /// Finish building the current instance of @ref qualified_type_diff.
3868 void
3869 qualified_type_diff::finish_diff_type()
3870 {
3871   if (diff::priv_->finished_)
3872     return;
3873   chain_into_hierarchy();
3874   diff::priv_->finished_ = true;
3875 }
3876
3877 /// Getter for the first qualified type of the diff.
3878 ///
3879 /// @return the first qualified type of the diff.
3880 const qualified_type_def_sptr
3881 qualified_type_diff::first_qualified_type() const
3882 {return dynamic_pointer_cast<qualified_type_def>(first_subject());}
3883
3884 /// Getter for the second qualified type of the diff.
3885 ///
3886 /// @return the second qualified type of the diff.
3887 const qualified_type_def_sptr
3888 qualified_type_diff::second_qualified_type() const
3889 {return dynamic_pointer_cast<qualified_type_def>(second_subject());}
3890
3891 /// Getter for the diff between the underlying types of the two
3892 /// qualified types.
3893 ///
3894 /// @return the diff between the underlying types of the two qualified
3895 /// types.
3896 diff_sptr
3897 qualified_type_diff::underlying_type_diff() const
3898 {return priv_->underlying_type_diff;}
3899
3900 /// Getter for the diff between the most underlying non-qualified
3901 /// types of two qualified types.
3902 ///
3903 /// @return the diff between the most underlying non-qualified types
3904 /// of two qualified types.
3905 diff_sptr
3906 qualified_type_diff::leaf_underlying_type_diff() const
3907 {
3908   if (!priv_->leaf_underlying_type_diff)
3909     priv_->leaf_underlying_type_diff
3910       = compute_diff_for_types(get_leaf_type(first_qualified_type()),
3911                                get_leaf_type(second_qualified_type()),
3912                                context());
3913
3914   return priv_->leaf_underlying_type_diff;
3915 }
3916
3917 /// Setter for the diff between the underlying types of the two
3918 /// qualified types.
3919 ///
3920 /// @return the diff between the underlying types of the two qualified
3921 /// types.
3922 void
3923 qualified_type_diff::underlying_type_diff(const diff_sptr d)
3924 {priv_->underlying_type_diff = d;}
3925
3926 /// @return the pretty representation of the current instance of @ref
3927 /// qualified_type_diff.
3928 const string&
3929 qualified_type_diff::get_pretty_representation() const
3930 {
3931   if (diff::priv_->pretty_representation_.empty())
3932     {
3933       std::ostringstream o;
3934       o << "qualified_type_diff["
3935         << first_subject()->get_pretty_representation()
3936         << ", "
3937         << second_subject()->get_pretty_representation()
3938         << "]";
3939       diff::priv_->pretty_representation_ = o.str();
3940     }
3941   return diff::priv_->pretty_representation_;
3942 }
3943
3944 /// Return true iff the current diff node carries a change.
3945 ///
3946 /// @return true iff the current diff node carries a change.
3947 bool
3948 qualified_type_diff::has_changes() const
3949 {return first_qualified_type() != second_qualified_type();}
3950
3951 /// @return the kind of local change carried by the current diff node.
3952 /// The value returned is zero if the current node carries no local
3953 /// change.
3954 enum change_kind
3955 qualified_type_diff::has_local_changes() const
3956 {
3957   ir::change_kind k = ir::NO_CHANGE_KIND;
3958   if (!equals(*first_qualified_type(), *second_qualified_type(), &k))
3959     return k & ir::ALL_LOCAL_CHANGES_MASK;
3960   return ir::NO_CHANGE_KIND;
3961 }
3962
3963 /// Report the diff in a serialized form.
3964 ///
3965 /// @param out the output stream to serialize to.
3966 ///
3967 /// @param indent the string to use to indent the lines of the report.
3968 void
3969 qualified_type_diff::report(ostream& out, const string& indent) const
3970 {
3971   context()->get_reporter()->report(*this, out, indent);
3972 }
3973
3974 /// Compute the diff between two qualified types.
3975 ///
3976 /// Note that the two types must have been created in the same @ref
3977 /// environment, otherwise, this function aborts.
3978 ///
3979 /// @param first the first qualified type to consider for the diff.
3980 ///
3981 /// @param second the second qualified type to consider for the diff.
3982 ///
3983 /// @param ctxt the diff context to use.
3984 qualified_type_diff_sptr
3985 compute_diff(const qualified_type_def_sptr      first,
3986              const qualified_type_def_sptr      second,
3987              diff_context_sptr                  ctxt)
3988 {
3989   if (first && second)
3990     ABG_ASSERT(first->get_environment() == second->get_environment());
3991
3992   diff_sptr d = compute_diff_for_types(first->get_underlying_type(),
3993                                        second->get_underlying_type(),
3994                                        ctxt);
3995   qualified_type_diff_sptr result(new qualified_type_diff(first, second,
3996                                                           d, ctxt));
3997   ctxt->initialize_canonical_diff(result);
3998   return result;
3999 }
4000
4001 // </qualified_type_diff stuff>
4002
4003 // <enum_diff stuff>
4004
4005 /// Clear the lookup tables useful for reporting an enum_diff.
4006 ///
4007 /// This function must be updated each time a lookup table is added or
4008 /// removed from the class_diff::priv.
4009 void
4010 enum_diff::clear_lookup_tables()
4011 {
4012   priv_->deleted_enumerators_.clear();
4013   priv_->inserted_enumerators_.clear();
4014   priv_->changed_enumerators_.clear();
4015 }
4016
4017 /// Tests if the lookup tables are empty.
4018 ///
4019 /// @return true if the lookup tables are empty, false otherwise.
4020 bool
4021 enum_diff::lookup_tables_empty() const
4022 {
4023   return (priv_->deleted_enumerators_.empty()
4024           && priv_->inserted_enumerators_.empty()
4025           && priv_->changed_enumerators_.empty());
4026 }
4027
4028 /// If the lookup tables are not yet built, walk the differences and
4029 /// fill the lookup tables.
4030 void
4031 enum_diff::ensure_lookup_tables_populated()
4032 {
4033   if (!lookup_tables_empty())
4034     return;
4035
4036   {
4037     edit_script e = priv_->enumerators_changes_;
4038
4039     for (vector<deletion>::const_iterator it = e.deletions().begin();
4040          it != e.deletions().end();
4041          ++it)
4042       {
4043         unsigned i = it->index();
4044         const enum_type_decl::enumerator& n =
4045           first_enum()->get_enumerators()[i];
4046         const string& name = n.get_name();
4047         ABG_ASSERT(priv_->deleted_enumerators_.find(n.get_name())
4048                == priv_->deleted_enumerators_.end());
4049         priv_->deleted_enumerators_[name] = n;
4050       }
4051
4052     for (vector<insertion>::const_iterator it = e.insertions().begin();
4053          it != e.insertions().end();
4054          ++it)
4055       {
4056         for (vector<unsigned>::const_iterator iit =
4057                it->inserted_indexes().begin();
4058              iit != it->inserted_indexes().end();
4059              ++iit)
4060           {
4061             unsigned i = *iit;
4062             const enum_type_decl::enumerator& n =
4063               second_enum()->get_enumerators()[i];
4064             const string& name = n.get_name();
4065             ABG_ASSERT(priv_->inserted_enumerators_.find(n.get_name())
4066                    == priv_->inserted_enumerators_.end());
4067             string_enumerator_map::const_iterator j =
4068               priv_->deleted_enumerators_.find(name);
4069             if (j == priv_->deleted_enumerators_.end())
4070               priv_->inserted_enumerators_[name] = n;
4071             else
4072               {
4073                 if (j->second != n)
4074                   priv_->changed_enumerators_[j->first] =
4075                     std::make_pair(j->second, n);
4076                 priv_->deleted_enumerators_.erase(j);
4077               }
4078           }
4079       }
4080   }
4081 }
4082
4083 /// Populate the vector of children node of the @ref diff base type
4084 /// sub-object of this instance of @ref enum_diff.
4085 ///
4086 /// The children node can then later be retrieved using
4087 /// diff::children_node().
4088 void
4089 enum_diff::chain_into_hierarchy()
4090 {append_child_node(underlying_type_diff());}
4091
4092 /// Constructor for enum_diff.
4093 ///
4094 /// @param first the first enum type of the diff.
4095 ///
4096 /// @param second the second enum type of the diff.
4097 ///
4098 /// @param underlying_type_diff the diff of the two underlying types
4099 /// of the two enum types.
4100 ///
4101 /// @param ctxt the diff context to use.
4102 enum_diff::enum_diff(const enum_type_decl_sptr  first,
4103                      const enum_type_decl_sptr  second,
4104                      const diff_sptr            underlying_type_diff,
4105                      const diff_context_sptr    ctxt)
4106   : type_diff_base(first, second, ctxt),
4107     priv_(new priv(underlying_type_diff))
4108 {}
4109
4110 /// Finish building the current instance of @ref enum_diff.
4111 void
4112 enum_diff::finish_diff_type()
4113 {
4114   if (diff::priv_->finished_)
4115     return;
4116   chain_into_hierarchy();
4117   diff::priv_->finished_ = true;
4118 }
4119
4120 /// @return the first enum of the diff.
4121 const enum_type_decl_sptr
4122 enum_diff::first_enum() const
4123 {return dynamic_pointer_cast<enum_type_decl>(first_subject());}
4124
4125 /// @return the second enum of the diff.
4126 const enum_type_decl_sptr
4127 enum_diff::second_enum() const
4128 {return dynamic_pointer_cast<enum_type_decl>(second_subject());}
4129
4130 /// @return the diff of the two underlying enum types.
4131 diff_sptr
4132 enum_diff::underlying_type_diff() const
4133 {return priv_->underlying_type_diff_;}
4134
4135 /// @return a map of the enumerators that were deleted.
4136 const string_enumerator_map&
4137 enum_diff::deleted_enumerators() const
4138 {return priv_->deleted_enumerators_;}
4139
4140 /// @return a map of the enumerators that were inserted
4141 const string_enumerator_map&
4142 enum_diff::inserted_enumerators() const
4143 {return priv_->inserted_enumerators_;}
4144
4145 /// @return a map of the enumerators that were changed
4146 const string_changed_enumerator_map&
4147 enum_diff::changed_enumerators() const
4148 {return priv_->changed_enumerators_;}
4149
4150 /// @return the pretty representation of the current instance of @ref
4151 /// enum_diff.
4152 const string&
4153 enum_diff::get_pretty_representation() const
4154 {
4155   if (diff::priv_->pretty_representation_.empty())
4156     {
4157       std::ostringstream o;
4158       o << "enum_diff["
4159         << first_subject()->get_pretty_representation()
4160         << ", "
4161         << second_subject()->get_pretty_representation()
4162         << "]";
4163       diff::priv_->pretty_representation_ = o.str();
4164     }
4165   return diff::priv_->pretty_representation_;
4166 }
4167
4168 /// Return true iff the current diff node carries a change.
4169 ///
4170 /// @return true iff the current diff node carries a change.
4171 bool
4172 enum_diff::has_changes() const
4173 {return first_enum() != second_enum();}
4174
4175 /// @return the kind of local change carried by the current diff node.
4176 /// The value returned is zero if the current node carries no local
4177 /// change.
4178 enum change_kind
4179 enum_diff::has_local_changes() const
4180 {
4181   ir::change_kind k = ir::NO_CHANGE_KIND;
4182   if (!equals(*first_enum(), *second_enum(), &k))
4183     return k & ir::ALL_LOCAL_CHANGES_MASK;
4184   return ir::NO_CHANGE_KIND;
4185 }
4186
4187 /// Report the differences between the two enums.
4188 ///
4189 /// @param out the output stream to send the report to.
4190 ///
4191 /// @param indent the string to use for indentation.
4192 void
4193 enum_diff::report(ostream& out, const string& indent) const
4194 {
4195   context()->get_reporter()->report(*this, out, indent);
4196 }
4197
4198 /// Compute the set of changes between two instances of @ref
4199 /// enum_type_decl.
4200 ///
4201 /// Note that the two types must have been created in the same @ref
4202 /// environment, otherwise, this function aborts.
4203 ///
4204 /// @param first a pointer to the first enum_type_decl to consider.
4205 ///
4206 /// @param second a pointer to the second enum_type_decl to consider.
4207 ///
4208 /// @return the resulting diff of the two enums @p first and @p
4209 /// second.
4210 ///
4211 /// @param ctxt the diff context to use.
4212 enum_diff_sptr
4213 compute_diff(const enum_type_decl_sptr first,
4214              const enum_type_decl_sptr second,
4215              diff_context_sptr ctxt)
4216 {
4217   if (first && second)
4218     ABG_ASSERT(first->get_environment() == second->get_environment());
4219
4220   diff_sptr ud = compute_diff_for_types(first->get_underlying_type(),
4221                                         second->get_underlying_type(),
4222                                         ctxt);
4223   enum_diff_sptr d(new enum_diff(first, second, ud, ctxt));
4224
4225   compute_diff(first->get_enumerators().begin(),
4226                first->get_enumerators().end(),
4227                second->get_enumerators().begin(),
4228                second->get_enumerators().end(),
4229                d->priv_->enumerators_changes_);
4230
4231   d->ensure_lookup_tables_populated();
4232
4233   ctxt->initialize_canonical_diff(d);
4234
4235   return d;
4236 }
4237 // </enum_diff stuff>
4238
4239 // <class_or_union_diff stuff>
4240
4241 /// Test if the current diff node carries a member type change for a
4242 /// member type which name is the same as the name of a given type
4243 /// declaration.
4244 ///
4245 /// @param d the type declaration which name should be equal to the
4246 /// name of the member type that might have changed.
4247 ///
4248 /// @return the member type that has changed, iff there were a member
4249 /// type (which name is the same as the name of @p d) that changed.
4250 /// Note that the member type that is returned is the new value of the
4251 /// member type that changed.
4252 type_or_decl_base_sptr
4253 class_or_union_diff::priv::member_type_has_changed(decl_base_sptr d) const
4254 {
4255   string qname = d->get_qualified_name();
4256   string_diff_sptr_map::const_iterator it =
4257     changed_member_types_.find(qname);
4258
4259   return ((it == changed_member_types_.end())
4260           ? type_or_decl_base_sptr()
4261           : it->second->second_subject());
4262 }
4263
4264 /// Test if the current diff node carries a data member change for a
4265 /// data member which name is the same as the name of a given type
4266 /// declaration.
4267 ///
4268 /// @param d the type declaration which name should be equal to the
4269 /// name of the data member that might have changed.
4270 ///
4271 /// @return the data member that has changed, iff there were a data
4272 /// member type (which name is the same as the name of @p d) that
4273 /// changed.  Note that the data member that is returned is the new
4274 /// value of the data member that changed.
4275 decl_base_sptr
4276 class_or_union_diff::priv::subtype_changed_dm(decl_base_sptr d) const
4277 {
4278   string qname = d->get_qualified_name();
4279   string_var_diff_sptr_map::const_iterator it =
4280     subtype_changed_dm_.find(qname);
4281
4282   if (it == subtype_changed_dm_.end())
4283     return decl_base_sptr();
4284   return it->second->second_var();
4285 }
4286
4287 /// Test if the current diff node carries a member class template
4288 /// change for a member class template which name is the same as the
4289 /// name of a given type declaration.
4290 ///
4291 /// @param d the type declaration which name should be equal to the
4292 /// name of the member class template that might have changed.
4293 ///
4294 /// @return the member class template that has changed, iff there were
4295 /// a member class template (which name is the same as the name of @p
4296 /// d) that changed.  Note that the member class template that is
4297 /// returned is the new value of the member class template that
4298 /// changed.
4299 decl_base_sptr
4300 class_or_union_diff::priv::member_class_tmpl_has_changed(decl_base_sptr d) const
4301 {
4302   string qname = d->get_qualified_name();
4303   string_diff_sptr_map::const_iterator it =
4304     changed_member_class_tmpls_.find(qname);
4305
4306   return ((it == changed_member_class_tmpls_.end())
4307           ? decl_base_sptr()
4308           : dynamic_pointer_cast<decl_base>(it->second->second_subject()));
4309 }
4310
4311 /// Get the number of non static data members that were deleted.
4312 ///
4313 /// @return the number of non static data members that were deleted.
4314 size_t
4315 class_or_union_diff::priv::get_deleted_non_static_data_members_number() const
4316 {
4317   size_t result = 0;
4318
4319   for (string_decl_base_sptr_map::const_iterator i =
4320          deleted_data_members_.begin();
4321        i != deleted_data_members_.end();
4322        ++i)
4323     if (is_member_decl(i->second)
4324         && !get_member_is_static(i->second))
4325       ++result;
4326
4327   return result;
4328 }
4329
4330 /// Get the number of non static data members that were inserted.
4331 ///
4332 /// @return the number of non static data members that were inserted.
4333 size_t
4334 class_or_union_diff::priv::get_inserted_non_static_data_members_number() const
4335 {
4336   size_t result = 0;
4337
4338   for (string_decl_base_sptr_map::const_iterator i =
4339          inserted_data_members_.begin();
4340        i != inserted_data_members_.end();
4341        ++i)
4342     if (is_member_decl(i->second)
4343         && !get_member_is_static(i->second))
4344       ++result;
4345
4346   return result;
4347 }
4348
4349 /// Get the number of data member sub-type changes carried by the
4350 /// current diff node that were filtered out.
4351 ///
4352 /// @param local_only if true, it means that only (filtered) local
4353 /// changes are considered.
4354 ///
4355 /// @return the number of data member sub-type changes carried by the
4356 /// current diff node that were filtered out.
4357 size_t
4358 class_or_union_diff::priv::count_filtered_subtype_changed_dm(bool local_only)
4359 {
4360   size_t num_filtered= 0;
4361   for (var_diff_sptrs_type::const_iterator i =
4362          sorted_subtype_changed_dm_.begin();
4363        i != sorted_subtype_changed_dm_.end();
4364        ++i)
4365     {
4366       if (local_only)
4367         {
4368           if ((*i)->has_changes()
4369               && !(*i)->has_local_changes_to_be_reported())
4370             ++num_filtered;
4371         }
4372       else
4373         {
4374           if ((*i)->is_filtered_out())
4375             ++num_filtered;
4376         }
4377     }
4378   return num_filtered;
4379 }
4380
4381 /// Get the number of data member changes carried by the current diff
4382 /// node that were filtered out.
4383 ///
4384 /// @param local_only if true, it means that only (filtered) local
4385 /// changes are considered.
4386 ///
4387 /// @return the number of data member changes carried by the current
4388 /// diff node that were filtered out.
4389 size_t
4390 class_or_union_diff::priv::count_filtered_changed_dm(bool local_only)
4391 {
4392   size_t num_filtered= 0;
4393
4394   for (unsigned_var_diff_sptr_map::const_iterator i = changed_dm_.begin();
4395        i != changed_dm_.end();
4396        ++i)
4397     {
4398       diff_sptr diff = i->second;
4399       if (local_only)
4400         {
4401           if ((diff->has_changes() && !diff->has_local_changes_to_be_reported())
4402               || diff->is_filtered_out())
4403             ++num_filtered;
4404         }
4405       else
4406         {
4407           if (diff->is_filtered_out())
4408             ++num_filtered;
4409         }
4410     }
4411   return num_filtered;
4412 }
4413
4414 /// Skip the processing of the current member function if its
4415 /// virtual-ness is disallowed by the user.
4416 ///
4417 /// This is to be used in the member functions below that are used to
4418 /// count the number of filtered inserted, deleted and changed member
4419 /// functions.
4420 #define SKIP_MEM_FN_IF_VIRTUALITY_DISALLOWED                            \
4421   do {                                                                  \
4422     if (get_member_function_is_virtual(f)                                       \
4423         || get_member_function_is_virtual(s))                           \
4424       {                                                         \
4425         if (!(allowed_category | VIRTUAL_MEMBER_CHANGE_CATEGORY))       \
4426           continue;                                                     \
4427       }                                                         \
4428     else                                                                \
4429       {                                                         \
4430         if (!(allowed_category | NON_VIRT_MEM_FUN_CHANGE_CATEGORY))     \
4431           continue;                                                     \
4432       }                                                         \
4433   } while (false)
4434
4435 /// Get the number of member functions changes carried by the current
4436 /// diff node that were filtered out.
4437 ///
4438 /// @return the number of member functions changes carried by the
4439 /// current diff node that were filtered out.
4440 size_t
4441 class_or_union_diff::priv::count_filtered_changed_mem_fns
4442 (const diff_context_sptr& ctxt)
4443 {
4444   size_t count = 0;
4445   diff_category allowed_category = ctxt->get_allowed_category();
4446
4447   for (function_decl_diff_sptrs_type::const_iterator i =
4448          sorted_changed_member_functions_.begin();
4449        i != sorted_changed_member_functions_.end();
4450        ++i)
4451     {
4452       method_decl_sptr f =
4453         dynamic_pointer_cast<method_decl>
4454         ((*i)->first_function_decl());
4455       ABG_ASSERT(f);
4456
4457       method_decl_sptr s =
4458         dynamic_pointer_cast<method_decl>
4459         ((*i)->second_function_decl());
4460       ABG_ASSERT(s);
4461
4462       SKIP_MEM_FN_IF_VIRTUALITY_DISALLOWED;
4463
4464       diff_sptr diff = *i;
4465       ctxt->maybe_apply_filters(diff);
4466
4467       if (diff->is_filtered_out())
4468         ++count;
4469     }
4470
4471   return count;
4472 }
4473
4474 /// Get the number of member functions insertions carried by the current
4475 /// diff node that were filtered out.
4476 ///
4477 /// @return the number of member functions insertions carried by the
4478 /// current diff node that were filtered out.
4479 size_t
4480 class_or_union_diff::priv::count_filtered_inserted_mem_fns
4481 (const diff_context_sptr& ctxt)
4482 {
4483     size_t count = 0;
4484   diff_category allowed_category = ctxt->get_allowed_category();
4485
4486   for (string_member_function_sptr_map::const_iterator i =
4487          inserted_member_functions_.begin();
4488        i != inserted_member_functions_.end();
4489        ++i)
4490     {
4491       method_decl_sptr f = i->second,
4492         s = i->second;
4493
4494       SKIP_MEM_FN_IF_VIRTUALITY_DISALLOWED;
4495
4496       diff_sptr diff = compute_diff_for_decls(f, s, ctxt);
4497       ctxt->maybe_apply_filters(diff);
4498
4499       if (diff->get_category() != NO_CHANGE_CATEGORY
4500           && diff->is_filtered_out())
4501         ++count;
4502     }
4503
4504   return count;
4505 }
4506
4507 /// Get the number of member functions deletions carried by the current
4508 /// diff node that were filtered out.
4509 ///
4510 /// @return the number of member functions deletions carried by the
4511 /// current diff node that were filtered out.
4512 size_t
4513 class_or_union_diff::priv::count_filtered_deleted_mem_fns
4514 (const diff_context_sptr& ctxt)
4515 {
4516   size_t count = 0;
4517   diff_category allowed_category = ctxt->get_allowed_category();
4518
4519   for (string_member_function_sptr_map::const_iterator i =
4520          deleted_member_functions_.begin();
4521        i != deleted_member_functions_.end();
4522        ++i)
4523     {
4524       method_decl_sptr f = i->second,
4525         s = i->second;
4526
4527       SKIP_MEM_FN_IF_VIRTUALITY_DISALLOWED;
4528
4529       diff_sptr diff = compute_diff_for_decls(f, s, ctxt);
4530       ctxt->maybe_apply_filters(diff);
4531
4532       if (diff->get_category() != NO_CHANGE_CATEGORY
4533           && diff->is_filtered_out())
4534         ++count;
4535     }
4536
4537   return count;
4538 }
4539
4540 /// Clear the lookup tables useful for reporting.
4541 ///
4542 /// This function must be updated each time a lookup table is added or
4543 /// removed from the class_or_union_diff::priv.
4544 void
4545 class_or_union_diff::clear_lookup_tables()
4546 {
4547   priv_->deleted_member_types_.clear();
4548   priv_->inserted_member_types_.clear();
4549   priv_->changed_member_types_.clear();
4550   priv_->deleted_data_members_.clear();
4551   priv_->inserted_data_members_.clear();
4552   priv_->subtype_changed_dm_.clear();
4553   priv_->deleted_member_functions_.clear();
4554   priv_->inserted_member_functions_.clear();
4555   priv_->changed_member_functions_.clear();
4556   priv_->deleted_member_class_tmpls_.clear();
4557   priv_->inserted_member_class_tmpls_.clear();
4558   priv_->changed_member_class_tmpls_.clear();
4559 }
4560
4561 /// Tests if the lookup tables are empty.
4562 ///
4563 /// @return true if the lookup tables are empty, false otherwise.
4564 bool
4565 class_or_union_diff::lookup_tables_empty(void) const
4566 {
4567   return (priv_->deleted_member_types_.empty()
4568           && priv_->inserted_member_types_.empty()
4569           && priv_->changed_member_types_.empty()
4570           && priv_->deleted_data_members_.empty()
4571           && priv_->inserted_data_members_.empty()
4572           && priv_->subtype_changed_dm_.empty()
4573           && priv_->inserted_member_functions_.empty()
4574           && priv_->deleted_member_functions_.empty()
4575           && priv_->changed_member_functions_.empty()
4576           && priv_->deleted_member_class_tmpls_.empty()
4577           && priv_->inserted_member_class_tmpls_.empty()
4578           && priv_->changed_member_class_tmpls_.empty());
4579 }
4580
4581 /// If the lookup tables are not yet built, walk the differences and
4582 /// fill them.
4583 void
4584 class_or_union_diff::ensure_lookup_tables_populated(void) const
4585 {
4586   {
4587     edit_script& e = priv_->member_types_changes_;
4588
4589     for (vector<deletion>::const_iterator it = e.deletions().begin();
4590          it != e.deletions().end();
4591          ++it)
4592       {
4593         unsigned i = it->index();
4594         decl_base_sptr d =
4595           get_type_declaration(first_class_or_union()->get_member_types()[i]);
4596         class_or_union_sptr record_type = is_class_or_union_type(d);
4597         if (record_type && record_type->get_is_declaration_only())
4598           continue;
4599         string name = d->get_name();
4600         priv_->deleted_member_types_[name] = d;
4601       }
4602
4603     for (vector<insertion>::const_iterator it = e.insertions().begin();
4604          it != e.insertions().end();
4605          ++it)
4606       {
4607         for (vector<unsigned>::const_iterator iit =
4608                it->inserted_indexes().begin();
4609              iit != it->inserted_indexes().end();
4610              ++iit)
4611           {
4612             unsigned i = *iit;
4613             decl_base_sptr d =
4614               get_type_declaration(second_class_or_union()->get_member_types()[i]);
4615             class_or_union_sptr record_type = is_class_or_union_type(d);
4616             if (record_type && record_type->get_is_declaration_only())
4617               continue;
4618             string name = d->get_name();
4619             string_decl_base_sptr_map::const_iterator j =
4620               priv_->deleted_member_types_.find(name);
4621             if (j != priv_->deleted_member_types_.end())
4622               {
4623                 if (*j->second != *d)
4624                   priv_->changed_member_types_[name] =
4625                     compute_diff(j->second, d, context());
4626
4627                 priv_->deleted_member_types_.erase(j);
4628               }
4629             else
4630               priv_->inserted_member_types_[name] = d;
4631           }
4632       }
4633   }
4634
4635   {
4636     edit_script& e = priv_->data_members_changes_;
4637
4638     for (vector<deletion>::const_iterator it = e.deletions().begin();
4639          it != e.deletions().end();
4640          ++it)
4641       {
4642         unsigned i = it->index();
4643         decl_base_sptr d = first_class_or_union()->get_non_static_data_members()[i];
4644         string name = d->get_name();
4645         ABG_ASSERT(priv_->deleted_data_members_.find(name)
4646                == priv_->deleted_data_members_.end());
4647         priv_->deleted_data_members_[name] = d;
4648       }
4649
4650     for (vector<insertion>::const_iterator it = e.insertions().begin();
4651          it != e.insertions().end();
4652          ++it)
4653       {
4654         for (vector<unsigned>::const_iterator iit =
4655                it->inserted_indexes().begin();
4656              iit != it->inserted_indexes().end();
4657              ++iit)
4658           {
4659             unsigned i = *iit;
4660             decl_base_sptr d =
4661               second_class_or_union()->get_non_static_data_members()[i];
4662             var_decl_sptr dm = is_var_decl(d);
4663             string name = dm->get_name();
4664             ABG_ASSERT(priv_->inserted_data_members_.find(name)
4665                    == priv_->inserted_data_members_.end());
4666             string_decl_base_sptr_map::const_iterator j =
4667               priv_->deleted_data_members_.find(name);
4668             if (j != priv_->deleted_data_members_.end())
4669               {
4670                 if (*j->second != *d)
4671                   {
4672                     var_decl_sptr old_dm = is_var_decl(j->second);
4673                     priv_->subtype_changed_dm_[name]=
4674                       compute_diff(old_dm, dm, context());
4675                   }
4676                 priv_->deleted_data_members_.erase(j);
4677               }
4678             else
4679               priv_->inserted_data_members_[name] = d;
4680           }
4681       }
4682
4683     // Now detect when a data member is deleted from offset N and
4684     // another one is added to offset N.  In that case, we want to be
4685     // able to say that the data member at offset N changed.
4686     for (string_decl_base_sptr_map::const_iterator i =
4687            priv_->deleted_data_members_.begin();
4688          i != priv_->deleted_data_members_.end();
4689          ++i)
4690       {
4691         unsigned offset = get_data_member_offset(i->second);
4692         priv_->deleted_dm_by_offset_[offset] = i->second;
4693       }
4694
4695     for (string_decl_base_sptr_map::const_iterator i =
4696            priv_->inserted_data_members_.begin();
4697          i != priv_->inserted_data_members_.end();
4698          ++i)
4699       {
4700         unsigned offset = get_data_member_offset(i->second);
4701         priv_->inserted_dm_by_offset_[offset] = i->second;
4702       }
4703
4704     for (unsigned_decl_base_sptr_map::const_iterator i =
4705            priv_->inserted_dm_by_offset_.begin();
4706          i != priv_->inserted_dm_by_offset_.end();
4707          ++i)
4708       {
4709         unsigned_decl_base_sptr_map::const_iterator j =
4710           priv_->deleted_dm_by_offset_.find(i->first);
4711         if (j != priv_->deleted_dm_by_offset_.end())
4712           {
4713             var_decl_sptr old_dm = is_var_decl(j->second);
4714             var_decl_sptr new_dm = is_var_decl(i->second);
4715             priv_->changed_dm_[i->first] =
4716               compute_diff(old_dm, new_dm, context());
4717           }
4718       }
4719
4720     for (unsigned_var_diff_sptr_map::const_iterator i =
4721            priv_->changed_dm_.begin();
4722          i != priv_->changed_dm_.end();
4723          ++i)
4724       {
4725         priv_->deleted_dm_by_offset_.erase(i->first);
4726         priv_->inserted_dm_by_offset_.erase(i->first);
4727         priv_->deleted_data_members_.erase
4728           (i->second->first_var()->get_name());
4729         priv_->inserted_data_members_.erase
4730           (i->second->second_var()->get_name());
4731       }
4732   }
4733   sort_string_data_member_diff_sptr_map(priv_->subtype_changed_dm_,
4734                                         priv_->sorted_subtype_changed_dm_);
4735   sort_unsigned_data_member_diff_sptr_map(priv_->changed_dm_,
4736                                           priv_->sorted_changed_dm_);
4737
4738   {
4739     edit_script& e = priv_->member_class_tmpls_changes_;
4740
4741     for (vector<deletion>::const_iterator it = e.deletions().begin();
4742          it != e.deletions().end();
4743          ++it)
4744       {
4745         unsigned i = it->index();
4746         decl_base_sptr d =
4747           first_class_or_union()->get_member_class_templates()[i]->
4748           as_class_tdecl();
4749         string name = d->get_name();
4750         ABG_ASSERT(priv_->deleted_member_class_tmpls_.find(name)
4751                == priv_->deleted_member_class_tmpls_.end());
4752         priv_->deleted_member_class_tmpls_[name] = d;
4753       }
4754
4755     for (vector<insertion>::const_iterator it = e.insertions().begin();
4756          it != e.insertions().end();
4757          ++it)
4758       {
4759         for (vector<unsigned>::const_iterator iit =
4760                it->inserted_indexes().begin();
4761              iit != it->inserted_indexes().end();
4762              ++iit)
4763           {
4764             unsigned i = *iit;
4765             decl_base_sptr d =
4766               second_class_or_union()->get_member_class_templates()[i]->
4767               as_class_tdecl();
4768             string name = d->get_name();
4769             ABG_ASSERT(priv_->inserted_member_class_tmpls_.find(name)
4770                    == priv_->inserted_member_class_tmpls_.end());
4771             string_decl_base_sptr_map::const_iterator j =
4772               priv_->deleted_member_class_tmpls_.find(name);
4773             if (j != priv_->deleted_member_class_tmpls_.end())
4774               {
4775                 if (*j->second != *d)
4776                   priv_->changed_member_types_[name]=
4777                     compute_diff(j->second, d, context());
4778                 priv_->deleted_member_class_tmpls_.erase(j);
4779               }
4780             else
4781               priv_->inserted_member_class_tmpls_[name] = d;
4782           }
4783       }
4784   }
4785   sort_string_diff_sptr_map(priv_->changed_member_types_,
4786                             priv_->sorted_changed_member_types_);
4787 }
4788
4789 /// Allocate the memory for the priv_ pimpl data member of the @ref
4790 /// class_or_union_diff class.
4791 void
4792 class_or_union_diff::allocate_priv_data()
4793 {
4794   if (!priv_)
4795     priv_.reset(new priv);
4796 }
4797
4798 /// Constructor for the @ref class_or_union_diff class.
4799 ///
4800 /// @param first_scope the first @ref class_or_union of the diff node.
4801 ///
4802 /// @param second_scope the second @ref class_or_union of the diff node.
4803 ///
4804 /// @param ctxt the context of the diff.
4805 class_or_union_diff::class_or_union_diff(class_or_union_sptr first_scope,
4806                                          class_or_union_sptr second_scope,
4807                                          diff_context_sptr ctxt)
4808   : type_diff_base(first_scope, second_scope, ctxt)
4809     //priv_(new priv)
4810 {}
4811
4812 /// Finish building the current instance of @ref class_or_union_diff.
4813 void
4814 class_or_union_diff::finish_diff_type()
4815 {
4816   if (diff::priv_->finished_)
4817     return;
4818   chain_into_hierarchy();
4819   diff::priv_->finished_ = true;
4820 }
4821
4822 /// Getter of the private data of the @ref class_or_union_diff type.
4823 ///
4824 /// Note that due to an optimization, the private data of @ref
4825 /// class_or_union_diff can be shared among several instances of
4826 /// class_or_union_diff, so you should never try to access
4827 /// class_or_union_diff::priv directly.
4828 ///
4829 /// When class_or_union_diff::priv is shared, this function returns
4830 /// the correct shared one.
4831 ///
4832 /// @return the (possibly) shared private data of the current instance
4833 /// of @ref class_or_union_diff.
4834 const class_or_union_diff::priv_sptr&
4835 class_or_union_diff::get_priv() const
4836 {
4837   if (priv_)
4838     return priv_;
4839
4840   // If the current class_or_union_diff::priv member is empty, then look for
4841   // the shared one, from the canonical type.
4842   class_or_union_diff *canonical =
4843     dynamic_cast<class_or_union_diff*>(get_canonical_diff());
4844   ABG_ASSERT(canonical);
4845   ABG_ASSERT(canonical->priv_);
4846
4847   return canonical->priv_;
4848 }
4849
4850 /// Destructor of class_or_union_diff.
4851 class_or_union_diff::~class_or_union_diff()
4852 {
4853 }
4854
4855 /// @return the first @ref class_or_union involved in the diff.
4856 class_or_union_sptr
4857 class_or_union_diff::first_class_or_union() const
4858 {return is_class_or_union_type(first_subject());}
4859
4860 /// @return the second @ref class_or_union involved in the diff.
4861 class_or_union_sptr
4862 class_or_union_diff::second_class_or_union() const
4863 {return is_class_or_union_type(second_subject());}
4864
4865 /// @return the edit script of the member types of the two @ref
4866 /// class_or_union.
4867 const edit_script&
4868 class_or_union_diff::member_types_changes() const
4869 {return get_priv()->member_types_changes_;}
4870
4871 /// @return the edit script of the member types of the two @ref
4872 /// class_or_union.
4873 edit_script&
4874 class_or_union_diff::member_types_changes()
4875 {return get_priv()->member_types_changes_;}
4876
4877 /// @return the edit script of the data members of the two @ref
4878 /// class_or_union.
4879 const edit_script&
4880 class_or_union_diff::data_members_changes() const
4881 {return get_priv()->data_members_changes_;}
4882
4883 /// @return the edit script of the data members of the two @ref
4884 /// class_or_union.
4885 edit_script&
4886 class_or_union_diff::data_members_changes()
4887 {return get_priv()->data_members_changes_;}
4888
4889 /// Getter for the data members that got inserted.
4890 ///
4891 /// @return a map of data members that got inserted.
4892 const string_decl_base_sptr_map&
4893 class_or_union_diff::inserted_data_members() const
4894 {return get_priv()->inserted_data_members_;}
4895
4896 /// Getter for the data members that got deleted.
4897 ///
4898 /// @return a map of data members that got deleted.
4899 const string_decl_base_sptr_map&
4900 class_or_union_diff::deleted_data_members() const
4901 {return get_priv()->deleted_data_members_;}
4902
4903 /// @return the edit script of the member functions of the two @ref
4904 /// class_or_union.
4905 const edit_script&
4906 class_or_union_diff::member_fns_changes() const
4907 {return get_priv()->member_fns_changes_;}
4908
4909 /// Getter for the virtual members functions that have had a change in
4910 /// a sub-type, without having a change in their symbol name.
4911 ///
4912 /// @return a sorted vector of virtual member functions that have a
4913 /// sub-type change.
4914 const function_decl_diff_sptrs_type&
4915 class_or_union_diff::changed_member_fns() const
4916 {return get_priv()->sorted_changed_member_functions_;}
4917
4918 /// @return the edit script of the member functions of the two
4919 /// classes.
4920 edit_script&
4921 class_or_union_diff::member_fns_changes()
4922 {return get_priv()->member_fns_changes_;}
4923
4924 /// @return a map of member functions that got deleted.
4925 const string_member_function_sptr_map&
4926 class_or_union_diff::deleted_member_fns() const
4927 {return get_priv()->deleted_member_functions_;}
4928
4929 /// @return a map of member functions that got inserted.
4930 const string_member_function_sptr_map&
4931 class_or_union_diff::inserted_member_fns() const
4932 {return get_priv()->inserted_member_functions_;}
4933
4934 /// @return the edit script of the member function templates of the two
4935 /// @ref class_or_union.
4936 const edit_script&
4937 class_or_union_diff::member_fn_tmpls_changes() const
4938 {return get_priv()->member_fn_tmpls_changes_;}
4939
4940 /// @return the edit script of the member function templates of the
4941 /// two @ref class_or_union.
4942 edit_script&
4943 class_or_union_diff::member_fn_tmpls_changes()
4944 {return get_priv()->member_fn_tmpls_changes_;}
4945
4946 /// @return the edit script of the member class templates of the two
4947 /// @ref class_or_union.
4948 const edit_script&
4949 class_or_union_diff::member_class_tmpls_changes() const
4950 {return get_priv()->member_class_tmpls_changes_;}
4951
4952 /// @return the edit script of the member class templates of the two
4953 /// @ref class_or_union.
4954 edit_script&
4955 class_or_union_diff::member_class_tmpls_changes()
4956 {return get_priv()->member_class_tmpls_changes_;}
4957
4958 /// Test if the current diff node carries a change.
4959 bool
4960 class_or_union_diff::has_changes() const
4961 {return first_class_or_union() != second_class_or_union();}
4962
4963 /// @return the kind of local change carried by the current diff node.
4964 /// The value returned is zero if the current node carries no local
4965 /// change.
4966 enum change_kind
4967 class_or_union_diff::has_local_changes() const
4968 {
4969   ir::change_kind k = ir::NO_CHANGE_KIND;
4970   if (!equals(*first_class_or_union(), *second_class_or_union(), &k))
4971     return k & ir::ALL_LOCAL_CHANGES_MASK;
4972   return ir::NO_CHANGE_KIND;
4973 }
4974
4975
4976 /// Report the changes carried by the current @ref class_or_union_diff
4977 /// node in a textual format.
4978 ///
4979 /// @param out the output stream to write the textual report to.
4980 ///
4981 /// @param indent the number of white space to use as indentation.
4982 void
4983 class_or_union_diff::report(ostream& out, const string& indent) const
4984 {
4985   context()->get_reporter()->report(*this, out, indent);
4986 }
4987
4988 /// Populate the vector of children node of the @ref diff base type
4989 /// sub-object of this instance of @ref class_or_union_diff.
4990 ///
4991 /// The children node can then later be retrieved using
4992 /// diff::children_node().
4993 void
4994 class_or_union_diff::chain_into_hierarchy()
4995 {
4996   // data member changes
4997   for (var_diff_sptrs_type::const_iterator i =
4998          get_priv()->sorted_subtype_changed_dm_.begin();
4999        i != get_priv()->sorted_subtype_changed_dm_.end();
5000        ++i)
5001     if (diff_sptr d = *i)
5002       append_child_node(d);
5003
5004   for (unsigned_var_diff_sptr_map::const_iterator i =
5005          get_priv()->changed_dm_.begin();
5006        i != get_priv()->changed_dm_.end();
5007        ++i)
5008     if (diff_sptr d = i->second)
5009       append_child_node(d);
5010
5011   // member types changes
5012   for (diff_sptrs_type::const_iterator i =
5013          get_priv()->sorted_changed_member_types_.begin();
5014        i != get_priv()->sorted_changed_member_types_.end();
5015        ++i)
5016     if (diff_sptr d = *i)
5017       append_child_node(d);
5018
5019   // member function changes
5020   for (function_decl_diff_sptrs_type::const_iterator i =
5021          get_priv()->sorted_changed_member_functions_.begin();
5022        i != get_priv()->sorted_changed_member_functions_.end();
5023        ++i)
5024     if (diff_sptr d = *i)
5025       append_child_node(d);
5026 }
5027
5028 // </class_or_union_diff stuff>
5029
5030 //<class_diff stuff>
5031
5032 /// Clear the lookup tables useful for reporting.
5033 ///
5034 /// This function must be updated each time a lookup table is added or
5035 /// removed from the class_diff::priv.
5036 void
5037 class_diff::clear_lookup_tables(void)
5038 {
5039   priv_->deleted_bases_.clear();
5040   priv_->inserted_bases_.clear();
5041   priv_->changed_bases_.clear();
5042 }
5043
5044 /// Tests if the lookup tables are empty.
5045 ///
5046 /// @return true if the lookup tables are empty, false otherwise.
5047 bool
5048 class_diff::lookup_tables_empty(void) const
5049 {
5050   return (priv_->deleted_bases_.empty()
5051           && priv_->inserted_bases_.empty()
5052           && priv_->changed_bases_.empty());
5053 }
5054
5055 /// If the lookup tables are not yet built, walk the differences and
5056 /// fill them.
5057 void
5058 class_diff::ensure_lookup_tables_populated(void) const
5059 {
5060   class_or_union_diff::ensure_lookup_tables_populated();
5061
5062   if (!lookup_tables_empty())
5063     return;
5064
5065   {
5066     edit_script& e = get_priv()->base_changes_;
5067
5068     for (vector<deletion>::const_iterator it = e.deletions().begin();
5069          it != e.deletions().end();
5070          ++it)
5071       {
5072         unsigned i = it->index();
5073         class_decl::base_spec_sptr b =
5074           first_class_decl()->get_base_specifiers()[i];
5075         string name = b->get_base_class()->get_name();
5076         ABG_ASSERT(get_priv()->deleted_bases_.find(name)
5077                == get_priv()->deleted_bases_.end());
5078         get_priv()->deleted_bases_[name] = b;
5079       }
5080
5081     for (vector<insertion>::const_iterator it = e.insertions().begin();
5082          it != e.insertions().end();
5083          ++it)
5084       {
5085         for (vector<unsigned>::const_iterator iit =
5086                it->inserted_indexes().begin();
5087              iit != it->inserted_indexes().end();
5088              ++iit)
5089           {
5090             unsigned i = *iit;
5091             class_decl::base_spec_sptr b =
5092               second_class_decl()->get_base_specifiers()[i];
5093             string name = b->get_base_class()->get_name();
5094             ABG_ASSERT(get_priv()->inserted_bases_.find(name)
5095                    == get_priv()->inserted_bases_.end());
5096             string_base_sptr_map::const_iterator j =
5097               get_priv()->deleted_bases_.find(name);
5098             if (j != get_priv()->deleted_bases_.end())
5099               {
5100                 if (j->second != b)
5101                   get_priv()->changed_bases_[name] =
5102                     compute_diff(j->second, b, context());
5103                 get_priv()->deleted_bases_.erase(j);
5104               }
5105             else
5106               get_priv()->inserted_bases_[name] = b;
5107           }
5108       }
5109   }
5110
5111   sort_string_base_sptr_map(get_priv()->deleted_bases_,
5112                             get_priv()->sorted_deleted_bases_);
5113   sort_string_base_sptr_map(get_priv()->inserted_bases_,
5114                             get_priv()->sorted_inserted_bases_);
5115   sort_string_base_diff_sptr_map(get_priv()->changed_bases_,
5116                                  get_priv()->sorted_changed_bases_);
5117
5118   {
5119     const class_or_union_diff::priv_sptr &p = class_or_union_diff::get_priv();
5120
5121     edit_script& e = p->member_fns_changes_;
5122
5123     for (vector<deletion>::const_iterator it = e.deletions().begin();
5124          it != e.deletions().end();
5125          ++it)
5126       {
5127         unsigned i = it->index();
5128         method_decl_sptr mem_fn =
5129           first_class_decl()->get_virtual_mem_fns()[i];
5130         string name = mem_fn->get_linkage_name();
5131         if (name.empty())
5132           name = mem_fn->get_pretty_representation();
5133         ABG_ASSERT(!name.empty());
5134         if (p->deleted_member_functions_.find(name)
5135             != p->deleted_member_functions_.end())
5136           continue;
5137         p->deleted_member_functions_[name] = mem_fn;
5138       }
5139
5140     for (vector<insertion>::const_iterator it = e.insertions().begin();
5141          it != e.insertions().end();
5142          ++it)
5143       {
5144         for (vector<unsigned>::const_iterator iit =
5145                it->inserted_indexes().begin();
5146              iit != it->inserted_indexes().end();
5147              ++iit)
5148           {
5149             unsigned i = *iit;
5150
5151             method_decl_sptr mem_fn =
5152               second_class_decl()->get_virtual_mem_fns()[i];
5153             string name = mem_fn->get_linkage_name();
5154             if (name.empty())
5155               name = mem_fn->get_pretty_representation();
5156             ABG_ASSERT(!name.empty());
5157             if (p->inserted_member_functions_.find(name)
5158                 != p->inserted_member_functions_.end())
5159               continue;
5160             string_member_function_sptr_map::const_iterator j =
5161               p->deleted_member_functions_.find(name);
5162
5163             if (j != p->deleted_member_functions_.end())
5164               {
5165                 if (*j->second != *mem_fn)
5166                   p->changed_member_functions_[name] =
5167                     compute_diff(static_pointer_cast<function_decl>(j->second),
5168                                  static_pointer_cast<function_decl>(mem_fn),
5169                                  context());
5170                 p->deleted_member_functions_.erase(j);
5171               }
5172             else
5173               p->inserted_member_functions_[name] = mem_fn;
5174           }
5175       }
5176
5177     // Now walk the allegedly deleted member functions; check if their
5178     // underlying symbols are deleted as well; otherwise, consider
5179     // that the member function in question hasn't been deleted.
5180
5181     vector<string> to_delete;
5182     corpus_sptr f = context()->get_first_corpus(),
5183       s = context()->get_second_corpus();;
5184     if (s)
5185       for (string_member_function_sptr_map::const_iterator i =
5186              deleted_member_fns().begin();
5187            i != deleted_member_fns().end();
5188            ++i)
5189         {
5190           if (get_member_function_is_virtual(i->second))
5191             continue;
5192           // We assume that all non-virtual member functions functions
5193           // we look at here have ELF symbols.
5194           if (!i->second->get_symbol()
5195               || s->lookup_function_symbol(*i->second->get_symbol()))
5196             to_delete.push_back(i->first);
5197         }
5198
5199
5200     for (vector<string>::const_iterator i = to_delete.begin();
5201          i != to_delete.end();
5202          ++i)
5203       p->deleted_member_functions_.erase(*i);
5204
5205     // Do something similar for added functions.
5206     to_delete.clear();
5207     if (f)
5208       for (string_member_function_sptr_map::const_iterator i =
5209              inserted_member_fns().begin();
5210            i != inserted_member_fns().end();
5211            ++i)
5212         {
5213           if (get_member_function_is_virtual(i->second))
5214             continue;
5215           // We assume that all non-virtual member functions functions
5216           // we look at here have ELF symbols.
5217           if (!i->second->get_symbol()
5218               || f->lookup_function_symbol(*i->second->get_symbol()))
5219             to_delete.push_back(i->first);
5220         }
5221
5222     for (vector<string>::const_iterator i = to_delete.begin();
5223          i != to_delete.end();
5224          ++i)
5225       p->inserted_member_functions_.erase(*i);
5226
5227     sort_string_virtual_member_function_diff_sptr_map
5228       (p->changed_member_functions_,
5229        p->sorted_changed_member_functions_);
5230   }
5231 }
5232
5233 /// Allocate the memory for the priv_ pimpl data member of the @ref
5234 /// class_diff class.
5235 void
5236 class_diff::allocate_priv_data()
5237 {
5238   class_or_union_diff::allocate_priv_data();
5239   if (!priv_)
5240     priv_.reset(new priv);
5241 }
5242
5243 /// Test whether a given base class has changed.  A base class has
5244 /// changed if it's in both in deleted *and* inserted bases.
5245 ///
5246 ///@param d the declaration for the base class to consider.
5247 ///
5248 /// @return the new base class if the given base class has changed, or
5249 /// NULL if it hasn't.
5250 class_decl::base_spec_sptr
5251 class_diff::priv::base_has_changed(class_decl::base_spec_sptr d) const
5252 {
5253   string qname = d->get_base_class()->get_qualified_name();
5254   string_base_diff_sptr_map::const_iterator it =
5255     changed_bases_.find(qname);
5256
5257   return (it == changed_bases_.end())
5258     ? class_decl::base_spec_sptr()
5259     : it->second->second_base();
5260
5261 }
5262
5263 /// Count the number of bases classes whose changes got filtered out.
5264 ///
5265 /// @return the number of bases classes whose changes got filtered
5266 /// out.
5267 size_t
5268 class_diff::priv::count_filtered_bases()
5269 {
5270   size_t num_filtered = 0;
5271   for (base_diff_sptrs_type::const_iterator i = sorted_changed_bases_.begin();
5272        i != sorted_changed_bases_.end();
5273        ++i)
5274     {
5275       diff_sptr diff = *i;
5276       if (diff && diff->is_filtered_out())
5277         ++num_filtered;
5278     }
5279   return num_filtered;
5280 }
5281
5282 /// Populate the vector of children node of the @ref diff base type
5283 /// sub-object of this instance of @ref class_diff.
5284 ///
5285 /// The children node can then later be retrieved using
5286 /// diff::children_node().
5287 void
5288 class_diff::chain_into_hierarchy()
5289 {
5290   class_or_union_diff::chain_into_hierarchy();
5291
5292   // base class changes.
5293   for (base_diff_sptrs_type::const_iterator i =
5294          get_priv()->sorted_changed_bases_.begin();
5295        i != get_priv()->sorted_changed_bases_.end();
5296        ++i)
5297     if (diff_sptr d = *i)
5298       append_child_node(d);
5299 }
5300
5301 /// Constructor of class_diff
5302 ///
5303 /// @param first_scope the first class of the diff.
5304 ///
5305 /// @param second_scope the second class of the diff.
5306 ///
5307 /// @param ctxt the diff context to use.
5308 class_diff::class_diff(class_decl_sptr first_scope,
5309                        class_decl_sptr second_scope,
5310                        diff_context_sptr ctxt)
5311   : class_or_union_diff(first_scope, second_scope, ctxt)
5312     //  We don't initialize the priv_ data member here.  This is an
5313     //  optimization to reduce memory consumption (and also execution
5314     //  time) for cases where there are a lot of instances of
5315     //  class_diff in the same equivalence class.  In compute_diff(),
5316     //  the priv_ is set to the priv_ of the canonical diff node.
5317     //  See PR libabigail/17948.
5318 {}
5319
5320 class_diff::~class_diff()
5321 {}
5322
5323 /// Getter of the private data of the @ref class_diff type.
5324 ///
5325 /// Note that due to an optimization, the private data of @ref
5326 /// class_diff can be shared among several instances of class_diff, so
5327 /// you should never try to access class_diff::priv directly.
5328 ///
5329 /// When class_diff::priv is shared, this function returns the correct
5330 /// shared one.
5331 ///
5332 /// @return the (possibly) shared private data of the current instance
5333 /// of class_diff.
5334 const class_diff::priv_sptr&
5335 class_diff::get_priv() const
5336 {
5337   if (priv_)
5338     return priv_;
5339
5340   // If the current class_diff::priv member is empty, then look for
5341   // the shared one, from the canonical type.
5342   class_diff *canonical =
5343     dynamic_cast<class_diff*>(get_canonical_diff());
5344   ABG_ASSERT(canonical);
5345   ABG_ASSERT(canonical->priv_);
5346
5347   return canonical->priv_;
5348 }
5349
5350 /// Finish building the current instance of @ref class_diff.
5351 void
5352 class_diff::finish_diff_type()
5353 {
5354   if (diff::priv_->finished_)
5355     return;
5356   chain_into_hierarchy();
5357   diff::priv_->finished_ = true;
5358 }
5359
5360 /// @return the pretty representation of the current instance of @ref
5361 /// class_diff.
5362 const string&
5363 class_diff::get_pretty_representation() const
5364 {
5365   if (diff::priv_->pretty_representation_.empty())
5366     {
5367       std::ostringstream o;
5368       o << "class_diff["
5369         << first_subject()->get_pretty_representation()
5370         << ", "
5371         << second_subject()->get_pretty_representation()
5372         << "]";
5373       diff::priv_->pretty_representation_ = o.str();
5374     }
5375   return diff::priv_->pretty_representation_;
5376 }
5377
5378 /// Return true iff the current diff node carries a change.
5379 ///
5380 /// @return true iff the current diff node carries a change.
5381 bool
5382 class_diff::has_changes() const
5383 {return (first_class_decl() != second_class_decl());}
5384
5385 /// @return the kind of local change carried by the current diff node.
5386 /// The value returned is zero if the current node carries no local
5387 /// change.
5388 enum change_kind
5389 class_diff::has_local_changes() const
5390 {
5391   ir::change_kind k = ir::NO_CHANGE_KIND;
5392   if (!equals(*first_class_decl(), *second_class_decl(), &k))
5393     return k & ir::ALL_LOCAL_CHANGES_MASK;
5394   return ir::NO_CHANGE_KIND;
5395 }
5396
5397 /// @return the first class invoveld in the diff.
5398 shared_ptr<class_decl>
5399 class_diff::first_class_decl() const
5400 {return dynamic_pointer_cast<class_decl>(first_subject());}
5401
5402 /// Getter of the second class involved in the diff.
5403 ///
5404 /// @return the second class invoveld in the diff
5405 shared_ptr<class_decl>
5406 class_diff::second_class_decl() const
5407 {return dynamic_pointer_cast<class_decl>(second_subject());}
5408
5409 /// @return the edit script of the bases of the two classes.
5410 const edit_script&
5411 class_diff::base_changes() const
5412 {return get_priv()->base_changes_;}
5413
5414 /// Getter for the deleted base classes of the diff.
5415 ///
5416 /// @return a map containing the deleted base classes, keyed with
5417 /// their pretty representation.
5418 const string_base_sptr_map&
5419 class_diff::deleted_bases() const
5420 {return get_priv()->deleted_bases_;}
5421
5422 /// Getter for the inserted base classes of the diff.
5423 ///
5424 /// @return a map containing the inserted base classes, keyed with
5425 /// their pretty representation.
5426 const string_base_sptr_map&
5427 class_diff::inserted_bases() const
5428 {return get_priv()->inserted_bases_;}
5429
5430 /// Getter for the changed base classes of the diff.
5431 ///
5432 /// @return a sorted vector containing the changed base classes
5433 const base_diff_sptrs_type&
5434 class_diff::changed_bases()
5435 {return get_priv()->sorted_changed_bases_;}
5436
5437 /// @return the edit script of the bases of the two classes.
5438 edit_script&
5439 class_diff::base_changes()
5440 {return get_priv()->base_changes_;}
5441
5442 /// Produce a basic report about the changes between two class_decl.
5443 ///
5444 /// @param out the output stream to report the changes to.
5445 ///
5446 /// @param indent the string to use as an indentation prefix in the
5447 /// report.
5448 void
5449 class_diff::report(ostream& out, const string& indent) const
5450 {
5451   context()->get_reporter()->report(*this, out, indent);
5452 }
5453
5454 /// Compute the set of changes between two instances of class_decl.
5455 ///
5456 /// Note that the two types must have been created in the same @ref
5457 /// environment, otherwise, this function aborts.
5458 ///
5459 /// @param first the first class_decl to consider.
5460 ///
5461 /// @param second the second class_decl to consider.
5462 ///
5463 /// @return changes the resulting changes.
5464 ///
5465 /// @param ctxt the diff context to use.
5466 class_diff_sptr
5467 compute_diff(const class_decl_sptr      first,
5468              const class_decl_sptr      second,
5469              diff_context_sptr          ctxt)
5470 {
5471   if (first && second)
5472     ABG_ASSERT(first->get_environment() == second->get_environment());
5473
5474   class_decl_sptr f = is_class_type(look_through_decl_only_class(first)),
5475     s = is_class_type(look_through_decl_only_class(second));
5476
5477   class_diff_sptr changes(new class_diff(f, s, ctxt));
5478
5479   ctxt->initialize_canonical_diff(changes);
5480   ABG_ASSERT(changes->get_canonical_diff());
5481
5482   if (!ctxt->get_canonical_diff_for(first, second))
5483     {
5484       // Either first or second is a decl-only class; let's set the
5485       // canonical diff here in that case.
5486       diff_sptr canonical_diff = ctxt->get_canonical_diff_for(changes);
5487       ABG_ASSERT(canonical_diff);
5488       ctxt->set_canonical_diff_for(first, second, canonical_diff);
5489     }
5490
5491   // Ok, so this is an optimization.  Do not freak out if it looks
5492   // weird, because, well, it does look weird.  This speeds up
5493   // greatly, for instance, the test case given at PR
5494   // libabigail/17948.
5495   //
5496   // We are setting the private data of the new instance of class_diff
5497   // (which is 'changes') to the private data of its canonical
5498   // instance.  That is, we are sharing the private data of 'changes'
5499   // with the private data of its canonical instance to consume less
5500   // memory in cases where the equivalence class of 'changes' is huge.
5501   //
5502   // But if changes is its own canonical instance, then we initialize
5503   // its private data properly
5504   if (is_class_diff(changes->get_canonical_diff()) == changes.get())
5505     // changes is its own canonical instance, so it gets a brand new
5506     // private data.
5507     changes->allocate_priv_data();
5508   else
5509     {
5510       // changes has a non-empty equivalence class so it's going to
5511       // share its private data with its canonical instance.  Next
5512       // time class_diff::get_priv() is invoked, it's going to return
5513       // the shared private data of the canonical instance.
5514       return changes;
5515     }
5516
5517   // Compare base specs
5518   compute_diff(f->get_base_specifiers().begin(),
5519                f->get_base_specifiers().end(),
5520                s->get_base_specifiers().begin(),
5521                s->get_base_specifiers().end(),
5522                changes->base_changes());
5523
5524   // Do *not* compare member types because it generates lots of noise
5525   // and I doubt it's really useful.
5526 #if 0
5527   compute_diff(f->get_member_types().begin(),
5528                f->get_member_types().end(),
5529                s->get_member_types().begin(),
5530                s->get_member_types().end(),
5531                changes->member_types_changes());
5532 #endif
5533
5534   // Compare data member
5535   compute_diff(f->get_non_static_data_members().begin(),
5536                f->get_non_static_data_members().end(),
5537                s->get_non_static_data_members().begin(),
5538                s->get_non_static_data_members().end(),
5539                changes->data_members_changes());
5540
5541   // Compare virtual member functions
5542   compute_diff(f->get_virtual_mem_fns().begin(),
5543                f->get_virtual_mem_fns().end(),
5544                s->get_virtual_mem_fns().begin(),
5545                s->get_virtual_mem_fns().end(),
5546                changes->member_fns_changes());
5547
5548   // Compare member function templates
5549   compute_diff(f->get_member_function_templates().begin(),
5550                f->get_member_function_templates().end(),
5551                s->get_member_function_templates().begin(),
5552                s->get_member_function_templates().end(),
5553                changes->member_fn_tmpls_changes());
5554
5555   // Likewise, do not compare member class templates
5556 #if 0
5557   compute_diff(f->get_member_class_templates().begin(),
5558                f->get_member_class_templates().end(),
5559                s->get_member_class_templates().begin(),
5560                s->get_member_class_templates().end(),
5561                changes->member_class_tmpls_changes());
5562 #endif
5563
5564   changes->ensure_lookup_tables_populated();
5565
5566   return changes;
5567 }
5568
5569 //</class_diff stuff>
5570
5571 // <base_diff stuff>
5572
5573 /// Populate the vector of children node of the @ref diff base type
5574 /// sub-object of this instance of @ref base_diff.
5575 ///
5576 /// The children node can then later be retrieved using
5577 /// diff::children_node().
5578 void
5579 base_diff::chain_into_hierarchy()
5580 {append_child_node(get_underlying_class_diff());}
5581
5582 /// @param first the first base spec to consider.
5583 ///
5584 /// @param second the second base spec to consider.
5585 ///
5586 /// @param ctxt the context of the diff.  Note that this context
5587 /// object must stay alive at least during the life time of the
5588 /// current instance of @ref base_diff.  Otherwise memory corruption
5589 /// issues occur.
5590 base_diff::base_diff(class_decl::base_spec_sptr first,
5591                      class_decl::base_spec_sptr second,
5592                      class_diff_sptr            underlying,
5593                      diff_context_sptr          ctxt)
5594   : diff(first, second, ctxt),
5595     priv_(new priv(underlying))
5596 {}
5597
5598 /// Finish building the current instance of @ref base_diff.
5599 void
5600 base_diff::finish_diff_type()
5601 {
5602   if (diff::priv_->finished_)
5603     return;
5604
5605   chain_into_hierarchy();
5606   diff::priv_->finished_ = true;
5607 }
5608
5609 /// Getter for the first base spec of the diff object.
5610 ///
5611 /// @return the first base specifier for the diff object.
5612 class_decl::base_spec_sptr
5613 base_diff::first_base() const
5614 {return dynamic_pointer_cast<class_decl::base_spec>(first_subject());}
5615
5616 /// Getter for the second base spec of the diff object.
5617 ///
5618 /// @return the second base specifier for the diff object.
5619 class_decl::base_spec_sptr
5620 base_diff::second_base() const
5621 {return dynamic_pointer_cast<class_decl::base_spec>(second_subject());}
5622
5623 /// Getter for the diff object for the diff of the underlying base
5624 /// classes.
5625 ///
5626 /// @return the diff object for the diff of the underlying base
5627 /// classes.
5628 const class_diff_sptr
5629 base_diff::get_underlying_class_diff() const
5630 {return priv_->underlying_class_diff_;}
5631
5632 /// Setter for the diff object for the diff of the underlyng base
5633 /// classes.
5634 ///
5635 /// @param d the new diff object for the diff of the underlying base
5636 /// classes.
5637 void
5638 base_diff::set_underlying_class_diff(class_diff_sptr d)
5639 {priv_->underlying_class_diff_ = d;}
5640
5641 /// @return the pretty representation for the current instance of @ref
5642 /// base_diff.
5643 const string&
5644 base_diff::get_pretty_representation() const
5645 {
5646   if (diff::priv_->pretty_representation_.empty())
5647     {
5648       std::ostringstream o;
5649       o << "base_diff["
5650         << first_subject()->get_pretty_representation()
5651         << ", "
5652         << second_subject()->get_pretty_representation()
5653         << "]";
5654       diff::priv_->pretty_representation_ = o.str();
5655     }
5656   return diff::priv_->pretty_representation_;
5657 }
5658
5659 /// Return true iff the current diff node carries a change.
5660 ///
5661 /// Return true iff the current diff node carries a change.
5662 bool
5663 base_diff::has_changes() const
5664 {return first_base() != second_base();}
5665
5666 /// @return the kind of local change carried by the current diff node.
5667 /// The value returned is zero if the current node carries no local
5668 /// change.
5669 enum change_kind
5670 base_diff::has_local_changes() const
5671 {
5672   ir::change_kind k = ir::NO_CHANGE_KIND;
5673   if (!equals(*first_base(), *second_base(), &k))
5674     return k & ir::ALL_LOCAL_CHANGES_MASK;
5675   return ir::NO_CHANGE_KIND;
5676 }
5677
5678 /// Generates a report for the current instance of base_diff.
5679 ///
5680 /// @param out the output stream to send the report to.
5681 ///
5682 /// @param indent the string to use for indentation.
5683 void
5684 base_diff::report(ostream& out, const string& indent) const
5685 {
5686   context()->get_reporter()->report(*this, out, indent);
5687 }
5688
5689 /// Constructs the diff object representing a diff between two base
5690 /// class specifications.
5691 ///
5692 /// Note that the two artifacts must have been created in the same
5693 /// @ref environment, otherwise, this function aborts.
5694 ///
5695 /// @param first the first base class specification.
5696 ///
5697 /// @param second the second base class specification.
5698 ///
5699 /// @param ctxt the content of the diff.
5700 ///
5701 /// @return the resulting diff object.
5702 base_diff_sptr
5703 compute_diff(const class_decl::base_spec_sptr   first,
5704              const class_decl::base_spec_sptr   second,
5705              diff_context_sptr                  ctxt)
5706 {
5707   if (first && second)
5708     {
5709       ABG_ASSERT(first->get_environment() == second->get_environment());
5710       ABG_ASSERT(first->get_base_class()->get_environment()
5711              == second->get_base_class()->get_environment());
5712       ABG_ASSERT(first->get_environment()
5713              == first->get_base_class()->get_environment());
5714     }
5715
5716   class_diff_sptr cl = compute_diff(first->get_base_class(),
5717                                     second->get_base_class(),
5718                                     ctxt);
5719   base_diff_sptr changes(new base_diff(first, second, cl, ctxt));
5720
5721   ctxt->initialize_canonical_diff(changes);
5722
5723   return changes;
5724 }
5725
5726 // </base_diff stuff>
5727
5728
5729 // <union_diff stuff>
5730
5731 /// Clear the lookup tables useful for reporting.
5732 ///
5733 /// This function must be updated each time a lookup table is added or
5734 /// removed from the union_diff::priv.
5735 void
5736 union_diff::clear_lookup_tables(void)
5737 {class_or_union_diff::clear_lookup_tables();}
5738
5739 /// Tests if the lookup tables are empty.
5740 ///
5741 /// @return true if the lookup tables are empty, false otherwise.
5742 bool
5743 union_diff::lookup_tables_empty(void) const
5744 {return class_or_union_diff::lookup_tables_empty();}
5745
5746 /// If the lookup tables are not yet built, walk the differences and
5747 /// fill them.
5748 void
5749 union_diff::ensure_lookup_tables_populated(void) const
5750 {class_or_union_diff::ensure_lookup_tables_populated();}
5751
5752 /// Allocate the memory for the priv_ pimpl data member of the @ref
5753 /// union_diff class.
5754 void
5755 union_diff::allocate_priv_data()
5756 {
5757   class_or_union_diff::allocate_priv_data();
5758 }
5759
5760 /// Constructor for the @ref union_diff type.
5761 ///
5762 /// @param first_union the first object of the comparison.
5763 ///
5764 /// @param second_union the second object of the comparison.
5765 ///
5766 /// @param ctxt the context of the comparison.
5767 union_diff::union_diff(union_decl_sptr first_union,
5768                        union_decl_sptr second_union,
5769                        diff_context_sptr ctxt)
5770   : class_or_union_diff(first_union, second_union, ctxt)
5771 {}
5772
5773 /// Finish building the current instance of @ref union_diff.
5774 void
5775 union_diff::finish_diff_type()
5776 {class_or_union_diff::finish_diff_type();}
5777
5778 /// Destructor of the union_diff node.
5779 union_diff::~union_diff()
5780 {}
5781
5782 /// @return the first object of the comparison.
5783 union_decl_sptr
5784 union_diff::first_union_decl() const
5785 {return is_union_type(first_subject());}
5786
5787 /// @return the second object of the comparison.
5788 union_decl_sptr
5789 union_diff::second_union_decl() const
5790 {return is_union_type(second_subject());}
5791
5792 /// @return the pretty representation of the current diff node.
5793 const string&
5794 union_diff::get_pretty_representation() const
5795 {
5796   if (diff::priv_->pretty_representation_.empty())
5797     {
5798       std::ostringstream o;
5799       o << "union_diff["
5800         << first_subject()->get_pretty_representation()
5801         << ", "
5802         << second_subject()->get_pretty_representation()
5803         << "]";
5804       diff::priv_->pretty_representation_ = o.str();
5805     }
5806   return diff::priv_->pretty_representation_;
5807 }
5808
5809 /// Report the changes carried by the current @ref union_diff node in
5810 /// a textual format.
5811 ///
5812 /// @param out the output stream to write the textual report to.
5813 ///
5814 /// @param indent the number of white space to use as indentation.
5815 void
5816 union_diff::report(ostream& out, const string& indent) const
5817 {
5818   context()->get_reporter()->report(*this, out, indent);
5819 }
5820
5821 /// Compute the difference between two @ref union_decl types.
5822 ///
5823 /// Note that the two types must hav been created in the same
5824 /// environment, otherwise, this function aborts.
5825 ///
5826 /// @param first the first @ref union_decl to consider.
5827 ///
5828 /// @param second the second @ref union_decl to consider.
5829 ///
5830 /// @param ctxt the context of the diff to use.
5831 union_diff_sptr
5832 compute_diff(const union_decl_sptr      first,
5833              const union_decl_sptr      second,
5834              diff_context_sptr  ctxt)
5835 {
5836   if (first && second)
5837     ABG_ASSERT(first->get_environment() == second->get_environment());
5838
5839   union_diff_sptr changes(new union_diff(first, second, ctxt));
5840
5841   ctxt->initialize_canonical_diff(changes);
5842   ABG_ASSERT(changes->get_canonical_diff());
5843
5844   // Ok, so this is an optimization.  Do not freak out if it looks
5845   // weird, because, well, it does look weird.  This speeds up
5846   // greatly, for instance, the test case given at PR
5847   // libabigail/17948.
5848   //
5849   // We are setting the private data of the new instance of class_diff
5850   // (which is 'changes') to the private data of its canonical
5851   // instance.  That is, we are sharing the private data of 'changes'
5852   // with the private data of its canonical instance to consume less
5853   // memory in cases where the equivalence class of 'changes' is huge.
5854   //
5855   // But if changes is its own canonical instance, then we initialize
5856   // its private data properly.
5857   if (is_union_diff(changes->get_canonical_diff()) ==  changes.get())
5858     // changes is its own canonical instance, so it gets a brand new
5859     // private data.
5860     changes->allocate_priv_data();
5861   else
5862     {
5863       // changes has a non-empty equivalence class so it's going to
5864       // share its private data with its canonical instance.  Next
5865       // time class_diff::get_priv() is invoked, it's going to return
5866       // the shared private data of the canonical instance.
5867       return changes;
5868     }
5869
5870   // Compare data member
5871   compute_diff(first->get_non_static_data_members().begin(),
5872                first->get_non_static_data_members().end(),
5873                second->get_non_static_data_members().begin(),
5874                second->get_non_static_data_members().end(),
5875                changes->data_members_changes());
5876
5877 #if 0
5878   // Compare member functions
5879   compute_diff(first->get_mem_fns().begin(),
5880                first->get_mem_fns().end(),
5881                second->get_mem_fns().begin(),
5882                second->get_mem_fns().end(),
5883                changes->member_fns_changes());
5884
5885   // Compare member function templates
5886   compute_diff(first->get_member_function_templates().begin(),
5887                first->get_member_function_templates().end(),
5888                second->get_member_function_templates().begin(),
5889                second->get_member_function_templates().end(),
5890                changes->member_fn_tmpls_changes());
5891 #endif
5892
5893   changes->ensure_lookup_tables_populated();
5894
5895   return changes;
5896 }
5897
5898 // </union_diff stuff>
5899
5900 //<scope_diff stuff>
5901
5902 /// Clear the lookup tables that are useful for reporting.
5903 ///
5904 /// This function must be updated each time a lookup table is added or
5905 /// removed.
5906 void
5907 scope_diff::clear_lookup_tables()
5908 {
5909   priv_->deleted_types_.clear();
5910   priv_->deleted_decls_.clear();
5911   priv_->inserted_types_.clear();
5912   priv_->inserted_decls_.clear();
5913   priv_->changed_types_.clear();
5914   priv_->changed_decls_.clear();
5915   priv_->removed_types_.clear();
5916   priv_->removed_decls_.clear();
5917   priv_->added_types_.clear();
5918   priv_->added_decls_.clear();
5919 }
5920
5921 /// Tests if the lookup tables are empty.
5922 ///
5923 /// This function must be updated each time a lookup table is added or
5924 /// removed.
5925 ///
5926 /// @return true iff all the lookup tables are empty.
5927 bool
5928 scope_diff::lookup_tables_empty() const
5929 {
5930   return (priv_->deleted_types_.empty()
5931           && priv_->deleted_decls_.empty()
5932           && priv_->inserted_types_.empty()
5933           && priv_->inserted_decls_.empty()
5934           && priv_->changed_types_.empty()
5935           && priv_->changed_decls_.empty()
5936           && priv_->removed_types_.empty()
5937           && priv_->removed_decls_.empty()
5938           && priv_->added_types_.empty()
5939           && priv_->added_decls_.empty());
5940 }
5941
5942 /// If the lookup tables are not yet built, walk the member_changes_
5943 /// member and fill the lookup tables.
5944 void
5945 scope_diff::ensure_lookup_tables_populated()
5946 {
5947   if (!lookup_tables_empty())
5948     return;
5949
5950   edit_script& e = priv_->member_changes_;
5951
5952   // Populate deleted types & decls lookup tables.
5953   for (vector<deletion>::const_iterator i = e.deletions().begin();
5954        i != e.deletions().end();
5955        ++i)
5956     {
5957       decl_base_sptr decl = deleted_member_at(i);
5958       string qname = decl->get_qualified_name();
5959       if (is_type(decl))
5960         {
5961           class_decl_sptr klass_decl = dynamic_pointer_cast<class_decl>(decl);
5962           if (klass_decl && klass_decl->get_is_declaration_only())
5963             continue;
5964
5965           ABG_ASSERT(priv_->deleted_types_.find(qname)
5966                  == priv_->deleted_types_.end());
5967           priv_->deleted_types_[qname] = decl;
5968         }
5969       else
5970         {
5971           ABG_ASSERT(priv_->deleted_decls_.find(qname)
5972                  == priv_->deleted_decls_.end());
5973           priv_->deleted_decls_[qname] = decl;
5974         }
5975     }
5976
5977   // Populate inserted types & decls as well as chagned types & decls
5978   // lookup tables.
5979   for (vector<insertion>::const_iterator it = e.insertions().begin();
5980        it != e.insertions().end();
5981        ++it)
5982     {
5983       for (vector<unsigned>::const_iterator i = it->inserted_indexes().begin();
5984            i != it->inserted_indexes().end();
5985            ++i)
5986         {
5987           decl_base_sptr decl = inserted_member_at(i);
5988           string qname = decl->get_qualified_name();
5989           if (is_type(decl))
5990             {
5991               class_decl_sptr klass_decl =
5992                 dynamic_pointer_cast<class_decl>(decl);
5993               if (klass_decl && klass_decl->get_is_declaration_only())
5994                 continue;
5995
5996               ABG_ASSERT(priv_->inserted_types_.find(qname)
5997                      == priv_->inserted_types_.end());
5998               string_decl_base_sptr_map::const_iterator j =
5999                 priv_->deleted_types_.find(qname);
6000               if (j != priv_->deleted_types_.end())
6001                 {
6002                   if (*j->second != *decl)
6003                     priv_->changed_types_[qname] =
6004                       compute_diff(j->second, decl, context());
6005                   priv_->deleted_types_.erase(j);
6006                 }
6007               else
6008                 priv_->inserted_types_[qname] = decl;
6009             }
6010           else
6011             {
6012               ABG_ASSERT(priv_->inserted_decls_.find(qname)
6013                      == priv_->inserted_decls_.end());
6014               string_decl_base_sptr_map::const_iterator j =
6015                 priv_->deleted_decls_.find(qname);
6016               if (j != priv_->deleted_decls_.end())
6017                 {
6018                   if (*j->second != *decl)
6019                     priv_->changed_decls_[qname] =
6020                       compute_diff(j->second, decl, context());
6021                   priv_->deleted_decls_.erase(j);
6022                 }
6023               else
6024                 priv_->inserted_decls_[qname] = decl;
6025             }
6026         }
6027     }
6028
6029   sort_string_diff_sptr_map(priv_->changed_decls_,
6030                             priv_->sorted_changed_decls_);
6031   sort_string_diff_sptr_map(priv_->changed_types_,
6032                             priv_->sorted_changed_types_);
6033
6034   // Populate removed types/decls lookup tables
6035   for (string_decl_base_sptr_map::const_iterator i =
6036          priv_->deleted_types_.begin();
6037        i != priv_->deleted_types_.end();
6038        ++i)
6039     {
6040       string_decl_base_sptr_map::const_iterator r =
6041         priv_->inserted_types_.find(i->first);
6042       if (r == priv_->inserted_types_.end())
6043         priv_->removed_types_[i->first] = i->second;
6044     }
6045   for (string_decl_base_sptr_map::const_iterator i =
6046          priv_->deleted_decls_.begin();
6047        i != priv_->deleted_decls_.end();
6048        ++i)
6049     {
6050       string_decl_base_sptr_map::const_iterator r =
6051         priv_->inserted_decls_.find(i->first);
6052       if (r == priv_->inserted_decls_.end())
6053         priv_->removed_decls_[i->first] = i->second;
6054     }
6055
6056   // Populate added types/decls.
6057   for (string_decl_base_sptr_map::const_iterator i =
6058          priv_->inserted_types_.begin();
6059        i != priv_->inserted_types_.end();
6060        ++i)
6061     {
6062       string_decl_base_sptr_map::const_iterator r =
6063         priv_->deleted_types_.find(i->first);
6064       if (r == priv_->deleted_types_.end())
6065         priv_->added_types_[i->first] = i->second;
6066     }
6067   for (string_decl_base_sptr_map::const_iterator i =
6068          priv_->inserted_decls_.begin();
6069        i != priv_->inserted_decls_.end();
6070        ++i)
6071     {
6072       string_decl_base_sptr_map::const_iterator r =
6073         priv_->deleted_decls_.find(i->first);
6074       if (r == priv_->deleted_decls_.end())
6075         priv_->added_decls_[i->first] = i->second;
6076     }
6077 }
6078
6079 /// Populate the vector of children node of the @ref diff base type
6080 /// sub-object of this instance of @ref scope_diff.
6081 ///
6082 /// The children node can then later be retrieved using
6083 /// diff::children_node().
6084 void
6085 scope_diff::chain_into_hierarchy()
6086 {
6087   for (diff_sptrs_type::const_iterator i = changed_types().begin();
6088        i != changed_types().end();
6089        ++i)
6090     if (*i)
6091       append_child_node(*i);
6092
6093   for (diff_sptrs_type::const_iterator i = changed_decls().begin();
6094        i != changed_decls().end();
6095        ++i)
6096     if (*i)
6097       append_child_node(*i);
6098 }
6099
6100 /// Constructor for scope_diff
6101 ///
6102 /// @param first_scope the first scope to consider for the diff.
6103 ///
6104 /// @param second_scope the second scope to consider for the diff.
6105 ///
6106 /// @param ctxt the diff context to use.  Note that this context
6107 /// object must stay alive at least during the life time of the
6108 /// current instance of @ref scope_diff.  Otherwise memory corruption
6109 /// issues occur.
6110 scope_diff::scope_diff(scope_decl_sptr first_scope,
6111                        scope_decl_sptr second_scope,
6112                        diff_context_sptr ctxt)
6113   : diff(first_scope, second_scope, ctxt),
6114     priv_(new priv)
6115 {}
6116
6117 /// Finish building the current instance of @ref scope_diff.
6118 void
6119 scope_diff::finish_diff_type()
6120 {
6121   if (diff::priv_->finished_)
6122     return;
6123   chain_into_hierarchy();
6124   diff::priv_->finished_ = true;
6125 }
6126
6127 /// Getter for the first scope of the diff.
6128 ///
6129 /// @return the first scope of the diff.
6130 const scope_decl_sptr
6131 scope_diff::first_scope() const
6132 {return dynamic_pointer_cast<scope_decl>(first_subject());}
6133
6134 /// Getter for the second scope of the diff.
6135 ///
6136 /// @return the second scope of the diff.
6137 const scope_decl_sptr
6138 scope_diff::second_scope() const
6139 {return dynamic_pointer_cast<scope_decl>(second_subject());}
6140
6141 /// Accessor of the edit script of the members of a scope.
6142 ///
6143 /// This edit script is computed using the equality operator that
6144 /// applies to shared_ptr<decl_base>.
6145 ///
6146 /// That has interesting consequences.  For instance, consider two
6147 /// scopes S0 and S1.  S0 contains a class C0 and S1 contains a class
6148 /// S0'.  C0 and C0' have the same qualified name, but have different
6149 /// members.  The edit script will consider that C0 has been deleted
6150 /// from S0 and that S0' has been inserted.  This is a low level
6151 /// canonical representation of the changes; a higher level
6152 /// representation would give us a simpler way to say "the class C0
6153 /// has been modified into C0'".  But worry not.  We do have such
6154 /// higher representation as well; that is what changed_types() and
6155 /// changed_decls() is for.
6156 ///
6157 /// @return the edit script of the changes encapsulatd in this
6158 /// instance of scope_diff.
6159 const edit_script&
6160 scope_diff::member_changes() const
6161 {return priv_->member_changes_;}
6162
6163 /// Accessor of the edit script of the members of a scope.
6164 ///
6165 /// This edit script is computed using the equality operator that
6166 /// applies to shared_ptr<decl_base>.
6167 ///
6168 /// That has interesting consequences.  For instance, consider two
6169 /// scopes S0 and S1.  S0 contains a class C0 and S1 contains a class
6170 /// S0'.  C0 and C0' have the same qualified name, but have different
6171 /// members.  The edit script will consider that C0 has been deleted
6172 /// from S0 and that S0' has been inserted.  This is a low level
6173 /// canonical representation of the changes; a higher level
6174 /// representation would give us a simpler way to say "the class C0
6175 /// has been modified into C0'".  But worry not.  We do have such
6176 /// higher representation as well; that is what changed_types() and
6177 /// changed_decls() is for.
6178 ///
6179 /// @return the edit script of the changes encapsulatd in this
6180 /// instance of scope_diff.
6181 edit_script&
6182 scope_diff::member_changes()
6183 {return priv_->member_changes_;}
6184
6185 /// Accessor that eases the manipulation of the edit script associated
6186 /// to this instance.  It returns the scope member that is reported
6187 /// (in the edit script) as deleted at a given index.
6188 ///
6189 /// @param i the index (in the edit script) of an element of the first
6190 /// scope that has been reported as being delete.
6191 ///
6192 /// @return the scope member that has been reported by the edit script
6193 /// as being deleted at index i.
6194 const decl_base_sptr
6195 scope_diff::deleted_member_at(unsigned i) const
6196 {
6197   scope_decl_sptr scope = dynamic_pointer_cast<scope_decl>(first_subject());
6198  return scope->get_member_decls()[i];
6199 }
6200
6201 /// Accessor that eases the manipulation of the edit script associated
6202 /// to this instance.  It returns the scope member (of the first scope
6203 /// of this diff instance) that is reported (in the edit script) as
6204 /// deleted at a given iterator.
6205 ///
6206 /// @param i the iterator of an element of the first scope that has
6207 /// been reported as being delete.
6208 ///
6209 /// @return the scope member of the first scope of this diff that has
6210 /// been reported by the edit script as being deleted at iterator i.
6211 const decl_base_sptr
6212 scope_diff::deleted_member_at(vector<deletion>::const_iterator i) const
6213 {return deleted_member_at(i->index());}
6214
6215 /// Accessor that eases the manipulation of the edit script associated
6216 /// to this instance.  It returns the scope member (of the second
6217 /// scope of this diff instance) that is reported as being inserted
6218 /// from a given index.
6219 ///
6220 /// @param i the index of an element of the second scope this diff
6221 /// that has been reported by the edit script as being inserted.
6222 ///
6223 /// @return the scope member of the second scope of this diff that has
6224 /// been reported as being inserted from index i.
6225 const decl_base_sptr
6226 scope_diff::inserted_member_at(unsigned i)
6227 {
6228   scope_decl_sptr scope = dynamic_pointer_cast<scope_decl>(second_subject());
6229   return scope->get_member_decls()[i];
6230 }
6231
6232 /// Accessor that eases the manipulation of the edit script associated
6233 /// to this instance.  It returns the scope member (of the second
6234 /// scope of this diff instance) that is reported as being inserted
6235 /// from a given iterator.
6236 ///
6237 /// @param i the iterator of an element of the second scope this diff
6238 /// that has been reported by the edit script as being inserted.
6239 ///
6240 /// @return the scope member of the second scope of this diff that has
6241 /// been reported as being inserted from iterator i.
6242 const decl_base_sptr
6243 scope_diff::inserted_member_at(vector<unsigned>::const_iterator i)
6244 {return inserted_member_at(*i);}
6245
6246 /// @return a sorted vector of the types which content has changed
6247 /// from the first scope to the other.
6248 const diff_sptrs_type&
6249 scope_diff::changed_types() const
6250 {return priv_->sorted_changed_types_;}
6251
6252 /// @return a sorted vector of the decls which content has changed
6253 /// from the first scope to the other.
6254 const diff_sptrs_type&
6255 scope_diff::changed_decls() const
6256 {return priv_->sorted_changed_decls_;}
6257
6258 const string_decl_base_sptr_map&
6259 scope_diff::removed_types() const
6260 {return priv_->removed_types_;}
6261
6262 const string_decl_base_sptr_map&
6263 scope_diff::removed_decls() const
6264 {return priv_->removed_decls_;}
6265
6266 const string_decl_base_sptr_map&
6267 scope_diff::added_types() const
6268 {return priv_->added_types_;}
6269
6270 const string_decl_base_sptr_map&
6271 scope_diff::added_decls() const
6272 {return priv_->added_decls_;}
6273
6274 /// @return the pretty representation for the current instance of @ref
6275 /// scope_diff.
6276 const string&
6277 scope_diff::get_pretty_representation() const
6278 {
6279   if (diff::priv_->pretty_representation_.empty())
6280     {
6281       std::ostringstream o;
6282       o << "scope_diff["
6283         << first_subject()->get_pretty_representation()
6284         << ", "
6285         << second_subject()->get_pretty_representation()
6286         << "]";
6287       diff::priv_->pretty_representation_ = o.str();
6288     }
6289   return diff::priv_->pretty_representation_;
6290 }
6291
6292 /// Return true iff the current diff node carries a change.
6293 ///
6294 /// Return true iff the current diff node carries a change.
6295 bool
6296 scope_diff::has_changes() const
6297 {
6298   // TODO: add the number of really removed/added stuff.
6299   return changed_types().size() + changed_decls().size();
6300 }
6301
6302 /// @return the kind of local change carried by the current diff node.
6303 /// The value returned is zero if the current node carries no local
6304 /// change.
6305 enum change_kind
6306 scope_diff::has_local_changes() const
6307 {
6308   ir::change_kind k = ir::NO_CHANGE_KIND;
6309   if (!equals(*first_scope(), *second_scope(), &k))
6310     return k & ir::ALL_LOCAL_CHANGES_MASK;
6311   return ir::NO_CHANGE_KIND;
6312 }
6313
6314 /// Report the changes of one scope against another.
6315 ///
6316 /// @param out the out stream to report the changes to.
6317 ///
6318 /// @param indent the string to use for indentation.
6319 void
6320 scope_diff::report(ostream& out, const string& indent) const
6321 {
6322   context()->get_reporter()->report(*this, out, indent);
6323 }
6324
6325 /// Compute the diff between two scopes.
6326 ///
6327 /// Note that the two decls must have been created in the same @ref
6328 /// environment, otherwise, this function aborts.
6329 ///
6330 /// @param first the first scope to consider in computing the diff.
6331 ///
6332 /// @param second the second scope to consider in the diff
6333 /// computation.  The second scope is diffed against the first scope.
6334 ///
6335 /// @param d a pointer to the diff object to populate with the
6336 /// computed diff.
6337 ///
6338 /// @return return the populated \a d parameter passed to this
6339 /// function.
6340 ///
6341 /// @param ctxt the diff context to use.
6342 scope_diff_sptr
6343 compute_diff(const scope_decl_sptr      first,
6344              const scope_decl_sptr      second,
6345              scope_diff_sptr            d,
6346              diff_context_sptr          ctxt)
6347 {
6348   ABG_ASSERT(d->first_scope() == first && d->second_scope() == second);
6349
6350   if (first && second)
6351     ABG_ASSERT(first->get_environment() == second->get_environment());
6352
6353   compute_diff(first->get_member_decls().begin(),
6354                first->get_member_decls().end(),
6355                second->get_member_decls().begin(),
6356                second->get_member_decls().end(),
6357                d->member_changes());
6358
6359   d->ensure_lookup_tables_populated();
6360   d->context(ctxt);
6361
6362   return d;
6363 }
6364
6365 /// Compute the diff between two scopes.
6366 ///
6367 /// Note that the two decls must have been created in the same @ref
6368 /// environment, otherwise, this function aborts.
6369 ///
6370 /// @param first_scope the first scope to consider in computing the diff.
6371 ///
6372 /// @param second_scope the second scope to consider in the diff
6373 /// computation.  The second scope is diffed against the first scope.
6374 ///
6375 /// @param ctxt the diff context to use.
6376 ///
6377 /// @return return the resulting diff
6378 scope_diff_sptr
6379 compute_diff(const scope_decl_sptr      first_scope,
6380              const scope_decl_sptr      second_scope,
6381              diff_context_sptr          ctxt)
6382 {
6383   if (first_scope && second_scope)
6384     ABG_ASSERT(first_scope->get_environment()
6385            == second_scope->get_environment());
6386
6387   scope_diff_sptr d(new scope_diff(first_scope, second_scope, ctxt));
6388   d = compute_diff(first_scope, second_scope, d, ctxt);
6389   ctxt->initialize_canonical_diff(d);
6390   return d;
6391 }
6392
6393 //</scope_diff stuff>
6394
6395 // <fn_parm_diff stuff>
6396
6397 /// Constructor for the fn_parm_diff type.
6398 ///
6399 /// @param first the first subject of the diff.
6400 ///
6401 /// @param second the second subject of the diff.
6402 ///
6403 /// @param ctxt the context of the diff.  Note that this context
6404 /// object must stay alive at least during the life time of the
6405 /// current instance of @ref fn_parm_diff.  Otherwise memory
6406 /// corruption issues occur.
6407 fn_parm_diff::fn_parm_diff(const function_decl::parameter_sptr  first,
6408                            const function_decl::parameter_sptr  second,
6409                            diff_context_sptr                    ctxt)
6410   : decl_diff_base(first, second, ctxt),
6411     priv_(new priv)
6412 {
6413   ABG_ASSERT(first->get_index() == second->get_index());
6414   priv_->type_diff = compute_diff(first->get_type(),
6415                                   second->get_type(),
6416                                   ctxt);
6417   ABG_ASSERT(priv_->type_diff);
6418 }
6419
6420 /// Finish the building of the current instance of @ref fn_parm_diff.
6421 void
6422 fn_parm_diff::finish_diff_type()
6423 {
6424   if (diff::priv_->finished_)
6425     return;
6426   chain_into_hierarchy();
6427   diff::priv_->finished_ = true;
6428 }
6429
6430 /// Getter for the first subject of this diff node.
6431 ///
6432 /// @return the first function_decl::parameter_sptr subject of this
6433 /// diff node.
6434 const function_decl::parameter_sptr
6435 fn_parm_diff::first_parameter() const
6436 {return dynamic_pointer_cast<function_decl::parameter>(first_subject());}
6437
6438 /// Getter for the second subject of this diff node.
6439 ///
6440 /// @return the second function_decl::parameter_sptr subject of this
6441 /// diff node.
6442 const function_decl::parameter_sptr
6443 fn_parm_diff::second_parameter() const
6444 {return dynamic_pointer_cast<function_decl::parameter>(second_subject());}
6445
6446 /// Getter for the diff representing the changes on the type of the
6447 /// function parameter involved in the current instance of @ref
6448 /// fn_parm_diff.
6449 ///
6450 /// @return a diff_sptr representing the changes on the type of the
6451 /// function parameter we are interested in.
6452 diff_sptr
6453 fn_parm_diff::type_diff() const
6454 {return priv_->type_diff;}
6455
6456 /// Build and return a textual representation of the current instance
6457 /// of @ref fn_parm_diff.
6458 ///
6459 /// @return the string representing the current instance of
6460 /// fn_parm_diff.
6461 const string&
6462 fn_parm_diff::get_pretty_representation() const
6463 {
6464   if (diff::priv_->pretty_representation_.empty())
6465     {
6466       std::ostringstream o;
6467       o << "function_parameter_diff["
6468         << first_subject()->get_pretty_representation()
6469         << ", "
6470         << second_subject()->get_pretty_representation()
6471         << "]";
6472       diff::priv_->pretty_representation_ = o.str();
6473     }
6474   return diff::priv_->pretty_representation_;
6475 }
6476
6477 /// Return true iff the current diff node carries a change.
6478 ///
6479 /// @return true iff the current diff node carries a change.
6480 bool
6481 fn_parm_diff::has_changes() const
6482 {return *first_parameter() != *second_parameter();}
6483
6484 /// Check if the current diff node carries a local change.
6485 ///
6486 /// @return the kind of local change carried by the current diff node.
6487 /// The value returned is zero if the current node carries no local
6488 /// change.
6489 enum change_kind
6490 fn_parm_diff::has_local_changes() const
6491 {
6492   ir::change_kind k = ir::NO_CHANGE_KIND;
6493   if (!equals(*first_parameter(), *second_parameter(), &k))
6494     return k & ir::ALL_LOCAL_CHANGES_MASK;
6495   return ir::NO_CHANGE_KIND;
6496 }
6497
6498 /// Emit a textual report about the current fn_parm_diff instance.
6499 ///
6500 /// @param out the output stream to emit the textual report to.
6501 ///
6502 /// @param indent the indentation string to use in the report.
6503 void
6504 fn_parm_diff::report(ostream& out, const string& indent) const
6505 {
6506   context()->get_reporter()->report(*this, out, indent);
6507 }
6508
6509 /// Populate the vector of children nodes of the @ref diff base type
6510 /// sub-object of this instance of @ref fn_parm_diff.
6511 ///
6512 /// The children nodes can then later be retrieved using
6513 /// diff::children_nodes()
6514 void
6515 fn_parm_diff::chain_into_hierarchy()
6516 {
6517   if (type_diff())
6518     append_child_node(type_diff());
6519 }
6520
6521 /// Compute the difference between two function_decl::parameter_sptr;
6522 /// that is, between two function parameters.  Return a resulting
6523 /// fn_parm_diff_sptr that represents the changes.
6524 ///
6525 /// Note that the two decls must have been created in the same @ref
6526 /// environment, otherwise, this function aborts.
6527 ///
6528 /// @param first the first subject of the diff.
6529 ///
6530 /// @param second the second subject of the diff.
6531 ///
6532 /// @param ctxt the context of the diff.
6533 ///
6534 /// @return fn_parm_diff_sptr the resulting diff node.
6535 fn_parm_diff_sptr
6536 compute_diff(const function_decl::parameter_sptr        first,
6537              const function_decl::parameter_sptr        second,
6538              diff_context_sptr                          ctxt)
6539 {
6540   if (!first || !second)
6541     return fn_parm_diff_sptr();
6542
6543   ABG_ASSERT(first->get_environment() == second->get_environment());
6544
6545   fn_parm_diff_sptr result(new fn_parm_diff(first, second, ctxt));
6546   ctxt->initialize_canonical_diff(result);
6547
6548   return result;
6549 }
6550 // </fn_parm_diff stuff>
6551
6552 // <function_type_diff stuff>
6553
6554 void
6555 function_type_diff::ensure_lookup_tables_populated()
6556 {
6557   priv_->return_type_diff_ =
6558     compute_diff(first_function_type()->get_return_type(),
6559                  second_function_type()->get_return_type(),
6560                  context());
6561
6562   string parm_name;
6563   function_decl::parameter_sptr parm;
6564   for (vector<deletion>::const_iterator i =
6565          priv_->parm_changes_.deletions().begin();
6566        i != priv_->parm_changes_.deletions().end();
6567        ++i)
6568     {
6569       parm = *(first_function_type()->get_first_non_implicit_parm()
6570                + i->index());
6571       parm_name = parm->get_name_id();
6572       // If for a reason the type name is empty we want to know and
6573       // fix that.
6574       ABG_ASSERT(!parm_name.empty());
6575       priv_->deleted_parms_[parm_name] = parm;
6576       priv_->deleted_parms_by_id_[parm->get_index()] = parm;
6577     }
6578
6579   for (vector<insertion>::const_iterator i =
6580          priv_->parm_changes_.insertions().begin();
6581        i != priv_->parm_changes_.insertions().end();
6582        ++i)
6583     {
6584       for (vector<unsigned>::const_iterator j =
6585              i->inserted_indexes().begin();
6586            j != i->inserted_indexes().end();
6587            ++j)
6588         {
6589           parm = *(second_function_type()->get_first_non_implicit_parm() + *j);
6590           parm_name = parm->get_name_id();
6591           // If for a reason the type name is empty we want to know and
6592           // fix that.
6593           ABG_ASSERT(!parm_name.empty());
6594           {
6595             string_parm_map::const_iterator k =
6596               priv_->deleted_parms_.find(parm_name);
6597             if (k != priv_->deleted_parms_.end())
6598               {
6599                 if (*k->second != *parm)
6600                   priv_->subtype_changed_parms_[parm_name] =
6601                     compute_diff(k->second, parm, context());
6602                 priv_->deleted_parms_.erase(parm_name);
6603               }
6604             else
6605               priv_->added_parms_[parm_name] = parm;
6606           }
6607           {
6608             unsigned_parm_map::const_iterator k =
6609               priv_->deleted_parms_by_id_.find(parm->get_index());
6610             if (k != priv_->deleted_parms_by_id_.end())
6611               {
6612                 if (*k->second != *parm
6613                     && (k->second->get_name_id() != parm_name))
6614                   priv_->changed_parms_by_id_[parm->get_index()] =
6615                     compute_diff(k->second, parm, context());
6616                 priv_->added_parms_.erase(parm_name);
6617                 priv_->deleted_parms_.erase(k->second->get_name_id());
6618                 priv_->deleted_parms_by_id_.erase(parm->get_index());
6619               }
6620             else
6621               priv_->added_parms_by_id_[parm->get_index()] = parm;
6622           }
6623         }
6624     }
6625
6626   sort_string_fn_parm_diff_sptr_map(priv_->subtype_changed_parms_,
6627                                     priv_->sorted_subtype_changed_parms_);
6628   sort_string_fn_parm_diff_sptr_map(priv_->changed_parms_by_id_,
6629                                     priv_->sorted_changed_parms_by_id_);
6630   sort_string_parm_map(priv_->deleted_parms_,
6631                        priv_->sorted_deleted_parms_);
6632
6633   sort_string_parm_map(priv_->added_parms_,
6634                        priv_->sorted_added_parms_);
6635 }
6636
6637 /// In the vector of deleted parameters, get the one that is at a given
6638 /// index.
6639 ///
6640 /// @param i the index of the deleted parameter to get.
6641 ///
6642 /// @return the parameter returned.
6643 const function_decl::parameter_sptr
6644 function_type_diff::deleted_parameter_at(int i) const
6645 {return first_function_type()->get_parameters()[i];}
6646
6647 /// In the vector of inserted parameters, get the one that is at a
6648 /// given index.
6649 ///
6650 /// @param i the index of the inserted parameter to get.
6651 ///
6652 /// @return the parameter returned.
6653 const function_decl::parameter_sptr
6654 function_type_diff::inserted_parameter_at(int i) const
6655 {return second_function_type()->get_parameters()[i];}
6656
6657 /// Consutrctor of the @ref function_type type.
6658 ///
6659 /// @param first the first @ref function_type subject of the diff to
6660 /// create.
6661 ///
6662 /// @param second the second @ref function_type subject of the diff to
6663 /// create.
6664 ///
6665 /// @param ctxt the diff context to be used by the newly created
6666 /// instance of function_type_diff.  Note that this context object
6667 /// must stay alive at least during the life time of the current
6668 /// instance of @ref function_type_diff.  Otherwise memory corruption
6669 /// issues occur.
6670 function_type_diff::function_type_diff(const function_type_sptr first,
6671                                        const function_type_sptr second,
6672                                        diff_context_sptr        ctxt)
6673   : type_diff_base(first, second, ctxt),
6674     priv_(new priv)
6675 {}
6676
6677 /// Finish building the current instance of @ref function_type_diff
6678 void
6679 function_type_diff::finish_diff_type()
6680 {
6681   if (diff::priv_->finished_)
6682     return;
6683   chain_into_hierarchy();
6684   diff::priv_->finished_ = true;
6685 }
6686
6687 /// Getter for the first subject of the diff.
6688 ///
6689 /// @return the first function type involved in the diff.
6690 const function_type_sptr
6691 function_type_diff::first_function_type() const
6692 {return dynamic_pointer_cast<function_type>(first_subject());}
6693
6694 /// Getter for the second subject of the diff.
6695 ///
6696 /// @return the second function type involved in the diff.
6697 const function_type_sptr
6698 function_type_diff::second_function_type() const
6699 {return dynamic_pointer_cast<function_type>(second_subject());}
6700
6701 /// Getter for the diff of the return types of the two function types
6702 /// of the current diff.
6703 ///
6704 /// @return the diff of the return types of the two function types of
6705 /// the current diff.
6706 const diff_sptr
6707 function_type_diff::return_type_diff() const
6708 {return priv_->return_type_diff_;}
6709
6710 /// Getter for the map of function parameter changes of the current diff.
6711 ///
6712 /// @return a map of function parameter changes of the current diff.
6713 const string_fn_parm_diff_sptr_map&
6714 function_type_diff::subtype_changed_parms() const
6715 {return priv_->subtype_changed_parms_;}
6716
6717 /// Getter for the map of parameters that got removed.
6718 ///
6719 /// @return the map of parameters that got removed.
6720 const string_parm_map&
6721 function_type_diff::removed_parms() const
6722 {return priv_->deleted_parms_;}
6723
6724 /// Getter for the map of parameters that got added.
6725 ///
6726 /// @return the map of parameters that got added.
6727 const string_parm_map&
6728 function_type_diff::added_parms() const
6729 {return priv_->added_parms_;}
6730
6731 /// Build and return a copy of a pretty representation of the current
6732 /// instance of @ref function_type_diff.
6733 ///
6734 /// @return a copy of the pretty representation of the current
6735 /// instance of @ref function_type_diff.
6736 const string&
6737 function_type_diff::get_pretty_representation() const
6738 {
6739   if (diff::priv_->pretty_representation_.empty())
6740     {
6741       std::ostringstream o;
6742       o << "function_type_diff["
6743         << abigail::ir::get_pretty_representation(first_function_type())
6744         << ", "
6745         << abigail::ir::get_pretty_representation(second_function_type())
6746         << "]";
6747       diff::priv_->pretty_representation_ = o.str();
6748     }
6749   return diff::priv_->pretty_representation_;
6750 }
6751
6752 /// Test if the current diff node carries changes.
6753 ///
6754 /// @return true iff the current diff node carries changes.
6755 bool
6756 function_type_diff::has_changes() const
6757 {return *first_function_type() != *second_function_type();}
6758
6759 /// Test if the current diff node carries local changes.
6760 ///
6761 /// A local change is a change that is carried by this diff node, not
6762 /// by any of its children nodes.
6763 ///
6764 /// @return the kind of local change carried by the current diff node.
6765 /// The value returned is zero if the current node carries no local
6766 /// change.
6767 enum change_kind
6768 function_type_diff::has_local_changes() const
6769 {
6770   ir::change_kind k = ir::NO_CHANGE_KIND;
6771   if (!equals(*first_function_type(), *second_function_type(), &k))
6772     return k & ir::ALL_LOCAL_CHANGES_MASK;
6773   return ir::NO_CHANGE_KIND;
6774 }
6775
6776 /// Build and emit a textual report about the current @ref
6777 /// function_type_diff instance.
6778 ///
6779 /// @param out the output stream.
6780 ///
6781 /// @param indent the indentation string to use.
6782 void
6783 function_type_diff::report(ostream& out, const string& indent) const
6784 {
6785   context()->get_reporter()->report(*this, out, indent);
6786 }
6787
6788 /// Populate the vector of children node of the @ref diff base type
6789 /// sub-object of this instance of @ref function_type_diff.
6790 ///
6791 /// The children node can then later be retrieved using
6792 /// diff::children_node().
6793 void
6794 function_type_diff::chain_into_hierarchy()
6795 {
6796   if (diff_sptr d = return_type_diff())
6797     append_child_node(d);
6798
6799   for (vector<fn_parm_diff_sptr>::const_iterator i =
6800          priv_->sorted_subtype_changed_parms_.begin();
6801        i != priv_->sorted_subtype_changed_parms_.end();
6802        ++i)
6803     if (diff_sptr d = *i)
6804       append_child_node(d);
6805
6806   for (vector<fn_parm_diff_sptr>::const_iterator i =
6807          priv_->sorted_changed_parms_by_id_.begin();
6808        i != priv_->sorted_changed_parms_by_id_.end();
6809        ++i)
6810     if (diff_sptr d = *i)
6811       append_child_node(d);
6812 }
6813
6814 /// Compute the diff between two instances of @ref function_type.
6815 ///
6816 /// Note that the two types must have been created in the same @ref
6817 /// environment, otherwise, this function aborts.
6818 ///
6819 /// @param first the first @ref function_type to consider for the diff.
6820 ///
6821 /// @param second the second @ref function_type to consider for the diff.
6822 ///
6823 /// @param ctxt the diff context to use.
6824 ///
6825 /// @return the resulting diff between the two @ref function_type.
6826 function_type_diff_sptr
6827 compute_diff(const function_type_sptr   first,
6828              const function_type_sptr   second,
6829              diff_context_sptr          ctxt)
6830 {
6831   if (!first || !second)
6832     {
6833       // TODO: implement this for either first or second being NULL.
6834       return function_type_diff_sptr();
6835     }
6836
6837   ABG_ASSERT(first->get_environment() == second->get_environment());
6838
6839   function_type_diff_sptr result(new function_type_diff(first, second, ctxt));
6840
6841   diff_utils::compute_diff(first->get_first_non_implicit_parm(),
6842                            first->get_parameters().end(),
6843                            second->get_first_non_implicit_parm(),
6844                            second->get_parameters().end(),
6845                            result->priv_->parm_changes_);
6846
6847   result->ensure_lookup_tables_populated();
6848
6849   ctxt->initialize_canonical_diff(result);
6850
6851   return result;
6852 }
6853 // </function_type_diff stuff>
6854
6855 // <function_decl_diff stuff>
6856
6857 /// Build the lookup tables of the diff, if necessary.
6858 void
6859 function_decl_diff::ensure_lookup_tables_populated()
6860 {
6861 }
6862
6863 /// Populate the vector of children node of the @ref diff base type
6864 /// sub-object of this instance of @ref function_decl_diff.
6865 ///
6866 /// The children node can then later be retrieved using
6867 /// diff::children_node().
6868 void
6869 function_decl_diff::chain_into_hierarchy()
6870 {
6871   if (diff_sptr d = type_diff())
6872     append_child_node(d);
6873 }
6874
6875 /// Constructor for function_decl_diff
6876 ///
6877 /// @param first the first function considered by the diff.
6878 ///
6879 /// @param second the second function considered by the diff.
6880 ///
6881 /// @param ctxt the context of the diff.  Note that this context
6882 /// object must stay alive at least during the life time of the
6883 /// current instance of @ref function_decl_diff.  Otherwise memory
6884 /// corruption issues occur.
6885 function_decl_diff::function_decl_diff(const function_decl_sptr first,
6886                                        const function_decl_sptr second,
6887                                        diff_context_sptr        ctxt)
6888   : decl_diff_base(first, second, ctxt),
6889     priv_(new priv)
6890 {
6891 }
6892
6893 /// Finish building the current instance of @ref function_decl_diff.
6894 void
6895 function_decl_diff::finish_diff_type()
6896 {
6897   if (diff::priv_->finished_)
6898     return;
6899   chain_into_hierarchy();
6900   diff::priv_->finished_ = true;
6901 }
6902
6903 /// @return the first function considered by the diff.
6904 const function_decl_sptr
6905 function_decl_diff::first_function_decl() const
6906 {return dynamic_pointer_cast<function_decl>(first_subject());}
6907
6908 /// @return the second function considered by the diff.
6909 const function_decl_sptr
6910 function_decl_diff::second_function_decl() const
6911 {return dynamic_pointer_cast<function_decl>(second_subject());}
6912
6913 const function_type_diff_sptr
6914 function_decl_diff::type_diff() const
6915 {return priv_->type_diff_;}
6916
6917 /// @return the pretty representation for the current instance of @ref
6918 /// function_decl_diff.
6919 const string&
6920 function_decl_diff::get_pretty_representation() const
6921 {
6922   if (diff::priv_->pretty_representation_.empty())
6923     {
6924       std::ostringstream o;
6925       o << "function_diff["
6926         << first_subject()->get_pretty_representation()
6927         << ", "
6928         << second_subject()->get_pretty_representation()
6929         << "]";
6930       diff::priv_->pretty_representation_ = o.str();
6931     }
6932   return diff::priv_->pretty_representation_;
6933 }
6934
6935 /// Return true iff the current diff node carries a change.
6936 ///
6937 /// @return true iff the current diff node carries a change.
6938 bool
6939 function_decl_diff::has_changes() const
6940 {return *first_function_decl() != *second_function_decl();}
6941
6942 /// @return the kind of local change carried by the current diff node.
6943 /// The value returned is zero if the current node carries no local
6944 /// change.
6945 enum change_kind
6946 function_decl_diff::has_local_changes() const
6947 {
6948   ir::change_kind k = ir::NO_CHANGE_KIND;
6949   if (!equals(*first_function_decl(), *second_function_decl(), &k))
6950     return k & ir::ALL_LOCAL_CHANGES_MASK;
6951   return ir::NO_CHANGE_KIND;
6952 }
6953
6954 /// Serialize a report of the changes encapsulated in the current
6955 /// instance of @ref function_decl_diff over to an output stream.
6956 ///
6957 /// @param out the output stream to serialize the report to.
6958 ///
6959 /// @param indent the string to use an an indentation prefix.
6960 void
6961 function_decl_diff::report(ostream& out, const string& indent) const
6962 {
6963   context()->get_reporter()->report(*this, out, indent);
6964 }
6965
6966 /// Compute the diff between two function_decl.
6967 ///
6968 /// Note that the two decls must have been created in the same @ref
6969 /// environment, otherwise, this function aborts.
6970 ///
6971 /// @param first the first function_decl to consider for the diff
6972 ///
6973 /// @param second the second function_decl to consider for the diff
6974 ///
6975 /// @param ctxt the diff context to use.
6976 ///
6977 /// @return the computed diff
6978 function_decl_diff_sptr
6979 compute_diff(const function_decl_sptr first,
6980              const function_decl_sptr second,
6981              diff_context_sptr ctxt)
6982 {
6983   if (!first || !second)
6984     {
6985       // TODO: implement this for either first or second being NULL.
6986       return function_decl_diff_sptr();
6987     }
6988
6989   ABG_ASSERT(first->get_environment() == second->get_environment());
6990
6991   function_type_diff_sptr type_diff = compute_diff(first->get_type(),
6992                                                    second->get_type(),
6993                                                    ctxt);
6994
6995   function_decl_diff_sptr result(new function_decl_diff(first, second,
6996                                                         ctxt));
6997   result->priv_->type_diff_ = type_diff;
6998
6999   result->ensure_lookup_tables_populated();
7000
7001   ctxt->initialize_canonical_diff(result);
7002
7003   return result;
7004 }
7005
7006 // </function_decl_diff stuff>
7007
7008 // <type_decl_diff stuff>
7009
7010 /// Constructor for type_decl_diff.
7011 ///
7012 /// @param first the first subject of the diff.
7013 ///
7014 /// @param second the second subject of the diff.
7015 ///
7016 /// @param ctxt the context of the diff.  Note that this context
7017 /// object must stay alive at least during the life time of the
7018 /// current instance of @ref type_decl_diff.  Otherwise memory
7019 /// corruption issues occur.
7020 type_decl_diff::type_decl_diff(const type_decl_sptr first,
7021                                const type_decl_sptr second,
7022                                diff_context_sptr ctxt)
7023   : type_diff_base(first, second, ctxt)
7024 {}
7025
7026 /// Finish building the current instance of @ref type_decl_diff.
7027 void
7028 type_decl_diff::finish_diff_type()
7029 {
7030   if (diff::priv_->finished_)
7031     return;
7032   diff::priv_->finished_ = true;
7033 }
7034
7035 /// Getter for the first subject of the type_decl_diff.
7036 ///
7037 /// @return the first type_decl involved in the diff.
7038 const type_decl_sptr
7039 type_decl_diff::first_type_decl() const
7040 {return dynamic_pointer_cast<type_decl>(first_subject());}
7041
7042 /// Getter for the second subject of the type_decl_diff.
7043 ///
7044 /// @return the second type_decl involved in the diff.
7045 const type_decl_sptr
7046 type_decl_diff::second_type_decl() const
7047 {return dynamic_pointer_cast<type_decl>(second_subject());}
7048
7049 /// @return the pretty representation for the current instance of @ref
7050 /// type_decl_diff.
7051 const string&
7052 type_decl_diff::get_pretty_representation() const
7053 {
7054   if (diff::priv_->pretty_representation_.empty())
7055     {
7056       std::ostringstream o;
7057       o << "type_decl_diff["
7058         << first_subject()->get_pretty_representation()
7059         << ", "
7060         << second_subject()->get_pretty_representation()
7061         << "]";
7062       diff::priv_->pretty_representation_ = o.str();
7063     }
7064   return diff::priv_->pretty_representation_;
7065 }
7066 /// Return true iff the current diff node carries a change.
7067 ///
7068 /// @return true iff the current diff node carries a change.
7069 bool
7070 type_decl_diff::has_changes() const
7071 {return first_type_decl() != second_type_decl();}
7072
7073 /// @return the kind of local change carried by the current diff node.
7074 /// The value returned is zero if the current node carries no local
7075 /// change.
7076 enum change_kind
7077 type_decl_diff::has_local_changes() const
7078 {
7079   ir::change_kind k = ir::NO_CHANGE_KIND;
7080   if (!equals(*first_type_decl(), *second_type_decl(), &k))
7081     return k & ir::ALL_LOCAL_CHANGES_MASK;
7082   return ir::NO_CHANGE_KIND;
7083 }
7084 /// Ouputs a report of the differences between of the two type_decl
7085 /// involved in the type_decl_diff.
7086 ///
7087 /// @param out the output stream to emit the report to.
7088 ///
7089 /// @param indent the string to use for indentatino indent.
7090 void
7091 type_decl_diff::report(ostream& out, const string& indent) const
7092 {
7093   context()->get_reporter()->report(*this, out, indent);
7094 }
7095
7096 /// Compute a diff between two type_decl.
7097 ///
7098 /// Note that the two types must have been created in the same @ref
7099 /// environment, otherwise, this function aborts.
7100 ///
7101 /// This function doesn't actually compute a diff.  As a type_decl is
7102 /// very simple (unlike compound constructs like function_decl or
7103 /// class_decl) it's easy to just compare the components of the
7104 /// type_decl to know what has changed.  Thus this function just
7105 /// builds and return a type_decl_diff object.  The
7106 /// type_decl_diff::report function will just compare the components
7107 /// of the the two type_decl and display where and how they differ.
7108 ///
7109 /// @param first a pointer to the first type_decl to
7110 /// consider.
7111 ///
7112 /// @param second a pointer to the second type_decl to consider.
7113 ///
7114 /// @param ctxt the diff context to use.
7115 ///
7116 /// @return a pointer to the resulting type_decl_diff.
7117 type_decl_diff_sptr
7118 compute_diff(const type_decl_sptr       first,
7119              const type_decl_sptr       second,
7120              diff_context_sptr          ctxt)
7121 {
7122   if (first && second)
7123     ABG_ASSERT(first->get_environment() == second->get_environment());
7124
7125   type_decl_diff_sptr result(new type_decl_diff(first, second, ctxt));
7126
7127   // We don't need to actually compute a diff here as a type_decl
7128   // doesn't have complicated sub-components.  type_decl_diff::report
7129   // just walks the members of the type_decls and display information
7130   // about the ones that have changed.  On a similar note,
7131   // type_decl_diff::length returns 0 if the two type_decls are equal,
7132   // and 1 otherwise.
7133
7134   ctxt->initialize_canonical_diff(result);
7135
7136   return result;
7137 }
7138
7139 // </type_decl_diff stuff>
7140
7141 // <typedef_diff stuff>
7142
7143 /// Populate the vector of children node of the @ref diff base type
7144 /// sub-object of this instance of @ref typedef_diff.
7145 ///
7146 /// The children node can then later be retrieved using
7147 /// diff::children_node().
7148 void
7149 typedef_diff::chain_into_hierarchy()
7150 {append_child_node(underlying_type_diff());}
7151
7152 /// Constructor for typedef_diff.
7153 ///
7154 /// @param first the first subject of the diff.
7155 ///
7156 /// @param second the second subject of the diff.
7157 ///
7158 /// @param underlying the underlying diff of the @ref typedef_diff.
7159 /// That is the diff between the underlying types of @p first and @p
7160 /// second.
7161 ///
7162 /// @param ctxt the context of the diff.  Note that this context
7163 /// object must stay alive at least during the life time of the
7164 /// current instance of @ref typedef_diff.  Otherwise memory
7165 /// corruption issues occur.
7166 typedef_diff::typedef_diff(const typedef_decl_sptr      first,
7167                            const typedef_decl_sptr      second,
7168                            const diff_sptr              underlying,
7169                            diff_context_sptr            ctxt)
7170   : type_diff_base(first, second, ctxt),
7171     priv_(new priv(underlying))
7172 {}
7173
7174 /// Finish building the current instance of @ref typedef_diff.
7175 void
7176 typedef_diff::finish_diff_type()
7177 {
7178   if (diff::priv_->finished_)
7179     return;
7180   chain_into_hierarchy();
7181   diff::priv_->finished_ = true;
7182 }
7183
7184 /// Getter for the firt typedef_decl involved in the diff.
7185 ///
7186 /// @return the first subject of the diff.
7187 const typedef_decl_sptr
7188 typedef_diff::first_typedef_decl() const
7189 {return dynamic_pointer_cast<typedef_decl>(first_subject());}
7190
7191 /// Getter for the second typedef_decl involved in the diff.
7192 ///
7193 /// @return the second subject of the diff.
7194 const typedef_decl_sptr
7195 typedef_diff::second_typedef_decl() const
7196 {return dynamic_pointer_cast<typedef_decl>(second_subject());}
7197
7198 /// Getter for the diff between the two underlying types of the
7199 /// typedefs.
7200 ///
7201 /// @return the diff object reprensenting the difference between the
7202 /// two underlying types of the typedefs.
7203 const diff_sptr
7204 typedef_diff::underlying_type_diff() const
7205 {return priv_->underlying_type_diff_;}
7206
7207 /// Setter for the diff between the two underlying types of the
7208 /// typedefs.
7209 ///
7210 /// @param d the new diff object reprensenting the difference between
7211 /// the two underlying types of the typedefs.
7212 void
7213 typedef_diff::underlying_type_diff(const diff_sptr d)
7214 {priv_->underlying_type_diff_ = d;}
7215
7216 /// @return the pretty representation for the current instance of @ref
7217 /// typedef_diff.
7218 const string&
7219 typedef_diff::get_pretty_representation() const
7220 {
7221   if (diff::priv_->pretty_representation_.empty())
7222     {
7223       std::ostringstream o;
7224       o << "typedef_diff["
7225         << first_subject()->get_pretty_representation()
7226         << ", "
7227         << second_subject()->get_pretty_representation()
7228         << "]";
7229       diff::priv_->pretty_representation_ = o.str();
7230     }
7231   return diff::priv_->pretty_representation_;
7232 }
7233
7234 /// Return true iff the current diff node carries a change.
7235 ///
7236 /// @return true iff the current diff node carries a change.
7237 bool
7238 typedef_diff::has_changes() const
7239 {
7240   decl_base_sptr second = second_typedef_decl();
7241   return !(*first_typedef_decl() == *second);
7242 }
7243
7244 /// @return the kind of local change carried by the current diff node.
7245 /// The value returned is zero if the current node carries no local
7246 /// change.
7247 enum change_kind
7248 typedef_diff::has_local_changes() const
7249 {
7250   ir::change_kind k = ir::NO_CHANGE_KIND;
7251   if (!equals(*first_typedef_decl(), *second_typedef_decl(), &k))
7252     return k & ir::ALL_LOCAL_CHANGES_MASK;
7253   return ir::NO_CHANGE_KIND;
7254 }
7255
7256 /// Reports the difference between the two subjects of the diff in a
7257 /// serialized form.
7258 ///
7259 /// @param out the output stream to emit the report to.
7260 ///
7261 /// @param indent the indentation string to use.
7262 void
7263 typedef_diff::report(ostream& out, const string& indent) const
7264 {
7265   context()->get_reporter()->report(*this, out, indent);
7266 }
7267
7268 /// Compute a diff between two typedef_decl.
7269 ///
7270 /// Note that the two types must have been created in the same @ref
7271 /// environment, otherwise, this function aborts.
7272 ///
7273 /// @param first a pointer to the first typedef_decl to consider.
7274 ///
7275 /// @param second a pointer to the second typedef_decl to consider.
7276 ///
7277 /// @param ctxt the diff context to use.
7278 ///
7279 /// @return a pointer to the the resulting typedef_diff.
7280 typedef_diff_sptr
7281 compute_diff(const typedef_decl_sptr    first,
7282              const typedef_decl_sptr    second,
7283              diff_context_sptr          ctxt)
7284 {
7285   if (first && second)
7286     ABG_ASSERT(first->get_environment() == second->get_environment());
7287
7288   diff_sptr d = compute_diff_for_types(first->get_underlying_type(),
7289                                        second->get_underlying_type(),
7290                                        ctxt);
7291   typedef_diff_sptr result(new typedef_diff(first, second, d, ctxt));
7292
7293   ctxt->initialize_canonical_diff(result);
7294
7295   return result;
7296 }
7297
7298 /// Return the leaf underlying diff node of a @ref typedef_diff node.
7299 ///
7300 /// If the underlying diff node of a @ref typedef_diff node is itself
7301 /// a @ref typedef_diff node, then recursively look at the underlying
7302 /// diff nodes to get the first one that is not a a @ref typedef_diff
7303 /// node.  This is what a leaf underlying diff node means.
7304 ///
7305 /// Otherwise, if the underlying diff node of @ref typedef_diff is
7306 /// *NOT* a @ref typedef_diff node, then just return the underlying
7307 /// diff node.
7308 ///
7309 /// And if the diff node considered is not a @ref typedef_diff node,
7310 /// then just return it.
7311 ///
7312 /// @return the leaf underlying diff node of a @p diff.
7313 const diff*
7314 get_typedef_diff_underlying_type_diff(const diff* diff)
7315 {
7316   const typedef_diff* d = dynamic_cast<const typedef_diff*>(diff);
7317   if (!d)
7318     return diff;
7319
7320   if (const typedef_diff* deef =
7321       dynamic_cast<const typedef_diff*>(d->underlying_type_diff().get()))
7322     return get_typedef_diff_underlying_type_diff(deef);
7323
7324   return d->underlying_type_diff().get();
7325 }
7326
7327 // </typedef_diff stuff>
7328
7329 // <translation_unit_diff stuff>
7330
7331 /// Constructor for translation_unit_diff.
7332 ///
7333 /// @param first the first translation unit to consider for this diff.
7334 ///
7335 /// @param second the second translation unit to consider for this diff.
7336 ///
7337 /// @param ctxt the context of the diff.  Note that this context
7338 /// object must stay alive at least during the life time of the
7339 /// current instance of @ref translation_unit_diff.  Otherwise memory
7340 /// corruption issues occur.
7341 translation_unit_diff::translation_unit_diff(translation_unit_sptr first,
7342                                              translation_unit_sptr second,
7343                                              diff_context_sptr ctxt)
7344   : scope_diff(first->get_global_scope(), second->get_global_scope(), ctxt),
7345     priv_(new priv(first, second))
7346 {
7347 }
7348
7349 /// Getter for the first translation unit of this diff.
7350 ///
7351 /// @return the first translation unit of this diff.
7352 const translation_unit_sptr
7353 translation_unit_diff::first_translation_unit() const
7354 {return priv_->first_;}
7355
7356 /// Getter for the second translation unit of this diff.
7357 ///
7358 /// @return the second translation unit of this diff.
7359 const translation_unit_sptr
7360 translation_unit_diff::second_translation_unit() const
7361 {return priv_->second_;}
7362
7363 /// Return true iff the current diff node carries a change.
7364 ///
7365 /// @return true iff the current diff node carries a change.
7366 bool
7367 translation_unit_diff::has_changes() const
7368 {return scope_diff::has_changes();}
7369
7370 /// @return the kind of local change carried by the current diff node.
7371 /// The value returned is zero if the current node carries no local
7372 /// change.
7373 enum change_kind
7374 translation_unit_diff::has_local_changes() const
7375 {return ir::NO_CHANGE_KIND;}
7376
7377 /// Report the diff in a serialized form.
7378 ///
7379 /// @param out the output stream to serialize the report to.
7380 ///
7381 /// @param indent the prefix to use as indentation for the report.
7382 void
7383 translation_unit_diff::report(ostream& out, const string& indent) const
7384 {scope_diff::report(out, indent);}
7385
7386 /// Compute the diff between two translation_units.
7387 ///
7388 /// Note that the two translation units must have been created in the
7389 /// same @ref environment, otherwise, this function aborts.
7390 ///
7391 /// @param first the first translation_unit to consider.
7392 ///
7393 /// @param second the second translation_unit to consider.
7394 ///
7395 /// @param ctxt the diff context to use.  If null, this function will
7396 /// create a new context and set to the diff object returned.
7397 ///
7398 /// @return the newly created diff object.
7399 translation_unit_diff_sptr
7400 compute_diff(const translation_unit_sptr        first,
7401              const translation_unit_sptr        second,
7402              diff_context_sptr                  ctxt)
7403 {
7404   ABG_ASSERT(first && second);
7405
7406   ABG_ASSERT(first->get_environment() == second->get_environment());
7407
7408   if (!ctxt)
7409     ctxt.reset(new diff_context);
7410
7411   // TODO: handle first or second having empty contents.
7412   translation_unit_diff_sptr tu_diff(new translation_unit_diff(first, second,
7413                                                                ctxt));
7414   scope_diff_sptr sc_diff = dynamic_pointer_cast<scope_diff>(tu_diff);
7415
7416   compute_diff(static_pointer_cast<scope_decl>(first->get_global_scope()),
7417                static_pointer_cast<scope_decl>(second->get_global_scope()),
7418                sc_diff,
7419                ctxt);
7420
7421   ctxt->initialize_canonical_diff(tu_diff);
7422
7423   return tu_diff;
7424 }
7425
7426 // </translation_unit_diff stuff>
7427
7428 // <diff_maps stuff>
7429
7430 /// The private data of the @ref diff_maps type.
7431 struct diff_maps::priv
7432 {
7433   string_diff_ptr_map type_decl_diff_map_;
7434   string_diff_ptr_map enum_diff_map_;
7435   string_diff_ptr_map class_diff_map_;
7436   string_diff_ptr_map union_diff_map_;
7437   string_diff_ptr_map typedef_diff_map_;
7438   string_diff_ptr_map array_diff_map_;
7439   string_diff_ptr_map reference_diff_map_;
7440   string_diff_ptr_map function_type_diff_map_;
7441   string_diff_ptr_map function_decl_diff_map_;
7442   string_diff_ptr_map var_decl_diff_map_;
7443   string_diff_ptr_map distinct_diff_map_;
7444   string_diff_ptr_map fn_parm_diff_map_;
7445   diff_artifact_set_map_type impacted_artifacts_map_;
7446 }; // end struct diff_maps::priv
7447
7448 /// Default constructor of the @ref diff_maps type.
7449 diff_maps::diff_maps()
7450   : priv_(new diff_maps::priv())
7451 {}
7452
7453 /// Getter of the map that contains basic type diffs.
7454 ///
7455 /// @return the map that contains basic type diffs.
7456 const string_diff_ptr_map&
7457 diff_maps::get_type_decl_diff_map() const
7458 {return priv_->type_decl_diff_map_;}
7459
7460 /// Getter of the map that contains basic type diffs.
7461 ///
7462 /// @return the map that contains basic type diffs.
7463 string_diff_ptr_map&
7464 diff_maps::get_type_decl_diff_map()
7465 {return priv_->type_decl_diff_map_;}
7466
7467 /// Getter of the map that contains enum type diffs.
7468 ///
7469 /// @return the map that contains enum type diffs.
7470 const string_diff_ptr_map&
7471 diff_maps::get_enum_diff_map() const
7472 {return priv_->enum_diff_map_;}
7473
7474 /// Getter of the map that contains enum type diffs.
7475 ///
7476 /// @return the map that contains enum type diffs.
7477 string_diff_ptr_map&
7478 diff_maps::get_enum_diff_map()
7479 {return priv_->enum_diff_map_;}
7480
7481 /// Getter of the map that contains class type diffs.
7482 ///
7483 /// @return the map that contains class type diffs.
7484 const string_diff_ptr_map&
7485 diff_maps::get_class_diff_map() const
7486 {return priv_->class_diff_map_;}
7487
7488 /// Getter of the map that contains class type diffs.
7489 ///
7490 /// @return the map that contains class type diffs.
7491 string_diff_ptr_map&
7492 diff_maps::get_class_diff_map()
7493 {return priv_->class_diff_map_;}
7494
7495 /// Getter of the map that contains union type diffs.
7496 ///
7497 /// @return the map that contains union type diffs.
7498 const string_diff_ptr_map&
7499 diff_maps::get_union_diff_map() const
7500 {return priv_->union_diff_map_;}
7501
7502 /// Getter of the map that contains union type diffs.
7503 ///
7504 /// @return the map that contains union type diffs.
7505 string_diff_ptr_map&
7506 diff_maps::get_union_diff_map()
7507 {return priv_->union_diff_map_;}
7508
7509 /// Getter of the map that contains typedef type diffs.
7510 ///
7511 /// @return the map that contains typedef type diffs.
7512 const string_diff_ptr_map&
7513 diff_maps::get_typedef_diff_map() const
7514 {return priv_->typedef_diff_map_;}
7515
7516 /// Getter of the map that contains typedef type diffs.
7517 ///
7518 /// @return the map that contains typedef type diffs.
7519 string_diff_ptr_map&
7520 diff_maps::get_typedef_diff_map()
7521 {return priv_->typedef_diff_map_;}
7522
7523 /// Getter of the map that contains array type diffs.
7524 ///
7525 /// @return the map that contains array type diffs.
7526 const string_diff_ptr_map&
7527 diff_maps::get_array_diff_map() const
7528 {return priv_->array_diff_map_;}
7529
7530 /// Getter of the map that contains array type diffs.
7531 ///
7532 /// @return the map that contains array type diffs.
7533 string_diff_ptr_map&
7534 diff_maps::get_array_diff_map()
7535 {return priv_->array_diff_map_;}
7536
7537 /// Getter of the map that contains reference type diffs.
7538 ///
7539 /// @return the map that contains reference type diffs.
7540 const string_diff_ptr_map&
7541 diff_maps::get_reference_diff_map() const
7542 {return priv_->reference_diff_map_;}
7543
7544 /// Getter of the map that contains reference type diffs.
7545 ///
7546 /// @return the map that contains reference type diffs.
7547 string_diff_ptr_map&
7548 diff_maps::get_reference_diff_map()
7549 {{return priv_->reference_diff_map_;}}
7550
7551 /// Getter of the map that contains function parameter diffs.
7552 ///
7553 /// @return the map that contains function parameter diffs.
7554 const string_diff_ptr_map&
7555 diff_maps::get_fn_parm_diff_map() const
7556 {return priv_->fn_parm_diff_map_;}
7557
7558 /// Getter of the map that contains function parameter diffs.
7559 ///
7560 /// @return the map that contains function parameter diffs.
7561 string_diff_ptr_map&
7562 diff_maps::get_fn_parm_diff_map()
7563 {return priv_->fn_parm_diff_map_;}
7564
7565 /// Getter of the map that contains function type diffs.
7566 ///
7567 /// @return the map that contains function type diffs.
7568 const string_diff_ptr_map&
7569 diff_maps::get_function_type_diff_map() const
7570 {return priv_->function_type_diff_map_;}
7571
7572 /// Getter of the map that contains function type diffs.
7573 ///
7574 /// @return the map that contains function type diffs.
7575 string_diff_ptr_map&
7576 diff_maps::get_function_type_diff_map()
7577 {return priv_->function_type_diff_map_;}
7578
7579 /// Getter of the map that contains function decl diffs.
7580 ///
7581 /// @return the map that contains function decl diffs.
7582 const string_diff_ptr_map&
7583 diff_maps::get_function_decl_diff_map() const
7584 {return priv_->function_decl_diff_map_;}
7585
7586 /// Getter of the map that contains function decl diffs.
7587 ///
7588 /// @return the map that contains function decl diffs.
7589 string_diff_ptr_map&
7590 diff_maps::get_function_decl_diff_map()
7591 {return priv_->function_decl_diff_map_;}
7592
7593 /// Getter of the map that contains var decl diffs.
7594 ///
7595 /// @return the map that contains var decl diffs.
7596 const string_diff_ptr_map&
7597 diff_maps::get_var_decl_diff_map() const
7598 {return priv_->var_decl_diff_map_;}
7599
7600 /// Getter of the map that contains var decl diffs.
7601 ///
7602 /// @return the map that contains var decl diffs.
7603 string_diff_ptr_map&
7604 diff_maps::get_var_decl_diff_map()
7605 {return priv_->var_decl_diff_map_;}
7606
7607 /// Getter of the map that contains distinct diffs.
7608 ///
7609 /// @return the map that contains distinct diffs.
7610 const string_diff_ptr_map&
7611 diff_maps::get_distinct_diff_map() const
7612 {return priv_->distinct_diff_map_;}
7613
7614 /// Getter of the map that contains distinct diffs.
7615 ///
7616 /// @return the map that contains distinct diffs.
7617 string_diff_ptr_map&
7618 diff_maps::get_distinct_diff_map()
7619 {return priv_->distinct_diff_map_;}
7620
7621 /// Insert a new diff node into the current instance of @ref diff_maps.
7622 ///
7623 /// @param dif the new diff node to insert into the @ref diff_maps.
7624 ///
7625 /// @return true iff the diff node could be added to the current
7626 /// instance of @ref diff_maps.
7627 bool
7628 diff_maps::insert_diff_node(const diff *dif,
7629                             const type_or_decl_base_sptr& impacted_iface)
7630 {
7631   string n = get_pretty_representation(dif->first_subject(),
7632                                        /*internal=*/true);
7633   if (const type_decl_diff *d = is_diff_of_basic_type(dif))
7634     get_type_decl_diff_map()[n] = const_cast<type_decl_diff*>(d);
7635   else if (const enum_diff *d = is_enum_diff(dif))
7636     get_enum_diff_map()[n] = const_cast<enum_diff*>(d);
7637   else if (const class_diff *d = is_class_diff(dif))
7638       get_class_diff_map()[n] = const_cast<class_diff*>(d);
7639   else if (const union_diff *d = is_union_diff(dif))
7640     get_union_diff_map()[n] = const_cast<union_diff*>(d);
7641   else if (const typedef_diff *d = is_typedef_diff(dif))
7642     get_typedef_diff_map()[n] = const_cast<typedef_diff*>(d);
7643   else if (const array_diff *d = is_array_diff(dif))
7644       get_array_diff_map()[n] = const_cast<array_diff*>(d);
7645   else if (const reference_diff *d = is_reference_diff(dif))
7646     get_reference_diff_map()[n] = const_cast<reference_diff*>(d);
7647   else if (const fn_parm_diff *d = is_fn_parm_diff(dif))
7648     get_fn_parm_diff_map()[n] = const_cast<fn_parm_diff*>(d);
7649   else if (const function_type_diff *d = is_function_type_diff(dif))
7650     get_function_type_diff_map()[n] = const_cast<function_type_diff*>(d);
7651   else if (const var_diff *d = is_var_diff(dif))
7652     get_var_decl_diff_map()[n] = const_cast<var_diff*>(d);
7653   else if (const function_decl_diff *d = is_function_decl_diff(dif))
7654     get_function_decl_diff_map()[n] = const_cast<function_decl_diff*>(d);
7655   else if (const distinct_diff *d = is_distinct_diff(dif))
7656     get_distinct_diff_map()[n] = const_cast<distinct_diff*>(d);
7657   else if (is_base_diff(dif))
7658     // we silently drop this case.
7659     return true;
7660   else
7661       ABG_ASSERT_NOT_REACHED;
7662
7663   // Update the map that associate the interface that is impacted by
7664   // this diff, to this diff node.
7665
7666   diff_artifact_set_map_type::iterator i =
7667     priv_->impacted_artifacts_map_.find(dif);
7668
7669   if (i == priv_->impacted_artifacts_map_.end())
7670     {
7671       artifact_sptr_set_type set;
7672       set.insert(impacted_iface);
7673       priv_->impacted_artifacts_map_[dif] = set;
7674     }
7675   else
7676     i->second.insert(impacted_iface);
7677
7678   return true;
7679 }
7680
7681 /// Lookup the interfaces that are impacted by a given leaf diff node.
7682 ///
7683 /// @param d the diff node to consider.
7684 ///
7685 /// @return the set of artifacts impacted by @p d.
7686 artifact_sptr_set_type*
7687 diff_maps::lookup_impacted_interfaces(const diff *d) const
7688 {
7689   diff_artifact_set_map_type::iterator i =
7690     priv_->impacted_artifacts_map_.find(d);
7691
7692   if (i == priv_->impacted_artifacts_map_.end())
7693     return 0;
7694
7695   return &i->second;
7696 }
7697
7698 //
7699 // </diff_maps stuff>
7700
7701 /// Constructor for the @ref diff_stat type.
7702 ///
7703 /// @param ctxt the context of the corpus diff.  Note that this
7704 /// context object must stay alive at least during the life time of
7705 /// the current instance of @ref corpus_diff::diff_stats.  Otherwise
7706 /// memory corruption issues occur.
7707 corpus_diff::diff_stats::diff_stats(diff_context_sptr ctxt)
7708   : priv_(new priv(ctxt))
7709 {}
7710
7711 /// Getter for the number of functions removed.
7712 ///
7713 /// @return the number of functions removed.
7714 size_t
7715 corpus_diff::diff_stats::num_func_removed() const
7716 {return priv_->num_func_removed;}
7717
7718 /// Setter for the number of functions removed.
7719 ///
7720 /// @param n the new number of functions removed.
7721 void
7722 corpus_diff::diff_stats::num_func_removed(size_t n)
7723 {priv_->num_func_removed = n;}
7724
7725 /// Getter for the number of removed functions that have been filtered
7726 /// out.
7727 ///
7728 /// @return the number of removed functions that have been filtered
7729 /// out.
7730 size_t
7731 corpus_diff::diff_stats::num_removed_func_filtered_out() const
7732 {
7733   if (priv_->ctxt() && !priv_->ctxt()->show_deleted_fns())
7734     return num_func_removed();
7735   return priv_->num_removed_func_filtered_out;
7736 }
7737
7738 /// Setter for the number of removed functions that have been filtered
7739 /// out.
7740 ///
7741 /// @param t the new value.
7742 void
7743 corpus_diff::diff_stats::num_removed_func_filtered_out(size_t t)
7744 {priv_->num_removed_func_filtered_out = t;}
7745
7746 /// Getter for the net number of function removed.
7747 ///
7748 /// This is the difference between the number of functions removed and
7749 /// the number of functons removed that have been filtered out.
7750 ///
7751 /// @return the net number of function removed.
7752 size_t
7753 corpus_diff::diff_stats::net_num_func_removed() const
7754 {
7755   ABG_ASSERT(num_func_removed() >= num_removed_func_filtered_out());
7756   return num_func_removed() - num_removed_func_filtered_out();
7757 }
7758
7759 /// Getter for the number of functions added.
7760 ///
7761 /// @return the number of functions added.
7762 size_t
7763 corpus_diff::diff_stats::num_func_added() const
7764 {return priv_->num_func_added;}
7765
7766 /// Setter for the number of functions added.
7767 ///
7768 /// @param n the new number of functions added.
7769 void
7770 corpus_diff::diff_stats::num_func_added(size_t n)
7771 {priv_->num_func_added = n;}
7772
7773 /// Getter for the number of added function that have been filtered out.
7774 ///
7775 /// @return the number of added function that have been filtered out.
7776 size_t
7777 corpus_diff::diff_stats::num_added_func_filtered_out() const
7778 {
7779   if (priv_->ctxt() && !priv_->ctxt()->show_added_fns())
7780     return num_func_added();
7781   return priv_->num_added_func_filtered_out;
7782 }
7783
7784 /// Setter for the number of added function that have been filtered
7785 /// out.
7786 ///
7787 /// @param n the new value.
7788 void
7789 corpus_diff::diff_stats::num_added_func_filtered_out(size_t n)
7790 {priv_->num_added_func_filtered_out = n;}
7791
7792 /// Getter for the net number of added functions.
7793 ///
7794 /// The net number of added functions is the difference between the
7795 /// number of added functions and the number of added functions that
7796 /// have been filtered out.
7797 ///
7798 /// @return the net number of added functions.
7799 size_t
7800 corpus_diff::diff_stats::net_num_func_added() const
7801 {
7802   ABG_ASSERT(num_func_added() >= num_added_func_filtered_out());
7803   return num_func_added() - num_added_func_filtered_out();
7804 }
7805
7806 /// Getter for the number of functions that have a change in one of
7807 /// their sub-types.
7808 ///
7809 /// @return the number of functions that have a change in one of their
7810 /// sub-types.
7811 size_t
7812 corpus_diff::diff_stats::num_func_changed() const
7813 {return priv_->num_func_changed;}
7814
7815 /// Setter for the number of functions that have a change in one of
7816 /// their sub-types.
7817 ///
7818 /// @@param n the new number of functions that have a change in one of
7819 /// their sub-types.
7820 void
7821 corpus_diff::diff_stats::num_func_changed(size_t n)
7822 {priv_->num_func_changed = n;}
7823
7824 /// Getter for the number of functions that have a change in one of
7825 /// their sub-types, and that have been filtered out.
7826 ///
7827 /// @return the number of functions that have a change in one of their
7828 /// sub-types, and that have been filtered out.
7829 size_t
7830 corpus_diff::diff_stats::num_changed_func_filtered_out() const
7831 {return priv_->num_changed_func_filtered_out;}
7832
7833 /// Setter for the number of functions that have a change in one of
7834 /// their sub-types, and that have been filtered out.
7835 ///
7836 /// @param n the new number of functions that have a change in one of their
7837 /// sub-types, and that have been filtered out.
7838 void
7839 corpus_diff::diff_stats::num_changed_func_filtered_out(size_t n)
7840 {priv_->num_changed_func_filtered_out = n;}
7841
7842 /// Getter for the number of functions that carry virtual member
7843 /// offset changes.
7844 ///
7845 /// @return the number of functions that carry virtual member changes.
7846 size_t
7847 corpus_diff::diff_stats::num_func_with_virtual_offset_changes() const
7848 {return priv_->num_func_with_virt_offset_changes;}
7849
7850 /// Setter for the number of functions that carry virtual member
7851 /// offset changes.
7852 ///
7853 /// @param n the new number of functions that carry virtual member
7854 /// offset.  changes.
7855 void
7856 corpus_diff::diff_stats::num_func_with_virtual_offset_changes(size_t n)
7857 {priv_->num_func_with_virt_offset_changes = n;}
7858
7859 /// Getter for the number of functions that have a change in their
7860 /// sub-types, minus the number of these functions that got filtered
7861 /// out from the diff.
7862 ///
7863 /// @return for the the number of functions that have a change in
7864 /// their sub-types, minus the number of these functions that got
7865 /// filtered out from the diff.
7866 size_t
7867 corpus_diff::diff_stats::net_num_func_changed() const
7868 {return num_func_changed() - num_changed_func_filtered_out();}
7869
7870 /// Getter for the number of variables removed.
7871 ///
7872 /// @return the number of variables removed.
7873 size_t
7874 corpus_diff::diff_stats::num_vars_removed() const
7875 {return priv_->num_vars_removed;}
7876
7877 /// Setter for the number of variables removed.
7878 ///
7879 /// @param n the new number of variables removed.
7880 void
7881 corpus_diff::diff_stats::num_vars_removed(size_t n)
7882 {priv_->num_vars_removed = n;}
7883
7884 /// Getter for the number removed variables that have been filtered
7885 /// out.
7886 ///
7887 /// @return the number removed variables that have been filtered out.
7888 size_t
7889 corpus_diff::diff_stats::num_removed_vars_filtered_out() const
7890 {
7891   if (priv_->ctxt() && !priv_->ctxt()->show_deleted_vars())
7892     return num_vars_removed();
7893   return priv_->num_removed_vars_filtered_out;
7894 }
7895
7896 /// Setter for the number of removed variables that have been filtered
7897 /// out.
7898 ///
7899 /// @param n the new value.
7900 void
7901 corpus_diff::diff_stats::num_removed_vars_filtered_out(size_t n) const
7902 {priv_->num_removed_vars_filtered_out = n;}
7903
7904 /// Getter for the net number of removed variables.
7905 ///
7906 /// The net number of removed variables is the difference between the
7907 /// number of removed variables and the number of removed variables
7908 /// that have been filtered out.
7909 ///
7910 /// @return the net number of removed variables.
7911 size_t
7912 corpus_diff::diff_stats::net_num_vars_removed() const
7913 {
7914   ABG_ASSERT(num_vars_removed() >= num_removed_vars_filtered_out());
7915   return num_vars_removed() - num_removed_vars_filtered_out();
7916 }
7917
7918 /// Getter for the number of variables added.
7919 ///
7920 /// @return the number of variables added.
7921 size_t
7922 corpus_diff::diff_stats::num_vars_added() const
7923 {return priv_->num_vars_added;}
7924
7925 /// Setter for the number of variables added.
7926 ///
7927 /// @param n the new number of variables added.
7928 void
7929 corpus_diff::diff_stats::num_vars_added(size_t n)
7930 {priv_->num_vars_added = n;}
7931
7932 /// Getter for the number of added variables that have been filtered
7933 /// out.
7934 ///
7935 /// @return the number of added variables that have been filtered out.
7936 size_t
7937 corpus_diff::diff_stats::num_added_vars_filtered_out() const
7938 {
7939   if (priv_->ctxt() && !priv_->ctxt()->show_added_vars())
7940     return num_vars_added();
7941   return priv_->num_added_vars_filtered_out;
7942 }
7943
7944 /// Setter for the number of added variables that have been filtered
7945 /// out.
7946 ///
7947 /// @param n the new value.
7948 void
7949 corpus_diff::diff_stats::num_added_vars_filtered_out(size_t n)
7950 {priv_->num_added_vars_filtered_out = n;}
7951
7952 /// Getter for the net number of added variables.
7953 ///
7954 /// The net number of added variables is the difference between the
7955 /// number of added variables and the number of added variables that
7956 /// have been filetered out.
7957 ///
7958 /// @return the net number of added variables.
7959 size_t
7960 corpus_diff::diff_stats::net_num_vars_added() const
7961 {
7962   ABG_ASSERT(num_vars_added() >= num_added_vars_filtered_out());
7963   return num_vars_added() - num_added_vars_filtered_out();
7964 }
7965
7966 /// Getter for the number of variables that have a change in one of
7967 /// their sub-types.
7968 ///
7969 /// @return the number of variables that have a change in one of their
7970 /// sub-types.
7971 size_t
7972 corpus_diff::diff_stats::num_vars_changed() const
7973 {return priv_->num_vars_changed;}
7974
7975 /// Setter for the number of variables that have a change in one of
7976 /// their sub-types.
7977 ///
7978 /// @param n the new number of variables that have a change in one of
7979 /// their sub-types.
7980 void
7981 corpus_diff::diff_stats::num_vars_changed(size_t n)
7982 {priv_->num_vars_changed = n;}
7983
7984 /// Getter for the number of variables that have a change in one of
7985 /// their sub-types, and that have been filtered out.
7986 ///
7987 /// @return the number of functions that have a change in one of their
7988 /// sub-types, and that have been filtered out.
7989 size_t
7990 corpus_diff::diff_stats::num_changed_vars_filtered_out() const
7991 {return priv_->num_changed_vars_filtered_out;}
7992
7993 /// Setter for the number of variables that have a change in one of
7994 /// their sub-types, and that have been filtered out.
7995 ///
7996 /// @param n the new number of variables that have a change in one of their
7997 /// sub-types, and that have been filtered out.
7998 void
7999 corpus_diff::diff_stats::num_changed_vars_filtered_out(size_t n)
8000 {priv_->num_changed_vars_filtered_out = n;}
8001
8002 /// Getter for the number of variables that have a change in their
8003 /// sub-types, minus the number of these variables that got filtered
8004 /// out from the diff.
8005 ///
8006 /// @return for the the number of variables that have a change in
8007 /// their sub-types, minus the number of these variables that got
8008 /// filtered out from the diff.
8009 size_t
8010 corpus_diff::diff_stats::net_num_vars_changed() const
8011 {return num_vars_changed() - num_changed_vars_filtered_out();}
8012
8013 /// Getter for the number of function symbols (not referenced by any
8014 /// debug info) that got removed.
8015 ///
8016 /// @return the number of function symbols (not referenced by any
8017 /// debug info) that got removed.
8018 size_t
8019 corpus_diff::diff_stats::num_func_syms_removed() const
8020 {return priv_->num_func_syms_removed;}
8021
8022 /// Setter for the number of function symbols (not referenced by any
8023 /// debug info) that got removed.
8024 ///
8025 /// @param n the number of function symbols (not referenced by any
8026 /// debug info) that got removed.
8027 void
8028 corpus_diff::diff_stats::num_func_syms_removed(size_t n)
8029 {priv_->num_func_syms_removed = n;}
8030
8031 /// Getter for the number of removed function symbols, not referenced
8032 /// by debug info, that have been filtered out.
8033 ///
8034 /// @return the number of removed function symbols, not referenced by
8035 /// debug info, that have been filtered out.
8036 size_t
8037 corpus_diff::diff_stats::num_removed_func_syms_filtered_out() const
8038 {
8039   if (priv_->ctxt()
8040       && !priv_->ctxt()->show_symbols_unreferenced_by_debug_info())
8041     return num_func_syms_removed();
8042   return priv_->num_removed_func_syms_filtered_out;
8043 }
8044
8045 /// Setter for the number of removed function symbols, not referenced
8046 /// by debug info, that have been filtered out.
8047 ///
8048 /// @param n the new the number of removed function symbols, not
8049 /// referenced by debug info, that have been filtered out.
8050 void
8051 corpus_diff::diff_stats::num_removed_func_syms_filtered_out(size_t n)
8052 {priv_->num_removed_func_syms_filtered_out = n;}
8053
8054 /// Getter of the net number of removed function symbols that are not
8055 /// referenced by any debug info.
8056 ///
8057 /// This is the difference between the total number of removed
8058 /// function symbols and the number of removed function symbols that
8059 /// have been filteted out.  Both numbers are for symbols not
8060 /// referenced by debug info.
8061 ///
8062 /// return the net number of removed function symbols that are not
8063 /// referenced by any debug info.
8064 size_t
8065 corpus_diff::diff_stats::net_num_removed_func_syms() const
8066 {
8067   ABG_ASSERT(num_func_syms_removed() >= num_removed_func_syms_filtered_out());
8068   return num_func_syms_removed() - num_removed_func_syms_filtered_out();
8069 }
8070
8071 /// Getter for the number of function symbols (not referenced by any
8072 /// debug info) that got added.
8073 ///
8074 /// @return the number of function symbols (not referenced by any
8075 /// debug info) that got added.
8076 size_t
8077 corpus_diff::diff_stats::num_func_syms_added() const
8078 {return priv_->num_func_syms_added;}
8079
8080 /// Setter for the number of function symbols (not referenced by any
8081 /// debug info) that got added.
8082 ///
8083 /// @param n the new number of function symbols (not referenced by any
8084 /// debug info) that got added.
8085 void
8086 corpus_diff::diff_stats::num_func_syms_added(size_t n)
8087 {priv_->num_func_syms_added = n;}
8088
8089 /// Getter for the number of added function symbols, not referenced by
8090 /// any debug info, that have been filtered out.
8091 ///
8092 /// @return the number of added function symbols, not referenced by
8093 /// any debug info, that have been filtered out.
8094 size_t
8095 corpus_diff::diff_stats::num_added_func_syms_filtered_out() const
8096 {
8097   if (priv_->ctxt()
8098       && !(priv_->ctxt()->show_added_symbols_unreferenced_by_debug_info()
8099            && priv_->ctxt()->show_symbols_unreferenced_by_debug_info()))
8100     return num_func_syms_added();
8101   return priv_->num_added_func_syms_filtered_out;
8102 }
8103
8104 /// Setter for the number of added function symbols, not referenced by
8105 /// any debug info, that have been filtered out.
8106 ///
8107 /// @param n the new number of added function symbols, not referenced
8108 /// by any debug info, that have been filtered out.
8109 void
8110 corpus_diff::diff_stats::num_added_func_syms_filtered_out(size_t n)
8111 {priv_->num_added_func_syms_filtered_out = n;}
8112
8113 /// Getter of the net number of added function symbols that are not
8114 /// referenced by any debug info.
8115 ///
8116 /// This is the difference between the total number of added
8117 /// function symbols and the number of added function symbols that
8118 /// have been filteted out.  Both numbers are for symbols not
8119 /// referenced by debug info.
8120 ///
8121 /// return the net number of added function symbols that are not
8122 /// referenced by any debug info.
8123 size_t
8124 corpus_diff::diff_stats::net_num_added_func_syms() const
8125 {
8126   ABG_ASSERT(num_func_syms_added() >= num_added_func_syms_filtered_out());
8127   return num_func_syms_added()- num_added_func_syms_filtered_out();
8128 }
8129
8130 /// Getter for the number of variable symbols (not referenced by any
8131 /// debug info) that got removed.
8132 ///
8133 /// @return the number of variable symbols (not referenced by any
8134 /// debug info) that got removed.
8135 size_t
8136 corpus_diff::diff_stats::num_var_syms_removed() const
8137 {return priv_->num_var_syms_removed;}
8138
8139 /// Setter for the number of variable symbols (not referenced by any
8140 /// debug info) that got removed.
8141 ///
8142 /// @param n the number of variable symbols (not referenced by any
8143 /// debug info) that got removed.
8144 void
8145 corpus_diff::diff_stats::num_var_syms_removed(size_t n)
8146 {priv_->num_var_syms_removed = n;}
8147
8148 /// Getter for the number of removed variable symbols, not referenced
8149 /// by any debug info, that have been filtered out.
8150 ///
8151 /// @return the number of removed variable symbols, not referenced
8152 /// by any debug info, that have been filtered out.
8153 size_t
8154 corpus_diff::diff_stats::num_removed_var_syms_filtered_out() const
8155 {
8156   if (priv_->ctxt()
8157       && !priv_->ctxt()->show_symbols_unreferenced_by_debug_info())
8158     return num_var_syms_removed();
8159   return priv_->num_removed_var_syms_filtered_out;
8160 }
8161
8162 /// Setter for the number of removed variable symbols, not referenced
8163 /// by any debug info, that have been filtered out.
8164 ///
8165 /// @param n the number of removed variable symbols, not referenced by
8166 /// any debug info, that have been filtered out.
8167 void
8168 corpus_diff::diff_stats::num_removed_var_syms_filtered_out(size_t n)
8169 {priv_->num_removed_var_syms_filtered_out = n;}
8170
8171 /// Getter of the net number of removed variable symbols that are not
8172 /// referenced by any debug info.
8173 ///
8174 /// This is the difference between the total number of removed
8175 /// variable symbols and the number of removed variable symbols that
8176 /// have been filteted out.  Both numbers are for symbols not
8177 /// referenced by debug info.
8178 ///
8179 /// return the net number of removed variable symbols that are not
8180 /// referenced by any debug info.
8181 size_t
8182 corpus_diff::diff_stats::net_num_removed_var_syms() const
8183 {
8184   ABG_ASSERT(num_var_syms_removed() >= num_removed_var_syms_filtered_out());
8185   return num_var_syms_removed() - num_removed_var_syms_filtered_out();
8186 }
8187
8188 /// Getter for the number of variable symbols (not referenced by any
8189 /// debug info) that got added.
8190 ///
8191 /// @return the number of variable symbols (not referenced by any
8192 /// debug info) that got added.
8193 size_t
8194 corpus_diff::diff_stats::num_var_syms_added() const
8195 {return priv_->num_var_syms_added;}
8196
8197 /// Setter for the number of variable symbols (not referenced by any
8198 /// debug info) that got added.
8199 ///
8200 /// @param n the new number of variable symbols (not referenced by any
8201 /// debug info) that got added.
8202 void
8203 corpus_diff::diff_stats::num_var_syms_added(size_t n)
8204 {priv_->num_var_syms_added = n;}
8205
8206 /// Getter for the number of added variable symbols, not referenced by
8207 /// any debug info, that have been filtered out.
8208 ///
8209 /// @return the number of added variable symbols, not referenced by
8210 /// any debug info, that have been filtered out.
8211 size_t
8212 corpus_diff::diff_stats::num_added_var_syms_filtered_out() const
8213 {
8214   if (priv_->ctxt()
8215       && !(priv_->ctxt()->show_added_symbols_unreferenced_by_debug_info()
8216            && priv_->ctxt()->show_symbols_unreferenced_by_debug_info()))
8217     return num_var_syms_added();
8218   return priv_->num_added_var_syms_filtered_out;
8219 }
8220
8221 /// Setter for the number of added variable symbols, not referenced by
8222 /// any debug info, that have been filtered out.
8223 ///
8224 /// @param n the new number of added variable symbols, not referenced
8225 /// by any debug info, that have been filtered out.
8226 void
8227 corpus_diff::diff_stats::num_added_var_syms_filtered_out(size_t n)
8228 {priv_->num_added_var_syms_filtered_out = n;}
8229
8230 /// Getter of the net number of added variable symbols that are not
8231 /// referenced by any debug info.
8232 ///
8233 /// This is the difference between the total number of added
8234 /// variable symbols and the number of added variable symbols that
8235 /// have been filteted out.  Both numbers are for symbols not
8236 /// referenced by debug info.
8237 ///
8238 /// return the net number of added variable symbols that are not
8239 /// referenced by any debug info.
8240 size_t
8241 corpus_diff::diff_stats::net_num_added_var_syms() const
8242 {
8243   ABG_ASSERT(num_var_syms_added() >= num_added_var_syms_filtered_out());
8244   return num_var_syms_added() - num_added_var_syms_filtered_out();
8245 }
8246
8247 /// Getter of the number of leaf type change diff nodes.
8248 ///
8249 /// @return the number of leaf type change diff nodes.
8250 size_t
8251 corpus_diff::diff_stats::num_leaf_changes() const
8252 {return priv_->num_leaf_changes;}
8253
8254 /// Setter of the number of leaf type change diff nodes.
8255 ///
8256 /// @param n the new number of leaf type change diff nodes.
8257 void
8258 corpus_diff::diff_stats::num_leaf_changes(size_t n)
8259 {priv_->num_leaf_changes = n;}
8260
8261 /// Getter of the number of leaf type change diff nodes that have been
8262 /// filtered out.
8263 ///
8264 /// @return the number of leaf type change diff nodes that have been
8265 size_t
8266 corpus_diff::diff_stats::num_leaf_changes_filtered_out() const
8267 {return priv_->num_leaf_changes_filtered_out;}
8268
8269 /// Setter of the number of leaf type change diff nodes that have been
8270 /// filtered out.
8271 ///
8272 /// @param n the new number of leaf type change diff nodes that have
8273 /// been filtered out.
8274 void
8275 corpus_diff::diff_stats::num_leaf_changes_filtered_out(size_t n)
8276 {priv_->num_leaf_changes_filtered_out = n;}
8277
8278 /// Getter of the net number of leaf change diff nodes.
8279 ///
8280 /// This is the difference between the total number of leaf change
8281 /// diff nodes, and the number of the leaf change diff nodes that have
8282 /// been filtered out.
8283 ///
8284 /// A leaf change is either a type change, a function change or a
8285 /// variable change.
8286 size_t
8287 corpus_diff::diff_stats::net_num_leaf_changes() const
8288 {
8289   ABG_ASSERT(num_leaf_changes() >= num_leaf_changes_filtered_out());
8290   return num_leaf_changes() - num_leaf_changes_filtered_out();
8291 }
8292
8293 /// Getter for the number of leaf type change diff nodes.
8294 ///
8295 /// @return the number of leaf type changes diff nodes.
8296 size_t
8297 corpus_diff::diff_stats::num_leaf_type_changes() const
8298 {return priv_->num_leaf_type_changes;}
8299
8300 /// Setter for the number of leaf type change diff nodes.
8301 ///
8302 /// @param n the new number of leaf type change diff nodes.
8303 void
8304 corpus_diff::diff_stats::num_leaf_type_changes(size_t n)
8305 {priv_->num_leaf_type_changes = n;}
8306
8307 /// Getter for the number of filtered out leaf type change diff nodes.
8308 ///
8309 /// @return the number of filtered out leaf type change diff nodes.
8310 size_t
8311 corpus_diff::diff_stats::num_leaf_type_changes_filtered_out() const
8312 {return priv_->num_leaf_type_changes_filtered_out;}
8313
8314 /// Setter for the number of filtered out leaf type change diff nodes.
8315 /// @param n the new number of filtered out leaf type change diff nodes.
8316 void
8317 corpus_diff::diff_stats::num_leaf_type_changes_filtered_out(size_t n)
8318 {priv_->num_leaf_type_changes_filtered_out = n;}
8319
8320 /// Getter for the net number of leaf type change diff nodes.
8321 ///
8322 /// This is the difference between the number of leaf type changes and
8323 /// the number of filtered out leaf type changes.
8324 ///
8325 /// @return the net number of leaf type change diff nodes.
8326 size_t
8327 corpus_diff::diff_stats::net_num_leaf_type_changes() const
8328 {return num_leaf_type_changes() - num_leaf_type_changes_filtered_out();}
8329
8330 /// Getter for the number of leaf function change diff nodes.
8331 ///
8332 /// @return the number of leaf function change diff nodes.
8333 size_t
8334 corpus_diff::diff_stats::num_leaf_func_changes() const
8335 {return priv_->num_leaf_func_changes;}
8336
8337 /// Setter for the number of leaf function change diff nodes.
8338 ///
8339 /// @param n the new number of leaf function change diff nodes.
8340 void
8341 corpus_diff::diff_stats::num_leaf_func_changes(size_t n)
8342 {priv_->num_leaf_func_changes = n;}
8343
8344 /// Getter for the number of leaf function change diff nodes that were
8345 /// filtered out.
8346 ///
8347 /// @return the number of leaf function change diff nodes that were
8348 /// filtered out.
8349 size_t
8350 corpus_diff::diff_stats::num_leaf_func_changes_filtered_out() const
8351 {return priv_->num_leaf_func_changes_filtered_out;}
8352
8353 /// Setter for the number of leaf function change diff nodes that were
8354 /// filtered out.
8355 ///
8356 /// @param n the new number of leaf function change diff nodes that
8357 /// were filtered out.
8358 void
8359 corpus_diff::diff_stats::num_leaf_func_changes_filtered_out(size_t n)
8360 {priv_->num_leaf_func_changes_filtered_out = n;}
8361
8362 /// Getter for the net number of leaf function change diff nodes.
8363 ///
8364 /// This is the difference between the number of leaf function change
8365 /// diff nodes and the number of filtered out leaf function change
8366 /// diff nodes.
8367 ///
8368 /// @return the net number of leaf function change diff nodes.
8369 size_t
8370 corpus_diff::diff_stats::net_num_leaf_func_changes() const
8371 {return num_leaf_func_changes() - num_leaf_func_changes_filtered_out();}
8372
8373 /// Getter for the number of leaf variable change diff nodes.
8374 ///
8375 /// @return the number of leaf variable change diff nodes.
8376 size_t
8377 corpus_diff::diff_stats::num_leaf_var_changes() const
8378 {return priv_->num_leaf_var_changes;}
8379
8380 /// Setter for the number of leaf variable change diff nodes.
8381 ///
8382 /// @param n the number of leaf variable change diff nodes.
8383 void
8384 corpus_diff::diff_stats::num_leaf_var_changes(size_t n)
8385 {priv_->num_leaf_var_changes = n;}
8386
8387 /// Getter for the number of leaf variable changes diff nodes that
8388 /// have been filtered out.
8389 ///
8390 /// @return the number of leaf variable changes diff nodes that have
8391 /// been filtered out.
8392 size_t
8393 corpus_diff::diff_stats::num_leaf_var_changes_filtered_out() const
8394 {return priv_->num_leaf_var_changes_filtered_out;}
8395
8396 /// Setter for the number of leaf variable changes diff nodes that
8397 /// have been filtered out.
8398 ///
8399 /// @param n the number of leaf variable changes diff nodes that have
8400 /// been filtered out.
8401 void
8402 corpus_diff::diff_stats::num_leaf_var_changes_filtered_out(size_t n)
8403 {priv_->num_leaf_var_changes_filtered_out = n;}
8404
8405 /// Getter for the net number of leaf variable change diff nodes.
8406 ///
8407 /// This the difference between the number of leaf variable change
8408 /// diff nodes and the number of filtered out leaf variable change
8409 /// diff nodes.
8410 ///
8411 /// @return the net number of leaf variable change diff nodes.
8412 size_t
8413 corpus_diff::diff_stats::net_num_leaf_var_changes() const
8414 {return num_leaf_var_changes() - num_leaf_var_changes_filtered_out();}
8415 // <corpus stuff>
8416
8417 /// Getter of the context associated with this corpus.
8418 ///
8419 /// @return a smart pointer to the context associate with the corpus.
8420 diff_context_sptr
8421 corpus_diff::priv::get_context()
8422 {
8423   if (ctxt_.expired())
8424     return diff_context_sptr();
8425   return diff_context_sptr(ctxt_);
8426 }
8427
8428 /// Tests if the lookup tables are empty.
8429 ///
8430 /// @return true if the lookup tables are empty, false otherwise.
8431 bool
8432 corpus_diff::priv::lookup_tables_empty() const
8433 {
8434   return (deleted_fns_.empty()
8435           && added_fns_.empty()
8436           && changed_fns_map_.empty()
8437           && deleted_vars_.empty()
8438           && added_vars_.empty()
8439           && changed_vars_map_.empty());
8440 }
8441
8442 /// Clear the lookup tables useful for reporting an enum_diff.
8443 void
8444 corpus_diff::priv::clear_lookup_tables()
8445 {
8446   deleted_fns_.clear();
8447   added_fns_.clear();
8448   changed_fns_map_.clear();
8449   deleted_vars_.clear();
8450   added_vars_.clear();
8451   changed_vars_map_.clear();
8452 }
8453
8454 /// If the lookup tables are not yet built, walk the differences and
8455 /// fill the lookup tables.
8456 void
8457 corpus_diff::priv::ensure_lookup_tables_populated()
8458 {
8459   if (!lookup_tables_empty())
8460     return;
8461
8462   diff_context_sptr ctxt = get_context();
8463
8464   {
8465     edit_script& e = fns_edit_script_;
8466
8467     for (vector<deletion>::const_iterator it = e.deletions().begin();
8468          it != e.deletions().end();
8469          ++it)
8470       {
8471         unsigned i = it->index();
8472         ABG_ASSERT(i < first_->get_functions().size());
8473
8474         function_decl* deleted_fn = first_->get_functions()[i];
8475         string n = deleted_fn->get_id();
8476         ABG_ASSERT(!n.empty());
8477         // The below is commented out because there can be several
8478         // functions with the same ID in the corpus.  So several
8479         // functions with the same ID can be deleted.
8480         // ABG_ASSERT(deleted_fns_.find(n) == deleted_fns_.end());
8481         deleted_fns_[n] = deleted_fn;
8482       }
8483
8484     for (vector<insertion>::const_iterator it = e.insertions().begin();
8485          it != e.insertions().end();
8486          ++it)
8487       {
8488         for (vector<unsigned>::const_iterator iit =
8489                it->inserted_indexes().begin();
8490              iit != it->inserted_indexes().end();
8491              ++iit)
8492           {
8493             unsigned i = *iit;
8494             function_decl* added_fn = second_->get_functions()[i];
8495             string n = added_fn->get_id();
8496             ABG_ASSERT(!n.empty());
8497             // The below is commented out because there can be several
8498             // functions with the same ID in the corpus.  So several
8499             // functions with the same ID can be added.
8500             // ABG_ASSERT(added_fns_.find(n) == added_fns_.end());
8501             string_function_ptr_map::const_iterator j =
8502               deleted_fns_.find(n);
8503             if (j != deleted_fns_.end())
8504               {
8505                 function_decl_sptr f(j->second, noop_deleter());
8506                 function_decl_sptr s(added_fn, noop_deleter());
8507                 function_decl_diff_sptr d = compute_diff(f, s, ctxt);
8508                 if (*j->second != *added_fn)
8509                   changed_fns_map_[j->first] = d;
8510                 deleted_fns_.erase(j);
8511               }
8512             else
8513               added_fns_[n] = added_fn;
8514           }
8515       }
8516     sort_string_function_decl_diff_sptr_map(changed_fns_map_, changed_fns_);
8517
8518     // Now walk the allegedly deleted functions; check if their
8519     // underlying symbols are deleted as well; otherwise, consider
8520     // that the function in question hasn't been deleted.
8521
8522     vector<string> to_delete;
8523     for (string_function_ptr_map::const_iterator i = deleted_fns_.begin();
8524          i != deleted_fns_.end();
8525          ++i)
8526       if (second_->lookup_function_symbol(*i->second->get_symbol()))
8527         to_delete.push_back(i->first);
8528
8529     for (vector<string>::const_iterator i = to_delete.begin();
8530          i != to_delete.end();
8531          ++i)
8532       deleted_fns_.erase(*i);
8533
8534     // Do something similar for added functions.
8535
8536     to_delete.clear();
8537     for (string_function_ptr_map::const_iterator i = added_fns_.begin();
8538          i != added_fns_.end();
8539          ++i)
8540       {
8541         if (first_->lookup_function_symbol(*i->second->get_symbol()))
8542           to_delete.push_back(i->first);
8543         else if (! i->second->get_symbol()->get_version().is_empty()
8544                  && i->second->get_symbol()->get_version().is_default())
8545           // We are looking for a symbol that has a default version,
8546           // and which seems to be newly added.  Let's see if the same
8547           // symbol with *no* version was already present in the
8548           // former corpus.  If yes, then the symbol shouldn't be
8549           // considered as 'added'.
8550           {
8551             elf_symbol::version empty_version;
8552             if (first_->lookup_function_symbol(i->second->get_symbol()->get_name(),
8553                                                empty_version))
8554               to_delete.push_back(i->first);
8555           }
8556       }
8557
8558     for (vector<string>::const_iterator i = to_delete.begin();
8559          i != to_delete.end();
8560          ++i)
8561       added_fns_.erase(*i);
8562   }
8563
8564   {
8565     edit_script& e = vars_edit_script_;
8566
8567     for (vector<deletion>::const_iterator it = e.deletions().begin();
8568          it != e.deletions().end();
8569          ++it)
8570       {
8571         unsigned i = it->index();
8572         ABG_ASSERT(i < first_->get_variables().size());
8573
8574         var_decl* deleted_var = first_->get_variables()[i];
8575         string n = deleted_var->get_id();
8576         ABG_ASSERT(!n.empty());
8577         ABG_ASSERT(deleted_vars_.find(n) == deleted_vars_.end());
8578         deleted_vars_[n] = deleted_var;
8579       }
8580
8581     for (vector<insertion>::const_iterator it = e.insertions().begin();
8582          it != e.insertions().end();
8583          ++it)
8584       {
8585         for (vector<unsigned>::const_iterator iit =
8586                it->inserted_indexes().begin();
8587              iit != it->inserted_indexes().end();
8588              ++iit)
8589           {
8590             unsigned i = *iit;
8591             var_decl* added_var = second_->get_variables()[i];
8592             string n = added_var->get_id();
8593             ABG_ASSERT(!n.empty());
8594             {
8595               string_var_ptr_map::const_iterator k = added_vars_.find(n);
8596               if ( k != added_vars_.end())
8597                 {
8598                   ABG_ASSERT(is_member_decl(k->second)
8599                          && get_member_is_static(k->second));
8600                   continue;
8601                 }
8602             }
8603             string_var_ptr_map::const_iterator j =
8604               deleted_vars_.find(n);
8605             if (j != deleted_vars_.end())
8606               {
8607                 if (*j->second != *added_var)
8608                   {
8609                     var_decl_sptr f(j->second, noop_deleter());
8610                     var_decl_sptr s(added_var, noop_deleter());
8611                     changed_vars_map_[n] = compute_diff(f, s, ctxt);
8612                   }
8613                 deleted_vars_.erase(j);
8614               }
8615             else
8616               added_vars_[n] = added_var;
8617           }
8618       }
8619     sort_string_var_diff_sptr_map(changed_vars_map_,
8620                                   sorted_changed_vars_);
8621
8622     // Now walk the allegedly deleted variables; check if their
8623     // underlying symbols are deleted as well; otherwise consider
8624     // that the variable in question hasn't been deleted.
8625
8626     vector<string> to_delete;
8627     for (string_var_ptr_map::const_iterator i = deleted_vars_.begin();
8628          i != deleted_vars_.end();
8629          ++i)
8630       if (second_->lookup_variable_symbol(*i->second->get_symbol()))
8631         to_delete.push_back(i->first);
8632
8633     for (vector<string>::const_iterator i = to_delete.begin();
8634          i != to_delete.end();
8635          ++i)
8636       deleted_vars_.erase(*i);
8637
8638     // Do something similar for added variables.
8639
8640     to_delete.clear();
8641     for (string_var_ptr_map::const_iterator i = added_vars_.begin();
8642          i != added_vars_.end();
8643          ++i)
8644       if (first_->lookup_variable_symbol(*i->second->get_symbol()))
8645         to_delete.push_back(i->first);
8646       else if (! i->second->get_symbol()->get_version().is_empty()
8647                  && i->second->get_symbol()->get_version().is_default())
8648         // We are looking for a symbol that has a default version,
8649         // and which seems to be newly added.  Let's see if the same
8650         // symbol with *no* version was already present in the
8651         // former corpus.  If yes, then the symbol shouldn't be
8652         // considered as 'added'.
8653         {
8654           elf_symbol::version empty_version;
8655           if (first_->lookup_variable_symbol(i->second->get_symbol()->get_name(),
8656                                              empty_version))
8657             to_delete.push_back(i->first);
8658         }
8659
8660     for (vector<string>::const_iterator i = to_delete.begin();
8661          i != to_delete.end();
8662          ++i)
8663       added_vars_.erase(*i);
8664   }
8665
8666   // Massage the edit script for added/removed function symbols that
8667   // were not referenced by any debug info and turn them into maps of
8668   // {symbol_name, symbol}.
8669   {
8670     edit_script& e = unrefed_fn_syms_edit_script_;
8671     for (vector<deletion>::const_iterator it = e.deletions().begin();
8672          it != e.deletions().end();
8673          ++it)
8674       {
8675         unsigned i = it->index();
8676         ABG_ASSERT(i < first_->get_unreferenced_function_symbols().size());
8677         elf_symbol_sptr deleted_sym =
8678           first_->get_unreferenced_function_symbols()[i];
8679         if (!second_->lookup_function_symbol(*deleted_sym))
8680           deleted_unrefed_fn_syms_[deleted_sym->get_id_string()] = deleted_sym;
8681       }
8682
8683     for (vector<insertion>::const_iterator it = e.insertions().begin();
8684          it != e.insertions().end();
8685          ++it)
8686       {
8687         for (vector<unsigned>::const_iterator iit =
8688                it->inserted_indexes().begin();
8689              iit != it->inserted_indexes().end();
8690              ++iit)
8691           {
8692             unsigned i = *iit;
8693             ABG_ASSERT(i < second_->get_unreferenced_function_symbols().size());
8694             elf_symbol_sptr added_sym =
8695               second_->get_unreferenced_function_symbols()[i];
8696             if ((deleted_unrefed_fn_syms_.find(added_sym->get_id_string())
8697                  == deleted_unrefed_fn_syms_.end()))
8698               {
8699                 if (!first_->lookup_function_symbol(*added_sym))
8700                   {
8701                     bool do_add = true;
8702                     if (! added_sym->get_version().is_empty()
8703                         && added_sym->get_version().is_default())
8704                       {
8705                         // So added_seem has a default version.  If
8706                         // the former corpus had a symbol with the
8707                         // same name as added_sym but with *no*
8708                         // version, then added_sym shouldn't be
8709                         // considered as a newly added symbol.
8710                         elf_symbol::version empty_version;
8711                         if (first_->lookup_function_symbol(added_sym->get_name(),
8712                                                            empty_version))
8713                           do_add = false;
8714                       }
8715
8716                     if (do_add)
8717                       added_unrefed_fn_syms_[added_sym->get_id_string()] =
8718                         added_sym;
8719                   }
8720               }
8721             else
8722               deleted_unrefed_fn_syms_.erase(added_sym->get_id_string());
8723           }
8724       }
8725   }
8726
8727   // Massage the edit script for added/removed variable symbols that
8728   // were not referenced by any debug info and turn them into maps of
8729   // {symbol_name, symbol}.
8730   {
8731     edit_script& e = unrefed_var_syms_edit_script_;
8732     for (vector<deletion>::const_iterator it = e.deletions().begin();
8733          it != e.deletions().end();
8734          ++it)
8735       {
8736         unsigned i = it->index();
8737         ABG_ASSERT(i < first_->get_unreferenced_variable_symbols().size());
8738         elf_symbol_sptr deleted_sym =
8739           first_->get_unreferenced_variable_symbols()[i];
8740         if (!second_->lookup_variable_symbol(*deleted_sym))
8741           deleted_unrefed_var_syms_[deleted_sym->get_id_string()] = deleted_sym;
8742       }
8743
8744     for (vector<insertion>::const_iterator it = e.insertions().begin();
8745          it != e.insertions().end();
8746          ++it)
8747       {
8748         for (vector<unsigned>::const_iterator iit =
8749                it->inserted_indexes().begin();
8750              iit != it->inserted_indexes().end();
8751              ++iit)
8752           {
8753             unsigned i = *iit;
8754             ABG_ASSERT(i < second_->get_unreferenced_variable_symbols().size());
8755             elf_symbol_sptr added_sym =
8756               second_->get_unreferenced_variable_symbols()[i];
8757             if (deleted_unrefed_var_syms_.find(added_sym->get_id_string())
8758                 == deleted_unrefed_var_syms_.end())
8759               {
8760                 if (!first_->lookup_variable_symbol(*added_sym))
8761                   {
8762                     bool do_add = true;
8763                     if (! added_sym->get_version().is_empty()
8764                         && added_sym->get_version().is_default())
8765                       {
8766                         // So added_seem has a default version.  If
8767                         // the former corpus had a symbol with the
8768                         // same name as added_sym but with *no*
8769                         // version, then added_sym shouldn't be
8770                         // considered as a newly added symbol.
8771                         elf_symbol::version empty_version;
8772                         if (first_->lookup_variable_symbol(added_sym->get_name(),
8773                                                            empty_version))
8774                           do_add = false;
8775                       }
8776
8777                     if (do_add)
8778                       added_unrefed_var_syms_[added_sym->get_id_string()] =
8779                         added_sym;
8780                   }
8781               }
8782             else
8783               deleted_unrefed_var_syms_.erase(added_sym->get_id_string());
8784           }
8785       }
8786   }
8787 }
8788
8789 /// Test if a change reports about a given @ref function_decl that is
8790 /// changed in a certain way is suppressed by a given suppression
8791 /// specifiation
8792 ///
8793 /// @param fn the @ref function_decl to consider.
8794 ///
8795 /// @param suppr the suppression specification to consider.
8796 ///
8797 /// @param k the kind of change that happened to @p fn.
8798 ///
8799 /// @param ctxt the context of the current diff.
8800 ///
8801 /// @return true iff the suppression specification @p suppr suppresses
8802 /// change reports about function @p fn, if that function changes in
8803 /// the way expressed by @p k.
8804 static bool
8805 function_is_suppressed(const function_decl* fn,
8806                        const suppression_sptr suppr,
8807                        function_suppression::change_kind k,
8808                        const diff_context_sptr ctxt)
8809 {
8810   function_suppression_sptr fn_suppr = is_function_suppression(suppr);
8811   if (!fn_suppr)
8812     return false;
8813   return fn_suppr->suppresses_function(fn, k, ctxt);
8814 }
8815
8816 /// Test if a change reports about a given @ref var_decl that is
8817 /// changed in a certain way is suppressed by a given suppression
8818 /// specifiation
8819 ///
8820 /// @param fn the @ref var_decl to consider.
8821 ///
8822 /// @param suppr the suppression specification to consider.
8823 ///
8824 /// @param k the kind of change that happened to @p fn.
8825 ///
8826 /// @param ctxt the context of the current diff.
8827 ///
8828 /// @return true iff the suppression specification @p suppr suppresses
8829 /// change reports about variable @p fn, if that variable changes in
8830 /// the way expressed by @p k.
8831 static bool
8832 variable_is_suppressed(const var_decl* var,
8833                        const suppression_sptr suppr,
8834                        variable_suppression::change_kind k,
8835                        const diff_context_sptr ctxt)
8836 {
8837   variable_suppression_sptr var_suppr = is_variable_suppression(suppr);
8838   if (!var_suppr)
8839     return false;
8840   return var_suppr->suppresses_variable(var, k, ctxt);
8841 }
8842
8843 /// Apply the suppression specifications for this corpus diff to the
8844 /// set of added and removed functions and variables.
8845 void
8846 corpus_diff::priv::apply_suppressions_to_added_removed_fns_vars()
8847 {
8848   diff_context_sptr ctxt = get_context();
8849
8850   const suppressions_type& suppressions = ctxt->suppressions();
8851   for (suppressions_type::const_iterator i = suppressions.begin();
8852        i != suppressions.end();
8853        ++i)
8854     {
8855       // Added/Deleted functions.
8856       if (function_suppression_sptr fn_suppr = is_function_suppression(*i))
8857         {
8858           // Added functions
8859           for (string_function_ptr_map::const_iterator e = added_fns_.begin();
8860                e != added_fns_.end();
8861                ++e)
8862             if (function_is_suppressed(e->second, fn_suppr,
8863                                        function_suppression::ADDED_FUNCTION_CHANGE_KIND,
8864                                        ctxt))
8865               suppressed_added_fns_[e->first] = e->second;
8866
8867           // Deleted functions.
8868           for (string_function_ptr_map::const_iterator e = deleted_fns_.begin();
8869                e != deleted_fns_.end();
8870                ++e)
8871             if (function_is_suppressed(e->second, fn_suppr,
8872                                        function_suppression::DELETED_FUNCTION_CHANGE_KIND,
8873                                        ctxt))
8874               suppressed_deleted_fns_[e->first] = e->second;
8875
8876           // Added function symbols not referenced by any debug info
8877           for (string_elf_symbol_map::const_iterator e =
8878                  added_unrefed_fn_syms_.begin();
8879                e != added_unrefed_fn_syms_.end();
8880                ++e)
8881             if (fn_suppr->suppresses_function_symbol(e->second,
8882                                                      function_suppression::ADDED_FUNCTION_CHANGE_KIND,
8883                                                      ctxt))
8884               suppressed_added_unrefed_fn_syms_[e->first] = e->second;
8885
8886           // Removed function symbols not referenced by any debug info
8887           for (string_elf_symbol_map::const_iterator e =
8888                  deleted_unrefed_fn_syms_.begin();
8889                e != deleted_unrefed_fn_syms_.end();
8890                ++e)
8891             if (fn_suppr->suppresses_function_symbol(e->second,
8892                                                      function_suppression::DELETED_FUNCTION_CHANGE_KIND,
8893                                                      ctxt))
8894               suppressed_deleted_unrefed_fn_syms_[e->first] = e->second;
8895         }
8896       // Added/Delete virtual member functions changes that might be
8897       // suppressed by a type_suppression that matches the enclosing
8898       // class of the virtual member function.
8899       else if (type_suppression_sptr type_suppr = is_type_suppression(*i))
8900         {
8901           // Added virtual functions
8902           for (string_function_ptr_map::const_iterator e = added_fns_.begin();
8903                e != added_fns_.end();
8904                ++e)
8905             if (is_member_function(e->second)
8906                 && get_member_function_is_virtual(e->second))
8907               {
8908                 function_decl *f = e->second;
8909                 class_decl_sptr c =
8910                   is_class_type(is_method_type(f->get_type())->get_class_type());
8911                 ABG_ASSERT(c);
8912                 if (type_suppr->suppresses_type(c, ctxt))
8913                   suppressed_added_fns_[e->first] = e->second;
8914               }
8915           // Deleted virtual functions
8916           for (string_function_ptr_map::const_iterator e = deleted_fns_.begin();
8917                e != deleted_fns_.end();
8918                ++e)
8919             if (is_member_function(e->second)
8920                 && get_member_function_is_virtual(e->second))
8921               {
8922                 function_decl *f = e->second;
8923                 class_decl_sptr c =
8924                   is_class_type(is_method_type(f->get_type())->get_class_type());
8925                 ABG_ASSERT(c);
8926                 if (type_suppr->suppresses_type(c, ctxt))
8927                   suppressed_deleted_fns_[e->first] = e->second;
8928               }
8929         }
8930       // Added/Deleted variables
8931       else if (variable_suppression_sptr var_suppr =
8932                is_variable_suppression(*i))
8933         {
8934           // Added variables
8935           for (string_var_ptr_map::const_iterator e = added_vars_.begin();
8936                e != added_vars_.end();
8937                ++e)
8938             if (variable_is_suppressed(e->second, var_suppr,
8939                                        variable_suppression::ADDED_VARIABLE_CHANGE_KIND,
8940                                        ctxt))
8941               suppressed_added_vars_[e->first] = e->second;
8942
8943           //Deleted variables
8944           for (string_var_ptr_map::const_iterator e = deleted_vars_.begin();
8945                e != deleted_vars_.end();
8946                ++e)
8947             if (variable_is_suppressed(e->second, var_suppr,
8948                                        variable_suppression::DELETED_VARIABLE_CHANGE_KIND,
8949                                        ctxt))
8950               suppressed_deleted_vars_[e->first] = e->second;
8951
8952           // Added variable symbols not referenced by any debug info
8953           for (string_elf_symbol_map::const_iterator e =
8954                  added_unrefed_var_syms_.begin();
8955                e != added_unrefed_var_syms_.end();
8956                ++e)
8957             if (var_suppr->suppresses_variable_symbol(e->second,
8958                                                       variable_suppression::ADDED_VARIABLE_CHANGE_KIND,
8959                                                       ctxt))
8960               suppressed_added_unrefed_var_syms_[e->first] = e->second;
8961
8962           // Removed variable symbols not referenced by any debug info
8963           for (string_elf_symbol_map::const_iterator e =
8964                  deleted_unrefed_var_syms_.begin();
8965                e != deleted_unrefed_var_syms_.end();
8966                ++e)
8967             if (var_suppr->suppresses_variable_symbol(e->second,
8968                                                       variable_suppression::DELETED_VARIABLE_CHANGE_KIND,
8969                                                       ctxt))
8970               suppressed_deleted_unrefed_var_syms_[e->first] = e->second;
8971         }
8972     }
8973 }
8974
8975 /// Test if the change reports for a given deleted function have
8976 /// been deleted.
8977 ///
8978 /// @param fn the function to consider.
8979 ///
8980 /// @return true iff the change reports for a give given deleted
8981 /// function have been deleted.
8982 bool
8983 corpus_diff::priv::deleted_function_is_suppressed(const function_decl* fn) const
8984 {
8985   if (!fn)
8986     return false;
8987
8988   string_function_ptr_map::const_iterator i =
8989     suppressed_deleted_fns_.find(fn->get_id());
8990
8991   return (i != suppressed_deleted_fns_.end());
8992 }
8993
8994 /// Test if the change reports for a give given added function has
8995 /// been deleted.
8996 ///
8997 /// @param fn the function to consider.
8998 ///
8999 /// @return true iff the change reports for a give given added
9000 /// function has been deleted.
9001 bool
9002 corpus_diff::priv::added_function_is_suppressed(const function_decl* fn) const
9003 {
9004   if (!fn)
9005     return false;
9006
9007   string_function_ptr_map::const_iterator i =
9008     suppressed_added_fns_.find(fn->get_id());
9009
9010   return (i != suppressed_added_fns_.end());
9011 }
9012
9013 /// Test if the change reports for a give given deleted variable has
9014 /// been deleted.
9015 ///
9016 /// @param var the variable to consider.
9017 ///
9018 /// @return true iff the change reports for a give given deleted
9019 /// variable has been deleted.
9020 bool
9021 corpus_diff::priv::deleted_variable_is_suppressed(const var_decl* var) const
9022 {
9023   if (!var)
9024     return false;
9025
9026   string_var_ptr_map::const_iterator i =
9027     suppressed_deleted_vars_.find(var->get_id());
9028
9029   return (i != suppressed_deleted_vars_.end());
9030 }
9031
9032 /// Test if the change reports for a given added variable have been
9033 /// suppressed.
9034 ///
9035 /// @param var the variable to consider.
9036 ///
9037 /// @return true iff the change reports for a given deleted
9038 /// variable has been deleted.
9039 bool
9040 corpus_diff::priv::added_variable_is_suppressed(const var_decl* var) const
9041 {
9042   if (!var)
9043     return false;
9044
9045   string_var_ptr_map::const_iterator i =
9046     suppressed_added_vars_.find(var->get_id());
9047
9048   return (i != suppressed_added_vars_.end());
9049 }
9050
9051 /// Test if the change reports for a given deleted function symbol
9052 /// (that is not referenced by any debug info) has been suppressed.
9053 ///
9054 /// @param var the function to consider.
9055 ///
9056 /// @return true iff the change reports for a given deleted function
9057 /// symbol has been suppressed.
9058 bool
9059 corpus_diff::priv::deleted_unrefed_fn_sym_is_suppressed(const elf_symbol* s) const
9060 {
9061   if (!s)
9062     return false;
9063
9064   string_elf_symbol_map::const_iterator i =
9065     suppressed_deleted_unrefed_fn_syms_.find(s->get_id_string());
9066
9067   return (i != suppressed_deleted_unrefed_fn_syms_.end());
9068 }
9069
9070 /// Test if the change reports for a given added function symbol
9071 /// (that is not referenced by any debug info) has been suppressed.
9072 ///
9073 /// @param var the function to consider.
9074 ///
9075 /// @return true iff the change reports for a given added function
9076 /// symbol has been suppressed.
9077 bool
9078 corpus_diff::priv::added_unrefed_fn_sym_is_suppressed(const elf_symbol* s) const
9079 {
9080   if (!s)
9081     return false;
9082
9083   string_elf_symbol_map::const_iterator i =
9084     suppressed_added_unrefed_fn_syms_.find(s->get_id_string());
9085
9086   return (i != suppressed_added_unrefed_fn_syms_.end());
9087 }
9088
9089 /// Test if the change reports for a given deleted variable symbol
9090 /// (that is not referenced by any debug info) has been suppressed.
9091 ///
9092 /// @param var the variable to consider.
9093 ///
9094 /// @return true iff the change reports for a given deleted variable
9095 /// symbol has been suppressed.
9096 bool
9097 corpus_diff::priv::deleted_unrefed_var_sym_is_suppressed(const elf_symbol* s) const
9098 {
9099   if (!s)
9100     return false;
9101
9102   string_elf_symbol_map::const_iterator i =
9103     suppressed_deleted_unrefed_var_syms_.find(s->get_id_string());
9104
9105   return (i != suppressed_deleted_unrefed_var_syms_.end());
9106 }
9107
9108 /// Test if the change reports for a given added variable symbol
9109 /// (that is not referenced by any debug info) has been suppressed.
9110 ///
9111 /// @param var the variable to consider.
9112 ///
9113 /// @return true iff the change reports for a given added variable
9114 /// symbol has been suppressed.
9115 bool
9116 corpus_diff::priv::added_unrefed_var_sym_is_suppressed(const elf_symbol* s) const
9117 {
9118   if (!s)
9119     return false;
9120
9121   string_elf_symbol_map::const_iterator i =
9122     suppressed_added_unrefed_var_syms_.find(s->get_id_string());
9123
9124   return (i != suppressed_added_unrefed_var_syms_.end());
9125 }
9126
9127 #ifdef do_count_diff_map_changes
9128 #undef do_count_diff_map_changes
9129 #endif
9130 #define do_count_diff_map_changes(diff_map, n_changes, n_filtered)      \
9131   {                                                                     \
9132     string_diff_ptr_map::const_iterator i;                              \
9133     for (i = diff_map.begin();                                          \
9134          i != diff_map.end();                                           \
9135          ++i)                                                           \
9136       { \
9137         if (const var_diff* d = is_var_diff(i->second))         \
9138           if (is_data_member(d->first_var()))                           \
9139             continue;                                                   \
9140                                                                         \
9141         if (i->second->has_local_changes())                             \
9142           ++n_changes;                                                  \
9143         if (!i->second->get_canonical_diff()->to_be_reported())         \
9144           ++n_filtered;                                         \
9145       }                                                         \
9146   }
9147
9148 /// Count the number of leaf changes as well as the number of the
9149 /// changes that have been filtered out.
9150 ///
9151 /// @param num_changes out parameter.  This is set to the total number
9152 /// of leaf changes.
9153 ///
9154 /// @param num_filtered out parameter.  This is set to the number of
9155 /// leaf changes that have been filtered out.
9156 void
9157 corpus_diff::priv::count_leaf_changes(size_t &num_changes, size_t &num_filtered)
9158 {
9159   count_leaf_type_changes(num_changes, num_filtered);
9160
9161   // Now count the non-type changes.
9162   do_count_diff_map_changes(leaf_diffs_.get_function_decl_diff_map(),
9163     num_changes, num_filtered);
9164   do_count_diff_map_changes(leaf_diffs_.get_var_decl_diff_map(),
9165     num_changes, num_filtered);
9166 }
9167
9168 /// Count the number of leaf *type* changes as well as the number of
9169 /// the leaf type changes that have been filtered out.
9170 ///
9171 /// @param num_changes out parameter.  This is set to the total number
9172 /// of leaf type changes.
9173 ///
9174 /// @param num_filtered out parameter.  This is set to the number of
9175 /// leaf type changes that have been filtered out.
9176 void
9177 corpus_diff::priv::count_leaf_type_changes(size_t &num_changes,
9178                                            size_t &num_filtered)
9179 {
9180   do_count_diff_map_changes(leaf_diffs_.get_type_decl_diff_map(),
9181     num_changes, num_filtered);
9182   do_count_diff_map_changes(leaf_diffs_.get_enum_diff_map(),
9183     num_changes, num_filtered);
9184   do_count_diff_map_changes(leaf_diffs_.get_class_diff_map(),
9185     num_changes, num_filtered);
9186   do_count_diff_map_changes(leaf_diffs_.get_union_diff_map(),
9187     num_changes, num_filtered);
9188   do_count_diff_map_changes(leaf_diffs_.get_typedef_diff_map(),
9189     num_changes, num_filtered);
9190   do_count_diff_map_changes(leaf_diffs_.get_array_diff_map(),
9191     num_changes, num_filtered);
9192   do_count_diff_map_changes(leaf_diffs_.get_distinct_diff_map(),
9193     num_changes, num_filtered);
9194   do_count_diff_map_changes(leaf_diffs_.get_fn_parm_diff_map(),
9195                             num_changes, num_filtered);
9196 }
9197
9198 /// Compute the diff stats.
9199 ///
9200 /// To know the number of functions that got filtered out, this
9201 /// function applies the categorizing filters to the diff sub-trees of
9202 /// each function changes diff, prior to calculating the stats.
9203 ///
9204 /// @param num_removed the number of removed functions.
9205 ///
9206 /// @param num_added the number of added functions.
9207 ///
9208 /// @param num_changed the number of changed functions.
9209 ///
9210 /// @param num_filtered_out the number of changed functions that are
9211 /// got filtered out from the report
9212 void
9213 corpus_diff::priv::apply_filters_and_compute_diff_stats(diff_stats& stat)
9214
9215 {
9216   stat.num_func_removed(deleted_fns_.size());
9217   stat.num_removed_func_filtered_out(suppressed_deleted_fns_.size());
9218   stat.num_func_added(added_fns_.size());
9219   stat.num_added_func_filtered_out(suppressed_added_fns_.size());
9220   stat.num_func_changed(changed_fns_map_.size());
9221
9222   stat.num_vars_removed(deleted_vars_.size());
9223   stat.num_removed_vars_filtered_out(suppressed_deleted_vars_.size());
9224   stat.num_vars_added(added_vars_.size());
9225   stat.num_added_vars_filtered_out(suppressed_added_vars_.size());
9226   stat.num_vars_changed(changed_vars_map_.size());
9227
9228   diff_context_sptr ctxt = get_context();
9229
9230   // Walk the changed function diff nodes to apply the categorization
9231   // filters.
9232   diff_sptr diff;
9233   for (function_decl_diff_sptrs_type::const_iterator i =
9234          changed_fns_.begin();
9235        i != changed_fns_.end();
9236        ++i)
9237     {
9238       diff_sptr diff = *i;
9239       ctxt->maybe_apply_filters(diff);
9240     }
9241
9242   // Walk the changed variable diff nodes to apply the categorization
9243   // filters.
9244   for (var_diff_sptrs_type::const_iterator i = sorted_changed_vars_.begin();
9245        i != sorted_changed_vars_.end();
9246        ++i)
9247     {
9248       diff_sptr diff = *i;
9249       ctxt->maybe_apply_filters(diff);
9250     }
9251
9252   categorize_redundant_changed_sub_nodes();
9253
9254   // Walk the changed function diff nodes to count the number of
9255   // filtered-out functions and the number of functions with virtual
9256   // offset changes.
9257   for (function_decl_diff_sptrs_type::const_iterator i =
9258          changed_fns_.begin();
9259        i != changed_fns_.end();
9260        ++i)
9261     {
9262       if ((*i)->is_filtered_out())
9263         {
9264           stat.num_changed_func_filtered_out
9265             (stat.num_changed_func_filtered_out() + 1);
9266
9267           if ((*i)->has_local_changes())
9268             stat.num_leaf_func_changes_filtered_out
9269               (stat.num_leaf_func_changes_filtered_out() + 1);
9270         }
9271       else
9272         {
9273           if ((*i)->get_category() & VIRTUAL_MEMBER_CHANGE_CATEGORY)
9274             stat.num_func_with_virtual_offset_changes
9275               (stat.num_func_with_virtual_offset_changes() + 1);
9276         }
9277
9278       if ((*i)->has_local_changes())
9279         stat.num_leaf_func_changes
9280           (stat.num_leaf_func_changes() + 1);
9281     }
9282
9283   // Walk the changed variables diff nodes to count the number of
9284   // filtered-out variables.
9285   for (var_diff_sptrs_type ::const_iterator i = sorted_changed_vars_.begin();
9286        i != sorted_changed_vars_.end();
9287        ++i)
9288     {
9289       if ((*i)->is_filtered_out())
9290         {
9291           stat.num_changed_vars_filtered_out
9292             (stat.num_changed_vars_filtered_out() + 1);
9293
9294           if ((*i)->has_local_changes())
9295             stat.num_leaf_var_changes_filtered_out
9296               (stat.num_leaf_var_changes_filtered_out() + 1);
9297         }
9298       if ((*i)->has_local_changes())
9299         stat.num_leaf_func_changes
9300           (stat.num_leaf_func_changes() + 1);
9301     }
9302
9303   stat.num_func_syms_added(added_unrefed_fn_syms_.size());
9304   stat.num_added_func_syms_filtered_out(suppressed_added_unrefed_fn_syms_.size());
9305   stat.num_func_syms_removed(deleted_unrefed_fn_syms_.size());
9306   stat.num_removed_func_syms_filtered_out(suppressed_deleted_unrefed_fn_syms_.size());
9307   stat.num_var_syms_added(added_unrefed_var_syms_.size());
9308   stat.num_added_var_syms_filtered_out(suppressed_added_unrefed_var_syms_.size());
9309   stat.num_var_syms_removed(deleted_unrefed_var_syms_.size());
9310   stat.num_removed_var_syms_filtered_out(suppressed_deleted_unrefed_var_syms_.size());
9311
9312   // Walk the general leaf type diff nodes to count them
9313   {
9314     size_t num_type_changes = 0, num_type_filtered = 0;
9315     count_leaf_type_changes(num_type_changes, num_type_filtered);
9316
9317     stat.num_leaf_type_changes(num_type_changes);
9318     stat.num_leaf_type_changes_filtered_out(num_type_filtered);
9319   }
9320
9321   // Walk the general leaf artefacts diff nodes to count them
9322   {
9323     size_t num_changes = 0, num_filtered = 0;
9324     count_leaf_changes(num_changes, num_filtered);
9325
9326     stat.num_leaf_changes(num_changes);
9327     stat.num_leaf_changes_filtered_out(num_filtered);
9328   }
9329 }
9330
9331 /// Emit the summary of the functions & variables that got
9332 /// removed/changed/added.
9333 ///
9334 /// @param out the output stream to emit the stats to.
9335 ///
9336 /// @param indent the indentation string to use in the summary.
9337 void
9338 corpus_diff::priv::emit_diff_stats(const diff_stats&    s,
9339                                    ostream&             out,
9340                                    const string&        indent)
9341 {
9342   /// Report added/removed/changed functions.
9343   size_t net_num_leaf_changes =
9344     s.net_num_func_removed() +
9345     s.net_num_func_added() +
9346     s.net_num_leaf_func_changes() +
9347     s.net_num_vars_removed() +
9348     s.net_num_vars_added() +
9349     s.net_num_vars_changed() +
9350     s.net_num_leaf_type_changes();
9351
9352   if (!sonames_equal_)
9353     out << indent << "ELF SONAME changed\n";
9354
9355   if (!architectures_equal_)
9356     out << indent << "ELF architecture changed\n";
9357
9358   diff_context_sptr ctxt = get_context();
9359
9360   if (ctxt->show_leaf_changes_only())
9361     {
9362       out << "Leaf changes summary: ";
9363       out << net_num_leaf_changes << " artifact";
9364       if (net_num_leaf_changes > 1)
9365         out << "s";
9366       out << " changed";
9367
9368       if (size_t num_filtered = s.num_leaf_changes_filtered_out())
9369         out << " (" << num_filtered << " filtered out)";
9370       out << "\n";
9371
9372
9373       out << indent << "Changed leaf types summary: "
9374           << s.net_num_leaf_type_changes();
9375       if (s.num_leaf_type_changes_filtered_out())
9376         out << " (" << s.num_leaf_type_changes_filtered_out()
9377             << " filtered out)";
9378       out << " leaf type";
9379       if (s.num_leaf_type_changes() > 1)
9380         out << "s";
9381       out << " changed\n";
9382
9383       // function changes summary
9384       out << indent << "Removed/Changed/Added functions summary: ";
9385       out << s.net_num_func_removed() << " Removed";
9386      if (s.num_removed_func_filtered_out())
9387         out << " ("
9388             << s.num_removed_func_filtered_out()
9389             << " filtered out)";
9390       out << ", ";
9391
9392       out << s.net_num_leaf_func_changes() << " Changed";
9393       if (s.num_leaf_func_changes_filtered_out())
9394             out << " ("
9395                 << s.num_leaf_func_changes_filtered_out()
9396                 << " filtered out)";
9397       out << ", ";
9398
9399       out << s.net_num_func_added()<< " Added ";
9400       if (s.net_num_func_added() <= 1)
9401         out << "function";
9402       else
9403         out << "functions";
9404       if (s.num_added_func_filtered_out())
9405         out << " (" << s.num_added_func_filtered_out() << " filtered out)";
9406       out << "\n";
9407
9408       // variables changes summary
9409       out << indent << "Removed/Changed/Added variables summary: ";
9410
9411       out << s.net_num_vars_removed() << " Removed";
9412       if (s.num_removed_vars_filtered_out())
9413         out << " (" << s.num_removed_vars_filtered_out()
9414             << " filtered out)";
9415       out << ", ";
9416
9417       out << s.net_num_leaf_var_changes() << " Changed";
9418       if (s.num_leaf_var_changes_filtered_out())
9419         out << " ("
9420             << s.num_leaf_var_changes_filtered_out()
9421             << " filtered out)";
9422       out << ", ";
9423
9424       out << s.net_num_vars_added() << " Added ";
9425       if (s.net_num_vars_added() <= 1)
9426         out << "variable";
9427       else
9428         out << "variables";
9429       if (s.num_added_vars_filtered_out())
9430         out << " (" << s.num_added_vars_filtered_out()
9431             << " filtered out)";
9432       out << "\n";
9433     }
9434   else // if (ctxt->show_leaf_changes_only())
9435     {
9436       size_t total_nb_function_changes = s.num_func_removed()
9437         + s.num_func_changed() +  s.num_func_added();
9438
9439       // function changes summary
9440       out << indent << "Functions changes summary: ";
9441       out << s.net_num_func_removed() << " Removed";
9442       if (s.num_removed_func_filtered_out())
9443         out << " ("
9444             << s.num_removed_func_filtered_out()
9445             << " filtered out)";
9446       out << ", ";
9447
9448       out << s.net_num_func_changed() << " Changed";
9449       if (s.num_changed_func_filtered_out())
9450         out << " (" << s.num_changed_func_filtered_out() << " filtered out)";
9451       out << ", ";
9452
9453       out << s.net_num_func_added()<< " Added";
9454       if (s.num_added_func_filtered_out())
9455         out << " (" << s.num_added_func_filtered_out() << " filtered out)";
9456       if (total_nb_function_changes <= 1)
9457         out << " function";
9458       else
9459         out << " functions";
9460       out << "\n";
9461
9462       // variables changes summary
9463       size_t total_nb_variable_changes = s.num_vars_removed()
9464         + s.num_vars_changed() + s.num_vars_added();
9465
9466       out << indent << "Variables changes summary: ";
9467
9468       out << s.net_num_vars_removed() << " Removed";
9469       if (s.num_removed_vars_filtered_out())
9470         out << " (" << s.num_removed_vars_filtered_out()
9471             << " filtered out)";
9472       out << ", ";
9473
9474       out << s.num_vars_changed() - s.num_changed_vars_filtered_out() << " Changed";
9475       if (s.num_changed_vars_filtered_out())
9476         out << " (" << s.num_changed_vars_filtered_out() << " filtered out)";
9477       out << ", ";
9478
9479       out << s.net_num_vars_added() << " Added";
9480       if (s.num_added_vars_filtered_out())
9481         out << " (" << s.num_added_vars_filtered_out()
9482             << " filtered out)";
9483       if (total_nb_variable_changes <= 1)
9484         out << " variable";
9485       else
9486         out << " variables";
9487       out << "\n";
9488     }
9489
9490   if (ctxt->show_symbols_unreferenced_by_debug_info()
9491       && (s.num_func_syms_removed()
9492           || s.num_func_syms_added()
9493           || s.num_var_syms_removed()
9494           || s.num_var_syms_added()))
9495     {
9496       // function symbols changes summary.
9497
9498       if (!ctxt->show_added_symbols_unreferenced_by_debug_info()
9499           && s.num_func_syms_removed() == 0
9500           && s.num_func_syms_added() != 0)
9501         // If the only unreferenced function symbol change is function
9502         // syms that got added, but we were forbidden to show function
9503         // syms being added, do nothing.
9504         ;
9505       else
9506         {
9507           out << indent
9508               << "Function symbols changes summary: "
9509               << s.net_num_removed_func_syms() << " Removed";
9510           if (s.num_removed_func_syms_filtered_out())
9511             out << " (" << s.num_removed_func_syms_filtered_out()
9512                 << " filtered out)";
9513           out << ", ";
9514           out << s.net_num_added_func_syms() << " Added";
9515           if (s.num_added_func_syms_filtered_out())
9516             out << " (" << s.num_added_func_syms_filtered_out()
9517                 << " filtered out)";
9518           out << " function symbol";
9519           if (s.num_func_syms_added() + s.num_func_syms_removed() > 1)
9520             out << "s";
9521           out << " not referenced by debug info\n";
9522         }
9523
9524       // variable symbol changes summary.
9525
9526       if (!ctxt->show_added_symbols_unreferenced_by_debug_info()
9527           && s.num_var_syms_removed() == 0
9528           && s.num_var_syms_added() != 0)
9529         // If the only unreferenced variable symbol change is variable
9530         // syms that got added, but we were forbidden to show variable
9531         // syms being added, do nothing.
9532         ;
9533       else
9534         {
9535           out << indent
9536               << "Variable symbols changes summary: "
9537               << s.net_num_removed_var_syms() << " Removed";
9538           if (s.num_removed_var_syms_filtered_out())
9539             out << " (" << s.num_removed_var_syms_filtered_out()
9540                 << " filtered out)";
9541           out << ", ";
9542           out << s.net_num_added_var_syms() << " Added";
9543           if (s.num_added_var_syms_filtered_out())
9544             out << " (" << s.num_added_var_syms_filtered_out()
9545                 << " filtered out)";
9546           out << " variable symbol";
9547           if (s.num_var_syms_added() + s.num_var_syms_removed() > 1)
9548             out << "s";
9549           out << " not referenced by debug info\n";
9550         }
9551     }
9552 }
9553
9554 /// Walk the changed functions and variables diff nodes to categorize
9555 /// redundant nodes.
9556 void
9557 corpus_diff::priv::categorize_redundant_changed_sub_nodes()
9558 {
9559   diff_sptr diff;
9560
9561   diff_context_sptr ctxt = get_context();
9562
9563   ctxt->forget_visited_diffs();
9564   for (function_decl_diff_sptrs_type::const_iterator i =
9565          changed_fns_.begin();
9566        i!= changed_fns_.end();
9567        ++i)
9568     {
9569       diff = *i;
9570       categorize_redundancy(diff);
9571     }
9572
9573   for (var_diff_sptrs_type::const_iterator i = sorted_changed_vars_.begin();
9574        i!= sorted_changed_vars_.end();
9575        ++i)
9576     {
9577       diff_sptr diff = *i;
9578       categorize_redundancy(diff);
9579     }
9580 }
9581
9582 /// Walk the changed functions and variables diff nodes and clear the
9583 /// redundancy categorization they might carry.
9584 void
9585 corpus_diff::priv::clear_redundancy_categorization()
9586 {
9587   diff_sptr diff;
9588   for (function_decl_diff_sptrs_type::const_iterator i = changed_fns_.begin();
9589        i!= changed_fns_.end();
9590        ++i)
9591     {
9592       diff = *i;
9593       abigail::comparison::clear_redundancy_categorization(diff);
9594     }
9595
9596   for (var_diff_sptrs_type::const_iterator i = sorted_changed_vars_.begin();
9597        i!= sorted_changed_vars_.end();
9598        ++i)
9599     {
9600       diff = *i;
9601       abigail::comparison::clear_redundancy_categorization(diff);
9602     }
9603 }
9604
9605 /// If the user asked to dump the diff tree node (for changed
9606 /// variables and functions) on the error output stream, then just do
9607 /// that.
9608 ///
9609 /// This function is used for debugging purposes.
9610 void
9611 corpus_diff::priv::maybe_dump_diff_tree()
9612 {
9613   diff_context_sptr ctxt = get_context();
9614
9615   if (!ctxt->dump_diff_tree()
9616       || ctxt->error_output_stream() == 0)
9617     return;
9618
9619   if (!changed_fns_.empty())
9620     {
9621       *ctxt->error_output_stream() << "changed functions diff tree: \n\n";
9622       for (function_decl_diff_sptrs_type::const_iterator i =
9623              changed_fns_.begin();
9624            i != changed_fns_.end();
9625            ++i)
9626         {
9627           diff_sptr d = *i;
9628           print_diff_tree(d, *ctxt->error_output_stream());
9629         }
9630     }
9631
9632   if (!sorted_changed_vars_.empty())
9633     {
9634       *ctxt->error_output_stream() << "\nchanged variables diff tree: \n\n";
9635       for (var_diff_sptrs_type::const_iterator i =
9636              sorted_changed_vars_.begin();
9637            i != sorted_changed_vars_.end();
9638            ++i)
9639         {
9640           diff_sptr d = *i;
9641           print_diff_tree(d, *ctxt->error_output_stream());
9642         }
9643     }
9644 }
9645
9646 /// Populate the vector of children node of the @ref corpus_diff type.
9647 ///
9648 /// The children node can then later be retrieved using
9649 /// corpus_diff::children_node().
9650 void
9651 corpus_diff::chain_into_hierarchy()
9652 {
9653   for (function_decl_diff_sptrs_type::const_iterator i =
9654          changed_functions_sorted().begin();
9655        i != changed_functions_sorted().end();
9656        ++i)
9657     if (diff_sptr d = *i)
9658       append_child_node(d);
9659 }
9660
9661 /// Constructor for @ref corpus_diff.
9662 ///
9663 /// @param first the first corpus of the diff.
9664 ///
9665 /// @param second the second corpus of the diff.
9666 ///
9667 /// @param ctxt the diff context to use.  Note that this context
9668 /// object must stay alive at least during the life time of the
9669 /// current instance of @ref corpus_diff.  Otherwise memory corruption
9670 /// issues occur.
9671 corpus_diff::corpus_diff(corpus_sptr first,
9672                          corpus_sptr second,
9673                          diff_context_sptr ctxt)
9674   : priv_(new priv(first, second, ctxt))
9675 {}
9676
9677 /// Finish building the current instance of @ref corpus_diff.
9678 void
9679 corpus_diff::finish_diff_type()
9680 {
9681   if (priv_->finished_)
9682     return;
9683   chain_into_hierarchy();
9684   priv_->finished_ = true;
9685 }
9686
9687 /// @return the first corpus of the diff.
9688 corpus_sptr
9689 corpus_diff::first_corpus() const
9690 {return priv_->first_;}
9691
9692 /// @return the second corpus of the diff.
9693 corpus_sptr
9694 corpus_diff::second_corpus() const
9695 {return priv_->second_;}
9696
9697 /// @return the children nodes of the current instance of corpus_diff.
9698 const vector<diff*>&
9699 corpus_diff::children_nodes() const
9700 {return priv_->children_;}
9701
9702 /// Append a new child node to the vector of children nodes for the
9703 /// current instance of @ref corpus_diff node.
9704 ///
9705 /// Note that the vector of children nodes for the current instance of
9706 /// @ref corpus_diff node must remain sorted, using
9707 /// diff_less_than_functor.
9708 ///
9709 /// @param d the new child node.  Note that the life time of the
9710 /// object held by @p d will thus equal the life time of the current
9711 /// instance of @ref corpus_diff.
9712 void
9713 corpus_diff::append_child_node(diff_sptr d)
9714 {
9715   ABG_ASSERT(d);
9716
9717   diff_less_than_functor is_less_than;
9718   bool inserted = false;
9719   for (vector<diff*>::iterator i = priv_->children_.begin();
9720        i != priv_->children_.end();
9721        ++i)
9722     // Look for the point where to insert the diff child node.
9723     if (!is_less_than(d.get(), *i))
9724       {
9725         context()->keep_diff_alive(d);
9726         priv_->children_.insert(i, d.get());
9727         // As we have just inserted 'd' into the vector, the iterator
9728         // 'i' is invalidated.  We must *NOT* use it anymore.
9729         inserted = true;
9730         break;
9731       }
9732
9733   if (!inserted)
9734     {
9735       context()->keep_diff_alive(d);
9736       // We didn't insert anything to the vector, presumably b/c it was
9737       // empty or had one element that was "less than" 'd'.  We can thus
9738       // just append 'd' to the end of the vector.
9739       priv_->children_.push_back(d.get());
9740     }
9741 }
9742
9743 /// @return the bare edit script of the functions changed as recorded
9744 /// by the diff.
9745 edit_script&
9746 corpus_diff::function_changes() const
9747 {return priv_->fns_edit_script_;}
9748
9749 /// @return the bare edit script of the variables changed as recorded
9750 /// by the diff.
9751 edit_script&
9752 corpus_diff::variable_changes() const
9753 {return priv_->vars_edit_script_;}
9754
9755 /// Test if the soname of the underlying corpus has changed.
9756 ///
9757 /// @return true iff the soname has changed.
9758 bool
9759 corpus_diff::soname_changed() const
9760 {return !priv_->sonames_equal_;}
9761
9762 /// Test if the architecture of the underlying corpus has changed.
9763 ///
9764 /// @return true iff the architecture has changed.
9765 bool
9766 corpus_diff::architecture_changed() const
9767 {return !priv_->architectures_equal_;}
9768
9769 /// Getter for the deleted functions of the diff.
9770 ///
9771 /// @return the the deleted functions of the diff.
9772 const string_function_ptr_map&
9773 corpus_diff::deleted_functions() const
9774 {return priv_->deleted_fns_;}
9775
9776 /// Getter for the added functions of the diff.
9777 ///
9778 /// @return the added functions of the diff.
9779 const string_function_ptr_map&
9780 corpus_diff::added_functions()
9781 {return priv_->added_fns_;}
9782
9783 /// Getter for the functions which signature didn't change, but which
9784 /// do have some indirect changes in their parms.
9785 ///
9786 /// @return a non-sorted map of functions which signature didn't
9787 /// change, but which do have some indirect changes in their parms.
9788 /// The key of the map is a unique identifier for the function; it's
9789 /// usually made of the name and version of the underlying ELF symbol
9790 /// of the function for corpora that were built from ELF files.
9791 const string_function_decl_diff_sptr_map&
9792 corpus_diff::changed_functions()
9793 {return priv_->changed_fns_map_;}
9794
9795 /// Getter for a sorted vector of functions which signature didn't
9796 /// change, but which do have some indirect changes in their parms.
9797 ///
9798 /// @return a sorted vector of functions which signature didn't
9799 /// change, but which do have some indirect changes in their parms.
9800 const function_decl_diff_sptrs_type&
9801 corpus_diff::changed_functions_sorted()
9802 {return priv_->changed_fns_;}
9803
9804 /// Getter for the variables that got deleted from the first subject
9805 /// of the diff.
9806 ///
9807 /// @return the map of deleted variable.
9808 const string_var_ptr_map&
9809 corpus_diff::deleted_variables() const
9810 {return priv_->deleted_vars_;}
9811
9812 /// Getter for the added variables of the diff.
9813 ///
9814 /// @return the map of added variable.
9815 const string_var_ptr_map&
9816 corpus_diff::added_variables() const
9817 {return priv_->added_vars_;}
9818
9819 /// Getter for the non-sorted map of variables which signature didn't
9820 /// change but which do have some indirect changes in some sub-types.
9821 ///
9822 /// @return the non-sorted map of changed variables.
9823 const string_var_diff_sptr_map&
9824 corpus_diff::changed_variables()
9825 {return priv_->changed_vars_map_;}
9826
9827 /// Getter for the sorted vector of variables which signature didn't
9828 /// change but which do have some indirect changes in some sub-types.
9829 ///
9830 /// @return a sorted vector of changed variables.
9831 const var_diff_sptrs_type&
9832 corpus_diff::changed_variables_sorted()
9833 {return priv_->sorted_changed_vars_;}
9834
9835 /// Getter for function symbols not referenced by any debug info and
9836 /// that got deleted.
9837 ///
9838 /// @return a map of elf function symbols not referenced by any debug
9839 /// info and that got deleted.
9840 const string_elf_symbol_map&
9841 corpus_diff::deleted_unrefed_function_symbols() const
9842 {return priv_->deleted_unrefed_fn_syms_;}
9843
9844 /// Getter for function symbols not referenced by any debug info and
9845 /// that got added.
9846 ///
9847 /// @return a map of elf function symbols not referenced by any debug
9848 /// info and that got added.
9849 const string_elf_symbol_map&
9850 corpus_diff::added_unrefed_function_symbols() const
9851 {return priv_->added_unrefed_fn_syms_;}
9852
9853 /// Getter for variable symbols not referenced by any debug info and
9854 /// that got deleted.
9855 ///
9856 /// @return a map of elf variable symbols not referenced by any debug
9857 /// info and that got deleted.
9858 const string_elf_symbol_map&
9859 corpus_diff::deleted_unrefed_variable_symbols() const
9860 {return priv_->deleted_unrefed_var_syms_;}
9861
9862 /// Getter for variable symbols not referenced by any debug info and
9863 /// that got added.
9864 ///
9865 /// @return a map of elf variable symbols not referenced by any debug
9866 /// info and that got added.
9867 const string_elf_symbol_map&
9868 corpus_diff::added_unrefed_variable_symbols() const
9869 {return priv_->added_unrefed_var_syms_;}
9870
9871 /// Getter of the diff context of this diff
9872 ///
9873 /// @return the diff context for this diff.
9874 const diff_context_sptr
9875 corpus_diff::context() const
9876 {return priv_->get_context();}
9877
9878 /// @return the pretty representation for the current instance of @ref
9879 /// corpus_diff
9880 const string&
9881 corpus_diff::get_pretty_representation() const
9882 {
9883   if (priv_->pretty_representation_.empty())
9884     {
9885       std::ostringstream o;
9886       o << "corpus_diff["
9887         << first_corpus()->get_path()
9888         << ", "
9889         << second_corpus()->get_path()
9890         << "]";
9891       priv_->pretty_representation_ = o.str();
9892     }
9893   return priv_->pretty_representation_;
9894 }
9895 /// Return true iff the current diff node carries a change.
9896 ///
9897 /// @return true iff the current diff node carries a change.
9898 bool
9899 corpus_diff::has_changes() const
9900 {
9901   return (soname_changed()
9902           || architecture_changed()
9903           || priv_->deleted_fns_.size()
9904           || priv_->added_fns_.size()
9905           || priv_->changed_fns_map_.size()
9906           || priv_->deleted_vars_.size()
9907           || priv_->added_vars_.size()
9908           || priv_->changed_vars_map_.size()
9909           || priv_->added_unrefed_fn_syms_.size()
9910           || priv_->deleted_unrefed_fn_syms_.size()
9911           || priv_->added_unrefed_var_syms_.size()
9912           || priv_->deleted_unrefed_var_syms_.size());
9913 }
9914
9915 /// Test if the current instance of @ref corpus_diff carries changes
9916 /// that we are sure are incompatible.  By incompatible change we mean
9917 /// a change that "breaks" the ABI of the corpus we are looking at.
9918 ///
9919 /// In concrete terms, this function considers the following changes
9920 /// as being ABI incompatible for sure:
9921 ///
9922 ///   - a soname change
9923 ///   - if exported functions or variables got removed
9924 ///
9925 /// Note that subtype changes *can* represent changes that break ABI
9926 /// too.  But they also can be changes that are OK, ABI-wise.
9927 ///
9928 /// It's up to the user to provide suppression specifications to say
9929 /// explicitely which subtype change is OK.  The remaining sub-type
9930 /// changes are then considered to be ABI incompatible.  But to test
9931 /// if such ABI incompatible subtype changes are present you need to
9932 /// use the function @ref corpus_diff::has_net_subtype_changes()
9933 ///
9934 /// @return true iff the current instance of @ref corpus_diff carries
9935 /// changes that we are sure are ABI incompatible.
9936 bool
9937 corpus_diff::has_incompatible_changes() const
9938 {
9939   const diff_stats& stats = const_cast<corpus_diff*>(this)->
9940     apply_filters_and_suppressions_before_reporting();
9941
9942   return (soname_changed() || architecture_changed()
9943           || stats.net_num_func_removed() != 0
9944           || (stats.num_func_with_virtual_offset_changes() != 0
9945               // If all reports about functions with sub-type changes
9946               // have been suppressd, then even those about functions
9947               // that are virtual don't matter anymore because the
9948               // user willingly requested to shut them down
9949               && stats.net_num_func_changed() != 0)
9950           || stats.net_num_vars_removed() != 0
9951           || stats.net_num_removed_func_syms() != 0
9952           || stats.net_num_removed_var_syms() != 0);
9953 }
9954
9955 /// Test if the current instance of @ref corpus_diff carries subtype
9956 /// changes whose reports are not suppressed by any suppression
9957 /// specification.  In effect, these are deemed incompatible ABI
9958 /// changes.
9959 ///
9960 /// @return true iff the the current instance of @ref corpus_diff
9961 /// carries subtype changes that are deemed incompatible ABI changes.
9962 bool
9963 corpus_diff::has_net_subtype_changes() const
9964 {
9965   const diff_stats& stats = const_cast<corpus_diff*>(this)->
9966       apply_filters_and_suppressions_before_reporting();
9967
9968   return (stats.net_num_func_changed() != 0
9969           || stats.net_num_vars_changed() != 0);
9970 }
9971
9972 /// Test if the current instance of @ref corpus_diff carries changes
9973 /// whose reports are not suppressed by any suppression specification.
9974 /// In effect, these are deemed incompatible ABI changes.
9975 ///
9976 /// @return true iff the the current instance of @ref corpus_diff
9977 /// carries subtype changes that are deemed incompatible ABI changes.
9978 bool
9979 corpus_diff::has_net_changes() const
9980 {
9981     const diff_stats& stats = const_cast<corpus_diff*>(this)->
9982       apply_filters_and_suppressions_before_reporting();
9983
9984     return (architecture_changed()
9985             || soname_changed()
9986             || stats.net_num_func_changed()
9987             || stats.net_num_vars_changed()
9988             || stats.net_num_func_added()
9989             || stats.net_num_added_func_syms()
9990             || stats.net_num_func_removed()
9991             || stats.net_num_removed_func_syms()
9992             || stats.net_num_vars_added()
9993             || stats.net_num_added_var_syms()
9994             || stats.net_num_vars_removed()
9995             || stats.net_num_removed_var_syms());
9996 }
9997
9998 /// Apply the different filters that are registered to be applied to
9999 /// the diff tree; that includes the categorization filters.  Also,
10000 /// apply the suppression interpretation filters.
10001 ///
10002 /// After the filters are applied, this function calculates some
10003 /// statistics about the changes carried by the current instance of
10004 /// @ref corpus_diff.  These statistics are represented by an instance
10005 /// of @ref corpus_diff::diff_stats.
10006 ///
10007 /// This member function is called by the reporting function
10008 /// corpus_diff::report().
10009 ///
10010 /// Note that for a given instance of corpus_diff, this function
10011 /// applies the filters and suppressions only the first time it is
10012 /// invoked.  Subsequent invocations just return the instance of
10013 /// corpus_diff::diff_stats that was cached after the first
10014 /// invocation.
10015 ///
10016 /// @return a reference to the statistics about the changes carried by
10017 /// the current instance of @ref corpus_diff.
10018 const corpus_diff::diff_stats&
10019 corpus_diff::apply_filters_and_suppressions_before_reporting()
10020 {
10021   if (priv_->diff_stats_)
10022     return *priv_->diff_stats_;
10023
10024   apply_suppressions(this);
10025   priv_->diff_stats_.reset(new diff_stats(context()));
10026   mark_leaf_diff_nodes();
10027   priv_->apply_filters_and_compute_diff_stats(*priv_->diff_stats_);
10028   return *priv_->diff_stats_;
10029 }
10030
10031 /// A visitor that marks leaf diff nodes by storing them in the
10032 /// instance of @ref diff_maps returned by
10033 /// corpus_diff::get_leaf_diffs() invoked on the current instance of
10034 /// corpus_diff.
10035 struct leaf_diff_node_marker_visitor : public diff_node_visitor
10036 {
10037   /// This is called when the visitor visits a diff node.
10038   ///
10039   /// It basically tests if the diff node being visited is a leaf diff
10040   /// node - that is, if contains local changes.  If it does, then the
10041   /// node is added to the set of maps that hold leaf diffs in the
10042   /// current corpus_diff.
10043   ///
10044   /// @param d the diff node being visited.
10045   virtual void
10046   visit_begin(diff *d)
10047   {
10048     if (d->has_local_changes()
10049         // A leaf basic (or class/union) type name change makes no
10050         // sense when showing just leaf changes.  It only makes sense
10051         // when it can explain the details about a non-leaf change.
10052         // In other words, it doesn't make sense to say that an "int"
10053         // became "unsigned int".  But it does make sense to say that
10054         // a typedef changed because its underlying type was 'int' and
10055         // is now an "unsigned int".
10056         && !filtering::has_basic_or_class_type_name_change(d)
10057         // Similarly, a *local* change describing a type that changed
10058         // its nature doesn't make sense.
10059         && !is_distinct_diff(d)
10060         // Similarly, a pointer (or reference or array) or qualified
10061         // type change in itself doesn't make sense.  It's would
10062         // rather make sense to show that pointer change as part of
10063         // the variable change whose pointer type changed, for
10064         // instance.
10065         && !is_pointer_diff(d)
10066         && !is_reference_diff(d)
10067         && !is_qualified_type_diff(d)
10068         && !is_array_diff(d)
10069         // Similarly a parameter chagne in itself doesn't make sense.
10070         // It should have already been reported as part of the change
10071         // of the function it belongs to.
10072         && !is_fn_parm_diff(d)
10073         // An anonymous class or union diff doesn't make sense on its
10074         // own.  It must have been described already by the diff of
10075         // the enclosing struct or union if 'd' is from an anonymous
10076         // data member, or from a typedef change if 'd' is from a
10077         // typedef change which underlying type is an anonymous
10078         // struct/union.
10079         && !is_anonymous_class_or_union_diff(d)
10080         // Don't show decl-only-ness changes of classes either.
10081         && !filtering::has_class_decl_only_def_change(d))
10082       {
10083         diff_context_sptr ctxt = d->context();
10084         const corpus_diff *corpus_diff_node = ctxt->get_corpus_diff().get();
10085         ABG_ASSERT(corpus_diff_node);
10086         type_or_decl_base_sptr iface =
10087           get_current_topmost_iface_diff()->first_subject();
10088         // So this is diff node carries a leaf change.  Let's add it
10089         // to the set of of leaf diffs of corpus_diff_node.
10090         const_cast<corpus_diff*>(corpus_diff_node)->
10091           get_leaf_diffs().insert_diff_node(d, iface);
10092       }
10093   }
10094 }; // end struct leaf_diff_node_marker_visitor
10095
10096 /// Walks the diff nodes associated to the current corpus diff and
10097 /// mark those that carry local changes.  They are said to be leaf
10098 /// diff nodes.
10099 ///
10100 /// The marked nodes are available from the
10101 /// corpus_diff::get_leaf_diffs() function.
10102 void
10103 corpus_diff::mark_leaf_diff_nodes()
10104 {
10105   if (!has_changes())
10106     return;
10107
10108   if (!context()->show_leaf_changes_only())
10109     return;
10110
10111   leaf_diff_node_marker_visitor v;
10112   context()->forget_visited_diffs();
10113   bool s = context()->visiting_a_node_twice_is_forbidden();
10114   context()->forbid_visiting_a_node_twice(true);
10115   context()->forbid_visiting_a_node_twice_per_interface(true);
10116   traverse(v);
10117   context()->forbid_visiting_a_node_twice(s);
10118   context()->forbid_visiting_a_node_twice_per_interface(false);
10119 }
10120
10121 /// Get the set of maps that contain leaf nodes.  A leaf node being a
10122 /// node with a local change.
10123 ///
10124 /// @return the set of maps that contain leaf nodes.  A leaf node
10125 /// being a node with a local change.
10126 diff_maps&
10127 corpus_diff::get_leaf_diffs()
10128 {return priv_->leaf_diffs_;}
10129
10130 /// Get the set of maps that contain leaf nodes.  A leaf node being a
10131 /// node with a local change.
10132 ///
10133 /// @return the set of maps that contain leaf nodes.  A leaf node
10134 /// being a node with a local change.
10135 const diff_maps&
10136 corpus_diff::get_leaf_diffs() const
10137 {return priv_->leaf_diffs_;}
10138
10139 /// Report the diff in a serialized form.
10140 ///
10141 /// @param out the stream to serialize the diff to.
10142 ///
10143 /// @param indent the prefix to use for the indentation of this
10144 /// serialization.
10145 void
10146 corpus_diff::report(ostream& out, const string& indent) const
10147 {
10148   context()->get_reporter()->report(*this, out, indent);
10149 }
10150
10151 /// Traverse the diff sub-tree under the current instance corpus_diff.
10152 ///
10153 /// @param v the visitor to invoke on each diff node of the sub-tree.
10154 ///
10155 /// @return true if the traversing has to keep going on, false otherwise.
10156 bool
10157 corpus_diff::traverse(diff_node_visitor& v)
10158 {
10159   finish_diff_type();
10160
10161   v.visit_begin(this);
10162
10163   if (!v.visit(this, true))
10164     {
10165       v.visit_end(this);
10166       return false;
10167     }
10168
10169   for (function_decl_diff_sptrs_type::const_iterator i =
10170          changed_functions_sorted().begin();
10171        i != changed_functions_sorted().end();
10172        ++i)
10173     {
10174       if (diff_sptr d = *i)
10175         {
10176           const diff_context_sptr &ctxt = context();
10177           if (ctxt->visiting_a_node_twice_is_forbidden_per_interface())
10178             ctxt->forget_visited_diffs();
10179
10180           v.set_current_topmost_iface_diff(d.get());
10181
10182           if (!d->traverse(v))
10183             {
10184               v.visit_end(this);
10185               v.set_current_topmost_iface_diff(0);
10186               return false;
10187             }
10188         }
10189     }
10190
10191   for (var_diff_sptrs_type::const_iterator i =
10192          changed_variables_sorted().begin();
10193        i != changed_variables_sorted().end();
10194        ++i)
10195     {
10196       if (diff_sptr d = *i)
10197         {
10198           const diff_context_sptr &ctxt = context();
10199           if (ctxt->visiting_a_node_twice_is_forbidden_per_interface())
10200             ctxt->forget_visited_diffs();
10201
10202           v.set_current_topmost_iface_diff(d.get());
10203
10204           if (!d->traverse(v))
10205             {
10206               v.visit_end(this);
10207               v.set_current_topmost_iface_diff(0);
10208               return false;
10209             }
10210         }
10211     }
10212
10213   v.set_current_topmost_iface_diff(0);
10214
10215   v.visit_end(this);
10216   return true;
10217 }
10218
10219 /// Compute the diff between two instances of @ref corpus.
10220 ///
10221 /// Note that the two corpora must have been created in the same @ref
10222 /// environment, otherwise, this function aborts.
10223 ///
10224 /// @param f the first @ref corpus to consider for the diff.
10225 ///
10226 /// @param s the second @ref corpus to consider for the diff.
10227 ///
10228 /// @param ctxt the diff context to use.
10229 ///
10230 /// @return the resulting diff between the two @ref corpus.
10231 corpus_diff_sptr
10232 compute_diff(const corpus_sptr  f,
10233              const corpus_sptr  s,
10234              diff_context_sptr  ctxt)
10235 {
10236   typedef corpus::functions::const_iterator fns_it_type;
10237   typedef corpus::variables::const_iterator vars_it_type;
10238   typedef elf_symbols::const_iterator symbols_it_type;
10239   typedef diff_utils::deep_ptr_eq_functor eq_type;
10240
10241   ABG_ASSERT(f && s);
10242
10243   // We can only compare two corpora that were built out of the same
10244   // environment.
10245   ABG_ASSERT(f->get_environment() == s->get_environment());
10246
10247   if (!ctxt)
10248     ctxt.reset(new diff_context);
10249
10250   corpus_diff_sptr r(new corpus_diff(f, s, ctxt));
10251
10252   ctxt->set_corpus_diff(r);
10253
10254   r->priv_->sonames_equal_ = f->get_soname() == s->get_soname();
10255
10256   r->priv_->architectures_equal_ =
10257     f->get_architecture_name() == s->get_architecture_name();
10258
10259   diff_utils::compute_diff<fns_it_type, eq_type>(f->get_functions().begin(),
10260                                                  f->get_functions().end(),
10261                                                  s->get_functions().begin(),
10262                                                  s->get_functions().end(),
10263                                                  r->priv_->fns_edit_script_);
10264
10265   diff_utils::compute_diff<vars_it_type, eq_type>
10266     (f->get_variables().begin(), f->get_variables().end(),
10267      s->get_variables().begin(), s->get_variables().end(),
10268      r->priv_->vars_edit_script_);
10269
10270   diff_utils::compute_diff<symbols_it_type, eq_type>
10271     (f->get_unreferenced_function_symbols().begin(),
10272      f->get_unreferenced_function_symbols().end(),
10273      s->get_unreferenced_function_symbols().begin(),
10274      s->get_unreferenced_function_symbols().end(),
10275      r->priv_->unrefed_fn_syms_edit_script_);
10276
10277     diff_utils::compute_diff<symbols_it_type, eq_type>
10278     (f->get_unreferenced_variable_symbols().begin(),
10279      f->get_unreferenced_variable_symbols().end(),
10280      s->get_unreferenced_variable_symbols().begin(),
10281      s->get_unreferenced_variable_symbols().end(),
10282      r->priv_->unrefed_var_syms_edit_script_);
10283
10284   r->priv_->ensure_lookup_tables_populated();
10285
10286   return r;
10287 }
10288
10289 // </corpus stuff>
10290
10291 /// Compute the diff between two instances of @ref corpus_group.
10292 ///
10293 /// Note that the two corpus_diff must have been created in the same
10294 /// @ref environment, otherwise, this function aborts.
10295 ///
10296 /// @param f the first @ref corpus_group to consider for the diff.
10297 ///
10298 /// @param s the second @ref corpus_group to consider for the diff.
10299 ///
10300 /// @param ctxt the diff context to use.
10301 ///
10302 /// @return the resulting diff between the two @ref corpus_group.
10303 corpus_diff_sptr
10304 compute_diff(const corpus_group_sptr&   f,
10305              const corpus_group_sptr&   s,
10306              diff_context_sptr  ctxt)
10307 {
10308
10309   corpus_sptr c1 = f;
10310   corpus_sptr c2 = s;
10311
10312   return compute_diff(c1, c2, ctxt);
10313 }
10314
10315 // <corpus_group stuff>
10316
10317 // </corpus_group stuff>
10318 // <diff_node_visitor stuff>
10319
10320 /// The private data of the @diff_node_visitor type.
10321 struct diff_node_visitor::priv
10322 {
10323   diff* topmost_interface_diff;
10324   visiting_kind kind;
10325
10326   priv()
10327     : topmost_interface_diff(),
10328       kind()
10329   {}
10330
10331   priv(visiting_kind k)
10332     : topmost_interface_diff(),
10333       kind(k)
10334   {}
10335 }; // end struct diff_node_visitor
10336
10337 /// Default constructor of the @ref diff_node_visitor type.
10338 diff_node_visitor::diff_node_visitor()
10339   : priv_(new priv)
10340 {}
10341
10342 /// Constructor of the @ref diff_node_visitor type.
10343 ///
10344 /// @param k how the visiting has to be performed.
10345 diff_node_visitor::diff_node_visitor(visiting_kind k)
10346   : priv_(new priv(k))
10347 {}
10348
10349 /// Getter for the visiting policy of the traversing code while
10350 /// invoking this visitor.
10351 ///
10352 /// @return the visiting policy used by the traversing code when
10353 /// invoking this visitor.
10354 visiting_kind
10355 diff_node_visitor::get_visiting_kind() const
10356 {return priv_->kind;}
10357
10358 /// Setter for the visiting policy of the traversing code while
10359 /// invoking this visitor.
10360 ///
10361 /// @param v a bit map representing the new visiting policy used by
10362 /// the traversing code when invoking this visitor.
10363 void
10364 diff_node_visitor::set_visiting_kind(visiting_kind v)
10365 {priv_->kind = v;}
10366
10367 /// Setter for the visiting policy of the traversing code while
10368 /// invoking this visitor.  This one makes a logical or between the
10369 /// current policy and the bitmap given in argument and assigns the
10370 /// current policy to the result.
10371 ///
10372 /// @param v a bitmap representing the visiting policy to or with
10373 /// the current policy.
10374 void
10375 diff_node_visitor::or_visiting_kind(visiting_kind v)
10376 {priv_->kind = priv_->kind | v;}
10377
10378 /// Setter of the diff current topmost interface which is impacted by
10379 /// the current diff node being visited.
10380 ///
10381 /// @param d the current topmost interface diff impacted.
10382 void
10383 diff_node_visitor::set_current_topmost_iface_diff(diff* d)
10384 {priv_->topmost_interface_diff = d;}
10385
10386 /// Getter of the diff current topmost interface which is impacted by
10387 /// the current diff node being visited.
10388 ///
10389 /// @return the current topmost interface diff impacted.
10390 diff*
10391 diff_node_visitor::get_current_topmost_iface_diff() const
10392 {return priv_->topmost_interface_diff;}
10393
10394 /// This is called by the traversing code on a @ref diff node just
10395 /// before visiting it.  That is, before visiting it and its children
10396 /// node.
10397 ///
10398 /// @param d the diff node to visit.
10399 void
10400 diff_node_visitor::visit_begin(diff* /*p*/)
10401 {}
10402
10403 /// This is called by the traversing code on a @ref diff node just
10404 /// after visiting it.  That is after visiting it and its children
10405 /// nodes.
10406 ///
10407 /// @param d the diff node that got visited.
10408 void
10409 diff_node_visitor::visit_end(diff* /*p*/)
10410 {}
10411
10412 /// This is called by the traversing code on a @ref corpus_diff node
10413 /// just before visiting it.  That is, before visiting it and its
10414 /// children node.
10415 ///
10416 /// @param p the corpus_diff node to visit.
10417 ///
10418 void
10419 diff_node_visitor::visit_begin(corpus_diff* /*p*/)
10420 {}
10421
10422 /// This is called by the traversing code on a @ref corpus_diff node
10423 /// just after visiting it.  That is after visiting it and its children
10424 /// nodes.
10425 ///
10426 /// @param d the diff node that got visited.
10427 void
10428 diff_node_visitor::visit_end(corpus_diff* /*d*/)
10429 {}
10430
10431 /// Default visitor implementation
10432 ///
10433 /// @return true
10434 bool
10435 diff_node_visitor::visit(diff*, bool)
10436 {return true;}
10437
10438 /// Default visitor implementation.
10439 ///
10440 /// @return true
10441 bool
10442 diff_node_visitor::visit(distinct_diff* dif, bool pre)
10443 {
10444   diff* d = dif;
10445   visit(d, pre);
10446
10447   return true;
10448 }
10449
10450 /// Default visitor implementation.
10451 ///
10452 /// @return true
10453 bool
10454 diff_node_visitor::visit(var_diff* dif, bool pre)
10455 {
10456   diff* d = dif;
10457   visit(d, pre);
10458
10459   return true;
10460 }
10461
10462 /// Default visitor implementation.
10463 ///
10464 /// @return true
10465 bool
10466 diff_node_visitor::visit(pointer_diff* dif, bool pre)
10467 {
10468   diff* d = dif;
10469   visit(d, pre);
10470
10471   return true;
10472 }
10473
10474 /// Default visitor implementation.
10475 ///
10476 /// @return true
10477 bool
10478 diff_node_visitor::visit(reference_diff* dif, bool pre)
10479 {
10480   diff* d = dif;
10481   visit(d, pre);
10482
10483   return true;
10484 }
10485
10486 /// Default visitor implementation.
10487 ///
10488 /// @return true
10489 bool
10490 diff_node_visitor::visit(qualified_type_diff* dif, bool pre)
10491 {
10492   diff* d = dif;
10493   visit(d, pre);
10494
10495   return true;
10496 }
10497
10498 /// Default visitor implementation.
10499 ///
10500 /// @return true
10501 bool
10502 diff_node_visitor::visit(enum_diff* dif, bool pre)
10503 {
10504   diff* d = dif;
10505   visit(d, pre);
10506
10507   return true;
10508 }
10509
10510 /// Default visitor implementation.
10511 ///
10512 /// @return true
10513 bool
10514 diff_node_visitor::visit(class_diff* dif, bool pre)
10515 {
10516   diff* d = dif;
10517   visit(d, pre);
10518
10519   return true;
10520 }
10521
10522 /// Default visitor implementation.
10523 ///
10524 /// @return true
10525 bool
10526 diff_node_visitor::visit(base_diff* dif, bool pre)
10527 {
10528   diff* d = dif;
10529   visit(d, pre);
10530
10531   return true;
10532 }
10533
10534 /// Default visitor implementation.
10535 ///
10536 /// @return true
10537 bool
10538 diff_node_visitor::visit(scope_diff* dif, bool pre)
10539 {
10540   diff* d = dif;
10541   visit(d, pre);
10542
10543   return true;
10544 }
10545
10546 /// Default visitor implementation.
10547 ///
10548 /// @return true
10549 bool
10550 diff_node_visitor::visit(function_decl_diff* dif, bool pre)
10551 {
10552   diff* d = dif;
10553   visit(d, pre);
10554
10555   return true;
10556 }
10557
10558 /// Default visitor implementation.
10559 ///
10560 /// @return true
10561 bool
10562 diff_node_visitor::visit(type_decl_diff* dif, bool pre)
10563 {
10564   diff* d = dif;
10565   visit(d, pre);
10566
10567   return true;
10568 }
10569
10570 /// Default visitor implementation.
10571 ///
10572 /// @return true
10573 bool
10574 diff_node_visitor::visit(typedef_diff* dif, bool pre)
10575 {
10576   diff* d = dif;
10577   visit(d, pre);
10578
10579   return true;
10580 }
10581
10582 /// Default visitor implementation.
10583 ///
10584 /// @return true
10585 bool
10586 diff_node_visitor::visit(translation_unit_diff* dif, bool pre)
10587 {
10588   diff* d = dif;
10589   visit(d, pre);
10590
10591   return true;
10592 }
10593
10594 /// Default visitor implementation.
10595 ///
10596 /// @return true
10597 bool
10598 diff_node_visitor::visit(corpus_diff*, bool)
10599 {return true;}
10600
10601 // </diff_node_visitor stuff>
10602
10603 // <redundant diff node marking>
10604
10605 // </redundant diff node marking>
10606
10607 // <diff tree category propagation>
10608
10609 /// A visitor to propagate the category of a node up to its parent
10610 /// nodes.  This visitor doesn't touch the REDUNDANT_CATEGORY or the
10611 /// SUPPRESSED_CATEGORY because those are propagated using other
10612 /// specific visitors.
10613 struct category_propagation_visitor : public diff_node_visitor
10614 {
10615   virtual void
10616   visit_end(diff* d)
10617   {
10618     // Has this diff node 'd' been already visited ?
10619     bool already_visited = d->context()->diff_has_been_visited(d);
10620
10621     // The canonical diff node of the class of equivalence of the diff
10622     // node 'd'.
10623     diff* canonical = d->get_canonical_diff();
10624
10625     // If this class of equivalence of diff node is being visited for
10626     // the first time, then update its canonical node's category too.
10627     bool update_canonical = !already_visited && canonical;
10628
10629     for (vector<diff*>::const_iterator i = d->children_nodes().begin();
10630          i != d->children_nodes().end();
10631          ++i)
10632       {
10633         // If we are visiting the class of equivalence of 'd' for the
10634         // first time, then let's look at the children of 'd' and
10635         // propagate their categories to 'd'.
10636         //
10637         // If the class of equivalence of 'd' has already been
10638         // visited, then let's look at the canonical diff nodes of the
10639         // children of 'd' and propagate their categories to 'd'.
10640         diff* diff = already_visited
10641           ? (*i)->get_canonical_diff()
10642           : *i;
10643
10644         ABG_ASSERT(diff);
10645
10646         diff_category c = diff->get_category();
10647         // Do not propagate redundant and suppressed categories. Those
10648         // are propagated in a specific pass elsewhere.
10649         c &= ~(REDUNDANT_CATEGORY
10650                | SUPPRESSED_CATEGORY
10651                | PRIVATE_TYPE_CATEGORY);
10652         // Also, if a (class) type has got a harmful name change, do not
10653         // propagate harmless name changes coming from its sub-types
10654         // (i.e, data members) to the class itself.
10655         if (filtering::has_harmful_name_change(d))
10656           c &= ~HARMLESS_DECL_NAME_CHANGE_CATEGORY;
10657
10658         d->add_to_category(c);
10659         if (!already_visited && canonical)
10660           if (update_canonical)
10661             canonical->add_to_category(c);
10662       }
10663   }
10664 };// end struct category_propagation_visitor
10665
10666 /// Visit all the nodes of a given sub-tree.  For each node that has a
10667 /// particular category set, propagate that category set up to its
10668 /// parent nodes.
10669 ///
10670 /// @param diff_tree the diff sub-tree to walk for categorization
10671 /// purpose;
10672 void
10673 propagate_categories(diff* diff_tree)
10674 {
10675   category_propagation_visitor v;
10676   bool s = diff_tree->context()->visiting_a_node_twice_is_forbidden();
10677   diff_tree->context()->forbid_visiting_a_node_twice(true);
10678   diff_tree->context()->forget_visited_diffs();
10679   diff_tree->traverse(v);
10680   diff_tree->context()->forbid_visiting_a_node_twice(s);
10681 }
10682
10683 /// Visit all the nodes of a given sub-tree.  For each node that has a
10684 /// particular category set, propagate that category set up to its
10685 /// parent nodes.
10686 ///
10687 /// @param diff_tree the diff sub-tree to walk for categorization
10688 /// purpose;
10689 void
10690 propagate_categories(diff_sptr diff_tree)
10691 {propagate_categories(diff_tree.get());}
10692
10693 /// Visit all the nodes of a given corpus tree.  For each node that
10694 /// has a particular category set, propagate that category set up to
10695 /// its parent nodes.
10696 ///
10697 /// @param diff_tree the corpus_diff tree to walk for categorization
10698 /// purpose;
10699 void
10700 propagate_categories(corpus_diff* diff_tree)
10701 {
10702   category_propagation_visitor v;
10703   bool s = diff_tree->context()->visiting_a_node_twice_is_forbidden();
10704   diff_tree->context()->forbid_visiting_a_node_twice(false);
10705   diff_tree->traverse(v);
10706   diff_tree->context()->forbid_visiting_a_node_twice(s);
10707 }
10708
10709 /// Visit all the nodes of a given corpus tree.  For each node that
10710 /// has a particular category set, propagate that category set up to
10711 /// its parent nodes.
10712 ///
10713 /// @param diff_tree the corpus_diff tree to walk for categorization
10714 /// purpose;
10715 void
10716 propagate_categories(corpus_diff_sptr diff_tree)
10717 {propagate_categories(diff_tree.get());}
10718
10719 /// A tree node visitor that knows how to categorizes a given in the
10720 /// SUPPRESSED_CATEGORY category and how to propagate that
10721 /// categorization.
10722 struct suppression_categorization_visitor : public diff_node_visitor
10723 {
10724
10725   /// Before visiting the children of the diff node, check if the node
10726   /// is suppressed by a suppression specification.  If it is, mark
10727   /// the node as belonging to the SUPPRESSED_CATEGORY category.
10728   ///
10729   /// @param p the diff node to visit.
10730   virtual void
10731   visit_begin(diff* d)
10732   {
10733     bool is_private_type = false;
10734     if (d->is_suppressed(is_private_type))
10735       {
10736         diff_category c = is_private_type
10737           ? PRIVATE_TYPE_CATEGORY
10738           : SUPPRESSED_CATEGORY;
10739         d->add_to_local_and_inherited_categories(c);
10740
10741         // If a node was suppressed, all the other nodes of its class
10742         // of equivalence are suppressed too.
10743         diff *canonical_diff = d->get_canonical_diff();
10744         if (canonical_diff != d)
10745           canonical_diff->add_to_category(c);
10746       }
10747   }
10748
10749   /// After visiting the children nodes of a given diff node,
10750   /// propagate the SUPPRESSED_CATEGORY from the children nodes to the
10751   /// diff node, if need be.
10752   ///
10753   /// That is, if all children nodes carry a suppressed change the
10754   /// current node should be marked as suppressed as well.
10755   ///
10756   /// In practice, this might be too strong of a condition.  If the
10757   /// current node carries a local change (i.e, a change not carried
10758   /// by any of its children node) and if that change is not
10759   /// suppressed, then the current node should *NOT* be suppressed.
10760   ///
10761   /// But right now, the IR doesn't let us know about local vs
10762   /// children-carried changes.  So we cannot be that precise yet.
10763   virtual void
10764   visit_end(diff* d)
10765   {
10766     bool has_non_suppressed_child = false;
10767     bool has_non_empty_child = false;
10768     bool has_suppressed_child = false;
10769     bool has_non_private_child = false;
10770     bool has_private_child = false;
10771
10772     if (// A node to which we can propagate the "SUPPRESSED_CATEGORY"
10773         // (or the PRIVATE_TYPE_CATEGORY for the same matter)
10774         // category from its children is a node which:
10775         //
10776         //  1/ hasn't been suppressed already
10777         //
10778         //  2/ and has no local change (unless it's a pointer,
10779         //  reference or qualified diff node).
10780         //
10781         //  Note that qualified type diff nodes are a bit special.
10782         //  The local changes of the underlying type are considered
10783         //  local for the qualified type, just like for
10784         //  pointer/reference types.  But then the qualified type
10785         //  itself can have local changes of its own, and those
10786         //  changes are of the kind LOCAL_NON_TYPE_CHANGE_KIND.  So a
10787         //  qualified type which have local changes that are *NOT* of
10788         //  LOCAL_NON_TYPE_CHANGE_KIND (or that has no local changes
10789         //  at all) and which is in the PRIVATE_TYPE_CATEGORY or
10790         //  SUPPRESSED_CATEGORY can see these categories be
10791         //  propagated.
10792         //
10793         // Note that all pointer/reference diff node changes are
10794         // potentially considered local, i.e, local changes of the
10795         // pointed-to-type are considered local to the pointer itself.
10796         !(d->get_category() & SUPPRESSED_CATEGORY)
10797         && (!d->has_local_changes()
10798             || is_pointer_diff(d)
10799             || is_reference_diff(d)
10800             || (is_qualified_type_diff(d)
10801                 && (!(d->has_local_changes() & LOCAL_NON_TYPE_CHANGE_KIND)))))
10802       {
10803         // Note that we handle private diff nodes differently from
10804         // generally suppressed diff nodes.  E.g, it's not because a
10805         // type is private (and suppressed because of that; i.e, in
10806         // the category PRIVATE_TYPE_CATEGORY) that a typedef to that
10807         // type should also be private and so suppressed.  Private
10808         // diff nodes thus have different propagation rules than
10809         // generally suppressed rules.
10810         for (vector<diff*>::const_iterator i = d->children_nodes().begin();
10811              i != d->children_nodes().end();
10812              ++i)
10813           {
10814             diff* child = *i;
10815             if (child->has_changes())
10816               {
10817                 has_non_empty_child = true;
10818                 if (child->get_class_of_equiv_category() & SUPPRESSED_CATEGORY)
10819                   has_suppressed_child = true;
10820                 else if (child->get_class_of_equiv_category()
10821                          & PRIVATE_TYPE_CATEGORY)
10822                   // Propagation of the PRIVATE_TYPE_CATEGORY is going
10823                   // to be handled later below.
10824                   ;
10825                 else
10826                   has_non_suppressed_child = true;
10827
10828                 if (child->get_class_of_equiv_category()
10829                     & PRIVATE_TYPE_CATEGORY)
10830                   has_private_child = true;
10831                 else if (child->get_class_of_equiv_category()
10832                          & SUPPRESSED_CATEGORY)
10833                   // Propagation of the SUPPRESSED_CATEGORY is going
10834                   // to be handled later below.
10835                   ;
10836                 else
10837                   has_non_private_child = true;
10838               }
10839           }
10840
10841         if (has_non_empty_child
10842             && has_suppressed_child
10843             && !has_non_suppressed_child)
10844           {
10845             d->add_to_category(SUPPRESSED_CATEGORY);
10846             // If a node was suppressed, all the other nodes of its class
10847             // of equivalence are suppressed too.
10848             diff *canonical_diff = d->get_canonical_diff();
10849             if (canonical_diff != d)
10850               canonical_diff->add_to_category(SUPPRESSED_CATEGORY);
10851           }
10852
10853         if (// We don't propagate "private type"-ness to typedefs
10854             // because defining "public" typedefs of private (opaque)
10855             // types is a common idiom.  So the typedef must stay
10856             // public.
10857             !is_typedef_diff(d)
10858             && has_non_empty_child
10859             && has_private_child
10860             && !has_non_private_child)
10861           {
10862             d->add_to_category(PRIVATE_TYPE_CATEGORY);
10863             // If a node was suppressed, all the other nodes of its class
10864             // of equivalence are suppressed too.
10865             diff *canonical_diff = d->get_canonical_diff();
10866             if (canonical_diff != d)
10867               canonical_diff->add_to_category(PRIVATE_TYPE_CATEGORY);
10868           }
10869
10870         // If the underlying type of a typedef is private and carries
10871         // changes (that are implicitely suppressed because it's
10872         // private) then the typedef must be suppressed too, so that
10873         // those changes to the underlying type are not seen.
10874         if (is_typedef_diff(d)
10875             && !d->has_local_changes()
10876             && has_private_child
10877             && has_non_empty_child)
10878           {
10879             d->add_to_category(SUPPRESSED_CATEGORY|PRIVATE_TYPE_CATEGORY);
10880             // If a node was suppressed, all the other nodes of its class
10881             // of equivalence are suppressed too.
10882             diff *canonical_diff = d->get_canonical_diff();
10883             if (canonical_diff != d)
10884               canonical_diff->add_to_category
10885                 (SUPPRESSED_CATEGORY|PRIVATE_TYPE_CATEGORY);
10886           }
10887       }
10888   }
10889 }; //end struct suppression_categorization_visitor
10890
10891 /// Walk a given diff-sub tree and appply the suppressions carried by
10892 /// the context.  If the suppression applies to a given node than
10893 /// categorize the node into the SUPPRESSED_CATEGORY category and
10894 /// propagate that categorization.
10895 ///
10896 /// @param diff_tree the diff-sub tree to apply the suppressions to.
10897 void
10898 apply_suppressions(diff* diff_tree)
10899 {
10900   if (diff_tree && !diff_tree->context()->suppressions().empty())
10901     {
10902       // Apply suppressions to functions and variables that have
10903       // changed sub-types.
10904       suppression_categorization_visitor v;
10905       diff_tree->context()->forget_visited_diffs();
10906       bool s = diff_tree->context()->visiting_a_node_twice_is_forbidden();
10907       diff_tree->context()->forbid_visiting_a_node_twice(true);
10908       diff_tree->traverse(v);
10909       diff_tree->context()->forbid_visiting_a_node_twice(s);
10910     }
10911 }
10912
10913 /// Walk a given diff-sub tree and appply the suppressions carried by
10914 /// the context.  If the suppression applies to a given node than
10915 /// categorize the node into the SUPPRESSED_CATEGORY category and
10916 /// propagate that categorization.
10917 ///
10918 /// @param diff_tree the diff-sub tree to apply the suppressions to.
10919 void
10920 apply_suppressions(diff_sptr diff_tree)
10921 {apply_suppressions(diff_tree.get());}
10922
10923 /// Walk a diff tree and appply the suppressions carried by the
10924 /// context.  If the suppression applies to a given node than
10925 /// categorize the node into the SUPPRESSED_CATEGORY category and
10926 /// propagate that categorization.
10927 ///
10928 /// @param diff_tree the diff tree to apply the suppressions to.
10929 void
10930 apply_suppressions(const corpus_diff* diff_tree)
10931 {
10932   if (diff_tree && !diff_tree->context()->suppressions().empty())
10933     {
10934       // First, visit the children trees of changed constructs:
10935       // changed functions, variables, as well as sub-types of these,
10936       // and apply suppression specifications to these ...
10937       suppression_categorization_visitor v;
10938       diff_tree->context()->forget_visited_diffs();
10939       bool s = diff_tree->context()->visiting_a_node_twice_is_forbidden();
10940       diff_tree->context()->forbid_visiting_a_node_twice(true);
10941       const_cast<corpus_diff*>(diff_tree)->traverse(v);
10942       diff_tree->context()->forbid_visiting_a_node_twice(s);
10943
10944       // ... then also visit the set added and removed functions,
10945       // variables, and symbols
10946       diff_tree->priv_->apply_suppressions_to_added_removed_fns_vars();
10947     }
10948 }
10949
10950 /// Walk a diff tree and appply the suppressions carried by the
10951 /// context.  If the suppression applies to a given node than
10952 /// categorize the node into the SUPPRESSED_CATEGORY category and
10953 /// propagate that categorization.
10954 ///
10955 /// @param diff_tree the diff tree to apply the suppressions to.
10956 void
10957 apply_suppressions(corpus_diff_sptr  diff_tree)
10958 {apply_suppressions(diff_tree.get());}
10959
10960 // </diff tree category propagation>
10961
10962 // <diff tree printing stuff>
10963
10964 /// A visitor to print (to an output stream) a pretty representation
10965 /// of a @ref diff sub-tree or of a complete @ref corpus_diff tree.
10966 struct diff_node_printer : public diff_node_visitor
10967 {
10968   ostream& out_;
10969   unsigned level_;
10970
10971   /// Emit a certain number of spaces to the output stream associated
10972   /// to this diff_node_printer.
10973   ///
10974   /// @param level half of the numver of spaces to emit.
10975   void
10976   do_indent(unsigned level)
10977   {
10978     for (unsigned i = 0; i < level; ++i)
10979       out_ << "  ";
10980   }
10981
10982   diff_node_printer(ostream& out)
10983     : diff_node_visitor(DO_NOT_MARK_VISITED_NODES_AS_VISITED),
10984       out_(out),
10985       level_(0)
10986   {}
10987
10988   virtual void
10989   visit_begin(diff*)
10990   {
10991     ++level_;
10992   }
10993
10994   virtual void
10995   visit_end(diff*)
10996   {
10997     --level_;
10998   }
10999
11000   virtual void
11001   visit_begin(corpus_diff*)
11002   {
11003     ++level_;
11004   }
11005
11006   virtual void
11007   visit_end(corpus_diff*)
11008   {
11009     --level_;
11010   }
11011
11012   virtual bool
11013   visit(diff* d, bool pre)
11014   {
11015     if (!pre)
11016       // We are post-visiting the diff node D.  Which means, we have
11017       // printed a pretty representation for it already.  So do
11018       // nothing now.
11019       return true;
11020
11021     do_indent(level_);
11022     out_ << d->get_pretty_representation();
11023     out_ << "\n";
11024     do_indent(level_);
11025     out_ << "{\n";
11026     do_indent(level_ + 1);
11027     out_ << "category: "<< d->get_category() << "\n";
11028     do_indent(level_ + 1);
11029     out_ << "@: " << std::hex << d << std::dec << "\n";
11030     do_indent(level_ + 1);
11031     out_ << "@-canonical: " << std::hex
11032          << d->get_canonical_diff()
11033          << std::dec << "\n";
11034     do_indent(level_);
11035     out_ << "}\n";
11036
11037     return true;
11038   }
11039
11040   virtual bool
11041   visit(corpus_diff* d, bool pre)
11042   {
11043     if (!pre)
11044       // We are post-visiting the diff node D.  Which means, we have
11045       // printed a pretty representation for it already.  So do
11046       // nothing now.
11047       return true;
11048
11049     // indent
11050     for (unsigned i = 0; i < level_; ++i)
11051       out_ << ' ';
11052     out_ << d->get_pretty_representation();
11053     out_ << '\n';
11054     return true;
11055   }
11056 }; // end struct diff_printer_visitor
11057
11058 // </ diff tree printing stuff>
11059
11060 /// Emit a textual representation of a @ref diff sub-tree to an
11061 /// output stream.
11062 ///
11063 /// @param diff_tree the sub-tree to emit the textual representation
11064 /// for.
11065 ///
11066 /// @param out the output stream to emit the textual representation
11067 /// for @p diff_tree to.
11068 void
11069 print_diff_tree(diff* diff_tree, ostream& out)
11070 {
11071   diff_node_printer p(out);
11072   bool s = diff_tree->context()->visiting_a_node_twice_is_forbidden();
11073   diff_tree->context()->forbid_visiting_a_node_twice(false);
11074   diff_tree->traverse(p);
11075   diff_tree->context()->forbid_visiting_a_node_twice(s);
11076 }
11077
11078 /// Emit a textual representation of a @ref corpus_diff tree to an
11079 /// output stream.
11080 ///
11081 /// @param diff_tree the @ref corpus_diff tree to emit the textual
11082 /// representation for.
11083 ///
11084 /// @param out the output stream to emit the textual representation
11085 /// for @p diff_tree to.
11086 void
11087 print_diff_tree(corpus_diff* diff_tree, std::ostream& out)
11088 {
11089   diff_node_printer p(out);
11090   bool s = diff_tree->context()->visiting_a_node_twice_is_forbidden();
11091   diff_tree->context()->forbid_visiting_a_node_twice(false);
11092   diff_tree->traverse(p);
11093   diff_tree->context()->forbid_visiting_a_node_twice(s);
11094 }
11095
11096 /// Emit a textual representation of a @ref diff sub-tree to an
11097 /// output stream.
11098 ///
11099 /// @param diff_tree the sub-tree to emit the textual representation
11100 /// for.
11101 ///
11102 /// @param out the output stream to emit the textual representation
11103 /// for @p diff_tree to.
11104 void
11105 print_diff_tree(diff_sptr diff_tree,
11106                 std::ostream& o)
11107 {print_diff_tree(diff_tree.get(), o);}
11108
11109 /// Emit a textual representation of a @ref corpus_diff tree to an
11110 /// output stream.
11111 ///
11112 /// @param diff_tree the @ref corpus_diff tree to emit the textual
11113 /// representation for.
11114 ///
11115 /// @param out the output stream to emit the textual representation
11116 /// for @p diff_tree to.
11117 void
11118 print_diff_tree(corpus_diff_sptr diff_tree,
11119                 std::ostream& o)
11120 {print_diff_tree(diff_tree.get(), o);}
11121
11122 // <redundancy_marking_visitor>
11123
11124 /// A tree visitor to categorize nodes with respect to the
11125 /// REDUNDANT_CATEGORY.  That is, detect if a node is redundant (is
11126 /// present on several spots of the tree) and mark such nodes
11127 /// appropriatly.  This visitor also takes care of propagating the
11128 /// REDUNDANT_CATEGORY of a given node to its parent nodes as
11129 /// appropriate.
11130 struct redundancy_marking_visitor : public diff_node_visitor
11131 {
11132   bool skip_children_nodes_;
11133
11134   redundancy_marking_visitor()
11135     : skip_children_nodes_()
11136   {}
11137
11138   virtual void
11139   visit_begin(diff* d)
11140   {
11141     if (d->to_be_reported())
11142       {
11143         // A diff node that carries a change and that has been already
11144         // traversed elsewhere is considered redundant.  So let's mark
11145         // it as such and let's not traverse it; that is, let's not
11146         // visit its children.
11147         if ((d->context()->diff_has_been_visited(d)
11148              || d->get_canonical_diff()->is_traversing())
11149             && d->has_changes())
11150           {
11151             // But if two diff nodes are redundant sibbling that carry
11152             // changes of base types, do not mark them as being
11153             // redundant.  This is to avoid marking nodes as redundant
11154             // in this case:
11155             //
11156             //     int foo(int a, int b);
11157             // compared with:
11158             //     float foo(float a, float b); (in C).
11159             //
11160             // In this case, we want to report all the occurences of
11161             // the int->float change because logically, they are at
11162             // the same level in the diff tree.
11163
11164             bool redundant_with_sibling_node = false;
11165             const diff* p = d->parent_node();
11166
11167             // If this is a child node of a fn_parm_diff, look through
11168             // the fn_parm_diff node to get the function diff node.
11169             if (p && dynamic_cast<const fn_parm_diff*>(p))
11170               p = p->parent_node();
11171
11172             if (p)
11173               for (vector<diff*>::const_iterator s =
11174                      p->children_nodes().begin();
11175                    s != p->children_nodes().end();
11176                    ++s)
11177                 {
11178                   if (*s == d)
11179                     continue;
11180                   diff* sib = *s;
11181                   // If this is a fn_parm_diff, look through the
11182                   // fn_parm_diff node to get at the real type node.
11183                   if (fn_parm_diff* f = dynamic_cast<fn_parm_diff*>(*s))
11184                     sib = f->type_diff().get();
11185                   if (sib == d)
11186                     continue;
11187                   if (sib->get_canonical_diff() == d->get_canonical_diff()
11188                       // Sibbling diff nodes that carry base type
11189                       // changes ar to be marked as redundant.
11190                       && (is_base_diff(sib) || is_distinct_diff(sib)))
11191                     {
11192                       redundant_with_sibling_node = true;
11193                       break;
11194                     }
11195                 }
11196             if (!redundant_with_sibling_node
11197                 // Changes to basic types should never be considered
11198                 // redundant.  For instance, if a member of integer
11199                 // type is changed into a char type in both a struct A
11200                 // and a struct B, we want to see both changes.
11201                 && !has_basic_type_change_only(d)
11202                 // The same goes for distinct type changes
11203                 && !filtering::is_mostly_distinct_diff(d)
11204                 // Functions with similar *local* changes are never marked
11205                 // redundant because otherwise one could miss important
11206                 // similar local changes that are applied to different
11207                 // functions.
11208                 && !is_function_type_diff_with_local_changes(d)
11209                 // Changes involving variadic parameters of functions
11210                 // should never be marked redundant because we want to see
11211                 // them all.
11212                 && !is_diff_of_variadic_parameter(d)
11213                 && !is_diff_of_variadic_parameter_type(d)
11214                 // If the canonical diff itself has been filtered out,
11215                 // then this one is not marked redundant, obviously.
11216                 && !d->get_canonical_diff()->is_filtered_out()
11217                 && !(diff_has_ancestor_filtered_out
11218                      (d->context()->
11219                       get_last_visited_diff_of_class_of_equivalence(d)))
11220                 // If the *same* diff node (not one that is merely
11221                 // equivalent to this one) has already been visited
11222                 // the do not mark it as beind redundant.  It's only
11223                 // the other nodes that are equivalent to this one
11224                 // that must be marked redundant.
11225                 && d->context()->diff_has_been_visited(d) != d
11226                 // If the diff node is a function parameter and is not
11227                 // a reference/pointer (to a non basic or a non
11228                 // distinct type diff) then do not mark it as
11229                 // redundant.
11230                 //
11231                 // Children nodes of base class diff nodes are never
11232                 // redundant either, we want to see them all.
11233                 && (is_reference_or_ptr_diff_to_non_basic_nor_distinct_types(d)
11234                     || (!is_child_node_of_function_parm_diff(d)
11235                         && !is_child_node_of_base_diff(d))))
11236               {
11237                 d->add_to_category(REDUNDANT_CATEGORY);
11238                 // As we said in preamble, as this node is marked as
11239                 // being redundant, let's not visit its children.
11240                 // This is not an optimization; it's needed for
11241                 // correctness.  In the case of a diff node involving
11242                 // a class type that refers to himself, visiting the
11243                 // children nodes might cause them to be wrongly
11244                 // marked as redundant.
11245                 set_visiting_kind(get_visiting_kind()
11246                                   | SKIP_CHILDREN_VISITING_KIND);
11247                 skip_children_nodes_ = true;
11248               }
11249           }
11250       }
11251     else
11252       {
11253         // If the node is not to be reported, do not look at it children.
11254         set_visiting_kind(get_visiting_kind() | SKIP_CHILDREN_VISITING_KIND);
11255         skip_children_nodes_ = true;
11256       }
11257
11258     d->context()->mark_last_diff_visited_per_class_of_equivalence(d);
11259   }
11260
11261   virtual void
11262   visit_begin(corpus_diff*)
11263   {
11264   }
11265
11266   virtual void
11267   visit_end(diff* d)
11268   {
11269     if (skip_children_nodes_)
11270       // When visiting this node, we decided to skip its children
11271       // node.  Now that we are done visiting the node, lets stop
11272       // avoiding the children nodes visiting for the other tree
11273       // nodes.
11274       {
11275         set_visiting_kind(get_visiting_kind() & (~SKIP_CHILDREN_VISITING_KIND));
11276         skip_children_nodes_ = false;
11277       }
11278     else
11279       {
11280         // Propagate the redundancy categorization of the children nodes
11281         // to this node.  But if this node has local changes, then it
11282         // doesn't inherit redundancy from its children nodes.
11283         if (!(d->get_category() & REDUNDANT_CATEGORY)
11284             && (!d->has_local_changes_to_be_reported()
11285                 // By default, pointer, reference and qualified types
11286                 // consider that a local changes to their underlying
11287                 // type is always a local change for themselves.
11288                 //
11289                 // This is as if those types don't have local changes
11290                 // in the same sense as other types.  So we always
11291                 // propagate redundancy to them, regardless of if they
11292                 // have local changes or not.
11293                 || is_pointer_diff(d)
11294                 || is_qualified_type_diff(d)))
11295           {
11296             bool has_non_redundant_child = false;
11297             bool has_non_empty_child = false;
11298             for (vector<diff*>::const_iterator i =
11299                    d->children_nodes().begin();
11300                  i != d->children_nodes().end();
11301                  ++i)
11302               {
11303                 if ((*i)->has_changes())
11304                   {
11305                     has_non_empty_child = true;
11306                     if ((*i)->to_be_reported()
11307                         && ((*i)->get_category() & REDUNDANT_CATEGORY) == 0)
11308                       has_non_redundant_child = true;
11309                   }
11310                 if (has_non_redundant_child)
11311                   break;
11312               }
11313
11314             // A diff node for which at least a child node carries a
11315             // change, and for which all the children are redundant is
11316             // deemed redundant too, unless it has local changes.
11317             if (has_non_empty_child
11318                 && !has_non_redundant_child)
11319               d->add_to_category(REDUNDANT_CATEGORY);
11320           }
11321       }
11322   }
11323
11324   virtual void
11325   visit_end(corpus_diff*)
11326   {
11327   }
11328
11329   virtual bool
11330   visit(diff*, bool)
11331   {return true;}
11332
11333   virtual bool
11334   visit(corpus_diff*, bool)
11335   {
11336     return true;
11337   }
11338 };// end struct redundancy_marking_visitor
11339
11340 /// A visitor of @ref diff nodes that clears the REDUNDANT_CATEGORY
11341 /// category out of the nodes.
11342 struct redundancy_clearing_visitor : public diff_node_visitor
11343 {
11344   bool
11345   visit(corpus_diff*, bool)
11346   {return true;}
11347
11348   bool
11349   visit(diff* d, bool)
11350   {
11351     // clear the REDUNDANT_CATEGORY out of the current node.
11352     diff_category c = d->get_category();
11353     c &= ~REDUNDANT_CATEGORY;
11354     d->set_category(c);
11355     return true;
11356   }
11357 }; // end struct redundancy_clearing_visitor
11358
11359 /// Walk a given @ref diff sub-tree to categorize each of the nodes
11360 /// with respect to the REDUNDANT_CATEGORY.
11361 ///
11362 /// @param diff_tree the @ref diff sub-tree to walk.
11363 void
11364 categorize_redundancy(diff* diff_tree)
11365 {
11366   if (diff_tree->context()->show_redundant_changes())
11367     return;
11368   redundancy_marking_visitor v;
11369   diff_tree->context()->clear_last_diffs_visited_per_class_of_equivalence();
11370   bool s = diff_tree->context()->visiting_a_node_twice_is_forbidden();
11371   diff_tree->context()->forbid_visiting_a_node_twice(false);
11372   diff_tree->traverse(v);
11373   diff_tree->context()->forbid_visiting_a_node_twice(s);
11374   diff_tree->context()->clear_last_diffs_visited_per_class_of_equivalence();
11375 }
11376
11377 /// Walk a given @ref diff sub-tree to categorize each of the nodes
11378 /// with respect to the REDUNDANT_CATEGORY.
11379 ///
11380 /// @param diff_tree the @ref diff sub-tree to walk.
11381 void
11382 categorize_redundancy(diff_sptr diff_tree)
11383 {categorize_redundancy(diff_tree.get());}
11384
11385 /// Walk a given @ref corpus_diff tree to categorize each of the nodes
11386 /// with respect to the REDUNDANT_CATEGORY.
11387 ///
11388 /// @param diff_tree the @ref corpus_diff tree to walk.
11389 void
11390 categorize_redundancy(corpus_diff* diff_tree)
11391 {
11392   redundancy_marking_visitor v;
11393   diff_tree->context()->forget_visited_diffs();
11394   bool s = diff_tree->context()->visiting_a_node_twice_is_forbidden();
11395   diff_tree->context()->forbid_visiting_a_node_twice(false);
11396   diff_tree->traverse(v);
11397   diff_tree->context()->forbid_visiting_a_node_twice(s);
11398 }
11399
11400 /// Walk a given @ref corpus_diff tree to categorize each of the nodes
11401 /// with respect to the REDUNDANT_CATEGORY.
11402 ///
11403 /// @param diff_tree the @ref corpus_diff tree to walk.
11404 void
11405 categorize_redundancy(corpus_diff_sptr diff_tree)
11406 {categorize_redundancy(diff_tree.get());}
11407
11408 // </redundancy_marking_visitor>
11409
11410 /// Walk a given @ref diff sub-tree to clear the REDUNDANT_CATEGORY
11411 /// out of the category of the nodes.
11412 ///
11413 /// @param diff_tree the @ref diff sub-tree to walk.
11414 void
11415 clear_redundancy_categorization(diff* diff_tree)
11416 {
11417   redundancy_clearing_visitor v;
11418   bool s = diff_tree->context()->visiting_a_node_twice_is_forbidden();
11419   diff_tree->context()->forbid_visiting_a_node_twice(false);
11420   diff_tree->traverse(v);
11421   diff_tree->context()->forbid_visiting_a_node_twice(s);
11422   diff_tree->context()->forget_visited_diffs();
11423 }
11424
11425 /// Walk a given @ref diff sub-tree to clear the REDUNDANT_CATEGORY
11426 /// out of the category of the nodes.
11427 ///
11428 /// @param diff_tree the @ref diff sub-tree to walk.
11429 void
11430 clear_redundancy_categorization(diff_sptr diff_tree)
11431 {clear_redundancy_categorization(diff_tree.get());}
11432
11433 /// Walk a given @ref corpus_diff tree to clear the REDUNDANT_CATEGORY
11434 /// out of the category of the nodes.
11435 ///
11436 /// @param diff_tree the @ref corpus_diff tree to walk.
11437 void
11438 clear_redundancy_categorization(corpus_diff* diff_tree)
11439 {
11440   redundancy_clearing_visitor v;
11441   bool s = diff_tree->context()->visiting_a_node_twice_is_forbidden();
11442   diff_tree->context()->forbid_visiting_a_node_twice(false);
11443   diff_tree->traverse(v);
11444   diff_tree->context()->forbid_visiting_a_node_twice(s);
11445   diff_tree->context()->forget_visited_diffs();
11446 }
11447
11448 /// Walk a given @ref corpus_diff tree to clear the REDUNDANT_CATEGORY
11449 /// out of the category of the nodes.
11450 ///
11451 /// @param diff_tree the @ref corpus_diff tree to walk.
11452 void
11453 clear_redundancy_categorization(corpus_diff_sptr diff_tree)
11454 {clear_redundancy_categorization(diff_tree.get());}
11455
11456 /// Apply the @ref diff tree filters that have been associated to the
11457 /// context of the a given @ref corpus_diff tree.  As a result, the
11458 /// nodes of the @diff tree are going to be categorized into one of
11459 /// several of the categories of @ref diff_category.
11460 ///
11461 /// @param diff_tree the @ref corpus_diff instance which @ref diff are
11462 /// to be categorized.
11463 void
11464 apply_filters(corpus_diff_sptr diff_tree)
11465 {
11466   diff_tree->context()->maybe_apply_filters(diff_tree);
11467   propagate_categories(diff_tree);
11468 }
11469
11470 /// Test if a diff node represents the difference between a variadic
11471 /// parameter type and something else.
11472 ///
11473 /// @param d the diff node to consider.
11474 ///
11475 /// @return true iff @p d is a diff node that represents the
11476 /// difference between a variadic parameter type and something else.
11477 bool
11478 is_diff_of_variadic_parameter_type(const diff* d)
11479 {
11480   if (!d)
11481     return false;
11482
11483   type_base_sptr t = is_type(d->first_subject());
11484   if (t && t->get_environment()->is_variadic_parameter_type(t))
11485     return true;
11486
11487   t = is_type(d->second_subject());
11488   if (t && t->get_environment()->is_variadic_parameter_type(t))
11489     return true;
11490
11491   return false;
11492 }
11493
11494 /// Test if a diff node represents the difference between a variadic
11495 /// parameter type and something else.
11496 ///
11497 /// @param d the diff node to consider.
11498 ///
11499 /// @return true iff @p d is a diff node that represents the
11500 /// difference between a variadic parameter type and something else.
11501 bool
11502 is_diff_of_variadic_parameter_type(const diff_sptr& d)
11503 {return is_diff_of_variadic_parameter_type(d.get());}
11504
11505 /// Test if a diff node represents the difference between a variadic
11506 /// parameter and something else.
11507 ///
11508 /// @param d the diff node to consider.
11509 ///
11510 /// @return true iff @p d is a diff node that represents the
11511 /// difference between a variadic parameter and something else.
11512 bool
11513 is_diff_of_variadic_parameter(const diff* d)
11514 {
11515   fn_parm_diff* diff =
11516     dynamic_cast<fn_parm_diff*>(const_cast<abigail::comparison::diff*>(d));
11517   return (diff && is_diff_of_variadic_parameter_type(diff->type_diff()));
11518 }
11519
11520 /// Test if a diff node represents the difference between a variadic
11521 /// parameter and something else.
11522 ///
11523 /// @param d the diff node to consider.
11524 ///
11525 /// @return true iff @p d is a diff node that represents the
11526 /// difference between a variadic parameter and something else.
11527 bool
11528 is_diff_of_variadic_parameter(const diff_sptr& d)
11529 {return is_diff_of_variadic_parameter(d.get());}
11530
11531 /// Test if a diff node represents a diff between two basic types.
11532 ///
11533 /// @param d the diff node to consider.
11534 ///
11535 /// @return true iff @p d is a diff between two basic types.
11536 const type_decl_diff*
11537 is_diff_of_basic_type(const diff *d)
11538 {return dynamic_cast<const type_decl_diff*>(d);}
11539
11540 /// Test if a diff node represents a diff between two basic types, or
11541 /// between pointers, references or qualified type to basic types.
11542 ///
11543 /// @param diff the diff node to consider.
11544 ///
11545 /// @param allow_indirect_type if true, then this function looks into
11546 /// pointer, reference or qualified diff types to see if they "point
11547 /// to" basic types.
11548 ///
11549 /// @return true iff @p d is a diff between two basic types.
11550 const type_decl_diff*
11551 is_diff_of_basic_type(const diff* diff, bool allow_indirect_type)
11552 {
11553   if (allow_indirect_type)
11554       diff = peel_pointer_or_qualified_type(diff);
11555   return is_diff_of_basic_type(diff);
11556 }
11557
11558 /// If a diff node is about changes between two typedef types, get the
11559 /// diff node about changes between the underlying types.
11560 ///
11561 /// Note that this function walks the tree of underlying diff nodes
11562 /// returns the first diff node about types that are not typedefs.
11563 ///
11564 /// @param dif the dif node to consider.
11565 ///
11566 /// @return the underlying diff node of @p dif, or just return @p dif
11567 /// if it's not a typedef diff node.
11568 const diff*
11569 peel_typedef_diff(const diff* dif)
11570 {
11571   const typedef_diff *d = 0;
11572   while ((d = is_typedef_diff(dif)))
11573     dif = d->underlying_type_diff().get();
11574   return dif;
11575 }
11576
11577 /// If a diff node is about changes between two pointer types, get the
11578 /// diff node about changes between the underlying (pointed-to) types.
11579 ///
11580 /// Note that this function walks the tree of underlying diff nodes
11581 /// returns the first diff node about types that are not pointers.
11582 ///
11583 /// @param dif the dif node to consider.
11584 ///
11585 /// @return the underlying diff node of @p dif, or just return @p dif
11586 /// if it's not a pointer diff node.
11587 const diff*
11588 peel_pointer_diff(const diff* dif)
11589 {
11590   const pointer_diff *d = 0;
11591   while ((d = is_pointer_diff(dif)))
11592     dif = d->underlying_type_diff().get();
11593   return dif;
11594 }
11595
11596 /// If a diff node is about changes between two reference types, get
11597 /// the diff node about changes between the underlying (pointed-to)
11598 /// types.
11599 ///
11600 /// Note that this function walks the tree of underlying diff nodes
11601 /// returns the first diff node about types that are not references.
11602 ///
11603 /// @param dif the dif node to consider.
11604 ///
11605 /// @return the underlying diff node of @p dif, or just return @p dif
11606 /// if it's not a reference diff node.
11607 const diff*
11608 peel_reference_diff(const diff* dif)
11609 {
11610   const reference_diff *d = 0;
11611   while ((d = is_reference_diff(dif)))
11612     dif = d->underlying_type_diff().get();
11613   return dif;
11614 }
11615
11616 /// If a diff node is about changes between two qualified types, get
11617 /// the diff node about changes between the underlying (non-qualified)
11618 /// types.
11619 ///
11620 /// Note that this function walks the tree of underlying diff nodes
11621 /// returns the first diff node about types that are not qualified.
11622 ///
11623 /// @param dif the dif node to consider.
11624 ///
11625 /// @return the underlying diff node of @p dif, or just return @p dif
11626 /// if it's not a qualified diff node.
11627 const diff*
11628 peel_qualified_diff(const diff* dif)
11629 {
11630   const qualified_type_diff *d = 0;
11631   while ((d = is_qualified_type_diff(dif)))
11632     dif = d->underlying_type_diff().get();
11633   return dif;
11634 }
11635
11636 /// If a diff node is about changes between two pointer, reference or
11637 /// qualified types, get the diff node about changes between the
11638 /// underlying types.
11639 ///
11640 /// Note that this function walks the tree of underlying diff nodes
11641 /// returns the first diff node about types that are not pointer,
11642 /// reference or qualified.
11643 ///
11644 /// @param dif the dif node to consider.
11645 ///
11646 /// @return the underlying diff node of @p dif, or just return @p dif
11647 /// if it's not a pointer, reference or qualified diff node.
11648 const diff*
11649 peel_pointer_or_qualified_type(const diff*dif)
11650 {
11651   while (true)
11652     {
11653       if (const pointer_diff *d = is_pointer_diff(dif))
11654         dif = peel_pointer_diff(d);
11655       else if (const reference_diff *d = is_reference_diff(dif))
11656         dif = peel_reference_diff(d);
11657       else if (const qualified_type_diff *d = is_qualified_type_diff(dif))
11658         dif = peel_qualified_diff(d);
11659       else
11660         break;
11661     }
11662   return dif;
11663 }
11664
11665 /// Test if a diff node represents a diff between two class or union
11666 /// types.
11667 ///
11668 /// @param d the diff node to consider.
11669 ///
11670 /// @return iff @p is a diff between two class or union types then
11671 /// return the instance of @ref class_or_union_diff that @p derives
11672 /// from.  Otherwise, return nil.
11673 const class_or_union_diff*
11674 is_diff_of_class_or_union_type(const diff *d)
11675 {return dynamic_cast<const class_or_union_diff*>(d);}
11676
11677 /// Test if a given diff node carries *only* a local type change.
11678 ///
11679 /// @param d the diff node to consider.
11680 ///
11681 /// @return true iff @p has a change and that change is a local type
11682 /// change.
11683 static bool
11684 has_local_type_change_only(const diff *d)
11685 {
11686   if (enum change_kind k = d->has_local_changes())
11687     if ((k & LOCAL_NON_TYPE_CHANGE_KIND) == 0
11688         && (k & LOCAL_TYPE_CHANGE_KIND) != 0)
11689       return true;
11690
11691   return false;
11692 }
11693
11694 /// Test if a diff node is a decl diff that only carries a basic type
11695 /// change on its type diff sub-node.
11696 ///
11697 ///Note that that pointers/references/qualified types diffs to basic
11698 /// type diffs are considered as having basic type change only.
11699 ///
11700 /// @param d the diff node to consider.
11701 ///
11702 /// @return true iff @p d is a decl diff that only carries a basic
11703 /// type change on its type diff sub-node.
11704 bool
11705 has_basic_type_change_only(const diff *d)
11706 {
11707   if (is_diff_of_basic_type(d, true) && d->has_changes())
11708     return true;
11709   else if (const var_diff * v = dynamic_cast<const var_diff*>(d))
11710     return (has_local_type_change_only(v)
11711             && is_diff_of_basic_type(v->type_diff().get(), true));
11712   else if (const fn_parm_diff * p = dynamic_cast<const fn_parm_diff*>(d))
11713     return (has_local_type_change_only(p)
11714             && is_diff_of_basic_type(p->type_diff().get(), true));
11715   else if (const function_decl_diff* f =
11716            dynamic_cast<const function_decl_diff*>(d))
11717     return (has_local_type_change_only(f)
11718             && f->type_diff()
11719             && is_diff_of_basic_type(f->type_diff()->return_type_diff().get(),
11720                                      true));
11721   return false;
11722 }
11723 }// end namespace comparison
11724 } // end namespace abigail