• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
2 // -*- Mode: C++ -*-
3 //
4 // Copyright (C) 2013-2023 Red Hat, Inc.
5 //
6 // Author: Dodji Seketeli
7 
8 /// @file
9 ///
10 /// This contains the implementation of the comparison engine of
11 /// libabigail.
12 
13 #include <ctype.h>
14 #include <libgen.h>
15 #include <algorithm>
16 #include <sstream>
17 #include <set>
18 
19 #include "abg-comparison-priv.h"
20 #include "abg-reporter-priv.h"
21 #include "abg-tools-utils.h"
22 
23 namespace abigail
24 {
25 
26 namespace comparison
27 {
28 
29 ///
30 ///
31 ///@defgroup DiffNode Internal Representation of the comparison engine
32 /// @{
33 ///
34 /// @brief How changes are represented in libabigail's comparison engine.
35 ///
36 ///@par diff nodes
37 ///
38 /// The internal representation of the comparison engine is basically
39 /// a graph of @ref instances of @ref diff node.  We refer to these
40 /// just as <em>diff nodes</em>.  A diff node represents a change
41 /// between two ABI artifacts represented by instances of types of the
42 /// abigail::ir namespace.  These two artifacts that are being
43 /// compared are called the <em>subjects of the diff</em>.
44 ///
45 /// The types of that IR are in the abigail::comparison namespace.
46 ///
47 ///@par comparing diff nodes
48 ///
49 /// Comparing two instances of @ref diff nodes amounts to comparing
50 /// the subject of the diff.  In other words, two @ref diff nodes are
51 /// equal if and only if their subjects are equal.  Thus, two @ref
52 /// diff nodes can have different memory addresses and yet be equal.
53 ///
54 ///@par diff reporting and context
55 ///
56 /// A diff node can be serialized to an output stream to express, in
57 /// a human-readable textual form, the different changes that exist
58 /// between its two subjects.  This is done by invoking the
59 /// diff::report() method.  That reporting is controlled by several
60 /// parameters that are conceptually part of the context of the diff.
61 /// That context is materialized by an instance of the @ref
62 /// diff_context type.
63 ///
64 /// Please note that the role of the instance(s) of @ref diff_context
65 /// is boreader than just controlling the reporting of @ref diff
66 /// nodes.  Basically, a @ref diff node itself is created following
67 /// behaviours that are controlled by a particular instance of
68 /// diff_context.  A diff node is created in a particular diff
69 /// context, so to speak.
70 ///
71 /// @}
72 ///
73 
74 ///
75 ///@defgroup CanonicalDiff Canonical diff tree nodes
76 /// @{
77 ///
78 /// @brief How equivalent diff nodes are quickly spotted.
79 ///
80 /// @par Equivalence of diff nodes.
81 ///
82 /// Each @ref diff node has a property named <em>Canonical Diff
83 /// Node</em>.  If \c D is a diff node, the canonical diff node of @c
84 /// D, noted @c C(D) is a particular diff node that is equal to @c D.
85 /// Thus, a fast way to compare two @ref diff node is to perform a
86 /// pointer comparison of their canonical diff nodes.
87 ///
88 /// A set of equivalent @ref diff nodes is a set of diff nodes that
89 /// all have the same canonical node.  All the nodes of that set are
90 /// equal.
91 ///
92 /// A canonical node is registereded for a given diff node by invoking
93 /// the method diff_context::initialize_canonical_diff().
94 ///
95 /// Please note that the diff_context holds all the canonical diffs
96 /// that got registered through it.  Thus, the life time of all of
97 /// canonical diff objects is the same as the life time of the @ref
98 /// diff_context they relate to.
99 ///
100 /// @}
101 ///
102 
103 // -----------------------------------------
104 // <private functions re-usable elsewhere>
105 // -----------------------------------------
106 /// Sort a map of enumerators by their value.
107 ///
108 /// @param enumerators_map the map to sort.
109 ///
110 /// @param sorted the resulting vector of sorted enumerators.
111 void
sort_enumerators(const string_enumerator_map & enumerators_map,enum_type_decl::enumerators & sorted)112 sort_enumerators(const string_enumerator_map& enumerators_map,
113 		 enum_type_decl::enumerators& sorted)
114 {
115   for (string_enumerator_map::const_iterator i = enumerators_map.begin();
116        i != enumerators_map.end();
117        ++i)
118     sorted.push_back(i->second);
119   enumerator_value_comp comp;
120   std::sort(sorted.begin(), sorted.end(), comp);
121 }
122 
123 /// Sort a map of changed enumerators.
124 ///
125 /// @param enumerators_map the map to sort.
126 ///
127 ///@param output parameter.  The resulting sorted enumerators.
128 void
sort_changed_enumerators(const string_changed_enumerator_map & enumerators_map,changed_enumerators_type & sorted)129 sort_changed_enumerators(const string_changed_enumerator_map& enumerators_map,
130 			 changed_enumerators_type& sorted)
131 {
132   for (string_changed_enumerator_map::const_iterator i =
133 	 enumerators_map.begin();
134        i != enumerators_map.end();
135        ++i)
136     sorted.push_back(i->second);
137 
138   changed_enumerator_comp comp;
139   std::sort(sorted.begin(), sorted.end(), comp);
140 }
141 
142 /// Sort a map of data members by the offset of their initial value.
143 ///
144 /// @param data_members the map of changed data members to sort.
145 ///
146 /// @param sorted the resulting vector of sorted changed data members.
147 void
sort_data_members(const string_decl_base_sptr_map & data_members,vector<decl_base_sptr> & sorted)148 sort_data_members(const string_decl_base_sptr_map &data_members,
149 		  vector<decl_base_sptr>& sorted)
150 {
151   sorted.reserve(data_members.size());
152   for (string_decl_base_sptr_map::const_iterator i = data_members.begin();
153        i != data_members.end();
154        ++i)
155     sorted.push_back(i->second);
156 
157   data_member_comp comp;
158   std::sort(sorted.begin(), sorted.end(), comp);
159 }
160 
161 /// Sort (in place) a vector of changed data members.
162 ///
163 /// @param to_sort the vector to sort.
164 void
sort_changed_data_members(changed_var_sptrs_type & to_sort)165 sort_changed_data_members(changed_var_sptrs_type& to_sort)
166 {
167   data_member_comp comp;
168   std::sort(to_sort.begin(), to_sort.end(), comp);
169 }
170 
171 /// Sort an instance of @ref string_function_ptr_map map and stuff a
172 /// resulting sorted vector of pointers to function_decl.
173 ///
174 /// @param map the map to sort.
175 ///
176 /// @param sorted the resulting sorted vector.
177 void
sort_string_function_ptr_map(const string_function_ptr_map & map,vector<function_decl * > & sorted)178 sort_string_function_ptr_map(const string_function_ptr_map& map,
179 			     vector<function_decl*>& sorted)
180 {
181   sorted.reserve(map.size());
182   for (string_function_ptr_map::const_iterator i = map.begin();
183        i != map.end();
184        ++i)
185     sorted.push_back(i->second);
186 
187   function_comp comp;
188   std::sort(sorted.begin(), sorted.end(), comp);
189 }
190 
191 /// Sort a map that's an instance of @ref
192 /// string_member_function_sptr_map and fill a vector of member
193 /// functions with the sorted result.
194 ///
195 /// @param map the map to sort.
196 ///
197 /// @param sorted the resulting sorted vector.
198 void
sort_string_member_function_sptr_map(const string_member_function_sptr_map & map,class_or_union::member_functions & sorted)199 sort_string_member_function_sptr_map(const string_member_function_sptr_map& map,
200 				     class_or_union::member_functions& sorted)
201 {
202   sorted.reserve(map.size());
203   for (string_member_function_sptr_map::const_iterator i = map.begin();
204        i != map.end();
205        ++i)
206     sorted.push_back(i->second);
207 
208   function_comp comp;
209   std::sort(sorted.begin(), sorted.end(), comp);
210 }
211 
212 /// Sort the values of a @ref string_function_decl_diff_sptr_map map
213 /// and store the result in a vector of @ref function_decl_diff_sptr
214 /// objects.
215 ///
216 /// @param map the map whose values to store.
217 ///
218 /// @param sorted the vector of function_decl_diff_sptr to store the
219 /// result of the sort into.
220 void
sort_string_function_decl_diff_sptr_map(const string_function_decl_diff_sptr_map & map,function_decl_diff_sptrs_type & sorted)221 sort_string_function_decl_diff_sptr_map
222 (const string_function_decl_diff_sptr_map& map,
223  function_decl_diff_sptrs_type& sorted)
224 {
225   sorted.reserve(map.size());
226   for (string_function_decl_diff_sptr_map::const_iterator i = map.begin();
227        i != map.end();
228        ++i)
229     sorted.push_back(i->second);
230   function_decl_diff_comp comp;
231   std::sort(sorted.begin(), sorted.end(), comp);
232 }
233 
234 /// Sort of an instance of @ref string_var_diff_sptr_map map.
235 ///
236 /// @param map the input map to sort.
237 ///
238 /// @param sorted the ouptut sorted vector of @ref var_diff_sptr.
239 /// It's populated with the sorted content.
240 void
sort_string_var_diff_sptr_map(const string_var_diff_sptr_map & map,var_diff_sptrs_type & sorted)241 sort_string_var_diff_sptr_map(const string_var_diff_sptr_map& map,
242 			      var_diff_sptrs_type& sorted)
243 {
244   sorted.reserve(map.size());
245   for (string_var_diff_sptr_map::const_iterator i = map.begin();
246        i != map.end();
247        ++i)
248     sorted.push_back(i->second);
249 
250   var_diff_sptr_comp comp;
251   std::sort(sorted.begin(), sorted.end(), comp);
252 }
253 
254 /// Sort a map of string -> pointer to @ref elf_symbol.
255 ///
256 /// The result is a vector of @ref elf_symbol_sptr sorted by the
257 /// name of the symbol.
258 ///
259 /// @param map the map to sort.
260 ///
261 /// @param sorted out parameter; the sorted vector of @ref
262 /// elf_symbol_sptr.
263 void
sort_string_elf_symbol_map(const string_elf_symbol_map & map,vector<elf_symbol_sptr> & sorted)264 sort_string_elf_symbol_map(const string_elf_symbol_map& map,
265 			   vector<elf_symbol_sptr>& sorted)
266 {
267   for (string_elf_symbol_map::const_iterator i = map.begin();
268        i!= map.end();
269        ++i)
270     sorted.push_back(i->second);
271 
272   elf_symbol_comp comp;
273   std::sort(sorted.begin(), sorted.end(), comp);
274 }
275 
276 /// Sort a map of string -> pointer to @ref var_decl.
277 ///
278 /// The result is a vector of var_decl* sorted by the qualified name
279 /// of the variables.
280 ///
281 /// @param map the map to sort.
282 ///
283 /// @param sorted out parameter; the sorted vector of @ref var_decl.
284 void
sort_string_var_ptr_map(const string_var_ptr_map & map,vector<var_decl * > & sorted)285 sort_string_var_ptr_map(const string_var_ptr_map& map,
286 			vector<var_decl*>& sorted)
287 {
288   for (string_var_ptr_map::const_iterator i = map.begin();
289        i != map.end();
290        ++i)
291     sorted.push_back(i->second);
292 
293   var_comp comp;
294   std::sort(sorted.begin(), sorted.end(), comp);
295 }
296 
297 /// Sort the values of a string_var_diff_sptr_map and store the result
298 /// in a vector of var_diff_sptr.
299 ///
300 /// @param map the map of changed data members to sort.
301 ///
302 /// @param sorted the resulting vector of var_diff_sptr.
303 void
sort_string_data_member_diff_sptr_map(const string_var_diff_sptr_map & map,var_diff_sptrs_type & sorted)304 sort_string_data_member_diff_sptr_map(const string_var_diff_sptr_map& map,
305 				      var_diff_sptrs_type& sorted)
306 {
307   sorted.reserve(map.size());
308   for (string_var_diff_sptr_map::const_iterator i = map.begin();
309        i != map.end();
310        ++i)
311     sorted.push_back(i->second);
312   data_member_diff_comp comp;
313   std::sort(sorted.begin(), sorted.end(), comp);
314 }
315 
316 /// Sort the values of a unsigned_var_diff_sptr_map map and store the
317 /// result into a vector of var_diff_sptr.
318 ///
319 /// @param map the map of changed data members to sort.
320 ///
321 /// @param sorted the resulting vector of sorted var_diff_sptr.
322 void
sort_unsigned_data_member_diff_sptr_map(const unsigned_var_diff_sptr_map map,var_diff_sptrs_type & sorted)323 sort_unsigned_data_member_diff_sptr_map(const unsigned_var_diff_sptr_map map,
324 					var_diff_sptrs_type& sorted)
325 {
326   sorted.reserve(map.size());
327   for (unsigned_var_diff_sptr_map::const_iterator i = map.begin();
328        i != map.end();
329        ++i)
330     sorted.push_back(i->second);
331   data_member_diff_comp comp;
332   std::sort(sorted.begin(), sorted.end(), comp);
333 }
334 
335 /// Sort an map of string -> virtual member function into a vector of
336 /// virtual member functions.  The virtual member functions are sorted
337 /// by increasing order of their virtual index.
338 ///
339 /// @param map the input map.
340 ///
341 /// @param sorted the resulting sorted vector of virtual function
342 /// member.
343 void
sort_string_virtual_member_function_diff_sptr_map(const string_function_decl_diff_sptr_map & map,function_decl_diff_sptrs_type & sorted)344 sort_string_virtual_member_function_diff_sptr_map
345 (const string_function_decl_diff_sptr_map& map,
346  function_decl_diff_sptrs_type& sorted)
347 {
348   sorted.reserve(map.size());
349   for (string_function_decl_diff_sptr_map::const_iterator i = map.begin();
350        i != map.end();
351        ++i)
352     sorted.push_back(i->second);
353 
354   virtual_member_function_diff_comp comp;
355   sort(sorted.begin(), sorted.end(), comp);
356 }
357 
358 /// Sort a map ofg string -> @ref diff_sptr into a vector of @ref
359 /// diff_sptr.  The diff_sptr are sorted lexicographically wrt
360 /// qualified names of their first subjects.
361 ///
362 /// @param map the map to sort.
363 ///
364 /// @param sorted the resulting sorted vector.
365 void
sort_string_diff_sptr_map(const string_diff_sptr_map & map,diff_sptrs_type & sorted)366 sort_string_diff_sptr_map(const string_diff_sptr_map& map,
367 			  diff_sptrs_type& sorted)
368 {
369   sorted.reserve(map.size());
370   for (string_diff_sptr_map::const_iterator i = map.begin();
371        i != map.end();
372        ++i)
373     sorted.push_back(i->second);
374 
375   diff_comp comp;
376   sort(sorted.begin(), sorted.end(), comp);
377 }
378 
379 /// Sort a map ofg string -> @ref diff* into a vector of @ref
380 /// diff_ptr.  The diff_ptr are sorted lexicographically wrt
381 /// qualified names of their first subjects.
382 ///
383 /// @param map the map to sort.
384 ///
385 /// @param sorted the resulting sorted vector.
386 void
sort_string_diff_ptr_map(const string_diff_ptr_map & map,diff_ptrs_type & sorted)387 sort_string_diff_ptr_map(const string_diff_ptr_map& map,
388 			  diff_ptrs_type& sorted)
389 {
390   sorted.reserve(map.size());
391   for (string_diff_ptr_map::const_iterator i = map.begin();
392        i != map.end();
393        ++i)
394     sorted.push_back(i->second);
395 
396   diff_comp comp;
397   sort(sorted.begin(), sorted.end(), comp);
398 }
399 
400 /// Sort a map of string -> base_diff_sptr into a sorted vector of
401 /// base_diff_sptr.  The base_diff_sptr are sorted by increasing value
402 /// of their offset in their containing type.
403 ///
404 /// @param map the input map to sort.
405 ///
406 /// @param sorted the resulting sorted vector.
407 void
sort_string_base_diff_sptr_map(const string_base_diff_sptr_map & map,base_diff_sptrs_type & sorted)408 sort_string_base_diff_sptr_map(const string_base_diff_sptr_map& map,
409 			       base_diff_sptrs_type& sorted)
410 {
411   for (string_base_diff_sptr_map::const_iterator i = map.begin();
412        i != map.end();
413        ++i)
414     sorted.push_back(i->second);
415   base_diff_comp comp;
416   sort(sorted.begin(), sorted.end(), comp);
417 }
418 
419 /// Lexicographically sort base specifications found
420 /// in instances of string_base_sptr_map.
421 void
sort_string_base_sptr_map(const string_base_sptr_map & m,class_decl::base_specs & sorted)422 sort_string_base_sptr_map(const string_base_sptr_map& m,
423 			  class_decl::base_specs& sorted)
424 {
425   for (string_base_sptr_map::const_iterator i = m.begin();
426        i != m.end();
427        ++i)
428     sorted.push_back(i->second);
429 
430   base_spec_comp comp;
431   std::sort(sorted.begin(), sorted.end(), comp);
432 }
433 
434 /// Sort a map of @ref fn_parm_diff by the indexes of the function
435 /// parameters.
436 ///
437 /// @param map the map to sort.
438 ///
439 /// @param sorted the resulting sorted vector of changed function
440 /// parms.
441 void
sort_string_fn_parm_diff_sptr_map(const unsigned_fn_parm_diff_sptr_map & map,vector<fn_parm_diff_sptr> & sorted)442 sort_string_fn_parm_diff_sptr_map(const unsigned_fn_parm_diff_sptr_map& map,
443 				  vector<fn_parm_diff_sptr>&		sorted)
444 {
445   sorted.reserve(map.size());
446   for (unsigned_fn_parm_diff_sptr_map::const_iterator i = map.begin();
447        i != map.end();
448        ++i)
449     sorted.push_back(i->second);
450 
451   fn_parm_diff_comp comp;
452   std::sort(sorted.begin(), sorted.end(), comp);
453 }
454 
455 /// Sort a map of changed function parameters by the indexes of the
456 /// function parameters.
457 ///
458 /// @param map the map to sort.
459 ///
460 /// @param sorted the resulting sorted vector of instances of @ref
461 /// fn_parm_diff_sptr
462 void
sort_string_fn_parm_diff_sptr_map(const string_fn_parm_diff_sptr_map & map,vector<fn_parm_diff_sptr> & sorted)463 sort_string_fn_parm_diff_sptr_map(const string_fn_parm_diff_sptr_map&	map,
464 				  vector<fn_parm_diff_sptr>&		sorted)
465 {
466   sorted.reserve(map.size());
467   for (string_fn_parm_diff_sptr_map::const_iterator i = map.begin();
468        i != map.end();
469        ++i)
470     sorted.push_back(i->second);
471 
472   fn_parm_diff_comp comp;
473   std::sort(sorted.begin(), sorted.end(), comp);
474 }
475 
476 /// Sort a map of string -> function parameters.
477 ///
478 /// @param map the map to sort.
479 ///
480 /// @param sorted the resulting sorted vector of
481 /// @ref vector<function_decl::parameter_sptr>
482 void
sort_string_parm_map(const string_parm_map & map,vector<function_decl::parameter_sptr> & sorted)483 sort_string_parm_map(const string_parm_map& map,
484 		     vector<function_decl::parameter_sptr>& sorted)
485 {
486   for (string_parm_map::const_iterator i = map.begin();
487        i != map.end();
488        ++i)
489     sorted.push_back(i->second);
490 
491   parm_comp comp;
492   std::sort(sorted.begin(), sorted.end(), comp);
493 }
494 
495 /// Sort the set of ABI artifacts contained in a @ref
496 /// artifact_sptr_set_type.
497 ///
498 /// @param set the set of ABI artifacts to sort.
499 ///
500 /// @param output parameter the vector containing the sorted ABI
501 /// artifacts.
502 void
sort_artifacts_set(const artifact_sptr_set_type & set,vector<type_or_decl_base_sptr> & sorted)503 sort_artifacts_set(const artifact_sptr_set_type& set,
504 		   vector<type_or_decl_base_sptr>& sorted)
505 {
506 
507   for (artifact_sptr_set_type::const_iterator it = set.begin();
508        it != set.end();
509        ++it)
510     sorted.push_back(*it);
511 
512   type_or_decl_base_comp comp;
513   std::sort(sorted.begin(), sorted.end(), comp);
514 }
515 
516 /// Sort a map of string to type_base_sptr entities.
517 ///
518 /// The entries are sorted based on the lexicographic order of the
519 /// pretty representation of the type_sptr_sptr.  The sorted result is
520 /// put in a vector of type_base_sptr.
521 ///
522 /// @param map the map to sort.
523 ///
524 /// @param sorted the resulting vector of type_base_sptr
525 /// lexicographically sorted using their pretty representation.
526 void
sort_string_type_base_sptr_map(string_type_base_sptr_map & map,vector<type_base_sptr> & sorted)527 sort_string_type_base_sptr_map(string_type_base_sptr_map& map,
528 			       vector<type_base_sptr>& sorted)
529 {
530   for (string_type_base_sptr_map::const_iterator i = map.begin();
531        i != map.end();
532        ++i)
533     sorted.push_back(i->second);
534 
535   type_or_decl_base_comp comp;
536   std::sort(sorted.begin(), sorted.end(), comp);
537 }
538 
539 /// Return the first underlying type that is not a qualified type.
540 /// @param t the qualified type to consider.
541 ///
542 /// @return the first underlying type that is not a qualified type, or
543 /// NULL if t is NULL.
544 type_base_sptr
get_leaf_type(qualified_type_def_sptr t)545 get_leaf_type(qualified_type_def_sptr t)
546 {
547   if (!t)
548     return type_base_sptr();
549 
550   type_base_sptr ut = t->get_underlying_type();
551   qualified_type_def_sptr qut = dynamic_pointer_cast<qualified_type_def>(ut);
552 
553   if (!qut)
554     return ut;
555   return get_leaf_type(qut);
556 }
557 
558 /// Tests if a given diff node is to represent the changes between two
559 /// gobal decls.
560 ///
561 /// @param d the diff node to consider.
562 ///
563 /// @return true iff @p d represents the changes between two global
564 /// decls.
565 bool
is_diff_of_global_decls(const diff * d)566 is_diff_of_global_decls(const diff* d)
567 {
568   ABG_ASSERT(d != 0);
569 
570   if (d == 0)
571     return false;
572 
573   type_or_decl_base_sptr first = d->first_subject();
574   ABG_ASSERT(first);
575 
576   type_or_decl_base_sptr second = d->first_subject();
577   ABG_ASSERT(second);
578 
579   if (decl_base_sptr decl = is_decl(first))
580     if (is_at_global_scope(decl))
581       if ((decl = is_decl(second)))
582 	if (is_at_global_scope(decl))
583 	  return true;
584 
585   return false;
586 }
587 
588 // -----------------------------------------
589 // </private functions re-usable elsewhere>
590 // -----------------------------------------
591 
592 /// The overloaded or operator for @ref visiting_kind.
593 visiting_kind
operator |(visiting_kind l,visiting_kind r)594 operator|(visiting_kind l, visiting_kind r)
595 {return static_cast<visiting_kind>(static_cast<unsigned>(l)
596 				   | static_cast<unsigned>(r));}
597 
598 /// The overloaded and operator for @ref visiting_kind.
599 visiting_kind
operator &(visiting_kind l,visiting_kind r)600 operator&(visiting_kind l, visiting_kind r)
601 {
602   return static_cast<visiting_kind>(static_cast<unsigned>(l)
603 				    & static_cast<unsigned>(r));
604 }
605 
606 /// The overloaded 'bit inversion' operator for @ref visiting_kind.
607 visiting_kind
operator ~(visiting_kind l)608 operator~(visiting_kind l)
609 {return static_cast<visiting_kind>(~static_cast<unsigned>(l));}
610 
611 /// Test if a diff node is about differences between types.
612 ///
613 /// @param diff the diff node to test.
614 ///
615 /// @return a pointer to the actual type_diff_base* that @p diff
616 /// extends, iff it is about differences between types.
617 const type_diff_base*
is_type_diff(const diff * diff)618 is_type_diff(const diff* diff)
619 {return dynamic_cast<const type_diff_base*>(diff);}
620 
621 /// Test if a diff node is about differences between declarations.
622 ///
623 /// @param diff the diff node to test.
624 ///
625 /// @return a pointer to the actual decl_diff_base @p diff extends,
626 /// iff it is about differences between declarations.
627 const decl_diff_base*
is_decl_diff(const diff * diff)628 is_decl_diff(const diff* diff)
629 {return dynamic_cast<const decl_diff_base*>(diff);}
630 
631 /// Test if a diff node is a @ref class_diff node.
632 ///
633 /// @param diff the diff node to consider.
634 ///
635 /// @return a non-nil pointer to a @ref class_diff iff @p diff is a
636 /// @ref class_diff node.
637 const class_diff*
is_class_diff(const diff * diff)638 is_class_diff(const diff* diff)
639 {return dynamic_cast<const class_diff*>(diff);}
640 
641 /// Test if a diff node is a @ref enum_diff node.
642 ///
643 /// @param diff the diff node to consider.
644 ///
645 /// @return a non-nil pointer to ad @ref enum_diff node iff @p diff is
646 /// a @ref enum_diff node.
647 const enum_diff*
is_enum_diff(const diff * diff)648 is_enum_diff(const diff *diff)
649 {return dynamic_cast<const enum_diff*>(diff);}
650 
651 /// Test if a diff node is a @ref union_diff node.
652 ///
653 /// @param diff the diff node to consider.
654 ///
655 /// @return a non-nil pointer to a @ref union_diff iff @p diff is a
656 /// @ref union_diff node.
657 const union_diff*
is_union_diff(const diff * diff)658 is_union_diff(const diff* diff)
659 {return dynamic_cast<const union_diff*>(diff);}
660 
661 /// Test if a diff node is a @ref class_or_union_diff node.
662 ///
663 /// @param d the diff node to consider.
664 ///
665 /// @return a non-nil pointer to the @ref class_or_union_diff denoted
666 /// by @p d iff @p d is a @ref class_or_union_diff.
667 const class_or_union_diff*
is_class_or_union_diff(const diff * d)668 is_class_or_union_diff(const diff* d)
669 {return dynamic_cast<const class_or_union_diff*>(d);}
670 
671 /// Test if a diff node is a @ref class_or_union_diff between two
672 /// anonymous classes or unions.
673 ///
674 /// @param d the diff node to consider.
675 ///
676 /// @return a non-nil pointer to the @ref class_or_union_diff iff @p
677 /// denoted by @p d iff @p is pointer to an anonymous class or union
678 /// diff.
679 const class_or_union_diff*
is_anonymous_class_or_union_diff(const diff * d)680 is_anonymous_class_or_union_diff(const diff* d)
681 {
682   if (const class_or_union_diff *dif = is_class_or_union_diff(d))
683     if (dif->first_class_or_union()->get_is_anonymous())
684       return dif;
685   return 0;
686 }
687 
688 /// Test if a diff node is a @ref typedef_diff node.
689 ///
690 /// @param diff the diff node to consider.
691 ///
692 /// @return a non-nil pointer to a @ref typedef_diff iff @p diff is a
693 /// @ref typedef_diff node.
694 const typedef_diff*
is_typedef_diff(const diff * diff)695 is_typedef_diff(const diff *diff)
696 {return dynamic_cast<const typedef_diff*>(diff);}
697 
698 /// Test if a diff node is a @ref subrange_diff node.
699 ///
700 /// @param diff the diff node to consider.
701 ///
702 /// @return a non-nil pointer to a @ref subrange_diff iff @p diff is a
703 /// @ref subrange_diff node.
704 const subrange_diff*
is_subrange_diff(const diff * diff)705 is_subrange_diff(const diff* diff)
706 {return dynamic_cast<const subrange_diff*>(diff);}
707 
708 /// Test if a diff node is a @ref array_diff node.
709 ///
710 /// @param diff the diff node to consider.
711 ///
712 /// @return a non-nil pointer to a @ref array_diff iff @p diff is a
713 /// @ref array_diff node.
714 const array_diff*
is_array_diff(const diff * diff)715 is_array_diff(const diff* diff)
716 {return dynamic_cast<const array_diff*>(diff);}
717 
718 /// Test if a diff node is a @ref function_type_diff node.
719 ///
720 /// @param diff the diff node to consider.
721 ///
722 /// @return a non-nil pointer to a @ref function_type_diff iff @p diff is a
723 /// @ref function_type_diff node.
724 const function_type_diff*
is_function_type_diff(const diff * diff)725 is_function_type_diff(const diff* diff)
726 {return dynamic_cast<const function_type_diff*>(diff);}
727 
728 /// Test if a given diff node carries a function type change with
729 /// local changes.
730 ///
731 /// @param diff the diff node to consider.
732 ///
733 /// @return a non-nil pointer to a @ref function_type_diff iff @p diff
734 /// is a function_type_diff node that carries a local change.
735 const function_type_diff*
is_function_type_diff_with_local_changes(const diff * diff)736 is_function_type_diff_with_local_changes(const diff* diff)
737 {
738   if (const function_type_diff* d = is_function_type_diff(diff))
739     if (d->has_local_changes())
740       return d;
741 
742   return 0;
743 }
744 
745 /// Test if a diff node is about differences between variables.
746 ///
747 /// @param diff the diff node to test.
748 ///
749 /// @return a pointer to the actual var_diff that @p diff is a type
750 /// of, iff it is about differences between variables.
751 const var_diff*
is_var_diff(const diff * diff)752 is_var_diff(const diff* diff)
753 {
754   const var_diff* d = dynamic_cast<const var_diff*>(diff);
755   if (d)
756     ABG_ASSERT(is_decl_diff(diff));
757   return d;
758 }
759 
760 /// Test if a diff node is about differences between functions.
761 ///
762 /// @param diff the diff node to test.
763 ///
764 /// @return a pointer to the actual var_diff that @p diff is a type
765 /// of, iff it is about differences between variables.
766 const function_decl_diff*
is_function_decl_diff(const diff * diff)767 is_function_decl_diff(const diff* diff)
768 {
769   const function_decl_diff *d = dynamic_cast<const function_decl_diff*>(diff);
770   if (d)
771     ABG_ASSERT(is_decl_diff(diff));
772   return d;
773 }
774 
775 /// Test if a diff node is about differences between two pointers.
776 ///
777 /// @param diff the diff node to consider.
778 ///
779 /// @return the @p diff converted into an instance of @ref
780 /// pointer_diff iff @p diff is about differences between two
781 /// pointers.
782 const pointer_diff*
is_pointer_diff(const diff * diff)783 is_pointer_diff(const diff* diff)
784 {return dynamic_cast<const pointer_diff*>(diff);}
785 
786 /// Test if a diff node is about differences between two references.
787 ///
788 /// @param diff the diff node to consider.
789 ///
790 /// @return the @p diff converted into an instance of @ref
791 /// reference_diff iff @p diff is about differences between two
792 /// references.
793 const reference_diff*
is_reference_diff(const diff * diff)794 is_reference_diff(const diff* diff)
795 {return dynamic_cast<const reference_diff*>(diff);}
796 
797 /// Test if a diff node is about differences between two qualified
798 /// types.
799 ///
800 /// @param diff the diff node to consider.
801 ///
802 /// @return @p diff converted into an instance of @ref
803 /// qualified_type_diff iff @p diff is about differences between two
804 /// qualified types.
805 const qualified_type_diff*
is_qualified_type_diff(const diff * diff)806 is_qualified_type_diff(const diff* diff)
807 {return dynamic_cast<const qualified_type_diff*>(diff);}
808 
809 /// Test if a diff node is a reference or pointer diff node to a
810 /// change that is neither basic type change nor distinct type change.
811 ///
812 /// Note that this function also works on diffs of typedefs of
813 /// reference or pointer.
814 ///
815 /// @param diff the diff node to consider.
816 ///
817 /// @return true iff @p diff is a eference or pointer diff node to a
818 /// change that is neither basic type change nor distinct type change.
819 bool
is_reference_or_ptr_diff_to_non_basic_nor_distinct_types(const diff * diff)820 is_reference_or_ptr_diff_to_non_basic_nor_distinct_types(const diff* diff)
821 {
822   diff = peel_typedef_diff(diff);
823   if (const reference_diff* d = is_reference_diff(diff))
824     {
825       diff = peel_reference_diff(d);
826       if (is_diff_of_basic_type(diff) || is_distinct_diff(diff))
827 	return false;
828       return true;
829     }
830   else if (const pointer_diff *d = is_pointer_diff(diff))
831     {
832       diff = peel_pointer_diff(d);
833       if (is_diff_of_basic_type(diff) || is_distinct_diff(diff))
834 	return false;
835       return true;
836     }
837 
838   return false;
839 }
840 
841 /// Test if a diff node is about differences between two function
842 /// parameters.
843 ///
844 /// @param diff the diff node to consider.
845 ///
846 /// @return the @p diff converted into an instance of @ref
847 /// reference_diff iff @p diff is about differences between two
848 /// function parameters.
849 const fn_parm_diff*
is_fn_parm_diff(const diff * diff)850 is_fn_parm_diff(const diff* diff)
851 {return dynamic_cast<const fn_parm_diff*>(diff);}
852 
853 /// Test if a diff node is about differences between two base class
854 /// specifiers.
855 ///
856 /// @param diff the diff node to consider.
857 ///
858 /// @return the @p diff converted into an instance of @ref base_diff
859 /// iff @p diff is about differences between two base class
860 /// specifiers.
861 const base_diff*
is_base_diff(const diff * diff)862 is_base_diff(const diff* diff)
863 {return dynamic_cast<const base_diff*>(diff);}
864 
865 /// Test if a diff node is about differences between two diff nodes of
866 /// different kinds.
867 ///
868 /// @param diff the diff node to consider.
869 ///
870 /// @return the @p diff converted into an instance of @ref
871 /// distintc_diff iff @p diff is about differences between two diff
872 /// nodes of different kinds.
873 const distinct_diff*
is_distinct_diff(const diff * diff)874 is_distinct_diff(const diff *diff)
875 {return dynamic_cast<const distinct_diff*>(diff);}
876 
877 /// Test if a diff node is a @ref corpus_diff node.
878 ///
879 /// @param diff the diff node to consider.
880 ///
881 /// @return a non-nil pointer to a @ref corpus_diff iff @p diff is a
882 /// @ref corpus_diff node.
883 const corpus_diff*
is_corpus_diff(const diff * diff)884 is_corpus_diff(const diff* diff)
885 {return dynamic_cast<const corpus_diff*>(diff);}
886 
887 /// Test if a diff node is a child node of a function parameter diff node.
888 ///
889 /// @param diff the diff node to test.
890 ///
891 /// @return true iff @p diff is a child node of a function parameter
892 /// diff node.
893 bool
is_child_node_of_function_parm_diff(const diff * diff)894 is_child_node_of_function_parm_diff(const diff* diff)
895 {return diff && is_fn_parm_diff(diff->parent_node());}
896 
897 /// Test if a diff node is a child node of a base diff node.
898 ///
899 /// @param diff the diff node to test.
900 ///
901 /// @return true iff @p diff is a child node of a base diff node.
902 bool
is_child_node_of_base_diff(const diff * diff)903 is_child_node_of_base_diff(const diff* diff)
904 {return diff && is_base_diff(diff->parent_node());}
905 
906 /// The default traverse function.
907 ///
908 /// @return true.
909 bool
traverse(diff_node_visitor &)910 diff_traversable_base::traverse(diff_node_visitor&)
911 {return true;}
912 
diff_context()913 diff_context::diff_context()
914   : priv_(new diff_context::priv)
915 {
916   // Setup all the diff output filters we have.
917   filtering::filter_base_sptr f;
918 
919   f.reset(new filtering::harmless_harmful_filter);
920   add_diff_filter(f);
921 
922   // f.reset(new filtering::harmless_filter);
923   // add_diff_filter(f);
924 
925   // f.reset(new filtering::harmful_filter);
926   // add_diff_filter(f);
927 }
928 
929 diff_context::~diff_context() = default;
930 
931 /// Test if logging was requested.
932 ///
933 /// @return true iff logging was requested.
934 bool
do_log() const935 diff_context::do_log() const
936 {return priv_->do_log_;}
937 
938 /// Set logging as requested.
939 ///
940 /// @param f the flag
941 void
do_log(bool f)942 diff_context::do_log(bool f)
943 {priv_->do_log_ = f;}
944 
945 /// Set the corpus diff relevant to this context.
946 ///
947 /// @param d the corpus_diff we are interested in.
948 void
set_corpus_diff(const corpus_diff_sptr & d)949 diff_context::set_corpus_diff(const corpus_diff_sptr& d)
950 {priv_->corpus_diff_ = d;}
951 
952 /// Get the corpus diff for the current context.
953 ///
954 /// @return the corpus diff of this context.
955 const corpus_diff_sptr&
get_corpus_diff() const956 diff_context::get_corpus_diff() const
957 {return priv_->corpus_diff_;}
958 
959 /// Getter for the first corpus of the corpus diff of the current context.
960 ///
961 /// @return the first corpus of the corpus diff of the current
962 /// context, if no corpus diff is associated to the context.
963 corpus_sptr
get_first_corpus() const964 diff_context::get_first_corpus() const
965 {
966   if (priv_->corpus_diff_)
967     return priv_->corpus_diff_->first_corpus();
968   return corpus_sptr();
969 }
970 
971 /// Getter for the second corpus of the corpus diff of the current
972 /// context.
973 ///
974 /// @return the second corpus of the corpus diff of the current
975 /// context, if no corpus diff is associated to the context.
976 corpus_sptr
get_second_corpus() const977 diff_context::get_second_corpus() const
978 {
979   if (priv_->corpus_diff_)
980     return priv_->corpus_diff_->second_corpus();
981   return corpus_sptr();
982 }
983 
984 /// Getter of the reporter to be used in this context.
985 ///
986 /// @return the reporter to be used in this context.
987 reporter_base_sptr
get_reporter() const988 diff_context::get_reporter() const
989 {
990   if (!priv_->reporter_)
991     {
992       if (show_leaf_changes_only())
993 	priv_->reporter_.reset(new leaf_reporter);
994       else
995 	priv_->reporter_.reset(new default_reporter);
996     }
997   ABG_ASSERT(priv_->reporter_);
998   return priv_->reporter_;
999 }
1000 
1001 /// Setter of the reporter to be used in this context.
1002 ///
1003 /// @param r the reporter to be used in this context.
1004 void
set_reporter(reporter_base_sptr & r)1005 diff_context::set_reporter(reporter_base_sptr& r)
1006 {priv_->reporter_ = r;}
1007 
1008 /// Tests if the current diff context already has a diff for two decls.
1009 ///
1010 /// @param first the first decl to consider.
1011 ///
1012 /// @param second the second decl to consider.
1013 ///
1014 /// @return a pointer to the diff for @p first @p second if found,
1015 /// null otherwise.
1016 diff_sptr
has_diff_for(const type_or_decl_base_sptr first,const type_or_decl_base_sptr second) const1017 diff_context::has_diff_for(const type_or_decl_base_sptr first,
1018 			   const type_or_decl_base_sptr second) const
1019 {
1020   types_or_decls_diff_map_type::const_iterator i =
1021     priv_->types_or_decls_diff_map.find(std::make_pair(first, second));
1022   if (i != priv_->types_or_decls_diff_map.end())
1023     return i->second;
1024   return diff_sptr();
1025 }
1026 
1027 /// Tests if the current diff context already has a diff for two types.
1028 ///
1029 /// @param first the first type to consider.
1030 ///
1031 /// @param second the second type to consider.
1032 ///
1033 /// @return a pointer to the diff for @p first @p second if found,
1034 /// null otherwise.
1035 diff_sptr
has_diff_for_types(const type_base_sptr first,const type_base_sptr second) const1036 diff_context::has_diff_for_types(const type_base_sptr first,
1037 				  const type_base_sptr second) const
1038 {return has_diff_for(first, second);}
1039 
1040 /// Tests if the current diff context already has a given diff.
1041 ///
1042 ///@param d the diff to consider.
1043 ///
1044 /// @return a pointer to the diff found for @p d
1045 const diff*
has_diff_for(const diff * d) const1046 diff_context::has_diff_for(const diff* d) const
1047 {return has_diff_for(d->first_subject(), d->second_subject()).get();}
1048 
1049 /// Tests if the current diff context already has a given diff.
1050 ///
1051 ///@param d the diff to consider.
1052 ///
1053 /// @return a pointer to the diff found for @p d
1054 diff_sptr
has_diff_for(const diff_sptr d) const1055 diff_context::has_diff_for(const diff_sptr d) const
1056 {return has_diff_for(d->first_subject(), d->second_subject());}
1057 
1058 /// Getter for the bitmap that represents the set of categories that
1059 /// the user wants to see reported.
1060 ///
1061 /// @return a bitmap that represents the set of categories that the
1062 /// user wants to see reported.
1063 diff_category
get_allowed_category() const1064 diff_context::get_allowed_category() const
1065 {return priv_->allowed_category_;}
1066 
1067 /// Setter for the bitmap that represents the set of categories that
1068 /// the user wants to see reported.
1069 ///
1070 /// @param c a bitmap that represents the set of categories that the
1071 /// user wants to see represented.
1072 void
set_allowed_category(diff_category c)1073 diff_context::set_allowed_category(diff_category c)
1074 {priv_->allowed_category_ = c;}
1075 
1076 /// Setter for the bitmap that represents the set of categories that
1077 /// the user wants to see reported
1078 ///
1079 /// This function perform a bitwise or between the new set of
1080 /// categories and the current ones, and then sets the current
1081 /// categories to the result of the or.
1082 ///
1083 /// @param c a bitmap that represents the set of categories that the
1084 /// user wants to see represented.
1085 void
switch_categories_on(diff_category c)1086 diff_context::switch_categories_on(diff_category c)
1087 {priv_->allowed_category_ = priv_->allowed_category_ | c;}
1088 
1089 /// Setter for the bitmap that represents the set of categories that
1090 /// the user wants to see reported
1091 ///
1092 /// This function actually unsets bits from the current categories.
1093 ///
1094 /// @param c a bitmap that represents the set of categories to unset
1095 /// from the current categories.
1096 void
switch_categories_off(diff_category c)1097 diff_context::switch_categories_off(diff_category c)
1098 {priv_->allowed_category_ = priv_->allowed_category_ & ~c;}
1099 
1100 /// Add a diff for two decls to the cache of the current diff_context.
1101 ///
1102 /// Doing this allows to later find the added diff from its two
1103 /// subject decls.
1104 ///
1105 /// @param first the first decl to consider.
1106 ///
1107 /// @param second the second decl to consider.
1108 ///
1109 /// @param the diff to add.
1110 void
add_diff(type_or_decl_base_sptr first,type_or_decl_base_sptr second,const diff_sptr d)1111 diff_context::add_diff(type_or_decl_base_sptr first,
1112 		       type_or_decl_base_sptr second,
1113 		       const diff_sptr d)
1114 {priv_->types_or_decls_diff_map[std::make_pair(first, second)] = d;}
1115 
1116 /// Add a diff tree node to the cache of the current diff_context
1117 ///
1118 /// @param d the diff tree node to add.
1119 void
add_diff(const diff * d)1120 diff_context::add_diff(const diff* d)
1121 {
1122   if (d)
1123     {
1124       diff_sptr dif(const_cast<diff*>(d), noop_deleter());
1125       add_diff(d->first_subject(), d->second_subject(), dif);
1126     }
1127 }
1128 
1129 /// Add a diff tree node to the cache of the current diff_context
1130 ///
1131 /// @param d the diff tree node to add.
1132 void
add_diff(const diff_sptr d)1133 diff_context::add_diff(const diff_sptr d)
1134 {
1135   if (d)
1136       add_diff(d->first_subject(), d->second_subject(), d);
1137 }
1138 
1139 /// Getter for the @ref CanonicalDiff "canonical diff node" for the
1140 /// @ref diff represented by their two subjects.
1141 ///
1142 /// @param first the first subject of the diff.
1143 ///
1144 /// @param second the second subject of the diff.
1145 ///
1146 /// @return the canonical diff for the diff node represented by the
1147 /// two diff subjects @p first and @p second.  If no canonical diff
1148 /// node was registered for these subjects, then a nil node is
1149 /// returned.
1150 diff_sptr
get_canonical_diff_for(const type_or_decl_base_sptr first,const type_or_decl_base_sptr second) const1151 diff_context::get_canonical_diff_for(const type_or_decl_base_sptr first,
1152 				     const type_or_decl_base_sptr second) const
1153 {return has_diff_for(first, second);}
1154 
1155 /// Getter for the @ref CanonicalDiff "canonical diff node" for the
1156 /// @ref diff represented by the two subjects of a given diff node.
1157 ///
1158 /// @param d the diff node to get the canonical node for.
1159 ///
1160 /// @return the canonical diff for the diff node represented by the
1161 /// two diff subjects of @p d.  If no canonical diff node was
1162 /// registered for these subjects, then a nil node is returned.
1163 diff_sptr
get_canonical_diff_for(const diff_sptr d) const1164 diff_context::get_canonical_diff_for(const diff_sptr d) const
1165 {return has_diff_for(d);}
1166 
1167 /// Setter for the @ref CanonicalDiff "canonical diff node" for the
1168 /// @ref diff represented by their two subjects.
1169 ///
1170 /// @param first the first subject of the diff.
1171 ///
1172 /// @param second the second subject of the diff.
1173 ///
1174 /// @param d the new canonical diff.
1175 void
set_canonical_diff_for(const type_or_decl_base_sptr first,const type_or_decl_base_sptr second,const diff_sptr d)1176 diff_context::set_canonical_diff_for(const type_or_decl_base_sptr first,
1177 				     const type_or_decl_base_sptr second,
1178 				     const diff_sptr d)
1179 {
1180   ABG_ASSERT(d);
1181   if (!has_diff_for(first, second))
1182     {
1183       add_diff(first, second, d);
1184       priv_->canonical_diffs.push_back(d);
1185     }
1186 }
1187 
1188 /// If there is is a @ref CanonicalDiff "canonical diff node"
1189 /// registered for two diff subjects, return it.  Otherwise, register
1190 /// a canonical diff node for these two diff subjects and return it.
1191 ///
1192 /// @param first the first subject of the diff.
1193 ///
1194 /// @param second the second subject of the diff.
1195 ///
1196 /// @param d the new canonical diff node.
1197 ///
1198 /// @return the canonical diff node.
1199 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)1200 diff_context::set_or_get_canonical_diff_for(const type_or_decl_base_sptr first,
1201 					    const type_or_decl_base_sptr second,
1202 					    const diff_sptr canonical_diff)
1203 {
1204   ABG_ASSERT(canonical_diff);
1205 
1206   diff_sptr canonical = get_canonical_diff_for(first, second);
1207   if (!canonical)
1208     {
1209       canonical = canonical_diff;
1210       set_canonical_diff_for(first, second, canonical);
1211     }
1212   return canonical;
1213 }
1214 
1215 /// Set the canonical diff node property of a given diff node
1216 /// appropriately.
1217 ///
1218 /// For a given diff node that has no canonical diff node, retrieve
1219 /// the canonical diff node (by looking at its diff subjects and at
1220 /// the current context) and set the canonical diff node property of
1221 /// the diff node to that canonical diff node.  If no canonical diff
1222 /// node has been registered to the diff context for the subjects of
1223 /// the diff node then, register the canonical diff node as being the
1224 /// diff node itself; and set its canonical diff node property as
1225 /// such.  Otherwise, if the diff node already has a canonical diff
1226 /// node, do nothing.
1227 ///
1228 /// @param diff the diff node to initialize the canonical diff node
1229 /// property for.
1230 void
initialize_canonical_diff(const diff_sptr diff)1231 diff_context::initialize_canonical_diff(const diff_sptr diff)
1232 {
1233   if (diff->get_canonical_diff() == 0)
1234     {
1235       diff_sptr canonical =
1236 	set_or_get_canonical_diff_for(diff->first_subject(),
1237 				      diff->second_subject(),
1238 				      diff);
1239       diff->set_canonical_diff(canonical.get());
1240     }
1241 }
1242 
1243 /// Add a diff node to the set of diff nodes that are kept alive for
1244 /// the life time of the current instance of diff_context.
1245 ///
1246 /// Note that diff added to the diff cache are kept alive as well, and
1247 /// don't need to be passed to this function to be kept alive.
1248 ///
1249 /// @param d the diff node to be kept alive during the life time of
1250 /// the current instance of @ref diff_context.
1251 void
keep_diff_alive(diff_sptr & d)1252 diff_context::keep_diff_alive(diff_sptr& d)
1253 {priv_->live_diffs_.insert(d);}
1254 
1255 /// Test if a diff node has been traversed.
1256 ///
1257 /// @param d the diff node to consider.
1258 ///
1259 /// @return the first diff node against which @p d is redundant.
1260 diff*
diff_has_been_visited(const diff * d) const1261 diff_context::diff_has_been_visited(const diff* d) const
1262 {
1263   const diff* canonical = d->get_canonical_diff();
1264   ABG_ASSERT(canonical);
1265 
1266   size_t ptr_value = reinterpret_cast<size_t>(canonical);
1267   pointer_map::iterator it = priv_->visited_diff_nodes_.find(ptr_value);
1268   if (it != priv_->visited_diff_nodes_.end())
1269     return reinterpret_cast<diff*>(it->second);
1270   else
1271     return 0;
1272 }
1273 
1274 /// Test if a diff node has been traversed.
1275 ///
1276 /// @param d the diff node to consider.
1277 ///
1278 /// @return the first diff node against which @p d is redundant.
1279 diff_sptr
diff_has_been_visited(const diff_sptr d) const1280 diff_context::diff_has_been_visited(const diff_sptr d) const
1281 {
1282   diff_sptr diff(diff_has_been_visited(d.get()));
1283   return diff;
1284 }
1285 
1286 /// Mark a diff node as traversed by a traversing algorithm.
1287 ///
1288 /// Actually, it's the @ref CanonicalDiff "canonical diff" of this
1289 /// node that is marked as traversed.
1290 ///
1291 /// Subsequent invocations of diff_has_been_visited() on the diff node
1292 /// will yield true.
1293 void
mark_diff_as_visited(const diff * d)1294 diff_context::mark_diff_as_visited(const diff* d)
1295 {
1296   if (diff_has_been_visited(d))
1297     return;
1298 
1299   const diff* canonical = d->get_canonical_diff();
1300   ABG_ASSERT(canonical);
1301 
1302    size_t canonical_ptr_value = reinterpret_cast<size_t>(canonical);
1303    size_t diff_ptr_value = reinterpret_cast<size_t>(d);
1304    priv_->visited_diff_nodes_[canonical_ptr_value] = diff_ptr_value;
1305 }
1306 
1307 /// Unmark all the diff nodes that were marked as being traversed.
1308 void
forget_visited_diffs()1309 diff_context::forget_visited_diffs()
1310 {priv_->visited_diff_nodes_.clear();}
1311 
1312 /// This sets a flag that, if it's true, then during the traversing of
1313 /// a diff nodes tree each node is visited at most once.
1314 ///
1315 /// @param f if true then during the traversing of a diff nodes tree
1316 /// each node is visited at most once.
1317 ///
1318 void
forbid_visiting_a_node_twice(bool f)1319 diff_context::forbid_visiting_a_node_twice(bool f)
1320 {priv_->forbid_visiting_a_node_twice_ = f;}
1321 
1322 /// This function sets a flag os that if @ref
1323 ///  forbid_visiting_a_node_twice() returns true, then each time the
1324 ///  node visitor starts visiting a new interface, it resets the
1325 ///  memory the systems has about already visited node.
1326 ///
1327 ///  @param f the flag to set.
1328 void
forbid_visiting_a_node_twice_per_interface(bool f)1329 diff_context::forbid_visiting_a_node_twice_per_interface(bool f)
1330 {priv_->reset_visited_diffs_for_each_interface_ = f;}
1331 
1332 /// Return a flag that, if true, then during the traversing of a diff
1333 /// nodes tree each node is visited at most once.
1334 ///
1335 /// @return the boolean flag.
1336 bool
visiting_a_node_twice_is_forbidden() const1337 diff_context::visiting_a_node_twice_is_forbidden() const
1338 {return priv_->forbid_visiting_a_node_twice_;}
1339 
1340 /// Return a flag that, if true, then during the traversing of a diff
1341 /// nodes tree each node is visited at most once, while visiting the
1342 /// diff tree underneath a given interface (public function or
1343 /// variable).  Each time a new interface is visited, the nodes
1344 /// visited while visiting previous interfaces can be visited again.
1345 ///
1346 /// @return the boolean flag.
1347 ///
1348 /// @return the boolean flag.
1349 bool
visiting_a_node_twice_is_forbidden_per_interface() const1350 diff_context::visiting_a_node_twice_is_forbidden_per_interface() const
1351 {
1352   return (priv_->forbid_visiting_a_node_twice_
1353 	  && priv_->reset_visited_diffs_for_each_interface_);
1354 }
1355 
1356 /// Getter for the diff tree nodes filters to apply to diff sub-trees.
1357 ///
1358 /// @return the vector of tree filters to apply to diff sub-trees.
1359 const filtering::filters&
diff_filters() const1360 diff_context::diff_filters() const
1361 {return priv_->filters_;}
1362 
1363 /// Setter for the diff filters to apply to a given diff sub-tree.
1364 ///
1365 /// @param f the new diff filter to add to the vector of diff filters
1366 /// to apply to diff sub-trees.
1367 void
add_diff_filter(filtering::filter_base_sptr f)1368 diff_context::add_diff_filter(filtering::filter_base_sptr f)
1369 {priv_->filters_.push_back(f);}
1370 
1371 /// Apply the diff filters to a given diff sub-tree.
1372 ///
1373 /// If the current context is instructed to filter out some categories
1374 /// then this function walks the given sub-tree and categorizes its
1375 /// nodes by using the filters held by the context.
1376 ///
1377 /// @param diff the diff sub-tree to apply the filters to.
1378 void
maybe_apply_filters(diff_sptr diff)1379 diff_context::maybe_apply_filters(diff_sptr diff)
1380 {
1381   if (!diff)
1382     return;
1383 
1384   if (!diff->has_changes())
1385     return;
1386 
1387   for (filtering::filters::const_iterator i = diff_filters().begin();
1388        i != diff_filters().end();
1389        ++i)
1390     {
1391       tools_utils::timer t;
1392       if (do_log())
1393 	{
1394 	  std::cerr << "applying a filter to diff '"
1395 		    << diff->get_pretty_representation()
1396 		    << "'...\n";
1397 	  t.start();
1398 	}
1399 
1400       filtering::apply_filter(*i, diff);
1401 
1402       if (do_log())
1403 	{
1404 	  t.stop();
1405 	  std::cerr << "filter applied!:" << t << "\n";
1406 
1407 	  std::cerr << "propagating categories for the same diff node ... \n";
1408 	  t.start();
1409 	}
1410 
1411       propagate_categories(diff);
1412 
1413       if (do_log())
1414 	{
1415 	  t.stop();
1416 	  std::cerr << "category propagated!: " << t << "\n";
1417 	}
1418     }
1419 
1420  }
1421 
1422 /// Apply the diff filters to the diff nodes of a @ref corpus_diff
1423 /// instance.
1424 ///
1425 /// If the current context is instructed to filter out some categories
1426 /// then this function walks the diff tree and categorizes its nodes
1427 /// by using the filters held by the context.
1428 ///
1429 /// @param diff the corpus diff to apply the filters to.
1430 void
maybe_apply_filters(corpus_diff_sptr diff)1431 diff_context::maybe_apply_filters(corpus_diff_sptr diff)
1432 {
1433 
1434   if (!diff || !diff->has_changes())
1435     return;
1436 
1437   for (filtering::filters::const_iterator i = diff_filters().begin();
1438        i != diff_filters().end();
1439        ++i)
1440     {
1441       filtering::apply_filter(**i, diff);
1442       propagate_categories(diff);
1443     }
1444 }
1445 
1446 /// Getter for the vector of suppressions that specify which diff node
1447 /// reports should be dropped on the floor.
1448 ///
1449 /// @return the set of suppressions.
1450 const suppressions_type&
suppressions() const1451 diff_context::suppressions() const
1452 {return priv_->suppressions_;}
1453 
1454 /// Getter for the vector of suppressions that specify which diff node
1455 /// reports should be dropped on the floor.
1456 ///
1457 /// @return the set of suppressions.
1458 suppr::suppressions_type&
suppressions()1459 diff_context::suppressions()
1460 {
1461   // Invalidate negated and direct suppressions caches that are built
1462   // from priv_->suppressions_;
1463   priv_->negated_suppressions_.clear();
1464   priv_->direct_suppressions_.clear();
1465   return priv_->suppressions_;
1466 }
1467 
1468 /// Getter of the negated suppression specifications that are
1469 /// comprised in the general vector of suppression specifications
1470 /// returned by diff_context::suppressions().
1471 ///
1472 /// Note that the first invocation of this function scans the vector
1473 /// returned by diff_context::suppressions() and caches the negated
1474 /// suppressions from there.
1475 ///
1476 /// Subsequent invocations of this function just return the cached
1477 /// negated suppressions.
1478 ///
1479 /// @return the negated suppression specifications stored in this diff
1480 /// context.
1481 const suppr::suppressions_type&
negated_suppressions() const1482 diff_context::negated_suppressions() const
1483 {
1484   if (priv_->negated_suppressions_.empty())
1485     for (auto s : suppressions())
1486       if (is_negated_suppression(s))
1487 	priv_->negated_suppressions_.push_back(s);
1488 
1489   return priv_->negated_suppressions_;
1490 }
1491 
1492 /// Getter of the direct suppression specification (those that are
1493 /// not negated) comprised in the general vector of suppression
1494 /// specifications returned by diff_context::suppression().
1495 ///
1496 /// Note that the first invocation of this function scans the vector
1497 /// returned by diff_context::suppressions() and caches the direct
1498 /// suppressions from there.
1499 ///
1500 /// Subsequent invocations of this function just return the cached
1501 /// direct suppressions.
1502 ///
1503 /// @return the direct suppression specifications.
1504 const suppr::suppressions_type&
direct_suppressions() const1505 diff_context::direct_suppressions() const
1506 {
1507    if (priv_->direct_suppressions_.empty())
1508     {
1509       for (auto s : suppressions())
1510 	if (!is_negated_suppression(s))
1511 	  priv_->direct_suppressions_.push_back(s);
1512     }
1513    return priv_->direct_suppressions_;
1514 }
1515 
1516 /// Add a new suppression specification that specifies which diff node
1517 /// reports should be dropped on the floor.
1518 ///
1519 /// @param suppr the new suppression specification to add to the
1520 /// existing set of suppressions specifications of the diff context.
1521 void
add_suppression(const suppression_sptr suppr)1522 diff_context::add_suppression(const suppression_sptr suppr)
1523 {
1524   priv_->suppressions_.push_back(suppr);
1525   // Invalidate negated and direct suppressions caches that are built
1526   // from priv_->suppressions_;
1527   priv_->negated_suppressions_.clear();
1528   priv_->direct_suppressions_.clear();
1529 }
1530 
1531 /// Add new suppression specifications that specify which diff node
1532 /// reports should be dropped on the floor.
1533 ///
1534 /// @param supprs the new suppression specifications to add to the
1535 /// existing set of suppression specifications of the diff context.
1536 void
add_suppressions(const suppressions_type & supprs)1537 diff_context::add_suppressions(const suppressions_type& supprs)
1538 {
1539   priv_->suppressions_.insert(priv_->suppressions_.end(),
1540 			      supprs.begin(), supprs.end());
1541 }
1542 
1543 /// Test if it's requested to perform diff node categorization.
1544 ///
1545 /// @return true iff it's requested to perform diff node
1546 /// categorization.
1547 bool
perform_change_categorization() const1548 diff_context::perform_change_categorization() const
1549 {return priv_->perform_change_categorization_;}
1550 
1551 /// Request change categorization or not.
1552 ///
1553 /// @param f true iff change categorization is requested.
1554 void
perform_change_categorization(bool f)1555 diff_context::perform_change_categorization(bool f)
1556 {priv_->perform_change_categorization_ = f;}
1557 
1558 /// Set the flag that indicates if the diff using this context should
1559 /// show only leaf changes or not.
1560 ///
1561 /// @param f the new value of the flag that indicates if the diff
1562 /// using this context should show only leaf changes or not.
1563 void
show_leaf_changes_only(bool f)1564 diff_context::show_leaf_changes_only(bool f)
1565 {
1566   // This function can be called only if the reporter hasn't yet been
1567   // created.  Once it's been created, we are supposed to live with
1568   // it.
1569   ABG_ASSERT(priv_->reporter_ == 0);
1570   priv_->leaf_changes_only_ = f;
1571 }
1572 
1573 /// Get the flag that indicates if the diff using this context should
1574 /// show only leaf changes or not.
1575 ///
1576 /// @return the value of the flag that indicates if the diff using
1577 /// this context should show only leaf changes or not.
1578 bool
show_leaf_changes_only() const1579 diff_context::show_leaf_changes_only() const
1580 {return priv_->leaf_changes_only_;}
1581 
1582 /// Get the flag that indicates if the diff reports using this context
1583 /// should show sizes and offsets in an hexadecimal base or not.  If
1584 /// not, then they are to be shown in a decimal base.
1585 ///
1586 /// @return true iff sizes and offsets are to be shown in an
1587 /// hexadecimal base.
1588 bool
show_hex_values() const1589 diff_context::show_hex_values() const
1590 {return priv_->hex_values_;}
1591 
1592 /// Set the flag that indicates if diff reports using this context
1593 /// should show sizes and offsets in an hexadecimal base or not.  If
1594 /// not, then they are to be shown in a decimal base.
1595 ///
1596 /// @param f if true then sizes and offsets are to be shown in an
1597 /// hexadecimal base.
1598 void
show_hex_values(bool f)1599 diff_context::show_hex_values(bool f)
1600 {priv_->hex_values_ = f;}
1601 
1602 /// Get the flag that indicates if diff reports using this context
1603 /// should show sizes and offsets in bits, rather than bytes.
1604 ///
1605 /// @return true iff sizes and offsets are to be shown in bits.
1606 /// Otherwise they are to be shown in bytes.
1607 bool
show_offsets_sizes_in_bits() const1608 diff_context::show_offsets_sizes_in_bits() const
1609 {return priv_->show_offsets_sizes_in_bits_;}
1610 
1611 /// Set the flag that indicates if diff reports using this context
1612 /// should show sizes and offsets in bits, rather than bytes.
1613 ///
1614 /// @param f if true then sizes and offsets are to be shown in bits.
1615 /// Otherwise they are to be shown in bytes.
1616 void
show_offsets_sizes_in_bits(bool f)1617 diff_context::show_offsets_sizes_in_bits(bool f)
1618 {priv_->show_offsets_sizes_in_bits_ = f;}
1619 
1620 /// Set a flag saying if offset changes should be reported in a
1621 /// relative way.  That is, if the report should say how of many bits
1622 /// a class/struct data member did move.
1623 ///
1624 /// @param f the new boolean value of the flag.
1625 void
show_relative_offset_changes(bool f)1626 diff_context::show_relative_offset_changes(bool f)
1627 {priv_->show_relative_offset_changes_ = f;}
1628 
1629 /// Get the flag saying if offset changes should be reported in a
1630 /// relative way.  That is, if the report should say how of many bits
1631 /// a class/struct data member did move.
1632 ///
1633 /// @return the boolean value of the flag.
1634 bool
show_relative_offset_changes(void)1635 diff_context::show_relative_offset_changes(void)
1636 {return priv_->show_relative_offset_changes_;}
1637 
1638 /// Set a flag saying if the comparison module should only show the
1639 /// diff stats.
1640 ///
1641 /// @param f the flag to set.
1642 void
show_stats_only(bool f)1643 diff_context::show_stats_only(bool f)
1644 {priv_->show_stats_only_ = f;}
1645 
1646 /// Test if the comparison module should only show the diff stats.
1647 ///
1648 /// @return true if the comparison module should only show the diff
1649 /// stats, false otherwise.
1650 bool
show_stats_only() const1651 diff_context::show_stats_only() const
1652 {return priv_->show_stats_only_;}
1653 
1654 /// Setter for the property that says if the comparison module should
1655 /// show the soname changes in its report.
1656 ///
1657 /// @param f the new value of the property.
1658 void
show_soname_change(bool f)1659 diff_context::show_soname_change(bool f)
1660 {priv_->show_soname_change_ = f;}
1661 
1662 /// Getter for the property that says if the comparison module should
1663 /// show the soname changes in its report.
1664 ///
1665 /// @return the value of the property.
1666 bool
show_soname_change() const1667 diff_context::show_soname_change() const
1668 {return priv_->show_soname_change_;}
1669 
1670 /// Setter for the property that says if the comparison module should
1671 /// show the architecture changes in its report.
1672 ///
1673 /// @param f the new value of the property.
1674 void
show_architecture_change(bool f)1675 diff_context::show_architecture_change(bool f)
1676 {priv_->show_architecture_change_ = f;}
1677 
1678 /// Getter for the property that says if the comparison module should
1679 /// show the architecture changes in its report.
1680 ///
1681 /// @return the value of the property.
1682 bool
show_architecture_change() const1683 diff_context::show_architecture_change() const
1684 {return priv_->show_architecture_change_;}
1685 
1686 /// Set a flag saying to show the deleted functions.
1687 ///
1688 /// @param f true to show deleted functions.
1689 void
show_deleted_fns(bool f)1690 diff_context::show_deleted_fns(bool f)
1691 {priv_->show_deleted_fns_ = f;}
1692 
1693 /// @return true if we want to show the deleted functions, false
1694 /// otherwise.
1695 bool
show_deleted_fns() const1696 diff_context::show_deleted_fns() const
1697 {return priv_->show_deleted_fns_;}
1698 
1699 /// Set a flag saying to show the changed functions.
1700 ///
1701 /// @param f true to show the changed functions.
1702 void
show_changed_fns(bool f)1703 diff_context::show_changed_fns(bool f)
1704 {priv_->show_changed_fns_ = f;}
1705 
1706 /// @return true if we want to show the changed functions, false otherwise.
1707 bool
show_changed_fns() const1708 diff_context::show_changed_fns() const
1709 {return priv_->show_changed_fns_;}
1710 
1711 /// Set a flag saying to show the added functions.
1712 ///
1713 /// @param f true to show the added functions.
1714 void
show_added_fns(bool f)1715 diff_context::show_added_fns(bool f)
1716 {priv_->show_added_fns_ = f;}
1717 
1718 /// @return true if we want to show the added functions, false
1719 /// otherwise.
1720 bool
show_added_fns() const1721 diff_context::show_added_fns() const
1722 {return priv_->show_added_fns_;}
1723 
1724 /// Set a flag saying to show the deleted variables.
1725 ///
1726 /// @param f true to show the deleted variables.
1727 void
show_deleted_vars(bool f)1728 diff_context::show_deleted_vars(bool f)
1729 {priv_->show_deleted_vars_ = f;}
1730 
1731 /// @return true if we want to show the deleted variables, false
1732 /// otherwise.
1733 bool
show_deleted_vars() const1734 diff_context::show_deleted_vars() const
1735 {return priv_->show_deleted_vars_;}
1736 
1737 /// Set a flag saying to show the changed variables.
1738 ///
1739 /// @param f true to show the changed variables.
1740 void
show_changed_vars(bool f)1741 diff_context::show_changed_vars(bool f)
1742 {priv_->show_changed_vars_ = f;}
1743 
1744 /// @return true if we want to show the changed variables, false otherwise.
1745 bool
show_changed_vars() const1746 diff_context::show_changed_vars() const
1747 {return priv_->show_changed_vars_;}
1748 
1749 /// Set a flag saying to show the added variables.
1750 ///
1751 /// @param f true to show the added variables.
1752 void
show_added_vars(bool f)1753 diff_context::show_added_vars(bool f)
1754 {priv_->show_added_vars_ = f;}
1755 
1756 /// @return true if we want to show the added variables, false
1757 /// otherwise.
1758 bool
show_added_vars() const1759 diff_context::show_added_vars() const
1760 {return priv_->show_added_vars_;}
1761 
1762 bool
show_linkage_names() const1763 diff_context::show_linkage_names() const
1764 {return priv_->show_linkage_names_;}
1765 
1766 void
show_linkage_names(bool f)1767 diff_context::show_linkage_names(bool f)
1768 {priv_->show_linkage_names_= f;}
1769 
1770 /// Set a flag saying to show location information.
1771 ///
1772 /// @param f true to show location information.
1773 void
show_locs(bool f)1774 diff_context::show_locs(bool f)
1775 {priv_->show_locs_= f;}
1776 
1777 /// @return true if we want to show location information, false
1778 /// otherwise.
1779 bool
show_locs() const1780 diff_context::show_locs() const
1781 {return priv_->show_locs_;}
1782 
1783 /// A getter for the flag that says if we should report about
1784 /// functions or variables diff nodes that have *exclusively*
1785 /// redundant diff tree children nodes.
1786 ///
1787 /// @return the flag.
1788 bool
show_redundant_changes() const1789 diff_context::show_redundant_changes() const
1790 {return priv_->show_redundant_changes_;}
1791 
1792 /// A setter for the flag that says if we should report about
1793 /// functions or variables diff nodes that have *exclusively*
1794 /// redundant diff tree children nodes.
1795 ///
1796 /// @param f the flag to set.
1797 void
show_redundant_changes(bool f)1798 diff_context::show_redundant_changes(bool f)
1799 {priv_->show_redundant_changes_ = f;}
1800 
1801 /// Getter for the flag that indicates if symbols not referenced by
1802 /// any debug info are to be compared and reported about.
1803 ///
1804 /// @return the boolean flag.
1805 bool
show_symbols_unreferenced_by_debug_info() const1806 diff_context::show_symbols_unreferenced_by_debug_info() const
1807 {return priv_->show_syms_unreferenced_by_di_;}
1808 
1809 /// Setter for the flag that indicates if symbols not referenced by
1810 /// any debug info are to be compared and reported about.
1811 ///
1812 /// @param f the new flag to set.
1813 void
show_symbols_unreferenced_by_debug_info(bool f)1814 diff_context::show_symbols_unreferenced_by_debug_info(bool f)
1815 {priv_->show_syms_unreferenced_by_di_ = f;}
1816 
1817 /// Getter for the flag that indicates if symbols not referenced by
1818 /// any debug info and that got added are to be reported about.
1819 ///
1820 /// @return true iff symbols not referenced by any debug info and that
1821 /// got added are to be reported about.
1822 bool
show_added_symbols_unreferenced_by_debug_info() const1823 diff_context::show_added_symbols_unreferenced_by_debug_info() const
1824 {return priv_->show_added_syms_unreferenced_by_di_;}
1825 
1826 /// Setter for the flag that indicates if symbols not referenced by
1827 /// any debug info and that got added are to be reported about.
1828 ///
1829 /// @param f the new flag that says if symbols not referenced by any
1830 /// debug info and that got added are to be reported about.
1831 void
show_added_symbols_unreferenced_by_debug_info(bool f)1832 diff_context::show_added_symbols_unreferenced_by_debug_info(bool f)
1833 {priv_->show_added_syms_unreferenced_by_di_ = f;}
1834 
1835 /// Setter for the flag that indicates if changes on types unreachable
1836 /// from global functions and variables are to be reported.
1837 ///
1838 /// @param f if true, then changes on types unreachable from global
1839 /// functions and variables are to be reported.
1840 void
show_unreachable_types(bool f)1841 diff_context::show_unreachable_types(bool f)
1842 {priv_->show_unreachable_types_ = f;}
1843 
1844 /// Getter for the flag that indicates if changes on types unreachable
1845 /// from global functions and variables are to be reported.
1846 ///
1847 /// @return true iff changes on types unreachable from global
1848 /// functions and variables are to be reported.
1849 bool
show_unreachable_types()1850 diff_context::show_unreachable_types()
1851 {return priv_->show_unreachable_types_;}
1852 
1853 /// Getter of the flag that indicates if the leaf reporter should
1854 /// display a summary of the interfaces impacted by a given leaf
1855 /// change or not.
1856 ///
1857 /// @return the flag that indicates if the leaf reporter should
1858 /// display a summary of the interfaces impacted by a given leaf
1859 /// change or not.
1860 bool
show_impacted_interfaces() const1861 diff_context::show_impacted_interfaces() const
1862 {return priv_->show_impacted_interfaces_;}
1863 
1864 /// Setter of the flag that indicates if the leaf reporter should
1865 /// display a summary of the interfaces impacted by a given leaf
1866 /// change or not.
1867 ///
1868 /// @param f the new value of the flag that indicates if the leaf
1869 /// reporter should display a summary of the interfaces impacted by a
1870 /// given leaf change or not.
1871 void
show_impacted_interfaces(bool f)1872 diff_context::show_impacted_interfaces(bool f)
1873 {priv_->show_impacted_interfaces_ = f;}
1874 
1875 /// Setter for the default output stream used by code of the
1876 /// comparison engine.  By default the default output stream is a NULL
1877 /// pointer.
1878 ///
1879 /// @param o a pointer to the default output stream.
1880 void
default_output_stream(ostream * o)1881 diff_context::default_output_stream(ostream* o)
1882 {priv_->default_output_stream_ = o;}
1883 
1884 /// Getter for the default output stream used by code of the
1885 /// comparison engine.  By default the default output stream is a NULL
1886 /// pointer.
1887 ///
1888 /// @return a pointer to the default output stream.
1889 ostream*
default_output_stream()1890 diff_context::default_output_stream()
1891 {return priv_->default_output_stream_;}
1892 
1893 /// Setter for the errror output stream used by code of the comparison
1894 /// engine.  By default the error output stream is a NULL pointer.
1895 ///
1896 /// @param o a pointer to the error output stream.
1897 void
error_output_stream(ostream * o)1898 diff_context::error_output_stream(ostream* o)
1899 {priv_->error_output_stream_ = o;}
1900 
1901 /// Getter for the errror output stream used by code of the comparison
1902 /// engine.  By default the error output stream is a NULL pointer.
1903 ///
1904 /// @return a pointer to the error output stream.
1905 ostream*
error_output_stream() const1906 diff_context::error_output_stream() const
1907 {return priv_->error_output_stream_;}
1908 
1909 /// Test if the comparison engine should dump the diff tree for the
1910 /// changed functions and variables it has.
1911 ///
1912 /// @return true if after the comparison, the engine should dump the
1913 /// diff tree for the changed functions and variables it has.
1914 bool
dump_diff_tree() const1915 diff_context::dump_diff_tree() const
1916 {return priv_->dump_diff_tree_;}
1917 
1918 /// Set if the comparison engine should dump the diff tree for the
1919 /// changed functions and variables it has.
1920 ///
1921 /// @param f true if after the comparison, the engine should dump the
1922 /// diff tree for the changed functions and variables it has.
1923 void
dump_diff_tree(bool f)1924 diff_context::dump_diff_tree(bool f)
1925 {priv_->dump_diff_tree_ = f;}
1926 
1927 /// Emit a textual representation of a diff tree to the error output
1928 /// stream of the current context, for debugging purposes.
1929 ///
1930 /// @param d the diff tree to serialize to the error output associated
1931 /// to the current instance of @ref diff_context.
1932 void
do_dump_diff_tree(const diff_sptr d) const1933 diff_context::do_dump_diff_tree(const diff_sptr d) const
1934 {
1935   if (error_output_stream())
1936     print_diff_tree(d, *error_output_stream());
1937 }
1938 
1939 /// Emit a textual representation of a @ref corpus_diff tree to the error
1940 /// output stream of the current context, for debugging purposes.
1941 ///
1942 /// @param d the @ref corpus_diff tree to serialize to the error
1943 /// output associated to the current instance of @ref diff_context.
1944 void
do_dump_diff_tree(const corpus_diff_sptr d) const1945 diff_context::do_dump_diff_tree(const corpus_diff_sptr d) const
1946 {
1947   if (error_output_stream())
1948     print_diff_tree(d, *error_output_stream());
1949 }
1950 // </diff_context stuff>
1951 
1952 // <diff stuff>
1953 
1954 /// Constructor for the @ref diff type.
1955 ///
1956 /// This constructs a diff between two subjects that are actually
1957 /// declarations; the first and the second one.
1958 ///
1959 /// @param first_subject the first decl (subject) of the diff.
1960 ///
1961 /// @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)1962 diff::diff(type_or_decl_base_sptr first_subject,
1963 	   type_or_decl_base_sptr second_subject)
1964   : priv_(new priv(first_subject, second_subject,
1965 		   diff_context_sptr(),
1966 		   NO_CHANGE_CATEGORY,
1967 		   /*reported_once=*/false,
1968 		   /*currently_reporting=*/false))
1969 {}
1970 
1971 /// Constructor for the @ref diff type.
1972 ///
1973 /// This constructs a diff between two subjects that are actually
1974 /// declarations; the first and the second one.
1975 ///
1976 /// @param first_subject the first decl (subject) of the diff.
1977 ///
1978 /// @param second_subject the second decl (subject) of the diff.
1979 ///
1980 /// @param ctxt the context of the diff.  Note that this context
1981 /// object must stay alive during the entire life time of the current
1982 /// 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)1983 diff::diff(type_or_decl_base_sptr	first_subject,
1984 	   type_or_decl_base_sptr	second_subject,
1985 	   diff_context_sptr	ctxt)
1986   : priv_(new priv(first_subject, second_subject,
1987 		   ctxt, NO_CHANGE_CATEGORY,
1988 		   /*reported_once=*/false,
1989 		   /*currently_reporting=*/false))
1990 {}
1991 
1992 /// Test if logging was requested
1993 ///
1994 /// @return true iff logging was requested.
1995 bool
do_log() const1996 diff::do_log() const
1997 {return context()->do_log();}
1998 
1999 /// Request logging (or not)
2000 ///
2001 /// @param f true iff logging is to be requested.
2002 void
do_log(bool f)2003 diff::do_log(bool f)
2004 {context()->do_log(f);}
2005 
2006 /// Flag a given diff node as being traversed.
2007 ///
2008 /// For certain diff nodes like @ref class_diff, it's important to
2009 /// avoid traversing the node again while it's already being
2010 /// traversed; otherwise this leads to infinite loops.  So the
2011 /// diff::begin_traversing() and diff::end_traversing() methods flag a
2012 /// given node as being traversed (or not), so that
2013 /// diff::is_traversing() can tell if the node is being traversed.
2014 ///
2015 /// Note that traversing a node means visiting it *and* visiting its
2016 /// children nodes.
2017 ///
2018 /// The canonical node is marked as being traversed too.
2019 ///
2020 /// These functions are called by the traversing code.
2021 void
begin_traversing()2022 diff::begin_traversing()
2023 {
2024   ABG_ASSERT(!is_traversing());
2025   if (priv_->canonical_diff_)
2026     priv_->canonical_diff_->priv_->traversing_ = true;
2027   priv_->traversing_ = true;
2028 }
2029 
2030 /// Tell if a given node is being traversed or not.
2031 ///
2032 /// Note that traversing a node means visiting it *and* visiting its
2033 /// children nodes.
2034 ///
2035 /// It's the canonical node which is looked at, actually.
2036 ///
2037 /// Please read the comments for the diff::begin_traversing() for mode
2038 /// context.
2039 ///
2040 /// @return true if the current instance of @diff is being traversed.
2041 bool
is_traversing() const2042 diff::is_traversing() const
2043 {
2044   if (priv_->canonical_diff_)
2045     return priv_->canonical_diff_->priv_->traversing_;
2046   return priv_->traversing_;
2047 }
2048 
2049 /// Flag a given diff node as not being traversed anymore.
2050 ///
2051 /// Note that traversing a node means visiting it *and* visiting its
2052 /// children nodes.
2053 ///
2054 /// Please read the comments of the function diff::begin_traversing()
2055 /// for mode context.
2056 void
end_traversing()2057 diff::end_traversing()
2058 {
2059   ABG_ASSERT(is_traversing());
2060   if (priv_->canonical_diff_)
2061     priv_->canonical_diff_->priv_->traversing_ = false;
2062   priv_->traversing_ = false;
2063 }
2064 
2065 /// Finish the insertion of a diff tree node into the diff graph.
2066 ///
2067 /// This function might be called several times.  It must perform the
2068 /// insertion only once.
2069 ///
2070 /// For instance, certain kinds of diff tree node have specific
2071 /// children nodes that are populated after the constructor of the
2072 /// diff tree node has been called.  In that case, calling overloads
2073 /// of this method ensures that these children nodes are properly
2074 /// gathered and setup.
2075 void
finish_diff_type()2076 diff::finish_diff_type()
2077 {
2078   if (diff::priv_->finished_)
2079     return;
2080   chain_into_hierarchy();
2081   diff::priv_->finished_ = true;
2082 }
2083 
2084 /// Getter of the first subject of the diff.
2085 ///
2086 /// @return the first subject of the diff.
2087 type_or_decl_base_sptr
first_subject() const2088 diff::first_subject() const
2089 {return dynamic_pointer_cast<type_or_decl_base>(priv_->first_subject_);}
2090 
2091 /// Getter of the second subject of the diff.
2092 ///
2093 /// @return the second subject of the diff.
2094 type_or_decl_base_sptr
second_subject() const2095 diff::second_subject() const
2096 {return dynamic_pointer_cast<type_or_decl_base>(priv_->second_subject_);}
2097 
2098 /// Getter for the children nodes of the current @ref diff node.
2099 ///
2100 /// @return a vector of the children nodes.
2101 const vector<diff*>&
children_nodes() const2102 diff::children_nodes() const
2103 {return priv_->children_;}
2104 
2105 /// Getter for the parent node of the current @ref diff node.
2106 ///
2107 /// @return the parent node of the current @ref diff node.
2108 const diff*
parent_node() const2109 diff::parent_node() const
2110 {return priv_->parent_;}
2111 
2112 /// Getter for the canonical diff of the current instance of @ref
2113 /// diff.
2114 ///
2115 /// Note that the canonical diff node for the current instanc eof diff
2116 /// node must have been set by invoking
2117 /// class_diff::initialize_canonical_diff() on the current instance of
2118 /// diff node.
2119 ///
2120 /// @return the canonical diff node or null if none was set.
2121 diff*
get_canonical_diff() const2122 diff::get_canonical_diff() const
2123 {return priv_->canonical_diff_;}
2124 
2125 /// Setter for the canonical diff of the current instance of @ref
2126 /// diff.
2127 ///
2128 /// @param d the new canonical node to set.
2129 void
set_canonical_diff(diff * d)2130 diff::set_canonical_diff(diff * d)
2131 {priv_->canonical_diff_ = d;}
2132 
2133 /// Add a new child node to the vector of children nodes for the
2134 /// current @ref diff node.
2135 ///
2136 /// @param d the new child node to add to the children nodes.
2137 void
append_child_node(diff_sptr d)2138 diff::append_child_node(diff_sptr d)
2139 {
2140   ABG_ASSERT(d);
2141 
2142   // Ensure 'd' is kept alive for the life time of the context of this
2143   // diff.
2144   context()->keep_diff_alive(d);
2145 
2146   // Add the underlying pointer of 'd' to the vector of children.
2147   // Note that this vector holds no reference to 'd'. This is to avoid
2148   // reference cycles.  The reference to 'd' is held by the context of
2149   // this diff, thanks to the call to context()->keep_diff_alive(d)
2150   // above.
2151   priv_->children_.push_back(d.get());
2152 
2153   d->priv_->parent_ = this;
2154 }
2155 
2156 /// Getter of the context of the current diff.
2157 ///
2158 /// @return the context of the current diff.
2159 const diff_context_sptr
context() const2160 diff::context() const
2161 {return priv_->get_context();}
2162 
2163 /// Setter of the context of the current diff.
2164 ///
2165 /// @param c the new context to set.
2166 void
context(diff_context_sptr c)2167 diff::context(diff_context_sptr c)
2168 {priv_->ctxt_ = c;}
2169 
2170 /// Tests if we are currently in the middle of emitting a report for
2171 /// this diff.
2172 ///
2173 /// @return true if we are currently emitting a report for the
2174 /// current diff, false otherwise.
2175 bool
currently_reporting() const2176 diff::currently_reporting() const
2177 {
2178   if (priv_->canonical_diff_)
2179     return priv_->canonical_diff_->priv_->currently_reporting_;
2180   return priv_->currently_reporting_;
2181 }
2182 
2183 /// Sets a flag saying if we are currently in the middle of emitting
2184 /// a report for this diff.
2185 ///
2186 /// @param f true if we are currently emitting a report for the
2187 /// current diff, false otherwise.
2188 void
currently_reporting(bool f) const2189 diff::currently_reporting(bool f) const
2190 {
2191   if (priv_->canonical_diff_)
2192     priv_->canonical_diff_->priv_->currently_reporting_ = f;
2193   priv_->currently_reporting_ = f;
2194 }
2195 
2196 /// Tests if a report has already been emitted for the current diff.
2197 ///
2198 /// @return true if a report has already been emitted for the
2199 /// current diff, false otherwise.
2200 bool
reported_once() const2201 diff::reported_once() const
2202 {
2203   ABG_ASSERT(priv_->canonical_diff_);
2204   return priv_->canonical_diff_->priv_->reported_once_;
2205 }
2206 
2207 /// The generic traversing code that walks a given diff sub-tree.
2208 ///
2209 /// Note that there is a difference between traversing a diff node and
2210 /// visiting it.  Basically, traversing a diff node means visiting it
2211 /// and visiting its children nodes too.  So one can visit a node
2212 /// without traversing it.  But traversing a node without visiting it
2213 /// is not possible.
2214 ///
2215 /// Note that the insertion of the "generic view" of the diff node
2216 /// into the graph being traversed is done "on the fly".  The
2217 /// insertion of the "typed view" of the diff node into the graph is
2218 /// done implicitely.  To learn more about the generic and typed view
2219 /// of the diff node, please read the introductory comments of the
2220 /// @ref diff class.
2221 ///
2222 /// Note that by default this traversing code visits a given class of
2223 /// equivalence of a diff node only once.  This behaviour can been
2224 /// changed by calling
2225 /// diff_context::visiting_a_node_twice_is_forbidden(), but this is
2226 /// very risky as it might create endless loops while visiting a diff
2227 /// tree graph that has changes that refer to themselves; that is,
2228 /// diff tree graphs with cycles.
2229 ///
2230 /// When a diff node is encountered, the
2231 /// diff_node_visitor::visit_begin() method is invoked on the diff
2232 /// node first.
2233 ///
2234 /// If the diff node has already been visited, then
2235 /// node_visitor::visit_end() is called on it and the node traversing
2236 /// is done; the children of the diff node are not visited in this
2237 /// case.
2238 ///
2239 /// If the diff node has *NOT* been visited yet, then the
2240 /// diff_node_visitor::visit() method is invoked with it's 'pre'
2241 /// argument set to true.  Then if the diff_node_visitor::visit()
2242 /// returns true, then the children nodes of the diff node are
2243 /// visited.  Otherwise, no children nodes of the diff node is
2244 /// visited and the diff_node_visitor::visit_end() is called.
2245 
2246 /// After the children nodes are visited (and only if they are
2247 /// visited) the diff_node_visitor::visit() method is invoked with
2248 /// it's 'pre' argument set to false.  And then the
2249 /// diff_node_visitor::visit_end() is called.
2250 ///
2251 /// @param v the entity that visits each node of the diff sub-tree.
2252 ///
2253 /// @return true to tell the caller that all of the sub-tree could be
2254 /// walked.  This instructs the caller to keep walking the rest of the
2255 /// tree.  Return false otherwise.
2256 bool
traverse(diff_node_visitor & v)2257 diff::traverse(diff_node_visitor& v)
2258 {
2259   // Insert the "generic view" of the diff node into its graph.
2260   finish_diff_type();
2261 
2262   v.visit_begin(this);
2263 
2264   bool already_visited = false;
2265   if (context()->visiting_a_node_twice_is_forbidden()
2266       && context()->diff_has_been_visited(this))
2267     already_visited = true;
2268 
2269   bool mark_visited_nodes_as_traversed =
2270     !(v.get_visiting_kind() & DO_NOT_MARK_VISITED_NODES_AS_VISITED);
2271 
2272   if (!already_visited && !v.visit(this, /*pre=*/true))
2273     {
2274       v.visit_end(this);
2275       if (mark_visited_nodes_as_traversed)
2276 	context()->mark_diff_as_visited(this);
2277       return false;
2278     }
2279 
2280   if (!(v.get_visiting_kind() & SKIP_CHILDREN_VISITING_KIND)
2281       && !is_traversing()
2282       && !already_visited)
2283     {
2284       begin_traversing();
2285       for (vector<diff*>::const_iterator i = children_nodes().begin();
2286 	   i != children_nodes().end();
2287 	   ++i)
2288 	{
2289 	  if (!(*i)->traverse(v))
2290 	    {
2291 	      v.visit_end(this);
2292 	      if (mark_visited_nodes_as_traversed)
2293 		context()->mark_diff_as_visited(this);
2294 	      end_traversing();
2295 	      return false;
2296 	    }
2297 	}
2298       end_traversing();
2299     }
2300 
2301   if (!v.visit(this, /*pref=*/false))
2302     {
2303       v.visit_end(this);
2304       if (mark_visited_nodes_as_traversed)
2305 	context()->mark_diff_as_visited(this);
2306       return false;
2307     }
2308 
2309   v.visit_end(this);
2310   if (!already_visited && mark_visited_nodes_as_traversed)
2311     context()->mark_diff_as_visited(this);
2312 
2313   return true;
2314 }
2315 
2316 /// Sets a flag saying if a report has already been emitted for the
2317 /// current diff.
2318 ///
2319 /// @param f true if a report has already been emitted for the
2320 /// current diff, false otherwise.
2321 void
reported_once(bool f) const2322 diff::reported_once(bool f) const
2323 {
2324   ABG_ASSERT(priv_->canonical_diff_);
2325   priv_->canonical_diff_->priv_->reported_once_ = f;
2326   priv_->reported_once_ = f;
2327 }
2328 
2329 /// Getter for the local category of the current diff tree node.
2330 ///
2331 /// The local category represents the set of categories of a diff
2332 /// node, not taking in account the categories inherited from its
2333 /// children nodes.
2334 ///
2335 /// @return the local category of the current diff tree node.
2336 diff_category
get_local_category() const2337 diff::get_local_category() const
2338 {return priv_->local_category_;}
2339 
2340 /// Getter of the category of the class of equivalence of the current
2341 /// diff tree node.
2342 ///
2343 /// That is, if the current diff tree node has a canonical node,
2344 /// return the category of that canonical node.  Otherwise, return the
2345 /// category of the current node.
2346 ///
2347 /// @return the category of the class of equivalence of the current
2348 /// tree node.
2349 diff_category
get_class_of_equiv_category() const2350 diff::get_class_of_equiv_category() const
2351 {
2352   diff* canonical = get_canonical_diff();
2353   return canonical ? canonical->get_category() : get_category();
2354 }
2355 
2356 /// Getter for the category of the current diff tree node.
2357 ///
2358 /// This category represents the union of the local category and the
2359 /// categories inherited from the children diff nodes.
2360 ///
2361 /// @return the category of the current diff tree node.
2362 diff_category
get_category() const2363 diff::get_category() const
2364 {return priv_->category_;}
2365 
2366 /// Adds the current diff tree node to an additional set of
2367 /// categories.  Note that the categories include thoses inherited
2368 /// from the children nodes of this diff node.
2369 ///
2370 /// @param c a bit-map representing the set of categories to add the
2371 /// current diff tree node to.
2372 ///
2373 /// @return the resulting bit-map representing the categories this
2374 /// current diff tree node belongs to, including those inherited from
2375 /// its children nodes.
2376 diff_category
add_to_category(diff_category c)2377 diff::add_to_category(diff_category c)
2378 {
2379   priv_->category_ = priv_->category_ | c;
2380   return priv_->category_;
2381 }
2382 
2383 /// Adds the current diff tree node to the categories resulting from
2384 /// the local changes of the current diff node.
2385 ///
2386 /// @param c a bit-map representing the set of categories to add the
2387 /// current diff tree node to.
2388 ///
2389 /// @return the resulting bit-map representing the categories this
2390 /// current diff tree node belongs to.
2391 diff_category
add_to_local_category(diff_category c)2392 diff::add_to_local_category(diff_category c)
2393 {
2394   priv_->local_category_ = priv_->local_category_ | c;
2395   return priv_->local_category_;
2396 }
2397 
2398 /// Adds the current diff tree node to the categories resulting from
2399 /// the local and inherited changes of the current diff node.
2400 ///
2401 /// @param c a bit-map representing the set of categories to add the
2402 /// current diff tree node to.
2403 void
add_to_local_and_inherited_categories(diff_category c)2404 diff::add_to_local_and_inherited_categories(diff_category c)
2405 {
2406   add_to_local_category(c);
2407   add_to_category(c);
2408 }
2409 
2410 /// Remove the current diff tree node from an a existing sef of
2411 /// categories.  The categories include those inherited from the
2412 /// children nodes of the current diff node.
2413 ///
2414 /// @param c a bit-map representing the set of categories to add the
2415 /// current diff tree node to.
2416 ///
2417 /// @return the resulting bit-map representing the categories this
2418 /// current diff tree onde belongs to, including the categories
2419 /// inherited from the children nodes of the current diff node.
2420 diff_category
remove_from_category(diff_category c)2421 diff::remove_from_category(diff_category c)
2422 {
2423   priv_->category_ = priv_->category_ & ~c;
2424   return priv_->category_;
2425 }
2426 
2427 /// Remove the current diff tree node from the categories resulting
2428 /// from the local changes.
2429 ///
2430 /// @param c a bit-map representing the set of categories to add the
2431 /// current diff tree node to.
2432 ///
2433 /// @return the resulting bit-map representing the categories this
2434 /// current diff tree onde belongs to.
2435 diff_category
remove_from_local_category(diff_category c)2436 diff::remove_from_local_category(diff_category c)
2437 {
2438   priv_->local_category_ = priv_->local_category_ & ~c;
2439   return priv_->local_category_;
2440 }
2441 
2442 /// Set the category of the current @ref diff node.  This category
2443 /// includes the categories inherited from the children nodes of the
2444 /// current diff node.
2445 ///
2446 /// @param c the new category for the current diff node.
2447 void
set_category(diff_category c)2448 diff::set_category(diff_category c)
2449 {priv_->category_ = c;}
2450 
2451 /// Set the local category of the current @ref diff node.
2452 ///
2453 /// @param c the new category for the current diff node.
2454 void
set_local_category(diff_category c)2455 diff::set_local_category(diff_category c)
2456 {priv_->local_category_ = c;}
2457 
2458 /// Test if this diff tree node is to be filtered out for reporting
2459 /// purposes.
2460 ///
2461 /// There is a difference between a diff node being filtered out and
2462 /// being suppressed.  Being suppressed means that there is a
2463 /// suppression specification that suppresses the diff node
2464 /// specifically.  Being filtered out mean the node is either
2465 /// suppressed, or it's filtered out because the suppression of a set
2466 /// of (children) nodes caused this node to be filtered out as well.
2467 /// For instance, if a function diff has all its children diff nodes
2468 /// suppressed and if the function diff node carries no local change,
2469 /// then the function diff node itself is going to be filtered out.
2470 ///
2471 /// The function tests if the categories of the diff tree node are
2472 /// "forbidden" by the context or not.
2473 ///
2474 /// @return true iff the current diff node should NOT be reported.
2475 bool
is_filtered_out() const2476 diff::is_filtered_out() const
2477 {
2478   if (diff * canonical = get_canonical_diff())
2479     if ((canonical->get_category() & SUPPRESSED_CATEGORY
2480 	 || canonical->get_category() & PRIVATE_TYPE_CATEGORY)
2481 	&& !canonical->is_allowed_by_specific_negated_suppression()
2482 	&& !canonical->has_descendant_allowed_by_specific_negated_suppression()
2483 	&& !canonical->has_parent_allowed_by_specific_negated_suppression())
2484       // The canonical type was suppressed either by a user-provided
2485       // suppression specification or by a "private-type" suppression
2486       // specification..  This means all the classes of equivalence of
2487       // that canonical type were suppressed.  So this node should be
2488       // filtered out.
2489       return true;
2490   return priv_->is_filtered_out(get_category());
2491 }
2492 
2493 /// Test if this diff tree node is to be filtered out for reporting
2494 /// purposes, but by considering only the categories that were *NOT*
2495 /// inherited from its children nodes.
2496 ///
2497 /// The function tests if the local categories of the diff tree node
2498 /// are "forbidden" by the context or not.
2499 ///
2500 /// @return true iff the current diff node should NOT be reported,
2501 /// with respect to its local categories.
2502 bool
is_filtered_out_wrt_non_inherited_categories() const2503 diff::is_filtered_out_wrt_non_inherited_categories() const
2504 {return priv_->is_filtered_out(get_local_category());}
2505 
2506 /// Test if this diff tree node is to be filtered out for reporting
2507 /// purposes, but without considering the categories that can /force/
2508 /// the node to be unfiltered.
2509 ///
2510 /// The function tests if the categories of the diff tree node are
2511 /// "forbidden" by the context or not.
2512 ///
2513 /// @return true iff the current diff node should should NOT be
2514 /// reported, with respect to the categories that might filter it out
2515 /// only.
2516 bool
is_filtered_out_without_looking_at_allowed_changes() const2517 diff::is_filtered_out_without_looking_at_allowed_changes() const
2518 {
2519   diff_category c = get_category();
2520   c &= ~(HAS_DESCENDANT_WITH_ALLOWED_CHANGE_CATEGORY
2521 	 | HAS_PARENT_WITH_ALLOWED_CHANGE_CATEGORY
2522 	 | HAS_ALLOWED_CHANGE_CATEGORY);
2523 
2524     return priv_->is_filtered_out(c);
2525 }
2526 
2527 /// Test if the current diff node has been suppressed by a
2528 /// user-provided suppression specification.
2529 ///
2530 /// @return true if the current diff node has been suppressed by a
2531 /// user-provided suppression list.
2532 bool
is_suppressed() const2533 diff::is_suppressed() const
2534 {
2535   bool is_private = false;
2536   return is_suppressed(is_private);
2537 }
2538 
2539 /// Test if the current diff node has been suppressed by a
2540 /// user-provided suppression specification or by an auto-generated
2541 /// "private type" suppression specification.
2542 ///
2543 /// Note that private type suppressions are auto-generated from the
2544 /// path to where public headers are, as given by the user.
2545 ///
2546 /// Here is the current algorithm:
2547 ///
2548 ///         First, suppress this diff node if it's not matched by any
2549 ///         negated suppression specifications.  If it's not
2550 ///         suppressed, then suppress it if it's matched by direct
2551 ///         suppression specifications.
2552 ///
2553 /// @param is_private_type out parameter if the current diff node was
2554 /// suppressed because it's a private type then this parameter is set
2555 /// to true.
2556 ///
2557 /// @return true if the current diff node has been suppressed by a
2558 /// user-provided suppression list.
2559 bool
is_suppressed(bool & is_private_type) const2560 diff::is_suppressed(bool &is_private_type) const
2561 {
2562   // If there is at least one negated suppression, then suppress the
2563   // current diff node by default ...
2564   bool do_suppress = !context()->negated_suppressions().empty();
2565 
2566   // ... unless there is at least one negated suppression that
2567   // specifically asks to keep this diff node around (un-suppressed).
2568   for (auto n : context()->negated_suppressions())
2569     if (!n->suppresses_diff(this))
2570       {
2571 	do_suppress = false;
2572 	break;
2573       }
2574 
2575   // Then walk the set of non-negated, AKA direct, suppressions.  If at
2576   // least one suppression suppresses the current diff node then the
2577   // diff node must be suppressed.
2578   for (auto d : context()->direct_suppressions())
2579     if (d->suppresses_diff(this))
2580       {
2581 	do_suppress = true;
2582 	if (is_private_type_suppr_spec(d))
2583 	  is_private_type = true;
2584 	break;
2585       }
2586 
2587   return do_suppress;
2588 }
2589 
2590 /// Test if this diff tree node should be reported.
2591 ///
2592 /// @return true iff the current node should be reported.
2593 bool
to_be_reported() const2594 diff::to_be_reported() const
2595 {
2596   if (has_changes() && !is_filtered_out())
2597     return true;
2598   return false;
2599 }
2600 
2601 /// Test if this diff tree node should be reported when considering
2602 /// the categories that were *NOT* inherited from its children nodes.
2603 ///
2604 /// @return true iff the current node should be reported.
2605 bool
has_local_changes_to_be_reported() const2606 diff::has_local_changes_to_be_reported() const
2607 {
2608   if (has_local_changes()
2609       && !is_filtered_out_wrt_non_inherited_categories())
2610     return true;
2611   return false;
2612 }
2613 
2614 /// Test if this diff node is allowed (prevented from being
2615 /// suppressed) by at least one negated suppression specification.
2616 ///
2617 /// @return true if this diff node is meant to be allowed by at least
2618 /// one negated suppression specification.
2619 bool
is_allowed_by_specific_negated_suppression() const2620 diff::is_allowed_by_specific_negated_suppression() const
2621 {
2622   const suppressions_type& suppressions = context()->suppressions();
2623   for (suppressions_type::const_iterator i = suppressions.begin();
2624        i != suppressions.end();
2625        ++i)
2626     {
2627       if (is_negated_suppression(*i)
2628 	  && !(*i)->suppresses_diff(this))
2629 	return true;
2630     }
2631   return false;
2632 }
2633 
2634 /// Test if the current diff node has a descendant node which is
2635 /// specifically allowed by a negated suppression specification.
2636 ///
2637 /// @return true iff the current diff node has a descendant node
2638 /// which is specifically allowed by a negated suppression
2639 /// specification.
2640 bool
has_descendant_allowed_by_specific_negated_suppression() const2641 diff::has_descendant_allowed_by_specific_negated_suppression() const
2642 {
2643   bool result = (get_category() & HAS_DESCENDANT_WITH_ALLOWED_CHANGE_CATEGORY);
2644   return result;
2645 }
2646 
2647 /// Test if the current diff node has a parent node which is
2648 /// specifically allowed by a negated suppression specification.
2649 ///
2650 /// @return true iff the current diff node has a parent node which is
2651 /// specifically allowed by a negated suppression specification.
2652 bool
has_parent_allowed_by_specific_negated_suppression() const2653 diff::has_parent_allowed_by_specific_negated_suppression() const
2654 {
2655   bool result = (get_category() & HAS_PARENT_WITH_ALLOWED_CHANGE_CATEGORY);
2656   return result;
2657 }
2658 
2659 /// Get a pretty representation of the current @ref diff node.
2660 ///
2661 /// This is suitable for e.g. emitting debugging traces for the diff
2662 /// tree nodes.
2663 ///
2664 /// @return the pretty representation of the diff node.
2665 const string&
get_pretty_representation() const2666 diff::get_pretty_representation() const
2667 {
2668   if (priv_->pretty_representation_.empty())
2669     priv_->pretty_representation_ = "empty_diff";
2670   return priv_->pretty_representation_;
2671 }
2672 
2673 /// Default implementation of the hierachy chaining virtual function.
2674 ///
2675 /// There are several types of diff nodes that have logical children
2676 /// nodes; for instance, a typedef_diff has the diff of the underlying
2677 /// type as a child node.  A var_diff has the diff of the types of the
2678 /// variables as a child node, etc.
2679 ///
2680 /// But because the @ref diff base has a generic representation for
2681 /// children nodes of the all the types of @ref diff nodes (regardless
2682 /// of the specific most-derived type of diff node) that one can get
2683 /// using the method diff::children_nodes(), one need to populate that
2684 /// vector of children node.
2685 ///
2686 /// Populating that vector of children node is done by this function;
2687 /// it must be overloaded by each most-derived type of diff node that
2688 /// extends the @ref diff type.
2689 void
chain_into_hierarchy()2690 diff::chain_into_hierarchy()
2691 {}
2692 
2693 // </diff stuff>
2694 
2695 // <type_diff_base stuff>
2696 
type_diff_base(type_base_sptr first_subject,type_base_sptr second_subject,diff_context_sptr ctxt)2697 type_diff_base::type_diff_base(type_base_sptr	first_subject,
2698 			       type_base_sptr	second_subject,
2699 			       diff_context_sptr	ctxt)
2700   : diff(first_subject, second_subject, ctxt),
2701     priv_(new priv)
2702 {}
2703 
~type_diff_base()2704 type_diff_base::~type_diff_base()
2705 {}
2706 // </type_diff_base stuff>
2707 
2708 // <decl_diff_base stuff>
2709 
2710 /// Constructor of @ref decl_diff_base.
2711 ///
2712 /// @param first_subject the first subject of the diff.
2713 ///
2714 /// @param second_subject the second subject of the diff.
2715 ///
2716 /// @param ctxt the context of the diff.  This object must stay alive
2717 /// at least during the life time of the current instance of @ref
2718 /// 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)2719 decl_diff_base::decl_diff_base(decl_base_sptr	first_subject,
2720 			       decl_base_sptr	second_subject,
2721 			       diff_context_sptr	ctxt)
2722   : diff(first_subject, second_subject, ctxt),
2723     priv_(new priv)
2724 {}
2725 
~decl_diff_base()2726 decl_diff_base::~decl_diff_base()
2727 {}
2728 
2729 // </decl_diff_base stuff>
2730 
2731 // <distinct_diff stuff>
2732 
2733 /// @return a pretty representation for the @ref distinct_diff node.
2734 const string&
get_pretty_representation() const2735 distinct_diff::get_pretty_representation() const
2736 {
2737   if (diff::priv_->pretty_representation_.empty())
2738     {
2739       std::ostringstream o;
2740       o << "distinct_diff[";
2741       if (first_subject())
2742 	o << first_subject()->get_pretty_representation();
2743       else
2744 	o << "null";
2745       o << ", ";
2746       if (second_subject())
2747 	o << second_subject()->get_pretty_representation() ;
2748       else
2749 	o << "null";
2750       o << "]" ;
2751       diff::priv_->pretty_representation_ = o.str();
2752     }
2753   return diff::priv_->pretty_representation_;
2754 }
2755 
2756 /// Populate the vector of children node of the @ref diff base type
2757 /// sub-object of this instance of @distinct_diff.
2758 ///
2759 /// The children nodes can then later be retrieved using
2760 /// diff::children_nodes().
2761 void
chain_into_hierarchy()2762 distinct_diff::chain_into_hierarchy()
2763 {
2764   ABG_ASSERT(entities_are_of_distinct_kinds(first(), second()));
2765 
2766   if (diff_sptr d = compatible_child_diff())
2767     append_child_node(d);
2768 }
2769 
2770 /// Constructor for @ref distinct_diff.
2771 ///
2772 /// Note that the two entities considered for the diff (and passed in
2773 /// parameter) must be of different kinds.
2774 ///
2775 /// @param first the first entity to consider for the diff.
2776 ///
2777 /// @param second the second entity to consider for the diff.
2778 ///
2779 /// @param ctxt the context of the diff.  Note that this context
2780 /// object must stay alive at least during the life time of the
2781 /// current instance of @ref distinct_diff.  Otherwise memory
2782 /// corruption issues occur.
distinct_diff(type_or_decl_base_sptr first,type_or_decl_base_sptr second,diff_context_sptr ctxt)2783 distinct_diff::distinct_diff(type_or_decl_base_sptr first,
2784 			     type_or_decl_base_sptr second,
2785 			     diff_context_sptr ctxt)
2786   : diff(first, second, ctxt),
2787     priv_(new priv)
2788 {ABG_ASSERT(entities_are_of_distinct_kinds(first, second));}
2789 
2790 /// Getter for the first subject of the diff.
2791 ///
2792 /// @return the first subject of the diff.
2793 const type_or_decl_base_sptr
first() const2794 distinct_diff::first() const
2795 {return first_subject();}
2796 
2797 /// Getter for the second subject of the diff.
2798 ///
2799 /// @return the second subject of the diff.
2800 const type_or_decl_base_sptr
second() const2801 distinct_diff::second() const
2802 {return second_subject();}
2803 
2804 /// Getter for the child diff of this distinct_diff instance.
2805 ///
2806 /// When a distinct_diff has two subjects that are different but
2807 /// compatible, then the distinct_diff instance has a child diff node
2808 /// (named the compatible child diff) that is the diff between the two
2809 /// subjects stripped from their typedefs.  Otherwise, the compatible
2810 /// child diff is nul.
2811 ///
2812 /// Note that two diff subjects (that compare different) are
2813 /// considered compatible if stripping typedefs out of them makes them
2814 /// comparing equal.
2815 ///
2816 /// @return the compatible child diff node, if any.  Otherwise, null.
2817 const diff_sptr
compatible_child_diff() const2818 distinct_diff::compatible_child_diff() const
2819 {
2820   if (!priv_->compatible_child_diff)
2821     {
2822       type_base_sptr fs = strip_typedef(is_type(first())),
2823 	ss = strip_typedef(is_type(second()));
2824 
2825       if (fs && ss
2826 	  && !entities_are_of_distinct_kinds(get_type_declaration(fs),
2827 					     get_type_declaration(ss)))
2828 	priv_->compatible_child_diff = compute_diff(get_type_declaration(fs),
2829 						    get_type_declaration(ss),
2830 						    context());
2831     }
2832   return priv_->compatible_child_diff;
2833 }
2834 
2835 /// Test if the two arguments are of different kind, or that are both
2836 /// NULL.
2837 ///
2838 /// @param first the first argument to test for similarity in kind.
2839 ///
2840 /// @param second the second argument to test for similarity in kind.
2841 ///
2842 /// @return true iff the two arguments are of different kind.
2843 bool
entities_are_of_distinct_kinds(type_or_decl_base_sptr first,type_or_decl_base_sptr second)2844 distinct_diff::entities_are_of_distinct_kinds(type_or_decl_base_sptr first,
2845 					      type_or_decl_base_sptr second)
2846 {
2847   if (!!first != !!second)
2848     return true;
2849   if (!first && !second)
2850     // We do consider diffs of two empty decls as a diff of distinct
2851     // kinds, for now.
2852     return true;
2853   if (first == second)
2854     return false;
2855 
2856   const type_or_decl_base &f = *first, &s = *second;
2857   return typeid(f) != typeid(s);
2858 }
2859 
2860 /// @return true if the two subjects of the diff are different, false
2861 /// otherwise.
2862 bool
has_changes() const2863 distinct_diff::has_changes() const
2864 {return first() != second();}
2865 
2866 /// @return the kind of local change carried by the current diff node.
2867 /// The value returned is zero if the current node carries no local
2868 /// change.
2869 enum change_kind
has_local_changes() const2870 distinct_diff::has_local_changes() const
2871 {
2872   // Changes on a distinct_diff are all local.
2873   if (has_changes())
2874     return LOCAL_TYPE_CHANGE_KIND;
2875   return NO_CHANGE_KIND;
2876 }
2877 
2878 /// Emit a report about the current diff instance.
2879 ///
2880 /// @param out the output stream to send the diff report to.
2881 ///
2882 /// @param indent the indentation string to use in the report.
2883 void
report(ostream & out,const string & indent) const2884 distinct_diff::report(ostream& out, const string& indent) const
2885 {
2886   context()->get_reporter()->report(*this, out, indent);
2887 }
2888 
2889 /// Try to diff entities that are of distinct kinds.
2890 ///
2891 /// @param first the first entity to consider for the diff.
2892 ///
2893 /// @param second the second entity to consider for the diff.
2894 ///
2895 /// @param ctxt the context of the diff.
2896 ///
2897 /// @return a non-null diff if a diff object could be built, null
2898 /// otherwise.
2899 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)2900 compute_diff_for_distinct_kinds(const type_or_decl_base_sptr first,
2901 				const type_or_decl_base_sptr second,
2902 				diff_context_sptr ctxt)
2903 {
2904   if (!distinct_diff::entities_are_of_distinct_kinds(first, second))
2905     return distinct_diff_sptr();
2906 
2907   distinct_diff_sptr result(new distinct_diff(first, second, ctxt));
2908 
2909   ctxt->initialize_canonical_diff(result);
2910 
2911   return result;
2912 }
2913 
2914 /// </distinct_diff stuff>
2915 
2916 /// Try to compute a diff on two instances of DiffType representation.
2917 ///
2918 /// The function template performs the diff if and only if the decl
2919 /// representations are of a DiffType.
2920 ///
2921 /// @tparm DiffType the type of instances to diff.
2922 ///
2923 /// @param first the first representation of decl to consider in the
2924 /// diff computation.
2925 ///
2926 /// @param second the second representation of decl to consider in the
2927 /// diff computation.
2928 ///
2929 /// @param ctxt the diff context to use.
2930 ///
2931 ///@return the diff of the two types @p first and @p second if and
2932 ///only if they represent the parametrized type DiffType.  Otherwise,
2933 ///returns a NULL pointer value.
2934 template<typename DiffType>
2935 diff_sptr
try_to_diff(const type_or_decl_base_sptr first,const type_or_decl_base_sptr second,diff_context_sptr ctxt)2936 try_to_diff(const type_or_decl_base_sptr first,
2937 	    const type_or_decl_base_sptr second,
2938 	    diff_context_sptr ctxt)
2939 {
2940   if (shared_ptr<DiffType> f =
2941       dynamic_pointer_cast<DiffType>(first))
2942     {
2943       shared_ptr<DiffType> s =
2944 	dynamic_pointer_cast<DiffType>(second);
2945       if (!s)
2946 	return diff_sptr();
2947       return compute_diff(f, s, ctxt);
2948     }
2949   return diff_sptr();
2950 }
2951 
2952 
2953 /// This is a specialization of @ref try_to_diff() template to diff
2954 /// instances of @ref class_decl.
2955 ///
2956 /// @param first the first representation of decl to consider in the
2957 /// diff computation.
2958 ///
2959 /// @param second the second representation of decl to consider in the
2960 /// diff computation.
2961 ///
2962 /// @param ctxt the diff context to use.
2963 template<>
2964 diff_sptr
try_to_diff(const type_or_decl_base_sptr first,const type_or_decl_base_sptr second,diff_context_sptr ctxt)2965 try_to_diff<class_decl>(const type_or_decl_base_sptr first,
2966 			const type_or_decl_base_sptr second,
2967 			diff_context_sptr ctxt)
2968 {
2969   if (class_decl_sptr f =
2970       dynamic_pointer_cast<class_decl>(first))
2971     {
2972       class_decl_sptr s = dynamic_pointer_cast<class_decl>(second);
2973       if (!s)
2974 	return diff_sptr();
2975 
2976       if (f->get_is_declaration_only())
2977 	{
2978 	  class_decl_sptr f2 =
2979 	    is_class_type (f->get_definition_of_declaration());
2980 	  if (f2)
2981 	    f = f2;
2982 	}
2983       if (s->get_is_declaration_only())
2984 	{
2985 	  class_decl_sptr s2 =
2986 	    is_class_type(s->get_definition_of_declaration());
2987 	  if (s2)
2988 	    s = s2;
2989 	}
2990       return compute_diff(f, s, ctxt);
2991     }
2992   return diff_sptr();
2993 }
2994 
2995 /// Try to diff entities that are of distinct kinds.
2996 ///
2997 /// @param first the first entity to consider for the diff.
2998 ///
2999 /// @param second the second entity to consider for the diff.
3000 ///
3001 /// @param ctxt the context of the diff.
3002 ///
3003 /// @return a non-null diff if a diff object could be built, null
3004 /// otherwise.
3005 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)3006 try_to_diff_distinct_kinds(const type_or_decl_base_sptr first,
3007 			   const type_or_decl_base_sptr second,
3008 			   diff_context_sptr ctxt)
3009 {return compute_diff_for_distinct_kinds(first, second, ctxt);}
3010 
3011 /// Compute the difference between two types.
3012 ///
3013 /// The function considers every possible types known to libabigail
3014 /// and runs the appropriate diff function on them.
3015 ///
3016 /// Whenever a new kind of type decl is supported by abigail, if we
3017 /// want to be able to diff two instances of it, we need to update
3018 /// this function to support it.
3019 ///
3020 /// @param first the first type decl to consider for the diff
3021 ///
3022 /// @param second the second type decl to consider for the diff.
3023 ///
3024 /// @param ctxt the diff context to use.
3025 ///
3026 /// @return the resulting diff.  It's a pointer to a descendent of
3027 /// abigail::comparison::diff.
3028 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)3029 compute_diff_for_types(const type_or_decl_base_sptr& first,
3030 		       const type_or_decl_base_sptr& second,
3031 		       const diff_context_sptr& ctxt)
3032 {
3033   type_or_decl_base_sptr f = first;
3034   type_or_decl_base_sptr s = second;
3035 
3036   diff_sptr d;
3037 
3038   ((d = try_to_diff<type_decl>(f, s, ctxt))
3039    ||(d = try_to_diff<enum_type_decl>(f, s, ctxt))
3040    ||(d = try_to_diff<union_decl>(f, s,ctxt))
3041    ||(d = try_to_diff<class_decl>(f, s,ctxt))
3042    ||(d = try_to_diff<pointer_type_def>(f, s, ctxt))
3043    ||(d = try_to_diff<reference_type_def>(f, s, ctxt))
3044    ||(d = try_to_diff<array_type_def::subrange_type>(f, s, ctxt))
3045    ||(d = try_to_diff<array_type_def>(f, s, ctxt))
3046    ||(d = try_to_diff<qualified_type_def>(f, s, ctxt))
3047    ||(d = try_to_diff<typedef_decl>(f, s, ctxt))
3048    ||(d = try_to_diff<function_type>(f, s, ctxt))
3049    ||(d = try_to_diff_distinct_kinds(f, s, ctxt)));
3050 
3051   ABG_ASSERT(d);
3052 
3053   return d;
3054 }
3055 
3056 diff_category
operator |(diff_category c1,diff_category c2)3057 operator|(diff_category c1, diff_category c2)
3058 {return static_cast<diff_category>(static_cast<unsigned>(c1)
3059 				   | static_cast<unsigned>(c2));}
3060 
3061 diff_category&
operator |=(diff_category & c1,diff_category c2)3062 operator|=(diff_category& c1, diff_category c2)
3063 {
3064   c1 = c1 | c2;
3065   return c1;
3066 }
3067 
3068 diff_category&
operator &=(diff_category & c1,diff_category c2)3069 operator&=(diff_category& c1, diff_category c2)
3070 {
3071   c1 = c1 & c2;
3072   return c1;
3073 }
3074 
3075 diff_category
operator ^(diff_category c1,diff_category c2)3076 operator^(diff_category c1, diff_category c2)
3077 {return static_cast<diff_category>(static_cast<unsigned>(c1)
3078 				   ^ static_cast<unsigned>(c2));}
3079 
3080 diff_category
operator &(diff_category c1,diff_category c2)3081 operator&(diff_category c1, diff_category c2)
3082 {return static_cast<diff_category>(static_cast<unsigned>(c1)
3083 				   & static_cast<unsigned>(c2));}
3084 
3085 diff_category
operator ~(diff_category c)3086 operator~(diff_category c)
3087 {return static_cast<diff_category>(~static_cast<unsigned>(c));}
3088 
3089 
3090 /// Getter of a bitmap made of the set of change categories that are
3091 /// considered harmless.
3092 ///
3093 /// @return the bitmap made of the set of change categories that are
3094 /// considered harmless.
3095 diff_category
get_default_harmless_categories_bitmap()3096 get_default_harmless_categories_bitmap()
3097 {
3098   return (abigail::comparison::ACCESS_CHANGE_CATEGORY
3099 	  | abigail::comparison::COMPATIBLE_TYPE_CHANGE_CATEGORY
3100 	  | abigail::comparison::HARMLESS_DECL_NAME_CHANGE_CATEGORY
3101 	  | abigail::comparison::NON_VIRT_MEM_FUN_CHANGE_CATEGORY
3102 	  | abigail::comparison::STATIC_DATA_MEMBER_CHANGE_CATEGORY
3103 	  | abigail::comparison::HARMLESS_ENUM_CHANGE_CATEGORY
3104 	  | abigail::comparison::HARMLESS_SYMBOL_ALIAS_CHANGE_CATEGORY
3105 	  | abigail::comparison::HARMLESS_UNION_CHANGE_CATEGORY
3106 	  | abigail::comparison::HARMLESS_DATA_MEMBER_CHANGE_CATEGORY
3107 	  | abigail::comparison::TYPE_DECL_ONLY_DEF_CHANGE_CATEGORY
3108 	  | abigail::comparison::FN_PARM_TYPE_TOP_CV_CHANGE_CATEGORY
3109 	  | abigail::comparison::FN_PARM_TYPE_CV_CHANGE_CATEGORY
3110 	  | abigail::comparison::FN_RETURN_TYPE_CV_CHANGE_CATEGORY
3111 	  | abigail::comparison::VAR_TYPE_CV_CHANGE_CATEGORY
3112 	  | abigail::comparison::VOID_PTR_TO_PTR_CHANGE_CATEGORY
3113 	  | abigail::comparison::BENIGN_INFINITE_ARRAY_CHANGE_CATEGORY);
3114 }
3115 
3116 /// Getter of a bitmap made of the set of change categories that are
3117 /// considered harmful.
3118 ///
3119 /// @return the bitmap made of the set of change categories that are
3120 /// considered harmful.
3121 diff_category
get_default_harmful_categories_bitmap()3122 get_default_harmful_categories_bitmap()
3123 {
3124   return (abigail::comparison::SIZE_OR_OFFSET_CHANGE_CATEGORY
3125 	  | abigail::comparison::VIRTUAL_MEMBER_CHANGE_CATEGORY
3126 	  | abigail::comparison::FN_PARM_ADD_REMOVE_CHANGE_CATEGORY);
3127 }
3128 
3129 /// Serialize an instance of @ref diff_category to an output stream.
3130 ///
3131 /// @param o the output stream to serialize @p c to.
3132 ///
3133 /// @param c the instance of diff_category to serialize.
3134 ///
3135 /// @return the output stream to serialize @p c to.
3136 ostream&
operator <<(ostream & o,diff_category c)3137 operator<<(ostream& o, diff_category c)
3138 {
3139   bool emitted_a_category = false;
3140 
3141   if (c == NO_CHANGE_CATEGORY)
3142     {
3143       o << "NO_CHANGE_CATEGORY";
3144       emitted_a_category = true;
3145     }
3146 
3147   if (c & ACCESS_CHANGE_CATEGORY)
3148     {
3149       if (emitted_a_category)
3150 	o << "|";
3151       o << "ACCESS_CHANGE_CATEGORY";
3152       emitted_a_category |= true;
3153     }
3154 
3155   if (c & COMPATIBLE_TYPE_CHANGE_CATEGORY)
3156     {
3157       if (emitted_a_category)
3158 	o << "|";
3159       o << "COMPATIBLE_TYPE_CHANGE_CATEGORY";
3160       emitted_a_category |= true;
3161     }
3162 
3163   if (c & HARMLESS_DECL_NAME_CHANGE_CATEGORY)
3164     {
3165       if (emitted_a_category)
3166 	o << "|";
3167       o << "HARMLESS_DECL_NAME_CHANGE_CATEGORY";
3168       emitted_a_category |= true;
3169     }
3170 
3171   if (c & NON_VIRT_MEM_FUN_CHANGE_CATEGORY)
3172     {
3173       if (emitted_a_category)
3174 	o << "|";
3175       o << "NON_VIRT_MEM_FUN_CHANGE_CATEGORY";
3176       emitted_a_category |= true;
3177     }
3178 
3179   if (c & STATIC_DATA_MEMBER_CHANGE_CATEGORY)
3180     {
3181       if (emitted_a_category)
3182 	o << "|";
3183       o << "STATIC_DATA_MEMBER_CHANGE_CATEGORY";
3184       emitted_a_category |= true;
3185     }
3186 
3187   if (c & HARMLESS_ENUM_CHANGE_CATEGORY)
3188     {
3189       if (emitted_a_category)
3190 	o << "|";
3191       o << "HARMLESS_ENUM_CHANGE_CATEGORY";
3192       emitted_a_category |= true;
3193     }
3194 
3195     if (c & HARMLESS_DATA_MEMBER_CHANGE_CATEGORY)
3196     {
3197       if (emitted_a_category)
3198 	o << "|";
3199       o << "HARMLESS_DATA_MEMBER_CHANGE_CATEGORY";
3200       emitted_a_category |= true;
3201     }
3202 
3203   if (c & HARMLESS_SYMBOL_ALIAS_CHANGE_CATEGORY)
3204     {
3205       if (emitted_a_category)
3206 	o << "|";
3207       o << "HARMLESS_SYMBOL_ALIAS_CHANGE_CATEGORY";
3208       emitted_a_category |= true;
3209     }
3210 
3211   if (c & HARMLESS_UNION_CHANGE_CATEGORY)
3212     {
3213       if (emitted_a_category)
3214 	o << "|";
3215       o << "HARMLESS_UNION_CHANGE_CATEGORY";
3216       emitted_a_category |= true;
3217     }
3218 
3219   if (c & SUPPRESSED_CATEGORY)
3220     {
3221       if (emitted_a_category)
3222 	o << "|";
3223       o << "SUPPRESSED_CATEGORY";
3224       emitted_a_category |= true;
3225     }
3226 
3227   if (c & PRIVATE_TYPE_CATEGORY)
3228     {
3229       if (emitted_a_category)
3230 	o << "|";
3231       o << "PRIVATE_TYPE_CATEGORY";
3232       emitted_a_category |= true;
3233     }
3234 
3235   if (c & SIZE_OR_OFFSET_CHANGE_CATEGORY)
3236     {
3237       if (emitted_a_category)
3238 	o << "|";
3239       o << "SIZE_OR_OFFSET_CHANGE_CATEGORY";
3240       emitted_a_category |= true;
3241     }
3242 
3243   if (c & VIRTUAL_MEMBER_CHANGE_CATEGORY)
3244     {
3245       if (emitted_a_category)
3246 	o << "|";
3247       o << "VIRTUAL_MEMBER_CHANGE_CATEGORY";
3248       emitted_a_category |= true;
3249     }
3250 
3251   if (c & REDUNDANT_CATEGORY)
3252     {
3253       if (emitted_a_category)
3254 	o << "|";
3255       o << "REDUNDANT_CATEGORY";
3256       emitted_a_category |= true;
3257     }
3258 
3259   if (c & TYPE_DECL_ONLY_DEF_CHANGE_CATEGORY)
3260     {
3261       if (emitted_a_category)
3262 	o << "|";
3263       o << "TYPE_DECL_ONLY_DEF_CHANGE_CATEGORY";
3264       emitted_a_category |= true;
3265     }
3266 
3267   if (c & FN_PARM_TYPE_TOP_CV_CHANGE_CATEGORY)
3268     {
3269       if (emitted_a_category)
3270 	o << "|";
3271       o << "FN_PARM_TYPE_TOP_CV_CHANGE_CATEGORY";
3272       emitted_a_category |= true;
3273     }
3274 
3275   if (c & FN_PARM_TYPE_CV_CHANGE_CATEGORY)
3276     {
3277       if (emitted_a_category)
3278 	o << "|";
3279       o << "FN_PARM_TYPE_CV_CHANGE_CATEGORY";
3280       emitted_a_category |= true;
3281     }
3282 
3283   if (c & FN_RETURN_TYPE_CV_CHANGE_CATEGORY)
3284     {
3285       if (emitted_a_category)
3286 	o << "|";
3287       o << "FN_RETURN_TYPE_CV_CHANGE_CATEGORY";
3288       emitted_a_category |= true;
3289     }
3290 
3291     if (c & FN_PARM_ADD_REMOVE_CHANGE_CATEGORY)
3292     {
3293       if (emitted_a_category)
3294 	o << "|";
3295       o << "FN_PARM_ADD_REMOVE_CHANGE_CATEGORY";
3296       emitted_a_category |= true;
3297     }
3298 
3299   if (c & VAR_TYPE_CV_CHANGE_CATEGORY)
3300     {
3301       if (emitted_a_category)
3302 	o << "|";
3303       o << "VAR_TYPE_CV_CHANGE_CATEGORY";
3304       emitted_a_category |= true;
3305     }
3306 
3307   if (c & VOID_PTR_TO_PTR_CHANGE_CATEGORY)
3308     {
3309       if (emitted_a_category)
3310 	o << "|";
3311       o << "VOID_PTR_TO_PTR_CHANGE_CATEGORY";
3312       emitted_a_category |= true;
3313     }
3314 
3315   if (c & BENIGN_INFINITE_ARRAY_CHANGE_CATEGORY)
3316     {
3317       if (emitted_a_category)
3318 	o << "|";
3319       o << "BENIGN_INFINITE_ARRAY_CHANGE_CATEGORY";
3320       emitted_a_category |= true;
3321     }
3322 
3323   if (c & HAS_ALLOWED_CHANGE_CATEGORY)
3324     {
3325       if (emitted_a_category)
3326 	o << "|";
3327       o << "HAS_ALLOWED_CHANGE_CATEGORY";
3328       emitted_a_category |= true;
3329     }
3330 
3331   if (c & HAS_DESCENDANT_WITH_ALLOWED_CHANGE_CATEGORY)
3332     {
3333       if (emitted_a_category)
3334 	o << "|";
3335       o << "HAS_DESCENDANT_WITH_ALLOWED_CHANGE_CATEGORY";
3336       emitted_a_category |= true;
3337     }
3338 
3339     if (c & HAS_PARENT_WITH_ALLOWED_CHANGE_CATEGORY)
3340     {
3341       if (emitted_a_category)
3342 	o << "|";
3343       o << "HAS_PARENT_WITH_ALLOWED_CHANGE_CATEGORY";
3344       emitted_a_category |= true;
3345     }
3346 
3347   return o;
3348 }
3349 
3350 /// Compute the difference between two decls.
3351 ///
3352 /// The function consider every possible decls known to libabigail and
3353 /// runs the appropriate diff function on them.
3354 ///
3355 /// Whenever a new kind of non-type decl is supported by abigail, if
3356 /// we want to be able to diff two instances of it, we need to update
3357 /// this function to support it.
3358 ///
3359 /// @param first the first decl to consider for the diff
3360 ///
3361 /// @param second the second decl to consider for the diff.
3362 ///
3363 /// @param ctxt the diff context to use.
3364 ///
3365 /// @return the resulting diff.
3366 static diff_sptr
compute_diff_for_decls(const decl_base_sptr first,const decl_base_sptr second,diff_context_sptr ctxt)3367 compute_diff_for_decls(const decl_base_sptr first,
3368 		       const decl_base_sptr second,
3369 		       diff_context_sptr ctxt)
3370 {
3371 
3372   diff_sptr d;
3373 
3374   ((d = try_to_diff<function_decl>(first, second, ctxt))
3375    || (d = try_to_diff<var_decl>(first, second, ctxt))
3376    || (d = try_to_diff_distinct_kinds(first, second, ctxt)));
3377 
3378    ABG_ASSERT(d);
3379 
3380   return d;
3381 }
3382 
3383 /// Compute the difference between two decls.  The decls can represent
3384 /// either type declarations, or non-type declaration.
3385 ///
3386 /// Note that the two decls must have been created in the same @ref
3387 /// environment, otherwise, this function aborts.
3388 ///
3389 /// @param first the first decl to consider.
3390 ///
3391 /// @param second the second decl to consider.
3392 ///
3393 /// @param ctxt the diff context to use.
3394 ///
3395 /// @return the resulting diff, or NULL if the diff could not be
3396 /// computed.
3397 diff_sptr
compute_diff(const decl_base_sptr first,const decl_base_sptr second,diff_context_sptr ctxt)3398 compute_diff(const decl_base_sptr	first,
3399 	     const decl_base_sptr	second,
3400 	     diff_context_sptr		ctxt)
3401 {
3402   if (!first || !second)
3403     return diff_sptr();
3404 
3405   diff_sptr d;
3406   if (is_type(first) && is_type(second))
3407     d = compute_diff_for_types(first, second, ctxt);
3408   else
3409     d = compute_diff_for_decls(first, second, ctxt);
3410   ABG_ASSERT(d);
3411   return d;
3412 }
3413 
3414 /// Compute the difference between two types.
3415 ///
3416 /// Note that the two types must have been created in the same @ref
3417 /// environment, otherwise, this function aborts.
3418 ///
3419 /// @param first the first type to consider.
3420 ///
3421 /// @param second the second type to consider.
3422 ///
3423 /// @param ctxt the diff context to use.
3424 ///
3425 /// @return the resulting diff, or NULL if the diff couldn't be
3426 /// computed.
3427 diff_sptr
compute_diff(const type_base_sptr first,const type_base_sptr second,diff_context_sptr ctxt)3428 compute_diff(const type_base_sptr	first,
3429 	     const type_base_sptr	second,
3430 	     diff_context_sptr		ctxt)
3431 {
3432   decl_base_sptr f = get_type_declaration(first),
3433     s = get_type_declaration(second);
3434 
3435   diff_sptr d = compute_diff_for_types(f,s, ctxt);
3436   ABG_ASSERT(d);
3437   return d;
3438 }
3439 
3440 /// Get a copy of the pretty representation of a diff node.
3441 ///
3442 /// @param d the diff node to consider.
3443 ///
3444 /// @return the pretty representation string.
3445 string
get_pretty_representation(diff * d)3446 get_pretty_representation(diff* d)
3447 {
3448   if (!d)
3449     return "";
3450   string prefix= "diff of ";
3451   return prefix + get_pretty_representation(d->first_subject());
3452 }
3453 
3454 // <var_diff stuff>
3455 
3456 /// Populate the vector of children node of the @ref diff base type
3457 /// sub-object of this instance of @ref var_diff.
3458 ///
3459 /// The children node can then later be retrieved using
3460 /// diff::children_node().
3461 void
chain_into_hierarchy()3462 var_diff::chain_into_hierarchy()
3463 {append_child_node(type_diff());}
3464 
3465 /// @return the pretty representation for this current instance of
3466 /// @ref var_diff.
3467 const string&
get_pretty_representation() const3468 var_diff::get_pretty_representation() const
3469 {
3470   if (diff::priv_->pretty_representation_.empty())
3471     {
3472       std::ostringstream o;
3473       o << "var_diff["
3474 	<< first_subject()->get_pretty_representation()
3475 	<< ", "
3476 	<< second_subject()->get_pretty_representation()
3477 	<< "]";
3478       diff::priv_->pretty_representation_ = o.str();
3479     }
3480   return diff::priv_->pretty_representation_;
3481 }
3482 /// Constructor for @ref var_diff.
3483 ///
3484 /// @param first the first instance of @ref var_decl to consider in
3485 /// the diff.
3486 ///
3487 /// @param second the second instance of @ref var_decl to consider in
3488 /// the diff.
3489 ///
3490 /// @param type_diff the diff between types of the instances of
3491 /// var_decl.
3492 ///
3493 /// @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)3494 var_diff::var_diff(var_decl_sptr	first,
3495 		   var_decl_sptr	second,
3496 		   diff_sptr		type_diff,
3497 		   diff_context_sptr	ctxt)
3498   : decl_diff_base(first, second, ctxt),
3499     priv_(new priv)
3500 {priv_->type_diff_ = type_diff;}
3501 
3502 /// Getter for the first @ref var_decl of the diff.
3503 ///
3504 /// @return the first @ref var_decl of the diff.
3505 var_decl_sptr
first_var() const3506 var_diff::first_var() const
3507 {return dynamic_pointer_cast<var_decl>(first_subject());}
3508 
3509 /// Getter for the second @ref var_decl of the diff.
3510 ///
3511 /// @return the second @ref var_decl of the diff.
3512 var_decl_sptr
second_var() const3513 var_diff::second_var() const
3514 {return dynamic_pointer_cast<var_decl>(second_subject());}
3515 
3516 /// Getter for the diff of the types of the instances of @ref
3517 /// var_decl.
3518 ///
3519 /// @return the diff of the types of the instances of @ref var_decl.
3520 diff_sptr
type_diff() const3521 var_diff::type_diff() const
3522 {
3523   if (diff_sptr result = priv_->type_diff_.lock())
3524     return result;
3525   else
3526     {
3527       result = compute_diff(first_var()->get_type(),
3528 			    second_var()->get_type(),
3529 			    context());
3530       context()->keep_diff_alive(result);
3531       priv_->type_diff_ = result;
3532       return result;
3533     }
3534 }
3535 
3536 /// Return true iff the diff node has a change.
3537 ///
3538 /// @return true iff the diff node has a change.
3539 bool
has_changes() const3540 var_diff::has_changes() const
3541 {return *first_var() != *second_var();}
3542 
3543 /// @return the kind of local change carried by the current diff node.
3544 /// The value returned is zero if the current node carries no local
3545 /// change.
3546 enum change_kind
has_local_changes() const3547 var_diff::has_local_changes() const
3548 {
3549   ir::change_kind k = ir::NO_CHANGE_KIND;
3550   if (!equals(*first_var(), *second_var(), &k))
3551     return k & ir::ALL_LOCAL_CHANGES_MASK;
3552   return ir::NO_CHANGE_KIND;
3553 }
3554 
3555 /// Report the diff in a serialized form.
3556 ///
3557 /// @param out the stream to serialize the diff to.
3558 ///
3559 /// @param indent the prefix to use for the indentation of this
3560 /// serialization.
3561 void
report(ostream & out,const string & indent) const3562 var_diff::report(ostream& out, const string& indent) const
3563 {
3564   context()->get_reporter()->report(*this, out, indent);
3565 }
3566 
3567 /// Compute the diff between two instances of @ref var_decl.
3568 ///
3569 /// Note that the two decls must have been created in the same @ref
3570 /// environment, otherwise, this function aborts.
3571 ///
3572 /// @param first the first @ref var_decl to consider for the diff.
3573 ///
3574 /// @param second the second @ref var_decl to consider for the diff.
3575 ///
3576 /// @param ctxt the diff context to use.
3577 ///
3578 /// @return the resulting diff between the two @ref var_decl.
3579 var_diff_sptr
compute_diff(const var_decl_sptr first,const var_decl_sptr second,diff_context_sptr ctxt)3580 compute_diff(const var_decl_sptr	first,
3581 	     const var_decl_sptr	second,
3582 	     diff_context_sptr		ctxt)
3583 {
3584   var_diff_sptr d(new var_diff(first, second, diff_sptr(), ctxt));
3585   ctxt->initialize_canonical_diff(d);
3586 
3587   return d;
3588 }
3589 
3590 // </var_diff stuff>
3591 
3592 // <pointer_type_def stuff>
3593 
3594 /// Populate the vector of children node of the @ref diff base type
3595 /// sub-object of this instance of @ref pointer_diff.
3596 ///
3597 /// The children node can then later be retrieved using
3598 /// diff::children_node().
3599 void
chain_into_hierarchy()3600 pointer_diff::chain_into_hierarchy()
3601 {append_child_node(underlying_type_diff());}
3602 
3603 /// Constructor for a pointer_diff.
3604 ///
3605 /// @param first the first pointer to consider for the diff.
3606 ///
3607 /// @param second the secon pointer to consider for the diff.
3608 ///
3609 /// @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)3610 pointer_diff::pointer_diff(pointer_type_def_sptr	first,
3611 			   pointer_type_def_sptr	second,
3612 			   diff_sptr			underlying,
3613 			   diff_context_sptr		ctxt)
3614   : type_diff_base(first, second, ctxt),
3615     priv_(new priv(underlying))
3616 {}
3617 
3618 /// Getter for the first subject of a pointer diff
3619 ///
3620 /// @return the first pointer considered in this pointer diff.
3621 const pointer_type_def_sptr
first_pointer() const3622 pointer_diff::first_pointer() const
3623 {return dynamic_pointer_cast<pointer_type_def>(first_subject());}
3624 
3625 /// Getter for the second subject of a pointer diff
3626 ///
3627 /// @return the second pointer considered in this pointer diff.
3628 const pointer_type_def_sptr
second_pointer() const3629 pointer_diff::second_pointer() const
3630 {return dynamic_pointer_cast<pointer_type_def>(second_subject());}
3631 
3632 /// @return the pretty represenation for the current instance of @ref
3633 /// pointer_diff.
3634 const string&
get_pretty_representation() const3635 pointer_diff::get_pretty_representation() const
3636 {
3637   if (diff::priv_->pretty_representation_.empty())
3638     {
3639       std::ostringstream o;
3640       o << "pointer_diff["
3641 	<< first_subject()->get_pretty_representation()
3642 	<< ", "
3643 	<< second_subject()->get_pretty_representation()
3644 	<< "]";
3645       diff::priv_->pretty_representation_ = o.str();
3646     }
3647   return diff::priv_->pretty_representation_;
3648 }
3649 
3650 /// Return true iff the current diff node carries a change.
3651 ///
3652 /// @return true iff the current diff node carries a change.
3653 bool
has_changes() const3654 pointer_diff::has_changes() const
3655 {return first_pointer() != second_pointer();}
3656 
3657 /// @return the kind of local change carried by the current diff node.
3658 /// The value returned is zero if the current node carries no local
3659 /// change.
3660 enum change_kind
has_local_changes() const3661 pointer_diff::has_local_changes() const
3662 {
3663   ir::change_kind k = ir::NO_CHANGE_KIND;
3664   if (!equals(*first_pointer(), *second_pointer(), &k))
3665     return k & ir::ALL_LOCAL_CHANGES_MASK;
3666   return ir::NO_CHANGE_KIND;
3667 }
3668 
3669 /// Getter for the diff between the pointed-to types of the pointers
3670 /// of this diff.
3671 ///
3672 /// @return the diff between the pointed-to types.
3673 diff_sptr
underlying_type_diff() const3674 pointer_diff::underlying_type_diff() const
3675 {return priv_->underlying_type_diff_;}
3676 
3677 /// Setter for the diff between the pointed-to types of the pointers
3678 /// of this diff.
3679 ///
3680 /// @param d the new diff between the pointed-to types of the pointers
3681 /// of this diff.
3682 void
underlying_type_diff(const diff_sptr d)3683 pointer_diff::underlying_type_diff(const diff_sptr d)
3684 {priv_->underlying_type_diff_ = d;}
3685 
3686 /// Report the diff in a serialized form.
3687 ///
3688 /// @param out the stream to serialize the diff to.
3689 ///
3690 /// @param indent the prefix to use for the indentation of this
3691 /// serialization.
3692 void
report(ostream & out,const string & indent) const3693 pointer_diff::report(ostream& out, const string& indent) const
3694 {
3695   context()->get_reporter()->report(*this, out, indent);
3696 }
3697 
3698 /// Compute the diff between between two pointers.
3699 ///
3700 /// Note that the two types must have been created in the same @ref
3701 /// environment, otherwise, this function aborts.
3702 ///
3703 /// @param first the pointer to consider for the diff.
3704 ///
3705 /// @param second the pointer to consider for the diff.
3706 ///
3707 /// @return the resulting diff between the two pointers.
3708 ///
3709 /// @param ctxt the diff context to use.
3710 pointer_diff_sptr
compute_diff(pointer_type_def_sptr first,pointer_type_def_sptr second,diff_context_sptr ctxt)3711 compute_diff(pointer_type_def_sptr	first,
3712 	     pointer_type_def_sptr	second,
3713 	     diff_context_sptr		ctxt)
3714 {
3715   diff_sptr d = compute_diff_for_types(first->get_pointed_to_type(),
3716 				       second->get_pointed_to_type(),
3717 				       ctxt);
3718   pointer_diff_sptr result(new pointer_diff(first, second, d, ctxt));
3719   ctxt->initialize_canonical_diff(result);
3720 
3721   return result;
3722 }
3723 
3724 // </pointer_type_def>
3725 
3726 // <subrange_diff >
3727 
3728 /// Constructor of the @ref subrange_diff diff node type.
3729 ///
3730 /// @param first the first subrange type to consider for the diff.
3731 ///
3732 /// @param second the second subrange type to consider for the diff.
3733 ///
3734 /// @param underlying_type_diff the underlying type diff between @p
3735 /// first and @p second.
3736 ///
3737 /// @param ctxt the diff context to use.
subrange_diff(const array_type_def::subrange_sptr & first,const array_type_def::subrange_sptr & second,const diff_sptr & underlying_type_diff,const diff_context_sptr ctxt)3738 subrange_diff::subrange_diff
3739 (const array_type_def::subrange_sptr&	first,
3740  const array_type_def::subrange_sptr&	second,
3741  const diff_sptr&			underlying_type_diff,
3742  const diff_context_sptr		ctxt)
3743   : type_diff_base(first, second, ctxt),
3744     priv_(new priv(underlying_type_diff))
3745 {}
3746 
3747 
3748 /// Getter of the first subrange of the current instance @ref
3749 /// subrange_diff.
3750 ///
3751 /// @return The first subrange of the current instance @ref subrange_diff.
3752 const array_type_def::subrange_sptr
first_subrange() const3753 subrange_diff::first_subrange() const
3754 {return is_subrange_type(first_subject());}
3755 
3756 /// Getter of the second subrange of the current instance @ref
3757 /// subrange_diff.
3758 ///
3759 /// @return The second subrange of the current instance @ref
3760 /// subrange_diff.
3761 const array_type_def::subrange_sptr
second_subrange() const3762 subrange_diff::second_subrange() const
3763 {return is_subrange_type(second_subject());}
3764 
3765 /// Getter of the diff node of the underlying types of the current
3766 /// @ref subrange_diff diff node.
3767 ///
3768 /// @return The diff node of the underlying types of the current @ref
3769 /// subrange_diff diff node.
3770 const diff_sptr
underlying_type_diff() const3771 subrange_diff::underlying_type_diff() const
3772 {return priv_->underlying_type_diff_;}
3773 
3774 /// Getter the pretty representation of the @ref subrange_diff diff
3775 /// node.
3776 ///
3777 /// @return The pretty representation of the @ref subrange_diff diff node.
3778 const string&
get_pretty_representation() const3779 subrange_diff::get_pretty_representation() const
3780 {
3781     if (diff::priv_->pretty_representation_.empty())
3782     {
3783       std::ostringstream o;
3784       o << "subrange_diff["
3785 	<< first_subject()->get_pretty_representation()
3786 	<< ","
3787 	<< second_subject()->get_pretty_representation()
3788 	<< "]";
3789       diff::priv_->pretty_representation_ = o.str();
3790     }
3791     return diff::priv_->pretty_representation_;
3792 }
3793 
3794 /// Test if the current @ref subrange_diff node carries any change.
3795 ///
3796 /// @return true iff the current @ref subrange_diff node carries any
3797 /// change.
3798 bool
has_changes() const3799 subrange_diff::has_changes() const
3800 {return *first_subrange() != *second_subrange();}
3801 
3802 /// Test if the current @ref subrange_diff node carries any local
3803 /// change.
3804 ///
3805 /// @return true iff the current @ref subrange_diff node carries any
3806 /// local change.
3807 enum change_kind
has_local_changes() const3808 subrange_diff::has_local_changes() const
3809 {
3810   ir::change_kind k = ir::NO_CHANGE_KIND;
3811   if (!equals(*first_subrange(), *second_subrange(), &k))
3812     return k & ir::ALL_LOCAL_CHANGES_MASK;
3813   return ir::NO_CHANGE_KIND;
3814 }
3815 
3816 /// Report about the changes carried by this node.
3817 ///
3818 /// @param out the output stream to send the report to.
3819 ///
3820 /// @param indent the indentation string to use.
3821 void
report(ostream & out,const string & indent) const3822 subrange_diff::report(ostream& out, const string& indent) const
3823 {context()->get_reporter()->report(*this, out, indent);}
3824 
3825 /// Populate the vector of children node of the @ref diff base type
3826 /// sub-object of this instance of @ref subrange_diff.
3827 ///
3828 /// The children node can then later be retrieved using
3829 /// diff::children_node().
3830 void
chain_into_hierarchy()3831 subrange_diff::chain_into_hierarchy()
3832 {append_child_node(underlying_type_diff());}
3833 
3834 /// Compute the diff between two instances of @ref subrange_diff.
3835 ///
3836 /// Note that the two decls must have been created in the same @ref
3837 /// environment, otherwise, this function aborts.
3838 ///
3839 /// @param first the first @ref subrange_diff to consider for the diff.
3840 ///
3841 /// @param second the second @ref subrange_diff to consider for the diff.
3842 ///
3843 /// @param ctxt the diff context to use.
3844 ///
3845 /// @return the resulting diff between the two @ref subrange_diff.
3846 subrange_diff_sptr
compute_diff(array_type_def::subrange_sptr first,array_type_def::subrange_sptr second,diff_context_sptr ctxt)3847 compute_diff(array_type_def::subrange_sptr first,
3848 	     array_type_def::subrange_sptr second,
3849 	     diff_context_sptr ctxt)
3850 {
3851   diff_sptr d = compute_diff_for_types(first->get_underlying_type(),
3852 				       second->get_underlying_type(),
3853 				       ctxt);
3854 
3855   subrange_diff_sptr result(new subrange_diff(first, second, d, ctxt));
3856   ctxt->initialize_canonical_diff(result);
3857   return result;
3858 }
3859 
3860 //</subrange_diff >
3861 
3862 
3863 // <array_type_def>
3864 
3865 /// Populate the vector of children node of the @ref diff base type
3866 /// sub-object of this instance of @ref array_diff.
3867 ///
3868 /// The children node can then later be retrieved using
3869 /// diff::children_node().
3870 void
chain_into_hierarchy()3871 array_diff::chain_into_hierarchy()
3872 {append_child_node(element_type_diff());}
3873 
3874 /// Constructor for array_diff
3875 ///
3876 /// @param first the first array_type of the diff.
3877 ///
3878 /// @param second the second array_type of the diff.
3879 ///
3880 /// @param element_type_diff the diff between the two array element
3881 /// types.
3882 ///
3883 /// @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)3884 array_diff::array_diff(const array_type_def_sptr	first,
3885 		       const array_type_def_sptr	second,
3886 		       diff_sptr			element_type_diff,
3887 		       diff_context_sptr		ctxt)
3888   : type_diff_base(first, second, ctxt),
3889     priv_(new priv(element_type_diff))
3890 {}
3891 
3892 /// Getter for the first array of the diff.
3893 ///
3894 /// @return the first array of the diff.
3895 const array_type_def_sptr
first_array() const3896 array_diff::first_array() const
3897 {return dynamic_pointer_cast<array_type_def>(first_subject());}
3898 
3899 /// Getter for the second array of the diff.
3900 ///
3901 /// @return for the second array of the diff.
3902 const array_type_def_sptr
second_array() const3903 array_diff::second_array() const
3904 {return dynamic_pointer_cast<array_type_def>(second_subject());}
3905 
3906 /// Getter for the diff between the two types of array elements.
3907 ///
3908 /// @return the diff between the two types of array elements.
3909 const diff_sptr&
element_type_diff() const3910 array_diff::element_type_diff() const
3911 {return priv_->element_type_diff_;}
3912 
3913 /// Setter for the diff between the two array element types.
3914 ///
3915 /// @param d the new diff betweend the two array element types.
3916 void
element_type_diff(diff_sptr d)3917 array_diff::element_type_diff(diff_sptr d)
3918 {priv_->element_type_diff_ = d;}
3919 
3920 /// @return the pretty representation for the current instance of @ref
3921 /// array_diff.
3922 const string&
get_pretty_representation() const3923 array_diff::get_pretty_representation() const
3924 {
3925   if (diff::priv_->pretty_representation_.empty())
3926     {
3927       std::ostringstream o;
3928       o << "array_diff["
3929 	<< first_subject()->get_pretty_representation()
3930 	<< ", "
3931 	<< second_subject()->get_pretty_representation()
3932 	<< "]";
3933       diff::priv_->pretty_representation_ = o.str();
3934     }
3935   return diff::priv_->pretty_representation_;
3936 }
3937 
3938 /// Return true iff the current diff node carries a change.
3939 ///
3940 /// @return true iff the current diff node carries a change.
3941 bool
has_changes() const3942 array_diff::has_changes() const
3943 {
3944   bool l = false;
3945 
3946   //  the array element types match check for differing dimensions
3947   //  etc...
3948   array_type_def_sptr
3949     f = dynamic_pointer_cast<array_type_def>(first_subject()),
3950     s = dynamic_pointer_cast<array_type_def>(second_subject());
3951 
3952   if (f->get_name() != s->get_name())
3953     l |= true;
3954   if (f->get_size_in_bits() != s->get_size_in_bits())
3955     l |= true;
3956   if (f->get_alignment_in_bits() != s->get_alignment_in_bits())
3957     l |= true;
3958 
3959   l |=  element_type_diff()
3960     ? element_type_diff()->has_changes()
3961     : false;
3962 
3963   return l;
3964 }
3965 
3966 
3967 /// @return the kind of local change carried by the current diff node.
3968 /// The value returned is zero if the current node carries no local
3969 /// change.
3970 enum change_kind
has_local_changes() const3971 array_diff::has_local_changes() const
3972 {
3973   ir::change_kind k = ir::NO_CHANGE_KIND;
3974   if (!equals(*first_array(), *second_array(), &k))
3975     return k & ir::ALL_LOCAL_CHANGES_MASK;
3976   return ir::NO_CHANGE_KIND;
3977 }
3978 
3979 /// Report the diff in a serialized form.
3980 ///
3981 /// @param out the output stream to serialize the dif to.
3982 ///
3983 /// @param indent the string to use for indenting the report.
3984 void
report(ostream & out,const string & indent) const3985 array_diff::report(ostream& out, const string& indent) const
3986 {
3987   context()->get_reporter()->report(*this, out, indent);
3988 }
3989 
3990 /// Compute the diff between two arrays.
3991 ///
3992 /// Note that the two types must have been created in the same @ref
3993 /// environment, otherwise, this function aborts.
3994 ///
3995 /// @param first the first array to consider for the diff.
3996 ///
3997 /// @param second the second array to consider for the diff.
3998 ///
3999 /// @param ctxt the diff context to use.
4000 array_diff_sptr
compute_diff(array_type_def_sptr first,array_type_def_sptr second,diff_context_sptr ctxt)4001 compute_diff(array_type_def_sptr	first,
4002 	     array_type_def_sptr	second,
4003 	     diff_context_sptr		ctxt)
4004 {
4005   diff_sptr d = compute_diff_for_types(first->get_element_type(),
4006 				       second->get_element_type(),
4007 				       ctxt);
4008   array_diff_sptr result(new array_diff(first, second, d, ctxt));
4009   ctxt->initialize_canonical_diff(result);
4010   return result;
4011 }
4012 // </array_type_def>
4013 
4014 // <reference_type_def>
4015 
4016 /// Populate the vector of children node of the @ref diff base type
4017 /// sub-object of this instance of @ref reference_diff.
4018 ///
4019 /// The children node can then later be retrieved using
4020 /// diff::children_node().
4021 void
chain_into_hierarchy()4022 reference_diff::chain_into_hierarchy()
4023 {append_child_node(underlying_type_diff());}
4024 
4025 /// Constructor for reference_diff
4026 ///
4027 /// @param first the first reference_type of the diff.
4028 ///
4029 /// @param second the second reference_type of the diff.
4030 ///
4031 /// @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)4032 reference_diff::reference_diff(const reference_type_def_sptr	first,
4033 			       const reference_type_def_sptr	second,
4034 			       diff_sptr			underlying,
4035 			       diff_context_sptr		ctxt)
4036   : type_diff_base(first, second, ctxt),
4037 	priv_(new priv(underlying))
4038 {}
4039 
4040 /// Getter for the first reference of the diff.
4041 ///
4042 /// @return the first reference of the diff.
4043 reference_type_def_sptr
first_reference() const4044 reference_diff::first_reference() const
4045 {return dynamic_pointer_cast<reference_type_def>(first_subject());}
4046 
4047 /// Getter for the second reference of the diff.
4048 ///
4049 /// @return for the second reference of the diff.
4050 reference_type_def_sptr
second_reference() const4051 reference_diff::second_reference() const
4052 {return dynamic_pointer_cast<reference_type_def>(second_subject());}
4053 
4054 
4055 /// Getter for the diff between the two referred-to types.
4056 ///
4057 /// @return the diff between the two referred-to types.
4058 const diff_sptr&
underlying_type_diff() const4059 reference_diff::underlying_type_diff() const
4060 {return priv_->underlying_type_diff_;}
4061 
4062 /// Setter for the diff between the two referred-to types.
4063 ///
4064 /// @param d the new diff betweend the two referred-to types.
4065 diff_sptr&
underlying_type_diff(diff_sptr d)4066 reference_diff::underlying_type_diff(diff_sptr d)
4067 {
4068   priv_->underlying_type_diff_ = d;
4069   return priv_->underlying_type_diff_;
4070 }
4071 
4072 /// @return the pretty representation for the current instance of @ref
4073 /// reference_diff.
4074 const string&
get_pretty_representation() const4075 reference_diff::get_pretty_representation() const
4076 {
4077   if (diff::priv_->pretty_representation_.empty())
4078     {
4079       std::ostringstream o;
4080       o << "reference_diff["
4081 	<< first_subject()->get_pretty_representation()
4082 	<< ", "
4083 	<< second_subject()->get_pretty_representation()
4084 	<< "]";
4085       diff::priv_->pretty_representation_ = o.str();
4086     }
4087   return diff::priv_->pretty_representation_;
4088 }
4089 
4090 /// Return true iff the current diff node carries a change.
4091 ///
4092 /// @return true iff the current diff node carries a change.
4093 bool
has_changes() const4094 reference_diff::has_changes() const
4095 {
4096   return first_reference() != second_reference();
4097 }
4098 
4099 /// @return the kind of local change carried by the current diff node.
4100 /// The value returned is zero if the current node carries no local
4101 /// change.
4102 enum change_kind
has_local_changes() const4103 reference_diff::has_local_changes() const
4104 {
4105   ir::change_kind k = ir::NO_CHANGE_KIND;
4106   if (!equals(*first_reference(), *second_reference(), &k))
4107     return k & ir::ALL_LOCAL_CHANGES_MASK;
4108   return ir::NO_CHANGE_KIND;
4109 }
4110 
4111 /// Report the diff in a serialized form.
4112 ///
4113 /// @param out the output stream to serialize the dif to.
4114 ///
4115 /// @param indent the string to use for indenting the report.
4116 void
report(ostream & out,const string & indent) const4117 reference_diff::report(ostream& out, const string& indent) const
4118 {
4119   context()->get_reporter()->report(*this, out, indent);
4120 }
4121 
4122 /// Compute the diff between two references.
4123 ///
4124 /// Note that the two types must have been created in the same @ref
4125 /// environment, otherwise, this function aborts.
4126 ///
4127 /// @param first the first reference to consider for the diff.
4128 ///
4129 /// @param second the second reference to consider for the diff.
4130 ///
4131 /// @param ctxt the diff context to use.
4132 reference_diff_sptr
compute_diff(reference_type_def_sptr first,reference_type_def_sptr second,diff_context_sptr ctxt)4133 compute_diff(reference_type_def_sptr	first,
4134 	     reference_type_def_sptr	second,
4135 	     diff_context_sptr		ctxt)
4136 {
4137   diff_sptr d = compute_diff_for_types(first->get_pointed_to_type(),
4138 				       second->get_pointed_to_type(),
4139 				       ctxt);
4140   reference_diff_sptr result(new reference_diff(first, second, d, ctxt));
4141   ctxt->initialize_canonical_diff(result);
4142   return result;
4143 }
4144 // </reference_type_def>
4145 
4146 // <qualified_type_diff stuff>
4147 
4148 /// Populate the vector of children node of the @ref diff base type
4149 /// sub-object of this instance of @ref qualified_type_diff.
4150 ///
4151 /// The children node can then later be retrieved using
4152 /// diff::children_node().
4153 void
chain_into_hierarchy()4154 qualified_type_diff::chain_into_hierarchy()
4155 {append_child_node(leaf_underlying_type_diff());}
4156 
4157 /// Constructor for qualified_type_diff.
4158 ///
4159 /// @param first the first qualified type of the diff.
4160 ///
4161 /// @param second the second qualified type of the diff.
4162 ///
4163 /// @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)4164 qualified_type_diff::qualified_type_diff(qualified_type_def_sptr	first,
4165 					 qualified_type_def_sptr	second,
4166 					 diff_sptr			under,
4167 					 diff_context_sptr		ctxt)
4168   : type_diff_base(first, second, ctxt),
4169     priv_(new priv(under))
4170 {}
4171 
4172 /// Getter for the first qualified type of the diff.
4173 ///
4174 /// @return the first qualified type of the diff.
4175 const qualified_type_def_sptr
first_qualified_type() const4176 qualified_type_diff::first_qualified_type() const
4177 {return dynamic_pointer_cast<qualified_type_def>(first_subject());}
4178 
4179 /// Getter for the second qualified type of the diff.
4180 ///
4181 /// @return the second qualified type of the diff.
4182 const qualified_type_def_sptr
second_qualified_type() const4183 qualified_type_diff::second_qualified_type() const
4184 {return dynamic_pointer_cast<qualified_type_def>(second_subject());}
4185 
4186 /// Getter for the diff between the underlying types of the two
4187 /// qualified types.
4188 ///
4189 /// @return the diff between the underlying types of the two qualified
4190 /// types.
4191 diff_sptr
underlying_type_diff() const4192 qualified_type_diff::underlying_type_diff() const
4193 {return priv_->underlying_type_diff;}
4194 
4195 /// Getter for the diff between the most underlying non-qualified
4196 /// types of two qualified types.
4197 ///
4198 /// @return the diff between the most underlying non-qualified types
4199 /// of two qualified types.
4200 diff_sptr
leaf_underlying_type_diff() const4201 qualified_type_diff::leaf_underlying_type_diff() const
4202 {
4203   if (!priv_->leaf_underlying_type_diff)
4204     priv_->leaf_underlying_type_diff
4205       = compute_diff_for_types(get_leaf_type(first_qualified_type()),
4206 			       get_leaf_type(second_qualified_type()),
4207 			       context());
4208 
4209   return priv_->leaf_underlying_type_diff;
4210 }
4211 
4212 /// Setter for the diff between the underlying types of the two
4213 /// qualified types.
4214 ///
4215 /// @return the diff between the underlying types of the two qualified
4216 /// types.
4217 void
underlying_type_diff(const diff_sptr d)4218 qualified_type_diff::underlying_type_diff(const diff_sptr d)
4219 {priv_->underlying_type_diff = d;}
4220 
4221 /// @return the pretty representation of the current instance of @ref
4222 /// qualified_type_diff.
4223 const string&
get_pretty_representation() const4224 qualified_type_diff::get_pretty_representation() const
4225 {
4226   if (diff::priv_->pretty_representation_.empty())
4227     {
4228       std::ostringstream o;
4229       o << "qualified_type_diff["
4230 	<< first_subject()->get_pretty_representation()
4231 	<< ", "
4232 	<< second_subject()->get_pretty_representation()
4233 	<< "]";
4234       diff::priv_->pretty_representation_ = o.str();
4235     }
4236   return diff::priv_->pretty_representation_;
4237 }
4238 
4239 /// Return true iff the current diff node carries a change.
4240 ///
4241 /// @return true iff the current diff node carries a change.
4242 bool
has_changes() const4243 qualified_type_diff::has_changes() const
4244 {return first_qualified_type() != second_qualified_type();}
4245 
4246 /// @return the kind of local change carried by the current diff node.
4247 /// The value returned is zero if the current node carries no local
4248 /// change.
4249 enum change_kind
has_local_changes() const4250 qualified_type_diff::has_local_changes() const
4251 {
4252   ir::change_kind k = ir::NO_CHANGE_KIND;
4253   if (!equals(*first_qualified_type(), *second_qualified_type(), &k))
4254     return k & ir::ALL_LOCAL_CHANGES_MASK;
4255   return ir::NO_CHANGE_KIND;
4256 }
4257 
4258 /// Report the diff in a serialized form.
4259 ///
4260 /// @param out the output stream to serialize to.
4261 ///
4262 /// @param indent the string to use to indent the lines of the report.
4263 void
report(ostream & out,const string & indent) const4264 qualified_type_diff::report(ostream& out, const string& indent) const
4265 {
4266   context()->get_reporter()->report(*this, out, indent);
4267 }
4268 
4269 /// Compute the diff between two qualified types.
4270 ///
4271 /// Note that the two types must have been created in the same @ref
4272 /// environment, otherwise, this function aborts.
4273 ///
4274 /// @param first the first qualified type to consider for the diff.
4275 ///
4276 /// @param second the second qualified type to consider for the diff.
4277 ///
4278 /// @param ctxt the diff context to use.
4279 qualified_type_diff_sptr
compute_diff(const qualified_type_def_sptr first,const qualified_type_def_sptr second,diff_context_sptr ctxt)4280 compute_diff(const qualified_type_def_sptr	first,
4281 	     const qualified_type_def_sptr	second,
4282 	     diff_context_sptr			ctxt)
4283 {
4284   diff_sptr d = compute_diff_for_types(first->get_underlying_type(),
4285 				       second->get_underlying_type(),
4286 				       ctxt);
4287   qualified_type_diff_sptr result(new qualified_type_diff(first, second,
4288 							  d, ctxt));
4289   ctxt->initialize_canonical_diff(result);
4290   return result;
4291 }
4292 
4293 // </qualified_type_diff stuff>
4294 
4295 // <enum_diff stuff>
4296 
4297 /// Clear the lookup tables useful for reporting an enum_diff.
4298 ///
4299 /// This function must be updated each time a lookup table is added or
4300 /// removed from the class_diff::priv.
4301 void
clear_lookup_tables()4302 enum_diff::clear_lookup_tables()
4303 {
4304   priv_->deleted_enumerators_.clear();
4305   priv_->inserted_enumerators_.clear();
4306   priv_->changed_enumerators_.clear();
4307 }
4308 
4309 /// Tests if the lookup tables are empty.
4310 ///
4311 /// @return true if the lookup tables are empty, false otherwise.
4312 bool
lookup_tables_empty() const4313 enum_diff::lookup_tables_empty() const
4314 {
4315   return (priv_->deleted_enumerators_.empty()
4316 	  && priv_->inserted_enumerators_.empty()
4317 	  && priv_->changed_enumerators_.empty());
4318 }
4319 
4320 /// If the lookup tables are not yet built, walk the differences and
4321 /// fill the lookup tables.
4322 void
ensure_lookup_tables_populated()4323 enum_diff::ensure_lookup_tables_populated()
4324 {
4325   if (!lookup_tables_empty())
4326     return;
4327 
4328   {
4329     edit_script e = priv_->enumerators_changes_;
4330 
4331     for (vector<deletion>::const_iterator it = e.deletions().begin();
4332 	 it != e.deletions().end();
4333 	 ++it)
4334       {
4335 	unsigned i = it->index();
4336 	const enum_type_decl::enumerator& n =
4337 	  first_enum()->get_enumerators()[i];
4338 	const string& name = n.get_name();
4339 	ABG_ASSERT(priv_->deleted_enumerators_.find(n.get_name())
4340 	       == priv_->deleted_enumerators_.end());
4341 	priv_->deleted_enumerators_[name] = n;
4342       }
4343 
4344     for (vector<insertion>::const_iterator it = e.insertions().begin();
4345 	 it != e.insertions().end();
4346 	 ++it)
4347       {
4348 	for (vector<unsigned>::const_iterator iit =
4349 	       it->inserted_indexes().begin();
4350 	     iit != it->inserted_indexes().end();
4351 	     ++iit)
4352 	  {
4353 	    unsigned i = *iit;
4354 	    const enum_type_decl::enumerator& n =
4355 	      second_enum()->get_enumerators()[i];
4356 	    const string& name = n.get_name();
4357 	    ABG_ASSERT(priv_->inserted_enumerators_.find(n.get_name())
4358 		   == priv_->inserted_enumerators_.end());
4359 	    string_enumerator_map::const_iterator j =
4360 	      priv_->deleted_enumerators_.find(name);
4361 	    if (j == priv_->deleted_enumerators_.end())
4362 	      priv_->inserted_enumerators_[name] = n;
4363 	    else
4364 	      {
4365 		if (j->second != n)
4366 		  priv_->changed_enumerators_[j->first] =
4367 		    std::make_pair(j->second, n);
4368 		priv_->deleted_enumerators_.erase(j);
4369 	      }
4370 	  }
4371       }
4372   }
4373 }
4374 
4375 /// Populate the vector of children node of the @ref diff base type
4376 /// sub-object of this instance of @ref enum_diff.
4377 ///
4378 /// The children node can then later be retrieved using
4379 /// diff::children_node().
4380 void
chain_into_hierarchy()4381 enum_diff::chain_into_hierarchy()
4382 {append_child_node(underlying_type_diff());}
4383 
4384 /// Constructor for enum_diff.
4385 ///
4386 /// @param first the first enum type of the diff.
4387 ///
4388 /// @param second the second enum type of the diff.
4389 ///
4390 /// @param underlying_type_diff the diff of the two underlying types
4391 /// of the two enum types.
4392 ///
4393 /// @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)4394 enum_diff::enum_diff(const enum_type_decl_sptr	first,
4395 		     const enum_type_decl_sptr	second,
4396 		     const diff_sptr		underlying_type_diff,
4397 		     const diff_context_sptr	ctxt)
4398   : type_diff_base(first, second, ctxt),
4399     priv_(new priv(underlying_type_diff))
4400 {}
4401 
4402 /// @return the first enum of the diff.
4403 const enum_type_decl_sptr
first_enum() const4404 enum_diff::first_enum() const
4405 {return dynamic_pointer_cast<enum_type_decl>(first_subject());}
4406 
4407 /// @return the second enum of the diff.
4408 const enum_type_decl_sptr
second_enum() const4409 enum_diff::second_enum() const
4410 {return dynamic_pointer_cast<enum_type_decl>(second_subject());}
4411 
4412 /// @return the diff of the two underlying enum types.
4413 diff_sptr
underlying_type_diff() const4414 enum_diff::underlying_type_diff() const
4415 {return priv_->underlying_type_diff_;}
4416 
4417 /// @return a map of the enumerators that were deleted.
4418 const string_enumerator_map&
deleted_enumerators() const4419 enum_diff::deleted_enumerators() const
4420 {return priv_->deleted_enumerators_;}
4421 
4422 /// @return a map of the enumerators that were inserted
4423 const string_enumerator_map&
inserted_enumerators() const4424 enum_diff::inserted_enumerators() const
4425 {return priv_->inserted_enumerators_;}
4426 
4427 /// @return a map of the enumerators that were changed
4428 const string_changed_enumerator_map&
changed_enumerators() const4429 enum_diff::changed_enumerators() const
4430 {return priv_->changed_enumerators_;}
4431 
4432 /// @return the pretty representation of the current instance of @ref
4433 /// enum_diff.
4434 const string&
get_pretty_representation() const4435 enum_diff::get_pretty_representation() const
4436 {
4437   if (diff::priv_->pretty_representation_.empty())
4438     {
4439       std::ostringstream o;
4440       o << "enum_diff["
4441 	<< first_subject()->get_pretty_representation()
4442 	<< ", "
4443 	<< second_subject()->get_pretty_representation()
4444 	<< "]";
4445       diff::priv_->pretty_representation_ = o.str();
4446     }
4447   return diff::priv_->pretty_representation_;
4448 }
4449 
4450 /// Return true iff the current diff node carries a change.
4451 ///
4452 /// @return true iff the current diff node carries a change.
4453 bool
has_changes() const4454 enum_diff::has_changes() const
4455 {return first_enum() != second_enum();}
4456 
4457 /// @return the kind of local change carried by the current diff node.
4458 /// The value returned is zero if the current node carries no local
4459 /// change.
4460 enum change_kind
has_local_changes() const4461 enum_diff::has_local_changes() const
4462 {
4463   ir::change_kind k = ir::NO_CHANGE_KIND;
4464   if (!equals(*first_enum(), *second_enum(), &k))
4465     return k & ir::ALL_LOCAL_CHANGES_MASK;
4466   return ir::NO_CHANGE_KIND;
4467 }
4468 
4469 /// Report the differences between the two enums.
4470 ///
4471 /// @param out the output stream to send the report to.
4472 ///
4473 /// @param indent the string to use for indentation.
4474 void
report(ostream & out,const string & indent) const4475 enum_diff::report(ostream& out, const string& indent) const
4476 {
4477   context()->get_reporter()->report(*this, out, indent);
4478 }
4479 
4480 /// Compute the set of changes between two instances of @ref
4481 /// enum_type_decl.
4482 ///
4483 /// Note that the two types must have been created in the same @ref
4484 /// environment, otherwise, this function aborts.
4485 ///
4486 /// @param first a pointer to the first enum_type_decl to consider.
4487 ///
4488 /// @param second a pointer to the second enum_type_decl to consider.
4489 ///
4490 /// @return the resulting diff of the two enums @p first and @p
4491 /// second.
4492 ///
4493 /// @param ctxt the diff context to use.
4494 enum_diff_sptr
compute_diff(const enum_type_decl_sptr first,const enum_type_decl_sptr second,diff_context_sptr ctxt)4495 compute_diff(const enum_type_decl_sptr first,
4496 	     const enum_type_decl_sptr second,
4497 	     diff_context_sptr ctxt)
4498 {
4499   diff_sptr ud = compute_diff_for_types(first->get_underlying_type(),
4500 					second->get_underlying_type(),
4501 					ctxt);
4502   enum_diff_sptr d(new enum_diff(first, second, ud, ctxt));
4503   if (first != second)
4504     {
4505       compute_diff(first->get_enumerators().begin(),
4506 		   first->get_enumerators().end(),
4507 		   second->get_enumerators().begin(),
4508 		   second->get_enumerators().end(),
4509 		   d->priv_->enumerators_changes_);
4510       d->ensure_lookup_tables_populated();
4511     }
4512   ctxt->initialize_canonical_diff(d);
4513 
4514   return d;
4515 }
4516 // </enum_diff stuff>
4517 
4518 // <class_or_union_diff stuff>
4519 
4520 /// Test if the current diff node carries a member type change for a
4521 /// member type which name is the same as the name of a given type
4522 /// declaration.
4523 ///
4524 /// @param d the type declaration which name should be equal to the
4525 /// name of the member type that might have changed.
4526 ///
4527 /// @return the member type that has changed, iff there were a member
4528 /// type (which name is the same as the name of @p d) that changed.
4529 /// Note that the member type that is returned is the new value of the
4530 /// member type that changed.
4531 type_or_decl_base_sptr
member_type_has_changed(decl_base_sptr d) const4532 class_or_union_diff::priv::member_type_has_changed(decl_base_sptr d) const
4533 {
4534   string qname = d->get_qualified_name();
4535   string_diff_sptr_map::const_iterator it =
4536     changed_member_types_.find(qname);
4537 
4538   return ((it == changed_member_types_.end())
4539 	  ? type_or_decl_base_sptr()
4540 	  : it->second->second_subject());
4541 }
4542 
4543 /// Test if the current diff node carries a data member change for a
4544 /// data member which name is the same as the name of a given type
4545 /// declaration.
4546 ///
4547 /// @param d the type declaration which name should be equal to the
4548 /// name of the data member that might have changed.
4549 ///
4550 /// @return the data member that has changed, iff there were a data
4551 /// member type (which name is the same as the name of @p d) that
4552 /// changed.  Note that the data member that is returned is the new
4553 /// value of the data member that changed.
4554 decl_base_sptr
subtype_changed_dm(decl_base_sptr d) const4555 class_or_union_diff::priv::subtype_changed_dm(decl_base_sptr d) const
4556 {
4557   string qname = d->get_qualified_name();
4558   string_var_diff_sptr_map::const_iterator it =
4559     subtype_changed_dm_.find(qname);
4560 
4561   if (it == subtype_changed_dm_.end())
4562     return decl_base_sptr();
4563   return it->second->second_var();
4564 }
4565 
4566 /// Test if the current diff node carries a member class template
4567 /// change for a member class template which name is the same as the
4568 /// name of a given type declaration.
4569 ///
4570 /// @param d the type declaration which name should be equal to the
4571 /// name of the member class template that might have changed.
4572 ///
4573 /// @return the member class template that has changed, iff there were
4574 /// a member class template (which name is the same as the name of @p
4575 /// d) that changed.  Note that the member class template that is
4576 /// returned is the new value of the member class template that
4577 /// changed.
4578 decl_base_sptr
member_class_tmpl_has_changed(decl_base_sptr d) const4579 class_or_union_diff::priv::member_class_tmpl_has_changed(decl_base_sptr d) const
4580 {
4581   string qname = d->get_qualified_name();
4582   string_diff_sptr_map::const_iterator it =
4583     changed_member_class_tmpls_.find(qname);
4584 
4585   return ((it == changed_member_class_tmpls_.end())
4586 	  ? decl_base_sptr()
4587 	  : dynamic_pointer_cast<decl_base>(it->second->second_subject()));
4588 }
4589 
4590 /// Get the number of non static data members that were deleted.
4591 ///
4592 /// @return the number of non static data members that were deleted.
4593 size_t
get_deleted_non_static_data_members_number() const4594 class_or_union_diff::priv::get_deleted_non_static_data_members_number() const
4595 {
4596   size_t result = 0;
4597 
4598   for (string_decl_base_sptr_map::const_iterator i =
4599 	 deleted_data_members_.begin();
4600        i != deleted_data_members_.end();
4601        ++i)
4602     if (is_member_decl(i->second)
4603 	&& !get_member_is_static(i->second))
4604       ++result;
4605 
4606   return result;
4607 }
4608 
4609 /// Get the number of non static data members that were inserted.
4610 ///
4611 /// @return the number of non static data members that were inserted.
4612 size_t
get_inserted_non_static_data_members_number() const4613 class_or_union_diff::priv::get_inserted_non_static_data_members_number() const
4614 {
4615   size_t result = 0;
4616 
4617   for (string_decl_base_sptr_map::const_iterator i =
4618 	 inserted_data_members_.begin();
4619        i != inserted_data_members_.end();
4620        ++i)
4621     if (is_member_decl(i->second)
4622 	&& !get_member_is_static(i->second))
4623       ++result;
4624 
4625   return result;
4626 }
4627 
4628 /// Get the number of data member sub-type changes carried by the
4629 /// current diff node that were filtered out.
4630 ///
4631 /// @param local_only if true, it means that only (filtered) local
4632 /// changes are considered.
4633 ///
4634 /// @return the number of data member sub-type changes carried by the
4635 /// current diff node that were filtered out.
4636 size_t
count_filtered_subtype_changed_dm(bool local_only)4637 class_or_union_diff::priv::count_filtered_subtype_changed_dm(bool local_only)
4638 {
4639   size_t num_filtered= 0;
4640   for (var_diff_sptrs_type::const_iterator i =
4641 	 sorted_subtype_changed_dm_.begin();
4642        i != sorted_subtype_changed_dm_.end();
4643        ++i)
4644     {
4645       if (local_only)
4646 	{
4647 	  if ((*i)->has_changes()
4648 	      && !(*i)->has_local_changes_to_be_reported())
4649 	    ++num_filtered;
4650 	}
4651       else
4652 	{
4653 	  if ((*i)->is_filtered_out())
4654 	    ++num_filtered;
4655 	}
4656     }
4657   return num_filtered;
4658 }
4659 
4660 /// Get the number of data member changes carried by the current diff
4661 /// node that were filtered out.
4662 ///
4663 /// @param local_only if true, it means that only (filtered) local
4664 /// changes are considered.
4665 ///
4666 /// @return the number of data member changes carried by the current
4667 /// diff node that were filtered out.
4668 size_t
count_filtered_changed_dm(bool local_only)4669 class_or_union_diff::priv::count_filtered_changed_dm(bool local_only)
4670 {
4671   size_t num_filtered= 0;
4672 
4673   for (unsigned_var_diff_sptr_map::const_iterator i = changed_dm_.begin();
4674        i != changed_dm_.end();
4675        ++i)
4676     {
4677       diff_sptr diff = i->second;
4678       if (local_only)
4679 	{
4680 	  if ((diff->has_changes() && !diff->has_local_changes_to_be_reported())
4681 	      || diff->is_filtered_out())
4682 	    ++num_filtered;
4683 	}
4684       else
4685 	{
4686 	  if (diff->is_filtered_out())
4687 	    ++num_filtered;
4688 	}
4689     }
4690   return num_filtered;
4691 }
4692 
4693 /// Skip the processing of the current member function if its
4694 /// virtual-ness is disallowed by the user.
4695 ///
4696 /// This is to be used in the member functions below that are used to
4697 /// count the number of filtered inserted, deleted and changed member
4698 /// functions.
4699 #define SKIP_MEM_FN_IF_VIRTUALITY_DISALLOWED				\
4700   do {									\
4701     if (get_member_function_is_virtual(f)					\
4702 	|| get_member_function_is_virtual(s))				\
4703       {								\
4704 	if (!(allowed_category | VIRTUAL_MEMBER_CHANGE_CATEGORY))	\
4705 	  continue;							\
4706       }								\
4707     else								\
4708       {								\
4709 	if (!(allowed_category | NON_VIRT_MEM_FUN_CHANGE_CATEGORY))	\
4710 	  continue;							\
4711       }								\
4712   } while (false)
4713 
4714 /// Get the number of member functions changes carried by the current
4715 /// diff node that were filtered out.
4716 ///
4717 /// @return the number of member functions changes carried by the
4718 /// current diff node that were filtered out.
4719 size_t
count_filtered_changed_mem_fns(const diff_context_sptr & ctxt)4720 class_or_union_diff::priv::count_filtered_changed_mem_fns
4721 (const diff_context_sptr& ctxt)
4722 {
4723   size_t count = 0;
4724   diff_category allowed_category = ctxt->get_allowed_category();
4725 
4726   for (function_decl_diff_sptrs_type::const_iterator i =
4727 	 sorted_changed_member_functions_.begin();
4728        i != sorted_changed_member_functions_.end();
4729        ++i)
4730     {
4731       method_decl_sptr f =
4732 	dynamic_pointer_cast<method_decl>
4733 	((*i)->first_function_decl());
4734       ABG_ASSERT(f);
4735 
4736       method_decl_sptr s =
4737 	dynamic_pointer_cast<method_decl>
4738 	((*i)->second_function_decl());
4739       ABG_ASSERT(s);
4740 
4741       SKIP_MEM_FN_IF_VIRTUALITY_DISALLOWED;
4742 
4743       diff_sptr diff = *i;
4744       ctxt->maybe_apply_filters(diff);
4745 
4746       if (diff->is_filtered_out())
4747 	++count;
4748     }
4749 
4750   return count;
4751 }
4752 
4753 /// Get the number of member functions insertions carried by the current
4754 /// diff node that were filtered out.
4755 ///
4756 /// @return the number of member functions insertions carried by the
4757 /// current diff node that were filtered out.
4758 size_t
count_filtered_inserted_mem_fns(const diff_context_sptr & ctxt)4759 class_or_union_diff::priv::count_filtered_inserted_mem_fns
4760 (const diff_context_sptr& ctxt)
4761 {
4762     size_t count = 0;
4763   diff_category allowed_category = ctxt->get_allowed_category();
4764 
4765   for (string_member_function_sptr_map::const_iterator i =
4766 	 inserted_member_functions_.begin();
4767        i != inserted_member_functions_.end();
4768        ++i)
4769     {
4770       method_decl_sptr f = i->second,
4771 	s = i->second;
4772 
4773       SKIP_MEM_FN_IF_VIRTUALITY_DISALLOWED;
4774 
4775       diff_sptr diff = compute_diff_for_decls(f, s, ctxt);
4776       ctxt->maybe_apply_filters(diff);
4777 
4778       if (diff->get_category() != NO_CHANGE_CATEGORY
4779 	  && diff->is_filtered_out())
4780 	++count;
4781     }
4782 
4783   return count;
4784 }
4785 
4786 /// Get the number of member functions deletions carried by the current
4787 /// diff node that were filtered out.
4788 ///
4789 /// @return the number of member functions deletions carried by the
4790 /// current diff node that were filtered out.
4791 size_t
count_filtered_deleted_mem_fns(const diff_context_sptr & ctxt)4792 class_or_union_diff::priv::count_filtered_deleted_mem_fns
4793 (const diff_context_sptr& ctxt)
4794 {
4795   size_t count = 0;
4796   diff_category allowed_category = ctxt->get_allowed_category();
4797 
4798   for (string_member_function_sptr_map::const_iterator i =
4799 	 deleted_member_functions_.begin();
4800        i != deleted_member_functions_.end();
4801        ++i)
4802     {
4803       method_decl_sptr f = i->second,
4804 	s = i->second;
4805 
4806       SKIP_MEM_FN_IF_VIRTUALITY_DISALLOWED;
4807 
4808       diff_sptr diff = compute_diff_for_decls(f, s, ctxt);
4809       ctxt->maybe_apply_filters(diff);
4810 
4811       if (diff->get_category() != NO_CHANGE_CATEGORY
4812 	  && diff->is_filtered_out())
4813 	++count;
4814     }
4815 
4816   return count;
4817 }
4818 
4819 /// Clear the lookup tables useful for reporting.
4820 ///
4821 /// This function must be updated each time a lookup table is added or
4822 /// removed from the class_or_union_diff::priv.
4823 void
clear_lookup_tables()4824 class_or_union_diff::clear_lookup_tables()
4825 {
4826   priv_->deleted_member_types_.clear();
4827   priv_->inserted_member_types_.clear();
4828   priv_->changed_member_types_.clear();
4829   priv_->deleted_data_members_.clear();
4830   priv_->inserted_data_members_.clear();
4831   priv_->subtype_changed_dm_.clear();
4832   priv_->deleted_member_functions_.clear();
4833   priv_->inserted_member_functions_.clear();
4834   priv_->changed_member_functions_.clear();
4835   priv_->deleted_member_class_tmpls_.clear();
4836   priv_->inserted_member_class_tmpls_.clear();
4837   priv_->changed_member_class_tmpls_.clear();
4838 }
4839 
4840 /// Tests if the lookup tables are empty.
4841 ///
4842 /// @return true if the lookup tables are empty, false otherwise.
4843 bool
lookup_tables_empty(void) const4844 class_or_union_diff::lookup_tables_empty(void) const
4845 {
4846   return (priv_->deleted_member_types_.empty()
4847 	  && priv_->inserted_member_types_.empty()
4848 	  && priv_->changed_member_types_.empty()
4849 	  && priv_->deleted_data_members_.empty()
4850 	  && priv_->inserted_data_members_.empty()
4851 	  && priv_->subtype_changed_dm_.empty()
4852 	  && priv_->inserted_member_functions_.empty()
4853 	  && priv_->deleted_member_functions_.empty()
4854 	  && priv_->changed_member_functions_.empty()
4855 	  && priv_->deleted_member_class_tmpls_.empty()
4856 	  && priv_->inserted_member_class_tmpls_.empty()
4857 	  && priv_->changed_member_class_tmpls_.empty());
4858 }
4859 
4860 /// If the lookup tables are not yet built, walk the differences and
4861 /// fill them.
4862 void
ensure_lookup_tables_populated(void) const4863 class_or_union_diff::ensure_lookup_tables_populated(void) const
4864 {
4865   {
4866     edit_script& e = priv_->member_types_changes_;
4867 
4868     for (vector<deletion>::const_iterator it = e.deletions().begin();
4869 	 it != e.deletions().end();
4870 	 ++it)
4871       {
4872 	unsigned i = it->index();
4873 	decl_base_sptr d =
4874 	  get_type_declaration(first_class_or_union()->get_member_types()[i]);
4875 	class_or_union_sptr record_type = is_class_or_union_type(d);
4876 	if (record_type && record_type->get_is_declaration_only())
4877 	  continue;
4878 	string name = d->get_name();
4879 	priv_->deleted_member_types_[name] = d;
4880       }
4881 
4882     for (vector<insertion>::const_iterator it = e.insertions().begin();
4883 	 it != e.insertions().end();
4884 	 ++it)
4885       {
4886 	for (vector<unsigned>::const_iterator iit =
4887 	       it->inserted_indexes().begin();
4888 	     iit != it->inserted_indexes().end();
4889 	     ++iit)
4890 	  {
4891 	    unsigned i = *iit;
4892 	    decl_base_sptr d =
4893 	      get_type_declaration(second_class_or_union()->get_member_types()[i]);
4894 	    class_or_union_sptr record_type = is_class_or_union_type(d);
4895 	    if (record_type && record_type->get_is_declaration_only())
4896 	      continue;
4897 	    string name = d->get_name();
4898 	    string_decl_base_sptr_map::const_iterator j =
4899 	      priv_->deleted_member_types_.find(name);
4900 	    if (j != priv_->deleted_member_types_.end())
4901 	      {
4902 		if (*j->second != *d)
4903 		  priv_->changed_member_types_[name] =
4904 		    compute_diff(j->second, d, context());
4905 
4906 		priv_->deleted_member_types_.erase(j);
4907 	      }
4908 	    else
4909 	      priv_->inserted_member_types_[name] = d;
4910 	  }
4911       }
4912   }
4913 
4914   {
4915     edit_script& e = priv_->data_members_changes_;
4916 
4917     for (vector<deletion>::const_iterator it = e.deletions().begin();
4918 	 it != e.deletions().end();
4919 	 ++it)
4920       {
4921 	unsigned i = it->index();
4922 	var_decl_sptr data_member =
4923 	  is_var_decl(first_class_or_union()->get_non_static_data_members()[i]);
4924 	string name = data_member->get_anon_dm_reliable_name();
4925 
4926 	ABG_ASSERT(priv_->deleted_data_members_.find(name)
4927 		   == priv_->deleted_data_members_.end());
4928 	priv_->deleted_data_members_[name] = data_member;
4929       }
4930 
4931     for (vector<insertion>::const_iterator it = e.insertions().begin();
4932 	 it != e.insertions().end();
4933 	 ++it)
4934       {
4935 	for (vector<unsigned>::const_iterator iit =
4936 	       it->inserted_indexes().begin();
4937 	     iit != it->inserted_indexes().end();
4938 	     ++iit)
4939 	  {
4940 	    unsigned i = *iit;
4941 	    decl_base_sptr d =
4942 	      second_class_or_union()->get_non_static_data_members()[i];
4943 	    var_decl_sptr added_dm = is_var_decl(d);
4944 	    string name = added_dm->get_anon_dm_reliable_name();
4945 	    ABG_ASSERT(priv_->inserted_data_members_.find(name)
4946 		       == priv_->inserted_data_members_.end());
4947 
4948 	    bool ignore_added_anonymous_data_member = false;
4949 	    if (is_anonymous_data_member(added_dm))
4950 	      {
4951 		//
4952 		// Handle insertion of anonymous data member to
4953 		// replace existing data members.
4954 		//
4955 		// For instance consider this:
4956 		//   struct S
4957 		//   {
4958 		//     int a;
4959 		//     int b;
4960 		//     int c;
4961 		//   };// end struct S
4962 		//
4963 		//   Where the data members 'a' and 'b' are replaced
4964 		//   by an anonymous data member without changing the
4965 		//   effective bit layout of the structure:
4966 		//
4967 		//   struct S
4968 		//   {
4969 		//     struct
4970 		//     {
4971 		//       union
4972 		//       {
4973 		//         int a;
4974 		//         char a_1;
4975 		//       };
4976 		//       union
4977 		//       {
4978 		//         int b;
4979 		//         char b_1;
4980 		//       };
4981 		//     };
4982 		//     int c;
4983 		//   }; // end struct S
4984 		//
4985 		var_decl_sptr replaced_dm, replacing_dm;
4986 		bool added_anon_dm_changes_dm = false;
4987 		// The vector of data members replaced by anonymous
4988 		// data members.
4989 		vector<var_decl_sptr> dms_replaced_by_anon_dm;
4990 
4991 		//
4992 		// Let's start collecting the set of data members
4993 		// which have been replaced by anonymous types in a
4994 		// harmless way.  These are going to be collected into
4995 		// dms_replaced_by_anon_dm and, ultimately, into
4996 		// priv_->dms_replaced_by_adms_
4997 		//
4998 		for (string_decl_base_sptr_map::const_iterator it =
4999 		       priv_->deleted_data_members_.begin();
5000 		     it != priv_->deleted_data_members_.end();
5001 		     ++it)
5002 		  {
5003 		    // We don't support this pattern for anonymous
5004 		    // data members themselves being replaced.  If
5005 		    // that occurs then we'll just report it verbatim.
5006 		    if (is_anonymous_data_member(it->second))
5007 		      continue;
5008 
5009 		    string deleted_dm_name = it->second->get_name();
5010 		    if ((replacing_dm =
5011 			 find_data_member_from_anonymous_data_member(added_dm,
5012 								     deleted_dm_name)))
5013 		      {
5014 			// So it looks like replacing_dm might have
5015 			// replaced the data member which name is
5016 			// 'deleted_dm_name'.  Let's look deeper to be
5017 			// sure.
5018 			//
5019 			// Note that replacing_dm is part (member) of
5020 			// an anonymous data member that might replace
5021 			// replaced_dm.
5022 
5023 			// So let's get that replaced data member.
5024 			replaced_dm = is_var_decl(it->second);
5025 			size_t replaced_dm_offset =
5026 			  get_data_member_offset(replaced_dm),
5027 			replacing_dm_offset =
5028 			  get_absolute_data_member_offset(replacing_dm);
5029 
5030 			if (replaced_dm_offset != replacing_dm_offset)
5031 			  {
5032 			    // So the replacing data member and the
5033 			    // replaced data member don't have the
5034 			    // same offset.  This is not the pattern we
5035 			    // are looking for.  Rather, it looks like
5036 			    // the anonymous data member has *changed*
5037 			    // the data member.
5038 			    added_anon_dm_changes_dm = true;
5039 			    break;
5040 			  }
5041 
5042 			if (replaced_dm->get_type()->get_size_in_bits()
5043 			    == replaced_dm->get_type()->get_size_in_bits())
5044 			  dms_replaced_by_anon_dm.push_back(replaced_dm);
5045 			else
5046 			  {
5047 			    added_anon_dm_changes_dm = true;
5048 			    break;
5049 			  }
5050 		      }
5051 		  }
5052 
5053 		// Now walk dms_replaced_by_anon_dm to fill up
5054 		// priv_->dms_replaced_by_adms_ with the set of data
5055 		// members replaced by anonymous data members.
5056 		if (!added_anon_dm_changes_dm
5057 		    && !dms_replaced_by_anon_dm.empty())
5058 		  {
5059 		    // See if the added data member isn't too big.
5060 		    type_base_sptr added_dm_type = added_dm->get_type();
5061 		    ABG_ASSERT(added_dm_type);
5062 		    var_decl_sptr new_next_dm =
5063 		      get_next_data_member(second_class_or_union(),
5064 					   added_dm);
5065 		    var_decl_sptr old_next_dm =
5066 		      first_class_or_union()->find_data_member(new_next_dm);
5067 
5068 		    if (!old_next_dm
5069 			|| (old_next_dm
5070 			    && (get_absolute_data_member_offset(old_next_dm)
5071 				== get_absolute_data_member_offset(new_next_dm))))
5072 		      {
5073 			// None of the data members that are replaced
5074 			// by the added union should be considered as
5075 			// having been deleted.
5076 			ignore_added_anonymous_data_member = true;
5077 			for (vector<var_decl_sptr>::const_iterator i =
5078 			       dms_replaced_by_anon_dm.begin();
5079 			     i != dms_replaced_by_anon_dm.end();
5080 			     ++i)
5081 			  {
5082 			    string n = (*i)->get_name();
5083 			    priv_->dms_replaced_by_adms_[n] =
5084 			      added_dm;
5085 			    priv_->deleted_data_members_.erase(n);
5086 			  }
5087 		      }
5088 		  }
5089 	      }
5090 
5091 	    if (!ignore_added_anonymous_data_member)
5092 	      {
5093 		// Detect changed data members.
5094 		//
5095 		// A changed data member (that we shall name D) is a data
5096 		// member that satisfies the conditions below:
5097 		//
5098 		// 1/ It must have been added.
5099 		//
5100 		// 2/ It must have been deleted as well.
5101 		//
5102 		// 3/ It there must be a non-empty difference between the
5103 		// deleted D and the added D.
5104 		string_decl_base_sptr_map::const_iterator j =
5105 		  priv_->deleted_data_members_.find(name);
5106 		if (j != priv_->deleted_data_members_.end())
5107 		  {
5108 		    if (*j->second != *d)
5109 		      {
5110 			var_decl_sptr old_dm = is_var_decl(j->second);
5111 			priv_->subtype_changed_dm_[name]=
5112 			  compute_diff(old_dm, added_dm, context());
5113 		      }
5114 		    priv_->deleted_data_members_.erase(j);
5115 		  }
5116 		else
5117 		  priv_->inserted_data_members_[name] = d;
5118 	      }
5119 	  }
5120       }
5121 
5122     // Now detect when a data member is deleted from offset N and
5123     // another one is added to offset N.  In that case, we want to be
5124     // able to say that the data member at offset N changed.
5125     for (string_decl_base_sptr_map::const_iterator i =
5126 	   priv_->deleted_data_members_.begin();
5127 	 i != priv_->deleted_data_members_.end();
5128 	 ++i)
5129       {
5130 	unsigned offset = get_data_member_offset(i->second);
5131 	priv_->deleted_dm_by_offset_[offset] = i->second;
5132       }
5133 
5134     for (string_decl_base_sptr_map::const_iterator i =
5135 	   priv_->inserted_data_members_.begin();
5136 	 i != priv_->inserted_data_members_.end();
5137 	 ++i)
5138       {
5139 	unsigned offset = get_data_member_offset(i->second);
5140 	priv_->inserted_dm_by_offset_[offset] = i->second;
5141       }
5142 
5143     for (unsigned_decl_base_sptr_map::const_iterator i =
5144 	   priv_->inserted_dm_by_offset_.begin();
5145 	 i != priv_->inserted_dm_by_offset_.end();
5146 	 ++i)
5147       {
5148 	unsigned_decl_base_sptr_map::const_iterator j =
5149 	  priv_->deleted_dm_by_offset_.find(i->first);
5150 	if (j != priv_->deleted_dm_by_offset_.end())
5151 	  {
5152 	    var_decl_sptr old_dm = is_var_decl(j->second);
5153 	    var_decl_sptr new_dm = is_var_decl(i->second);
5154 	    priv_->changed_dm_[i->first] =
5155 	      compute_diff(old_dm, new_dm, context());
5156 	  }
5157       }
5158 
5159     for (unsigned_var_diff_sptr_map::const_iterator i =
5160 	   priv_->changed_dm_.begin();
5161 	 i != priv_->changed_dm_.end();
5162 	 ++i)
5163       {
5164 	priv_->deleted_dm_by_offset_.erase(i->first);
5165 	priv_->inserted_dm_by_offset_.erase(i->first);
5166 	priv_->deleted_data_members_.erase
5167 	  (i->second->first_var()->get_anon_dm_reliable_name());
5168 	priv_->inserted_data_members_.erase
5169 	  (i->second->second_var()->get_anon_dm_reliable_name());
5170       }
5171   }
5172   sort_string_data_member_diff_sptr_map(priv_->subtype_changed_dm_,
5173 					priv_->sorted_subtype_changed_dm_);
5174   sort_unsigned_data_member_diff_sptr_map(priv_->changed_dm_,
5175 					  priv_->sorted_changed_dm_);
5176 
5177   {
5178     edit_script& e = priv_->member_class_tmpls_changes_;
5179 
5180     for (vector<deletion>::const_iterator it = e.deletions().begin();
5181 	 it != e.deletions().end();
5182 	 ++it)
5183       {
5184 	unsigned i = it->index();
5185 	decl_base_sptr d =
5186 	  first_class_or_union()->get_member_class_templates()[i]->
5187 	  as_class_tdecl();
5188 	string name = d->get_name();
5189 	ABG_ASSERT(priv_->deleted_member_class_tmpls_.find(name)
5190 	       == priv_->deleted_member_class_tmpls_.end());
5191 	priv_->deleted_member_class_tmpls_[name] = d;
5192       }
5193 
5194     for (vector<insertion>::const_iterator it = e.insertions().begin();
5195 	 it != e.insertions().end();
5196 	 ++it)
5197       {
5198 	for (vector<unsigned>::const_iterator iit =
5199 	       it->inserted_indexes().begin();
5200 	     iit != it->inserted_indexes().end();
5201 	     ++iit)
5202 	  {
5203 	    unsigned i = *iit;
5204 	    decl_base_sptr d =
5205 	      second_class_or_union()->get_member_class_templates()[i]->
5206 	      as_class_tdecl();
5207 	    string name = d->get_name();
5208 	    ABG_ASSERT(priv_->inserted_member_class_tmpls_.find(name)
5209 		   == priv_->inserted_member_class_tmpls_.end());
5210 	    string_decl_base_sptr_map::const_iterator j =
5211 	      priv_->deleted_member_class_tmpls_.find(name);
5212 	    if (j != priv_->deleted_member_class_tmpls_.end())
5213 	      {
5214 		if (*j->second != *d)
5215 		  priv_->changed_member_types_[name]=
5216 		    compute_diff(j->second, d, context());
5217 		priv_->deleted_member_class_tmpls_.erase(j);
5218 	      }
5219 	    else
5220 	      priv_->inserted_member_class_tmpls_[name] = d;
5221 	  }
5222       }
5223   }
5224   sort_string_diff_sptr_map(priv_->changed_member_types_,
5225 			    priv_->sorted_changed_member_types_);
5226 }
5227 
5228 /// Allocate the memory for the priv_ pimpl data member of the @ref
5229 /// class_or_union_diff class.
5230 void
allocate_priv_data()5231 class_or_union_diff::allocate_priv_data()
5232 {
5233   if (!priv_)
5234     priv_.reset(new priv);
5235 }
5236 
5237 /// Constructor for the @ref class_or_union_diff class.
5238 ///
5239 /// @param first_scope the first @ref class_or_union of the diff node.
5240 ///
5241 /// @param second_scope the second @ref class_or_union of the diff node.
5242 ///
5243 /// @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)5244 class_or_union_diff::class_or_union_diff(class_or_union_sptr first_scope,
5245 					 class_or_union_sptr second_scope,
5246 					 diff_context_sptr ctxt)
5247   : type_diff_base(first_scope, second_scope, ctxt)
5248     //priv_(new priv)
5249 {}
5250 
5251 /// Getter of the private data of the @ref class_or_union_diff type.
5252 ///
5253 /// Note that due to an optimization, the private data of @ref
5254 /// class_or_union_diff can be shared among several instances of
5255 /// class_or_union_diff, so you should never try to access
5256 /// class_or_union_diff::priv directly.
5257 ///
5258 /// When class_or_union_diff::priv is shared, this function returns
5259 /// the correct shared one.
5260 ///
5261 /// @return the (possibly) shared private data of the current instance
5262 /// of @ref class_or_union_diff.
5263 const class_or_union_diff::priv_ptr&
get_priv() const5264 class_or_union_diff::get_priv() const
5265 {
5266   if (priv_)
5267     return priv_;
5268 
5269   // If the current class_or_union_diff::priv member is empty, then look for
5270   // the shared one, from the canonical type.
5271   class_or_union_diff *canonical =
5272     dynamic_cast<class_or_union_diff*>(get_canonical_diff());
5273   ABG_ASSERT(canonical);
5274   ABG_ASSERT(canonical->priv_);
5275 
5276   return canonical->priv_;
5277 }
5278 
5279 /// Destructor of class_or_union_diff.
~class_or_union_diff()5280 class_or_union_diff::~class_or_union_diff()
5281 {
5282 }
5283 
5284 /// @return the first @ref class_or_union involved in the diff.
5285 class_or_union_sptr
first_class_or_union() const5286 class_or_union_diff::first_class_or_union() const
5287 {return is_class_or_union_type(first_subject());}
5288 
5289 /// @return the second @ref class_or_union involved in the diff.
5290 class_or_union_sptr
second_class_or_union() const5291 class_or_union_diff::second_class_or_union() const
5292 {return is_class_or_union_type(second_subject());}
5293 
5294 /// @return the edit script of the member types of the two @ref
5295 /// class_or_union.
5296 const edit_script&
member_types_changes() const5297 class_or_union_diff::member_types_changes() const
5298 {return get_priv()->member_types_changes_;}
5299 
5300 /// @return the edit script of the member types of the two @ref
5301 /// class_or_union.
5302 edit_script&
member_types_changes()5303 class_or_union_diff::member_types_changes()
5304 {return get_priv()->member_types_changes_;}
5305 
5306 /// @return the edit script of the data members of the two @ref
5307 /// class_or_union.
5308 const edit_script&
data_members_changes() const5309 class_or_union_diff::data_members_changes() const
5310 {return get_priv()->data_members_changes_;}
5311 
5312 /// @return the edit script of the data members of the two @ref
5313 /// class_or_union.
5314 edit_script&
data_members_changes()5315 class_or_union_diff::data_members_changes()
5316 {return get_priv()->data_members_changes_;}
5317 
5318 /// Getter for the data members that got inserted.
5319 ///
5320 /// @return a map of data members that got inserted.
5321 const string_decl_base_sptr_map&
inserted_data_members() const5322 class_or_union_diff::inserted_data_members() const
5323 {return get_priv()->inserted_data_members_;}
5324 
5325 /// Getter for the data members that got deleted.
5326 ///
5327 /// @return a map of data members that got deleted.
5328 const string_decl_base_sptr_map&
deleted_data_members() const5329 class_or_union_diff::deleted_data_members() const
5330 {return get_priv()->deleted_data_members_;}
5331 
5332 /// @return the edit script of the member functions of the two @ref
5333 /// class_or_union.
5334 const edit_script&
member_fns_changes() const5335 class_or_union_diff::member_fns_changes() const
5336 {return get_priv()->member_fns_changes_;}
5337 
5338 /// Getter for the virtual members functions that have had a change in
5339 /// a sub-type, without having a change in their symbol name.
5340 ///
5341 /// @return a sorted vector of virtual member functions that have a
5342 /// sub-type change.
5343 const function_decl_diff_sptrs_type&
changed_member_fns() const5344 class_or_union_diff::changed_member_fns() const
5345 {return get_priv()->sorted_changed_member_functions_;}
5346 
5347 /// @return the edit script of the member functions of the two
5348 /// classes.
5349 edit_script&
member_fns_changes()5350 class_or_union_diff::member_fns_changes()
5351 {return get_priv()->member_fns_changes_;}
5352 
5353 /// @return a map of member functions that got deleted.
5354 const string_member_function_sptr_map&
deleted_member_fns() const5355 class_or_union_diff::deleted_member_fns() const
5356 {return get_priv()->deleted_member_functions_;}
5357 
5358 /// @return a map of member functions that got inserted.
5359 const string_member_function_sptr_map&
inserted_member_fns() const5360 class_or_union_diff::inserted_member_fns() const
5361 {return get_priv()->inserted_member_functions_;}
5362 
5363 /// Getter of the map of data members that got replaced by another
5364 /// data member.  The key of the map is the offset at which the
5365 /// element got replaced and the value is a pointer to the @ref
5366 /// var_diff representing the replacement of the data member.
5367 ///
5368 /// @return sorted vector of changed data member.
5369 const unsigned_var_diff_sptr_map&
changed_data_members() const5370 class_or_union_diff::changed_data_members() const
5371 {return get_priv()->changed_dm_;}
5372 
5373 /// Getter of the sorted vector of data members that got replaced by
5374 /// another data member.
5375 ///
5376 /// @return sorted vector of changed data member.
5377 const var_diff_sptrs_type&
sorted_changed_data_members() const5378 class_or_union_diff::sorted_changed_data_members() const
5379 {return get_priv()->sorted_changed_dm_;}
5380 
5381 /// Count the number of /filtered/ data members that got replaced by
5382 /// another data member.
5383 ///
5384 /// @return the number of changed data member that got filtered out.
5385 size_t
count_filtered_changed_data_members(bool local) const5386 class_or_union_diff::count_filtered_changed_data_members(bool local) const
5387 {return get_priv()->count_filtered_changed_dm(local);}
5388 
5389 /// Getter of the sorted vector of data members with a (sub-)type change.
5390 ///
5391 /// @return sorted vector of changed data member.
5392 const var_diff_sptrs_type&
sorted_subtype_changed_data_members() const5393 class_or_union_diff::sorted_subtype_changed_data_members() const
5394 {return get_priv()->sorted_subtype_changed_dm_;}
5395 
5396 /// Count the number of /filtered/ data members with a sub-type change.
5397 ///
5398 /// @return the number of changed data member that got filtered out.
5399 size_t
count_filtered_subtype_changed_data_members(bool local) const5400 class_or_union_diff::count_filtered_subtype_changed_data_members(bool local) const
5401 {return get_priv()->count_filtered_subtype_changed_dm(local);}
5402 
5403 /// Get the map of data members that got replaced by anonymous data
5404 /// members.
5405 ///
5406 /// The key of a map entry is the name of the replaced data member and
5407 /// the value is the anonymous data member that replaces it.
5408 ///
5409 /// @return the map of data members replaced by anonymous data
5410 /// members.
5411 const string_decl_base_sptr_map&
data_members_replaced_by_adms() const5412 class_or_union_diff::data_members_replaced_by_adms() const
5413 {return get_priv()->dms_replaced_by_adms_;}
5414 
5415 /// Get an ordered vector of of data members that got replaced by
5416 /// anonymous data members.
5417 ///
5418 /// This returns a vector of pair of two data members: the one that
5419 /// was replaced, and the anonymous data member that replaced it.
5420 ///
5421 /// @return the sorted vector data members replaced by anonymous data members.
5422 const changed_var_sptrs_type&
ordered_data_members_replaced_by_adms() const5423 class_or_union_diff::ordered_data_members_replaced_by_adms() const
5424 {
5425   if (priv_->dms_replaced_by_adms_ordered_.empty())
5426     {
5427       for (string_decl_base_sptr_map::const_iterator it =
5428 	     priv_->dms_replaced_by_adms_.begin();
5429 	   it != priv_->dms_replaced_by_adms_.end();
5430 	   ++it)
5431 	{
5432 	  const var_decl_sptr dm =
5433 	    first_class_or_union()->find_data_member(it->first);
5434 	  ABG_ASSERT(dm);
5435 	  changed_var_sptr changed_dm(dm, is_data_member(it->second));
5436 	  priv_->dms_replaced_by_adms_ordered_.push_back(changed_dm);
5437 	}
5438       sort_changed_data_members(priv_->dms_replaced_by_adms_ordered_);
5439     }
5440 
5441   return priv_->dms_replaced_by_adms_ordered_;
5442 }
5443 
5444 /// @return the edit script of the member function templates of the two
5445 /// @ref class_or_union.
5446 const edit_script&
member_fn_tmpls_changes() const5447 class_or_union_diff::member_fn_tmpls_changes() const
5448 {return get_priv()->member_fn_tmpls_changes_;}
5449 
5450 /// @return the edit script of the member function templates of the
5451 /// two @ref class_or_union.
5452 edit_script&
member_fn_tmpls_changes()5453 class_or_union_diff::member_fn_tmpls_changes()
5454 {return get_priv()->member_fn_tmpls_changes_;}
5455 
5456 /// @return the edit script of the member class templates of the two
5457 /// @ref class_or_union.
5458 const edit_script&
member_class_tmpls_changes() const5459 class_or_union_diff::member_class_tmpls_changes() const
5460 {return get_priv()->member_class_tmpls_changes_;}
5461 
5462 /// @return the edit script of the member class templates of the two
5463 /// @ref class_or_union.
5464 edit_script&
member_class_tmpls_changes()5465 class_or_union_diff::member_class_tmpls_changes()
5466 {return get_priv()->member_class_tmpls_changes_;}
5467 
5468 /// Test if the current diff node carries a change.
5469 bool
has_changes() const5470 class_or_union_diff::has_changes() const
5471 {return first_class_or_union() != second_class_or_union();}
5472 
5473 /// @return the kind of local change carried by the current diff node.
5474 /// The value returned is zero if the current node carries no local
5475 /// change.
5476 enum change_kind
has_local_changes() const5477 class_or_union_diff::has_local_changes() const
5478 {
5479   ir::change_kind k = ir::NO_CHANGE_KIND;
5480   if (!equals(*first_class_or_union(), *second_class_or_union(), &k))
5481     return k & ir::ALL_LOCAL_CHANGES_MASK;
5482   return ir::NO_CHANGE_KIND;
5483 }
5484 
5485 
5486 /// Report the changes carried by the current @ref class_or_union_diff
5487 /// node in a textual format.
5488 ///
5489 /// @param out the output stream to write the textual report to.
5490 ///
5491 /// @param indent the number of white space to use as indentation.
5492 void
report(ostream & out,const string & indent) const5493 class_or_union_diff::report(ostream& out, const string& indent) const
5494 {
5495   context()->get_reporter()->report(*this, out, indent);
5496 }
5497 
5498 /// Populate the vector of children node of the @ref diff base type
5499 /// sub-object of this instance of @ref class_or_union_diff.
5500 ///
5501 /// The children node can then later be retrieved using
5502 /// diff::children_node().
5503 void
chain_into_hierarchy()5504 class_or_union_diff::chain_into_hierarchy()
5505 {
5506   // data member changes
5507   for (var_diff_sptrs_type::const_iterator i =
5508 	 get_priv()->sorted_subtype_changed_dm_.begin();
5509        i != get_priv()->sorted_subtype_changed_dm_.end();
5510        ++i)
5511     if (diff_sptr d = *i)
5512       append_child_node(d);
5513 
5514   for (var_diff_sptrs_type::const_iterator i =
5515 	 get_priv()->sorted_changed_dm_.begin();
5516        i != get_priv()->sorted_changed_dm_.end();
5517        ++i)
5518     if (diff_sptr d = *i)
5519       append_child_node(d);
5520 
5521   // member types changes
5522   for (diff_sptrs_type::const_iterator i =
5523 	 get_priv()->sorted_changed_member_types_.begin();
5524        i != get_priv()->sorted_changed_member_types_.end();
5525        ++i)
5526     if (diff_sptr d = *i)
5527       append_child_node(d);
5528 
5529   // member function changes
5530   for (function_decl_diff_sptrs_type::const_iterator i =
5531 	 get_priv()->sorted_changed_member_functions_.begin();
5532        i != get_priv()->sorted_changed_member_functions_.end();
5533        ++i)
5534     if (diff_sptr d = *i)
5535       append_child_node(d);
5536 }
5537 
5538 // </class_or_union_diff stuff>
5539 
5540 //<class_diff stuff>
5541 
5542 /// Clear the lookup tables useful for reporting.
5543 ///
5544 /// This function must be updated each time a lookup table is added or
5545 /// removed from the class_diff::priv.
5546 void
clear_lookup_tables(void)5547 class_diff::clear_lookup_tables(void)
5548 {
5549   priv_->deleted_bases_.clear();
5550   priv_->inserted_bases_.clear();
5551   priv_->changed_bases_.clear();
5552 }
5553 
5554 /// Tests if the lookup tables are empty.
5555 ///
5556 /// @return true if the lookup tables are empty, false otherwise.
5557 bool
lookup_tables_empty(void) const5558 class_diff::lookup_tables_empty(void) const
5559 {
5560   return (priv_->deleted_bases_.empty()
5561 	  && priv_->inserted_bases_.empty()
5562 	  && priv_->changed_bases_.empty());
5563 }
5564 
5565 /// Find a virtual destructor in a map of member functions
5566 ///
5567 /// @param map the map of member functions.  Note that the key of the
5568 /// map is the member function name.  The key is the member function.
5569 ///
5570 /// @return an iterator to the destructor found or, if no virtual destructor
5571 /// was found, return map.end()
5572 static string_member_function_sptr_map::const_iterator
find_virtual_dtor_in_map(const string_member_function_sptr_map & map)5573 find_virtual_dtor_in_map(const string_member_function_sptr_map& map)
5574 {
5575   for (string_member_function_sptr_map::const_iterator i = map.begin();
5576        i !=map.end();
5577        ++i)
5578     {
5579       if (get_member_function_is_dtor(i->second)
5580 	  && get_member_function_is_virtual(i->second))
5581 	return i;
5582     }
5583   return map.end();
5584 }
5585 
5586 /// If the lookup tables are not yet built, walk the differences and
5587 /// fill them.
5588 void
ensure_lookup_tables_populated(void) const5589 class_diff::ensure_lookup_tables_populated(void) const
5590 {
5591   class_or_union_diff::ensure_lookup_tables_populated();
5592 
5593   if (!lookup_tables_empty())
5594     return;
5595 
5596   {
5597     edit_script& e = get_priv()->base_changes_;
5598 
5599     for (vector<deletion>::const_iterator it = e.deletions().begin();
5600 	 it != e.deletions().end();
5601 	 ++it)
5602       {
5603 	unsigned i = it->index();
5604 	class_decl::base_spec_sptr b =
5605 	  first_class_decl()->get_base_specifiers()[i];
5606 	string name = b->get_base_class()->get_qualified_name();
5607 	ABG_ASSERT(get_priv()->deleted_bases_.find(name)
5608 	       == get_priv()->deleted_bases_.end());
5609 	get_priv()->deleted_bases_[name] = b;
5610       }
5611 
5612     for (vector<insertion>::const_iterator it = e.insertions().begin();
5613 	 it != e.insertions().end();
5614 	 ++it)
5615       {
5616 	for (vector<unsigned>::const_iterator iit =
5617 	       it->inserted_indexes().begin();
5618 	     iit != it->inserted_indexes().end();
5619 	     ++iit)
5620 	  {
5621 	    unsigned i = *iit;
5622 	    class_decl::base_spec_sptr b =
5623 	      second_class_decl()->get_base_specifiers()[i];
5624 	    string name = b->get_base_class()->get_qualified_name();
5625 	    ABG_ASSERT(get_priv()->inserted_bases_.find(name)
5626 		   == get_priv()->inserted_bases_.end());
5627 	    string_base_sptr_map::const_iterator j =
5628 	      get_priv()->deleted_bases_.find(name);
5629 	    if (j != get_priv()->deleted_bases_.end())
5630 	      {
5631 		if (j->second != b)
5632 		  get_priv()->changed_bases_[name] =
5633 		    compute_diff(j->second, b, context());
5634 		else
5635 		  // The base class changed place.  IOW, the base
5636 		  // classes got re-arranged.  Let's keep track of the
5637 		  // base classes that moved.
5638 		  get_priv()->moved_bases_.push_back(b);
5639 		get_priv()->deleted_bases_.erase(j);
5640 	      }
5641 	    else
5642 	      get_priv()->inserted_bases_[name] = b;
5643 	  }
5644       }
5645   }
5646 
5647   sort_string_base_sptr_map(get_priv()->deleted_bases_,
5648 			    get_priv()->sorted_deleted_bases_);
5649   sort_string_base_sptr_map(get_priv()->inserted_bases_,
5650 			    get_priv()->sorted_inserted_bases_);
5651   sort_string_base_diff_sptr_map(get_priv()->changed_bases_,
5652 				 get_priv()->sorted_changed_bases_);
5653 
5654   {
5655     const class_or_union_diff::priv_ptr &p = class_or_union_diff::get_priv();
5656 
5657     edit_script& e = p->member_fns_changes_;
5658 
5659     for (vector<deletion>::const_iterator it = e.deletions().begin();
5660 	 it != e.deletions().end();
5661 	 ++it)
5662       {
5663 	unsigned i = it->index();
5664 	method_decl_sptr mem_fn =
5665 	  first_class_decl()->get_virtual_mem_fns()[i];
5666 	string name = mem_fn->get_linkage_name();
5667 	if (name.empty())
5668 	  name = mem_fn->get_pretty_representation();
5669 	ABG_ASSERT(!name.empty());
5670 	if (p->deleted_member_functions_.find(name)
5671 	    != p->deleted_member_functions_.end())
5672 	  continue;
5673 	p->deleted_member_functions_[name] = mem_fn;
5674       }
5675 
5676     for (vector<insertion>::const_iterator it = e.insertions().begin();
5677 	 it != e.insertions().end();
5678 	 ++it)
5679       {
5680 	for (vector<unsigned>::const_iterator iit =
5681 	       it->inserted_indexes().begin();
5682 	     iit != it->inserted_indexes().end();
5683 	     ++iit)
5684 	  {
5685 	    unsigned i = *iit;
5686 
5687 	    method_decl_sptr mem_fn =
5688 	      second_class_decl()->get_virtual_mem_fns()[i];
5689 	    string name = mem_fn->get_linkage_name();
5690 	    if (name.empty())
5691 	      name = mem_fn->get_pretty_representation();
5692 	    ABG_ASSERT(!name.empty());
5693 	    if (p->inserted_member_functions_.find(name)
5694 		!= p->inserted_member_functions_.end())
5695 	      continue;
5696 	    string_member_function_sptr_map::const_iterator j =
5697 	      p->deleted_member_functions_.find(name);
5698 
5699 	    if (j != p->deleted_member_functions_.end())
5700 	      {
5701 		if (*j->second != *mem_fn)
5702 		  p->changed_member_functions_[name] =
5703 		    compute_diff(static_pointer_cast<function_decl>(j->second),
5704 				 static_pointer_cast<function_decl>(mem_fn),
5705 				 context());
5706 		p->deleted_member_functions_.erase(j);
5707 	      }
5708 	    else
5709 	      p->inserted_member_functions_[name] = mem_fn;
5710 	  }
5711       }
5712 
5713     // Now walk the allegedly deleted member functions; check if their
5714     // underlying symbols are deleted as well; otherwise, consider
5715     // that the member function in question hasn't been deleted.
5716 
5717     // Also, while walking the deleted member functions, we attend at
5718     // a particular cleanup business related to (virtual) C++
5719     // destructors:
5720     //
5721     // In the binary, there can be at least three types of
5722     // destructors, defined in the document
5723     // https://itanium-cxx-abi.github.io/cxx-abi/abi.html#definitions:
5724     //
5725     //   1/ Base object destructor (aka D2 destructor):
5726     //
5727     //      "A function that runs the destructors for non-static data
5728     //      members of T and non-virtual direct base classes of T. "
5729     //
5730     //   2/ Complete object destructor (aka D1 destructor):
5731     //
5732     //      "A function that, in addition to the actions required of a
5733     //      base object destructor, runs the destructors for the
5734     //      virtual base classes of T."
5735     //
5736     //   3/ Deleting destructor (aka D0 destructor):
5737     //
5738     //      "A function that, in addition to the actions required of a
5739     //      complete object destructor, calls the appropriate
5740     //      deallocation function (i.e,. operator delete) for T."
5741     //
5742     // With binaries generated by GCC, these destructors might be ELF
5743     // clones of each others, meaning, their ELF symbols can be
5744     // aliases.
5745     //
5746     // Also, note that because the actual destructor invoked by user
5747     // code is virtual, it's invoked through the vtable.  So the
5748     // presence of the underlying D0, D1, D2 in the binary might vary
5749     // without that variation being an ABI issue, provided that the
5750     // destructor invoked through the vtable is present.
5751     //
5752     // So, a particular virtual destructor implementation for a class
5753     // might disapear and be replaced by another one in a subsequent
5754     // version of the binary.  If all versions of the binary have an
5755     // actual virtual destructor, things might be considered fine.
5756     vector<string> to_delete;
5757     corpus_sptr f = context()->get_first_corpus(),
5758       s = context()->get_second_corpus();
5759     if (s)
5760       for (string_member_function_sptr_map::const_iterator i =
5761 	     deleted_member_fns().begin();
5762 	   i != deleted_member_fns().end();
5763 	   ++i)
5764 	{
5765 	  if (get_member_function_is_virtual(i->second))
5766 	    {
5767 	      if (get_member_function_is_dtor(i->second))
5768 		{
5769 		  // If a particular virtual destructor is deleted,
5770 		  // but the new binary still have a virtual
5771 		  // destructor for that class we consider that things
5772 		  // are fine.  For instance, in the
5773 		  // tests/data/test-diff-pkg/tbb-4.1-9.20130314.fc22.x86_64--tbb-4.3-3.20141204.fc23.x86_64-report-0.txt
5774 		  // test, a new D4 destructor replaces the old ones.
5775 		  // But because the virtual destructor is still
5776 		  // there, this is not an ABI issue.  So let's detect
5777 		  // this case.
5778 		  auto it =
5779 		    find_virtual_dtor_in_map(p->inserted_member_functions_);
5780 		  if (it != p->inserted_member_functions_.end())
5781 		    {
5782 		      // So the deleted virtual destructor is not
5783 		      // really deleted, because a proper virtual
5784 		      // destructor was added to the new version.
5785 		      // Let's remove the deleted/added virtual
5786 		      // destructor then.
5787 		      string name =
5788 			(!i->second->get_linkage_name().empty())
5789 			? i->second->get_linkage_name()
5790 			: i->second->get_pretty_representation();
5791 		      to_delete.push_back(name);
5792 		      p->inserted_member_functions_.erase(it);
5793 		    }
5794 		}
5795 	      continue;
5796 	    }
5797 	  // We assume that all non-virtual member functions functions
5798 	  // we look at here have ELF symbols.
5799 	  if (!i->second->get_symbol()
5800 	      || s->lookup_function_symbol(*i->second->get_symbol()))
5801 	    to_delete.push_back(i->first);
5802 	}
5803 
5804 
5805     for (vector<string>::const_iterator i = to_delete.begin();
5806 	 i != to_delete.end();
5807 	 ++i)
5808       p->deleted_member_functions_.erase(*i);
5809 
5810     // Do something similar for added functions.
5811     to_delete.clear();
5812     if (f)
5813       for (string_member_function_sptr_map::const_iterator i =
5814 	     inserted_member_fns().begin();
5815 	   i != inserted_member_fns().end();
5816 	   ++i)
5817 	{
5818 	  if (get_member_function_is_virtual(i->second))
5819 	    continue;
5820 	  // We assume that all non-virtual member functions functions
5821 	  // we look at here have ELF symbols.
5822 	  if (!i->second->get_symbol()
5823 	      || f->lookup_function_symbol(*i->second->get_symbol()))
5824 	    to_delete.push_back(i->first);
5825 	}
5826 
5827     for (vector<string>::const_iterator i = to_delete.begin();
5828 	 i != to_delete.end();
5829 	 ++i)
5830       p->inserted_member_functions_.erase(*i);
5831 
5832     sort_string_member_function_sptr_map(p->deleted_member_functions_,
5833 					 p->sorted_deleted_member_functions_);
5834 
5835     sort_string_member_function_sptr_map(p->inserted_member_functions_,
5836 					 p->sorted_inserted_member_functions_);
5837 
5838     sort_string_virtual_member_function_diff_sptr_map
5839       (p->changed_member_functions_,
5840        p->sorted_changed_member_functions_);
5841   }
5842 }
5843 
5844 /// Allocate the memory for the priv_ pimpl data member of the @ref
5845 /// class_diff class.
5846 void
allocate_priv_data()5847 class_diff::allocate_priv_data()
5848 {
5849   class_or_union_diff::allocate_priv_data();
5850   if (!priv_)
5851     priv_.reset(new priv);
5852 }
5853 
5854 /// Test whether a given base class has changed.  A base class has
5855 /// changed if it's in both in deleted *and* inserted bases.
5856 ///
5857 ///@param d the declaration for the base class to consider.
5858 ///
5859 /// @return the new base class if the given base class has changed, or
5860 /// NULL if it hasn't.
5861 class_decl::base_spec_sptr
base_has_changed(class_decl::base_spec_sptr d) const5862 class_diff::priv::base_has_changed(class_decl::base_spec_sptr d) const
5863 {
5864   string qname = d->get_base_class()->get_qualified_name();
5865   string_base_diff_sptr_map::const_iterator it =
5866     changed_bases_.find(qname);
5867 
5868   return (it == changed_bases_.end())
5869     ? class_decl::base_spec_sptr()
5870     : it->second->second_base();
5871 
5872 }
5873 
5874 /// Count the number of bases classes whose changes got filtered out.
5875 ///
5876 /// @return the number of bases classes whose changes got filtered
5877 /// out.
5878 size_t
count_filtered_bases()5879 class_diff::priv::count_filtered_bases()
5880 {
5881   size_t num_filtered = 0;
5882   for (base_diff_sptrs_type::const_iterator i = sorted_changed_bases_.begin();
5883        i != sorted_changed_bases_.end();
5884        ++i)
5885     {
5886       diff_sptr diff = *i;
5887       if (diff && diff->is_filtered_out())
5888 	++num_filtered;
5889     }
5890   return num_filtered;
5891 }
5892 
5893 /// Populate the vector of children node of the @ref diff base type
5894 /// sub-object of this instance of @ref class_diff.
5895 ///
5896 /// The children node can then later be retrieved using
5897 /// diff::children_node().
5898 void
chain_into_hierarchy()5899 class_diff::chain_into_hierarchy()
5900 {
5901   class_or_union_diff::chain_into_hierarchy();
5902 
5903   // base class changes.
5904   for (base_diff_sptrs_type::const_iterator i =
5905 	 get_priv()->sorted_changed_bases_.begin();
5906        i != get_priv()->sorted_changed_bases_.end();
5907        ++i)
5908     if (diff_sptr d = *i)
5909       append_child_node(d);
5910 }
5911 
5912 /// Constructor of class_diff
5913 ///
5914 /// @param first_scope the first class of the diff.
5915 ///
5916 /// @param second_scope the second class of the diff.
5917 ///
5918 /// @param ctxt the diff context to use.
class_diff(class_decl_sptr first_scope,class_decl_sptr second_scope,diff_context_sptr ctxt)5919 class_diff::class_diff(class_decl_sptr first_scope,
5920 		       class_decl_sptr second_scope,
5921 		       diff_context_sptr ctxt)
5922   : class_or_union_diff(first_scope, second_scope, ctxt)
5923     //  We don't initialize the priv_ data member here.  This is an
5924     //  optimization to reduce memory consumption (and also execution
5925     //  time) for cases where there are a lot of instances of
5926     //  class_diff in the same equivalence class.  In compute_diff(),
5927     //  the priv_ is set to the priv_ of the canonical diff node.
5928     //  See PR libabigail/17948.
5929 {}
5930 
~class_diff()5931 class_diff::~class_diff()
5932 {}
5933 
5934 /// Getter of the private data of the @ref class_diff type.
5935 ///
5936 /// Note that due to an optimization, the private data of @ref
5937 /// class_diff can be shared among several instances of class_diff, so
5938 /// you should never try to access class_diff::priv directly.
5939 ///
5940 /// When class_diff::priv is shared, this function returns the correct
5941 /// shared one.
5942 ///
5943 /// @return the (possibly) shared private data of the current instance
5944 /// of class_diff.
5945 const class_diff::priv_ptr&
get_priv() const5946 class_diff::get_priv() const
5947 {
5948   if (priv_)
5949     return priv_;
5950 
5951   // If the current class_diff::priv member is empty, then look for
5952   // the shared one, from the canonical type.
5953   class_diff *canonical =
5954     dynamic_cast<class_diff*>(get_canonical_diff());
5955   ABG_ASSERT(canonical);
5956   ABG_ASSERT(canonical->priv_);
5957 
5958   return canonical->priv_;
5959 }
5960 
5961 /// @return the pretty representation of the current instance of @ref
5962 /// class_diff.
5963 const string&
get_pretty_representation() const5964 class_diff::get_pretty_representation() const
5965 {
5966   if (diff::priv_->pretty_representation_.empty())
5967     {
5968       std::ostringstream o;
5969       o << "class_diff["
5970 	<< first_subject()->get_pretty_representation()
5971 	<< ", "
5972 	<< second_subject()->get_pretty_representation()
5973 	<< "]";
5974       diff::priv_->pretty_representation_ = o.str();
5975     }
5976   return diff::priv_->pretty_representation_;
5977 }
5978 
5979 /// Return true iff the current diff node carries a change.
5980 ///
5981 /// @return true iff the current diff node carries a change.
5982 bool
has_changes() const5983 class_diff::has_changes() const
5984 {return (first_class_decl() != second_class_decl());}
5985 
5986 /// @return the kind of local change carried by the current diff node.
5987 /// The value returned is zero if the current node carries no local
5988 /// change.
5989 enum change_kind
has_local_changes() const5990 class_diff::has_local_changes() const
5991 {
5992   ir::change_kind k = ir::NO_CHANGE_KIND;
5993   if (!equals(*first_class_decl(), *second_class_decl(), &k))
5994     return k & ir::ALL_LOCAL_CHANGES_MASK;
5995   return ir::NO_CHANGE_KIND;
5996 }
5997 
5998 /// @return the first class invoveld in the diff.
5999 shared_ptr<class_decl>
first_class_decl() const6000 class_diff::first_class_decl() const
6001 {return dynamic_pointer_cast<class_decl>(first_subject());}
6002 
6003 /// Getter of the second class involved in the diff.
6004 ///
6005 /// @return the second class invoveld in the diff
6006 shared_ptr<class_decl>
second_class_decl() const6007 class_diff::second_class_decl() const
6008 {return dynamic_pointer_cast<class_decl>(second_subject());}
6009 
6010 /// @return the edit script of the bases of the two classes.
6011 const edit_script&
base_changes() const6012 class_diff::base_changes() const
6013 {return get_priv()->base_changes_;}
6014 
6015 /// Getter for the deleted base classes of the diff.
6016 ///
6017 /// @return a map containing the deleted base classes, keyed with
6018 /// their pretty representation.
6019 const string_base_sptr_map&
deleted_bases() const6020 class_diff::deleted_bases() const
6021 {return get_priv()->deleted_bases_;}
6022 
6023 /// Getter for the inserted base classes of the diff.
6024 ///
6025 /// @return a map containing the inserted base classes, keyed with
6026 /// their pretty representation.
6027 const string_base_sptr_map&
inserted_bases() const6028 class_diff::inserted_bases() const
6029 {return get_priv()->inserted_bases_;}
6030 
6031 /// Getter for the changed base classes of the diff.
6032 ///
6033 /// @return a sorted vector containing the changed base classes
6034 const base_diff_sptrs_type&
changed_bases()6035 class_diff::changed_bases()
6036 {return get_priv()->sorted_changed_bases_;}
6037 
6038 /// Getter for the vector of bases that "moved".
6039 /// That is, the vector of base types which position changed.  If this
6040 /// vector is not empty, it means the bases of the underlying class
6041 /// type got re-ordered.
6042 ///
6043 /// @return the vector of bases that moved.
6044 const vector<class_decl::base_spec_sptr>&
moved_bases() const6045 class_diff::moved_bases() const
6046 {return get_priv()->moved_bases_;}
6047 
6048 /// @return the edit script of the bases of the two classes.
6049 edit_script&
base_changes()6050 class_diff::base_changes()
6051 {return get_priv()->base_changes_;}
6052 
6053 /// Produce a basic report about the changes between two class_decl.
6054 ///
6055 /// @param out the output stream to report the changes to.
6056 ///
6057 /// @param indent the string to use as an indentation prefix in the
6058 /// report.
6059 void
report(ostream & out,const string & indent) const6060 class_diff::report(ostream& out, const string& indent) const
6061 {
6062   context()->get_reporter()->report(*this, out, indent);
6063 }
6064 
6065 /// Compute the set of changes between two instances of class_decl.
6066 ///
6067 /// Note that the two types must have been created in the same @ref
6068 /// environment, otherwise, this function aborts.
6069 ///
6070 /// @param first the first class_decl to consider.
6071 ///
6072 /// @param second the second class_decl to consider.
6073 ///
6074 /// @return changes the resulting changes.
6075 ///
6076 /// @param ctxt the diff context to use.
6077 class_diff_sptr
compute_diff(const class_decl_sptr first,const class_decl_sptr second,diff_context_sptr ctxt)6078 compute_diff(const class_decl_sptr	first,
6079 	     const class_decl_sptr	second,
6080 	     diff_context_sptr		ctxt)
6081 {
6082   class_decl_sptr f = is_class_type(look_through_decl_only_class(first)),
6083     s = is_class_type(look_through_decl_only_class(second));
6084 
6085   class_diff_sptr changes(new class_diff(f, s, ctxt));
6086 
6087   ctxt->initialize_canonical_diff(changes);
6088   ABG_ASSERT(changes->get_canonical_diff());
6089 
6090   if (!ctxt->get_canonical_diff_for(first, second))
6091     {
6092       // Either first or second is a decl-only class; let's set the
6093       // canonical diff here in that case.
6094       diff_sptr canonical_diff = ctxt->get_canonical_diff_for(changes);
6095       ABG_ASSERT(canonical_diff);
6096       ctxt->set_canonical_diff_for(first, second, canonical_diff);
6097     }
6098 
6099   // Ok, so this is an optimization.  Do not freak out if it looks
6100   // weird, because, well, it does look weird.  This speeds up
6101   // greatly, for instance, the test case given at PR
6102   // libabigail/17948.
6103   //
6104   // We are setting the private data of the new instance of class_diff
6105   // (which is 'changes') to the private data of its canonical
6106   // instance.  That is, we are sharing the private data of 'changes'
6107   // with the private data of its canonical instance to consume less
6108   // memory in cases where the equivalence class of 'changes' is huge.
6109   //
6110   // But if changes is its own canonical instance, then we initialize
6111   // its private data properly
6112   if (is_class_diff(changes->get_canonical_diff()) == changes.get())
6113     // changes is its own canonical instance, so it gets a brand new
6114     // private data.
6115     changes->allocate_priv_data();
6116   else
6117     {
6118       // changes has a non-empty equivalence class so it's going to
6119       // share its private data with its canonical instance.  Next
6120       // time class_diff::get_priv() is invoked, it's going to return
6121       // the shared private data of the canonical instance.
6122       return changes;
6123     }
6124 
6125   // Compare base specs
6126   compute_diff(f->get_base_specifiers().begin(),
6127 	       f->get_base_specifiers().end(),
6128 	       s->get_base_specifiers().begin(),
6129 	       s->get_base_specifiers().end(),
6130 	       changes->base_changes());
6131 
6132   // Do *not* compare member types because it generates lots of noise
6133   // and I doubt it's really useful.
6134 #if 0
6135   compute_diff(f->get_member_types().begin(),
6136 	       f->get_member_types().end(),
6137 	       s->get_member_types().begin(),
6138 	       s->get_member_types().end(),
6139 	       changes->member_types_changes());
6140 #endif
6141 
6142   // Compare data member
6143   compute_diff(f->get_non_static_data_members().begin(),
6144 	       f->get_non_static_data_members().end(),
6145 	       s->get_non_static_data_members().begin(),
6146 	       s->get_non_static_data_members().end(),
6147 	       changes->data_members_changes());
6148 
6149   // Compare virtual member functions
6150   compute_diff(f->get_virtual_mem_fns().begin(),
6151 	       f->get_virtual_mem_fns().end(),
6152 	       s->get_virtual_mem_fns().begin(),
6153 	       s->get_virtual_mem_fns().end(),
6154 	       changes->member_fns_changes());
6155 
6156   // Compare member function templates
6157   compute_diff(f->get_member_function_templates().begin(),
6158 	       f->get_member_function_templates().end(),
6159 	       s->get_member_function_templates().begin(),
6160 	       s->get_member_function_templates().end(),
6161 	       changes->member_fn_tmpls_changes());
6162 
6163   // Likewise, do not compare member class templates
6164 #if 0
6165   compute_diff(f->get_member_class_templates().begin(),
6166 	       f->get_member_class_templates().end(),
6167 	       s->get_member_class_templates().begin(),
6168 	       s->get_member_class_templates().end(),
6169 	       changes->member_class_tmpls_changes());
6170 #endif
6171 
6172   changes->ensure_lookup_tables_populated();
6173 
6174   return changes;
6175 }
6176 
6177 //</class_diff stuff>
6178 
6179 // <base_diff stuff>
6180 
6181 /// Populate the vector of children node of the @ref diff base type
6182 /// sub-object of this instance of @ref base_diff.
6183 ///
6184 /// The children node can then later be retrieved using
6185 /// diff::children_node().
6186 void
chain_into_hierarchy()6187 base_diff::chain_into_hierarchy()
6188 {append_child_node(get_underlying_class_diff());}
6189 
6190 /// @param first the first base spec to consider.
6191 ///
6192 /// @param second the second base spec to consider.
6193 ///
6194 /// @param ctxt the context of the diff.  Note that this context
6195 /// object must stay alive at least during the life time of the
6196 /// current instance of @ref base_diff.  Otherwise memory corruption
6197 /// issues occur.
base_diff(class_decl::base_spec_sptr first,class_decl::base_spec_sptr second,class_diff_sptr underlying,diff_context_sptr ctxt)6198 base_diff::base_diff(class_decl::base_spec_sptr first,
6199 		     class_decl::base_spec_sptr second,
6200 		     class_diff_sptr		underlying,
6201 		     diff_context_sptr		ctxt)
6202   : diff(first, second, ctxt),
6203     priv_(new priv(underlying))
6204 {}
6205 
6206 /// Getter for the first base spec of the diff object.
6207 ///
6208 /// @return the first base specifier for the diff object.
6209 class_decl::base_spec_sptr
first_base() const6210 base_diff::first_base() const
6211 {return dynamic_pointer_cast<class_decl::base_spec>(first_subject());}
6212 
6213 /// Getter for the second base spec of the diff object.
6214 ///
6215 /// @return the second base specifier for the diff object.
6216 class_decl::base_spec_sptr
second_base() const6217 base_diff::second_base() const
6218 {return dynamic_pointer_cast<class_decl::base_spec>(second_subject());}
6219 
6220 /// Getter for the diff object for the diff of the underlying base
6221 /// classes.
6222 ///
6223 /// @return the diff object for the diff of the underlying base
6224 /// classes.
6225 const class_diff_sptr
get_underlying_class_diff() const6226 base_diff::get_underlying_class_diff() const
6227 {return priv_->underlying_class_diff_;}
6228 
6229 /// Setter for the diff object for the diff of the underlyng base
6230 /// classes.
6231 ///
6232 /// @param d the new diff object for the diff of the underlying base
6233 /// classes.
6234 void
set_underlying_class_diff(class_diff_sptr d)6235 base_diff::set_underlying_class_diff(class_diff_sptr d)
6236 {priv_->underlying_class_diff_ = d;}
6237 
6238 /// @return the pretty representation for the current instance of @ref
6239 /// base_diff.
6240 const string&
get_pretty_representation() const6241 base_diff::get_pretty_representation() const
6242 {
6243   if (diff::priv_->pretty_representation_.empty())
6244     {
6245       std::ostringstream o;
6246       o << "base_diff["
6247 	<< first_subject()->get_pretty_representation()
6248 	<< ", "
6249 	<< second_subject()->get_pretty_representation()
6250 	<< "]";
6251       diff::priv_->pretty_representation_ = o.str();
6252     }
6253   return diff::priv_->pretty_representation_;
6254 }
6255 
6256 /// Return true iff the current diff node carries a change.
6257 ///
6258 /// Return true iff the current diff node carries a change.
6259 bool
has_changes() const6260 base_diff::has_changes() const
6261 {return first_base() != second_base();}
6262 
6263 /// @return the kind of local change carried by the current diff node.
6264 /// The value returned is zero if the current node carries no local
6265 /// change.
6266 enum change_kind
has_local_changes() const6267 base_diff::has_local_changes() const
6268 {
6269   ir::change_kind k = ir::NO_CHANGE_KIND;
6270   if (!equals(*first_base(), *second_base(), &k))
6271     return k & ir::ALL_LOCAL_CHANGES_MASK;
6272   return ir::NO_CHANGE_KIND;
6273 }
6274 
6275 /// Generates a report for the current instance of base_diff.
6276 ///
6277 /// @param out the output stream to send the report to.
6278 ///
6279 /// @param indent the string to use for indentation.
6280 void
report(ostream & out,const string & indent) const6281 base_diff::report(ostream& out, const string& indent) const
6282 {
6283   context()->get_reporter()->report(*this, out, indent);
6284 }
6285 
6286 /// Constructs the diff object representing a diff between two base
6287 /// class specifications.
6288 ///
6289 /// Note that the two artifacts must have been created in the same
6290 /// @ref environment, otherwise, this function aborts.
6291 ///
6292 /// @param first the first base class specification.
6293 ///
6294 /// @param second the second base class specification.
6295 ///
6296 /// @param ctxt the content of the diff.
6297 ///
6298 /// @return the resulting diff object.
6299 base_diff_sptr
compute_diff(const class_decl::base_spec_sptr first,const class_decl::base_spec_sptr second,diff_context_sptr ctxt)6300 compute_diff(const class_decl::base_spec_sptr	first,
6301 	     const class_decl::base_spec_sptr	second,
6302 	     diff_context_sptr			ctxt)
6303 {
6304   class_diff_sptr cl = compute_diff(first->get_base_class(),
6305 				    second->get_base_class(),
6306 				    ctxt);
6307   base_diff_sptr changes(new base_diff(first, second, cl, ctxt));
6308 
6309   ctxt->initialize_canonical_diff(changes);
6310 
6311   return changes;
6312 }
6313 
6314 // </base_diff stuff>
6315 
6316 
6317 // <union_diff stuff>
6318 
6319 /// Clear the lookup tables useful for reporting.
6320 ///
6321 /// This function must be updated each time a lookup table is added or
6322 /// removed from the union_diff::priv.
6323 void
clear_lookup_tables(void)6324 union_diff::clear_lookup_tables(void)
6325 {class_or_union_diff::clear_lookup_tables();}
6326 
6327 /// Tests if the lookup tables are empty.
6328 ///
6329 /// @return true if the lookup tables are empty, false otherwise.
6330 bool
lookup_tables_empty(void) const6331 union_diff::lookup_tables_empty(void) const
6332 {return class_or_union_diff::lookup_tables_empty();}
6333 
6334 /// If the lookup tables are not yet built, walk the differences and
6335 /// fill them.
6336 void
ensure_lookup_tables_populated(void) const6337 union_diff::ensure_lookup_tables_populated(void) const
6338 {class_or_union_diff::ensure_lookup_tables_populated();}
6339 
6340 /// Allocate the memory for the priv_ pimpl data member of the @ref
6341 /// union_diff class.
6342 void
allocate_priv_data()6343 union_diff::allocate_priv_data()
6344 {
6345   class_or_union_diff::allocate_priv_data();
6346 }
6347 
6348 /// Constructor for the @ref union_diff type.
6349 ///
6350 /// @param first_union the first object of the comparison.
6351 ///
6352 /// @param second_union the second object of the comparison.
6353 ///
6354 /// @param ctxt the context of the comparison.
union_diff(union_decl_sptr first_union,union_decl_sptr second_union,diff_context_sptr ctxt)6355 union_diff::union_diff(union_decl_sptr first_union,
6356 		       union_decl_sptr second_union,
6357 		       diff_context_sptr ctxt)
6358   : class_or_union_diff(first_union, second_union, ctxt)
6359 {}
6360 
6361 /// Destructor of the union_diff node.
~union_diff()6362 union_diff::~union_diff()
6363 {}
6364 
6365 /// @return the first object of the comparison.
6366 union_decl_sptr
first_union_decl() const6367 union_diff::first_union_decl() const
6368 {return is_union_type(first_subject());}
6369 
6370 /// @return the second object of the comparison.
6371 union_decl_sptr
second_union_decl() const6372 union_diff::second_union_decl() const
6373 {return is_union_type(second_subject());}
6374 
6375 /// @return the pretty representation of the current diff node.
6376 const string&
get_pretty_representation() const6377 union_diff::get_pretty_representation() const
6378 {
6379   if (diff::priv_->pretty_representation_.empty())
6380     {
6381       std::ostringstream o;
6382       o << "union_diff["
6383 	<< first_subject()->get_pretty_representation()
6384 	<< ", "
6385 	<< second_subject()->get_pretty_representation()
6386 	<< "]";
6387       diff::priv_->pretty_representation_ = o.str();
6388     }
6389   return diff::priv_->pretty_representation_;
6390 }
6391 
6392 /// Report the changes carried by the current @ref union_diff node in
6393 /// a textual format.
6394 ///
6395 /// @param out the output stream to write the textual report to.
6396 ///
6397 /// @param indent the number of white space to use as indentation.
6398 void
report(ostream & out,const string & indent) const6399 union_diff::report(ostream& out, const string& indent) const
6400 {
6401   context()->get_reporter()->report(*this, out, indent);
6402 }
6403 
6404 /// Compute the difference between two @ref union_decl types.
6405 ///
6406 /// Note that the two types must hav been created in the same
6407 /// environment, otherwise, this function aborts.
6408 ///
6409 /// @param first the first @ref union_decl to consider.
6410 ///
6411 /// @param second the second @ref union_decl to consider.
6412 ///
6413 /// @param ctxt the context of the diff to use.
6414 union_diff_sptr
compute_diff(const union_decl_sptr first,const union_decl_sptr second,diff_context_sptr ctxt)6415 compute_diff(const union_decl_sptr	first,
6416 	     const union_decl_sptr	second,
6417 	     diff_context_sptr	ctxt)
6418 {
6419   union_diff_sptr changes(new union_diff(first, second, ctxt));
6420 
6421   ctxt->initialize_canonical_diff(changes);
6422   ABG_ASSERT(changes->get_canonical_diff());
6423 
6424   // Ok, so this is an optimization.  Do not freak out if it looks
6425   // weird, because, well, it does look weird.  This speeds up
6426   // greatly, for instance, the test case given at PR
6427   // libabigail/17948.
6428   //
6429   // We are setting the private data of the new instance of class_diff
6430   // (which is 'changes') to the private data of its canonical
6431   // instance.  That is, we are sharing the private data of 'changes'
6432   // with the private data of its canonical instance to consume less
6433   // memory in cases where the equivalence class of 'changes' is huge.
6434   //
6435   // But if changes is its own canonical instance, then we initialize
6436   // its private data properly.
6437   if (is_union_diff(changes->get_canonical_diff()) ==  changes.get())
6438     // changes is its own canonical instance, so it gets a brand new
6439     // private data.
6440     changes->allocate_priv_data();
6441   else
6442     {
6443       // changes has a non-empty equivalence class so it's going to
6444       // share its private data with its canonical instance.  Next
6445       // time class_diff::get_priv() is invoked, it's going to return
6446       // the shared private data of the canonical instance.
6447       return changes;
6448     }
6449 
6450   // Compare data member
6451   compute_diff(first->get_non_static_data_members().begin(),
6452 	       first->get_non_static_data_members().end(),
6453 	       second->get_non_static_data_members().begin(),
6454 	       second->get_non_static_data_members().end(),
6455 	       changes->data_members_changes());
6456 
6457 #if 0
6458   // Compare member functions
6459   compute_diff(first->get_mem_fns().begin(),
6460 	       first->get_mem_fns().end(),
6461 	       second->get_mem_fns().begin(),
6462 	       second->get_mem_fns().end(),
6463 	       changes->member_fns_changes());
6464 
6465   // Compare member function templates
6466   compute_diff(first->get_member_function_templates().begin(),
6467 	       first->get_member_function_templates().end(),
6468 	       second->get_member_function_templates().begin(),
6469 	       second->get_member_function_templates().end(),
6470 	       changes->member_fn_tmpls_changes());
6471 #endif
6472 
6473   changes->ensure_lookup_tables_populated();
6474 
6475   return changes;
6476 }
6477 
6478 // </union_diff stuff>
6479 
6480 //<scope_diff stuff>
6481 
6482 /// Clear the lookup tables that are useful for reporting.
6483 ///
6484 /// This function must be updated each time a lookup table is added or
6485 /// removed.
6486 void
clear_lookup_tables()6487 scope_diff::clear_lookup_tables()
6488 {
6489   priv_->deleted_types_.clear();
6490   priv_->deleted_decls_.clear();
6491   priv_->inserted_types_.clear();
6492   priv_->inserted_decls_.clear();
6493   priv_->changed_types_.clear();
6494   priv_->changed_decls_.clear();
6495   priv_->removed_types_.clear();
6496   priv_->removed_decls_.clear();
6497   priv_->added_types_.clear();
6498   priv_->added_decls_.clear();
6499 }
6500 
6501 /// Tests if the lookup tables are empty.
6502 ///
6503 /// This function must be updated each time a lookup table is added or
6504 /// removed.
6505 ///
6506 /// @return true iff all the lookup tables are empty.
6507 bool
lookup_tables_empty() const6508 scope_diff::lookup_tables_empty() const
6509 {
6510   return (priv_->deleted_types_.empty()
6511 	  && priv_->deleted_decls_.empty()
6512 	  && priv_->inserted_types_.empty()
6513 	  && priv_->inserted_decls_.empty()
6514 	  && priv_->changed_types_.empty()
6515 	  && priv_->changed_decls_.empty()
6516 	  && priv_->removed_types_.empty()
6517 	  && priv_->removed_decls_.empty()
6518 	  && priv_->added_types_.empty()
6519 	  && priv_->added_decls_.empty());
6520 }
6521 
6522 /// If the lookup tables are not yet built, walk the member_changes_
6523 /// member and fill the lookup tables.
6524 void
ensure_lookup_tables_populated()6525 scope_diff::ensure_lookup_tables_populated()
6526 {
6527   if (!lookup_tables_empty())
6528     return;
6529 
6530   edit_script& e = priv_->member_changes_;
6531 
6532   // Populate deleted types & decls lookup tables.
6533   for (const auto& deletion : e.deletions())
6534     {
6535       unsigned i = deletion.index();
6536       decl_base_sptr decl = deleted_member_at(i);
6537       string qname = decl->get_qualified_name();
6538       if (is_type(decl))
6539 	{
6540 	  class_decl_sptr klass_decl = dynamic_pointer_cast<class_decl>(decl);
6541 	  if (klass_decl && klass_decl->get_is_declaration_only())
6542 	    continue;
6543 
6544 	  // Unique types are artifically put in a scope because they
6545 	  // have to belong somewhere, but they should not be
6546 	  // considered added/removed from any scope because they are
6547 	  // artificial and always present in the system.
6548 	  if (is_unique_type(is_type(decl)))
6549 	    continue;
6550 
6551 	  ABG_ASSERT(priv_->deleted_types_.find(qname)
6552 		 == priv_->deleted_types_.end());
6553 	  priv_->deleted_types_[qname] = decl;
6554 	}
6555       else
6556 	{
6557 	  ABG_ASSERT(priv_->deleted_decls_.find(qname)
6558 		     == priv_->deleted_decls_.end());
6559 	  priv_->deleted_decls_[qname] = decl;
6560 	}
6561     }
6562 
6563   // Populate inserted types & decls as well as chagned types & decls
6564   // lookup tables.
6565   for (vector<insertion>::const_iterator it = e.insertions().begin();
6566        it != e.insertions().end();
6567        ++it)
6568     {
6569       for (vector<unsigned>::const_iterator i = it->inserted_indexes().begin();
6570 	   i != it->inserted_indexes().end();
6571 	   ++i)
6572 	{
6573 	  decl_base_sptr decl = inserted_member_at(i);
6574 	  string qname = decl->get_qualified_name();
6575 	  if (is_type(decl))
6576 	    {
6577 	      class_decl_sptr klass_decl =
6578 		dynamic_pointer_cast<class_decl>(decl);
6579 	      if (klass_decl && klass_decl->get_is_declaration_only())
6580 		continue;
6581 
6582 	      // Unique types are artifically put in a scope because they
6583 	      // have to belong somewhere, but they should not be
6584 	      // considered added/removed from any scope because they are
6585 	      // artificial and always present in the system.
6586 	      if (is_unique_type(is_type(decl)))
6587 		continue;
6588 
6589 	      ABG_ASSERT(priv_->inserted_types_.find(qname)
6590 		     == priv_->inserted_types_.end());
6591 	      string_decl_base_sptr_map::const_iterator j =
6592 		priv_->deleted_types_.find(qname);
6593 	      if (j != priv_->deleted_types_.end())
6594 		{
6595 		  if (*j->second != *decl)
6596 		    priv_->changed_types_[qname] =
6597 		      compute_diff(j->second, decl, context());
6598 		  priv_->deleted_types_.erase(j);
6599 		}
6600 	      else
6601 		priv_->inserted_types_[qname] = decl;
6602 	    }
6603 	  else
6604 	    {
6605 	      ABG_ASSERT(priv_->inserted_decls_.find(qname)
6606 		     == priv_->inserted_decls_.end());
6607 	      string_decl_base_sptr_map::const_iterator j =
6608 		priv_->deleted_decls_.find(qname);
6609 	      if (j != priv_->deleted_decls_.end())
6610 		{
6611 		  if (*j->second != *decl)
6612 		    priv_->changed_decls_[qname] =
6613 		      compute_diff(j->second, decl, context());
6614 		  priv_->deleted_decls_.erase(j);
6615 		}
6616 	      else
6617 		priv_->inserted_decls_[qname] = decl;
6618 	    }
6619 	}
6620     }
6621 
6622   sort_string_diff_sptr_map(priv_->changed_decls_,
6623 			    priv_->sorted_changed_decls_);
6624   sort_string_diff_sptr_map(priv_->changed_types_,
6625 			    priv_->sorted_changed_types_);
6626 
6627   // Populate removed types/decls lookup tables
6628   for (string_decl_base_sptr_map::const_iterator i =
6629 	 priv_->deleted_types_.begin();
6630        i != priv_->deleted_types_.end();
6631        ++i)
6632     {
6633       string_decl_base_sptr_map::const_iterator r =
6634 	priv_->inserted_types_.find(i->first);
6635       if (r == priv_->inserted_types_.end())
6636 	priv_->removed_types_[i->first] = i->second;
6637     }
6638   for (string_decl_base_sptr_map::const_iterator i =
6639 	 priv_->deleted_decls_.begin();
6640        i != priv_->deleted_decls_.end();
6641        ++i)
6642     {
6643       string_decl_base_sptr_map::const_iterator r =
6644 	priv_->inserted_decls_.find(i->first);
6645       if (r == priv_->inserted_decls_.end())
6646 	priv_->removed_decls_[i->first] = i->second;
6647     }
6648 
6649   // Populate added types/decls.
6650   for (string_decl_base_sptr_map::const_iterator i =
6651 	 priv_->inserted_types_.begin();
6652        i != priv_->inserted_types_.end();
6653        ++i)
6654     {
6655       string_decl_base_sptr_map::const_iterator r =
6656 	priv_->deleted_types_.find(i->first);
6657       if (r == priv_->deleted_types_.end())
6658 	priv_->added_types_[i->first] = i->second;
6659     }
6660   for (string_decl_base_sptr_map::const_iterator i =
6661 	 priv_->inserted_decls_.begin();
6662        i != priv_->inserted_decls_.end();
6663        ++i)
6664     {
6665       string_decl_base_sptr_map::const_iterator r =
6666 	priv_->deleted_decls_.find(i->first);
6667       if (r == priv_->deleted_decls_.end())
6668 	priv_->added_decls_[i->first] = i->second;
6669     }
6670 }
6671 
6672 /// Populate the vector of children node of the @ref diff base type
6673 /// sub-object of this instance of @ref scope_diff.
6674 ///
6675 /// The children node can then later be retrieved using
6676 /// diff::children_node().
6677 void
chain_into_hierarchy()6678 scope_diff::chain_into_hierarchy()
6679 {
6680   for (diff_sptrs_type::const_iterator i = changed_types().begin();
6681        i != changed_types().end();
6682        ++i)
6683     if (*i)
6684       append_child_node(*i);
6685 
6686   for (diff_sptrs_type::const_iterator i = changed_decls().begin();
6687        i != changed_decls().end();
6688        ++i)
6689     if (*i)
6690       append_child_node(*i);
6691 }
6692 
6693 /// Constructor for scope_diff
6694 ///
6695 /// @param first_scope the first scope to consider for the diff.
6696 ///
6697 /// @param second_scope the second scope to consider for the diff.
6698 ///
6699 /// @param ctxt the diff context to use.  Note that this context
6700 /// object must stay alive at least during the life time of the
6701 /// current instance of @ref scope_diff.  Otherwise memory corruption
6702 /// issues occur.
scope_diff(scope_decl_sptr first_scope,scope_decl_sptr second_scope,diff_context_sptr ctxt)6703 scope_diff::scope_diff(scope_decl_sptr first_scope,
6704 		       scope_decl_sptr second_scope,
6705 		       diff_context_sptr ctxt)
6706   : diff(first_scope, second_scope, ctxt),
6707     priv_(new priv)
6708 {}
6709 
6710 /// Getter for the first scope of the diff.
6711 ///
6712 /// @return the first scope of the diff.
6713 const scope_decl_sptr
first_scope() const6714 scope_diff::first_scope() const
6715 {return dynamic_pointer_cast<scope_decl>(first_subject());}
6716 
6717 /// Getter for the second scope of the diff.
6718 ///
6719 /// @return the second scope of the diff.
6720 const scope_decl_sptr
second_scope() const6721 scope_diff::second_scope() const
6722 {return dynamic_pointer_cast<scope_decl>(second_subject());}
6723 
6724 /// Accessor of the edit script of the members of a scope.
6725 ///
6726 /// This edit script is computed using the equality operator that
6727 /// applies to shared_ptr<decl_base>.
6728 ///
6729 /// That has interesting consequences.  For instance, consider two
6730 /// scopes S0 and S1.  S0 contains a class C0 and S1 contains a class
6731 /// S0'.  C0 and C0' have the same qualified name, but have different
6732 /// members.  The edit script will consider that C0 has been deleted
6733 /// from S0 and that S0' has been inserted.  This is a low level
6734 /// canonical representation of the changes; a higher level
6735 /// representation would give us a simpler way to say "the class C0
6736 /// has been modified into C0'".  But worry not.  We do have such
6737 /// higher representation as well; that is what changed_types() and
6738 /// changed_decls() is for.
6739 ///
6740 /// @return the edit script of the changes encapsulatd in this
6741 /// instance of scope_diff.
6742 const edit_script&
member_changes() const6743 scope_diff::member_changes() const
6744 {return priv_->member_changes_;}
6745 
6746 /// Accessor of the edit script of the members of a scope.
6747 ///
6748 /// This edit script is computed using the equality operator that
6749 /// applies to shared_ptr<decl_base>.
6750 ///
6751 /// That has interesting consequences.  For instance, consider two
6752 /// scopes S0 and S1.  S0 contains a class C0 and S1 contains a class
6753 /// S0'.  C0 and C0' have the same qualified name, but have different
6754 /// members.  The edit script will consider that C0 has been deleted
6755 /// from S0 and that S0' has been inserted.  This is a low level
6756 /// canonical representation of the changes; a higher level
6757 /// representation would give us a simpler way to say "the class C0
6758 /// has been modified into C0'".  But worry not.  We do have such
6759 /// higher representation as well; that is what changed_types() and
6760 /// changed_decls() is for.
6761 ///
6762 /// @return the edit script of the changes encapsulatd in this
6763 /// instance of scope_diff.
6764 edit_script&
member_changes()6765 scope_diff::member_changes()
6766 {return priv_->member_changes_;}
6767 
6768 /// Accessor that eases the manipulation of the edit script associated
6769 /// to this instance.  It returns the scope member that is reported
6770 /// (in the edit script) as deleted at a given index.
6771 ///
6772 /// @param i the index (in the edit script) of an element of the first
6773 /// scope that has been reported as being delete.
6774 ///
6775 /// @return the scope member that has been reported by the edit script
6776 /// as being deleted at index i.
6777 const decl_base_sptr
deleted_member_at(unsigned i) const6778 scope_diff::deleted_member_at(unsigned i) const
6779 {
6780   scope_decl_sptr scope = dynamic_pointer_cast<scope_decl>(first_subject());
6781  return scope->get_member_decls()[i];
6782 }
6783 
6784 /// Accessor that eases the manipulation of the edit script associated
6785 /// to this instance.  It returns the scope member (of the first scope
6786 /// of this diff instance) that is reported (in the edit script) as
6787 /// deleted at a given iterator.
6788 ///
6789 /// @param i the iterator of an element of the first scope that has
6790 /// been reported as being delete.
6791 ///
6792 /// @return the scope member of the first scope of this diff that has
6793 /// been reported by the edit script as being deleted at iterator i.
6794 const decl_base_sptr
deleted_member_at(vector<deletion>::const_iterator i) const6795 scope_diff::deleted_member_at(vector<deletion>::const_iterator i) const
6796 {return deleted_member_at(i->index());}
6797 
6798 /// Accessor that eases the manipulation of the edit script associated
6799 /// to this instance.  It returns the scope member (of the second
6800 /// scope of this diff instance) that is reported as being inserted
6801 /// from a given index.
6802 ///
6803 /// @param i the index of an element of the second scope this diff
6804 /// that has been reported by the edit script as being inserted.
6805 ///
6806 /// @return the scope member of the second scope of this diff that has
6807 /// been reported as being inserted from index i.
6808 const decl_base_sptr
inserted_member_at(unsigned i)6809 scope_diff::inserted_member_at(unsigned i)
6810 {
6811   scope_decl_sptr scope = dynamic_pointer_cast<scope_decl>(second_subject());
6812   return scope->get_member_decls()[i];
6813 }
6814 
6815 /// Accessor that eases the manipulation of the edit script associated
6816 /// to this instance.  It returns the scope member (of the second
6817 /// scope of this diff instance) that is reported as being inserted
6818 /// from a given iterator.
6819 ///
6820 /// @param i the iterator of an element of the second scope this diff
6821 /// that has been reported by the edit script as being inserted.
6822 ///
6823 /// @return the scope member of the second scope of this diff that has
6824 /// been reported as being inserted from iterator i.
6825 const decl_base_sptr
inserted_member_at(vector<unsigned>::const_iterator i)6826 scope_diff::inserted_member_at(vector<unsigned>::const_iterator i)
6827 {return inserted_member_at(*i);}
6828 
6829 /// @return a sorted vector of the types which content has changed
6830 /// from the first scope to the other.
6831 const diff_sptrs_type&
changed_types() const6832 scope_diff::changed_types() const
6833 {return priv_->sorted_changed_types_;}
6834 
6835 /// @return a sorted vector of the decls which content has changed
6836 /// from the first scope to the other.
6837 const diff_sptrs_type&
changed_decls() const6838 scope_diff::changed_decls() const
6839 {return priv_->sorted_changed_decls_;}
6840 
6841 const string_decl_base_sptr_map&
removed_types() const6842 scope_diff::removed_types() const
6843 {return priv_->removed_types_;}
6844 
6845 const string_decl_base_sptr_map&
removed_decls() const6846 scope_diff::removed_decls() const
6847 {return priv_->removed_decls_;}
6848 
6849 const string_decl_base_sptr_map&
added_types() const6850 scope_diff::added_types() const
6851 {return priv_->added_types_;}
6852 
6853 const string_decl_base_sptr_map&
added_decls() const6854 scope_diff::added_decls() const
6855 {return priv_->added_decls_;}
6856 
6857 /// @return the pretty representation for the current instance of @ref
6858 /// scope_diff.
6859 const string&
get_pretty_representation() const6860 scope_diff::get_pretty_representation() const
6861 {
6862   if (diff::priv_->pretty_representation_.empty())
6863     {
6864       std::ostringstream o;
6865       o << "scope_diff["
6866 	<< first_subject()->get_pretty_representation()
6867 	<< ", "
6868 	<< second_subject()->get_pretty_representation()
6869 	<< "]";
6870       diff::priv_->pretty_representation_ = o.str();
6871     }
6872   return diff::priv_->pretty_representation_;
6873 }
6874 
6875 /// Return true iff the current diff node carries a change.
6876 ///
6877 /// Return true iff the current diff node carries a change.
6878 bool
has_changes() const6879 scope_diff::has_changes() const
6880 {
6881   // TODO: add the number of really removed/added stuff.
6882   return changed_types().size() + changed_decls().size();
6883 }
6884 
6885 /// @return the kind of local change carried by the current diff node.
6886 /// The value returned is zero if the current node carries no local
6887 /// change.
6888 enum change_kind
has_local_changes() const6889 scope_diff::has_local_changes() const
6890 {
6891   ir::change_kind k = ir::NO_CHANGE_KIND;
6892   if (!equals(*first_scope(), *second_scope(), &k))
6893     return k & ir::ALL_LOCAL_CHANGES_MASK;
6894   return ir::NO_CHANGE_KIND;
6895 }
6896 
6897 /// Report the changes of one scope against another.
6898 ///
6899 /// @param out the out stream to report the changes to.
6900 ///
6901 /// @param indent the string to use for indentation.
6902 void
report(ostream & out,const string & indent) const6903 scope_diff::report(ostream& out, const string& indent) const
6904 {
6905   context()->get_reporter()->report(*this, out, indent);
6906 }
6907 
6908 /// Compute the diff between two scopes.
6909 ///
6910 /// Note that the two decls must have been created in the same @ref
6911 /// environment, otherwise, this function aborts.
6912 ///
6913 /// @param first the first scope to consider in computing the diff.
6914 ///
6915 /// @param second the second scope to consider in the diff
6916 /// computation.  The second scope is diffed against the first scope.
6917 ///
6918 /// @param d a pointer to the diff object to populate with the
6919 /// computed diff.
6920 ///
6921 /// @return return the populated \a d parameter passed to this
6922 /// function.
6923 ///
6924 /// @param ctxt the diff context to use.
6925 scope_diff_sptr
compute_diff(const scope_decl_sptr first,const scope_decl_sptr second,scope_diff_sptr d,diff_context_sptr ctxt)6926 compute_diff(const scope_decl_sptr	first,
6927 	     const scope_decl_sptr	second,
6928 	     scope_diff_sptr		d,
6929 	     diff_context_sptr		ctxt)
6930 {
6931   ABG_ASSERT(d->first_scope() == first && d->second_scope() == second);
6932 
6933   compute_diff(first->get_member_decls().begin(),
6934 	       first->get_member_decls().end(),
6935 	       second->get_member_decls().begin(),
6936 	       second->get_member_decls().end(),
6937 	       d->member_changes());
6938 
6939   d->ensure_lookup_tables_populated();
6940   d->context(ctxt);
6941 
6942   return d;
6943 }
6944 
6945 /// Compute the diff between two scopes.
6946 ///
6947 /// Note that the two decls must have been created in the same @ref
6948 /// environment, otherwise, this function aborts.
6949 ///
6950 /// @param first_scope the first scope to consider in computing the diff.
6951 ///
6952 /// @param second_scope the second scope to consider in the diff
6953 /// computation.  The second scope is diffed against the first scope.
6954 ///
6955 /// @param ctxt the diff context to use.
6956 ///
6957 /// @return return the resulting diff
6958 scope_diff_sptr
compute_diff(const scope_decl_sptr first_scope,const scope_decl_sptr second_scope,diff_context_sptr ctxt)6959 compute_diff(const scope_decl_sptr	first_scope,
6960 	     const scope_decl_sptr	second_scope,
6961 	     diff_context_sptr		ctxt)
6962 {
6963   scope_diff_sptr d(new scope_diff(first_scope, second_scope, ctxt));
6964   d = compute_diff(first_scope, second_scope, d, ctxt);
6965   ctxt->initialize_canonical_diff(d);
6966   return d;
6967 }
6968 
6969 //</scope_diff stuff>
6970 
6971 // <fn_parm_diff stuff>
6972 
6973 /// Constructor for the fn_parm_diff type.
6974 ///
6975 /// @param first the first subject of the diff.
6976 ///
6977 /// @param second the second subject of the diff.
6978 ///
6979 /// @param ctxt the context of the diff.  Note that this context
6980 /// object must stay alive at least during the life time of the
6981 /// current instance of @ref fn_parm_diff.  Otherwise memory
6982 /// corruption issues occur.
fn_parm_diff(const function_decl::parameter_sptr first,const function_decl::parameter_sptr second,diff_context_sptr ctxt)6983 fn_parm_diff::fn_parm_diff(const function_decl::parameter_sptr	first,
6984 			   const function_decl::parameter_sptr	second,
6985 			   diff_context_sptr			ctxt)
6986   : decl_diff_base(first, second, ctxt),
6987     priv_(new priv)
6988 {
6989   ABG_ASSERT(first->get_index() == second->get_index());
6990   priv_->type_diff = compute_diff(first->get_type(),
6991 				  second->get_type(),
6992 				  ctxt);
6993   ABG_ASSERT(priv_->type_diff);
6994 }
6995 
6996 /// Getter for the first subject of this diff node.
6997 ///
6998 /// @return the first function_decl::parameter_sptr subject of this
6999 /// diff node.
7000 const function_decl::parameter_sptr
first_parameter() const7001 fn_parm_diff::first_parameter() const
7002 {return dynamic_pointer_cast<function_decl::parameter>(first_subject());}
7003 
7004 /// Getter for the second subject of this diff node.
7005 ///
7006 /// @return the second function_decl::parameter_sptr subject of this
7007 /// diff node.
7008 const function_decl::parameter_sptr
second_parameter() const7009 fn_parm_diff::second_parameter() const
7010 {return dynamic_pointer_cast<function_decl::parameter>(second_subject());}
7011 
7012 /// Getter for the diff representing the changes on the type of the
7013 /// function parameter involved in the current instance of @ref
7014 /// fn_parm_diff.
7015 ///
7016 /// @return a diff_sptr representing the changes on the type of the
7017 /// function parameter we are interested in.
7018 diff_sptr
type_diff() const7019 fn_parm_diff::type_diff() const
7020 {return priv_->type_diff;}
7021 
7022 /// Build and return a textual representation of the current instance
7023 /// of @ref fn_parm_diff.
7024 ///
7025 /// @return the string representing the current instance of
7026 /// fn_parm_diff.
7027 const string&
get_pretty_representation() const7028 fn_parm_diff::get_pretty_representation() const
7029 {
7030   if (diff::priv_->pretty_representation_.empty())
7031     {
7032       std::ostringstream o;
7033       o << "function_parameter_diff["
7034 	<< first_subject()->get_pretty_representation()
7035 	<< ", "
7036 	<< second_subject()->get_pretty_representation()
7037 	<< "]";
7038       diff::priv_->pretty_representation_ = o.str();
7039     }
7040   return diff::priv_->pretty_representation_;
7041 }
7042 
7043 /// Return true iff the current diff node carries a change.
7044 ///
7045 /// @return true iff the current diff node carries a change.
7046 bool
has_changes() const7047 fn_parm_diff::has_changes() const
7048 {return *first_parameter() != *second_parameter();}
7049 
7050 /// Check if the current diff node carries a local change.
7051 ///
7052 /// @return the kind of local change carried by the current diff node.
7053 /// The value returned is zero if the current node carries no local
7054 /// change.
7055 enum change_kind
has_local_changes() const7056 fn_parm_diff::has_local_changes() const
7057 {
7058   ir::change_kind k = ir::NO_CHANGE_KIND;
7059   if (!equals(*first_parameter(), *second_parameter(), &k))
7060     return k & ir::ALL_LOCAL_CHANGES_MASK;
7061   return ir::NO_CHANGE_KIND;
7062 }
7063 
7064 /// Emit a textual report about the current fn_parm_diff instance.
7065 ///
7066 /// @param out the output stream to emit the textual report to.
7067 ///
7068 /// @param indent the indentation string to use in the report.
7069 void
report(ostream & out,const string & indent) const7070 fn_parm_diff::report(ostream& out, const string& indent) const
7071 {
7072   context()->get_reporter()->report(*this, out, indent);
7073 }
7074 
7075 /// Populate the vector of children nodes of the @ref diff base type
7076 /// sub-object of this instance of @ref fn_parm_diff.
7077 ///
7078 /// The children nodes can then later be retrieved using
7079 /// diff::children_nodes()
7080 void
chain_into_hierarchy()7081 fn_parm_diff::chain_into_hierarchy()
7082 {
7083   if (type_diff())
7084     append_child_node(type_diff());
7085 }
7086 
7087 /// Compute the difference between two function_decl::parameter_sptr;
7088 /// that is, between two function parameters.  Return a resulting
7089 /// fn_parm_diff_sptr that represents the changes.
7090 ///
7091 /// Note that the two decls must have been created in the same @ref
7092 /// environment, otherwise, this function aborts.
7093 ///
7094 /// @param first the first subject of the diff.
7095 ///
7096 /// @param second the second subject of the diff.
7097 ///
7098 /// @param ctxt the context of the diff.
7099 ///
7100 /// @return fn_parm_diff_sptr the resulting diff node.
7101 fn_parm_diff_sptr
compute_diff(const function_decl::parameter_sptr first,const function_decl::parameter_sptr second,diff_context_sptr ctxt)7102 compute_diff(const function_decl::parameter_sptr	first,
7103 	     const function_decl::parameter_sptr	second,
7104 	     diff_context_sptr				ctxt)
7105 {
7106   if (!first || !second)
7107     return fn_parm_diff_sptr();
7108 
7109   fn_parm_diff_sptr result(new fn_parm_diff(first, second, ctxt));
7110   ctxt->initialize_canonical_diff(result);
7111 
7112   return result;
7113 }
7114 // </fn_parm_diff stuff>
7115 
7116 // <function_type_diff stuff>
7117 
7118 void
ensure_lookup_tables_populated()7119 function_type_diff::ensure_lookup_tables_populated()
7120 {
7121   priv_->return_type_diff_ =
7122     compute_diff(first_function_type()->get_return_type(),
7123 		 second_function_type()->get_return_type(),
7124 		 context());
7125 
7126   string parm_name;
7127   function_decl::parameter_sptr parm;
7128   for (vector<deletion>::const_iterator i =
7129 	 priv_->parm_changes_.deletions().begin();
7130        i != priv_->parm_changes_.deletions().end();
7131        ++i)
7132     {
7133       parm = *(first_function_type()->get_first_parm()
7134 	       + i->index());
7135       parm_name = parm->get_name_id();
7136       // If for a reason the type name is empty we want to know and
7137       // fix that.
7138       ABG_ASSERT(!parm_name.empty());
7139       priv_->deleted_parms_[parm_name] = parm;
7140       priv_->deleted_parms_by_id_[parm->get_index()] = parm;
7141     }
7142 
7143   for (vector<insertion>::const_iterator i =
7144 	 priv_->parm_changes_.insertions().begin();
7145        i != priv_->parm_changes_.insertions().end();
7146        ++i)
7147     {
7148       for (vector<unsigned>::const_iterator j =
7149 	     i->inserted_indexes().begin();
7150 	   j != i->inserted_indexes().end();
7151 	   ++j)
7152 	{
7153 	  parm = *(second_function_type()->get_first_parm() + *j);
7154 	  parm_name = parm->get_name_id();
7155 	  // If for a reason the type name is empty we want to know and
7156 	  // fix that.
7157 	  ABG_ASSERT(!parm_name.empty());
7158 	  {
7159 	    string_parm_map::const_iterator k =
7160 	      priv_->deleted_parms_.find(parm_name);
7161 	    if (k != priv_->deleted_parms_.end())
7162 	      {
7163 		if (*k->second != *parm)
7164 		  priv_->subtype_changed_parms_[parm_name] =
7165 		    compute_diff(k->second, parm, context());
7166 		priv_->deleted_parms_.erase(parm_name);
7167 	      }
7168 	    else
7169 	      priv_->added_parms_[parm_name] = parm;
7170 	  }
7171 	  {
7172 	    unsigned_parm_map::const_iterator k =
7173 	      priv_->deleted_parms_by_id_.find(parm->get_index());
7174 	    if (k != priv_->deleted_parms_by_id_.end())
7175 	      {
7176 		if (*k->second != *parm
7177 		    && (k->second->get_name_id() != parm_name))
7178 		  priv_->changed_parms_by_id_[parm->get_index()] =
7179 		    compute_diff(k->second, parm, context());
7180 		priv_->added_parms_.erase(parm_name);
7181 		priv_->deleted_parms_.erase(k->second->get_name_id());
7182 		priv_->deleted_parms_by_id_.erase(parm->get_index());
7183 	      }
7184 	    else
7185 	      priv_->added_parms_by_id_[parm->get_index()] = parm;
7186 	  }
7187 	}
7188     }
7189 
7190   sort_string_fn_parm_diff_sptr_map(priv_->subtype_changed_parms_,
7191 				    priv_->sorted_subtype_changed_parms_);
7192   sort_string_fn_parm_diff_sptr_map(priv_->changed_parms_by_id_,
7193 				    priv_->sorted_changed_parms_by_id_);
7194   sort_string_parm_map(priv_->deleted_parms_,
7195 		       priv_->sorted_deleted_parms_);
7196 
7197   sort_string_parm_map(priv_->added_parms_,
7198 		       priv_->sorted_added_parms_);
7199 }
7200 
7201 /// In the vector of deleted parameters, get the one that is at a given
7202 /// index.
7203 ///
7204 /// @param i the index of the deleted parameter to get.
7205 ///
7206 /// @return the parameter returned.
7207 const function_decl::parameter_sptr
deleted_parameter_at(int i) const7208 function_type_diff::deleted_parameter_at(int i) const
7209 {return first_function_type()->get_parameters()[i];}
7210 
7211 /// Getter for the sorted vector of deleted parameters.
7212 ///
7213 /// @return the sorted vector of deleted parameters.
7214 const vector<function_decl::parameter_sptr>&
sorted_deleted_parms() const7215 function_type_diff::sorted_deleted_parms() const
7216 {return priv_->sorted_deleted_parms_;}
7217 
7218 /// Getter for the sorted vector of added parameters .
7219 ///
7220 /// @return the sorted vector of added parameters.
7221 const vector<function_decl::parameter_sptr>&
sorted_added_parms() const7222 function_type_diff::sorted_added_parms() const
7223 {return priv_->sorted_added_parms_;}
7224 
7225 /// In the vector of inserted parameters, get the one that is at a
7226 /// given index.
7227 ///
7228 /// @param i the index of the inserted parameter to get.
7229 ///
7230 /// @return the parameter returned.
7231 const function_decl::parameter_sptr
inserted_parameter_at(int i) const7232 function_type_diff::inserted_parameter_at(int i) const
7233 {return second_function_type()->get_parameters()[i];}
7234 
7235 /// Consutrctor of the @ref function_type type.
7236 ///
7237 /// @param first the first @ref function_type subject of the diff to
7238 /// create.
7239 ///
7240 /// @param second the second @ref function_type subject of the diff to
7241 /// create.
7242 ///
7243 /// @param ctxt the diff context to be used by the newly created
7244 /// instance of function_type_diff.  Note that this context object
7245 /// must stay alive at least during the life time of the current
7246 /// instance of @ref function_type_diff.  Otherwise memory corruption
7247 /// issues occur.
function_type_diff(const function_type_sptr first,const function_type_sptr second,diff_context_sptr ctxt)7248 function_type_diff::function_type_diff(const function_type_sptr first,
7249 				       const function_type_sptr second,
7250 				       diff_context_sptr	ctxt)
7251   : type_diff_base(first, second, ctxt),
7252     priv_(new priv)
7253 {}
7254 
7255 /// Getter for the first subject of the diff.
7256 ///
7257 /// @return the first function type involved in the diff.
7258 const function_type_sptr
first_function_type() const7259 function_type_diff::first_function_type() const
7260 {return dynamic_pointer_cast<function_type>(first_subject());}
7261 
7262 /// Getter for the second subject of the diff.
7263 ///
7264 /// @return the second function type involved in the diff.
7265 const function_type_sptr
second_function_type() const7266 function_type_diff::second_function_type() const
7267 {return dynamic_pointer_cast<function_type>(second_subject());}
7268 
7269 /// Getter for the diff of the return types of the two function types
7270 /// of the current diff.
7271 ///
7272 /// @return the diff of the return types of the two function types of
7273 /// the current diff.
7274 const diff_sptr
return_type_diff() const7275 function_type_diff::return_type_diff() const
7276 {return priv_->return_type_diff_;}
7277 
7278 /// Getter for the map of function parameter changes of the current diff.
7279 ///
7280 /// @return a map of function parameter changes of the current diff.
7281 const string_fn_parm_diff_sptr_map&
subtype_changed_parms() const7282 function_type_diff::subtype_changed_parms() const
7283 {return priv_->subtype_changed_parms_;}
7284 
7285 /// Getter for the map of parameters that got removed.
7286 ///
7287 /// @return the map of parameters that got removed.
7288 const string_parm_map&
removed_parms() const7289 function_type_diff::removed_parms() const
7290 {return priv_->deleted_parms_;}
7291 
7292 /// Getter for the map of parameters that got added.
7293 ///
7294 /// @return the map of parameters that got added.
7295 const string_parm_map&
added_parms() const7296 function_type_diff::added_parms() const
7297 {return priv_->added_parms_;}
7298 
7299 /// Build and return a copy of a pretty representation of the current
7300 /// instance of @ref function_type_diff.
7301 ///
7302 /// @return a copy of the pretty representation of the current
7303 /// instance of @ref function_type_diff.
7304 const string&
get_pretty_representation() const7305 function_type_diff::get_pretty_representation() const
7306 {
7307   if (diff::priv_->pretty_representation_.empty())
7308     {
7309       std::ostringstream o;
7310       o << "function_type_diff["
7311 	<< abigail::ir::get_pretty_representation(first_function_type())
7312 	<< ", "
7313 	<< abigail::ir::get_pretty_representation(second_function_type())
7314 	<< "]";
7315       diff::priv_->pretty_representation_ = o.str();
7316     }
7317   return diff::priv_->pretty_representation_;
7318 }
7319 
7320 /// Test if the current diff node carries changes.
7321 ///
7322 /// @return true iff the current diff node carries changes.
7323 bool
has_changes() const7324 function_type_diff::has_changes() const
7325 {return *first_function_type() != *second_function_type();}
7326 
7327 /// Test if the current diff node carries local changes.
7328 ///
7329 /// A local change is a change that is carried by this diff node, not
7330 /// by any of its children nodes.
7331 ///
7332 /// @return the kind of local change carried by the current diff node.
7333 /// The value returned is zero if the current node carries no local
7334 /// change.
7335 enum change_kind
has_local_changes() const7336 function_type_diff::has_local_changes() const
7337 {
7338   ir::change_kind k = ir::NO_CHANGE_KIND;
7339   if (!equals(*first_function_type(), *second_function_type(), &k))
7340     return k & ir::ALL_LOCAL_CHANGES_MASK;
7341   return ir::NO_CHANGE_KIND;
7342 }
7343 
7344 /// Build and emit a textual report about the current @ref
7345 /// function_type_diff instance.
7346 ///
7347 /// @param out the output stream.
7348 ///
7349 /// @param indent the indentation string to use.
7350 void
report(ostream & out,const string & indent) const7351 function_type_diff::report(ostream& out, const string& indent) const
7352 {
7353   context()->get_reporter()->report(*this, out, indent);
7354 }
7355 
7356 /// Populate the vector of children node of the @ref diff base type
7357 /// sub-object of this instance of @ref function_type_diff.
7358 ///
7359 /// The children node can then later be retrieved using
7360 /// diff::children_node().
7361 void
chain_into_hierarchy()7362 function_type_diff::chain_into_hierarchy()
7363 {
7364   if (diff_sptr d = return_type_diff())
7365     append_child_node(d);
7366 
7367   for (vector<fn_parm_diff_sptr>::const_iterator i =
7368 	 priv_->sorted_subtype_changed_parms_.begin();
7369        i != priv_->sorted_subtype_changed_parms_.end();
7370        ++i)
7371     if (diff_sptr d = *i)
7372       append_child_node(d);
7373 
7374   for (vector<fn_parm_diff_sptr>::const_iterator i =
7375 	 priv_->sorted_changed_parms_by_id_.begin();
7376        i != priv_->sorted_changed_parms_by_id_.end();
7377        ++i)
7378     if (diff_sptr d = *i)
7379       append_child_node(d);
7380 }
7381 
7382 /// Compute the diff between two instances of @ref function_type.
7383 ///
7384 /// Note that the two types must have been created in the same @ref
7385 /// environment, otherwise, this function aborts.
7386 ///
7387 /// @param first the first @ref function_type to consider for the diff.
7388 ///
7389 /// @param second the second @ref function_type to consider for the diff.
7390 ///
7391 /// @param ctxt the diff context to use.
7392 ///
7393 /// @return the resulting diff between the two @ref function_type.
7394 function_type_diff_sptr
compute_diff(const function_type_sptr first,const function_type_sptr second,diff_context_sptr ctxt)7395 compute_diff(const function_type_sptr	first,
7396 	     const function_type_sptr	second,
7397 	     diff_context_sptr		ctxt)
7398 {
7399   if (!first || !second)
7400     {
7401       // TODO: implement this for either first or second being NULL.
7402       return function_type_diff_sptr();
7403     }
7404 
7405   function_type_diff_sptr result(new function_type_diff(first, second, ctxt));
7406 
7407   diff_utils::compute_diff(first->get_first_parm(),
7408 			   first->get_parameters().end(),
7409 			   second->get_first_parm(),
7410 			   second->get_parameters().end(),
7411 			   result->priv_->parm_changes_);
7412 
7413   result->ensure_lookup_tables_populated();
7414 
7415   ctxt->initialize_canonical_diff(result);
7416 
7417   return result;
7418 }
7419 // </function_type_diff stuff>
7420 
7421 // <function_decl_diff stuff>
7422 
7423 /// Build the lookup tables of the diff, if necessary.
7424 void
ensure_lookup_tables_populated()7425 function_decl_diff::ensure_lookup_tables_populated()
7426 {
7427 }
7428 
7429 /// Populate the vector of children node of the @ref diff base type
7430 /// sub-object of this instance of @ref function_decl_diff.
7431 ///
7432 /// The children node can then later be retrieved using
7433 /// diff::children_node().
7434 void
chain_into_hierarchy()7435 function_decl_diff::chain_into_hierarchy()
7436 {
7437   if (diff_sptr d = type_diff())
7438     append_child_node(d);
7439 }
7440 
7441 /// Constructor for function_decl_diff
7442 ///
7443 /// @param first the first function considered by the diff.
7444 ///
7445 /// @param second the second function considered by the diff.
7446 ///
7447 /// @param ctxt the context of the diff.  Note that this context
7448 /// object must stay alive at least during the life time of the
7449 /// current instance of @ref function_decl_diff.  Otherwise memory
7450 /// corruption issues occur.
function_decl_diff(const function_decl_sptr first,const function_decl_sptr second,diff_context_sptr ctxt)7451 function_decl_diff::function_decl_diff(const function_decl_sptr first,
7452 				       const function_decl_sptr second,
7453 				       diff_context_sptr	ctxt)
7454   : decl_diff_base(first, second, ctxt),
7455     priv_(new priv)
7456 {
7457 }
7458 
7459 /// @return the first function considered by the diff.
7460 const function_decl_sptr
first_function_decl() const7461 function_decl_diff::first_function_decl() const
7462 {return dynamic_pointer_cast<function_decl>(first_subject());}
7463 
7464 /// @return the second function considered by the diff.
7465 const function_decl_sptr
second_function_decl() const7466 function_decl_diff::second_function_decl() const
7467 {return dynamic_pointer_cast<function_decl>(second_subject());}
7468 
7469 const function_type_diff_sptr
type_diff() const7470 function_decl_diff::type_diff() const
7471 {return priv_->type_diff_;}
7472 
7473 /// @return the pretty representation for the current instance of @ref
7474 /// function_decl_diff.
7475 const string&
get_pretty_representation() const7476 function_decl_diff::get_pretty_representation() const
7477 {
7478   if (diff::priv_->pretty_representation_.empty())
7479     {
7480       std::ostringstream o;
7481       o << "function_diff["
7482 	<< first_subject()->get_pretty_representation()
7483 	<< ", "
7484 	<< second_subject()->get_pretty_representation()
7485 	<< "]";
7486       diff::priv_->pretty_representation_ = o.str();
7487     }
7488   return diff::priv_->pretty_representation_;
7489 }
7490 
7491 /// Return true iff the current diff node carries a change.
7492 ///
7493 /// @return true iff the current diff node carries a change.
7494 bool
has_changes() const7495 function_decl_diff::has_changes() const
7496 {return *first_function_decl() != *second_function_decl();}
7497 
7498 /// @return the kind of local change carried by the current diff node.
7499 /// The value returned is zero if the current node carries no local
7500 /// change.
7501 enum change_kind
has_local_changes() const7502 function_decl_diff::has_local_changes() const
7503 {
7504   ir::change_kind k = ir::NO_CHANGE_KIND;
7505   if (!equals(*first_function_decl(), *second_function_decl(), &k))
7506     return k & ir::ALL_LOCAL_CHANGES_MASK;
7507   return ir::NO_CHANGE_KIND;
7508 }
7509 
7510 /// Serialize a report of the changes encapsulated in the current
7511 /// instance of @ref function_decl_diff over to an output stream.
7512 ///
7513 /// @param out the output stream to serialize the report to.
7514 ///
7515 /// @param indent the string to use an an indentation prefix.
7516 void
report(ostream & out,const string & indent) const7517 function_decl_diff::report(ostream& out, const string& indent) const
7518 {
7519   context()->get_reporter()->report(*this, out, indent);
7520 }
7521 
7522 /// Compute the diff between two function_decl.
7523 ///
7524 /// Note that the two decls must have been created in the same @ref
7525 /// environment, otherwise, this function aborts.
7526 ///
7527 /// @param first the first function_decl to consider for the diff
7528 ///
7529 /// @param second the second function_decl to consider for the diff
7530 ///
7531 /// @param ctxt the diff context to use.
7532 ///
7533 /// @return the computed diff
7534 function_decl_diff_sptr
compute_diff(const function_decl_sptr first,const function_decl_sptr second,diff_context_sptr ctxt)7535 compute_diff(const function_decl_sptr first,
7536 	     const function_decl_sptr second,
7537 	     diff_context_sptr ctxt)
7538 {
7539   if (!first || !second)
7540     {
7541       // TODO: implement this for either first or second being NULL.
7542       return function_decl_diff_sptr();
7543     }
7544 
7545   function_type_diff_sptr type_diff = compute_diff(first->get_type(),
7546 						   second->get_type(),
7547 						   ctxt);
7548 
7549   function_decl_diff_sptr result(new function_decl_diff(first, second,
7550 							ctxt));
7551   result->priv_->type_diff_ = type_diff;
7552 
7553   result->ensure_lookup_tables_populated();
7554 
7555   ctxt->initialize_canonical_diff(result);
7556 
7557   return result;
7558 }
7559 
7560 // </function_decl_diff stuff>
7561 
7562 // <type_decl_diff stuff>
7563 
7564 /// Constructor for type_decl_diff.
7565 ///
7566 /// @param first the first subject of the diff.
7567 ///
7568 /// @param second the second subject of the diff.
7569 ///
7570 /// @param ctxt the context of the diff.  Note that this context
7571 /// object must stay alive at least during the life time of the
7572 /// current instance of @ref type_decl_diff.  Otherwise memory
7573 /// corruption issues occur.
type_decl_diff(const type_decl_sptr first,const type_decl_sptr second,diff_context_sptr ctxt)7574 type_decl_diff::type_decl_diff(const type_decl_sptr first,
7575 			       const type_decl_sptr second,
7576 			       diff_context_sptr ctxt)
7577   : type_diff_base(first, second, ctxt)
7578 {}
7579 
7580 /// Getter for the first subject of the type_decl_diff.
7581 ///
7582 /// @return the first type_decl involved in the diff.
7583 const type_decl_sptr
first_type_decl() const7584 type_decl_diff::first_type_decl() const
7585 {return dynamic_pointer_cast<type_decl>(first_subject());}
7586 
7587 /// Getter for the second subject of the type_decl_diff.
7588 ///
7589 /// @return the second type_decl involved in the diff.
7590 const type_decl_sptr
second_type_decl() const7591 type_decl_diff::second_type_decl() const
7592 {return dynamic_pointer_cast<type_decl>(second_subject());}
7593 
7594 /// @return the pretty representation for the current instance of @ref
7595 /// type_decl_diff.
7596 const string&
get_pretty_representation() const7597 type_decl_diff::get_pretty_representation() const
7598 {
7599   if (diff::priv_->pretty_representation_.empty())
7600     {
7601       std::ostringstream o;
7602       o << "type_decl_diff["
7603 	<< first_subject()->get_pretty_representation()
7604 	<< ", "
7605 	<< second_subject()->get_pretty_representation()
7606 	<< "]";
7607       diff::priv_->pretty_representation_ = o.str();
7608     }
7609   return diff::priv_->pretty_representation_;
7610 }
7611 /// Return true iff the current diff node carries a change.
7612 ///
7613 /// @return true iff the current diff node carries a change.
7614 bool
has_changes() const7615 type_decl_diff::has_changes() const
7616 {return first_type_decl() != second_type_decl();}
7617 
7618 /// @return the kind of local change carried by the current diff node.
7619 /// The value returned is zero if the current node carries no local
7620 /// change.
7621 enum change_kind
has_local_changes() const7622 type_decl_diff::has_local_changes() const
7623 {
7624   ir::change_kind k = ir::NO_CHANGE_KIND;
7625   if (!equals(*first_type_decl(), *second_type_decl(), &k))
7626     return k & ir::ALL_LOCAL_CHANGES_MASK;
7627   return ir::NO_CHANGE_KIND;
7628 }
7629 /// Ouputs a report of the differences between of the two type_decl
7630 /// involved in the type_decl_diff.
7631 ///
7632 /// @param out the output stream to emit the report to.
7633 ///
7634 /// @param indent the string to use for indentatino indent.
7635 void
report(ostream & out,const string & indent) const7636 type_decl_diff::report(ostream& out, const string& indent) const
7637 {
7638   context()->get_reporter()->report(*this, out, indent);
7639 }
7640 
7641 /// Compute a diff between two type_decl.
7642 ///
7643 /// Note that the two types must have been created in the same @ref
7644 /// environment, otherwise, this function aborts.
7645 ///
7646 /// This function doesn't actually compute a diff.  As a type_decl is
7647 /// very simple (unlike compound constructs like function_decl or
7648 /// class_decl) it's easy to just compare the components of the
7649 /// type_decl to know what has changed.  Thus this function just
7650 /// builds and return a type_decl_diff object.  The
7651 /// type_decl_diff::report function will just compare the components
7652 /// of the the two type_decl and display where and how they differ.
7653 ///
7654 /// @param first a pointer to the first type_decl to
7655 /// consider.
7656 ///
7657 /// @param second a pointer to the second type_decl to consider.
7658 ///
7659 /// @param ctxt the diff context to use.
7660 ///
7661 /// @return a pointer to the resulting type_decl_diff.
7662 type_decl_diff_sptr
compute_diff(const type_decl_sptr first,const type_decl_sptr second,diff_context_sptr ctxt)7663 compute_diff(const type_decl_sptr	first,
7664 	     const type_decl_sptr	second,
7665 	     diff_context_sptr		ctxt)
7666 {
7667   type_decl_diff_sptr result(new type_decl_diff(first, second, ctxt));
7668 
7669   // We don't need to actually compute a diff here as a type_decl
7670   // doesn't have complicated sub-components.  type_decl_diff::report
7671   // just walks the members of the type_decls and display information
7672   // about the ones that have changed.  On a similar note,
7673   // type_decl_diff::length returns 0 if the two type_decls are equal,
7674   // and 1 otherwise.
7675 
7676   ctxt->initialize_canonical_diff(result);
7677 
7678   return result;
7679 }
7680 
7681 // </type_decl_diff stuff>
7682 
7683 // <typedef_diff stuff>
7684 
7685 /// Populate the vector of children node of the @ref diff base type
7686 /// sub-object of this instance of @ref typedef_diff.
7687 ///
7688 /// The children node can then later be retrieved using
7689 /// diff::children_node().
7690 void
chain_into_hierarchy()7691 typedef_diff::chain_into_hierarchy()
7692 {append_child_node(underlying_type_diff());}
7693 
7694 /// Constructor for typedef_diff.
7695 ///
7696 /// @param first the first subject of the diff.
7697 ///
7698 /// @param second the second subject of the diff.
7699 ///
7700 /// @param underlying the underlying diff of the @ref typedef_diff.
7701 /// That is the diff between the underlying types of @p first and @p
7702 /// second.
7703 ///
7704 /// @param ctxt the context of the diff.  Note that this context
7705 /// object must stay alive at least during the life time of the
7706 /// current instance of @ref typedef_diff.  Otherwise memory
7707 /// corruption issues occur.
typedef_diff(const typedef_decl_sptr first,const typedef_decl_sptr second,const diff_sptr underlying,diff_context_sptr ctxt)7708 typedef_diff::typedef_diff(const typedef_decl_sptr	first,
7709 			   const typedef_decl_sptr	second,
7710 			   const diff_sptr		underlying,
7711 			   diff_context_sptr		ctxt)
7712   : type_diff_base(first, second, ctxt),
7713     priv_(new priv(underlying))
7714 {}
7715 
7716 /// Getter for the firt typedef_decl involved in the diff.
7717 ///
7718 /// @return the first subject of the diff.
7719 const typedef_decl_sptr
first_typedef_decl() const7720 typedef_diff::first_typedef_decl() const
7721 {return dynamic_pointer_cast<typedef_decl>(first_subject());}
7722 
7723 /// Getter for the second typedef_decl involved in the diff.
7724 ///
7725 /// @return the second subject of the diff.
7726 const typedef_decl_sptr
second_typedef_decl() const7727 typedef_diff::second_typedef_decl() const
7728 {return dynamic_pointer_cast<typedef_decl>(second_subject());}
7729 
7730 /// Getter for the diff between the two underlying types of the
7731 /// typedefs.
7732 ///
7733 /// @return the diff object reprensenting the difference between the
7734 /// two underlying types of the typedefs.
7735 const diff_sptr
underlying_type_diff() const7736 typedef_diff::underlying_type_diff() const
7737 {return priv_->underlying_type_diff_;}
7738 
7739 /// Setter for the diff between the two underlying types of the
7740 /// typedefs.
7741 ///
7742 /// @param d the new diff object reprensenting the difference between
7743 /// the two underlying types of the typedefs.
7744 void
underlying_type_diff(const diff_sptr d)7745 typedef_diff::underlying_type_diff(const diff_sptr d)
7746 {priv_->underlying_type_diff_ = d;}
7747 
7748 /// @return the pretty representation for the current instance of @ref
7749 /// typedef_diff.
7750 const string&
get_pretty_representation() const7751 typedef_diff::get_pretty_representation() const
7752 {
7753   if (diff::priv_->pretty_representation_.empty())
7754     {
7755       std::ostringstream o;
7756       o << "typedef_diff["
7757 	<< first_subject()->get_pretty_representation()
7758 	<< ", "
7759 	<< second_subject()->get_pretty_representation()
7760 	<< "]";
7761       diff::priv_->pretty_representation_ = o.str();
7762     }
7763   return diff::priv_->pretty_representation_;
7764 }
7765 
7766 /// Return true iff the current diff node carries a change.
7767 ///
7768 /// @return true iff the current diff node carries a change.
7769 bool
has_changes() const7770 typedef_diff::has_changes() const
7771 {
7772   decl_base_sptr second = second_typedef_decl();
7773   return !(*first_typedef_decl() == *second);
7774 }
7775 
7776 /// @return the kind of local change carried by the current diff node.
7777 /// The value returned is zero if the current node carries no local
7778 /// change.
7779 enum change_kind
has_local_changes() const7780 typedef_diff::has_local_changes() const
7781 {
7782   ir::change_kind k = ir::NO_CHANGE_KIND;
7783   if (!equals(*first_typedef_decl(), *second_typedef_decl(), &k))
7784     return k & ir::ALL_LOCAL_CHANGES_MASK;
7785   return ir::NO_CHANGE_KIND;
7786 }
7787 
7788 /// Reports the difference between the two subjects of the diff in a
7789 /// serialized form.
7790 ///
7791 /// @param out the output stream to emit the report to.
7792 ///
7793 /// @param indent the indentation string to use.
7794 void
report(ostream & out,const string & indent) const7795 typedef_diff::report(ostream& out, const string& indent) const
7796 {
7797   context()->get_reporter()->report(*this, out, indent);
7798 }
7799 
7800 /// Compute a diff between two typedef_decl.
7801 ///
7802 /// Note that the two types must have been created in the same @ref
7803 /// environment, otherwise, this function aborts.
7804 ///
7805 /// @param first a pointer to the first typedef_decl to consider.
7806 ///
7807 /// @param second a pointer to the second typedef_decl to consider.
7808 ///
7809 /// @param ctxt the diff context to use.
7810 ///
7811 /// @return a pointer to the the resulting typedef_diff.
7812 typedef_diff_sptr
compute_diff(const typedef_decl_sptr first,const typedef_decl_sptr second,diff_context_sptr ctxt)7813 compute_diff(const typedef_decl_sptr	first,
7814 	     const typedef_decl_sptr	second,
7815 	     diff_context_sptr		ctxt)
7816 {
7817   diff_sptr d = compute_diff_for_types(first->get_underlying_type(),
7818 				       second->get_underlying_type(),
7819 				       ctxt);
7820   typedef_diff_sptr result(new typedef_diff(first, second, d, ctxt));
7821 
7822   ctxt->initialize_canonical_diff(result);
7823 
7824   return result;
7825 }
7826 
7827 /// Return the leaf underlying diff node of a @ref typedef_diff node.
7828 ///
7829 /// If the underlying diff node of a @ref typedef_diff node is itself
7830 /// a @ref typedef_diff node, then recursively look at the underlying
7831 /// diff nodes to get the first one that is not a a @ref typedef_diff
7832 /// node.  This is what a leaf underlying diff node means.
7833 ///
7834 /// Otherwise, if the underlying diff node of @ref typedef_diff is
7835 /// *NOT* a @ref typedef_diff node, then just return the underlying
7836 /// diff node.
7837 ///
7838 /// And if the diff node considered is not a @ref typedef_diff node,
7839 /// then just return it.
7840 ///
7841 /// @return the leaf underlying diff node of a @p diff.
7842 const diff*
get_typedef_diff_underlying_type_diff(const diff * diff)7843 get_typedef_diff_underlying_type_diff(const diff* diff)
7844 {
7845   const typedef_diff* d = dynamic_cast<const typedef_diff*>(diff);
7846   if (!d)
7847     return diff;
7848 
7849   if (const typedef_diff* deef =
7850       dynamic_cast<const typedef_diff*>(d->underlying_type_diff().get()))
7851     return get_typedef_diff_underlying_type_diff(deef);
7852 
7853   return d->underlying_type_diff().get();
7854 }
7855 
7856 // </typedef_diff stuff>
7857 
7858 // <translation_unit_diff stuff>
7859 
7860 /// Constructor for translation_unit_diff.
7861 ///
7862 /// @param first the first translation unit to consider for this diff.
7863 ///
7864 /// @param second the second translation unit to consider for this diff.
7865 ///
7866 /// @param ctxt the context of the diff.  Note that this context
7867 /// object must stay alive at least during the life time of the
7868 /// current instance of @ref translation_unit_diff.  Otherwise memory
7869 /// corruption issues occur.
translation_unit_diff(translation_unit_sptr first,translation_unit_sptr second,diff_context_sptr ctxt)7870 translation_unit_diff::translation_unit_diff(translation_unit_sptr first,
7871 					     translation_unit_sptr second,
7872 					     diff_context_sptr ctxt)
7873   : scope_diff(first->get_global_scope(), second->get_global_scope(), ctxt),
7874     priv_(new priv(first, second))
7875 {
7876 }
7877 
7878 /// Getter for the first translation unit of this diff.
7879 ///
7880 /// @return the first translation unit of this diff.
7881 const translation_unit_sptr
first_translation_unit() const7882 translation_unit_diff::first_translation_unit() const
7883 {return priv_->first_;}
7884 
7885 /// Getter for the second translation unit of this diff.
7886 ///
7887 /// @return the second translation unit of this diff.
7888 const translation_unit_sptr
second_translation_unit() const7889 translation_unit_diff::second_translation_unit() const
7890 {return priv_->second_;}
7891 
7892 /// Return true iff the current diff node carries a change.
7893 ///
7894 /// @return true iff the current diff node carries a change.
7895 bool
has_changes() const7896 translation_unit_diff::has_changes() const
7897 {return scope_diff::has_changes();}
7898 
7899 /// @return the kind of local change carried by the current diff node.
7900 /// The value returned is zero if the current node carries no local
7901 /// change.
7902 enum change_kind
has_local_changes() const7903 translation_unit_diff::has_local_changes() const
7904 {return ir::NO_CHANGE_KIND;}
7905 
7906 /// Report the diff in a serialized form.
7907 ///
7908 /// @param out the output stream to serialize the report to.
7909 ///
7910 /// @param indent the prefix to use as indentation for the report.
7911 void
report(ostream & out,const string & indent) const7912 translation_unit_diff::report(ostream& out, const string& indent) const
7913 {scope_diff::report(out, indent);}
7914 
7915 /// Compute the diff between two translation_units.
7916 ///
7917 /// Note that the two translation units must have been created in the
7918 /// same @ref environment, otherwise, this function aborts.
7919 ///
7920 /// @param first the first translation_unit to consider.
7921 ///
7922 /// @param second the second translation_unit to consider.
7923 ///
7924 /// @param ctxt the diff context to use.  If null, this function will
7925 /// create a new context and set to the diff object returned.
7926 ///
7927 /// @return the newly created diff object.
7928 translation_unit_diff_sptr
compute_diff(const translation_unit_sptr first,const translation_unit_sptr second,diff_context_sptr ctxt)7929 compute_diff(const translation_unit_sptr	first,
7930 	     const translation_unit_sptr	second,
7931 	     diff_context_sptr			ctxt)
7932 {
7933   ABG_ASSERT(first && second);
7934 
7935   if (!ctxt)
7936     ctxt.reset(new diff_context);
7937 
7938   // TODO: handle first or second having empty contents.
7939   translation_unit_diff_sptr tu_diff(new translation_unit_diff(first, second,
7940 							       ctxt));
7941   scope_diff_sptr sc_diff = dynamic_pointer_cast<scope_diff>(tu_diff);
7942 
7943   compute_diff(static_pointer_cast<scope_decl>(first->get_global_scope()),
7944 	       static_pointer_cast<scope_decl>(second->get_global_scope()),
7945 	       sc_diff,
7946 	       ctxt);
7947 
7948   ctxt->initialize_canonical_diff(tu_diff);
7949 
7950   return tu_diff;
7951 }
7952 
7953 // </translation_unit_diff stuff>
7954 
7955 // <diff_maps stuff>
7956 
7957 /// The private data of the @ref diff_maps type.
7958 struct diff_maps::priv
7959 {
7960   string_diff_ptr_map type_decl_diff_map_;
7961   string_diff_ptr_map enum_diff_map_;
7962   string_diff_ptr_map class_diff_map_;
7963   string_diff_ptr_map union_diff_map_;
7964   string_diff_ptr_map typedef_diff_map_;
7965   string_diff_ptr_map subrange_diff_map_;
7966   string_diff_ptr_map array_diff_map_;
7967   string_diff_ptr_map reference_diff_map_;
7968   string_diff_ptr_map function_type_diff_map_;
7969   string_diff_ptr_map function_decl_diff_map_;
7970   string_diff_ptr_map var_decl_diff_map_;
7971   string_diff_ptr_map distinct_diff_map_;
7972   string_diff_ptr_map fn_parm_diff_map_;
7973   diff_artifact_set_map_type impacted_artifacts_map_;
7974 }; // end struct diff_maps::priv
7975 
7976 /// Default constructor of the @ref diff_maps type.
diff_maps()7977 diff_maps::diff_maps()
7978   : priv_(new diff_maps::priv())
7979 {}
7980 
7981 diff_maps::~diff_maps() = default;
7982 
7983 /// Getter of the map that contains basic type diffs.
7984 ///
7985 /// @return the map that contains basic type diffs.
7986 const string_diff_ptr_map&
get_type_decl_diff_map() const7987 diff_maps::get_type_decl_diff_map() const
7988 {return priv_->type_decl_diff_map_;}
7989 
7990 /// Getter of the map that contains basic type diffs.
7991 ///
7992 /// @return the map that contains basic type diffs.
7993 string_diff_ptr_map&
get_type_decl_diff_map()7994 diff_maps::get_type_decl_diff_map()
7995 {return priv_->type_decl_diff_map_;}
7996 
7997 /// Getter of the map that contains enum type diffs.
7998 ///
7999 /// @return the map that contains enum type diffs.
8000 const string_diff_ptr_map&
get_enum_diff_map() const8001 diff_maps::get_enum_diff_map() const
8002 {return priv_->enum_diff_map_;}
8003 
8004 /// Getter of the map that contains enum type diffs.
8005 ///
8006 /// @return the map that contains enum type diffs.
8007 string_diff_ptr_map&
get_enum_diff_map()8008 diff_maps::get_enum_diff_map()
8009 {return priv_->enum_diff_map_;}
8010 
8011 /// Getter of the map that contains class type diffs.
8012 ///
8013 /// @return the map that contains class type diffs.
8014 const string_diff_ptr_map&
get_class_diff_map() const8015 diff_maps::get_class_diff_map() const
8016 {return priv_->class_diff_map_;}
8017 
8018 /// Getter of the map that contains class type diffs.
8019 ///
8020 /// @return the map that contains class type diffs.
8021 string_diff_ptr_map&
get_class_diff_map()8022 diff_maps::get_class_diff_map()
8023 {return priv_->class_diff_map_;}
8024 
8025 /// Getter of the map that contains union type diffs.
8026 ///
8027 /// @return the map that contains union type diffs.
8028 const string_diff_ptr_map&
get_union_diff_map() const8029 diff_maps::get_union_diff_map() const
8030 {return priv_->union_diff_map_;}
8031 
8032 /// Getter of the map that contains union type diffs.
8033 ///
8034 /// @return the map that contains union type diffs.
8035 string_diff_ptr_map&
get_union_diff_map()8036 diff_maps::get_union_diff_map()
8037 {return priv_->union_diff_map_;}
8038 
8039 /// Getter of the map that contains typedef type diffs.
8040 ///
8041 /// @return the map that contains typedef type diffs.
8042 const string_diff_ptr_map&
get_typedef_diff_map() const8043 diff_maps::get_typedef_diff_map() const
8044 {return priv_->typedef_diff_map_;}
8045 
8046 /// Getter of the map that contains typedef type diffs.
8047 ///
8048 /// @return the map that contains typedef type diffs.
8049 string_diff_ptr_map&
get_typedef_diff_map()8050 diff_maps::get_typedef_diff_map()
8051 {return priv_->typedef_diff_map_;}
8052 
8053 /// Getter of the map that contains subrange type diffs.
8054 ///
8055 /// @return the map that contains subrange type diffs.
8056 const string_diff_ptr_map&
get_subrange_diff_map() const8057 diff_maps::get_subrange_diff_map() const
8058 {return priv_->subrange_diff_map_;}
8059 
8060 /// Getter of the map that contains subrange type diffs.
8061 ///
8062 /// @return the map that contains subrange type diffs.
8063 string_diff_ptr_map&
get_subrange_diff_map()8064 diff_maps::get_subrange_diff_map()
8065 {return priv_->subrange_diff_map_;}
8066 
8067 /// Getter of the map that contains array type diffs.
8068 ///
8069 /// @return the map that contains array type diffs.
8070 const string_diff_ptr_map&
get_array_diff_map() const8071 diff_maps::get_array_diff_map() const
8072 {return priv_->array_diff_map_;}
8073 
8074 /// Getter of the map that contains array type diffs.
8075 ///
8076 /// @return the map that contains array type diffs.
8077 string_diff_ptr_map&
get_array_diff_map()8078 diff_maps::get_array_diff_map()
8079 {return priv_->array_diff_map_;}
8080 
8081 /// Getter of the map that contains reference type diffs.
8082 ///
8083 /// @return the map that contains reference type diffs.
8084 const string_diff_ptr_map&
get_reference_diff_map() const8085 diff_maps::get_reference_diff_map() const
8086 {return priv_->reference_diff_map_;}
8087 
8088 /// Getter of the map that contains reference type diffs.
8089 ///
8090 /// @return the map that contains reference type diffs.
8091 string_diff_ptr_map&
get_reference_diff_map()8092 diff_maps::get_reference_diff_map()
8093 {{return priv_->reference_diff_map_;}}
8094 
8095 /// Getter of the map that contains function parameter diffs.
8096 ///
8097 /// @return the map that contains function parameter diffs.
8098 const string_diff_ptr_map&
get_fn_parm_diff_map() const8099 diff_maps::get_fn_parm_diff_map() const
8100 {return priv_->fn_parm_diff_map_;}
8101 
8102 /// Getter of the map that contains function parameter diffs.
8103 ///
8104 /// @return the map that contains function parameter diffs.
8105 string_diff_ptr_map&
get_fn_parm_diff_map()8106 diff_maps::get_fn_parm_diff_map()
8107 {return priv_->fn_parm_diff_map_;}
8108 
8109 /// Getter of the map that contains function type diffs.
8110 ///
8111 /// @return the map that contains function type diffs.
8112 const string_diff_ptr_map&
get_function_type_diff_map() const8113 diff_maps::get_function_type_diff_map() const
8114 {return priv_->function_type_diff_map_;}
8115 
8116 /// Getter of the map that contains function type diffs.
8117 ///
8118 /// @return the map that contains function type diffs.
8119 string_diff_ptr_map&
get_function_type_diff_map()8120 diff_maps::get_function_type_diff_map()
8121 {return priv_->function_type_diff_map_;}
8122 
8123 /// Getter of the map that contains function decl diffs.
8124 ///
8125 /// @return the map that contains function decl diffs.
8126 const string_diff_ptr_map&
get_function_decl_diff_map() const8127 diff_maps::get_function_decl_diff_map() const
8128 {return priv_->function_decl_diff_map_;}
8129 
8130 /// Getter of the map that contains function decl diffs.
8131 ///
8132 /// @return the map that contains function decl diffs.
8133 string_diff_ptr_map&
get_function_decl_diff_map()8134 diff_maps::get_function_decl_diff_map()
8135 {return priv_->function_decl_diff_map_;}
8136 
8137 /// Getter of the map that contains var decl diffs.
8138 ///
8139 /// @return the map that contains var decl diffs.
8140 const string_diff_ptr_map&
get_var_decl_diff_map() const8141 diff_maps::get_var_decl_diff_map() const
8142 {return priv_->var_decl_diff_map_;}
8143 
8144 /// Getter of the map that contains var decl diffs.
8145 ///
8146 /// @return the map that contains var decl diffs.
8147 string_diff_ptr_map&
get_var_decl_diff_map()8148 diff_maps::get_var_decl_diff_map()
8149 {return priv_->var_decl_diff_map_;}
8150 
8151 /// Getter of the map that contains distinct diffs.
8152 ///
8153 /// @return the map that contains distinct diffs.
8154 const string_diff_ptr_map&
get_distinct_diff_map() const8155 diff_maps::get_distinct_diff_map() const
8156 {return priv_->distinct_diff_map_;}
8157 
8158 /// Getter of the map that contains distinct diffs.
8159 ///
8160 /// @return the map that contains distinct diffs.
8161 string_diff_ptr_map&
get_distinct_diff_map()8162 diff_maps::get_distinct_diff_map()
8163 {return priv_->distinct_diff_map_;}
8164 
8165 /// Insert a new diff node into the current instance of @ref diff_maps.
8166 ///
8167 /// @param dif the new diff node to insert into the @ref diff_maps.
8168 ///
8169 /// @param impacted_iface the interface (global function or variable)
8170 /// currently being analysed that led to analysing the diff node @p
8171 /// dif.  In other words, this is the interface impacted by the diff
8172 /// node @p dif.  Note that this can be nil in cases where we are
8173 /// directly analysing changes to a type that is not reachable from
8174 /// any global function or variable.
8175 ///
8176 /// @return true iff the diff node could be added to the current
8177 /// instance of @ref diff_maps.
8178 bool
insert_diff_node(const diff * dif,const type_or_decl_base_sptr & impacted_iface)8179 diff_maps::insert_diff_node(const diff *dif,
8180 			    const type_or_decl_base_sptr& impacted_iface)
8181 {
8182   string n = get_pretty_representation(dif->first_subject(),
8183 				       /*internal=*/true);
8184   if (const type_decl_diff *d = is_diff_of_basic_type(dif))
8185     get_type_decl_diff_map()[n] = const_cast<type_decl_diff*>(d);
8186   else if (const enum_diff *d = is_enum_diff(dif))
8187     get_enum_diff_map()[n] = const_cast<enum_diff*>(d);
8188   else if (const class_diff *d = is_class_diff(dif))
8189       get_class_diff_map()[n] = const_cast<class_diff*>(d);
8190   else if (const union_diff *d = is_union_diff(dif))
8191     get_union_diff_map()[n] = const_cast<union_diff*>(d);
8192   else if (const typedef_diff *d = is_typedef_diff(dif))
8193     get_typedef_diff_map()[n] = const_cast<typedef_diff*>(d);
8194   else if (const subrange_diff *d = is_subrange_diff(dif))
8195     get_subrange_diff_map()[n] = const_cast<subrange_diff*>(d);
8196   else if (const array_diff *d = is_array_diff(dif))
8197       get_array_diff_map()[n] = const_cast<array_diff*>(d);
8198   else if (const reference_diff *d = is_reference_diff(dif))
8199     get_reference_diff_map()[n] = const_cast<reference_diff*>(d);
8200   else if (const fn_parm_diff *d = is_fn_parm_diff(dif))
8201     get_fn_parm_diff_map()[n] = const_cast<fn_parm_diff*>(d);
8202   else if (const function_type_diff *d = is_function_type_diff(dif))
8203     get_function_type_diff_map()[n] = const_cast<function_type_diff*>(d);
8204   else if (const var_diff *d = is_var_diff(dif))
8205     get_var_decl_diff_map()[n] = const_cast<var_diff*>(d);
8206   else if (const function_decl_diff *d = is_function_decl_diff(dif))
8207     get_function_decl_diff_map()[n] = const_cast<function_decl_diff*>(d);
8208   else if (const distinct_diff *d = is_distinct_diff(dif))
8209     get_distinct_diff_map()[n] = const_cast<distinct_diff*>(d);
8210   else if (is_base_diff(dif))
8211     // we silently drop this case.
8212     return true;
8213   else
8214       ABG_ASSERT_NOT_REACHED;
8215 
8216   // Update the map that associates this diff node to the set of
8217   // interfaces it impacts.
8218 
8219   if (impacted_iface)
8220     {
8221       diff_artifact_set_map_type::iterator i =
8222 	priv_->impacted_artifacts_map_.find(dif);
8223 
8224       if (i == priv_->impacted_artifacts_map_.end())
8225 	{
8226 	  artifact_sptr_set_type set;
8227 	  set.insert(impacted_iface);
8228 	  priv_->impacted_artifacts_map_[dif] = set;
8229 	}
8230       else
8231 	i->second.insert(impacted_iface);
8232     }
8233 
8234   return true;
8235 }
8236 
8237 /// Lookup the interfaces that are impacted by a given leaf diff node.
8238 ///
8239 /// @param d the diff node to consider.
8240 ///
8241 /// @return the set of artifacts impacted by @p d.
8242 artifact_sptr_set_type*
lookup_impacted_interfaces(const diff * d) const8243 diff_maps::lookup_impacted_interfaces(const diff *d) const
8244 {
8245   diff_artifact_set_map_type::iterator i =
8246     priv_->impacted_artifacts_map_.find(d);
8247 
8248   if (i == priv_->impacted_artifacts_map_.end())
8249     return 0;
8250 
8251   return &i->second;
8252 }
8253 
8254 //
8255 // </diff_maps stuff>
8256 
8257 /// Constructor for the @ref diff_stat type.
8258 ///
8259 /// @param ctxt the context of the corpus diff.  Note that this
8260 /// context object must stay alive at least during the life time of
8261 /// the current instance of @ref corpus_diff::diff_stats.  Otherwise
8262 /// memory corruption issues occur.
diff_stats(diff_context_sptr ctxt)8263 corpus_diff::diff_stats::diff_stats(diff_context_sptr ctxt)
8264   : priv_(new priv(ctxt))
8265 {}
8266 
8267 /// Getter for the number of functions removed.
8268 ///
8269 /// @return the number of functions removed.
8270 size_t
num_func_removed() const8271 corpus_diff::diff_stats::num_func_removed() const
8272 {return priv_->num_func_removed;}
8273 
8274 /// Setter for the number of functions removed.
8275 ///
8276 /// @param n the new number of functions removed.
8277 void
num_func_removed(size_t n)8278 corpus_diff::diff_stats::num_func_removed(size_t n)
8279 {priv_->num_func_removed = n;}
8280 
8281 /// Getter for the number of removed functions that have been filtered
8282 /// out.
8283 ///
8284 /// @return the number of removed functions that have been filtered
8285 /// out.
8286 size_t
num_removed_func_filtered_out() const8287 corpus_diff::diff_stats::num_removed_func_filtered_out() const
8288 {
8289   if (priv_->ctxt() && !priv_->ctxt()->show_deleted_fns())
8290     return num_func_removed();
8291   return priv_->num_removed_func_filtered_out;
8292 }
8293 
8294 /// Setter for the number of removed functions that have been filtered
8295 /// out.
8296 ///
8297 /// @param t the new value.
8298 void
num_removed_func_filtered_out(size_t t)8299 corpus_diff::diff_stats::num_removed_func_filtered_out(size_t t)
8300 {priv_->num_removed_func_filtered_out = t;}
8301 
8302 /// Getter for the net number of function removed.
8303 ///
8304 /// This is the difference between the number of functions removed and
8305 /// the number of functons removed that have been filtered out.
8306 ///
8307 /// @return the net number of function removed.
8308 size_t
net_num_func_removed() const8309 corpus_diff::diff_stats::net_num_func_removed() const
8310 {
8311   ABG_ASSERT(num_func_removed() >= num_removed_func_filtered_out());
8312   return num_func_removed() - num_removed_func_filtered_out();
8313 }
8314 
8315 /// Getter for the number of functions added.
8316 ///
8317 /// @return the number of functions added.
8318 size_t
num_func_added() const8319 corpus_diff::diff_stats::num_func_added() const
8320 {return priv_->num_func_added;}
8321 
8322 /// Setter for the number of functions added.
8323 ///
8324 /// @param n the new number of functions added.
8325 void
num_func_added(size_t n)8326 corpus_diff::diff_stats::num_func_added(size_t n)
8327 {priv_->num_func_added = n;}
8328 
8329 /// Getter for the number of added function that have been filtered out.
8330 ///
8331 /// @return the number of added function that have been filtered out.
8332 size_t
num_added_func_filtered_out() const8333 corpus_diff::diff_stats::num_added_func_filtered_out() const
8334 {
8335   if (priv_->ctxt() && !priv_->ctxt()->show_added_fns())
8336     return num_func_added();
8337   return priv_->num_added_func_filtered_out;
8338 }
8339 
8340 /// Setter for the number of added function that have been filtered
8341 /// out.
8342 ///
8343 /// @param n the new value.
8344 void
num_added_func_filtered_out(size_t n)8345 corpus_diff::diff_stats::num_added_func_filtered_out(size_t n)
8346 {priv_->num_added_func_filtered_out = n;}
8347 
8348 /// Getter for the net number of added functions.
8349 ///
8350 /// The net number of added functions is the difference between the
8351 /// number of added functions and the number of added functions that
8352 /// have been filtered out.
8353 ///
8354 /// @return the net number of added functions.
8355 size_t
net_num_func_added() const8356 corpus_diff::diff_stats::net_num_func_added() const
8357 {
8358   ABG_ASSERT(num_func_added() >= num_added_func_filtered_out());
8359   return num_func_added() - num_added_func_filtered_out();
8360 }
8361 
8362 /// Getter for the number of functions that have a change in one of
8363 /// their sub-types.
8364 ///
8365 /// @return the number of functions that have a change in one of their
8366 /// sub-types.
8367 size_t
num_func_changed() const8368 corpus_diff::diff_stats::num_func_changed() const
8369 {return priv_->num_func_changed;}
8370 
8371 /// Setter for the number of functions that have a change in one of
8372 /// their sub-types.
8373 ///
8374 /// @@param n the new number of functions that have a change in one of
8375 /// their sub-types.
8376 void
num_func_changed(size_t n)8377 corpus_diff::diff_stats::num_func_changed(size_t n)
8378 {priv_->num_func_changed = n;}
8379 
8380 /// Getter for the number of functions that have a change in one of
8381 /// their sub-types, and that have been filtered out.
8382 ///
8383 /// @return the number of functions that have a change in one of their
8384 /// sub-types, and that have been filtered out.
8385 size_t
num_changed_func_filtered_out() const8386 corpus_diff::diff_stats::num_changed_func_filtered_out() const
8387 {return priv_->num_changed_func_filtered_out;}
8388 
8389 /// Setter for the number of functions that have a change in one of
8390 /// their sub-types, and that have been filtered out.
8391 ///
8392 /// @param n the new number of functions that have a change in one of their
8393 /// sub-types, and that have been filtered out.
8394 void
num_changed_func_filtered_out(size_t n)8395 corpus_diff::diff_stats::num_changed_func_filtered_out(size_t n)
8396 {priv_->num_changed_func_filtered_out = n;}
8397 
8398 /// Getter for the number of functions that carry virtual member
8399 /// offset changes.
8400 ///
8401 /// @return the number of functions that carry virtual member changes.
8402 size_t
num_func_with_virtual_offset_changes() const8403 corpus_diff::diff_stats::num_func_with_virtual_offset_changes() const
8404 {return priv_->num_func_with_virt_offset_changes;}
8405 
8406 /// Setter for the number of functions that carry virtual member
8407 /// offset changes.
8408 ///
8409 /// @param n the new number of functions that carry virtual member
8410 /// offset.  changes.
8411 void
num_func_with_virtual_offset_changes(size_t n)8412 corpus_diff::diff_stats::num_func_with_virtual_offset_changes(size_t n)
8413 {priv_->num_func_with_virt_offset_changes = n;}
8414 
8415 /// Getter for the number of functions that have a change in their
8416 /// sub-types, minus the number of these functions that got filtered
8417 /// out from the diff.
8418 ///
8419 /// @return for the the number of functions that have a change in
8420 /// their sub-types, minus the number of these functions that got
8421 /// filtered out from the diff.
8422 size_t
net_num_func_changed() const8423 corpus_diff::diff_stats::net_num_func_changed() const
8424 {return num_func_changed() - num_changed_func_filtered_out();}
8425 
8426 /// Getter for the number of variables removed.
8427 ///
8428 /// @return the number of variables removed.
8429 size_t
num_vars_removed() const8430 corpus_diff::diff_stats::num_vars_removed() const
8431 {return priv_->num_vars_removed;}
8432 
8433 /// Setter for the number of variables removed.
8434 ///
8435 /// @param n the new number of variables removed.
8436 void
num_vars_removed(size_t n)8437 corpus_diff::diff_stats::num_vars_removed(size_t n)
8438 {priv_->num_vars_removed = n;}
8439 
8440 /// Getter for the number removed variables that have been filtered
8441 /// out.
8442 ///
8443 /// @return the number removed variables that have been filtered out.
8444 size_t
num_removed_vars_filtered_out() const8445 corpus_diff::diff_stats::num_removed_vars_filtered_out() const
8446 {
8447   if (priv_->ctxt() && !priv_->ctxt()->show_deleted_vars())
8448     return num_vars_removed();
8449   return priv_->num_removed_vars_filtered_out;
8450 }
8451 
8452 /// Setter for the number of removed variables that have been filtered
8453 /// out.
8454 ///
8455 /// @param n the new value.
8456 void
num_removed_vars_filtered_out(size_t n) const8457 corpus_diff::diff_stats::num_removed_vars_filtered_out(size_t n) const
8458 {priv_->num_removed_vars_filtered_out = n;}
8459 
8460 /// Getter for the net number of removed variables.
8461 ///
8462 /// The net number of removed variables is the difference between the
8463 /// number of removed variables and the number of removed variables
8464 /// that have been filtered out.
8465 ///
8466 /// @return the net number of removed variables.
8467 size_t
net_num_vars_removed() const8468 corpus_diff::diff_stats::net_num_vars_removed() const
8469 {
8470   ABG_ASSERT(num_vars_removed() >= num_removed_vars_filtered_out());
8471   return num_vars_removed() - num_removed_vars_filtered_out();
8472 }
8473 
8474 /// Getter for the number of variables added.
8475 ///
8476 /// @return the number of variables added.
8477 size_t
num_vars_added() const8478 corpus_diff::diff_stats::num_vars_added() const
8479 {return priv_->num_vars_added;}
8480 
8481 /// Setter for the number of variables added.
8482 ///
8483 /// @param n the new number of variables added.
8484 void
num_vars_added(size_t n)8485 corpus_diff::diff_stats::num_vars_added(size_t n)
8486 {priv_->num_vars_added = n;}
8487 
8488 /// Getter for the number of added variables that have been filtered
8489 /// out.
8490 ///
8491 /// @return the number of added variables that have been filtered out.
8492 size_t
num_added_vars_filtered_out() const8493 corpus_diff::diff_stats::num_added_vars_filtered_out() const
8494 {
8495   if (priv_->ctxt() && !priv_->ctxt()->show_added_vars())
8496     return num_vars_added();
8497   return priv_->num_added_vars_filtered_out;
8498 }
8499 
8500 /// Setter for the number of added variables that have been filtered
8501 /// out.
8502 ///
8503 /// @param n the new value.
8504 void
num_added_vars_filtered_out(size_t n)8505 corpus_diff::diff_stats::num_added_vars_filtered_out(size_t n)
8506 {priv_->num_added_vars_filtered_out = n;}
8507 
8508 /// Getter for the net number of added variables.
8509 ///
8510 /// The net number of added variables is the difference between the
8511 /// number of added variables and the number of added variables that
8512 /// have been filetered out.
8513 ///
8514 /// @return the net number of added variables.
8515 size_t
net_num_vars_added() const8516 corpus_diff::diff_stats::net_num_vars_added() const
8517 {
8518   ABG_ASSERT(num_vars_added() >= num_added_vars_filtered_out());
8519   return num_vars_added() - num_added_vars_filtered_out();
8520 }
8521 
8522 /// Getter for the number of variables that have a change in one of
8523 /// their sub-types.
8524 ///
8525 /// @return the number of variables that have a change in one of their
8526 /// sub-types.
8527 size_t
num_vars_changed() const8528 corpus_diff::diff_stats::num_vars_changed() const
8529 {return priv_->num_vars_changed;}
8530 
8531 /// Setter for the number of variables that have a change in one of
8532 /// their sub-types.
8533 ///
8534 /// @param n the new number of variables that have a change in one of
8535 /// their sub-types.
8536 void
num_vars_changed(size_t n)8537 corpus_diff::diff_stats::num_vars_changed(size_t n)
8538 {priv_->num_vars_changed = n;}
8539 
8540 /// Getter for the number of variables that have a change in one of
8541 /// their sub-types, and that have been filtered out.
8542 ///
8543 /// @return the number of functions that have a change in one of their
8544 /// sub-types, and that have been filtered out.
8545 size_t
num_changed_vars_filtered_out() const8546 corpus_diff::diff_stats::num_changed_vars_filtered_out() const
8547 {return priv_->num_changed_vars_filtered_out;}
8548 
8549 /// Setter for the number of variables that have a change in one of
8550 /// their sub-types, and that have been filtered out.
8551 ///
8552 /// @param n the new number of variables that have a change in one of their
8553 /// sub-types, and that have been filtered out.
8554 void
num_changed_vars_filtered_out(size_t n)8555 corpus_diff::diff_stats::num_changed_vars_filtered_out(size_t n)
8556 {priv_->num_changed_vars_filtered_out = n;}
8557 
8558 /// Getter for the number of variables that have a change in their
8559 /// sub-types, minus the number of these variables that got filtered
8560 /// out from the diff.
8561 ///
8562 /// @return for the the number of variables that have a change in
8563 /// their sub-types, minus the number of these variables that got
8564 /// filtered out from the diff.
8565 size_t
net_num_vars_changed() const8566 corpus_diff::diff_stats::net_num_vars_changed() const
8567 {return num_vars_changed() - num_changed_vars_filtered_out();}
8568 
8569 /// Getter for the number of function symbols (not referenced by any
8570 /// debug info) that got removed.
8571 ///
8572 /// @return the number of function symbols (not referenced by any
8573 /// debug info) that got removed.
8574 size_t
num_func_syms_removed() const8575 corpus_diff::diff_stats::num_func_syms_removed() const
8576 {return priv_->num_func_syms_removed;}
8577 
8578 /// Setter for the number of function symbols (not referenced by any
8579 /// debug info) that got removed.
8580 ///
8581 /// @param n the number of function symbols (not referenced by any
8582 /// debug info) that got removed.
8583 void
num_func_syms_removed(size_t n)8584 corpus_diff::diff_stats::num_func_syms_removed(size_t n)
8585 {priv_->num_func_syms_removed = n;}
8586 
8587 /// Getter for the number of removed function symbols, not referenced
8588 /// by debug info, that have been filtered out.
8589 ///
8590 /// @return the number of removed function symbols, not referenced by
8591 /// debug info, that have been filtered out.
8592 size_t
num_removed_func_syms_filtered_out() const8593 corpus_diff::diff_stats::num_removed_func_syms_filtered_out() const
8594 {
8595   if (priv_->ctxt()
8596       && !priv_->ctxt()->show_symbols_unreferenced_by_debug_info())
8597     return num_func_syms_removed();
8598   return priv_->num_removed_func_syms_filtered_out;
8599 }
8600 
8601 /// Setter for the number of removed function symbols, not referenced
8602 /// by debug info, that have been filtered out.
8603 ///
8604 /// @param n the new the number of removed function symbols, not
8605 /// referenced by debug info, that have been filtered out.
8606 void
num_removed_func_syms_filtered_out(size_t n)8607 corpus_diff::diff_stats::num_removed_func_syms_filtered_out(size_t n)
8608 {priv_->num_removed_func_syms_filtered_out = n;}
8609 
8610 /// Getter of the net number of removed function symbols that are not
8611 /// referenced by any debug info.
8612 ///
8613 /// This is the difference between the total number of removed
8614 /// function symbols and the number of removed function symbols that
8615 /// have been filteted out.  Both numbers are for symbols not
8616 /// referenced by debug info.
8617 ///
8618 /// return the net number of removed function symbols that are not
8619 /// referenced by any debug info.
8620 size_t
net_num_removed_func_syms() const8621 corpus_diff::diff_stats::net_num_removed_func_syms() const
8622 {
8623   ABG_ASSERT(num_func_syms_removed() >= num_removed_func_syms_filtered_out());
8624   return num_func_syms_removed() - num_removed_func_syms_filtered_out();
8625 }
8626 
8627 /// Getter for the number of function symbols (not referenced by any
8628 /// debug info) that got added.
8629 ///
8630 /// @return the number of function symbols (not referenced by any
8631 /// debug info) that got added.
8632 size_t
num_func_syms_added() const8633 corpus_diff::diff_stats::num_func_syms_added() const
8634 {return priv_->num_func_syms_added;}
8635 
8636 /// Setter for the number of function symbols (not referenced by any
8637 /// debug info) that got added.
8638 ///
8639 /// @param n the new number of function symbols (not referenced by any
8640 /// debug info) that got added.
8641 void
num_func_syms_added(size_t n)8642 corpus_diff::diff_stats::num_func_syms_added(size_t n)
8643 {priv_->num_func_syms_added = n;}
8644 
8645 /// Getter for the number of added function symbols, not referenced by
8646 /// any debug info, that have been filtered out.
8647 ///
8648 /// @return the number of added function symbols, not referenced by
8649 /// any debug info, that have been filtered out.
8650 size_t
num_added_func_syms_filtered_out() const8651 corpus_diff::diff_stats::num_added_func_syms_filtered_out() const
8652 {
8653   if (priv_->ctxt()
8654       && !(priv_->ctxt()->show_added_symbols_unreferenced_by_debug_info()
8655 	   && priv_->ctxt()->show_symbols_unreferenced_by_debug_info()))
8656     return num_func_syms_added();
8657   return priv_->num_added_func_syms_filtered_out;
8658 }
8659 
8660 /// Setter for the number of added function symbols, not referenced by
8661 /// any debug info, that have been filtered out.
8662 ///
8663 /// @param n the new number of added function symbols, not referenced
8664 /// by any debug info, that have been filtered out.
8665 void
num_added_func_syms_filtered_out(size_t n)8666 corpus_diff::diff_stats::num_added_func_syms_filtered_out(size_t n)
8667 {priv_->num_added_func_syms_filtered_out = n;}
8668 
8669 /// Getter of the net number of added function symbols that are not
8670 /// referenced by any debug info.
8671 ///
8672 /// This is the difference between the total number of added
8673 /// function symbols and the number of added function symbols that
8674 /// have been filteted out.  Both numbers are for symbols not
8675 /// referenced by debug info.
8676 ///
8677 /// return the net number of added function symbols that are not
8678 /// referenced by any debug info.
8679 size_t
net_num_added_func_syms() const8680 corpus_diff::diff_stats::net_num_added_func_syms() const
8681 {
8682   ABG_ASSERT(num_func_syms_added() >= num_added_func_syms_filtered_out());
8683   return num_func_syms_added()- num_added_func_syms_filtered_out();
8684 }
8685 
8686 /// Getter for the number of variable symbols (not referenced by any
8687 /// debug info) that got removed.
8688 ///
8689 /// @return the number of variable symbols (not referenced by any
8690 /// debug info) that got removed.
8691 size_t
num_var_syms_removed() const8692 corpus_diff::diff_stats::num_var_syms_removed() const
8693 {return priv_->num_var_syms_removed;}
8694 
8695 /// Setter for the number of variable symbols (not referenced by any
8696 /// debug info) that got removed.
8697 ///
8698 /// @param n the number of variable symbols (not referenced by any
8699 /// debug info) that got removed.
8700 void
num_var_syms_removed(size_t n)8701 corpus_diff::diff_stats::num_var_syms_removed(size_t n)
8702 {priv_->num_var_syms_removed = n;}
8703 
8704 /// Getter for the number of removed variable symbols, not referenced
8705 /// by any debug info, that have been filtered out.
8706 ///
8707 /// @return the number of removed variable symbols, not referenced
8708 /// by any debug info, that have been filtered out.
8709 size_t
num_removed_var_syms_filtered_out() const8710 corpus_diff::diff_stats::num_removed_var_syms_filtered_out() const
8711 {
8712   if (priv_->ctxt()
8713       && !priv_->ctxt()->show_symbols_unreferenced_by_debug_info())
8714     return num_var_syms_removed();
8715   return priv_->num_removed_var_syms_filtered_out;
8716 }
8717 
8718 /// Setter for the number of removed variable symbols, not referenced
8719 /// by any debug info, that have been filtered out.
8720 ///
8721 /// @param n the number of removed variable symbols, not referenced by
8722 /// any debug info, that have been filtered out.
8723 void
num_removed_var_syms_filtered_out(size_t n)8724 corpus_diff::diff_stats::num_removed_var_syms_filtered_out(size_t n)
8725 {priv_->num_removed_var_syms_filtered_out = n;}
8726 
8727 /// Getter of the net number of removed variable symbols that are not
8728 /// referenced by any debug info.
8729 ///
8730 /// This is the difference between the total number of removed
8731 /// variable symbols and the number of removed variable symbols that
8732 /// have been filteted out.  Both numbers are for symbols not
8733 /// referenced by debug info.
8734 ///
8735 /// return the net number of removed variable symbols that are not
8736 /// referenced by any debug info.
8737 size_t
net_num_removed_var_syms() const8738 corpus_diff::diff_stats::net_num_removed_var_syms() const
8739 {
8740   ABG_ASSERT(num_var_syms_removed() >= num_removed_var_syms_filtered_out());
8741   return num_var_syms_removed() - num_removed_var_syms_filtered_out();
8742 }
8743 
8744 /// Getter for the number of variable symbols (not referenced by any
8745 /// debug info) that got added.
8746 ///
8747 /// @return the number of variable symbols (not referenced by any
8748 /// debug info) that got added.
8749 size_t
num_var_syms_added() const8750 corpus_diff::diff_stats::num_var_syms_added() const
8751 {return priv_->num_var_syms_added;}
8752 
8753 /// Setter for the number of variable symbols (not referenced by any
8754 /// debug info) that got added.
8755 ///
8756 /// @param n the new number of variable symbols (not referenced by any
8757 /// debug info) that got added.
8758 void
num_var_syms_added(size_t n)8759 corpus_diff::diff_stats::num_var_syms_added(size_t n)
8760 {priv_->num_var_syms_added = n;}
8761 
8762 /// Getter for the number of added variable symbols, not referenced by
8763 /// any debug info, that have been filtered out.
8764 ///
8765 /// @return the number of added variable symbols, not referenced by
8766 /// any debug info, that have been filtered out.
8767 size_t
num_added_var_syms_filtered_out() const8768 corpus_diff::diff_stats::num_added_var_syms_filtered_out() const
8769 {
8770   if (priv_->ctxt()
8771       && !(priv_->ctxt()->show_added_symbols_unreferenced_by_debug_info()
8772 	   && priv_->ctxt()->show_symbols_unreferenced_by_debug_info()))
8773     return num_var_syms_added();
8774   return priv_->num_added_var_syms_filtered_out;
8775 }
8776 
8777 /// Setter for the number of added variable symbols, not referenced by
8778 /// any debug info, that have been filtered out.
8779 ///
8780 /// @param n the new number of added variable symbols, not referenced
8781 /// by any debug info, that have been filtered out.
8782 void
num_added_var_syms_filtered_out(size_t n)8783 corpus_diff::diff_stats::num_added_var_syms_filtered_out(size_t n)
8784 {priv_->num_added_var_syms_filtered_out = n;}
8785 
8786 /// Getter of the net number of added variable symbols that are not
8787 /// referenced by any debug info.
8788 ///
8789 /// This is the difference between the total number of added
8790 /// variable symbols and the number of added variable symbols that
8791 /// have been filteted out.  Both numbers are for symbols not
8792 /// referenced by debug info.
8793 ///
8794 /// return the net number of added variable symbols that are not
8795 /// referenced by any debug info.
8796 size_t
net_num_added_var_syms() const8797 corpus_diff::diff_stats::net_num_added_var_syms() const
8798 {
8799   ABG_ASSERT(num_var_syms_added() >= num_added_var_syms_filtered_out());
8800   return num_var_syms_added() - num_added_var_syms_filtered_out();
8801 }
8802 
8803 /// Getter of the number of leaf type change diff nodes.
8804 ///
8805 /// @return the number of leaf type change diff nodes.
8806 size_t
num_leaf_changes() const8807 corpus_diff::diff_stats::num_leaf_changes() const
8808 {return priv_->num_leaf_changes;}
8809 
8810 /// Setter of the number of leaf type change diff nodes.
8811 ///
8812 /// @param n the new number of leaf type change diff nodes.
8813 void
num_leaf_changes(size_t n)8814 corpus_diff::diff_stats::num_leaf_changes(size_t n)
8815 {priv_->num_leaf_changes = n;}
8816 
8817 /// Getter of the number of leaf type change diff nodes that have been
8818 /// filtered out.
8819 ///
8820 /// @return the number of leaf type change diff nodes that have been
8821 size_t
num_leaf_changes_filtered_out() const8822 corpus_diff::diff_stats::num_leaf_changes_filtered_out() const
8823 {return priv_->num_leaf_changes_filtered_out;}
8824 
8825 /// Setter of the number of leaf type change diff nodes that have been
8826 /// filtered out.
8827 ///
8828 /// @param n the new number of leaf type change diff nodes that have
8829 /// been filtered out.
8830 void
num_leaf_changes_filtered_out(size_t n)8831 corpus_diff::diff_stats::num_leaf_changes_filtered_out(size_t n)
8832 {priv_->num_leaf_changes_filtered_out = n;}
8833 
8834 /// Getter of the net number of leaf change diff nodes.
8835 ///
8836 /// This is the difference between the total number of leaf change
8837 /// diff nodes, and the number of the leaf change diff nodes that have
8838 /// been filtered out.
8839 ///
8840 /// A leaf change is either a type change, a function change or a
8841 /// variable change.
8842 size_t
net_num_leaf_changes() const8843 corpus_diff::diff_stats::net_num_leaf_changes() const
8844 {
8845   ABG_ASSERT(num_leaf_changes() >= num_leaf_changes_filtered_out());
8846   return num_leaf_changes() - num_leaf_changes_filtered_out();
8847 }
8848 
8849 /// Getter for the number of leaf type change diff nodes.
8850 ///
8851 /// @return the number of leaf type changes diff nodes.
8852 size_t
num_leaf_type_changes() const8853 corpus_diff::diff_stats::num_leaf_type_changes() const
8854 {return priv_->num_leaf_type_changes;}
8855 
8856 /// Setter for the number of leaf type change diff nodes.
8857 ///
8858 /// @param n the new number of leaf type change diff nodes.
8859 void
num_leaf_type_changes(size_t n)8860 corpus_diff::diff_stats::num_leaf_type_changes(size_t n)
8861 {priv_->num_leaf_type_changes = n;}
8862 
8863 /// Getter for the number of filtered out leaf type change diff nodes.
8864 ///
8865 /// @return the number of filtered out leaf type change diff nodes.
8866 size_t
num_leaf_type_changes_filtered_out() const8867 corpus_diff::diff_stats::num_leaf_type_changes_filtered_out() const
8868 {return priv_->num_leaf_type_changes_filtered_out;}
8869 
8870 /// Setter for the number of filtered out leaf type change diff nodes.
8871 /// @param n the new number of filtered out leaf type change diff nodes.
8872 void
num_leaf_type_changes_filtered_out(size_t n)8873 corpus_diff::diff_stats::num_leaf_type_changes_filtered_out(size_t n)
8874 {priv_->num_leaf_type_changes_filtered_out = n;}
8875 
8876 /// Getter for the net number of leaf type change diff nodes.
8877 ///
8878 /// This is the difference between the number of leaf type changes and
8879 /// the number of filtered out leaf type changes.
8880 ///
8881 /// @return the net number of leaf type change diff nodes.
8882 size_t
net_num_leaf_type_changes() const8883 corpus_diff::diff_stats::net_num_leaf_type_changes() const
8884 {return num_leaf_type_changes() - num_leaf_type_changes_filtered_out();}
8885 
8886 /// Getter for the number of leaf function change diff nodes.
8887 ///
8888 /// @return the number of leaf function change diff nodes.
8889 size_t
num_leaf_func_changes() const8890 corpus_diff::diff_stats::num_leaf_func_changes() const
8891 {return priv_->num_leaf_func_changes;}
8892 
8893 /// Setter for the number of leaf function change diff nodes.
8894 ///
8895 /// @param n the new number of leaf function change diff nodes.
8896 void
num_leaf_func_changes(size_t n)8897 corpus_diff::diff_stats::num_leaf_func_changes(size_t n)
8898 {priv_->num_leaf_func_changes = n;}
8899 
8900 /// Getter for the number of leaf function change diff nodes that were
8901 /// filtered out.
8902 ///
8903 /// @return the number of leaf function change diff nodes that were
8904 /// filtered out.
8905 size_t
num_leaf_func_changes_filtered_out() const8906 corpus_diff::diff_stats::num_leaf_func_changes_filtered_out() const
8907 {return priv_->num_leaf_func_changes_filtered_out;}
8908 
8909 /// Setter for the number of leaf function change diff nodes that were
8910 /// filtered out.
8911 ///
8912 /// @param n the new number of leaf function change diff nodes that
8913 /// were filtered out.
8914 void
num_leaf_func_changes_filtered_out(size_t n)8915 corpus_diff::diff_stats::num_leaf_func_changes_filtered_out(size_t n)
8916 {priv_->num_leaf_func_changes_filtered_out = n;}
8917 
8918 /// Getter for the net number of leaf function change diff nodes.
8919 ///
8920 /// This is the difference between the number of leaf function change
8921 /// diff nodes and the number of filtered out leaf function change
8922 /// diff nodes.
8923 ///
8924 /// @return the net number of leaf function change diff nodes.
8925 size_t
net_num_leaf_func_changes() const8926 corpus_diff::diff_stats::net_num_leaf_func_changes() const
8927 {return num_leaf_func_changes() - num_leaf_func_changes_filtered_out();}
8928 
8929 /// Getter for the number of leaf variable change diff nodes.
8930 ///
8931 /// @return the number of leaf variable change diff nodes.
8932 size_t
num_leaf_var_changes() const8933 corpus_diff::diff_stats::num_leaf_var_changes() const
8934 {return priv_->num_leaf_var_changes;}
8935 
8936 /// Setter for the number of leaf variable change diff nodes.
8937 ///
8938 /// @param n the number of leaf variable change diff nodes.
8939 void
num_leaf_var_changes(size_t n)8940 corpus_diff::diff_stats::num_leaf_var_changes(size_t n)
8941 {priv_->num_leaf_var_changes = n;}
8942 
8943 /// Getter of the number of added types that are unreachable from the
8944 /// public interface of the ABI corpus.
8945 ///
8946 /// Public interface means the set of defined and publicly exported
8947 /// functions and variables of the ABI corpus.
8948 ///
8949 /// @return the number of added types that are unreachable from the
8950 /// public interface of the ABI corpus.
8951 size_t
num_added_unreachable_types() const8952 corpus_diff::diff_stats::num_added_unreachable_types() const
8953 {return priv_->num_added_unreachable_types;}
8954 
8955 /// Setter of the number of added types that are unreachable from the
8956 /// public interface (global functions or variables) of the ABI
8957 /// corpus.
8958 ///
8959 /// Public interface means the set of defined and publicly exported
8960 /// functions and variables of the ABI corpus.
8961 ///
8962 /// @param n the new number of added types that are unreachable from
8963 /// the public interface of the ABI corpus.
8964 void
num_added_unreachable_types(size_t n)8965 corpus_diff::diff_stats::num_added_unreachable_types(size_t n)
8966 {priv_->num_added_unreachable_types = n;}
8967 
8968 /// Getter of the number of added types that are unreachable from
8969 /// public interfaces and that are filtered out by suppression
8970 /// specifications.
8971 ///
8972 /// @return the number of added types that are unreachable from public
8973 /// interfaces and that are filtered out by suppression
8974 /// specifications.
8975 size_t
num_added_unreachable_types_filtered_out() const8976 corpus_diff::diff_stats::num_added_unreachable_types_filtered_out() const
8977 {return priv_->num_added_unreachable_types_filtered_out;}
8978 
8979 /// Setter of the number of added types that are unreachable from
8980 /// public interfaces and that are filtered out by suppression
8981 /// specifications.
8982 ///
8983 /// @param n the new number of added types that are unreachable from
8984 /// public interfaces and that are filtered out by suppression
8985 /// specifications.
8986 void
num_added_unreachable_types_filtered_out(size_t n)8987 corpus_diff::diff_stats::num_added_unreachable_types_filtered_out(size_t n)
8988 {priv_->num_added_unreachable_types_filtered_out = n;}
8989 
8990 /// Getter of the number of added types that are unreachable from
8991 /// public interfaces and that are *NOT* filtered out by suppression
8992 /// specifications.
8993 ///
8994 /// @return the number of added types that are unreachable from public
8995 /// interfaces and that are *NOT* filtered out by suppression
8996 /// specifications.
8997 size_t
net_num_added_unreachable_types() const8998 corpus_diff::diff_stats::net_num_added_unreachable_types() const
8999 {
9000   ABG_ASSERT(num_added_unreachable_types()
9001 	     >=
9002 	     num_added_unreachable_types_filtered_out());
9003 
9004   return (num_added_unreachable_types()
9005 	  -
9006 	  num_added_unreachable_types_filtered_out());
9007 }
9008 
9009 /// Getter of the number of removed types that are unreachable from
9010 /// the public interface of the ABI corpus.
9011 ///
9012 /// Public interface means the set of defined and publicly exported
9013 /// functions and variables of the ABI corpus.
9014 ///
9015 /// @return the number of removed types that are unreachable from
9016 /// the public interface of the ABI corpus.
9017 size_t
num_removed_unreachable_types() const9018 corpus_diff::diff_stats::num_removed_unreachable_types() const
9019 {return priv_->num_removed_unreachable_types;}
9020 
9021 /// Setter of the number of removed types that are unreachable from
9022 /// the public interface of the ABI corpus.
9023 ///
9024 /// Public interface means the set of defined and publicly exported
9025 /// functions and variables of the ABI corpus.
9026 ///
9027 ///@param n the new number of removed types that are unreachable from
9028 /// the public interface of the ABI corpus.
9029 void
num_removed_unreachable_types(size_t n)9030 corpus_diff::diff_stats::num_removed_unreachable_types(size_t n)
9031 {priv_->num_removed_unreachable_types = n;}
9032 
9033 /// Getter of the number of removed types that are not reachable from
9034 /// public interfaces and that have been filtered out by suppression
9035 /// specifications.
9036 ///
9037 /// @return the number of removed types that are not reachable from
9038 /// public interfaces and that have been filtered out by suppression
9039 /// specifications.
9040 size_t
num_removed_unreachable_types_filtered_out() const9041 corpus_diff::diff_stats::num_removed_unreachable_types_filtered_out() const
9042 {return priv_->num_removed_unreachable_types_filtered_out;}
9043 
9044 /// Setter of the number of removed types that are not reachable from
9045 /// public interfaces and that have been filtered out by suppression
9046 /// specifications.
9047 ///
9048 /// @param n the new number of removed types that are not reachable
9049 /// from public interfaces and that have been filtered out by
9050 /// suppression specifications.
9051 void
num_removed_unreachable_types_filtered_out(size_t n)9052 corpus_diff::diff_stats::num_removed_unreachable_types_filtered_out(size_t n)
9053 {priv_->num_removed_unreachable_types_filtered_out = n;}
9054 
9055 /// Getter of the number of removed types that are not reachable from
9056 /// public interfaces and that have *NOT* been filtered out by
9057 /// suppression specifications.
9058 ///
9059 /// @return the number of removed types that are not reachable from
9060 /// public interfaces and that have *NOT* been filtered out by
9061 /// suppression specifications.
9062 size_t
net_num_removed_unreachable_types() const9063 corpus_diff::diff_stats::net_num_removed_unreachable_types() const
9064 {
9065   ABG_ASSERT(num_removed_unreachable_types()
9066 	     >=
9067 	     num_removed_unreachable_types_filtered_out());
9068 
9069   return (num_removed_unreachable_types()
9070 	  -
9071 	  num_removed_unreachable_types_filtered_out());
9072 }
9073 
9074 /// Getter of the number of changed types that are unreachable from
9075 /// the public interface of the ABI corpus.
9076 ///
9077 /// Public interface means the set of defined and publicly exported
9078 /// functions and variables of the ABI corpus.
9079 ///
9080 /// @return the number of changed types that are unreachable from the
9081 /// public interface of the ABI corpus.
9082 size_t
num_changed_unreachable_types() const9083 corpus_diff::diff_stats::num_changed_unreachable_types() const
9084 {return priv_->num_changed_unreachable_types;}
9085 
9086 /// Setter of the number of changed types that are unreachable from
9087 /// the public interface of the ABI corpus.
9088 ///
9089 /// Public interface means the set of defined and publicly exported
9090 /// functions and variables of the ABI corpus.
9091 ///
9092 ///@param n the new number of changed types that are unreachable from
9093 /// the public interface of the ABI corpus.
9094 void
num_changed_unreachable_types(size_t n)9095 corpus_diff::diff_stats::num_changed_unreachable_types(size_t n)
9096 {priv_->num_changed_unreachable_types = n;}
9097 
9098 /// Getter of the number of changed types that are unreachable from
9099 /// public interfaces and that have been filtered out by suppression
9100 /// specifications.
9101 ///
9102 /// @return the number of changed types that are unreachable from
9103 /// public interfaces and that have been filtered out by suppression
9104 /// specifications.
9105 size_t
num_changed_unreachable_types_filtered_out() const9106 corpus_diff::diff_stats::num_changed_unreachable_types_filtered_out() const
9107 {return priv_->num_changed_unreachable_types_filtered_out;}
9108 
9109 /// Setter of the number of changed types that are unreachable from
9110 /// public interfaces and that have been filtered out by suppression
9111 /// specifications.
9112 ///
9113 /// @param n the new number of changed types that are unreachable from
9114 /// public interfaces and that have been filtered out by suppression
9115 /// specifications.
9116 void
num_changed_unreachable_types_filtered_out(size_t n)9117 corpus_diff::diff_stats::num_changed_unreachable_types_filtered_out(size_t n)
9118 {priv_->num_changed_unreachable_types_filtered_out = n;}
9119 
9120 /// Getter of the number of changed types that are unreachable from
9121 /// public interfaces and that have *NOT* been filtered out by
9122 /// suppression specifications.
9123 ///
9124 /// @return the number of changed types that are unreachable from
9125 /// public interfaces and that have *NOT* been filtered out by
9126 /// suppression specifications.
9127 size_t
net_num_changed_unreachable_types() const9128 corpus_diff::diff_stats::net_num_changed_unreachable_types() const
9129 {
9130   ABG_ASSERT(num_changed_unreachable_types()
9131 	     >=
9132 	     num_changed_unreachable_types_filtered_out());
9133 
9134   return (num_changed_unreachable_types()
9135 	  -
9136 	  num_changed_unreachable_types_filtered_out());
9137 }
9138 
9139 /// Getter for the number of leaf variable changes diff nodes that
9140 /// have been filtered out.
9141 ///
9142 /// @return the number of leaf variable changes diff nodes that have
9143 /// been filtered out.
9144 size_t
num_leaf_var_changes_filtered_out() const9145 corpus_diff::diff_stats::num_leaf_var_changes_filtered_out() const
9146 {return priv_->num_leaf_var_changes_filtered_out;}
9147 
9148 /// Setter for the number of leaf variable changes diff nodes that
9149 /// have been filtered out.
9150 ///
9151 /// @param n the number of leaf variable changes diff nodes that have
9152 /// been filtered out.
9153 void
num_leaf_var_changes_filtered_out(size_t n)9154 corpus_diff::diff_stats::num_leaf_var_changes_filtered_out(size_t n)
9155 {priv_->num_leaf_var_changes_filtered_out = n;}
9156 
9157 /// Getter for the net number of leaf variable change diff nodes.
9158 ///
9159 /// This the difference between the number of leaf variable change
9160 /// diff nodes and the number of filtered out leaf variable change
9161 /// diff nodes.
9162 ///
9163 /// @return the net number of leaf variable change diff nodes.
9164 size_t
net_num_leaf_var_changes() const9165 corpus_diff::diff_stats::net_num_leaf_var_changes() const
9166 {return num_leaf_var_changes() - num_leaf_var_changes_filtered_out();}
9167 
9168 
9169 // <corpus_diff stuff>
9170 
9171 /// Getter of the context associated with this corpus.
9172 ///
9173 /// @return a smart pointer to the context associate with the corpus.
9174 diff_context_sptr
get_context()9175 corpus_diff::priv::get_context()
9176 {return ctxt_.lock();}
9177 
9178 /// Tests if the lookup tables are empty.
9179 ///
9180 /// @return true if the lookup tables are empty, false otherwise.
9181 bool
lookup_tables_empty() const9182 corpus_diff::priv::lookup_tables_empty() const
9183 {
9184   return (deleted_fns_.empty()
9185 	  && added_fns_.empty()
9186 	  && changed_fns_map_.empty()
9187 	  && deleted_vars_.empty()
9188 	  && added_vars_.empty()
9189 	  && changed_vars_map_.empty());
9190 }
9191 
9192 /// Clear the lookup tables useful for reporting an enum_diff.
9193 void
clear_lookup_tables()9194 corpus_diff::priv::clear_lookup_tables()
9195 {
9196   deleted_fns_.clear();
9197   added_fns_.clear();
9198   changed_fns_map_.clear();
9199   deleted_vars_.clear();
9200   added_vars_.clear();
9201   changed_vars_map_.clear();
9202 }
9203 
9204 /// If the lookup tables are not yet built, walk the differences and
9205 /// fill the lookup tables.
9206 void
ensure_lookup_tables_populated()9207 corpus_diff::priv::ensure_lookup_tables_populated()
9208 {
9209   if (!lookup_tables_empty())
9210     return;
9211 
9212   diff_context_sptr ctxt = get_context();
9213 
9214   {
9215     edit_script& e = fns_edit_script_;
9216 
9217     for (vector<deletion>::const_iterator it = e.deletions().begin();
9218 	 it != e.deletions().end();
9219 	 ++it)
9220       {
9221 	unsigned i = it->index();
9222 	ABG_ASSERT(i < first_->get_functions().size());
9223 
9224 	function_decl* deleted_fn = first_->get_functions()[i];
9225 	string n = get_function_id_or_pretty_representation(deleted_fn);
9226 	ABG_ASSERT(!n.empty());
9227 	// The below is commented out because there can be several
9228 	// functions with the same ID in the corpus.  So several
9229 	// functions with the same ID can be deleted.
9230 	// ABG_ASSERT(deleted_fns_.find(n) == deleted_fns_.end());
9231 	deleted_fns_[n] = deleted_fn;
9232       }
9233 
9234     for (vector<insertion>::const_iterator it = e.insertions().begin();
9235 	 it != e.insertions().end();
9236 	 ++it)
9237       {
9238 	for (vector<unsigned>::const_iterator iit =
9239 	       it->inserted_indexes().begin();
9240 	     iit != it->inserted_indexes().end();
9241 	     ++iit)
9242 	  {
9243 	    unsigned i = *iit;
9244 	    function_decl* added_fn = second_->get_functions()[i];
9245 	    string n = get_function_id_or_pretty_representation(added_fn);
9246 	    ABG_ASSERT(!n.empty());
9247 	    // The below is commented out because there can be several
9248 	    // functions with the same ID in the corpus.  So several
9249 	    // functions with the same ID can be added.
9250 	    // ABG_ASSERT(added_fns_.find(n) == added_fns_.end());
9251 	    string_function_ptr_map::const_iterator j =
9252 	      deleted_fns_.find(n);
9253 	    if (j != deleted_fns_.end())
9254 	      {
9255 		function_decl_sptr f(j->second, noop_deleter());
9256 		function_decl_sptr s(added_fn, noop_deleter());
9257 		function_decl_diff_sptr d = compute_diff(f, s, ctxt);
9258 		if (*j->second != *added_fn)
9259 		  changed_fns_map_[j->first] = d;
9260 		deleted_fns_.erase(j);
9261 	      }
9262 	    else
9263 	      added_fns_[n] = added_fn;
9264 	  }
9265       }
9266     sort_string_function_decl_diff_sptr_map(changed_fns_map_, changed_fns_);
9267 
9268     // Now walk the allegedly deleted functions; check if their
9269     // underlying symbols are deleted as well; otherwise, consider
9270     // that the function in question hasn't been deleted.
9271 
9272     vector<string> to_delete;
9273     for (string_function_ptr_map::const_iterator i = deleted_fns_.begin();
9274 	 i != deleted_fns_.end();
9275 	 ++i)
9276       if (second_->lookup_function_symbol(*i->second->get_symbol()))
9277 	to_delete.push_back(i->first);
9278 
9279     for (vector<string>::const_iterator i = to_delete.begin();
9280 	 i != to_delete.end();
9281 	 ++i)
9282       deleted_fns_.erase(*i);
9283 
9284     // Do something similar for added functions.
9285 
9286     to_delete.clear();
9287     for (string_function_ptr_map::const_iterator i = added_fns_.begin();
9288 	 i != added_fns_.end();
9289 	 ++i)
9290       {
9291 	if (first_->lookup_function_symbol(*i->second->get_symbol()))
9292 	  to_delete.push_back(i->first);
9293 	else if (! i->second->get_symbol()->get_version().is_empty()
9294 		 && i->second->get_symbol()->get_version().is_default())
9295 	  // We are looking for a symbol that has a default version,
9296 	  // and which seems to be newly added.  Let's see if the same
9297 	  // symbol with *no* version was already present in the
9298 	  // former corpus.  If yes, then the symbol shouldn't be
9299 	  // considered as 'added'.
9300 	  {
9301 	    elf_symbol::version empty_version;
9302 	    if (first_->lookup_function_symbol(i->second->get_symbol()->get_name(),
9303 					       empty_version))
9304 	      to_delete.push_back(i->first);
9305 	  }
9306       }
9307 
9308     for (vector<string>::const_iterator i = to_delete.begin();
9309 	 i != to_delete.end();
9310 	 ++i)
9311       added_fns_.erase(*i);
9312   }
9313 
9314   {
9315     edit_script& e = vars_edit_script_;
9316 
9317     for (vector<deletion>::const_iterator it = e.deletions().begin();
9318 	 it != e.deletions().end();
9319 	 ++it)
9320       {
9321 	unsigned i = it->index();
9322 	ABG_ASSERT(i < first_->get_variables().size());
9323 
9324 	var_decl* deleted_var = first_->get_variables()[i];
9325 	string n = deleted_var->get_id();
9326 	ABG_ASSERT(!n.empty());
9327 	ABG_ASSERT(deleted_vars_.find(n) == deleted_vars_.end());
9328 	deleted_vars_[n] = deleted_var;
9329       }
9330 
9331     for (vector<insertion>::const_iterator it = e.insertions().begin();
9332 	 it != e.insertions().end();
9333 	 ++it)
9334       {
9335 	for (vector<unsigned>::const_iterator iit =
9336 	       it->inserted_indexes().begin();
9337 	     iit != it->inserted_indexes().end();
9338 	     ++iit)
9339 	  {
9340 	    unsigned i = *iit;
9341 	    var_decl* added_var = second_->get_variables()[i];
9342 	    string n = added_var->get_id();
9343 	    ABG_ASSERT(!n.empty());
9344 	    {
9345 	      string_var_ptr_map::const_iterator k = added_vars_.find(n);
9346 	      if ( k != added_vars_.end())
9347 		{
9348 		  ABG_ASSERT(is_member_decl(k->second)
9349 			 && get_member_is_static(k->second));
9350 		  continue;
9351 		}
9352 	    }
9353 	    string_var_ptr_map::const_iterator j =
9354 	      deleted_vars_.find(n);
9355 	    if (j != deleted_vars_.end())
9356 	      {
9357 		if (*j->second != *added_var)
9358 		  {
9359 		    var_decl_sptr f(j->second, noop_deleter());
9360 		    var_decl_sptr s(added_var, noop_deleter());
9361 		    changed_vars_map_[n] = compute_diff(f, s, ctxt);
9362 		  }
9363 		deleted_vars_.erase(j);
9364 	      }
9365 	    else
9366 	      added_vars_[n] = added_var;
9367 	  }
9368       }
9369     sort_string_var_diff_sptr_map(changed_vars_map_,
9370 				  sorted_changed_vars_);
9371 
9372     // Now walk the allegedly deleted variables; check if their
9373     // underlying symbols are deleted as well; otherwise consider
9374     // that the variable in question hasn't been deleted.
9375 
9376     vector<string> to_delete;
9377     for (string_var_ptr_map::const_iterator i = deleted_vars_.begin();
9378 	 i != deleted_vars_.end();
9379 	 ++i)
9380       if (second_->lookup_variable_symbol(*i->second->get_symbol()))
9381 	to_delete.push_back(i->first);
9382 
9383     for (vector<string>::const_iterator i = to_delete.begin();
9384 	 i != to_delete.end();
9385 	 ++i)
9386       deleted_vars_.erase(*i);
9387 
9388     // Do something similar for added variables.
9389 
9390     to_delete.clear();
9391     for (string_var_ptr_map::const_iterator i = added_vars_.begin();
9392 	 i != added_vars_.end();
9393 	 ++i)
9394       if (first_->lookup_variable_symbol(*i->second->get_symbol()))
9395 	to_delete.push_back(i->first);
9396       else if (! i->second->get_symbol()->get_version().is_empty()
9397 		 && i->second->get_symbol()->get_version().is_default())
9398 	// We are looking for a symbol that has a default version,
9399 	// and which seems to be newly added.  Let's see if the same
9400 	// symbol with *no* version was already present in the
9401 	// former corpus.  If yes, then the symbol shouldn't be
9402 	// considered as 'added'.
9403 	{
9404 	  elf_symbol::version empty_version;
9405 	  if (first_->lookup_variable_symbol(i->second->get_symbol()->get_name(),
9406 					     empty_version))
9407 	    to_delete.push_back(i->first);
9408 	}
9409 
9410     for (vector<string>::const_iterator i = to_delete.begin();
9411 	 i != to_delete.end();
9412 	 ++i)
9413       added_vars_.erase(*i);
9414   }
9415 
9416   // Massage the edit script for added/removed function symbols that
9417   // were not referenced by any debug info and turn them into maps of
9418   // {symbol_name, symbol}.
9419   {
9420     edit_script& e = unrefed_fn_syms_edit_script_;
9421     for (vector<deletion>::const_iterator it = e.deletions().begin();
9422 	 it != e.deletions().end();
9423 	 ++it)
9424       {
9425 	unsigned i = it->index();
9426 	ABG_ASSERT(i < first_->get_unreferenced_function_symbols().size());
9427 	elf_symbol_sptr deleted_sym =
9428 	  first_->get_unreferenced_function_symbols()[i];
9429 	if (!second_->lookup_function_symbol(*deleted_sym))
9430 	  deleted_unrefed_fn_syms_[deleted_sym->get_id_string()] = deleted_sym;
9431       }
9432 
9433     for (vector<insertion>::const_iterator it = e.insertions().begin();
9434 	 it != e.insertions().end();
9435 	 ++it)
9436       {
9437 	for (vector<unsigned>::const_iterator iit =
9438 	       it->inserted_indexes().begin();
9439 	     iit != it->inserted_indexes().end();
9440 	     ++iit)
9441 	  {
9442 	    unsigned i = *iit;
9443 	    ABG_ASSERT(i < second_->get_unreferenced_function_symbols().size());
9444 	    elf_symbol_sptr added_sym =
9445 	      second_->get_unreferenced_function_symbols()[i];
9446 	    if ((deleted_unrefed_fn_syms_.find(added_sym->get_id_string())
9447 		 == deleted_unrefed_fn_syms_.end()))
9448 	      {
9449 		if (!first_->lookup_function_symbol(*added_sym))
9450 		  {
9451 		    bool do_add = true;
9452 		    if (! added_sym->get_version().is_empty()
9453 			&& added_sym->get_version().is_default())
9454 		      {
9455 			// So added_seem has a default version.  If
9456 			// the former corpus had a symbol with the
9457 			// same name as added_sym but with *no*
9458 			// version, then added_sym shouldn't be
9459 			// considered as a newly added symbol.
9460 			elf_symbol::version empty_version;
9461 			if (first_->lookup_function_symbol(added_sym->get_name(),
9462 							   empty_version))
9463 			  do_add = false;
9464 		      }
9465 
9466 		    if (do_add)
9467 		      added_unrefed_fn_syms_[added_sym->get_id_string()] =
9468 			added_sym;
9469 		  }
9470 	      }
9471 	    else
9472 	      deleted_unrefed_fn_syms_.erase(added_sym->get_id_string());
9473 	  }
9474       }
9475   }
9476 
9477   // Massage the edit script for added/removed variable symbols that
9478   // were not referenced by any debug info and turn them into maps of
9479   // {symbol_name, symbol}.
9480   {
9481     edit_script& e = unrefed_var_syms_edit_script_;
9482     for (vector<deletion>::const_iterator it = e.deletions().begin();
9483 	 it != e.deletions().end();
9484 	 ++it)
9485       {
9486 	unsigned i = it->index();
9487 	ABG_ASSERT(i < first_->get_unreferenced_variable_symbols().size());
9488 	elf_symbol_sptr deleted_sym =
9489 	  first_->get_unreferenced_variable_symbols()[i];
9490 	if (!second_->lookup_variable_symbol(*deleted_sym))
9491 	  deleted_unrefed_var_syms_[deleted_sym->get_id_string()] = deleted_sym;
9492       }
9493 
9494     for (vector<insertion>::const_iterator it = e.insertions().begin();
9495 	 it != e.insertions().end();
9496 	 ++it)
9497       {
9498 	for (vector<unsigned>::const_iterator iit =
9499 	       it->inserted_indexes().begin();
9500 	     iit != it->inserted_indexes().end();
9501 	     ++iit)
9502 	  {
9503 	    unsigned i = *iit;
9504 	    ABG_ASSERT(i < second_->get_unreferenced_variable_symbols().size());
9505 	    elf_symbol_sptr added_sym =
9506 	      second_->get_unreferenced_variable_symbols()[i];
9507 	    if (deleted_unrefed_var_syms_.find(added_sym->get_id_string())
9508 		== deleted_unrefed_var_syms_.end())
9509 	      {
9510 		if (!first_->lookup_variable_symbol(*added_sym))
9511 		  {
9512 		    bool do_add = true;
9513 		    if (! added_sym->get_version().is_empty()
9514 			&& added_sym->get_version().is_default())
9515 		      {
9516 			// So added_seem has a default version.  If
9517 			// the former corpus had a symbol with the
9518 			// same name as added_sym but with *no*
9519 			// version, then added_sym shouldn't be
9520 			// considered as a newly added symbol.
9521 			elf_symbol::version empty_version;
9522 			if (first_->lookup_variable_symbol(added_sym->get_name(),
9523 							   empty_version))
9524 			  do_add = false;
9525 		      }
9526 
9527 		    if (do_add)
9528 		      added_unrefed_var_syms_[added_sym->get_id_string()] =
9529 			added_sym;
9530 		  }
9531 	      }
9532 	    else
9533 	      deleted_unrefed_var_syms_.erase(added_sym->get_id_string());
9534 	  }
9535       }
9536   }
9537 
9538   // Handle the unreachable_types_edit_script_
9539   {
9540     edit_script& e = unreachable_types_edit_script_;
9541 
9542     // Populate the map of deleted unreachable types from the
9543     // deletions of the edit script.
9544     for (vector<deletion>::const_iterator it = e.deletions().begin();
9545 	 it != e.deletions().end();
9546 	 ++it)
9547       {
9548 	unsigned i = it->index();
9549 	type_base_sptr t
9550 	  (first_->get_types_not_reachable_from_public_interfaces()[i]);
9551 
9552 	if (!is_user_defined_type(t))
9553 	  continue;
9554 
9555 	string repr =
9556 	  abigail::ir::get_pretty_representation(t, /*internal=*/false);
9557 	deleted_unreachable_types_[repr] = t;
9558       }
9559 
9560     // Populate the map of added and change unreachable types from the
9561     // insertions of the edit script.
9562     for (vector<insertion>::const_iterator it = e.insertions().begin();
9563 	 it != e.insertions().end();
9564 	 ++it)
9565       {
9566 	for (vector<unsigned>::const_iterator iit =
9567 	       it->inserted_indexes().begin();
9568 	     iit != it->inserted_indexes().end();
9569 	     ++iit)
9570 	  {
9571 	    unsigned i = *iit;
9572 	    type_base_sptr t
9573 	      (second_->get_types_not_reachable_from_public_interfaces()[i]);
9574 
9575 	    if (!is_user_defined_type(t))
9576 	      continue;
9577 
9578 	    string repr =
9579 	      abigail::ir::get_pretty_representation(t, /*internal=*/false);
9580 
9581 	    // Let's see if the inserted type we are looking at was
9582 	    // reported as deleted as well.
9583 	    //
9584 	    // If it's been deleted and a different version of it has
9585 	    // now been added, it means it's been *changed*.  In that
9586 	    // case we'll compute the diff of that change and store it
9587 	    // in the map of changed unreachable types.
9588 	    //
9589 	    // Otherwise, it means the type's been added so we'll add
9590 	    // it to the set of added unreachable types.
9591 
9592 	    string_type_base_sptr_map::const_iterator j =
9593 	      deleted_unreachable_types_.find(repr);
9594 	    if (j != deleted_unreachable_types_.end())
9595 	      {
9596 		// So there was another type of the same pretty
9597 		// representation which was reported as deleted.
9598 		// Let's see if they are different or not ...
9599 		decl_base_sptr old_type = is_decl(j->second);
9600 		decl_base_sptr new_type = is_decl(t);
9601 		if (old_type != new_type)
9602 		  {
9603 		    // The previously added type is different from this
9604 		    // one that is added.  That means the initial type
9605 		    // was changed.  Let's compute its diff and store it
9606 		    // as a changed type.
9607 		    diff_sptr d = compute_diff(old_type, new_type, ctxt);
9608 		    ABG_ASSERT(d->has_changes());
9609 		    changed_unreachable_types_[repr]= d;
9610 		  }
9611 
9612 		// In any case, the type was both deleted and added,
9613 		// so we cannot have it marked as being deleted.  So
9614 		// let's remove it from the deleted types.
9615 		deleted_unreachable_types_.erase(j);
9616 	      }
9617 	    else
9618 	      // The type wasn't previously reported as deleted, so
9619 	      // it's really added.
9620 	      added_unreachable_types_[repr] = t;
9621 	  }
9622       }
9623 
9624     // Handle anonymous enums that got changed.  An anonymous enum is
9625     // designated by its flat textual representation. So a change to
9626     // any of its enumerators results in a different enum.  That is
9627     // represented by a deletion of the previous anonymous enum, and
9628     // the addition of a new one.  For the user however, it's the same
9629     // enum that changed.  Let's massage this "added/removed" pattern
9630     // to show what the user expects, namely, a changed anonymous
9631     // enum.
9632     {
9633       std::set<type_base_sptr> deleted_anon_types;
9634       std::set<type_base_sptr> added_anon_types;
9635 
9636       for (auto entry : deleted_unreachable_types_)
9637 	{
9638 	  if ((is_enum_type(entry.second)
9639 	       && is_enum_type(entry.second)->get_is_anonymous())
9640 	      || (is_class_or_union_type(entry.second)
9641 		  && is_class_or_union_type(entry.second)->get_is_anonymous()))
9642 	  deleted_anon_types.insert(entry.second);
9643 	}
9644 
9645 
9646       for (auto entry : added_unreachable_types_)
9647 	if ((is_enum_type(entry.second)
9648 	     && is_enum_type(entry.second)->get_is_anonymous())
9649 	    || (is_class_or_union_type(entry.second)
9650 		&& is_class_or_union_type(entry.second)->get_is_anonymous()))
9651 	  added_anon_types.insert(entry.second);
9652 
9653       string_type_base_sptr_map added_anon_types_to_erase;
9654       string_type_base_sptr_map removed_anon_types_to_erase;
9655       enum_type_decl_sptr deleted_enum;
9656       class_or_union_sptr deleted_class;
9657 
9658       // Look for deleted anonymous types (enums, unions, structs &
9659       // classes) which have enumerators or data members present in an
9660       // added anonymous type ...
9661       for (auto deleted: deleted_anon_types)
9662 	{
9663 	  deleted_enum = is_enum_type(deleted);
9664 	  deleted_class = is_class_or_union_type(deleted);
9665 
9666 	  // For enums, look for any enumerator of 'deleted_enum' that
9667 	  // is also present in an added anonymous enum.
9668 	  if (deleted_enum)
9669 	    {
9670 	      for (auto enr : deleted_enum->get_enumerators())
9671 		{
9672 		  bool this_enum_got_changed = false;
9673 		  for (auto t : added_anon_types)
9674 		    {
9675 		      if (enum_type_decl_sptr added_enum = is_enum_type(t))
9676 			if (is_enumerator_present_in_enum(enr, *added_enum))
9677 			  {
9678 			    // So the enumerator 'enr' from the
9679 			    // 'deleted_enum' enum is also present in the
9680 			    // 'added_enum' enum so we assume that
9681 			    // 'deleted_enum' and 'added_enum' are the same
9682 			    // enum that got changed.  Let's represent it
9683 			    // using a diff node.
9684 			    diff_sptr d = compute_diff(deleted_enum,
9685 						       added_enum, ctxt);
9686 			    ABG_ASSERT(d->has_changes());
9687 			    string repr =
9688 			      abigail::ir::get_pretty_representation(is_type(deleted_enum),
9689 								     /*internal=*/false);
9690 			    changed_unreachable_types_[repr]= d;
9691 			    this_enum_got_changed = true;
9692 			    string r1 =
9693 			      abigail::ir::get_pretty_representation(is_type(deleted_enum),
9694 								     /*internal=*/false);
9695 			    string r2 =
9696 			      abigail::ir::get_pretty_representation(is_type(added_enum),
9697 								     /*internal=*/false);
9698 			    removed_anon_types_to_erase[r1] = deleted_enum;
9699 			    added_anon_types_to_erase[r2] = added_enum;
9700 			    break;
9701 			  }
9702 		    }
9703 		  if (this_enum_got_changed)
9704 		    break;
9705 		}
9706 	    }
9707 	  else if (deleted_class)
9708 	    {
9709 	      // For unions, structs & classes, look for any data
9710 	      // member of 'deleted_class' that is also present in an
9711 	      // added anonymous class.
9712 	      for (auto dm : deleted_class->get_data_members())
9713 		{
9714 		  bool this_class_got_changed = false;
9715 		  for (auto klass : added_anon_types)
9716 		    {
9717 		      if (class_or_union_sptr added_class =
9718 			  is_class_or_union_type(klass))
9719 			if (class_or_union_types_of_same_kind(deleted_class,
9720 							      added_class)
9721 			    && lookup_data_member(added_class, dm))
9722 			  {
9723 			    // So the data member 'dm' from the
9724 			    // 'deleted_class' class is also present in
9725 			    // the 'added_class' class so we assume that
9726 			    // 'deleted_class' and 'added_class' are the
9727 			    // same anonymous class that got changed.
9728 			    // Let's represent it using a diff node.
9729 			    diff_sptr d = compute_diff(is_type(deleted_class),
9730 						       is_type(added_class),
9731 						       ctxt);
9732 			    ABG_ASSERT(d->has_changes());
9733 			    string repr =
9734 			      abigail::ir::get_pretty_representation(is_type(deleted_class),
9735 								     /*internal=*/false);
9736 			    changed_unreachable_types_[repr]= d;
9737 			    this_class_got_changed = true;
9738 			    string r1 =
9739 			      abigail::ir::get_pretty_representation(is_type(deleted_class),
9740 								     /*internal=*/false);
9741 			    string r2 =
9742 			      abigail::ir::get_pretty_representation(is_type(added_class),
9743 								     /*internal=*/false);
9744 			    removed_anon_types_to_erase[r1] = deleted_class;
9745 			    added_anon_types_to_erase[r2] = added_class;
9746 			    break;
9747 			  }
9748 		    }
9749 		  if (this_class_got_changed)
9750 		    break;
9751 		}
9752 	    }
9753 	}
9754 
9755       // Now remove the added/removed anonymous types from their maps,
9756       // as they are now represented as a changed type, not an added
9757       // and removed anonymous type.
9758       for (auto entry : added_anon_types_to_erase)
9759 	added_unreachable_types_.erase(entry.first);
9760 
9761       for (auto entry : removed_anon_types_to_erase)
9762 	deleted_unreachable_types_.erase(entry.first);
9763     }
9764   }
9765 }
9766 
9767 /// Test if a change reports about a given @ref function_decl that is
9768 /// changed in a certain way is suppressed by a given suppression
9769 /// specifiation
9770 ///
9771 /// @param fn the @ref function_decl to consider.
9772 ///
9773 /// @param suppr the suppression specification to consider.
9774 ///
9775 /// @param k the kind of change that happened to @p fn.
9776 ///
9777 /// @param ctxt the context of the current diff.
9778 ///
9779 /// @return true iff the suppression specification @p suppr suppresses
9780 /// change reports about function @p fn, if that function changes in
9781 /// the way expressed by @p k.
9782 static bool
function_is_suppressed(const function_decl * fn,const suppression_sptr suppr,function_suppression::change_kind k,const diff_context_sptr ctxt)9783 function_is_suppressed(const function_decl* fn,
9784 		       const suppression_sptr suppr,
9785 		       function_suppression::change_kind k,
9786 		       const diff_context_sptr ctxt)
9787 {
9788   function_suppression_sptr fn_suppr = is_function_suppression(suppr);
9789   if (!fn_suppr)
9790     return false;
9791   return fn_suppr->suppresses_function(fn, k, ctxt);
9792 }
9793 
9794 /// Test if a change reports about a given @ref var_decl that is
9795 /// changed in a certain way is suppressed by a given suppression
9796 /// specifiation
9797 ///
9798 /// @param fn the @ref var_decl to consider.
9799 ///
9800 /// @param suppr the suppression specification to consider.
9801 ///
9802 /// @param k the kind of change that happened to @p fn.
9803 ///
9804 /// @param ctxt the context of the current diff.
9805 ///
9806 /// @return true iff the suppression specification @p suppr suppresses
9807 /// change reports about variable @p fn, if that variable changes in
9808 /// the way expressed by @p k.
9809 static bool
variable_is_suppressed(const var_decl * var,const suppression_sptr suppr,variable_suppression::change_kind k,const diff_context_sptr ctxt)9810 variable_is_suppressed(const var_decl* var,
9811 		       const suppression_sptr suppr,
9812 		       variable_suppression::change_kind k,
9813 		       const diff_context_sptr ctxt)
9814 {
9815   variable_suppression_sptr var_suppr = is_variable_suppression(suppr);
9816   if (!var_suppr)
9817     return false;
9818   return var_suppr->suppresses_variable(var, k, ctxt);
9819 }
9820 
9821 /// Apply suppression specifications for this corpus diff to the set
9822 /// of added/removed functions/variables, as well as to types not
9823 /// reachable from global functions/variables.
9824 void
apply_supprs_to_added_removed_fns_vars_unreachable_types()9825 corpus_diff::priv::apply_supprs_to_added_removed_fns_vars_unreachable_types()
9826 {
9827   diff_context_sptr ctxt = get_context();
9828 
9829   const suppressions_type& suppressions = ctxt->suppressions();
9830   for (suppressions_type::const_iterator i = suppressions.begin();
9831        i != suppressions.end();
9832        ++i)
9833     {
9834       // Added/Deleted functions.
9835       if (function_suppression_sptr fn_suppr = is_function_suppression(*i))
9836 	{
9837 	  // Added functions
9838 	  for (string_function_ptr_map::const_iterator e = added_fns_.begin();
9839 	       e != added_fns_.end();
9840 	       ++e)
9841 	    if (function_is_suppressed(e->second, fn_suppr,
9842 				       function_suppression::ADDED_FUNCTION_CHANGE_KIND,
9843 				       ctxt))
9844 	      suppressed_added_fns_[e->first] = e->second;
9845 
9846 	  // Deleted functions.
9847 	  for (string_function_ptr_map::const_iterator e = deleted_fns_.begin();
9848 	       e != deleted_fns_.end();
9849 	       ++e)
9850 	    if (function_is_suppressed(e->second, fn_suppr,
9851 				       function_suppression::DELETED_FUNCTION_CHANGE_KIND,
9852 				       ctxt))
9853 	      suppressed_deleted_fns_[e->first] = e->second;
9854 
9855 	  // Added function symbols not referenced by any debug info
9856 	  for (string_elf_symbol_map::const_iterator e =
9857 		 added_unrefed_fn_syms_.begin();
9858 	       e != added_unrefed_fn_syms_.end();
9859 	       ++e)
9860 	    if (fn_suppr->suppresses_function_symbol(e->second,
9861 						     function_suppression::ADDED_FUNCTION_CHANGE_KIND,
9862 						     ctxt))
9863 	      suppressed_added_unrefed_fn_syms_[e->first] = e->second;
9864 
9865 	  // Removed function symbols not referenced by any debug info
9866 	  for (string_elf_symbol_map::const_iterator e =
9867 		 deleted_unrefed_fn_syms_.begin();
9868 	       e != deleted_unrefed_fn_syms_.end();
9869 	       ++e)
9870 	    if (fn_suppr->suppresses_function_symbol(e->second,
9871 						     function_suppression::DELETED_FUNCTION_CHANGE_KIND,
9872 						     ctxt))
9873 	      suppressed_deleted_unrefed_fn_syms_[e->first] = e->second;
9874 	}
9875       // Added/Delete virtual member functions changes that might be
9876       // suppressed by a type_suppression that matches the enclosing
9877       // class of the virtual member function.
9878       else if (type_suppression_sptr type_suppr = is_type_suppression(*i))
9879 	{
9880 	  // Added virtual functions
9881 	  for (string_function_ptr_map::const_iterator e = added_fns_.begin();
9882 	       e != added_fns_.end();
9883 	       ++e)
9884 	    if (is_member_function(e->second)
9885 		&& get_member_function_is_virtual(e->second))
9886 	      {
9887 		function_decl *f = e->second;
9888 		class_decl_sptr c =
9889 		  is_class_type(is_method_type(f->get_type())->get_class_type());
9890 		ABG_ASSERT(c);
9891 		if (type_suppr->suppresses_type(c, ctxt))
9892 		  suppressed_added_fns_[e->first] = e->second;
9893 	      }
9894 	  // Deleted virtual functions
9895 	  for (string_function_ptr_map::const_iterator e = deleted_fns_.begin();
9896 	       e != deleted_fns_.end();
9897 	       ++e)
9898 	    if (is_member_function(e->second)
9899 		&& get_member_function_is_virtual(e->second))
9900 	      {
9901 		function_decl *f = e->second;
9902 		class_decl_sptr c =
9903 		  is_class_type(is_method_type(f->get_type())->get_class_type());
9904 		ABG_ASSERT(c);
9905 		if (type_suppr->suppresses_type(c, ctxt))
9906 		  suppressed_deleted_fns_[e->first] = e->second;
9907 	      }
9908 
9909 	  // Apply this type suppression to deleted types
9910 	  // non-reachable from a public interface.
9911 	  for (string_type_base_sptr_map::const_iterator e =
9912 		 deleted_unreachable_types_.begin();
9913 	       e != deleted_unreachable_types_.end();
9914 	       ++e)
9915 	    if (type_suppr->suppresses_type(e->second, ctxt))
9916 	      suppressed_deleted_unreachable_types_[e->first] = e->second;
9917 
9918 	  // Apply this type suppression to added types
9919 	  // non-reachable from a public interface.
9920 	  for (string_type_base_sptr_map::const_iterator e =
9921 		 added_unreachable_types_.begin();
9922 	       e != added_unreachable_types_.end();
9923 	       ++e)
9924 	    if (type_suppr->suppresses_type(e->second, ctxt))
9925 	      suppressed_added_unreachable_types_[e->first] = e->second;
9926 	}
9927       // Added/Deleted variables
9928       else if (variable_suppression_sptr var_suppr =
9929 	       is_variable_suppression(*i))
9930 	{
9931 	  // Added variables
9932 	  for (string_var_ptr_map::const_iterator e = added_vars_.begin();
9933 	       e != added_vars_.end();
9934 	       ++e)
9935 	    if (variable_is_suppressed(e->second, var_suppr,
9936 				       variable_suppression::ADDED_VARIABLE_CHANGE_KIND,
9937 				       ctxt))
9938 	      suppressed_added_vars_[e->first] = e->second;
9939 
9940 	  //Deleted variables
9941 	  for (string_var_ptr_map::const_iterator e = deleted_vars_.begin();
9942 	       e != deleted_vars_.end();
9943 	       ++e)
9944 	    if (variable_is_suppressed(e->second, var_suppr,
9945 				       variable_suppression::DELETED_VARIABLE_CHANGE_KIND,
9946 				       ctxt))
9947 	      suppressed_deleted_vars_[e->first] = e->second;
9948 
9949 	  // Added variable symbols not referenced by any debug info
9950 	  for (string_elf_symbol_map::const_iterator e =
9951 		 added_unrefed_var_syms_.begin();
9952 	       e != added_unrefed_var_syms_.end();
9953 	       ++e)
9954 	    if (var_suppr->suppresses_variable_symbol(e->second,
9955 						      variable_suppression::ADDED_VARIABLE_CHANGE_KIND,
9956 						      ctxt))
9957 	      suppressed_added_unrefed_var_syms_[e->first] = e->second;
9958 
9959 	  // Removed variable symbols not referenced by any debug info
9960 	  for (string_elf_symbol_map::const_iterator e =
9961 		 deleted_unrefed_var_syms_.begin();
9962 	       e != deleted_unrefed_var_syms_.end();
9963 	       ++e)
9964 	    if (var_suppr->suppresses_variable_symbol(e->second,
9965 						      variable_suppression::DELETED_VARIABLE_CHANGE_KIND,
9966 						      ctxt))
9967 	      suppressed_deleted_unrefed_var_syms_[e->first] = e->second;
9968 	}
9969     }
9970 }
9971 
9972 /// Test if the change reports for a given deleted function have
9973 /// been deleted.
9974 ///
9975 /// @param fn the function to consider.
9976 ///
9977 /// @return true iff the change reports for a give given deleted
9978 /// function have been deleted.
9979 bool
deleted_function_is_suppressed(const function_decl * fn) const9980 corpus_diff::priv::deleted_function_is_suppressed(const function_decl* fn) const
9981 {
9982   if (!fn)
9983     return false;
9984 
9985   string_function_ptr_map::const_iterator i =
9986     suppressed_deleted_fns_.find(fn->get_id());
9987 
9988   return (i != suppressed_deleted_fns_.end());
9989 }
9990 
9991 /// Test if an added type that is unreachable from public interface
9992 /// has been suppressed by a suppression specification.
9993 ///
9994 /// @param t the added unreachable type to be considered.
9995 ///
9996 /// @return true iff @p t has been suppressed by a suppression
9997 /// specification.
9998 bool
added_unreachable_type_is_suppressed(const type_base * t) const9999 corpus_diff::priv::added_unreachable_type_is_suppressed(const type_base *t)const
10000 {
10001   if (!t)
10002     return false;
10003 
10004   string repr = abigail::ir::get_pretty_representation(t, /*internal=*/false);
10005   string_type_base_sptr_map::const_iterator i =
10006     suppressed_added_unreachable_types_.find(repr);
10007   if (i == suppressed_added_unreachable_types_.end())
10008     return false;
10009 
10010   return true;
10011 }
10012 
10013 /// Test if a deleted type that is unreachable from public interface
10014 /// has been suppressed by a suppression specification.
10015 ///
10016 /// @param t the deleted unreachable type to be considered.
10017 ///
10018 /// @return true iff @p t has been suppressed by a suppression
10019 /// specification.
10020 bool
deleted_unreachable_type_is_suppressed(const type_base * t) const10021 corpus_diff::priv::deleted_unreachable_type_is_suppressed(const type_base *t) const
10022 {
10023   if (!t)
10024     return false;
10025 
10026   string repr = abigail::ir::get_pretty_representation(t, /*internal=*/false);
10027   string_type_base_sptr_map::const_iterator i =
10028     suppressed_deleted_unreachable_types_.find(repr);
10029   if (i == suppressed_deleted_unreachable_types_.end())
10030     return false;
10031 
10032   return true;
10033 }
10034 
10035 /// Test if the change reports for a give given added function has
10036 /// been deleted.
10037 ///
10038 /// @param fn the function to consider.
10039 ///
10040 /// @return true iff the change reports for a give given added
10041 /// function has been deleted.
10042 bool
added_function_is_suppressed(const function_decl * fn) const10043 corpus_diff::priv::added_function_is_suppressed(const function_decl* fn) const
10044 {
10045   if (!fn)
10046     return false;
10047 
10048   string_function_ptr_map::const_iterator i =
10049     suppressed_added_fns_.find(fn->get_id());
10050 
10051   return (i != suppressed_added_fns_.end());
10052 }
10053 
10054 /// Test if the change reports for a give given deleted variable has
10055 /// been deleted.
10056 ///
10057 /// @param var the variable to consider.
10058 ///
10059 /// @return true iff the change reports for a give given deleted
10060 /// variable has been deleted.
10061 bool
deleted_variable_is_suppressed(const var_decl * var) const10062 corpus_diff::priv::deleted_variable_is_suppressed(const var_decl* var) const
10063 {
10064   if (!var)
10065     return false;
10066 
10067   string_var_ptr_map::const_iterator i =
10068     suppressed_deleted_vars_.find(var->get_id());
10069 
10070   return (i != suppressed_deleted_vars_.end());
10071 }
10072 
10073 /// Test if the change reports for a given added variable have been
10074 /// suppressed.
10075 ///
10076 /// @param var the variable to consider.
10077 ///
10078 /// @return true iff the change reports for a given deleted
10079 /// variable has been deleted.
10080 bool
added_variable_is_suppressed(const var_decl * var) const10081 corpus_diff::priv::added_variable_is_suppressed(const var_decl* var) const
10082 {
10083   if (!var)
10084     return false;
10085 
10086   string_var_ptr_map::const_iterator i =
10087     suppressed_added_vars_.find(var->get_id());
10088 
10089   return (i != suppressed_added_vars_.end());
10090 }
10091 
10092 /// Test if the change reports for a given deleted function symbol
10093 /// (that is not referenced by any debug info) has been suppressed.
10094 ///
10095 /// @param var the function to consider.
10096 ///
10097 /// @return true iff the change reports for a given deleted function
10098 /// symbol has been suppressed.
10099 bool
deleted_unrefed_fn_sym_is_suppressed(const elf_symbol * s) const10100 corpus_diff::priv::deleted_unrefed_fn_sym_is_suppressed(const elf_symbol* s) const
10101 {
10102   if (!s)
10103     return false;
10104 
10105   string_elf_symbol_map::const_iterator i =
10106     suppressed_deleted_unrefed_fn_syms_.find(s->get_id_string());
10107 
10108   return (i != suppressed_deleted_unrefed_fn_syms_.end());
10109 }
10110 
10111 /// Test if the change reports for a given added function symbol
10112 /// (that is not referenced by any debug info) has been suppressed.
10113 ///
10114 /// @param var the function to consider.
10115 ///
10116 /// @return true iff the change reports for a given added function
10117 /// symbol has been suppressed.
10118 bool
added_unrefed_fn_sym_is_suppressed(const elf_symbol * s) const10119 corpus_diff::priv::added_unrefed_fn_sym_is_suppressed(const elf_symbol* s) const
10120 {
10121   if (!s)
10122     return false;
10123 
10124   string_elf_symbol_map::const_iterator i =
10125     suppressed_added_unrefed_fn_syms_.find(s->get_id_string());
10126 
10127   return (i != suppressed_added_unrefed_fn_syms_.end());
10128 }
10129 
10130 /// Test if the change reports for a given deleted variable symbol
10131 /// (that is not referenced by any debug info) has been suppressed.
10132 ///
10133 /// @param var the variable to consider.
10134 ///
10135 /// @return true iff the change reports for a given deleted variable
10136 /// symbol has been suppressed.
10137 bool
deleted_unrefed_var_sym_is_suppressed(const elf_symbol * s) const10138 corpus_diff::priv::deleted_unrefed_var_sym_is_suppressed(const elf_symbol* s) const
10139 {
10140   if (!s)
10141     return false;
10142 
10143   string_elf_symbol_map::const_iterator i =
10144     suppressed_deleted_unrefed_var_syms_.find(s->get_id_string());
10145 
10146   return (i != suppressed_deleted_unrefed_var_syms_.end());
10147 }
10148 
10149 /// Test if the change reports for a given added variable symbol
10150 /// (that is not referenced by any debug info) has been suppressed.
10151 ///
10152 /// @param var the variable to consider.
10153 ///
10154 /// @return true iff the change reports for a given added variable
10155 /// symbol has been suppressed.
10156 bool
added_unrefed_var_sym_is_suppressed(const elf_symbol * s) const10157 corpus_diff::priv::added_unrefed_var_sym_is_suppressed(const elf_symbol* s) const
10158 {
10159   if (!s)
10160     return false;
10161 
10162   string_elf_symbol_map::const_iterator i =
10163     suppressed_added_unrefed_var_syms_.find(s->get_id_string());
10164 
10165   return (i != suppressed_added_unrefed_var_syms_.end());
10166 }
10167 
10168 #ifdef do_count_diff_map_changes
10169 #undef do_count_diff_map_changes
10170 #endif
10171 #define do_count_diff_map_changes(diff_map, n_changes, n_filtered)	\
10172   {									\
10173     string_diff_ptr_map::const_iterator i;				\
10174     for (i = diff_map.begin();						\
10175 	 i != diff_map.end();						\
10176 	 ++i)								\
10177       { \
10178 	if (const var_diff* d = is_var_diff(i->second))		\
10179 	  if (is_data_member(d->first_var()))				\
10180 	    continue;							\
10181 									\
10182 	if (i->second->has_local_changes())				\
10183 	  ++n_changes;							\
10184 	if (!i->second->get_canonical_diff()->to_be_reported())		\
10185 	  ++n_filtered;						\
10186       }								\
10187   }
10188 
10189 /// Count the number of leaf changes as well as the number of the
10190 /// changes that have been filtered out.
10191 ///
10192 /// @param num_changes out parameter.  This is set to the total number
10193 /// of leaf changes.
10194 ///
10195 /// @param num_filtered out parameter.  This is set to the number of
10196 /// leaf changes that have been filtered out.
10197 void
count_leaf_changes(size_t & num_changes,size_t & num_filtered)10198 corpus_diff::priv::count_leaf_changes(size_t &num_changes, size_t &num_filtered)
10199 {
10200   count_leaf_type_changes(num_changes, num_filtered);
10201 
10202   // Now count the non-type changes.
10203   do_count_diff_map_changes(leaf_diffs_.get_function_decl_diff_map(),
10204     num_changes, num_filtered);
10205   do_count_diff_map_changes(leaf_diffs_.get_var_decl_diff_map(),
10206     num_changes, num_filtered);
10207 }
10208 
10209 /// Count the number of leaf *type* changes as well as the number of
10210 /// the leaf type changes that have been filtered out.
10211 ///
10212 /// @param num_changes out parameter.  This is set to the total number
10213 /// of leaf type changes.
10214 ///
10215 /// @param num_filtered out parameter.  This is set to the number of
10216 /// leaf type changes that have been filtered out.
10217 void
count_leaf_type_changes(size_t & num_changes,size_t & num_filtered)10218 corpus_diff::priv::count_leaf_type_changes(size_t &num_changes,
10219 					   size_t &num_filtered)
10220 {
10221   do_count_diff_map_changes(leaf_diffs_.get_type_decl_diff_map(),
10222     num_changes, num_filtered);
10223   do_count_diff_map_changes(leaf_diffs_.get_enum_diff_map(),
10224     num_changes, num_filtered);
10225   do_count_diff_map_changes(leaf_diffs_.get_class_diff_map(),
10226     num_changes, num_filtered);
10227   do_count_diff_map_changes(leaf_diffs_.get_union_diff_map(),
10228     num_changes, num_filtered);
10229   do_count_diff_map_changes(leaf_diffs_.get_typedef_diff_map(),
10230     num_changes, num_filtered);
10231   do_count_diff_map_changes(leaf_diffs_.get_subrange_diff_map(),
10232 			    num_changes, num_filtered);
10233   do_count_diff_map_changes(leaf_diffs_.get_array_diff_map(),
10234     num_changes, num_filtered);
10235   do_count_diff_map_changes(leaf_diffs_.get_distinct_diff_map(),
10236     num_changes, num_filtered);
10237   do_count_diff_map_changes(leaf_diffs_.get_fn_parm_diff_map(),
10238 			    num_changes, num_filtered);
10239 }
10240 
10241 /// Count the number of types not reachable from the interface (i.e,
10242 /// not reachable from global functions or variables).
10243 ///
10244 /// @param num_added this is set to the number of added types not
10245 /// reachable from the interface.
10246 ///
10247 /// @param num_deleted this is set to the number of deleted types not
10248 /// reachable from the interface.
10249 ///
10250 /// @param num_changed this is set to the number of changed types not
10251 /// reachable from the interface.
10252 ///
10253 /// @param num_filtered_added this is set to the number of added types
10254 /// not reachable from the interface and that have been filtered out
10255 /// by suppression specifications.
10256 ///
10257 /// @param num_filtered_deleted this is set to the number of deleted
10258 /// types not reachable from the interface and that have been filtered
10259 /// out by suppression specifications.
10260 ///
10261 /// @param num_filtered_changed this is set to the number of changed
10262 /// types not reachable from the interface and that have been filtered
10263 /// out by suppression specifications.
10264 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)10265 corpus_diff::priv::count_unreachable_types(size_t &num_added,
10266 					   size_t &num_deleted,
10267 					   size_t &num_changed,
10268 					   size_t &num_filtered_added,
10269 					   size_t &num_filtered_deleted,
10270 					   size_t &num_filtered_changed)
10271 {
10272   num_added = added_unreachable_types_.size();
10273   num_deleted = deleted_unreachable_types_.size();
10274   num_changed = changed_unreachable_types_.size();
10275   num_filtered_added = suppressed_added_unreachable_types_.size();
10276   num_filtered_deleted = suppressed_deleted_unreachable_types_.size();
10277 
10278   for (vector<diff_sptr>::const_iterator i =
10279 	 changed_unreachable_types_sorted().begin();
10280        i != changed_unreachable_types_sorted().end();
10281        ++i)
10282     if (!(*i)->to_be_reported())
10283       ++num_filtered_changed;
10284 }
10285 
10286 /// Get the map of diff nodes representing changed unreachable types.
10287 ///
10288 /// @return the map of diff nodes representing changed unreachable
10289 /// types.
10290 const string_diff_sptr_map&
changed_unreachable_types() const10291 corpus_diff::priv::changed_unreachable_types() const
10292 {return changed_unreachable_types_;}
10293 
10294 /// Get the sorted vector of diff nodes representing changed
10295 /// unreachable types.
10296 ///
10297 /// Upon the first invocation of this method, if the vector is empty,
10298 /// this function gets the diff nodes representing changed
10299 /// unreachable, sort them, and return the sorted vector.
10300 ///
10301 /// @return the sorted vector of diff nodes representing changed
10302 /// unreachable types.
10303 const vector<diff_sptr>&
changed_unreachable_types_sorted() const10304 corpus_diff::priv::changed_unreachable_types_sorted() const
10305 {
10306 if (changed_unreachable_types_sorted_.empty())
10307   if (!changed_unreachable_types_.empty())
10308     sort_string_diff_sptr_map(changed_unreachable_types_,
10309 			      changed_unreachable_types_sorted_);
10310 
10311  return changed_unreachable_types_sorted_;
10312 }
10313 
10314 /// Compute the diff stats.
10315 ///
10316 /// To know the number of functions that got filtered out, this
10317 /// function applies the categorizing filters to the diff sub-trees of
10318 /// each function changes diff, prior to calculating the stats.
10319 ///
10320 /// @param num_removed the number of removed functions.
10321 ///
10322 /// @param num_added the number of added functions.
10323 ///
10324 /// @param num_changed the number of changed functions.
10325 ///
10326 /// @param num_filtered_out the number of changed functions that are
10327 /// got filtered out from the report
10328 void
apply_filters_and_compute_diff_stats(diff_stats & stat)10329 corpus_diff::priv::apply_filters_and_compute_diff_stats(diff_stats& stat)
10330 {
10331   stat.num_func_removed(deleted_fns_.size());
10332   stat.num_removed_func_filtered_out(suppressed_deleted_fns_.size());
10333   stat.num_func_added(added_fns_.size());
10334   stat.num_added_func_filtered_out(suppressed_added_fns_.size());
10335   stat.num_func_changed(changed_fns_map_.size());
10336 
10337   stat.num_vars_removed(deleted_vars_.size());
10338   stat.num_removed_vars_filtered_out(suppressed_deleted_vars_.size());
10339   stat.num_vars_added(added_vars_.size());
10340   stat.num_added_vars_filtered_out(suppressed_added_vars_.size());
10341   stat.num_vars_changed(changed_vars_map_.size());
10342 
10343   diff_context_sptr ctxt = get_context();
10344 
10345   tools_utils::timer t;
10346   if (ctxt->perform_change_categorization())
10347     {
10348       if (get_context()->do_log())
10349 	{
10350 	  std::cerr << "in apply_filters_and_compute_diff_stats:"
10351 		    << "applying filters to "
10352 		    << changed_fns_.size()
10353 		    << " changed fns ...\n";
10354 	  t.start();
10355 	}
10356       // Walk the changed function diff nodes to apply the categorization
10357       // filters.
10358       diff_sptr diff;
10359       for (function_decl_diff_sptrs_type::const_iterator i =
10360 	     changed_fns_.begin();
10361 	   i != changed_fns_.end();
10362 	   ++i)
10363 	{
10364 	  diff_sptr diff = *i;
10365 	  ctxt->maybe_apply_filters(diff);
10366 	}
10367 
10368       if (get_context()->do_log())
10369 	{
10370 	  t.stop();
10371 	  std::cerr << "in apply_filters_and_compute_diff_stats:"
10372 		    << "filters to changed fn applied!:" << t << "\n";
10373 
10374 	  std::cerr << "in apply_filters_and_compute_diff_stats:"
10375 		    << "applying filters to "
10376 		    << sorted_changed_vars_.size()
10377 		    << " changed vars ...\n";
10378 	  t.start();
10379 	}
10380 
10381       // Walk the changed variable diff nodes to apply the categorization
10382       // filters.
10383       for (var_diff_sptrs_type::const_iterator i = sorted_changed_vars_.begin();
10384 	   i != sorted_changed_vars_.end();
10385 	   ++i)
10386 	{
10387 	  diff_sptr diff = *i;
10388 	  ctxt->maybe_apply_filters(diff);
10389 	}
10390 
10391       if (get_context()->do_log())
10392 	{
10393 	  t.stop();
10394 	  std::cerr << "in apply_filters_and_compute_diff_stats:"
10395 		    << "filters to changed vars applied!:" << t << "\n";
10396 
10397 	  std::cerr << "in apply_filters_and_compute_diff_stats:"
10398 		    << "applying filters to unreachable types ...\n";
10399 	  t.start();
10400 	}
10401 
10402       // walk the changed unreachable types to apply categorization
10403       // filters
10404       for (auto& diff : changed_unreachable_types_sorted())
10405 	ctxt->maybe_apply_filters(diff);
10406 
10407       for (auto& entry : changed_unreachable_types())
10408 	ctxt->maybe_apply_filters(entry.second);
10409 
10410       if (get_context()->do_log())
10411 	{
10412 	  t.stop();
10413 	  std::cerr << "in apply_filters_and_compute_diff_stats:"
10414 		    << "filters to unreachable types applied!:" << t << "\n";
10415 
10416 	  std::cerr << "in apply_filters_and_compute_diff_stats:"
10417 		    << "categorizing redundant changed sub nodes ...\n";
10418 	  t.start();
10419 	}
10420 
10421       categorize_redundant_changed_sub_nodes();
10422 
10423       if (get_context()->do_log())
10424 	{
10425 	  t.stop();
10426 	  std::cerr << "in apply_filters_and_compute_diff_stats:"
10427 		    << "redundant changed sub nodes categorized!:" << t << "\n";
10428 
10429 	  std::cerr << "in apply_filters_and_compute_diff_stats:"
10430 		    << "count changed fns ...\n";
10431 	  t.start();
10432 	}
10433     }
10434 
10435   // Walk the changed function diff nodes to count the number of
10436   // filtered-out functions and the number of functions with virtual
10437   // offset changes.
10438   for (function_decl_diff_sptrs_type::const_iterator i =
10439 	 changed_fns_.begin();
10440        i != changed_fns_.end();
10441        ++i)
10442     {
10443       if ((*i)->is_filtered_out())
10444 	{
10445 	  stat.num_changed_func_filtered_out
10446 	    (stat.num_changed_func_filtered_out() + 1);
10447 
10448 	  if ((*i)->has_local_changes())
10449 	    stat.num_leaf_func_changes_filtered_out
10450 	      (stat.num_leaf_func_changes_filtered_out() + 1);
10451 	}
10452       else
10453 	{
10454 	  if ((*i)->get_category() & VIRTUAL_MEMBER_CHANGE_CATEGORY)
10455 	    stat.num_func_with_virtual_offset_changes
10456 	      (stat.num_func_with_virtual_offset_changes() + 1);
10457 	}
10458 
10459       if ((*i)->has_local_changes())
10460 	stat.num_leaf_func_changes
10461 	  (stat.num_leaf_func_changes() + 1);
10462     }
10463 
10464   if (get_context()->do_log())
10465     {
10466       t.stop();
10467       std::cerr << "in apply_filters_and_compute_diff_stats:"
10468 		<< "changed fn counted!:" << t << "\n";
10469 
10470       std::cerr << "in apply_filters_and_compute_diff_stats:"
10471 		<< "count changed vars ...\n";
10472       t.start();
10473     }
10474 
10475   // Walk the changed variables diff nodes to count the number of
10476   // filtered-out variables.
10477   for (var_diff_sptrs_type ::const_iterator i = sorted_changed_vars_.begin();
10478        i != sorted_changed_vars_.end();
10479        ++i)
10480     {
10481       if ((*i)->is_filtered_out())
10482 	{
10483 	  stat.num_changed_vars_filtered_out
10484 	    (stat.num_changed_vars_filtered_out() + 1);
10485 
10486 	  if ((*i)->has_local_changes())
10487 	    stat.num_leaf_var_changes_filtered_out
10488 	      (stat.num_leaf_var_changes_filtered_out() + 1);
10489 	}
10490       if ((*i)->has_local_changes())
10491 	stat.num_leaf_var_changes
10492 	  (stat.num_leaf_var_changes() + 1);
10493     }
10494 
10495   if (get_context()->do_log())
10496     {
10497       t.stop();
10498       std::cerr << "in apply_filters_and_compute_diff_stats:"
10499 		<< "changed vars counted!:" << t << "\n";
10500 
10501       std::cerr << "in apply_filters_and_compute_diff_stats:"
10502 		<< "count leaf changed types ...\n";
10503       t.start();
10504     }
10505 
10506   stat.num_func_syms_added(added_unrefed_fn_syms_.size());
10507   stat.num_added_func_syms_filtered_out(suppressed_added_unrefed_fn_syms_.size());
10508   stat.num_func_syms_removed(deleted_unrefed_fn_syms_.size());
10509   stat.num_removed_func_syms_filtered_out(suppressed_deleted_unrefed_fn_syms_.size());
10510   stat.num_var_syms_added(added_unrefed_var_syms_.size());
10511   stat.num_added_var_syms_filtered_out(suppressed_added_unrefed_var_syms_.size());
10512   stat.num_var_syms_removed(deleted_unrefed_var_syms_.size());
10513   stat.num_removed_var_syms_filtered_out(suppressed_deleted_unrefed_var_syms_.size());
10514 
10515   // Walk the general leaf type diff nodes to count them
10516   {
10517     size_t num_type_changes = 0, num_type_filtered = 0;
10518     count_leaf_type_changes(num_type_changes, num_type_filtered);
10519 
10520     stat.num_leaf_type_changes(num_type_changes);
10521     stat.num_leaf_type_changes_filtered_out(num_type_filtered);
10522   }
10523 
10524   if (get_context()->do_log())
10525     {
10526       t.stop();
10527       std::cerr << "in apply_filters_and_compute_diff_stats:"
10528 		<< "changed leaf types counted!:" << t << "\n";
10529 
10530       std::cerr << "in apply_filters_and_compute_diff_stats:"
10531 		<< "count leaf changed artefacts ...\n";
10532       t.start();
10533     }
10534 
10535   // Walk the general leaf artefacts diff nodes to count them
10536   {
10537     size_t num_changes = 0, num_filtered = 0;
10538     count_leaf_changes(num_changes, num_filtered);
10539 
10540     stat.num_leaf_changes(num_changes);
10541     stat.num_leaf_changes_filtered_out(num_filtered);
10542   }
10543 
10544   if (get_context()->do_log())
10545     {
10546       t.stop();
10547       std::cerr << "in apply_filters_and_compute_diff_stats:"
10548 		<< "changed leaf artefacts counted!:" << t << "\n";
10549 
10550       std::cerr << "in apply_filters_and_compute_diff_stats:"
10551 		<< "count unreachable types ...\n";
10552       t.start();
10553     }
10554 
10555   // Walk the unreachable types to count them
10556   {
10557     size_t num_added_unreachable_types = 0,
10558       num_changed_unreachable_types = 0,
10559       num_deleted_unreachable_types = 0,
10560       num_added_unreachable_types_filtered = 0,
10561       num_changed_unreachable_types_filtered = 0,
10562       num_deleted_unreachable_types_filtered = 0;
10563 
10564     count_unreachable_types(num_added_unreachable_types,
10565 			    num_deleted_unreachable_types,
10566 			    num_changed_unreachable_types,
10567 			    num_added_unreachable_types_filtered,
10568 			    num_deleted_unreachable_types_filtered,
10569 			    num_changed_unreachable_types_filtered);
10570 
10571     if (get_context()->do_log())
10572       {
10573 	t.stop();
10574 	std::cerr << "in apply_filters_and_compute_diff_stats:"
10575 		  << "unreachable types counted!:" << t << "\n";
10576       }
10577 
10578     stat.num_added_unreachable_types(num_added_unreachable_types);
10579     stat.num_removed_unreachable_types(num_deleted_unreachable_types);
10580     stat.num_changed_unreachable_types(num_changed_unreachable_types);
10581     stat.num_added_unreachable_types_filtered_out
10582       (num_added_unreachable_types_filtered);
10583     stat.num_removed_unreachable_types_filtered_out
10584       (num_deleted_unreachable_types_filtered);
10585     stat.num_changed_unreachable_types_filtered_out
10586       (num_changed_unreachable_types_filtered);
10587   }
10588 }
10589 
10590 /// Emit the summary of the functions & variables that got
10591 /// removed/changed/added.
10592 ///
10593 /// TODO: This should be handled by the reporters, just like what is
10594 /// done for reporter_base::diff_to_be_reported.
10595 ///
10596 /// @param out the output stream to emit the stats to.
10597 ///
10598 /// @param indent the indentation string to use in the summary.
10599 void
emit_diff_stats(const diff_stats & s,ostream & out,const string & indent)10600 corpus_diff::priv::emit_diff_stats(const diff_stats&	s,
10601 				   ostream&		out,
10602 				   const string&	indent)
10603 {
10604   /// Report added/removed/changed functions.
10605   size_t net_num_leaf_changes =
10606     s.net_num_func_removed() +
10607     s.net_num_func_added() +
10608     s.net_num_leaf_func_changes() +
10609     s.net_num_vars_removed() +
10610     s.net_num_vars_added() +
10611     s.net_num_leaf_var_changes() +
10612     s.net_num_leaf_type_changes() +
10613     s.net_num_removed_func_syms() +
10614     s.net_num_added_func_syms() +
10615     s.net_num_removed_var_syms() +
10616     s.net_num_added_var_syms();
10617 
10618   if (!sonames_equal_)
10619     out << indent << "ELF SONAME changed\n";
10620 
10621   if (!architectures_equal_)
10622     out << indent << "ELF architecture changed\n";
10623 
10624   diff_context_sptr ctxt = get_context();
10625 
10626   if (ctxt->show_leaf_changes_only())
10627     {
10628       out << "Leaf changes summary: ";
10629       out << net_num_leaf_changes << " artifact";
10630       if (net_num_leaf_changes > 1)
10631 	out << "s";
10632       out << " changed";
10633 
10634       if (size_t num_filtered = s.num_leaf_changes_filtered_out())
10635 	out << " (" << num_filtered << " filtered out)";
10636       out << "\n";
10637 
10638       out << indent << "Changed leaf types summary: "
10639 	  << s.net_num_leaf_type_changes();
10640       if (s.num_leaf_type_changes_filtered_out())
10641 	out << " (" << s.num_leaf_type_changes_filtered_out()
10642 	    << " filtered out)";
10643       out << " leaf type";
10644       if (s.num_leaf_type_changes() > 1)
10645 	out << "s";
10646       out << " changed\n";
10647 
10648       // function changes summary
10649       out << indent << "Removed/Changed/Added functions summary: ";
10650       out << s.net_num_func_removed() << " Removed";
10651      if (s.num_removed_func_filtered_out())
10652 	out << " ("
10653 	    << s.num_removed_func_filtered_out()
10654 	    << " filtered out)";
10655       out << ", ";
10656 
10657       out << s.net_num_leaf_func_changes() << " Changed";
10658       if (s.num_leaf_func_changes_filtered_out())
10659 	    out << " ("
10660 		<< s.num_leaf_func_changes_filtered_out()
10661 		<< " filtered out)";
10662       out << ", ";
10663 
10664       out << s.net_num_func_added()<< " Added ";
10665       if (s.net_num_func_added() <= 1)
10666 	out << "function";
10667       else
10668 	out << "functions";
10669       if (s.num_added_func_filtered_out())
10670 	out << " (" << s.num_added_func_filtered_out() << " filtered out)";
10671       out << "\n";
10672 
10673       // variables changes summary
10674       out << indent << "Removed/Changed/Added variables summary: ";
10675       out << s.net_num_vars_removed() << " Removed";
10676       if (s.num_removed_vars_filtered_out())
10677 	out << " (" << s.num_removed_vars_filtered_out()
10678 	    << " filtered out)";
10679       out << ", ";
10680 
10681       out << s.net_num_leaf_var_changes() << " Changed";
10682       if (s.num_leaf_var_changes_filtered_out())
10683 	out << " ("
10684 	    << s.num_leaf_var_changes_filtered_out()
10685 	    << " filtered out)";
10686       out << ", ";
10687 
10688       out << s.net_num_vars_added() << " Added ";
10689       if (s.net_num_vars_added() <= 1)
10690 	out << "variable";
10691       else
10692 	out << "variables";
10693       if (s.num_added_vars_filtered_out())
10694 	out << " (" << s.num_added_vars_filtered_out()
10695 	    << " filtered out)";
10696       out << "\n";
10697     }
10698   else // if (ctxt->show_leaf_changes_only())
10699     {
10700       size_t total_nb_function_changes = s.num_func_removed()
10701 	+ s.num_func_changed() +  s.num_func_added();
10702 
10703       // function changes summary
10704       out << indent << "Functions changes summary: ";
10705       out << s.net_num_func_removed() << " Removed";
10706       if (s.num_removed_func_filtered_out())
10707 	out << " ("
10708 	    << s.num_removed_func_filtered_out()
10709 	    << " filtered out)";
10710       out << ", ";
10711 
10712       out << s.net_num_func_changed() << " Changed";
10713       if (s.num_changed_func_filtered_out())
10714 	out << " (" << s.num_changed_func_filtered_out() << " filtered out)";
10715       out << ", ";
10716 
10717       out << s.net_num_func_added() << " Added";
10718       if (s.num_added_func_filtered_out())
10719 	out << " (" << s.num_added_func_filtered_out() << " filtered out)";
10720       if (total_nb_function_changes <= 1)
10721 	out << " function";
10722       else
10723 	out << " functions";
10724       out << "\n";
10725 
10726       // variables changes summary
10727       size_t total_nb_variable_changes = s.num_vars_removed()
10728 	+ s.num_vars_changed() + s.num_vars_added();
10729 
10730       out << indent << "Variables changes summary: ";
10731       out << s.net_num_vars_removed() << " Removed";
10732       if (s.num_removed_vars_filtered_out())
10733 	out << " (" << s.num_removed_vars_filtered_out()
10734 	    << " filtered out)";
10735       out << ", ";
10736 
10737       out << s.num_vars_changed() - s.num_changed_vars_filtered_out() << " Changed";
10738       if (s.num_changed_vars_filtered_out())
10739 	out << " (" << s.num_changed_vars_filtered_out() << " filtered out)";
10740       out << ", ";
10741 
10742       out << s.net_num_vars_added() << " Added";
10743       if (s.num_added_vars_filtered_out())
10744 	out << " (" << s.num_added_vars_filtered_out()
10745 	    << " filtered out)";
10746       if (total_nb_variable_changes <= 1)
10747 	out << " variable";
10748       else
10749 	out << " variables";
10750       out << "\n";
10751     }
10752 
10753   // Show statistics about types not reachable from global
10754   // functions/variables.
10755   if (ctxt->show_unreachable_types())
10756     {
10757       size_t total_nb_unreachable_type_changes =
10758 	s.num_removed_unreachable_types()
10759 	+ s.num_changed_unreachable_types()
10760 	+ s.num_added_unreachable_types();
10761 
10762       // Show summary of unreachable types
10763       out << indent << "Unreachable types summary: "
10764 	  << s.net_num_removed_unreachable_types()
10765 	  << " removed";
10766       if (s.num_removed_unreachable_types_filtered_out())
10767 	out << " (" << s.num_removed_unreachable_types_filtered_out()
10768 	    << " filtered out)";
10769       out << ", ";
10770 
10771       out << s.net_num_changed_unreachable_types()
10772 	  << " changed";
10773       if (s.num_changed_unreachable_types_filtered_out())
10774 	out << " (" << s.num_changed_unreachable_types_filtered_out()
10775 	    << " filtered out)";
10776       out << ", ";
10777 
10778       out << s.net_num_added_unreachable_types()
10779 	  << " added";
10780       if (s.num_added_unreachable_types_filtered_out())
10781 	out << " (" << s.num_added_unreachable_types_filtered_out()
10782 	    << " filtered out)";
10783       if (total_nb_unreachable_type_changes <= 1)
10784 	out << " type";
10785       else
10786 	out << " types";
10787       out << "\n";
10788     }
10789 
10790   if (ctxt->show_symbols_unreferenced_by_debug_info()
10791       && (s.num_func_syms_removed()
10792 	  || s.num_func_syms_added()
10793 	  || s.num_var_syms_removed()
10794 	  || s.num_var_syms_added()))
10795     {
10796       // function symbols changes summary.
10797 
10798       if (!ctxt->show_added_symbols_unreferenced_by_debug_info()
10799 	  && s.num_func_syms_removed() == 0
10800 	  && s.num_func_syms_added() != 0)
10801 	// If the only unreferenced function symbol change is function
10802 	// syms that got added, but we were forbidden to show function
10803 	// syms being added, do nothing.
10804 	;
10805       else
10806 	{
10807 	  out << indent
10808 	      << "Function symbols changes summary: "
10809 	      << s.net_num_removed_func_syms() << " Removed";
10810 	  if (s.num_removed_func_syms_filtered_out())
10811 	    out << " (" << s.num_removed_func_syms_filtered_out()
10812 		<< " filtered out)";
10813 	  out << ", ";
10814 	  out << s.net_num_added_func_syms() << " Added";
10815 	  if (s.num_added_func_syms_filtered_out())
10816 	    out << " (" << s.num_added_func_syms_filtered_out()
10817 		<< " filtered out)";
10818 	  out << " function symbol";
10819 	  if (s.num_func_syms_added() + s.num_func_syms_removed() > 1)
10820 	    out << "s";
10821 	  out << " not referenced by debug info\n";
10822 	}
10823 
10824       // variable symbol changes summary.
10825 
10826       if (!ctxt->show_added_symbols_unreferenced_by_debug_info()
10827 	  && s.num_var_syms_removed() == 0
10828 	  && s.num_var_syms_added() != 0)
10829 	// If the only unreferenced variable symbol change is variable
10830 	// syms that got added, but we were forbidden to show variable
10831 	// syms being added, do nothing.
10832 	;
10833       else
10834 	{
10835 	  out << indent
10836 	      << "Variable symbols changes summary: "
10837 	      << s.net_num_removed_var_syms() << " Removed";
10838 	  if (s.num_removed_var_syms_filtered_out())
10839 	    out << " (" << s.num_removed_var_syms_filtered_out()
10840 		<< " filtered out)";
10841 	  out << ", ";
10842 	  out << s.net_num_added_var_syms() << " Added";
10843 	  if (s.num_added_var_syms_filtered_out())
10844 	    out << " (" << s.num_added_var_syms_filtered_out()
10845 		<< " filtered out)";
10846 	  out << " variable symbol";
10847 	  if (s.num_var_syms_added() + s.num_var_syms_removed() > 1)
10848 	    out << "s";
10849 	  out << " not referenced by debug info\n";
10850 	}
10851     }
10852 }
10853 
10854 /// Walk the changed functions and variables diff nodes to categorize
10855 /// redundant nodes.
10856 void
categorize_redundant_changed_sub_nodes()10857 corpus_diff::priv::categorize_redundant_changed_sub_nodes()
10858 {
10859   diff_sptr diff;
10860 
10861   diff_context_sptr ctxt = get_context();
10862 
10863   ctxt->forget_visited_diffs();
10864   for (function_decl_diff_sptrs_type::const_iterator i =
10865 	 changed_fns_.begin();
10866        i!= changed_fns_.end();
10867        ++i)
10868     {
10869       diff = *i;
10870       categorize_redundancy(diff);
10871     }
10872 
10873   for (var_diff_sptrs_type::const_iterator i = sorted_changed_vars_.begin();
10874        i!= sorted_changed_vars_.end();
10875        ++i)
10876     {
10877       diff_sptr diff = *i;
10878       categorize_redundancy(diff);
10879     }
10880 
10881   for (diff_sptrs_type::const_iterator i =
10882 	 changed_unreachable_types_sorted().begin();
10883        i!= changed_unreachable_types_sorted().end();
10884        ++i)
10885     {
10886       diff_sptr diff = *i;
10887       categorize_redundancy(diff);
10888     }
10889 }
10890 
10891 /// Walk the changed functions and variables diff nodes and clear the
10892 /// redundancy categorization they might carry.
10893 void
clear_redundancy_categorization()10894 corpus_diff::priv::clear_redundancy_categorization()
10895 {
10896   diff_sptr diff;
10897   for (function_decl_diff_sptrs_type::const_iterator i = changed_fns_.begin();
10898        i!= changed_fns_.end();
10899        ++i)
10900     {
10901       diff = *i;
10902       abigail::comparison::clear_redundancy_categorization(diff);
10903     }
10904 
10905   for (var_diff_sptrs_type::const_iterator i = sorted_changed_vars_.begin();
10906        i!= sorted_changed_vars_.end();
10907        ++i)
10908     {
10909       diff = *i;
10910       abigail::comparison::clear_redundancy_categorization(diff);
10911     }
10912 }
10913 
10914 /// If the user asked to dump the diff tree node (for changed
10915 /// variables and functions) on the error output stream, then just do
10916 /// that.
10917 ///
10918 /// This function is used for debugging purposes.
10919 void
maybe_dump_diff_tree()10920 corpus_diff::priv::maybe_dump_diff_tree()
10921 {
10922   diff_context_sptr ctxt = get_context();
10923 
10924   if (!ctxt->dump_diff_tree()
10925       || ctxt->error_output_stream() == 0)
10926     return;
10927 
10928   if (!changed_fns_.empty())
10929     {
10930       *ctxt->error_output_stream() << "changed functions diff tree: \n\n";
10931       for (function_decl_diff_sptrs_type::const_iterator i =
10932 	     changed_fns_.begin();
10933 	   i != changed_fns_.end();
10934 	   ++i)
10935 	{
10936 	  diff_sptr d = *i;
10937 	  print_diff_tree(d, *ctxt->error_output_stream());
10938 	}
10939     }
10940 
10941   if (!sorted_changed_vars_.empty())
10942     {
10943       *ctxt->error_output_stream() << "\nchanged variables diff tree: \n\n";
10944       for (var_diff_sptrs_type::const_iterator i =
10945 	     sorted_changed_vars_.begin();
10946 	   i != sorted_changed_vars_.end();
10947 	   ++i)
10948 	{
10949 	  diff_sptr d = *i;
10950 	  print_diff_tree(d, *ctxt->error_output_stream());
10951 	}
10952     }
10953 
10954   if (!changed_unreachable_types_sorted().empty())
10955     {
10956       *ctxt->error_output_stream() << "\nchanged unreachable "
10957 	"types diff tree: \n\n";
10958       for (vector<diff_sptr>::const_iterator i =
10959 	     changed_unreachable_types_sorted().begin();
10960 	   i != changed_unreachable_types_sorted().end();
10961 	   ++i)
10962 	{
10963 	  diff_sptr d = *i;
10964 	  print_diff_tree(d, *ctxt->error_output_stream());
10965 	}
10966     }
10967 }
10968 
10969 /// Populate the vector of children node of the @ref corpus_diff type.
10970 ///
10971 /// The children node can then later be retrieved using
10972 /// corpus_diff::children_node().
10973 void
chain_into_hierarchy()10974 corpus_diff::chain_into_hierarchy()
10975 {
10976   for (function_decl_diff_sptrs_type::const_iterator i =
10977 	 changed_functions_sorted().begin();
10978        i != changed_functions_sorted().end();
10979        ++i)
10980     if (diff_sptr d = *i)
10981       append_child_node(d);
10982 }
10983 
10984 /// Constructor for @ref corpus_diff.
10985 ///
10986 /// @param first the first corpus of the diff.
10987 ///
10988 /// @param second the second corpus of the diff.
10989 ///
10990 /// @param ctxt the diff context to use.  Note that this context
10991 /// object must stay alive at least during the life time of the
10992 /// current instance of @ref corpus_diff.  Otherwise memory corruption
10993 /// issues occur.
corpus_diff(corpus_sptr first,corpus_sptr second,diff_context_sptr ctxt)10994 corpus_diff::corpus_diff(corpus_sptr first,
10995 			 corpus_sptr second,
10996 			 diff_context_sptr ctxt)
10997   : priv_(new priv(first, second, ctxt))
10998 {}
10999 
11000 corpus_diff::~corpus_diff() = default;
11001 
11002 /// Finish building the current instance of @ref corpus_diff.
11003 void
finish_diff_type()11004 corpus_diff::finish_diff_type()
11005 {
11006   if (priv_->finished_)
11007     return;
11008   chain_into_hierarchy();
11009   priv_->finished_ = true;
11010 }
11011 
11012 /// Test if logging was requested.
11013 ///
11014 /// @return true iff logging was requested.
11015 bool
do_log() const11016 corpus_diff::do_log() const
11017 {return context()->do_log();}
11018 
11019 /// Request logging, or not.
11020 ///
11021 /// @param f true iff logging is requested.
11022 void
do_log(bool f)11023 corpus_diff::do_log(bool f)
11024 {context()->do_log(f);}
11025 
11026 /// @return the first corpus of the diff.
11027 corpus_sptr
first_corpus() const11028 corpus_diff::first_corpus() const
11029 {return priv_->first_;}
11030 
11031 /// @return the second corpus of the diff.
11032 corpus_sptr
second_corpus() const11033 corpus_diff::second_corpus() const
11034 {return priv_->second_;}
11035 
11036 /// @return the children nodes of the current instance of corpus_diff.
11037 const vector<diff*>&
children_nodes() const11038 corpus_diff::children_nodes() const
11039 {return priv_->children_;}
11040 
11041 /// Append a new child node to the vector of children nodes for the
11042 /// current instance of @ref corpus_diff node.
11043 ///
11044 /// Note that the vector of children nodes for the current instance of
11045 /// @ref corpus_diff node must remain sorted, using
11046 /// diff_less_than_functor.
11047 ///
11048 /// @param d the new child node.  Note that the life time of the
11049 /// object held by @p d will thus equal the life time of the current
11050 /// instance of @ref corpus_diff.
11051 void
append_child_node(diff_sptr d)11052 corpus_diff::append_child_node(diff_sptr d)
11053 {
11054   ABG_ASSERT(d);
11055 
11056   diff_less_than_functor is_less_than;
11057   bool inserted = false;
11058   for (vector<diff*>::iterator i = priv_->children_.begin();
11059        i != priv_->children_.end();
11060        ++i)
11061     // Look for the point where to insert the diff child node.
11062     if (!is_less_than(d.get(), *i))
11063       {
11064 	context()->keep_diff_alive(d);
11065 	priv_->children_.insert(i, d.get());
11066 	// As we have just inserted 'd' into the vector, the iterator
11067 	// 'i' is invalidated.  We must *NOT* use it anymore.
11068 	inserted = true;
11069 	break;
11070       }
11071 
11072   if (!inserted)
11073     {
11074       context()->keep_diff_alive(d);
11075       // We didn't insert anything to the vector, presumably b/c it was
11076       // empty or had one element that was "less than" 'd'.  We can thus
11077       // just append 'd' to the end of the vector.
11078       priv_->children_.push_back(d.get());
11079     }
11080 }
11081 
11082 /// @return the bare edit script of the functions changed as recorded
11083 /// by the diff.
11084 edit_script&
function_changes() const11085 corpus_diff::function_changes() const
11086 {return priv_->fns_edit_script_;}
11087 
11088 /// @return the bare edit script of the variables changed as recorded
11089 /// by the diff.
11090 edit_script&
variable_changes() const11091 corpus_diff::variable_changes() const
11092 {return priv_->vars_edit_script_;}
11093 
11094 /// Test if the soname of the underlying corpus has changed.
11095 ///
11096 /// @return true iff the soname has changed.
11097 bool
soname_changed() const11098 corpus_diff::soname_changed() const
11099 {return !priv_->sonames_equal_;}
11100 
11101 /// Test if the architecture of the underlying corpus has changed.
11102 ///
11103 /// @return true iff the architecture has changed.
11104 bool
architecture_changed() const11105 corpus_diff::architecture_changed() const
11106 {return !priv_->architectures_equal_;}
11107 
11108 /// Getter for the deleted functions of the diff.
11109 ///
11110 /// @return the the deleted functions of the diff.
11111 const string_function_ptr_map&
deleted_functions() const11112 corpus_diff::deleted_functions() const
11113 {return priv_->deleted_fns_;}
11114 
11115 /// Getter for the added functions of the diff.
11116 ///
11117 /// @return the added functions of the diff.
11118 const string_function_ptr_map&
added_functions()11119 corpus_diff::added_functions()
11120 {return priv_->added_fns_;}
11121 
11122 /// Getter for the functions which signature didn't change, but which
11123 /// do have some indirect changes in their parms.
11124 ///
11125 /// @return a non-sorted map of functions which signature didn't
11126 /// change, but which do have some indirect changes in their parms.
11127 /// The key of the map is a unique identifier for the function; it's
11128 /// usually made of the name and version of the underlying ELF symbol
11129 /// of the function for corpora that were built from ELF files.
11130 const string_function_decl_diff_sptr_map&
changed_functions()11131 corpus_diff::changed_functions()
11132 {return priv_->changed_fns_map_;}
11133 
11134 /// Getter for a sorted vector of functions which signature didn't
11135 /// change, but which do have some indirect changes in their parms.
11136 ///
11137 /// @return a sorted vector of functions which signature didn't
11138 /// change, but which do have some indirect changes in their parms.
11139 const function_decl_diff_sptrs_type&
changed_functions_sorted()11140 corpus_diff::changed_functions_sorted()
11141 {return priv_->changed_fns_;}
11142 
11143 /// Getter for the variables that got deleted from the first subject
11144 /// of the diff.
11145 ///
11146 /// @return the map of deleted variable.
11147 const string_var_ptr_map&
deleted_variables() const11148 corpus_diff::deleted_variables() const
11149 {return priv_->deleted_vars_;}
11150 
11151 /// Getter for the added variables of the diff.
11152 ///
11153 /// @return the map of added variable.
11154 const string_var_ptr_map&
added_variables() const11155 corpus_diff::added_variables() const
11156 {return priv_->added_vars_;}
11157 
11158 /// Getter for the non-sorted map of variables which signature didn't
11159 /// change but which do have some indirect changes in some sub-types.
11160 ///
11161 /// @return the non-sorted map of changed variables.
11162 const string_var_diff_sptr_map&
changed_variables()11163 corpus_diff::changed_variables()
11164 {return priv_->changed_vars_map_;}
11165 
11166 /// Getter for the sorted vector of variables which signature didn't
11167 /// change but which do have some indirect changes in some sub-types.
11168 ///
11169 /// @return a sorted vector of changed variables.
11170 const var_diff_sptrs_type&
changed_variables_sorted()11171 corpus_diff::changed_variables_sorted()
11172 {return priv_->sorted_changed_vars_;}
11173 
11174 /// Getter for function symbols not referenced by any debug info and
11175 /// that got deleted.
11176 ///
11177 /// @return a map of elf function symbols not referenced by any debug
11178 /// info and that got deleted.
11179 const string_elf_symbol_map&
deleted_unrefed_function_symbols() const11180 corpus_diff::deleted_unrefed_function_symbols() const
11181 {return priv_->deleted_unrefed_fn_syms_;}
11182 
11183 /// Getter for function symbols not referenced by any debug info and
11184 /// that got added.
11185 ///
11186 /// @return a map of elf function symbols not referenced by any debug
11187 /// info and that got added.
11188 const string_elf_symbol_map&
added_unrefed_function_symbols() const11189 corpus_diff::added_unrefed_function_symbols() const
11190 {return priv_->added_unrefed_fn_syms_;}
11191 
11192 /// Getter for variable symbols not referenced by any debug info and
11193 /// that got deleted.
11194 ///
11195 /// @return a map of elf variable symbols not referenced by any debug
11196 /// info and that got deleted.
11197 const string_elf_symbol_map&
deleted_unrefed_variable_symbols() const11198 corpus_diff::deleted_unrefed_variable_symbols() const
11199 {return priv_->deleted_unrefed_var_syms_;}
11200 
11201 /// Getter for variable symbols not referenced by any debug info and
11202 /// that got added.
11203 ///
11204 /// @return a map of elf variable symbols not referenced by any debug
11205 /// info and that got added.
11206 const string_elf_symbol_map&
added_unrefed_variable_symbols() const11207 corpus_diff::added_unrefed_variable_symbols() const
11208 {return priv_->added_unrefed_var_syms_;}
11209 
11210 /// Getter for a map of deleted types that are not reachable from
11211 /// global functions/variables.
11212 ///
11213 /// @return a map that associates pretty representation of deleted
11214 /// unreachable types and said types.
11215 const string_type_base_sptr_map&
deleted_unreachable_types() const11216 corpus_diff::deleted_unreachable_types() const
11217 {return priv_->deleted_unreachable_types_;}
11218 
11219 /// Getter of a sorted vector of deleted types that are not reachable
11220 /// from global functions/variables.
11221 ///
11222 /// @return a sorted vector of deleted types that are not reachable
11223 /// from global functions/variables.  The types are lexicographically
11224 /// sorted by considering their pretty representation.
11225 const vector<type_base_sptr>&
deleted_unreachable_types_sorted() const11226 corpus_diff::deleted_unreachable_types_sorted() const
11227 {
11228   if (priv_->deleted_unreachable_types_sorted_.empty())
11229     if (!priv_->deleted_unreachable_types_.empty())
11230       sort_string_type_base_sptr_map(priv_->deleted_unreachable_types_,
11231 				     priv_->deleted_unreachable_types_sorted_);
11232 
11233   return priv_->deleted_unreachable_types_sorted_;
11234 }
11235 
11236 /// Getter for a map of added types that are not reachable from global
11237 /// functions/variables.
11238 ///
11239 /// @return a map that associates pretty representation of added
11240 /// unreachable types and said types.
11241 const string_type_base_sptr_map&
added_unreachable_types() const11242 corpus_diff::added_unreachable_types() const
11243 {return priv_->added_unreachable_types_;}
11244 
11245 /// Getter of a sorted vector of added types that are not reachable
11246 /// from global functions/variables.
11247 ///
11248 /// @return a sorted vector of added types that are not reachable from
11249 /// global functions/variables.  The types are lexicographically
11250 /// sorted by considering their pretty representation.
11251 const vector<type_base_sptr>&
added_unreachable_types_sorted() const11252 corpus_diff::added_unreachable_types_sorted() const
11253 {
11254   if (priv_->added_unreachable_types_sorted_.empty())
11255     if (!priv_->added_unreachable_types_.empty())
11256       sort_string_type_base_sptr_map(priv_->added_unreachable_types_,
11257 				     priv_->added_unreachable_types_sorted_);
11258 
11259   return priv_->added_unreachable_types_sorted_;
11260 }
11261 
11262 /// Getter for a map of changed types that are not reachable from
11263 /// global functions/variables.
11264 ///
11265 /// @return a map that associates pretty representation of changed
11266 /// unreachable types and said types.
11267 const string_diff_sptr_map&
changed_unreachable_types() const11268 corpus_diff::changed_unreachable_types() const
11269 {return priv_->changed_unreachable_types_;}
11270 
11271 /// Getter of a sorted vector of changed types that are not reachable
11272 /// from global functions/variables.
11273 ///
11274 /// @return a sorted vector of changed types that are not reachable
11275 /// from global functions/variables.  The diffs are lexicographically
11276 /// sorted by considering their pretty representation.
11277 const vector<diff_sptr>&
changed_unreachable_types_sorted() const11278 corpus_diff::changed_unreachable_types_sorted() const
11279 {return priv_->changed_unreachable_types_sorted();}
11280 
11281 /// Getter of the diff context of this diff
11282 ///
11283 /// @return the diff context for this diff.
11284 const diff_context_sptr
context() const11285 corpus_diff::context() const
11286 {return priv_->get_context();}
11287 
11288 /// @return the pretty representation for the current instance of @ref
11289 /// corpus_diff
11290 const string&
get_pretty_representation() const11291 corpus_diff::get_pretty_representation() const
11292 {
11293   if (priv_->pretty_representation_.empty())
11294     {
11295       std::ostringstream o;
11296       o << "corpus_diff["
11297 	<< first_corpus()->get_path()
11298 	<< ", "
11299 	<< second_corpus()->get_path()
11300 	<< "]";
11301       priv_->pretty_representation_ = o.str();
11302     }
11303   return priv_->pretty_representation_;
11304 }
11305 /// Return true iff the current @ref corpus_diff node carries a
11306 /// change.
11307 ///
11308 /// @return true iff the current diff node carries a change.
11309 bool
has_changes() const11310 corpus_diff::has_changes() const
11311 {
11312   return (soname_changed()
11313 	  || architecture_changed()
11314 	  || !(priv_->deleted_fns_.empty()
11315 	       && priv_->added_fns_.empty()
11316 	       && priv_->changed_fns_map_.empty()
11317 	       && priv_->deleted_vars_.empty()
11318 	       && priv_->added_vars_.empty()
11319 	       && priv_->changed_vars_map_.empty()
11320 	       && priv_->added_unrefed_fn_syms_.empty()
11321 	       && priv_->deleted_unrefed_fn_syms_.empty()
11322 	       && priv_->added_unrefed_var_syms_.empty()
11323 	       && priv_->deleted_unrefed_var_syms_.empty()
11324 	       && priv_->deleted_unreachable_types_.empty()
11325 	       && priv_->added_unreachable_types_.empty()
11326 	       && priv_->changed_unreachable_types_.empty()));
11327 }
11328 
11329 /// Test if the current instance of @ref corpus_diff carries changes
11330 /// that we are sure are incompatible.  By incompatible change we mean
11331 /// a change that "breaks" the ABI of the corpus we are looking at.
11332 ///
11333 /// In concrete terms, this function considers the following changes
11334 /// as being ABI incompatible for sure:
11335 ///
11336 ///   - a soname change
11337 ///   - if exported functions or variables got removed
11338 ///
11339 /// Note that subtype changes *can* represent changes that break ABI
11340 /// too.  But they also can be changes that are OK, ABI-wise.
11341 ///
11342 /// It's up to the user to provide suppression specifications to say
11343 /// explicitely which subtype change is OK.  The remaining sub-type
11344 /// changes are then considered to be ABI incompatible.  But to test
11345 /// if such ABI incompatible subtype changes are present you need to
11346 /// use the function @ref corpus_diff::has_net_subtype_changes()
11347 ///
11348 /// @return true iff the current instance of @ref corpus_diff carries
11349 /// changes that we are sure are ABI incompatible.
11350 bool
has_incompatible_changes() const11351 corpus_diff::has_incompatible_changes() const
11352 {
11353   const diff_stats& stats = const_cast<corpus_diff*>(this)->
11354     apply_filters_and_suppressions_before_reporting();
11355 
11356   bool has_incompatible_changes  =
11357     (soname_changed() || architecture_changed()
11358 	  || stats.net_num_func_removed() != 0
11359 	  || (stats.num_func_with_virtual_offset_changes() != 0
11360 	      // If all reports about functions with sub-type changes
11361 	      // have been suppressed, then even those about functions
11362 	      // that are virtual don't matter anymore because the
11363 	      // user willingly requested to shut them down
11364 	      && stats.net_num_func_changed() != 0)
11365 	  || stats.net_num_vars_removed() != 0
11366 	  || stats.net_num_removed_func_syms() != 0
11367 	  || stats.net_num_removed_var_syms() != 0
11368 	  || stats.net_num_removed_unreachable_types() != 0);
11369 
11370   // If stats.net_num_changed_unreachable_types() != 0 then walk the
11371   // corpus_diff::priv::changed_unreachable_types_, and see if there
11372   // is one that is harmful by bitwise and-ing their category with
11373   // abigail::comparison::get_default_harmful_categories_bitmap().
11374   if (!has_incompatible_changes
11375       && stats.net_num_changed_unreachable_types())
11376     {
11377       // The changed unreachable types can carry harmful changes.
11378       // Let's figure if they actually do.
11379 
11380       diff_context_sptr ctxt = context();
11381       for (auto &entry : priv_->changed_unreachable_types())
11382 	{
11383 	  diff_sptr dif = entry.second;
11384 
11385 	  // Let's see if any of the categories of this diff node
11386 	  // belong to the "harmful" ones.
11387 	  if (dif->get_category() & get_default_harmful_categories_bitmap())
11388 	    {
11389 	      has_incompatible_changes |= true;
11390 	      break;
11391 	    }
11392 	}
11393     }
11394 
11395   return has_incompatible_changes;
11396 }
11397 
11398 /// Test if the current instance of @ref corpus_diff carries subtype
11399 /// changes whose reports are not suppressed by any suppression
11400 /// specification.  In effect, these are deemed incompatible ABI
11401 /// changes.
11402 ///
11403 /// @return true iff the the current instance of @ref corpus_diff
11404 /// carries subtype changes that are deemed incompatible ABI changes.
11405 bool
has_net_subtype_changes() const11406 corpus_diff::has_net_subtype_changes() const
11407 {
11408   const diff_stats& stats = const_cast<corpus_diff*>(this)->
11409       apply_filters_and_suppressions_before_reporting();
11410 
11411   return (stats.net_num_func_changed() != 0
11412 	  || stats.net_num_vars_changed() != 0
11413 	  || stats.net_num_removed_unreachable_types() != 0
11414 	  || stats.net_num_changed_unreachable_types() != 0);
11415 }
11416 
11417 /// Test if the current instance of @ref corpus_diff carries changes
11418 /// whose reports are not suppressed by any suppression specification.
11419 /// In effect, these are deemed incompatible ABI changes.
11420 ///
11421 /// @return true iff the the current instance of @ref corpus_diff
11422 /// carries subtype changes that are deemed incompatible ABI changes.
11423 bool
has_net_changes() const11424 corpus_diff::has_net_changes() const
11425 {return  context()->get_reporter()->diff_has_net_changes(this);}
11426 
11427 /// Apply the different filters that are registered to be applied to
11428 /// the diff tree; that includes the categorization filters.  Also,
11429 /// apply the suppression interpretation filters.
11430 ///
11431 /// After the filters are applied, this function calculates some
11432 /// statistics about the changes carried by the current instance of
11433 /// @ref corpus_diff.  These statistics are represented by an instance
11434 /// of @ref corpus_diff::diff_stats.
11435 ///
11436 /// This member function is called by the reporting function
11437 /// corpus_diff::report().
11438 ///
11439 /// Note that for a given instance of corpus_diff, this function
11440 /// applies the filters and suppressions only the first time it is
11441 /// invoked.  Subsequent invocations just return the instance of
11442 /// corpus_diff::diff_stats that was cached after the first
11443 /// invocation.
11444 ///
11445 /// @return a reference to the statistics about the changes carried by
11446 /// the current instance of @ref corpus_diff.
11447 const corpus_diff::diff_stats&
apply_filters_and_suppressions_before_reporting()11448 corpus_diff::apply_filters_and_suppressions_before_reporting()
11449 {
11450   if (priv_->diff_stats_)
11451     return *priv_->diff_stats_;
11452 
11453   tools_utils::timer t;
11454   if (do_log())
11455     {
11456       std::cerr << "Applying suppressions ...\n";
11457       t.start();
11458     }
11459 
11460   apply_suppressions(this);
11461 
11462   if (do_log())
11463     {
11464       t.stop();
11465       std::cerr << "suppressions applied!:" << t << "\n";
11466     }
11467 
11468   priv_->diff_stats_.reset(new diff_stats(context()));
11469 
11470   if (do_log())
11471     {
11472       std::cerr << "Marking leaf nodes ...\n";
11473       t.start();
11474     }
11475 
11476   mark_leaf_diff_nodes();
11477 
11478   if (do_log())
11479     {
11480       t.stop();
11481       std::cerr << "leaf nodes marked!:" << t << "\n";
11482       std::cerr << "Applying filters and computing diff stats ...\n";
11483       t.start();
11484     }
11485 
11486   priv_->apply_filters_and_compute_diff_stats(*priv_->diff_stats_);
11487 
11488   if (do_log())
11489     {
11490       t.stop();
11491       std::cerr << "Filters applied and diff stats computed!: " << t << "\n";
11492     }
11493 
11494   return *priv_->diff_stats_;
11495 }
11496 
11497 /// A visitor that marks leaf diff nodes by storing them in the
11498 /// instance of @ref diff_maps returned by
11499 /// corpus_diff::get_leaf_diffs() invoked on the current instance of
11500 /// corpus_diff.
11501 struct leaf_diff_node_marker_visitor : public diff_node_visitor
11502 {
11503   /// This is called when the visitor visits a diff node.
11504   ///
11505   /// It basically tests if the diff node being visited is a leaf diff
11506   /// node - that is, it contains local changes.  If it does, then the
11507   /// node is added to the set of maps that hold leaf diffs in the
11508   /// current corpus_diff.
11509   ///
11510   /// Note that only leaf nodes that are reachable from public
11511   /// interfaces (global functions or variables) are collected by this
11512   /// visitor.
11513   ///
11514   /// @param d the diff node being visited.
11515   virtual void
visit_beginabigail::comparison::leaf_diff_node_marker_visitor11516   visit_begin(diff *d)
11517   {
11518     if (d->has_local_changes()
11519 	// A leaf basic (or class/union) type name change makes no
11520 	// sense when showing just leaf changes.  It only makes sense
11521 	// when it can explain the details about a non-leaf change.
11522 	// In other words, it doesn't make sense to say that an "int"
11523 	// became "unsigned int".  But it does make sense to say that
11524 	// a typedef changed because its underlying type was 'int' and
11525 	// is now an "unsigned int".
11526 	&& !filtering::has_basic_or_class_type_name_change(d)
11527 	// Similarly, a *local* change describing a type that changed
11528 	// its nature doesn't make sense.
11529 	&& !is_distinct_diff(d)
11530 	// Similarly, a pointer (or reference or array), a typedef or
11531 	// qualified type change in itself doesn't make sense.  It
11532 	// would rather make sense to show that pointer change as part
11533 	// of the variable change whose pointer type changed, for
11534 	// instance.
11535 	&& !is_pointer_diff(d)
11536 	&& !is_reference_diff(d)
11537 	&& !is_qualified_type_diff(d)
11538 	&& !is_typedef_diff(d)
11539 	&& !is_array_diff(d)
11540 	// Similarly a parameter change in itself doesn't make sense.
11541 	// It should have already been reported as part of the change
11542 	// of the function it belongs to.
11543 	&& !is_fn_parm_diff(d)
11544 	// An anonymous class or union diff doesn't make sense on its
11545 	// own.  It must have been described already by the diff of
11546 	// the enclosing struct or union if 'd' is from an anonymous
11547 	// data member, or from a typedef change if 'd' is from a
11548 	// typedef change which underlying type is an anonymous
11549 	// struct/union.
11550 	&& !is_anonymous_class_or_union_diff(d)
11551 	// Don't show decl-only-ness changes either.
11552 	&& !filtering::has_decl_only_def_change(d)
11553 	// Sometime, we can encounter artifacts of bogus DWARF that
11554 	// yield a diff node for a decl-only class (and empty class
11555 	// with the is_declaration flag set) that carries a non-zero
11556 	// size!  And of course at some point that non-zero size
11557 	// changes.  We need to be able to detect that.
11558 	&& !filtering::is_decl_only_class_with_size_change(d))
11559       {
11560 	diff_context_sptr ctxt = d->context();
11561 	const corpus_diff *corpus_diff_node = ctxt->get_corpus_diff().get();
11562 	ABG_ASSERT(corpus_diff_node);
11563 
11564 	if (diff *iface_diff = get_current_topmost_iface_diff())
11565 	  {
11566 	    type_or_decl_base_sptr iface = iface_diff->first_subject();
11567 	    // So, this diff node that is reachable from a global
11568 	    // function or variable carries a leaf change.  Let's add
11569 	    // it to the set of of leaf diffs of corpus_diff_node.
11570 	    const_cast<corpus_diff*>(corpus_diff_node)->
11571 	      get_leaf_diffs().insert_diff_node(d, iface);
11572 	  }
11573       }
11574   }
11575 }; // end struct leaf_diff_node_marker_visitor
11576 
11577 /// Walks the diff nodes associated to the current corpus diff and
11578 /// mark those that carry local changes.  They are said to be leaf
11579 /// diff nodes.
11580 ///
11581 /// The marked nodes are available from the
11582 /// corpus_diff::get_leaf_diffs() function.
11583 void
mark_leaf_diff_nodes()11584 corpus_diff::mark_leaf_diff_nodes()
11585 {
11586   if (!has_changes())
11587     return;
11588 
11589   if (!context()->show_leaf_changes_only())
11590     return;
11591 
11592   leaf_diff_node_marker_visitor v;
11593   context()->forget_visited_diffs();
11594   bool s = context()->visiting_a_node_twice_is_forbidden();
11595   context()->forbid_visiting_a_node_twice(true);
11596   if (context()->show_impacted_interfaces())
11597     context()->forbid_visiting_a_node_twice_per_interface(true);
11598   traverse(v);
11599   context()->forbid_visiting_a_node_twice(s);
11600   context()->forbid_visiting_a_node_twice_per_interface(false);
11601 }
11602 
11603 /// Get the set of maps that contain leaf nodes.  A leaf node being a
11604 /// node with a local change.
11605 ///
11606 /// @return the set of maps that contain leaf nodes.  A leaf node
11607 /// being a node with a local change.
11608 diff_maps&
get_leaf_diffs()11609 corpus_diff::get_leaf_diffs()
11610 {return priv_->leaf_diffs_;}
11611 
11612 /// Get the set of maps that contain leaf nodes.  A leaf node being a
11613 /// node with a local change.
11614 ///
11615 /// @return the set of maps that contain leaf nodes.  A leaf node
11616 /// being a node with a local change.
11617 const diff_maps&
get_leaf_diffs() const11618 corpus_diff::get_leaf_diffs() const
11619 {return priv_->leaf_diffs_;}
11620 
11621 /// Report the diff in a serialized form.
11622 ///
11623 /// @param out the stream to serialize the diff to.
11624 ///
11625 /// @param indent the prefix to use for the indentation of this
11626 /// serialization.
11627 void
report(ostream & out,const string & indent) const11628 corpus_diff::report(ostream& out, const string& indent) const
11629 {
11630   context()->get_reporter()->report(*this, out, indent);
11631 }
11632 
11633 /// Traverse the diff sub-tree under the current instance corpus_diff.
11634 ///
11635 /// @param v the visitor to invoke on each diff node of the sub-tree.
11636 ///
11637 /// @return true if the traversing has to keep going on, false otherwise.
11638 bool
traverse(diff_node_visitor & v)11639 corpus_diff::traverse(diff_node_visitor& v)
11640 {
11641   finish_diff_type();
11642 
11643   v.visit_begin(this);
11644 
11645   if (!v.visit(this, true))
11646     {
11647       v.visit_end(this);
11648       return false;
11649     }
11650 
11651   for (function_decl_diff_sptrs_type::const_iterator i =
11652 	 changed_functions_sorted().begin();
11653        i != changed_functions_sorted().end();
11654        ++i)
11655     {
11656       if (diff_sptr d = *i)
11657 	{
11658 	  const diff_context_sptr &ctxt = context();
11659 	  if (ctxt->visiting_a_node_twice_is_forbidden_per_interface())
11660 	    ctxt->forget_visited_diffs();
11661 
11662 	  v.set_current_topmost_iface_diff(d.get());
11663 
11664 	  if (!d->traverse(v))
11665 	    {
11666 	      v.visit_end(this);
11667 	      v.set_current_topmost_iface_diff(0);
11668 	      return false;
11669 	    }
11670 	}
11671     }
11672 
11673   for (var_diff_sptrs_type::const_iterator i =
11674 	 changed_variables_sorted().begin();
11675        i != changed_variables_sorted().end();
11676        ++i)
11677     {
11678       if (diff_sptr d = *i)
11679 	{
11680 	  const diff_context_sptr &ctxt = context();
11681 	  if (ctxt->visiting_a_node_twice_is_forbidden_per_interface())
11682 	    ctxt->forget_visited_diffs();
11683 
11684 	  v.set_current_topmost_iface_diff(d.get());
11685 
11686 	  if (!d->traverse(v))
11687 	    {
11688 	      v.visit_end(this);
11689 	      v.set_current_topmost_iface_diff(0);
11690 	      return false;
11691 	    }
11692 	}
11693     }
11694 
11695   v.set_current_topmost_iface_diff(0);
11696 
11697   // Traverse the changed unreachable type diffs.  These diffs are on
11698   // types that are not reachable from global functions or variables.
11699   for (vector<diff_sptr>::const_iterator i =
11700 	 changed_unreachable_types_sorted().begin();
11701        i != changed_unreachable_types_sorted().end();
11702        ++i)
11703     {
11704       if (diff_sptr d = *i)
11705 	{
11706 	  const diff_context_sptr &ctxt = context();
11707 	  if (ctxt->visiting_a_node_twice_is_forbidden_per_interface())
11708 	    ctxt->forget_visited_diffs();
11709 
11710 	  if (!d->traverse(v))
11711 	    {
11712 	      v.visit_end(this);
11713 	      return false;
11714 	    }
11715 	}
11716     }
11717 
11718   v.visit_end(this);
11719   return true;
11720 }
11721 
11722 /// Compute the diff between two instances of @ref corpus.
11723 ///
11724 /// Note that the two corpora must have been created in the same @ref
11725 /// environment, otherwise, this function aborts.
11726 ///
11727 /// @param f the first @ref corpus to consider for the diff.
11728 ///
11729 /// @param s the second @ref corpus to consider for the diff.
11730 ///
11731 /// @param ctxt the diff context to use.
11732 ///
11733 /// @return the resulting diff between the two @ref corpus.
11734 corpus_diff_sptr
compute_diff(const corpus_sptr f,const corpus_sptr s,diff_context_sptr ctxt)11735 compute_diff(const corpus_sptr	f,
11736 	     const corpus_sptr	s,
11737 	     diff_context_sptr	ctxt)
11738 {
11739   typedef corpus::functions::const_iterator fns_it_type;
11740   typedef corpus::variables::const_iterator vars_it_type;
11741   typedef elf_symbols::const_iterator symbols_it_type;
11742   typedef diff_utils::deep_ptr_eq_functor eq_type;
11743   typedef vector<type_base_wptr>::const_iterator type_base_wptr_it_type;
11744 
11745   ABG_ASSERT(f && s);
11746 
11747   if (!ctxt)
11748     ctxt.reset(new diff_context);
11749 
11750   corpus_diff_sptr r(new corpus_diff(f, s, ctxt));
11751 
11752   ctxt->set_corpus_diff(r);
11753 
11754   if(ctxt->show_soname_change())
11755     r->priv_->sonames_equal_ = f->get_soname() == s->get_soname();
11756   else
11757     r->priv_->sonames_equal_ = true;
11758 
11759   r->priv_->architectures_equal_ =
11760     f->get_architecture_name() == s->get_architecture_name();
11761 
11762   // Compute the diff of publicly defined and exported functions
11763   diff_utils::compute_diff<fns_it_type, eq_type>(f->get_functions().begin(),
11764 						 f->get_functions().end(),
11765 						 s->get_functions().begin(),
11766 						 s->get_functions().end(),
11767 						 r->priv_->fns_edit_script_);
11768 
11769   // Compute the diff of publicly defined and exported variables.
11770   diff_utils::compute_diff<vars_it_type, eq_type>
11771     (f->get_variables().begin(), f->get_variables().end(),
11772      s->get_variables().begin(), s->get_variables().end(),
11773      r->priv_->vars_edit_script_);
11774 
11775   // Compute the diff of function elf symbols not referenced by debug
11776   // info.
11777   diff_utils::compute_diff<symbols_it_type, eq_type>
11778     (f->get_unreferenced_function_symbols().begin(),
11779      f->get_unreferenced_function_symbols().end(),
11780      s->get_unreferenced_function_symbols().begin(),
11781      s->get_unreferenced_function_symbols().end(),
11782      r->priv_->unrefed_fn_syms_edit_script_);
11783 
11784   // Compute the diff of variable elf symbols not referenced by debug
11785   // info.
11786     diff_utils::compute_diff<symbols_it_type, eq_type>
11787     (f->get_unreferenced_variable_symbols().begin(),
11788      f->get_unreferenced_variable_symbols().end(),
11789      s->get_unreferenced_variable_symbols().begin(),
11790      s->get_unreferenced_variable_symbols().end(),
11791      r->priv_->unrefed_var_syms_edit_script_);
11792 
11793     if (ctxt->show_unreachable_types())
11794       // Compute the diff of types not reachable from public functions
11795       // or global variables that are exported.
11796       diff_utils::compute_diff<type_base_wptr_it_type, eq_type>
11797 	(f->get_types_not_reachable_from_public_interfaces().begin(),
11798 	 f->get_types_not_reachable_from_public_interfaces().end(),
11799 	 s->get_types_not_reachable_from_public_interfaces().begin(),
11800 	 s->get_types_not_reachable_from_public_interfaces().end(),
11801 	 r->priv_->unreachable_types_edit_script_);
11802 
11803   r->priv_->ensure_lookup_tables_populated();
11804 
11805   return r;
11806 }
11807 
11808 // </corpus stuff>
11809 
11810 /// Compute the diff between two instances of @ref corpus_group.
11811 ///
11812 /// Note that the two corpus_diff must have been created in the same
11813 /// @ref environment, otherwise, this function aborts.
11814 ///
11815 /// @param f the first @ref corpus_group to consider for the diff.
11816 ///
11817 /// @param s the second @ref corpus_group to consider for the diff.
11818 ///
11819 /// @param ctxt the diff context to use.
11820 ///
11821 /// @return the resulting diff between the two @ref corpus_group.
11822 corpus_diff_sptr
compute_diff(const corpus_group_sptr & f,const corpus_group_sptr & s,diff_context_sptr ctxt)11823 compute_diff(const corpus_group_sptr&	f,
11824 	     const corpus_group_sptr&	s,
11825 	     diff_context_sptr	ctxt)
11826 {
11827 
11828   corpus_sptr c1 = f;
11829   corpus_sptr c2 = s;
11830 
11831   return compute_diff(c1, c2, ctxt);
11832 }
11833 
11834 // <corpus_group stuff>
11835 
11836 // </corpus_group stuff>
11837 // <diff_node_visitor stuff>
11838 
11839 /// The private data of the @diff_node_visitor type.
11840 struct diff_node_visitor::priv
11841 {
11842   diff*	topmost_interface_diff;
11843   visiting_kind kind;
11844 
privabigail::comparison::diff_node_visitor::priv11845   priv()
11846     : topmost_interface_diff(),
11847       kind()
11848   {}
11849 
privabigail::comparison::diff_node_visitor::priv11850   priv(visiting_kind k)
11851     : topmost_interface_diff(),
11852       kind(k)
11853   {}
11854 }; // end struct diff_node_visitor
11855 
11856 /// Default constructor of the @ref diff_node_visitor type.
diff_node_visitor()11857 diff_node_visitor::diff_node_visitor()
11858   : priv_(new priv)
11859 {}
11860 
11861 diff_node_visitor::~diff_node_visitor() = default;
11862 
11863 /// Constructor of the @ref diff_node_visitor type.
11864 ///
11865 /// @param k how the visiting has to be performed.
diff_node_visitor(visiting_kind k)11866 diff_node_visitor::diff_node_visitor(visiting_kind k)
11867   : priv_(new priv(k))
11868 {}
11869 
11870 /// Getter for the visiting policy of the traversing code while
11871 /// invoking this visitor.
11872 ///
11873 /// @return the visiting policy used by the traversing code when
11874 /// invoking this visitor.
11875 visiting_kind
get_visiting_kind() const11876 diff_node_visitor::get_visiting_kind() const
11877 {return priv_->kind;}
11878 
11879 /// Setter for the visiting policy of the traversing code while
11880 /// invoking this visitor.
11881 ///
11882 /// @param v a bit map representing the new visiting policy used by
11883 /// the traversing code when invoking this visitor.
11884 void
set_visiting_kind(visiting_kind v)11885 diff_node_visitor::set_visiting_kind(visiting_kind v)
11886 {priv_->kind = v;}
11887 
11888 /// Setter for the visiting policy of the traversing code while
11889 /// invoking this visitor.  This one makes a logical or between the
11890 /// current policy and the bitmap given in argument and assigns the
11891 /// current policy to the result.
11892 ///
11893 /// @param v a bitmap representing the visiting policy to or with
11894 /// the current policy.
11895 void
or_visiting_kind(visiting_kind v)11896 diff_node_visitor::or_visiting_kind(visiting_kind v)
11897 {priv_->kind = priv_->kind | v;}
11898 
11899 /// Setter of the diff current topmost interface which is impacted by
11900 /// the current diff node being visited.
11901 ///
11902 /// @param d the current topmost interface diff impacted.
11903 void
set_current_topmost_iface_diff(diff * d)11904 diff_node_visitor::set_current_topmost_iface_diff(diff* d)
11905 {priv_->topmost_interface_diff = d;}
11906 
11907 /// Getter of the diff current topmost interface which is impacted by
11908 /// the current diff node being visited.
11909 ///
11910 /// @return the current topmost interface diff impacted.
11911 diff*
get_current_topmost_iface_diff() const11912 diff_node_visitor::get_current_topmost_iface_diff() const
11913 {return priv_->topmost_interface_diff;}
11914 
11915 /// This is called by the traversing code on a @ref diff node just
11916 /// before visiting it.  That is, before visiting it and its children
11917 /// node.
11918 ///
11919 /// @param d the diff node to visit.
11920 void
visit_begin(diff *)11921 diff_node_visitor::visit_begin(diff* /*p*/)
11922 {}
11923 
11924 /// This is called by the traversing code on a @ref diff node just
11925 /// after visiting it.  That is after visiting it and its children
11926 /// nodes.
11927 ///
11928 /// @param d the diff node that got visited.
11929 void
visit_end(diff *)11930 diff_node_visitor::visit_end(diff* /*p*/)
11931 {}
11932 
11933 /// This is called by the traversing code on a @ref corpus_diff node
11934 /// just before visiting it.  That is, before visiting it and its
11935 /// children node.
11936 ///
11937 /// @param p the corpus_diff node to visit.
11938 ///
11939 void
visit_begin(corpus_diff *)11940 diff_node_visitor::visit_begin(corpus_diff* /*p*/)
11941 {}
11942 
11943 /// This is called by the traversing code on a @ref corpus_diff node
11944 /// just after visiting it.  That is after visiting it and its children
11945 /// nodes.
11946 ///
11947 /// @param d the diff node that got visited.
11948 void
visit_end(corpus_diff *)11949 diff_node_visitor::visit_end(corpus_diff* /*d*/)
11950 {}
11951 
11952 /// Default visitor implementation
11953 ///
11954 /// @return true
11955 bool
visit(diff *,bool)11956 diff_node_visitor::visit(diff*, bool)
11957 {return true;}
11958 
11959 /// Default visitor implementation.
11960 ///
11961 /// @return true
11962 bool
visit(distinct_diff * dif,bool pre)11963 diff_node_visitor::visit(distinct_diff* dif, bool pre)
11964 {
11965   diff* d = dif;
11966   visit(d, pre);
11967 
11968   return true;
11969 }
11970 
11971 /// Default visitor implementation.
11972 ///
11973 /// @return true
11974 bool
visit(var_diff * dif,bool pre)11975 diff_node_visitor::visit(var_diff* dif, bool pre)
11976 {
11977   diff* d = dif;
11978   visit(d, pre);
11979 
11980   return true;
11981 }
11982 
11983 /// Default visitor implementation.
11984 ///
11985 /// @return true
11986 bool
visit(pointer_diff * dif,bool pre)11987 diff_node_visitor::visit(pointer_diff* dif, bool pre)
11988 {
11989   diff* d = dif;
11990   visit(d, pre);
11991 
11992   return true;
11993 }
11994 
11995 /// Default visitor implementation.
11996 ///
11997 /// @return true
11998 bool
visit(reference_diff * dif,bool pre)11999 diff_node_visitor::visit(reference_diff* dif, bool pre)
12000 {
12001   diff* d = dif;
12002   visit(d, pre);
12003 
12004   return true;
12005 }
12006 
12007 /// Default visitor implementation.
12008 ///
12009 /// @return true
12010 bool
visit(qualified_type_diff * dif,bool pre)12011 diff_node_visitor::visit(qualified_type_diff* dif, bool pre)
12012 {
12013   diff* d = dif;
12014   visit(d, pre);
12015 
12016   return true;
12017 }
12018 
12019 /// Default visitor implementation.
12020 ///
12021 /// @return true
12022 bool
visit(enum_diff * dif,bool pre)12023 diff_node_visitor::visit(enum_diff* dif, bool pre)
12024 {
12025   diff* d = dif;
12026   visit(d, pre);
12027 
12028   return true;
12029 }
12030 
12031 /// Default visitor implementation.
12032 ///
12033 /// @return true
12034 bool
visit(class_diff * dif,bool pre)12035 diff_node_visitor::visit(class_diff* dif, bool pre)
12036 {
12037   diff* d = dif;
12038   visit(d, pre);
12039 
12040   return true;
12041 }
12042 
12043 /// Default visitor implementation.
12044 ///
12045 /// @return true
12046 bool
visit(base_diff * dif,bool pre)12047 diff_node_visitor::visit(base_diff* dif, bool pre)
12048 {
12049   diff* d = dif;
12050   visit(d, pre);
12051 
12052   return true;
12053 }
12054 
12055 /// Default visitor implementation.
12056 ///
12057 /// @return true
12058 bool
visit(scope_diff * dif,bool pre)12059 diff_node_visitor::visit(scope_diff* dif, bool pre)
12060 {
12061   diff* d = dif;
12062   visit(d, pre);
12063 
12064   return true;
12065 }
12066 
12067 /// Default visitor implementation.
12068 ///
12069 /// @return true
12070 bool
visit(function_decl_diff * dif,bool pre)12071 diff_node_visitor::visit(function_decl_diff* dif, bool pre)
12072 {
12073   diff* d = dif;
12074   visit(d, pre);
12075 
12076   return true;
12077 }
12078 
12079 /// Default visitor implementation.
12080 ///
12081 /// @return true
12082 bool
visit(type_decl_diff * dif,bool pre)12083 diff_node_visitor::visit(type_decl_diff* dif, bool pre)
12084 {
12085   diff* d = dif;
12086   visit(d, pre);
12087 
12088   return true;
12089 }
12090 
12091 /// Default visitor implementation.
12092 ///
12093 /// @return true
12094 bool
visit(typedef_diff * dif,bool pre)12095 diff_node_visitor::visit(typedef_diff* dif, bool pre)
12096 {
12097   diff* d = dif;
12098   visit(d, pre);
12099 
12100   return true;
12101 }
12102 
12103 /// Default visitor implementation.
12104 ///
12105 /// @return true
12106 bool
visit(translation_unit_diff * dif,bool pre)12107 diff_node_visitor::visit(translation_unit_diff* dif, bool pre)
12108 {
12109   diff* d = dif;
12110   visit(d, pre);
12111 
12112   return true;
12113 }
12114 
12115 /// Default visitor implementation.
12116 ///
12117 /// @return true
12118 bool
visit(corpus_diff *,bool)12119 diff_node_visitor::visit(corpus_diff*, bool)
12120 {return true;}
12121 
12122 // </diff_node_visitor stuff>
12123 
12124 // <redundant diff node marking>
12125 
12126 // </redundant diff node marking>
12127 
12128 // <diff tree category propagation>
12129 
12130 /// A visitor to propagate the category of a node up to its parent
12131 /// nodes.  This visitor doesn't touch the REDUNDANT_CATEGORY or the
12132 /// SUPPRESSED_CATEGORY because those are propagated using other
12133 /// specific visitors.
12134 struct category_propagation_visitor : public diff_node_visitor
12135 {
12136   virtual void
visit_endabigail::comparison::category_propagation_visitor12137   visit_end(diff* d)
12138   {
12139     // Has this diff node 'd' been already visited ?
12140     bool already_visited = d->context()->diff_has_been_visited(d);
12141 
12142     // The canonical diff node of the class of equivalence of the diff
12143     // node 'd'.
12144     diff* canonical = d->get_canonical_diff();
12145 
12146     // If this class of equivalence of diff node is being visited for
12147     // the first time, then update its canonical node's category too.
12148     bool update_canonical = !already_visited && canonical;
12149 
12150     for (vector<diff*>::const_iterator i = d->children_nodes().begin();
12151 	 i != d->children_nodes().end();
12152 	 ++i)
12153       {
12154 	// If we are visiting the class of equivalence of 'd' for the
12155 	// first time, then let's look at the children of 'd' and
12156 	// propagate their categories to 'd'.
12157 	//
12158 	// If the class of equivalence of 'd' has already been
12159 	// visited, then let's look at the canonical diff nodes of the
12160 	// children of 'd' and propagate their categories to 'd'.
12161 	diff* diff = already_visited
12162 	  ? (*i)->get_canonical_diff()
12163 	  : *i;
12164 
12165 	ABG_ASSERT(diff);
12166 
12167 	diff_category c = diff->get_category();
12168 	// Do not propagate redundant and suppressed categories. Those
12169 	// are propagated in a specific pass elsewhere.
12170 	c &= ~(REDUNDANT_CATEGORY
12171 	       | SUPPRESSED_CATEGORY
12172 	       | PRIVATE_TYPE_CATEGORY
12173 	       | HAS_ALLOWED_CHANGE_CATEGORY
12174 	       | HAS_DESCENDANT_WITH_ALLOWED_CHANGE_CATEGORY
12175 	       | HAS_PARENT_WITH_ALLOWED_CHANGE_CATEGORY);
12176 	// Also, if a (class) type has got a harmful name change, do not
12177 	// propagate harmless name changes coming from its sub-types
12178 	// (i.e, data members) to the class itself.
12179 	if (filtering::has_harmful_name_change(d))
12180 	  c &= ~HARMLESS_DECL_NAME_CHANGE_CATEGORY;
12181 
12182 	d->add_to_category(c);
12183 	if (!already_visited && canonical)
12184 	  if (update_canonical)
12185 	    canonical->add_to_category(c);
12186       }
12187   }
12188 };// end struct category_propagation_visitor
12189 
12190 /// Visit all the nodes of a given sub-tree.  For each node that has a
12191 /// particular category set, propagate that category set up to its
12192 /// parent nodes.
12193 ///
12194 /// @param diff_tree the diff sub-tree to walk for categorization
12195 /// purpose;
12196 void
propagate_categories(diff * diff_tree)12197 propagate_categories(diff* diff_tree)
12198 {
12199   category_propagation_visitor v;
12200   bool s = diff_tree->context()->visiting_a_node_twice_is_forbidden();
12201   diff_tree->context()->forbid_visiting_a_node_twice(true);
12202   diff_tree->context()->forget_visited_diffs();
12203   diff_tree->traverse(v);
12204   diff_tree->context()->forbid_visiting_a_node_twice(s);
12205 }
12206 
12207 /// Visit all the nodes of a given sub-tree.  For each node that has a
12208 /// particular category set, propagate that category set up to its
12209 /// parent nodes.
12210 ///
12211 /// @param diff_tree the diff sub-tree to walk for categorization
12212 /// purpose;
12213 void
propagate_categories(diff_sptr diff_tree)12214 propagate_categories(diff_sptr diff_tree)
12215 {propagate_categories(diff_tree.get());}
12216 
12217 /// Visit all the nodes of a given corpus tree.  For each node that
12218 /// has a particular category set, propagate that category set up to
12219 /// its parent nodes.
12220 ///
12221 /// @param diff_tree the corpus_diff tree to walk for categorization
12222 /// purpose;
12223 void
propagate_categories(corpus_diff * diff_tree)12224 propagate_categories(corpus_diff* diff_tree)
12225 {
12226   category_propagation_visitor v;
12227   bool s = diff_tree->context()->visiting_a_node_twice_is_forbidden();
12228   diff_tree->context()->forbid_visiting_a_node_twice(false);
12229   diff_tree->traverse(v);
12230   diff_tree->context()->forbid_visiting_a_node_twice(s);
12231 }
12232 
12233 /// Visit all the nodes of a given corpus tree.  For each node that
12234 /// has a particular category set, propagate that category set up to
12235 /// its parent nodes.
12236 ///
12237 /// @param diff_tree the corpus_diff tree to walk for categorization
12238 /// purpose;
12239 void
propagate_categories(corpus_diff_sptr diff_tree)12240 propagate_categories(corpus_diff_sptr diff_tree)
12241 {propagate_categories(diff_tree.get());}
12242 
12243 /// A tree node visitor that knows how to categorizes a given diff
12244 /// node in the SUPPRESSED_CATEGORY category and how to propagate that
12245 /// categorization.
12246 struct suppression_categorization_visitor : public diff_node_visitor
12247 {
12248 
12249   /// Before visiting the children of the diff node, check if the node
12250   /// is suppressed by a suppression specification.  If it is, mark
12251   /// the node as belonging to the SUPPRESSED_CATEGORY category.
12252   ///
12253   /// @param p the diff node to visit.
12254   virtual void
visit_beginabigail::comparison::suppression_categorization_visitor12255   visit_begin(diff* d)
12256   {
12257     bool is_private_type = false;
12258     if (d->is_suppressed(is_private_type))
12259       {
12260 	diff_category c = is_private_type
12261 	  ? PRIVATE_TYPE_CATEGORY
12262 	  : SUPPRESSED_CATEGORY;
12263 	d->add_to_local_and_inherited_categories(c);
12264 
12265 	// If a node was suppressed, all the other nodes of its class
12266 	// of equivalence are suppressed too.
12267 	diff *canonical_diff = d->get_canonical_diff();
12268 	if (canonical_diff != d)
12269 	  canonical_diff->add_to_category(c);
12270       }
12271     else if (d->is_allowed_by_specific_negated_suppression())
12272       {
12273 	// This diff node is specifically allowed by a
12274 	// negated_suppression, then mark it as being in the
12275 	// HAS_ALLOWED_CHANGE_CATEGORY.
12276 	diff_category c = HAS_ALLOWED_CHANGE_CATEGORY;
12277 	d->add_to_local_category(c);
12278 	diff *canonical_diff = d->get_canonical_diff();
12279 	canonical_diff->add_to_category(c);
12280 
12281 	// Note that some complementary code later down below does
12282 	// categorize the descendants and parents nodes of this node
12283 	// as HAS_PARENT_WITH_ALLOWED_CHANGE_CATEGORY and
12284 	// HAS_DESCENDANT_WITH_ALLOWED_CHANGE_CATEGORY, repectively.
12285       }
12286 
12287     // If a parent node has been allowed by a negated suppression
12288     // specification, then categorize the current node as
12289     // HAS_PARENT_WITH_ALLOWED_CHANGE_CATEGORY.
12290     if (d->parent_node())
12291       {
12292 	diff_category c = d->parent_node()->get_local_category();
12293 	if (c & (HAS_ALLOWED_CHANGE_CATEGORY
12294 		 | HAS_PARENT_WITH_ALLOWED_CHANGE_CATEGORY))
12295 	  d->add_to_category(HAS_PARENT_WITH_ALLOWED_CHANGE_CATEGORY);
12296 	else
12297 	  {
12298 	    c = d->parent_node()->get_category();
12299 	    if (c & (HAS_ALLOWED_CHANGE_CATEGORY
12300 		     | HAS_PARENT_WITH_ALLOWED_CHANGE_CATEGORY))
12301 	      d->add_to_category(HAS_PARENT_WITH_ALLOWED_CHANGE_CATEGORY);
12302 	  }
12303       }
12304 
12305   }
12306 
12307   /// After visiting the children nodes of a given diff node,
12308   /// propagate the SUPPRESSED_CATEGORY from the children nodes to the
12309   /// diff node, if need be.
12310   ///
12311   /// That is, if all children nodes carry a suppressed change the
12312   /// current node should be marked as suppressed as well.
12313   ///
12314   /// In practice, this might be too strong of a condition.  If the
12315   /// current node carries a local change (i.e, a change not carried
12316   /// by any of its children node) and if that change is not
12317   /// suppressed, then the current node should *NOT* be suppressed.
12318   ///
12319   /// But right now, the IR doesn't let us know about local vs
12320   /// children-carried changes.  So we cannot be that precise yet.
12321   virtual void
visit_endabigail::comparison::suppression_categorization_visitor12322   visit_end(diff* d)
12323   {
12324     bool has_non_suppressed_child = false;
12325     bool has_non_empty_child = false;
12326     bool has_suppressed_child = false;
12327     bool has_non_private_child = false;
12328     bool has_private_child = false;
12329     bool has_descendant_with_allowed_change = false;
12330 
12331     if (// A node to which we can propagate the "SUPPRESSED_CATEGORY"
12332 	// (or the PRIVATE_TYPE_CATEGORY for the same matter)
12333 	// category from its children is a node which:
12334 	//
12335 	//  1/ hasn't been suppressed already
12336 	//
12337 	//  2/ and has no local change (unless it's a pointer,
12338 	//  reference or qualified diff node).
12339 	//
12340 	//  Note that qualified type and typedef diff nodes are a bit
12341 	//  special.  The local changes of the underlying type are
12342 	//  considered local for the qualified/typedef type, just like
12343 	//  for pointer/reference types.  But then the qualified or
12344 	//  typedef type itself can have local changes of its own, and
12345 	//  those changes are of the kind LOCAL_NON_TYPE_CHANGE_KIND.
12346 	//  So a qualified type which have local changes that are
12347 	//  *NOT* of LOCAL_NON_TYPE_CHANGE_KIND (or that has no local
12348 	//  changes at all) and which is in the PRIVATE_TYPE_CATEGORY
12349 	//  or SUPPRESSED_CATEGORY can see these categories be
12350 	//  propagated.
12351 	//
12352 	// Note that all pointer/reference diff node changes are
12353 	// potentially considered local, i.e, local changes of the
12354 	// pointed-to-type are considered local to the pointer itself.
12355 	//
12356 	// Similarly, changes local to the type of function parameters,
12357 	// variables (and data members) and classes (that are not of
12358 	// LOCAL_NON_TYPE_CHANGE_KIND kind) and that have been
12359 	// suppressed can propagate their SUPPRESSED_CATEGORY-ness to
12360 	// those kinds of diff node.
12361 	!(d->get_category() & SUPPRESSED_CATEGORY)
12362 	&& (!d->has_local_changes()
12363 	    || is_pointer_diff(d)
12364 	    || is_reference_diff(d)
12365 	    || (is_qualified_type_diff(d)
12366 		&& (!(d->has_local_changes() & LOCAL_NON_TYPE_CHANGE_KIND)))
12367 	    || (is_typedef_diff(d)
12368 		&& (!(d->has_local_changes() & LOCAL_NON_TYPE_CHANGE_KIND)))
12369 	    || (is_function_decl_diff(d)
12370 		&& (!(d->has_local_changes() & LOCAL_NON_TYPE_CHANGE_KIND)))
12371 	    || (is_fn_parm_diff(d)
12372 		&& (!(d->has_local_changes() & LOCAL_NON_TYPE_CHANGE_KIND)))
12373 	    || (is_function_type_diff(d)
12374 		&& (!(d->has_local_changes() & LOCAL_NON_TYPE_CHANGE_KIND)))
12375 	    || (is_var_diff(d)
12376 		&& (!(d->has_local_changes() & LOCAL_NON_TYPE_CHANGE_KIND)))
12377 	    ||  (is_class_diff(d)
12378 		&& (!(d->has_local_changes() & LOCAL_NON_TYPE_CHANGE_KIND)))))
12379       {
12380 	// Note that we handle private diff nodes differently from
12381 	// generally suppressed diff nodes.  E.g, it's not because a
12382 	// type is private (and suppressed because of that; i.e, in
12383 	// the category PRIVATE_TYPE_CATEGORY) that a typedef to that
12384 	// type should also be private and so suppressed.  Private
12385 	// diff nodes thus have different propagation rules than
12386 	// generally suppressed rules.
12387 	for (vector<diff*>::const_iterator i = d->children_nodes().begin();
12388 	     i != d->children_nodes().end();
12389 	     ++i)
12390 	  {
12391 	    diff* child = *i;
12392 	    if (child->has_changes())
12393 	      {
12394 		has_non_empty_child = true;
12395 		if (child->get_class_of_equiv_category() & SUPPRESSED_CATEGORY)
12396 		  has_suppressed_child = true;
12397 		else if (child->get_class_of_equiv_category()
12398 			 & PRIVATE_TYPE_CATEGORY)
12399 		  // Propagation of the PRIVATE_TYPE_CATEGORY is going
12400 		  // to be handled later below.
12401 		  ;
12402 		else
12403 		  has_non_suppressed_child = true;
12404 
12405 		if (child->get_class_of_equiv_category()
12406 		    & PRIVATE_TYPE_CATEGORY)
12407 		  has_private_child = true;
12408 		else if (child->get_class_of_equiv_category()
12409 			 & SUPPRESSED_CATEGORY)
12410 		  // Propagation of the SUPPRESSED_CATEGORY has been
12411 		  // handled above already.
12412 		  ;
12413 		else
12414 		  has_non_private_child = true;
12415 	      }
12416 	  }
12417 
12418 	if (has_non_empty_child
12419 	    && has_suppressed_child
12420 	    && !has_non_suppressed_child)
12421 	  {
12422 	    d->add_to_category(SUPPRESSED_CATEGORY);
12423 	    // If a node was suppressed, all the other nodes of its class
12424 	    // of equivalence are suppressed too.
12425 	    diff *canonical_diff = d->get_canonical_diff();
12426 	    if (canonical_diff != d)
12427 	      canonical_diff->add_to_category(SUPPRESSED_CATEGORY);
12428 	  }
12429 
12430 	// Note that the private-ness of a an underlying type won't be
12431 	// propagated to its parent typedef, by virtue of the big "if"
12432 	// clause at the beginning of this function.  So we don't have
12433 	// to handle that case here.  So the idiom of defining
12434 	// typedefs of private (opaque) types will be respected;
12435 	// meaning that changes to opaque underlying type will be
12436 	// flagged as private and the typedef will be flagged private
12437 	// as well, unless the typedef itself has local non-type
12438 	// changes.  In the later case, changes to the typedef will be
12439 	// emitted because the typedef won't inherit the privateness
12440 	// of its underlying type.  So in practise, the typedef
12441 	// remains public for the purpose of change reporting.
12442 	if (has_non_empty_child
12443 	    && has_private_child
12444 	    && !has_non_private_child)
12445 	  {
12446 	    d->add_to_category(PRIVATE_TYPE_CATEGORY);
12447 	    // If a node was suppressed, all the other nodes of its class
12448 	    // of equivalence are suppressed too.
12449 	    diff *canonical_diff = d->get_canonical_diff();
12450 	    if (canonical_diff != d)
12451 	      canonical_diff->add_to_category(PRIVATE_TYPE_CATEGORY);
12452 	  }
12453 
12454 	// If the underlying type of a typedef is private and carries
12455 	// changes (that are implicitely suppressed because it's
12456 	// private) then the typedef must be suppressed too, so that
12457 	// those changes to the underlying type are not seen.
12458 	if (is_typedef_diff(d)
12459 	    && !d->has_local_changes()
12460 	    && has_private_child
12461 	    && has_non_empty_child)
12462 	  {
12463 	    d->add_to_category(SUPPRESSED_CATEGORY|PRIVATE_TYPE_CATEGORY);
12464 	    // If a node was suppressed, all the other nodes of its class
12465 	    // of equivalence are suppressed too.
12466 	    diff *canonical_diff = d->get_canonical_diff();
12467 	    if (canonical_diff != d)
12468 	      canonical_diff->add_to_category
12469 		(SUPPRESSED_CATEGORY|PRIVATE_TYPE_CATEGORY);
12470 	  }
12471 
12472 	if (const function_decl_diff *fn_diff = is_function_decl_diff(d))
12473 	  if (!(d->has_local_changes() & LOCAL_NON_TYPE_CHANGE_KIND))
12474 	    {
12475 	      // d is a function diff that carries a local *type*
12476 	      // change (that means it's a change to the function
12477 	      // type).  Let's see if the child function type diff
12478 	      // node is suppressed.  That would mean that we are
12479 	      // instructed to show details of a diff that is deemed
12480 	      // suppressed; this means the suppression conflicts with
12481 	      // a local type change.  In that case, let's follow what
12482 	      // the user asked and suppress the function altogether,
12483 	      if (function_type_diff_sptr fn_type_diff = fn_diff->type_diff())
12484 		if (fn_type_diff->is_suppressed())
12485 		  {
12486 		    d->add_to_category(SUPPRESSED_CATEGORY);
12487 		    // If a node was suppressed, all the other nodes
12488 		    // of its class of equivalence are suppressed too.
12489 		    diff *canonical_diff = d->get_canonical_diff();
12490 		    if (canonical_diff != d)
12491 		      canonical_diff->add_to_category(SUPPRESSED_CATEGORY);
12492 		  }
12493 	  }
12494       }
12495 
12496     // If any descendant node was selected by a negated suppression
12497     // specification then categorize the current one as
12498     // HAS_DESCENDANT_WITH_ALLOWED_CHANGE_CATEGORY.
12499     for (auto child_node : d->children_nodes())
12500       {
12501 	diff *canonical_diff = child_node->get_canonical_diff();
12502 	diff_category c = canonical_diff->get_category();
12503 	if (c & (HAS_ALLOWED_CHANGE_CATEGORY
12504 		 | HAS_DESCENDANT_WITH_ALLOWED_CHANGE_CATEGORY))
12505 	  has_descendant_with_allowed_change = true;
12506       }
12507     if (has_descendant_with_allowed_change)
12508       {
12509 	diff_category c = HAS_DESCENDANT_WITH_ALLOWED_CHANGE_CATEGORY;
12510 	d->add_to_category(c);
12511 	d->get_canonical_diff()->add_to_category(c);
12512       }
12513   }
12514 }; //end struct suppression_categorization_visitor
12515 
12516 /// Walk a given diff-sub tree and appply the suppressions carried by
12517 /// the context.  If the suppression applies to a given node than
12518 /// categorize the node into the SUPPRESSED_CATEGORY category and
12519 /// propagate that categorization.
12520 ///
12521 /// @param diff_tree the diff-sub tree to apply the suppressions to.
12522 void
apply_suppressions(diff * diff_tree)12523 apply_suppressions(diff* diff_tree)
12524 {
12525   if (diff_tree && !diff_tree->context()->suppressions().empty())
12526     {
12527       // Apply suppressions to functions and variables that have
12528       // changed sub-types.
12529       suppression_categorization_visitor v;
12530       diff_tree->context()->forget_visited_diffs();
12531       bool s = diff_tree->context()->visiting_a_node_twice_is_forbidden();
12532       diff_tree->context()->forbid_visiting_a_node_twice(true);
12533       diff_tree->traverse(v);
12534       diff_tree->context()->forbid_visiting_a_node_twice(s);
12535     }
12536 }
12537 
12538 /// Walk a given diff-sub tree and appply the suppressions carried by
12539 /// the context.  If the suppression applies to a given node than
12540 /// categorize the node into the SUPPRESSED_CATEGORY category and
12541 /// propagate that categorization.
12542 ///
12543 /// @param diff_tree the diff-sub tree to apply the suppressions to.
12544 void
apply_suppressions(diff_sptr diff_tree)12545 apply_suppressions(diff_sptr diff_tree)
12546 {apply_suppressions(diff_tree.get());}
12547 
12548 /// Walk a @ref corpus_diff tree and appply the suppressions carried
12549 /// by the context.  If the suppression applies to a given node then
12550 /// categorize the node into the SUPPRESSED_CATEGORY category and
12551 /// propagate that categorization.
12552 ///
12553 /// @param diff_tree the diff tree to apply the suppressions to.
12554 void
apply_suppressions(const corpus_diff * diff_tree)12555 apply_suppressions(const corpus_diff* diff_tree)
12556 {
12557   if (diff_tree && !diff_tree->context()->suppressions().empty())
12558     {
12559       // First, visit the children trees of changed constructs:
12560       // changed functions, variables, as well as sub-types of these,
12561       // and apply suppression specifications to these ...
12562       suppression_categorization_visitor v;
12563       diff_tree->context()->forget_visited_diffs();
12564       bool s = diff_tree->context()->visiting_a_node_twice_is_forbidden();
12565       diff_tree->context()->forbid_visiting_a_node_twice(true);
12566       const_cast<corpus_diff*>(diff_tree)->traverse(v);
12567       diff_tree->context()->forbid_visiting_a_node_twice(s);
12568 
12569       // ... then also visit the set of added and removed functions,
12570       // variables, symbols, and types not reachable from global
12571       // functions and variables.
12572       diff_tree->priv_->
12573 	apply_supprs_to_added_removed_fns_vars_unreachable_types();
12574     }
12575 }
12576 
12577 /// Walk a diff tree and appply the suppressions carried by the
12578 /// context.  If the suppression applies to a given node than
12579 /// categorize the node into the SUPPRESSED_CATEGORY category and
12580 /// propagate that categorization.
12581 ///
12582 /// @param diff_tree the diff tree to apply the suppressions to.
12583 void
apply_suppressions(corpus_diff_sptr diff_tree)12584 apply_suppressions(corpus_diff_sptr  diff_tree)
12585 {apply_suppressions(diff_tree.get());}
12586 
12587 // </diff tree category propagation>
12588 
12589 // <diff tree printing stuff>
12590 
12591 /// A visitor to print (to an output stream) a pretty representation
12592 /// of a @ref diff sub-tree or of a complete @ref corpus_diff tree.
12593 struct diff_node_printer : public diff_node_visitor
12594 {
12595   ostream& out_;
12596   unsigned level_;
12597 
12598   /// Emit a certain number of spaces to the output stream associated
12599   /// to this diff_node_printer.
12600   ///
12601   /// @param level half of the numver of spaces to emit.
12602   void
do_indentabigail::comparison::diff_node_printer12603   do_indent(unsigned level)
12604   {
12605     for (unsigned i = 0; i < level; ++i)
12606       out_ << "  ";
12607   }
12608 
diff_node_printerabigail::comparison::diff_node_printer12609   diff_node_printer(ostream& out)
12610     : diff_node_visitor(DO_NOT_MARK_VISITED_NODES_AS_VISITED),
12611       out_(out),
12612       level_(0)
12613   {}
12614 
12615   virtual void
visit_beginabigail::comparison::diff_node_printer12616   visit_begin(diff*)
12617   {
12618     ++level_;
12619   }
12620 
12621   virtual void
visit_endabigail::comparison::diff_node_printer12622   visit_end(diff*)
12623   {
12624     --level_;
12625   }
12626 
12627   virtual void
visit_beginabigail::comparison::diff_node_printer12628   visit_begin(corpus_diff*)
12629   {
12630     ++level_;
12631   }
12632 
12633   virtual void
visit_endabigail::comparison::diff_node_printer12634   visit_end(corpus_diff*)
12635   {
12636     --level_;
12637   }
12638 
12639   virtual bool
visitabigail::comparison::diff_node_printer12640   visit(diff* d, bool pre)
12641   {
12642     if (!pre)
12643       // We are post-visiting the diff node D.  Which means, we have
12644       // printed a pretty representation for it already.  So do
12645       // nothing now.
12646       return true;
12647 
12648     do_indent(level_);
12649     out_ << d->get_pretty_representation();
12650     out_ << "\n";
12651     do_indent(level_);
12652     out_ << "{\n";
12653     do_indent(level_ + 1);
12654     out_ << "category: "<< d->get_category() << "\n";
12655     do_indent(level_ + 1);
12656     out_ << "@: " << std::hex << d << std::dec << "\n";
12657     do_indent(level_ + 1);
12658     out_ << "@-canonical: " << std::hex
12659 	 << d->get_canonical_diff()
12660 	 << std::dec << "\n";
12661     do_indent(level_);
12662     out_ << "}\n";
12663 
12664     return true;
12665   }
12666 
12667   virtual bool
visitabigail::comparison::diff_node_printer12668   visit(corpus_diff* d, bool pre)
12669   {
12670     if (!pre)
12671       // We are post-visiting the diff node D.  Which means, we have
12672       // printed a pretty representation for it already.  So do
12673       // nothing now.
12674       return true;
12675 
12676     // indent
12677     for (unsigned i = 0; i < level_; ++i)
12678       out_ << ' ';
12679     out_ << d->get_pretty_representation();
12680     out_ << '\n';
12681     return true;
12682   }
12683 }; // end struct diff_printer_visitor
12684 
12685 // </ diff tree printing stuff>
12686 
12687 /// Emit a textual representation of a @ref diff sub-tree to an
12688 /// output stream.
12689 ///
12690 /// @param diff_tree the sub-tree to emit the textual representation
12691 /// for.
12692 ///
12693 /// @param out the output stream to emit the textual representation
12694 /// for @p diff_tree to.
12695 void
print_diff_tree(diff * diff_tree,ostream & out)12696 print_diff_tree(diff* diff_tree, ostream& out)
12697 {
12698   diff_node_printer p(out);
12699   bool s = diff_tree->context()->visiting_a_node_twice_is_forbidden();
12700   diff_tree->context()->forbid_visiting_a_node_twice(false);
12701   diff_tree->traverse(p);
12702   diff_tree->context()->forbid_visiting_a_node_twice(s);
12703 }
12704 
12705 /// Emit a textual representation of a @ref corpus_diff tree to an
12706 /// output stream.
12707 ///
12708 /// @param diff_tree the @ref corpus_diff tree to emit the textual
12709 /// representation for.
12710 ///
12711 /// @param out the output stream to emit the textual representation
12712 /// for @p diff_tree to.
12713 void
print_diff_tree(corpus_diff * diff_tree,std::ostream & out)12714 print_diff_tree(corpus_diff* diff_tree, std::ostream& out)
12715 {
12716   diff_node_printer p(out);
12717   bool s = diff_tree->context()->visiting_a_node_twice_is_forbidden();
12718   diff_tree->context()->forbid_visiting_a_node_twice(false);
12719   diff_tree->traverse(p);
12720   diff_tree->context()->forbid_visiting_a_node_twice(s);
12721 }
12722 
12723 /// Emit a textual representation of a @ref diff sub-tree to an
12724 /// output stream.
12725 ///
12726 /// @param diff_tree the sub-tree to emit the textual representation
12727 /// for.
12728 ///
12729 /// @param out the output stream to emit the textual representation
12730 /// for @p diff_tree to.
12731 void
print_diff_tree(diff_sptr diff_tree,std::ostream & o)12732 print_diff_tree(diff_sptr diff_tree,
12733 		std::ostream& o)
12734 {print_diff_tree(diff_tree.get(), o);}
12735 
12736 /// Emit a textual representation of a @ref corpus_diff tree to an
12737 /// output stream.
12738 ///
12739 /// @param diff_tree the @ref corpus_diff tree to emit the textual
12740 /// representation for.
12741 ///
12742 /// @param out the output stream to emit the textual representation
12743 /// for @p diff_tree to.
12744 void
print_diff_tree(corpus_diff_sptr diff_tree,std::ostream & o)12745 print_diff_tree(corpus_diff_sptr diff_tree,
12746 		std::ostream& o)
12747 {print_diff_tree(diff_tree.get(), o);}
12748 
12749 // <redundancy_marking_visitor>
12750 
12751 /// A tree visitor to categorize nodes with respect to the
12752 /// REDUNDANT_CATEGORY.  That is, detect if a node is redundant (is
12753 /// present on several spots of the tree) and mark such nodes
12754 /// appropriatly.  This visitor also takes care of propagating the
12755 /// REDUNDANT_CATEGORY of a given node to its parent nodes as
12756 /// appropriate.
12757 struct redundancy_marking_visitor : public diff_node_visitor
12758 {
12759   bool skip_children_nodes_;
12760 
redundancy_marking_visitorabigail::comparison::redundancy_marking_visitor12761   redundancy_marking_visitor()
12762     : skip_children_nodes_()
12763   {}
12764 
12765   virtual void
visit_beginabigail::comparison::redundancy_marking_visitor12766   visit_begin(diff* d)
12767   {
12768     if (d->to_be_reported())
12769       {
12770 	// A diff node that carries a change and that has been already
12771 	// traversed elsewhere is considered redundant.  So let's mark
12772 	// it as such and let's not traverse it; that is, let's not
12773 	// visit its children.
12774 	if ((d->context()->diff_has_been_visited(d)
12775 	     || d->get_canonical_diff()->is_traversing())
12776 	    && d->has_changes())
12777 	  {
12778 	    // But if two diff nodes are redundant sibbling that carry
12779 	    // changes of base types, do not mark them as being
12780 	    // redundant.  This is to avoid marking nodes as redundant
12781 	    // in this case:
12782 	    //
12783 	    //     int foo(int a, int b);
12784 	    // compared with:
12785 	    //     float foo(float a, float b); (in C).
12786 	    //
12787 	    // In this case, we want to report all the occurences of
12788 	    // the int->float change because logically, they are at
12789 	    // the same level in the diff tree.
12790 
12791 	    bool redundant_with_sibling_node = false;
12792 	    const diff* p = d->parent_node();
12793 
12794 	    // If this is a child node of a fn_parm_diff, look through
12795 	    // the fn_parm_diff node to get the function diff node.
12796 	    if (p && dynamic_cast<const fn_parm_diff*>(p))
12797 	      p = p->parent_node();
12798 
12799 	    if (p)
12800 	      for (vector<diff*>::const_iterator s =
12801 		     p->children_nodes().begin();
12802 		   s != p->children_nodes().end();
12803 		   ++s)
12804 		{
12805 		  if (*s == d)
12806 		    continue;
12807 		  diff* sib = *s;
12808 		  // If this is a fn_parm_diff, look through the
12809 		  // fn_parm_diff node to get at the real type node.
12810 		  if (fn_parm_diff* f = dynamic_cast<fn_parm_diff*>(*s))
12811 		    sib = f->type_diff().get();
12812 		  if (sib == d)
12813 		    continue;
12814 		  if (sib->get_canonical_diff() == d->get_canonical_diff()
12815 		      // Sibbling diff nodes that carry base type
12816 		      // changes ar to be marked as redundant.
12817 		      && (is_base_diff(sib) || is_distinct_diff(sib)))
12818 		    {
12819 		      redundant_with_sibling_node = true;
12820 		      break;
12821 		    }
12822 		}
12823 	    if (!redundant_with_sibling_node
12824 		// Changes to basic types should never be considered
12825 		// redundant.  For instance, if a member of integer
12826 		// type is changed into a char type in both a struct A
12827 		// and a struct B, we want to see both changes.
12828 		&& !has_basic_type_change_only(d)
12829 		// The same goes for distinct type changes
12830 		&& !filtering::is_mostly_distinct_diff(d)
12831 		// Functions with similar *local* changes are never marked
12832 		// redundant because otherwise one could miss important
12833 		// similar local changes that are applied to different
12834 		// functions.
12835 		&& !is_function_type_diff_with_local_changes(d)
12836 		// Changes involving variadic parameters of functions
12837 		// should never be marked redundant because we want to see
12838 		// them all.
12839 		&& !is_diff_of_variadic_parameter(d)
12840 		&& !is_diff_of_variadic_parameter_type(d)
12841 		// If the canonical diff itself has been filtered out,
12842 		// then this one is not marked redundant, unless the
12843 		// canonical diff was already redundant.
12844 		&& (!d->get_canonical_diff()->is_filtered_out()
12845 		    || (d->get_canonical_diff()->get_category()
12846 			& REDUNDANT_CATEGORY))
12847 		// If the *same* diff node (not one that is merely
12848 		// equivalent to this one) has already been visited
12849 		// the do not mark it as beind redundant.  It's only
12850 		// the other nodes that are equivalent to this one
12851 		// that must be marked redundant.
12852 		&& d->context()->diff_has_been_visited(d) != d
12853 		// If the diff node is a function parameter and is not
12854 		// a reference/pointer (to a non basic or a non
12855 		// distinct type diff) then do not mark it as
12856 		// redundant.
12857 		//
12858 		// Children nodes of base class diff nodes are never
12859 		// redundant either, we want to see them all.
12860 		&& (is_reference_or_ptr_diff_to_non_basic_nor_distinct_types(d)
12861 		    || (!is_child_node_of_function_parm_diff(d)
12862 			&& !is_child_node_of_base_diff(d))))
12863 	      {
12864 		d->add_to_category(REDUNDANT_CATEGORY);
12865 		// As we said in preamble, as this node is marked as
12866 		// being redundant, let's not visit its children.
12867 		// This is not an optimization; it's needed for
12868 		// correctness.  In the case of a diff node involving
12869 		// a class type that refers to himself, visiting the
12870 		// children nodes might cause them to be wrongly
12871 		// marked as redundant.
12872 		set_visiting_kind(get_visiting_kind()
12873 				  | SKIP_CHILDREN_VISITING_KIND);
12874 		skip_children_nodes_ = true;
12875 	      }
12876 	  }
12877       }
12878     else
12879       {
12880 	// If the node is not to be reported, do not look at it children.
12881 	set_visiting_kind(get_visiting_kind() | SKIP_CHILDREN_VISITING_KIND);
12882 	skip_children_nodes_ = true;
12883       }
12884   }
12885 
12886   virtual void
visit_beginabigail::comparison::redundancy_marking_visitor12887   visit_begin(corpus_diff*)
12888   {
12889   }
12890 
12891   virtual void
visit_endabigail::comparison::redundancy_marking_visitor12892   visit_end(diff* d)
12893   {
12894     if (skip_children_nodes_)
12895       // When visiting this node, we decided to skip its children
12896       // node.  Now that we are done visiting the node, lets stop
12897       // avoiding the children nodes visiting for the other tree
12898       // nodes.
12899       {
12900 	set_visiting_kind(get_visiting_kind() & (~SKIP_CHILDREN_VISITING_KIND));
12901 	skip_children_nodes_ = false;
12902       }
12903     else
12904       {
12905 	// Propagate the redundancy categorization of the children nodes
12906 	// to this node.  But if this node has local changes, then it
12907 	// doesn't inherit redundancy from its children nodes.
12908 	if (!(d->get_category() & REDUNDANT_CATEGORY)
12909 	    && (!d->has_local_changes_to_be_reported()
12910 		// By default, pointer, reference and qualified types
12911 		// consider that a local changes to their underlying
12912 		// type is always a local change for themselves.
12913 		//
12914 		// This is as if those types don't have local changes
12915 		// in the same sense as other types.  So we always
12916 		// propagate redundancy to them, regardless of if they
12917 		// have local changes or not.
12918 		//
12919 		// We also propagate redundancy to typedef types if
12920 		// these /only/ carry changes to their underlying
12921 		// type.
12922 		//
12923 		// Note that changes to the underlying type of a
12924 		// typedef is considered local of
12925 		// LOCAL_TYPE_CHANGE_KIND kind.  The other changes to the
12926 		// typedef itself are considered local of
12927 		// LOCAL_NON_TYPE_CHANGE_KIND kind.
12928 		|| is_pointer_diff(d)
12929 		|| is_qualified_type_diff(d)
12930 		// A typedef with local non-type changes should not
12931 		// see redundancy propagation from its underlying
12932 		// type, otherwise, the non-type change might be
12933 		// "suppressed" away.
12934 		|| (is_typedef_diff(d)
12935 		    && (!(d->has_local_changes()
12936 			  & LOCAL_NON_TYPE_CHANGE_KIND)))
12937 		// A (member) variable with non-type local changes
12938 		// should not see redundacy propagation from its type.
12939 		// If redundant local-type changes are carried by its
12940 		// type however, then that redundancy is propagated to
12941 		// the variable.  This is key to keep the redundancy
12942 		// consistency in the system; otherwise, a type change
12943 		// would be rightfully considered redundant at some
12944 		// places but not at others.
12945 		|| (is_var_diff(d)
12946 		    && (!(d->has_local_changes()
12947 			  & LOCAL_NON_TYPE_CHANGE_KIND)))
12948 		// A function parameter with non-type local changes
12949 		// should not see redundancy propagation either.  But
12950 		// a function parameter with local type changes can
12951 		// definitely be redundant.
12952 		|| (is_fn_parm_diff(d)
12953 		    && (!(d->has_local_changes()
12954 			  & LOCAL_NON_TYPE_CHANGE_KIND)))
12955 		))
12956 	  {
12957 	    bool has_non_redundant_child = false;
12958 	    bool has_non_empty_child = false;
12959 	    for (vector<diff*>::const_iterator i =
12960 		   d->children_nodes().begin();
12961 		 i != d->children_nodes().end();
12962 		 ++i)
12963 	      {
12964 		if ((*i)->has_changes())
12965 		  {
12966 		    has_non_empty_child = true;
12967 		    // Let's see if the current child node '*i' is
12968 		    // "non-redundant".
12969 		    //
12970 		    // A non-redundant node would be a node that
12971 		    // carries a change to be reported and has not
12972 		    // been marked as being redundant.
12973 		    if ((*i)->to_be_reported()
12974 			&& ((*i)->get_category() & REDUNDANT_CATEGORY) == 0)
12975 		      has_non_redundant_child = true;
12976 		  }
12977 		if (has_non_redundant_child)
12978 		  break;
12979 	      }
12980 
12981 	    // A diff node for which at least a child node carries a
12982 	    // change, and for which all the children are redundant is
12983 	    // deemed redundant too, unless it has local changes.
12984 	    if (has_non_empty_child
12985 		&& !has_non_redundant_child)
12986 	      d->add_to_category(REDUNDANT_CATEGORY);
12987 	  }
12988       }
12989   }
12990 
12991   virtual void
visit_endabigail::comparison::redundancy_marking_visitor12992   visit_end(corpus_diff*)
12993   {
12994   }
12995 
12996   virtual bool
visitabigail::comparison::redundancy_marking_visitor12997   visit(diff*, bool)
12998   {return true;}
12999 
13000   virtual bool
visitabigail::comparison::redundancy_marking_visitor13001   visit(corpus_diff*, bool)
13002   {
13003     return true;
13004   }
13005 };// end struct redundancy_marking_visitor
13006 
13007 /// A visitor of @ref diff nodes that clears the REDUNDANT_CATEGORY
13008 /// category out of the nodes.
13009 struct redundancy_clearing_visitor : public diff_node_visitor
13010 {
13011   bool
visitabigail::comparison::redundancy_clearing_visitor13012   visit(corpus_diff*, bool)
13013   {return true;}
13014 
13015   bool
visitabigail::comparison::redundancy_clearing_visitor13016   visit(diff* d, bool)
13017   {
13018     // clear the REDUNDANT_CATEGORY out of the current node.
13019     diff_category c = d->get_category();
13020     c &= ~REDUNDANT_CATEGORY;
13021     d->set_category(c);
13022     return true;
13023   }
13024 }; // end struct redundancy_clearing_visitor
13025 
13026 /// Walk a given @ref diff sub-tree to categorize each of the nodes
13027 /// with respect to the REDUNDANT_CATEGORY.
13028 ///
13029 /// @param diff_tree the @ref diff sub-tree to walk.
13030 void
categorize_redundancy(diff * diff_tree)13031 categorize_redundancy(diff* diff_tree)
13032 {
13033   if (diff_tree->context()->show_redundant_changes())
13034     return;
13035   redundancy_marking_visitor v;
13036   bool s = diff_tree->context()->visiting_a_node_twice_is_forbidden();
13037   diff_tree->context()->forbid_visiting_a_node_twice(false);
13038   diff_tree->traverse(v);
13039   diff_tree->context()->forbid_visiting_a_node_twice(s);
13040 }
13041 
13042 /// Walk a given @ref diff sub-tree to categorize each of the nodes
13043 /// with respect to the REDUNDANT_CATEGORY.
13044 ///
13045 /// @param diff_tree the @ref diff sub-tree to walk.
13046 void
categorize_redundancy(diff_sptr diff_tree)13047 categorize_redundancy(diff_sptr diff_tree)
13048 {categorize_redundancy(diff_tree.get());}
13049 
13050 /// Walk a given @ref corpus_diff tree to categorize each of the nodes
13051 /// with respect to the REDUNDANT_CATEGORY.
13052 ///
13053 /// @param diff_tree the @ref corpus_diff tree to walk.
13054 void
categorize_redundancy(corpus_diff * diff_tree)13055 categorize_redundancy(corpus_diff* diff_tree)
13056 {
13057   redundancy_marking_visitor v;
13058   diff_tree->context()->forget_visited_diffs();
13059   bool s = diff_tree->context()->visiting_a_node_twice_is_forbidden();
13060   diff_tree->context()->forbid_visiting_a_node_twice(false);
13061   diff_tree->traverse(v);
13062   diff_tree->context()->forbid_visiting_a_node_twice(s);
13063 }
13064 
13065 /// Walk a given @ref corpus_diff tree to categorize each of the nodes
13066 /// with respect to the REDUNDANT_CATEGORY.
13067 ///
13068 /// @param diff_tree the @ref corpus_diff tree to walk.
13069 void
categorize_redundancy(corpus_diff_sptr diff_tree)13070 categorize_redundancy(corpus_diff_sptr diff_tree)
13071 {categorize_redundancy(diff_tree.get());}
13072 
13073 // </redundancy_marking_visitor>
13074 
13075 /// Walk a given @ref diff sub-tree to clear the REDUNDANT_CATEGORY
13076 /// out of the category of the nodes.
13077 ///
13078 /// @param diff_tree the @ref diff sub-tree to walk.
13079 void
clear_redundancy_categorization(diff * diff_tree)13080 clear_redundancy_categorization(diff* diff_tree)
13081 {
13082   redundancy_clearing_visitor v;
13083   bool s = diff_tree->context()->visiting_a_node_twice_is_forbidden();
13084   diff_tree->context()->forbid_visiting_a_node_twice(false);
13085   diff_tree->traverse(v);
13086   diff_tree->context()->forbid_visiting_a_node_twice(s);
13087   diff_tree->context()->forget_visited_diffs();
13088 }
13089 
13090 /// Walk a given @ref diff sub-tree to clear the REDUNDANT_CATEGORY
13091 /// out of the category of the nodes.
13092 ///
13093 /// @param diff_tree the @ref diff sub-tree to walk.
13094 void
clear_redundancy_categorization(diff_sptr diff_tree)13095 clear_redundancy_categorization(diff_sptr diff_tree)
13096 {clear_redundancy_categorization(diff_tree.get());}
13097 
13098 /// Walk a given @ref corpus_diff tree to clear the REDUNDANT_CATEGORY
13099 /// out of the category of the nodes.
13100 ///
13101 /// @param diff_tree the @ref corpus_diff tree to walk.
13102 void
clear_redundancy_categorization(corpus_diff * diff_tree)13103 clear_redundancy_categorization(corpus_diff* diff_tree)
13104 {
13105   redundancy_clearing_visitor v;
13106   bool s = diff_tree->context()->visiting_a_node_twice_is_forbidden();
13107   diff_tree->context()->forbid_visiting_a_node_twice(false);
13108   diff_tree->traverse(v);
13109   diff_tree->context()->forbid_visiting_a_node_twice(s);
13110   diff_tree->context()->forget_visited_diffs();
13111 }
13112 
13113 /// Walk a given @ref corpus_diff tree to clear the REDUNDANT_CATEGORY
13114 /// out of the category of the nodes.
13115 ///
13116 /// @param diff_tree the @ref corpus_diff tree to walk.
13117 void
clear_redundancy_categorization(corpus_diff_sptr diff_tree)13118 clear_redundancy_categorization(corpus_diff_sptr diff_tree)
13119 {clear_redundancy_categorization(diff_tree.get());}
13120 
13121 /// Apply the @ref diff tree filters that have been associated to the
13122 /// context of the a given @ref corpus_diff tree.  As a result, the
13123 /// nodes of the @diff tree are going to be categorized into one of
13124 /// several of the categories of @ref diff_category.
13125 ///
13126 /// @param diff_tree the @ref corpus_diff instance which @ref diff are
13127 /// to be categorized.
13128 void
apply_filters(corpus_diff_sptr diff_tree)13129 apply_filters(corpus_diff_sptr diff_tree)
13130 {
13131   diff_tree->context()->maybe_apply_filters(diff_tree);
13132   propagate_categories(diff_tree);
13133 }
13134 
13135 /// Test if a diff node represents the difference between a variadic
13136 /// parameter type and something else.
13137 ///
13138 /// @param d the diff node to consider.
13139 ///
13140 /// @return true iff @p d is a diff node that represents the
13141 /// difference between a variadic parameter type and something else.
13142 bool
is_diff_of_variadic_parameter_type(const diff * d)13143 is_diff_of_variadic_parameter_type(const diff* d)
13144 {
13145   if (!d)
13146     return false;
13147 
13148   type_base_sptr t = is_type(d->first_subject());
13149   if (t && t->get_environment().is_variadic_parameter_type(t))
13150     return true;
13151 
13152   t = is_type(d->second_subject());
13153   if (t && t->get_environment().is_variadic_parameter_type(t))
13154     return true;
13155 
13156   return false;
13157 }
13158 
13159 /// Test if a diff node represents the difference between a variadic
13160 /// parameter type and something else.
13161 ///
13162 /// @param d the diff node to consider.
13163 ///
13164 /// @return true iff @p d is a diff node that represents the
13165 /// difference between a variadic parameter type and something else.
13166 bool
is_diff_of_variadic_parameter_type(const diff_sptr & d)13167 is_diff_of_variadic_parameter_type(const diff_sptr& d)
13168 {return is_diff_of_variadic_parameter_type(d.get());}
13169 
13170 /// Test if a diff node represents the difference between a variadic
13171 /// parameter and something else.
13172 ///
13173 /// @param d the diff node to consider.
13174 ///
13175 /// @return true iff @p d is a diff node that represents the
13176 /// difference between a variadic parameter and something else.
13177 bool
is_diff_of_variadic_parameter(const diff * d)13178 is_diff_of_variadic_parameter(const diff* d)
13179 {
13180   fn_parm_diff* diff =
13181     dynamic_cast<fn_parm_diff*>(const_cast<abigail::comparison::diff*>(d));
13182   return (diff && is_diff_of_variadic_parameter_type(diff->type_diff()));
13183 }
13184 
13185 /// Test if a diff node represents the difference between a variadic
13186 /// parameter and something else.
13187 ///
13188 /// @param d the diff node to consider.
13189 ///
13190 /// @return true iff @p d is a diff node that represents the
13191 /// difference between a variadic parameter and something else.
13192 bool
is_diff_of_variadic_parameter(const diff_sptr & d)13193 is_diff_of_variadic_parameter(const diff_sptr& d)
13194 {return is_diff_of_variadic_parameter(d.get());}
13195 
13196 /// Test if a diff node represents a diff between two basic types.
13197 ///
13198 /// @param d the diff node to consider.
13199 ///
13200 /// @return true iff @p d is a diff between two basic types.
13201 const type_decl_diff*
is_diff_of_basic_type(const diff * d)13202 is_diff_of_basic_type(const diff *d)
13203 {return dynamic_cast<const type_decl_diff*>(d);}
13204 
13205 /// Test if a diff node represents a diff between two basic types, or
13206 /// between pointers, references or qualified type to basic types.
13207 ///
13208 /// @param diff the diff node to consider.
13209 ///
13210 /// @param allow_indirect_type if true, then this function looks into
13211 /// pointer, reference or qualified diff types to see if they "point
13212 /// to" basic types.
13213 ///
13214 /// @return true iff @p d is a diff between two basic types.
13215 const type_decl_diff*
is_diff_of_basic_type(const diff * diff,bool allow_indirect_type)13216 is_diff_of_basic_type(const diff* diff, bool allow_indirect_type)
13217 {
13218   if (allow_indirect_type)
13219       diff = peel_pointer_or_qualified_type_diff(diff);
13220   return is_diff_of_basic_type(diff);
13221 }
13222 
13223 /// If a diff node is about changes between two typedef types, get the
13224 /// diff node about changes between the underlying types.
13225 ///
13226 /// Note that this function walks the tree of underlying diff nodes
13227 /// returns the first diff node about types that are not typedefs.
13228 ///
13229 /// @param dif the dif node to consider.
13230 ///
13231 /// @return the underlying diff node of @p dif, or just return @p dif
13232 /// if it's not a typedef diff node.
13233 const diff*
peel_typedef_diff(const diff * dif)13234 peel_typedef_diff(const diff* dif)
13235 {
13236   const typedef_diff *d = 0;
13237   while ((d = is_typedef_diff(dif)))
13238     dif = d->underlying_type_diff().get();
13239   return dif;
13240 }
13241 
13242 /// If a diff node is about changes between two pointer types, get the
13243 /// diff node about changes between the underlying (pointed-to) types.
13244 ///
13245 /// Note that this function walks the tree of underlying diff nodes
13246 /// returns the first diff node about types that are not pointers.
13247 ///
13248 /// @param dif the dif node to consider.
13249 ///
13250 /// @return the underlying diff node of @p dif, or just return @p dif
13251 /// if it's not a pointer diff node.
13252 const diff*
peel_pointer_diff(const diff * dif)13253 peel_pointer_diff(const diff* dif)
13254 {
13255   const pointer_diff *d = 0;
13256   while ((d = is_pointer_diff(dif)))
13257     dif = d->underlying_type_diff().get();
13258   return dif;
13259 }
13260 
13261 /// If a diff node is about changes between two reference types, get
13262 /// the diff node about changes between the underlying (pointed-to)
13263 /// types.
13264 ///
13265 /// Note that this function walks the tree of underlying diff nodes
13266 /// returns the first diff node about types that are not references.
13267 ///
13268 /// @param dif the dif node to consider.
13269 ///
13270 /// @return the underlying diff node of @p dif, or just return @p dif
13271 /// if it's not a reference diff node.
13272 const diff*
peel_reference_diff(const diff * dif)13273 peel_reference_diff(const diff* dif)
13274 {
13275   const reference_diff *d = 0;
13276   while ((d = is_reference_diff(dif)))
13277     dif = d->underlying_type_diff().get();
13278   return dif;
13279 }
13280 
13281 /// If a diff node is about changes between two qualified types, get
13282 /// the diff node about changes between the underlying (non-qualified)
13283 /// types.
13284 ///
13285 /// Note that this function walks the tree of underlying diff nodes
13286 /// returns the first diff node about types that are not qualified.
13287 ///
13288 /// @param dif the dif node to consider.
13289 ///
13290 /// @return the underlying diff node of @p dif, or just return @p dif
13291 /// if it's not a qualified diff node.
13292 const diff*
peel_qualified_diff(const diff * dif)13293 peel_qualified_diff(const diff* dif)
13294 {
13295   const qualified_type_diff *d = 0;
13296   while ((d = is_qualified_type_diff(dif)))
13297     dif = d->underlying_type_diff().get();
13298   return dif;
13299 }
13300 
13301 /// If a diff node is about changes between two function parameters
13302 /// get the diff node about changes between the types of the parameters.
13303 ///
13304 /// @param dif the dif node to consider.
13305 ///
13306 /// @return the diff of the types of the parameters.
13307 const diff*
peel_fn_parm_diff(const diff * dif)13308 peel_fn_parm_diff(const diff* dif)
13309 {
13310   const fn_parm_diff *d = 0;
13311   while ((d = is_fn_parm_diff(dif)))
13312     dif = d->type_diff().get();
13313   return dif;
13314 }
13315 
13316 /// If a diff node is about changes between two pointer, reference or
13317 /// qualified types, get the diff node about changes between the
13318 /// underlying types.
13319 ///
13320 /// Note that this function walks the tree of underlying diff nodes
13321 /// returns the first diff node about types that are not pointer,
13322 /// reference or qualified.
13323 ///
13324 /// @param dif the dif node to consider.
13325 ///
13326 /// @return the underlying diff node of @p dif, or just return @p dif
13327 /// if it's not a pointer, reference or qualified diff node.
13328 const diff*
peel_pointer_or_qualified_type_diff(const diff * dif)13329 peel_pointer_or_qualified_type_diff(const diff*dif)
13330 {
13331   while (true)
13332     {
13333       if (const pointer_diff *d = is_pointer_diff(dif))
13334 	dif = peel_pointer_diff(d);
13335       else if (const reference_diff *d = is_reference_diff(dif))
13336 	dif = peel_reference_diff(d);
13337       else if (const qualified_type_diff *d = is_qualified_type_diff(dif))
13338 	dif = peel_qualified_diff(d);
13339       else
13340 	break;
13341     }
13342   return dif;
13343 }
13344 
13345 /// If a diff node is about changes between two typedefs or qualified
13346 /// types, get the diff node about changes between the underlying
13347 /// types.
13348 ///
13349 /// Note that this function walks the tree of underlying diff nodes
13350 /// returns the first diff node about types that are not typedef or
13351 /// qualified types.
13352 ///
13353 /// @param dif the dif node to consider.
13354 ///
13355 /// @return the underlying diff node of @p dif, or just return @p dif
13356 /// if it's not typedef or qualified diff node.
13357 const diff*
peel_typedef_or_qualified_type_diff(const diff * dif)13358 peel_typedef_or_qualified_type_diff(const diff *dif)
13359 {
13360   while (true)
13361     {
13362       if (const typedef_diff *d = is_typedef_diff(dif))
13363 	dif = peel_typedef_diff(d);
13364       else if (const qualified_type_diff *d = is_qualified_type_diff(dif))
13365 	dif = peel_qualified_diff(d);
13366       else
13367 	break;
13368     }
13369   return dif;
13370 }
13371 
13372 /// If a diff node is about changes between two typedefs or qualified
13373 /// types, get the diff node about changes between the underlying
13374 /// types.
13375 ///
13376 /// Note that this function walks the tree of underlying diff nodes
13377 /// returns the first diff node about types that are neither typedef,
13378 /// qualified type nor parameters.
13379 ///
13380 /// @param dif the dif node to consider.
13381 ///
13382 /// @return the diff node about changes between the underlying types.
13383 const diff*
peel_typedef_qualified_type_or_parameter_diff(const diff * dif)13384 peel_typedef_qualified_type_or_parameter_diff(const diff *dif)
13385 {
13386   while (true)
13387     {
13388       if (const typedef_diff *d = is_typedef_diff(dif))
13389 	dif = peel_typedef_diff(d);
13390       else if (const qualified_type_diff *d = is_qualified_type_diff(dif))
13391 	dif = peel_qualified_diff(d);
13392       else if (const fn_parm_diff *d = is_fn_parm_diff(dif))
13393 	dif = peel_fn_parm_diff(d);
13394       else
13395 	break;
13396     }
13397   return dif;
13398 }
13399 
13400 /// Test if a diff node represents a diff between two class or union
13401 /// types.
13402 ///
13403 /// @param d the diff node to consider.
13404 ///
13405 /// @return iff @p is a diff between two class or union types then
13406 /// return the instance of @ref class_or_union_diff that @p derives
13407 /// from.  Otherwise, return nil.
13408 const class_or_union_diff*
is_diff_of_class_or_union_type(const diff * d)13409 is_diff_of_class_or_union_type(const diff *d)
13410 {return dynamic_cast<const class_or_union_diff*>(d);}
13411 
13412 /// Test if a given diff node carries *only* a local type change.
13413 ///
13414 /// @param d the diff node to consider.
13415 ///
13416 /// @return true iff @p has a change and that change is a local type
13417 /// change.
13418 static bool
has_local_type_change_only(const diff * d)13419 has_local_type_change_only(const diff *d)
13420 {
13421   if (enum change_kind k = d->has_local_changes())
13422     if ((k & LOCAL_NON_TYPE_CHANGE_KIND) == 0
13423 	&& (k & LOCAL_TYPE_CHANGE_KIND) != 0)
13424       return true;
13425 
13426   return false;
13427 }
13428 
13429 /// Test if a diff node is a decl diff that only carries a basic type
13430 /// change on its type diff sub-node.
13431 ///
13432 ///Note that that pointers/references/qualified types diffs to basic
13433 /// type diffs are considered as having basic type change only.
13434 ///
13435 /// @param d the diff node to consider.
13436 ///
13437 /// @return true iff @p d is a decl diff that only carries a basic
13438 /// type change on its type diff sub-node.
13439 bool
has_basic_type_change_only(const diff * d)13440 has_basic_type_change_only(const diff *d)
13441 {
13442   d = peel_typedef_qualified_type_or_parameter_diff(d);
13443 
13444   if (is_diff_of_basic_type(d, true) && d->has_changes())
13445     return true;
13446   else if (const var_diff * v = dynamic_cast<const var_diff*>(d))
13447     return (has_local_type_change_only(v)
13448 	    && is_diff_of_basic_type(v->type_diff().get(), true));
13449   else if (const fn_parm_diff * p = dynamic_cast<const fn_parm_diff*>(d))
13450     return (has_local_type_change_only(p)
13451 	    && is_diff_of_basic_type(p->type_diff().get(), true));
13452   else if (const function_decl_diff* f =
13453 	   dynamic_cast<const function_decl_diff*>(d))
13454     return (has_local_type_change_only(f)
13455 	    && f->type_diff()
13456 	    && is_diff_of_basic_type(f->type_diff()->return_type_diff().get(),
13457 				     true));
13458   return false;
13459 }
13460 }// end namespace comparison
13461 } // end namespace abigail
13462