• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
2 // -*- Mode: C++ -*-
3 //
4 // Copyright (C) 2013-2022 Red Hat, Inc.
5 //
6 // Author: Dodji Seketeli
7 
8 /// @file
9 ///
10 /// This contains the implementation of the comparison engine of
11 /// libabigail.
12 
13 #include <ctype.h>
14 #include <libgen.h>
15 #include <algorithm>
16 #include <sstream>
17 
18 #include "abg-comparison-priv.h"
19 #include "abg-reporter-priv.h"
20 
21 namespace abigail
22 {
23 
24 namespace comparison
25 {
26 
27 ///
28 ///
29 ///@defgroup DiffNode Internal Representation of the comparison engine
30 /// @{
31 ///
32 /// @brief How changes are represented in libabigail's comparison engine.
33 ///
34 ///@par diff nodes
35 ///
36 /// The internal representation of the comparison engine is basically
37 /// a graph of @ref instances of @ref diff node.  We refer to these
38 /// just as <em>diff nodes</em>.  A diff node represents a change
39 /// between two ABI artifacts represented by instances of types of the
40 /// abigail::ir namespace.  These two artifacts that are being
41 /// compared are called the <em>subjects of the diff</em>.
42 ///
43 /// The types of that IR are in the abigail::comparison namespace.
44 ///
45 ///@par comparing diff nodes
46 ///
47 /// Comparing two instances of @ref diff nodes amounts to comparing
48 /// the subject of the diff.  In other words, two @ref diff nodes are
49 /// equal if and only if their subjects are equal.  Thus, two @ref
50 /// diff nodes can have different memory addresses and yet be equal.
51 ///
52 ///@par diff reporting and context
53 ///
54 /// A diff node can be serialized to an output stream to express, in
55 /// a human-readable textual form, the different changes that exist
56 /// between its two subjects.  This is done by invoking the
57 /// diff::report() method.  That reporting is controlled by several
58 /// parameters that are conceptually part of the context of the diff.
59 /// That context is materialized by an instance of the @ref
60 /// diff_context type.
61 ///
62 /// Please note that the role of the instance(s) of @ref diff_context
63 /// is boreader than just controlling the reporting of @ref diff
64 /// nodes.  Basically, a @ref diff node itself is created following
65 /// behaviours that are controlled by a particular instance of
66 /// diff_context.  A diff node is created in a particular diff
67 /// context, so to speak.
68 ///
69 /// @}
70 ///
71 
72 ///
73 ///@defgroup CanonicalDiff Canonical diff tree nodes
74 /// @{
75 ///
76 /// @brief How equivalent diff nodes are quickly spotted.
77 ///
78 /// @par Equivalence of diff nodes.
79 ///
80 /// Each @ref diff node has a property named <em>Canonical Diff
81 /// Node</em>.  If \c D is a diff node, the canonical diff node of @c
82 /// D, noted @c C(D) is a particular diff node that is equal to @c D.
83 /// Thus, a fast way to compare two @ref diff node is to perform a
84 /// pointer comparison of their canonical diff nodes.
85 ///
86 /// A set of equivalent @ref diff nodes is a set of diff nodes that
87 /// all have the same canonical node.  All the nodes of that set are
88 /// equal.
89 ///
90 /// A canonical node is registereded for a given diff node by invoking
91 /// the method diff_context::initialize_canonical_diff().
92 ///
93 /// Please note that the diff_context holds all the canonical diffs
94 /// that got registered through it.  Thus, the life time of all of
95 /// canonical diff objects is the same as the life time of the @ref
96 /// diff_context they relate to.
97 ///
98 /// @}
99 ///
100 
101 // -----------------------------------------
102 // <private functions re-usable elsewhere>
103 // -----------------------------------------
104 /// Sort a map of enumerators by their value.
105 ///
106 /// @param enumerators_map the map to sort.
107 ///
108 /// @param sorted the resulting vector of sorted enumerators.
109 void
sort_enumerators(const string_enumerator_map & enumerators_map,enum_type_decl::enumerators & sorted)110 sort_enumerators(const string_enumerator_map& enumerators_map,
111 		 enum_type_decl::enumerators& sorted)
112 {
113   for (string_enumerator_map::const_iterator i = enumerators_map.begin();
114        i != enumerators_map.end();
115        ++i)
116     sorted.push_back(i->second);
117   enumerator_value_comp comp;
118   std::sort(sorted.begin(), sorted.end(), comp);
119 }
120 
121 /// Sort a map of changed enumerators.
122 ///
123 /// @param enumerators_map the map to sort.
124 ///
125 ///@param output parameter.  The resulting sorted enumerators.
126 void
sort_changed_enumerators(const string_changed_enumerator_map & enumerators_map,changed_enumerators_type & sorted)127 sort_changed_enumerators(const string_changed_enumerator_map& enumerators_map,
128 			 changed_enumerators_type& sorted)
129 {
130   for (string_changed_enumerator_map::const_iterator i =
131 	 enumerators_map.begin();
132        i != enumerators_map.end();
133        ++i)
134     sorted.push_back(i->second);
135 
136   changed_enumerator_comp comp;
137   std::sort(sorted.begin(), sorted.end(), comp);
138 }
139 
140 /// Sort a map of data members by the offset of their initial value.
141 ///
142 /// @param data_members the map of changed data members to sort.
143 ///
144 /// @param sorted the resulting vector of sorted changed data members.
145 void
sort_data_members(const string_decl_base_sptr_map & data_members,vector<decl_base_sptr> & sorted)146 sort_data_members(const string_decl_base_sptr_map &data_members,
147 		  vector<decl_base_sptr>& sorted)
148 {
149   sorted.reserve(data_members.size());
150   for (string_decl_base_sptr_map::const_iterator i = data_members.begin();
151        i != data_members.end();
152        ++i)
153     sorted.push_back(i->second);
154 
155   data_member_comp comp;
156   std::sort(sorted.begin(), sorted.end(), comp);
157 }
158 
159 /// Sort (in place) a vector of changed data members.
160 ///
161 /// @param to_sort the vector to sort.
162 void
sort_changed_data_members(changed_var_sptrs_type & to_sort)163 sort_changed_data_members(changed_var_sptrs_type& to_sort)
164 {
165   data_member_comp comp;
166   std::sort(to_sort.begin(), to_sort.end(), comp);
167 }
168 
169 /// Sort an instance of @ref string_function_ptr_map map and stuff a
170 /// resulting sorted vector of pointers to function_decl.
171 ///
172 /// @param map the map to sort.
173 ///
174 /// @param sorted the resulting sorted vector.
175 void
sort_string_function_ptr_map(const string_function_ptr_map & map,vector<function_decl * > & sorted)176 sort_string_function_ptr_map(const string_function_ptr_map& map,
177 			     vector<function_decl*>& sorted)
178 {
179   sorted.reserve(map.size());
180   for (string_function_ptr_map::const_iterator i = map.begin();
181        i != map.end();
182        ++i)
183     sorted.push_back(i->second);
184 
185   function_comp comp;
186   std::sort(sorted.begin(), sorted.end(), comp);
187 }
188 
189 /// Sort a map that's an instance of @ref
190 /// string_member_function_sptr_map and fill a vector of member
191 /// functions with the sorted result.
192 ///
193 /// @param map the map to sort.
194 ///
195 /// @param sorted the resulting sorted vector.
196 void
sort_string_member_function_sptr_map(const string_member_function_sptr_map & map,class_or_union::member_functions & sorted)197 sort_string_member_function_sptr_map(const string_member_function_sptr_map& map,
198 				     class_or_union::member_functions& sorted)
199 {
200   sorted.reserve(map.size());
201   for (string_member_function_sptr_map::const_iterator i = map.begin();
202        i != map.end();
203        ++i)
204     sorted.push_back(i->second);
205 
206   function_comp comp;
207   std::sort(sorted.begin(), sorted.end(), comp);
208 }
209 
210 /// Sort the values of a @ref string_function_decl_diff_sptr_map map
211 /// and store the result in a vector of @ref function_decl_diff_sptr
212 /// objects.
213 ///
214 /// @param map the map whose values to store.
215 ///
216 /// @param sorted the vector of function_decl_diff_sptr to store the
217 /// result of the sort into.
218 void
sort_string_function_decl_diff_sptr_map(const string_function_decl_diff_sptr_map & map,function_decl_diff_sptrs_type & sorted)219 sort_string_function_decl_diff_sptr_map
220 (const string_function_decl_diff_sptr_map& map,
221  function_decl_diff_sptrs_type& sorted)
222 {
223   sorted.reserve(map.size());
224   for (string_function_decl_diff_sptr_map::const_iterator i = map.begin();
225        i != map.end();
226        ++i)
227     sorted.push_back(i->second);
228   function_decl_diff_comp comp;
229   std::sort(sorted.begin(), sorted.end(), comp);
230 }
231 
232 /// Sort of an instance of @ref string_var_diff_sptr_map map.
233 ///
234 /// @param map the input map to sort.
235 ///
236 /// @param sorted the ouptut sorted vector of @ref var_diff_sptr.
237 /// It's populated with the sorted content.
238 void
sort_string_var_diff_sptr_map(const string_var_diff_sptr_map & map,var_diff_sptrs_type & sorted)239 sort_string_var_diff_sptr_map(const string_var_diff_sptr_map& map,
240 			      var_diff_sptrs_type& sorted)
241 {
242   sorted.reserve(map.size());
243   for (string_var_diff_sptr_map::const_iterator i = map.begin();
244        i != map.end();
245        ++i)
246     sorted.push_back(i->second);
247 
248   var_diff_sptr_comp comp;
249   std::sort(sorted.begin(), sorted.end(), comp);
250 }
251 
252 /// Sort a map of string -> pointer to @ref elf_symbol.
253 ///
254 /// The result is a vector of @ref elf_symbol_sptr sorted by the
255 /// name of the symbol.
256 ///
257 /// @param map the map to sort.
258 ///
259 /// @param sorted out parameter; the sorted vector of @ref
260 /// elf_symbol_sptr.
261 void
sort_string_elf_symbol_map(const string_elf_symbol_map & map,vector<elf_symbol_sptr> & sorted)262 sort_string_elf_symbol_map(const string_elf_symbol_map& map,
263 			   vector<elf_symbol_sptr>& sorted)
264 {
265   for (string_elf_symbol_map::const_iterator i = map.begin();
266        i!= map.end();
267        ++i)
268     sorted.push_back(i->second);
269 
270   elf_symbol_comp comp;
271   std::sort(sorted.begin(), sorted.end(), comp);
272 }
273 
274 /// Sort a map of string -> pointer to @ref var_decl.
275 ///
276 /// The result is a vector of var_decl* sorted by the qualified name
277 /// of the variables.
278 ///
279 /// @param map the map to sort.
280 ///
281 /// @param sorted out parameter; the sorted vector of @ref var_decl.
282 void
sort_string_var_ptr_map(const string_var_ptr_map & map,vector<var_decl * > & sorted)283 sort_string_var_ptr_map(const string_var_ptr_map& map,
284 			vector<var_decl*>& sorted)
285 {
286   for (string_var_ptr_map::const_iterator i = map.begin();
287        i != map.end();
288        ++i)
289     sorted.push_back(i->second);
290 
291   var_comp comp;
292   std::sort(sorted.begin(), sorted.end(), comp);
293 }
294 
295 /// Sort the values of a string_var_diff_sptr_map and store the result
296 /// in a vector of var_diff_sptr.
297 ///
298 /// @param map the map of changed data members to sort.
299 ///
300 /// @param sorted the resulting vector of var_diff_sptr.
301 void
sort_string_data_member_diff_sptr_map(const string_var_diff_sptr_map & map,var_diff_sptrs_type & sorted)302 sort_string_data_member_diff_sptr_map(const string_var_diff_sptr_map& map,
303 				      var_diff_sptrs_type& sorted)
304 {
305   sorted.reserve(map.size());
306   for (string_var_diff_sptr_map::const_iterator i = map.begin();
307        i != map.end();
308        ++i)
309     sorted.push_back(i->second);
310   data_member_diff_comp comp;
311   std::sort(sorted.begin(), sorted.end(), comp);
312 }
313 
314 /// Sort the values of a unsigned_var_diff_sptr_map map and store the
315 /// result into a vector of var_diff_sptr.
316 ///
317 /// @param map the map of changed data members to sort.
318 ///
319 /// @param sorted the resulting vector of sorted var_diff_sptr.
320 void
sort_unsigned_data_member_diff_sptr_map(const unsigned_var_diff_sptr_map map,var_diff_sptrs_type & sorted)321 sort_unsigned_data_member_diff_sptr_map(const unsigned_var_diff_sptr_map map,
322 					var_diff_sptrs_type& sorted)
323 {
324   sorted.reserve(map.size());
325   for (unsigned_var_diff_sptr_map::const_iterator i = map.begin();
326        i != map.end();
327        ++i)
328     sorted.push_back(i->second);
329   data_member_diff_comp comp;
330   std::sort(sorted.begin(), sorted.end(), comp);
331 }
332 
333 /// Sort an map of string -> virtual member function into a vector of
334 /// virtual member functions.  The virtual member functions are sorted
335 /// by increasing order of their virtual index.
336 ///
337 /// @param map the input map.
338 ///
339 /// @param sorted the resulting sorted vector of virtual function
340 /// member.
341 void
sort_string_virtual_member_function_diff_sptr_map(const string_function_decl_diff_sptr_map & map,function_decl_diff_sptrs_type & sorted)342 sort_string_virtual_member_function_diff_sptr_map
343 (const string_function_decl_diff_sptr_map& map,
344  function_decl_diff_sptrs_type& sorted)
345 {
346   sorted.reserve(map.size());
347   for (string_function_decl_diff_sptr_map::const_iterator i = map.begin();
348        i != map.end();
349        ++i)
350     sorted.push_back(i->second);
351 
352   virtual_member_function_diff_comp comp;
353   sort(sorted.begin(), sorted.end(), comp);
354 }
355 
356 /// Sort a map ofg string -> @ref diff_sptr into a vector of @ref
357 /// diff_sptr.  The diff_sptr are sorted lexicographically wrt
358 /// qualified names of their first subjects.
359 ///
360 /// @param map the map to sort.
361 ///
362 /// @param sorted the resulting sorted vector.
363 void
sort_string_diff_sptr_map(const string_diff_sptr_map & map,diff_sptrs_type & sorted)364 sort_string_diff_sptr_map(const string_diff_sptr_map& map,
365 			  diff_sptrs_type& sorted)
366 {
367   sorted.reserve(map.size());
368   for (string_diff_sptr_map::const_iterator i = map.begin();
369        i != map.end();
370        ++i)
371     sorted.push_back(i->second);
372 
373   diff_comp comp;
374   sort(sorted.begin(), sorted.end(), comp);
375 }
376 
377 /// Sort a map ofg string -> @ref diff* into a vector of @ref
378 /// diff_ptr.  The diff_ptr are sorted lexicographically wrt
379 /// qualified names of their first subjects.
380 ///
381 /// @param map the map to sort.
382 ///
383 /// @param sorted the resulting sorted vector.
384 void
sort_string_diff_ptr_map(const string_diff_ptr_map & map,diff_ptrs_type & sorted)385 sort_string_diff_ptr_map(const string_diff_ptr_map& map,
386 			  diff_ptrs_type& sorted)
387 {
388   sorted.reserve(map.size());
389   for (string_diff_ptr_map::const_iterator i = map.begin();
390        i != map.end();
391        ++i)
392     sorted.push_back(i->second);
393 
394   diff_comp comp;
395   sort(sorted.begin(), sorted.end(), comp);
396 }
397 
398 /// Sort a map of string -> base_diff_sptr into a sorted vector of
399 /// base_diff_sptr.  The base_diff_sptr are sorted by increasing value
400 /// of their offset in their containing type.
401 ///
402 /// @param map the input map to sort.
403 ///
404 /// @param sorted the resulting sorted vector.
405 void
sort_string_base_diff_sptr_map(const string_base_diff_sptr_map & map,base_diff_sptrs_type & sorted)406 sort_string_base_diff_sptr_map(const string_base_diff_sptr_map& map,
407 			       base_diff_sptrs_type& sorted)
408 {
409   for (string_base_diff_sptr_map::const_iterator i = map.begin();
410        i != map.end();
411        ++i)
412     sorted.push_back(i->second);
413   base_diff_comp comp;
414   sort(sorted.begin(), sorted.end(), comp);
415 }
416 
417 /// Lexicographically sort base specifications found
418 /// in instances of string_base_sptr_map.
419 void
sort_string_base_sptr_map(const string_base_sptr_map & m,class_decl::base_specs & sorted)420 sort_string_base_sptr_map(const string_base_sptr_map& m,
421 			  class_decl::base_specs& sorted)
422 {
423   for (string_base_sptr_map::const_iterator i = m.begin();
424        i != m.end();
425        ++i)
426     sorted.push_back(i->second);
427 
428   base_spec_comp comp;
429   std::sort(sorted.begin(), sorted.end(), comp);
430 }
431 
432 /// Sort a map of @ref fn_parm_diff by the indexes of the function
433 /// parameters.
434 ///
435 /// @param map the map to sort.
436 ///
437 /// @param sorted the resulting sorted vector of changed function
438 /// parms.
439 void
sort_string_fn_parm_diff_sptr_map(const unsigned_fn_parm_diff_sptr_map & map,vector<fn_parm_diff_sptr> & sorted)440 sort_string_fn_parm_diff_sptr_map(const unsigned_fn_parm_diff_sptr_map& map,
441 				  vector<fn_parm_diff_sptr>&		sorted)
442 {
443   sorted.reserve(map.size());
444   for (unsigned_fn_parm_diff_sptr_map::const_iterator i = map.begin();
445        i != map.end();
446        ++i)
447     sorted.push_back(i->second);
448 
449   fn_parm_diff_comp comp;
450   std::sort(sorted.begin(), sorted.end(), comp);
451 }
452 
453 /// Sort a map of changed function parameters by the indexes of the
454 /// function parameters.
455 ///
456 /// @param map the map to sort.
457 ///
458 /// @param sorted the resulting sorted vector of instances of @ref
459 /// fn_parm_diff_sptr
460 void
sort_string_fn_parm_diff_sptr_map(const string_fn_parm_diff_sptr_map & map,vector<fn_parm_diff_sptr> & sorted)461 sort_string_fn_parm_diff_sptr_map(const string_fn_parm_diff_sptr_map&	map,
462 				  vector<fn_parm_diff_sptr>&		sorted)
463 {
464   sorted.reserve(map.size());
465   for (string_fn_parm_diff_sptr_map::const_iterator i = map.begin();
466        i != map.end();
467        ++i)
468     sorted.push_back(i->second);
469 
470   fn_parm_diff_comp comp;
471   std::sort(sorted.begin(), sorted.end(), comp);
472 }
473 
474 /// Sort a map of string -> function parameters.
475 ///
476 /// @param map the map to sort.
477 ///
478 /// @param sorted the resulting sorted vector of
479 /// @ref vector<function_decl::parameter_sptr>
480 void
sort_string_parm_map(const string_parm_map & map,vector<function_decl::parameter_sptr> & sorted)481 sort_string_parm_map(const string_parm_map& map,
482 		     vector<function_decl::parameter_sptr>& sorted)
483 {
484   for (string_parm_map::const_iterator i = map.begin();
485        i != map.end();
486        ++i)
487     sorted.push_back(i->second);
488 
489   parm_comp comp;
490   std::sort(sorted.begin(), sorted.end(), comp);
491 }
492 
493 /// Sort the set of ABI artifacts contained in a @ref
494 /// artifact_sptr_set_type.
495 ///
496 /// @param set the set of ABI artifacts to sort.
497 ///
498 /// @param output parameter the vector containing the sorted ABI
499 /// artifacts.
500 void
sort_artifacts_set(const artifact_sptr_set_type & set,vector<type_or_decl_base_sptr> & sorted)501 sort_artifacts_set(const artifact_sptr_set_type& set,
502 		   vector<type_or_decl_base_sptr>& sorted)
503 {
504 
505   for (artifact_sptr_set_type::const_iterator it = set.begin();
506        it != set.end();
507        ++it)
508     sorted.push_back(*it);
509 
510   type_or_decl_base_comp comp;
511   std::sort(sorted.begin(), sorted.end(), comp);
512 }
513 
514 /// Sort a map of string to type_base_sptr entities.
515 ///
516 /// The entries are sorted based on the lexicographic order of the
517 /// pretty representation of the type_sptr_sptr.  The sorted result is
518 /// put in a vector of type_base_sptr.
519 ///
520 /// @param map the map to sort.
521 ///
522 /// @param sorted the resulting vector of type_base_sptr
523 /// lexicographically sorted using their pretty representation.
524 void
sort_string_type_base_sptr_map(string_type_base_sptr_map & map,vector<type_base_sptr> & sorted)525 sort_string_type_base_sptr_map(string_type_base_sptr_map& map,
526 			       vector<type_base_sptr>& sorted)
527 {
528   for (string_type_base_sptr_map::const_iterator i = map.begin();
529        i != map.end();
530        ++i)
531     sorted.push_back(i->second);
532 
533   type_or_decl_base_comp comp;
534   std::sort(sorted.begin(), sorted.end(), comp);
535 }
536 
537 /// Return the first underlying type that is not a qualified type.
538 /// @param t the qualified type to consider.
539 ///
540 /// @return the first underlying type that is not a qualified type, or
541 /// NULL if t is NULL.
542 type_base_sptr
get_leaf_type(qualified_type_def_sptr t)543 get_leaf_type(qualified_type_def_sptr t)
544 {
545   if (!t)
546     return type_base_sptr();
547 
548   type_base_sptr ut = t->get_underlying_type();
549   qualified_type_def_sptr qut = dynamic_pointer_cast<qualified_type_def>(ut);
550 
551   if (!qut)
552     return ut;
553   return get_leaf_type(qut);
554 }
555 
556 /// Tests if a given diff node is to represent the changes between two
557 /// gobal decls.
558 ///
559 /// @param d the diff node to consider.
560 ///
561 /// @return true iff @p d represents the changes between two global
562 /// decls.
563 bool
is_diff_of_global_decls(const diff * d)564 is_diff_of_global_decls(const diff* d)
565 {
566   ABG_ASSERT(d != 0);
567 
568   if (d == 0)
569     return false;
570 
571   type_or_decl_base_sptr first = d->first_subject();
572   ABG_ASSERT(first);
573 
574   type_or_decl_base_sptr second = d->first_subject();
575   ABG_ASSERT(second);
576 
577   if (decl_base_sptr decl = is_decl(first))
578     if (is_at_global_scope(decl))
579       if ((decl = is_decl(second)))
580 	if (is_at_global_scope(decl))
581 	  return true;
582 
583   return false;
584 }
585 
586 // -----------------------------------------
587 // </private functions re-usable elsewhere>
588 // -----------------------------------------
589 
590 /// The overloaded or operator for @ref visiting_kind.
591 visiting_kind
operator |(visiting_kind l,visiting_kind r)592 operator|(visiting_kind l, visiting_kind r)
593 {return static_cast<visiting_kind>(static_cast<unsigned>(l)
594 				   | static_cast<unsigned>(r));}
595 
596 /// The overloaded and operator for @ref visiting_kind.
597 visiting_kind
operator &(visiting_kind l,visiting_kind r)598 operator&(visiting_kind l, visiting_kind r)
599 {
600   return static_cast<visiting_kind>(static_cast<unsigned>(l)
601 				    & static_cast<unsigned>(r));
602 }
603 
604 /// The overloaded 'bit inversion' operator for @ref visiting_kind.
605 visiting_kind
operator ~(visiting_kind l)606 operator~(visiting_kind l)
607 {return static_cast<visiting_kind>(~static_cast<unsigned>(l));}
608 
609 /// Test if a diff node is about differences between types.
610 ///
611 /// @param diff the diff node to test.
612 ///
613 /// @return a pointer to the actual type_diff_base* that @p diff
614 /// extends, iff it is about differences between types.
615 const type_diff_base*
is_type_diff(const diff * diff)616 is_type_diff(const diff* diff)
617 {return dynamic_cast<const type_diff_base*>(diff);}
618 
619 /// Test if a diff node is about differences between declarations.
620 ///
621 /// @param diff the diff node to test.
622 ///
623 /// @return a pointer to the actual decl_diff_base @p diff extends,
624 /// iff it is about differences between declarations.
625 const decl_diff_base*
is_decl_diff(const diff * diff)626 is_decl_diff(const diff* diff)
627 {return dynamic_cast<const decl_diff_base*>(diff);}
628 
629 /// Test if a diff node is a @ref class_diff node.
630 ///
631 /// @param diff the diff node to consider.
632 ///
633 /// @return a non-nil pointer to a @ref class_diff iff @p diff is a
634 /// @ref class_diff node.
635 const class_diff*
is_class_diff(const diff * diff)636 is_class_diff(const diff* diff)
637 {return dynamic_cast<const class_diff*>(diff);}
638 
639 /// Test if a diff node is a @ref enum_diff node.
640 ///
641 /// @param diff the diff node to consider.
642 ///
643 /// @return a non-nil pointer to ad @ref enum_diff node iff @p diff is
644 /// a @ref enum_diff node.
645 const enum_diff*
is_enum_diff(const diff * diff)646 is_enum_diff(const diff *diff)
647 {return dynamic_cast<const enum_diff*>(diff);}
648 
649 /// Test if a diff node is a @ref union_diff node.
650 ///
651 /// @param diff the diff node to consider.
652 ///
653 /// @return a non-nil pointer to a @ref union_diff iff @p diff is a
654 /// @ref union_diff node.
655 const union_diff*
is_union_diff(const diff * diff)656 is_union_diff(const diff* diff)
657 {return dynamic_cast<const union_diff*>(diff);}
658 
659 /// Test if a diff node is a @ref class_or_union_diff node.
660 ///
661 /// @param d the diff node to consider.
662 ///
663 /// @return a non-nil pointer to the @ref class_or_union_diff denoted
664 /// by @p d iff @p d is a @ref class_or_union_diff.
665 const class_or_union_diff*
is_class_or_union_diff(const diff * d)666 is_class_or_union_diff(const diff* d)
667 {return dynamic_cast<const class_or_union_diff*>(d);}
668 
669 /// Test if a diff node is a @ref class_or_union_diff between two
670 /// anonymous classes or unions.
671 ///
672 /// @param d the diff node to consider.
673 ///
674 /// @return a non-nil pointer to the @ref class_or_union_diff iff @p
675 /// denoted by @p d iff @p is pointer to an anonymous class or union
676 /// diff.
677 const class_or_union_diff*
is_anonymous_class_or_union_diff(const diff * d)678 is_anonymous_class_or_union_diff(const diff* d)
679 {
680   if (const class_or_union_diff *dif = is_class_or_union_diff(d))
681     if (dif->first_class_or_union()->get_is_anonymous())
682       return dif;
683   return 0;
684 }
685 
686 /// Test if a diff node is a @ref typedef_diff node.
687 ///
688 /// @param diff the diff node to consider.
689 ///
690 /// @return a non-nil pointer to a @ref typedef_diff iff @p diff is a
691 /// @ref typedef_diff node.
692 const typedef_diff*
is_typedef_diff(const diff * diff)693 is_typedef_diff(const diff *diff)
694 {return dynamic_cast<const typedef_diff*>(diff);}
695 
696 /// Test if a diff node is a @ref array_diff node.
697 ///
698 /// @param diff the diff node to consider.
699 ///
700 /// @return a non-nil pointer to a @ref array_diff iff @p diff is a
701 /// @ref array_diff node.
702 const array_diff*
is_array_diff(const diff * diff)703 is_array_diff(const diff* diff)
704 {return dynamic_cast<const array_diff*>(diff);}
705 
706 /// Test if a diff node is a @ref function_type_diff node.
707 ///
708 /// @param diff the diff node to consider.
709 ///
710 /// @return a non-nil pointer to a @ref function_type_diff iff @p diff is a
711 /// @ref function_type_diff node.
712 const function_type_diff*
is_function_type_diff(const diff * diff)713 is_function_type_diff(const diff* diff)
714 {return dynamic_cast<const function_type_diff*>(diff);}
715 
716 /// Test if a given diff node carries a function type change with
717 /// local changes.
718 ///
719 /// @param diff the diff node to consider.
720 ///
721 /// @return a non-nil pointer to a @ref function_type_diff iff @p diff
722 /// is a function_type_diff node that carries a local change.
723 const function_type_diff*
is_function_type_diff_with_local_changes(const diff * diff)724 is_function_type_diff_with_local_changes(const diff* diff)
725 {
726   if (const function_type_diff* d = is_function_type_diff(diff))
727     if (d->has_local_changes())
728       return d;
729 
730   return 0;
731 }
732 
733 /// Test if a diff node is about differences between variables.
734 ///
735 /// @param diff the diff node to test.
736 ///
737 /// @return a pointer to the actual var_diff that @p diff is a type
738 /// of, iff it is about differences between variables.
739 const var_diff*
is_var_diff(const diff * diff)740 is_var_diff(const diff* diff)
741 {
742   const var_diff* d = dynamic_cast<const var_diff*>(diff);
743   if (d)
744     ABG_ASSERT(is_decl_diff(diff));
745   return d;
746 }
747 
748 /// Test if a diff node is about differences between functions.
749 ///
750 /// @param diff the diff node to test.
751 ///
752 /// @return a pointer to the actual var_diff that @p diff is a type
753 /// of, iff it is about differences between variables.
754 const function_decl_diff*
is_function_decl_diff(const diff * diff)755 is_function_decl_diff(const diff* diff)
756 {
757   const function_decl_diff *d = dynamic_cast<const function_decl_diff*>(diff);
758   if (d)
759     ABG_ASSERT(is_decl_diff(diff));
760   return d;
761 }
762 
763 /// Test if a diff node is about differences between two pointers.
764 ///
765 /// @param diff the diff node to consider.
766 ///
767 /// @return the @p diff converted into an instance of @ref
768 /// pointer_diff iff @p diff is about differences between two
769 /// pointers.
770 const pointer_diff*
is_pointer_diff(const diff * diff)771 is_pointer_diff(const diff* diff)
772 {return dynamic_cast<const pointer_diff*>(diff);}
773 
774 /// Test if a diff node is about differences between two references.
775 ///
776 /// @param diff the diff node to consider.
777 ///
778 /// @return the @p diff converted into an instance of @ref
779 /// reference_diff iff @p diff is about differences between two
780 /// references.
781 const reference_diff*
is_reference_diff(const diff * diff)782 is_reference_diff(const diff* diff)
783 {return dynamic_cast<const reference_diff*>(diff);}
784 
785 /// Test if a diff node is about differences between two qualified
786 /// types.
787 ///
788 /// @param diff the diff node to consider.
789 ///
790 /// @return @p diff converted into an instance of @ref
791 /// qualified_type_diff iff @p diff is about differences between two
792 /// qualified types.
793 const qualified_type_diff*
is_qualified_type_diff(const diff * diff)794 is_qualified_type_diff(const diff* diff)
795 {return dynamic_cast<const qualified_type_diff*>(diff);}
796 
797 /// Test if a diff node is a reference or pointer diff node to a
798 /// change that is neither basic type change nor distinct type change.
799 ///
800 /// Note that this function also works on diffs of typedefs of
801 /// reference or pointer.
802 ///
803 /// @param diff the diff node to consider.
804 ///
805 /// @return true iff @p diff is a eference or pointer diff node to a
806 /// change that is neither basic type change nor distinct type change.
807 bool
is_reference_or_ptr_diff_to_non_basic_nor_distinct_types(const diff * diff)808 is_reference_or_ptr_diff_to_non_basic_nor_distinct_types(const diff* diff)
809 {
810   diff = peel_typedef_diff(diff);
811   if (const reference_diff* d = is_reference_diff(diff))
812     {
813       diff = peel_reference_diff(d);
814       if (is_diff_of_basic_type(diff) || is_distinct_diff(diff))
815 	return false;
816       return true;
817     }
818   else if (const pointer_diff *d = is_pointer_diff(diff))
819     {
820       diff = peel_pointer_diff(d);
821       if (is_diff_of_basic_type(diff) || is_distinct_diff(diff))
822 	return false;
823       return true;
824     }
825 
826   return false;
827 }
828 
829 /// Test if a diff node is about differences between two function
830 /// parameters.
831 ///
832 /// @param diff the diff node to consider.
833 ///
834 /// @return the @p diff converted into an instance of @ref
835 /// reference_diff iff @p diff is about differences between two
836 /// function parameters.
837 const fn_parm_diff*
is_fn_parm_diff(const diff * diff)838 is_fn_parm_diff(const diff* diff)
839 {return dynamic_cast<const fn_parm_diff*>(diff);}
840 
841 /// Test if a diff node is about differences between two base class
842 /// specifiers.
843 ///
844 /// @param diff the diff node to consider.
845 ///
846 /// @return the @p diff converted into an instance of @ref base_diff
847 /// iff @p diff is about differences between two base class
848 /// specifiers.
849 const base_diff*
is_base_diff(const diff * diff)850 is_base_diff(const diff* diff)
851 {return dynamic_cast<const base_diff*>(diff);}
852 
853 /// Test if a diff node is about differences between two diff nodes of
854 /// different kinds.
855 ///
856 /// @param diff the diff node to consider.
857 ///
858 /// @return the @p diff converted into an instance of @ref
859 /// distintc_diff iff @p diff is about differences between two diff
860 /// nodes of different kinds.
861 const distinct_diff*
is_distinct_diff(const diff * diff)862 is_distinct_diff(const diff *diff)
863 {return dynamic_cast<const distinct_diff*>(diff);}
864 
865 /// Test if a diff node is a @ref corpus_diff node.
866 ///
867 /// @param diff the diff node to consider.
868 ///
869 /// @return a non-nil pointer to a @ref corpus_diff iff @p diff is a
870 /// @ref corpus_diff node.
871 const corpus_diff*
is_corpus_diff(const diff * diff)872 is_corpus_diff(const diff* diff)
873 {return dynamic_cast<const corpus_diff*>(diff);}
874 
875 /// Test if a diff node is a child node of a function parameter diff node.
876 ///
877 /// @param diff the diff node to test.
878 ///
879 /// @return true iff @p diff is a child node of a function parameter
880 /// diff node.
881 bool
is_child_node_of_function_parm_diff(const diff * diff)882 is_child_node_of_function_parm_diff(const diff* diff)
883 {return diff && is_fn_parm_diff(diff->parent_node());}
884 
885 /// Test if a diff node is a child node of a base diff node.
886 ///
887 /// @param diff the diff node to test.
888 ///
889 /// @return true iff @p diff is a child node of a base diff node.
890 bool
is_child_node_of_base_diff(const diff * diff)891 is_child_node_of_base_diff(const diff* diff)
892 {return diff && is_base_diff(diff->parent_node());}
893 
894 /// The default traverse function.
895 ///
896 /// @return true.
897 bool
traverse(diff_node_visitor &)898 diff_traversable_base::traverse(diff_node_visitor&)
899 {return true;}
900 
diff_context()901 diff_context::diff_context()
902   : priv_(new diff_context::priv)
903 {
904   // Setup all the diff output filters we have.
905   filtering::filter_base_sptr f;
906 
907   f.reset(new filtering::harmless_harmful_filter);
908   add_diff_filter(f);
909 
910   // f.reset(new filtering::harmless_filter);
911   // add_diff_filter(f);
912 
913   // f.reset(new filtering::harmful_filter);
914   // add_diff_filter(f);
915 }
916 
917 diff_context::~diff_context() = default;
918 
919 /// Set the corpus diff relevant to this context.
920 ///
921 /// @param d the corpus_diff we are interested in.
922 void
set_corpus_diff(const corpus_diff_sptr & d)923 diff_context::set_corpus_diff(const corpus_diff_sptr& d)
924 {priv_->corpus_diff_ = d;}
925 
926 /// Get the corpus diff for the current context.
927 ///
928 /// @return the corpus diff of this context.
929 const corpus_diff_sptr&
get_corpus_diff() const930 diff_context::get_corpus_diff() const
931 {return priv_->corpus_diff_;}
932 
933 /// Getter for the first corpus of the corpus diff of the current context.
934 ///
935 /// @return the first corpus of the corpus diff of the current
936 /// context, if no corpus diff is associated to the context.
937 corpus_sptr
get_first_corpus() const938 diff_context::get_first_corpus() const
939 {
940   if (priv_->corpus_diff_)
941     return priv_->corpus_diff_->first_corpus();
942   return corpus_sptr();
943 }
944 
945 /// Getter for the second corpus of the corpus diff of the current
946 /// context.
947 ///
948 /// @return the second corpus of the corpus diff of the current
949 /// context, if no corpus diff is associated to the context.
950 corpus_sptr
get_second_corpus() const951 diff_context::get_second_corpus() const
952 {
953   if (priv_->corpus_diff_)
954     return priv_->corpus_diff_->second_corpus();
955   return corpus_sptr();
956 }
957 
958 /// Getter of the reporter to be used in this context.
959 ///
960 /// @return the reporter to be used in this context.
961 reporter_base_sptr
get_reporter() const962 diff_context::get_reporter() const
963 {
964   if (!priv_->reporter_)
965     {
966       if (show_leaf_changes_only())
967 	priv_->reporter_.reset(new leaf_reporter);
968       else
969 	priv_->reporter_.reset(new default_reporter);
970     }
971   ABG_ASSERT(priv_->reporter_);
972   return priv_->reporter_;
973 }
974 
975 /// Setter of the reporter to be used in this context.
976 ///
977 /// @param r the reporter to be used in this context.
978 void
set_reporter(reporter_base_sptr & r)979 diff_context::set_reporter(reporter_base_sptr& r)
980 {priv_->reporter_ = r;}
981 
982 /// Tests if the current diff context already has a diff for two decls.
983 ///
984 /// @param first the first decl to consider.
985 ///
986 /// @param second the second decl to consider.
987 ///
988 /// @return a pointer to the diff for @p first @p second if found,
989 /// null otherwise.
990 diff_sptr
has_diff_for(const type_or_decl_base_sptr first,const type_or_decl_base_sptr second) const991 diff_context::has_diff_for(const type_or_decl_base_sptr first,
992 			   const type_or_decl_base_sptr second) const
993 {
994   types_or_decls_diff_map_type::const_iterator i =
995     priv_->types_or_decls_diff_map.find(std::make_pair(first, second));
996   if (i != priv_->types_or_decls_diff_map.end())
997     return i->second;
998   return diff_sptr();
999 }
1000 
1001 /// Tests if the current diff context already has a diff for two types.
1002 ///
1003 /// @param first the first type to consider.
1004 ///
1005 /// @param second the second type to consider.
1006 ///
1007 /// @return a pointer to the diff for @p first @p second if found,
1008 /// null otherwise.
1009 diff_sptr
has_diff_for_types(const type_base_sptr first,const type_base_sptr second) const1010 diff_context::has_diff_for_types(const type_base_sptr first,
1011 				  const type_base_sptr second) const
1012 {return has_diff_for(first, second);}
1013 
1014 /// Tests if the current diff context already has a given diff.
1015 ///
1016 ///@param d the diff to consider.
1017 ///
1018 /// @return a pointer to the diff found for @p d
1019 const diff*
has_diff_for(const diff * d) const1020 diff_context::has_diff_for(const diff* d) const
1021 {return has_diff_for(d->first_subject(), d->second_subject()).get();}
1022 
1023 /// Tests if the current diff context already has a given diff.
1024 ///
1025 ///@param d the diff to consider.
1026 ///
1027 /// @return a pointer to the diff found for @p d
1028 diff_sptr
has_diff_for(const diff_sptr d) const1029 diff_context::has_diff_for(const diff_sptr d) const
1030 {return has_diff_for(d->first_subject(), d->second_subject());}
1031 
1032 /// Getter for the bitmap that represents the set of categories that
1033 /// the user wants to see reported.
1034 ///
1035 /// @return a bitmap that represents the set of categories that the
1036 /// user wants to see reported.
1037 diff_category
get_allowed_category() const1038 diff_context::get_allowed_category() const
1039 {return priv_->allowed_category_;}
1040 
1041 /// Setter for the bitmap that represents the set of categories that
1042 /// the user wants to see reported.
1043 ///
1044 /// @param c a bitmap that represents the set of categories that the
1045 /// user wants to see represented.
1046 void
set_allowed_category(diff_category c)1047 diff_context::set_allowed_category(diff_category c)
1048 {priv_->allowed_category_ = c;}
1049 
1050 /// Setter for the bitmap that represents the set of categories that
1051 /// the user wants to see reported
1052 ///
1053 /// This function perform a bitwise or between the new set of
1054 /// categories and the current ones, and then sets the current
1055 /// categories to the result of the or.
1056 ///
1057 /// @param c a bitmap that represents the set of categories that the
1058 /// user wants to see represented.
1059 void
switch_categories_on(diff_category c)1060 diff_context::switch_categories_on(diff_category c)
1061 {priv_->allowed_category_ = priv_->allowed_category_ | c;}
1062 
1063 /// Setter for the bitmap that represents the set of categories that
1064 /// the user wants to see reported
1065 ///
1066 /// This function actually unsets bits from the current categories.
1067 ///
1068 /// @param c a bitmap that represents the set of categories to unset
1069 /// from the current categories.
1070 void
switch_categories_off(diff_category c)1071 diff_context::switch_categories_off(diff_category c)
1072 {priv_->allowed_category_ = priv_->allowed_category_ & ~c;}
1073 
1074 /// Add a diff for two decls to the cache of the current diff_context.
1075 ///
1076 /// Doing this allows to later find the added diff from its two
1077 /// subject decls.
1078 ///
1079 /// @param first the first decl to consider.
1080 ///
1081 /// @param second the second decl to consider.
1082 ///
1083 /// @param the diff to add.
1084 void
add_diff(type_or_decl_base_sptr first,type_or_decl_base_sptr second,const diff_sptr d)1085 diff_context::add_diff(type_or_decl_base_sptr first,
1086 		       type_or_decl_base_sptr second,
1087 		       const diff_sptr d)
1088 {priv_->types_or_decls_diff_map[std::make_pair(first, second)] = d;}
1089 
1090 /// Add a diff tree node to the cache of the current diff_context
1091 ///
1092 /// @param d the diff tree node to add.
1093 void
add_diff(const diff * d)1094 diff_context::add_diff(const diff* d)
1095 {
1096   if (d)
1097     {
1098       diff_sptr dif(const_cast<diff*>(d), noop_deleter());
1099       add_diff(d->first_subject(), d->second_subject(), dif);
1100     }
1101 }
1102 
1103 /// Add a diff tree node to the cache of the current diff_context
1104 ///
1105 /// @param d the diff tree node to add.
1106 void
add_diff(const diff_sptr d)1107 diff_context::add_diff(const diff_sptr d)
1108 {
1109   if (d)
1110       add_diff(d->first_subject(), d->second_subject(), d);
1111 }
1112 
1113 /// Getter for the @ref CanonicalDiff "canonical diff node" for the
1114 /// @ref diff represented by their two subjects.
1115 ///
1116 /// @param first the first subject of the diff.
1117 ///
1118 /// @param second the second subject of the diff.
1119 ///
1120 /// @return the canonical diff for the diff node represented by the
1121 /// two diff subjects @p first and @p second.  If no canonical diff
1122 /// node was registered for these subjects, then a nil node is
1123 /// returned.
1124 diff_sptr
get_canonical_diff_for(const type_or_decl_base_sptr first,const type_or_decl_base_sptr second) const1125 diff_context::get_canonical_diff_for(const type_or_decl_base_sptr first,
1126 				     const type_or_decl_base_sptr second) const
1127 {return has_diff_for(first, second);}
1128 
1129 /// Getter for the @ref CanonicalDiff "canonical diff node" for the
1130 /// @ref diff represented by the two subjects of a given diff node.
1131 ///
1132 /// @param d the diff node to get the canonical node for.
1133 ///
1134 /// @return the canonical diff for the diff node represented by the
1135 /// two diff subjects of @p d.  If no canonical diff node was
1136 /// registered for these subjects, then a nil node is returned.
1137 diff_sptr
get_canonical_diff_for(const diff_sptr d) const1138 diff_context::get_canonical_diff_for(const diff_sptr d) const
1139 {return has_diff_for(d);}
1140 
1141 /// Setter for the @ref CanonicalDiff "canonical diff node" for the
1142 /// @ref diff represented by their two subjects.
1143 ///
1144 /// @param first the first subject of the diff.
1145 ///
1146 /// @param second the second subject of the diff.
1147 ///
1148 /// @param d the new canonical diff.
1149 void
set_canonical_diff_for(const type_or_decl_base_sptr first,const type_or_decl_base_sptr second,const diff_sptr d)1150 diff_context::set_canonical_diff_for(const type_or_decl_base_sptr first,
1151 				     const type_or_decl_base_sptr second,
1152 				     const diff_sptr d)
1153 {
1154   ABG_ASSERT(d);
1155   if (!has_diff_for(first, second))
1156     {
1157       add_diff(first, second, d);
1158       priv_->canonical_diffs.push_back(d);
1159     }
1160 }
1161 
1162 /// If there is is a @ref CanonicalDiff "canonical diff node"
1163 /// registered for two diff subjects, return it.  Otherwise, register
1164 /// a canonical diff node for these two diff subjects and return it.
1165 ///
1166 /// @param first the first subject of the diff.
1167 ///
1168 /// @param second the second subject of the diff.
1169 ///
1170 /// @param d the new canonical diff node.
1171 ///
1172 /// @return the canonical diff node.
1173 diff_sptr
set_or_get_canonical_diff_for(const type_or_decl_base_sptr first,const type_or_decl_base_sptr second,const diff_sptr canonical_diff)1174 diff_context::set_or_get_canonical_diff_for(const type_or_decl_base_sptr first,
1175 					    const type_or_decl_base_sptr second,
1176 					    const diff_sptr canonical_diff)
1177 {
1178   ABG_ASSERT(canonical_diff);
1179 
1180   diff_sptr canonical = get_canonical_diff_for(first, second);
1181   if (!canonical)
1182     {
1183       canonical = canonical_diff;
1184       set_canonical_diff_for(first, second, canonical);
1185     }
1186   return canonical;
1187 }
1188 
1189 /// Set the canonical diff node property of a given diff node
1190 /// appropriately.
1191 ///
1192 /// For a given diff node that has no canonical diff node, retrieve
1193 /// the canonical diff node (by looking at its diff subjects and at
1194 /// the current context) and set the canonical diff node property of
1195 /// the diff node to that canonical diff node.  If no canonical diff
1196 /// node has been registered to the diff context for the subjects of
1197 /// the diff node then, register the canonical diff node as being the
1198 /// diff node itself; and set its canonical diff node property as
1199 /// such.  Otherwise, if the diff node already has a canonical diff
1200 /// node, do nothing.
1201 ///
1202 /// @param diff the diff node to initialize the canonical diff node
1203 /// property for.
1204 void
initialize_canonical_diff(const diff_sptr diff)1205 diff_context::initialize_canonical_diff(const diff_sptr diff)
1206 {
1207   if (diff->get_canonical_diff() == 0)
1208     {
1209       diff_sptr canonical =
1210 	set_or_get_canonical_diff_for(diff->first_subject(),
1211 				      diff->second_subject(),
1212 				      diff);
1213       diff->set_canonical_diff(canonical.get());
1214     }
1215 }
1216 
1217 /// Add a diff node to the set of diff nodes that are kept alive for
1218 /// the life time of the current instance of diff_context.
1219 ///
1220 /// Note that diff added to the diff cache are kept alive as well, and
1221 /// don't need to be passed to this function to be kept alive.
1222 ///
1223 /// @param d the diff node to be kept alive during the life time of
1224 /// the current instance of @ref diff_context.
1225 void
keep_diff_alive(diff_sptr & d)1226 diff_context::keep_diff_alive(diff_sptr& d)
1227 {priv_->live_diffs_.insert(d);}
1228 
1229 /// Test if a diff node has been traversed.
1230 ///
1231 /// @param d the diff node to consider.
1232 ///
1233 /// @return the first diff node against which @p d is redundant.
1234 diff*
diff_has_been_visited(const diff * d) const1235 diff_context::diff_has_been_visited(const diff* d) const
1236 {
1237   const diff* canonical = d->get_canonical_diff();
1238   ABG_ASSERT(canonical);
1239 
1240   size_t ptr_value = reinterpret_cast<size_t>(canonical);
1241   pointer_map::iterator it = priv_->visited_diff_nodes_.find(ptr_value);
1242   if (it != priv_->visited_diff_nodes_.end())
1243     return reinterpret_cast<diff*>(it->second);
1244   else
1245     return 0;
1246 }
1247 
1248 /// Test if a diff node has been traversed.
1249 ///
1250 /// @param d the diff node to consider.
1251 ///
1252 /// @return the first diff node against which @p d is redundant.
1253 diff_sptr
diff_has_been_visited(const diff_sptr d) const1254 diff_context::diff_has_been_visited(const diff_sptr d) const
1255 {
1256   diff_sptr diff(diff_has_been_visited(d.get()));
1257   return diff;
1258 }
1259 
1260 /// Mark a diff node as traversed by a traversing algorithm.
1261 ///
1262 /// Actually, it's the @ref CanonicalDiff "canonical diff" of this
1263 /// node that is marked as traversed.
1264 ///
1265 /// Subsequent invocations of diff_has_been_visited() on the diff node
1266 /// will yield true.
1267 void
mark_diff_as_visited(const diff * d)1268 diff_context::mark_diff_as_visited(const diff* d)
1269 {
1270   if (diff_has_been_visited(d))
1271     return;
1272 
1273   const diff* canonical = d->get_canonical_diff();
1274   ABG_ASSERT(canonical);
1275 
1276    size_t canonical_ptr_value = reinterpret_cast<size_t>(canonical);
1277    size_t diff_ptr_value = reinterpret_cast<size_t>(d);
1278    priv_->visited_diff_nodes_[canonical_ptr_value] = diff_ptr_value;
1279 }
1280 
1281 /// Unmark all the diff nodes that were marked as being traversed.
1282 void
forget_visited_diffs()1283 diff_context::forget_visited_diffs()
1284 {priv_->visited_diff_nodes_.clear();}
1285 
1286 /// This sets a flag that, if it's true, then during the traversing of
1287 /// a diff nodes tree each node is visited at most once.
1288 ///
1289 /// @param f if true then during the traversing of a diff nodes tree
1290 /// each node is visited at most once.
1291 ///
1292 void
forbid_visiting_a_node_twice(bool f)1293 diff_context::forbid_visiting_a_node_twice(bool f)
1294 {priv_->forbid_visiting_a_node_twice_ = f;}
1295 
1296 /// This function sets a flag os that if @ref
1297 ///  forbid_visiting_a_node_twice() returns true, then each time the
1298 ///  node visitor starts visiting a new interface, it resets the
1299 ///  memory the systems has about already visited node.
1300 ///
1301 ///  @param f the flag to set.
1302 void
forbid_visiting_a_node_twice_per_interface(bool f)1303 diff_context::forbid_visiting_a_node_twice_per_interface(bool f)
1304 {priv_->reset_visited_diffs_for_each_interface_ = f;}
1305 
1306 /// Return a flag that, if true, then during the traversing of a diff
1307 /// nodes tree each node is visited at most once.
1308 ///
1309 /// @return the boolean flag.
1310 bool
visiting_a_node_twice_is_forbidden() const1311 diff_context::visiting_a_node_twice_is_forbidden() const
1312 {return priv_->forbid_visiting_a_node_twice_;}
1313 
1314 /// Return a flag that, if true, then during the traversing of a diff
1315 /// nodes tree each node is visited at most once, while visiting the
1316 /// diff tree underneath a given interface (public function or
1317 /// variable).  Each time a new interface is visited, the nodes
1318 /// visited while visiting previous interfaces can be visited again.
1319 ///
1320 /// @return the boolean flag.
1321 ///
1322 /// @return the boolean flag.
1323 bool
visiting_a_node_twice_is_forbidden_per_interface() const1324 diff_context::visiting_a_node_twice_is_forbidden_per_interface() const
1325 {
1326   return (priv_->forbid_visiting_a_node_twice_
1327 	  && priv_->reset_visited_diffs_for_each_interface_);
1328 }
1329 
1330 /// Getter for the diff tree nodes filters to apply to diff sub-trees.
1331 ///
1332 /// @return the vector of tree filters to apply to diff sub-trees.
1333 const filtering::filters&
diff_filters() const1334 diff_context::diff_filters() const
1335 {return priv_->filters_;}
1336 
1337 /// Setter for the diff filters to apply to a given diff sub-tree.
1338 ///
1339 /// @param f the new diff filter to add to the vector of diff filters
1340 /// to apply to diff sub-trees.
1341 void
add_diff_filter(filtering::filter_base_sptr f)1342 diff_context::add_diff_filter(filtering::filter_base_sptr f)
1343 {priv_->filters_.push_back(f);}
1344 
1345 /// Apply the diff filters to a given diff sub-tree.
1346 ///
1347 /// If the current context is instructed to filter out some categories
1348 /// then this function walks the given sub-tree and categorizes its
1349 /// nodes by using the filters held by the context.
1350 ///
1351 /// @param diff the diff sub-tree to apply the filters to.
1352 void
maybe_apply_filters(diff_sptr diff)1353 diff_context::maybe_apply_filters(diff_sptr diff)
1354 {
1355   if (!diff)
1356     return;
1357 
1358   if (get_allowed_category() == EVERYTHING_CATEGORY)
1359     return;
1360 
1361   if (!diff->has_changes())
1362     return;
1363 
1364   for (filtering::filters::const_iterator i = diff_filters().begin();
1365        i != diff_filters().end();
1366        ++i)
1367     {
1368       filtering::apply_filter(*i, diff);
1369       propagate_categories(diff);
1370     }
1371 
1372  }
1373 
1374 /// Apply the diff filters to the diff nodes of a @ref corpus_diff
1375 /// instance.
1376 ///
1377 /// If the current context is instructed to filter out some categories
1378 /// then this function walks the diff tree and categorizes its nodes
1379 /// by using the filters held by the context.
1380 ///
1381 /// @param diff the corpus diff to apply the filters to.
1382 void
maybe_apply_filters(corpus_diff_sptr diff)1383 diff_context::maybe_apply_filters(corpus_diff_sptr diff)
1384 {
1385 
1386   if (!diff || !diff->has_changes())
1387     return;
1388 
1389   for (filtering::filters::const_iterator i = diff_filters().begin();
1390        i != diff_filters().end();
1391        ++i)
1392     {
1393       filtering::apply_filter(**i, diff);
1394       propagate_categories(diff);
1395     }
1396 }
1397 
1398 /// Getter for the vector of suppressions that specify which diff node
1399 /// reports should be dropped on the floor.
1400 ///
1401 /// @return the set of suppressions.
1402 suppressions_type&
suppressions() const1403 diff_context::suppressions() const
1404 {return priv_->suppressions_;}
1405 
1406 /// Add a new suppression specification that specifies which diff node
1407 /// reports should be dropped on the floor.
1408 ///
1409 /// @param suppr the new suppression specification to add to the
1410 /// existing set of suppressions specifications of the diff context.
1411 void
add_suppression(const suppression_sptr suppr)1412 diff_context::add_suppression(const suppression_sptr suppr)
1413 {priv_->suppressions_.push_back(suppr);}
1414 
1415 /// Add new suppression specifications that specify which diff node
1416 /// reports should be dropped on the floor.
1417 ///
1418 /// @param supprs the new suppression specifications to add to the
1419 /// existing set of suppression specifications of the diff context.
1420 void
add_suppressions(const suppressions_type & supprs)1421 diff_context::add_suppressions(const suppressions_type& supprs)
1422 {
1423   priv_->suppressions_.insert(priv_->suppressions_.end(),
1424 			      supprs.begin(), supprs.end());
1425 }
1426 
1427 /// Set the flag that indicates if the diff using this context should
1428 /// show only leaf changes or not.
1429 ///
1430 /// @param f the new value of the flag that indicates if the diff
1431 /// using this context should show only leaf changes or not.
1432 void
show_leaf_changes_only(bool f)1433 diff_context::show_leaf_changes_only(bool f)
1434 {
1435   // This function can be called only if the reporter hasn't yet been
1436   // created.  Once it's been created, we are supposed to live with
1437   // it.
1438   ABG_ASSERT(priv_->reporter_ == 0);
1439   priv_->leaf_changes_only_ = f;
1440 }
1441 
1442 /// Get the flag that indicates if the diff using this context should
1443 /// show only leaf changes or not.
1444 ///
1445 /// @return the value of the flag that indicates if the diff using
1446 /// this context should show only leaf changes or not.
1447 bool
show_leaf_changes_only() const1448 diff_context::show_leaf_changes_only() const
1449 {return priv_->leaf_changes_only_;}
1450 
1451 /// Get the flag that indicates if the diff reports using this context
1452 /// should show sizes and offsets in an hexadecimal base or not.  If
1453 /// not, then they are to be shown in a decimal base.
1454 ///
1455 /// @return true iff sizes and offsets are to be shown in an
1456 /// hexadecimal base.
1457 bool
show_hex_values() const1458 diff_context::show_hex_values() const
1459 {return priv_->hex_values_;}
1460 
1461 /// Set the flag that indicates if diff reports using this context
1462 /// should show sizes and offsets in an hexadecimal base or not.  If
1463 /// not, then they are to be shown in a decimal base.
1464 ///
1465 /// @param f if true then sizes and offsets are to be shown in an
1466 /// hexadecimal base.
1467 void
show_hex_values(bool f)1468 diff_context::show_hex_values(bool f)
1469 {priv_->hex_values_ = f;}
1470 
1471 /// Get the flag that indicates if diff reports using this context
1472 /// should show sizes and offsets in bits, rather than bytes.
1473 ///
1474 /// @return true iff sizes and offsets are to be shown in bits.
1475 /// Otherwise they are to be shown in bytes.
1476 bool
show_offsets_sizes_in_bits() const1477 diff_context::show_offsets_sizes_in_bits() const
1478 {return priv_->show_offsets_sizes_in_bits_;}
1479 
1480 /// Set the flag that indicates if diff reports using this context
1481 /// should show sizes and offsets in bits, rather than bytes.
1482 ///
1483 /// @param f if true then sizes and offsets are to be shown in bits.
1484 /// Otherwise they are to be shown in bytes.
1485 void
show_offsets_sizes_in_bits(bool f)1486 diff_context::show_offsets_sizes_in_bits(bool f)
1487 {priv_->show_offsets_sizes_in_bits_ = f;}
1488 
1489 /// Set a flag saying if offset changes should be reported in a
1490 /// relative way.  That is, if the report should say how of many bits
1491 /// a class/struct data member did move.
1492 ///
1493 /// @param f the new boolean value of the flag.
1494 void
show_relative_offset_changes(bool f)1495 diff_context::show_relative_offset_changes(bool f)
1496 {priv_->show_relative_offset_changes_ = f;}
1497 
1498 /// Get the flag saying if offset changes should be reported in a
1499 /// relative way.  That is, if the report should say how of many bits
1500 /// a class/struct data member did move.
1501 ///
1502 /// @return the boolean value of the flag.
1503 bool
show_relative_offset_changes(void)1504 diff_context::show_relative_offset_changes(void)
1505 {return priv_->show_relative_offset_changes_;}
1506 
1507 /// Set a flag saying if the comparison module should only show the
1508 /// diff stats.
1509 ///
1510 /// @param f the flag to set.
1511 void
show_stats_only(bool f)1512 diff_context::show_stats_only(bool f)
1513 {priv_->show_stats_only_ = f;}
1514 
1515 /// Test if the comparison module should only show the diff stats.
1516 ///
1517 /// @return true if the comparison module should only show the diff
1518 /// stats, false otherwise.
1519 bool
show_stats_only() const1520 diff_context::show_stats_only() const
1521 {return priv_->show_stats_only_;}
1522 
1523 /// Setter for the property that says if the comparison module should
1524 /// show the soname changes in its report.
1525 ///
1526 /// @param f the new value of the property.
1527 void
show_soname_change(bool f)1528 diff_context::show_soname_change(bool f)
1529 {priv_->show_soname_change_ = f;}
1530 
1531 /// Getter for the property that says if the comparison module should
1532 /// show the soname changes in its report.
1533 ///
1534 /// @return the value of the property.
1535 bool
show_soname_change() const1536 diff_context::show_soname_change() const
1537 {return priv_->show_soname_change_;}
1538 
1539 /// Setter for the property that says if the comparison module should
1540 /// show the architecture changes in its report.
1541 ///
1542 /// @param f the new value of the property.
1543 void
show_architecture_change(bool f)1544 diff_context::show_architecture_change(bool f)
1545 {priv_->show_architecture_change_ = f;}
1546 
1547 /// Getter for the property that says if the comparison module should
1548 /// show the architecture changes in its report.
1549 ///
1550 /// @return the value of the property.
1551 bool
show_architecture_change() const1552 diff_context::show_architecture_change() const
1553 {return priv_->show_architecture_change_;}
1554 
1555 /// Set a flag saying to show the deleted functions.
1556 ///
1557 /// @param f true to show deleted functions.
1558 void
show_deleted_fns(bool f)1559 diff_context::show_deleted_fns(bool f)
1560 {priv_->show_deleted_fns_ = f;}
1561 
1562 /// @return true if we want to show the deleted functions, false
1563 /// otherwise.
1564 bool
show_deleted_fns() const1565 diff_context::show_deleted_fns() const
1566 {return priv_->show_deleted_fns_;}
1567 
1568 /// Set a flag saying to show the changed functions.
1569 ///
1570 /// @param f true to show the changed functions.
1571 void
show_changed_fns(bool f)1572 diff_context::show_changed_fns(bool f)
1573 {priv_->show_changed_fns_ = f;}
1574 
1575 /// @return true if we want to show the changed functions, false otherwise.
1576 bool
show_changed_fns() const1577 diff_context::show_changed_fns() const
1578 {return priv_->show_changed_fns_;}
1579 
1580 /// Set a flag saying to show the added functions.
1581 ///
1582 /// @param f true to show the added functions.
1583 void
show_added_fns(bool f)1584 diff_context::show_added_fns(bool f)
1585 {priv_->show_added_fns_ = f;}
1586 
1587 /// @return true if we want to show the added functions, false
1588 /// otherwise.
1589 bool
show_added_fns() const1590 diff_context::show_added_fns() const
1591 {return priv_->show_added_fns_;}
1592 
1593 /// Set a flag saying to show the deleted variables.
1594 ///
1595 /// @param f true to show the deleted variables.
1596 void
show_deleted_vars(bool f)1597 diff_context::show_deleted_vars(bool f)
1598 {priv_->show_deleted_vars_ = f;}
1599 
1600 /// @return true if we want to show the deleted variables, false
1601 /// otherwise.
1602 bool
show_deleted_vars() const1603 diff_context::show_deleted_vars() const
1604 {return priv_->show_deleted_vars_;}
1605 
1606 /// Set a flag saying to show the changed variables.
1607 ///
1608 /// @param f true to show the changed variables.
1609 void
show_changed_vars(bool f)1610 diff_context::show_changed_vars(bool f)
1611 {priv_->show_changed_vars_ = f;}
1612 
1613 /// @return true if we want to show the changed variables, false otherwise.
1614 bool
show_changed_vars() const1615 diff_context::show_changed_vars() const
1616 {return priv_->show_changed_vars_;}
1617 
1618 /// Set a flag saying to show the added variables.
1619 ///
1620 /// @param f true to show the added variables.
1621 void
show_added_vars(bool f)1622 diff_context::show_added_vars(bool f)
1623 {priv_->show_added_vars_ = f;}
1624 
1625 /// @return true if we want to show the added variables, false
1626 /// otherwise.
1627 bool
show_added_vars() const1628 diff_context::show_added_vars() const
1629 {return priv_->show_added_vars_;}
1630 
1631 bool
show_linkage_names() const1632 diff_context::show_linkage_names() const
1633 {return priv_->show_linkage_names_;}
1634 
1635 void
show_linkage_names(bool f)1636 diff_context::show_linkage_names(bool f)
1637 {priv_->show_linkage_names_= f;}
1638 
1639 /// Set a flag saying to show location information.
1640 ///
1641 /// @param f true to show location information.
1642 void
show_locs(bool f)1643 diff_context::show_locs(bool f)
1644 {priv_->show_locs_= f;}
1645 
1646 /// @return true if we want to show location information, false
1647 /// otherwise.
1648 bool
show_locs() const1649 diff_context::show_locs() const
1650 {return priv_->show_locs_;}
1651 
1652 /// A getter for the flag that says if we should report about
1653 /// functions or variables diff nodes that have *exclusively*
1654 /// redundant diff tree children nodes.
1655 ///
1656 /// @return the flag.
1657 bool
show_redundant_changes() const1658 diff_context::show_redundant_changes() const
1659 {return priv_->show_redundant_changes_;}
1660 
1661 /// A setter for the flag that says if we should report about
1662 /// functions or variables diff nodes that have *exclusively*
1663 /// redundant diff tree children nodes.
1664 ///
1665 /// @param f the flag to set.
1666 void
show_redundant_changes(bool f)1667 diff_context::show_redundant_changes(bool f)
1668 {priv_->show_redundant_changes_ = f;}
1669 
1670 /// Getter for the flag that indicates if symbols not referenced by
1671 /// any debug info are to be compared and reported about.
1672 ///
1673 /// @return the boolean flag.
1674 bool
show_symbols_unreferenced_by_debug_info() const1675 diff_context::show_symbols_unreferenced_by_debug_info() const
1676 {return priv_->show_syms_unreferenced_by_di_;}
1677 
1678 /// Setter for the flag that indicates if symbols not referenced by
1679 /// any debug info are to be compared and reported about.
1680 ///
1681 /// @param f the new flag to set.
1682 void
show_symbols_unreferenced_by_debug_info(bool f)1683 diff_context::show_symbols_unreferenced_by_debug_info(bool f)
1684 {priv_->show_syms_unreferenced_by_di_ = f;}
1685 
1686 /// Getter for the flag that indicates if symbols not referenced by
1687 /// any debug info and that got added are to be reported about.
1688 ///
1689 /// @return true iff symbols not referenced by any debug info and that
1690 /// got added are to be reported about.
1691 bool
show_added_symbols_unreferenced_by_debug_info() const1692 diff_context::show_added_symbols_unreferenced_by_debug_info() const
1693 {return priv_->show_added_syms_unreferenced_by_di_;}
1694 
1695 /// Setter for the flag that indicates if symbols not referenced by
1696 /// any debug info and that got added are to be reported about.
1697 ///
1698 /// @param f the new flag that says if symbols not referenced by any
1699 /// debug info and that got added are to be reported about.
1700 void
show_added_symbols_unreferenced_by_debug_info(bool f)1701 diff_context::show_added_symbols_unreferenced_by_debug_info(bool f)
1702 {priv_->show_added_syms_unreferenced_by_di_ = f;}
1703 
1704 /// Setter for the flag that indicates if changes on types unreachable
1705 /// from global functions and variables are to be reported.
1706 ///
1707 /// @param f if true, then changes on types unreachable from global
1708 /// functions and variables are to be reported.
1709 void
show_unreachable_types(bool f)1710 diff_context::show_unreachable_types(bool f)
1711 {priv_->show_unreachable_types_ = f;}
1712 
1713 /// Getter for the flag that indicates if changes on types unreachable
1714 /// from global functions and variables are to be reported.
1715 ///
1716 /// @return true iff changes on types unreachable from global
1717 /// functions and variables are to be reported.
1718 bool
show_unreachable_types()1719 diff_context::show_unreachable_types()
1720 {return priv_->show_unreachable_types_;}
1721 
1722 /// Getter of the flag that indicates if the leaf reporter should
1723 /// display a summary of the interfaces impacted by a given leaf
1724 /// change or not.
1725 ///
1726 /// @return the flag that indicates if the leaf reporter should
1727 /// display a summary of the interfaces impacted by a given leaf
1728 /// change or not.
1729 bool
show_impacted_interfaces() const1730 diff_context::show_impacted_interfaces() const
1731 {return priv_->show_impacted_interfaces_;}
1732 
1733 /// Setter of the flag that indicates if the leaf reporter should
1734 /// display a summary of the interfaces impacted by a given leaf
1735 /// change or not.
1736 ///
1737 /// @param f the new value of the flag that indicates if the leaf
1738 /// reporter should display a summary of the interfaces impacted by a
1739 /// given leaf change or not.
1740 void
show_impacted_interfaces(bool f)1741 diff_context::show_impacted_interfaces(bool f)
1742 {priv_->show_impacted_interfaces_ = f;}
1743 
1744 /// Setter for the default output stream used by code of the
1745 /// comparison engine.  By default the default output stream is a NULL
1746 /// pointer.
1747 ///
1748 /// @param o a pointer to the default output stream.
1749 void
default_output_stream(ostream * o)1750 diff_context::default_output_stream(ostream* o)
1751 {priv_->default_output_stream_ = o;}
1752 
1753 /// Getter for the default output stream used by code of the
1754 /// comparison engine.  By default the default output stream is a NULL
1755 /// pointer.
1756 ///
1757 /// @return a pointer to the default output stream.
1758 ostream*
default_output_stream()1759 diff_context::default_output_stream()
1760 {return priv_->default_output_stream_;}
1761 
1762 /// Setter for the errror output stream used by code of the comparison
1763 /// engine.  By default the error output stream is a NULL pointer.
1764 ///
1765 /// @param o a pointer to the error output stream.
1766 void
error_output_stream(ostream * o)1767 diff_context::error_output_stream(ostream* o)
1768 {priv_->error_output_stream_ = o;}
1769 
1770 /// Getter for the errror output stream used by code of the comparison
1771 /// engine.  By default the error output stream is a NULL pointer.
1772 ///
1773 /// @return a pointer to the error output stream.
1774 ostream*
error_output_stream() const1775 diff_context::error_output_stream() const
1776 {return priv_->error_output_stream_;}
1777 
1778 /// Test if the comparison engine should dump the diff tree for the
1779 /// changed functions and variables it has.
1780 ///
1781 /// @return true if after the comparison, the engine should dump the
1782 /// diff tree for the changed functions and variables it has.
1783 bool
dump_diff_tree() const1784 diff_context::dump_diff_tree() const
1785 {return priv_->dump_diff_tree_;}
1786 
1787 /// Set if the comparison engine should dump the diff tree for the
1788 /// changed functions and variables it has.
1789 ///
1790 /// @param f true if after the comparison, the engine should dump the
1791 /// diff tree for the changed functions and variables it has.
1792 void
dump_diff_tree(bool f)1793 diff_context::dump_diff_tree(bool f)
1794 {priv_->dump_diff_tree_ = f;}
1795 
1796 /// Emit a textual representation of a diff tree to the error output
1797 /// stream of the current context, for debugging purposes.
1798 ///
1799 /// @param d the diff tree to serialize to the error output associated
1800 /// to the current instance of @ref diff_context.
1801 void
do_dump_diff_tree(const diff_sptr d) const1802 diff_context::do_dump_diff_tree(const diff_sptr d) const
1803 {
1804   if (error_output_stream())
1805     print_diff_tree(d, *error_output_stream());
1806 }
1807 
1808 /// Emit a textual representation of a @ref corpus_diff tree to the error
1809 /// output stream of the current context, for debugging purposes.
1810 ///
1811 /// @param d the @ref corpus_diff tree to serialize to the error
1812 /// output associated to the current instance of @ref diff_context.
1813 void
do_dump_diff_tree(const corpus_diff_sptr d) const1814 diff_context::do_dump_diff_tree(const corpus_diff_sptr d) const
1815 {
1816   if (error_output_stream())
1817     print_diff_tree(d, *error_output_stream());
1818 }
1819 // </diff_context stuff>
1820 
1821 // <diff stuff>
1822 
1823 /// Constructor for the @ref diff type.
1824 ///
1825 /// This constructs a diff between two subjects that are actually
1826 /// declarations; the first and the second one.
1827 ///
1828 /// @param first_subject the first decl (subject) of the diff.
1829 ///
1830 /// @param second_subject the second decl (subject) of the diff.
diff(type_or_decl_base_sptr first_subject,type_or_decl_base_sptr second_subject)1831 diff::diff(type_or_decl_base_sptr first_subject,
1832 	   type_or_decl_base_sptr second_subject)
1833   : priv_(new priv(first_subject, second_subject,
1834 		   diff_context_sptr(),
1835 		   NO_CHANGE_CATEGORY,
1836 		   /*reported_once=*/false,
1837 		   /*currently_reporting=*/false))
1838 {}
1839 
1840 /// Constructor for the @ref diff type.
1841 ///
1842 /// This constructs a diff between two subjects that are actually
1843 /// declarations; the first and the second one.
1844 ///
1845 /// @param first_subject the first decl (subject) of the diff.
1846 ///
1847 /// @param second_subject the second decl (subject) of the diff.
1848 ///
1849 /// @param ctxt the context of the diff.  Note that this context
1850 /// object must stay alive during the entire life time of the current
1851 /// instance of @ref diff.  Otherwise, memory corruption issues occur.
diff(type_or_decl_base_sptr first_subject,type_or_decl_base_sptr second_subject,diff_context_sptr ctxt)1852 diff::diff(type_or_decl_base_sptr	first_subject,
1853 	   type_or_decl_base_sptr	second_subject,
1854 	   diff_context_sptr	ctxt)
1855   : priv_(new priv(first_subject, second_subject,
1856 		   ctxt, NO_CHANGE_CATEGORY,
1857 		   /*reported_once=*/false,
1858 		   /*currently_reporting=*/false))
1859 {}
1860 
1861 /// Flag a given diff node as being traversed.
1862 ///
1863 /// For certain diff nodes like @ref class_diff, it's important to
1864 /// avoid traversing the node again while it's already being
1865 /// traversed; otherwise this leads to infinite loops.  So the
1866 /// diff::begin_traversing() and diff::end_traversing() methods flag a
1867 /// given node as being traversed (or not), so that
1868 /// diff::is_traversing() can tell if the node is being traversed.
1869 ///
1870 /// Note that traversing a node means visiting it *and* visiting its
1871 /// children nodes.
1872 ///
1873 /// The canonical node is marked as being traversed too.
1874 ///
1875 /// These functions are called by the traversing code.
1876 void
begin_traversing()1877 diff::begin_traversing()
1878 {
1879   ABG_ASSERT(!is_traversing());
1880   if (priv_->canonical_diff_)
1881     priv_->canonical_diff_->priv_->traversing_ = true;
1882   priv_->traversing_ = true;
1883 }
1884 
1885 /// Tell if a given node is being traversed or not.
1886 ///
1887 /// Note that traversing a node means visiting it *and* visiting its
1888 /// children nodes.
1889 ///
1890 /// It's the canonical node which is looked at, actually.
1891 ///
1892 /// Please read the comments for the diff::begin_traversing() for mode
1893 /// context.
1894 ///
1895 /// @return true if the current instance of @diff is being traversed.
1896 bool
is_traversing() const1897 diff::is_traversing() const
1898 {
1899   if (priv_->canonical_diff_)
1900     return priv_->canonical_diff_->priv_->traversing_;
1901   return priv_->traversing_;
1902 }
1903 
1904 /// Flag a given diff node as not being traversed anymore.
1905 ///
1906 /// Note that traversing a node means visiting it *and* visiting its
1907 /// children nodes.
1908 ///
1909 /// Please read the comments of the function diff::begin_traversing()
1910 /// for mode context.
1911 void
end_traversing()1912 diff::end_traversing()
1913 {
1914   ABG_ASSERT(is_traversing());
1915   if (priv_->canonical_diff_)
1916     priv_->canonical_diff_->priv_->traversing_ = false;
1917   priv_->traversing_ = false;
1918 }
1919 
1920 /// Finish the insertion of a diff tree node into the diff graph.
1921 ///
1922 /// This function might be called several times.  It must perform the
1923 /// insertion only once.
1924 ///
1925 /// For instance, certain kinds of diff tree node have specific
1926 /// children nodes that are populated after the constructor of the
1927 /// diff tree node has been called.  In that case, calling overloads
1928 /// of this method ensures that these children nodes are properly
1929 /// gathered and setup.
1930 void
finish_diff_type()1931 diff::finish_diff_type()
1932 {
1933   if (diff::priv_->finished_)
1934     return;
1935   chain_into_hierarchy();
1936   diff::priv_->finished_ = true;
1937 }
1938 
1939 /// Getter of the first subject of the diff.
1940 ///
1941 /// @return the first subject of the diff.
1942 type_or_decl_base_sptr
first_subject() const1943 diff::first_subject() const
1944 {return dynamic_pointer_cast<type_or_decl_base>(priv_->first_subject_);}
1945 
1946 /// Getter of the second subject of the diff.
1947 ///
1948 /// @return the second subject of the diff.
1949 type_or_decl_base_sptr
second_subject() const1950 diff::second_subject() const
1951 {return dynamic_pointer_cast<type_or_decl_base>(priv_->second_subject_);}
1952 
1953 /// Getter for the children nodes of the current @ref diff node.
1954 ///
1955 /// @return a vector of the children nodes.
1956 const vector<diff*>&
children_nodes() const1957 diff::children_nodes() const
1958 {return priv_->children_;}
1959 
1960 /// Getter for the parent node of the current @ref diff node.
1961 ///
1962 /// @return the parent node of the current @ref diff node.
1963 const diff*
parent_node() const1964 diff::parent_node() const
1965 {return priv_->parent_;}
1966 
1967 /// Getter for the canonical diff of the current instance of @ref
1968 /// diff.
1969 ///
1970 /// Note that the canonical diff node for the current instanc eof diff
1971 /// node must have been set by invoking
1972 /// class_diff::initialize_canonical_diff() on the current instance of
1973 /// diff node.
1974 ///
1975 /// @return the canonical diff node or null if none was set.
1976 diff*
get_canonical_diff() const1977 diff::get_canonical_diff() const
1978 {return priv_->canonical_diff_;}
1979 
1980 /// Setter for the canonical diff of the current instance of @ref
1981 /// diff.
1982 ///
1983 /// @param d the new canonical node to set.
1984 void
set_canonical_diff(diff * d)1985 diff::set_canonical_diff(diff * d)
1986 {priv_->canonical_diff_ = d;}
1987 
1988 /// Add a new child node to the vector of children nodes for the
1989 /// current @ref diff node.
1990 ///
1991 /// @param d the new child node to add to the children nodes.
1992 void
append_child_node(diff_sptr d)1993 diff::append_child_node(diff_sptr d)
1994 {
1995   ABG_ASSERT(d);
1996 
1997   // Ensure 'd' is kept alive for the life time of the context of this
1998   // diff.
1999   context()->keep_diff_alive(d);
2000 
2001   // Add the underlying pointer of 'd' to the vector of children.
2002   // Note that this vector holds no reference to 'd'. This is to avoid
2003   // reference cycles.  The reference to 'd' is held by the context of
2004   // this diff, thanks to the call to context()->keep_diff_alive(d)
2005   // above.
2006   priv_->children_.push_back(d.get());
2007 
2008   d->priv_->parent_ = this;
2009 }
2010 
2011 /// Getter of the context of the current diff.
2012 ///
2013 /// @return the context of the current diff.
2014 const diff_context_sptr
context() const2015 diff::context() const
2016 {return priv_->get_context();}
2017 
2018 /// Setter of the context of the current diff.
2019 ///
2020 /// @param c the new context to set.
2021 void
context(diff_context_sptr c)2022 diff::context(diff_context_sptr c)
2023 {priv_->ctxt_ = c;}
2024 
2025 /// Tests if we are currently in the middle of emitting a report for
2026 /// this diff.
2027 ///
2028 /// @return true if we are currently emitting a report for the
2029 /// current diff, false otherwise.
2030 bool
currently_reporting() const2031 diff::currently_reporting() const
2032 {
2033   if (priv_->canonical_diff_)
2034     return priv_->canonical_diff_->priv_->currently_reporting_;
2035   return priv_->currently_reporting_;
2036 }
2037 
2038 /// Sets a flag saying if we are currently in the middle of emitting
2039 /// a report for this diff.
2040 ///
2041 /// @param f true if we are currently emitting a report for the
2042 /// current diff, false otherwise.
2043 void
currently_reporting(bool f) const2044 diff::currently_reporting(bool f) const
2045 {
2046   if (priv_->canonical_diff_)
2047     priv_->canonical_diff_->priv_->currently_reporting_ = f;
2048   priv_->currently_reporting_ = f;
2049 }
2050 
2051 /// Tests if a report has already been emitted for the current diff.
2052 ///
2053 /// @return true if a report has already been emitted for the
2054 /// current diff, false otherwise.
2055 bool
reported_once() const2056 diff::reported_once() const
2057 {
2058   ABG_ASSERT(priv_->canonical_diff_);
2059   return priv_->canonical_diff_->priv_->reported_once_;
2060 }
2061 
2062 /// The generic traversing code that walks a given diff sub-tree.
2063 ///
2064 /// Note that there is a difference between traversing a diff node and
2065 /// visiting it.  Basically, traversing a diff node means visiting it
2066 /// and visiting its children nodes too.  So one can visit a node
2067 /// without traversing it.  But traversing a node without visiting it
2068 /// is not possible.
2069 ///
2070 /// Note that the insertion of the "generic view" of the diff node
2071 /// into the graph being traversed is done "on the fly".  The
2072 /// insertion of the "typed view" of the diff node into the graph is
2073 /// done implicitely.  To learn more about the generic and typed view
2074 /// of the diff node, please read the introductory comments of the
2075 /// @ref diff class.
2076 ///
2077 /// Note that by default this traversing code visits a given class of
2078 /// equivalence of a diff node only once.  This behaviour can been
2079 /// changed by calling
2080 /// diff_context::visiting_a_node_twice_is_forbidden(), but this is
2081 /// very risky as it might create endless loops while visiting a diff
2082 /// tree graph that has changes that refer to themselves; that is,
2083 /// diff tree graphs with cycles.
2084 ///
2085 /// When a diff node is encountered, the
2086 /// diff_node_visitor::visit_begin() method is invoked on the diff
2087 /// node first.
2088 ///
2089 /// If the diff node has already been visited, then
2090 /// node_visitor::visit_end() is called on it and the node traversing
2091 /// is done; the children of the diff node are not visited in this
2092 /// case.
2093 ///
2094 /// If the diff node has *NOT* been visited yet, then the
2095 /// diff_node_visitor::visit() method is invoked with it's 'pre'
2096 /// argument set to true.  Then if the diff_node_visitor::visit()
2097 /// returns true, then the children nodes of the diff node are
2098 /// visited.  Otherwise, no children nodes of the diff node is
2099 /// visited and the diff_node_visitor::visit_end() is called.
2100 
2101 /// After the children nodes are visited (and only if they are
2102 /// visited) the diff_node_visitor::visit() method is invoked with
2103 /// it's 'pre' argument set to false.  And then the
2104 /// diff_node_visitor::visit_end() is called.
2105 ///
2106 /// @param v the entity that visits each node of the diff sub-tree.
2107 ///
2108 /// @return true to tell the caller that all of the sub-tree could be
2109 /// walked.  This instructs the caller to keep walking the rest of the
2110 /// tree.  Return false otherwise.
2111 bool
traverse(diff_node_visitor & v)2112 diff::traverse(diff_node_visitor& v)
2113 {
2114   // Insert the "generic view" of the diff node into its graph.
2115   finish_diff_type();
2116 
2117   v.visit_begin(this);
2118 
2119   bool already_visited = false;
2120   if (context()->visiting_a_node_twice_is_forbidden()
2121       && context()->diff_has_been_visited(this))
2122     already_visited = true;
2123 
2124   bool mark_visited_nodes_as_traversed =
2125     !(v.get_visiting_kind() & DO_NOT_MARK_VISITED_NODES_AS_VISITED);
2126 
2127   if (!already_visited && !v.visit(this, /*pre=*/true))
2128     {
2129       v.visit_end(this);
2130       if (mark_visited_nodes_as_traversed)
2131 	context()->mark_diff_as_visited(this);
2132       return false;
2133     }
2134 
2135   if (!(v.get_visiting_kind() & SKIP_CHILDREN_VISITING_KIND)
2136       && !is_traversing()
2137       && !already_visited)
2138     {
2139       begin_traversing();
2140       for (vector<diff*>::const_iterator i = children_nodes().begin();
2141 	   i != children_nodes().end();
2142 	   ++i)
2143 	{
2144 	  if (!(*i)->traverse(v))
2145 	    {
2146 	      v.visit_end(this);
2147 	      if (mark_visited_nodes_as_traversed)
2148 		context()->mark_diff_as_visited(this);
2149 	      end_traversing();
2150 	      return false;
2151 	    }
2152 	}
2153       end_traversing();
2154     }
2155 
2156   if (!v.visit(this, /*pref=*/false))
2157     {
2158       v.visit_end(this);
2159       if (mark_visited_nodes_as_traversed)
2160 	context()->mark_diff_as_visited(this);
2161       return false;
2162     }
2163 
2164   v.visit_end(this);
2165   if (!already_visited && mark_visited_nodes_as_traversed)
2166     context()->mark_diff_as_visited(this);
2167 
2168   return true;
2169 }
2170 
2171 /// Sets a flag saying if a report has already been emitted for the
2172 /// current diff.
2173 ///
2174 /// @param f true if a report has already been emitted for the
2175 /// current diff, false otherwise.
2176 void
reported_once(bool f) const2177 diff::reported_once(bool f) const
2178 {
2179   ABG_ASSERT(priv_->canonical_diff_);
2180   priv_->canonical_diff_->priv_->reported_once_ = f;
2181   priv_->reported_once_ = f;
2182 }
2183 
2184 /// Getter for the local category of the current diff tree node.
2185 ///
2186 /// The local category represents the set of categories of a diff
2187 /// node, not taking in account the categories inherited from its
2188 /// children nodes.
2189 ///
2190 /// @return the local category of the current diff tree node.
2191 diff_category
get_local_category() const2192 diff::get_local_category() const
2193 {return priv_->local_category_;}
2194 
2195 /// Getter of the category of the class of equivalence of the current
2196 /// diff tree node.
2197 ///
2198 /// That is, if the current diff tree node has a canonical node,
2199 /// return the category of that canonical node.  Otherwise, return the
2200 /// category of the current node.
2201 ///
2202 /// @return the category of the class of equivalence of the current
2203 /// tree node.
2204 diff_category
get_class_of_equiv_category() const2205 diff::get_class_of_equiv_category() const
2206 {
2207   diff* canonical = get_canonical_diff();
2208   return canonical ? canonical->get_category() : get_category();
2209 }
2210 
2211 /// Getter for the category of the current diff tree node.
2212 ///
2213 /// This category represents the union of the local category and the
2214 /// categories inherited from the children diff nodes.
2215 ///
2216 /// @return the category of the current diff tree node.
2217 diff_category
get_category() const2218 diff::get_category() const
2219 {return priv_->category_;}
2220 
2221 /// Adds the current diff tree node to an additional set of
2222 /// categories.  Note that the categories include thoses inherited
2223 /// from the children nodes of this diff node.
2224 ///
2225 /// @param c a bit-map representing the set of categories to add the
2226 /// current diff tree node to.
2227 ///
2228 /// @return the resulting bit-map representing the categories this
2229 /// current diff tree node belongs to, including those inherited from
2230 /// its children nodes.
2231 diff_category
add_to_category(diff_category c)2232 diff::add_to_category(diff_category c)
2233 {
2234   priv_->category_ = priv_->category_ | c;
2235   return priv_->category_;
2236 }
2237 
2238 /// Adds the current diff tree node to the categories resulting from
2239 /// the local changes of the current diff node.
2240 ///
2241 /// @param c a bit-map representing the set of categories to add the
2242 /// current diff tree node to.
2243 ///
2244 /// @return the resulting bit-map representing the categories this
2245 /// current diff tree node belongs to.
2246 diff_category
add_to_local_category(diff_category c)2247 diff::add_to_local_category(diff_category c)
2248 {
2249   priv_->local_category_ = priv_->local_category_ | c;
2250   return priv_->local_category_;
2251 }
2252 
2253 /// Adds the current diff tree node to the categories resulting from
2254 /// the local and inherited changes of the current diff node.
2255 ///
2256 /// @param c a bit-map representing the set of categories to add the
2257 /// current diff tree node to.
2258 void
add_to_local_and_inherited_categories(diff_category c)2259 diff::add_to_local_and_inherited_categories(diff_category c)
2260 {
2261   add_to_local_category(c);
2262   add_to_category(c);
2263 }
2264 
2265 /// Remove the current diff tree node from an a existing sef of
2266 /// categories.  The categories include those inherited from the
2267 /// children nodes of the current diff node.
2268 ///
2269 /// @param c a bit-map representing the set of categories to add the
2270 /// current diff tree node to.
2271 ///
2272 /// @return the resulting bit-map representing the categories this
2273 /// current diff tree onde belongs to, including the categories
2274 /// inherited from the children nodes of the current diff node.
2275 diff_category
remove_from_category(diff_category c)2276 diff::remove_from_category(diff_category c)
2277 {
2278   priv_->category_ = priv_->category_ & ~c;
2279   return priv_->category_;
2280 }
2281 
2282 /// Remove the current diff tree node from the categories resulting
2283 /// from the local changes.
2284 ///
2285 /// @param c a bit-map representing the set of categories to add the
2286 /// current diff tree node to.
2287 ///
2288 /// @return the resulting bit-map representing the categories this
2289 /// current diff tree onde belongs to.
2290 diff_category
remove_from_local_category(diff_category c)2291 diff::remove_from_local_category(diff_category c)
2292 {
2293   priv_->local_category_ = priv_->local_category_ & ~c;
2294   return priv_->local_category_;
2295 }
2296 
2297 /// Set the category of the current @ref diff node.  This category
2298 /// includes the categories inherited from the children nodes of the
2299 /// current diff node.
2300 ///
2301 /// @param c the new category for the current diff node.
2302 void
set_category(diff_category c)2303 diff::set_category(diff_category c)
2304 {priv_->category_ = c;}
2305 
2306 /// Set the local category of the current @ref diff node.
2307 ///
2308 /// @param c the new category for the current diff node.
2309 void
set_local_category(diff_category c)2310 diff::set_local_category(diff_category c)
2311 {priv_->local_category_ = c;}
2312 
2313 /// Test if this diff tree node is to be filtered out for reporting
2314 /// purposes.
2315 ///
2316 /// The function tests if the categories of the diff tree node are
2317 /// "forbidden" by the context or not.
2318 ///
2319 /// @return true iff the current diff node should NOT be reported.
2320 bool
is_filtered_out() const2321 diff::is_filtered_out() const
2322 {
2323   if (diff * canonical = get_canonical_diff())
2324     if (canonical->get_category() & SUPPRESSED_CATEGORY
2325 	|| canonical->get_category() & PRIVATE_TYPE_CATEGORY)
2326       // The canonical type was suppressed either by a user-provided
2327       // suppression specification or by a "private-type" suppression
2328       // specification..  This means all the class of equivalence of
2329       // that canonical type was suppressed.  So this node should be
2330       // suppressed too.
2331       return true;
2332   return priv_->is_filtered_out(get_category());
2333 }
2334 
2335 /// Test if this diff tree node is to be filtered out for reporting
2336 /// purposes, but by considering only the categories that were *NOT*
2337 /// inherited from its children nodes.
2338 ///
2339 /// The function tests if the local categories of the diff tree node
2340 /// are "forbidden" by the context or not.
2341 ///
2342 /// @return true iff the current diff node should NOT be reported,
2343 /// with respect to its local categories.
2344 bool
is_filtered_out_wrt_non_inherited_categories() const2345 diff::is_filtered_out_wrt_non_inherited_categories() const
2346 {return priv_->is_filtered_out(get_local_category());}
2347 
2348 /// Test if the current diff node has been suppressed by a
2349 /// user-provided suppression specification.
2350 ///
2351 /// @return true if the current diff node has been suppressed by a
2352 /// user-provided suppression list.
2353 bool
is_suppressed() const2354 diff::is_suppressed() const
2355 {
2356   bool is_private = false;
2357   return is_suppressed(is_private);
2358 }
2359 
2360 /// Test if the current diff node has been suppressed by a
2361 /// user-provided suppression specification or by an auto-generated
2362 /// "private type" suppression specification.
2363 ///
2364 /// Note that private type suppressions are auto-generated from the
2365 /// path to where public headers are, as given by the user.
2366 ///
2367 /// @param is_private_type out parameter if the current diff node was
2368 /// suppressed because it's a private type then this parameter is set
2369 /// to true.
2370 ///
2371 /// @return true if the current diff node has been suppressed by a
2372 /// user-provided suppression list.
2373 bool
is_suppressed(bool & is_private_type) const2374 diff::is_suppressed(bool &is_private_type) const
2375 {
2376   const suppressions_type& suppressions = context()->suppressions();
2377   for (suppressions_type::const_iterator i = suppressions.begin();
2378        i != suppressions.end();
2379        ++i)
2380     {
2381       if ((*i)->suppresses_diff(this))
2382 	{
2383 	  if (is_private_type_suppr_spec(*i))
2384 	    is_private_type = true;
2385 	  return true;
2386 	}
2387     }
2388   return false;
2389 }
2390 
2391 /// Test if this diff tree node should be reported.
2392 ///
2393 /// @return true iff the current node should be reported.
2394 bool
to_be_reported() const2395 diff::to_be_reported() const
2396 {
2397   if (has_changes() && !is_filtered_out())
2398     return true;
2399   return false;
2400 }
2401 
2402 /// Test if this diff tree node should be reported when considering
2403 /// the categories that were *NOT* inherited from its children nodes.
2404 ///
2405 /// @return true iff the current node should be reported.
2406 bool
has_local_changes_to_be_reported() const2407 diff::has_local_changes_to_be_reported() const
2408 {
2409   if (has_local_changes()
2410       && !is_filtered_out_wrt_non_inherited_categories())
2411     return true;
2412   return false;
2413 }
2414 
2415 /// Get a pretty representation of the current @ref diff node.
2416 ///
2417 /// This is suitable for e.g. emitting debugging traces for the diff
2418 /// tree nodes.
2419 ///
2420 /// @return the pretty representation of the diff node.
2421 const string&
get_pretty_representation() const2422 diff::get_pretty_representation() const
2423 {
2424   if (priv_->pretty_representation_.empty())
2425     priv_->pretty_representation_ = "empty_diff";
2426   return priv_->pretty_representation_;
2427 }
2428 
2429 /// Default implementation of the hierachy chaining virtual function.
2430 ///
2431 /// There are several types of diff nodes that have logical children
2432 /// nodes; for instance, a typedef_diff has the diff of the underlying
2433 /// type as a child node.  A var_diff has the diff of the types of the
2434 /// variables as a child node, etc.
2435 ///
2436 /// But because the @ref diff base has a generic representation for
2437 /// children nodes of the all the types of @ref diff nodes (regardless
2438 /// of the specific most-derived type of diff node) that one can get
2439 /// using the method diff::children_nodes(), one need to populate that
2440 /// vector of children node.
2441 ///
2442 /// Populating that vector of children node is done by this function;
2443 /// it must be overloaded by each most-derived type of diff node that
2444 /// extends the @ref diff type.
2445 void
chain_into_hierarchy()2446 diff::chain_into_hierarchy()
2447 {}
2448 
2449 // </diff stuff>
2450 
2451 // <type_diff_base stuff>
2452 
type_diff_base(type_base_sptr first_subject,type_base_sptr second_subject,diff_context_sptr ctxt)2453 type_diff_base::type_diff_base(type_base_sptr	first_subject,
2454 			       type_base_sptr	second_subject,
2455 			       diff_context_sptr	ctxt)
2456   : diff(first_subject, second_subject, ctxt),
2457     priv_(new priv)
2458 {}
2459 
~type_diff_base()2460 type_diff_base::~type_diff_base()
2461 {}
2462 // </type_diff_base stuff>
2463 
2464 // <decl_diff_base stuff>
2465 
2466 /// Constructor of @ref decl_diff_base.
2467 ///
2468 /// @param first_subject the first subject of the diff.
2469 ///
2470 /// @param second_subject the second subject of the diff.
2471 ///
2472 /// @param ctxt the context of the diff.  This object must stay alive
2473 /// at least during the life time of the current instance of @ref
2474 /// decl_diff_base, otherwise, memory corruption issues occur.
decl_diff_base(decl_base_sptr first_subject,decl_base_sptr second_subject,diff_context_sptr ctxt)2475 decl_diff_base::decl_diff_base(decl_base_sptr	first_subject,
2476 			       decl_base_sptr	second_subject,
2477 			       diff_context_sptr	ctxt)
2478   : diff(first_subject, second_subject, ctxt),
2479     priv_(new priv)
2480 {}
2481 
~decl_diff_base()2482 decl_diff_base::~decl_diff_base()
2483 {}
2484 
2485 // </decl_diff_base stuff>
2486 
2487 // <distinct_diff stuff>
2488 
2489 /// @return a pretty representation for the @ref distinct_diff node.
2490 const string&
get_pretty_representation() const2491 distinct_diff::get_pretty_representation() const
2492 {
2493   if (diff::priv_->pretty_representation_.empty())
2494     {
2495       std::ostringstream o;
2496       o << "distinct_diff[";
2497       if (first_subject())
2498 	o << first_subject()->get_pretty_representation();
2499       else
2500 	o << "null";
2501       o << ", ";
2502       if (second_subject())
2503 	o << second_subject()->get_pretty_representation() ;
2504       else
2505 	o << "null";
2506       o << "]" ;
2507       diff::priv_->pretty_representation_ = o.str();
2508     }
2509   return diff::priv_->pretty_representation_;
2510 }
2511 
2512 /// Populate the vector of children node of the @ref diff base type
2513 /// sub-object of this instance of @distinct_diff.
2514 ///
2515 /// The children nodes can then later be retrieved using
2516 /// diff::children_nodes().
2517 void
chain_into_hierarchy()2518 distinct_diff::chain_into_hierarchy()
2519 {
2520   ABG_ASSERT(entities_are_of_distinct_kinds(first(), second()));
2521 
2522   if (diff_sptr d = compatible_child_diff())
2523     append_child_node(d);
2524 }
2525 
2526 /// Constructor for @ref distinct_diff.
2527 ///
2528 /// Note that the two entities considered for the diff (and passed in
2529 /// parameter) must be of different kinds.
2530 ///
2531 /// @param first the first entity to consider for the diff.
2532 ///
2533 /// @param second the second entity to consider for the diff.
2534 ///
2535 /// @param ctxt the context of the diff.  Note that this context
2536 /// object must stay alive at least during the life time of the
2537 /// current instance of @ref distinct_diff.  Otherwise memory
2538 /// corruption issues occur.
distinct_diff(type_or_decl_base_sptr first,type_or_decl_base_sptr second,diff_context_sptr ctxt)2539 distinct_diff::distinct_diff(type_or_decl_base_sptr first,
2540 			     type_or_decl_base_sptr second,
2541 			     diff_context_sptr ctxt)
2542   : diff(first, second, ctxt),
2543     priv_(new priv)
2544 {ABG_ASSERT(entities_are_of_distinct_kinds(first, second));}
2545 
2546 /// Getter for the first subject of the diff.
2547 ///
2548 /// @return the first subject of the diff.
2549 const type_or_decl_base_sptr
first() const2550 distinct_diff::first() const
2551 {return first_subject();}
2552 
2553 /// Getter for the second subject of the diff.
2554 ///
2555 /// @return the second subject of the diff.
2556 const type_or_decl_base_sptr
second() const2557 distinct_diff::second() const
2558 {return second_subject();}
2559 
2560 /// Getter for the child diff of this distinct_diff instance.
2561 ///
2562 /// When a distinct_diff has two subjects that are different but
2563 /// compatible, then the distinct_diff instance has a child diff node
2564 /// (named the compatible child diff) that is the diff between the two
2565 /// subjects stripped from their typedefs.  Otherwise, the compatible
2566 /// child diff is nul.
2567 ///
2568 /// Note that two diff subjects (that compare different) are
2569 /// considered compatible if stripping typedefs out of them makes them
2570 /// comparing equal.
2571 ///
2572 /// @return the compatible child diff node, if any.  Otherwise, null.
2573 const diff_sptr
compatible_child_diff() const2574 distinct_diff::compatible_child_diff() const
2575 {
2576   if (!priv_->compatible_child_diff)
2577     {
2578       type_base_sptr fs = strip_typedef(is_type(first())),
2579 	ss = strip_typedef(is_type(second()));
2580 
2581       if (fs && ss
2582 	  && !entities_are_of_distinct_kinds(get_type_declaration(fs),
2583 					     get_type_declaration(ss)))
2584 	priv_->compatible_child_diff = compute_diff(get_type_declaration(fs),
2585 						    get_type_declaration(ss),
2586 						    context());
2587     }
2588   return priv_->compatible_child_diff;
2589 }
2590 
2591 /// Test if the two arguments are of different kind, or that are both
2592 /// NULL.
2593 ///
2594 /// @param first the first argument to test for similarity in kind.
2595 ///
2596 /// @param second the second argument to test for similarity in kind.
2597 ///
2598 /// @return true iff the two arguments are of different kind.
2599 bool
entities_are_of_distinct_kinds(type_or_decl_base_sptr first,type_or_decl_base_sptr second)2600 distinct_diff::entities_are_of_distinct_kinds(type_or_decl_base_sptr first,
2601 					      type_or_decl_base_sptr second)
2602 {
2603   if (!!first != !!second)
2604     return true;
2605   if (!first && !second)
2606     // We do consider diffs of two empty decls as a diff of distinct
2607     // kinds, for now.
2608     return true;
2609   if (first == second)
2610     return false;
2611 
2612   const type_or_decl_base &f = *first, &s = *second;
2613   return typeid(f) != typeid(s);
2614 }
2615 
2616 /// @return true if the two subjects of the diff are different, false
2617 /// otherwise.
2618 bool
has_changes() const2619 distinct_diff::has_changes() const
2620 {return first() != second();}
2621 
2622 /// @return the kind of local change carried by the current diff node.
2623 /// The value returned is zero if the current node carries no local
2624 /// change.
2625 enum change_kind
has_local_changes() const2626 distinct_diff::has_local_changes() const
2627 {
2628   // Changes on a distinct_diff are all local.
2629   if (has_changes())
2630     return LOCAL_TYPE_CHANGE_KIND;
2631   return NO_CHANGE_KIND;
2632 }
2633 
2634 /// Emit a report about the current diff instance.
2635 ///
2636 /// @param out the output stream to send the diff report to.
2637 ///
2638 /// @param indent the indentation string to use in the report.
2639 void
report(ostream & out,const string & indent) const2640 distinct_diff::report(ostream& out, const string& indent) const
2641 {
2642   context()->get_reporter()->report(*this, out, indent);
2643 }
2644 
2645 /// Try to diff entities that are of distinct kinds.
2646 ///
2647 /// @param first the first entity to consider for the diff.
2648 ///
2649 /// @param second the second entity to consider for the diff.
2650 ///
2651 /// @param ctxt the context of the diff.
2652 ///
2653 /// @return a non-null diff if a diff object could be built, null
2654 /// otherwise.
2655 distinct_diff_sptr
compute_diff_for_distinct_kinds(const type_or_decl_base_sptr first,const type_or_decl_base_sptr second,diff_context_sptr ctxt)2656 compute_diff_for_distinct_kinds(const type_or_decl_base_sptr first,
2657 				const type_or_decl_base_sptr second,
2658 				diff_context_sptr ctxt)
2659 {
2660   if (!distinct_diff::entities_are_of_distinct_kinds(first, second))
2661     return distinct_diff_sptr();
2662 
2663   distinct_diff_sptr result(new distinct_diff(first, second, ctxt));
2664 
2665   ctxt->initialize_canonical_diff(result);
2666 
2667   return result;
2668 }
2669 
2670 /// </distinct_diff stuff>
2671 
2672 /// Try to compute a diff on two instances of DiffType representation.
2673 ///
2674 /// The function template performs the diff if and only if the decl
2675 /// representations are of a DiffType.
2676 ///
2677 /// @tparm DiffType the type of instances to diff.
2678 ///
2679 /// @param first the first representation of decl to consider in the
2680 /// diff computation.
2681 ///
2682 /// @param second the second representation of decl to consider in the
2683 /// diff computation.
2684 ///
2685 /// @param ctxt the diff context to use.
2686 ///
2687 ///@return the diff of the two types @p first and @p second if and
2688 ///only if they represent the parametrized type DiffType.  Otherwise,
2689 ///returns a NULL pointer value.
2690 template<typename DiffType>
2691 diff_sptr
try_to_diff(const type_or_decl_base_sptr first,const type_or_decl_base_sptr second,diff_context_sptr ctxt)2692 try_to_diff(const type_or_decl_base_sptr first,
2693 	    const type_or_decl_base_sptr second,
2694 	    diff_context_sptr ctxt)
2695 {
2696   if (shared_ptr<DiffType> f =
2697       dynamic_pointer_cast<DiffType>(first))
2698     {
2699       shared_ptr<DiffType> s =
2700 	dynamic_pointer_cast<DiffType>(second);
2701       if (!s)
2702 	return diff_sptr();
2703       return compute_diff(f, s, ctxt);
2704     }
2705   return diff_sptr();
2706 }
2707 
2708 
2709 /// This is a specialization of @ref try_to_diff() template to diff
2710 /// instances of @ref class_decl.
2711 ///
2712 /// @param first the first representation of decl to consider in the
2713 /// diff computation.
2714 ///
2715 /// @param second the second representation of decl to consider in the
2716 /// diff computation.
2717 ///
2718 /// @param ctxt the diff context to use.
2719 template<>
2720 diff_sptr
try_to_diff(const type_or_decl_base_sptr first,const type_or_decl_base_sptr second,diff_context_sptr ctxt)2721 try_to_diff<class_decl>(const type_or_decl_base_sptr first,
2722 			const type_or_decl_base_sptr second,
2723 			diff_context_sptr ctxt)
2724 {
2725   if (class_decl_sptr f =
2726       dynamic_pointer_cast<class_decl>(first))
2727     {
2728       class_decl_sptr s = dynamic_pointer_cast<class_decl>(second);
2729       if (!s)
2730 	return diff_sptr();
2731 
2732       if (f->get_is_declaration_only())
2733 	{
2734 	  class_decl_sptr f2 =
2735 	    is_class_type (f->get_definition_of_declaration());
2736 	  if (f2)
2737 	    f = f2;
2738 	}
2739       if (s->get_is_declaration_only())
2740 	{
2741 	  class_decl_sptr s2 =
2742 	    is_class_type(s->get_definition_of_declaration());
2743 	  if (s2)
2744 	    s = s2;
2745 	}
2746       return compute_diff(f, s, ctxt);
2747     }
2748   return diff_sptr();
2749 }
2750 
2751 /// Try to diff entities that are of distinct kinds.
2752 ///
2753 /// @param first the first entity to consider for the diff.
2754 ///
2755 /// @param second the second entity to consider for the diff.
2756 ///
2757 /// @param ctxt the context of the diff.
2758 ///
2759 /// @return a non-null diff if a diff object could be built, null
2760 /// otherwise.
2761 static diff_sptr
try_to_diff_distinct_kinds(const type_or_decl_base_sptr first,const type_or_decl_base_sptr second,diff_context_sptr ctxt)2762 try_to_diff_distinct_kinds(const type_or_decl_base_sptr first,
2763 			   const type_or_decl_base_sptr second,
2764 			   diff_context_sptr ctxt)
2765 {return compute_diff_for_distinct_kinds(first, second, ctxt);}
2766 
2767 /// Compute the difference between two types.
2768 ///
2769 /// The function considers every possible types known to libabigail
2770 /// and runs the appropriate diff function on them.
2771 ///
2772 /// Whenever a new kind of type decl is supported by abigail, if we
2773 /// want to be able to diff two instances of it, we need to update
2774 /// this function to support it.
2775 ///
2776 /// @param first the first type decl to consider for the diff
2777 ///
2778 /// @param second the second type decl to consider for the diff.
2779 ///
2780 /// @param ctxt the diff context to use.
2781 ///
2782 /// @return the resulting diff.  It's a pointer to a descendent of
2783 /// abigail::comparison::diff.
2784 static diff_sptr
compute_diff_for_types(const type_or_decl_base_sptr & first,const type_or_decl_base_sptr & second,const diff_context_sptr & ctxt)2785 compute_diff_for_types(const type_or_decl_base_sptr& first,
2786 		       const type_or_decl_base_sptr& second,
2787 		       const diff_context_sptr& ctxt)
2788 {
2789   type_or_decl_base_sptr f = first;
2790   type_or_decl_base_sptr s = second;
2791 
2792   diff_sptr d;
2793 
2794   ((d = try_to_diff<type_decl>(f, s, ctxt))
2795    ||(d = try_to_diff<enum_type_decl>(f, s, ctxt))
2796    ||(d = try_to_diff<union_decl>(f, s,ctxt))
2797    ||(d = try_to_diff<class_decl>(f, s,ctxt))
2798    ||(d = try_to_diff<pointer_type_def>(f, s, ctxt))
2799    ||(d = try_to_diff<reference_type_def>(f, s, ctxt))
2800    ||(d = try_to_diff<array_type_def>(f, s, ctxt))
2801    ||(d = try_to_diff<qualified_type_def>(f, s, ctxt))
2802    ||(d = try_to_diff<typedef_decl>(f, s, ctxt))
2803    ||(d = try_to_diff<function_type>(f, s, ctxt))
2804    ||(d = try_to_diff_distinct_kinds(f, s, ctxt)));
2805 
2806   ABG_ASSERT(d);
2807 
2808   return d;
2809 }
2810 
2811 diff_category
operator |(diff_category c1,diff_category c2)2812 operator|(diff_category c1, diff_category c2)
2813 {return static_cast<diff_category>(static_cast<unsigned>(c1)
2814 				   | static_cast<unsigned>(c2));}
2815 
2816 diff_category&
operator |=(diff_category & c1,diff_category c2)2817 operator|=(diff_category& c1, diff_category c2)
2818 {
2819   c1 = c1 | c2;
2820   return c1;
2821 }
2822 
2823 diff_category&
operator &=(diff_category & c1,diff_category c2)2824 operator&=(diff_category& c1, diff_category c2)
2825 {
2826   c1 = c1 & c2;
2827   return c1;
2828 }
2829 
2830 diff_category
operator ^(diff_category c1,diff_category c2)2831 operator^(diff_category c1, diff_category c2)
2832 {return static_cast<diff_category>(static_cast<unsigned>(c1)
2833 				   ^ static_cast<unsigned>(c2));}
2834 
2835 diff_category
operator &(diff_category c1,diff_category c2)2836 operator&(diff_category c1, diff_category c2)
2837 {return static_cast<diff_category>(static_cast<unsigned>(c1)
2838 				   & static_cast<unsigned>(c2));}
2839 
2840 diff_category
operator ~(diff_category c)2841 operator~(diff_category c)
2842 {return static_cast<diff_category>(~static_cast<unsigned>(c));}
2843 
2844 
2845 /// Getter of a bitmap made of the set of change categories that are
2846 /// considered harmless.
2847 ///
2848 /// @return the bitmap made of the set of change categories that are
2849 /// considered harmless.
2850 diff_category
get_default_harmless_categories_bitmap()2851 get_default_harmless_categories_bitmap()
2852 {
2853   return (abigail::comparison::ACCESS_CHANGE_CATEGORY
2854 	  | abigail::comparison::COMPATIBLE_TYPE_CHANGE_CATEGORY
2855 	  | abigail::comparison::HARMLESS_DECL_NAME_CHANGE_CATEGORY
2856 	  | abigail::comparison::NON_VIRT_MEM_FUN_CHANGE_CATEGORY
2857 	  | abigail::comparison::STATIC_DATA_MEMBER_CHANGE_CATEGORY
2858 	  | abigail::comparison::HARMLESS_ENUM_CHANGE_CATEGORY
2859 	  | abigail::comparison::HARMLESS_SYMBOL_ALIAS_CHANGE_CATEGORY
2860 	  | abigail::comparison::HARMLESS_UNION_CHANGE_CATEGORY
2861 	  | abigail::comparison::HARMLESS_DATA_MEMBER_CHANGE_CATEGORY
2862 	  | abigail::comparison::TYPE_DECL_ONLY_DEF_CHANGE_CATEGORY
2863 	  | abigail::comparison::FN_PARM_TYPE_TOP_CV_CHANGE_CATEGORY
2864 	  | abigail::comparison::FN_PARM_TYPE_CV_CHANGE_CATEGORY
2865 	  | abigail::comparison::FN_RETURN_TYPE_CV_CHANGE_CATEGORY
2866 	  | abigail::comparison::VAR_TYPE_CV_CHANGE_CATEGORY
2867 	  | abigail::comparison::VOID_PTR_TO_PTR_CHANGE_CATEGORY
2868 	  | abigail::comparison::BENIGN_INFINITE_ARRAY_CHANGE_CATEGORY);
2869 }
2870 
2871 /// Getter of a bitmap made of the set of change categories that are
2872 /// considered harmful.
2873 ///
2874 /// @return the bitmap made of the set of change categories that are
2875 /// considered harmful.
2876 diff_category
get_default_harmful_categories_bitmap()2877 get_default_harmful_categories_bitmap()
2878 {
2879   return (abigail::comparison::SIZE_OR_OFFSET_CHANGE_CATEGORY
2880 	  | abigail::comparison::VIRTUAL_MEMBER_CHANGE_CATEGORY
2881 	  | abigail::comparison::FN_PARM_ADD_REMOVE_CHANGE_CATEGORY);
2882 }
2883 
2884 /// Serialize an instance of @ref diff_category to an output stream.
2885 ///
2886 /// @param o the output stream to serialize @p c to.
2887 ///
2888 /// @param c the instance of diff_category to serialize.
2889 ///
2890 /// @return the output stream to serialize @p c to.
2891 ostream&
operator <<(ostream & o,diff_category c)2892 operator<<(ostream& o, diff_category c)
2893 {
2894   bool emitted_a_category = false;
2895 
2896   if (c == NO_CHANGE_CATEGORY)
2897     {
2898       o << "NO_CHANGE_CATEGORY";
2899       emitted_a_category = true;
2900     }
2901 
2902   if (c & ACCESS_CHANGE_CATEGORY)
2903     {
2904       if (emitted_a_category)
2905 	o << "|";
2906       o << "ACCESS_CHANGE_CATEGORY";
2907       emitted_a_category |= true;
2908     }
2909 
2910   if (c & COMPATIBLE_TYPE_CHANGE_CATEGORY)
2911     {
2912       if (emitted_a_category)
2913 	o << "|";
2914       o << "COMPATIBLE_TYPE_CHANGE_CATEGORY";
2915       emitted_a_category |= true;
2916     }
2917 
2918   if (c & HARMLESS_DECL_NAME_CHANGE_CATEGORY)
2919     {
2920       if (emitted_a_category)
2921 	o << "|";
2922       o << "HARMLESS_DECL_NAME_CHANGE_CATEGORY";
2923       emitted_a_category |= true;
2924     }
2925 
2926   if (c & NON_VIRT_MEM_FUN_CHANGE_CATEGORY)
2927     {
2928       if (emitted_a_category)
2929 	o << "|";
2930       o << "NON_VIRT_MEM_FUN_CHANGE_CATEGORY";
2931       emitted_a_category |= true;
2932     }
2933 
2934   if (c & STATIC_DATA_MEMBER_CHANGE_CATEGORY)
2935     {
2936       if (emitted_a_category)
2937 	o << "|";
2938       o << "STATIC_DATA_MEMBER_CHANGE_CATEGORY";
2939       emitted_a_category |= true;
2940     }
2941 
2942   if (c & HARMLESS_ENUM_CHANGE_CATEGORY)
2943     {
2944       if (emitted_a_category)
2945 	o << "|";
2946       o << "HARMLESS_ENUM_CHANGE_CATEGORY";
2947       emitted_a_category |= true;
2948     }
2949 
2950     if (c & HARMLESS_DATA_MEMBER_CHANGE_CATEGORY)
2951     {
2952       if (emitted_a_category)
2953 	o << "|";
2954       o << "HARMLESS_DATA_MEMBER_CHANGE_CATEGORY";
2955       emitted_a_category |= true;
2956     }
2957 
2958   if (c & HARMLESS_SYMBOL_ALIAS_CHANGE_CATEGORY)
2959     {
2960       if (emitted_a_category)
2961 	o << "|";
2962       o << "HARMLESS_SYMBOL_ALIAS_CHANGE_CATEGORY";
2963       emitted_a_category |= true;
2964     }
2965 
2966   if (c & HARMLESS_UNION_CHANGE_CATEGORY)
2967     {
2968       if (emitted_a_category)
2969 	o << "|";
2970       o << "HARMLESS_UNION_CHANGE_CATEGORY";
2971       emitted_a_category |= true;
2972     }
2973 
2974   if (c & SUPPRESSED_CATEGORY)
2975     {
2976       if (emitted_a_category)
2977 	o << "|";
2978       o << "SUPPRESSED_CATEGORY";
2979       emitted_a_category |= true;
2980     }
2981 
2982   if (c & PRIVATE_TYPE_CATEGORY)
2983     {
2984       if (emitted_a_category)
2985 	o << "|";
2986       o << "PRIVATE_TYPE_CATEGORY";
2987       emitted_a_category |= true;
2988     }
2989 
2990   if (c & SIZE_OR_OFFSET_CHANGE_CATEGORY)
2991     {
2992       if (emitted_a_category)
2993 	o << "|";
2994       o << "SIZE_OR_OFFSET_CHANGE_CATEGORY";
2995       emitted_a_category |= true;
2996     }
2997 
2998   if (c & VIRTUAL_MEMBER_CHANGE_CATEGORY)
2999     {
3000       if (emitted_a_category)
3001 	o << "|";
3002       o << "VIRTUAL_MEMBER_CHANGE_CATEGORY";
3003       emitted_a_category |= true;
3004     }
3005 
3006   if (c & REDUNDANT_CATEGORY)
3007     {
3008       if (emitted_a_category)
3009 	o << "|";
3010       o << "REDUNDANT_CATEGORY";
3011       emitted_a_category |= true;
3012     }
3013 
3014   if (c & TYPE_DECL_ONLY_DEF_CHANGE_CATEGORY)
3015     {
3016       if (emitted_a_category)
3017 	o << "|";
3018       o << "TYPE_DECL_ONLY_DEF_CHANGE_CATEGORY";
3019       emitted_a_category |= true;
3020     }
3021 
3022   if (c & FN_PARM_TYPE_TOP_CV_CHANGE_CATEGORY)
3023     {
3024       if (emitted_a_category)
3025 	o << "|";
3026       o << "FN_PARM_TYPE_TOP_CV_CHANGE_CATEGORY";
3027       emitted_a_category |= true;
3028     }
3029 
3030   if (c & FN_PARM_TYPE_CV_CHANGE_CATEGORY)
3031     {
3032       if (emitted_a_category)
3033 	o << "|";
3034       o << "FN_PARM_TYPE_CV_CHANGE_CATEGORY";
3035       emitted_a_category |= true;
3036     }
3037 
3038   if (c & FN_RETURN_TYPE_CV_CHANGE_CATEGORY)
3039     {
3040       if (emitted_a_category)
3041 	o << "|";
3042       o << "FN_RETURN_TYPE_CV_CHANGE_CATEGORY";
3043       emitted_a_category |= true;
3044     }
3045 
3046     if (c & FN_PARM_ADD_REMOVE_CHANGE_CATEGORY)
3047     {
3048       if (emitted_a_category)
3049 	o << "|";
3050       o << "FN_PARM_ADD_REMOVE_CHANGE_CATEGORY";
3051       emitted_a_category |= true;
3052     }
3053 
3054   if (c & VAR_TYPE_CV_CHANGE_CATEGORY)
3055     {
3056       if (emitted_a_category)
3057 	o << "|";
3058       o << "VAR_TYPE_CV_CHANGE_CATEGORY";
3059       emitted_a_category |= true;
3060     }
3061 
3062   if (c & VOID_PTR_TO_PTR_CHANGE_CATEGORY)
3063     {
3064       if (emitted_a_category)
3065 	o << "|";
3066       o << "VOID_PTR_TO_PTR_CHANGE_CATEGORY";
3067       emitted_a_category |= true;
3068     }
3069 
3070   if (c & BENIGN_INFINITE_ARRAY_CHANGE_CATEGORY)
3071     {
3072       if (emitted_a_category)
3073 	o << "|";
3074       o << "BENIGN_INFINITE_ARRAY_CHANGE_CATEGORY";
3075       emitted_a_category |= true;
3076     }
3077 
3078   return o;
3079 }
3080 
3081 /// Compute the difference between two decls.
3082 ///
3083 /// The function consider every possible decls known to libabigail and
3084 /// runs the appropriate diff function on them.
3085 ///
3086 /// Whenever a new kind of non-type decl is supported by abigail, if
3087 /// we want to be able to diff two instances of it, we need to update
3088 /// this function to support it.
3089 ///
3090 /// @param first the first decl to consider for the diff
3091 ///
3092 /// @param second the second decl to consider for the diff.
3093 ///
3094 /// @param ctxt the diff context to use.
3095 ///
3096 /// @return the resulting diff.
3097 static diff_sptr
compute_diff_for_decls(const decl_base_sptr first,const decl_base_sptr second,diff_context_sptr ctxt)3098 compute_diff_for_decls(const decl_base_sptr first,
3099 		       const decl_base_sptr second,
3100 		       diff_context_sptr ctxt)
3101 {
3102 
3103   diff_sptr d;
3104 
3105   ((d = try_to_diff<function_decl>(first, second, ctxt))
3106    || (d = try_to_diff<var_decl>(first, second, ctxt))
3107    || (d = try_to_diff_distinct_kinds(first, second, ctxt)));
3108 
3109    ABG_ASSERT(d);
3110 
3111   return d;
3112 }
3113 
3114 /// Compute the difference between two decls.  The decls can represent
3115 /// either type declarations, or non-type declaration.
3116 ///
3117 /// Note that the two decls must have been created in the same @ref
3118 /// environment, otherwise, this function aborts.
3119 ///
3120 /// @param first the first decl to consider.
3121 ///
3122 /// @param second the second decl to consider.
3123 ///
3124 /// @param ctxt the diff context to use.
3125 ///
3126 /// @return the resulting diff, or NULL if the diff could not be
3127 /// computed.
3128 diff_sptr
compute_diff(const decl_base_sptr first,const decl_base_sptr second,diff_context_sptr ctxt)3129 compute_diff(const decl_base_sptr	first,
3130 	     const decl_base_sptr	second,
3131 	     diff_context_sptr		ctxt)
3132 {
3133   if (!first || !second)
3134     return diff_sptr();
3135 
3136   diff_sptr d;
3137   if (is_type(first) && is_type(second))
3138     d = compute_diff_for_types(first, second, ctxt);
3139   else
3140     d = compute_diff_for_decls(first, second, ctxt);
3141   ABG_ASSERT(d);
3142   return d;
3143 }
3144 
3145 /// Compute the difference between two types.
3146 ///
3147 /// Note that the two types must have been created in the same @ref
3148 /// environment, otherwise, this function aborts.
3149 ///
3150 /// @param first the first type to consider.
3151 ///
3152 /// @param second the second type to consider.
3153 ///
3154 /// @param ctxt the diff context to use.
3155 ///
3156 /// @return the resulting diff, or NULL if the diff couldn't be
3157 /// computed.
3158 diff_sptr
compute_diff(const type_base_sptr first,const type_base_sptr second,diff_context_sptr ctxt)3159 compute_diff(const type_base_sptr	first,
3160 	     const type_base_sptr	second,
3161 	     diff_context_sptr		ctxt)
3162 {
3163   decl_base_sptr f = get_type_declaration(first),
3164     s = get_type_declaration(second);
3165 
3166   diff_sptr d = compute_diff_for_types(f,s, ctxt);
3167   ABG_ASSERT(d);
3168   return d;
3169 }
3170 
3171 /// Get a copy of the pretty representation of a diff node.
3172 ///
3173 /// @param d the diff node to consider.
3174 ///
3175 /// @return the pretty representation string.
3176 string
get_pretty_representation(diff * d)3177 get_pretty_representation(diff* d)
3178 {
3179   if (!d)
3180     return "";
3181   string prefix= "diff of ";
3182   return prefix + get_pretty_representation(d->first_subject());
3183 }
3184 
3185 // <var_diff stuff>
3186 
3187 /// Populate the vector of children node of the @ref diff base type
3188 /// sub-object of this instance of @ref var_diff.
3189 ///
3190 /// The children node can then later be retrieved using
3191 /// diff::children_node().
3192 void
chain_into_hierarchy()3193 var_diff::chain_into_hierarchy()
3194 {append_child_node(type_diff());}
3195 
3196 /// @return the pretty representation for this current instance of
3197 /// @ref var_diff.
3198 const string&
get_pretty_representation() const3199 var_diff::get_pretty_representation() const
3200 {
3201   if (diff::priv_->pretty_representation_.empty())
3202     {
3203       std::ostringstream o;
3204       o << "var_diff["
3205 	<< first_subject()->get_pretty_representation()
3206 	<< ", "
3207 	<< second_subject()->get_pretty_representation()
3208 	<< "]";
3209       diff::priv_->pretty_representation_ = o.str();
3210     }
3211   return diff::priv_->pretty_representation_;
3212 }
3213 /// Constructor for @ref var_diff.
3214 ///
3215 /// @param first the first instance of @ref var_decl to consider in
3216 /// the diff.
3217 ///
3218 /// @param second the second instance of @ref var_decl to consider in
3219 /// the diff.
3220 ///
3221 /// @param type_diff the diff between types of the instances of
3222 /// var_decl.
3223 ///
3224 /// @param ctxt the diff context to use.
var_diff(var_decl_sptr first,var_decl_sptr second,diff_sptr type_diff,diff_context_sptr ctxt)3225 var_diff::var_diff(var_decl_sptr	first,
3226 		   var_decl_sptr	second,
3227 		   diff_sptr		type_diff,
3228 		   diff_context_sptr	ctxt)
3229   : decl_diff_base(first, second, ctxt),
3230     priv_(new priv)
3231 {priv_->type_diff_ = type_diff;}
3232 
3233 /// Getter for the first @ref var_decl of the diff.
3234 ///
3235 /// @return the first @ref var_decl of the diff.
3236 var_decl_sptr
first_var() const3237 var_diff::first_var() const
3238 {return dynamic_pointer_cast<var_decl>(first_subject());}
3239 
3240 /// Getter for the second @ref var_decl of the diff.
3241 ///
3242 /// @return the second @ref var_decl of the diff.
3243 var_decl_sptr
second_var() const3244 var_diff::second_var() const
3245 {return dynamic_pointer_cast<var_decl>(second_subject());}
3246 
3247 /// Getter for the diff of the types of the instances of @ref
3248 /// var_decl.
3249 ///
3250 /// @return the diff of the types of the instances of @ref var_decl.
3251 diff_sptr
type_diff() const3252 var_diff::type_diff() const
3253 {
3254   if (diff_sptr result = priv_->type_diff_.lock())
3255     return result;
3256   else
3257     {
3258       result = compute_diff(first_var()->get_type(),
3259 			    second_var()->get_type(),
3260 			    context());
3261       context()->keep_diff_alive(result);
3262       priv_->type_diff_ = result;
3263       return result;
3264     }
3265 }
3266 
3267 /// Return true iff the diff node has a change.
3268 ///
3269 /// @return true iff the diff node has a change.
3270 bool
has_changes() const3271 var_diff::has_changes() const
3272 {return *first_var() != *second_var();}
3273 
3274 /// @return the kind of local change carried by the current diff node.
3275 /// The value returned is zero if the current node carries no local
3276 /// change.
3277 enum change_kind
has_local_changes() const3278 var_diff::has_local_changes() const
3279 {
3280   ir::change_kind k = ir::NO_CHANGE_KIND;
3281   if (!equals(*first_var(), *second_var(), &k))
3282     return k & ir::ALL_LOCAL_CHANGES_MASK;
3283   return ir::NO_CHANGE_KIND;
3284 }
3285 
3286 /// Report the diff in a serialized form.
3287 ///
3288 /// @param out the stream to serialize the diff to.
3289 ///
3290 /// @param indent the prefix to use for the indentation of this
3291 /// serialization.
3292 void
report(ostream & out,const string & indent) const3293 var_diff::report(ostream& out, const string& indent) const
3294 {
3295   context()->get_reporter()->report(*this, out, indent);
3296 }
3297 
3298 /// Compute the diff between two instances of @ref var_decl.
3299 ///
3300 /// Note that the two decls must have been created in the same @ref
3301 /// environment, otherwise, this function aborts.
3302 ///
3303 /// @param first the first @ref var_decl to consider for the diff.
3304 ///
3305 /// @param second the second @ref var_decl to consider for the diff.
3306 ///
3307 /// @param ctxt the diff context to use.
3308 ///
3309 /// @return the resulting diff between the two @ref var_decl.
3310 var_diff_sptr
compute_diff(const var_decl_sptr first,const var_decl_sptr second,diff_context_sptr ctxt)3311 compute_diff(const var_decl_sptr	first,
3312 	     const var_decl_sptr	second,
3313 	     diff_context_sptr		ctxt)
3314 {
3315   var_diff_sptr d(new var_diff(first, second, diff_sptr(), ctxt));
3316   ctxt->initialize_canonical_diff(d);
3317 
3318   return d;
3319 }
3320 
3321 // </var_diff stuff>
3322 
3323 // <pointer_type_def stuff>
3324 
3325 /// Populate the vector of children node of the @ref diff base type
3326 /// sub-object of this instance of @ref pointer_diff.
3327 ///
3328 /// The children node can then later be retrieved using
3329 /// diff::children_node().
3330 void
chain_into_hierarchy()3331 pointer_diff::chain_into_hierarchy()
3332 {append_child_node(underlying_type_diff());}
3333 
3334 /// Constructor for a pointer_diff.
3335 ///
3336 /// @param first the first pointer to consider for the diff.
3337 ///
3338 /// @param second the secon pointer to consider for the diff.
3339 ///
3340 /// @param ctxt the diff context to use.
pointer_diff(pointer_type_def_sptr first,pointer_type_def_sptr second,diff_sptr underlying,diff_context_sptr ctxt)3341 pointer_diff::pointer_diff(pointer_type_def_sptr	first,
3342 			   pointer_type_def_sptr	second,
3343 			   diff_sptr			underlying,
3344 			   diff_context_sptr		ctxt)
3345   : type_diff_base(first, second, ctxt),
3346     priv_(new priv(underlying))
3347 {}
3348 
3349 /// Getter for the first subject of a pointer diff
3350 ///
3351 /// @return the first pointer considered in this pointer diff.
3352 const pointer_type_def_sptr
first_pointer() const3353 pointer_diff::first_pointer() const
3354 {return dynamic_pointer_cast<pointer_type_def>(first_subject());}
3355 
3356 /// Getter for the second subject of a pointer diff
3357 ///
3358 /// @return the second pointer considered in this pointer diff.
3359 const pointer_type_def_sptr
second_pointer() const3360 pointer_diff::second_pointer() const
3361 {return dynamic_pointer_cast<pointer_type_def>(second_subject());}
3362 
3363 /// @return the pretty represenation for the current instance of @ref
3364 /// pointer_diff.
3365 const string&
get_pretty_representation() const3366 pointer_diff::get_pretty_representation() const
3367 {
3368   if (diff::priv_->pretty_representation_.empty())
3369     {
3370       std::ostringstream o;
3371       o << "pointer_diff["
3372 	<< first_subject()->get_pretty_representation()
3373 	<< ", "
3374 	<< second_subject()->get_pretty_representation()
3375 	<< "]";
3376       diff::priv_->pretty_representation_ = o.str();
3377     }
3378   return diff::priv_->pretty_representation_;
3379 }
3380 
3381 /// Return true iff the current diff node carries a change.
3382 ///
3383 /// @return true iff the current diff node carries a change.
3384 bool
has_changes() const3385 pointer_diff::has_changes() const
3386 {return first_pointer() != second_pointer();}
3387 
3388 /// @return the kind of local change carried by the current diff node.
3389 /// The value returned is zero if the current node carries no local
3390 /// change.
3391 enum change_kind
has_local_changes() const3392 pointer_diff::has_local_changes() const
3393 {
3394   ir::change_kind k = ir::NO_CHANGE_KIND;
3395   if (!equals(*first_pointer(), *second_pointer(), &k))
3396     return k & ir::ALL_LOCAL_CHANGES_MASK;
3397   return ir::NO_CHANGE_KIND;
3398 }
3399 
3400 /// Getter for the diff between the pointed-to types of the pointers
3401 /// of this diff.
3402 ///
3403 /// @return the diff between the pointed-to types.
3404 diff_sptr
underlying_type_diff() const3405 pointer_diff::underlying_type_diff() const
3406 {return priv_->underlying_type_diff_;}
3407 
3408 /// Setter for the diff between the pointed-to types of the pointers
3409 /// of this diff.
3410 ///
3411 /// @param d the new diff between the pointed-to types of the pointers
3412 /// of this diff.
3413 void
underlying_type_diff(const diff_sptr d)3414 pointer_diff::underlying_type_diff(const diff_sptr d)
3415 {priv_->underlying_type_diff_ = d;}
3416 
3417 /// Report the diff in a serialized form.
3418 ///
3419 /// @param out the stream to serialize the diff to.
3420 ///
3421 /// @param indent the prefix to use for the indentation of this
3422 /// serialization.
3423 void
report(ostream & out,const string & indent) const3424 pointer_diff::report(ostream& out, const string& indent) const
3425 {
3426   context()->get_reporter()->report(*this, out, indent);
3427 }
3428 
3429 /// Compute the diff between between two pointers.
3430 ///
3431 /// Note that the two types must have been created in the same @ref
3432 /// environment, otherwise, this function aborts.
3433 ///
3434 /// @param first the pointer to consider for the diff.
3435 ///
3436 /// @param second the pointer to consider for the diff.
3437 ///
3438 /// @return the resulting diff between the two pointers.
3439 ///
3440 /// @param ctxt the diff context to use.
3441 pointer_diff_sptr
compute_diff(pointer_type_def_sptr first,pointer_type_def_sptr second,diff_context_sptr ctxt)3442 compute_diff(pointer_type_def_sptr	first,
3443 	     pointer_type_def_sptr	second,
3444 	     diff_context_sptr		ctxt)
3445 {
3446   diff_sptr d = compute_diff_for_types(first->get_pointed_to_type(),
3447 				       second->get_pointed_to_type(),
3448 				       ctxt);
3449   pointer_diff_sptr result(new pointer_diff(first, second, d, ctxt));
3450   ctxt->initialize_canonical_diff(result);
3451 
3452   return result;
3453 }
3454 
3455 // </pointer_type_def>
3456 
3457 // <array_type_def>
3458 
3459 /// Populate the vector of children node of the @ref diff base type
3460 /// sub-object of this instance of @ref array_diff.
3461 ///
3462 /// The children node can then later be retrieved using
3463 /// diff::children_node().
3464 void
chain_into_hierarchy()3465 array_diff::chain_into_hierarchy()
3466 {append_child_node(element_type_diff());}
3467 
3468 /// Constructor for array_diff
3469 ///
3470 /// @param first the first array_type of the diff.
3471 ///
3472 /// @param second the second array_type of the diff.
3473 ///
3474 /// @param element_type_diff the diff between the two array element
3475 /// types.
3476 ///
3477 /// @param ctxt the diff context to use.
array_diff(const array_type_def_sptr first,const array_type_def_sptr second,diff_sptr element_type_diff,diff_context_sptr ctxt)3478 array_diff::array_diff(const array_type_def_sptr	first,
3479 		       const array_type_def_sptr	second,
3480 		       diff_sptr			element_type_diff,
3481 		       diff_context_sptr		ctxt)
3482   : type_diff_base(first, second, ctxt),
3483     priv_(new priv(element_type_diff))
3484 {}
3485 
3486 /// Getter for the first array of the diff.
3487 ///
3488 /// @return the first array of the diff.
3489 const array_type_def_sptr
first_array() const3490 array_diff::first_array() const
3491 {return dynamic_pointer_cast<array_type_def>(first_subject());}
3492 
3493 /// Getter for the second array of the diff.
3494 ///
3495 /// @return for the second array of the diff.
3496 const array_type_def_sptr
second_array() const3497 array_diff::second_array() const
3498 {return dynamic_pointer_cast<array_type_def>(second_subject());}
3499 
3500 /// Getter for the diff between the two types of array elements.
3501 ///
3502 /// @return the diff between the two types of array elements.
3503 const diff_sptr&
element_type_diff() const3504 array_diff::element_type_diff() const
3505 {return priv_->element_type_diff_;}
3506 
3507 /// Setter for the diff between the two array element types.
3508 ///
3509 /// @param d the new diff betweend the two array element types.
3510 void
element_type_diff(diff_sptr d)3511 array_diff::element_type_diff(diff_sptr d)
3512 {priv_->element_type_diff_ = d;}
3513 
3514 /// @return the pretty representation for the current instance of @ref
3515 /// array_diff.
3516 const string&
get_pretty_representation() const3517 array_diff::get_pretty_representation() const
3518 {
3519   if (diff::priv_->pretty_representation_.empty())
3520     {
3521       std::ostringstream o;
3522       o << "array_diff["
3523 	<< first_subject()->get_pretty_representation()
3524 	<< ", "
3525 	<< second_subject()->get_pretty_representation()
3526 	<< "]";
3527       diff::priv_->pretty_representation_ = o.str();
3528     }
3529   return diff::priv_->pretty_representation_;
3530 }
3531 
3532 /// Return true iff the current diff node carries a change.
3533 ///
3534 /// @return true iff the current diff node carries a change.
3535 bool
has_changes() const3536 array_diff::has_changes() const
3537 {
3538   bool l = false;
3539 
3540   //  the array element types match check for differing dimensions
3541   //  etc...
3542   array_type_def_sptr
3543     f = dynamic_pointer_cast<array_type_def>(first_subject()),
3544     s = dynamic_pointer_cast<array_type_def>(second_subject());
3545 
3546   if (f->get_name() != s->get_name())
3547     l |= true;
3548   if (f->get_size_in_bits() != s->get_size_in_bits())
3549     l |= true;
3550   if (f->get_alignment_in_bits() != s->get_alignment_in_bits())
3551     l |= true;
3552 
3553   l |=  element_type_diff()
3554     ? element_type_diff()->has_changes()
3555     : false;
3556 
3557   return l;
3558 }
3559 
3560 
3561 /// @return the kind of local change carried by the current diff node.
3562 /// The value returned is zero if the current node carries no local
3563 /// change.
3564 enum change_kind
has_local_changes() const3565 array_diff::has_local_changes() const
3566 {
3567   ir::change_kind k = ir::NO_CHANGE_KIND;
3568   if (!equals(*first_array(), *second_array(), &k))
3569     return k & ir::ALL_LOCAL_CHANGES_MASK;
3570   return ir::NO_CHANGE_KIND;
3571 }
3572 
3573 /// Report the diff in a serialized form.
3574 ///
3575 /// @param out the output stream to serialize the dif to.
3576 ///
3577 /// @param indent the string to use for indenting the report.
3578 void
report(ostream & out,const string & indent) const3579 array_diff::report(ostream& out, const string& indent) const
3580 {
3581   context()->get_reporter()->report(*this, out, indent);
3582 }
3583 
3584 /// Compute the diff between two arrays.
3585 ///
3586 /// Note that the two types must have been created in the same @ref
3587 /// environment, otherwise, this function aborts.
3588 ///
3589 /// @param first the first array to consider for the diff.
3590 ///
3591 /// @param second the second array to consider for the diff.
3592 ///
3593 /// @param ctxt the diff context to use.
3594 array_diff_sptr
compute_diff(array_type_def_sptr first,array_type_def_sptr second,diff_context_sptr ctxt)3595 compute_diff(array_type_def_sptr	first,
3596 	     array_type_def_sptr	second,
3597 	     diff_context_sptr		ctxt)
3598 {
3599   diff_sptr d = compute_diff_for_types(first->get_element_type(),
3600 				       second->get_element_type(),
3601 				       ctxt);
3602   array_diff_sptr result(new array_diff(first, second, d, ctxt));
3603   ctxt->initialize_canonical_diff(result);
3604   return result;
3605 }
3606 // </array_type_def>
3607 
3608 // <reference_type_def>
3609 
3610 /// Populate the vector of children node of the @ref diff base type
3611 /// sub-object of this instance of @ref reference_diff.
3612 ///
3613 /// The children node can then later be retrieved using
3614 /// diff::children_node().
3615 void
chain_into_hierarchy()3616 reference_diff::chain_into_hierarchy()
3617 {append_child_node(underlying_type_diff());}
3618 
3619 /// Constructor for reference_diff
3620 ///
3621 /// @param first the first reference_type of the diff.
3622 ///
3623 /// @param second the second reference_type of the diff.
3624 ///
3625 /// @param ctxt the diff context to use.
reference_diff(const reference_type_def_sptr first,const reference_type_def_sptr second,diff_sptr underlying,diff_context_sptr ctxt)3626 reference_diff::reference_diff(const reference_type_def_sptr	first,
3627 			       const reference_type_def_sptr	second,
3628 			       diff_sptr			underlying,
3629 			       diff_context_sptr		ctxt)
3630   : type_diff_base(first, second, ctxt),
3631 	priv_(new priv(underlying))
3632 {}
3633 
3634 /// Getter for the first reference of the diff.
3635 ///
3636 /// @return the first reference of the diff.
3637 reference_type_def_sptr
first_reference() const3638 reference_diff::first_reference() const
3639 {return dynamic_pointer_cast<reference_type_def>(first_subject());}
3640 
3641 /// Getter for the second reference of the diff.
3642 ///
3643 /// @return for the second reference of the diff.
3644 reference_type_def_sptr
second_reference() const3645 reference_diff::second_reference() const
3646 {return dynamic_pointer_cast<reference_type_def>(second_subject());}
3647 
3648 
3649 /// Getter for the diff between the two referred-to types.
3650 ///
3651 /// @return the diff between the two referred-to types.
3652 const diff_sptr&
underlying_type_diff() const3653 reference_diff::underlying_type_diff() const
3654 {return priv_->underlying_type_diff_;}
3655 
3656 /// Setter for the diff between the two referred-to types.
3657 ///
3658 /// @param d the new diff betweend the two referred-to types.
3659 diff_sptr&
underlying_type_diff(diff_sptr d)3660 reference_diff::underlying_type_diff(diff_sptr d)
3661 {
3662   priv_->underlying_type_diff_ = d;
3663   return priv_->underlying_type_diff_;
3664 }
3665 
3666 /// @return the pretty representation for the current instance of @ref
3667 /// reference_diff.
3668 const string&
get_pretty_representation() const3669 reference_diff::get_pretty_representation() const
3670 {
3671   if (diff::priv_->pretty_representation_.empty())
3672     {
3673       std::ostringstream o;
3674       o << "reference_diff["
3675 	<< first_subject()->get_pretty_representation()
3676 	<< ", "
3677 	<< second_subject()->get_pretty_representation()
3678 	<< "]";
3679       diff::priv_->pretty_representation_ = o.str();
3680     }
3681   return diff::priv_->pretty_representation_;
3682 }
3683 
3684 /// Return true iff the current diff node carries a change.
3685 ///
3686 /// @return true iff the current diff node carries a change.
3687 bool
has_changes() const3688 reference_diff::has_changes() const
3689 {
3690   return first_reference() != second_reference();
3691 }
3692 
3693 /// @return the kind of local change carried by the current diff node.
3694 /// The value returned is zero if the current node carries no local
3695 /// change.
3696 enum change_kind
has_local_changes() const3697 reference_diff::has_local_changes() const
3698 {
3699   ir::change_kind k = ir::NO_CHANGE_KIND;
3700   if (!equals(*first_reference(), *second_reference(), &k))
3701     return k & ir::ALL_LOCAL_CHANGES_MASK;
3702   return ir::NO_CHANGE_KIND;
3703 }
3704 
3705 /// Report the diff in a serialized form.
3706 ///
3707 /// @param out the output stream to serialize the dif to.
3708 ///
3709 /// @param indent the string to use for indenting the report.
3710 void
report(ostream & out,const string & indent) const3711 reference_diff::report(ostream& out, const string& indent) const
3712 {
3713   context()->get_reporter()->report(*this, out, indent);
3714 }
3715 
3716 /// Compute the diff between two references.
3717 ///
3718 /// Note that the two types must have been created in the same @ref
3719 /// environment, otherwise, this function aborts.
3720 ///
3721 /// @param first the first reference to consider for the diff.
3722 ///
3723 /// @param second the second reference to consider for the diff.
3724 ///
3725 /// @param ctxt the diff context to use.
3726 reference_diff_sptr
compute_diff(reference_type_def_sptr first,reference_type_def_sptr second,diff_context_sptr ctxt)3727 compute_diff(reference_type_def_sptr	first,
3728 	     reference_type_def_sptr	second,
3729 	     diff_context_sptr		ctxt)
3730 {
3731   diff_sptr d = compute_diff_for_types(first->get_pointed_to_type(),
3732 				       second->get_pointed_to_type(),
3733 				       ctxt);
3734   reference_diff_sptr result(new reference_diff(first, second, d, ctxt));
3735   ctxt->initialize_canonical_diff(result);
3736   return result;
3737 }
3738 // </reference_type_def>
3739 
3740 // <qualified_type_diff stuff>
3741 
3742 /// Populate the vector of children node of the @ref diff base type
3743 /// sub-object of this instance of @ref qualified_type_diff.
3744 ///
3745 /// The children node can then later be retrieved using
3746 /// diff::children_node().
3747 void
chain_into_hierarchy()3748 qualified_type_diff::chain_into_hierarchy()
3749 {append_child_node(leaf_underlying_type_diff());}
3750 
3751 /// Constructor for qualified_type_diff.
3752 ///
3753 /// @param first the first qualified type of the diff.
3754 ///
3755 /// @param second the second qualified type of the diff.
3756 ///
3757 /// @param ctxt the diff context to use.
qualified_type_diff(qualified_type_def_sptr first,qualified_type_def_sptr second,diff_sptr under,diff_context_sptr ctxt)3758 qualified_type_diff::qualified_type_diff(qualified_type_def_sptr	first,
3759 					 qualified_type_def_sptr	second,
3760 					 diff_sptr			under,
3761 					 diff_context_sptr		ctxt)
3762   : type_diff_base(first, second, ctxt),
3763     priv_(new priv(under))
3764 {}
3765 
3766 /// Getter for the first qualified type of the diff.
3767 ///
3768 /// @return the first qualified type of the diff.
3769 const qualified_type_def_sptr
first_qualified_type() const3770 qualified_type_diff::first_qualified_type() const
3771 {return dynamic_pointer_cast<qualified_type_def>(first_subject());}
3772 
3773 /// Getter for the second qualified type of the diff.
3774 ///
3775 /// @return the second qualified type of the diff.
3776 const qualified_type_def_sptr
second_qualified_type() const3777 qualified_type_diff::second_qualified_type() const
3778 {return dynamic_pointer_cast<qualified_type_def>(second_subject());}
3779 
3780 /// Getter for the diff between the underlying types of the two
3781 /// qualified types.
3782 ///
3783 /// @return the diff between the underlying types of the two qualified
3784 /// types.
3785 diff_sptr
underlying_type_diff() const3786 qualified_type_diff::underlying_type_diff() const
3787 {return priv_->underlying_type_diff;}
3788 
3789 /// Getter for the diff between the most underlying non-qualified
3790 /// types of two qualified types.
3791 ///
3792 /// @return the diff between the most underlying non-qualified types
3793 /// of two qualified types.
3794 diff_sptr
leaf_underlying_type_diff() const3795 qualified_type_diff::leaf_underlying_type_diff() const
3796 {
3797   if (!priv_->leaf_underlying_type_diff)
3798     priv_->leaf_underlying_type_diff
3799       = compute_diff_for_types(get_leaf_type(first_qualified_type()),
3800 			       get_leaf_type(second_qualified_type()),
3801 			       context());
3802 
3803   return priv_->leaf_underlying_type_diff;
3804 }
3805 
3806 /// Setter for the diff between the underlying types of the two
3807 /// qualified types.
3808 ///
3809 /// @return the diff between the underlying types of the two qualified
3810 /// types.
3811 void
underlying_type_diff(const diff_sptr d)3812 qualified_type_diff::underlying_type_diff(const diff_sptr d)
3813 {priv_->underlying_type_diff = d;}
3814 
3815 /// @return the pretty representation of the current instance of @ref
3816 /// qualified_type_diff.
3817 const string&
get_pretty_representation() const3818 qualified_type_diff::get_pretty_representation() const
3819 {
3820   if (diff::priv_->pretty_representation_.empty())
3821     {
3822       std::ostringstream o;
3823       o << "qualified_type_diff["
3824 	<< first_subject()->get_pretty_representation()
3825 	<< ", "
3826 	<< second_subject()->get_pretty_representation()
3827 	<< "]";
3828       diff::priv_->pretty_representation_ = o.str();
3829     }
3830   return diff::priv_->pretty_representation_;
3831 }
3832 
3833 /// Return true iff the current diff node carries a change.
3834 ///
3835 /// @return true iff the current diff node carries a change.
3836 bool
has_changes() const3837 qualified_type_diff::has_changes() const
3838 {return first_qualified_type() != second_qualified_type();}
3839 
3840 /// @return the kind of local change carried by the current diff node.
3841 /// The value returned is zero if the current node carries no local
3842 /// change.
3843 enum change_kind
has_local_changes() const3844 qualified_type_diff::has_local_changes() const
3845 {
3846   ir::change_kind k = ir::NO_CHANGE_KIND;
3847   if (!equals(*first_qualified_type(), *second_qualified_type(), &k))
3848     return k & ir::ALL_LOCAL_CHANGES_MASK;
3849   return ir::NO_CHANGE_KIND;
3850 }
3851 
3852 /// Report the diff in a serialized form.
3853 ///
3854 /// @param out the output stream to serialize to.
3855 ///
3856 /// @param indent the string to use to indent the lines of the report.
3857 void
report(ostream & out,const string & indent) const3858 qualified_type_diff::report(ostream& out, const string& indent) const
3859 {
3860   context()->get_reporter()->report(*this, out, indent);
3861 }
3862 
3863 /// Compute the diff between two qualified types.
3864 ///
3865 /// Note that the two types must have been created in the same @ref
3866 /// environment, otherwise, this function aborts.
3867 ///
3868 /// @param first the first qualified type to consider for the diff.
3869 ///
3870 /// @param second the second qualified type to consider for the diff.
3871 ///
3872 /// @param ctxt the diff context to use.
3873 qualified_type_diff_sptr
compute_diff(const qualified_type_def_sptr first,const qualified_type_def_sptr second,diff_context_sptr ctxt)3874 compute_diff(const qualified_type_def_sptr	first,
3875 	     const qualified_type_def_sptr	second,
3876 	     diff_context_sptr			ctxt)
3877 {
3878   diff_sptr d = compute_diff_for_types(first->get_underlying_type(),
3879 				       second->get_underlying_type(),
3880 				       ctxt);
3881   qualified_type_diff_sptr result(new qualified_type_diff(first, second,
3882 							  d, ctxt));
3883   ctxt->initialize_canonical_diff(result);
3884   return result;
3885 }
3886 
3887 // </qualified_type_diff stuff>
3888 
3889 // <enum_diff stuff>
3890 
3891 /// Clear the lookup tables useful for reporting an enum_diff.
3892 ///
3893 /// This function must be updated each time a lookup table is added or
3894 /// removed from the class_diff::priv.
3895 void
clear_lookup_tables()3896 enum_diff::clear_lookup_tables()
3897 {
3898   priv_->deleted_enumerators_.clear();
3899   priv_->inserted_enumerators_.clear();
3900   priv_->changed_enumerators_.clear();
3901 }
3902 
3903 /// Tests if the lookup tables are empty.
3904 ///
3905 /// @return true if the lookup tables are empty, false otherwise.
3906 bool
lookup_tables_empty() const3907 enum_diff::lookup_tables_empty() const
3908 {
3909   return (priv_->deleted_enumerators_.empty()
3910 	  && priv_->inserted_enumerators_.empty()
3911 	  && priv_->changed_enumerators_.empty());
3912 }
3913 
3914 /// If the lookup tables are not yet built, walk the differences and
3915 /// fill the lookup tables.
3916 void
ensure_lookup_tables_populated()3917 enum_diff::ensure_lookup_tables_populated()
3918 {
3919   if (!lookup_tables_empty())
3920     return;
3921 
3922   {
3923     edit_script e = priv_->enumerators_changes_;
3924 
3925     for (vector<deletion>::const_iterator it = e.deletions().begin();
3926 	 it != e.deletions().end();
3927 	 ++it)
3928       {
3929 	unsigned i = it->index();
3930 	const enum_type_decl::enumerator& n =
3931 	  first_enum()->get_enumerators()[i];
3932 	const string& name = n.get_name();
3933 	ABG_ASSERT(priv_->deleted_enumerators_.find(n.get_name())
3934 	       == priv_->deleted_enumerators_.end());
3935 	priv_->deleted_enumerators_[name] = n;
3936       }
3937 
3938     for (vector<insertion>::const_iterator it = e.insertions().begin();
3939 	 it != e.insertions().end();
3940 	 ++it)
3941       {
3942 	for (vector<unsigned>::const_iterator iit =
3943 	       it->inserted_indexes().begin();
3944 	     iit != it->inserted_indexes().end();
3945 	     ++iit)
3946 	  {
3947 	    unsigned i = *iit;
3948 	    const enum_type_decl::enumerator& n =
3949 	      second_enum()->get_enumerators()[i];
3950 	    const string& name = n.get_name();
3951 	    ABG_ASSERT(priv_->inserted_enumerators_.find(n.get_name())
3952 		   == priv_->inserted_enumerators_.end());
3953 	    string_enumerator_map::const_iterator j =
3954 	      priv_->deleted_enumerators_.find(name);
3955 	    if (j == priv_->deleted_enumerators_.end())
3956 	      priv_->inserted_enumerators_[name] = n;
3957 	    else
3958 	      {
3959 		if (j->second != n)
3960 		  priv_->changed_enumerators_[j->first] =
3961 		    std::make_pair(j->second, n);
3962 		priv_->deleted_enumerators_.erase(j);
3963 	      }
3964 	  }
3965       }
3966   }
3967 }
3968 
3969 /// Populate the vector of children node of the @ref diff base type
3970 /// sub-object of this instance of @ref enum_diff.
3971 ///
3972 /// The children node can then later be retrieved using
3973 /// diff::children_node().
3974 void
chain_into_hierarchy()3975 enum_diff::chain_into_hierarchy()
3976 {append_child_node(underlying_type_diff());}
3977 
3978 /// Constructor for enum_diff.
3979 ///
3980 /// @param first the first enum type of the diff.
3981 ///
3982 /// @param second the second enum type of the diff.
3983 ///
3984 /// @param underlying_type_diff the diff of the two underlying types
3985 /// of the two enum types.
3986 ///
3987 /// @param ctxt the diff context to use.
enum_diff(const enum_type_decl_sptr first,const enum_type_decl_sptr second,const diff_sptr underlying_type_diff,const diff_context_sptr ctxt)3988 enum_diff::enum_diff(const enum_type_decl_sptr	first,
3989 		     const enum_type_decl_sptr	second,
3990 		     const diff_sptr		underlying_type_diff,
3991 		     const diff_context_sptr	ctxt)
3992   : type_diff_base(first, second, ctxt),
3993     priv_(new priv(underlying_type_diff))
3994 {}
3995 
3996 /// @return the first enum of the diff.
3997 const enum_type_decl_sptr
first_enum() const3998 enum_diff::first_enum() const
3999 {return dynamic_pointer_cast<enum_type_decl>(first_subject());}
4000 
4001 /// @return the second enum of the diff.
4002 const enum_type_decl_sptr
second_enum() const4003 enum_diff::second_enum() const
4004 {return dynamic_pointer_cast<enum_type_decl>(second_subject());}
4005 
4006 /// @return the diff of the two underlying enum types.
4007 diff_sptr
underlying_type_diff() const4008 enum_diff::underlying_type_diff() const
4009 {return priv_->underlying_type_diff_;}
4010 
4011 /// @return a map of the enumerators that were deleted.
4012 const string_enumerator_map&
deleted_enumerators() const4013 enum_diff::deleted_enumerators() const
4014 {return priv_->deleted_enumerators_;}
4015 
4016 /// @return a map of the enumerators that were inserted
4017 const string_enumerator_map&
inserted_enumerators() const4018 enum_diff::inserted_enumerators() const
4019 {return priv_->inserted_enumerators_;}
4020 
4021 /// @return a map of the enumerators that were changed
4022 const string_changed_enumerator_map&
changed_enumerators() const4023 enum_diff::changed_enumerators() const
4024 {return priv_->changed_enumerators_;}
4025 
4026 /// @return the pretty representation of the current instance of @ref
4027 /// enum_diff.
4028 const string&
get_pretty_representation() const4029 enum_diff::get_pretty_representation() const
4030 {
4031   if (diff::priv_->pretty_representation_.empty())
4032     {
4033       std::ostringstream o;
4034       o << "enum_diff["
4035 	<< first_subject()->get_pretty_representation()
4036 	<< ", "
4037 	<< second_subject()->get_pretty_representation()
4038 	<< "]";
4039       diff::priv_->pretty_representation_ = o.str();
4040     }
4041   return diff::priv_->pretty_representation_;
4042 }
4043 
4044 /// Return true iff the current diff node carries a change.
4045 ///
4046 /// @return true iff the current diff node carries a change.
4047 bool
has_changes() const4048 enum_diff::has_changes() const
4049 {return first_enum() != second_enum();}
4050 
4051 /// @return the kind of local change carried by the current diff node.
4052 /// The value returned is zero if the current node carries no local
4053 /// change.
4054 enum change_kind
has_local_changes() const4055 enum_diff::has_local_changes() const
4056 {
4057   ir::change_kind k = ir::NO_CHANGE_KIND;
4058   if (!equals(*first_enum(), *second_enum(), &k))
4059     return k & ir::ALL_LOCAL_CHANGES_MASK;
4060   return ir::NO_CHANGE_KIND;
4061 }
4062 
4063 /// Report the differences between the two enums.
4064 ///
4065 /// @param out the output stream to send the report to.
4066 ///
4067 /// @param indent the string to use for indentation.
4068 void
report(ostream & out,const string & indent) const4069 enum_diff::report(ostream& out, const string& indent) const
4070 {
4071   context()->get_reporter()->report(*this, out, indent);
4072 }
4073 
4074 /// Compute the set of changes between two instances of @ref
4075 /// enum_type_decl.
4076 ///
4077 /// Note that the two types must have been created in the same @ref
4078 /// environment, otherwise, this function aborts.
4079 ///
4080 /// @param first a pointer to the first enum_type_decl to consider.
4081 ///
4082 /// @param second a pointer to the second enum_type_decl to consider.
4083 ///
4084 /// @return the resulting diff of the two enums @p first and @p
4085 /// second.
4086 ///
4087 /// @param ctxt the diff context to use.
4088 enum_diff_sptr
compute_diff(const enum_type_decl_sptr first,const enum_type_decl_sptr second,diff_context_sptr ctxt)4089 compute_diff(const enum_type_decl_sptr first,
4090 	     const enum_type_decl_sptr second,
4091 	     diff_context_sptr ctxt)
4092 {
4093   diff_sptr ud = compute_diff_for_types(first->get_underlying_type(),
4094 					second->get_underlying_type(),
4095 					ctxt);
4096   enum_diff_sptr d(new enum_diff(first, second, ud, ctxt));
4097   if (first != second)
4098     {
4099       compute_diff(first->get_enumerators().begin(),
4100 		   first->get_enumerators().end(),
4101 		   second->get_enumerators().begin(),
4102 		   second->get_enumerators().end(),
4103 		   d->priv_->enumerators_changes_);
4104       d->ensure_lookup_tables_populated();
4105     }
4106   ctxt->initialize_canonical_diff(d);
4107 
4108   return d;
4109 }
4110 // </enum_diff stuff>
4111 
4112 // <class_or_union_diff stuff>
4113 
4114 /// Test if the current diff node carries a member type change for a
4115 /// member type which name is the same as the name of a given type
4116 /// declaration.
4117 ///
4118 /// @param d the type declaration which name should be equal to the
4119 /// name of the member type that might have changed.
4120 ///
4121 /// @return the member type that has changed, iff there were a member
4122 /// type (which name is the same as the name of @p d) that changed.
4123 /// Note that the member type that is returned is the new value of the
4124 /// member type that changed.
4125 type_or_decl_base_sptr
member_type_has_changed(decl_base_sptr d) const4126 class_or_union_diff::priv::member_type_has_changed(decl_base_sptr d) const
4127 {
4128   string qname = d->get_qualified_name();
4129   string_diff_sptr_map::const_iterator it =
4130     changed_member_types_.find(qname);
4131 
4132   return ((it == changed_member_types_.end())
4133 	  ? type_or_decl_base_sptr()
4134 	  : it->second->second_subject());
4135 }
4136 
4137 /// Test if the current diff node carries a data member change for a
4138 /// data member which name is the same as the name of a given type
4139 /// declaration.
4140 ///
4141 /// @param d the type declaration which name should be equal to the
4142 /// name of the data member that might have changed.
4143 ///
4144 /// @return the data member that has changed, iff there were a data
4145 /// member type (which name is the same as the name of @p d) that
4146 /// changed.  Note that the data member that is returned is the new
4147 /// value of the data member that changed.
4148 decl_base_sptr
subtype_changed_dm(decl_base_sptr d) const4149 class_or_union_diff::priv::subtype_changed_dm(decl_base_sptr d) const
4150 {
4151   string qname = d->get_qualified_name();
4152   string_var_diff_sptr_map::const_iterator it =
4153     subtype_changed_dm_.find(qname);
4154 
4155   if (it == subtype_changed_dm_.end())
4156     return decl_base_sptr();
4157   return it->second->second_var();
4158 }
4159 
4160 /// Test if the current diff node carries a member class template
4161 /// change for a member class template which name is the same as the
4162 /// name of a given type declaration.
4163 ///
4164 /// @param d the type declaration which name should be equal to the
4165 /// name of the member class template that might have changed.
4166 ///
4167 /// @return the member class template that has changed, iff there were
4168 /// a member class template (which name is the same as the name of @p
4169 /// d) that changed.  Note that the member class template that is
4170 /// returned is the new value of the member class template that
4171 /// changed.
4172 decl_base_sptr
member_class_tmpl_has_changed(decl_base_sptr d) const4173 class_or_union_diff::priv::member_class_tmpl_has_changed(decl_base_sptr d) const
4174 {
4175   string qname = d->get_qualified_name();
4176   string_diff_sptr_map::const_iterator it =
4177     changed_member_class_tmpls_.find(qname);
4178 
4179   return ((it == changed_member_class_tmpls_.end())
4180 	  ? decl_base_sptr()
4181 	  : dynamic_pointer_cast<decl_base>(it->second->second_subject()));
4182 }
4183 
4184 /// Get the number of non static data members that were deleted.
4185 ///
4186 /// @return the number of non static data members that were deleted.
4187 size_t
get_deleted_non_static_data_members_number() const4188 class_or_union_diff::priv::get_deleted_non_static_data_members_number() const
4189 {
4190   size_t result = 0;
4191 
4192   for (string_decl_base_sptr_map::const_iterator i =
4193 	 deleted_data_members_.begin();
4194        i != deleted_data_members_.end();
4195        ++i)
4196     if (is_member_decl(i->second)
4197 	&& !get_member_is_static(i->second))
4198       ++result;
4199 
4200   return result;
4201 }
4202 
4203 /// Get the number of non static data members that were inserted.
4204 ///
4205 /// @return the number of non static data members that were inserted.
4206 size_t
get_inserted_non_static_data_members_number() const4207 class_or_union_diff::priv::get_inserted_non_static_data_members_number() const
4208 {
4209   size_t result = 0;
4210 
4211   for (string_decl_base_sptr_map::const_iterator i =
4212 	 inserted_data_members_.begin();
4213        i != inserted_data_members_.end();
4214        ++i)
4215     if (is_member_decl(i->second)
4216 	&& !get_member_is_static(i->second))
4217       ++result;
4218 
4219   return result;
4220 }
4221 
4222 /// Get the number of data member sub-type changes carried by the
4223 /// current diff node that were filtered out.
4224 ///
4225 /// @param local_only if true, it means that only (filtered) local
4226 /// changes are considered.
4227 ///
4228 /// @return the number of data member sub-type changes carried by the
4229 /// current diff node that were filtered out.
4230 size_t
count_filtered_subtype_changed_dm(bool local_only)4231 class_or_union_diff::priv::count_filtered_subtype_changed_dm(bool local_only)
4232 {
4233   size_t num_filtered= 0;
4234   for (var_diff_sptrs_type::const_iterator i =
4235 	 sorted_subtype_changed_dm_.begin();
4236        i != sorted_subtype_changed_dm_.end();
4237        ++i)
4238     {
4239       if (local_only)
4240 	{
4241 	  if ((*i)->has_changes()
4242 	      && !(*i)->has_local_changes_to_be_reported())
4243 	    ++num_filtered;
4244 	}
4245       else
4246 	{
4247 	  if ((*i)->is_filtered_out())
4248 	    ++num_filtered;
4249 	}
4250     }
4251   return num_filtered;
4252 }
4253 
4254 /// Get the number of data member changes carried by the current diff
4255 /// node that were filtered out.
4256 ///
4257 /// @param local_only if true, it means that only (filtered) local
4258 /// changes are considered.
4259 ///
4260 /// @return the number of data member changes carried by the current
4261 /// diff node that were filtered out.
4262 size_t
count_filtered_changed_dm(bool local_only)4263 class_or_union_diff::priv::count_filtered_changed_dm(bool local_only)
4264 {
4265   size_t num_filtered= 0;
4266 
4267   for (unsigned_var_diff_sptr_map::const_iterator i = changed_dm_.begin();
4268        i != changed_dm_.end();
4269        ++i)
4270     {
4271       diff_sptr diff = i->second;
4272       if (local_only)
4273 	{
4274 	  if ((diff->has_changes() && !diff->has_local_changes_to_be_reported())
4275 	      || diff->is_filtered_out())
4276 	    ++num_filtered;
4277 	}
4278       else
4279 	{
4280 	  if (diff->is_filtered_out())
4281 	    ++num_filtered;
4282 	}
4283     }
4284   return num_filtered;
4285 }
4286 
4287 /// Skip the processing of the current member function if its
4288 /// virtual-ness is disallowed by the user.
4289 ///
4290 /// This is to be used in the member functions below that are used to
4291 /// count the number of filtered inserted, deleted and changed member
4292 /// functions.
4293 #define SKIP_MEM_FN_IF_VIRTUALITY_DISALLOWED				\
4294   do {									\
4295     if (get_member_function_is_virtual(f)					\
4296 	|| get_member_function_is_virtual(s))				\
4297       {								\
4298 	if (!(allowed_category | VIRTUAL_MEMBER_CHANGE_CATEGORY))	\
4299 	  continue;							\
4300       }								\
4301     else								\
4302       {								\
4303 	if (!(allowed_category | NON_VIRT_MEM_FUN_CHANGE_CATEGORY))	\
4304 	  continue;							\
4305       }								\
4306   } while (false)
4307 
4308 /// Get the number of member functions changes carried by the current
4309 /// diff node that were filtered out.
4310 ///
4311 /// @return the number of member functions changes carried by the
4312 /// current diff node that were filtered out.
4313 size_t
count_filtered_changed_mem_fns(const diff_context_sptr & ctxt)4314 class_or_union_diff::priv::count_filtered_changed_mem_fns
4315 (const diff_context_sptr& ctxt)
4316 {
4317   size_t count = 0;
4318   diff_category allowed_category = ctxt->get_allowed_category();
4319 
4320   for (function_decl_diff_sptrs_type::const_iterator i =
4321 	 sorted_changed_member_functions_.begin();
4322        i != sorted_changed_member_functions_.end();
4323        ++i)
4324     {
4325       method_decl_sptr f =
4326 	dynamic_pointer_cast<method_decl>
4327 	((*i)->first_function_decl());
4328       ABG_ASSERT(f);
4329 
4330       method_decl_sptr s =
4331 	dynamic_pointer_cast<method_decl>
4332 	((*i)->second_function_decl());
4333       ABG_ASSERT(s);
4334 
4335       SKIP_MEM_FN_IF_VIRTUALITY_DISALLOWED;
4336 
4337       diff_sptr diff = *i;
4338       ctxt->maybe_apply_filters(diff);
4339 
4340       if (diff->is_filtered_out())
4341 	++count;
4342     }
4343 
4344   return count;
4345 }
4346 
4347 /// Get the number of member functions insertions carried by the current
4348 /// diff node that were filtered out.
4349 ///
4350 /// @return the number of member functions insertions carried by the
4351 /// current diff node that were filtered out.
4352 size_t
count_filtered_inserted_mem_fns(const diff_context_sptr & ctxt)4353 class_or_union_diff::priv::count_filtered_inserted_mem_fns
4354 (const diff_context_sptr& ctxt)
4355 {
4356     size_t count = 0;
4357   diff_category allowed_category = ctxt->get_allowed_category();
4358 
4359   for (string_member_function_sptr_map::const_iterator i =
4360 	 inserted_member_functions_.begin();
4361        i != inserted_member_functions_.end();
4362        ++i)
4363     {
4364       method_decl_sptr f = i->second,
4365 	s = i->second;
4366 
4367       SKIP_MEM_FN_IF_VIRTUALITY_DISALLOWED;
4368 
4369       diff_sptr diff = compute_diff_for_decls(f, s, ctxt);
4370       ctxt->maybe_apply_filters(diff);
4371 
4372       if (diff->get_category() != NO_CHANGE_CATEGORY
4373 	  && diff->is_filtered_out())
4374 	++count;
4375     }
4376 
4377   return count;
4378 }
4379 
4380 /// Get the number of member functions deletions carried by the current
4381 /// diff node that were filtered out.
4382 ///
4383 /// @return the number of member functions deletions carried by the
4384 /// current diff node that were filtered out.
4385 size_t
count_filtered_deleted_mem_fns(const diff_context_sptr & ctxt)4386 class_or_union_diff::priv::count_filtered_deleted_mem_fns
4387 (const diff_context_sptr& ctxt)
4388 {
4389   size_t count = 0;
4390   diff_category allowed_category = ctxt->get_allowed_category();
4391 
4392   for (string_member_function_sptr_map::const_iterator i =
4393 	 deleted_member_functions_.begin();
4394        i != deleted_member_functions_.end();
4395        ++i)
4396     {
4397       method_decl_sptr f = i->second,
4398 	s = i->second;
4399 
4400       SKIP_MEM_FN_IF_VIRTUALITY_DISALLOWED;
4401 
4402       diff_sptr diff = compute_diff_for_decls(f, s, ctxt);
4403       ctxt->maybe_apply_filters(diff);
4404 
4405       if (diff->get_category() != NO_CHANGE_CATEGORY
4406 	  && diff->is_filtered_out())
4407 	++count;
4408     }
4409 
4410   return count;
4411 }
4412 
4413 /// Clear the lookup tables useful for reporting.
4414 ///
4415 /// This function must be updated each time a lookup table is added or
4416 /// removed from the class_or_union_diff::priv.
4417 void
clear_lookup_tables()4418 class_or_union_diff::clear_lookup_tables()
4419 {
4420   priv_->deleted_member_types_.clear();
4421   priv_->inserted_member_types_.clear();
4422   priv_->changed_member_types_.clear();
4423   priv_->deleted_data_members_.clear();
4424   priv_->inserted_data_members_.clear();
4425   priv_->subtype_changed_dm_.clear();
4426   priv_->deleted_member_functions_.clear();
4427   priv_->inserted_member_functions_.clear();
4428   priv_->changed_member_functions_.clear();
4429   priv_->deleted_member_class_tmpls_.clear();
4430   priv_->inserted_member_class_tmpls_.clear();
4431   priv_->changed_member_class_tmpls_.clear();
4432 }
4433 
4434 /// Tests if the lookup tables are empty.
4435 ///
4436 /// @return true if the lookup tables are empty, false otherwise.
4437 bool
lookup_tables_empty(void) const4438 class_or_union_diff::lookup_tables_empty(void) const
4439 {
4440   return (priv_->deleted_member_types_.empty()
4441 	  && priv_->inserted_member_types_.empty()
4442 	  && priv_->changed_member_types_.empty()
4443 	  && priv_->deleted_data_members_.empty()
4444 	  && priv_->inserted_data_members_.empty()
4445 	  && priv_->subtype_changed_dm_.empty()
4446 	  && priv_->inserted_member_functions_.empty()
4447 	  && priv_->deleted_member_functions_.empty()
4448 	  && priv_->changed_member_functions_.empty()
4449 	  && priv_->deleted_member_class_tmpls_.empty()
4450 	  && priv_->inserted_member_class_tmpls_.empty()
4451 	  && priv_->changed_member_class_tmpls_.empty());
4452 }
4453 
4454 /// If the lookup tables are not yet built, walk the differences and
4455 /// fill them.
4456 void
ensure_lookup_tables_populated(void) const4457 class_or_union_diff::ensure_lookup_tables_populated(void) const
4458 {
4459   {
4460     edit_script& e = priv_->member_types_changes_;
4461 
4462     for (vector<deletion>::const_iterator it = e.deletions().begin();
4463 	 it != e.deletions().end();
4464 	 ++it)
4465       {
4466 	unsigned i = it->index();
4467 	decl_base_sptr d =
4468 	  get_type_declaration(first_class_or_union()->get_member_types()[i]);
4469 	class_or_union_sptr record_type = is_class_or_union_type(d);
4470 	if (record_type && record_type->get_is_declaration_only())
4471 	  continue;
4472 	string name = d->get_name();
4473 	priv_->deleted_member_types_[name] = d;
4474       }
4475 
4476     for (vector<insertion>::const_iterator it = e.insertions().begin();
4477 	 it != e.insertions().end();
4478 	 ++it)
4479       {
4480 	for (vector<unsigned>::const_iterator iit =
4481 	       it->inserted_indexes().begin();
4482 	     iit != it->inserted_indexes().end();
4483 	     ++iit)
4484 	  {
4485 	    unsigned i = *iit;
4486 	    decl_base_sptr d =
4487 	      get_type_declaration(second_class_or_union()->get_member_types()[i]);
4488 	    class_or_union_sptr record_type = is_class_or_union_type(d);
4489 	    if (record_type && record_type->get_is_declaration_only())
4490 	      continue;
4491 	    string name = d->get_name();
4492 	    string_decl_base_sptr_map::const_iterator j =
4493 	      priv_->deleted_member_types_.find(name);
4494 	    if (j != priv_->deleted_member_types_.end())
4495 	      {
4496 		if (*j->second != *d)
4497 		  priv_->changed_member_types_[name] =
4498 		    compute_diff(j->second, d, context());
4499 
4500 		priv_->deleted_member_types_.erase(j);
4501 	      }
4502 	    else
4503 	      priv_->inserted_member_types_[name] = d;
4504 	  }
4505       }
4506   }
4507 
4508   {
4509     edit_script& e = priv_->data_members_changes_;
4510 
4511     for (vector<deletion>::const_iterator it = e.deletions().begin();
4512 	 it != e.deletions().end();
4513 	 ++it)
4514       {
4515 	unsigned i = it->index();
4516 	var_decl_sptr data_member =
4517 	  is_var_decl(first_class_or_union()->get_non_static_data_members()[i]);
4518 	string name = data_member->get_anon_dm_reliable_name();
4519 
4520 	ABG_ASSERT(priv_->deleted_data_members_.find(name)
4521 		   == priv_->deleted_data_members_.end());
4522 	priv_->deleted_data_members_[name] = data_member;
4523       }
4524 
4525     for (vector<insertion>::const_iterator it = e.insertions().begin();
4526 	 it != e.insertions().end();
4527 	 ++it)
4528       {
4529 	for (vector<unsigned>::const_iterator iit =
4530 	       it->inserted_indexes().begin();
4531 	     iit != it->inserted_indexes().end();
4532 	     ++iit)
4533 	  {
4534 	    unsigned i = *iit;
4535 	    decl_base_sptr d =
4536 	      second_class_or_union()->get_non_static_data_members()[i];
4537 	    var_decl_sptr added_dm = is_var_decl(d);
4538 	    string name = added_dm->get_anon_dm_reliable_name();
4539 	    ABG_ASSERT(priv_->inserted_data_members_.find(name)
4540 		       == priv_->inserted_data_members_.end());
4541 
4542 	    bool ignore_added_anonymous_data_member = false;
4543 	    if (is_anonymous_data_member(added_dm))
4544 	      {
4545 		//
4546 		// Handle insertion of anonymous data member to
4547 		// replace existing data members.
4548 		//
4549 		// For instance consider this:
4550 		//   struct S
4551 		//   {
4552 		//     int a;
4553 		//     int b;
4554 		//     int c;
4555 		//   };// end struct S
4556 		//
4557 		//   Where the data members 'a' and 'b' are replaced
4558 		//   by an anonymous data member without changing the
4559 		//   effective bit layout of the structure:
4560 		//
4561 		//   struct S
4562 		//   {
4563 		//     struct
4564 		//     {
4565 		//       union
4566 		//       {
4567 		//         int a;
4568 		//         char a_1;
4569 		//       };
4570 		//       union
4571 		//       {
4572 		//         int b;
4573 		//         char b_1;
4574 		//       };
4575 		//     };
4576 		//     int c;
4577 		//   }; // end struct S
4578 		//
4579 		var_decl_sptr replaced_dm, replacing_dm;
4580 		bool added_anon_dm_changes_dm = false;
4581 		// The vector of data members replaced by anonymous
4582 		// data members.
4583 		vector<var_decl_sptr> dms_replaced_by_anon_dm;
4584 
4585 		//
4586 		// Let's start collecting the set of data members
4587 		// which have been replaced by anonymous types in a
4588 		// harmless way.  These are going to be collected into
4589 		// dms_replaced_by_anon_dm and, ultimately, into
4590 		// priv_->dms_replaced_by_adms_
4591 		//
4592 		for (string_decl_base_sptr_map::const_iterator it =
4593 		       priv_->deleted_data_members_.begin();
4594 		     it != priv_->deleted_data_members_.end();
4595 		     ++it)
4596 		  {
4597 		    // We don't support this pattern for anonymous
4598 		    // data members themselves being replaced.  If
4599 		    // that occurs then we'll just report it verbatim.
4600 		    if (is_anonymous_data_member(it->second))
4601 		      continue;
4602 
4603 		    string deleted_dm_name = it->second->get_name();
4604 		    if ((replacing_dm =
4605 			 find_data_member_from_anonymous_data_member(added_dm,
4606 								     deleted_dm_name)))
4607 		      {
4608 			// So it looks like replacing_dm might have
4609 			// replaced the data member which name is
4610 			// 'deleted_dm_name'.  Let's look deeper to be
4611 			// sure.
4612 			//
4613 			// Note that replacing_dm is part (member) of
4614 			// an anonymous data member that might replace
4615 			// replaced_dm.
4616 
4617 			// So let's get that replaced data member.
4618 			replaced_dm = is_var_decl(it->second);
4619 			size_t replaced_dm_offset =
4620 			  get_data_member_offset(replaced_dm),
4621 			replacing_dm_offset =
4622 			  get_absolute_data_member_offset(replacing_dm);
4623 
4624 			if (replaced_dm_offset != replacing_dm_offset)
4625 			  {
4626 			    // So the replacing data member and the
4627 			    // replaced data member don't have the
4628 			    // same offset.  This is not the pattern we
4629 			    // are looking for.  Rather, it looks like
4630 			    // the anonymous data member has *changed*
4631 			    // the data member.
4632 			    added_anon_dm_changes_dm = true;
4633 			    break;
4634 			  }
4635 
4636 			if (replaced_dm->get_type()->get_size_in_bits()
4637 			    == replaced_dm->get_type()->get_size_in_bits())
4638 			  dms_replaced_by_anon_dm.push_back(replaced_dm);
4639 			else
4640 			  {
4641 			    added_anon_dm_changes_dm = true;
4642 			    break;
4643 			  }
4644 		      }
4645 		  }
4646 
4647 		// Now walk dms_replaced_by_anon_dm to fill up
4648 		// priv_->dms_replaced_by_adms_ with the set of data
4649 		// members replaced by anonymous data members.
4650 		if (!added_anon_dm_changes_dm
4651 		    && !dms_replaced_by_anon_dm.empty())
4652 		  {
4653 		    // See if the added data member isn't too big.
4654 		    type_base_sptr added_dm_type = added_dm->get_type();
4655 		    ABG_ASSERT(added_dm_type);
4656 		    var_decl_sptr new_next_dm =
4657 		      get_next_data_member(second_class_or_union(),
4658 					   added_dm);
4659 		    var_decl_sptr old_next_dm =
4660 		      first_class_or_union()->find_data_member(new_next_dm);
4661 
4662 		    if (!old_next_dm
4663 			|| (old_next_dm
4664 			    && (get_absolute_data_member_offset(old_next_dm)
4665 				== get_absolute_data_member_offset(new_next_dm))))
4666 		      {
4667 			// None of the data members that are replaced
4668 			// by the added union should be considered as
4669 			// having been deleted.
4670 			ignore_added_anonymous_data_member = true;
4671 			for (vector<var_decl_sptr>::const_iterator i =
4672 			       dms_replaced_by_anon_dm.begin();
4673 			     i != dms_replaced_by_anon_dm.end();
4674 			     ++i)
4675 			  {
4676 			    string n = (*i)->get_name();
4677 			    priv_->dms_replaced_by_adms_[n] =
4678 			      added_dm;
4679 			    priv_->deleted_data_members_.erase(n);
4680 			  }
4681 		      }
4682 		  }
4683 	      }
4684 
4685 	    if (!ignore_added_anonymous_data_member)
4686 	      {
4687 		// Detect changed data members.
4688 		//
4689 		// A changed data member (that we shall name D) is a data
4690 		// member that satisfies the conditions below:
4691 		//
4692 		// 1/ It must have been added.
4693 		//
4694 		// 2/ It must have been deleted as well.
4695 		//
4696 		// 3/ It there must be a non-empty difference between the
4697 		// deleted D and the added D.
4698 		string_decl_base_sptr_map::const_iterator j =
4699 		  priv_->deleted_data_members_.find(name);
4700 		if (j != priv_->deleted_data_members_.end())
4701 		  {
4702 		    if (*j->second != *d)
4703 		      {
4704 			var_decl_sptr old_dm = is_var_decl(j->second);
4705 			priv_->subtype_changed_dm_[name]=
4706 			  compute_diff(old_dm, added_dm, context());
4707 		      }
4708 		    priv_->deleted_data_members_.erase(j);
4709 		  }
4710 		else
4711 		  priv_->inserted_data_members_[name] = d;
4712 	      }
4713 	  }
4714       }
4715 
4716     // Now detect when a data member is deleted from offset N and
4717     // another one is added to offset N.  In that case, we want to be
4718     // able to say that the data member at offset N changed.
4719     for (string_decl_base_sptr_map::const_iterator i =
4720 	   priv_->deleted_data_members_.begin();
4721 	 i != priv_->deleted_data_members_.end();
4722 	 ++i)
4723       {
4724 	unsigned offset = get_data_member_offset(i->second);
4725 	priv_->deleted_dm_by_offset_[offset] = i->second;
4726       }
4727 
4728     for (string_decl_base_sptr_map::const_iterator i =
4729 	   priv_->inserted_data_members_.begin();
4730 	 i != priv_->inserted_data_members_.end();
4731 	 ++i)
4732       {
4733 	unsigned offset = get_data_member_offset(i->second);
4734 	priv_->inserted_dm_by_offset_[offset] = i->second;
4735       }
4736 
4737     for (unsigned_decl_base_sptr_map::const_iterator i =
4738 	   priv_->inserted_dm_by_offset_.begin();
4739 	 i != priv_->inserted_dm_by_offset_.end();
4740 	 ++i)
4741       {
4742 	unsigned_decl_base_sptr_map::const_iterator j =
4743 	  priv_->deleted_dm_by_offset_.find(i->first);
4744 	if (j != priv_->deleted_dm_by_offset_.end())
4745 	  {
4746 	    var_decl_sptr old_dm = is_var_decl(j->second);
4747 	    var_decl_sptr new_dm = is_var_decl(i->second);
4748 	    priv_->changed_dm_[i->first] =
4749 	      compute_diff(old_dm, new_dm, context());
4750 	  }
4751       }
4752 
4753     for (unsigned_var_diff_sptr_map::const_iterator i =
4754 	   priv_->changed_dm_.begin();
4755 	 i != priv_->changed_dm_.end();
4756 	 ++i)
4757       {
4758 	priv_->deleted_dm_by_offset_.erase(i->first);
4759 	priv_->inserted_dm_by_offset_.erase(i->first);
4760 	priv_->deleted_data_members_.erase
4761 	  (i->second->first_var()->get_anon_dm_reliable_name());
4762 	priv_->inserted_data_members_.erase
4763 	  (i->second->second_var()->get_anon_dm_reliable_name());
4764       }
4765   }
4766   sort_string_data_member_diff_sptr_map(priv_->subtype_changed_dm_,
4767 					priv_->sorted_subtype_changed_dm_);
4768   sort_unsigned_data_member_diff_sptr_map(priv_->changed_dm_,
4769 					  priv_->sorted_changed_dm_);
4770 
4771   {
4772     edit_script& e = priv_->member_class_tmpls_changes_;
4773 
4774     for (vector<deletion>::const_iterator it = e.deletions().begin();
4775 	 it != e.deletions().end();
4776 	 ++it)
4777       {
4778 	unsigned i = it->index();
4779 	decl_base_sptr d =
4780 	  first_class_or_union()->get_member_class_templates()[i]->
4781 	  as_class_tdecl();
4782 	string name = d->get_name();
4783 	ABG_ASSERT(priv_->deleted_member_class_tmpls_.find(name)
4784 	       == priv_->deleted_member_class_tmpls_.end());
4785 	priv_->deleted_member_class_tmpls_[name] = d;
4786       }
4787 
4788     for (vector<insertion>::const_iterator it = e.insertions().begin();
4789 	 it != e.insertions().end();
4790 	 ++it)
4791       {
4792 	for (vector<unsigned>::const_iterator iit =
4793 	       it->inserted_indexes().begin();
4794 	     iit != it->inserted_indexes().end();
4795 	     ++iit)
4796 	  {
4797 	    unsigned i = *iit;
4798 	    decl_base_sptr d =
4799 	      second_class_or_union()->get_member_class_templates()[i]->
4800 	      as_class_tdecl();
4801 	    string name = d->get_name();
4802 	    ABG_ASSERT(priv_->inserted_member_class_tmpls_.find(name)
4803 		   == priv_->inserted_member_class_tmpls_.end());
4804 	    string_decl_base_sptr_map::const_iterator j =
4805 	      priv_->deleted_member_class_tmpls_.find(name);
4806 	    if (j != priv_->deleted_member_class_tmpls_.end())
4807 	      {
4808 		if (*j->second != *d)
4809 		  priv_->changed_member_types_[name]=
4810 		    compute_diff(j->second, d, context());
4811 		priv_->deleted_member_class_tmpls_.erase(j);
4812 	      }
4813 	    else
4814 	      priv_->inserted_member_class_tmpls_[name] = d;
4815 	  }
4816       }
4817   }
4818   sort_string_diff_sptr_map(priv_->changed_member_types_,
4819 			    priv_->sorted_changed_member_types_);
4820 }
4821 
4822 /// Allocate the memory for the priv_ pimpl data member of the @ref
4823 /// class_or_union_diff class.
4824 void
allocate_priv_data()4825 class_or_union_diff::allocate_priv_data()
4826 {
4827   if (!priv_)
4828     priv_.reset(new priv);
4829 }
4830 
4831 /// Constructor for the @ref class_or_union_diff class.
4832 ///
4833 /// @param first_scope the first @ref class_or_union of the diff node.
4834 ///
4835 /// @param second_scope the second @ref class_or_union of the diff node.
4836 ///
4837 /// @param ctxt the context of the diff.
class_or_union_diff(class_or_union_sptr first_scope,class_or_union_sptr second_scope,diff_context_sptr ctxt)4838 class_or_union_diff::class_or_union_diff(class_or_union_sptr first_scope,
4839 					 class_or_union_sptr second_scope,
4840 					 diff_context_sptr ctxt)
4841   : type_diff_base(first_scope, second_scope, ctxt)
4842     //priv_(new priv)
4843 {}
4844 
4845 /// Getter of the private data of the @ref class_or_union_diff type.
4846 ///
4847 /// Note that due to an optimization, the private data of @ref
4848 /// class_or_union_diff can be shared among several instances of
4849 /// class_or_union_diff, so you should never try to access
4850 /// class_or_union_diff::priv directly.
4851 ///
4852 /// When class_or_union_diff::priv is shared, this function returns
4853 /// the correct shared one.
4854 ///
4855 /// @return the (possibly) shared private data of the current instance
4856 /// of @ref class_or_union_diff.
4857 const class_or_union_diff::priv_ptr&
get_priv() const4858 class_or_union_diff::get_priv() const
4859 {
4860   if (priv_)
4861     return priv_;
4862 
4863   // If the current class_or_union_diff::priv member is empty, then look for
4864   // the shared one, from the canonical type.
4865   class_or_union_diff *canonical =
4866     dynamic_cast<class_or_union_diff*>(get_canonical_diff());
4867   ABG_ASSERT(canonical);
4868   ABG_ASSERT(canonical->priv_);
4869 
4870   return canonical->priv_;
4871 }
4872 
4873 /// Destructor of class_or_union_diff.
~class_or_union_diff()4874 class_or_union_diff::~class_or_union_diff()
4875 {
4876 }
4877 
4878 /// @return the first @ref class_or_union involved in the diff.
4879 class_or_union_sptr
first_class_or_union() const4880 class_or_union_diff::first_class_or_union() const
4881 {return is_class_or_union_type(first_subject());}
4882 
4883 /// @return the second @ref class_or_union involved in the diff.
4884 class_or_union_sptr
second_class_or_union() const4885 class_or_union_diff::second_class_or_union() const
4886 {return is_class_or_union_type(second_subject());}
4887 
4888 /// @return the edit script of the member types of the two @ref
4889 /// class_or_union.
4890 const edit_script&
member_types_changes() const4891 class_or_union_diff::member_types_changes() const
4892 {return get_priv()->member_types_changes_;}
4893 
4894 /// @return the edit script of the member types of the two @ref
4895 /// class_or_union.
4896 edit_script&
member_types_changes()4897 class_or_union_diff::member_types_changes()
4898 {return get_priv()->member_types_changes_;}
4899 
4900 /// @return the edit script of the data members of the two @ref
4901 /// class_or_union.
4902 const edit_script&
data_members_changes() const4903 class_or_union_diff::data_members_changes() const
4904 {return get_priv()->data_members_changes_;}
4905 
4906 /// @return the edit script of the data members of the two @ref
4907 /// class_or_union.
4908 edit_script&
data_members_changes()4909 class_or_union_diff::data_members_changes()
4910 {return get_priv()->data_members_changes_;}
4911 
4912 /// Getter for the data members that got inserted.
4913 ///
4914 /// @return a map of data members that got inserted.
4915 const string_decl_base_sptr_map&
inserted_data_members() const4916 class_or_union_diff::inserted_data_members() const
4917 {return get_priv()->inserted_data_members_;}
4918 
4919 /// Getter for the data members that got deleted.
4920 ///
4921 /// @return a map of data members that got deleted.
4922 const string_decl_base_sptr_map&
deleted_data_members() const4923 class_or_union_diff::deleted_data_members() const
4924 {return get_priv()->deleted_data_members_;}
4925 
4926 /// @return the edit script of the member functions of the two @ref
4927 /// class_or_union.
4928 const edit_script&
member_fns_changes() const4929 class_or_union_diff::member_fns_changes() const
4930 {return get_priv()->member_fns_changes_;}
4931 
4932 /// Getter for the virtual members functions that have had a change in
4933 /// a sub-type, without having a change in their symbol name.
4934 ///
4935 /// @return a sorted vector of virtual member functions that have a
4936 /// sub-type change.
4937 const function_decl_diff_sptrs_type&
changed_member_fns() const4938 class_or_union_diff::changed_member_fns() const
4939 {return get_priv()->sorted_changed_member_functions_;}
4940 
4941 /// @return the edit script of the member functions of the two
4942 /// classes.
4943 edit_script&
member_fns_changes()4944 class_or_union_diff::member_fns_changes()
4945 {return get_priv()->member_fns_changes_;}
4946 
4947 /// @return a map of member functions that got deleted.
4948 const string_member_function_sptr_map&
deleted_member_fns() const4949 class_or_union_diff::deleted_member_fns() const
4950 {return get_priv()->deleted_member_functions_;}
4951 
4952 /// @return a map of member functions that got inserted.
4953 const string_member_function_sptr_map&
inserted_member_fns() const4954 class_or_union_diff::inserted_member_fns() const
4955 {return get_priv()->inserted_member_functions_;}
4956 
4957 /// Getter of the sorted vector of data members that got replaced by
4958 /// another data member.
4959 ///
4960 /// @return sorted vector of changed data member.
4961 const var_diff_sptrs_type&
sorted_changed_data_members() const4962 class_or_union_diff::sorted_changed_data_members() const
4963 {return get_priv()->sorted_changed_dm_;}
4964 
4965 /// Count the number of /filtered/ data members that got replaced by
4966 /// another data member.
4967 ///
4968 /// @return the number of changed data member that got filtered out.
4969 size_t
count_filtered_changed_data_members(bool local) const4970 class_or_union_diff::count_filtered_changed_data_members(bool local) const
4971 {return get_priv()->count_filtered_changed_dm(local);}
4972 
4973 /// Getter of the sorted vector of data members with a (sub-)type change.
4974 ///
4975 /// @return sorted vector of changed data member.
4976 const var_diff_sptrs_type&
sorted_subtype_changed_data_members() const4977 class_or_union_diff::sorted_subtype_changed_data_members() const
4978 {return get_priv()->sorted_subtype_changed_dm_;}
4979 
4980 /// Count the number of /filtered/ data members with a sub-type change.
4981 ///
4982 /// @return the number of changed data member that got filtered out.
4983 size_t
count_filtered_subtype_changed_data_members(bool local) const4984 class_or_union_diff::count_filtered_subtype_changed_data_members(bool local) const
4985 {return get_priv()->count_filtered_subtype_changed_dm(local);}
4986 
4987 /// Get the map of data members that got replaced by anonymous data
4988 /// members.
4989 ///
4990 /// The key of a map entry is the name of the replaced data member and
4991 /// the value is the anonymous data member that replaces it.
4992 ///
4993 /// @return the map of data members replaced by anonymous data
4994 /// members.
4995 const string_decl_base_sptr_map&
data_members_replaced_by_adms() const4996 class_or_union_diff::data_members_replaced_by_adms() const
4997 {return get_priv()->dms_replaced_by_adms_;}
4998 
4999 /// Get an ordered vector of of data members that got replaced by
5000 /// anonymous data members.
5001 ///
5002 /// This returns a vector of pair of two data members: the one that
5003 /// was replaced, and the anonymous data member that replaced it.
5004 ///
5005 /// @return the sorted vector data members replaced by anonymous data members.
5006 const changed_var_sptrs_type&
ordered_data_members_replaced_by_adms() const5007 class_or_union_diff::ordered_data_members_replaced_by_adms() const
5008 {
5009   if (priv_->dms_replaced_by_adms_ordered_.empty())
5010     {
5011       for (string_decl_base_sptr_map::const_iterator it =
5012 	     priv_->dms_replaced_by_adms_.begin();
5013 	   it != priv_->dms_replaced_by_adms_.end();
5014 	   ++it)
5015 	{
5016 	  const var_decl_sptr dm =
5017 	    first_class_or_union()->find_data_member(it->first);
5018 	  ABG_ASSERT(dm);
5019 	  changed_var_sptr changed_dm(dm, is_data_member(it->second));
5020 	  priv_->dms_replaced_by_adms_ordered_.push_back(changed_dm);
5021 	}
5022       sort_changed_data_members(priv_->dms_replaced_by_adms_ordered_);
5023     }
5024 
5025   return priv_->dms_replaced_by_adms_ordered_;
5026 }
5027 
5028 /// @return the edit script of the member function templates of the two
5029 /// @ref class_or_union.
5030 const edit_script&
member_fn_tmpls_changes() const5031 class_or_union_diff::member_fn_tmpls_changes() const
5032 {return get_priv()->member_fn_tmpls_changes_;}
5033 
5034 /// @return the edit script of the member function templates of the
5035 /// two @ref class_or_union.
5036 edit_script&
member_fn_tmpls_changes()5037 class_or_union_diff::member_fn_tmpls_changes()
5038 {return get_priv()->member_fn_tmpls_changes_;}
5039 
5040 /// @return the edit script of the member class templates of the two
5041 /// @ref class_or_union.
5042 const edit_script&
member_class_tmpls_changes() const5043 class_or_union_diff::member_class_tmpls_changes() const
5044 {return get_priv()->member_class_tmpls_changes_;}
5045 
5046 /// @return the edit script of the member class templates of the two
5047 /// @ref class_or_union.
5048 edit_script&
member_class_tmpls_changes()5049 class_or_union_diff::member_class_tmpls_changes()
5050 {return get_priv()->member_class_tmpls_changes_;}
5051 
5052 /// Test if the current diff node carries a change.
5053 bool
has_changes() const5054 class_or_union_diff::has_changes() const
5055 {return first_class_or_union() != second_class_or_union();}
5056 
5057 /// @return the kind of local change carried by the current diff node.
5058 /// The value returned is zero if the current node carries no local
5059 /// change.
5060 enum change_kind
has_local_changes() const5061 class_or_union_diff::has_local_changes() const
5062 {
5063   ir::change_kind k = ir::NO_CHANGE_KIND;
5064   if (!equals(*first_class_or_union(), *second_class_or_union(), &k))
5065     return k & ir::ALL_LOCAL_CHANGES_MASK;
5066   return ir::NO_CHANGE_KIND;
5067 }
5068 
5069 
5070 /// Report the changes carried by the current @ref class_or_union_diff
5071 /// node in a textual format.
5072 ///
5073 /// @param out the output stream to write the textual report to.
5074 ///
5075 /// @param indent the number of white space to use as indentation.
5076 void
report(ostream & out,const string & indent) const5077 class_or_union_diff::report(ostream& out, const string& indent) const
5078 {
5079   context()->get_reporter()->report(*this, out, indent);
5080 }
5081 
5082 /// Populate the vector of children node of the @ref diff base type
5083 /// sub-object of this instance of @ref class_or_union_diff.
5084 ///
5085 /// The children node can then later be retrieved using
5086 /// diff::children_node().
5087 void
chain_into_hierarchy()5088 class_or_union_diff::chain_into_hierarchy()
5089 {
5090   // data member changes
5091   for (var_diff_sptrs_type::const_iterator i =
5092 	 get_priv()->sorted_subtype_changed_dm_.begin();
5093        i != get_priv()->sorted_subtype_changed_dm_.end();
5094        ++i)
5095     if (diff_sptr d = *i)
5096       append_child_node(d);
5097 
5098   for (var_diff_sptrs_type::const_iterator i =
5099 	 get_priv()->sorted_changed_dm_.begin();
5100        i != get_priv()->sorted_changed_dm_.end();
5101        ++i)
5102     if (diff_sptr d = *i)
5103       append_child_node(d);
5104 
5105   // member types changes
5106   for (diff_sptrs_type::const_iterator i =
5107 	 get_priv()->sorted_changed_member_types_.begin();
5108        i != get_priv()->sorted_changed_member_types_.end();
5109        ++i)
5110     if (diff_sptr d = *i)
5111       append_child_node(d);
5112 
5113   // member function changes
5114   for (function_decl_diff_sptrs_type::const_iterator i =
5115 	 get_priv()->sorted_changed_member_functions_.begin();
5116        i != get_priv()->sorted_changed_member_functions_.end();
5117        ++i)
5118     if (diff_sptr d = *i)
5119       append_child_node(d);
5120 }
5121 
5122 // </class_or_union_diff stuff>
5123 
5124 //<class_diff stuff>
5125 
5126 /// Clear the lookup tables useful for reporting.
5127 ///
5128 /// This function must be updated each time a lookup table is added or
5129 /// removed from the class_diff::priv.
5130 void
clear_lookup_tables(void)5131 class_diff::clear_lookup_tables(void)
5132 {
5133   priv_->deleted_bases_.clear();
5134   priv_->inserted_bases_.clear();
5135   priv_->changed_bases_.clear();
5136 }
5137 
5138 /// Tests if the lookup tables are empty.
5139 ///
5140 /// @return true if the lookup tables are empty, false otherwise.
5141 bool
lookup_tables_empty(void) const5142 class_diff::lookup_tables_empty(void) const
5143 {
5144   return (priv_->deleted_bases_.empty()
5145 	  && priv_->inserted_bases_.empty()
5146 	  && priv_->changed_bases_.empty());
5147 }
5148 
5149 /// Find a virtual destructor in a map of member functions
5150 ///
5151 /// @param map the map of member functions.  Note that the key of the
5152 /// map is the member function name.  The key is the member function.
5153 ///
5154 /// @return an iterator to the destructor found or, if no virtual destructor
5155 /// was found, return map.end()
5156 static string_member_function_sptr_map::const_iterator
find_virtual_dtor_in_map(const string_member_function_sptr_map & map)5157 find_virtual_dtor_in_map(const string_member_function_sptr_map& map)
5158 {
5159   for (string_member_function_sptr_map::const_iterator i = map.begin();
5160        i !=map.end();
5161        ++i)
5162     {
5163       if (get_member_function_is_dtor(i->second)
5164 	  && get_member_function_is_virtual(i->second))
5165 	return i;
5166     }
5167   return map.end();
5168 }
5169 
5170 /// If the lookup tables are not yet built, walk the differences and
5171 /// fill them.
5172 void
ensure_lookup_tables_populated(void) const5173 class_diff::ensure_lookup_tables_populated(void) const
5174 {
5175   class_or_union_diff::ensure_lookup_tables_populated();
5176 
5177   if (!lookup_tables_empty())
5178     return;
5179 
5180   {
5181     edit_script& e = get_priv()->base_changes_;
5182 
5183     for (vector<deletion>::const_iterator it = e.deletions().begin();
5184 	 it != e.deletions().end();
5185 	 ++it)
5186       {
5187 	unsigned i = it->index();
5188 	class_decl::base_spec_sptr b =
5189 	  first_class_decl()->get_base_specifiers()[i];
5190 	string name = b->get_base_class()->get_qualified_name();
5191 	ABG_ASSERT(get_priv()->deleted_bases_.find(name)
5192 	       == get_priv()->deleted_bases_.end());
5193 	get_priv()->deleted_bases_[name] = b;
5194       }
5195 
5196     for (vector<insertion>::const_iterator it = e.insertions().begin();
5197 	 it != e.insertions().end();
5198 	 ++it)
5199       {
5200 	for (vector<unsigned>::const_iterator iit =
5201 	       it->inserted_indexes().begin();
5202 	     iit != it->inserted_indexes().end();
5203 	     ++iit)
5204 	  {
5205 	    unsigned i = *iit;
5206 	    class_decl::base_spec_sptr b =
5207 	      second_class_decl()->get_base_specifiers()[i];
5208 	    string name = b->get_base_class()->get_qualified_name();
5209 	    ABG_ASSERT(get_priv()->inserted_bases_.find(name)
5210 		   == get_priv()->inserted_bases_.end());
5211 	    string_base_sptr_map::const_iterator j =
5212 	      get_priv()->deleted_bases_.find(name);
5213 	    if (j != get_priv()->deleted_bases_.end())
5214 	      {
5215 		if (j->second != b)
5216 		  get_priv()->changed_bases_[name] =
5217 		    compute_diff(j->second, b, context());
5218 		else
5219 		  // The base class changed place.  IOW, the base
5220 		  // classes got re-arranged.  Let's keep track of the
5221 		  // base classes that moved.
5222 		  get_priv()->moved_bases_.push_back(b);
5223 		get_priv()->deleted_bases_.erase(j);
5224 	      }
5225 	    else
5226 	      get_priv()->inserted_bases_[name] = b;
5227 	  }
5228       }
5229   }
5230 
5231   sort_string_base_sptr_map(get_priv()->deleted_bases_,
5232 			    get_priv()->sorted_deleted_bases_);
5233   sort_string_base_sptr_map(get_priv()->inserted_bases_,
5234 			    get_priv()->sorted_inserted_bases_);
5235   sort_string_base_diff_sptr_map(get_priv()->changed_bases_,
5236 				 get_priv()->sorted_changed_bases_);
5237 
5238   {
5239     const class_or_union_diff::priv_ptr &p = class_or_union_diff::get_priv();
5240 
5241     edit_script& e = p->member_fns_changes_;
5242 
5243     for (vector<deletion>::const_iterator it = e.deletions().begin();
5244 	 it != e.deletions().end();
5245 	 ++it)
5246       {
5247 	unsigned i = it->index();
5248 	method_decl_sptr mem_fn =
5249 	  first_class_decl()->get_virtual_mem_fns()[i];
5250 	string name = mem_fn->get_linkage_name();
5251 	if (name.empty())
5252 	  name = mem_fn->get_pretty_representation();
5253 	ABG_ASSERT(!name.empty());
5254 	if (p->deleted_member_functions_.find(name)
5255 	    != p->deleted_member_functions_.end())
5256 	  continue;
5257 	p->deleted_member_functions_[name] = mem_fn;
5258       }
5259 
5260     for (vector<insertion>::const_iterator it = e.insertions().begin();
5261 	 it != e.insertions().end();
5262 	 ++it)
5263       {
5264 	for (vector<unsigned>::const_iterator iit =
5265 	       it->inserted_indexes().begin();
5266 	     iit != it->inserted_indexes().end();
5267 	     ++iit)
5268 	  {
5269 	    unsigned i = *iit;
5270 
5271 	    method_decl_sptr mem_fn =
5272 	      second_class_decl()->get_virtual_mem_fns()[i];
5273 	    string name = mem_fn->get_linkage_name();
5274 	    if (name.empty())
5275 	      name = mem_fn->get_pretty_representation();
5276 	    ABG_ASSERT(!name.empty());
5277 	    if (p->inserted_member_functions_.find(name)
5278 		!= p->inserted_member_functions_.end())
5279 	      continue;
5280 	    string_member_function_sptr_map::const_iterator j =
5281 	      p->deleted_member_functions_.find(name);
5282 
5283 	    if (j != p->deleted_member_functions_.end())
5284 	      {
5285 		if (*j->second != *mem_fn)
5286 		  p->changed_member_functions_[name] =
5287 		    compute_diff(static_pointer_cast<function_decl>(j->second),
5288 				 static_pointer_cast<function_decl>(mem_fn),
5289 				 context());
5290 		p->deleted_member_functions_.erase(j);
5291 	      }
5292 	    else
5293 	      p->inserted_member_functions_[name] = mem_fn;
5294 	  }
5295       }
5296 
5297     // Now walk the allegedly deleted member functions; check if their
5298     // underlying symbols are deleted as well; otherwise, consider
5299     // that the member function in question hasn't been deleted.
5300 
5301     // Also, while walking the deleted member functions, we attend at
5302     // a particular cleanup business related to (virtual) C++
5303     // destructors:
5304     //
5305     // In the binary, there can be at least three types of
5306     // destructors, defined in the document
5307     // https://itanium-cxx-abi.github.io/cxx-abi/abi.html#definitions:
5308     //
5309     //   1/ Base object destructor (aka D2 destructor):
5310     //
5311     //      "A function that runs the destructors for non-static data
5312     //      members of T and non-virtual direct base classes of T. "
5313     //
5314     //   2/ Complete object destructor (aka D1 destructor):
5315     //
5316     //      "A function that, in addition to the actions required of a
5317     //      base object destructor, runs the destructors for the
5318     //      virtual base classes of T."
5319     //
5320     //   3/ Deleting destructor (aka D0 destructor):
5321     //
5322     //      "A function that, in addition to the actions required of a
5323     //      complete object destructor, calls the appropriate
5324     //      deallocation function (i.e,. operator delete) for T."
5325     //
5326     // With binaries generated by GCC, these destructors might be ELF
5327     // clones of each others, meaning, their ELF symbols can be
5328     // aliases.
5329     //
5330     // Also, note that because the actual destructor invoked by user
5331     // code is virtual, it's invoked through the vtable.  So the
5332     // presence of the underlying D0, D1, D2 in the binary might vary
5333     // without that variation being an ABI issue, provided that the
5334     // destructor invoked through the vtable is present.
5335     //
5336     // So, a particular virtual destructor implementation for a class
5337     // might disapear and be replaced by another one in a subsequent
5338     // version of the binary.  If all versions of the binary have an
5339     // actual virtual destructor, things might be considered fine.
5340     vector<string> to_delete;
5341     corpus_sptr f = context()->get_first_corpus(),
5342       s = context()->get_second_corpus();
5343     if (s)
5344       for (string_member_function_sptr_map::const_iterator i =
5345 	     deleted_member_fns().begin();
5346 	   i != deleted_member_fns().end();
5347 	   ++i)
5348 	{
5349 	  if (get_member_function_is_virtual(i->second))
5350 	    {
5351 	      if (get_member_function_is_dtor(i->second))
5352 		{
5353 		  // If a particular virtual destructor is deleted,
5354 		  // but the new binary still have a virtual
5355 		  // destructor for that class we consider that things
5356 		  // are fine.  For instance, in the
5357 		  // tests/data/test-diff-pkg/tbb-4.1-9.20130314.fc22.x86_64--tbb-4.3-3.20141204.fc23.x86_64-report-0.txt
5358 		  // test, a new D4 destructor replaces the old ones.
5359 		  // But because the virtual destructor is still
5360 		  // there, this is not an ABI issue.  So let's detect
5361 		  // this case.
5362 		  auto it =
5363 		    find_virtual_dtor_in_map(p->inserted_member_functions_);
5364 		  if (it != p->inserted_member_functions_.end())
5365 		    {
5366 		      // So the deleted virtual destructor is not
5367 		      // really deleted, because a proper virtual
5368 		      // destructor was added to the new version.
5369 		      // Let's remove the deleted/added virtual
5370 		      // destructor then.
5371 		      string name =
5372 			(!i->second->get_linkage_name().empty())
5373 			? i->second->get_linkage_name()
5374 			: i->second->get_pretty_representation();
5375 		      to_delete.push_back(name);
5376 		      p->inserted_member_functions_.erase(it);
5377 		    }
5378 		}
5379 	      continue;
5380 	    }
5381 	  // We assume that all non-virtual member functions functions
5382 	  // we look at here have ELF symbols.
5383 	  if (!i->second->get_symbol()
5384 	      || s->lookup_function_symbol(*i->second->get_symbol()))
5385 	    to_delete.push_back(i->first);
5386 	}
5387 
5388 
5389     for (vector<string>::const_iterator i = to_delete.begin();
5390 	 i != to_delete.end();
5391 	 ++i)
5392       p->deleted_member_functions_.erase(*i);
5393 
5394     // Do something similar for added functions.
5395     to_delete.clear();
5396     if (f)
5397       for (string_member_function_sptr_map::const_iterator i =
5398 	     inserted_member_fns().begin();
5399 	   i != inserted_member_fns().end();
5400 	   ++i)
5401 	{
5402 	  if (get_member_function_is_virtual(i->second))
5403 	    continue;
5404 	  // We assume that all non-virtual member functions functions
5405 	  // we look at here have ELF symbols.
5406 	  if (!i->second->get_symbol()
5407 	      || f->lookup_function_symbol(*i->second->get_symbol()))
5408 	    to_delete.push_back(i->first);
5409 	}
5410 
5411     for (vector<string>::const_iterator i = to_delete.begin();
5412 	 i != to_delete.end();
5413 	 ++i)
5414       p->inserted_member_functions_.erase(*i);
5415 
5416     sort_string_member_function_sptr_map(p->deleted_member_functions_,
5417 					 p->sorted_deleted_member_functions_);
5418 
5419     sort_string_member_function_sptr_map(p->inserted_member_functions_,
5420 					 p->sorted_inserted_member_functions_);
5421 
5422     sort_string_virtual_member_function_diff_sptr_map
5423       (p->changed_member_functions_,
5424        p->sorted_changed_member_functions_);
5425   }
5426 }
5427 
5428 /// Allocate the memory for the priv_ pimpl data member of the @ref
5429 /// class_diff class.
5430 void
allocate_priv_data()5431 class_diff::allocate_priv_data()
5432 {
5433   class_or_union_diff::allocate_priv_data();
5434   if (!priv_)
5435     priv_.reset(new priv);
5436 }
5437 
5438 /// Test whether a given base class has changed.  A base class has
5439 /// changed if it's in both in deleted *and* inserted bases.
5440 ///
5441 ///@param d the declaration for the base class to consider.
5442 ///
5443 /// @return the new base class if the given base class has changed, or
5444 /// NULL if it hasn't.
5445 class_decl::base_spec_sptr
base_has_changed(class_decl::base_spec_sptr d) const5446 class_diff::priv::base_has_changed(class_decl::base_spec_sptr d) const
5447 {
5448   string qname = d->get_base_class()->get_qualified_name();
5449   string_base_diff_sptr_map::const_iterator it =
5450     changed_bases_.find(qname);
5451 
5452   return (it == changed_bases_.end())
5453     ? class_decl::base_spec_sptr()
5454     : it->second->second_base();
5455 
5456 }
5457 
5458 /// Count the number of bases classes whose changes got filtered out.
5459 ///
5460 /// @return the number of bases classes whose changes got filtered
5461 /// out.
5462 size_t
count_filtered_bases()5463 class_diff::priv::count_filtered_bases()
5464 {
5465   size_t num_filtered = 0;
5466   for (base_diff_sptrs_type::const_iterator i = sorted_changed_bases_.begin();
5467        i != sorted_changed_bases_.end();
5468        ++i)
5469     {
5470       diff_sptr diff = *i;
5471       if (diff && diff->is_filtered_out())
5472 	++num_filtered;
5473     }
5474   return num_filtered;
5475 }
5476 
5477 /// Populate the vector of children node of the @ref diff base type
5478 /// sub-object of this instance of @ref class_diff.
5479 ///
5480 /// The children node can then later be retrieved using
5481 /// diff::children_node().
5482 void
chain_into_hierarchy()5483 class_diff::chain_into_hierarchy()
5484 {
5485   class_or_union_diff::chain_into_hierarchy();
5486 
5487   // base class changes.
5488   for (base_diff_sptrs_type::const_iterator i =
5489 	 get_priv()->sorted_changed_bases_.begin();
5490        i != get_priv()->sorted_changed_bases_.end();
5491        ++i)
5492     if (diff_sptr d = *i)
5493       append_child_node(d);
5494 }
5495 
5496 /// Constructor of class_diff
5497 ///
5498 /// @param first_scope the first class of the diff.
5499 ///
5500 /// @param second_scope the second class of the diff.
5501 ///
5502 /// @param ctxt the diff context to use.
class_diff(class_decl_sptr first_scope,class_decl_sptr second_scope,diff_context_sptr ctxt)5503 class_diff::class_diff(class_decl_sptr first_scope,
5504 		       class_decl_sptr second_scope,
5505 		       diff_context_sptr ctxt)
5506   : class_or_union_diff(first_scope, second_scope, ctxt)
5507     //  We don't initialize the priv_ data member here.  This is an
5508     //  optimization to reduce memory consumption (and also execution
5509     //  time) for cases where there are a lot of instances of
5510     //  class_diff in the same equivalence class.  In compute_diff(),
5511     //  the priv_ is set to the priv_ of the canonical diff node.
5512     //  See PR libabigail/17948.
5513 {}
5514 
~class_diff()5515 class_diff::~class_diff()
5516 {}
5517 
5518 /// Getter of the private data of the @ref class_diff type.
5519 ///
5520 /// Note that due to an optimization, the private data of @ref
5521 /// class_diff can be shared among several instances of class_diff, so
5522 /// you should never try to access class_diff::priv directly.
5523 ///
5524 /// When class_diff::priv is shared, this function returns the correct
5525 /// shared one.
5526 ///
5527 /// @return the (possibly) shared private data of the current instance
5528 /// of class_diff.
5529 const class_diff::priv_ptr&
get_priv() const5530 class_diff::get_priv() const
5531 {
5532   if (priv_)
5533     return priv_;
5534 
5535   // If the current class_diff::priv member is empty, then look for
5536   // the shared one, from the canonical type.
5537   class_diff *canonical =
5538     dynamic_cast<class_diff*>(get_canonical_diff());
5539   ABG_ASSERT(canonical);
5540   ABG_ASSERT(canonical->priv_);
5541 
5542   return canonical->priv_;
5543 }
5544 
5545 /// @return the pretty representation of the current instance of @ref
5546 /// class_diff.
5547 const string&
get_pretty_representation() const5548 class_diff::get_pretty_representation() const
5549 {
5550   if (diff::priv_->pretty_representation_.empty())
5551     {
5552       std::ostringstream o;
5553       o << "class_diff["
5554 	<< first_subject()->get_pretty_representation()
5555 	<< ", "
5556 	<< second_subject()->get_pretty_representation()
5557 	<< "]";
5558       diff::priv_->pretty_representation_ = o.str();
5559     }
5560   return diff::priv_->pretty_representation_;
5561 }
5562 
5563 /// Return true iff the current diff node carries a change.
5564 ///
5565 /// @return true iff the current diff node carries a change.
5566 bool
has_changes() const5567 class_diff::has_changes() const
5568 {return (first_class_decl() != second_class_decl());}
5569 
5570 /// @return the kind of local change carried by the current diff node.
5571 /// The value returned is zero if the current node carries no local
5572 /// change.
5573 enum change_kind
has_local_changes() const5574 class_diff::has_local_changes() const
5575 {
5576   ir::change_kind k = ir::NO_CHANGE_KIND;
5577   if (!equals(*first_class_decl(), *second_class_decl(), &k))
5578     return k & ir::ALL_LOCAL_CHANGES_MASK;
5579   return ir::NO_CHANGE_KIND;
5580 }
5581 
5582 /// @return the first class invoveld in the diff.
5583 shared_ptr<class_decl>
first_class_decl() const5584 class_diff::first_class_decl() const
5585 {return dynamic_pointer_cast<class_decl>(first_subject());}
5586 
5587 /// Getter of the second class involved in the diff.
5588 ///
5589 /// @return the second class invoveld in the diff
5590 shared_ptr<class_decl>
second_class_decl() const5591 class_diff::second_class_decl() const
5592 {return dynamic_pointer_cast<class_decl>(second_subject());}
5593 
5594 /// @return the edit script of the bases of the two classes.
5595 const edit_script&
base_changes() const5596 class_diff::base_changes() const
5597 {return get_priv()->base_changes_;}
5598 
5599 /// Getter for the deleted base classes of the diff.
5600 ///
5601 /// @return a map containing the deleted base classes, keyed with
5602 /// their pretty representation.
5603 const string_base_sptr_map&
deleted_bases() const5604 class_diff::deleted_bases() const
5605 {return get_priv()->deleted_bases_;}
5606 
5607 /// Getter for the inserted base classes of the diff.
5608 ///
5609 /// @return a map containing the inserted base classes, keyed with
5610 /// their pretty representation.
5611 const string_base_sptr_map&
inserted_bases() const5612 class_diff::inserted_bases() const
5613 {return get_priv()->inserted_bases_;}
5614 
5615 /// Getter for the changed base classes of the diff.
5616 ///
5617 /// @return a sorted vector containing the changed base classes
5618 const base_diff_sptrs_type&
changed_bases()5619 class_diff::changed_bases()
5620 {return get_priv()->sorted_changed_bases_;}
5621 
5622 /// Getter for the vector of bases that "moved".
5623 /// That is, the vector of base types which position changed.  If this
5624 /// vector is not empty, it means the bases of the underlying class
5625 /// type got re-ordered.
5626 ///
5627 /// @return the vector of bases that moved.
5628 const vector<class_decl::base_spec_sptr>&
moved_bases() const5629 class_diff::moved_bases() const
5630 {return get_priv()->moved_bases_;}
5631 
5632 /// @return the edit script of the bases of the two classes.
5633 edit_script&
base_changes()5634 class_diff::base_changes()
5635 {return get_priv()->base_changes_;}
5636 
5637 /// Produce a basic report about the changes between two class_decl.
5638 ///
5639 /// @param out the output stream to report the changes to.
5640 ///
5641 /// @param indent the string to use as an indentation prefix in the
5642 /// report.
5643 void
report(ostream & out,const string & indent) const5644 class_diff::report(ostream& out, const string& indent) const
5645 {
5646   context()->get_reporter()->report(*this, out, indent);
5647 }
5648 
5649 /// Compute the set of changes between two instances of class_decl.
5650 ///
5651 /// Note that the two types must have been created in the same @ref
5652 /// environment, otherwise, this function aborts.
5653 ///
5654 /// @param first the first class_decl to consider.
5655 ///
5656 /// @param second the second class_decl to consider.
5657 ///
5658 /// @return changes the resulting changes.
5659 ///
5660 /// @param ctxt the diff context to use.
5661 class_diff_sptr
compute_diff(const class_decl_sptr first,const class_decl_sptr second,diff_context_sptr ctxt)5662 compute_diff(const class_decl_sptr	first,
5663 	     const class_decl_sptr	second,
5664 	     diff_context_sptr		ctxt)
5665 {
5666   class_decl_sptr f = is_class_type(look_through_decl_only_class(first)),
5667     s = is_class_type(look_through_decl_only_class(second));
5668 
5669   class_diff_sptr changes(new class_diff(f, s, ctxt));
5670 
5671   ctxt->initialize_canonical_diff(changes);
5672   ABG_ASSERT(changes->get_canonical_diff());
5673 
5674   if (!ctxt->get_canonical_diff_for(first, second))
5675     {
5676       // Either first or second is a decl-only class; let's set the
5677       // canonical diff here in that case.
5678       diff_sptr canonical_diff = ctxt->get_canonical_diff_for(changes);
5679       ABG_ASSERT(canonical_diff);
5680       ctxt->set_canonical_diff_for(first, second, canonical_diff);
5681     }
5682 
5683   // Ok, so this is an optimization.  Do not freak out if it looks
5684   // weird, because, well, it does look weird.  This speeds up
5685   // greatly, for instance, the test case given at PR
5686   // libabigail/17948.
5687   //
5688   // We are setting the private data of the new instance of class_diff
5689   // (which is 'changes') to the private data of its canonical
5690   // instance.  That is, we are sharing the private data of 'changes'
5691   // with the private data of its canonical instance to consume less
5692   // memory in cases where the equivalence class of 'changes' is huge.
5693   //
5694   // But if changes is its own canonical instance, then we initialize
5695   // its private data properly
5696   if (is_class_diff(changes->get_canonical_diff()) == changes.get())
5697     // changes is its own canonical instance, so it gets a brand new
5698     // private data.
5699     changes->allocate_priv_data();
5700   else
5701     {
5702       // changes has a non-empty equivalence class so it's going to
5703       // share its private data with its canonical instance.  Next
5704       // time class_diff::get_priv() is invoked, it's going to return
5705       // the shared private data of the canonical instance.
5706       return changes;
5707     }
5708 
5709   // Compare base specs
5710   compute_diff(f->get_base_specifiers().begin(),
5711 	       f->get_base_specifiers().end(),
5712 	       s->get_base_specifiers().begin(),
5713 	       s->get_base_specifiers().end(),
5714 	       changes->base_changes());
5715 
5716   // Do *not* compare member types because it generates lots of noise
5717   // and I doubt it's really useful.
5718 #if 0
5719   compute_diff(f->get_member_types().begin(),
5720 	       f->get_member_types().end(),
5721 	       s->get_member_types().begin(),
5722 	       s->get_member_types().end(),
5723 	       changes->member_types_changes());
5724 #endif
5725 
5726   // Compare data member
5727   compute_diff(f->get_non_static_data_members().begin(),
5728 	       f->get_non_static_data_members().end(),
5729 	       s->get_non_static_data_members().begin(),
5730 	       s->get_non_static_data_members().end(),
5731 	       changes->data_members_changes());
5732 
5733   // Compare virtual member functions
5734   compute_diff(f->get_virtual_mem_fns().begin(),
5735 	       f->get_virtual_mem_fns().end(),
5736 	       s->get_virtual_mem_fns().begin(),
5737 	       s->get_virtual_mem_fns().end(),
5738 	       changes->member_fns_changes());
5739 
5740   // Compare member function templates
5741   compute_diff(f->get_member_function_templates().begin(),
5742 	       f->get_member_function_templates().end(),
5743 	       s->get_member_function_templates().begin(),
5744 	       s->get_member_function_templates().end(),
5745 	       changes->member_fn_tmpls_changes());
5746 
5747   // Likewise, do not compare member class templates
5748 #if 0
5749   compute_diff(f->get_member_class_templates().begin(),
5750 	       f->get_member_class_templates().end(),
5751 	       s->get_member_class_templates().begin(),
5752 	       s->get_member_class_templates().end(),
5753 	       changes->member_class_tmpls_changes());
5754 #endif
5755 
5756   changes->ensure_lookup_tables_populated();
5757 
5758   return changes;
5759 }
5760 
5761 //</class_diff stuff>
5762 
5763 // <base_diff stuff>
5764 
5765 /// Populate the vector of children node of the @ref diff base type
5766 /// sub-object of this instance of @ref base_diff.
5767 ///
5768 /// The children node can then later be retrieved using
5769 /// diff::children_node().
5770 void
chain_into_hierarchy()5771 base_diff::chain_into_hierarchy()
5772 {append_child_node(get_underlying_class_diff());}
5773 
5774 /// @param first the first base spec to consider.
5775 ///
5776 /// @param second the second base spec to consider.
5777 ///
5778 /// @param ctxt the context of the diff.  Note that this context
5779 /// object must stay alive at least during the life time of the
5780 /// current instance of @ref base_diff.  Otherwise memory corruption
5781 /// issues occur.
base_diff(class_decl::base_spec_sptr first,class_decl::base_spec_sptr second,class_diff_sptr underlying,diff_context_sptr ctxt)5782 base_diff::base_diff(class_decl::base_spec_sptr first,
5783 		     class_decl::base_spec_sptr second,
5784 		     class_diff_sptr		underlying,
5785 		     diff_context_sptr		ctxt)
5786   : diff(first, second, ctxt),
5787     priv_(new priv(underlying))
5788 {}
5789 
5790 /// Getter for the first base spec of the diff object.
5791 ///
5792 /// @return the first base specifier for the diff object.
5793 class_decl::base_spec_sptr
first_base() const5794 base_diff::first_base() const
5795 {return dynamic_pointer_cast<class_decl::base_spec>(first_subject());}
5796 
5797 /// Getter for the second base spec of the diff object.
5798 ///
5799 /// @return the second base specifier for the diff object.
5800 class_decl::base_spec_sptr
second_base() const5801 base_diff::second_base() const
5802 {return dynamic_pointer_cast<class_decl::base_spec>(second_subject());}
5803 
5804 /// Getter for the diff object for the diff of the underlying base
5805 /// classes.
5806 ///
5807 /// @return the diff object for the diff of the underlying base
5808 /// classes.
5809 const class_diff_sptr
get_underlying_class_diff() const5810 base_diff::get_underlying_class_diff() const
5811 {return priv_->underlying_class_diff_;}
5812 
5813 /// Setter for the diff object for the diff of the underlyng base
5814 /// classes.
5815 ///
5816 /// @param d the new diff object for the diff of the underlying base
5817 /// classes.
5818 void
set_underlying_class_diff(class_diff_sptr d)5819 base_diff::set_underlying_class_diff(class_diff_sptr d)
5820 {priv_->underlying_class_diff_ = d;}
5821 
5822 /// @return the pretty representation for the current instance of @ref
5823 /// base_diff.
5824 const string&
get_pretty_representation() const5825 base_diff::get_pretty_representation() const
5826 {
5827   if (diff::priv_->pretty_representation_.empty())
5828     {
5829       std::ostringstream o;
5830       o << "base_diff["
5831 	<< first_subject()->get_pretty_representation()
5832 	<< ", "
5833 	<< second_subject()->get_pretty_representation()
5834 	<< "]";
5835       diff::priv_->pretty_representation_ = o.str();
5836     }
5837   return diff::priv_->pretty_representation_;
5838 }
5839 
5840 /// Return true iff the current diff node carries a change.
5841 ///
5842 /// Return true iff the current diff node carries a change.
5843 bool
has_changes() const5844 base_diff::has_changes() const
5845 {return first_base() != second_base();}
5846 
5847 /// @return the kind of local change carried by the current diff node.
5848 /// The value returned is zero if the current node carries no local
5849 /// change.
5850 enum change_kind
has_local_changes() const5851 base_diff::has_local_changes() const
5852 {
5853   ir::change_kind k = ir::NO_CHANGE_KIND;
5854   if (!equals(*first_base(), *second_base(), &k))
5855     return k & ir::ALL_LOCAL_CHANGES_MASK;
5856   return ir::NO_CHANGE_KIND;
5857 }
5858 
5859 /// Generates a report for the current instance of base_diff.
5860 ///
5861 /// @param out the output stream to send the report to.
5862 ///
5863 /// @param indent the string to use for indentation.
5864 void
report(ostream & out,const string & indent) const5865 base_diff::report(ostream& out, const string& indent) const
5866 {
5867   context()->get_reporter()->report(*this, out, indent);
5868 }
5869 
5870 /// Constructs the diff object representing a diff between two base
5871 /// class specifications.
5872 ///
5873 /// Note that the two artifacts must have been created in the same
5874 /// @ref environment, otherwise, this function aborts.
5875 ///
5876 /// @param first the first base class specification.
5877 ///
5878 /// @param second the second base class specification.
5879 ///
5880 /// @param ctxt the content of the diff.
5881 ///
5882 /// @return the resulting diff object.
5883 base_diff_sptr
compute_diff(const class_decl::base_spec_sptr first,const class_decl::base_spec_sptr second,diff_context_sptr ctxt)5884 compute_diff(const class_decl::base_spec_sptr	first,
5885 	     const class_decl::base_spec_sptr	second,
5886 	     diff_context_sptr			ctxt)
5887 {
5888   class_diff_sptr cl = compute_diff(first->get_base_class(),
5889 				    second->get_base_class(),
5890 				    ctxt);
5891   base_diff_sptr changes(new base_diff(first, second, cl, ctxt));
5892 
5893   ctxt->initialize_canonical_diff(changes);
5894 
5895   return changes;
5896 }
5897 
5898 // </base_diff stuff>
5899 
5900 
5901 // <union_diff stuff>
5902 
5903 /// Clear the lookup tables useful for reporting.
5904 ///
5905 /// This function must be updated each time a lookup table is added or
5906 /// removed from the union_diff::priv.
5907 void
clear_lookup_tables(void)5908 union_diff::clear_lookup_tables(void)
5909 {class_or_union_diff::clear_lookup_tables();}
5910 
5911 /// Tests if the lookup tables are empty.
5912 ///
5913 /// @return true if the lookup tables are empty, false otherwise.
5914 bool
lookup_tables_empty(void) const5915 union_diff::lookup_tables_empty(void) const
5916 {return class_or_union_diff::lookup_tables_empty();}
5917 
5918 /// If the lookup tables are not yet built, walk the differences and
5919 /// fill them.
5920 void
ensure_lookup_tables_populated(void) const5921 union_diff::ensure_lookup_tables_populated(void) const
5922 {class_or_union_diff::ensure_lookup_tables_populated();}
5923 
5924 /// Allocate the memory for the priv_ pimpl data member of the @ref
5925 /// union_diff class.
5926 void
allocate_priv_data()5927 union_diff::allocate_priv_data()
5928 {
5929   class_or_union_diff::allocate_priv_data();
5930 }
5931 
5932 /// Constructor for the @ref union_diff type.
5933 ///
5934 /// @param first_union the first object of the comparison.
5935 ///
5936 /// @param second_union the second object of the comparison.
5937 ///
5938 /// @param ctxt the context of the comparison.
union_diff(union_decl_sptr first_union,union_decl_sptr second_union,diff_context_sptr ctxt)5939 union_diff::union_diff(union_decl_sptr first_union,
5940 		       union_decl_sptr second_union,
5941 		       diff_context_sptr ctxt)
5942   : class_or_union_diff(first_union, second_union, ctxt)
5943 {}
5944 
5945 /// Destructor of the union_diff node.
~union_diff()5946 union_diff::~union_diff()
5947 {}
5948 
5949 /// @return the first object of the comparison.
5950 union_decl_sptr
first_union_decl() const5951 union_diff::first_union_decl() const
5952 {return is_union_type(first_subject());}
5953 
5954 /// @return the second object of the comparison.
5955 union_decl_sptr
second_union_decl() const5956 union_diff::second_union_decl() const
5957 {return is_union_type(second_subject());}
5958 
5959 /// @return the pretty representation of the current diff node.
5960 const string&
get_pretty_representation() const5961 union_diff::get_pretty_representation() const
5962 {
5963   if (diff::priv_->pretty_representation_.empty())
5964     {
5965       std::ostringstream o;
5966       o << "union_diff["
5967 	<< first_subject()->get_pretty_representation()
5968 	<< ", "
5969 	<< second_subject()->get_pretty_representation()
5970 	<< "]";
5971       diff::priv_->pretty_representation_ = o.str();
5972     }
5973   return diff::priv_->pretty_representation_;
5974 }
5975 
5976 /// Report the changes carried by the current @ref union_diff node in
5977 /// a textual format.
5978 ///
5979 /// @param out the output stream to write the textual report to.
5980 ///
5981 /// @param indent the number of white space to use as indentation.
5982 void
report(ostream & out,const string & indent) const5983 union_diff::report(ostream& out, const string& indent) const
5984 {
5985   context()->get_reporter()->report(*this, out, indent);
5986 }
5987 
5988 /// Compute the difference between two @ref union_decl types.
5989 ///
5990 /// Note that the two types must hav been created in the same
5991 /// environment, otherwise, this function aborts.
5992 ///
5993 /// @param first the first @ref union_decl to consider.
5994 ///
5995 /// @param second the second @ref union_decl to consider.
5996 ///
5997 /// @param ctxt the context of the diff to use.
5998 union_diff_sptr
compute_diff(const union_decl_sptr first,const union_decl_sptr second,diff_context_sptr ctxt)5999 compute_diff(const union_decl_sptr	first,
6000 	     const union_decl_sptr	second,
6001 	     diff_context_sptr	ctxt)
6002 {
6003   union_diff_sptr changes(new union_diff(first, second, ctxt));
6004 
6005   ctxt->initialize_canonical_diff(changes);
6006   ABG_ASSERT(changes->get_canonical_diff());
6007 
6008   // Ok, so this is an optimization.  Do not freak out if it looks
6009   // weird, because, well, it does look weird.  This speeds up
6010   // greatly, for instance, the test case given at PR
6011   // libabigail/17948.
6012   //
6013   // We are setting the private data of the new instance of class_diff
6014   // (which is 'changes') to the private data of its canonical
6015   // instance.  That is, we are sharing the private data of 'changes'
6016   // with the private data of its canonical instance to consume less
6017   // memory in cases where the equivalence class of 'changes' is huge.
6018   //
6019   // But if changes is its own canonical instance, then we initialize
6020   // its private data properly.
6021   if (is_union_diff(changes->get_canonical_diff()) ==  changes.get())
6022     // changes is its own canonical instance, so it gets a brand new
6023     // private data.
6024     changes->allocate_priv_data();
6025   else
6026     {
6027       // changes has a non-empty equivalence class so it's going to
6028       // share its private data with its canonical instance.  Next
6029       // time class_diff::get_priv() is invoked, it's going to return
6030       // the shared private data of the canonical instance.
6031       return changes;
6032     }
6033 
6034   // Compare data member
6035   compute_diff(first->get_non_static_data_members().begin(),
6036 	       first->get_non_static_data_members().end(),
6037 	       second->get_non_static_data_members().begin(),
6038 	       second->get_non_static_data_members().end(),
6039 	       changes->data_members_changes());
6040 
6041 #if 0
6042   // Compare member functions
6043   compute_diff(first->get_mem_fns().begin(),
6044 	       first->get_mem_fns().end(),
6045 	       second->get_mem_fns().begin(),
6046 	       second->get_mem_fns().end(),
6047 	       changes->member_fns_changes());
6048 
6049   // Compare member function templates
6050   compute_diff(first->get_member_function_templates().begin(),
6051 	       first->get_member_function_templates().end(),
6052 	       second->get_member_function_templates().begin(),
6053 	       second->get_member_function_templates().end(),
6054 	       changes->member_fn_tmpls_changes());
6055 #endif
6056 
6057   changes->ensure_lookup_tables_populated();
6058 
6059   return changes;
6060 }
6061 
6062 // </union_diff stuff>
6063 
6064 //<scope_diff stuff>
6065 
6066 /// Clear the lookup tables that are useful for reporting.
6067 ///
6068 /// This function must be updated each time a lookup table is added or
6069 /// removed.
6070 void
clear_lookup_tables()6071 scope_diff::clear_lookup_tables()
6072 {
6073   priv_->deleted_types_.clear();
6074   priv_->deleted_decls_.clear();
6075   priv_->inserted_types_.clear();
6076   priv_->inserted_decls_.clear();
6077   priv_->changed_types_.clear();
6078   priv_->changed_decls_.clear();
6079   priv_->removed_types_.clear();
6080   priv_->removed_decls_.clear();
6081   priv_->added_types_.clear();
6082   priv_->added_decls_.clear();
6083 }
6084 
6085 /// Tests if the lookup tables are empty.
6086 ///
6087 /// This function must be updated each time a lookup table is added or
6088 /// removed.
6089 ///
6090 /// @return true iff all the lookup tables are empty.
6091 bool
lookup_tables_empty() const6092 scope_diff::lookup_tables_empty() const
6093 {
6094   return (priv_->deleted_types_.empty()
6095 	  && priv_->deleted_decls_.empty()
6096 	  && priv_->inserted_types_.empty()
6097 	  && priv_->inserted_decls_.empty()
6098 	  && priv_->changed_types_.empty()
6099 	  && priv_->changed_decls_.empty()
6100 	  && priv_->removed_types_.empty()
6101 	  && priv_->removed_decls_.empty()
6102 	  && priv_->added_types_.empty()
6103 	  && priv_->added_decls_.empty());
6104 }
6105 
6106 /// If the lookup tables are not yet built, walk the member_changes_
6107 /// member and fill the lookup tables.
6108 void
ensure_lookup_tables_populated()6109 scope_diff::ensure_lookup_tables_populated()
6110 {
6111   if (!lookup_tables_empty())
6112     return;
6113 
6114   edit_script& e = priv_->member_changes_;
6115 
6116   // Populate deleted types & decls lookup tables.
6117   for (vector<deletion>::const_iterator i = e.deletions().begin();
6118        i != e.deletions().end();
6119        ++i)
6120     {
6121       decl_base_sptr decl = deleted_member_at(i);
6122       string qname = decl->get_qualified_name();
6123       if (is_type(decl))
6124 	{
6125 	  class_decl_sptr klass_decl = dynamic_pointer_cast<class_decl>(decl);
6126 	  if (klass_decl && klass_decl->get_is_declaration_only())
6127 	    continue;
6128 
6129 	  ABG_ASSERT(priv_->deleted_types_.find(qname)
6130 		 == priv_->deleted_types_.end());
6131 	  priv_->deleted_types_[qname] = decl;
6132 	}
6133       else
6134 	{
6135 	  ABG_ASSERT(priv_->deleted_decls_.find(qname)
6136 		 == priv_->deleted_decls_.end());
6137 	  priv_->deleted_decls_[qname] = decl;
6138 	}
6139     }
6140 
6141   // Populate inserted types & decls as well as chagned types & decls
6142   // lookup tables.
6143   for (vector<insertion>::const_iterator it = e.insertions().begin();
6144        it != e.insertions().end();
6145        ++it)
6146     {
6147       for (vector<unsigned>::const_iterator i = it->inserted_indexes().begin();
6148 	   i != it->inserted_indexes().end();
6149 	   ++i)
6150 	{
6151 	  decl_base_sptr decl = inserted_member_at(i);
6152 	  string qname = decl->get_qualified_name();
6153 	  if (is_type(decl))
6154 	    {
6155 	      class_decl_sptr klass_decl =
6156 		dynamic_pointer_cast<class_decl>(decl);
6157 	      if (klass_decl && klass_decl->get_is_declaration_only())
6158 		continue;
6159 
6160 	      ABG_ASSERT(priv_->inserted_types_.find(qname)
6161 		     == priv_->inserted_types_.end());
6162 	      string_decl_base_sptr_map::const_iterator j =
6163 		priv_->deleted_types_.find(qname);
6164 	      if (j != priv_->deleted_types_.end())
6165 		{
6166 		  if (*j->second != *decl)
6167 		    priv_->changed_types_[qname] =
6168 		      compute_diff(j->second, decl, context());
6169 		  priv_->deleted_types_.erase(j);
6170 		}
6171 	      else
6172 		priv_->inserted_types_[qname] = decl;
6173 	    }
6174 	  else
6175 	    {
6176 	      ABG_ASSERT(priv_->inserted_decls_.find(qname)
6177 		     == priv_->inserted_decls_.end());
6178 	      string_decl_base_sptr_map::const_iterator j =
6179 		priv_->deleted_decls_.find(qname);
6180 	      if (j != priv_->deleted_decls_.end())
6181 		{
6182 		  if (*j->second != *decl)
6183 		    priv_->changed_decls_[qname] =
6184 		      compute_diff(j->second, decl, context());
6185 		  priv_->deleted_decls_.erase(j);
6186 		}
6187 	      else
6188 		priv_->inserted_decls_[qname] = decl;
6189 	    }
6190 	}
6191     }
6192 
6193   sort_string_diff_sptr_map(priv_->changed_decls_,
6194 			    priv_->sorted_changed_decls_);
6195   sort_string_diff_sptr_map(priv_->changed_types_,
6196 			    priv_->sorted_changed_types_);
6197 
6198   // Populate removed types/decls lookup tables
6199   for (string_decl_base_sptr_map::const_iterator i =
6200 	 priv_->deleted_types_.begin();
6201        i != priv_->deleted_types_.end();
6202        ++i)
6203     {
6204       string_decl_base_sptr_map::const_iterator r =
6205 	priv_->inserted_types_.find(i->first);
6206       if (r == priv_->inserted_types_.end())
6207 	priv_->removed_types_[i->first] = i->second;
6208     }
6209   for (string_decl_base_sptr_map::const_iterator i =
6210 	 priv_->deleted_decls_.begin();
6211        i != priv_->deleted_decls_.end();
6212        ++i)
6213     {
6214       string_decl_base_sptr_map::const_iterator r =
6215 	priv_->inserted_decls_.find(i->first);
6216       if (r == priv_->inserted_decls_.end())
6217 	priv_->removed_decls_[i->first] = i->second;
6218     }
6219 
6220   // Populate added types/decls.
6221   for (string_decl_base_sptr_map::const_iterator i =
6222 	 priv_->inserted_types_.begin();
6223        i != priv_->inserted_types_.end();
6224        ++i)
6225     {
6226       string_decl_base_sptr_map::const_iterator r =
6227 	priv_->deleted_types_.find(i->first);
6228       if (r == priv_->deleted_types_.end())
6229 	priv_->added_types_[i->first] = i->second;
6230     }
6231   for (string_decl_base_sptr_map::const_iterator i =
6232 	 priv_->inserted_decls_.begin();
6233        i != priv_->inserted_decls_.end();
6234        ++i)
6235     {
6236       string_decl_base_sptr_map::const_iterator r =
6237 	priv_->deleted_decls_.find(i->first);
6238       if (r == priv_->deleted_decls_.end())
6239 	priv_->added_decls_[i->first] = i->second;
6240     }
6241 }
6242 
6243 /// Populate the vector of children node of the @ref diff base type
6244 /// sub-object of this instance of @ref scope_diff.
6245 ///
6246 /// The children node can then later be retrieved using
6247 /// diff::children_node().
6248 void
chain_into_hierarchy()6249 scope_diff::chain_into_hierarchy()
6250 {
6251   for (diff_sptrs_type::const_iterator i = changed_types().begin();
6252        i != changed_types().end();
6253        ++i)
6254     if (*i)
6255       append_child_node(*i);
6256 
6257   for (diff_sptrs_type::const_iterator i = changed_decls().begin();
6258        i != changed_decls().end();
6259        ++i)
6260     if (*i)
6261       append_child_node(*i);
6262 }
6263 
6264 /// Constructor for scope_diff
6265 ///
6266 /// @param first_scope the first scope to consider for the diff.
6267 ///
6268 /// @param second_scope the second scope to consider for the diff.
6269 ///
6270 /// @param ctxt the diff context to use.  Note that this context
6271 /// object must stay alive at least during the life time of the
6272 /// current instance of @ref scope_diff.  Otherwise memory corruption
6273 /// issues occur.
scope_diff(scope_decl_sptr first_scope,scope_decl_sptr second_scope,diff_context_sptr ctxt)6274 scope_diff::scope_diff(scope_decl_sptr first_scope,
6275 		       scope_decl_sptr second_scope,
6276 		       diff_context_sptr ctxt)
6277   : diff(first_scope, second_scope, ctxt),
6278     priv_(new priv)
6279 {}
6280 
6281 /// Getter for the first scope of the diff.
6282 ///
6283 /// @return the first scope of the diff.
6284 const scope_decl_sptr
first_scope() const6285 scope_diff::first_scope() const
6286 {return dynamic_pointer_cast<scope_decl>(first_subject());}
6287 
6288 /// Getter for the second scope of the diff.
6289 ///
6290 /// @return the second scope of the diff.
6291 const scope_decl_sptr
second_scope() const6292 scope_diff::second_scope() const
6293 {return dynamic_pointer_cast<scope_decl>(second_subject());}
6294 
6295 /// Accessor of the edit script of the members of a scope.
6296 ///
6297 /// This edit script is computed using the equality operator that
6298 /// applies to shared_ptr<decl_base>.
6299 ///
6300 /// That has interesting consequences.  For instance, consider two
6301 /// scopes S0 and S1.  S0 contains a class C0 and S1 contains a class
6302 /// S0'.  C0 and C0' have the same qualified name, but have different
6303 /// members.  The edit script will consider that C0 has been deleted
6304 /// from S0 and that S0' has been inserted.  This is a low level
6305 /// canonical representation of the changes; a higher level
6306 /// representation would give us a simpler way to say "the class C0
6307 /// has been modified into C0'".  But worry not.  We do have such
6308 /// higher representation as well; that is what changed_types() and
6309 /// changed_decls() is for.
6310 ///
6311 /// @return the edit script of the changes encapsulatd in this
6312 /// instance of scope_diff.
6313 const edit_script&
member_changes() const6314 scope_diff::member_changes() const
6315 {return priv_->member_changes_;}
6316 
6317 /// Accessor of the edit script of the members of a scope.
6318 ///
6319 /// This edit script is computed using the equality operator that
6320 /// applies to shared_ptr<decl_base>.
6321 ///
6322 /// That has interesting consequences.  For instance, consider two
6323 /// scopes S0 and S1.  S0 contains a class C0 and S1 contains a class
6324 /// S0'.  C0 and C0' have the same qualified name, but have different
6325 /// members.  The edit script will consider that C0 has been deleted
6326 /// from S0 and that S0' has been inserted.  This is a low level
6327 /// canonical representation of the changes; a higher level
6328 /// representation would give us a simpler way to say "the class C0
6329 /// has been modified into C0'".  But worry not.  We do have such
6330 /// higher representation as well; that is what changed_types() and
6331 /// changed_decls() is for.
6332 ///
6333 /// @return the edit script of the changes encapsulatd in this
6334 /// instance of scope_diff.
6335 edit_script&
member_changes()6336 scope_diff::member_changes()
6337 {return priv_->member_changes_;}
6338 
6339 /// Accessor that eases the manipulation of the edit script associated
6340 /// to this instance.  It returns the scope member that is reported
6341 /// (in the edit script) as deleted at a given index.
6342 ///
6343 /// @param i the index (in the edit script) of an element of the first
6344 /// scope that has been reported as being delete.
6345 ///
6346 /// @return the scope member that has been reported by the edit script
6347 /// as being deleted at index i.
6348 const decl_base_sptr
deleted_member_at(unsigned i) const6349 scope_diff::deleted_member_at(unsigned i) const
6350 {
6351   scope_decl_sptr scope = dynamic_pointer_cast<scope_decl>(first_subject());
6352  return scope->get_member_decls()[i];
6353 }
6354 
6355 /// Accessor that eases the manipulation of the edit script associated
6356 /// to this instance.  It returns the scope member (of the first scope
6357 /// of this diff instance) that is reported (in the edit script) as
6358 /// deleted at a given iterator.
6359 ///
6360 /// @param i the iterator of an element of the first scope that has
6361 /// been reported as being delete.
6362 ///
6363 /// @return the scope member of the first scope of this diff that has
6364 /// been reported by the edit script as being deleted at iterator i.
6365 const decl_base_sptr
deleted_member_at(vector<deletion>::const_iterator i) const6366 scope_diff::deleted_member_at(vector<deletion>::const_iterator i) const
6367 {return deleted_member_at(i->index());}
6368 
6369 /// Accessor that eases the manipulation of the edit script associated
6370 /// to this instance.  It returns the scope member (of the second
6371 /// scope of this diff instance) that is reported as being inserted
6372 /// from a given index.
6373 ///
6374 /// @param i the index of an element of the second scope this diff
6375 /// that has been reported by the edit script as being inserted.
6376 ///
6377 /// @return the scope member of the second scope of this diff that has
6378 /// been reported as being inserted from index i.
6379 const decl_base_sptr
inserted_member_at(unsigned i)6380 scope_diff::inserted_member_at(unsigned i)
6381 {
6382   scope_decl_sptr scope = dynamic_pointer_cast<scope_decl>(second_subject());
6383   return scope->get_member_decls()[i];
6384 }
6385 
6386 /// Accessor that eases the manipulation of the edit script associated
6387 /// to this instance.  It returns the scope member (of the second
6388 /// scope of this diff instance) that is reported as being inserted
6389 /// from a given iterator.
6390 ///
6391 /// @param i the iterator of an element of the second scope this diff
6392 /// that has been reported by the edit script as being inserted.
6393 ///
6394 /// @return the scope member of the second scope of this diff that has
6395 /// been reported as being inserted from iterator i.
6396 const decl_base_sptr
inserted_member_at(vector<unsigned>::const_iterator i)6397 scope_diff::inserted_member_at(vector<unsigned>::const_iterator i)
6398 {return inserted_member_at(*i);}
6399 
6400 /// @return a sorted vector of the types which content has changed
6401 /// from the first scope to the other.
6402 const diff_sptrs_type&
changed_types() const6403 scope_diff::changed_types() const
6404 {return priv_->sorted_changed_types_;}
6405 
6406 /// @return a sorted vector of the decls which content has changed
6407 /// from the first scope to the other.
6408 const diff_sptrs_type&
changed_decls() const6409 scope_diff::changed_decls() const
6410 {return priv_->sorted_changed_decls_;}
6411 
6412 const string_decl_base_sptr_map&
removed_types() const6413 scope_diff::removed_types() const
6414 {return priv_->removed_types_;}
6415 
6416 const string_decl_base_sptr_map&
removed_decls() const6417 scope_diff::removed_decls() const
6418 {return priv_->removed_decls_;}
6419 
6420 const string_decl_base_sptr_map&
added_types() const6421 scope_diff::added_types() const
6422 {return priv_->added_types_;}
6423 
6424 const string_decl_base_sptr_map&
added_decls() const6425 scope_diff::added_decls() const
6426 {return priv_->added_decls_;}
6427 
6428 /// @return the pretty representation for the current instance of @ref
6429 /// scope_diff.
6430 const string&
get_pretty_representation() const6431 scope_diff::get_pretty_representation() const
6432 {
6433   if (diff::priv_->pretty_representation_.empty())
6434     {
6435       std::ostringstream o;
6436       o << "scope_diff["
6437 	<< first_subject()->get_pretty_representation()
6438 	<< ", "
6439 	<< second_subject()->get_pretty_representation()
6440 	<< "]";
6441       diff::priv_->pretty_representation_ = o.str();
6442     }
6443   return diff::priv_->pretty_representation_;
6444 }
6445 
6446 /// Return true iff the current diff node carries a change.
6447 ///
6448 /// Return true iff the current diff node carries a change.
6449 bool
has_changes() const6450 scope_diff::has_changes() const
6451 {
6452   // TODO: add the number of really removed/added stuff.
6453   return changed_types().size() + changed_decls().size();
6454 }
6455 
6456 /// @return the kind of local change carried by the current diff node.
6457 /// The value returned is zero if the current node carries no local
6458 /// change.
6459 enum change_kind
has_local_changes() const6460 scope_diff::has_local_changes() const
6461 {
6462   ir::change_kind k = ir::NO_CHANGE_KIND;
6463   if (!equals(*first_scope(), *second_scope(), &k))
6464     return k & ir::ALL_LOCAL_CHANGES_MASK;
6465   return ir::NO_CHANGE_KIND;
6466 }
6467 
6468 /// Report the changes of one scope against another.
6469 ///
6470 /// @param out the out stream to report the changes to.
6471 ///
6472 /// @param indent the string to use for indentation.
6473 void
report(ostream & out,const string & indent) const6474 scope_diff::report(ostream& out, const string& indent) const
6475 {
6476   context()->get_reporter()->report(*this, out, indent);
6477 }
6478 
6479 /// Compute the diff between two scopes.
6480 ///
6481 /// Note that the two decls must have been created in the same @ref
6482 /// environment, otherwise, this function aborts.
6483 ///
6484 /// @param first the first scope to consider in computing the diff.
6485 ///
6486 /// @param second the second scope to consider in the diff
6487 /// computation.  The second scope is diffed against the first scope.
6488 ///
6489 /// @param d a pointer to the diff object to populate with the
6490 /// computed diff.
6491 ///
6492 /// @return return the populated \a d parameter passed to this
6493 /// function.
6494 ///
6495 /// @param ctxt the diff context to use.
6496 scope_diff_sptr
compute_diff(const scope_decl_sptr first,const scope_decl_sptr second,scope_diff_sptr d,diff_context_sptr ctxt)6497 compute_diff(const scope_decl_sptr	first,
6498 	     const scope_decl_sptr	second,
6499 	     scope_diff_sptr		d,
6500 	     diff_context_sptr		ctxt)
6501 {
6502   ABG_ASSERT(d->first_scope() == first && d->second_scope() == second);
6503 
6504   compute_diff(first->get_member_decls().begin(),
6505 	       first->get_member_decls().end(),
6506 	       second->get_member_decls().begin(),
6507 	       second->get_member_decls().end(),
6508 	       d->member_changes());
6509 
6510   d->ensure_lookup_tables_populated();
6511   d->context(ctxt);
6512 
6513   return d;
6514 }
6515 
6516 /// Compute the diff between two scopes.
6517 ///
6518 /// Note that the two decls must have been created in the same @ref
6519 /// environment, otherwise, this function aborts.
6520 ///
6521 /// @param first_scope the first scope to consider in computing the diff.
6522 ///
6523 /// @param second_scope the second scope to consider in the diff
6524 /// computation.  The second scope is diffed against the first scope.
6525 ///
6526 /// @param ctxt the diff context to use.
6527 ///
6528 /// @return return the resulting diff
6529 scope_diff_sptr
compute_diff(const scope_decl_sptr first_scope,const scope_decl_sptr second_scope,diff_context_sptr ctxt)6530 compute_diff(const scope_decl_sptr	first_scope,
6531 	     const scope_decl_sptr	second_scope,
6532 	     diff_context_sptr		ctxt)
6533 {
6534   scope_diff_sptr d(new scope_diff(first_scope, second_scope, ctxt));
6535   d = compute_diff(first_scope, second_scope, d, ctxt);
6536   ctxt->initialize_canonical_diff(d);
6537   return d;
6538 }
6539 
6540 //</scope_diff stuff>
6541 
6542 // <fn_parm_diff stuff>
6543 
6544 /// Constructor for the fn_parm_diff type.
6545 ///
6546 /// @param first the first subject of the diff.
6547 ///
6548 /// @param second the second subject of the diff.
6549 ///
6550 /// @param ctxt the context of the diff.  Note that this context
6551 /// object must stay alive at least during the life time of the
6552 /// current instance of @ref fn_parm_diff.  Otherwise memory
6553 /// corruption issues occur.
fn_parm_diff(const function_decl::parameter_sptr first,const function_decl::parameter_sptr second,diff_context_sptr ctxt)6554 fn_parm_diff::fn_parm_diff(const function_decl::parameter_sptr	first,
6555 			   const function_decl::parameter_sptr	second,
6556 			   diff_context_sptr			ctxt)
6557   : decl_diff_base(first, second, ctxt),
6558     priv_(new priv)
6559 {
6560   ABG_ASSERT(first->get_index() == second->get_index());
6561   priv_->type_diff = compute_diff(first->get_type(),
6562 				  second->get_type(),
6563 				  ctxt);
6564   ABG_ASSERT(priv_->type_diff);
6565 }
6566 
6567 /// Getter for the first subject of this diff node.
6568 ///
6569 /// @return the first function_decl::parameter_sptr subject of this
6570 /// diff node.
6571 const function_decl::parameter_sptr
first_parameter() const6572 fn_parm_diff::first_parameter() const
6573 {return dynamic_pointer_cast<function_decl::parameter>(first_subject());}
6574 
6575 /// Getter for the second subject of this diff node.
6576 ///
6577 /// @return the second function_decl::parameter_sptr subject of this
6578 /// diff node.
6579 const function_decl::parameter_sptr
second_parameter() const6580 fn_parm_diff::second_parameter() const
6581 {return dynamic_pointer_cast<function_decl::parameter>(second_subject());}
6582 
6583 /// Getter for the diff representing the changes on the type of the
6584 /// function parameter involved in the current instance of @ref
6585 /// fn_parm_diff.
6586 ///
6587 /// @return a diff_sptr representing the changes on the type of the
6588 /// function parameter we are interested in.
6589 diff_sptr
type_diff() const6590 fn_parm_diff::type_diff() const
6591 {return priv_->type_diff;}
6592 
6593 /// Build and return a textual representation of the current instance
6594 /// of @ref fn_parm_diff.
6595 ///
6596 /// @return the string representing the current instance of
6597 /// fn_parm_diff.
6598 const string&
get_pretty_representation() const6599 fn_parm_diff::get_pretty_representation() const
6600 {
6601   if (diff::priv_->pretty_representation_.empty())
6602     {
6603       std::ostringstream o;
6604       o << "function_parameter_diff["
6605 	<< first_subject()->get_pretty_representation()
6606 	<< ", "
6607 	<< second_subject()->get_pretty_representation()
6608 	<< "]";
6609       diff::priv_->pretty_representation_ = o.str();
6610     }
6611   return diff::priv_->pretty_representation_;
6612 }
6613 
6614 /// Return true iff the current diff node carries a change.
6615 ///
6616 /// @return true iff the current diff node carries a change.
6617 bool
has_changes() const6618 fn_parm_diff::has_changes() const
6619 {return *first_parameter() != *second_parameter();}
6620 
6621 /// Check if the current diff node carries a local change.
6622 ///
6623 /// @return the kind of local change carried by the current diff node.
6624 /// The value returned is zero if the current node carries no local
6625 /// change.
6626 enum change_kind
has_local_changes() const6627 fn_parm_diff::has_local_changes() const
6628 {
6629   ir::change_kind k = ir::NO_CHANGE_KIND;
6630   if (!equals(*first_parameter(), *second_parameter(), &k))
6631     return k & ir::ALL_LOCAL_CHANGES_MASK;
6632   return ir::NO_CHANGE_KIND;
6633 }
6634 
6635 /// Emit a textual report about the current fn_parm_diff instance.
6636 ///
6637 /// @param out the output stream to emit the textual report to.
6638 ///
6639 /// @param indent the indentation string to use in the report.
6640 void
report(ostream & out,const string & indent) const6641 fn_parm_diff::report(ostream& out, const string& indent) const
6642 {
6643   context()->get_reporter()->report(*this, out, indent);
6644 }
6645 
6646 /// Populate the vector of children nodes of the @ref diff base type
6647 /// sub-object of this instance of @ref fn_parm_diff.
6648 ///
6649 /// The children nodes can then later be retrieved using
6650 /// diff::children_nodes()
6651 void
chain_into_hierarchy()6652 fn_parm_diff::chain_into_hierarchy()
6653 {
6654   if (type_diff())
6655     append_child_node(type_diff());
6656 }
6657 
6658 /// Compute the difference between two function_decl::parameter_sptr;
6659 /// that is, between two function parameters.  Return a resulting
6660 /// fn_parm_diff_sptr that represents the changes.
6661 ///
6662 /// Note that the two decls must have been created in the same @ref
6663 /// environment, otherwise, this function aborts.
6664 ///
6665 /// @param first the first subject of the diff.
6666 ///
6667 /// @param second the second subject of the diff.
6668 ///
6669 /// @param ctxt the context of the diff.
6670 ///
6671 /// @return fn_parm_diff_sptr the resulting diff node.
6672 fn_parm_diff_sptr
compute_diff(const function_decl::parameter_sptr first,const function_decl::parameter_sptr second,diff_context_sptr ctxt)6673 compute_diff(const function_decl::parameter_sptr	first,
6674 	     const function_decl::parameter_sptr	second,
6675 	     diff_context_sptr				ctxt)
6676 {
6677   if (!first || !second)
6678     return fn_parm_diff_sptr();
6679 
6680   fn_parm_diff_sptr result(new fn_parm_diff(first, second, ctxt));
6681   ctxt->initialize_canonical_diff(result);
6682 
6683   return result;
6684 }
6685 // </fn_parm_diff stuff>
6686 
6687 // <function_type_diff stuff>
6688 
6689 void
ensure_lookup_tables_populated()6690 function_type_diff::ensure_lookup_tables_populated()
6691 {
6692   priv_->return_type_diff_ =
6693     compute_diff(first_function_type()->get_return_type(),
6694 		 second_function_type()->get_return_type(),
6695 		 context());
6696 
6697   string parm_name;
6698   function_decl::parameter_sptr parm;
6699   for (vector<deletion>::const_iterator i =
6700 	 priv_->parm_changes_.deletions().begin();
6701        i != priv_->parm_changes_.deletions().end();
6702        ++i)
6703     {
6704       parm = *(first_function_type()->get_first_parm()
6705 	       + i->index());
6706       parm_name = parm->get_name_id();
6707       // If for a reason the type name is empty we want to know and
6708       // fix that.
6709       ABG_ASSERT(!parm_name.empty());
6710       priv_->deleted_parms_[parm_name] = parm;
6711       priv_->deleted_parms_by_id_[parm->get_index()] = parm;
6712     }
6713 
6714   for (vector<insertion>::const_iterator i =
6715 	 priv_->parm_changes_.insertions().begin();
6716        i != priv_->parm_changes_.insertions().end();
6717        ++i)
6718     {
6719       for (vector<unsigned>::const_iterator j =
6720 	     i->inserted_indexes().begin();
6721 	   j != i->inserted_indexes().end();
6722 	   ++j)
6723 	{
6724 	  parm = *(second_function_type()->get_first_parm() + *j);
6725 	  parm_name = parm->get_name_id();
6726 	  // If for a reason the type name is empty we want to know and
6727 	  // fix that.
6728 	  ABG_ASSERT(!parm_name.empty());
6729 	  {
6730 	    string_parm_map::const_iterator k =
6731 	      priv_->deleted_parms_.find(parm_name);
6732 	    if (k != priv_->deleted_parms_.end())
6733 	      {
6734 		if (*k->second != *parm)
6735 		  priv_->subtype_changed_parms_[parm_name] =
6736 		    compute_diff(k->second, parm, context());
6737 		priv_->deleted_parms_.erase(parm_name);
6738 	      }
6739 	    else
6740 	      priv_->added_parms_[parm_name] = parm;
6741 	  }
6742 	  {
6743 	    unsigned_parm_map::const_iterator k =
6744 	      priv_->deleted_parms_by_id_.find(parm->get_index());
6745 	    if (k != priv_->deleted_parms_by_id_.end())
6746 	      {
6747 		if (*k->second != *parm
6748 		    && (k->second->get_name_id() != parm_name))
6749 		  priv_->changed_parms_by_id_[parm->get_index()] =
6750 		    compute_diff(k->second, parm, context());
6751 		priv_->added_parms_.erase(parm_name);
6752 		priv_->deleted_parms_.erase(k->second->get_name_id());
6753 		priv_->deleted_parms_by_id_.erase(parm->get_index());
6754 	      }
6755 	    else
6756 	      priv_->added_parms_by_id_[parm->get_index()] = parm;
6757 	  }
6758 	}
6759     }
6760 
6761   sort_string_fn_parm_diff_sptr_map(priv_->subtype_changed_parms_,
6762 				    priv_->sorted_subtype_changed_parms_);
6763   sort_string_fn_parm_diff_sptr_map(priv_->changed_parms_by_id_,
6764 				    priv_->sorted_changed_parms_by_id_);
6765   sort_string_parm_map(priv_->deleted_parms_,
6766 		       priv_->sorted_deleted_parms_);
6767 
6768   sort_string_parm_map(priv_->added_parms_,
6769 		       priv_->sorted_added_parms_);
6770 }
6771 
6772 /// In the vector of deleted parameters, get the one that is at a given
6773 /// index.
6774 ///
6775 /// @param i the index of the deleted parameter to get.
6776 ///
6777 /// @return the parameter returned.
6778 const function_decl::parameter_sptr
deleted_parameter_at(int i) const6779 function_type_diff::deleted_parameter_at(int i) const
6780 {return first_function_type()->get_parameters()[i];}
6781 
6782 /// Getter for the sorted vector of deleted parameters.
6783 ///
6784 /// @return the sorted vector of deleted parameters.
6785 const vector<function_decl::parameter_sptr>&
sorted_deleted_parms() const6786 function_type_diff::sorted_deleted_parms() const
6787 {return priv_->sorted_deleted_parms_;}
6788 
6789 /// Getter for the sorted vector of added parameters .
6790 ///
6791 /// @return the sorted vector of added parameters.
6792 const vector<function_decl::parameter_sptr>&
sorted_added_parms() const6793 function_type_diff::sorted_added_parms() const
6794 {return priv_->sorted_added_parms_;}
6795 
6796 /// In the vector of inserted parameters, get the one that is at a
6797 /// given index.
6798 ///
6799 /// @param i the index of the inserted parameter to get.
6800 ///
6801 /// @return the parameter returned.
6802 const function_decl::parameter_sptr
inserted_parameter_at(int i) const6803 function_type_diff::inserted_parameter_at(int i) const
6804 {return second_function_type()->get_parameters()[i];}
6805 
6806 /// Consutrctor of the @ref function_type type.
6807 ///
6808 /// @param first the first @ref function_type subject of the diff to
6809 /// create.
6810 ///
6811 /// @param second the second @ref function_type subject of the diff to
6812 /// create.
6813 ///
6814 /// @param ctxt the diff context to be used by the newly created
6815 /// instance of function_type_diff.  Note that this context object
6816 /// must stay alive at least during the life time of the current
6817 /// instance of @ref function_type_diff.  Otherwise memory corruption
6818 /// issues occur.
function_type_diff(const function_type_sptr first,const function_type_sptr second,diff_context_sptr ctxt)6819 function_type_diff::function_type_diff(const function_type_sptr first,
6820 				       const function_type_sptr second,
6821 				       diff_context_sptr	ctxt)
6822   : type_diff_base(first, second, ctxt),
6823     priv_(new priv)
6824 {}
6825 
6826 /// Getter for the first subject of the diff.
6827 ///
6828 /// @return the first function type involved in the diff.
6829 const function_type_sptr
first_function_type() const6830 function_type_diff::first_function_type() const
6831 {return dynamic_pointer_cast<function_type>(first_subject());}
6832 
6833 /// Getter for the second subject of the diff.
6834 ///
6835 /// @return the second function type involved in the diff.
6836 const function_type_sptr
second_function_type() const6837 function_type_diff::second_function_type() const
6838 {return dynamic_pointer_cast<function_type>(second_subject());}
6839 
6840 /// Getter for the diff of the return types of the two function types
6841 /// of the current diff.
6842 ///
6843 /// @return the diff of the return types of the two function types of
6844 /// the current diff.
6845 const diff_sptr
return_type_diff() const6846 function_type_diff::return_type_diff() const
6847 {return priv_->return_type_diff_;}
6848 
6849 /// Getter for the map of function parameter changes of the current diff.
6850 ///
6851 /// @return a map of function parameter changes of the current diff.
6852 const string_fn_parm_diff_sptr_map&
subtype_changed_parms() const6853 function_type_diff::subtype_changed_parms() const
6854 {return priv_->subtype_changed_parms_;}
6855 
6856 /// Getter for the map of parameters that got removed.
6857 ///
6858 /// @return the map of parameters that got removed.
6859 const string_parm_map&
removed_parms() const6860 function_type_diff::removed_parms() const
6861 {return priv_->deleted_parms_;}
6862 
6863 /// Getter for the map of parameters that got added.
6864 ///
6865 /// @return the map of parameters that got added.
6866 const string_parm_map&
added_parms() const6867 function_type_diff::added_parms() const
6868 {return priv_->added_parms_;}
6869 
6870 /// Build and return a copy of a pretty representation of the current
6871 /// instance of @ref function_type_diff.
6872 ///
6873 /// @return a copy of the pretty representation of the current
6874 /// instance of @ref function_type_diff.
6875 const string&
get_pretty_representation() const6876 function_type_diff::get_pretty_representation() const
6877 {
6878   if (diff::priv_->pretty_representation_.empty())
6879     {
6880       std::ostringstream o;
6881       o << "function_type_diff["
6882 	<< abigail::ir::get_pretty_representation(first_function_type())
6883 	<< ", "
6884 	<< abigail::ir::get_pretty_representation(second_function_type())
6885 	<< "]";
6886       diff::priv_->pretty_representation_ = o.str();
6887     }
6888   return diff::priv_->pretty_representation_;
6889 }
6890 
6891 /// Test if the current diff node carries changes.
6892 ///
6893 /// @return true iff the current diff node carries changes.
6894 bool
has_changes() const6895 function_type_diff::has_changes() const
6896 {return *first_function_type() != *second_function_type();}
6897 
6898 /// Test if the current diff node carries local changes.
6899 ///
6900 /// A local change is a change that is carried by this diff node, not
6901 /// by any of its children nodes.
6902 ///
6903 /// @return the kind of local change carried by the current diff node.
6904 /// The value returned is zero if the current node carries no local
6905 /// change.
6906 enum change_kind
has_local_changes() const6907 function_type_diff::has_local_changes() const
6908 {
6909   ir::change_kind k = ir::NO_CHANGE_KIND;
6910   if (!equals(*first_function_type(), *second_function_type(), &k))
6911     return k & ir::ALL_LOCAL_CHANGES_MASK;
6912   return ir::NO_CHANGE_KIND;
6913 }
6914 
6915 /// Build and emit a textual report about the current @ref
6916 /// function_type_diff instance.
6917 ///
6918 /// @param out the output stream.
6919 ///
6920 /// @param indent the indentation string to use.
6921 void
report(ostream & out,const string & indent) const6922 function_type_diff::report(ostream& out, const string& indent) const
6923 {
6924   context()->get_reporter()->report(*this, out, indent);
6925 }
6926 
6927 /// Populate the vector of children node of the @ref diff base type
6928 /// sub-object of this instance of @ref function_type_diff.
6929 ///
6930 /// The children node can then later be retrieved using
6931 /// diff::children_node().
6932 void
chain_into_hierarchy()6933 function_type_diff::chain_into_hierarchy()
6934 {
6935   if (diff_sptr d = return_type_diff())
6936     append_child_node(d);
6937 
6938   for (vector<fn_parm_diff_sptr>::const_iterator i =
6939 	 priv_->sorted_subtype_changed_parms_.begin();
6940        i != priv_->sorted_subtype_changed_parms_.end();
6941        ++i)
6942     if (diff_sptr d = *i)
6943       append_child_node(d);
6944 
6945   for (vector<fn_parm_diff_sptr>::const_iterator i =
6946 	 priv_->sorted_changed_parms_by_id_.begin();
6947        i != priv_->sorted_changed_parms_by_id_.end();
6948        ++i)
6949     if (diff_sptr d = *i)
6950       append_child_node(d);
6951 }
6952 
6953 /// Compute the diff between two instances of @ref function_type.
6954 ///
6955 /// Note that the two types must have been created in the same @ref
6956 /// environment, otherwise, this function aborts.
6957 ///
6958 /// @param first the first @ref function_type to consider for the diff.
6959 ///
6960 /// @param second the second @ref function_type to consider for the diff.
6961 ///
6962 /// @param ctxt the diff context to use.
6963 ///
6964 /// @return the resulting diff between the two @ref function_type.
6965 function_type_diff_sptr
compute_diff(const function_type_sptr first,const function_type_sptr second,diff_context_sptr ctxt)6966 compute_diff(const function_type_sptr	first,
6967 	     const function_type_sptr	second,
6968 	     diff_context_sptr		ctxt)
6969 {
6970   if (!first || !second)
6971     {
6972       // TODO: implement this for either first or second being NULL.
6973       return function_type_diff_sptr();
6974     }
6975 
6976   function_type_diff_sptr result(new function_type_diff(first, second, ctxt));
6977 
6978   diff_utils::compute_diff(first->get_first_parm(),
6979 			   first->get_parameters().end(),
6980 			   second->get_first_parm(),
6981 			   second->get_parameters().end(),
6982 			   result->priv_->parm_changes_);
6983 
6984   result->ensure_lookup_tables_populated();
6985 
6986   ctxt->initialize_canonical_diff(result);
6987 
6988   return result;
6989 }
6990 // </function_type_diff stuff>
6991 
6992 // <function_decl_diff stuff>
6993 
6994 /// Build the lookup tables of the diff, if necessary.
6995 void
ensure_lookup_tables_populated()6996 function_decl_diff::ensure_lookup_tables_populated()
6997 {
6998 }
6999 
7000 /// Populate the vector of children node of the @ref diff base type
7001 /// sub-object of this instance of @ref function_decl_diff.
7002 ///
7003 /// The children node can then later be retrieved using
7004 /// diff::children_node().
7005 void
chain_into_hierarchy()7006 function_decl_diff::chain_into_hierarchy()
7007 {
7008   if (diff_sptr d = type_diff())
7009     append_child_node(d);
7010 }
7011 
7012 /// Constructor for function_decl_diff
7013 ///
7014 /// @param first the first function considered by the diff.
7015 ///
7016 /// @param second the second function considered by the diff.
7017 ///
7018 /// @param ctxt the context of the diff.  Note that this context
7019 /// object must stay alive at least during the life time of the
7020 /// current instance of @ref function_decl_diff.  Otherwise memory
7021 /// corruption issues occur.
function_decl_diff(const function_decl_sptr first,const function_decl_sptr second,diff_context_sptr ctxt)7022 function_decl_diff::function_decl_diff(const function_decl_sptr first,
7023 				       const function_decl_sptr second,
7024 				       diff_context_sptr	ctxt)
7025   : decl_diff_base(first, second, ctxt),
7026     priv_(new priv)
7027 {
7028 }
7029 
7030 /// @return the first function considered by the diff.
7031 const function_decl_sptr
first_function_decl() const7032 function_decl_diff::first_function_decl() const
7033 {return dynamic_pointer_cast<function_decl>(first_subject());}
7034 
7035 /// @return the second function considered by the diff.
7036 const function_decl_sptr
second_function_decl() const7037 function_decl_diff::second_function_decl() const
7038 {return dynamic_pointer_cast<function_decl>(second_subject());}
7039 
7040 const function_type_diff_sptr
type_diff() const7041 function_decl_diff::type_diff() const
7042 {return priv_->type_diff_;}
7043 
7044 /// @return the pretty representation for the current instance of @ref
7045 /// function_decl_diff.
7046 const string&
get_pretty_representation() const7047 function_decl_diff::get_pretty_representation() const
7048 {
7049   if (diff::priv_->pretty_representation_.empty())
7050     {
7051       std::ostringstream o;
7052       o << "function_diff["
7053 	<< first_subject()->get_pretty_representation()
7054 	<< ", "
7055 	<< second_subject()->get_pretty_representation()
7056 	<< "]";
7057       diff::priv_->pretty_representation_ = o.str();
7058     }
7059   return diff::priv_->pretty_representation_;
7060 }
7061 
7062 /// Return true iff the current diff node carries a change.
7063 ///
7064 /// @return true iff the current diff node carries a change.
7065 bool
has_changes() const7066 function_decl_diff::has_changes() const
7067 {return *first_function_decl() != *second_function_decl();}
7068 
7069 /// @return the kind of local change carried by the current diff node.
7070 /// The value returned is zero if the current node carries no local
7071 /// change.
7072 enum change_kind
has_local_changes() const7073 function_decl_diff::has_local_changes() const
7074 {
7075   ir::change_kind k = ir::NO_CHANGE_KIND;
7076   if (!equals(*first_function_decl(), *second_function_decl(), &k))
7077     return k & ir::ALL_LOCAL_CHANGES_MASK;
7078   return ir::NO_CHANGE_KIND;
7079 }
7080 
7081 /// Serialize a report of the changes encapsulated in the current
7082 /// instance of @ref function_decl_diff over to an output stream.
7083 ///
7084 /// @param out the output stream to serialize the report to.
7085 ///
7086 /// @param indent the string to use an an indentation prefix.
7087 void
report(ostream & out,const string & indent) const7088 function_decl_diff::report(ostream& out, const string& indent) const
7089 {
7090   context()->get_reporter()->report(*this, out, indent);
7091 }
7092 
7093 /// Compute the diff between two function_decl.
7094 ///
7095 /// Note that the two decls must have been created in the same @ref
7096 /// environment, otherwise, this function aborts.
7097 ///
7098 /// @param first the first function_decl to consider for the diff
7099 ///
7100 /// @param second the second function_decl to consider for the diff
7101 ///
7102 /// @param ctxt the diff context to use.
7103 ///
7104 /// @return the computed diff
7105 function_decl_diff_sptr
compute_diff(const function_decl_sptr first,const function_decl_sptr second,diff_context_sptr ctxt)7106 compute_diff(const function_decl_sptr first,
7107 	     const function_decl_sptr second,
7108 	     diff_context_sptr ctxt)
7109 {
7110   if (!first || !second)
7111     {
7112       // TODO: implement this for either first or second being NULL.
7113       return function_decl_diff_sptr();
7114     }
7115 
7116   function_type_diff_sptr type_diff = compute_diff(first->get_type(),
7117 						   second->get_type(),
7118 						   ctxt);
7119 
7120   function_decl_diff_sptr result(new function_decl_diff(first, second,
7121 							ctxt));
7122   result->priv_->type_diff_ = type_diff;
7123 
7124   result->ensure_lookup_tables_populated();
7125 
7126   ctxt->initialize_canonical_diff(result);
7127 
7128   return result;
7129 }
7130 
7131 // </function_decl_diff stuff>
7132 
7133 // <type_decl_diff stuff>
7134 
7135 /// Constructor for type_decl_diff.
7136 ///
7137 /// @param first the first subject of the diff.
7138 ///
7139 /// @param second the second subject of the diff.
7140 ///
7141 /// @param ctxt the context of the diff.  Note that this context
7142 /// object must stay alive at least during the life time of the
7143 /// current instance of @ref type_decl_diff.  Otherwise memory
7144 /// corruption issues occur.
type_decl_diff(const type_decl_sptr first,const type_decl_sptr second,diff_context_sptr ctxt)7145 type_decl_diff::type_decl_diff(const type_decl_sptr first,
7146 			       const type_decl_sptr second,
7147 			       diff_context_sptr ctxt)
7148   : type_diff_base(first, second, ctxt)
7149 {}
7150 
7151 /// Getter for the first subject of the type_decl_diff.
7152 ///
7153 /// @return the first type_decl involved in the diff.
7154 const type_decl_sptr
first_type_decl() const7155 type_decl_diff::first_type_decl() const
7156 {return dynamic_pointer_cast<type_decl>(first_subject());}
7157 
7158 /// Getter for the second subject of the type_decl_diff.
7159 ///
7160 /// @return the second type_decl involved in the diff.
7161 const type_decl_sptr
second_type_decl() const7162 type_decl_diff::second_type_decl() const
7163 {return dynamic_pointer_cast<type_decl>(second_subject());}
7164 
7165 /// @return the pretty representation for the current instance of @ref
7166 /// type_decl_diff.
7167 const string&
get_pretty_representation() const7168 type_decl_diff::get_pretty_representation() const
7169 {
7170   if (diff::priv_->pretty_representation_.empty())
7171     {
7172       std::ostringstream o;
7173       o << "type_decl_diff["
7174 	<< first_subject()->get_pretty_representation()
7175 	<< ", "
7176 	<< second_subject()->get_pretty_representation()
7177 	<< "]";
7178       diff::priv_->pretty_representation_ = o.str();
7179     }
7180   return diff::priv_->pretty_representation_;
7181 }
7182 /// Return true iff the current diff node carries a change.
7183 ///
7184 /// @return true iff the current diff node carries a change.
7185 bool
has_changes() const7186 type_decl_diff::has_changes() const
7187 {return first_type_decl() != second_type_decl();}
7188 
7189 /// @return the kind of local change carried by the current diff node.
7190 /// The value returned is zero if the current node carries no local
7191 /// change.
7192 enum change_kind
has_local_changes() const7193 type_decl_diff::has_local_changes() const
7194 {
7195   ir::change_kind k = ir::NO_CHANGE_KIND;
7196   if (!equals(*first_type_decl(), *second_type_decl(), &k))
7197     return k & ir::ALL_LOCAL_CHANGES_MASK;
7198   return ir::NO_CHANGE_KIND;
7199 }
7200 /// Ouputs a report of the differences between of the two type_decl
7201 /// involved in the type_decl_diff.
7202 ///
7203 /// @param out the output stream to emit the report to.
7204 ///
7205 /// @param indent the string to use for indentatino indent.
7206 void
report(ostream & out,const string & indent) const7207 type_decl_diff::report(ostream& out, const string& indent) const
7208 {
7209   context()->get_reporter()->report(*this, out, indent);
7210 }
7211 
7212 /// Compute a diff between two type_decl.
7213 ///
7214 /// Note that the two types must have been created in the same @ref
7215 /// environment, otherwise, this function aborts.
7216 ///
7217 /// This function doesn't actually compute a diff.  As a type_decl is
7218 /// very simple (unlike compound constructs like function_decl or
7219 /// class_decl) it's easy to just compare the components of the
7220 /// type_decl to know what has changed.  Thus this function just
7221 /// builds and return a type_decl_diff object.  The
7222 /// type_decl_diff::report function will just compare the components
7223 /// of the the two type_decl and display where and how they differ.
7224 ///
7225 /// @param first a pointer to the first type_decl to
7226 /// consider.
7227 ///
7228 /// @param second a pointer to the second type_decl to consider.
7229 ///
7230 /// @param ctxt the diff context to use.
7231 ///
7232 /// @return a pointer to the resulting type_decl_diff.
7233 type_decl_diff_sptr
compute_diff(const type_decl_sptr first,const type_decl_sptr second,diff_context_sptr ctxt)7234 compute_diff(const type_decl_sptr	first,
7235 	     const type_decl_sptr	second,
7236 	     diff_context_sptr		ctxt)
7237 {
7238   type_decl_diff_sptr result(new type_decl_diff(first, second, ctxt));
7239 
7240   // We don't need to actually compute a diff here as a type_decl
7241   // doesn't have complicated sub-components.  type_decl_diff::report
7242   // just walks the members of the type_decls and display information
7243   // about the ones that have changed.  On a similar note,
7244   // type_decl_diff::length returns 0 if the two type_decls are equal,
7245   // and 1 otherwise.
7246 
7247   ctxt->initialize_canonical_diff(result);
7248 
7249   return result;
7250 }
7251 
7252 // </type_decl_diff stuff>
7253 
7254 // <typedef_diff stuff>
7255 
7256 /// Populate the vector of children node of the @ref diff base type
7257 /// sub-object of this instance of @ref typedef_diff.
7258 ///
7259 /// The children node can then later be retrieved using
7260 /// diff::children_node().
7261 void
chain_into_hierarchy()7262 typedef_diff::chain_into_hierarchy()
7263 {append_child_node(underlying_type_diff());}
7264 
7265 /// Constructor for typedef_diff.
7266 ///
7267 /// @param first the first subject of the diff.
7268 ///
7269 /// @param second the second subject of the diff.
7270 ///
7271 /// @param underlying the underlying diff of the @ref typedef_diff.
7272 /// That is the diff between the underlying types of @p first and @p
7273 /// second.
7274 ///
7275 /// @param ctxt the context of the diff.  Note that this context
7276 /// object must stay alive at least during the life time of the
7277 /// current instance of @ref typedef_diff.  Otherwise memory
7278 /// corruption issues occur.
typedef_diff(const typedef_decl_sptr first,const typedef_decl_sptr second,const diff_sptr underlying,diff_context_sptr ctxt)7279 typedef_diff::typedef_diff(const typedef_decl_sptr	first,
7280 			   const typedef_decl_sptr	second,
7281 			   const diff_sptr		underlying,
7282 			   diff_context_sptr		ctxt)
7283   : type_diff_base(first, second, ctxt),
7284     priv_(new priv(underlying))
7285 {}
7286 
7287 /// Getter for the firt typedef_decl involved in the diff.
7288 ///
7289 /// @return the first subject of the diff.
7290 const typedef_decl_sptr
first_typedef_decl() const7291 typedef_diff::first_typedef_decl() const
7292 {return dynamic_pointer_cast<typedef_decl>(first_subject());}
7293 
7294 /// Getter for the second typedef_decl involved in the diff.
7295 ///
7296 /// @return the second subject of the diff.
7297 const typedef_decl_sptr
second_typedef_decl() const7298 typedef_diff::second_typedef_decl() const
7299 {return dynamic_pointer_cast<typedef_decl>(second_subject());}
7300 
7301 /// Getter for the diff between the two underlying types of the
7302 /// typedefs.
7303 ///
7304 /// @return the diff object reprensenting the difference between the
7305 /// two underlying types of the typedefs.
7306 const diff_sptr
underlying_type_diff() const7307 typedef_diff::underlying_type_diff() const
7308 {return priv_->underlying_type_diff_;}
7309 
7310 /// Setter for the diff between the two underlying types of the
7311 /// typedefs.
7312 ///
7313 /// @param d the new diff object reprensenting the difference between
7314 /// the two underlying types of the typedefs.
7315 void
underlying_type_diff(const diff_sptr d)7316 typedef_diff::underlying_type_diff(const diff_sptr d)
7317 {priv_->underlying_type_diff_ = d;}
7318 
7319 /// @return the pretty representation for the current instance of @ref
7320 /// typedef_diff.
7321 const string&
get_pretty_representation() const7322 typedef_diff::get_pretty_representation() const
7323 {
7324   if (diff::priv_->pretty_representation_.empty())
7325     {
7326       std::ostringstream o;
7327       o << "typedef_diff["
7328 	<< first_subject()->get_pretty_representation()
7329 	<< ", "
7330 	<< second_subject()->get_pretty_representation()
7331 	<< "]";
7332       diff::priv_->pretty_representation_ = o.str();
7333     }
7334   return diff::priv_->pretty_representation_;
7335 }
7336 
7337 /// Return true iff the current diff node carries a change.
7338 ///
7339 /// @return true iff the current diff node carries a change.
7340 bool
has_changes() const7341 typedef_diff::has_changes() const
7342 {
7343   decl_base_sptr second = second_typedef_decl();
7344   return !(*first_typedef_decl() == *second);
7345 }
7346 
7347 /// @return the kind of local change carried by the current diff node.
7348 /// The value returned is zero if the current node carries no local
7349 /// change.
7350 enum change_kind
has_local_changes() const7351 typedef_diff::has_local_changes() const
7352 {
7353   ir::change_kind k = ir::NO_CHANGE_KIND;
7354   if (!equals(*first_typedef_decl(), *second_typedef_decl(), &k))
7355     return k & ir::ALL_LOCAL_CHANGES_MASK;
7356   return ir::NO_CHANGE_KIND;
7357 }
7358 
7359 /// Reports the difference between the two subjects of the diff in a
7360 /// serialized form.
7361 ///
7362 /// @param out the output stream to emit the report to.
7363 ///
7364 /// @param indent the indentation string to use.
7365 void
report(ostream & out,const string & indent) const7366 typedef_diff::report(ostream& out, const string& indent) const
7367 {
7368   context()->get_reporter()->report(*this, out, indent);
7369 }
7370 
7371 /// Compute a diff between two typedef_decl.
7372 ///
7373 /// Note that the two types must have been created in the same @ref
7374 /// environment, otherwise, this function aborts.
7375 ///
7376 /// @param first a pointer to the first typedef_decl to consider.
7377 ///
7378 /// @param second a pointer to the second typedef_decl to consider.
7379 ///
7380 /// @param ctxt the diff context to use.
7381 ///
7382 /// @return a pointer to the the resulting typedef_diff.
7383 typedef_diff_sptr
compute_diff(const typedef_decl_sptr first,const typedef_decl_sptr second,diff_context_sptr ctxt)7384 compute_diff(const typedef_decl_sptr	first,
7385 	     const typedef_decl_sptr	second,
7386 	     diff_context_sptr		ctxt)
7387 {
7388   diff_sptr d = compute_diff_for_types(first->get_underlying_type(),
7389 				       second->get_underlying_type(),
7390 				       ctxt);
7391   typedef_diff_sptr result(new typedef_diff(first, second, d, ctxt));
7392 
7393   ctxt->initialize_canonical_diff(result);
7394 
7395   return result;
7396 }
7397 
7398 /// Return the leaf underlying diff node of a @ref typedef_diff node.
7399 ///
7400 /// If the underlying diff node of a @ref typedef_diff node is itself
7401 /// a @ref typedef_diff node, then recursively look at the underlying
7402 /// diff nodes to get the first one that is not a a @ref typedef_diff
7403 /// node.  This is what a leaf underlying diff node means.
7404 ///
7405 /// Otherwise, if the underlying diff node of @ref typedef_diff is
7406 /// *NOT* a @ref typedef_diff node, then just return the underlying
7407 /// diff node.
7408 ///
7409 /// And if the diff node considered is not a @ref typedef_diff node,
7410 /// then just return it.
7411 ///
7412 /// @return the leaf underlying diff node of a @p diff.
7413 const diff*
get_typedef_diff_underlying_type_diff(const diff * diff)7414 get_typedef_diff_underlying_type_diff(const diff* diff)
7415 {
7416   const typedef_diff* d = dynamic_cast<const typedef_diff*>(diff);
7417   if (!d)
7418     return diff;
7419 
7420   if (const typedef_diff* deef =
7421       dynamic_cast<const typedef_diff*>(d->underlying_type_diff().get()))
7422     return get_typedef_diff_underlying_type_diff(deef);
7423 
7424   return d->underlying_type_diff().get();
7425 }
7426 
7427 // </typedef_diff stuff>
7428 
7429 // <translation_unit_diff stuff>
7430 
7431 /// Constructor for translation_unit_diff.
7432 ///
7433 /// @param first the first translation unit to consider for this diff.
7434 ///
7435 /// @param second the second translation unit to consider for this diff.
7436 ///
7437 /// @param ctxt the context of the diff.  Note that this context
7438 /// object must stay alive at least during the life time of the
7439 /// current instance of @ref translation_unit_diff.  Otherwise memory
7440 /// corruption issues occur.
translation_unit_diff(translation_unit_sptr first,translation_unit_sptr second,diff_context_sptr ctxt)7441 translation_unit_diff::translation_unit_diff(translation_unit_sptr first,
7442 					     translation_unit_sptr second,
7443 					     diff_context_sptr ctxt)
7444   : scope_diff(first->get_global_scope(), second->get_global_scope(), ctxt),
7445     priv_(new priv(first, second))
7446 {
7447 }
7448 
7449 /// Getter for the first translation unit of this diff.
7450 ///
7451 /// @return the first translation unit of this diff.
7452 const translation_unit_sptr
first_translation_unit() const7453 translation_unit_diff::first_translation_unit() const
7454 {return priv_->first_;}
7455 
7456 /// Getter for the second translation unit of this diff.
7457 ///
7458 /// @return the second translation unit of this diff.
7459 const translation_unit_sptr
second_translation_unit() const7460 translation_unit_diff::second_translation_unit() const
7461 {return priv_->second_;}
7462 
7463 /// Return true iff the current diff node carries a change.
7464 ///
7465 /// @return true iff the current diff node carries a change.
7466 bool
has_changes() const7467 translation_unit_diff::has_changes() const
7468 {return scope_diff::has_changes();}
7469 
7470 /// @return the kind of local change carried by the current diff node.
7471 /// The value returned is zero if the current node carries no local
7472 /// change.
7473 enum change_kind
has_local_changes() const7474 translation_unit_diff::has_local_changes() const
7475 {return ir::NO_CHANGE_KIND;}
7476 
7477 /// Report the diff in a serialized form.
7478 ///
7479 /// @param out the output stream to serialize the report to.
7480 ///
7481 /// @param indent the prefix to use as indentation for the report.
7482 void
report(ostream & out,const string & indent) const7483 translation_unit_diff::report(ostream& out, const string& indent) const
7484 {scope_diff::report(out, indent);}
7485 
7486 /// Compute the diff between two translation_units.
7487 ///
7488 /// Note that the two translation units must have been created in the
7489 /// same @ref environment, otherwise, this function aborts.
7490 ///
7491 /// @param first the first translation_unit to consider.
7492 ///
7493 /// @param second the second translation_unit to consider.
7494 ///
7495 /// @param ctxt the diff context to use.  If null, this function will
7496 /// create a new context and set to the diff object returned.
7497 ///
7498 /// @return the newly created diff object.
7499 translation_unit_diff_sptr
compute_diff(const translation_unit_sptr first,const translation_unit_sptr second,diff_context_sptr ctxt)7500 compute_diff(const translation_unit_sptr	first,
7501 	     const translation_unit_sptr	second,
7502 	     diff_context_sptr			ctxt)
7503 {
7504   ABG_ASSERT(first && second);
7505 
7506   if (!ctxt)
7507     ctxt.reset(new diff_context);
7508 
7509   // TODO: handle first or second having empty contents.
7510   translation_unit_diff_sptr tu_diff(new translation_unit_diff(first, second,
7511 							       ctxt));
7512   scope_diff_sptr sc_diff = dynamic_pointer_cast<scope_diff>(tu_diff);
7513 
7514   compute_diff(static_pointer_cast<scope_decl>(first->get_global_scope()),
7515 	       static_pointer_cast<scope_decl>(second->get_global_scope()),
7516 	       sc_diff,
7517 	       ctxt);
7518 
7519   ctxt->initialize_canonical_diff(tu_diff);
7520 
7521   return tu_diff;
7522 }
7523 
7524 // </translation_unit_diff stuff>
7525 
7526 // <diff_maps stuff>
7527 
7528 /// The private data of the @ref diff_maps type.
7529 struct diff_maps::priv
7530 {
7531   string_diff_ptr_map type_decl_diff_map_;
7532   string_diff_ptr_map enum_diff_map_;
7533   string_diff_ptr_map class_diff_map_;
7534   string_diff_ptr_map union_diff_map_;
7535   string_diff_ptr_map typedef_diff_map_;
7536   string_diff_ptr_map array_diff_map_;
7537   string_diff_ptr_map reference_diff_map_;
7538   string_diff_ptr_map function_type_diff_map_;
7539   string_diff_ptr_map function_decl_diff_map_;
7540   string_diff_ptr_map var_decl_diff_map_;
7541   string_diff_ptr_map distinct_diff_map_;
7542   string_diff_ptr_map fn_parm_diff_map_;
7543   diff_artifact_set_map_type impacted_artifacts_map_;
7544 }; // end struct diff_maps::priv
7545 
7546 /// Default constructor of the @ref diff_maps type.
diff_maps()7547 diff_maps::diff_maps()
7548   : priv_(new diff_maps::priv())
7549 {}
7550 
7551 diff_maps::~diff_maps() = default;
7552 
7553 /// Getter of the map that contains basic type diffs.
7554 ///
7555 /// @return the map that contains basic type diffs.
7556 const string_diff_ptr_map&
get_type_decl_diff_map() const7557 diff_maps::get_type_decl_diff_map() const
7558 {return priv_->type_decl_diff_map_;}
7559 
7560 /// Getter of the map that contains basic type diffs.
7561 ///
7562 /// @return the map that contains basic type diffs.
7563 string_diff_ptr_map&
get_type_decl_diff_map()7564 diff_maps::get_type_decl_diff_map()
7565 {return priv_->type_decl_diff_map_;}
7566 
7567 /// Getter of the map that contains enum type diffs.
7568 ///
7569 /// @return the map that contains enum type diffs.
7570 const string_diff_ptr_map&
get_enum_diff_map() const7571 diff_maps::get_enum_diff_map() const
7572 {return priv_->enum_diff_map_;}
7573 
7574 /// Getter of the map that contains enum type diffs.
7575 ///
7576 /// @return the map that contains enum type diffs.
7577 string_diff_ptr_map&
get_enum_diff_map()7578 diff_maps::get_enum_diff_map()
7579 {return priv_->enum_diff_map_;}
7580 
7581 /// Getter of the map that contains class type diffs.
7582 ///
7583 /// @return the map that contains class type diffs.
7584 const string_diff_ptr_map&
get_class_diff_map() const7585 diff_maps::get_class_diff_map() const
7586 {return priv_->class_diff_map_;}
7587 
7588 /// Getter of the map that contains class type diffs.
7589 ///
7590 /// @return the map that contains class type diffs.
7591 string_diff_ptr_map&
get_class_diff_map()7592 diff_maps::get_class_diff_map()
7593 {return priv_->class_diff_map_;}
7594 
7595 /// Getter of the map that contains union type diffs.
7596 ///
7597 /// @return the map that contains union type diffs.
7598 const string_diff_ptr_map&
get_union_diff_map() const7599 diff_maps::get_union_diff_map() const
7600 {return priv_->union_diff_map_;}
7601 
7602 /// Getter of the map that contains union type diffs.
7603 ///
7604 /// @return the map that contains union type diffs.
7605 string_diff_ptr_map&
get_union_diff_map()7606 diff_maps::get_union_diff_map()
7607 {return priv_->union_diff_map_;}
7608 
7609 /// Getter of the map that contains typedef type diffs.
7610 ///
7611 /// @return the map that contains typedef type diffs.
7612 const string_diff_ptr_map&
get_typedef_diff_map() const7613 diff_maps::get_typedef_diff_map() const
7614 {return priv_->typedef_diff_map_;}
7615 
7616 /// Getter of the map that contains typedef type diffs.
7617 ///
7618 /// @return the map that contains typedef type diffs.
7619 string_diff_ptr_map&
get_typedef_diff_map()7620 diff_maps::get_typedef_diff_map()
7621 {return priv_->typedef_diff_map_;}
7622 
7623 /// Getter of the map that contains array type diffs.
7624 ///
7625 /// @return the map that contains array type diffs.
7626 const string_diff_ptr_map&
get_array_diff_map() const7627 diff_maps::get_array_diff_map() const
7628 {return priv_->array_diff_map_;}
7629 
7630 /// Getter of the map that contains array type diffs.
7631 ///
7632 /// @return the map that contains array type diffs.
7633 string_diff_ptr_map&
get_array_diff_map()7634 diff_maps::get_array_diff_map()
7635 {return priv_->array_diff_map_;}
7636 
7637 /// Getter of the map that contains reference type diffs.
7638 ///
7639 /// @return the map that contains reference type diffs.
7640 const string_diff_ptr_map&
get_reference_diff_map() const7641 diff_maps::get_reference_diff_map() const
7642 {return priv_->reference_diff_map_;}
7643 
7644 /// Getter of the map that contains reference type diffs.
7645 ///
7646 /// @return the map that contains reference type diffs.
7647 string_diff_ptr_map&
get_reference_diff_map()7648 diff_maps::get_reference_diff_map()
7649 {{return priv_->reference_diff_map_;}}
7650 
7651 /// Getter of the map that contains function parameter diffs.
7652 ///
7653 /// @return the map that contains function parameter diffs.
7654 const string_diff_ptr_map&
get_fn_parm_diff_map() const7655 diff_maps::get_fn_parm_diff_map() const
7656 {return priv_->fn_parm_diff_map_;}
7657 
7658 /// Getter of the map that contains function parameter diffs.
7659 ///
7660 /// @return the map that contains function parameter diffs.
7661 string_diff_ptr_map&
get_fn_parm_diff_map()7662 diff_maps::get_fn_parm_diff_map()
7663 {return priv_->fn_parm_diff_map_;}
7664 
7665 /// Getter of the map that contains function type diffs.
7666 ///
7667 /// @return the map that contains function type diffs.
7668 const string_diff_ptr_map&
get_function_type_diff_map() const7669 diff_maps::get_function_type_diff_map() const
7670 {return priv_->function_type_diff_map_;}
7671 
7672 /// Getter of the map that contains function type diffs.
7673 ///
7674 /// @return the map that contains function type diffs.
7675 string_diff_ptr_map&
get_function_type_diff_map()7676 diff_maps::get_function_type_diff_map()
7677 {return priv_->function_type_diff_map_;}
7678 
7679 /// Getter of the map that contains function decl diffs.
7680 ///
7681 /// @return the map that contains function decl diffs.
7682 const string_diff_ptr_map&
get_function_decl_diff_map() const7683 diff_maps::get_function_decl_diff_map() const
7684 {return priv_->function_decl_diff_map_;}
7685 
7686 /// Getter of the map that contains function decl diffs.
7687 ///
7688 /// @return the map that contains function decl diffs.
7689 string_diff_ptr_map&
get_function_decl_diff_map()7690 diff_maps::get_function_decl_diff_map()
7691 {return priv_->function_decl_diff_map_;}
7692 
7693 /// Getter of the map that contains var decl diffs.
7694 ///
7695 /// @return the map that contains var decl diffs.
7696 const string_diff_ptr_map&
get_var_decl_diff_map() const7697 diff_maps::get_var_decl_diff_map() const
7698 {return priv_->var_decl_diff_map_;}
7699 
7700 /// Getter of the map that contains var decl diffs.
7701 ///
7702 /// @return the map that contains var decl diffs.
7703 string_diff_ptr_map&
get_var_decl_diff_map()7704 diff_maps::get_var_decl_diff_map()
7705 {return priv_->var_decl_diff_map_;}
7706 
7707 /// Getter of the map that contains distinct diffs.
7708 ///
7709 /// @return the map that contains distinct diffs.
7710 const string_diff_ptr_map&
get_distinct_diff_map() const7711 diff_maps::get_distinct_diff_map() const
7712 {return priv_->distinct_diff_map_;}
7713 
7714 /// Getter of the map that contains distinct diffs.
7715 ///
7716 /// @return the map that contains distinct diffs.
7717 string_diff_ptr_map&
get_distinct_diff_map()7718 diff_maps::get_distinct_diff_map()
7719 {return priv_->distinct_diff_map_;}
7720 
7721 /// Insert a new diff node into the current instance of @ref diff_maps.
7722 ///
7723 /// @param dif the new diff node to insert into the @ref diff_maps.
7724 ///
7725 /// @param impacted_iface the interface (global function or variable)
7726 /// currently being analysed that led to analysing the diff node @p
7727 /// dif.  In other words, this is the interface impacted by the diff
7728 /// node @p dif.  Note that this can be nil in cases where we are
7729 /// directly analysing changes to a type that is not reachable from
7730 /// any global function or variable.
7731 ///
7732 /// @return true iff the diff node could be added to the current
7733 /// instance of @ref diff_maps.
7734 bool
insert_diff_node(const diff * dif,const type_or_decl_base_sptr & impacted_iface)7735 diff_maps::insert_diff_node(const diff *dif,
7736 			    const type_or_decl_base_sptr& impacted_iface)
7737 {
7738   string n = get_pretty_representation(dif->first_subject(),
7739 				       /*internal=*/true);
7740   if (const type_decl_diff *d = is_diff_of_basic_type(dif))
7741     get_type_decl_diff_map()[n] = const_cast<type_decl_diff*>(d);
7742   else if (const enum_diff *d = is_enum_diff(dif))
7743     get_enum_diff_map()[n] = const_cast<enum_diff*>(d);
7744   else if (const class_diff *d = is_class_diff(dif))
7745       get_class_diff_map()[n] = const_cast<class_diff*>(d);
7746   else if (const union_diff *d = is_union_diff(dif))
7747     get_union_diff_map()[n] = const_cast<union_diff*>(d);
7748   else if (const typedef_diff *d = is_typedef_diff(dif))
7749     get_typedef_diff_map()[n] = const_cast<typedef_diff*>(d);
7750   else if (const array_diff *d = is_array_diff(dif))
7751       get_array_diff_map()[n] = const_cast<array_diff*>(d);
7752   else if (const reference_diff *d = is_reference_diff(dif))
7753     get_reference_diff_map()[n] = const_cast<reference_diff*>(d);
7754   else if (const fn_parm_diff *d = is_fn_parm_diff(dif))
7755     get_fn_parm_diff_map()[n] = const_cast<fn_parm_diff*>(d);
7756   else if (const function_type_diff *d = is_function_type_diff(dif))
7757     get_function_type_diff_map()[n] = const_cast<function_type_diff*>(d);
7758   else if (const var_diff *d = is_var_diff(dif))
7759     get_var_decl_diff_map()[n] = const_cast<var_diff*>(d);
7760   else if (const function_decl_diff *d = is_function_decl_diff(dif))
7761     get_function_decl_diff_map()[n] = const_cast<function_decl_diff*>(d);
7762   else if (const distinct_diff *d = is_distinct_diff(dif))
7763     get_distinct_diff_map()[n] = const_cast<distinct_diff*>(d);
7764   else if (is_base_diff(dif))
7765     // we silently drop this case.
7766     return true;
7767   else
7768       ABG_ASSERT_NOT_REACHED;
7769 
7770   // Update the map that associates this diff node to the set of
7771   // interfaces it impacts.
7772 
7773   if (impacted_iface)
7774     {
7775       diff_artifact_set_map_type::iterator i =
7776 	priv_->impacted_artifacts_map_.find(dif);
7777 
7778       if (i == priv_->impacted_artifacts_map_.end())
7779 	{
7780 	  artifact_sptr_set_type set;
7781 	  set.insert(impacted_iface);
7782 	  priv_->impacted_artifacts_map_[dif] = set;
7783 	}
7784       else
7785 	i->second.insert(impacted_iface);
7786     }
7787 
7788   return true;
7789 }
7790 
7791 /// Lookup the interfaces that are impacted by a given leaf diff node.
7792 ///
7793 /// @param d the diff node to consider.
7794 ///
7795 /// @return the set of artifacts impacted by @p d.
7796 artifact_sptr_set_type*
lookup_impacted_interfaces(const diff * d) const7797 diff_maps::lookup_impacted_interfaces(const diff *d) const
7798 {
7799   diff_artifact_set_map_type::iterator i =
7800     priv_->impacted_artifacts_map_.find(d);
7801 
7802   if (i == priv_->impacted_artifacts_map_.end())
7803     return 0;
7804 
7805   return &i->second;
7806 }
7807 
7808 //
7809 // </diff_maps stuff>
7810 
7811 /// Constructor for the @ref diff_stat type.
7812 ///
7813 /// @param ctxt the context of the corpus diff.  Note that this
7814 /// context object must stay alive at least during the life time of
7815 /// the current instance of @ref corpus_diff::diff_stats.  Otherwise
7816 /// memory corruption issues occur.
diff_stats(diff_context_sptr ctxt)7817 corpus_diff::diff_stats::diff_stats(diff_context_sptr ctxt)
7818   : priv_(new priv(ctxt))
7819 {}
7820 
7821 /// Getter for the number of functions removed.
7822 ///
7823 /// @return the number of functions removed.
7824 size_t
num_func_removed() const7825 corpus_diff::diff_stats::num_func_removed() const
7826 {return priv_->num_func_removed;}
7827 
7828 /// Setter for the number of functions removed.
7829 ///
7830 /// @param n the new number of functions removed.
7831 void
num_func_removed(size_t n)7832 corpus_diff::diff_stats::num_func_removed(size_t n)
7833 {priv_->num_func_removed = n;}
7834 
7835 /// Getter for the number of removed functions that have been filtered
7836 /// out.
7837 ///
7838 /// @return the number of removed functions that have been filtered
7839 /// out.
7840 size_t
num_removed_func_filtered_out() const7841 corpus_diff::diff_stats::num_removed_func_filtered_out() const
7842 {
7843   if (priv_->ctxt() && !priv_->ctxt()->show_deleted_fns())
7844     return num_func_removed();
7845   return priv_->num_removed_func_filtered_out;
7846 }
7847 
7848 /// Setter for the number of removed functions that have been filtered
7849 /// out.
7850 ///
7851 /// @param t the new value.
7852 void
num_removed_func_filtered_out(size_t t)7853 corpus_diff::diff_stats::num_removed_func_filtered_out(size_t t)
7854 {priv_->num_removed_func_filtered_out = t;}
7855 
7856 /// Getter for the net number of function removed.
7857 ///
7858 /// This is the difference between the number of functions removed and
7859 /// the number of functons removed that have been filtered out.
7860 ///
7861 /// @return the net number of function removed.
7862 size_t
net_num_func_removed() const7863 corpus_diff::diff_stats::net_num_func_removed() const
7864 {
7865   ABG_ASSERT(num_func_removed() >= num_removed_func_filtered_out());
7866   return num_func_removed() - num_removed_func_filtered_out();
7867 }
7868 
7869 /// Getter for the number of functions added.
7870 ///
7871 /// @return the number of functions added.
7872 size_t
num_func_added() const7873 corpus_diff::diff_stats::num_func_added() const
7874 {return priv_->num_func_added;}
7875 
7876 /// Setter for the number of functions added.
7877 ///
7878 /// @param n the new number of functions added.
7879 void
num_func_added(size_t n)7880 corpus_diff::diff_stats::num_func_added(size_t n)
7881 {priv_->num_func_added = n;}
7882 
7883 /// Getter for the number of added function that have been filtered out.
7884 ///
7885 /// @return the number of added function that have been filtered out.
7886 size_t
num_added_func_filtered_out() const7887 corpus_diff::diff_stats::num_added_func_filtered_out() const
7888 {
7889   if (priv_->ctxt() && !priv_->ctxt()->show_added_fns())
7890     return num_func_added();
7891   return priv_->num_added_func_filtered_out;
7892 }
7893 
7894 /// Setter for the number of added function that have been filtered
7895 /// out.
7896 ///
7897 /// @param n the new value.
7898 void
num_added_func_filtered_out(size_t n)7899 corpus_diff::diff_stats::num_added_func_filtered_out(size_t n)
7900 {priv_->num_added_func_filtered_out = n;}
7901 
7902 /// Getter for the net number of added functions.
7903 ///
7904 /// The net number of added functions is the difference between the
7905 /// number of added functions and the number of added functions that
7906 /// have been filtered out.
7907 ///
7908 /// @return the net number of added functions.
7909 size_t
net_num_func_added() const7910 corpus_diff::diff_stats::net_num_func_added() const
7911 {
7912   ABG_ASSERT(num_func_added() >= num_added_func_filtered_out());
7913   return num_func_added() - num_added_func_filtered_out();
7914 }
7915 
7916 /// Getter for the number of functions that have a change in one of
7917 /// their sub-types.
7918 ///
7919 /// @return the number of functions that have a change in one of their
7920 /// sub-types.
7921 size_t
num_func_changed() const7922 corpus_diff::diff_stats::num_func_changed() const
7923 {return priv_->num_func_changed;}
7924 
7925 /// Setter for the number of functions that have a change in one of
7926 /// their sub-types.
7927 ///
7928 /// @@param n the new number of functions that have a change in one of
7929 /// their sub-types.
7930 void
num_func_changed(size_t n)7931 corpus_diff::diff_stats::num_func_changed(size_t n)
7932 {priv_->num_func_changed = n;}
7933 
7934 /// Getter for the number of functions that have a change in one of
7935 /// their sub-types, and that have been filtered out.
7936 ///
7937 /// @return the number of functions that have a change in one of their
7938 /// sub-types, and that have been filtered out.
7939 size_t
num_changed_func_filtered_out() const7940 corpus_diff::diff_stats::num_changed_func_filtered_out() const
7941 {return priv_->num_changed_func_filtered_out;}
7942 
7943 /// Setter for the number of functions that have a change in one of
7944 /// their sub-types, and that have been filtered out.
7945 ///
7946 /// @param n the new number of functions that have a change in one of their
7947 /// sub-types, and that have been filtered out.
7948 void
num_changed_func_filtered_out(size_t n)7949 corpus_diff::diff_stats::num_changed_func_filtered_out(size_t n)
7950 {priv_->num_changed_func_filtered_out = n;}
7951 
7952 /// Getter for the number of functions that carry virtual member
7953 /// offset changes.
7954 ///
7955 /// @return the number of functions that carry virtual member changes.
7956 size_t
num_func_with_virtual_offset_changes() const7957 corpus_diff::diff_stats::num_func_with_virtual_offset_changes() const
7958 {return priv_->num_func_with_virt_offset_changes;}
7959 
7960 /// Setter for the number of functions that carry virtual member
7961 /// offset changes.
7962 ///
7963 /// @param n the new number of functions that carry virtual member
7964 /// offset.  changes.
7965 void
num_func_with_virtual_offset_changes(size_t n)7966 corpus_diff::diff_stats::num_func_with_virtual_offset_changes(size_t n)
7967 {priv_->num_func_with_virt_offset_changes = n;}
7968 
7969 /// Getter for the number of functions that have a change in their
7970 /// sub-types, minus the number of these functions that got filtered
7971 /// out from the diff.
7972 ///
7973 /// @return for the the number of functions that have a change in
7974 /// their sub-types, minus the number of these functions that got
7975 /// filtered out from the diff.
7976 size_t
net_num_func_changed() const7977 corpus_diff::diff_stats::net_num_func_changed() const
7978 {return num_func_changed() - num_changed_func_filtered_out();}
7979 
7980 /// Getter for the number of variables removed.
7981 ///
7982 /// @return the number of variables removed.
7983 size_t
num_vars_removed() const7984 corpus_diff::diff_stats::num_vars_removed() const
7985 {return priv_->num_vars_removed;}
7986 
7987 /// Setter for the number of variables removed.
7988 ///
7989 /// @param n the new number of variables removed.
7990 void
num_vars_removed(size_t n)7991 corpus_diff::diff_stats::num_vars_removed(size_t n)
7992 {priv_->num_vars_removed = n;}
7993 
7994 /// Getter for the number removed variables that have been filtered
7995 /// out.
7996 ///
7997 /// @return the number removed variables that have been filtered out.
7998 size_t
num_removed_vars_filtered_out() const7999 corpus_diff::diff_stats::num_removed_vars_filtered_out() const
8000 {
8001   if (priv_->ctxt() && !priv_->ctxt()->show_deleted_vars())
8002     return num_vars_removed();
8003   return priv_->num_removed_vars_filtered_out;
8004 }
8005 
8006 /// Setter for the number of removed variables that have been filtered
8007 /// out.
8008 ///
8009 /// @param n the new value.
8010 void
num_removed_vars_filtered_out(size_t n) const8011 corpus_diff::diff_stats::num_removed_vars_filtered_out(size_t n) const
8012 {priv_->num_removed_vars_filtered_out = n;}
8013 
8014 /// Getter for the net number of removed variables.
8015 ///
8016 /// The net number of removed variables is the difference between the
8017 /// number of removed variables and the number of removed variables
8018 /// that have been filtered out.
8019 ///
8020 /// @return the net number of removed variables.
8021 size_t
net_num_vars_removed() const8022 corpus_diff::diff_stats::net_num_vars_removed() const
8023 {
8024   ABG_ASSERT(num_vars_removed() >= num_removed_vars_filtered_out());
8025   return num_vars_removed() - num_removed_vars_filtered_out();
8026 }
8027 
8028 /// Getter for the number of variables added.
8029 ///
8030 /// @return the number of variables added.
8031 size_t
num_vars_added() const8032 corpus_diff::diff_stats::num_vars_added() const
8033 {return priv_->num_vars_added;}
8034 
8035 /// Setter for the number of variables added.
8036 ///
8037 /// @param n the new number of variables added.
8038 void
num_vars_added(size_t n)8039 corpus_diff::diff_stats::num_vars_added(size_t n)
8040 {priv_->num_vars_added = n;}
8041 
8042 /// Getter for the number of added variables that have been filtered
8043 /// out.
8044 ///
8045 /// @return the number of added variables that have been filtered out.
8046 size_t
num_added_vars_filtered_out() const8047 corpus_diff::diff_stats::num_added_vars_filtered_out() const
8048 {
8049   if (priv_->ctxt() && !priv_->ctxt()->show_added_vars())
8050     return num_vars_added();
8051   return priv_->num_added_vars_filtered_out;
8052 }
8053 
8054 /// Setter for the number of added variables that have been filtered
8055 /// out.
8056 ///
8057 /// @param n the new value.
8058 void
num_added_vars_filtered_out(size_t n)8059 corpus_diff::diff_stats::num_added_vars_filtered_out(size_t n)
8060 {priv_->num_added_vars_filtered_out = n;}
8061 
8062 /// Getter for the net number of added variables.
8063 ///
8064 /// The net number of added variables is the difference between the
8065 /// number of added variables and the number of added variables that
8066 /// have been filetered out.
8067 ///
8068 /// @return the net number of added variables.
8069 size_t
net_num_vars_added() const8070 corpus_diff::diff_stats::net_num_vars_added() const
8071 {
8072   ABG_ASSERT(num_vars_added() >= num_added_vars_filtered_out());
8073   return num_vars_added() - num_added_vars_filtered_out();
8074 }
8075 
8076 /// Getter for the number of variables that have a change in one of
8077 /// their sub-types.
8078 ///
8079 /// @return the number of variables that have a change in one of their
8080 /// sub-types.
8081 size_t
num_vars_changed() const8082 corpus_diff::diff_stats::num_vars_changed() const
8083 {return priv_->num_vars_changed;}
8084 
8085 /// Setter for the number of variables that have a change in one of
8086 /// their sub-types.
8087 ///
8088 /// @param n the new number of variables that have a change in one of
8089 /// their sub-types.
8090 void
num_vars_changed(size_t n)8091 corpus_diff::diff_stats::num_vars_changed(size_t n)
8092 {priv_->num_vars_changed = n;}
8093 
8094 /// Getter for the number of variables that have a change in one of
8095 /// their sub-types, and that have been filtered out.
8096 ///
8097 /// @return the number of functions that have a change in one of their
8098 /// sub-types, and that have been filtered out.
8099 size_t
num_changed_vars_filtered_out() const8100 corpus_diff::diff_stats::num_changed_vars_filtered_out() const
8101 {return priv_->num_changed_vars_filtered_out;}
8102 
8103 /// Setter for the number of variables that have a change in one of
8104 /// their sub-types, and that have been filtered out.
8105 ///
8106 /// @param n the new number of variables that have a change in one of their
8107 /// sub-types, and that have been filtered out.
8108 void
num_changed_vars_filtered_out(size_t n)8109 corpus_diff::diff_stats::num_changed_vars_filtered_out(size_t n)
8110 {priv_->num_changed_vars_filtered_out = n;}
8111 
8112 /// Getter for the number of variables that have a change in their
8113 /// sub-types, minus the number of these variables that got filtered
8114 /// out from the diff.
8115 ///
8116 /// @return for the the number of variables that have a change in
8117 /// their sub-types, minus the number of these variables that got
8118 /// filtered out from the diff.
8119 size_t
net_num_vars_changed() const8120 corpus_diff::diff_stats::net_num_vars_changed() const
8121 {return num_vars_changed() - num_changed_vars_filtered_out();}
8122 
8123 /// Getter for the number of function symbols (not referenced by any
8124 /// debug info) that got removed.
8125 ///
8126 /// @return the number of function symbols (not referenced by any
8127 /// debug info) that got removed.
8128 size_t
num_func_syms_removed() const8129 corpus_diff::diff_stats::num_func_syms_removed() const
8130 {return priv_->num_func_syms_removed;}
8131 
8132 /// Setter for the number of function symbols (not referenced by any
8133 /// debug info) that got removed.
8134 ///
8135 /// @param n the number of function symbols (not referenced by any
8136 /// debug info) that got removed.
8137 void
num_func_syms_removed(size_t n)8138 corpus_diff::diff_stats::num_func_syms_removed(size_t n)
8139 {priv_->num_func_syms_removed = n;}
8140 
8141 /// Getter for the number of removed function symbols, not referenced
8142 /// by debug info, that have been filtered out.
8143 ///
8144 /// @return the number of removed function symbols, not referenced by
8145 /// debug info, that have been filtered out.
8146 size_t
num_removed_func_syms_filtered_out() const8147 corpus_diff::diff_stats::num_removed_func_syms_filtered_out() const
8148 {
8149   if (priv_->ctxt()
8150       && !priv_->ctxt()->show_symbols_unreferenced_by_debug_info())
8151     return num_func_syms_removed();
8152   return priv_->num_removed_func_syms_filtered_out;
8153 }
8154 
8155 /// Setter for the number of removed function symbols, not referenced
8156 /// by debug info, that have been filtered out.
8157 ///
8158 /// @param n the new the number of removed function symbols, not
8159 /// referenced by debug info, that have been filtered out.
8160 void
num_removed_func_syms_filtered_out(size_t n)8161 corpus_diff::diff_stats::num_removed_func_syms_filtered_out(size_t n)
8162 {priv_->num_removed_func_syms_filtered_out = n;}
8163 
8164 /// Getter of the net number of removed function symbols that are not
8165 /// referenced by any debug info.
8166 ///
8167 /// This is the difference between the total number of removed
8168 /// function symbols and the number of removed function symbols that
8169 /// have been filteted out.  Both numbers are for symbols not
8170 /// referenced by debug info.
8171 ///
8172 /// return the net number of removed function symbols that are not
8173 /// referenced by any debug info.
8174 size_t
net_num_removed_func_syms() const8175 corpus_diff::diff_stats::net_num_removed_func_syms() const
8176 {
8177   ABG_ASSERT(num_func_syms_removed() >= num_removed_func_syms_filtered_out());
8178   return num_func_syms_removed() - num_removed_func_syms_filtered_out();
8179 }
8180 
8181 /// Getter for the number of function symbols (not referenced by any
8182 /// debug info) that got added.
8183 ///
8184 /// @return the number of function symbols (not referenced by any
8185 /// debug info) that got added.
8186 size_t
num_func_syms_added() const8187 corpus_diff::diff_stats::num_func_syms_added() const
8188 {return priv_->num_func_syms_added;}
8189 
8190 /// Setter for the number of function symbols (not referenced by any
8191 /// debug info) that got added.
8192 ///
8193 /// @param n the new number of function symbols (not referenced by any
8194 /// debug info) that got added.
8195 void
num_func_syms_added(size_t n)8196 corpus_diff::diff_stats::num_func_syms_added(size_t n)
8197 {priv_->num_func_syms_added = n;}
8198 
8199 /// Getter for the number of added function symbols, not referenced by
8200 /// any debug info, that have been filtered out.
8201 ///
8202 /// @return the number of added function symbols, not referenced by
8203 /// any debug info, that have been filtered out.
8204 size_t
num_added_func_syms_filtered_out() const8205 corpus_diff::diff_stats::num_added_func_syms_filtered_out() const
8206 {
8207   if (priv_->ctxt()
8208       && !(priv_->ctxt()->show_added_symbols_unreferenced_by_debug_info()
8209 	   && priv_->ctxt()->show_symbols_unreferenced_by_debug_info()))
8210     return num_func_syms_added();
8211   return priv_->num_added_func_syms_filtered_out;
8212 }
8213 
8214 /// Setter for the number of added function symbols, not referenced by
8215 /// any debug info, that have been filtered out.
8216 ///
8217 /// @param n the new number of added function symbols, not referenced
8218 /// by any debug info, that have been filtered out.
8219 void
num_added_func_syms_filtered_out(size_t n)8220 corpus_diff::diff_stats::num_added_func_syms_filtered_out(size_t n)
8221 {priv_->num_added_func_syms_filtered_out = n;}
8222 
8223 /// Getter of the net number of added function symbols that are not
8224 /// referenced by any debug info.
8225 ///
8226 /// This is the difference between the total number of added
8227 /// function symbols and the number of added function symbols that
8228 /// have been filteted out.  Both numbers are for symbols not
8229 /// referenced by debug info.
8230 ///
8231 /// return the net number of added function symbols that are not
8232 /// referenced by any debug info.
8233 size_t
net_num_added_func_syms() const8234 corpus_diff::diff_stats::net_num_added_func_syms() const
8235 {
8236   ABG_ASSERT(num_func_syms_added() >= num_added_func_syms_filtered_out());
8237   return num_func_syms_added()- num_added_func_syms_filtered_out();
8238 }
8239 
8240 /// Getter for the number of variable symbols (not referenced by any
8241 /// debug info) that got removed.
8242 ///
8243 /// @return the number of variable symbols (not referenced by any
8244 /// debug info) that got removed.
8245 size_t
num_var_syms_removed() const8246 corpus_diff::diff_stats::num_var_syms_removed() const
8247 {return priv_->num_var_syms_removed;}
8248 
8249 /// Setter for the number of variable symbols (not referenced by any
8250 /// debug info) that got removed.
8251 ///
8252 /// @param n the number of variable symbols (not referenced by any
8253 /// debug info) that got removed.
8254 void
num_var_syms_removed(size_t n)8255 corpus_diff::diff_stats::num_var_syms_removed(size_t n)
8256 {priv_->num_var_syms_removed = n;}
8257 
8258 /// Getter for the number of removed variable symbols, not referenced
8259 /// by any debug info, that have been filtered out.
8260 ///
8261 /// @return the number of removed variable symbols, not referenced
8262 /// by any debug info, that have been filtered out.
8263 size_t
num_removed_var_syms_filtered_out() const8264 corpus_diff::diff_stats::num_removed_var_syms_filtered_out() const
8265 {
8266   if (priv_->ctxt()
8267       && !priv_->ctxt()->show_symbols_unreferenced_by_debug_info())
8268     return num_var_syms_removed();
8269   return priv_->num_removed_var_syms_filtered_out;
8270 }
8271 
8272 /// Setter for the number of removed variable symbols, not referenced
8273 /// by any debug info, that have been filtered out.
8274 ///
8275 /// @param n the number of removed variable symbols, not referenced by
8276 /// any debug info, that have been filtered out.
8277 void
num_removed_var_syms_filtered_out(size_t n)8278 corpus_diff::diff_stats::num_removed_var_syms_filtered_out(size_t n)
8279 {priv_->num_removed_var_syms_filtered_out = n;}
8280 
8281 /// Getter of the net number of removed variable symbols that are not
8282 /// referenced by any debug info.
8283 ///
8284 /// This is the difference between the total number of removed
8285 /// variable symbols and the number of removed variable symbols that
8286 /// have been filteted out.  Both numbers are for symbols not
8287 /// referenced by debug info.
8288 ///
8289 /// return the net number of removed variable symbols that are not
8290 /// referenced by any debug info.
8291 size_t
net_num_removed_var_syms() const8292 corpus_diff::diff_stats::net_num_removed_var_syms() const
8293 {
8294   ABG_ASSERT(num_var_syms_removed() >= num_removed_var_syms_filtered_out());
8295   return num_var_syms_removed() - num_removed_var_syms_filtered_out();
8296 }
8297 
8298 /// Getter for the number of variable symbols (not referenced by any
8299 /// debug info) that got added.
8300 ///
8301 /// @return the number of variable symbols (not referenced by any
8302 /// debug info) that got added.
8303 size_t
num_var_syms_added() const8304 corpus_diff::diff_stats::num_var_syms_added() const
8305 {return priv_->num_var_syms_added;}
8306 
8307 /// Setter for the number of variable symbols (not referenced by any
8308 /// debug info) that got added.
8309 ///
8310 /// @param n the new number of variable symbols (not referenced by any
8311 /// debug info) that got added.
8312 void
num_var_syms_added(size_t n)8313 corpus_diff::diff_stats::num_var_syms_added(size_t n)
8314 {priv_->num_var_syms_added = n;}
8315 
8316 /// Getter for the number of added variable symbols, not referenced by
8317 /// any debug info, that have been filtered out.
8318 ///
8319 /// @return the number of added variable symbols, not referenced by
8320 /// any debug info, that have been filtered out.
8321 size_t
num_added_var_syms_filtered_out() const8322 corpus_diff::diff_stats::num_added_var_syms_filtered_out() const
8323 {
8324   if (priv_->ctxt()
8325       && !(priv_->ctxt()->show_added_symbols_unreferenced_by_debug_info()
8326 	   && priv_->ctxt()->show_symbols_unreferenced_by_debug_info()))
8327     return num_var_syms_added();
8328   return priv_->num_added_var_syms_filtered_out;
8329 }
8330 
8331 /// Setter for the number of added variable symbols, not referenced by
8332 /// any debug info, that have been filtered out.
8333 ///
8334 /// @param n the new number of added variable symbols, not referenced
8335 /// by any debug info, that have been filtered out.
8336 void
num_added_var_syms_filtered_out(size_t n)8337 corpus_diff::diff_stats::num_added_var_syms_filtered_out(size_t n)
8338 {priv_->num_added_var_syms_filtered_out = n;}
8339 
8340 /// Getter of the net number of added variable symbols that are not
8341 /// referenced by any debug info.
8342 ///
8343 /// This is the difference between the total number of added
8344 /// variable symbols and the number of added variable symbols that
8345 /// have been filteted out.  Both numbers are for symbols not
8346 /// referenced by debug info.
8347 ///
8348 /// return the net number of added variable symbols that are not
8349 /// referenced by any debug info.
8350 size_t
net_num_added_var_syms() const8351 corpus_diff::diff_stats::net_num_added_var_syms() const
8352 {
8353   ABG_ASSERT(num_var_syms_added() >= num_added_var_syms_filtered_out());
8354   return num_var_syms_added() - num_added_var_syms_filtered_out();
8355 }
8356 
8357 /// Getter of the number of leaf type change diff nodes.
8358 ///
8359 /// @return the number of leaf type change diff nodes.
8360 size_t
num_leaf_changes() const8361 corpus_diff::diff_stats::num_leaf_changes() const
8362 {return priv_->num_leaf_changes;}
8363 
8364 /// Setter of the number of leaf type change diff nodes.
8365 ///
8366 /// @param n the new number of leaf type change diff nodes.
8367 void
num_leaf_changes(size_t n)8368 corpus_diff::diff_stats::num_leaf_changes(size_t n)
8369 {priv_->num_leaf_changes = n;}
8370 
8371 /// Getter of the number of leaf type change diff nodes that have been
8372 /// filtered out.
8373 ///
8374 /// @return the number of leaf type change diff nodes that have been
8375 size_t
num_leaf_changes_filtered_out() const8376 corpus_diff::diff_stats::num_leaf_changes_filtered_out() const
8377 {return priv_->num_leaf_changes_filtered_out;}
8378 
8379 /// Setter of the number of leaf type change diff nodes that have been
8380 /// filtered out.
8381 ///
8382 /// @param n the new number of leaf type change diff nodes that have
8383 /// been filtered out.
8384 void
num_leaf_changes_filtered_out(size_t n)8385 corpus_diff::diff_stats::num_leaf_changes_filtered_out(size_t n)
8386 {priv_->num_leaf_changes_filtered_out = n;}
8387 
8388 /// Getter of the net number of leaf change diff nodes.
8389 ///
8390 /// This is the difference between the total number of leaf change
8391 /// diff nodes, and the number of the leaf change diff nodes that have
8392 /// been filtered out.
8393 ///
8394 /// A leaf change is either a type change, a function change or a
8395 /// variable change.
8396 size_t
net_num_leaf_changes() const8397 corpus_diff::diff_stats::net_num_leaf_changes() const
8398 {
8399   ABG_ASSERT(num_leaf_changes() >= num_leaf_changes_filtered_out());
8400   return num_leaf_changes() - num_leaf_changes_filtered_out();
8401 }
8402 
8403 /// Getter for the number of leaf type change diff nodes.
8404 ///
8405 /// @return the number of leaf type changes diff nodes.
8406 size_t
num_leaf_type_changes() const8407 corpus_diff::diff_stats::num_leaf_type_changes() const
8408 {return priv_->num_leaf_type_changes;}
8409 
8410 /// Setter for the number of leaf type change diff nodes.
8411 ///
8412 /// @param n the new number of leaf type change diff nodes.
8413 void
num_leaf_type_changes(size_t n)8414 corpus_diff::diff_stats::num_leaf_type_changes(size_t n)
8415 {priv_->num_leaf_type_changes = n;}
8416 
8417 /// Getter for the number of filtered out leaf type change diff nodes.
8418 ///
8419 /// @return the number of filtered out leaf type change diff nodes.
8420 size_t
num_leaf_type_changes_filtered_out() const8421 corpus_diff::diff_stats::num_leaf_type_changes_filtered_out() const
8422 {return priv_->num_leaf_type_changes_filtered_out;}
8423 
8424 /// Setter for the number of filtered out leaf type change diff nodes.
8425 /// @param n the new number of filtered out leaf type change diff nodes.
8426 void
num_leaf_type_changes_filtered_out(size_t n)8427 corpus_diff::diff_stats::num_leaf_type_changes_filtered_out(size_t n)
8428 {priv_->num_leaf_type_changes_filtered_out = n;}
8429 
8430 /// Getter for the net number of leaf type change diff nodes.
8431 ///
8432 /// This is the difference between the number of leaf type changes and
8433 /// the number of filtered out leaf type changes.
8434 ///
8435 /// @return the net number of leaf type change diff nodes.
8436 size_t
net_num_leaf_type_changes() const8437 corpus_diff::diff_stats::net_num_leaf_type_changes() const
8438 {return num_leaf_type_changes() - num_leaf_type_changes_filtered_out();}
8439 
8440 /// Getter for the number of leaf function change diff nodes.
8441 ///
8442 /// @return the number of leaf function change diff nodes.
8443 size_t
num_leaf_func_changes() const8444 corpus_diff::diff_stats::num_leaf_func_changes() const
8445 {return priv_->num_leaf_func_changes;}
8446 
8447 /// Setter for the number of leaf function change diff nodes.
8448 ///
8449 /// @param n the new number of leaf function change diff nodes.
8450 void
num_leaf_func_changes(size_t n)8451 corpus_diff::diff_stats::num_leaf_func_changes(size_t n)
8452 {priv_->num_leaf_func_changes = n;}
8453 
8454 /// Getter for the number of leaf function change diff nodes that were
8455 /// filtered out.
8456 ///
8457 /// @return the number of leaf function change diff nodes that were
8458 /// filtered out.
8459 size_t
num_leaf_func_changes_filtered_out() const8460 corpus_diff::diff_stats::num_leaf_func_changes_filtered_out() const
8461 {return priv_->num_leaf_func_changes_filtered_out;}
8462 
8463 /// Setter for the number of leaf function change diff nodes that were
8464 /// filtered out.
8465 ///
8466 /// @param n the new number of leaf function change diff nodes that
8467 /// were filtered out.
8468 void
num_leaf_func_changes_filtered_out(size_t n)8469 corpus_diff::diff_stats::num_leaf_func_changes_filtered_out(size_t n)
8470 {priv_->num_leaf_func_changes_filtered_out = n;}
8471 
8472 /// Getter for the net number of leaf function change diff nodes.
8473 ///
8474 /// This is the difference between the number of leaf function change
8475 /// diff nodes and the number of filtered out leaf function change
8476 /// diff nodes.
8477 ///
8478 /// @return the net number of leaf function change diff nodes.
8479 size_t
net_num_leaf_func_changes() const8480 corpus_diff::diff_stats::net_num_leaf_func_changes() const
8481 {return num_leaf_func_changes() - num_leaf_func_changes_filtered_out();}
8482 
8483 /// Getter for the number of leaf variable change diff nodes.
8484 ///
8485 /// @return the number of leaf variable change diff nodes.
8486 size_t
num_leaf_var_changes() const8487 corpus_diff::diff_stats::num_leaf_var_changes() const
8488 {return priv_->num_leaf_var_changes;}
8489 
8490 /// Setter for the number of leaf variable change diff nodes.
8491 ///
8492 /// @param n the number of leaf variable change diff nodes.
8493 void
num_leaf_var_changes(size_t n)8494 corpus_diff::diff_stats::num_leaf_var_changes(size_t n)
8495 {priv_->num_leaf_var_changes = n;}
8496 
8497 /// Getter of the number of added types that are unreachable from the
8498 /// public interface of the ABI corpus.
8499 ///
8500 /// Public interface means the set of defined and publicly exported
8501 /// functions and variables of the ABI corpus.
8502 ///
8503 /// @return the number of added types that are unreachable from the
8504 /// public interface of the ABI corpus.
8505 size_t
num_added_unreachable_types() const8506 corpus_diff::diff_stats::num_added_unreachable_types() const
8507 {return priv_->num_added_unreachable_types;}
8508 
8509 /// Setter of the number of added types that are unreachable from the
8510 /// public interface (global functions or variables) of the ABI
8511 /// corpus.
8512 ///
8513 /// Public interface means the set of defined and publicly exported
8514 /// functions and variables of the ABI corpus.
8515 ///
8516 /// @param n the new number of added types that are unreachable from
8517 /// the public interface of the ABI corpus.
8518 void
num_added_unreachable_types(size_t n)8519 corpus_diff::diff_stats::num_added_unreachable_types(size_t n)
8520 {priv_->num_added_unreachable_types = n;}
8521 
8522 /// Getter of the number of added types that are unreachable from
8523 /// public interfaces and that are filtered out by suppression
8524 /// specifications.
8525 ///
8526 /// @return the number of added types that are unreachable from public
8527 /// interfaces and that are filtered out by suppression
8528 /// specifications.
8529 size_t
num_added_unreachable_types_filtered_out() const8530 corpus_diff::diff_stats::num_added_unreachable_types_filtered_out() const
8531 {return priv_->num_added_unreachable_types_filtered_out;}
8532 
8533 /// Setter of the number of added types that are unreachable from
8534 /// public interfaces and that are filtered out by suppression
8535 /// specifications.
8536 ///
8537 /// @param n the new number of added types that are unreachable from
8538 /// public interfaces and that are filtered out by suppression
8539 /// specifications.
8540 void
num_added_unreachable_types_filtered_out(size_t n)8541 corpus_diff::diff_stats::num_added_unreachable_types_filtered_out(size_t n)
8542 {priv_->num_added_unreachable_types_filtered_out = n;}
8543 
8544 /// Getter of the number of added types that are unreachable from
8545 /// public interfaces and that are *NOT* filtered out by suppression
8546 /// specifications.
8547 ///
8548 /// @return the number of added types that are unreachable from public
8549 /// interfaces and that are *NOT* filtered out by suppression
8550 /// specifications.
8551 size_t
net_num_added_unreachable_types() const8552 corpus_diff::diff_stats::net_num_added_unreachable_types() const
8553 {
8554   ABG_ASSERT(num_added_unreachable_types()
8555 	     >=
8556 	     num_added_unreachable_types_filtered_out());
8557 
8558   return (num_added_unreachable_types()
8559 	  -
8560 	  num_added_unreachable_types_filtered_out());
8561 }
8562 
8563 /// Getter of the number of removed types that are unreachable from
8564 /// the public interface of the ABI corpus.
8565 ///
8566 /// Public interface means the set of defined and publicly exported
8567 /// functions and variables of the ABI corpus.
8568 ///
8569 /// @return the number of removed types that are unreachable from
8570 /// the public interface of the ABI corpus.
8571 size_t
num_removed_unreachable_types() const8572 corpus_diff::diff_stats::num_removed_unreachable_types() const
8573 {return priv_->num_removed_unreachable_types;}
8574 
8575 /// Setter of the number of removed types that are unreachable from
8576 /// the public interface of the ABI corpus.
8577 ///
8578 /// Public interface means the set of defined and publicly exported
8579 /// functions and variables of the ABI corpus.
8580 ///
8581 ///@param n the new number of removed types that are unreachable from
8582 /// the public interface of the ABI corpus.
8583 void
num_removed_unreachable_types(size_t n)8584 corpus_diff::diff_stats::num_removed_unreachable_types(size_t n)
8585 {priv_->num_removed_unreachable_types = n;}
8586 
8587 /// Getter of the number of removed types that are not reachable from
8588 /// public interfaces and that have been filtered out by suppression
8589 /// specifications.
8590 ///
8591 /// @return the number of removed types that are not reachable from
8592 /// public interfaces and that have been filtered out by suppression
8593 /// specifications.
8594 size_t
num_removed_unreachable_types_filtered_out() const8595 corpus_diff::diff_stats::num_removed_unreachable_types_filtered_out() const
8596 {return priv_->num_removed_unreachable_types_filtered_out;}
8597 
8598 /// Setter of the number of removed types that are not reachable from
8599 /// public interfaces and that have been filtered out by suppression
8600 /// specifications.
8601 ///
8602 /// @param n the new number of removed types that are not reachable
8603 /// from public interfaces and that have been filtered out by
8604 /// suppression specifications.
8605 void
num_removed_unreachable_types_filtered_out(size_t n)8606 corpus_diff::diff_stats::num_removed_unreachable_types_filtered_out(size_t n)
8607 {priv_->num_removed_unreachable_types_filtered_out = n;}
8608 
8609 /// Getter of the number of removed types that are not reachable from
8610 /// public interfaces and that have *NOT* been filtered out by
8611 /// suppression specifications.
8612 ///
8613 /// @return the number of removed types that are not reachable from
8614 /// public interfaces and that have *NOT* been filtered out by
8615 /// suppression specifications.
8616 size_t
net_num_removed_unreachable_types() const8617 corpus_diff::diff_stats::net_num_removed_unreachable_types() const
8618 {
8619   ABG_ASSERT(num_removed_unreachable_types()
8620 	     >=
8621 	     num_removed_unreachable_types_filtered_out());
8622 
8623   return (num_removed_unreachable_types()
8624 	  -
8625 	  num_removed_unreachable_types_filtered_out());
8626 }
8627 
8628 /// Getter of the number of changed types that are unreachable from
8629 /// the public interface of the ABI corpus.
8630 ///
8631 /// Public interface means the set of defined and publicly exported
8632 /// functions and variables of the ABI corpus.
8633 ///
8634 /// @return the number of changed types that are unreachable from the
8635 /// public interface of the ABI corpus.
8636 size_t
num_changed_unreachable_types() const8637 corpus_diff::diff_stats::num_changed_unreachable_types() const
8638 {return priv_->num_changed_unreachable_types;}
8639 
8640 /// Setter of the number of changed types that are unreachable from
8641 /// the public interface of the ABI corpus.
8642 ///
8643 /// Public interface means the set of defined and publicly exported
8644 /// functions and variables of the ABI corpus.
8645 ///
8646 ///@param n the new number of changed types that are unreachable from
8647 /// the public interface of the ABI corpus.
8648 void
num_changed_unreachable_types(size_t n)8649 corpus_diff::diff_stats::num_changed_unreachable_types(size_t n)
8650 {priv_->num_changed_unreachable_types = n;}
8651 
8652 /// Getter of the number of changed types that are unreachable from
8653 /// public interfaces and that have been filtered out by suppression
8654 /// specifications.
8655 ///
8656 /// @return the number of changed types that are unreachable from
8657 /// public interfaces and that have been filtered out by suppression
8658 /// specifications.
8659 size_t
num_changed_unreachable_types_filtered_out() const8660 corpus_diff::diff_stats::num_changed_unreachable_types_filtered_out() const
8661 {return priv_->num_changed_unreachable_types_filtered_out;}
8662 
8663 /// Setter of the number of changed types that are unreachable from
8664 /// public interfaces and that have been filtered out by suppression
8665 /// specifications.
8666 ///
8667 /// @param n the new number of changed types that are unreachable from
8668 /// public interfaces and that have been filtered out by suppression
8669 /// specifications.
8670 void
num_changed_unreachable_types_filtered_out(size_t n)8671 corpus_diff::diff_stats::num_changed_unreachable_types_filtered_out(size_t n)
8672 {priv_->num_changed_unreachable_types_filtered_out = n;}
8673 
8674 /// Getter of the number of changed types that are unreachable from
8675 /// public interfaces and that have *NOT* been filtered out by
8676 /// suppression specifications.
8677 ///
8678 /// @return the number of changed types that are unreachable from
8679 /// public interfaces and that have *NOT* been filtered out by
8680 /// suppression specifications.
8681 size_t
net_num_changed_unreachable_types() const8682 corpus_diff::diff_stats::net_num_changed_unreachable_types() const
8683 {
8684   ABG_ASSERT(num_changed_unreachable_types()
8685 	     >=
8686 	     num_changed_unreachable_types_filtered_out());
8687 
8688   return (num_changed_unreachable_types()
8689 	  -
8690 	  num_changed_unreachable_types_filtered_out());
8691 }
8692 
8693 /// Getter for the number of leaf variable changes diff nodes that
8694 /// have been filtered out.
8695 ///
8696 /// @return the number of leaf variable changes diff nodes that have
8697 /// been filtered out.
8698 size_t
num_leaf_var_changes_filtered_out() const8699 corpus_diff::diff_stats::num_leaf_var_changes_filtered_out() const
8700 {return priv_->num_leaf_var_changes_filtered_out;}
8701 
8702 /// Setter for the number of leaf variable changes diff nodes that
8703 /// have been filtered out.
8704 ///
8705 /// @param n the number of leaf variable changes diff nodes that have
8706 /// been filtered out.
8707 void
num_leaf_var_changes_filtered_out(size_t n)8708 corpus_diff::diff_stats::num_leaf_var_changes_filtered_out(size_t n)
8709 {priv_->num_leaf_var_changes_filtered_out = n;}
8710 
8711 /// Getter for the net number of leaf variable change diff nodes.
8712 ///
8713 /// This the difference between the number of leaf variable change
8714 /// diff nodes and the number of filtered out leaf variable change
8715 /// diff nodes.
8716 ///
8717 /// @return the net number of leaf variable change diff nodes.
8718 size_t
net_num_leaf_var_changes() const8719 corpus_diff::diff_stats::net_num_leaf_var_changes() const
8720 {return num_leaf_var_changes() - num_leaf_var_changes_filtered_out();}
8721 
8722 
8723 // <corpus_diff stuff>
8724 
8725 /// Getter of the context associated with this corpus.
8726 ///
8727 /// @return a smart pointer to the context associate with the corpus.
8728 diff_context_sptr
get_context()8729 corpus_diff::priv::get_context()
8730 {return ctxt_.lock();}
8731 
8732 /// Tests if the lookup tables are empty.
8733 ///
8734 /// @return true if the lookup tables are empty, false otherwise.
8735 bool
lookup_tables_empty() const8736 corpus_diff::priv::lookup_tables_empty() const
8737 {
8738   return (deleted_fns_.empty()
8739 	  && added_fns_.empty()
8740 	  && changed_fns_map_.empty()
8741 	  && deleted_vars_.empty()
8742 	  && added_vars_.empty()
8743 	  && changed_vars_map_.empty());
8744 }
8745 
8746 /// Clear the lookup tables useful for reporting an enum_diff.
8747 void
clear_lookup_tables()8748 corpus_diff::priv::clear_lookup_tables()
8749 {
8750   deleted_fns_.clear();
8751   added_fns_.clear();
8752   changed_fns_map_.clear();
8753   deleted_vars_.clear();
8754   added_vars_.clear();
8755   changed_vars_map_.clear();
8756 }
8757 
8758 /// If the lookup tables are not yet built, walk the differences and
8759 /// fill the lookup tables.
8760 void
ensure_lookup_tables_populated()8761 corpus_diff::priv::ensure_lookup_tables_populated()
8762 {
8763   if (!lookup_tables_empty())
8764     return;
8765 
8766   diff_context_sptr ctxt = get_context();
8767 
8768   {
8769     edit_script& e = fns_edit_script_;
8770 
8771     for (vector<deletion>::const_iterator it = e.deletions().begin();
8772 	 it != e.deletions().end();
8773 	 ++it)
8774       {
8775 	unsigned i = it->index();
8776 	ABG_ASSERT(i < first_->get_functions().size());
8777 
8778 	function_decl* deleted_fn = first_->get_functions()[i];
8779 	string n = deleted_fn->get_id();
8780 	ABG_ASSERT(!n.empty());
8781 	// The below is commented out because there can be several
8782 	// functions with the same ID in the corpus.  So several
8783 	// functions with the same ID can be deleted.
8784 	// ABG_ASSERT(deleted_fns_.find(n) == deleted_fns_.end());
8785 	deleted_fns_[n] = deleted_fn;
8786       }
8787 
8788     for (vector<insertion>::const_iterator it = e.insertions().begin();
8789 	 it != e.insertions().end();
8790 	 ++it)
8791       {
8792 	for (vector<unsigned>::const_iterator iit =
8793 	       it->inserted_indexes().begin();
8794 	     iit != it->inserted_indexes().end();
8795 	     ++iit)
8796 	  {
8797 	    unsigned i = *iit;
8798 	    function_decl* added_fn = second_->get_functions()[i];
8799 	    string n = added_fn->get_id();
8800 	    ABG_ASSERT(!n.empty());
8801 	    // The below is commented out because there can be several
8802 	    // functions with the same ID in the corpus.  So several
8803 	    // functions with the same ID can be added.
8804 	    // ABG_ASSERT(added_fns_.find(n) == added_fns_.end());
8805 	    string_function_ptr_map::const_iterator j =
8806 	      deleted_fns_.find(n);
8807 	    if (j != deleted_fns_.end())
8808 	      {
8809 		function_decl_sptr f(j->second, noop_deleter());
8810 		function_decl_sptr s(added_fn, noop_deleter());
8811 		function_decl_diff_sptr d = compute_diff(f, s, ctxt);
8812 		if (*j->second != *added_fn)
8813 		  changed_fns_map_[j->first] = d;
8814 		deleted_fns_.erase(j);
8815 	      }
8816 	    else
8817 	      added_fns_[n] = added_fn;
8818 	  }
8819       }
8820     sort_string_function_decl_diff_sptr_map(changed_fns_map_, changed_fns_);
8821 
8822     // Now walk the allegedly deleted functions; check if their
8823     // underlying symbols are deleted as well; otherwise, consider
8824     // that the function in question hasn't been deleted.
8825 
8826     vector<string> to_delete;
8827     for (string_function_ptr_map::const_iterator i = deleted_fns_.begin();
8828 	 i != deleted_fns_.end();
8829 	 ++i)
8830       if (second_->lookup_function_symbol(*i->second->get_symbol()))
8831 	to_delete.push_back(i->first);
8832 
8833     for (vector<string>::const_iterator i = to_delete.begin();
8834 	 i != to_delete.end();
8835 	 ++i)
8836       deleted_fns_.erase(*i);
8837 
8838     // Do something similar for added functions.
8839 
8840     to_delete.clear();
8841     for (string_function_ptr_map::const_iterator i = added_fns_.begin();
8842 	 i != added_fns_.end();
8843 	 ++i)
8844       {
8845 	if (first_->lookup_function_symbol(*i->second->get_symbol()))
8846 	  to_delete.push_back(i->first);
8847 	else if (! i->second->get_symbol()->get_version().is_empty()
8848 		 && i->second->get_symbol()->get_version().is_default())
8849 	  // We are looking for a symbol that has a default version,
8850 	  // and which seems to be newly added.  Let's see if the same
8851 	  // symbol with *no* version was already present in the
8852 	  // former corpus.  If yes, then the symbol shouldn't be
8853 	  // considered as 'added'.
8854 	  {
8855 	    elf_symbol::version empty_version;
8856 	    if (first_->lookup_function_symbol(i->second->get_symbol()->get_name(),
8857 					       empty_version))
8858 	      to_delete.push_back(i->first);
8859 	  }
8860       }
8861 
8862     for (vector<string>::const_iterator i = to_delete.begin();
8863 	 i != to_delete.end();
8864 	 ++i)
8865       added_fns_.erase(*i);
8866   }
8867 
8868   {
8869     edit_script& e = vars_edit_script_;
8870 
8871     for (vector<deletion>::const_iterator it = e.deletions().begin();
8872 	 it != e.deletions().end();
8873 	 ++it)
8874       {
8875 	unsigned i = it->index();
8876 	ABG_ASSERT(i < first_->get_variables().size());
8877 
8878 	var_decl* deleted_var = first_->get_variables()[i];
8879 	string n = deleted_var->get_id();
8880 	ABG_ASSERT(!n.empty());
8881 	ABG_ASSERT(deleted_vars_.find(n) == deleted_vars_.end());
8882 	deleted_vars_[n] = deleted_var;
8883       }
8884 
8885     for (vector<insertion>::const_iterator it = e.insertions().begin();
8886 	 it != e.insertions().end();
8887 	 ++it)
8888       {
8889 	for (vector<unsigned>::const_iterator iit =
8890 	       it->inserted_indexes().begin();
8891 	     iit != it->inserted_indexes().end();
8892 	     ++iit)
8893 	  {
8894 	    unsigned i = *iit;
8895 	    var_decl* added_var = second_->get_variables()[i];
8896 	    string n = added_var->get_id();
8897 	    ABG_ASSERT(!n.empty());
8898 	    {
8899 	      string_var_ptr_map::const_iterator k = added_vars_.find(n);
8900 	      if ( k != added_vars_.end())
8901 		{
8902 		  ABG_ASSERT(is_member_decl(k->second)
8903 			 && get_member_is_static(k->second));
8904 		  continue;
8905 		}
8906 	    }
8907 	    string_var_ptr_map::const_iterator j =
8908 	      deleted_vars_.find(n);
8909 	    if (j != deleted_vars_.end())
8910 	      {
8911 		if (*j->second != *added_var)
8912 		  {
8913 		    var_decl_sptr f(j->second, noop_deleter());
8914 		    var_decl_sptr s(added_var, noop_deleter());
8915 		    changed_vars_map_[n] = compute_diff(f, s, ctxt);
8916 		  }
8917 		deleted_vars_.erase(j);
8918 	      }
8919 	    else
8920 	      added_vars_[n] = added_var;
8921 	  }
8922       }
8923     sort_string_var_diff_sptr_map(changed_vars_map_,
8924 				  sorted_changed_vars_);
8925 
8926     // Now walk the allegedly deleted variables; check if their
8927     // underlying symbols are deleted as well; otherwise consider
8928     // that the variable in question hasn't been deleted.
8929 
8930     vector<string> to_delete;
8931     for (string_var_ptr_map::const_iterator i = deleted_vars_.begin();
8932 	 i != deleted_vars_.end();
8933 	 ++i)
8934       if (second_->lookup_variable_symbol(*i->second->get_symbol()))
8935 	to_delete.push_back(i->first);
8936 
8937     for (vector<string>::const_iterator i = to_delete.begin();
8938 	 i != to_delete.end();
8939 	 ++i)
8940       deleted_vars_.erase(*i);
8941 
8942     // Do something similar for added variables.
8943 
8944     to_delete.clear();
8945     for (string_var_ptr_map::const_iterator i = added_vars_.begin();
8946 	 i != added_vars_.end();
8947 	 ++i)
8948       if (first_->lookup_variable_symbol(*i->second->get_symbol()))
8949 	to_delete.push_back(i->first);
8950       else if (! i->second->get_symbol()->get_version().is_empty()
8951 		 && i->second->get_symbol()->get_version().is_default())
8952 	// We are looking for a symbol that has a default version,
8953 	// and which seems to be newly added.  Let's see if the same
8954 	// symbol with *no* version was already present in the
8955 	// former corpus.  If yes, then the symbol shouldn't be
8956 	// considered as 'added'.
8957 	{
8958 	  elf_symbol::version empty_version;
8959 	  if (first_->lookup_variable_symbol(i->second->get_symbol()->get_name(),
8960 					     empty_version))
8961 	    to_delete.push_back(i->first);
8962 	}
8963 
8964     for (vector<string>::const_iterator i = to_delete.begin();
8965 	 i != to_delete.end();
8966 	 ++i)
8967       added_vars_.erase(*i);
8968   }
8969 
8970   // Massage the edit script for added/removed function symbols that
8971   // were not referenced by any debug info and turn them into maps of
8972   // {symbol_name, symbol}.
8973   {
8974     edit_script& e = unrefed_fn_syms_edit_script_;
8975     for (vector<deletion>::const_iterator it = e.deletions().begin();
8976 	 it != e.deletions().end();
8977 	 ++it)
8978       {
8979 	unsigned i = it->index();
8980 	ABG_ASSERT(i < first_->get_unreferenced_function_symbols().size());
8981 	elf_symbol_sptr deleted_sym =
8982 	  first_->get_unreferenced_function_symbols()[i];
8983 	if (!second_->lookup_function_symbol(*deleted_sym))
8984 	  deleted_unrefed_fn_syms_[deleted_sym->get_id_string()] = deleted_sym;
8985       }
8986 
8987     for (vector<insertion>::const_iterator it = e.insertions().begin();
8988 	 it != e.insertions().end();
8989 	 ++it)
8990       {
8991 	for (vector<unsigned>::const_iterator iit =
8992 	       it->inserted_indexes().begin();
8993 	     iit != it->inserted_indexes().end();
8994 	     ++iit)
8995 	  {
8996 	    unsigned i = *iit;
8997 	    ABG_ASSERT(i < second_->get_unreferenced_function_symbols().size());
8998 	    elf_symbol_sptr added_sym =
8999 	      second_->get_unreferenced_function_symbols()[i];
9000 	    if ((deleted_unrefed_fn_syms_.find(added_sym->get_id_string())
9001 		 == deleted_unrefed_fn_syms_.end()))
9002 	      {
9003 		if (!first_->lookup_function_symbol(*added_sym))
9004 		  {
9005 		    bool do_add = true;
9006 		    if (! added_sym->get_version().is_empty()
9007 			&& added_sym->get_version().is_default())
9008 		      {
9009 			// So added_seem has a default version.  If
9010 			// the former corpus had a symbol with the
9011 			// same name as added_sym but with *no*
9012 			// version, then added_sym shouldn't be
9013 			// considered as a newly added symbol.
9014 			elf_symbol::version empty_version;
9015 			if (first_->lookup_function_symbol(added_sym->get_name(),
9016 							   empty_version))
9017 			  do_add = false;
9018 		      }
9019 
9020 		    if (do_add)
9021 		      added_unrefed_fn_syms_[added_sym->get_id_string()] =
9022 			added_sym;
9023 		  }
9024 	      }
9025 	    else
9026 	      deleted_unrefed_fn_syms_.erase(added_sym->get_id_string());
9027 	  }
9028       }
9029   }
9030 
9031   // Massage the edit script for added/removed variable symbols that
9032   // were not referenced by any debug info and turn them into maps of
9033   // {symbol_name, symbol}.
9034   {
9035     edit_script& e = unrefed_var_syms_edit_script_;
9036     for (vector<deletion>::const_iterator it = e.deletions().begin();
9037 	 it != e.deletions().end();
9038 	 ++it)
9039       {
9040 	unsigned i = it->index();
9041 	ABG_ASSERT(i < first_->get_unreferenced_variable_symbols().size());
9042 	elf_symbol_sptr deleted_sym =
9043 	  first_->get_unreferenced_variable_symbols()[i];
9044 	if (!second_->lookup_variable_symbol(*deleted_sym))
9045 	  deleted_unrefed_var_syms_[deleted_sym->get_id_string()] = deleted_sym;
9046       }
9047 
9048     for (vector<insertion>::const_iterator it = e.insertions().begin();
9049 	 it != e.insertions().end();
9050 	 ++it)
9051       {
9052 	for (vector<unsigned>::const_iterator iit =
9053 	       it->inserted_indexes().begin();
9054 	     iit != it->inserted_indexes().end();
9055 	     ++iit)
9056 	  {
9057 	    unsigned i = *iit;
9058 	    ABG_ASSERT(i < second_->get_unreferenced_variable_symbols().size());
9059 	    elf_symbol_sptr added_sym =
9060 	      second_->get_unreferenced_variable_symbols()[i];
9061 	    if (deleted_unrefed_var_syms_.find(added_sym->get_id_string())
9062 		== deleted_unrefed_var_syms_.end())
9063 	      {
9064 		if (!first_->lookup_variable_symbol(*added_sym))
9065 		  {
9066 		    bool do_add = true;
9067 		    if (! added_sym->get_version().is_empty()
9068 			&& added_sym->get_version().is_default())
9069 		      {
9070 			// So added_seem has a default version.  If
9071 			// the former corpus had a symbol with the
9072 			// same name as added_sym but with *no*
9073 			// version, then added_sym shouldn't be
9074 			// considered as a newly added symbol.
9075 			elf_symbol::version empty_version;
9076 			if (first_->lookup_variable_symbol(added_sym->get_name(),
9077 							   empty_version))
9078 			  do_add = false;
9079 		      }
9080 
9081 		    if (do_add)
9082 		      added_unrefed_var_syms_[added_sym->get_id_string()] =
9083 			added_sym;
9084 		  }
9085 	      }
9086 	    else
9087 	      deleted_unrefed_var_syms_.erase(added_sym->get_id_string());
9088 	  }
9089       }
9090   }
9091 
9092   // Handle the unreachable_types_edit_script_
9093   {
9094     edit_script& e = unreachable_types_edit_script_;
9095 
9096     // Populate the map of deleted unreachable types from the
9097     // deletions of the edit script.
9098     for (vector<deletion>::const_iterator it = e.deletions().begin();
9099 	 it != e.deletions().end();
9100 	 ++it)
9101       {
9102 	unsigned i = it->index();
9103 	type_base_sptr t
9104 	  (first_->get_types_not_reachable_from_public_interfaces()[i]);
9105 
9106 	if (!is_user_defined_type(t))
9107 	  continue;
9108 
9109 	string repr = abigail::ir::get_pretty_representation(t, true);
9110 	deleted_unreachable_types_[repr] = t;
9111       }
9112 
9113     // Populate the map of added and change unreachable types from the
9114     // insertions of the edit script.
9115     for (vector<insertion>::const_iterator it = e.insertions().begin();
9116 	 it != e.insertions().end();
9117 	 ++it)
9118       {
9119 	for (vector<unsigned>::const_iterator iit =
9120 	       it->inserted_indexes().begin();
9121 	     iit != it->inserted_indexes().end();
9122 	     ++iit)
9123 	  {
9124 	    unsigned i = *iit;
9125 	    type_base_sptr t
9126 	      (second_->get_types_not_reachable_from_public_interfaces()[i]);
9127 
9128 	    if (!is_user_defined_type(t))
9129 	      continue;
9130 
9131 	    string repr = abigail::ir::get_pretty_representation(t, true);
9132 
9133 	    // Let's see if the inserted type we are looking at was
9134 	    // reported as deleted as well.
9135 	    //
9136 	    // If it's been deleted and a different version of it has
9137 	    // now been added, it means it's been *changed*.  In that
9138 	    // case we'll compute the diff of that change and store it
9139 	    // in the map of changed unreachable types.
9140 	    //
9141 	    // Otherwise, it means the type's been added so we'll add
9142 	    // it to the set of added unreachable types.
9143 
9144 	    string_type_base_sptr_map::const_iterator j =
9145 	      deleted_unreachable_types_.find(repr);
9146 	    if (j != deleted_unreachable_types_.end())
9147 	      {
9148 		// So there was another type of the same pretty
9149 		// representation which was reported as deleted.
9150 		// Let's see if they are different or not ...
9151 		decl_base_sptr old_type = is_decl(j->second);
9152 		decl_base_sptr new_type = is_decl(t);
9153 		if (old_type != new_type)
9154 		  {
9155 		    // The previously added type is different from this
9156 		    // one that is added.  That means the initial type
9157 		    // was changed.  Let's compute its diff and store it
9158 		    // as a changed type.
9159 		    diff_sptr d = compute_diff(old_type, new_type, ctxt);
9160 		    ABG_ASSERT(d->has_changes());
9161 		    changed_unreachable_types_[repr]= d;
9162 		  }
9163 
9164 		// In any case, the type was both deleted and added,
9165 		// so we cannot have it marked as being deleted.  So
9166 		// let's remove it from the deleted types.
9167 		deleted_unreachable_types_.erase(j);
9168 	      }
9169 	    else
9170 	      // The type wasn't previously reported as deleted, so
9171 	      // it's really added.
9172 	      added_unreachable_types_[repr] = t;
9173 	  }
9174       }
9175   }
9176 }
9177 
9178 /// Test if a change reports about a given @ref function_decl that is
9179 /// changed in a certain way is suppressed by a given suppression
9180 /// specifiation
9181 ///
9182 /// @param fn the @ref function_decl to consider.
9183 ///
9184 /// @param suppr the suppression specification to consider.
9185 ///
9186 /// @param k the kind of change that happened to @p fn.
9187 ///
9188 /// @param ctxt the context of the current diff.
9189 ///
9190 /// @return true iff the suppression specification @p suppr suppresses
9191 /// change reports about function @p fn, if that function changes in
9192 /// the way expressed by @p k.
9193 static bool
function_is_suppressed(const function_decl * fn,const suppression_sptr suppr,function_suppression::change_kind k,const diff_context_sptr ctxt)9194 function_is_suppressed(const function_decl* fn,
9195 		       const suppression_sptr suppr,
9196 		       function_suppression::change_kind k,
9197 		       const diff_context_sptr ctxt)
9198 {
9199   function_suppression_sptr fn_suppr = is_function_suppression(suppr);
9200   if (!fn_suppr)
9201     return false;
9202   return fn_suppr->suppresses_function(fn, k, ctxt);
9203 }
9204 
9205 /// Test if a change reports about a given @ref var_decl that is
9206 /// changed in a certain way is suppressed by a given suppression
9207 /// specifiation
9208 ///
9209 /// @param fn the @ref var_decl to consider.
9210 ///
9211 /// @param suppr the suppression specification to consider.
9212 ///
9213 /// @param k the kind of change that happened to @p fn.
9214 ///
9215 /// @param ctxt the context of the current diff.
9216 ///
9217 /// @return true iff the suppression specification @p suppr suppresses
9218 /// change reports about variable @p fn, if that variable changes in
9219 /// the way expressed by @p k.
9220 static bool
variable_is_suppressed(const var_decl * var,const suppression_sptr suppr,variable_suppression::change_kind k,const diff_context_sptr ctxt)9221 variable_is_suppressed(const var_decl* var,
9222 		       const suppression_sptr suppr,
9223 		       variable_suppression::change_kind k,
9224 		       const diff_context_sptr ctxt)
9225 {
9226   variable_suppression_sptr var_suppr = is_variable_suppression(suppr);
9227   if (!var_suppr)
9228     return false;
9229   return var_suppr->suppresses_variable(var, k, ctxt);
9230 }
9231 
9232 /// Apply suppression specifications for this corpus diff to the set
9233 /// of added/removed functions/variables, as well as to types not
9234 /// reachable from global functions/variables.
9235 void
apply_supprs_to_added_removed_fns_vars_unreachable_types()9236 corpus_diff::priv::apply_supprs_to_added_removed_fns_vars_unreachable_types()
9237 {
9238   diff_context_sptr ctxt = get_context();
9239 
9240   const suppressions_type& suppressions = ctxt->suppressions();
9241   for (suppressions_type::const_iterator i = suppressions.begin();
9242        i != suppressions.end();
9243        ++i)
9244     {
9245       // Added/Deleted functions.
9246       if (function_suppression_sptr fn_suppr = is_function_suppression(*i))
9247 	{
9248 	  // Added functions
9249 	  for (string_function_ptr_map::const_iterator e = added_fns_.begin();
9250 	       e != added_fns_.end();
9251 	       ++e)
9252 	    if (function_is_suppressed(e->second, fn_suppr,
9253 				       function_suppression::ADDED_FUNCTION_CHANGE_KIND,
9254 				       ctxt))
9255 	      suppressed_added_fns_[e->first] = e->second;
9256 
9257 	  // Deleted functions.
9258 	  for (string_function_ptr_map::const_iterator e = deleted_fns_.begin();
9259 	       e != deleted_fns_.end();
9260 	       ++e)
9261 	    if (function_is_suppressed(e->second, fn_suppr,
9262 				       function_suppression::DELETED_FUNCTION_CHANGE_KIND,
9263 				       ctxt))
9264 	      suppressed_deleted_fns_[e->first] = e->second;
9265 
9266 	  // Added function symbols not referenced by any debug info
9267 	  for (string_elf_symbol_map::const_iterator e =
9268 		 added_unrefed_fn_syms_.begin();
9269 	       e != added_unrefed_fn_syms_.end();
9270 	       ++e)
9271 	    if (fn_suppr->suppresses_function_symbol(e->second,
9272 						     function_suppression::ADDED_FUNCTION_CHANGE_KIND,
9273 						     ctxt))
9274 	      suppressed_added_unrefed_fn_syms_[e->first] = e->second;
9275 
9276 	  // Removed function symbols not referenced by any debug info
9277 	  for (string_elf_symbol_map::const_iterator e =
9278 		 deleted_unrefed_fn_syms_.begin();
9279 	       e != deleted_unrefed_fn_syms_.end();
9280 	       ++e)
9281 	    if (fn_suppr->suppresses_function_symbol(e->second,
9282 						     function_suppression::DELETED_FUNCTION_CHANGE_KIND,
9283 						     ctxt))
9284 	      suppressed_deleted_unrefed_fn_syms_[e->first] = e->second;
9285 	}
9286       // Added/Delete virtual member functions changes that might be
9287       // suppressed by a type_suppression that matches the enclosing
9288       // class of the virtual member function.
9289       else if (type_suppression_sptr type_suppr = is_type_suppression(*i))
9290 	{
9291 	  // Added virtual functions
9292 	  for (string_function_ptr_map::const_iterator e = added_fns_.begin();
9293 	       e != added_fns_.end();
9294 	       ++e)
9295 	    if (is_member_function(e->second)
9296 		&& get_member_function_is_virtual(e->second))
9297 	      {
9298 		function_decl *f = e->second;
9299 		class_decl_sptr c =
9300 		  is_class_type(is_method_type(f->get_type())->get_class_type());
9301 		ABG_ASSERT(c);
9302 		if (type_suppr->suppresses_type(c, ctxt))
9303 		  suppressed_added_fns_[e->first] = e->second;
9304 	      }
9305 	  // Deleted virtual functions
9306 	  for (string_function_ptr_map::const_iterator e = deleted_fns_.begin();
9307 	       e != deleted_fns_.end();
9308 	       ++e)
9309 	    if (is_member_function(e->second)
9310 		&& get_member_function_is_virtual(e->second))
9311 	      {
9312 		function_decl *f = e->second;
9313 		class_decl_sptr c =
9314 		  is_class_type(is_method_type(f->get_type())->get_class_type());
9315 		ABG_ASSERT(c);
9316 		if (type_suppr->suppresses_type(c, ctxt))
9317 		  suppressed_deleted_fns_[e->first] = e->second;
9318 	      }
9319 
9320 	  // Apply this type suppression to deleted types
9321 	  // non-reachable from a public interface.
9322 	  for (string_type_base_sptr_map::const_iterator e =
9323 		 deleted_unreachable_types_.begin();
9324 	       e != deleted_unreachable_types_.end();
9325 	       ++e)
9326 	    if (type_suppr->suppresses_type(e->second, ctxt))
9327 	      suppressed_deleted_unreachable_types_[e->first] = e->second;
9328 
9329 	  // Apply this type suppression to added types
9330 	  // non-reachable from a public interface.
9331 	  for (string_type_base_sptr_map::const_iterator e =
9332 		 added_unreachable_types_.begin();
9333 	       e != added_unreachable_types_.end();
9334 	       ++e)
9335 	    if (type_suppr->suppresses_type(e->second, ctxt))
9336 	      suppressed_added_unreachable_types_[e->first] = e->second;
9337 	}
9338       // Added/Deleted variables
9339       else if (variable_suppression_sptr var_suppr =
9340 	       is_variable_suppression(*i))
9341 	{
9342 	  // Added variables
9343 	  for (string_var_ptr_map::const_iterator e = added_vars_.begin();
9344 	       e != added_vars_.end();
9345 	       ++e)
9346 	    if (variable_is_suppressed(e->second, var_suppr,
9347 				       variable_suppression::ADDED_VARIABLE_CHANGE_KIND,
9348 				       ctxt))
9349 	      suppressed_added_vars_[e->first] = e->second;
9350 
9351 	  //Deleted variables
9352 	  for (string_var_ptr_map::const_iterator e = deleted_vars_.begin();
9353 	       e != deleted_vars_.end();
9354 	       ++e)
9355 	    if (variable_is_suppressed(e->second, var_suppr,
9356 				       variable_suppression::DELETED_VARIABLE_CHANGE_KIND,
9357 				       ctxt))
9358 	      suppressed_deleted_vars_[e->first] = e->second;
9359 
9360 	  // Added variable symbols not referenced by any debug info
9361 	  for (string_elf_symbol_map::const_iterator e =
9362 		 added_unrefed_var_syms_.begin();
9363 	       e != added_unrefed_var_syms_.end();
9364 	       ++e)
9365 	    if (var_suppr->suppresses_variable_symbol(e->second,
9366 						      variable_suppression::ADDED_VARIABLE_CHANGE_KIND,
9367 						      ctxt))
9368 	      suppressed_added_unrefed_var_syms_[e->first] = e->second;
9369 
9370 	  // Removed variable symbols not referenced by any debug info
9371 	  for (string_elf_symbol_map::const_iterator e =
9372 		 deleted_unrefed_var_syms_.begin();
9373 	       e != deleted_unrefed_var_syms_.end();
9374 	       ++e)
9375 	    if (var_suppr->suppresses_variable_symbol(e->second,
9376 						      variable_suppression::DELETED_VARIABLE_CHANGE_KIND,
9377 						      ctxt))
9378 	      suppressed_deleted_unrefed_var_syms_[e->first] = e->second;
9379 	}
9380     }
9381 }
9382 
9383 /// Test if the change reports for a given deleted function have
9384 /// been deleted.
9385 ///
9386 /// @param fn the function to consider.
9387 ///
9388 /// @return true iff the change reports for a give given deleted
9389 /// function have been deleted.
9390 bool
deleted_function_is_suppressed(const function_decl * fn) const9391 corpus_diff::priv::deleted_function_is_suppressed(const function_decl* fn) const
9392 {
9393   if (!fn)
9394     return false;
9395 
9396   string_function_ptr_map::const_iterator i =
9397     suppressed_deleted_fns_.find(fn->get_id());
9398 
9399   return (i != suppressed_deleted_fns_.end());
9400 }
9401 
9402 /// Test if an added type that is unreachable from public interface
9403 /// has been suppressed by a suppression specification.
9404 ///
9405 /// @param t the added unreachable type to be considered.
9406 ///
9407 /// @return true iff @p t has been suppressed by a suppression
9408 /// specification.
9409 bool
added_unreachable_type_is_suppressed(const type_base * t) const9410 corpus_diff::priv::added_unreachable_type_is_suppressed(const type_base *t)const
9411 {
9412   if (!t)
9413     return false;
9414 
9415   string repr = abigail::ir::get_pretty_representation(t, /*internal=*/true);
9416   string_type_base_sptr_map::const_iterator i =
9417     suppressed_added_unreachable_types_.find(repr);
9418   if (i == suppressed_added_unreachable_types_.end())
9419     return false;
9420 
9421   return true;
9422 }
9423 
9424 /// Test if a deleted type that is unreachable from public interface
9425 /// has been suppressed by a suppression specification.
9426 ///
9427 /// @param t the deleted unreachable type to be considered.
9428 ///
9429 /// @return true iff @p t has been suppressed by a suppression
9430 /// specification.
9431 bool
deleted_unreachable_type_is_suppressed(const type_base * t) const9432 corpus_diff::priv::deleted_unreachable_type_is_suppressed(const type_base *t) const
9433 {
9434   if (!t)
9435     return false;
9436 
9437   string repr = abigail::ir::get_pretty_representation(t, /*internal=*/true);
9438   string_type_base_sptr_map::const_iterator i =
9439     suppressed_deleted_unreachable_types_.find(repr);
9440   if (i == suppressed_deleted_unreachable_types_.end())
9441     return false;
9442 
9443   return true;
9444 }
9445 
9446 /// Test if the change reports for a give given added function has
9447 /// been deleted.
9448 ///
9449 /// @param fn the function to consider.
9450 ///
9451 /// @return true iff the change reports for a give given added
9452 /// function has been deleted.
9453 bool
added_function_is_suppressed(const function_decl * fn) const9454 corpus_diff::priv::added_function_is_suppressed(const function_decl* fn) const
9455 {
9456   if (!fn)
9457     return false;
9458 
9459   string_function_ptr_map::const_iterator i =
9460     suppressed_added_fns_.find(fn->get_id());
9461 
9462   return (i != suppressed_added_fns_.end());
9463 }
9464 
9465 /// Test if the change reports for a give given deleted variable has
9466 /// been deleted.
9467 ///
9468 /// @param var the variable to consider.
9469 ///
9470 /// @return true iff the change reports for a give given deleted
9471 /// variable has been deleted.
9472 bool
deleted_variable_is_suppressed(const var_decl * var) const9473 corpus_diff::priv::deleted_variable_is_suppressed(const var_decl* var) const
9474 {
9475   if (!var)
9476     return false;
9477 
9478   string_var_ptr_map::const_iterator i =
9479     suppressed_deleted_vars_.find(var->get_id());
9480 
9481   return (i != suppressed_deleted_vars_.end());
9482 }
9483 
9484 /// Test if the change reports for a given added variable have been
9485 /// suppressed.
9486 ///
9487 /// @param var the variable to consider.
9488 ///
9489 /// @return true iff the change reports for a given deleted
9490 /// variable has been deleted.
9491 bool
added_variable_is_suppressed(const var_decl * var) const9492 corpus_diff::priv::added_variable_is_suppressed(const var_decl* var) const
9493 {
9494   if (!var)
9495     return false;
9496 
9497   string_var_ptr_map::const_iterator i =
9498     suppressed_added_vars_.find(var->get_id());
9499 
9500   return (i != suppressed_added_vars_.end());
9501 }
9502 
9503 /// Test if the change reports for a given deleted function symbol
9504 /// (that is not referenced by any debug info) has been suppressed.
9505 ///
9506 /// @param var the function to consider.
9507 ///
9508 /// @return true iff the change reports for a given deleted function
9509 /// symbol has been suppressed.
9510 bool
deleted_unrefed_fn_sym_is_suppressed(const elf_symbol * s) const9511 corpus_diff::priv::deleted_unrefed_fn_sym_is_suppressed(const elf_symbol* s) const
9512 {
9513   if (!s)
9514     return false;
9515 
9516   string_elf_symbol_map::const_iterator i =
9517     suppressed_deleted_unrefed_fn_syms_.find(s->get_id_string());
9518 
9519   return (i != suppressed_deleted_unrefed_fn_syms_.end());
9520 }
9521 
9522 /// Test if the change reports for a given added function symbol
9523 /// (that is not referenced by any debug info) has been suppressed.
9524 ///
9525 /// @param var the function to consider.
9526 ///
9527 /// @return true iff the change reports for a given added function
9528 /// symbol has been suppressed.
9529 bool
added_unrefed_fn_sym_is_suppressed(const elf_symbol * s) const9530 corpus_diff::priv::added_unrefed_fn_sym_is_suppressed(const elf_symbol* s) const
9531 {
9532   if (!s)
9533     return false;
9534 
9535   string_elf_symbol_map::const_iterator i =
9536     suppressed_added_unrefed_fn_syms_.find(s->get_id_string());
9537 
9538   return (i != suppressed_added_unrefed_fn_syms_.end());
9539 }
9540 
9541 /// Test if the change reports for a given deleted variable symbol
9542 /// (that is not referenced by any debug info) has been suppressed.
9543 ///
9544 /// @param var the variable to consider.
9545 ///
9546 /// @return true iff the change reports for a given deleted variable
9547 /// symbol has been suppressed.
9548 bool
deleted_unrefed_var_sym_is_suppressed(const elf_symbol * s) const9549 corpus_diff::priv::deleted_unrefed_var_sym_is_suppressed(const elf_symbol* s) const
9550 {
9551   if (!s)
9552     return false;
9553 
9554   string_elf_symbol_map::const_iterator i =
9555     suppressed_deleted_unrefed_var_syms_.find(s->get_id_string());
9556 
9557   return (i != suppressed_deleted_unrefed_var_syms_.end());
9558 }
9559 
9560 /// Test if the change reports for a given added variable symbol
9561 /// (that is not referenced by any debug info) has been suppressed.
9562 ///
9563 /// @param var the variable to consider.
9564 ///
9565 /// @return true iff the change reports for a given added variable
9566 /// symbol has been suppressed.
9567 bool
added_unrefed_var_sym_is_suppressed(const elf_symbol * s) const9568 corpus_diff::priv::added_unrefed_var_sym_is_suppressed(const elf_symbol* s) const
9569 {
9570   if (!s)
9571     return false;
9572 
9573   string_elf_symbol_map::const_iterator i =
9574     suppressed_added_unrefed_var_syms_.find(s->get_id_string());
9575 
9576   return (i != suppressed_added_unrefed_var_syms_.end());
9577 }
9578 
9579 #ifdef do_count_diff_map_changes
9580 #undef do_count_diff_map_changes
9581 #endif
9582 #define do_count_diff_map_changes(diff_map, n_changes, n_filtered)	\
9583   {									\
9584     string_diff_ptr_map::const_iterator i;				\
9585     for (i = diff_map.begin();						\
9586 	 i != diff_map.end();						\
9587 	 ++i)								\
9588       { \
9589 	if (const var_diff* d = is_var_diff(i->second))		\
9590 	  if (is_data_member(d->first_var()))				\
9591 	    continue;							\
9592 									\
9593 	if (i->second->has_local_changes())				\
9594 	  ++n_changes;							\
9595 	if (!i->second->get_canonical_diff()->to_be_reported())		\
9596 	  ++n_filtered;						\
9597       }								\
9598   }
9599 
9600 /// Count the number of leaf changes as well as the number of the
9601 /// changes that have been filtered out.
9602 ///
9603 /// @param num_changes out parameter.  This is set to the total number
9604 /// of leaf changes.
9605 ///
9606 /// @param num_filtered out parameter.  This is set to the number of
9607 /// leaf changes that have been filtered out.
9608 void
count_leaf_changes(size_t & num_changes,size_t & num_filtered)9609 corpus_diff::priv::count_leaf_changes(size_t &num_changes, size_t &num_filtered)
9610 {
9611   count_leaf_type_changes(num_changes, num_filtered);
9612 
9613   // Now count the non-type changes.
9614   do_count_diff_map_changes(leaf_diffs_.get_function_decl_diff_map(),
9615     num_changes, num_filtered);
9616   do_count_diff_map_changes(leaf_diffs_.get_var_decl_diff_map(),
9617     num_changes, num_filtered);
9618 }
9619 
9620 /// Count the number of leaf *type* changes as well as the number of
9621 /// the leaf type changes that have been filtered out.
9622 ///
9623 /// @param num_changes out parameter.  This is set to the total number
9624 /// of leaf type changes.
9625 ///
9626 /// @param num_filtered out parameter.  This is set to the number of
9627 /// leaf type changes that have been filtered out.
9628 void
count_leaf_type_changes(size_t & num_changes,size_t & num_filtered)9629 corpus_diff::priv::count_leaf_type_changes(size_t &num_changes,
9630 					   size_t &num_filtered)
9631 {
9632   do_count_diff_map_changes(leaf_diffs_.get_type_decl_diff_map(),
9633     num_changes, num_filtered);
9634   do_count_diff_map_changes(leaf_diffs_.get_enum_diff_map(),
9635     num_changes, num_filtered);
9636   do_count_diff_map_changes(leaf_diffs_.get_class_diff_map(),
9637     num_changes, num_filtered);
9638   do_count_diff_map_changes(leaf_diffs_.get_union_diff_map(),
9639     num_changes, num_filtered);
9640   do_count_diff_map_changes(leaf_diffs_.get_typedef_diff_map(),
9641     num_changes, num_filtered);
9642   do_count_diff_map_changes(leaf_diffs_.get_array_diff_map(),
9643     num_changes, num_filtered);
9644   do_count_diff_map_changes(leaf_diffs_.get_distinct_diff_map(),
9645     num_changes, num_filtered);
9646   do_count_diff_map_changes(leaf_diffs_.get_fn_parm_diff_map(),
9647 			    num_changes, num_filtered);
9648 }
9649 
9650 /// Count the number of types not reachable from the interface (i.e,
9651 /// not reachable from global functions or variables).
9652 ///
9653 /// @param num_added this is set to the number of added types not
9654 /// reachable from the interface.
9655 ///
9656 /// @param num_deleted this is set to the number of deleted types not
9657 /// reachable from the interface.
9658 ///
9659 /// @param num_changed this is set to the number of changed types not
9660 /// reachable from the interface.
9661 ///
9662 /// @param num_filtered_added this is set to the number of added types
9663 /// not reachable from the interface and that have been filtered out
9664 /// by suppression specifications.
9665 ///
9666 /// @param num_filtered_deleted this is set to the number of deleted
9667 /// types not reachable from the interface and that have been filtered
9668 /// out by suppression specifications.
9669 ///
9670 /// @param num_filtered_changed this is set to the number of changed
9671 /// types not reachable from the interface and that have been filtered
9672 /// out by suppression specifications.
9673 void
count_unreachable_types(size_t & num_added,size_t & num_deleted,size_t & num_changed,size_t & num_filtered_added,size_t & num_filtered_deleted,size_t & num_filtered_changed)9674 corpus_diff::priv::count_unreachable_types(size_t &num_added,
9675 					   size_t &num_deleted,
9676 					   size_t &num_changed,
9677 					   size_t &num_filtered_added,
9678 					   size_t &num_filtered_deleted,
9679 					   size_t &num_filtered_changed)
9680 {
9681   num_added = added_unreachable_types_.size();
9682   num_deleted = deleted_unreachable_types_.size();
9683   num_changed = changed_unreachable_types_.size();
9684   num_filtered_added = suppressed_added_unreachable_types_.size();
9685   num_filtered_deleted = suppressed_deleted_unreachable_types_.size();
9686 
9687   for (vector<diff_sptr>::const_iterator i =
9688 	 changed_unreachable_types_sorted().begin();
9689        i != changed_unreachable_types_sorted().end();
9690        ++i)
9691     if (!(*i)->to_be_reported())
9692       ++num_filtered_changed;
9693 }
9694 
9695 /// Get the sorted vector of diff nodes representing changed
9696 /// unreachable types.
9697 ///
9698 /// Upon the first invocation of this method, if the vector is empty,
9699 /// this function gets the diff nodes representing changed
9700 /// unreachable, sort them, and return the sorted vector.
9701 ///
9702 /// @return the sorted vector of diff nodes representing changed
9703 /// unreachable types.
9704 const vector<diff_sptr>&
changed_unreachable_types_sorted() const9705 corpus_diff::priv::changed_unreachable_types_sorted() const
9706 {
9707 if (changed_unreachable_types_sorted_.empty())
9708   if (!changed_unreachable_types_.empty())
9709     sort_string_diff_sptr_map(changed_unreachable_types_,
9710 			      changed_unreachable_types_sorted_);
9711 
9712  return changed_unreachable_types_sorted_;
9713 }
9714 
9715 /// Compute the diff stats.
9716 ///
9717 /// To know the number of functions that got filtered out, this
9718 /// function applies the categorizing filters to the diff sub-trees of
9719 /// each function changes diff, prior to calculating the stats.
9720 ///
9721 /// @param num_removed the number of removed functions.
9722 ///
9723 /// @param num_added the number of added functions.
9724 ///
9725 /// @param num_changed the number of changed functions.
9726 ///
9727 /// @param num_filtered_out the number of changed functions that are
9728 /// got filtered out from the report
9729 void
apply_filters_and_compute_diff_stats(diff_stats & stat)9730 corpus_diff::priv::apply_filters_and_compute_diff_stats(diff_stats& stat)
9731 {
9732   stat.num_func_removed(deleted_fns_.size());
9733   stat.num_removed_func_filtered_out(suppressed_deleted_fns_.size());
9734   stat.num_func_added(added_fns_.size());
9735   stat.num_added_func_filtered_out(suppressed_added_fns_.size());
9736   stat.num_func_changed(changed_fns_map_.size());
9737 
9738   stat.num_vars_removed(deleted_vars_.size());
9739   stat.num_removed_vars_filtered_out(suppressed_deleted_vars_.size());
9740   stat.num_vars_added(added_vars_.size());
9741   stat.num_added_vars_filtered_out(suppressed_added_vars_.size());
9742   stat.num_vars_changed(changed_vars_map_.size());
9743 
9744   diff_context_sptr ctxt = get_context();
9745 
9746   // Walk the changed function diff nodes to apply the categorization
9747   // filters.
9748   diff_sptr diff;
9749   for (function_decl_diff_sptrs_type::const_iterator i =
9750 	 changed_fns_.begin();
9751        i != changed_fns_.end();
9752        ++i)
9753     {
9754       diff_sptr diff = *i;
9755       ctxt->maybe_apply_filters(diff);
9756     }
9757 
9758   // Walk the changed variable diff nodes to apply the categorization
9759   // filters.
9760   for (var_diff_sptrs_type::const_iterator i = sorted_changed_vars_.begin();
9761        i != sorted_changed_vars_.end();
9762        ++i)
9763     {
9764       diff_sptr diff = *i;
9765       ctxt->maybe_apply_filters(diff);
9766     }
9767 
9768   // walk the changed unreachable types to apply categorization
9769   // filters
9770   for (diff_sptrs_type::const_iterator i =
9771 	  changed_unreachable_types_sorted().begin();
9772 	i != changed_unreachable_types_sorted().end();
9773        ++i)
9774     {
9775       diff_sptr diff = *i;
9776       ctxt->maybe_apply_filters(diff);
9777     }
9778 
9779   categorize_redundant_changed_sub_nodes();
9780 
9781   // Walk the changed function diff nodes to count the number of
9782   // filtered-out functions and the number of functions with virtual
9783   // offset changes.
9784   for (function_decl_diff_sptrs_type::const_iterator i =
9785 	 changed_fns_.begin();
9786        i != changed_fns_.end();
9787        ++i)
9788     {
9789       if ((*i)->is_filtered_out())
9790 	{
9791 	  stat.num_changed_func_filtered_out
9792 	    (stat.num_changed_func_filtered_out() + 1);
9793 
9794 	  if ((*i)->has_local_changes())
9795 	    stat.num_leaf_func_changes_filtered_out
9796 	      (stat.num_leaf_func_changes_filtered_out() + 1);
9797 	}
9798       else
9799 	{
9800 	  if ((*i)->get_category() & VIRTUAL_MEMBER_CHANGE_CATEGORY)
9801 	    stat.num_func_with_virtual_offset_changes
9802 	      (stat.num_func_with_virtual_offset_changes() + 1);
9803 	}
9804 
9805       if ((*i)->has_local_changes())
9806 	stat.num_leaf_func_changes
9807 	  (stat.num_leaf_func_changes() + 1);
9808     }
9809 
9810   // Walk the changed variables diff nodes to count the number of
9811   // filtered-out variables.
9812   for (var_diff_sptrs_type ::const_iterator i = sorted_changed_vars_.begin();
9813        i != sorted_changed_vars_.end();
9814        ++i)
9815     {
9816       if ((*i)->is_filtered_out())
9817 	{
9818 	  stat.num_changed_vars_filtered_out
9819 	    (stat.num_changed_vars_filtered_out() + 1);
9820 
9821 	  if ((*i)->has_local_changes())
9822 	    stat.num_leaf_var_changes_filtered_out
9823 	      (stat.num_leaf_var_changes_filtered_out() + 1);
9824 	}
9825       if ((*i)->has_local_changes())
9826 	stat.num_leaf_var_changes
9827 	  (stat.num_leaf_var_changes() + 1);
9828     }
9829 
9830   stat.num_func_syms_added(added_unrefed_fn_syms_.size());
9831   stat.num_added_func_syms_filtered_out(suppressed_added_unrefed_fn_syms_.size());
9832   stat.num_func_syms_removed(deleted_unrefed_fn_syms_.size());
9833   stat.num_removed_func_syms_filtered_out(suppressed_deleted_unrefed_fn_syms_.size());
9834   stat.num_var_syms_added(added_unrefed_var_syms_.size());
9835   stat.num_added_var_syms_filtered_out(suppressed_added_unrefed_var_syms_.size());
9836   stat.num_var_syms_removed(deleted_unrefed_var_syms_.size());
9837   stat.num_removed_var_syms_filtered_out(suppressed_deleted_unrefed_var_syms_.size());
9838 
9839   // Walk the general leaf type diff nodes to count them
9840   {
9841     size_t num_type_changes = 0, num_type_filtered = 0;
9842     count_leaf_type_changes(num_type_changes, num_type_filtered);
9843 
9844     stat.num_leaf_type_changes(num_type_changes);
9845     stat.num_leaf_type_changes_filtered_out(num_type_filtered);
9846   }
9847 
9848   // Walk the general leaf artefacts diff nodes to count them
9849   {
9850     size_t num_changes = 0, num_filtered = 0;
9851     count_leaf_changes(num_changes, num_filtered);
9852 
9853     stat.num_leaf_changes(num_changes);
9854     stat.num_leaf_changes_filtered_out(num_filtered);
9855   }
9856 
9857   // Walk the unreachable types to count them
9858   {
9859     size_t num_added_unreachable_types = 0,
9860       num_changed_unreachable_types = 0,
9861       num_deleted_unreachable_types = 0,
9862       num_added_unreachable_types_filtered = 0,
9863       num_changed_unreachable_types_filtered = 0,
9864       num_deleted_unreachable_types_filtered = 0;
9865 
9866     count_unreachable_types(num_added_unreachable_types,
9867 			    num_deleted_unreachable_types,
9868 			    num_changed_unreachable_types,
9869 			    num_added_unreachable_types_filtered,
9870 			    num_deleted_unreachable_types_filtered,
9871 			    num_changed_unreachable_types_filtered);
9872 
9873     stat.num_added_unreachable_types(num_added_unreachable_types);
9874     stat.num_removed_unreachable_types(num_deleted_unreachable_types);
9875     stat.num_changed_unreachable_types(num_changed_unreachable_types);
9876     stat.num_added_unreachable_types_filtered_out
9877       (num_added_unreachable_types_filtered);
9878     stat.num_removed_unreachable_types_filtered_out
9879       (num_deleted_unreachable_types_filtered);
9880     stat.num_changed_unreachable_types_filtered_out
9881       (num_changed_unreachable_types_filtered);
9882   }
9883 }
9884 
9885 /// Emit the summary of the functions & variables that got
9886 /// removed/changed/added.
9887 ///
9888 /// TODO: This should be handled by the reporters, just like what is
9889 /// done for reporter_base::diff_to_be_reported.
9890 ///
9891 /// @param out the output stream to emit the stats to.
9892 ///
9893 /// @param indent the indentation string to use in the summary.
9894 void
emit_diff_stats(const diff_stats & s,ostream & out,const string & indent)9895 corpus_diff::priv::emit_diff_stats(const diff_stats&	s,
9896 				   ostream&		out,
9897 				   const string&	indent)
9898 {
9899   /// Report added/removed/changed functions.
9900   size_t net_num_leaf_changes =
9901     s.net_num_func_removed() +
9902     s.net_num_func_added() +
9903     s.net_num_leaf_func_changes() +
9904     s.net_num_vars_removed() +
9905     s.net_num_vars_added() +
9906     s.net_num_leaf_var_changes() +
9907     s.net_num_leaf_type_changes() +
9908     s.net_num_removed_func_syms() +
9909     s.net_num_added_func_syms() +
9910     s.net_num_removed_var_syms() +
9911     s.net_num_added_var_syms();
9912 
9913   if (!sonames_equal_)
9914     out << indent << "ELF SONAME changed\n";
9915 
9916   if (!architectures_equal_)
9917     out << indent << "ELF architecture changed\n";
9918 
9919   diff_context_sptr ctxt = get_context();
9920 
9921   if (ctxt->show_leaf_changes_only())
9922     {
9923       out << "Leaf changes summary: ";
9924       out << net_num_leaf_changes << " artifact";
9925       if (net_num_leaf_changes > 1)
9926 	out << "s";
9927       out << " changed";
9928 
9929       if (size_t num_filtered = s.num_leaf_changes_filtered_out())
9930 	out << " (" << num_filtered << " filtered out)";
9931       out << "\n";
9932 
9933       out << indent << "Changed leaf types summary: "
9934 	  << s.net_num_leaf_type_changes();
9935       if (s.num_leaf_type_changes_filtered_out())
9936 	out << " (" << s.num_leaf_type_changes_filtered_out()
9937 	    << " filtered out)";
9938       out << " leaf type";
9939       if (s.num_leaf_type_changes() > 1)
9940 	out << "s";
9941       out << " changed\n";
9942 
9943       // function changes summary
9944       out << indent << "Removed/Changed/Added functions summary: ";
9945       out << s.net_num_func_removed() << " Removed";
9946      if (s.num_removed_func_filtered_out())
9947 	out << " ("
9948 	    << s.num_removed_func_filtered_out()
9949 	    << " filtered out)";
9950       out << ", ";
9951 
9952       out << s.net_num_leaf_func_changes() << " Changed";
9953       if (s.num_leaf_func_changes_filtered_out())
9954 	    out << " ("
9955 		<< s.num_leaf_func_changes_filtered_out()
9956 		<< " filtered out)";
9957       out << ", ";
9958 
9959       out << s.net_num_func_added()<< " Added ";
9960       if (s.net_num_func_added() <= 1)
9961 	out << "function";
9962       else
9963 	out << "functions";
9964       if (s.num_added_func_filtered_out())
9965 	out << " (" << s.num_added_func_filtered_out() << " filtered out)";
9966       out << "\n";
9967 
9968       // variables changes summary
9969       out << indent << "Removed/Changed/Added variables summary: ";
9970       out << s.net_num_vars_removed() << " Removed";
9971       if (s.num_removed_vars_filtered_out())
9972 	out << " (" << s.num_removed_vars_filtered_out()
9973 	    << " filtered out)";
9974       out << ", ";
9975 
9976       out << s.net_num_leaf_var_changes() << " Changed";
9977       if (s.num_leaf_var_changes_filtered_out())
9978 	out << " ("
9979 	    << s.num_leaf_var_changes_filtered_out()
9980 	    << " filtered out)";
9981       out << ", ";
9982 
9983       out << s.net_num_vars_added() << " Added ";
9984       if (s.net_num_vars_added() <= 1)
9985 	out << "variable";
9986       else
9987 	out << "variables";
9988       if (s.num_added_vars_filtered_out())
9989 	out << " (" << s.num_added_vars_filtered_out()
9990 	    << " filtered out)";
9991       out << "\n";
9992     }
9993   else // if (ctxt->show_leaf_changes_only())
9994     {
9995       size_t total_nb_function_changes = s.num_func_removed()
9996 	+ s.num_func_changed() +  s.num_func_added();
9997 
9998       // function changes summary
9999       out << indent << "Functions changes summary: ";
10000       out << s.net_num_func_removed() << " Removed";
10001       if (s.num_removed_func_filtered_out())
10002 	out << " ("
10003 	    << s.num_removed_func_filtered_out()
10004 	    << " filtered out)";
10005       out << ", ";
10006 
10007       out << s.net_num_func_changed() << " Changed";
10008       if (s.num_changed_func_filtered_out())
10009 	out << " (" << s.num_changed_func_filtered_out() << " filtered out)";
10010       out << ", ";
10011 
10012       out << s.net_num_func_added() << " Added";
10013       if (s.num_added_func_filtered_out())
10014 	out << " (" << s.num_added_func_filtered_out() << " filtered out)";
10015       if (total_nb_function_changes <= 1)
10016 	out << " function";
10017       else
10018 	out << " functions";
10019       out << "\n";
10020 
10021       // variables changes summary
10022       size_t total_nb_variable_changes = s.num_vars_removed()
10023 	+ s.num_vars_changed() + s.num_vars_added();
10024 
10025       out << indent << "Variables changes summary: ";
10026       out << s.net_num_vars_removed() << " Removed";
10027       if (s.num_removed_vars_filtered_out())
10028 	out << " (" << s.num_removed_vars_filtered_out()
10029 	    << " filtered out)";
10030       out << ", ";
10031 
10032       out << s.num_vars_changed() - s.num_changed_vars_filtered_out() << " Changed";
10033       if (s.num_changed_vars_filtered_out())
10034 	out << " (" << s.num_changed_vars_filtered_out() << " filtered out)";
10035       out << ", ";
10036 
10037       out << s.net_num_vars_added() << " Added";
10038       if (s.num_added_vars_filtered_out())
10039 	out << " (" << s.num_added_vars_filtered_out()
10040 	    << " filtered out)";
10041       if (total_nb_variable_changes <= 1)
10042 	out << " variable";
10043       else
10044 	out << " variables";
10045       out << "\n";
10046     }
10047 
10048   // Show statistics about types not reachable from global
10049   // functions/variables.
10050   if (ctxt->show_unreachable_types())
10051     {
10052       size_t total_nb_unreachable_type_changes =
10053 	s.num_removed_unreachable_types()
10054 	+ s.num_changed_unreachable_types()
10055 	+ s.num_added_unreachable_types();
10056 
10057       // Show summary of unreachable types
10058       out << indent << "Unreachable types summary: "
10059 	  << s.net_num_removed_unreachable_types()
10060 	  << " removed";
10061       if (s.num_removed_unreachable_types_filtered_out())
10062 	out << " (" << s.num_removed_unreachable_types_filtered_out()
10063 	    << " filtered out)";
10064       out << ", ";
10065 
10066       out << s.net_num_changed_unreachable_types()
10067 	  << " changed";
10068       if (s.num_changed_unreachable_types_filtered_out())
10069 	out << " (" << s.num_changed_unreachable_types_filtered_out()
10070 	    << " filtered out)";
10071       out << ", ";
10072 
10073       out << s.net_num_added_unreachable_types()
10074 	  << " added";
10075       if (s.num_added_unreachable_types_filtered_out())
10076 	out << " (" << s.num_added_unreachable_types_filtered_out()
10077 	    << " filtered out)";
10078       if (total_nb_unreachable_type_changes <= 1)
10079 	out << " type";
10080       else
10081 	out << " types";
10082       out << "\n";
10083     }
10084 
10085   if (ctxt->show_symbols_unreferenced_by_debug_info()
10086       && (s.num_func_syms_removed()
10087 	  || s.num_func_syms_added()
10088 	  || s.num_var_syms_removed()
10089 	  || s.num_var_syms_added()))
10090     {
10091       // function symbols changes summary.
10092 
10093       if (!ctxt->show_added_symbols_unreferenced_by_debug_info()
10094 	  && s.num_func_syms_removed() == 0
10095 	  && s.num_func_syms_added() != 0)
10096 	// If the only unreferenced function symbol change is function
10097 	// syms that got added, but we were forbidden to show function
10098 	// syms being added, do nothing.
10099 	;
10100       else
10101 	{
10102 	  out << indent
10103 	      << "Function symbols changes summary: "
10104 	      << s.net_num_removed_func_syms() << " Removed";
10105 	  if (s.num_removed_func_syms_filtered_out())
10106 	    out << " (" << s.num_removed_func_syms_filtered_out()
10107 		<< " filtered out)";
10108 	  out << ", ";
10109 	  out << s.net_num_added_func_syms() << " Added";
10110 	  if (s.num_added_func_syms_filtered_out())
10111 	    out << " (" << s.num_added_func_syms_filtered_out()
10112 		<< " filtered out)";
10113 	  out << " function symbol";
10114 	  if (s.num_func_syms_added() + s.num_func_syms_removed() > 1)
10115 	    out << "s";
10116 	  out << " not referenced by debug info\n";
10117 	}
10118 
10119       // variable symbol changes summary.
10120 
10121       if (!ctxt->show_added_symbols_unreferenced_by_debug_info()
10122 	  && s.num_var_syms_removed() == 0
10123 	  && s.num_var_syms_added() != 0)
10124 	// If the only unreferenced variable symbol change is variable
10125 	// syms that got added, but we were forbidden to show variable
10126 	// syms being added, do nothing.
10127 	;
10128       else
10129 	{
10130 	  out << indent
10131 	      << "Variable symbols changes summary: "
10132 	      << s.net_num_removed_var_syms() << " Removed";
10133 	  if (s.num_removed_var_syms_filtered_out())
10134 	    out << " (" << s.num_removed_var_syms_filtered_out()
10135 		<< " filtered out)";
10136 	  out << ", ";
10137 	  out << s.net_num_added_var_syms() << " Added";
10138 	  if (s.num_added_var_syms_filtered_out())
10139 	    out << " (" << s.num_added_var_syms_filtered_out()
10140 		<< " filtered out)";
10141 	  out << " variable symbol";
10142 	  if (s.num_var_syms_added() + s.num_var_syms_removed() > 1)
10143 	    out << "s";
10144 	  out << " not referenced by debug info\n";
10145 	}
10146     }
10147 }
10148 
10149 /// Walk the changed functions and variables diff nodes to categorize
10150 /// redundant nodes.
10151 void
categorize_redundant_changed_sub_nodes()10152 corpus_diff::priv::categorize_redundant_changed_sub_nodes()
10153 {
10154   diff_sptr diff;
10155 
10156   diff_context_sptr ctxt = get_context();
10157 
10158   ctxt->forget_visited_diffs();
10159   for (function_decl_diff_sptrs_type::const_iterator i =
10160 	 changed_fns_.begin();
10161        i!= changed_fns_.end();
10162        ++i)
10163     {
10164       diff = *i;
10165       categorize_redundancy(diff);
10166     }
10167 
10168   for (var_diff_sptrs_type::const_iterator i = sorted_changed_vars_.begin();
10169        i!= sorted_changed_vars_.end();
10170        ++i)
10171     {
10172       diff_sptr diff = *i;
10173       categorize_redundancy(diff);
10174     }
10175 
10176   for (diff_sptrs_type::const_iterator i =
10177 	 changed_unreachable_types_sorted().begin();
10178        i!= changed_unreachable_types_sorted().end();
10179        ++i)
10180     {
10181       diff_sptr diff = *i;
10182       categorize_redundancy(diff);
10183     }
10184 }
10185 
10186 /// Walk the changed functions and variables diff nodes and clear the
10187 /// redundancy categorization they might carry.
10188 void
clear_redundancy_categorization()10189 corpus_diff::priv::clear_redundancy_categorization()
10190 {
10191   diff_sptr diff;
10192   for (function_decl_diff_sptrs_type::const_iterator i = changed_fns_.begin();
10193        i!= changed_fns_.end();
10194        ++i)
10195     {
10196       diff = *i;
10197       abigail::comparison::clear_redundancy_categorization(diff);
10198     }
10199 
10200   for (var_diff_sptrs_type::const_iterator i = sorted_changed_vars_.begin();
10201        i!= sorted_changed_vars_.end();
10202        ++i)
10203     {
10204       diff = *i;
10205       abigail::comparison::clear_redundancy_categorization(diff);
10206     }
10207 }
10208 
10209 /// If the user asked to dump the diff tree node (for changed
10210 /// variables and functions) on the error output stream, then just do
10211 /// that.
10212 ///
10213 /// This function is used for debugging purposes.
10214 void
maybe_dump_diff_tree()10215 corpus_diff::priv::maybe_dump_diff_tree()
10216 {
10217   diff_context_sptr ctxt = get_context();
10218 
10219   if (!ctxt->dump_diff_tree()
10220       || ctxt->error_output_stream() == 0)
10221     return;
10222 
10223   if (!changed_fns_.empty())
10224     {
10225       *ctxt->error_output_stream() << "changed functions diff tree: \n\n";
10226       for (function_decl_diff_sptrs_type::const_iterator i =
10227 	     changed_fns_.begin();
10228 	   i != changed_fns_.end();
10229 	   ++i)
10230 	{
10231 	  diff_sptr d = *i;
10232 	  print_diff_tree(d, *ctxt->error_output_stream());
10233 	}
10234     }
10235 
10236   if (!sorted_changed_vars_.empty())
10237     {
10238       *ctxt->error_output_stream() << "\nchanged variables diff tree: \n\n";
10239       for (var_diff_sptrs_type::const_iterator i =
10240 	     sorted_changed_vars_.begin();
10241 	   i != sorted_changed_vars_.end();
10242 	   ++i)
10243 	{
10244 	  diff_sptr d = *i;
10245 	  print_diff_tree(d, *ctxt->error_output_stream());
10246 	}
10247     }
10248 
10249   if (!changed_unreachable_types_sorted().empty())
10250     {
10251       *ctxt->error_output_stream() << "\nchanged unreachable "
10252 	"types diff tree: \n\n";
10253       for (vector<diff_sptr>::const_iterator i =
10254 	     changed_unreachable_types_sorted().begin();
10255 	   i != changed_unreachable_types_sorted().end();
10256 	   ++i)
10257 	{
10258 	  diff_sptr d = *i;
10259 	  print_diff_tree(d, *ctxt->error_output_stream());
10260 	}
10261     }
10262 }
10263 
10264 /// Populate the vector of children node of the @ref corpus_diff type.
10265 ///
10266 /// The children node can then later be retrieved using
10267 /// corpus_diff::children_node().
10268 void
chain_into_hierarchy()10269 corpus_diff::chain_into_hierarchy()
10270 {
10271   for (function_decl_diff_sptrs_type::const_iterator i =
10272 	 changed_functions_sorted().begin();
10273        i != changed_functions_sorted().end();
10274        ++i)
10275     if (diff_sptr d = *i)
10276       append_child_node(d);
10277 }
10278 
10279 /// Constructor for @ref corpus_diff.
10280 ///
10281 /// @param first the first corpus of the diff.
10282 ///
10283 /// @param second the second corpus of the diff.
10284 ///
10285 /// @param ctxt the diff context to use.  Note that this context
10286 /// object must stay alive at least during the life time of the
10287 /// current instance of @ref corpus_diff.  Otherwise memory corruption
10288 /// issues occur.
corpus_diff(corpus_sptr first,corpus_sptr second,diff_context_sptr ctxt)10289 corpus_diff::corpus_diff(corpus_sptr first,
10290 			 corpus_sptr second,
10291 			 diff_context_sptr ctxt)
10292   : priv_(new priv(first, second, ctxt))
10293 {}
10294 
10295 corpus_diff::~corpus_diff() = default;
10296 
10297 /// Finish building the current instance of @ref corpus_diff.
10298 void
finish_diff_type()10299 corpus_diff::finish_diff_type()
10300 {
10301   if (priv_->finished_)
10302     return;
10303   chain_into_hierarchy();
10304   priv_->finished_ = true;
10305 }
10306 
10307 /// @return the first corpus of the diff.
10308 corpus_sptr
first_corpus() const10309 corpus_diff::first_corpus() const
10310 {return priv_->first_;}
10311 
10312 /// @return the second corpus of the diff.
10313 corpus_sptr
second_corpus() const10314 corpus_diff::second_corpus() const
10315 {return priv_->second_;}
10316 
10317 /// @return the children nodes of the current instance of corpus_diff.
10318 const vector<diff*>&
children_nodes() const10319 corpus_diff::children_nodes() const
10320 {return priv_->children_;}
10321 
10322 /// Append a new child node to the vector of children nodes for the
10323 /// current instance of @ref corpus_diff node.
10324 ///
10325 /// Note that the vector of children nodes for the current instance of
10326 /// @ref corpus_diff node must remain sorted, using
10327 /// diff_less_than_functor.
10328 ///
10329 /// @param d the new child node.  Note that the life time of the
10330 /// object held by @p d will thus equal the life time of the current
10331 /// instance of @ref corpus_diff.
10332 void
append_child_node(diff_sptr d)10333 corpus_diff::append_child_node(diff_sptr d)
10334 {
10335   ABG_ASSERT(d);
10336 
10337   diff_less_than_functor is_less_than;
10338   bool inserted = false;
10339   for (vector<diff*>::iterator i = priv_->children_.begin();
10340        i != priv_->children_.end();
10341        ++i)
10342     // Look for the point where to insert the diff child node.
10343     if (!is_less_than(d.get(), *i))
10344       {
10345 	context()->keep_diff_alive(d);
10346 	priv_->children_.insert(i, d.get());
10347 	// As we have just inserted 'd' into the vector, the iterator
10348 	// 'i' is invalidated.  We must *NOT* use it anymore.
10349 	inserted = true;
10350 	break;
10351       }
10352 
10353   if (!inserted)
10354     {
10355       context()->keep_diff_alive(d);
10356       // We didn't insert anything to the vector, presumably b/c it was
10357       // empty or had one element that was "less than" 'd'.  We can thus
10358       // just append 'd' to the end of the vector.
10359       priv_->children_.push_back(d.get());
10360     }
10361 }
10362 
10363 /// @return the bare edit script of the functions changed as recorded
10364 /// by the diff.
10365 edit_script&
function_changes() const10366 corpus_diff::function_changes() const
10367 {return priv_->fns_edit_script_;}
10368 
10369 /// @return the bare edit script of the variables changed as recorded
10370 /// by the diff.
10371 edit_script&
variable_changes() const10372 corpus_diff::variable_changes() const
10373 {return priv_->vars_edit_script_;}
10374 
10375 /// Test if the soname of the underlying corpus has changed.
10376 ///
10377 /// @return true iff the soname has changed.
10378 bool
soname_changed() const10379 corpus_diff::soname_changed() const
10380 {return !priv_->sonames_equal_;}
10381 
10382 /// Test if the architecture of the underlying corpus has changed.
10383 ///
10384 /// @return true iff the architecture has changed.
10385 bool
architecture_changed() const10386 corpus_diff::architecture_changed() const
10387 {return !priv_->architectures_equal_;}
10388 
10389 /// Getter for the deleted functions of the diff.
10390 ///
10391 /// @return the the deleted functions of the diff.
10392 const string_function_ptr_map&
deleted_functions() const10393 corpus_diff::deleted_functions() const
10394 {return priv_->deleted_fns_;}
10395 
10396 /// Getter for the added functions of the diff.
10397 ///
10398 /// @return the added functions of the diff.
10399 const string_function_ptr_map&
added_functions()10400 corpus_diff::added_functions()
10401 {return priv_->added_fns_;}
10402 
10403 /// Getter for the functions which signature didn't change, but which
10404 /// do have some indirect changes in their parms.
10405 ///
10406 /// @return a non-sorted map of functions which signature didn't
10407 /// change, but which do have some indirect changes in their parms.
10408 /// The key of the map is a unique identifier for the function; it's
10409 /// usually made of the name and version of the underlying ELF symbol
10410 /// of the function for corpora that were built from ELF files.
10411 const string_function_decl_diff_sptr_map&
changed_functions()10412 corpus_diff::changed_functions()
10413 {return priv_->changed_fns_map_;}
10414 
10415 /// Getter for a sorted vector of functions which signature didn't
10416 /// change, but which do have some indirect changes in their parms.
10417 ///
10418 /// @return a sorted vector of functions which signature didn't
10419 /// change, but which do have some indirect changes in their parms.
10420 const function_decl_diff_sptrs_type&
changed_functions_sorted()10421 corpus_diff::changed_functions_sorted()
10422 {return priv_->changed_fns_;}
10423 
10424 /// Getter for the variables that got deleted from the first subject
10425 /// of the diff.
10426 ///
10427 /// @return the map of deleted variable.
10428 const string_var_ptr_map&
deleted_variables() const10429 corpus_diff::deleted_variables() const
10430 {return priv_->deleted_vars_;}
10431 
10432 /// Getter for the added variables of the diff.
10433 ///
10434 /// @return the map of added variable.
10435 const string_var_ptr_map&
added_variables() const10436 corpus_diff::added_variables() const
10437 {return priv_->added_vars_;}
10438 
10439 /// Getter for the non-sorted map of variables which signature didn't
10440 /// change but which do have some indirect changes in some sub-types.
10441 ///
10442 /// @return the non-sorted map of changed variables.
10443 const string_var_diff_sptr_map&
changed_variables()10444 corpus_diff::changed_variables()
10445 {return priv_->changed_vars_map_;}
10446 
10447 /// Getter for the sorted vector of variables which signature didn't
10448 /// change but which do have some indirect changes in some sub-types.
10449 ///
10450 /// @return a sorted vector of changed variables.
10451 const var_diff_sptrs_type&
changed_variables_sorted()10452 corpus_diff::changed_variables_sorted()
10453 {return priv_->sorted_changed_vars_;}
10454 
10455 /// Getter for function symbols not referenced by any debug info and
10456 /// that got deleted.
10457 ///
10458 /// @return a map of elf function symbols not referenced by any debug
10459 /// info and that got deleted.
10460 const string_elf_symbol_map&
deleted_unrefed_function_symbols() const10461 corpus_diff::deleted_unrefed_function_symbols() const
10462 {return priv_->deleted_unrefed_fn_syms_;}
10463 
10464 /// Getter for function symbols not referenced by any debug info and
10465 /// that got added.
10466 ///
10467 /// @return a map of elf function symbols not referenced by any debug
10468 /// info and that got added.
10469 const string_elf_symbol_map&
added_unrefed_function_symbols() const10470 corpus_diff::added_unrefed_function_symbols() const
10471 {return priv_->added_unrefed_fn_syms_;}
10472 
10473 /// Getter for variable symbols not referenced by any debug info and
10474 /// that got deleted.
10475 ///
10476 /// @return a map of elf variable symbols not referenced by any debug
10477 /// info and that got deleted.
10478 const string_elf_symbol_map&
deleted_unrefed_variable_symbols() const10479 corpus_diff::deleted_unrefed_variable_symbols() const
10480 {return priv_->deleted_unrefed_var_syms_;}
10481 
10482 /// Getter for variable symbols not referenced by any debug info and
10483 /// that got added.
10484 ///
10485 /// @return a map of elf variable symbols not referenced by any debug
10486 /// info and that got added.
10487 const string_elf_symbol_map&
added_unrefed_variable_symbols() const10488 corpus_diff::added_unrefed_variable_symbols() const
10489 {return priv_->added_unrefed_var_syms_;}
10490 
10491 /// Getter for a map of deleted types that are not reachable from
10492 /// global functions/variables.
10493 ///
10494 /// @return a map that associates pretty representation of deleted
10495 /// unreachable types and said types.
10496 const string_type_base_sptr_map&
deleted_unreachable_types() const10497 corpus_diff::deleted_unreachable_types() const
10498 {return priv_->deleted_unreachable_types_;}
10499 
10500 /// Getter of a sorted vector of deleted types that are not reachable
10501 /// from global functions/variables.
10502 ///
10503 /// @return a sorted vector of deleted types that are not reachable
10504 /// from global functions/variables.  The types are lexicographically
10505 /// sorted by considering their pretty representation.
10506 const vector<type_base_sptr>&
deleted_unreachable_types_sorted() const10507 corpus_diff::deleted_unreachable_types_sorted() const
10508 {
10509   if (priv_->deleted_unreachable_types_sorted_.empty())
10510     if (!priv_->deleted_unreachable_types_.empty())
10511       sort_string_type_base_sptr_map(priv_->deleted_unreachable_types_,
10512 				     priv_->deleted_unreachable_types_sorted_);
10513 
10514   return priv_->deleted_unreachable_types_sorted_;
10515 }
10516 
10517 /// Getter for a map of added types that are not reachable from global
10518 /// functions/variables.
10519 ///
10520 /// @return a map that associates pretty representation of added
10521 /// unreachable types and said types.
10522 const string_type_base_sptr_map&
added_unreachable_types() const10523 corpus_diff::added_unreachable_types() const
10524 {return priv_->added_unreachable_types_;}
10525 
10526 /// Getter of a sorted vector of added types that are not reachable
10527 /// from global functions/variables.
10528 ///
10529 /// @return a sorted vector of added types that are not reachable from
10530 /// global functions/variables.  The types are lexicographically
10531 /// sorted by considering their pretty representation.
10532 const vector<type_base_sptr>&
added_unreachable_types_sorted() const10533 corpus_diff::added_unreachable_types_sorted() const
10534 {
10535   if (priv_->added_unreachable_types_sorted_.empty())
10536     if (!priv_->added_unreachable_types_.empty())
10537       sort_string_type_base_sptr_map(priv_->added_unreachable_types_,
10538 				     priv_->added_unreachable_types_sorted_);
10539 
10540   return priv_->added_unreachable_types_sorted_;
10541 }
10542 
10543 /// Getter for a map of changed types that are not reachable from
10544 /// global functions/variables.
10545 ///
10546 /// @return a map that associates pretty representation of changed
10547 /// unreachable types and said types.
10548 const string_diff_sptr_map&
changed_unreachable_types() const10549 corpus_diff::changed_unreachable_types() const
10550 {return priv_->changed_unreachable_types_;}
10551 
10552 /// Getter of a sorted vector of changed types that are not reachable
10553 /// from global functions/variables.
10554 ///
10555 /// @return a sorted vector of changed types that are not reachable
10556 /// from global functions/variables.  The diffs are lexicographically
10557 /// sorted by considering their pretty representation.
10558 const vector<diff_sptr>&
changed_unreachable_types_sorted() const10559 corpus_diff::changed_unreachable_types_sorted() const
10560 {return priv_->changed_unreachable_types_sorted();}
10561 
10562 /// Getter of the diff context of this diff
10563 ///
10564 /// @return the diff context for this diff.
10565 const diff_context_sptr
context() const10566 corpus_diff::context() const
10567 {return priv_->get_context();}
10568 
10569 /// @return the pretty representation for the current instance of @ref
10570 /// corpus_diff
10571 const string&
get_pretty_representation() const10572 corpus_diff::get_pretty_representation() const
10573 {
10574   if (priv_->pretty_representation_.empty())
10575     {
10576       std::ostringstream o;
10577       o << "corpus_diff["
10578 	<< first_corpus()->get_path()
10579 	<< ", "
10580 	<< second_corpus()->get_path()
10581 	<< "]";
10582       priv_->pretty_representation_ = o.str();
10583     }
10584   return priv_->pretty_representation_;
10585 }
10586 /// Return true iff the current @ref corpus_diff node carries a
10587 /// change.
10588 ///
10589 /// @return true iff the current diff node carries a change.
10590 bool
has_changes() const10591 corpus_diff::has_changes() const
10592 {
10593   return (soname_changed()
10594 	  || architecture_changed()
10595 	  || !(priv_->deleted_fns_.empty()
10596 	       && priv_->added_fns_.empty()
10597 	       && priv_->changed_fns_map_.empty()
10598 	       && priv_->deleted_vars_.empty()
10599 	       && priv_->added_vars_.empty()
10600 	       && priv_->changed_vars_map_.empty()
10601 	       && priv_->added_unrefed_fn_syms_.empty()
10602 	       && priv_->deleted_unrefed_fn_syms_.empty()
10603 	       && priv_->added_unrefed_var_syms_.empty()
10604 	       && priv_->deleted_unrefed_var_syms_.empty()
10605 	       && priv_->deleted_unreachable_types_.empty()
10606 	       && priv_->added_unreachable_types_.empty()
10607 	       && priv_->changed_unreachable_types_.empty()));
10608 }
10609 
10610 /// Test if the current instance of @ref corpus_diff carries changes
10611 /// that we are sure are incompatible.  By incompatible change we mean
10612 /// a change that "breaks" the ABI of the corpus we are looking at.
10613 ///
10614 /// In concrete terms, this function considers the following changes
10615 /// as being ABI incompatible for sure:
10616 ///
10617 ///   - a soname change
10618 ///   - if exported functions or variables got removed
10619 ///
10620 /// Note that subtype changes *can* represent changes that break ABI
10621 /// too.  But they also can be changes that are OK, ABI-wise.
10622 ///
10623 /// It's up to the user to provide suppression specifications to say
10624 /// explicitely which subtype change is OK.  The remaining sub-type
10625 /// changes are then considered to be ABI incompatible.  But to test
10626 /// if such ABI incompatible subtype changes are present you need to
10627 /// use the function @ref corpus_diff::has_net_subtype_changes()
10628 ///
10629 /// @return true iff the current instance of @ref corpus_diff carries
10630 /// changes that we are sure are ABI incompatible.
10631 bool
has_incompatible_changes() const10632 corpus_diff::has_incompatible_changes() const
10633 {
10634   const diff_stats& stats = const_cast<corpus_diff*>(this)->
10635     apply_filters_and_suppressions_before_reporting();
10636 
10637   return (soname_changed() || architecture_changed()
10638 	  || stats.net_num_func_removed() != 0
10639 	  || (stats.num_func_with_virtual_offset_changes() != 0
10640 	      // If all reports about functions with sub-type changes
10641 	      // have been suppressed, then even those about functions
10642 	      // that are virtual don't matter anymore because the
10643 	      // user willingly requested to shut them down
10644 	      && stats.net_num_func_changed() != 0)
10645 	  || stats.net_num_vars_removed() != 0
10646 	  || stats.net_num_removed_func_syms() != 0
10647 	  || stats.net_num_removed_var_syms() != 0
10648 	  || stats.net_num_removed_unreachable_types() != 0
10649 	  || stats.net_num_changed_unreachable_types() != 0);
10650 }
10651 
10652 /// Test if the current instance of @ref corpus_diff carries subtype
10653 /// changes whose reports are not suppressed by any suppression
10654 /// specification.  In effect, these are deemed incompatible ABI
10655 /// changes.
10656 ///
10657 /// @return true iff the the current instance of @ref corpus_diff
10658 /// carries subtype changes that are deemed incompatible ABI changes.
10659 bool
has_net_subtype_changes() const10660 corpus_diff::has_net_subtype_changes() const
10661 {
10662   const diff_stats& stats = const_cast<corpus_diff*>(this)->
10663       apply_filters_and_suppressions_before_reporting();
10664 
10665   return (stats.net_num_func_changed() != 0
10666 	  || stats.net_num_vars_changed() != 0
10667 	  || stats.net_num_removed_unreachable_types() != 0
10668 	  || stats.net_num_changed_unreachable_types() != 0);
10669 }
10670 
10671 /// Test if the current instance of @ref corpus_diff carries changes
10672 /// whose reports are not suppressed by any suppression specification.
10673 /// In effect, these are deemed incompatible ABI changes.
10674 ///
10675 /// @return true iff the the current instance of @ref corpus_diff
10676 /// carries subtype changes that are deemed incompatible ABI changes.
10677 bool
has_net_changes() const10678 corpus_diff::has_net_changes() const
10679 {return  context()->get_reporter()->diff_has_net_changes(this);}
10680 
10681 /// Apply the different filters that are registered to be applied to
10682 /// the diff tree; that includes the categorization filters.  Also,
10683 /// apply the suppression interpretation filters.
10684 ///
10685 /// After the filters are applied, this function calculates some
10686 /// statistics about the changes carried by the current instance of
10687 /// @ref corpus_diff.  These statistics are represented by an instance
10688 /// of @ref corpus_diff::diff_stats.
10689 ///
10690 /// This member function is called by the reporting function
10691 /// corpus_diff::report().
10692 ///
10693 /// Note that for a given instance of corpus_diff, this function
10694 /// applies the filters and suppressions only the first time it is
10695 /// invoked.  Subsequent invocations just return the instance of
10696 /// corpus_diff::diff_stats that was cached after the first
10697 /// invocation.
10698 ///
10699 /// @return a reference to the statistics about the changes carried by
10700 /// the current instance of @ref corpus_diff.
10701 const corpus_diff::diff_stats&
apply_filters_and_suppressions_before_reporting()10702 corpus_diff::apply_filters_and_suppressions_before_reporting()
10703 {
10704   if (priv_->diff_stats_)
10705     return *priv_->diff_stats_;
10706 
10707   apply_suppressions(this);
10708   priv_->diff_stats_.reset(new diff_stats(context()));
10709   mark_leaf_diff_nodes();
10710   priv_->apply_filters_and_compute_diff_stats(*priv_->diff_stats_);
10711   return *priv_->diff_stats_;
10712 }
10713 
10714 /// A visitor that marks leaf diff nodes by storing them in the
10715 /// instance of @ref diff_maps returned by
10716 /// corpus_diff::get_leaf_diffs() invoked on the current instance of
10717 /// corpus_diff.
10718 struct leaf_diff_node_marker_visitor : public diff_node_visitor
10719 {
10720   /// This is called when the visitor visits a diff node.
10721   ///
10722   /// It basically tests if the diff node being visited is a leaf diff
10723   /// node - that is, it contains local changes.  If it does, then the
10724   /// node is added to the set of maps that hold leaf diffs in the
10725   /// current corpus_diff.
10726   ///
10727   /// Note that only leaf nodes that are reachable from public
10728   /// interfaces (global functions or variables) are collected by this
10729   /// visitor.
10730   ///
10731   /// @param d the diff node being visited.
10732   virtual void
visit_beginabigail::comparison::leaf_diff_node_marker_visitor10733   visit_begin(diff *d)
10734   {
10735     if (d->has_local_changes()
10736 	// A leaf basic (or class/union) type name change makes no
10737 	// sense when showing just leaf changes.  It only makes sense
10738 	// when it can explain the details about a non-leaf change.
10739 	// In other words, it doesn't make sense to say that an "int"
10740 	// became "unsigned int".  But it does make sense to say that
10741 	// a typedef changed because its underlying type was 'int' and
10742 	// is now an "unsigned int".
10743 	&& !filtering::has_basic_or_class_type_name_change(d)
10744 	// Similarly, a *local* change describing a type that changed
10745 	// its nature doesn't make sense.
10746 	&& !is_distinct_diff(d)
10747 	// Similarly, a pointer (or reference or array), a typedef or
10748 	// qualified type change in itself doesn't make sense.  It
10749 	// would rather make sense to show that pointer change as part
10750 	// of the variable change whose pointer type changed, for
10751 	// instance.
10752 	&& !is_pointer_diff(d)
10753 	&& !is_reference_diff(d)
10754 	&& !is_qualified_type_diff(d)
10755 	&& !is_typedef_diff(d)
10756 	&& !is_array_diff(d)
10757 	// Similarly a parameter change in itself doesn't make sense.
10758 	// It should have already been reported as part of the change
10759 	// of the function it belongs to.
10760 	&& !is_fn_parm_diff(d)
10761 	// An anonymous class or union diff doesn't make sense on its
10762 	// own.  It must have been described already by the diff of
10763 	// the enclosing struct or union if 'd' is from an anonymous
10764 	// data member, or from a typedef change if 'd' is from a
10765 	// typedef change which underlying type is an anonymous
10766 	// struct/union.
10767 	&& !is_anonymous_class_or_union_diff(d)
10768 	// Don't show decl-only-ness changes either.
10769 	&& !filtering::has_decl_only_def_change(d)
10770 	// Sometime, we can encounter artifacts of bogus DWARF that
10771 	// yield a diff node for a decl-only class (and empty class
10772 	// with the is_declaration flag set) that carries a non-zero
10773 	// size!  And of course at some point that non-zero size
10774 	// changes.  We need to be able to detect that.
10775 	&& !filtering::is_decl_only_class_with_size_change(d))
10776       {
10777 	diff_context_sptr ctxt = d->context();
10778 	const corpus_diff *corpus_diff_node = ctxt->get_corpus_diff().get();
10779 	ABG_ASSERT(corpus_diff_node);
10780 
10781 	if (diff *iface_diff = get_current_topmost_iface_diff())
10782 	  {
10783 	    type_or_decl_base_sptr iface = iface_diff->first_subject();
10784 	    // So, this diff node that is reachable from a global
10785 	    // function or variable carries a leaf change.  Let's add
10786 	    // it to the set of of leaf diffs of corpus_diff_node.
10787 	    const_cast<corpus_diff*>(corpus_diff_node)->
10788 	      get_leaf_diffs().insert_diff_node(d, iface);
10789 	  }
10790       }
10791   }
10792 }; // end struct leaf_diff_node_marker_visitor
10793 
10794 /// Walks the diff nodes associated to the current corpus diff and
10795 /// mark those that carry local changes.  They are said to be leaf
10796 /// diff nodes.
10797 ///
10798 /// The marked nodes are available from the
10799 /// corpus_diff::get_leaf_diffs() function.
10800 void
mark_leaf_diff_nodes()10801 corpus_diff::mark_leaf_diff_nodes()
10802 {
10803   if (!has_changes())
10804     return;
10805 
10806   if (!context()->show_leaf_changes_only())
10807     return;
10808 
10809   leaf_diff_node_marker_visitor v;
10810   context()->forget_visited_diffs();
10811   bool s = context()->visiting_a_node_twice_is_forbidden();
10812   context()->forbid_visiting_a_node_twice(true);
10813   context()->forbid_visiting_a_node_twice_per_interface(true);
10814   traverse(v);
10815   context()->forbid_visiting_a_node_twice(s);
10816   context()->forbid_visiting_a_node_twice_per_interface(false);
10817 }
10818 
10819 /// Get the set of maps that contain leaf nodes.  A leaf node being a
10820 /// node with a local change.
10821 ///
10822 /// @return the set of maps that contain leaf nodes.  A leaf node
10823 /// being a node with a local change.
10824 diff_maps&
get_leaf_diffs()10825 corpus_diff::get_leaf_diffs()
10826 {return priv_->leaf_diffs_;}
10827 
10828 /// Get the set of maps that contain leaf nodes.  A leaf node being a
10829 /// node with a local change.
10830 ///
10831 /// @return the set of maps that contain leaf nodes.  A leaf node
10832 /// being a node with a local change.
10833 const diff_maps&
get_leaf_diffs() const10834 corpus_diff::get_leaf_diffs() const
10835 {return priv_->leaf_diffs_;}
10836 
10837 /// Report the diff in a serialized form.
10838 ///
10839 /// @param out the stream to serialize the diff to.
10840 ///
10841 /// @param indent the prefix to use for the indentation of this
10842 /// serialization.
10843 void
report(ostream & out,const string & indent) const10844 corpus_diff::report(ostream& out, const string& indent) const
10845 {
10846   context()->get_reporter()->report(*this, out, indent);
10847 }
10848 
10849 /// Traverse the diff sub-tree under the current instance corpus_diff.
10850 ///
10851 /// @param v the visitor to invoke on each diff node of the sub-tree.
10852 ///
10853 /// @return true if the traversing has to keep going on, false otherwise.
10854 bool
traverse(diff_node_visitor & v)10855 corpus_diff::traverse(diff_node_visitor& v)
10856 {
10857   finish_diff_type();
10858 
10859   v.visit_begin(this);
10860 
10861   if (!v.visit(this, true))
10862     {
10863       v.visit_end(this);
10864       return false;
10865     }
10866 
10867   for (function_decl_diff_sptrs_type::const_iterator i =
10868 	 changed_functions_sorted().begin();
10869        i != changed_functions_sorted().end();
10870        ++i)
10871     {
10872       if (diff_sptr d = *i)
10873 	{
10874 	  const diff_context_sptr &ctxt = context();
10875 	  if (ctxt->visiting_a_node_twice_is_forbidden_per_interface())
10876 	    ctxt->forget_visited_diffs();
10877 
10878 	  v.set_current_topmost_iface_diff(d.get());
10879 
10880 	  if (!d->traverse(v))
10881 	    {
10882 	      v.visit_end(this);
10883 	      v.set_current_topmost_iface_diff(0);
10884 	      return false;
10885 	    }
10886 	}
10887     }
10888 
10889   for (var_diff_sptrs_type::const_iterator i =
10890 	 changed_variables_sorted().begin();
10891        i != changed_variables_sorted().end();
10892        ++i)
10893     {
10894       if (diff_sptr d = *i)
10895 	{
10896 	  const diff_context_sptr &ctxt = context();
10897 	  if (ctxt->visiting_a_node_twice_is_forbidden_per_interface())
10898 	    ctxt->forget_visited_diffs();
10899 
10900 	  v.set_current_topmost_iface_diff(d.get());
10901 
10902 	  if (!d->traverse(v))
10903 	    {
10904 	      v.visit_end(this);
10905 	      v.set_current_topmost_iface_diff(0);
10906 	      return false;
10907 	    }
10908 	}
10909     }
10910 
10911   v.set_current_topmost_iface_diff(0);
10912 
10913   // Traverse the changed unreachable type diffs.  These diffs are on
10914   // types that are not reachable from global functions or variables.
10915   for (vector<diff_sptr>::const_iterator i =
10916 	 changed_unreachable_types_sorted().begin();
10917        i != changed_unreachable_types_sorted().end();
10918        ++i)
10919     {
10920       if (diff_sptr d = *i)
10921 	{
10922 	  const diff_context_sptr &ctxt = context();
10923 	  if (ctxt->visiting_a_node_twice_is_forbidden_per_interface())
10924 	    ctxt->forget_visited_diffs();
10925 
10926 	  if (!d->traverse(v))
10927 	    {
10928 	      v.visit_end(this);
10929 	      return false;
10930 	    }
10931 	}
10932     }
10933 
10934   v.visit_end(this);
10935   return true;
10936 }
10937 
10938 /// Compute the diff between two instances of @ref corpus.
10939 ///
10940 /// Note that the two corpora must have been created in the same @ref
10941 /// environment, otherwise, this function aborts.
10942 ///
10943 /// @param f the first @ref corpus to consider for the diff.
10944 ///
10945 /// @param s the second @ref corpus to consider for the diff.
10946 ///
10947 /// @param ctxt the diff context to use.
10948 ///
10949 /// @return the resulting diff between the two @ref corpus.
10950 corpus_diff_sptr
compute_diff(const corpus_sptr f,const corpus_sptr s,diff_context_sptr ctxt)10951 compute_diff(const corpus_sptr	f,
10952 	     const corpus_sptr	s,
10953 	     diff_context_sptr	ctxt)
10954 {
10955   typedef corpus::functions::const_iterator fns_it_type;
10956   typedef corpus::variables::const_iterator vars_it_type;
10957   typedef elf_symbols::const_iterator symbols_it_type;
10958   typedef diff_utils::deep_ptr_eq_functor eq_type;
10959   typedef vector<type_base_wptr>::const_iterator type_base_wptr_it_type;
10960 
10961   ABG_ASSERT(f && s);
10962 
10963   if (!ctxt)
10964     ctxt.reset(new diff_context);
10965 
10966   corpus_diff_sptr r(new corpus_diff(f, s, ctxt));
10967 
10968   ctxt->set_corpus_diff(r);
10969 
10970   if(ctxt->show_soname_change())
10971     r->priv_->sonames_equal_ = f->get_soname() == s->get_soname();
10972   else
10973     r->priv_->sonames_equal_ = true;
10974 
10975   r->priv_->architectures_equal_ =
10976     f->get_architecture_name() == s->get_architecture_name();
10977 
10978   // Compute the diff of publicly defined and exported functions
10979   diff_utils::compute_diff<fns_it_type, eq_type>(f->get_functions().begin(),
10980 						 f->get_functions().end(),
10981 						 s->get_functions().begin(),
10982 						 s->get_functions().end(),
10983 						 r->priv_->fns_edit_script_);
10984 
10985   // Compute the diff of publicly defined and exported variables.
10986   diff_utils::compute_diff<vars_it_type, eq_type>
10987     (f->get_variables().begin(), f->get_variables().end(),
10988      s->get_variables().begin(), s->get_variables().end(),
10989      r->priv_->vars_edit_script_);
10990 
10991   // Compute the diff of function elf symbols not referenced by debug
10992   // info.
10993   diff_utils::compute_diff<symbols_it_type, eq_type>
10994     (f->get_unreferenced_function_symbols().begin(),
10995      f->get_unreferenced_function_symbols().end(),
10996      s->get_unreferenced_function_symbols().begin(),
10997      s->get_unreferenced_function_symbols().end(),
10998      r->priv_->unrefed_fn_syms_edit_script_);
10999 
11000   // Compute the diff of variable elf symbols not referenced by debug
11001   // info.
11002     diff_utils::compute_diff<symbols_it_type, eq_type>
11003     (f->get_unreferenced_variable_symbols().begin(),
11004      f->get_unreferenced_variable_symbols().end(),
11005      s->get_unreferenced_variable_symbols().begin(),
11006      s->get_unreferenced_variable_symbols().end(),
11007      r->priv_->unrefed_var_syms_edit_script_);
11008 
11009     if (ctxt->show_unreachable_types())
11010       // Compute the diff of types not reachable from public functions
11011       // or global variables that are exported.
11012       diff_utils::compute_diff<type_base_wptr_it_type, eq_type>
11013 	(f->get_types_not_reachable_from_public_interfaces().begin(),
11014 	 f->get_types_not_reachable_from_public_interfaces().end(),
11015 	 s->get_types_not_reachable_from_public_interfaces().begin(),
11016 	 s->get_types_not_reachable_from_public_interfaces().end(),
11017 	 r->priv_->unreachable_types_edit_script_);
11018 
11019   r->priv_->ensure_lookup_tables_populated();
11020 
11021   return r;
11022 }
11023 
11024 // </corpus stuff>
11025 
11026 /// Compute the diff between two instances of @ref corpus_group.
11027 ///
11028 /// Note that the two corpus_diff must have been created in the same
11029 /// @ref environment, otherwise, this function aborts.
11030 ///
11031 /// @param f the first @ref corpus_group to consider for the diff.
11032 ///
11033 /// @param s the second @ref corpus_group to consider for the diff.
11034 ///
11035 /// @param ctxt the diff context to use.
11036 ///
11037 /// @return the resulting diff between the two @ref corpus_group.
11038 corpus_diff_sptr
compute_diff(const corpus_group_sptr & f,const corpus_group_sptr & s,diff_context_sptr ctxt)11039 compute_diff(const corpus_group_sptr&	f,
11040 	     const corpus_group_sptr&	s,
11041 	     diff_context_sptr	ctxt)
11042 {
11043 
11044   corpus_sptr c1 = f;
11045   corpus_sptr c2 = s;
11046 
11047   return compute_diff(c1, c2, ctxt);
11048 }
11049 
11050 // <corpus_group stuff>
11051 
11052 // </corpus_group stuff>
11053 // <diff_node_visitor stuff>
11054 
11055 /// The private data of the @diff_node_visitor type.
11056 struct diff_node_visitor::priv
11057 {
11058   diff*	topmost_interface_diff;
11059   visiting_kind kind;
11060 
privabigail::comparison::diff_node_visitor::priv11061   priv()
11062     : topmost_interface_diff(),
11063       kind()
11064   {}
11065 
privabigail::comparison::diff_node_visitor::priv11066   priv(visiting_kind k)
11067     : topmost_interface_diff(),
11068       kind(k)
11069   {}
11070 }; // end struct diff_node_visitor
11071 
11072 /// Default constructor of the @ref diff_node_visitor type.
diff_node_visitor()11073 diff_node_visitor::diff_node_visitor()
11074   : priv_(new priv)
11075 {}
11076 
11077 diff_node_visitor::~diff_node_visitor() = default;
11078 
11079 /// Constructor of the @ref diff_node_visitor type.
11080 ///
11081 /// @param k how the visiting has to be performed.
diff_node_visitor(visiting_kind k)11082 diff_node_visitor::diff_node_visitor(visiting_kind k)
11083   : priv_(new priv(k))
11084 {}
11085 
11086 /// Getter for the visiting policy of the traversing code while
11087 /// invoking this visitor.
11088 ///
11089 /// @return the visiting policy used by the traversing code when
11090 /// invoking this visitor.
11091 visiting_kind
get_visiting_kind() const11092 diff_node_visitor::get_visiting_kind() const
11093 {return priv_->kind;}
11094 
11095 /// Setter for the visiting policy of the traversing code while
11096 /// invoking this visitor.
11097 ///
11098 /// @param v a bit map representing the new visiting policy used by
11099 /// the traversing code when invoking this visitor.
11100 void
set_visiting_kind(visiting_kind v)11101 diff_node_visitor::set_visiting_kind(visiting_kind v)
11102 {priv_->kind = v;}
11103 
11104 /// Setter for the visiting policy of the traversing code while
11105 /// invoking this visitor.  This one makes a logical or between the
11106 /// current policy and the bitmap given in argument and assigns the
11107 /// current policy to the result.
11108 ///
11109 /// @param v a bitmap representing the visiting policy to or with
11110 /// the current policy.
11111 void
or_visiting_kind(visiting_kind v)11112 diff_node_visitor::or_visiting_kind(visiting_kind v)
11113 {priv_->kind = priv_->kind | v;}
11114 
11115 /// Setter of the diff current topmost interface which is impacted by
11116 /// the current diff node being visited.
11117 ///
11118 /// @param d the current topmost interface diff impacted.
11119 void
set_current_topmost_iface_diff(diff * d)11120 diff_node_visitor::set_current_topmost_iface_diff(diff* d)
11121 {priv_->topmost_interface_diff = d;}
11122 
11123 /// Getter of the diff current topmost interface which is impacted by
11124 /// the current diff node being visited.
11125 ///
11126 /// @return the current topmost interface diff impacted.
11127 diff*
get_current_topmost_iface_diff() const11128 diff_node_visitor::get_current_topmost_iface_diff() const
11129 {return priv_->topmost_interface_diff;}
11130 
11131 /// This is called by the traversing code on a @ref diff node just
11132 /// before visiting it.  That is, before visiting it and its children
11133 /// node.
11134 ///
11135 /// @param d the diff node to visit.
11136 void
visit_begin(diff *)11137 diff_node_visitor::visit_begin(diff* /*p*/)
11138 {}
11139 
11140 /// This is called by the traversing code on a @ref diff node just
11141 /// after visiting it.  That is after visiting it and its children
11142 /// nodes.
11143 ///
11144 /// @param d the diff node that got visited.
11145 void
visit_end(diff *)11146 diff_node_visitor::visit_end(diff* /*p*/)
11147 {}
11148 
11149 /// This is called by the traversing code on a @ref corpus_diff node
11150 /// just before visiting it.  That is, before visiting it and its
11151 /// children node.
11152 ///
11153 /// @param p the corpus_diff node to visit.
11154 ///
11155 void
visit_begin(corpus_diff *)11156 diff_node_visitor::visit_begin(corpus_diff* /*p*/)
11157 {}
11158 
11159 /// This is called by the traversing code on a @ref corpus_diff node
11160 /// just after visiting it.  That is after visiting it and its children
11161 /// nodes.
11162 ///
11163 /// @param d the diff node that got visited.
11164 void
visit_end(corpus_diff *)11165 diff_node_visitor::visit_end(corpus_diff* /*d*/)
11166 {}
11167 
11168 /// Default visitor implementation
11169 ///
11170 /// @return true
11171 bool
visit(diff *,bool)11172 diff_node_visitor::visit(diff*, bool)
11173 {return true;}
11174 
11175 /// Default visitor implementation.
11176 ///
11177 /// @return true
11178 bool
visit(distinct_diff * dif,bool pre)11179 diff_node_visitor::visit(distinct_diff* dif, bool pre)
11180 {
11181   diff* d = dif;
11182   visit(d, pre);
11183 
11184   return true;
11185 }
11186 
11187 /// Default visitor implementation.
11188 ///
11189 /// @return true
11190 bool
visit(var_diff * dif,bool pre)11191 diff_node_visitor::visit(var_diff* dif, bool pre)
11192 {
11193   diff* d = dif;
11194   visit(d, pre);
11195 
11196   return true;
11197 }
11198 
11199 /// Default visitor implementation.
11200 ///
11201 /// @return true
11202 bool
visit(pointer_diff * dif,bool pre)11203 diff_node_visitor::visit(pointer_diff* dif, bool pre)
11204 {
11205   diff* d = dif;
11206   visit(d, pre);
11207 
11208   return true;
11209 }
11210 
11211 /// Default visitor implementation.
11212 ///
11213 /// @return true
11214 bool
visit(reference_diff * dif,bool pre)11215 diff_node_visitor::visit(reference_diff* dif, bool pre)
11216 {
11217   diff* d = dif;
11218   visit(d, pre);
11219 
11220   return true;
11221 }
11222 
11223 /// Default visitor implementation.
11224 ///
11225 /// @return true
11226 bool
visit(qualified_type_diff * dif,bool pre)11227 diff_node_visitor::visit(qualified_type_diff* dif, bool pre)
11228 {
11229   diff* d = dif;
11230   visit(d, pre);
11231 
11232   return true;
11233 }
11234 
11235 /// Default visitor implementation.
11236 ///
11237 /// @return true
11238 bool
visit(enum_diff * dif,bool pre)11239 diff_node_visitor::visit(enum_diff* dif, bool pre)
11240 {
11241   diff* d = dif;
11242   visit(d, pre);
11243 
11244   return true;
11245 }
11246 
11247 /// Default visitor implementation.
11248 ///
11249 /// @return true
11250 bool
visit(class_diff * dif,bool pre)11251 diff_node_visitor::visit(class_diff* dif, bool pre)
11252 {
11253   diff* d = dif;
11254   visit(d, pre);
11255 
11256   return true;
11257 }
11258 
11259 /// Default visitor implementation.
11260 ///
11261 /// @return true
11262 bool
visit(base_diff * dif,bool pre)11263 diff_node_visitor::visit(base_diff* dif, bool pre)
11264 {
11265   diff* d = dif;
11266   visit(d, pre);
11267 
11268   return true;
11269 }
11270 
11271 /// Default visitor implementation.
11272 ///
11273 /// @return true
11274 bool
visit(scope_diff * dif,bool pre)11275 diff_node_visitor::visit(scope_diff* dif, bool pre)
11276 {
11277   diff* d = dif;
11278   visit(d, pre);
11279 
11280   return true;
11281 }
11282 
11283 /// Default visitor implementation.
11284 ///
11285 /// @return true
11286 bool
visit(function_decl_diff * dif,bool pre)11287 diff_node_visitor::visit(function_decl_diff* dif, bool pre)
11288 {
11289   diff* d = dif;
11290   visit(d, pre);
11291 
11292   return true;
11293 }
11294 
11295 /// Default visitor implementation.
11296 ///
11297 /// @return true
11298 bool
visit(type_decl_diff * dif,bool pre)11299 diff_node_visitor::visit(type_decl_diff* dif, bool pre)
11300 {
11301   diff* d = dif;
11302   visit(d, pre);
11303 
11304   return true;
11305 }
11306 
11307 /// Default visitor implementation.
11308 ///
11309 /// @return true
11310 bool
visit(typedef_diff * dif,bool pre)11311 diff_node_visitor::visit(typedef_diff* dif, bool pre)
11312 {
11313   diff* d = dif;
11314   visit(d, pre);
11315 
11316   return true;
11317 }
11318 
11319 /// Default visitor implementation.
11320 ///
11321 /// @return true
11322 bool
visit(translation_unit_diff * dif,bool pre)11323 diff_node_visitor::visit(translation_unit_diff* dif, bool pre)
11324 {
11325   diff* d = dif;
11326   visit(d, pre);
11327 
11328   return true;
11329 }
11330 
11331 /// Default visitor implementation.
11332 ///
11333 /// @return true
11334 bool
visit(corpus_diff *,bool)11335 diff_node_visitor::visit(corpus_diff*, bool)
11336 {return true;}
11337 
11338 // </diff_node_visitor stuff>
11339 
11340 // <redundant diff node marking>
11341 
11342 // </redundant diff node marking>
11343 
11344 // <diff tree category propagation>
11345 
11346 /// A visitor to propagate the category of a node up to its parent
11347 /// nodes.  This visitor doesn't touch the REDUNDANT_CATEGORY or the
11348 /// SUPPRESSED_CATEGORY because those are propagated using other
11349 /// specific visitors.
11350 struct category_propagation_visitor : public diff_node_visitor
11351 {
11352   virtual void
visit_endabigail::comparison::category_propagation_visitor11353   visit_end(diff* d)
11354   {
11355     // Has this diff node 'd' been already visited ?
11356     bool already_visited = d->context()->diff_has_been_visited(d);
11357 
11358     // The canonical diff node of the class of equivalence of the diff
11359     // node 'd'.
11360     diff* canonical = d->get_canonical_diff();
11361 
11362     // If this class of equivalence of diff node is being visited for
11363     // the first time, then update its canonical node's category too.
11364     bool update_canonical = !already_visited && canonical;
11365 
11366     for (vector<diff*>::const_iterator i = d->children_nodes().begin();
11367 	 i != d->children_nodes().end();
11368 	 ++i)
11369       {
11370 	// If we are visiting the class of equivalence of 'd' for the
11371 	// first time, then let's look at the children of 'd' and
11372 	// propagate their categories to 'd'.
11373 	//
11374 	// If the class of equivalence of 'd' has already been
11375 	// visited, then let's look at the canonical diff nodes of the
11376 	// children of 'd' and propagate their categories to 'd'.
11377 	diff* diff = already_visited
11378 	  ? (*i)->get_canonical_diff()
11379 	  : *i;
11380 
11381 	ABG_ASSERT(diff);
11382 
11383 	diff_category c = diff->get_category();
11384 	// Do not propagate redundant and suppressed categories. Those
11385 	// are propagated in a specific pass elsewhere.
11386 	c &= ~(REDUNDANT_CATEGORY
11387 	       | SUPPRESSED_CATEGORY
11388 	       | PRIVATE_TYPE_CATEGORY);
11389 	// Also, if a (class) type has got a harmful name change, do not
11390 	// propagate harmless name changes coming from its sub-types
11391 	// (i.e, data members) to the class itself.
11392 	if (filtering::has_harmful_name_change(d))
11393 	  c &= ~HARMLESS_DECL_NAME_CHANGE_CATEGORY;
11394 
11395 	d->add_to_category(c);
11396 	if (!already_visited && canonical)
11397 	  if (update_canonical)
11398 	    canonical->add_to_category(c);
11399       }
11400   }
11401 };// end struct category_propagation_visitor
11402 
11403 /// Visit all the nodes of a given sub-tree.  For each node that has a
11404 /// particular category set, propagate that category set up to its
11405 /// parent nodes.
11406 ///
11407 /// @param diff_tree the diff sub-tree to walk for categorization
11408 /// purpose;
11409 void
propagate_categories(diff * diff_tree)11410 propagate_categories(diff* diff_tree)
11411 {
11412   category_propagation_visitor v;
11413   bool s = diff_tree->context()->visiting_a_node_twice_is_forbidden();
11414   diff_tree->context()->forbid_visiting_a_node_twice(true);
11415   diff_tree->context()->forget_visited_diffs();
11416   diff_tree->traverse(v);
11417   diff_tree->context()->forbid_visiting_a_node_twice(s);
11418 }
11419 
11420 /// Visit all the nodes of a given sub-tree.  For each node that has a
11421 /// particular category set, propagate that category set up to its
11422 /// parent nodes.
11423 ///
11424 /// @param diff_tree the diff sub-tree to walk for categorization
11425 /// purpose;
11426 void
propagate_categories(diff_sptr diff_tree)11427 propagate_categories(diff_sptr diff_tree)
11428 {propagate_categories(diff_tree.get());}
11429 
11430 /// Visit all the nodes of a given corpus tree.  For each node that
11431 /// has a particular category set, propagate that category set up to
11432 /// its parent nodes.
11433 ///
11434 /// @param diff_tree the corpus_diff tree to walk for categorization
11435 /// purpose;
11436 void
propagate_categories(corpus_diff * diff_tree)11437 propagate_categories(corpus_diff* diff_tree)
11438 {
11439   category_propagation_visitor v;
11440   bool s = diff_tree->context()->visiting_a_node_twice_is_forbidden();
11441   diff_tree->context()->forbid_visiting_a_node_twice(false);
11442   diff_tree->traverse(v);
11443   diff_tree->context()->forbid_visiting_a_node_twice(s);
11444 }
11445 
11446 /// Visit all the nodes of a given corpus tree.  For each node that
11447 /// has a particular category set, propagate that category set up to
11448 /// its parent nodes.
11449 ///
11450 /// @param diff_tree the corpus_diff tree to walk for categorization
11451 /// purpose;
11452 void
propagate_categories(corpus_diff_sptr diff_tree)11453 propagate_categories(corpus_diff_sptr diff_tree)
11454 {propagate_categories(diff_tree.get());}
11455 
11456 /// A tree node visitor that knows how to categorizes a given diff
11457 /// node in the SUPPRESSED_CATEGORY category and how to propagate that
11458 /// categorization.
11459 struct suppression_categorization_visitor : public diff_node_visitor
11460 {
11461 
11462   /// Before visiting the children of the diff node, check if the node
11463   /// is suppressed by a suppression specification.  If it is, mark
11464   /// the node as belonging to the SUPPRESSED_CATEGORY category.
11465   ///
11466   /// @param p the diff node to visit.
11467   virtual void
visit_beginabigail::comparison::suppression_categorization_visitor11468   visit_begin(diff* d)
11469   {
11470     bool is_private_type = false;
11471     if (d->is_suppressed(is_private_type))
11472       {
11473 	diff_category c = is_private_type
11474 	  ? PRIVATE_TYPE_CATEGORY
11475 	  : SUPPRESSED_CATEGORY;
11476 	d->add_to_local_and_inherited_categories(c);
11477 
11478 	// If a node was suppressed, all the other nodes of its class
11479 	// of equivalence are suppressed too.
11480 	diff *canonical_diff = d->get_canonical_diff();
11481 	if (canonical_diff != d)
11482 	  canonical_diff->add_to_category(c);
11483       }
11484   }
11485 
11486   /// After visiting the children nodes of a given diff node,
11487   /// propagate the SUPPRESSED_CATEGORY from the children nodes to the
11488   /// diff node, if need be.
11489   ///
11490   /// That is, if all children nodes carry a suppressed change the
11491   /// current node should be marked as suppressed as well.
11492   ///
11493   /// In practice, this might be too strong of a condition.  If the
11494   /// current node carries a local change (i.e, a change not carried
11495   /// by any of its children node) and if that change is not
11496   /// suppressed, then the current node should *NOT* be suppressed.
11497   ///
11498   /// But right now, the IR doesn't let us know about local vs
11499   /// children-carried changes.  So we cannot be that precise yet.
11500   virtual void
visit_endabigail::comparison::suppression_categorization_visitor11501   visit_end(diff* d)
11502   {
11503     bool has_non_suppressed_child = false;
11504     bool has_non_empty_child = false;
11505     bool has_suppressed_child = false;
11506     bool has_non_private_child = false;
11507     bool has_private_child = false;
11508 
11509     if (// A node to which we can propagate the "SUPPRESSED_CATEGORY"
11510 	// (or the PRIVATE_TYPE_CATEGORY for the same matter)
11511 	// category from its children is a node which:
11512 	//
11513 	//  1/ hasn't been suppressed already
11514 	//
11515 	//  2/ and has no local change (unless it's a pointer,
11516 	//  reference or qualified diff node).
11517 	//
11518 	//  Note that qualified type and typedef diff nodes are a bit
11519 	//  special.  The local changes of the underlying type are
11520 	//  considered local for the qualified/typedef type, just like
11521 	//  for pointer/reference types.  But then the qualified or
11522 	//  typedef type itself can have local changes of its own, and
11523 	//  those changes are of the kind LOCAL_NON_TYPE_CHANGE_KIND.
11524 	//  So a qualified type which have local changes that are
11525 	//  *NOT* of LOCAL_NON_TYPE_CHANGE_KIND (or that has no local
11526 	//  changes at all) and which is in the PRIVATE_TYPE_CATEGORY
11527 	//  or SUPPRESSED_CATEGORY can see these categories be
11528 	//  propagated.
11529 	//
11530 	// Note that all pointer/reference diff node changes are
11531 	// potentially considered local, i.e, local changes of the
11532 	// pointed-to-type are considered local to the pointer itself.
11533 	//
11534 	// Similarly, changes local to the type of function parameters,
11535 	// variables (and data members) and classes (that are not of
11536 	// LOCAL_NON_TYPE_CHANGE_KIND kind) and that have been
11537 	// suppressed can propagate their SUPPRESSED_CATEGORY-ness to
11538 	// those kinds of diff node.
11539 	!(d->get_category() & SUPPRESSED_CATEGORY)
11540 	&& (!d->has_local_changes()
11541 	    || is_pointer_diff(d)
11542 	    || is_reference_diff(d)
11543 	    || (is_qualified_type_diff(d)
11544 		&& (!(d->has_local_changes() & LOCAL_NON_TYPE_CHANGE_KIND)))
11545 	    || (is_typedef_diff(d)
11546 		&& (!(d->has_local_changes() & LOCAL_NON_TYPE_CHANGE_KIND)))
11547 	    || (is_function_decl_diff(d)
11548 		&& (!(d->has_local_changes() & LOCAL_NON_TYPE_CHANGE_KIND)))
11549 	    || (is_fn_parm_diff(d)
11550 		&& (!(d->has_local_changes() & LOCAL_NON_TYPE_CHANGE_KIND)))
11551 	    || (is_function_type_diff(d)
11552 		&& (!(d->has_local_changes() & LOCAL_NON_TYPE_CHANGE_KIND)))
11553 	    || (is_var_diff(d)
11554 		&& (!(d->has_local_changes() & LOCAL_NON_TYPE_CHANGE_KIND)))
11555 	    ||  (is_class_diff(d)
11556 		&& (!(d->has_local_changes() & LOCAL_NON_TYPE_CHANGE_KIND)))))
11557       {
11558 	// Note that we handle private diff nodes differently from
11559 	// generally suppressed diff nodes.  E.g, it's not because a
11560 	// type is private (and suppressed because of that; i.e, in
11561 	// the category PRIVATE_TYPE_CATEGORY) that a typedef to that
11562 	// type should also be private and so suppressed.  Private
11563 	// diff nodes thus have different propagation rules than
11564 	// generally suppressed rules.
11565 	for (vector<diff*>::const_iterator i = d->children_nodes().begin();
11566 	     i != d->children_nodes().end();
11567 	     ++i)
11568 	  {
11569 	    diff* child = *i;
11570 	    if (child->has_changes())
11571 	      {
11572 		has_non_empty_child = true;
11573 		if (child->get_class_of_equiv_category() & SUPPRESSED_CATEGORY)
11574 		  has_suppressed_child = true;
11575 		else if (child->get_class_of_equiv_category()
11576 			 & PRIVATE_TYPE_CATEGORY)
11577 		  // Propagation of the PRIVATE_TYPE_CATEGORY is going
11578 		  // to be handled later below.
11579 		  ;
11580 		else
11581 		  has_non_suppressed_child = true;
11582 
11583 		if (child->get_class_of_equiv_category()
11584 		    & PRIVATE_TYPE_CATEGORY)
11585 		  has_private_child = true;
11586 		else if (child->get_class_of_equiv_category()
11587 			 & SUPPRESSED_CATEGORY)
11588 		  // Propagation of the SUPPRESSED_CATEGORY has been
11589 		  // handled above already.
11590 		  ;
11591 		else
11592 		  has_non_private_child = true;
11593 	      }
11594 	  }
11595 
11596 	if (has_non_empty_child
11597 	    && has_suppressed_child
11598 	    && !has_non_suppressed_child)
11599 	  {
11600 	    d->add_to_category(SUPPRESSED_CATEGORY);
11601 	    // If a node was suppressed, all the other nodes of its class
11602 	    // of equivalence are suppressed too.
11603 	    diff *canonical_diff = d->get_canonical_diff();
11604 	    if (canonical_diff != d)
11605 	      canonical_diff->add_to_category(SUPPRESSED_CATEGORY);
11606 	  }
11607 
11608 	// Note that the private-ness of a an underlying type won't be
11609 	// propagated to its parent typedef, by virtue of the big "if"
11610 	// clause at the beginning of this function.  So we don't have
11611 	// to handle that case here.  So the idiom of defining
11612 	// typedefs of private (opaque) types will be respected;
11613 	// meaning that changes to opaque underlying type will be
11614 	// flagged as private and the typedef will be flagged private
11615 	// as well, unless the typedef itself has local non-type
11616 	// changes.  In the later case, changes to the typedef will be
11617 	// emitted because the typedef won't inherit the privateness
11618 	// of its underlying type.  So in practise, the typedef
11619 	// remains public for the purpose of change reporting.
11620 	if (has_non_empty_child
11621 	    && has_private_child
11622 	    && !has_non_private_child)
11623 	  {
11624 	    d->add_to_category(PRIVATE_TYPE_CATEGORY);
11625 	    // If a node was suppressed, all the other nodes of its class
11626 	    // of equivalence are suppressed too.
11627 	    diff *canonical_diff = d->get_canonical_diff();
11628 	    if (canonical_diff != d)
11629 	      canonical_diff->add_to_category(PRIVATE_TYPE_CATEGORY);
11630 	  }
11631 
11632 	// If the underlying type of a typedef is private and carries
11633 	// changes (that are implicitely suppressed because it's
11634 	// private) then the typedef must be suppressed too, so that
11635 	// those changes to the underlying type are not seen.
11636 	if (is_typedef_diff(d)
11637 	    && !d->has_local_changes()
11638 	    && has_private_child
11639 	    && has_non_empty_child)
11640 	  {
11641 	    d->add_to_category(SUPPRESSED_CATEGORY|PRIVATE_TYPE_CATEGORY);
11642 	    // If a node was suppressed, all the other nodes of its class
11643 	    // of equivalence are suppressed too.
11644 	    diff *canonical_diff = d->get_canonical_diff();
11645 	    if (canonical_diff != d)
11646 	      canonical_diff->add_to_category
11647 		(SUPPRESSED_CATEGORY|PRIVATE_TYPE_CATEGORY);
11648 	  }
11649 
11650 	if (const function_decl_diff *fn_diff = is_function_decl_diff(d))
11651 	  if (!(d->has_local_changes() & LOCAL_NON_TYPE_CHANGE_KIND))
11652 	    {
11653 	      // d is a function diff that carries a local *type*
11654 	      // change (that means it's a change to the function
11655 	      // type).  Let's see if the child function type diff
11656 	      // node is suppressed.  That would mean that we are
11657 	      // instructed to show details of a diff that is deemed
11658 	      // suppressed; this means the suppression conflicts with
11659 	      // a local type change.  In that case, let's follow what
11660 	      // the user asked and suppress the function altogether,
11661 	      if (function_type_diff_sptr fn_type_diff = fn_diff->type_diff())
11662 		if (fn_type_diff->is_suppressed())
11663 		  {
11664 		    d->add_to_category(SUPPRESSED_CATEGORY);
11665 		    // If a node was suppressed, all the other nodes
11666 		    // of its class of equivalence are suppressed too.
11667 		    diff *canonical_diff = d->get_canonical_diff();
11668 		    if (canonical_diff != d)
11669 		      canonical_diff->add_to_category(SUPPRESSED_CATEGORY);
11670 		  }
11671 	  }
11672       }
11673   }
11674 }; //end struct suppression_categorization_visitor
11675 
11676 /// Walk a given diff-sub tree and appply the suppressions carried by
11677 /// the context.  If the suppression applies to a given node than
11678 /// categorize the node into the SUPPRESSED_CATEGORY category and
11679 /// propagate that categorization.
11680 ///
11681 /// @param diff_tree the diff-sub tree to apply the suppressions to.
11682 void
apply_suppressions(diff * diff_tree)11683 apply_suppressions(diff* diff_tree)
11684 {
11685   if (diff_tree && !diff_tree->context()->suppressions().empty())
11686     {
11687       // Apply suppressions to functions and variables that have
11688       // changed sub-types.
11689       suppression_categorization_visitor v;
11690       diff_tree->context()->forget_visited_diffs();
11691       bool s = diff_tree->context()->visiting_a_node_twice_is_forbidden();
11692       diff_tree->context()->forbid_visiting_a_node_twice(true);
11693       diff_tree->traverse(v);
11694       diff_tree->context()->forbid_visiting_a_node_twice(s);
11695     }
11696 }
11697 
11698 /// Walk a given diff-sub tree and appply the suppressions carried by
11699 /// the context.  If the suppression applies to a given node than
11700 /// categorize the node into the SUPPRESSED_CATEGORY category and
11701 /// propagate that categorization.
11702 ///
11703 /// @param diff_tree the diff-sub tree to apply the suppressions to.
11704 void
apply_suppressions(diff_sptr diff_tree)11705 apply_suppressions(diff_sptr diff_tree)
11706 {apply_suppressions(diff_tree.get());}
11707 
11708 /// Walk a @ref corpus_diff tree and appply the suppressions carried
11709 /// by the context.  If the suppression applies to a given node then
11710 /// categorize the node into the SUPPRESSED_CATEGORY category and
11711 /// propagate that categorization.
11712 ///
11713 /// @param diff_tree the diff tree to apply the suppressions to.
11714 void
apply_suppressions(const corpus_diff * diff_tree)11715 apply_suppressions(const corpus_diff* diff_tree)
11716 {
11717   if (diff_tree && !diff_tree->context()->suppressions().empty())
11718     {
11719       // First, visit the children trees of changed constructs:
11720       // changed functions, variables, as well as sub-types of these,
11721       // and apply suppression specifications to these ...
11722       suppression_categorization_visitor v;
11723       diff_tree->context()->forget_visited_diffs();
11724       bool s = diff_tree->context()->visiting_a_node_twice_is_forbidden();
11725       diff_tree->context()->forbid_visiting_a_node_twice(true);
11726       const_cast<corpus_diff*>(diff_tree)->traverse(v);
11727       diff_tree->context()->forbid_visiting_a_node_twice(s);
11728 
11729       // ... then also visit the set of added and removed functions,
11730       // variables, symbols, and types not reachable from global
11731       // functions and variables.
11732       diff_tree->priv_->
11733 	apply_supprs_to_added_removed_fns_vars_unreachable_types();
11734     }
11735 }
11736 
11737 /// Walk a diff tree and appply the suppressions carried by the
11738 /// context.  If the suppression applies to a given node than
11739 /// categorize the node into the SUPPRESSED_CATEGORY category and
11740 /// propagate that categorization.
11741 ///
11742 /// @param diff_tree the diff tree to apply the suppressions to.
11743 void
apply_suppressions(corpus_diff_sptr diff_tree)11744 apply_suppressions(corpus_diff_sptr  diff_tree)
11745 {apply_suppressions(diff_tree.get());}
11746 
11747 // </diff tree category propagation>
11748 
11749 // <diff tree printing stuff>
11750 
11751 /// A visitor to print (to an output stream) a pretty representation
11752 /// of a @ref diff sub-tree or of a complete @ref corpus_diff tree.
11753 struct diff_node_printer : public diff_node_visitor
11754 {
11755   ostream& out_;
11756   unsigned level_;
11757 
11758   /// Emit a certain number of spaces to the output stream associated
11759   /// to this diff_node_printer.
11760   ///
11761   /// @param level half of the numver of spaces to emit.
11762   void
do_indentabigail::comparison::diff_node_printer11763   do_indent(unsigned level)
11764   {
11765     for (unsigned i = 0; i < level; ++i)
11766       out_ << "  ";
11767   }
11768 
diff_node_printerabigail::comparison::diff_node_printer11769   diff_node_printer(ostream& out)
11770     : diff_node_visitor(DO_NOT_MARK_VISITED_NODES_AS_VISITED),
11771       out_(out),
11772       level_(0)
11773   {}
11774 
11775   virtual void
visit_beginabigail::comparison::diff_node_printer11776   visit_begin(diff*)
11777   {
11778     ++level_;
11779   }
11780 
11781   virtual void
visit_endabigail::comparison::diff_node_printer11782   visit_end(diff*)
11783   {
11784     --level_;
11785   }
11786 
11787   virtual void
visit_beginabigail::comparison::diff_node_printer11788   visit_begin(corpus_diff*)
11789   {
11790     ++level_;
11791   }
11792 
11793   virtual void
visit_endabigail::comparison::diff_node_printer11794   visit_end(corpus_diff*)
11795   {
11796     --level_;
11797   }
11798 
11799   virtual bool
visitabigail::comparison::diff_node_printer11800   visit(diff* d, bool pre)
11801   {
11802     if (!pre)
11803       // We are post-visiting the diff node D.  Which means, we have
11804       // printed a pretty representation for it already.  So do
11805       // nothing now.
11806       return true;
11807 
11808     do_indent(level_);
11809     out_ << d->get_pretty_representation();
11810     out_ << "\n";
11811     do_indent(level_);
11812     out_ << "{\n";
11813     do_indent(level_ + 1);
11814     out_ << "category: "<< d->get_category() << "\n";
11815     do_indent(level_ + 1);
11816     out_ << "@: " << std::hex << d << std::dec << "\n";
11817     do_indent(level_ + 1);
11818     out_ << "@-canonical: " << std::hex
11819 	 << d->get_canonical_diff()
11820 	 << std::dec << "\n";
11821     do_indent(level_);
11822     out_ << "}\n";
11823 
11824     return true;
11825   }
11826 
11827   virtual bool
visitabigail::comparison::diff_node_printer11828   visit(corpus_diff* d, bool pre)
11829   {
11830     if (!pre)
11831       // We are post-visiting the diff node D.  Which means, we have
11832       // printed a pretty representation for it already.  So do
11833       // nothing now.
11834       return true;
11835 
11836     // indent
11837     for (unsigned i = 0; i < level_; ++i)
11838       out_ << ' ';
11839     out_ << d->get_pretty_representation();
11840     out_ << '\n';
11841     return true;
11842   }
11843 }; // end struct diff_printer_visitor
11844 
11845 // </ diff tree printing stuff>
11846 
11847 /// Emit a textual representation of a @ref diff sub-tree to an
11848 /// output stream.
11849 ///
11850 /// @param diff_tree the sub-tree to emit the textual representation
11851 /// for.
11852 ///
11853 /// @param out the output stream to emit the textual representation
11854 /// for @p diff_tree to.
11855 void
print_diff_tree(diff * diff_tree,ostream & out)11856 print_diff_tree(diff* diff_tree, ostream& out)
11857 {
11858   diff_node_printer p(out);
11859   bool s = diff_tree->context()->visiting_a_node_twice_is_forbidden();
11860   diff_tree->context()->forbid_visiting_a_node_twice(false);
11861   diff_tree->traverse(p);
11862   diff_tree->context()->forbid_visiting_a_node_twice(s);
11863 }
11864 
11865 /// Emit a textual representation of a @ref corpus_diff tree to an
11866 /// output stream.
11867 ///
11868 /// @param diff_tree the @ref corpus_diff tree to emit the textual
11869 /// representation for.
11870 ///
11871 /// @param out the output stream to emit the textual representation
11872 /// for @p diff_tree to.
11873 void
print_diff_tree(corpus_diff * diff_tree,std::ostream & out)11874 print_diff_tree(corpus_diff* diff_tree, std::ostream& out)
11875 {
11876   diff_node_printer p(out);
11877   bool s = diff_tree->context()->visiting_a_node_twice_is_forbidden();
11878   diff_tree->context()->forbid_visiting_a_node_twice(false);
11879   diff_tree->traverse(p);
11880   diff_tree->context()->forbid_visiting_a_node_twice(s);
11881 }
11882 
11883 /// Emit a textual representation of a @ref diff sub-tree to an
11884 /// output stream.
11885 ///
11886 /// @param diff_tree the sub-tree to emit the textual representation
11887 /// for.
11888 ///
11889 /// @param out the output stream to emit the textual representation
11890 /// for @p diff_tree to.
11891 void
print_diff_tree(diff_sptr diff_tree,std::ostream & o)11892 print_diff_tree(diff_sptr diff_tree,
11893 		std::ostream& o)
11894 {print_diff_tree(diff_tree.get(), o);}
11895 
11896 /// Emit a textual representation of a @ref corpus_diff tree to an
11897 /// output stream.
11898 ///
11899 /// @param diff_tree the @ref corpus_diff tree to emit the textual
11900 /// representation for.
11901 ///
11902 /// @param out the output stream to emit the textual representation
11903 /// for @p diff_tree to.
11904 void
print_diff_tree(corpus_diff_sptr diff_tree,std::ostream & o)11905 print_diff_tree(corpus_diff_sptr diff_tree,
11906 		std::ostream& o)
11907 {print_diff_tree(diff_tree.get(), o);}
11908 
11909 // <redundancy_marking_visitor>
11910 
11911 /// A tree visitor to categorize nodes with respect to the
11912 /// REDUNDANT_CATEGORY.  That is, detect if a node is redundant (is
11913 /// present on several spots of the tree) and mark such nodes
11914 /// appropriatly.  This visitor also takes care of propagating the
11915 /// REDUNDANT_CATEGORY of a given node to its parent nodes as
11916 /// appropriate.
11917 struct redundancy_marking_visitor : public diff_node_visitor
11918 {
11919   bool skip_children_nodes_;
11920 
redundancy_marking_visitorabigail::comparison::redundancy_marking_visitor11921   redundancy_marking_visitor()
11922     : skip_children_nodes_()
11923   {}
11924 
11925   virtual void
visit_beginabigail::comparison::redundancy_marking_visitor11926   visit_begin(diff* d)
11927   {
11928     if (d->to_be_reported())
11929       {
11930 	// A diff node that carries a change and that has been already
11931 	// traversed elsewhere is considered redundant.  So let's mark
11932 	// it as such and let's not traverse it; that is, let's not
11933 	// visit its children.
11934 	if ((d->context()->diff_has_been_visited(d)
11935 	     || d->get_canonical_diff()->is_traversing())
11936 	    && d->has_changes())
11937 	  {
11938 	    // But if two diff nodes are redundant sibbling that carry
11939 	    // changes of base types, do not mark them as being
11940 	    // redundant.  This is to avoid marking nodes as redundant
11941 	    // in this case:
11942 	    //
11943 	    //     int foo(int a, int b);
11944 	    // compared with:
11945 	    //     float foo(float a, float b); (in C).
11946 	    //
11947 	    // In this case, we want to report all the occurences of
11948 	    // the int->float change because logically, they are at
11949 	    // the same level in the diff tree.
11950 
11951 	    bool redundant_with_sibling_node = false;
11952 	    const diff* p = d->parent_node();
11953 
11954 	    // If this is a child node of a fn_parm_diff, look through
11955 	    // the fn_parm_diff node to get the function diff node.
11956 	    if (p && dynamic_cast<const fn_parm_diff*>(p))
11957 	      p = p->parent_node();
11958 
11959 	    if (p)
11960 	      for (vector<diff*>::const_iterator s =
11961 		     p->children_nodes().begin();
11962 		   s != p->children_nodes().end();
11963 		   ++s)
11964 		{
11965 		  if (*s == d)
11966 		    continue;
11967 		  diff* sib = *s;
11968 		  // If this is a fn_parm_diff, look through the
11969 		  // fn_parm_diff node to get at the real type node.
11970 		  if (fn_parm_diff* f = dynamic_cast<fn_parm_diff*>(*s))
11971 		    sib = f->type_diff().get();
11972 		  if (sib == d)
11973 		    continue;
11974 		  if (sib->get_canonical_diff() == d->get_canonical_diff()
11975 		      // Sibbling diff nodes that carry base type
11976 		      // changes ar to be marked as redundant.
11977 		      && (is_base_diff(sib) || is_distinct_diff(sib)))
11978 		    {
11979 		      redundant_with_sibling_node = true;
11980 		      break;
11981 		    }
11982 		}
11983 	    if (!redundant_with_sibling_node
11984 		// Changes to basic types should never be considered
11985 		// redundant.  For instance, if a member of integer
11986 		// type is changed into a char type in both a struct A
11987 		// and a struct B, we want to see both changes.
11988 		&& !has_basic_type_change_only(d)
11989 		// The same goes for distinct type changes
11990 		&& !filtering::is_mostly_distinct_diff(d)
11991 		// Functions with similar *local* changes are never marked
11992 		// redundant because otherwise one could miss important
11993 		// similar local changes that are applied to different
11994 		// functions.
11995 		&& !is_function_type_diff_with_local_changes(d)
11996 		// Changes involving variadic parameters of functions
11997 		// should never be marked redundant because we want to see
11998 		// them all.
11999 		&& !is_diff_of_variadic_parameter(d)
12000 		&& !is_diff_of_variadic_parameter_type(d)
12001 		// If the canonical diff itself has been filtered out,
12002 		// then this one is not marked redundant, unless the
12003 		// canonical diff was already redundant.
12004 		&& (!d->get_canonical_diff()->is_filtered_out()
12005 		    || (d->get_canonical_diff()->get_category()
12006 			& REDUNDANT_CATEGORY))
12007 		// If the *same* diff node (not one that is merely
12008 		// equivalent to this one) has already been visited
12009 		// the do not mark it as beind redundant.  It's only
12010 		// the other nodes that are equivalent to this one
12011 		// that must be marked redundant.
12012 		&& d->context()->diff_has_been_visited(d) != d
12013 		// If the diff node is a function parameter and is not
12014 		// a reference/pointer (to a non basic or a non
12015 		// distinct type diff) then do not mark it as
12016 		// redundant.
12017 		//
12018 		// Children nodes of base class diff nodes are never
12019 		// redundant either, we want to see them all.
12020 		&& (is_reference_or_ptr_diff_to_non_basic_nor_distinct_types(d)
12021 		    || (!is_child_node_of_function_parm_diff(d)
12022 			&& !is_child_node_of_base_diff(d))))
12023 	      {
12024 		d->add_to_category(REDUNDANT_CATEGORY);
12025 		// As we said in preamble, as this node is marked as
12026 		// being redundant, let's not visit its children.
12027 		// This is not an optimization; it's needed for
12028 		// correctness.  In the case of a diff node involving
12029 		// a class type that refers to himself, visiting the
12030 		// children nodes might cause them to be wrongly
12031 		// marked as redundant.
12032 		set_visiting_kind(get_visiting_kind()
12033 				  | SKIP_CHILDREN_VISITING_KIND);
12034 		skip_children_nodes_ = true;
12035 	      }
12036 	  }
12037       }
12038     else
12039       {
12040 	// If the node is not to be reported, do not look at it children.
12041 	set_visiting_kind(get_visiting_kind() | SKIP_CHILDREN_VISITING_KIND);
12042 	skip_children_nodes_ = true;
12043       }
12044   }
12045 
12046   virtual void
visit_beginabigail::comparison::redundancy_marking_visitor12047   visit_begin(corpus_diff*)
12048   {
12049   }
12050 
12051   virtual void
visit_endabigail::comparison::redundancy_marking_visitor12052   visit_end(diff* d)
12053   {
12054     if (skip_children_nodes_)
12055       // When visiting this node, we decided to skip its children
12056       // node.  Now that we are done visiting the node, lets stop
12057       // avoiding the children nodes visiting for the other tree
12058       // nodes.
12059       {
12060 	set_visiting_kind(get_visiting_kind() & (~SKIP_CHILDREN_VISITING_KIND));
12061 	skip_children_nodes_ = false;
12062       }
12063     else
12064       {
12065 	// Propagate the redundancy categorization of the children nodes
12066 	// to this node.  But if this node has local changes, then it
12067 	// doesn't inherit redundancy from its children nodes.
12068 	if (!(d->get_category() & REDUNDANT_CATEGORY)
12069 	    && (!d->has_local_changes_to_be_reported()
12070 		// By default, pointer, reference and qualified types
12071 		// consider that a local changes to their underlying
12072 		// type is always a local change for themselves.
12073 		//
12074 		// This is as if those types don't have local changes
12075 		// in the same sense as other types.  So we always
12076 		// propagate redundancy to them, regardless of if they
12077 		// have local changes or not.
12078 		//
12079 		// We also propagate redundancy to typedef types if
12080 		// these /only/ carry changes to their underlying
12081 		// type.
12082 		//
12083 		// Note that changes to the underlying type of a
12084 		// typedef is considered local of
12085 		// LOCAL_TYPE_CHANGE_KIND kind.  The other changes to the
12086 		// typedef itself are considered local of
12087 		// LOCAL_NON_TYPE_CHANGE_KIND kind.
12088 		|| is_pointer_diff(d)
12089 		|| is_qualified_type_diff(d)
12090 		// A typedef with local non-type changes should not
12091 		// see redundancy propagation from its underlying
12092 		// type, otherwise, the non-type change might be
12093 		// "suppressed" away.
12094 		|| (is_typedef_diff(d)
12095 		    && (!(d->has_local_changes()
12096 			  & LOCAL_NON_TYPE_CHANGE_KIND)))
12097 		// A (member) variable with non-type local changes
12098 		// should not see redundacy propagation from its type.
12099 		// If redundant local-type changes are carried by its
12100 		// type however, then that redundancy is propagated to
12101 		// the variable.  This is key to keep the redundancy
12102 		// consistency in the system; otherwise, a type change
12103 		// would be rightfully considered redundant at some
12104 		// places but not at others.
12105 		|| (is_var_diff(d)
12106 		    && (!(d->has_local_changes()
12107 			  & LOCAL_NON_TYPE_CHANGE_KIND)))
12108 		))
12109 	  {
12110 	    bool has_non_redundant_child = false;
12111 	    bool has_non_empty_child = false;
12112 	    for (vector<diff*>::const_iterator i =
12113 		   d->children_nodes().begin();
12114 		 i != d->children_nodes().end();
12115 		 ++i)
12116 	      {
12117 		if ((*i)->has_changes())
12118 		  {
12119 		    has_non_empty_child = true;
12120 		    // Let's see if the current child node '*i' is
12121 		    // "non-redundant".
12122 		    //
12123 		    // A non-redundant node would be a node that
12124 		    // carries a change to be reported and has not
12125 		    // been marked as being redundant.
12126 		    if ((*i)->to_be_reported()
12127 			&& ((*i)->get_category() & REDUNDANT_CATEGORY) == 0)
12128 		      has_non_redundant_child = true;
12129 		  }
12130 		if (has_non_redundant_child)
12131 		  break;
12132 	      }
12133 
12134 	    // A diff node for which at least a child node carries a
12135 	    // change, and for which all the children are redundant is
12136 	    // deemed redundant too, unless it has local changes.
12137 	    if (has_non_empty_child
12138 		&& !has_non_redundant_child)
12139 	      d->add_to_category(REDUNDANT_CATEGORY);
12140 	  }
12141       }
12142   }
12143 
12144   virtual void
visit_endabigail::comparison::redundancy_marking_visitor12145   visit_end(corpus_diff*)
12146   {
12147   }
12148 
12149   virtual bool
visitabigail::comparison::redundancy_marking_visitor12150   visit(diff*, bool)
12151   {return true;}
12152 
12153   virtual bool
visitabigail::comparison::redundancy_marking_visitor12154   visit(corpus_diff*, bool)
12155   {
12156     return true;
12157   }
12158 };// end struct redundancy_marking_visitor
12159 
12160 /// A visitor of @ref diff nodes that clears the REDUNDANT_CATEGORY
12161 /// category out of the nodes.
12162 struct redundancy_clearing_visitor : public diff_node_visitor
12163 {
12164   bool
visitabigail::comparison::redundancy_clearing_visitor12165   visit(corpus_diff*, bool)
12166   {return true;}
12167 
12168   bool
visitabigail::comparison::redundancy_clearing_visitor12169   visit(diff* d, bool)
12170   {
12171     // clear the REDUNDANT_CATEGORY out of the current node.
12172     diff_category c = d->get_category();
12173     c &= ~REDUNDANT_CATEGORY;
12174     d->set_category(c);
12175     return true;
12176   }
12177 }; // end struct redundancy_clearing_visitor
12178 
12179 /// Walk a given @ref diff sub-tree to categorize each of the nodes
12180 /// with respect to the REDUNDANT_CATEGORY.
12181 ///
12182 /// @param diff_tree the @ref diff sub-tree to walk.
12183 void
categorize_redundancy(diff * diff_tree)12184 categorize_redundancy(diff* diff_tree)
12185 {
12186   if (diff_tree->context()->show_redundant_changes())
12187     return;
12188   redundancy_marking_visitor v;
12189   bool s = diff_tree->context()->visiting_a_node_twice_is_forbidden();
12190   diff_tree->context()->forbid_visiting_a_node_twice(false);
12191   diff_tree->traverse(v);
12192   diff_tree->context()->forbid_visiting_a_node_twice(s);
12193 }
12194 
12195 /// Walk a given @ref diff sub-tree to categorize each of the nodes
12196 /// with respect to the REDUNDANT_CATEGORY.
12197 ///
12198 /// @param diff_tree the @ref diff sub-tree to walk.
12199 void
categorize_redundancy(diff_sptr diff_tree)12200 categorize_redundancy(diff_sptr diff_tree)
12201 {categorize_redundancy(diff_tree.get());}
12202 
12203 /// Walk a given @ref corpus_diff tree to categorize each of the nodes
12204 /// with respect to the REDUNDANT_CATEGORY.
12205 ///
12206 /// @param diff_tree the @ref corpus_diff tree to walk.
12207 void
categorize_redundancy(corpus_diff * diff_tree)12208 categorize_redundancy(corpus_diff* diff_tree)
12209 {
12210   redundancy_marking_visitor v;
12211   diff_tree->context()->forget_visited_diffs();
12212   bool s = diff_tree->context()->visiting_a_node_twice_is_forbidden();
12213   diff_tree->context()->forbid_visiting_a_node_twice(false);
12214   diff_tree->traverse(v);
12215   diff_tree->context()->forbid_visiting_a_node_twice(s);
12216 }
12217 
12218 /// Walk a given @ref corpus_diff tree to categorize each of the nodes
12219 /// with respect to the REDUNDANT_CATEGORY.
12220 ///
12221 /// @param diff_tree the @ref corpus_diff tree to walk.
12222 void
categorize_redundancy(corpus_diff_sptr diff_tree)12223 categorize_redundancy(corpus_diff_sptr diff_tree)
12224 {categorize_redundancy(diff_tree.get());}
12225 
12226 // </redundancy_marking_visitor>
12227 
12228 /// Walk a given @ref diff sub-tree to clear the REDUNDANT_CATEGORY
12229 /// out of the category of the nodes.
12230 ///
12231 /// @param diff_tree the @ref diff sub-tree to walk.
12232 void
clear_redundancy_categorization(diff * diff_tree)12233 clear_redundancy_categorization(diff* diff_tree)
12234 {
12235   redundancy_clearing_visitor v;
12236   bool s = diff_tree->context()->visiting_a_node_twice_is_forbidden();
12237   diff_tree->context()->forbid_visiting_a_node_twice(false);
12238   diff_tree->traverse(v);
12239   diff_tree->context()->forbid_visiting_a_node_twice(s);
12240   diff_tree->context()->forget_visited_diffs();
12241 }
12242 
12243 /// Walk a given @ref diff sub-tree to clear the REDUNDANT_CATEGORY
12244 /// out of the category of the nodes.
12245 ///
12246 /// @param diff_tree the @ref diff sub-tree to walk.
12247 void
clear_redundancy_categorization(diff_sptr diff_tree)12248 clear_redundancy_categorization(diff_sptr diff_tree)
12249 {clear_redundancy_categorization(diff_tree.get());}
12250 
12251 /// Walk a given @ref corpus_diff tree to clear the REDUNDANT_CATEGORY
12252 /// out of the category of the nodes.
12253 ///
12254 /// @param diff_tree the @ref corpus_diff tree to walk.
12255 void
clear_redundancy_categorization(corpus_diff * diff_tree)12256 clear_redundancy_categorization(corpus_diff* diff_tree)
12257 {
12258   redundancy_clearing_visitor v;
12259   bool s = diff_tree->context()->visiting_a_node_twice_is_forbidden();
12260   diff_tree->context()->forbid_visiting_a_node_twice(false);
12261   diff_tree->traverse(v);
12262   diff_tree->context()->forbid_visiting_a_node_twice(s);
12263   diff_tree->context()->forget_visited_diffs();
12264 }
12265 
12266 /// Walk a given @ref corpus_diff tree to clear the REDUNDANT_CATEGORY
12267 /// out of the category of the nodes.
12268 ///
12269 /// @param diff_tree the @ref corpus_diff tree to walk.
12270 void
clear_redundancy_categorization(corpus_diff_sptr diff_tree)12271 clear_redundancy_categorization(corpus_diff_sptr diff_tree)
12272 {clear_redundancy_categorization(diff_tree.get());}
12273 
12274 /// Apply the @ref diff tree filters that have been associated to the
12275 /// context of the a given @ref corpus_diff tree.  As a result, the
12276 /// nodes of the @diff tree are going to be categorized into one of
12277 /// several of the categories of @ref diff_category.
12278 ///
12279 /// @param diff_tree the @ref corpus_diff instance which @ref diff are
12280 /// to be categorized.
12281 void
apply_filters(corpus_diff_sptr diff_tree)12282 apply_filters(corpus_diff_sptr diff_tree)
12283 {
12284   diff_tree->context()->maybe_apply_filters(diff_tree);
12285   propagate_categories(diff_tree);
12286 }
12287 
12288 /// Test if a diff node represents the difference between a variadic
12289 /// parameter type and something else.
12290 ///
12291 /// @param d the diff node to consider.
12292 ///
12293 /// @return true iff @p d is a diff node that represents the
12294 /// difference between a variadic parameter type and something else.
12295 bool
is_diff_of_variadic_parameter_type(const diff * d)12296 is_diff_of_variadic_parameter_type(const diff* d)
12297 {
12298   if (!d)
12299     return false;
12300 
12301   type_base_sptr t = is_type(d->first_subject());
12302   if (t && t->get_environment().is_variadic_parameter_type(t))
12303     return true;
12304 
12305   t = is_type(d->second_subject());
12306   if (t && t->get_environment().is_variadic_parameter_type(t))
12307     return true;
12308 
12309   return false;
12310 }
12311 
12312 /// Test if a diff node represents the difference between a variadic
12313 /// parameter type and something else.
12314 ///
12315 /// @param d the diff node to consider.
12316 ///
12317 /// @return true iff @p d is a diff node that represents the
12318 /// difference between a variadic parameter type and something else.
12319 bool
is_diff_of_variadic_parameter_type(const diff_sptr & d)12320 is_diff_of_variadic_parameter_type(const diff_sptr& d)
12321 {return is_diff_of_variadic_parameter_type(d.get());}
12322 
12323 /// Test if a diff node represents the difference between a variadic
12324 /// parameter and something else.
12325 ///
12326 /// @param d the diff node to consider.
12327 ///
12328 /// @return true iff @p d is a diff node that represents the
12329 /// difference between a variadic parameter and something else.
12330 bool
is_diff_of_variadic_parameter(const diff * d)12331 is_diff_of_variadic_parameter(const diff* d)
12332 {
12333   fn_parm_diff* diff =
12334     dynamic_cast<fn_parm_diff*>(const_cast<abigail::comparison::diff*>(d));
12335   return (diff && is_diff_of_variadic_parameter_type(diff->type_diff()));
12336 }
12337 
12338 /// Test if a diff node represents the difference between a variadic
12339 /// parameter and something else.
12340 ///
12341 /// @param d the diff node to consider.
12342 ///
12343 /// @return true iff @p d is a diff node that represents the
12344 /// difference between a variadic parameter and something else.
12345 bool
is_diff_of_variadic_parameter(const diff_sptr & d)12346 is_diff_of_variadic_parameter(const diff_sptr& d)
12347 {return is_diff_of_variadic_parameter(d.get());}
12348 
12349 /// Test if a diff node represents a diff between two basic types.
12350 ///
12351 /// @param d the diff node to consider.
12352 ///
12353 /// @return true iff @p d is a diff between two basic types.
12354 const type_decl_diff*
is_diff_of_basic_type(const diff * d)12355 is_diff_of_basic_type(const diff *d)
12356 {return dynamic_cast<const type_decl_diff*>(d);}
12357 
12358 /// Test if a diff node represents a diff between two basic types, or
12359 /// between pointers, references or qualified type to basic types.
12360 ///
12361 /// @param diff the diff node to consider.
12362 ///
12363 /// @param allow_indirect_type if true, then this function looks into
12364 /// pointer, reference or qualified diff types to see if they "point
12365 /// to" basic types.
12366 ///
12367 /// @return true iff @p d is a diff between two basic types.
12368 const type_decl_diff*
is_diff_of_basic_type(const diff * diff,bool allow_indirect_type)12369 is_diff_of_basic_type(const diff* diff, bool allow_indirect_type)
12370 {
12371   if (allow_indirect_type)
12372       diff = peel_pointer_or_qualified_type_diff(diff);
12373   return is_diff_of_basic_type(diff);
12374 }
12375 
12376 /// If a diff node is about changes between two typedef types, get the
12377 /// diff node about changes between the underlying types.
12378 ///
12379 /// Note that this function walks the tree of underlying diff nodes
12380 /// returns the first diff node about types that are not typedefs.
12381 ///
12382 /// @param dif the dif node to consider.
12383 ///
12384 /// @return the underlying diff node of @p dif, or just return @p dif
12385 /// if it's not a typedef diff node.
12386 const diff*
peel_typedef_diff(const diff * dif)12387 peel_typedef_diff(const diff* dif)
12388 {
12389   const typedef_diff *d = 0;
12390   while ((d = is_typedef_diff(dif)))
12391     dif = d->underlying_type_diff().get();
12392   return dif;
12393 }
12394 
12395 /// If a diff node is about changes between two pointer types, get the
12396 /// diff node about changes between the underlying (pointed-to) types.
12397 ///
12398 /// Note that this function walks the tree of underlying diff nodes
12399 /// returns the first diff node about types that are not pointers.
12400 ///
12401 /// @param dif the dif node to consider.
12402 ///
12403 /// @return the underlying diff node of @p dif, or just return @p dif
12404 /// if it's not a pointer diff node.
12405 const diff*
peel_pointer_diff(const diff * dif)12406 peel_pointer_diff(const diff* dif)
12407 {
12408   const pointer_diff *d = 0;
12409   while ((d = is_pointer_diff(dif)))
12410     dif = d->underlying_type_diff().get();
12411   return dif;
12412 }
12413 
12414 /// If a diff node is about changes between two reference types, get
12415 /// the diff node about changes between the underlying (pointed-to)
12416 /// types.
12417 ///
12418 /// Note that this function walks the tree of underlying diff nodes
12419 /// returns the first diff node about types that are not references.
12420 ///
12421 /// @param dif the dif node to consider.
12422 ///
12423 /// @return the underlying diff node of @p dif, or just return @p dif
12424 /// if it's not a reference diff node.
12425 const diff*
peel_reference_diff(const diff * dif)12426 peel_reference_diff(const diff* dif)
12427 {
12428   const reference_diff *d = 0;
12429   while ((d = is_reference_diff(dif)))
12430     dif = d->underlying_type_diff().get();
12431   return dif;
12432 }
12433 
12434 /// If a diff node is about changes between two qualified types, get
12435 /// the diff node about changes between the underlying (non-qualified)
12436 /// types.
12437 ///
12438 /// Note that this function walks the tree of underlying diff nodes
12439 /// returns the first diff node about types that are not qualified.
12440 ///
12441 /// @param dif the dif node to consider.
12442 ///
12443 /// @return the underlying diff node of @p dif, or just return @p dif
12444 /// if it's not a qualified diff node.
12445 const diff*
peel_qualified_diff(const diff * dif)12446 peel_qualified_diff(const diff* dif)
12447 {
12448   const qualified_type_diff *d = 0;
12449   while ((d = is_qualified_type_diff(dif)))
12450     dif = d->underlying_type_diff().get();
12451   return dif;
12452 }
12453 
12454 /// If a diff node is about changes between two function parameters
12455 /// get the diff node about changes between the types of the parameters.
12456 ///
12457 /// @param dif the dif node to consider.
12458 ///
12459 /// @return the diff of the types of the parameters.
12460 const diff*
peel_fn_parm_diff(const diff * dif)12461 peel_fn_parm_diff(const diff* dif)
12462 {
12463   const fn_parm_diff *d = 0;
12464   while ((d = is_fn_parm_diff(dif)))
12465     dif = d->type_diff().get();
12466   return dif;
12467 }
12468 
12469 /// If a diff node is about changes between two pointer, reference or
12470 /// qualified types, get the diff node about changes between the
12471 /// underlying types.
12472 ///
12473 /// Note that this function walks the tree of underlying diff nodes
12474 /// returns the first diff node about types that are not pointer,
12475 /// reference or qualified.
12476 ///
12477 /// @param dif the dif node to consider.
12478 ///
12479 /// @return the underlying diff node of @p dif, or just return @p dif
12480 /// if it's not a pointer, reference or qualified diff node.
12481 const diff*
peel_pointer_or_qualified_type_diff(const diff * dif)12482 peel_pointer_or_qualified_type_diff(const diff*dif)
12483 {
12484   while (true)
12485     {
12486       if (const pointer_diff *d = is_pointer_diff(dif))
12487 	dif = peel_pointer_diff(d);
12488       else if (const reference_diff *d = is_reference_diff(dif))
12489 	dif = peel_reference_diff(d);
12490       else if (const qualified_type_diff *d = is_qualified_type_diff(dif))
12491 	dif = peel_qualified_diff(d);
12492       else
12493 	break;
12494     }
12495   return dif;
12496 }
12497 
12498 /// If a diff node is about changes between two typedefs or qualified
12499 /// types, get the diff node about changes between the underlying
12500 /// types.
12501 ///
12502 /// Note that this function walks the tree of underlying diff nodes
12503 /// returns the first diff node about types that are not typedef or
12504 /// qualified types.
12505 ///
12506 /// @param dif the dif node to consider.
12507 ///
12508 /// @return the underlying diff node of @p dif, or just return @p dif
12509 /// if it's not typedef or qualified diff node.
12510 const diff*
peel_typedef_or_qualified_type_diff(const diff * dif)12511 peel_typedef_or_qualified_type_diff(const diff *dif)
12512 {
12513   while (true)
12514     {
12515       if (const typedef_diff *d = is_typedef_diff(dif))
12516 	dif = peel_typedef_diff(d);
12517       else if (const qualified_type_diff *d = is_qualified_type_diff(dif))
12518 	dif = peel_qualified_diff(d);
12519       else
12520 	break;
12521     }
12522   return dif;
12523 }
12524 
12525 /// If a diff node is about changes between two typedefs or qualified
12526 /// types, get the diff node about changes between the underlying
12527 /// types.
12528 ///
12529 /// Note that this function walks the tree of underlying diff nodes
12530 /// returns the first diff node about types that are neither typedef,
12531 /// qualified type nor parameters.
12532 ///
12533 /// @param dif the dif node to consider.
12534 ///
12535 /// @return the diff node about changes between the underlying types.
12536 const diff*
peel_typedef_qualified_type_or_parameter_diff(const diff * dif)12537 peel_typedef_qualified_type_or_parameter_diff(const diff *dif)
12538 {
12539   while (true)
12540     {
12541       if (const typedef_diff *d = is_typedef_diff(dif))
12542 	dif = peel_typedef_diff(d);
12543       else if (const qualified_type_diff *d = is_qualified_type_diff(dif))
12544 	dif = peel_qualified_diff(d);
12545       else if (const fn_parm_diff *d = is_fn_parm_diff(dif))
12546 	dif = peel_fn_parm_diff(d);
12547       else
12548 	break;
12549     }
12550   return dif;
12551 }
12552 
12553 /// Test if a diff node represents a diff between two class or union
12554 /// types.
12555 ///
12556 /// @param d the diff node to consider.
12557 ///
12558 /// @return iff @p is a diff between two class or union types then
12559 /// return the instance of @ref class_or_union_diff that @p derives
12560 /// from.  Otherwise, return nil.
12561 const class_or_union_diff*
is_diff_of_class_or_union_type(const diff * d)12562 is_diff_of_class_or_union_type(const diff *d)
12563 {return dynamic_cast<const class_or_union_diff*>(d);}
12564 
12565 /// Test if a given diff node carries *only* a local type change.
12566 ///
12567 /// @param d the diff node to consider.
12568 ///
12569 /// @return true iff @p has a change and that change is a local type
12570 /// change.
12571 static bool
has_local_type_change_only(const diff * d)12572 has_local_type_change_only(const diff *d)
12573 {
12574   if (enum change_kind k = d->has_local_changes())
12575     if ((k & LOCAL_NON_TYPE_CHANGE_KIND) == 0
12576 	&& (k & LOCAL_TYPE_CHANGE_KIND) != 0)
12577       return true;
12578 
12579   return false;
12580 }
12581 
12582 /// Test if a diff node is a decl diff that only carries a basic type
12583 /// change on its type diff sub-node.
12584 ///
12585 ///Note that that pointers/references/qualified types diffs to basic
12586 /// type diffs are considered as having basic type change only.
12587 ///
12588 /// @param d the diff node to consider.
12589 ///
12590 /// @return true iff @p d is a decl diff that only carries a basic
12591 /// type change on its type diff sub-node.
12592 bool
has_basic_type_change_only(const diff * d)12593 has_basic_type_change_only(const diff *d)
12594 {
12595   d = peel_typedef_qualified_type_or_parameter_diff(d);
12596 
12597   if (is_diff_of_basic_type(d, true) && d->has_changes())
12598     return true;
12599   else if (const var_diff * v = dynamic_cast<const var_diff*>(d))
12600     return (has_local_type_change_only(v)
12601 	    && is_diff_of_basic_type(v->type_diff().get(), true));
12602   else if (const fn_parm_diff * p = dynamic_cast<const fn_parm_diff*>(d))
12603     return (has_local_type_change_only(p)
12604 	    && is_diff_of_basic_type(p->type_diff().get(), true));
12605   else if (const function_decl_diff* f =
12606 	   dynamic_cast<const function_decl_diff*>(d))
12607     return (has_local_type_change_only(f)
12608 	    && f->type_diff()
12609 	    && is_diff_of_basic_type(f->type_diff()->return_type_diff().get(),
12610 				     true));
12611   return false;
12612 }
12613 }// end namespace comparison
12614 } // end namespace abigail
12615