• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
2 // -*- Mode: C++ -*-
3 //
4 // Copyright (C) 2013-2020 Red Hat, Inc.
5 //
6 // Author: Dodji Seketeli
7 
8 /// @file
9 ///
10 /// This contains the implementation of the comparison engine of
11 /// libabigail.
12 
13 #include <ctype.h>
14 #include <libgen.h>
15 #include <algorithm>
16 #include <sstream>
17 
18 #include "abg-comparison-priv.h"
19 #include "abg-reporter-priv.h"
20 
21 namespace abigail
22 {
23 
24 namespace comparison
25 {
26 
27 ///
28 ///
29 ///@defgroup DiffNode Internal Representation of the comparison engine
30 /// @{
31 ///
32 /// @brief How changes are represented in libabigail's comparison engine.
33 ///
34 ///@par diff nodes
35 ///
36 /// The internal representation of the comparison engine is basically
37 /// a graph of @ref instances of @ref diff node.  We refer to these
38 /// just as <em>diff nodes</em>.  A diff node represents a change
39 /// between two ABI artifacts represented by instances of types of the
40 /// abigail::ir namespace.  These two artifacts that are being
41 /// compared are called the <em>subjects of the diff</em>.
42 ///
43 /// The types of that IR are in the abigail::comparison namespace.
44 ///
45 ///@par comparing diff nodes
46 ///
47 /// Comparing two instances of @ref diff nodes amounts to comparing
48 /// the subject of the diff.  In other words, two @ref diff nodes are
49 /// equal if and only if their subjects are equal.  Thus, two @ref
50 /// diff nodes can have different memory addresses and yet be equal.
51 ///
52 ///@par diff reporting and context
53 ///
54 /// A diff node can be serialized to an output stream to express, in
55 /// a human-readable textual form, the different changes that exist
56 /// between its two subjects.  This is done by invoking the
57 /// diff::report() method.  That reporting is controlled by several
58 /// parameters that are conceptually part of the context of the diff.
59 /// That context is materialized by an instance of the @ref
60 /// diff_context type.
61 ///
62 /// Please note that the role of the instance(s) of @ref diff_context
63 /// is boreader than just controlling the reporting of @ref diff
64 /// nodes.  Basically, a @ref diff node itself is created following
65 /// behaviours that are controlled by a particular instance of
66 /// diff_context.  A diff node is created in a particular diff
67 /// context, so to speak.
68 ///
69 /// @}
70 ///
71 
72 ///
73 ///@defgroup CanonicalDiff Canonical diff tree nodes
74 /// @{
75 ///
76 /// @brief How equivalent diff nodes are quickly spotted.
77 ///
78 /// @par Equivalence of diff nodes.
79 ///
80 /// Each @ref diff node has a property named <em>Canonical Diff
81 /// Node</em>.  If \c D is a diff node, the canonical diff node of @c
82 /// D, noted @c C(D) is a particular diff node that is equal to @c D.
83 /// Thus, a fast way to compare two @ref diff node is to perform a
84 /// pointer comparison of their canonical diff nodes.
85 ///
86 /// A set of equivalent @ref diff nodes is a set of diff nodes that
87 /// all have the same canonical node.  All the nodes of that set are
88 /// equal.
89 ///
90 /// A canonical node is registereded for a given diff node by invoking
91 /// the method diff_context::initialize_canonical_diff().
92 ///
93 /// Please note that the diff_context holds all the canonical diffs
94 /// that got registered through it.  Thus, the life time of all of
95 /// canonical diff objects is the same as the life time of the @ref
96 /// diff_context they relate to.
97 ///
98 /// @}
99 ///
100 
101 // -----------------------------------------
102 // <private functions re-usable elsewhere>
103 // -----------------------------------------
104 /// Sort a map of enumerators by their value.
105 ///
106 /// @param enumerators_map the map to sort.
107 ///
108 /// @param sorted the resulting vector of sorted enumerators.
109 void
sort_enumerators(const string_enumerator_map & enumerators_map,enum_type_decl::enumerators & sorted)110 sort_enumerators(const string_enumerator_map& enumerators_map,
111 		 enum_type_decl::enumerators& sorted)
112 {
113   for (string_enumerator_map::const_iterator i = enumerators_map.begin();
114        i != enumerators_map.end();
115        ++i)
116     sorted.push_back(i->second);
117   enumerator_value_comp comp;
118   std::sort(sorted.begin(), sorted.end(), comp);
119 }
120 
121 /// Sort a map of changed enumerators.
122 ///
123 /// @param enumerators_map the map to sort.
124 ///
125 ///@param output parameter.  The resulting sorted enumerators.
126 void
sort_changed_enumerators(const string_changed_enumerator_map & enumerators_map,changed_enumerators_type & sorted)127 sort_changed_enumerators(const string_changed_enumerator_map& enumerators_map,
128 			 changed_enumerators_type& sorted)
129 {
130   for (string_changed_enumerator_map::const_iterator i =
131 	 enumerators_map.begin();
132        i != enumerators_map.end();
133        ++i)
134     sorted.push_back(i->second);
135 
136   changed_enumerator_comp comp;
137   std::sort(sorted.begin(), sorted.end(), comp);
138 }
139 
140 /// Sort a map of data members by the offset of their initial value.
141 ///
142 /// @param data_members the map of changed data members to sort.
143 ///
144 /// @param sorted the resulting vector of sorted changed data members.
145 void
sort_data_members(const string_decl_base_sptr_map & data_members,vector<decl_base_sptr> & sorted)146 sort_data_members(const string_decl_base_sptr_map &data_members,
147 		  vector<decl_base_sptr>& sorted)
148 {
149   sorted.reserve(data_members.size());
150   for (string_decl_base_sptr_map::const_iterator i = data_members.begin();
151        i != data_members.end();
152        ++i)
153     sorted.push_back(i->second);
154 
155   data_member_comp comp;
156   std::sort(sorted.begin(), sorted.end(), comp);
157 }
158 
159 /// Sort (in place) a vector of changed data members.
160 ///
161 /// @param to_sort the vector to sort.
162 void
sort_changed_data_members(changed_var_sptrs_type & to_sort)163 sort_changed_data_members(changed_var_sptrs_type& to_sort)
164 {
165   data_member_comp comp;
166   std::sort(to_sort.begin(), to_sort.end(), comp);
167 }
168 
169 /// Sort an instance of @ref string_function_ptr_map map and stuff a
170 /// resulting sorted vector of pointers to function_decl.
171 ///
172 /// @param map the map to sort.
173 ///
174 /// @param sorted the resulting sorted vector.
175 void
sort_string_function_ptr_map(const string_function_ptr_map & map,vector<function_decl * > & sorted)176 sort_string_function_ptr_map(const string_function_ptr_map& map,
177 			     vector<function_decl*>& sorted)
178 {
179   sorted.reserve(map.size());
180   for (string_function_ptr_map::const_iterator i = map.begin();
181        i != map.end();
182        ++i)
183     sorted.push_back(i->second);
184 
185   function_comp comp;
186   std::sort(sorted.begin(), sorted.end(), comp);
187 }
188 
189 /// Sort a map that's an instance of @ref
190 /// string_member_function_sptr_map and fill a vector of member
191 /// functions with the sorted result.
192 ///
193 /// @param map the map to sort.
194 ///
195 /// @param sorted the resulting sorted vector.
196 void
sort_string_member_function_sptr_map(const string_member_function_sptr_map & map,class_or_union::member_functions & sorted)197 sort_string_member_function_sptr_map(const string_member_function_sptr_map& map,
198 				     class_or_union::member_functions& sorted)
199 {
200   sorted.reserve(map.size());
201   for (string_member_function_sptr_map::const_iterator i = map.begin();
202        i != map.end();
203        ++i)
204     sorted.push_back(i->second);
205 
206   function_comp comp;
207   std::sort(sorted.begin(), sorted.end(), comp);
208 }
209 
210 /// Sort the values of a @ref string_function_decl_diff_sptr_map map
211 /// and store the result in a vector of @ref function_decl_diff_sptr
212 /// objects.
213 ///
214 /// @param map the map whose values to store.
215 ///
216 /// @param sorted the vector of function_decl_diff_sptr to store the
217 /// result of the sort into.
218 void
sort_string_function_decl_diff_sptr_map(const string_function_decl_diff_sptr_map & map,function_decl_diff_sptrs_type & sorted)219 sort_string_function_decl_diff_sptr_map
220 (const string_function_decl_diff_sptr_map& map,
221  function_decl_diff_sptrs_type& sorted)
222 {
223   sorted.reserve(map.size());
224   for (string_function_decl_diff_sptr_map::const_iterator i = map.begin();
225        i != map.end();
226        ++i)
227     sorted.push_back(i->second);
228   function_decl_diff_comp comp;
229   std::sort(sorted.begin(), sorted.end(), comp);
230 }
231 
232 /// Sort of an instance of @ref string_var_diff_sptr_map map.
233 ///
234 /// @param map the input map to sort.
235 ///
236 /// @param sorted the ouptut sorted vector of @ref var_diff_sptr.
237 /// It's populated with the sorted content.
238 void
sort_string_var_diff_sptr_map(const string_var_diff_sptr_map & map,var_diff_sptrs_type & sorted)239 sort_string_var_diff_sptr_map(const string_var_diff_sptr_map& map,
240 			      var_diff_sptrs_type& sorted)
241 {
242   sorted.reserve(map.size());
243   for (string_var_diff_sptr_map::const_iterator i = map.begin();
244        i != map.end();
245        ++i)
246     sorted.push_back(i->second);
247 
248   var_diff_sptr_comp comp;
249   std::sort(sorted.begin(), sorted.end(), comp);
250 }
251 
252 /// Sort a map of string -> pointer to @ref elf_symbol.
253 ///
254 /// The result is a vector of @ref elf_symbol_sptr sorted by the
255 /// name of the symbol.
256 ///
257 /// @param map the map to sort.
258 ///
259 /// @param sorted out parameter; the sorted vector of @ref
260 /// elf_symbol_sptr.
261 void
sort_string_elf_symbol_map(const string_elf_symbol_map & map,vector<elf_symbol_sptr> & sorted)262 sort_string_elf_symbol_map(const string_elf_symbol_map& map,
263 			   vector<elf_symbol_sptr>& sorted)
264 {
265   for (string_elf_symbol_map::const_iterator i = map.begin();
266        i!= map.end();
267        ++i)
268     sorted.push_back(i->second);
269 
270   elf_symbol_comp comp;
271   std::sort(sorted.begin(), sorted.end(), comp);
272 }
273 
274 /// Sort a map of string -> pointer to @ref var_decl.
275 ///
276 /// The result is a vector of var_decl* sorted by the qualified name
277 /// of the variables.
278 ///
279 /// @param map the map to sort.
280 ///
281 /// @param sorted out parameter; the sorted vector of @ref var_decl.
282 void
sort_string_var_ptr_map(const string_var_ptr_map & map,vector<var_decl * > & sorted)283 sort_string_var_ptr_map(const string_var_ptr_map& map,
284 			vector<var_decl*>& sorted)
285 {
286   for (string_var_ptr_map::const_iterator i = map.begin();
287        i != map.end();
288        ++i)
289     sorted.push_back(i->second);
290 
291   var_comp comp;
292   std::sort(sorted.begin(), sorted.end(), comp);
293 }
294 
295 /// Sort the values of a string_var_diff_sptr_map and store the result
296 /// in a vector of var_diff_sptr.
297 ///
298 /// @param map the map of changed data members to sort.
299 ///
300 /// @param sorted the resulting vector of var_diff_sptr.
301 void
sort_string_data_member_diff_sptr_map(const string_var_diff_sptr_map & map,var_diff_sptrs_type & sorted)302 sort_string_data_member_diff_sptr_map(const string_var_diff_sptr_map& map,
303 				      var_diff_sptrs_type& sorted)
304 {
305   sorted.reserve(map.size());
306   for (string_var_diff_sptr_map::const_iterator i = map.begin();
307        i != map.end();
308        ++i)
309     sorted.push_back(i->second);
310   data_member_diff_comp comp;
311   std::sort(sorted.begin(), sorted.end(), comp);
312 }
313 
314 /// Sort the values of a unsigned_var_diff_sptr_map map and store the
315 /// result into a vector of var_diff_sptr.
316 ///
317 /// @param map the map of changed data members to sort.
318 ///
319 /// @param sorted the resulting vector of sorted var_diff_sptr.
320 void
sort_unsigned_data_member_diff_sptr_map(const unsigned_var_diff_sptr_map map,var_diff_sptrs_type & sorted)321 sort_unsigned_data_member_diff_sptr_map(const unsigned_var_diff_sptr_map map,
322 					var_diff_sptrs_type& sorted)
323 {
324   sorted.reserve(map.size());
325   for (unsigned_var_diff_sptr_map::const_iterator i = map.begin();
326        i != map.end();
327        ++i)
328     sorted.push_back(i->second);
329   data_member_diff_comp comp;
330   std::sort(sorted.begin(), sorted.end(), comp);
331 }
332 
333 /// Sort an map of string -> virtual member function into a vector of
334 /// virtual member functions.  The virtual member functions are sorted
335 /// by increasing order of their virtual index.
336 ///
337 /// @param map the input map.
338 ///
339 /// @param sorted the resulting sorted vector of virtual function
340 /// member.
341 void
sort_string_virtual_member_function_diff_sptr_map(const string_function_decl_diff_sptr_map & map,function_decl_diff_sptrs_type & sorted)342 sort_string_virtual_member_function_diff_sptr_map
343 (const string_function_decl_diff_sptr_map& map,
344  function_decl_diff_sptrs_type& sorted)
345 {
346   sorted.reserve(map.size());
347   for (string_function_decl_diff_sptr_map::const_iterator i = map.begin();
348        i != map.end();
349        ++i)
350     sorted.push_back(i->second);
351 
352   virtual_member_function_diff_comp comp;
353   sort(sorted.begin(), sorted.end(), comp);
354 }
355 
356 /// Sort a map ofg string -> @ref diff_sptr into a vector of @ref
357 /// diff_sptr.  The diff_sptr are sorted lexicographically wrt
358 /// qualified names of their first subjects.
359 ///
360 /// @param map the map to sort.
361 ///
362 /// @param sorted the resulting sorted vector.
363 void
sort_string_diff_sptr_map(const string_diff_sptr_map & map,diff_sptrs_type & sorted)364 sort_string_diff_sptr_map(const string_diff_sptr_map& map,
365 			  diff_sptrs_type& sorted)
366 {
367   sorted.reserve(map.size());
368   for (string_diff_sptr_map::const_iterator i = map.begin();
369        i != map.end();
370        ++i)
371     sorted.push_back(i->second);
372 
373   diff_comp comp;
374   sort(sorted.begin(), sorted.end(), comp);
375 }
376 
377 /// Sort a map ofg string -> @ref diff* into a vector of @ref
378 /// diff_ptr.  The diff_ptr are sorted lexicographically wrt
379 /// qualified names of their first subjects.
380 ///
381 /// @param map the map to sort.
382 ///
383 /// @param sorted the resulting sorted vector.
384 void
sort_string_diff_ptr_map(const string_diff_ptr_map & map,diff_ptrs_type & sorted)385 sort_string_diff_ptr_map(const string_diff_ptr_map& map,
386 			  diff_ptrs_type& sorted)
387 {
388   sorted.reserve(map.size());
389   for (string_diff_ptr_map::const_iterator i = map.begin();
390        i != map.end();
391        ++i)
392     sorted.push_back(i->second);
393 
394   diff_comp comp;
395   sort(sorted.begin(), sorted.end(), comp);
396 }
397 
398 /// Sort a map of string -> base_diff_sptr into a sorted vector of
399 /// base_diff_sptr.  The base_diff_sptr are sorted by increasing value
400 /// of their offset in their containing type.
401 ///
402 /// @param map the input map to sort.
403 ///
404 /// @param sorted the resulting sorted vector.
405 void
sort_string_base_diff_sptr_map(const string_base_diff_sptr_map & map,base_diff_sptrs_type & sorted)406 sort_string_base_diff_sptr_map(const string_base_diff_sptr_map& map,
407 			       base_diff_sptrs_type& sorted)
408 {
409   for (string_base_diff_sptr_map::const_iterator i = map.begin();
410        i != map.end();
411        ++i)
412     sorted.push_back(i->second);
413   base_diff_comp comp;
414   sort(sorted.begin(), sorted.end(), comp);
415 }
416 
417 /// Lexicographically sort base specifications found
418 /// in instances of string_base_sptr_map.
419 void
sort_string_base_sptr_map(const string_base_sptr_map & m,class_decl::base_specs & sorted)420 sort_string_base_sptr_map(const string_base_sptr_map& m,
421 			  class_decl::base_specs& sorted)
422 {
423   for (string_base_sptr_map::const_iterator i = m.begin();
424        i != m.end();
425        ++i)
426     sorted.push_back(i->second);
427 
428   base_spec_comp comp;
429   std::sort(sorted.begin(), sorted.end(), comp);
430 }
431 
432 /// Sort a map of @ref fn_parm_diff by the indexes of the function
433 /// parameters.
434 ///
435 /// @param map the map to sort.
436 ///
437 /// @param sorted the resulting sorted vector of changed function
438 /// parms.
439 void
sort_string_fn_parm_diff_sptr_map(const unsigned_fn_parm_diff_sptr_map & map,vector<fn_parm_diff_sptr> & sorted)440 sort_string_fn_parm_diff_sptr_map(const unsigned_fn_parm_diff_sptr_map& map,
441 				  vector<fn_parm_diff_sptr>&		sorted)
442 {
443   sorted.reserve(map.size());
444   for (unsigned_fn_parm_diff_sptr_map::const_iterator i = map.begin();
445        i != map.end();
446        ++i)
447     sorted.push_back(i->second);
448 
449   fn_parm_diff_comp comp;
450   std::sort(sorted.begin(), sorted.end(), comp);
451 }
452 
453 /// Sort a map of changed function parameters by the indexes of the
454 /// function parameters.
455 ///
456 /// @param map the map to sort.
457 ///
458 /// @param sorted the resulting sorted vector of instances of @ref
459 /// fn_parm_diff_sptr
460 void
sort_string_fn_parm_diff_sptr_map(const string_fn_parm_diff_sptr_map & map,vector<fn_parm_diff_sptr> & sorted)461 sort_string_fn_parm_diff_sptr_map(const string_fn_parm_diff_sptr_map&	map,
462 				  vector<fn_parm_diff_sptr>&		sorted)
463 {
464   sorted.reserve(map.size());
465   for (string_fn_parm_diff_sptr_map::const_iterator i = map.begin();
466        i != map.end();
467        ++i)
468     sorted.push_back(i->second);
469 
470   fn_parm_diff_comp comp;
471   std::sort(sorted.begin(), sorted.end(), comp);
472 }
473 
474 /// Sort a map of string -> function parameters.
475 ///
476 /// @param map the map to sort.
477 ///
478 /// @param sorted the resulting sorted vector of
479 /// @ref vector<function_decl::parameter_sptr>
480 void
sort_string_parm_map(const string_parm_map & map,vector<function_decl::parameter_sptr> & sorted)481 sort_string_parm_map(const string_parm_map& map,
482 		     vector<function_decl::parameter_sptr>& sorted)
483 {
484   for (string_parm_map::const_iterator i = map.begin();
485        i != map.end();
486        ++i)
487     sorted.push_back(i->second);
488 
489   parm_comp comp;
490   std::sort(sorted.begin(), sorted.end(), comp);
491 }
492 
493 /// Sort the set of ABI artifacts contained in a @ref
494 /// artifact_sptr_set_type.
495 ///
496 /// @param set the set of ABI artifacts to sort.
497 ///
498 /// @param output parameter the vector containing the sorted ABI
499 /// artifacts.
500 void
sort_artifacts_set(const artifact_sptr_set_type & set,vector<type_or_decl_base_sptr> & sorted)501 sort_artifacts_set(const artifact_sptr_set_type& set,
502 		   vector<type_or_decl_base_sptr>& sorted)
503 {
504 
505   for (artifact_sptr_set_type::const_iterator it = set.begin();
506        it != set.end();
507        ++it)
508     sorted.push_back(*it);
509 
510   type_or_decl_base_comp comp;
511   std::sort(sorted.begin(), sorted.end(), comp);
512 }
513 
514 /// Sort a map of string to type_base_sptr entities.
515 ///
516 /// The entries are sorted based on the lexicographic order of the
517 /// pretty representation of the type_sptr_sptr.  The sorted result is
518 /// put in a vector of type_base_sptr.
519 ///
520 /// @param map the map to sort.
521 ///
522 /// @param sorted the resulting vector of type_base_sptr
523 /// lexicographically sorted using their pretty representation.
524 void
sort_string_type_base_sptr_map(string_type_base_sptr_map & map,vector<type_base_sptr> & sorted)525 sort_string_type_base_sptr_map(string_type_base_sptr_map& map,
526 			       vector<type_base_sptr>& sorted)
527 {
528   for (string_type_base_sptr_map::const_iterator i = map.begin();
529        i != map.end();
530        ++i)
531     sorted.push_back(i->second);
532 
533   type_or_decl_base_comp comp;
534   std::sort(sorted.begin(), sorted.end(), comp);
535 }
536 
537 /// Return the first underlying type that is not a qualified type.
538 /// @param t the qualified type to consider.
539 ///
540 /// @return the first underlying type that is not a qualified type, or
541 /// NULL if t is NULL.
542 type_base_sptr
get_leaf_type(qualified_type_def_sptr t)543 get_leaf_type(qualified_type_def_sptr t)
544 {
545   if (!t)
546     return type_base_sptr();
547 
548   type_base_sptr ut = t->get_underlying_type();
549   qualified_type_def_sptr qut = dynamic_pointer_cast<qualified_type_def>(ut);
550 
551   if (!qut)
552     return ut;
553   return get_leaf_type(qut);
554 }
555 
556 /// Tests if a given diff node is to represent the changes between two
557 /// gobal decls.
558 ///
559 /// @param d the diff node to consider.
560 ///
561 /// @return true iff @p d represents the changes between two global
562 /// decls.
563 bool
is_diff_of_global_decls(const diff * d)564 is_diff_of_global_decls(const diff* d)
565 {
566   ABG_ASSERT(d != 0);
567 
568   if (d == 0)
569     return false;
570 
571   type_or_decl_base_sptr first = d->first_subject();
572   ABG_ASSERT(first);
573 
574   type_or_decl_base_sptr second = d->first_subject();
575   ABG_ASSERT(second);
576 
577   if (decl_base_sptr decl = is_decl(first))
578     if (is_at_global_scope(decl))
579       if ((decl = is_decl(second)))
580 	if (is_at_global_scope(decl))
581 	  return true;
582 
583   return false;
584 }
585 
586 // -----------------------------------------
587 // </private functions re-usable elsewhere>
588 // -----------------------------------------
589 
590 /// The overloaded or operator for @ref visiting_kind.
591 visiting_kind
operator |(visiting_kind l,visiting_kind r)592 operator|(visiting_kind l, visiting_kind r)
593 {return static_cast<visiting_kind>(static_cast<unsigned>(l)
594 				   | static_cast<unsigned>(r));}
595 
596 /// The overloaded and operator for @ref visiting_kind.
597 visiting_kind
operator &(visiting_kind l,visiting_kind r)598 operator&(visiting_kind l, visiting_kind r)
599 {
600   return static_cast<visiting_kind>(static_cast<unsigned>(l)
601 				    & static_cast<unsigned>(r));
602 }
603 
604 /// The overloaded 'bit inversion' operator for @ref visiting_kind.
605 visiting_kind
operator ~(visiting_kind l)606 operator~(visiting_kind l)
607 {return static_cast<visiting_kind>(~static_cast<unsigned>(l));}
608 
609 /// Test if a diff node is about differences between types.
610 ///
611 /// @param diff the diff node to test.
612 ///
613 /// @return a pointer to the actual type_diff_base* that @p diff
614 /// extends, iff it is about differences between types.
615 const type_diff_base*
is_type_diff(const diff * diff)616 is_type_diff(const diff* diff)
617 {return dynamic_cast<const type_diff_base*>(diff);}
618 
619 /// Test if a diff node is about differences between declarations.
620 ///
621 /// @param diff the diff node to test.
622 ///
623 /// @return a pointer to the actual decl_diff_base @p diff extends,
624 /// iff it is about differences between declarations.
625 const decl_diff_base*
is_decl_diff(const diff * diff)626 is_decl_diff(const diff* diff)
627 {return dynamic_cast<const decl_diff_base*>(diff);}
628 
629 /// Test if a diff node is a @ref class_diff node.
630 ///
631 /// @param diff the diff node to consider.
632 ///
633 /// @return a non-nil pointer to a @ref class_diff iff @p diff is a
634 /// @ref class_diff node.
635 const class_diff*
is_class_diff(const diff * diff)636 is_class_diff(const diff* diff)
637 {return dynamic_cast<const class_diff*>(diff);}
638 
639 /// Test if a diff node is a @ref enum_diff node.
640 ///
641 /// @param diff the diff node to consider.
642 ///
643 /// @return a non-nil pointer to ad @ref enum_diff node iff @p diff is
644 /// a @ref enum_diff node.
645 const enum_diff*
is_enum_diff(const diff * diff)646 is_enum_diff(const diff *diff)
647 {return dynamic_cast<const enum_diff*>(diff);}
648 
649 /// Test if a diff node is a @ref union_diff node.
650 ///
651 /// @param diff the diff node to consider.
652 ///
653 /// @return a non-nil pointer to a @ref union_diff iff @p diff is a
654 /// @ref union_diff node.
655 const union_diff*
is_union_diff(const diff * diff)656 is_union_diff(const diff* diff)
657 {return dynamic_cast<const union_diff*>(diff);}
658 
659 /// Test if a diff node is a @ref class_or_union_diff node.
660 ///
661 /// @param d the diff node to consider.
662 ///
663 /// @return a non-nil pointer to the @ref class_or_union_diff denoted
664 /// by @p d iff @p d is a @ref class_or_union_diff.
665 const class_or_union_diff*
is_class_or_union_diff(const diff * d)666 is_class_or_union_diff(const diff* d)
667 {return dynamic_cast<const class_or_union_diff*>(d);}
668 
669 /// Test if a diff node is a @ref class_or_union_diff between two
670 /// anonymous classes or unions.
671 ///
672 /// @param d the diff node to consider.
673 ///
674 /// @return a non-nil pointer to the @ref class_or_union_diff iff @p
675 /// denoted by @p d iff @p is pointer to an anonymous class or union
676 /// diff.
677 const class_or_union_diff*
is_anonymous_class_or_union_diff(const diff * d)678 is_anonymous_class_or_union_diff(const diff* d)
679 {
680   if (const class_or_union_diff *dif = is_class_or_union_diff(d))
681     if (dif->first_class_or_union()->get_is_anonymous())
682       return dif;
683   return 0;
684 }
685 
686 /// Test if a diff node is a @ref typedef_diff node.
687 ///
688 /// @param diff the diff node to consider.
689 ///
690 /// @return a non-nil pointer to a @ref typedef_diff iff @p diff is a
691 /// @ref typedef_diff node.
692 const typedef_diff*
is_typedef_diff(const diff * diff)693 is_typedef_diff(const diff *diff)
694 {return dynamic_cast<const typedef_diff*>(diff);}
695 
696 /// Test if a diff node is a @ref array_diff node.
697 ///
698 /// @param diff the diff node to consider.
699 ///
700 /// @return a non-nil pointer to a @ref array_diff iff @p diff is a
701 /// @ref array_diff node.
702 const array_diff*
is_array_diff(const diff * diff)703 is_array_diff(const diff* diff)
704 {return dynamic_cast<const array_diff*>(diff);}
705 
706 /// Test if a diff node is a @ref function_type_diff node.
707 ///
708 /// @param diff the diff node to consider.
709 ///
710 /// @return a non-nil pointer to a @ref function_type_diff iff @p diff is a
711 /// @ref function_type_diff node.
712 const function_type_diff*
is_function_type_diff(const diff * diff)713 is_function_type_diff(const diff* diff)
714 {return dynamic_cast<const function_type_diff*>(diff);}
715 
716 /// Test if a given diff node carries a function type change with
717 /// local changes.
718 ///
719 /// @param diff the diff node to consider.
720 ///
721 /// @return a non-nil pointer to a @ref function_type_diff iff @p diff
722 /// is a function_type_diff node that carries a local change.
723 const function_type_diff*
is_function_type_diff_with_local_changes(const diff * diff)724 is_function_type_diff_with_local_changes(const diff* diff)
725 {
726   if (const function_type_diff* d = is_function_type_diff(diff))
727     if (d->has_local_changes())
728       return d;
729 
730   return 0;
731 }
732 
733 /// Test if a diff node is about differences between variables.
734 ///
735 /// @param diff the diff node to test.
736 ///
737 /// @return a pointer to the actual var_diff that @p diff is a type
738 /// of, iff it is about differences between variables.
739 const var_diff*
is_var_diff(const diff * diff)740 is_var_diff(const diff* diff)
741 {
742   const var_diff* d = dynamic_cast<const var_diff*>(diff);
743   if (d)
744     ABG_ASSERT(is_decl_diff(diff));
745   return d;
746 }
747 
748 /// Test if a diff node is about differences between functions.
749 ///
750 /// @param diff the diff node to test.
751 ///
752 /// @return a pointer to the actual var_diff that @p diff is a type
753 /// of, iff it is about differences between variables.
754 const function_decl_diff*
is_function_decl_diff(const diff * diff)755 is_function_decl_diff(const diff* diff)
756 {
757   const function_decl_diff *d = dynamic_cast<const function_decl_diff*>(diff);
758   if (d)
759     ABG_ASSERT(is_decl_diff(diff));
760   return d;
761 }
762 
763 /// Test if a diff node is about differences between two pointers.
764 ///
765 /// @param diff the diff node to consider.
766 ///
767 /// @return the @p diff converted into an instance of @ref
768 /// pointer_diff iff @p diff is about differences between two
769 /// pointers.
770 const pointer_diff*
is_pointer_diff(const diff * diff)771 is_pointer_diff(const diff* diff)
772 {return dynamic_cast<const pointer_diff*>(diff);}
773 
774 /// Test if a diff node is about differences between two references.
775 ///
776 /// @param diff the diff node to consider.
777 ///
778 /// @return the @p diff converted into an instance of @ref
779 /// reference_diff iff @p diff is about differences between two
780 /// references.
781 const reference_diff*
is_reference_diff(const diff * diff)782 is_reference_diff(const diff* diff)
783 {return dynamic_cast<const reference_diff*>(diff);}
784 
785 /// Test if a diff node is about differences between two qualified
786 /// types.
787 ///
788 /// @param diff the diff node to consider.
789 ///
790 /// @return @p diff converted into an instance of @ref
791 /// qualified_type_diff iff @p diff is about differences between two
792 /// qualified types.
793 const qualified_type_diff*
is_qualified_type_diff(const diff * diff)794 is_qualified_type_diff(const diff* diff)
795 {return dynamic_cast<const qualified_type_diff*>(diff);}
796 
797 /// Test if a diff node is a reference or pointer diff node to a
798 /// change that is neither basic type change nor distinct type change.
799 ///
800 /// Note that this function also works on diffs of typedefs of
801 /// reference or pointer.
802 ///
803 /// @param diff the diff node to consider.
804 ///
805 /// @return true iff @p diff is a eference or pointer diff node to a
806 /// change that is neither basic type change nor distinct type change.
807 bool
is_reference_or_ptr_diff_to_non_basic_nor_distinct_types(const diff * diff)808 is_reference_or_ptr_diff_to_non_basic_nor_distinct_types(const diff* diff)
809 {
810   diff = peel_typedef_diff(diff);
811   if (const reference_diff* d = is_reference_diff(diff))
812     {
813       diff = peel_reference_diff(d);
814       if (is_diff_of_basic_type(diff) || is_distinct_diff(diff))
815 	return false;
816       return true;
817     }
818   else if (const pointer_diff *d = is_pointer_diff(diff))
819     {
820       diff = peel_pointer_diff(d);
821       if (is_diff_of_basic_type(diff) || is_distinct_diff(diff))
822 	return false;
823       return true;
824     }
825 
826   return false;
827 }
828 
829 /// Test if a diff node is about differences between two function
830 /// parameters.
831 ///
832 /// @param diff the diff node to consider.
833 ///
834 /// @return the @p diff converted into an instance of @ref
835 /// reference_diff iff @p diff is about differences between two
836 /// function parameters.
837 const fn_parm_diff*
is_fn_parm_diff(const diff * diff)838 is_fn_parm_diff(const diff* diff)
839 {return dynamic_cast<const fn_parm_diff*>(diff);}
840 
841 /// Test if a diff node is about differences between two base class
842 /// specifiers.
843 ///
844 /// @param diff the diff node to consider.
845 ///
846 /// @return the @p diff converted into an instance of @ref base_diff
847 /// iff @p diff is about differences between two base class
848 /// specifiers.
849 const base_diff*
is_base_diff(const diff * diff)850 is_base_diff(const diff* diff)
851 {return dynamic_cast<const base_diff*>(diff);}
852 
853 /// Test if a diff node is about differences between two diff nodes of
854 /// different kinds.
855 ///
856 /// @param diff the diff node to consider.
857 ///
858 /// @return the @p diff converted into an instance of @ref
859 /// distintc_diff iff @p diff is about differences between two diff
860 /// nodes of different kinds.
861 const distinct_diff*
is_distinct_diff(const diff * diff)862 is_distinct_diff(const diff *diff)
863 {return dynamic_cast<const distinct_diff*>(diff);}
864 
865 /// Test if a diff node is a @ref corpus_diff node.
866 ///
867 /// @param diff the diff node to consider.
868 ///
869 /// @return a non-nil pointer to a @ref corpus_diff iff @p diff is a
870 /// @ref corpus_diff node.
871 const corpus_diff*
is_corpus_diff(const diff * diff)872 is_corpus_diff(const diff* diff)
873 {return dynamic_cast<const corpus_diff*>(diff);}
874 
875 /// Test if a diff node is a child node of a function parameter diff node.
876 ///
877 /// @param diff the diff node to test.
878 ///
879 /// @return true iff @p diff is a child node of a function parameter
880 /// diff node.
881 bool
is_child_node_of_function_parm_diff(const diff * diff)882 is_child_node_of_function_parm_diff(const diff* diff)
883 {return diff && is_fn_parm_diff(diff->parent_node());}
884 
885 /// Test if a diff node is a child node of a base diff node.
886 ///
887 /// @param diff the diff node to test.
888 ///
889 /// @return true iff @p diff is a child node of a base diff node.
890 bool
is_child_node_of_base_diff(const diff * diff)891 is_child_node_of_base_diff(const diff* diff)
892 {return diff && is_base_diff(diff->parent_node());}
893 
894 /// The default traverse function.
895 ///
896 /// @return true.
897 bool
traverse(diff_node_visitor &)898 diff_traversable_base::traverse(diff_node_visitor&)
899 {return true;}
900 
diff_context()901 diff_context::diff_context()
902   : priv_(new diff_context::priv)
903 {
904   // Setup all the diff output filters we have.
905   filtering::filter_base_sptr f;
906 
907   f.reset(new filtering::harmless_harmful_filter);
908   add_diff_filter(f);
909 
910   // f.reset(new filtering::harmless_filter);
911   // add_diff_filter(f);
912 
913   // f.reset(new filtering::harmful_filter);
914   // add_diff_filter(f);
915 }
916 
917 diff_context::~diff_context() = default;
918 
919 /// Set the corpus diff relevant to this context.
920 ///
921 /// @param d the corpus_diff we are interested in.
922 void
set_corpus_diff(const corpus_diff_sptr & d)923 diff_context::set_corpus_diff(const corpus_diff_sptr& d)
924 {priv_->corpus_diff_ = d;}
925 
926 /// Get the corpus diff for the current context.
927 ///
928 /// @return the corpus diff of this context.
929 const corpus_diff_sptr&
get_corpus_diff() const930 diff_context::get_corpus_diff() const
931 {return priv_->corpus_diff_;}
932 
933 /// Getter for the first corpus of the corpus diff of the current context.
934 ///
935 /// @return the first corpus of the corpus diff of the current
936 /// context, if no corpus diff is associated to the context.
937 corpus_sptr
get_first_corpus() const938 diff_context::get_first_corpus() const
939 {
940   if (priv_->corpus_diff_)
941     return priv_->corpus_diff_->first_corpus();
942   return corpus_sptr();
943 }
944 
945 /// Getter for the second corpus of the corpus diff of the current
946 /// context.
947 ///
948 /// @return the second corpus of the corpus diff of the current
949 /// context, if no corpus diff is associated to the context.
950 corpus_sptr
get_second_corpus() const951 diff_context::get_second_corpus() const
952 {
953   if (priv_->corpus_diff_)
954     return priv_->corpus_diff_->second_corpus();
955   return corpus_sptr();
956 }
957 
958 /// Getter of the reporter to be used in this context.
959 ///
960 /// @return the reporter to be used in this context.
961 reporter_base_sptr
get_reporter() const962 diff_context::get_reporter() const
963 {
964   if (!priv_->reporter_)
965     {
966       if (show_leaf_changes_only())
967 	priv_->reporter_.reset(new leaf_reporter);
968       else
969 	priv_->reporter_.reset(new default_reporter);
970     }
971   ABG_ASSERT(priv_->reporter_);
972   return priv_->reporter_;
973 }
974 
975 /// Setter of the reporter to be used in this context.
976 ///
977 /// @param r the reporter to be used in this context.
978 void
set_reporter(reporter_base_sptr & r)979 diff_context::set_reporter(reporter_base_sptr& r)
980 {priv_->reporter_ = r;}
981 
982 /// Tests if the current diff context already has a diff for two decls.
983 ///
984 /// @param first the first decl to consider.
985 ///
986 /// @param second the second decl to consider.
987 ///
988 /// @return a pointer to the diff for @p first @p second if found,
989 /// null otherwise.
990 diff_sptr
has_diff_for(const type_or_decl_base_sptr first,const type_or_decl_base_sptr second) const991 diff_context::has_diff_for(const type_or_decl_base_sptr first,
992 			   const type_or_decl_base_sptr second) const
993 {
994   types_or_decls_diff_map_type::const_iterator i =
995     priv_->types_or_decls_diff_map.find(std::make_pair(first, second));
996   if (i != priv_->types_or_decls_diff_map.end())
997     return i->second;
998   return diff_sptr();
999 }
1000 
1001 /// Tests if the current diff context already has a diff for two types.
1002 ///
1003 /// @param first the first type to consider.
1004 ///
1005 /// @param second the second type to consider.
1006 ///
1007 /// @return a pointer to the diff for @p first @p second if found,
1008 /// null otherwise.
1009 diff_sptr
has_diff_for_types(const type_base_sptr first,const type_base_sptr second) const1010 diff_context::has_diff_for_types(const type_base_sptr first,
1011 				  const type_base_sptr second) const
1012 {return has_diff_for(first, second);}
1013 
1014 /// Tests if the current diff context already has a given diff.
1015 ///
1016 ///@param d the diff to consider.
1017 ///
1018 /// @return a pointer to the diff found for @p d
1019 const diff*
has_diff_for(const diff * d) const1020 diff_context::has_diff_for(const diff* d) const
1021 {return has_diff_for(d->first_subject(), d->second_subject()).get();}
1022 
1023 /// Tests if the current diff context already has a given diff.
1024 ///
1025 ///@param d the diff to consider.
1026 ///
1027 /// @return a pointer to the diff found for @p d
1028 diff_sptr
has_diff_for(const diff_sptr d) const1029 diff_context::has_diff_for(const diff_sptr d) const
1030 {return has_diff_for(d->first_subject(), d->second_subject());}
1031 
1032 /// Getter for the bitmap that represents the set of categories that
1033 /// the user wants to see reported.
1034 ///
1035 /// @return a bitmap that represents the set of categories that the
1036 /// user wants to see reported.
1037 diff_category
get_allowed_category() const1038 diff_context::get_allowed_category() const
1039 {return priv_->allowed_category_;}
1040 
1041 /// Setter for the bitmap that represents the set of categories that
1042 /// the user wants to see reported.
1043 ///
1044 /// @param c a bitmap that represents the set of categories that the
1045 /// user wants to see represented.
1046 void
set_allowed_category(diff_category c)1047 diff_context::set_allowed_category(diff_category c)
1048 {priv_->allowed_category_ = c;}
1049 
1050 /// Setter for the bitmap that represents the set of categories that
1051 /// the user wants to see reported
1052 ///
1053 /// This function perform a bitwise or between the new set of
1054 /// categories and the current ones, and then sets the current
1055 /// categories to the result of the or.
1056 ///
1057 /// @param c a bitmap that represents the set of categories that the
1058 /// user wants to see represented.
1059 void
switch_categories_on(diff_category c)1060 diff_context::switch_categories_on(diff_category c)
1061 {priv_->allowed_category_ = priv_->allowed_category_ | c;}
1062 
1063 /// Setter for the bitmap that represents the set of categories that
1064 /// the user wants to see reported
1065 ///
1066 /// This function actually unsets bits from the current categories.
1067 ///
1068 /// @param c a bitmap that represents the set of categories to unset
1069 /// from the current categories.
1070 void
switch_categories_off(diff_category c)1071 diff_context::switch_categories_off(diff_category c)
1072 {priv_->allowed_category_ = priv_->allowed_category_ & ~c;}
1073 
1074 /// Add a diff for two decls to the cache of the current diff_context.
1075 ///
1076 /// Doing this allows to later find the added diff from its two
1077 /// subject decls.
1078 ///
1079 /// @param first the first decl to consider.
1080 ///
1081 /// @param second the second decl to consider.
1082 ///
1083 /// @param the diff to add.
1084 void
add_diff(type_or_decl_base_sptr first,type_or_decl_base_sptr second,const diff_sptr d)1085 diff_context::add_diff(type_or_decl_base_sptr first,
1086 		       type_or_decl_base_sptr second,
1087 		       const diff_sptr d)
1088 {priv_->types_or_decls_diff_map[std::make_pair(first, second)] = d;}
1089 
1090 /// Add a diff tree node to the cache of the current diff_context
1091 ///
1092 /// @param d the diff tree node to add.
1093 void
add_diff(const diff * d)1094 diff_context::add_diff(const diff* d)
1095 {
1096   if (d)
1097     {
1098       diff_sptr dif(const_cast<diff*>(d), noop_deleter());
1099       add_diff(d->first_subject(), d->second_subject(), dif);
1100     }
1101 }
1102 
1103 /// Add a diff tree node to the cache of the current diff_context
1104 ///
1105 /// @param d the diff tree node to add.
1106 void
add_diff(const diff_sptr d)1107 diff_context::add_diff(const diff_sptr d)
1108 {
1109   if (d)
1110       add_diff(d->first_subject(), d->second_subject(), d);
1111 }
1112 
1113 /// Getter for the @ref CanonicalDiff "canonical diff node" for the
1114 /// @ref diff represented by their two subjects.
1115 ///
1116 /// @param first the first subject of the diff.
1117 ///
1118 /// @param second the second subject of the diff.
1119 ///
1120 /// @return the canonical diff for the diff node represented by the
1121 /// two diff subjects @p first and @p second.  If no canonical diff
1122 /// node was registered for these subjects, then a nil node is
1123 /// returned.
1124 diff_sptr
get_canonical_diff_for(const type_or_decl_base_sptr first,const type_or_decl_base_sptr second) const1125 diff_context::get_canonical_diff_for(const type_or_decl_base_sptr first,
1126 				     const type_or_decl_base_sptr second) const
1127 {return has_diff_for(first, second);}
1128 
1129 /// Getter for the @ref CanonicalDiff "canonical diff node" for the
1130 /// @ref diff represented by the two subjects of a given diff node.
1131 ///
1132 /// @param d the diff node to get the canonical node for.
1133 ///
1134 /// @return the canonical diff for the diff node represented by the
1135 /// two diff subjects of @p d.  If no canonical diff node was
1136 /// registered for these subjects, then a nil node is returned.
1137 diff_sptr
get_canonical_diff_for(const diff_sptr d) const1138 diff_context::get_canonical_diff_for(const diff_sptr d) const
1139 {return has_diff_for(d);}
1140 
1141 /// Setter for the @ref CanonicalDiff "canonical diff node" for the
1142 /// @ref diff represented by their two subjects.
1143 ///
1144 /// @param first the first subject of the diff.
1145 ///
1146 /// @param second the second subject of the diff.
1147 ///
1148 /// @param d the new canonical diff.
1149 void
set_canonical_diff_for(const type_or_decl_base_sptr first,const type_or_decl_base_sptr second,const diff_sptr d)1150 diff_context::set_canonical_diff_for(const type_or_decl_base_sptr first,
1151 				     const type_or_decl_base_sptr second,
1152 				     const diff_sptr d)
1153 {
1154   ABG_ASSERT(d);
1155   if (!has_diff_for(first, second))
1156     {
1157       add_diff(first, second, d);
1158       priv_->canonical_diffs.push_back(d);
1159     }
1160 }
1161 
1162 /// If there is is a @ref CanonicalDiff "canonical diff node"
1163 /// registered for two diff subjects, return it.  Otherwise, register
1164 /// a canonical diff node for these two diff subjects and return it.
1165 ///
1166 /// @param first the first subject of the diff.
1167 ///
1168 /// @param second the second subject of the diff.
1169 ///
1170 /// @param d the new canonical diff node.
1171 ///
1172 /// @return the canonical diff node.
1173 diff_sptr
set_or_get_canonical_diff_for(const type_or_decl_base_sptr first,const type_or_decl_base_sptr second,const diff_sptr canonical_diff)1174 diff_context::set_or_get_canonical_diff_for(const type_or_decl_base_sptr first,
1175 					    const type_or_decl_base_sptr second,
1176 					    const diff_sptr canonical_diff)
1177 {
1178   ABG_ASSERT(canonical_diff);
1179 
1180   diff_sptr canonical = get_canonical_diff_for(first, second);
1181   if (!canonical)
1182     {
1183       canonical = canonical_diff;
1184       set_canonical_diff_for(first, second, canonical);
1185     }
1186   return canonical;
1187 }
1188 
1189 /// Set the canonical diff node property of a given diff node
1190 /// appropriately.
1191 ///
1192 /// For a given diff node that has no canonical diff node, retrieve
1193 /// the canonical diff node (by looking at its diff subjects and at
1194 /// the current context) and set the canonical diff node property of
1195 /// the diff node to that canonical diff node.  If no canonical diff
1196 /// node has been registered to the diff context for the subjects of
1197 /// the diff node then, register the canonical diff node as being the
1198 /// diff node itself; and set its canonical diff node property as
1199 /// such.  Otherwise, if the diff node already has a canonical diff
1200 /// node, do nothing.
1201 ///
1202 /// @param diff the diff node to initialize the canonical diff node
1203 /// property for.
1204 void
initialize_canonical_diff(const diff_sptr diff)1205 diff_context::initialize_canonical_diff(const diff_sptr diff)
1206 {
1207   if (diff->get_canonical_diff() == 0)
1208     {
1209       diff_sptr canonical =
1210 	set_or_get_canonical_diff_for(diff->first_subject(),
1211 				      diff->second_subject(),
1212 				      diff);
1213       diff->set_canonical_diff(canonical.get());
1214     }
1215 }
1216 
1217 /// Add a diff node to the set of diff nodes that are kept alive for
1218 /// the life time of the current instance of diff_context.
1219 ///
1220 /// Note that diff added to the diff cache are kept alive as well, and
1221 /// don't need to be passed to this function to be kept alive.
1222 ///
1223 /// @param d the diff node to be kept alive during the life time of
1224 /// the current instance of @ref diff_context.
1225 void
keep_diff_alive(diff_sptr & d)1226 diff_context::keep_diff_alive(diff_sptr& d)
1227 {priv_->live_diffs_.insert(d);}
1228 
1229 /// Test if a diff node has been traversed.
1230 ///
1231 /// @param d the diff node to consider.
1232 ///
1233 /// @return the first diff node against which @p d is redundant.
1234 diff*
diff_has_been_visited(const diff * d) const1235 diff_context::diff_has_been_visited(const diff* d) const
1236 {
1237   const diff* canonical = d->get_canonical_diff();
1238   ABG_ASSERT(canonical);
1239 
1240   size_t ptr_value = reinterpret_cast<size_t>(canonical);
1241   pointer_map::iterator it = priv_->visited_diff_nodes_.find(ptr_value);
1242   if (it != priv_->visited_diff_nodes_.end())
1243     return reinterpret_cast<diff*>(it->second);
1244   else
1245     return 0;
1246 }
1247 
1248 /// Test if a diff node has been traversed.
1249 ///
1250 /// @param d the diff node to consider.
1251 ///
1252 /// @return the first diff node against which @p d is redundant.
1253 diff_sptr
diff_has_been_visited(const diff_sptr d) const1254 diff_context::diff_has_been_visited(const diff_sptr d) const
1255 {
1256   diff_sptr diff(diff_has_been_visited(d.get()));
1257   return diff;
1258 }
1259 
1260 /// Mark a diff node as traversed by a traversing algorithm.
1261 ///
1262 /// Actually, it's the @ref CanonicalDiff "canonical diff" of this
1263 /// node that is marked as traversed.
1264 ///
1265 /// Subsequent invocations of diff_has_been_visited() on the diff node
1266 /// will yield true.
1267 void
mark_diff_as_visited(const diff * d)1268 diff_context::mark_diff_as_visited(const diff* d)
1269 {
1270   if (diff_has_been_visited(d))
1271     return;
1272 
1273   const diff* canonical = d->get_canonical_diff();
1274   ABG_ASSERT(canonical);
1275 
1276    size_t canonical_ptr_value = reinterpret_cast<size_t>(canonical);
1277    size_t diff_ptr_value = reinterpret_cast<size_t>(d);
1278    priv_->visited_diff_nodes_[canonical_ptr_value] = diff_ptr_value;
1279 }
1280 
1281 /// Unmark all the diff nodes that were marked as being traversed.
1282 void
forget_visited_diffs()1283 diff_context::forget_visited_diffs()
1284 {priv_->visited_diff_nodes_.clear();}
1285 
1286 /// This sets a flag that, if it's true, then during the traversing of
1287 /// a diff nodes tree each node is visited at most once.
1288 ///
1289 /// @param f if true then during the traversing of a diff nodes tree
1290 /// each node is visited at most once.
1291 ///
1292 void
forbid_visiting_a_node_twice(bool f)1293 diff_context::forbid_visiting_a_node_twice(bool f)
1294 {priv_->forbid_visiting_a_node_twice_ = f;}
1295 
1296 /// This function sets a flag os that if @ref
1297 ///  forbid_visiting_a_node_twice() returns true, then each time the
1298 ///  node visitor starts visiting a new interface, it resets the
1299 ///  memory the systems has about already visited node.
1300 ///
1301 ///  @param f the flag to set.
1302 void
forbid_visiting_a_node_twice_per_interface(bool f)1303 diff_context::forbid_visiting_a_node_twice_per_interface(bool f)
1304 {priv_->reset_visited_diffs_for_each_interface_ = f;}
1305 
1306 /// Return a flag that, if true, then during the traversing of a diff
1307 /// nodes tree each node is visited at most once.
1308 ///
1309 /// @return the boolean flag.
1310 bool
visiting_a_node_twice_is_forbidden() const1311 diff_context::visiting_a_node_twice_is_forbidden() const
1312 {return priv_->forbid_visiting_a_node_twice_;}
1313 
1314 /// Return a flag that, if true, then during the traversing of a diff
1315 /// nodes tree each node is visited at most once, while visiting the
1316 /// diff tree underneath a given interface (public function or
1317 /// variable).  Each time a new interface is visited, the nodes
1318 /// visited while visiting previous interfaces can be visited again.
1319 ///
1320 /// @return the boolean flag.
1321 ///
1322 /// @return the boolean flag.
1323 bool
visiting_a_node_twice_is_forbidden_per_interface() const1324 diff_context::visiting_a_node_twice_is_forbidden_per_interface() const
1325 {
1326   return (priv_->forbid_visiting_a_node_twice_
1327 	  && priv_->reset_visited_diffs_for_each_interface_);
1328 }
1329 
1330 /// Getter for the diff tree nodes filters to apply to diff sub-trees.
1331 ///
1332 /// @return the vector of tree filters to apply to diff sub-trees.
1333 const filtering::filters&
diff_filters() const1334 diff_context::diff_filters() const
1335 {return priv_->filters_;}
1336 
1337 /// Setter for the diff filters to apply to a given diff sub-tree.
1338 ///
1339 /// @param f the new diff filter to add to the vector of diff filters
1340 /// to apply to diff sub-trees.
1341 void
add_diff_filter(filtering::filter_base_sptr f)1342 diff_context::add_diff_filter(filtering::filter_base_sptr f)
1343 {priv_->filters_.push_back(f);}
1344 
1345 /// Apply the diff filters to a given diff sub-tree.
1346 ///
1347 /// If the current context is instructed to filter out some categories
1348 /// then this function walks the given sub-tree and categorizes its
1349 /// nodes by using the filters held by the context.
1350 ///
1351 /// @param diff the diff sub-tree to apply the filters to.
1352 void
maybe_apply_filters(diff_sptr diff)1353 diff_context::maybe_apply_filters(diff_sptr diff)
1354 {
1355   if (!diff)
1356     return;
1357 
1358   if (get_allowed_category() == EVERYTHING_CATEGORY)
1359     return;
1360 
1361   if (!diff->has_changes())
1362     return;
1363 
1364   for (filtering::filters::const_iterator i = diff_filters().begin();
1365        i != diff_filters().end();
1366        ++i)
1367     {
1368       filtering::apply_filter(*i, diff);
1369       propagate_categories(diff);
1370     }
1371 
1372  }
1373 
1374 /// Apply the diff filters to the diff nodes of a @ref corpus_diff
1375 /// instance.
1376 ///
1377 /// If the current context is instructed to filter out some categories
1378 /// then this function walks the diff tree and categorizes its nodes
1379 /// by using the filters held by the context.
1380 ///
1381 /// @param diff the corpus diff to apply the filters to.
1382 void
maybe_apply_filters(corpus_diff_sptr diff)1383 diff_context::maybe_apply_filters(corpus_diff_sptr diff)
1384 {
1385 
1386   if (!diff || !diff->has_changes())
1387     return;
1388 
1389   for (filtering::filters::const_iterator i = diff_filters().begin();
1390        i != diff_filters().end();
1391        ++i)
1392     {
1393       filtering::apply_filter(**i, diff);
1394       propagate_categories(diff);
1395     }
1396 }
1397 
1398 /// Getter for the vector of suppressions that specify which diff node
1399 /// reports should be dropped on the floor.
1400 ///
1401 /// @return the set of suppressions.
1402 suppressions_type&
suppressions() const1403 diff_context::suppressions() const
1404 {return priv_->suppressions_;}
1405 
1406 /// Add a new suppression specification that specifies which diff node
1407 /// reports should be dropped on the floor.
1408 ///
1409 /// @param suppr the new suppression specification to add to the
1410 /// existing set of suppressions specifications of the diff context.
1411 void
add_suppression(const suppression_sptr suppr)1412 diff_context::add_suppression(const suppression_sptr suppr)
1413 {priv_->suppressions_.push_back(suppr);}
1414 
1415 /// Add new suppression specifications that specify which diff node
1416 /// reports should be dropped on the floor.
1417 ///
1418 /// @param supprs the new suppression specifications to add to the
1419 /// existing set of suppression specifications of the diff context.
1420 void
add_suppressions(const suppressions_type & supprs)1421 diff_context::add_suppressions(const suppressions_type& supprs)
1422 {
1423   priv_->suppressions_.insert(priv_->suppressions_.end(),
1424 			      supprs.begin(), supprs.end());
1425 }
1426 
1427 /// Set the flag that indicates if the diff using this context should
1428 /// show only leaf changes or not.
1429 ///
1430 /// @param f the new value of the flag that indicates if the diff
1431 /// using this context should show only leaf changes or not.
1432 void
show_leaf_changes_only(bool f)1433 diff_context::show_leaf_changes_only(bool f)
1434 {
1435   // This function can be called only if the reporter hasn't yet been
1436   // created.  Once it's been created, we are supposed to live with
1437   // it.
1438   ABG_ASSERT(priv_->reporter_ == 0);
1439   priv_->leaf_changes_only_ = f;
1440 }
1441 
1442 /// Get the flag that indicates if the diff using this context should
1443 /// show only leaf changes or not.
1444 ///
1445 /// @return the value of the flag that indicates if the diff using
1446 /// this context should show only leaf changes or not.
1447 bool
show_leaf_changes_only() const1448 diff_context::show_leaf_changes_only() const
1449 {return priv_->leaf_changes_only_;}
1450 
1451 /// Get the flag that indicates if the diff reports using this context
1452 /// should show sizes and offsets in an hexadecimal base or not.  If
1453 /// not, then they are to be shown in a decimal base.
1454 ///
1455 /// @return true iff sizes and offsets are to be shown in an
1456 /// hexadecimal base.
1457 bool
show_hex_values() const1458 diff_context::show_hex_values() const
1459 {return priv_->hex_values_;}
1460 
1461 /// Set the flag that indicates if diff reports using this context
1462 /// should show sizes and offsets in an hexadecimal base or not.  If
1463 /// not, then they are to be shown in a decimal base.
1464 ///
1465 /// @param f if true then sizes and offsets are to be shown in an
1466 /// hexadecimal base.
1467 void
show_hex_values(bool f)1468 diff_context::show_hex_values(bool f)
1469 {priv_->hex_values_ = f;}
1470 
1471 /// Get the flag that indicates if diff reports using this context
1472 /// should show sizes and offsets in bits, rather than bytes.
1473 ///
1474 /// @return true iff sizes and offsets are to be shown in bits.
1475 /// Otherwise they are to be shown in bytes.
1476 bool
show_offsets_sizes_in_bits() const1477 diff_context::show_offsets_sizes_in_bits() const
1478 {return priv_->show_offsets_sizes_in_bits_;}
1479 
1480 /// Set the flag that indicates if diff reports using this context
1481 /// should show sizes and offsets in bits, rather than bytes.
1482 ///
1483 /// @param f if true then sizes and offsets are to be shown in bits.
1484 /// Otherwise they are to be shown in bytes.
1485 void
show_offsets_sizes_in_bits(bool f)1486 diff_context::show_offsets_sizes_in_bits(bool f)
1487 {priv_->show_offsets_sizes_in_bits_ = f;}
1488 
1489 /// Set a flag saying if offset changes should be reported in a
1490 /// relative way.  That is, if the report should say how of many bits
1491 /// a class/struct data member did move.
1492 ///
1493 /// @param f the new boolean value of the flag.
1494 void
show_relative_offset_changes(bool f)1495 diff_context::show_relative_offset_changes(bool f)
1496 {priv_->show_relative_offset_changes_ = f;}
1497 
1498 /// Get the flag saying if offset changes should be reported in a
1499 /// relative way.  That is, if the report should say how of many bits
1500 /// a class/struct data member did move.
1501 ///
1502 /// @return the boolean value of the flag.
1503 bool
show_relative_offset_changes(void)1504 diff_context::show_relative_offset_changes(void)
1505 {return priv_->show_relative_offset_changes_;}
1506 
1507 /// Set a flag saying if the comparison module should only show the
1508 /// diff stats.
1509 ///
1510 /// @param f the flag to set.
1511 void
show_stats_only(bool f)1512 diff_context::show_stats_only(bool f)
1513 {priv_->show_stats_only_ = f;}
1514 
1515 /// Test if the comparison module should only show the diff stats.
1516 ///
1517 /// @return true if the comparison module should only show the diff
1518 /// stats, false otherwise.
1519 bool
show_stats_only() const1520 diff_context::show_stats_only() const
1521 {return priv_->show_stats_only_;}
1522 
1523 /// Setter for the property that says if the comparison module should
1524 /// show the soname changes in its report.
1525 ///
1526 /// @param f the new value of the property.
1527 void
show_soname_change(bool f)1528 diff_context::show_soname_change(bool f)
1529 {priv_->show_soname_change_ = f;}
1530 
1531 /// Getter for the property that says if the comparison module should
1532 /// show the soname changes in its report.
1533 ///
1534 /// @return the value of the property.
1535 bool
show_soname_change() const1536 diff_context::show_soname_change() const
1537 {return priv_->show_soname_change_;}
1538 
1539 /// Setter for the property that says if the comparison module should
1540 /// show the architecture changes in its report.
1541 ///
1542 /// @param f the new value of the property.
1543 void
show_architecture_change(bool f)1544 diff_context::show_architecture_change(bool f)
1545 {priv_->show_architecture_change_ = f;}
1546 
1547 /// Getter for the property that says if the comparison module should
1548 /// show the architecture changes in its report.
1549 ///
1550 /// @return the value of the property.
1551 bool
show_architecture_change() const1552 diff_context::show_architecture_change() const
1553 {return priv_->show_architecture_change_;}
1554 
1555 /// Set a flag saying to show the deleted functions.
1556 ///
1557 /// @param f true to show deleted functions.
1558 void
show_deleted_fns(bool f)1559 diff_context::show_deleted_fns(bool f)
1560 {priv_->show_deleted_fns_ = f;}
1561 
1562 /// @return true if we want to show the deleted functions, false
1563 /// otherwise.
1564 bool
show_deleted_fns() const1565 diff_context::show_deleted_fns() const
1566 {return priv_->show_deleted_fns_;}
1567 
1568 /// Set a flag saying to show the changed functions.
1569 ///
1570 /// @param f true to show the changed functions.
1571 void
show_changed_fns(bool f)1572 diff_context::show_changed_fns(bool f)
1573 {priv_->show_changed_fns_ = f;}
1574 
1575 /// @return true if we want to show the changed functions, false otherwise.
1576 bool
show_changed_fns() const1577 diff_context::show_changed_fns() const
1578 {return priv_->show_changed_fns_;}
1579 
1580 /// Set a flag saying to show the added functions.
1581 ///
1582 /// @param f true to show the added functions.
1583 void
show_added_fns(bool f)1584 diff_context::show_added_fns(bool f)
1585 {priv_->show_added_fns_ = f;}
1586 
1587 /// @return true if we want to show the added functions, false
1588 /// otherwise.
1589 bool
show_added_fns() const1590 diff_context::show_added_fns() const
1591 {return priv_->show_added_fns_;}
1592 
1593 /// Set a flag saying to show the deleted variables.
1594 ///
1595 /// @param f true to show the deleted variables.
1596 void
show_deleted_vars(bool f)1597 diff_context::show_deleted_vars(bool f)
1598 {priv_->show_deleted_vars_ = f;}
1599 
1600 /// @return true if we want to show the deleted variables, false
1601 /// otherwise.
1602 bool
show_deleted_vars() const1603 diff_context::show_deleted_vars() const
1604 {return priv_->show_deleted_vars_;}
1605 
1606 /// Set a flag saying to show the changed variables.
1607 ///
1608 /// @param f true to show the changed variables.
1609 void
show_changed_vars(bool f)1610 diff_context::show_changed_vars(bool f)
1611 {priv_->show_changed_vars_ = f;}
1612 
1613 /// @return true if we want to show the changed variables, false otherwise.
1614 bool
show_changed_vars() const1615 diff_context::show_changed_vars() const
1616 {return priv_->show_changed_vars_;}
1617 
1618 /// Set a flag saying to show the added variables.
1619 ///
1620 /// @param f true to show the added variables.
1621 void
show_added_vars(bool f)1622 diff_context::show_added_vars(bool f)
1623 {priv_->show_added_vars_ = f;}
1624 
1625 /// @return true if we want to show the added variables, false
1626 /// otherwise.
1627 bool
show_added_vars() const1628 diff_context::show_added_vars() const
1629 {return priv_->show_added_vars_;}
1630 
1631 bool
show_linkage_names() const1632 diff_context::show_linkage_names() const
1633 {return priv_->show_linkage_names_;}
1634 
1635 void
show_linkage_names(bool f)1636 diff_context::show_linkage_names(bool f)
1637 {priv_->show_linkage_names_= f;}
1638 
1639 /// Set a flag saying to show location information.
1640 ///
1641 /// @param f true to show location information.
1642 void
show_locs(bool f)1643 diff_context::show_locs(bool f)
1644 {priv_->show_locs_= f;}
1645 
1646 /// @return true if we want to show location information, false
1647 /// otherwise.
1648 bool
show_locs() const1649 diff_context::show_locs() const
1650 {return priv_->show_locs_;}
1651 
1652 /// A getter for the flag that says if we should report about
1653 /// functions or variables diff nodes that have *exclusively*
1654 /// redundant diff tree children nodes.
1655 ///
1656 /// @return the flag.
1657 bool
show_redundant_changes() const1658 diff_context::show_redundant_changes() const
1659 {return priv_->show_redundant_changes_;}
1660 
1661 /// A setter for the flag that says if we should report about
1662 /// functions or variables diff nodes that have *exclusively*
1663 /// redundant diff tree children nodes.
1664 ///
1665 /// @param f the flag to set.
1666 void
show_redundant_changes(bool f)1667 diff_context::show_redundant_changes(bool f)
1668 {priv_->show_redundant_changes_ = f;}
1669 
1670 /// Getter for the flag that indicates if symbols not referenced by
1671 /// any debug info are to be compared and reported about.
1672 ///
1673 /// @return the boolean flag.
1674 bool
show_symbols_unreferenced_by_debug_info() const1675 diff_context::show_symbols_unreferenced_by_debug_info() const
1676 {return priv_->show_syms_unreferenced_by_di_;}
1677 
1678 /// Setter for the flag that indicates if symbols not referenced by
1679 /// any debug info are to be compared and reported about.
1680 ///
1681 /// @param f the new flag to set.
1682 void
show_symbols_unreferenced_by_debug_info(bool f)1683 diff_context::show_symbols_unreferenced_by_debug_info(bool f)
1684 {priv_->show_syms_unreferenced_by_di_ = f;}
1685 
1686 /// Getter for the flag that indicates if symbols not referenced by
1687 /// any debug info and that got added are to be reported about.
1688 ///
1689 /// @return true iff symbols not referenced by any debug info and that
1690 /// got added are to be reported about.
1691 bool
show_added_symbols_unreferenced_by_debug_info() const1692 diff_context::show_added_symbols_unreferenced_by_debug_info() const
1693 {return priv_->show_added_syms_unreferenced_by_di_;}
1694 
1695 /// Setter for the flag that indicates if symbols not referenced by
1696 /// any debug info and that got added are to be reported about.
1697 ///
1698 /// @param f the new flag that says if symbols not referenced by any
1699 /// debug info and that got added are to be reported about.
1700 void
show_added_symbols_unreferenced_by_debug_info(bool f)1701 diff_context::show_added_symbols_unreferenced_by_debug_info(bool f)
1702 {priv_->show_added_syms_unreferenced_by_di_ = f;}
1703 
1704 /// Setter for the flag that indicates if changes on types unreachable
1705 /// from global functions and variables are to be reported.
1706 ///
1707 /// @param f if true, then changes on types unreachable from global
1708 /// functions and variables are to be reported.
1709 void
show_unreachable_types(bool f)1710 diff_context::show_unreachable_types(bool f)
1711 {priv_->show_unreachable_types_ = f;}
1712 
1713 /// Getter for the flag that indicates if changes on types unreachable
1714 /// from global functions and variables are to be reported.
1715 ///
1716 /// @return true iff changes on types unreachable from global
1717 /// functions and variables are to be reported.
1718 bool
show_unreachable_types()1719 diff_context::show_unreachable_types()
1720 {return priv_->show_unreachable_types_;}
1721 
1722 /// Getter of the flag that indicates if the leaf reporter should
1723 /// display a summary of the interfaces impacted by a given leaf
1724 /// change or not.
1725 ///
1726 /// @return the flag that indicates if the leaf reporter should
1727 /// display a summary of the interfaces impacted by a given leaf
1728 /// change or not.
1729 bool
show_impacted_interfaces() const1730 diff_context::show_impacted_interfaces() const
1731 {return priv_->show_impacted_interfaces_;}
1732 
1733 /// Setter of the flag that indicates if the leaf reporter should
1734 /// display a summary of the interfaces impacted by a given leaf
1735 /// change or not.
1736 ///
1737 /// @param f the new value of the flag that indicates if the leaf
1738 /// reporter should display a summary of the interfaces impacted by a
1739 /// given leaf change or not.
1740 void
show_impacted_interfaces(bool f)1741 diff_context::show_impacted_interfaces(bool f)
1742 {priv_->show_impacted_interfaces_ = f;}
1743 
1744 /// Setter for the default output stream used by code of the
1745 /// comparison engine.  By default the default output stream is a NULL
1746 /// pointer.
1747 ///
1748 /// @param o a pointer to the default output stream.
1749 void
default_output_stream(ostream * o)1750 diff_context::default_output_stream(ostream* o)
1751 {priv_->default_output_stream_ = o;}
1752 
1753 /// Getter for the default output stream used by code of the
1754 /// comparison engine.  By default the default output stream is a NULL
1755 /// pointer.
1756 ///
1757 /// @return a pointer to the default output stream.
1758 ostream*
default_output_stream()1759 diff_context::default_output_stream()
1760 {return priv_->default_output_stream_;}
1761 
1762 /// Setter for the errror output stream used by code of the comparison
1763 /// engine.  By default the error output stream is a NULL pointer.
1764 ///
1765 /// @param o a pointer to the error output stream.
1766 void
error_output_stream(ostream * o)1767 diff_context::error_output_stream(ostream* o)
1768 {priv_->error_output_stream_ = o;}
1769 
1770 /// Getter for the errror output stream used by code of the comparison
1771 /// engine.  By default the error output stream is a NULL pointer.
1772 ///
1773 /// @return a pointer to the error output stream.
1774 ostream*
error_output_stream() const1775 diff_context::error_output_stream() const
1776 {return priv_->error_output_stream_;}
1777 
1778 /// Test if the comparison engine should dump the diff tree for the
1779 /// changed functions and variables it has.
1780 ///
1781 /// @return true if after the comparison, the engine should dump the
1782 /// diff tree for the changed functions and variables it has.
1783 bool
dump_diff_tree() const1784 diff_context::dump_diff_tree() const
1785 {return priv_->dump_diff_tree_;}
1786 
1787 /// Set if the comparison engine should dump the diff tree for the
1788 /// changed functions and variables it has.
1789 ///
1790 /// @param f true if after the comparison, the engine should dump the
1791 /// diff tree for the changed functions and variables it has.
1792 void
dump_diff_tree(bool f)1793 diff_context::dump_diff_tree(bool f)
1794 {priv_->dump_diff_tree_ = f;}
1795 
1796 /// Emit a textual representation of a diff tree to the error output
1797 /// stream of the current context, for debugging purposes.
1798 ///
1799 /// @param d the diff tree to serialize to the error output associated
1800 /// to the current instance of @ref diff_context.
1801 void
do_dump_diff_tree(const diff_sptr d) const1802 diff_context::do_dump_diff_tree(const diff_sptr d) const
1803 {
1804   if (error_output_stream())
1805     print_diff_tree(d, *error_output_stream());
1806 }
1807 
1808 /// Emit a textual representation of a @ref corpus_diff tree to the error
1809 /// output stream of the current context, for debugging purposes.
1810 ///
1811 /// @param d the @ref corpus_diff tree to serialize to the error
1812 /// output associated to the current instance of @ref diff_context.
1813 void
do_dump_diff_tree(const corpus_diff_sptr d) const1814 diff_context::do_dump_diff_tree(const corpus_diff_sptr d) const
1815 {
1816   if (error_output_stream())
1817     print_diff_tree(d, *error_output_stream());
1818 }
1819 // </diff_context stuff>
1820 
1821 // <diff stuff>
1822 
1823 /// Constructor for the @ref diff type.
1824 ///
1825 /// This constructs a diff between two subjects that are actually
1826 /// declarations; the first and the second one.
1827 ///
1828 /// @param first_subject the first decl (subject) of the diff.
1829 ///
1830 /// @param second_subject the second decl (subject) of the diff.
diff(type_or_decl_base_sptr first_subject,type_or_decl_base_sptr second_subject)1831 diff::diff(type_or_decl_base_sptr first_subject,
1832 	   type_or_decl_base_sptr second_subject)
1833   : priv_(new priv(first_subject, second_subject,
1834 		   diff_context_sptr(),
1835 		   NO_CHANGE_CATEGORY,
1836 		   /*reported_once=*/false,
1837 		   /*currently_reporting=*/false))
1838 {}
1839 
1840 /// Constructor for the @ref diff type.
1841 ///
1842 /// This constructs a diff between two subjects that are actually
1843 /// declarations; the first and the second one.
1844 ///
1845 /// @param first_subject the first decl (subject) of the diff.
1846 ///
1847 /// @param second_subject the second decl (subject) of the diff.
1848 ///
1849 /// @param ctxt the context of the diff.  Note that this context
1850 /// object must stay alive during the entire life time of the current
1851 /// instance of @ref diff.  Otherwise, memory corruption issues occur.
diff(type_or_decl_base_sptr first_subject,type_or_decl_base_sptr second_subject,diff_context_sptr ctxt)1852 diff::diff(type_or_decl_base_sptr	first_subject,
1853 	   type_or_decl_base_sptr	second_subject,
1854 	   diff_context_sptr	ctxt)
1855   : priv_(new priv(first_subject, second_subject,
1856 		   ctxt, NO_CHANGE_CATEGORY,
1857 		   /*reported_once=*/false,
1858 		   /*currently_reporting=*/false))
1859 {}
1860 
1861 /// Flag a given diff node as being traversed.
1862 ///
1863 /// For certain diff nodes like @ref class_diff, it's important to
1864 /// avoid traversing the node again while it's already being
1865 /// traversed; otherwise this leads to infinite loops.  So the
1866 /// diff::begin_traversing() and diff::end_traversing() methods flag a
1867 /// given node as being traversed (or not), so that
1868 /// diff::is_traversing() can tell if the node is being traversed.
1869 ///
1870 /// Note that traversing a node means visiting it *and* visiting its
1871 /// children nodes.
1872 ///
1873 /// The canonical node is marked as being traversed too.
1874 ///
1875 /// These functions are called by the traversing code.
1876 void
begin_traversing()1877 diff::begin_traversing()
1878 {
1879   ABG_ASSERT(!is_traversing());
1880   if (priv_->canonical_diff_)
1881     priv_->canonical_diff_->priv_->traversing_ = true;
1882   priv_->traversing_ = true;
1883 }
1884 
1885 /// Tell if a given node is being traversed or not.
1886 ///
1887 /// Note that traversing a node means visiting it *and* visiting its
1888 /// children nodes.
1889 ///
1890 /// It's the canonical node which is looked at, actually.
1891 ///
1892 /// Please read the comments for the diff::begin_traversing() for mode
1893 /// context.
1894 ///
1895 /// @return true if the current instance of @diff is being traversed.
1896 bool
is_traversing() const1897 diff::is_traversing() const
1898 {
1899   if (priv_->canonical_diff_)
1900     return priv_->canonical_diff_->priv_->traversing_;
1901   return priv_->traversing_;
1902 }
1903 
1904 /// Flag a given diff node as not being traversed anymore.
1905 ///
1906 /// Note that traversing a node means visiting it *and* visiting its
1907 /// children nodes.
1908 ///
1909 /// Please read the comments of the function diff::begin_traversing()
1910 /// for mode context.
1911 void
end_traversing()1912 diff::end_traversing()
1913 {
1914   ABG_ASSERT(is_traversing());
1915   if (priv_->canonical_diff_)
1916     priv_->canonical_diff_->priv_->traversing_ = false;
1917   priv_->traversing_ = false;
1918 }
1919 
1920 /// Finish the insertion of a diff tree node into the diff graph.
1921 ///
1922 /// This function might be called several times.  It must perform the
1923 /// insertion only once.
1924 ///
1925 /// For instance, certain kinds of diff tree node have specific
1926 /// children nodes that are populated after the constructor of the
1927 /// diff tree node has been called.  In that case, calling overloads
1928 /// of this method ensures that these children nodes are properly
1929 /// gathered and setup.
1930 void
finish_diff_type()1931 diff::finish_diff_type()
1932 {
1933   if (diff::priv_->finished_)
1934     return;
1935   chain_into_hierarchy();
1936   diff::priv_->finished_ = true;
1937 }
1938 
1939 /// Getter of the first subject of the diff.
1940 ///
1941 /// @return the first subject of the diff.
1942 type_or_decl_base_sptr
first_subject() const1943 diff::first_subject() const
1944 {return dynamic_pointer_cast<type_or_decl_base>(priv_->first_subject_);}
1945 
1946 /// Getter of the second subject of the diff.
1947 ///
1948 /// @return the second subject of the diff.
1949 type_or_decl_base_sptr
second_subject() const1950 diff::second_subject() const
1951 {return dynamic_pointer_cast<type_or_decl_base>(priv_->second_subject_);}
1952 
1953 /// Getter for the children nodes of the current @ref diff node.
1954 ///
1955 /// @return a vector of the children nodes.
1956 const vector<diff*>&
children_nodes() const1957 diff::children_nodes() const
1958 {return priv_->children_;}
1959 
1960 /// Getter for the parent node of the current @ref diff node.
1961 ///
1962 /// @return the parent node of the current @ref diff node.
1963 const diff*
parent_node() const1964 diff::parent_node() const
1965 {return priv_->parent_;}
1966 
1967 /// Getter for the canonical diff of the current instance of @ref
1968 /// diff.
1969 ///
1970 /// Note that the canonical diff node for the current instanc eof diff
1971 /// node must have been set by invoking
1972 /// class_diff::initialize_canonical_diff() on the current instance of
1973 /// diff node.
1974 ///
1975 /// @return the canonical diff node or null if none was set.
1976 diff*
get_canonical_diff() const1977 diff::get_canonical_diff() const
1978 {return priv_->canonical_diff_;}
1979 
1980 /// Setter for the canonical diff of the current instance of @ref
1981 /// diff.
1982 ///
1983 /// @param d the new canonical node to set.
1984 void
set_canonical_diff(diff * d)1985 diff::set_canonical_diff(diff * d)
1986 {priv_->canonical_diff_ = d;}
1987 
1988 /// Add a new child node to the vector of children nodes for the
1989 /// current @ref diff node.
1990 ///
1991 /// @param d the new child node to add to the children nodes.
1992 void
append_child_node(diff_sptr d)1993 diff::append_child_node(diff_sptr d)
1994 {
1995   ABG_ASSERT(d);
1996 
1997   // Ensure 'd' is kept alive for the life time of the context of this
1998   // diff.
1999   context()->keep_diff_alive(d);
2000 
2001   // Add the underlying pointer of 'd' to the vector of children.
2002   // Note that this vector holds no reference to 'd'. This is to avoid
2003   // reference cycles.  The reference to 'd' is held by the context of
2004   // this diff, thanks to the call to context()->keep_diff_alive(d)
2005   // above.
2006   priv_->children_.push_back(d.get());
2007 
2008   d->priv_->parent_ = this;
2009 }
2010 
2011 /// Getter of the context of the current diff.
2012 ///
2013 /// @return the context of the current diff.
2014 const diff_context_sptr
context() const2015 diff::context() const
2016 {return priv_->get_context();}
2017 
2018 /// Setter of the context of the current diff.
2019 ///
2020 /// @param c the new context to set.
2021 void
context(diff_context_sptr c)2022 diff::context(diff_context_sptr c)
2023 {priv_->ctxt_ = c;}
2024 
2025 /// Tests if we are currently in the middle of emitting a report for
2026 /// this diff.
2027 ///
2028 /// @return true if we are currently emitting a report for the
2029 /// current diff, false otherwise.
2030 bool
currently_reporting() const2031 diff::currently_reporting() const
2032 {
2033   if (priv_->canonical_diff_)
2034     return priv_->canonical_diff_->priv_->currently_reporting_;
2035   return priv_->currently_reporting_;
2036 }
2037 
2038 /// Sets a flag saying if we are currently in the middle of emitting
2039 /// a report for this diff.
2040 ///
2041 /// @param f true if we are currently emitting a report for the
2042 /// current diff, false otherwise.
2043 void
currently_reporting(bool f) const2044 diff::currently_reporting(bool f) const
2045 {
2046   if (priv_->canonical_diff_)
2047     priv_->canonical_diff_->priv_->currently_reporting_ = f;
2048   priv_->currently_reporting_ = f;
2049 }
2050 
2051 /// Tests if a report has already been emitted for the current diff.
2052 ///
2053 /// @return true if a report has already been emitted for the
2054 /// current diff, false otherwise.
2055 bool
reported_once() const2056 diff::reported_once() const
2057 {
2058   ABG_ASSERT(priv_->canonical_diff_);
2059   return priv_->canonical_diff_->priv_->reported_once_;
2060 }
2061 
2062 /// The generic traversing code that walks a given diff sub-tree.
2063 ///
2064 /// Note that there is a difference between traversing a diff node and
2065 /// visiting it.  Basically, traversing a diff node means visiting it
2066 /// and visiting its children nodes too.  So one can visit a node
2067 /// without traversing it.  But traversing a node without visiting it
2068 /// is not possible.
2069 ///
2070 /// Note that the insertion of the "generic view" of the diff node
2071 /// into the graph being traversed is done "on the fly".  The
2072 /// insertion of the "typed view" of the diff node into the graph is
2073 /// done implicitely.  To learn more about the generic and typed view
2074 /// of the diff node, please read the introductory comments of the
2075 /// @ref diff class.
2076 ///
2077 /// Note that by default this traversing code visits a given class of
2078 /// equivalence of a diff node only once.  This behaviour can been
2079 /// changed by calling
2080 /// diff_context::visiting_a_node_twice_is_forbidden(), but this is
2081 /// very risky as it might create endless loops while visiting a diff
2082 /// tree graph that has changes that refer to themselves; that is,
2083 /// diff tree graphs with cycles.
2084 ///
2085 /// When a diff node is encountered, the
2086 /// diff_node_visitor::visit_begin() method is invoked on the diff
2087 /// node first.
2088 ///
2089 /// If the diff node has already been visited, then
2090 /// node_visitor::visit_end() is called on it and the node traversing
2091 /// is done; the children of the diff node are not visited in this
2092 /// case.
2093 ///
2094 /// If the diff node has *NOT* been visited yet, then the
2095 /// diff_node_visitor::visit() method is invoked with it's 'pre'
2096 /// argument set to true.  Then if the diff_node_visitor::visit()
2097 /// returns true, then the children nodes of the diff node are
2098 /// visited.  Otherwise, no children nodes of the diff node is
2099 /// visited and the diff_node_visitor::visit_end() is called.
2100 
2101 /// After the children nodes are visited (and only if they are
2102 /// visited) the diff_node_visitor::visit() method is invoked with
2103 /// it's 'pre' argument set to false.  And then the
2104 /// diff_node_visitor::visit_end() is called.
2105 ///
2106 /// @param v the entity that visits each node of the diff sub-tree.
2107 ///
2108 /// @return true to tell the caller that all of the sub-tree could be
2109 /// walked.  This instructs the caller to keep walking the rest of the
2110 /// tree.  Return false otherwise.
2111 bool
traverse(diff_node_visitor & v)2112 diff::traverse(diff_node_visitor& v)
2113 {
2114   // Insert the "generic view" of the diff node into its graph.
2115   finish_diff_type();
2116 
2117   v.visit_begin(this);
2118 
2119   bool already_visited = false;
2120   if (context()->visiting_a_node_twice_is_forbidden()
2121       && context()->diff_has_been_visited(this))
2122     already_visited = true;
2123 
2124   bool mark_visited_nodes_as_traversed =
2125     !(v.get_visiting_kind() & DO_NOT_MARK_VISITED_NODES_AS_VISITED);
2126 
2127   if (!already_visited && !v.visit(this, /*pre=*/true))
2128     {
2129       v.visit_end(this);
2130       if (mark_visited_nodes_as_traversed)
2131 	context()->mark_diff_as_visited(this);
2132       return false;
2133     }
2134 
2135   if (!(v.get_visiting_kind() & SKIP_CHILDREN_VISITING_KIND)
2136       && !is_traversing()
2137       && !already_visited)
2138     {
2139       begin_traversing();
2140       for (vector<diff*>::const_iterator i = children_nodes().begin();
2141 	   i != children_nodes().end();
2142 	   ++i)
2143 	{
2144 	  if (!(*i)->traverse(v))
2145 	    {
2146 	      v.visit_end(this);
2147 	      if (mark_visited_nodes_as_traversed)
2148 		context()->mark_diff_as_visited(this);
2149 	      end_traversing();
2150 	      return false;
2151 	    }
2152 	}
2153       end_traversing();
2154     }
2155 
2156   if (!v.visit(this, /*pref=*/false))
2157     {
2158       v.visit_end(this);
2159       if (mark_visited_nodes_as_traversed)
2160 	context()->mark_diff_as_visited(this);
2161       return false;
2162     }
2163 
2164   v.visit_end(this);
2165   if (!already_visited && mark_visited_nodes_as_traversed)
2166     context()->mark_diff_as_visited(this);
2167 
2168   return true;
2169 }
2170 
2171 /// Sets a flag saying if a report has already been emitted for the
2172 /// current diff.
2173 ///
2174 /// @param f true if a report has already been emitted for the
2175 /// current diff, false otherwise.
2176 void
reported_once(bool f) const2177 diff::reported_once(bool f) const
2178 {
2179   ABG_ASSERT(priv_->canonical_diff_);
2180   priv_->canonical_diff_->priv_->reported_once_ = f;
2181   priv_->reported_once_ = f;
2182 }
2183 
2184 /// Getter for the local category of the current diff tree node.
2185 ///
2186 /// The local category represents the set of categories of a diff
2187 /// node, not taking in account the categories inherited from its
2188 /// children nodes.
2189 ///
2190 /// @return the local category of the current diff tree node.
2191 diff_category
get_local_category() const2192 diff::get_local_category() const
2193 {return priv_->local_category_;}
2194 
2195 /// Getter of the category of the class of equivalence of the current
2196 /// diff tree node.
2197 ///
2198 /// That is, if the current diff tree node has a canonical node,
2199 /// return the category of that canonical node.  Otherwise, return the
2200 /// category of the current node.
2201 ///
2202 /// @return the category of the class of equivalence of the current
2203 /// tree node.
2204 diff_category
get_class_of_equiv_category() const2205 diff::get_class_of_equiv_category() const
2206 {
2207   diff* canonical = get_canonical_diff();
2208   return canonical ? canonical->get_category() : get_category();
2209 }
2210 
2211 /// Getter for the category of the current diff tree node.
2212 ///
2213 /// This category represents the union of the local category and the
2214 /// categories inherited from the children diff nodes.
2215 ///
2216 /// @return the category of the current diff tree node.
2217 diff_category
get_category() const2218 diff::get_category() const
2219 {return priv_->category_;}
2220 
2221 /// Adds the current diff tree node to an additional set of
2222 /// categories.  Note that the categories include thoses inherited
2223 /// from the children nodes of this diff node.
2224 ///
2225 /// @param c a bit-map representing the set of categories to add the
2226 /// current diff tree node to.
2227 ///
2228 /// @return the resulting bit-map representing the categories this
2229 /// current diff tree node belongs to, including those inherited from
2230 /// its children nodes.
2231 diff_category
add_to_category(diff_category c)2232 diff::add_to_category(diff_category c)
2233 {
2234   priv_->category_ = priv_->category_ | c;
2235   return priv_->category_;
2236 }
2237 
2238 /// Adds the current diff tree node to the categories resulting from
2239 /// the local changes of the current diff node.
2240 ///
2241 /// @param c a bit-map representing the set of categories to add the
2242 /// current diff tree node to.
2243 ///
2244 /// @return the resulting bit-map representing the categories this
2245 /// current diff tree node belongs to.
2246 diff_category
add_to_local_category(diff_category c)2247 diff::add_to_local_category(diff_category c)
2248 {
2249   priv_->local_category_ = priv_->local_category_ | c;
2250   return priv_->local_category_;
2251 }
2252 
2253 /// Adds the current diff tree node to the categories resulting from
2254 /// the local and inherited changes of the current diff node.
2255 ///
2256 /// @param c a bit-map representing the set of categories to add the
2257 /// current diff tree node to.
2258 void
add_to_local_and_inherited_categories(diff_category c)2259 diff::add_to_local_and_inherited_categories(diff_category c)
2260 {
2261   add_to_local_category(c);
2262   add_to_category(c);
2263 }
2264 
2265 /// Remove the current diff tree node from an a existing sef of
2266 /// categories.  The categories include those inherited from the
2267 /// children nodes of the current diff node.
2268 ///
2269 /// @param c a bit-map representing the set of categories to add the
2270 /// current diff tree node to.
2271 ///
2272 /// @return the resulting bit-map representing the categories this
2273 /// current diff tree onde belongs to, including the categories
2274 /// inherited from the children nodes of the current diff node.
2275 diff_category
remove_from_category(diff_category c)2276 diff::remove_from_category(diff_category c)
2277 {
2278   priv_->category_ = priv_->category_ & ~c;
2279   return priv_->category_;
2280 }
2281 
2282 /// Remove the current diff tree node from the categories resulting
2283 /// from the local changes.
2284 ///
2285 /// @param c a bit-map representing the set of categories to add the
2286 /// current diff tree node to.
2287 ///
2288 /// @return the resulting bit-map representing the categories this
2289 /// current diff tree onde belongs to.
2290 diff_category
remove_from_local_category(diff_category c)2291 diff::remove_from_local_category(diff_category c)
2292 {
2293   priv_->local_category_ = priv_->local_category_ & ~c;
2294   return priv_->local_category_;
2295 }
2296 
2297 /// Set the category of the current @ref diff node.  This category
2298 /// includes the categories inherited from the children nodes of the
2299 /// current diff node.
2300 ///
2301 /// @param c the new category for the current diff node.
2302 void
set_category(diff_category c)2303 diff::set_category(diff_category c)
2304 {priv_->category_ = c;}
2305 
2306 /// Set the local category of the current @ref diff node.
2307 ///
2308 /// @param c the new category for the current diff node.
2309 void
set_local_category(diff_category c)2310 diff::set_local_category(diff_category c)
2311 {priv_->local_category_ = c;}
2312 
2313 /// Test if this diff tree node is to be filtered out for reporting
2314 /// purposes.
2315 ///
2316 /// The function tests if the categories of the diff tree node are
2317 /// "forbidden" by the context or not.
2318 ///
2319 /// @return true iff the current diff node should NOT be reported.
2320 bool
is_filtered_out() const2321 diff::is_filtered_out() const
2322 {
2323   if (diff * canonical = get_canonical_diff())
2324     if (canonical->get_category() & SUPPRESSED_CATEGORY
2325 	|| canonical->get_category() & PRIVATE_TYPE_CATEGORY)
2326       // The canonical type was suppressed either by a user-provided
2327       // suppression specification or by a "private-type" suppression
2328       // specification..  This means all the class of equivalence of
2329       // that canonical type was suppressed.  So this node should be
2330       // suppressed too.
2331       return true;
2332   return priv_->is_filtered_out(get_category());
2333 }
2334 
2335 /// Test if this diff tree node is to be filtered out for reporting
2336 /// purposes, but by considering only the categories that were *NOT*
2337 /// inherited from its children nodes.
2338 ///
2339 /// The function tests if the local categories of the diff tree node
2340 /// are "forbidden" by the context or not.
2341 ///
2342 /// @return true iff the current diff node should NOT be reported,
2343 /// with respect to its local categories.
2344 bool
is_filtered_out_wrt_non_inherited_categories() const2345 diff::is_filtered_out_wrt_non_inherited_categories() const
2346 {return priv_->is_filtered_out(get_local_category());}
2347 
2348 /// Test if the current diff node has been suppressed by a
2349 /// user-provided suppression specification.
2350 ///
2351 /// @return true if the current diff node has been suppressed by a
2352 /// user-provided suppression list.
2353 bool
is_suppressed() const2354 diff::is_suppressed() const
2355 {
2356   bool is_private = false;
2357   return is_suppressed(is_private);
2358 }
2359 
2360 /// Test if the current diff node has been suppressed by a
2361 /// user-provided suppression specification or by an auto-generated
2362 /// "private type" suppression specification.
2363 ///
2364 /// Note that private type suppressions are auto-generated from the
2365 /// path to where public headers are, as given by the user.
2366 ///
2367 /// @param is_private_type out parameter if the current diff node was
2368 /// suppressed because it's a private type then this parameter is set
2369 /// to true.
2370 ///
2371 /// @return true if the current diff node has been suppressed by a
2372 /// user-provided suppression list.
2373 bool
is_suppressed(bool & is_private_type) const2374 diff::is_suppressed(bool &is_private_type) const
2375 {
2376   const suppressions_type& suppressions = context()->suppressions();
2377   for (suppressions_type::const_iterator i = suppressions.begin();
2378        i != suppressions.end();
2379        ++i)
2380     {
2381       if ((*i)->suppresses_diff(this))
2382 	{
2383 	  if (is_private_type_suppr_spec(*i))
2384 	    is_private_type = true;
2385 	  return true;
2386 	}
2387     }
2388   return false;
2389 }
2390 
2391 /// Test if this diff tree node should be reported.
2392 ///
2393 /// @return true iff the current node should be reported.
2394 bool
to_be_reported() const2395 diff::to_be_reported() const
2396 {
2397   if (has_changes() && !is_filtered_out())
2398     return true;
2399   return false;
2400 }
2401 
2402 /// Test if this diff tree node should be reported when considering
2403 /// the categories that were *NOT* inherited from its children nodes.
2404 ///
2405 /// @return true iff the current node should be reported.
2406 bool
has_local_changes_to_be_reported() const2407 diff::has_local_changes_to_be_reported() const
2408 {
2409   if (has_local_changes()
2410       && !is_filtered_out_wrt_non_inherited_categories())
2411     return true;
2412   return false;
2413 }
2414 
2415 /// Get a pretty representation of the current @ref diff node.
2416 ///
2417 /// This is suitable for e.g. emitting debugging traces for the diff
2418 /// tree nodes.
2419 ///
2420 /// @return the pretty representation of the diff node.
2421 const string&
get_pretty_representation() const2422 diff::get_pretty_representation() const
2423 {
2424   if (priv_->pretty_representation_.empty())
2425     priv_->pretty_representation_ = "empty_diff";
2426   return priv_->pretty_representation_;
2427 }
2428 
2429 /// Default implementation of the hierachy chaining virtual function.
2430 ///
2431 /// There are several types of diff nodes that have logical children
2432 /// nodes; for instance, a typedef_diff has the diff of the underlying
2433 /// type as a child node.  A var_diff has the diff of the types of the
2434 /// variables as a child node, etc.
2435 ///
2436 /// But because the @ref diff base has a generic representation for
2437 /// children nodes of the all the types of @ref diff nodes (regardless
2438 /// of the specific most-derived type of diff node) that one can get
2439 /// using the method diff::children_nodes(), one need to populate that
2440 /// vector of children node.
2441 ///
2442 /// Populating that vector of children node is done by this function;
2443 /// it must be overloaded by each most-derived type of diff node that
2444 /// extends the @ref diff type.
2445 void
chain_into_hierarchy()2446 diff::chain_into_hierarchy()
2447 {}
2448 
2449 // </diff stuff>
2450 
2451 // <type_diff_base stuff>
2452 
type_diff_base(type_base_sptr first_subject,type_base_sptr second_subject,diff_context_sptr ctxt)2453 type_diff_base::type_diff_base(type_base_sptr	first_subject,
2454 			       type_base_sptr	second_subject,
2455 			       diff_context_sptr	ctxt)
2456   : diff(first_subject, second_subject, ctxt),
2457     priv_(new priv)
2458 {}
2459 
~type_diff_base()2460 type_diff_base::~type_diff_base()
2461 {}
2462 // </type_diff_base stuff>
2463 
2464 // <decl_diff_base stuff>
2465 
2466 /// Constructor of @ref decl_diff_base.
2467 ///
2468 /// @param first_subject the first subject of the diff.
2469 ///
2470 /// @param second_subject the second subject of the diff.
2471 ///
2472 /// @param ctxt the context of the diff.  This object must stay alive
2473 /// at least during the life time of the current instance of @ref
2474 /// decl_diff_base, otherwise, memory corruption issues occur.
decl_diff_base(decl_base_sptr first_subject,decl_base_sptr second_subject,diff_context_sptr ctxt)2475 decl_diff_base::decl_diff_base(decl_base_sptr	first_subject,
2476 			       decl_base_sptr	second_subject,
2477 			       diff_context_sptr	ctxt)
2478   : diff(first_subject, second_subject, ctxt),
2479     priv_(new priv)
2480 {}
2481 
~decl_diff_base()2482 decl_diff_base::~decl_diff_base()
2483 {}
2484 
2485 // </decl_diff_base stuff>
2486 
2487 // <distinct_diff stuff>
2488 
2489 /// @return a pretty representation for the @ref distinct_diff node.
2490 const string&
get_pretty_representation() const2491 distinct_diff::get_pretty_representation() const
2492 {
2493   if (diff::priv_->pretty_representation_.empty())
2494     {
2495       std::ostringstream o;
2496       o << "distinct_diff[";
2497       if (first_subject())
2498 	o << first_subject()->get_pretty_representation();
2499       else
2500 	o << "null";
2501       o << ", ";
2502       if (second_subject())
2503 	o << second_subject()->get_pretty_representation() ;
2504       else
2505 	o << "null";
2506       o << "]" ;
2507       diff::priv_->pretty_representation_ = o.str();
2508     }
2509   return diff::priv_->pretty_representation_;
2510 }
2511 
2512 /// Populate the vector of children node of the @ref diff base type
2513 /// sub-object of this instance of @distinct_diff.
2514 ///
2515 /// The children nodes can then later be retrieved using
2516 /// diff::children_nodes().
2517 void
chain_into_hierarchy()2518 distinct_diff::chain_into_hierarchy()
2519 {
2520   ABG_ASSERT(entities_are_of_distinct_kinds(first(), second()));
2521 
2522   if (diff_sptr d = compatible_child_diff())
2523     append_child_node(d);
2524 }
2525 
2526 /// Constructor for @ref distinct_diff.
2527 ///
2528 /// Note that the two entities considered for the diff (and passed in
2529 /// parameter) must be of different kinds.
2530 ///
2531 /// @param first the first entity to consider for the diff.
2532 ///
2533 /// @param second the second entity to consider for the diff.
2534 ///
2535 /// @param ctxt the context of the diff.  Note that this context
2536 /// object must stay alive at least during the life time of the
2537 /// current instance of @ref distinct_diff.  Otherwise memory
2538 /// corruption issues occur.
distinct_diff(type_or_decl_base_sptr first,type_or_decl_base_sptr second,diff_context_sptr ctxt)2539 distinct_diff::distinct_diff(type_or_decl_base_sptr first,
2540 			     type_or_decl_base_sptr second,
2541 			     diff_context_sptr ctxt)
2542   : diff(first, second, ctxt),
2543     priv_(new priv)
2544 {ABG_ASSERT(entities_are_of_distinct_kinds(first, second));}
2545 
2546 /// Getter for the first subject of the diff.
2547 ///
2548 /// @return the first subject of the diff.
2549 const type_or_decl_base_sptr
first() const2550 distinct_diff::first() const
2551 {return first_subject();}
2552 
2553 /// Getter for the second subject of the diff.
2554 ///
2555 /// @return the second subject of the diff.
2556 const type_or_decl_base_sptr
second() const2557 distinct_diff::second() const
2558 {return second_subject();}
2559 
2560 /// Getter for the child diff of this distinct_diff instance.
2561 ///
2562 /// When a distinct_diff has two subjects that are different but
2563 /// compatible, then the distinct_diff instance has a child diff node
2564 /// (named the compatible child diff) that is the diff between the two
2565 /// subjects stripped from their typedefs.  Otherwise, the compatible
2566 /// child diff is nul.
2567 ///
2568 /// Note that two diff subjects (that compare different) are
2569 /// considered compatible if stripping typedefs out of them makes them
2570 /// comparing equal.
2571 ///
2572 /// @return the compatible child diff node, if any.  Otherwise, null.
2573 const diff_sptr
compatible_child_diff() const2574 distinct_diff::compatible_child_diff() const
2575 {
2576   if (!priv_->compatible_child_diff)
2577     {
2578       type_base_sptr fs = strip_typedef(is_type(first())),
2579 	ss = strip_typedef(is_type(second()));
2580 
2581       if (fs && ss
2582 	  && !entities_are_of_distinct_kinds(get_type_declaration(fs),
2583 					     get_type_declaration(ss)))
2584 	priv_->compatible_child_diff = compute_diff(get_type_declaration(fs),
2585 						    get_type_declaration(ss),
2586 						    context());
2587     }
2588   return priv_->compatible_child_diff;
2589 }
2590 
2591 /// Test if the two arguments are of different kind, or that are both
2592 /// NULL.
2593 ///
2594 /// @param first the first argument to test for similarity in kind.
2595 ///
2596 /// @param second the second argument to test for similarity in kind.
2597 ///
2598 /// @return true iff the two arguments are of different kind.
2599 bool
entities_are_of_distinct_kinds(type_or_decl_base_sptr first,type_or_decl_base_sptr second)2600 distinct_diff::entities_are_of_distinct_kinds(type_or_decl_base_sptr first,
2601 					      type_or_decl_base_sptr second)
2602 {
2603   if (!!first != !!second)
2604     return true;
2605   if (!first && !second)
2606     // We do consider diffs of two empty decls as a diff of distinct
2607     // kinds, for now.
2608     return true;
2609   if (first == second)
2610     return false;
2611 
2612   const type_or_decl_base &f = *first, &s = *second;
2613   return typeid(f) != typeid(s);
2614 }
2615 
2616 /// @return true if the two subjects of the diff are different, false
2617 /// otherwise.
2618 bool
has_changes() const2619 distinct_diff::has_changes() const
2620 {return first() != second();}
2621 
2622 /// @return the kind of local change carried by the current diff node.
2623 /// The value returned is zero if the current node carries no local
2624 /// change.
2625 enum change_kind
has_local_changes() const2626 distinct_diff::has_local_changes() const
2627 {
2628   // Changes on a distinct_diff are all local.
2629   if (has_changes())
2630     return LOCAL_TYPE_CHANGE_KIND;
2631   return NO_CHANGE_KIND;
2632 }
2633 
2634 /// Emit a report about the current diff instance.
2635 ///
2636 /// @param out the output stream to send the diff report to.
2637 ///
2638 /// @param indent the indentation string to use in the report.
2639 void
report(ostream & out,const string & indent) const2640 distinct_diff::report(ostream& out, const string& indent) const
2641 {
2642   context()->get_reporter()->report(*this, out, indent);
2643 }
2644 
2645 /// Try to diff entities that are of distinct kinds.
2646 ///
2647 /// @param first the first entity to consider for the diff.
2648 ///
2649 /// @param second the second entity to consider for the diff.
2650 ///
2651 /// @param ctxt the context of the diff.
2652 ///
2653 /// @return a non-null diff if a diff object could be built, null
2654 /// otherwise.
2655 distinct_diff_sptr
compute_diff_for_distinct_kinds(const type_or_decl_base_sptr first,const type_or_decl_base_sptr second,diff_context_sptr ctxt)2656 compute_diff_for_distinct_kinds(const type_or_decl_base_sptr first,
2657 				const type_or_decl_base_sptr second,
2658 				diff_context_sptr ctxt)
2659 {
2660   if (!distinct_diff::entities_are_of_distinct_kinds(first, second))
2661     return distinct_diff_sptr();
2662 
2663   distinct_diff_sptr result(new distinct_diff(first, second, ctxt));
2664 
2665   ctxt->initialize_canonical_diff(result);
2666 
2667   return result;
2668 }
2669 
2670 /// </distinct_diff stuff>
2671 
2672 /// Try to compute a diff on two instances of DiffType representation.
2673 ///
2674 /// The function template performs the diff if and only if the decl
2675 /// representations are of a DiffType.
2676 ///
2677 /// @tparm DiffType the type of instances to diff.
2678 ///
2679 /// @param first the first representation of decl to consider in the
2680 /// diff computation.
2681 ///
2682 /// @param second the second representation of decl to consider in the
2683 /// diff computation.
2684 ///
2685 /// @param ctxt the diff context to use.
2686 ///
2687 ///@return the diff of the two types @p first and @p second if and
2688 ///only if they represent the parametrized type DiffType.  Otherwise,
2689 ///returns a NULL pointer value.
2690 template<typename DiffType>
2691 diff_sptr
try_to_diff(const type_or_decl_base_sptr first,const type_or_decl_base_sptr second,diff_context_sptr ctxt)2692 try_to_diff(const type_or_decl_base_sptr first,
2693 	    const type_or_decl_base_sptr second,
2694 	    diff_context_sptr ctxt)
2695 {
2696   if (shared_ptr<DiffType> f =
2697       dynamic_pointer_cast<DiffType>(first))
2698     {
2699       shared_ptr<DiffType> s =
2700 	dynamic_pointer_cast<DiffType>(second);
2701       if (!s)
2702 	return diff_sptr();
2703       return compute_diff(f, s, ctxt);
2704     }
2705   return diff_sptr();
2706 }
2707 
2708 
2709 /// This is a specialization of @ref try_to_diff() template to diff
2710 /// instances of @ref class_decl.
2711 ///
2712 /// @param first the first representation of decl to consider in the
2713 /// diff computation.
2714 ///
2715 /// @param second the second representation of decl to consider in the
2716 /// diff computation.
2717 ///
2718 /// @param ctxt the diff context to use.
2719 template<>
2720 diff_sptr
try_to_diff(const type_or_decl_base_sptr first,const type_or_decl_base_sptr second,diff_context_sptr ctxt)2721 try_to_diff<class_decl>(const type_or_decl_base_sptr first,
2722 			const type_or_decl_base_sptr second,
2723 			diff_context_sptr ctxt)
2724 {
2725   if (class_decl_sptr f =
2726       dynamic_pointer_cast<class_decl>(first))
2727     {
2728       class_decl_sptr s = dynamic_pointer_cast<class_decl>(second);
2729       if (!s)
2730 	return diff_sptr();
2731 
2732       if (f->get_is_declaration_only())
2733 	{
2734 	  class_decl_sptr f2 =
2735 	    is_class_type (f->get_definition_of_declaration());
2736 	  if (f2)
2737 	    f = f2;
2738 	}
2739       if (s->get_is_declaration_only())
2740 	{
2741 	  class_decl_sptr s2 =
2742 	    is_class_type(s->get_definition_of_declaration());
2743 	  if (s2)
2744 	    s = s2;
2745 	}
2746       return compute_diff(f, s, ctxt);
2747     }
2748   return diff_sptr();
2749 }
2750 
2751 /// Try to diff entities that are of distinct kinds.
2752 ///
2753 /// @param first the first entity to consider for the diff.
2754 ///
2755 /// @param second the second entity to consider for the diff.
2756 ///
2757 /// @param ctxt the context of the diff.
2758 ///
2759 /// @return a non-null diff if a diff object could be built, null
2760 /// otherwise.
2761 static diff_sptr
try_to_diff_distinct_kinds(const type_or_decl_base_sptr first,const type_or_decl_base_sptr second,diff_context_sptr ctxt)2762 try_to_diff_distinct_kinds(const type_or_decl_base_sptr first,
2763 			   const type_or_decl_base_sptr second,
2764 			   diff_context_sptr ctxt)
2765 {return compute_diff_for_distinct_kinds(first, second, ctxt);}
2766 
2767 /// Compute the difference between two types.
2768 ///
2769 /// The function considers every possible types known to libabigail
2770 /// and runs the appropriate diff function on them.
2771 ///
2772 /// Whenever a new kind of type decl is supported by abigail, if we
2773 /// want to be able to diff two instances of it, we need to update
2774 /// this function to support it.
2775 ///
2776 /// @param first the first type decl to consider for the diff
2777 ///
2778 /// @param second the second type decl to consider for the diff.
2779 ///
2780 /// @param ctxt the diff context to use.
2781 ///
2782 /// @return the resulting diff.  It's a pointer to a descendent of
2783 /// abigail::comparison::diff.
2784 static diff_sptr
compute_diff_for_types(const type_or_decl_base_sptr & first,const type_or_decl_base_sptr & second,const diff_context_sptr & ctxt)2785 compute_diff_for_types(const type_or_decl_base_sptr& first,
2786 		       const type_or_decl_base_sptr& second,
2787 		       const diff_context_sptr& ctxt)
2788 {
2789   type_or_decl_base_sptr f = first;
2790   type_or_decl_base_sptr s = second;
2791 
2792   diff_sptr d;
2793 
2794   ((d = try_to_diff<type_decl>(f, s, ctxt))
2795    ||(d = try_to_diff<enum_type_decl>(f, s, ctxt))
2796    ||(d = try_to_diff<union_decl>(f, s,ctxt))
2797    ||(d = try_to_diff<class_decl>(f, s,ctxt))
2798    ||(d = try_to_diff<pointer_type_def>(f, s, ctxt))
2799    ||(d = try_to_diff<reference_type_def>(f, s, ctxt))
2800    ||(d = try_to_diff<array_type_def>(f, s, ctxt))
2801    ||(d = try_to_diff<qualified_type_def>(f, s, ctxt))
2802    ||(d = try_to_diff<typedef_decl>(f, s, ctxt))
2803    ||(d = try_to_diff<function_type>(f, s, ctxt))
2804    ||(d = try_to_diff_distinct_kinds(f, s, ctxt)));
2805 
2806   ABG_ASSERT(d);
2807 
2808   return d;
2809 }
2810 
2811 diff_category
operator |(diff_category c1,diff_category c2)2812 operator|(diff_category c1, diff_category c2)
2813 {return static_cast<diff_category>(static_cast<unsigned>(c1)
2814 				   | static_cast<unsigned>(c2));}
2815 
2816 diff_category&
operator |=(diff_category & c1,diff_category c2)2817 operator|=(diff_category& c1, diff_category c2)
2818 {
2819   c1 = c1 | c2;
2820   return c1;
2821 }
2822 
2823 diff_category&
operator &=(diff_category & c1,diff_category c2)2824 operator&=(diff_category& c1, diff_category c2)
2825 {
2826   c1 = c1 & c2;
2827   return c1;
2828 }
2829 
2830 diff_category
operator ^(diff_category c1,diff_category c2)2831 operator^(diff_category c1, diff_category c2)
2832 {return static_cast<diff_category>(static_cast<unsigned>(c1)
2833 				   ^ static_cast<unsigned>(c2));}
2834 
2835 diff_category
operator &(diff_category c1,diff_category c2)2836 operator&(diff_category c1, diff_category c2)
2837 {return static_cast<diff_category>(static_cast<unsigned>(c1)
2838 				   & static_cast<unsigned>(c2));}
2839 
2840 diff_category
operator ~(diff_category c)2841 operator~(diff_category c)
2842 {return static_cast<diff_category>(~static_cast<unsigned>(c));}
2843 
2844 
2845 /// Getter of a bitmap made of the set of change categories that are
2846 /// considered harmless.
2847 ///
2848 /// @return the bitmap made of the set of change categories that are
2849 /// considered harmless.
2850 diff_category
get_default_harmless_categories_bitmap()2851 get_default_harmless_categories_bitmap()
2852 {
2853   return (abigail::comparison::ACCESS_CHANGE_CATEGORY
2854 	  | abigail::comparison::COMPATIBLE_TYPE_CHANGE_CATEGORY
2855 	  | abigail::comparison::HARMLESS_DECL_NAME_CHANGE_CATEGORY
2856 	  | abigail::comparison::NON_VIRT_MEM_FUN_CHANGE_CATEGORY
2857 	  | abigail::comparison::STATIC_DATA_MEMBER_CHANGE_CATEGORY
2858 	  | abigail::comparison::HARMLESS_ENUM_CHANGE_CATEGORY
2859 	  | abigail::comparison::HARMLESS_SYMBOL_ALIAS_CHANGE_CATEGORY
2860 	  | abigail::comparison::HARMLESS_UNION_CHANGE_CATEGORY
2861 	  | abigail::comparison::HARMLESS_DATA_MEMBER_CHANGE_CATEGORY
2862 	  | abigail::comparison::TYPE_DECL_ONLY_DEF_CHANGE_CATEGORY
2863 	  | abigail::comparison::FN_PARM_TYPE_TOP_CV_CHANGE_CATEGORY
2864 	  | abigail::comparison::FN_PARM_TYPE_CV_CHANGE_CATEGORY
2865 	  | abigail::comparison::FN_RETURN_TYPE_CV_CHANGE_CATEGORY
2866 	  | abigail::comparison::VAR_TYPE_CV_CHANGE_CATEGORY
2867 	  | abigail::comparison::VOID_PTR_TO_PTR_CHANGE_CATEGORY
2868 	  | abigail::comparison::BENIGN_INFINITE_ARRAY_CHANGE_CATEGORY);
2869 }
2870 
2871 /// Getter of a bitmap made of the set of change categories that are
2872 /// considered harmful.
2873 ///
2874 /// @return the bitmap made of the set of change categories that are
2875 /// considered harmful.
2876 diff_category
get_default_harmful_categories_bitmap()2877 get_default_harmful_categories_bitmap()
2878 {
2879   return (abigail::comparison::SIZE_OR_OFFSET_CHANGE_CATEGORY
2880 	  | abigail::comparison::VIRTUAL_MEMBER_CHANGE_CATEGORY
2881 	  | abigail::comparison::FN_PARM_ADD_REMOVE_CHANGE_CATEGORY);
2882 }
2883 
2884 /// Serialize an instance of @ref diff_category to an output stream.
2885 ///
2886 /// @param o the output stream to serialize @p c to.
2887 ///
2888 /// @param c the instance of diff_category to serialize.
2889 ///
2890 /// @return the output stream to serialize @p c to.
2891 ostream&
operator <<(ostream & o,diff_category c)2892 operator<<(ostream& o, diff_category c)
2893 {
2894   bool emitted_a_category = false;
2895 
2896   if (c == NO_CHANGE_CATEGORY)
2897     {
2898       o << "NO_CHANGE_CATEGORY";
2899       emitted_a_category = true;
2900     }
2901 
2902   if (c & ACCESS_CHANGE_CATEGORY)
2903     {
2904       if (emitted_a_category)
2905 	o << "|";
2906       o << "ACCESS_CHANGE_CATEGORY";
2907       emitted_a_category |= true;
2908     }
2909 
2910   if (c & COMPATIBLE_TYPE_CHANGE_CATEGORY)
2911     {
2912       if (emitted_a_category)
2913 	o << "|";
2914       o << "COMPATIBLE_TYPE_CHANGE_CATEGORY";
2915       emitted_a_category |= true;
2916     }
2917 
2918   if (c & HARMLESS_DECL_NAME_CHANGE_CATEGORY)
2919     {
2920       if (emitted_a_category)
2921 	o << "|";
2922       o << "HARMLESS_DECL_NAME_CHANGE_CATEGORY";
2923       emitted_a_category |= true;
2924     }
2925 
2926   if (c & NON_VIRT_MEM_FUN_CHANGE_CATEGORY)
2927     {
2928       if (emitted_a_category)
2929 	o << "|";
2930       o << "NON_VIRT_MEM_FUN_CHANGE_CATEGORY";
2931       emitted_a_category |= true;
2932     }
2933 
2934   if (c & STATIC_DATA_MEMBER_CHANGE_CATEGORY)
2935     {
2936       if (emitted_a_category)
2937 	o << "|";
2938       o << "STATIC_DATA_MEMBER_CHANGE_CATEGORY";
2939       emitted_a_category |= true;
2940     }
2941 
2942   if (c & HARMLESS_ENUM_CHANGE_CATEGORY)
2943     {
2944       if (emitted_a_category)
2945 	o << "|";
2946       o << "HARMLESS_ENUM_CHANGE_CATEGORY";
2947       emitted_a_category |= true;
2948     }
2949 
2950     if (c & HARMLESS_DATA_MEMBER_CHANGE_CATEGORY)
2951     {
2952       if (emitted_a_category)
2953 	o << "|";
2954       o << "HARMLESS_DATA_MEMBER_CHANGE_CATEGORY";
2955       emitted_a_category |= true;
2956     }
2957 
2958   if (c & HARMLESS_SYMBOL_ALIAS_CHANGE_CATEGORY)
2959     {
2960       if (emitted_a_category)
2961 	o << "|";
2962       o << "HARMLESS_SYMBOL_ALIAS_CHANGE_CATEGORY";
2963       emitted_a_category |= true;
2964     }
2965 
2966   if (c & HARMLESS_UNION_CHANGE_CATEGORY)
2967     {
2968       if (emitted_a_category)
2969 	o << "|";
2970       o << "HARMLESS_UNION_CHANGE_CATEGORY";
2971       emitted_a_category |= true;
2972     }
2973 
2974   if (c & SUPPRESSED_CATEGORY)
2975     {
2976       if (emitted_a_category)
2977 	o << "|";
2978       o << "SUPPRESSED_CATEGORY";
2979       emitted_a_category |= true;
2980     }
2981 
2982   if (c & PRIVATE_TYPE_CATEGORY)
2983     {
2984       if (emitted_a_category)
2985 	o << "|";
2986       o << "PRIVATE_TYPE_CATEGORY";
2987       emitted_a_category |= true;
2988     }
2989 
2990   if (c & SIZE_OR_OFFSET_CHANGE_CATEGORY)
2991     {
2992       if (emitted_a_category)
2993 	o << "|";
2994       o << "SIZE_OR_OFFSET_CHANGE_CATEGORY";
2995       emitted_a_category |= true;
2996     }
2997 
2998   if (c & VIRTUAL_MEMBER_CHANGE_CATEGORY)
2999     {
3000       if (emitted_a_category)
3001 	o << "|";
3002       o << "VIRTUAL_MEMBER_CHANGE_CATEGORY";
3003       emitted_a_category |= true;
3004     }
3005 
3006   if (c & REDUNDANT_CATEGORY)
3007     {
3008       if (emitted_a_category)
3009 	o << "|";
3010       o << "REDUNDANT_CATEGORY";
3011       emitted_a_category |= true;
3012     }
3013 
3014   if (c & TYPE_DECL_ONLY_DEF_CHANGE_CATEGORY)
3015     {
3016       if (emitted_a_category)
3017 	o << "|";
3018       o << "TYPE_DECL_ONLY_DEF_CHANGE_CATEGORY";
3019       emitted_a_category |= true;
3020     }
3021 
3022   if (c & FN_PARM_TYPE_TOP_CV_CHANGE_CATEGORY)
3023     {
3024       if (emitted_a_category)
3025 	o << "|";
3026       o << "FN_PARM_TYPE_TOP_CV_CHANGE_CATEGORY";
3027       emitted_a_category |= true;
3028     }
3029 
3030   if (c & FN_PARM_TYPE_CV_CHANGE_CATEGORY)
3031     {
3032       if (emitted_a_category)
3033 	o << "|";
3034       o << "FN_PARM_TYPE_CV_CHANGE_CATEGORY";
3035       emitted_a_category |= true;
3036     }
3037 
3038   if (c & FN_RETURN_TYPE_CV_CHANGE_CATEGORY)
3039     {
3040       if (emitted_a_category)
3041 	o << "|";
3042       o << "FN_RETURN_TYPE_CV_CHANGE_CATEGORY";
3043       emitted_a_category |= true;
3044     }
3045 
3046     if (c & FN_PARM_ADD_REMOVE_CHANGE_CATEGORY)
3047     {
3048       if (emitted_a_category)
3049 	o << "|";
3050       o << "FN_PARM_ADD_REMOVE_CHANGE_CATEGORY";
3051       emitted_a_category |= true;
3052     }
3053 
3054   if (c & VAR_TYPE_CV_CHANGE_CATEGORY)
3055     {
3056       if (emitted_a_category)
3057 	o << "|";
3058       o << "VAR_TYPE_CV_CHANGE_CATEGORY";
3059       emitted_a_category |= true;
3060     }
3061 
3062   if (c & VOID_PTR_TO_PTR_CHANGE_CATEGORY)
3063     {
3064       if (emitted_a_category)
3065 	o << "|";
3066       o << "VOID_PTR_TO_PTR_CHANGE_CATEGORY";
3067       emitted_a_category |= true;
3068     }
3069 
3070   if (c & BENIGN_INFINITE_ARRAY_CHANGE_CATEGORY)
3071     {
3072       if (emitted_a_category)
3073 	o << "|";
3074       o << "BENIGN_INFINITE_ARRAY_CHANGE_CATEGORY";
3075       emitted_a_category |= true;
3076     }
3077 
3078   return o;
3079 }
3080 
3081 /// Compute the difference between two decls.
3082 ///
3083 /// The function consider every possible decls known to libabigail and
3084 /// runs the appropriate diff function on them.
3085 ///
3086 /// Whenever a new kind of non-type decl is supported by abigail, if
3087 /// we want to be able to diff two instances of it, we need to update
3088 /// this function to support it.
3089 ///
3090 /// @param first the first decl to consider for the diff
3091 ///
3092 /// @param second the second decl to consider for the diff.
3093 ///
3094 /// @param ctxt the diff context to use.
3095 ///
3096 /// @return the resulting diff.
3097 static diff_sptr
compute_diff_for_decls(const decl_base_sptr first,const decl_base_sptr second,diff_context_sptr ctxt)3098 compute_diff_for_decls(const decl_base_sptr first,
3099 		       const decl_base_sptr second,
3100 		       diff_context_sptr ctxt)
3101 {
3102 
3103   diff_sptr d;
3104 
3105   ((d = try_to_diff<function_decl>(first, second, ctxt))
3106    || (d = try_to_diff<var_decl>(first, second, ctxt))
3107    || (d = try_to_diff_distinct_kinds(first, second, ctxt)));
3108 
3109    ABG_ASSERT(d);
3110 
3111   return d;
3112 }
3113 
3114 /// Compute the difference between two decls.  The decls can represent
3115 /// either type declarations, or non-type declaration.
3116 ///
3117 /// Note that the two decls must have been created in the same @ref
3118 /// environment, otherwise, this function aborts.
3119 ///
3120 /// @param first the first decl to consider.
3121 ///
3122 /// @param second the second decl to consider.
3123 ///
3124 /// @param ctxt the diff context to use.
3125 ///
3126 /// @return the resulting diff, or NULL if the diff could not be
3127 /// computed.
3128 diff_sptr
compute_diff(const decl_base_sptr first,const decl_base_sptr second,diff_context_sptr ctxt)3129 compute_diff(const decl_base_sptr	first,
3130 	     const decl_base_sptr	second,
3131 	     diff_context_sptr		ctxt)
3132 {
3133   if (!first || !second)
3134     return diff_sptr();
3135 
3136   ABG_ASSERT(first->get_environment() == second->get_environment());
3137 
3138   diff_sptr d;
3139   if (is_type(first) && is_type(second))
3140     d = compute_diff_for_types(first, second, ctxt);
3141   else
3142     d = compute_diff_for_decls(first, second, ctxt);
3143   ABG_ASSERT(d);
3144   return d;
3145 }
3146 
3147 /// Compute the difference between two types.
3148 ///
3149 /// Note that the two types must have been created in the same @ref
3150 /// environment, otherwise, this function aborts.
3151 ///
3152 /// @param first the first type to consider.
3153 ///
3154 /// @param second the second type to consider.
3155 ///
3156 /// @param ctxt the diff context to use.
3157 ///
3158 /// @return the resulting diff, or NULL if the diff couldn't be
3159 /// computed.
3160 diff_sptr
compute_diff(const type_base_sptr first,const type_base_sptr second,diff_context_sptr ctxt)3161 compute_diff(const type_base_sptr	first,
3162 	     const type_base_sptr	second,
3163 	     diff_context_sptr		ctxt)
3164 {
3165   decl_base_sptr f = get_type_declaration(first),
3166     s = get_type_declaration(second);
3167 
3168   if (first && second)
3169     ABG_ASSERT(first->get_environment() == second->get_environment());
3170 
3171   diff_sptr d = compute_diff_for_types(f,s, ctxt);
3172   ABG_ASSERT(d);
3173   return d;
3174 }
3175 
3176 /// Get a copy of the pretty representation of a diff node.
3177 ///
3178 /// @param d the diff node to consider.
3179 ///
3180 /// @return the pretty representation string.
3181 string
get_pretty_representation(diff * d)3182 get_pretty_representation(diff* d)
3183 {
3184   if (!d)
3185     return "";
3186   string prefix= "diff of ";
3187   return prefix + get_pretty_representation(d->first_subject());
3188 }
3189 
3190 // <var_diff stuff>
3191 
3192 /// Populate the vector of children node of the @ref diff base type
3193 /// sub-object of this instance of @ref var_diff.
3194 ///
3195 /// The children node can then later be retrieved using
3196 /// diff::children_node().
3197 void
chain_into_hierarchy()3198 var_diff::chain_into_hierarchy()
3199 {append_child_node(type_diff());}
3200 
3201 /// @return the pretty representation for this current instance of
3202 /// @ref var_diff.
3203 const string&
get_pretty_representation() const3204 var_diff::get_pretty_representation() const
3205 {
3206   if (diff::priv_->pretty_representation_.empty())
3207     {
3208       std::ostringstream o;
3209       o << "var_diff["
3210 	<< first_subject()->get_pretty_representation()
3211 	<< ", "
3212 	<< second_subject()->get_pretty_representation()
3213 	<< "]";
3214       diff::priv_->pretty_representation_ = o.str();
3215     }
3216   return diff::priv_->pretty_representation_;
3217 }
3218 /// Constructor for @ref var_diff.
3219 ///
3220 /// @param first the first instance of @ref var_decl to consider in
3221 /// the diff.
3222 ///
3223 /// @param second the second instance of @ref var_decl to consider in
3224 /// the diff.
3225 ///
3226 /// @param type_diff the diff between types of the instances of
3227 /// var_decl.
3228 ///
3229 /// @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)3230 var_diff::var_diff(var_decl_sptr	first,
3231 		   var_decl_sptr	second,
3232 		   diff_sptr		type_diff,
3233 		   diff_context_sptr	ctxt)
3234   : decl_diff_base(first, second, ctxt),
3235     priv_(new priv)
3236 {priv_->type_diff_ = type_diff;}
3237 
3238 /// Getter for the first @ref var_decl of the diff.
3239 ///
3240 /// @return the first @ref var_decl of the diff.
3241 var_decl_sptr
first_var() const3242 var_diff::first_var() const
3243 {return dynamic_pointer_cast<var_decl>(first_subject());}
3244 
3245 /// Getter for the second @ref var_decl of the diff.
3246 ///
3247 /// @return the second @ref var_decl of the diff.
3248 var_decl_sptr
second_var() const3249 var_diff::second_var() const
3250 {return dynamic_pointer_cast<var_decl>(second_subject());}
3251 
3252 /// Getter for the diff of the types of the instances of @ref
3253 /// var_decl.
3254 ///
3255 /// @return the diff of the types of the instances of @ref var_decl.
3256 diff_sptr
type_diff() const3257 var_diff::type_diff() const
3258 {
3259   if (diff_sptr result = priv_->type_diff_.lock())
3260     return result;
3261   else
3262     {
3263       result = compute_diff(first_var()->get_type(),
3264 			    second_var()->get_type(),
3265 			    context());
3266       context()->keep_diff_alive(result);
3267       priv_->type_diff_ = result;
3268       return result;
3269     }
3270 }
3271 
3272 /// Return true iff the diff node has a change.
3273 ///
3274 /// @return true iff the diff node has a change.
3275 bool
has_changes() const3276 var_diff::has_changes() const
3277 {return *first_var() != *second_var();}
3278 
3279 /// @return the kind of local change carried by the current diff node.
3280 /// The value returned is zero if the current node carries no local
3281 /// change.
3282 enum change_kind
has_local_changes() const3283 var_diff::has_local_changes() const
3284 {
3285   ir::change_kind k = ir::NO_CHANGE_KIND;
3286   if (!equals(*first_var(), *second_var(), &k))
3287     return k & ir::ALL_LOCAL_CHANGES_MASK;
3288   return ir::NO_CHANGE_KIND;
3289 }
3290 
3291 /// Report the diff in a serialized form.
3292 ///
3293 /// @param out the stream to serialize the diff to.
3294 ///
3295 /// @param indent the prefix to use for the indentation of this
3296 /// serialization.
3297 void
report(ostream & out,const string & indent) const3298 var_diff::report(ostream& out, const string& indent) const
3299 {
3300   context()->get_reporter()->report(*this, out, indent);
3301 }
3302 
3303 /// Compute the diff between two instances of @ref var_decl.
3304 ///
3305 /// Note that the two decls must have been created in the same @ref
3306 /// environment, otherwise, this function aborts.
3307 ///
3308 /// @param first the first @ref var_decl to consider for the diff.
3309 ///
3310 /// @param second the second @ref var_decl to consider for the diff.
3311 ///
3312 /// @param ctxt the diff context to use.
3313 ///
3314 /// @return the resulting diff between the two @ref var_decl.
3315 var_diff_sptr
compute_diff(const var_decl_sptr first,const var_decl_sptr second,diff_context_sptr ctxt)3316 compute_diff(const var_decl_sptr	first,
3317 	     const var_decl_sptr	second,
3318 	     diff_context_sptr		ctxt)
3319 {
3320   if (first && second)
3321     ABG_ASSERT(first->get_environment() == second->get_environment());
3322 
3323   var_diff_sptr d(new var_diff(first, second, diff_sptr(), ctxt));
3324   ctxt->initialize_canonical_diff(d);
3325 
3326   return d;
3327 }
3328 
3329 // </var_diff stuff>
3330 
3331 // <pointer_type_def stuff>
3332 
3333 /// Populate the vector of children node of the @ref diff base type
3334 /// sub-object of this instance of @ref pointer_diff.
3335 ///
3336 /// The children node can then later be retrieved using
3337 /// diff::children_node().
3338 void
chain_into_hierarchy()3339 pointer_diff::chain_into_hierarchy()
3340 {append_child_node(underlying_type_diff());}
3341 
3342 /// Constructor for a pointer_diff.
3343 ///
3344 /// @param first the first pointer to consider for the diff.
3345 ///
3346 /// @param second the secon pointer to consider for the diff.
3347 ///
3348 /// @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)3349 pointer_diff::pointer_diff(pointer_type_def_sptr	first,
3350 			   pointer_type_def_sptr	second,
3351 			   diff_sptr			underlying,
3352 			   diff_context_sptr		ctxt)
3353   : type_diff_base(first, second, ctxt),
3354     priv_(new priv(underlying))
3355 {}
3356 
3357 /// Getter for the first subject of a pointer diff
3358 ///
3359 /// @return the first pointer considered in this pointer diff.
3360 const pointer_type_def_sptr
first_pointer() const3361 pointer_diff::first_pointer() const
3362 {return dynamic_pointer_cast<pointer_type_def>(first_subject());}
3363 
3364 /// Getter for the second subject of a pointer diff
3365 ///
3366 /// @return the second pointer considered in this pointer diff.
3367 const pointer_type_def_sptr
second_pointer() const3368 pointer_diff::second_pointer() const
3369 {return dynamic_pointer_cast<pointer_type_def>(second_subject());}
3370 
3371 /// @return the pretty represenation for the current instance of @ref
3372 /// pointer_diff.
3373 const string&
get_pretty_representation() const3374 pointer_diff::get_pretty_representation() const
3375 {
3376   if (diff::priv_->pretty_representation_.empty())
3377     {
3378       std::ostringstream o;
3379       o << "pointer_diff["
3380 	<< first_subject()->get_pretty_representation()
3381 	<< ", "
3382 	<< second_subject()->get_pretty_representation()
3383 	<< "]";
3384       diff::priv_->pretty_representation_ = o.str();
3385     }
3386   return diff::priv_->pretty_representation_;
3387 }
3388 
3389 /// Return true iff the current diff node carries a change.
3390 ///
3391 /// @return true iff the current diff node carries a change.
3392 bool
has_changes() const3393 pointer_diff::has_changes() const
3394 {return first_pointer() != second_pointer();}
3395 
3396 /// @return the kind of local change carried by the current diff node.
3397 /// The value returned is zero if the current node carries no local
3398 /// change.
3399 enum change_kind
has_local_changes() const3400 pointer_diff::has_local_changes() const
3401 {
3402   ir::change_kind k = ir::NO_CHANGE_KIND;
3403   if (!equals(*first_pointer(), *second_pointer(), &k))
3404     return k & ir::ALL_LOCAL_CHANGES_MASK;
3405   return ir::NO_CHANGE_KIND;
3406 }
3407 
3408 /// Getter for the diff between the pointed-to types of the pointers
3409 /// of this diff.
3410 ///
3411 /// @return the diff between the pointed-to types.
3412 diff_sptr
underlying_type_diff() const3413 pointer_diff::underlying_type_diff() const
3414 {return priv_->underlying_type_diff_;}
3415 
3416 /// Setter for the diff between the pointed-to types of the pointers
3417 /// of this diff.
3418 ///
3419 /// @param d the new diff between the pointed-to types of the pointers
3420 /// of this diff.
3421 void
underlying_type_diff(const diff_sptr d)3422 pointer_diff::underlying_type_diff(const diff_sptr d)
3423 {priv_->underlying_type_diff_ = d;}
3424 
3425 /// Report the diff in a serialized form.
3426 ///
3427 /// @param out the stream to serialize the diff to.
3428 ///
3429 /// @param indent the prefix to use for the indentation of this
3430 /// serialization.
3431 void
report(ostream & out,const string & indent) const3432 pointer_diff::report(ostream& out, const string& indent) const
3433 {
3434   context()->get_reporter()->report(*this, out, indent);
3435 }
3436 
3437 /// Compute the diff between between two pointers.
3438 ///
3439 /// Note that the two types must have been created in the same @ref
3440 /// environment, otherwise, this function aborts.
3441 ///
3442 /// @param first the pointer to consider for the diff.
3443 ///
3444 /// @param second the pointer to consider for the diff.
3445 ///
3446 /// @return the resulting diff between the two pointers.
3447 ///
3448 /// @param ctxt the diff context to use.
3449 pointer_diff_sptr
compute_diff(pointer_type_def_sptr first,pointer_type_def_sptr second,diff_context_sptr ctxt)3450 compute_diff(pointer_type_def_sptr	first,
3451 	     pointer_type_def_sptr	second,
3452 	     diff_context_sptr		ctxt)
3453 {
3454   if (first && second)
3455     ABG_ASSERT(first->get_environment() == second->get_environment());
3456 
3457   diff_sptr d = compute_diff_for_types(first->get_pointed_to_type(),
3458 				       second->get_pointed_to_type(),
3459 				       ctxt);
3460   pointer_diff_sptr result(new pointer_diff(first, second, d, ctxt));
3461   ctxt->initialize_canonical_diff(result);
3462 
3463   return result;
3464 }
3465 
3466 // </pointer_type_def>
3467 
3468 // <array_type_def>
3469 
3470 /// Populate the vector of children node of the @ref diff base type
3471 /// sub-object of this instance of @ref array_diff.
3472 ///
3473 /// The children node can then later be retrieved using
3474 /// diff::children_node().
3475 void
chain_into_hierarchy()3476 array_diff::chain_into_hierarchy()
3477 {append_child_node(element_type_diff());}
3478 
3479 /// Constructor for array_diff
3480 ///
3481 /// @param first the first array_type of the diff.
3482 ///
3483 /// @param second the second array_type of the diff.
3484 ///
3485 /// @param element_type_diff the diff between the two array element
3486 /// types.
3487 ///
3488 /// @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)3489 array_diff::array_diff(const array_type_def_sptr	first,
3490 		       const array_type_def_sptr	second,
3491 		       diff_sptr			element_type_diff,
3492 		       diff_context_sptr		ctxt)
3493   : type_diff_base(first, second, ctxt),
3494     priv_(new priv(element_type_diff))
3495 {}
3496 
3497 /// Getter for the first array of the diff.
3498 ///
3499 /// @return the first array of the diff.
3500 const array_type_def_sptr
first_array() const3501 array_diff::first_array() const
3502 {return dynamic_pointer_cast<array_type_def>(first_subject());}
3503 
3504 /// Getter for the second array of the diff.
3505 ///
3506 /// @return for the second array of the diff.
3507 const array_type_def_sptr
second_array() const3508 array_diff::second_array() const
3509 {return dynamic_pointer_cast<array_type_def>(second_subject());}
3510 
3511 /// Getter for the diff between the two types of array elements.
3512 ///
3513 /// @return the diff between the two types of array elements.
3514 const diff_sptr&
element_type_diff() const3515 array_diff::element_type_diff() const
3516 {return priv_->element_type_diff_;}
3517 
3518 /// Setter for the diff between the two array element types.
3519 ///
3520 /// @param d the new diff betweend the two array element types.
3521 void
element_type_diff(diff_sptr d)3522 array_diff::element_type_diff(diff_sptr d)
3523 {priv_->element_type_diff_ = d;}
3524 
3525 /// @return the pretty representation for the current instance of @ref
3526 /// array_diff.
3527 const string&
get_pretty_representation() const3528 array_diff::get_pretty_representation() const
3529 {
3530   if (diff::priv_->pretty_representation_.empty())
3531     {
3532       std::ostringstream o;
3533       o << "array_diff["
3534 	<< first_subject()->get_pretty_representation()
3535 	<< ", "
3536 	<< second_subject()->get_pretty_representation()
3537 	<< "]";
3538       diff::priv_->pretty_representation_ = o.str();
3539     }
3540   return diff::priv_->pretty_representation_;
3541 }
3542 
3543 /// Return true iff the current diff node carries a change.
3544 ///
3545 /// @return true iff the current diff node carries a change.
3546 bool
has_changes() const3547 array_diff::has_changes() const
3548 {
3549   bool l = false;
3550 
3551   //  the array element types match check for differing dimensions
3552   //  etc...
3553   array_type_def_sptr
3554     f = dynamic_pointer_cast<array_type_def>(first_subject()),
3555     s = dynamic_pointer_cast<array_type_def>(second_subject());
3556 
3557   if (f->get_name() != s->get_name())
3558     l |= true;
3559   if (f->get_size_in_bits() != s->get_size_in_bits())
3560     l |= true;
3561   if (f->get_alignment_in_bits() != s->get_alignment_in_bits())
3562     l |= true;
3563 
3564   l |=  element_type_diff()
3565     ? element_type_diff()->has_changes()
3566     : false;
3567 
3568   return l;
3569 }
3570 
3571 
3572 /// @return the kind of local change carried by the current diff node.
3573 /// The value returned is zero if the current node carries no local
3574 /// change.
3575 enum change_kind
has_local_changes() const3576 array_diff::has_local_changes() const
3577 {
3578   ir::change_kind k = ir::NO_CHANGE_KIND;
3579   if (!equals(*first_array(), *second_array(), &k))
3580     return k & ir::ALL_LOCAL_CHANGES_MASK;
3581   return ir::NO_CHANGE_KIND;
3582 }
3583 
3584 /// Report the diff in a serialized form.
3585 ///
3586 /// @param out the output stream to serialize the dif to.
3587 ///
3588 /// @param indent the string to use for indenting the report.
3589 void
report(ostream & out,const string & indent) const3590 array_diff::report(ostream& out, const string& indent) const
3591 {
3592   context()->get_reporter()->report(*this, out, indent);
3593 }
3594 
3595 /// Compute the diff between two arrays.
3596 ///
3597 /// Note that the two types must have been created in the same @ref
3598 /// environment, otherwise, this function aborts.
3599 ///
3600 /// @param first the first array to consider for the diff.
3601 ///
3602 /// @param second the second array to consider for the diff.
3603 ///
3604 /// @param ctxt the diff context to use.
3605 array_diff_sptr
compute_diff(array_type_def_sptr first,array_type_def_sptr second,diff_context_sptr ctxt)3606 compute_diff(array_type_def_sptr	first,
3607 	     array_type_def_sptr	second,
3608 	     diff_context_sptr		ctxt)
3609 {
3610   if (first && second)
3611     ABG_ASSERT(first->get_environment() == second->get_environment());
3612 
3613   diff_sptr d = compute_diff_for_types(first->get_element_type(),
3614 				       second->get_element_type(),
3615 				       ctxt);
3616   array_diff_sptr result(new array_diff(first, second, d, ctxt));
3617   ctxt->initialize_canonical_diff(result);
3618   return result;
3619 }
3620 // </array_type_def>
3621 
3622 // <reference_type_def>
3623 
3624 /// Populate the vector of children node of the @ref diff base type
3625 /// sub-object of this instance of @ref reference_diff.
3626 ///
3627 /// The children node can then later be retrieved using
3628 /// diff::children_node().
3629 void
chain_into_hierarchy()3630 reference_diff::chain_into_hierarchy()
3631 {append_child_node(underlying_type_diff());}
3632 
3633 /// Constructor for reference_diff
3634 ///
3635 /// @param first the first reference_type of the diff.
3636 ///
3637 /// @param second the second reference_type of the diff.
3638 ///
3639 /// @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)3640 reference_diff::reference_diff(const reference_type_def_sptr	first,
3641 			       const reference_type_def_sptr	second,
3642 			       diff_sptr			underlying,
3643 			       diff_context_sptr		ctxt)
3644   : type_diff_base(first, second, ctxt),
3645 	priv_(new priv(underlying))
3646 {}
3647 
3648 /// Getter for the first reference of the diff.
3649 ///
3650 /// @return the first reference of the diff.
3651 reference_type_def_sptr
first_reference() const3652 reference_diff::first_reference() const
3653 {return dynamic_pointer_cast<reference_type_def>(first_subject());}
3654 
3655 /// Getter for the second reference of the diff.
3656 ///
3657 /// @return for the second reference of the diff.
3658 reference_type_def_sptr
second_reference() const3659 reference_diff::second_reference() const
3660 {return dynamic_pointer_cast<reference_type_def>(second_subject());}
3661 
3662 
3663 /// Getter for the diff between the two referred-to types.
3664 ///
3665 /// @return the diff between the two referred-to types.
3666 const diff_sptr&
underlying_type_diff() const3667 reference_diff::underlying_type_diff() const
3668 {return priv_->underlying_type_diff_;}
3669 
3670 /// Setter for the diff between the two referred-to types.
3671 ///
3672 /// @param d the new diff betweend the two referred-to types.
3673 diff_sptr&
underlying_type_diff(diff_sptr d)3674 reference_diff::underlying_type_diff(diff_sptr d)
3675 {
3676   priv_->underlying_type_diff_ = d;
3677   return priv_->underlying_type_diff_;
3678 }
3679 
3680 /// @return the pretty representation for the current instance of @ref
3681 /// reference_diff.
3682 const string&
get_pretty_representation() const3683 reference_diff::get_pretty_representation() const
3684 {
3685   if (diff::priv_->pretty_representation_.empty())
3686     {
3687       std::ostringstream o;
3688       o << "reference_diff["
3689 	<< first_subject()->get_pretty_representation()
3690 	<< ", "
3691 	<< second_subject()->get_pretty_representation()
3692 	<< "]";
3693       diff::priv_->pretty_representation_ = o.str();
3694     }
3695   return diff::priv_->pretty_representation_;
3696 }
3697 
3698 /// Return true iff the current diff node carries a change.
3699 ///
3700 /// @return true iff the current diff node carries a change.
3701 bool
has_changes() const3702 reference_diff::has_changes() const
3703 {
3704   return first_reference() != second_reference();
3705 }
3706 
3707 /// @return the kind of local change carried by the current diff node.
3708 /// The value returned is zero if the current node carries no local
3709 /// change.
3710 enum change_kind
has_local_changes() const3711 reference_diff::has_local_changes() const
3712 {
3713   ir::change_kind k = ir::NO_CHANGE_KIND;
3714   if (!equals(*first_reference(), *second_reference(), &k))
3715     return k & ir::ALL_LOCAL_CHANGES_MASK;
3716   return ir::NO_CHANGE_KIND;
3717 }
3718 
3719 /// Report the diff in a serialized form.
3720 ///
3721 /// @param out the output stream to serialize the dif to.
3722 ///
3723 /// @param indent the string to use for indenting the report.
3724 void
report(ostream & out,const string & indent) const3725 reference_diff::report(ostream& out, const string& indent) const
3726 {
3727   context()->get_reporter()->report(*this, out, indent);
3728 }
3729 
3730 /// Compute the diff between two references.
3731 ///
3732 /// Note that the two types must have been created in the same @ref
3733 /// environment, otherwise, this function aborts.
3734 ///
3735 /// @param first the first reference to consider for the diff.
3736 ///
3737 /// @param second the second reference to consider for the diff.
3738 ///
3739 /// @param ctxt the diff context to use.
3740 reference_diff_sptr
compute_diff(reference_type_def_sptr first,reference_type_def_sptr second,diff_context_sptr ctxt)3741 compute_diff(reference_type_def_sptr	first,
3742 	     reference_type_def_sptr	second,
3743 	     diff_context_sptr		ctxt)
3744 {
3745   if (first && second)
3746     ABG_ASSERT(first->get_environment() == second->get_environment());
3747 
3748   diff_sptr d = compute_diff_for_types(first->get_pointed_to_type(),
3749 				       second->get_pointed_to_type(),
3750 				       ctxt);
3751   reference_diff_sptr result(new reference_diff(first, second, d, ctxt));
3752   ctxt->initialize_canonical_diff(result);
3753   return result;
3754 }
3755 // </reference_type_def>
3756 
3757 // <qualified_type_diff stuff>
3758 
3759 /// Populate the vector of children node of the @ref diff base type
3760 /// sub-object of this instance of @ref qualified_type_diff.
3761 ///
3762 /// The children node can then later be retrieved using
3763 /// diff::children_node().
3764 void
chain_into_hierarchy()3765 qualified_type_diff::chain_into_hierarchy()
3766 {append_child_node(leaf_underlying_type_diff());}
3767 
3768 /// Constructor for qualified_type_diff.
3769 ///
3770 /// @param first the first qualified type of the diff.
3771 ///
3772 /// @param second the second qualified type of the diff.
3773 ///
3774 /// @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)3775 qualified_type_diff::qualified_type_diff(qualified_type_def_sptr	first,
3776 					 qualified_type_def_sptr	second,
3777 					 diff_sptr			under,
3778 					 diff_context_sptr		ctxt)
3779   : type_diff_base(first, second, ctxt),
3780     priv_(new priv(under))
3781 {}
3782 
3783 /// Getter for the first qualified type of the diff.
3784 ///
3785 /// @return the first qualified type of the diff.
3786 const qualified_type_def_sptr
first_qualified_type() const3787 qualified_type_diff::first_qualified_type() const
3788 {return dynamic_pointer_cast<qualified_type_def>(first_subject());}
3789 
3790 /// Getter for the second qualified type of the diff.
3791 ///
3792 /// @return the second qualified type of the diff.
3793 const qualified_type_def_sptr
second_qualified_type() const3794 qualified_type_diff::second_qualified_type() const
3795 {return dynamic_pointer_cast<qualified_type_def>(second_subject());}
3796 
3797 /// Getter for the diff between the underlying types of the two
3798 /// qualified types.
3799 ///
3800 /// @return the diff between the underlying types of the two qualified
3801 /// types.
3802 diff_sptr
underlying_type_diff() const3803 qualified_type_diff::underlying_type_diff() const
3804 {return priv_->underlying_type_diff;}
3805 
3806 /// Getter for the diff between the most underlying non-qualified
3807 /// types of two qualified types.
3808 ///
3809 /// @return the diff between the most underlying non-qualified types
3810 /// of two qualified types.
3811 diff_sptr
leaf_underlying_type_diff() const3812 qualified_type_diff::leaf_underlying_type_diff() const
3813 {
3814   if (!priv_->leaf_underlying_type_diff)
3815     priv_->leaf_underlying_type_diff
3816       = compute_diff_for_types(get_leaf_type(first_qualified_type()),
3817 			       get_leaf_type(second_qualified_type()),
3818 			       context());
3819 
3820   return priv_->leaf_underlying_type_diff;
3821 }
3822 
3823 /// Setter for the diff between the underlying types of the two
3824 /// qualified types.
3825 ///
3826 /// @return the diff between the underlying types of the two qualified
3827 /// types.
3828 void
underlying_type_diff(const diff_sptr d)3829 qualified_type_diff::underlying_type_diff(const diff_sptr d)
3830 {priv_->underlying_type_diff = d;}
3831 
3832 /// @return the pretty representation of the current instance of @ref
3833 /// qualified_type_diff.
3834 const string&
get_pretty_representation() const3835 qualified_type_diff::get_pretty_representation() const
3836 {
3837   if (diff::priv_->pretty_representation_.empty())
3838     {
3839       std::ostringstream o;
3840       o << "qualified_type_diff["
3841 	<< first_subject()->get_pretty_representation()
3842 	<< ", "
3843 	<< second_subject()->get_pretty_representation()
3844 	<< "]";
3845       diff::priv_->pretty_representation_ = o.str();
3846     }
3847   return diff::priv_->pretty_representation_;
3848 }
3849 
3850 /// Return true iff the current diff node carries a change.
3851 ///
3852 /// @return true iff the current diff node carries a change.
3853 bool
has_changes() const3854 qualified_type_diff::has_changes() const
3855 {return first_qualified_type() != second_qualified_type();}
3856 
3857 /// @return the kind of local change carried by the current diff node.
3858 /// The value returned is zero if the current node carries no local
3859 /// change.
3860 enum change_kind
has_local_changes() const3861 qualified_type_diff::has_local_changes() const
3862 {
3863   ir::change_kind k = ir::NO_CHANGE_KIND;
3864   if (!equals(*first_qualified_type(), *second_qualified_type(), &k))
3865     return k & ir::ALL_LOCAL_CHANGES_MASK;
3866   return ir::NO_CHANGE_KIND;
3867 }
3868 
3869 /// Report the diff in a serialized form.
3870 ///
3871 /// @param out the output stream to serialize to.
3872 ///
3873 /// @param indent the string to use to indent the lines of the report.
3874 void
report(ostream & out,const string & indent) const3875 qualified_type_diff::report(ostream& out, const string& indent) const
3876 {
3877   context()->get_reporter()->report(*this, out, indent);
3878 }
3879 
3880 /// Compute the diff between two qualified types.
3881 ///
3882 /// Note that the two types must have been created in the same @ref
3883 /// environment, otherwise, this function aborts.
3884 ///
3885 /// @param first the first qualified type to consider for the diff.
3886 ///
3887 /// @param second the second qualified type to consider for the diff.
3888 ///
3889 /// @param ctxt the diff context to use.
3890 qualified_type_diff_sptr
compute_diff(const qualified_type_def_sptr first,const qualified_type_def_sptr second,diff_context_sptr ctxt)3891 compute_diff(const qualified_type_def_sptr	first,
3892 	     const qualified_type_def_sptr	second,
3893 	     diff_context_sptr			ctxt)
3894 {
3895   if (first && second)
3896     ABG_ASSERT(first->get_environment() == second->get_environment());
3897 
3898   diff_sptr d = compute_diff_for_types(first->get_underlying_type(),
3899 				       second->get_underlying_type(),
3900 				       ctxt);
3901   qualified_type_diff_sptr result(new qualified_type_diff(first, second,
3902 							  d, ctxt));
3903   ctxt->initialize_canonical_diff(result);
3904   return result;
3905 }
3906 
3907 // </qualified_type_diff stuff>
3908 
3909 // <enum_diff stuff>
3910 
3911 /// Clear the lookup tables useful for reporting an enum_diff.
3912 ///
3913 /// This function must be updated each time a lookup table is added or
3914 /// removed from the class_diff::priv.
3915 void
clear_lookup_tables()3916 enum_diff::clear_lookup_tables()
3917 {
3918   priv_->deleted_enumerators_.clear();
3919   priv_->inserted_enumerators_.clear();
3920   priv_->changed_enumerators_.clear();
3921 }
3922 
3923 /// Tests if the lookup tables are empty.
3924 ///
3925 /// @return true if the lookup tables are empty, false otherwise.
3926 bool
lookup_tables_empty() const3927 enum_diff::lookup_tables_empty() const
3928 {
3929   return (priv_->deleted_enumerators_.empty()
3930 	  && priv_->inserted_enumerators_.empty()
3931 	  && priv_->changed_enumerators_.empty());
3932 }
3933 
3934 /// If the lookup tables are not yet built, walk the differences and
3935 /// fill the lookup tables.
3936 void
ensure_lookup_tables_populated()3937 enum_diff::ensure_lookup_tables_populated()
3938 {
3939   if (!lookup_tables_empty())
3940     return;
3941 
3942   {
3943     edit_script e = priv_->enumerators_changes_;
3944 
3945     for (vector<deletion>::const_iterator it = e.deletions().begin();
3946 	 it != e.deletions().end();
3947 	 ++it)
3948       {
3949 	unsigned i = it->index();
3950 	const enum_type_decl::enumerator& n =
3951 	  first_enum()->get_enumerators()[i];
3952 	const string& name = n.get_name();
3953 	ABG_ASSERT(priv_->deleted_enumerators_.find(n.get_name())
3954 	       == priv_->deleted_enumerators_.end());
3955 	priv_->deleted_enumerators_[name] = n;
3956       }
3957 
3958     for (vector<insertion>::const_iterator it = e.insertions().begin();
3959 	 it != e.insertions().end();
3960 	 ++it)
3961       {
3962 	for (vector<unsigned>::const_iterator iit =
3963 	       it->inserted_indexes().begin();
3964 	     iit != it->inserted_indexes().end();
3965 	     ++iit)
3966 	  {
3967 	    unsigned i = *iit;
3968 	    const enum_type_decl::enumerator& n =
3969 	      second_enum()->get_enumerators()[i];
3970 	    const string& name = n.get_name();
3971 	    ABG_ASSERT(priv_->inserted_enumerators_.find(n.get_name())
3972 		   == priv_->inserted_enumerators_.end());
3973 	    string_enumerator_map::const_iterator j =
3974 	      priv_->deleted_enumerators_.find(name);
3975 	    if (j == priv_->deleted_enumerators_.end())
3976 	      priv_->inserted_enumerators_[name] = n;
3977 	    else
3978 	      {
3979 		if (j->second != n)
3980 		  priv_->changed_enumerators_[j->first] =
3981 		    std::make_pair(j->second, n);
3982 		priv_->deleted_enumerators_.erase(j);
3983 	      }
3984 	  }
3985       }
3986   }
3987 }
3988 
3989 /// Populate the vector of children node of the @ref diff base type
3990 /// sub-object of this instance of @ref enum_diff.
3991 ///
3992 /// The children node can then later be retrieved using
3993 /// diff::children_node().
3994 void
chain_into_hierarchy()3995 enum_diff::chain_into_hierarchy()
3996 {append_child_node(underlying_type_diff());}
3997 
3998 /// Constructor for enum_diff.
3999 ///
4000 /// @param first the first enum type of the diff.
4001 ///
4002 /// @param second the second enum type of the diff.
4003 ///
4004 /// @param underlying_type_diff the diff of the two underlying types
4005 /// of the two enum types.
4006 ///
4007 /// @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)4008 enum_diff::enum_diff(const enum_type_decl_sptr	first,
4009 		     const enum_type_decl_sptr	second,
4010 		     const diff_sptr		underlying_type_diff,
4011 		     const diff_context_sptr	ctxt)
4012   : type_diff_base(first, second, ctxt),
4013     priv_(new priv(underlying_type_diff))
4014 {}
4015 
4016 /// @return the first enum of the diff.
4017 const enum_type_decl_sptr
first_enum() const4018 enum_diff::first_enum() const
4019 {return dynamic_pointer_cast<enum_type_decl>(first_subject());}
4020 
4021 /// @return the second enum of the diff.
4022 const enum_type_decl_sptr
second_enum() const4023 enum_diff::second_enum() const
4024 {return dynamic_pointer_cast<enum_type_decl>(second_subject());}
4025 
4026 /// @return the diff of the two underlying enum types.
4027 diff_sptr
underlying_type_diff() const4028 enum_diff::underlying_type_diff() const
4029 {return priv_->underlying_type_diff_;}
4030 
4031 /// @return a map of the enumerators that were deleted.
4032 const string_enumerator_map&
deleted_enumerators() const4033 enum_diff::deleted_enumerators() const
4034 {return priv_->deleted_enumerators_;}
4035 
4036 /// @return a map of the enumerators that were inserted
4037 const string_enumerator_map&
inserted_enumerators() const4038 enum_diff::inserted_enumerators() const
4039 {return priv_->inserted_enumerators_;}
4040 
4041 /// @return a map of the enumerators that were changed
4042 const string_changed_enumerator_map&
changed_enumerators() const4043 enum_diff::changed_enumerators() const
4044 {return priv_->changed_enumerators_;}
4045 
4046 /// @return the pretty representation of the current instance of @ref
4047 /// enum_diff.
4048 const string&
get_pretty_representation() const4049 enum_diff::get_pretty_representation() const
4050 {
4051   if (diff::priv_->pretty_representation_.empty())
4052     {
4053       std::ostringstream o;
4054       o << "enum_diff["
4055 	<< first_subject()->get_pretty_representation()
4056 	<< ", "
4057 	<< second_subject()->get_pretty_representation()
4058 	<< "]";
4059       diff::priv_->pretty_representation_ = o.str();
4060     }
4061   return diff::priv_->pretty_representation_;
4062 }
4063 
4064 /// Return true iff the current diff node carries a change.
4065 ///
4066 /// @return true iff the current diff node carries a change.
4067 bool
has_changes() const4068 enum_diff::has_changes() const
4069 {return first_enum() != second_enum();}
4070 
4071 /// @return the kind of local change carried by the current diff node.
4072 /// The value returned is zero if the current node carries no local
4073 /// change.
4074 enum change_kind
has_local_changes() const4075 enum_diff::has_local_changes() const
4076 {
4077   ir::change_kind k = ir::NO_CHANGE_KIND;
4078   if (!equals(*first_enum(), *second_enum(), &k))
4079     return k & ir::ALL_LOCAL_CHANGES_MASK;
4080   return ir::NO_CHANGE_KIND;
4081 }
4082 
4083 /// Report the differences between the two enums.
4084 ///
4085 /// @param out the output stream to send the report to.
4086 ///
4087 /// @param indent the string to use for indentation.
4088 void
report(ostream & out,const string & indent) const4089 enum_diff::report(ostream& out, const string& indent) const
4090 {
4091   context()->get_reporter()->report(*this, out, indent);
4092 }
4093 
4094 /// Compute the set of changes between two instances of @ref
4095 /// enum_type_decl.
4096 ///
4097 /// Note that the two types must have been created in the same @ref
4098 /// environment, otherwise, this function aborts.
4099 ///
4100 /// @param first a pointer to the first enum_type_decl to consider.
4101 ///
4102 /// @param second a pointer to the second enum_type_decl to consider.
4103 ///
4104 /// @return the resulting diff of the two enums @p first and @p
4105 /// second.
4106 ///
4107 /// @param ctxt the diff context to use.
4108 enum_diff_sptr
compute_diff(const enum_type_decl_sptr first,const enum_type_decl_sptr second,diff_context_sptr ctxt)4109 compute_diff(const enum_type_decl_sptr first,
4110 	     const enum_type_decl_sptr second,
4111 	     diff_context_sptr ctxt)
4112 {
4113   if (first && second)
4114     ABG_ASSERT(first->get_environment() == second->get_environment());
4115 
4116   diff_sptr ud = compute_diff_for_types(first->get_underlying_type(),
4117 					second->get_underlying_type(),
4118 					ctxt);
4119   enum_diff_sptr d(new enum_diff(first, second, ud, ctxt));
4120   if (first != second)
4121     {
4122       compute_diff(first->get_enumerators().begin(),
4123 		   first->get_enumerators().end(),
4124 		   second->get_enumerators().begin(),
4125 		   second->get_enumerators().end(),
4126 		   d->priv_->enumerators_changes_);
4127       d->ensure_lookup_tables_populated();
4128     }
4129   ctxt->initialize_canonical_diff(d);
4130 
4131   return d;
4132 }
4133 // </enum_diff stuff>
4134 
4135 // <class_or_union_diff stuff>
4136 
4137 /// Test if the current diff node carries a member type change for a
4138 /// member type which name is the same as the name of a given type
4139 /// declaration.
4140 ///
4141 /// @param d the type declaration which name should be equal to the
4142 /// name of the member type that might have changed.
4143 ///
4144 /// @return the member type that has changed, iff there were a member
4145 /// type (which name is the same as the name of @p d) that changed.
4146 /// Note that the member type that is returned is the new value of the
4147 /// member type that changed.
4148 type_or_decl_base_sptr
member_type_has_changed(decl_base_sptr d) const4149 class_or_union_diff::priv::member_type_has_changed(decl_base_sptr d) const
4150 {
4151   string qname = d->get_qualified_name();
4152   string_diff_sptr_map::const_iterator it =
4153     changed_member_types_.find(qname);
4154 
4155   return ((it == changed_member_types_.end())
4156 	  ? type_or_decl_base_sptr()
4157 	  : it->second->second_subject());
4158 }
4159 
4160 /// Test if the current diff node carries a data member change for a
4161 /// data member which name is the same as the name of a given type
4162 /// declaration.
4163 ///
4164 /// @param d the type declaration which name should be equal to the
4165 /// name of the data member that might have changed.
4166 ///
4167 /// @return the data member that has changed, iff there were a data
4168 /// member type (which name is the same as the name of @p d) that
4169 /// changed.  Note that the data member that is returned is the new
4170 /// value of the data member that changed.
4171 decl_base_sptr
subtype_changed_dm(decl_base_sptr d) const4172 class_or_union_diff::priv::subtype_changed_dm(decl_base_sptr d) const
4173 {
4174   string qname = d->get_qualified_name();
4175   string_var_diff_sptr_map::const_iterator it =
4176     subtype_changed_dm_.find(qname);
4177 
4178   if (it == subtype_changed_dm_.end())
4179     return decl_base_sptr();
4180   return it->second->second_var();
4181 }
4182 
4183 /// Test if the current diff node carries a member class template
4184 /// change for a member class template which name is the same as the
4185 /// name of a given type declaration.
4186 ///
4187 /// @param d the type declaration which name should be equal to the
4188 /// name of the member class template that might have changed.
4189 ///
4190 /// @return the member class template that has changed, iff there were
4191 /// a member class template (which name is the same as the name of @p
4192 /// d) that changed.  Note that the member class template that is
4193 /// returned is the new value of the member class template that
4194 /// changed.
4195 decl_base_sptr
member_class_tmpl_has_changed(decl_base_sptr d) const4196 class_or_union_diff::priv::member_class_tmpl_has_changed(decl_base_sptr d) const
4197 {
4198   string qname = d->get_qualified_name();
4199   string_diff_sptr_map::const_iterator it =
4200     changed_member_class_tmpls_.find(qname);
4201 
4202   return ((it == changed_member_class_tmpls_.end())
4203 	  ? decl_base_sptr()
4204 	  : dynamic_pointer_cast<decl_base>(it->second->second_subject()));
4205 }
4206 
4207 /// Get the number of non static data members that were deleted.
4208 ///
4209 /// @return the number of non static data members that were deleted.
4210 size_t
get_deleted_non_static_data_members_number() const4211 class_or_union_diff::priv::get_deleted_non_static_data_members_number() const
4212 {
4213   size_t result = 0;
4214 
4215   for (string_decl_base_sptr_map::const_iterator i =
4216 	 deleted_data_members_.begin();
4217        i != deleted_data_members_.end();
4218        ++i)
4219     if (is_member_decl(i->second)
4220 	&& !get_member_is_static(i->second))
4221       ++result;
4222 
4223   return result;
4224 }
4225 
4226 /// Get the number of non static data members that were inserted.
4227 ///
4228 /// @return the number of non static data members that were inserted.
4229 size_t
get_inserted_non_static_data_members_number() const4230 class_or_union_diff::priv::get_inserted_non_static_data_members_number() const
4231 {
4232   size_t result = 0;
4233 
4234   for (string_decl_base_sptr_map::const_iterator i =
4235 	 inserted_data_members_.begin();
4236        i != inserted_data_members_.end();
4237        ++i)
4238     if (is_member_decl(i->second)
4239 	&& !get_member_is_static(i->second))
4240       ++result;
4241 
4242   return result;
4243 }
4244 
4245 /// Get the number of data member sub-type changes carried by the
4246 /// current diff node that were filtered out.
4247 ///
4248 /// @param local_only if true, it means that only (filtered) local
4249 /// changes are considered.
4250 ///
4251 /// @return the number of data member sub-type changes carried by the
4252 /// current diff node that were filtered out.
4253 size_t
count_filtered_subtype_changed_dm(bool local_only)4254 class_or_union_diff::priv::count_filtered_subtype_changed_dm(bool local_only)
4255 {
4256   size_t num_filtered= 0;
4257   for (var_diff_sptrs_type::const_iterator i =
4258 	 sorted_subtype_changed_dm_.begin();
4259        i != sorted_subtype_changed_dm_.end();
4260        ++i)
4261     {
4262       if (local_only)
4263 	{
4264 	  if ((*i)->has_changes()
4265 	      && !(*i)->has_local_changes_to_be_reported())
4266 	    ++num_filtered;
4267 	}
4268       else
4269 	{
4270 	  if ((*i)->is_filtered_out())
4271 	    ++num_filtered;
4272 	}
4273     }
4274   return num_filtered;
4275 }
4276 
4277 /// Get the number of data member changes carried by the current diff
4278 /// node that were filtered out.
4279 ///
4280 /// @param local_only if true, it means that only (filtered) local
4281 /// changes are considered.
4282 ///
4283 /// @return the number of data member changes carried by the current
4284 /// diff node that were filtered out.
4285 size_t
count_filtered_changed_dm(bool local_only)4286 class_or_union_diff::priv::count_filtered_changed_dm(bool local_only)
4287 {
4288   size_t num_filtered= 0;
4289 
4290   for (unsigned_var_diff_sptr_map::const_iterator i = changed_dm_.begin();
4291        i != changed_dm_.end();
4292        ++i)
4293     {
4294       diff_sptr diff = i->second;
4295       if (local_only)
4296 	{
4297 	  if ((diff->has_changes() && !diff->has_local_changes_to_be_reported())
4298 	      || diff->is_filtered_out())
4299 	    ++num_filtered;
4300 	}
4301       else
4302 	{
4303 	  if (diff->is_filtered_out())
4304 	    ++num_filtered;
4305 	}
4306     }
4307   return num_filtered;
4308 }
4309 
4310 /// Skip the processing of the current member function if its
4311 /// virtual-ness is disallowed by the user.
4312 ///
4313 /// This is to be used in the member functions below that are used to
4314 /// count the number of filtered inserted, deleted and changed member
4315 /// functions.
4316 #define SKIP_MEM_FN_IF_VIRTUALITY_DISALLOWED				\
4317   do {									\
4318     if (get_member_function_is_virtual(f)					\
4319 	|| get_member_function_is_virtual(s))				\
4320       {								\
4321 	if (!(allowed_category | VIRTUAL_MEMBER_CHANGE_CATEGORY))	\
4322 	  continue;							\
4323       }								\
4324     else								\
4325       {								\
4326 	if (!(allowed_category | NON_VIRT_MEM_FUN_CHANGE_CATEGORY))	\
4327 	  continue;							\
4328       }								\
4329   } while (false)
4330 
4331 /// Get the number of member functions changes carried by the current
4332 /// diff node that were filtered out.
4333 ///
4334 /// @return the number of member functions changes carried by the
4335 /// current diff node that were filtered out.
4336 size_t
count_filtered_changed_mem_fns(const diff_context_sptr & ctxt)4337 class_or_union_diff::priv::count_filtered_changed_mem_fns
4338 (const diff_context_sptr& ctxt)
4339 {
4340   size_t count = 0;
4341   diff_category allowed_category = ctxt->get_allowed_category();
4342 
4343   for (function_decl_diff_sptrs_type::const_iterator i =
4344 	 sorted_changed_member_functions_.begin();
4345        i != sorted_changed_member_functions_.end();
4346        ++i)
4347     {
4348       method_decl_sptr f =
4349 	dynamic_pointer_cast<method_decl>
4350 	((*i)->first_function_decl());
4351       ABG_ASSERT(f);
4352 
4353       method_decl_sptr s =
4354 	dynamic_pointer_cast<method_decl>
4355 	((*i)->second_function_decl());
4356       ABG_ASSERT(s);
4357 
4358       SKIP_MEM_FN_IF_VIRTUALITY_DISALLOWED;
4359 
4360       diff_sptr diff = *i;
4361       ctxt->maybe_apply_filters(diff);
4362 
4363       if (diff->is_filtered_out())
4364 	++count;
4365     }
4366 
4367   return count;
4368 }
4369 
4370 /// Get the number of member functions insertions carried by the current
4371 /// diff node that were filtered out.
4372 ///
4373 /// @return the number of member functions insertions carried by the
4374 /// current diff node that were filtered out.
4375 size_t
count_filtered_inserted_mem_fns(const diff_context_sptr & ctxt)4376 class_or_union_diff::priv::count_filtered_inserted_mem_fns
4377 (const diff_context_sptr& ctxt)
4378 {
4379     size_t count = 0;
4380   diff_category allowed_category = ctxt->get_allowed_category();
4381 
4382   for (string_member_function_sptr_map::const_iterator i =
4383 	 inserted_member_functions_.begin();
4384        i != inserted_member_functions_.end();
4385        ++i)
4386     {
4387       method_decl_sptr f = i->second,
4388 	s = i->second;
4389 
4390       SKIP_MEM_FN_IF_VIRTUALITY_DISALLOWED;
4391 
4392       diff_sptr diff = compute_diff_for_decls(f, s, ctxt);
4393       ctxt->maybe_apply_filters(diff);
4394 
4395       if (diff->get_category() != NO_CHANGE_CATEGORY
4396 	  && diff->is_filtered_out())
4397 	++count;
4398     }
4399 
4400   return count;
4401 }
4402 
4403 /// Get the number of member functions deletions carried by the current
4404 /// diff node that were filtered out.
4405 ///
4406 /// @return the number of member functions deletions carried by the
4407 /// current diff node that were filtered out.
4408 size_t
count_filtered_deleted_mem_fns(const diff_context_sptr & ctxt)4409 class_or_union_diff::priv::count_filtered_deleted_mem_fns
4410 (const diff_context_sptr& ctxt)
4411 {
4412   size_t count = 0;
4413   diff_category allowed_category = ctxt->get_allowed_category();
4414 
4415   for (string_member_function_sptr_map::const_iterator i =
4416 	 deleted_member_functions_.begin();
4417        i != deleted_member_functions_.end();
4418        ++i)
4419     {
4420       method_decl_sptr f = i->second,
4421 	s = i->second;
4422 
4423       SKIP_MEM_FN_IF_VIRTUALITY_DISALLOWED;
4424 
4425       diff_sptr diff = compute_diff_for_decls(f, s, ctxt);
4426       ctxt->maybe_apply_filters(diff);
4427 
4428       if (diff->get_category() != NO_CHANGE_CATEGORY
4429 	  && diff->is_filtered_out())
4430 	++count;
4431     }
4432 
4433   return count;
4434 }
4435 
4436 /// Clear the lookup tables useful for reporting.
4437 ///
4438 /// This function must be updated each time a lookup table is added or
4439 /// removed from the class_or_union_diff::priv.
4440 void
clear_lookup_tables()4441 class_or_union_diff::clear_lookup_tables()
4442 {
4443   priv_->deleted_member_types_.clear();
4444   priv_->inserted_member_types_.clear();
4445   priv_->changed_member_types_.clear();
4446   priv_->deleted_data_members_.clear();
4447   priv_->inserted_data_members_.clear();
4448   priv_->subtype_changed_dm_.clear();
4449   priv_->deleted_member_functions_.clear();
4450   priv_->inserted_member_functions_.clear();
4451   priv_->changed_member_functions_.clear();
4452   priv_->deleted_member_class_tmpls_.clear();
4453   priv_->inserted_member_class_tmpls_.clear();
4454   priv_->changed_member_class_tmpls_.clear();
4455 }
4456 
4457 /// Tests if the lookup tables are empty.
4458 ///
4459 /// @return true if the lookup tables are empty, false otherwise.
4460 bool
lookup_tables_empty(void) const4461 class_or_union_diff::lookup_tables_empty(void) const
4462 {
4463   return (priv_->deleted_member_types_.empty()
4464 	  && priv_->inserted_member_types_.empty()
4465 	  && priv_->changed_member_types_.empty()
4466 	  && priv_->deleted_data_members_.empty()
4467 	  && priv_->inserted_data_members_.empty()
4468 	  && priv_->subtype_changed_dm_.empty()
4469 	  && priv_->inserted_member_functions_.empty()
4470 	  && priv_->deleted_member_functions_.empty()
4471 	  && priv_->changed_member_functions_.empty()
4472 	  && priv_->deleted_member_class_tmpls_.empty()
4473 	  && priv_->inserted_member_class_tmpls_.empty()
4474 	  && priv_->changed_member_class_tmpls_.empty());
4475 }
4476 
4477 /// If the lookup tables are not yet built, walk the differences and
4478 /// fill them.
4479 void
ensure_lookup_tables_populated(void) const4480 class_or_union_diff::ensure_lookup_tables_populated(void) const
4481 {
4482   {
4483     edit_script& e = priv_->member_types_changes_;
4484 
4485     for (vector<deletion>::const_iterator it = e.deletions().begin();
4486 	 it != e.deletions().end();
4487 	 ++it)
4488       {
4489 	unsigned i = it->index();
4490 	decl_base_sptr d =
4491 	  get_type_declaration(first_class_or_union()->get_member_types()[i]);
4492 	class_or_union_sptr record_type = is_class_or_union_type(d);
4493 	if (record_type && record_type->get_is_declaration_only())
4494 	  continue;
4495 	string name = d->get_name();
4496 	priv_->deleted_member_types_[name] = d;
4497       }
4498 
4499     for (vector<insertion>::const_iterator it = e.insertions().begin();
4500 	 it != e.insertions().end();
4501 	 ++it)
4502       {
4503 	for (vector<unsigned>::const_iterator iit =
4504 	       it->inserted_indexes().begin();
4505 	     iit != it->inserted_indexes().end();
4506 	     ++iit)
4507 	  {
4508 	    unsigned i = *iit;
4509 	    decl_base_sptr d =
4510 	      get_type_declaration(second_class_or_union()->get_member_types()[i]);
4511 	    class_or_union_sptr record_type = is_class_or_union_type(d);
4512 	    if (record_type && record_type->get_is_declaration_only())
4513 	      continue;
4514 	    string name = d->get_name();
4515 	    string_decl_base_sptr_map::const_iterator j =
4516 	      priv_->deleted_member_types_.find(name);
4517 	    if (j != priv_->deleted_member_types_.end())
4518 	      {
4519 		if (*j->second != *d)
4520 		  priv_->changed_member_types_[name] =
4521 		    compute_diff(j->second, d, context());
4522 
4523 		priv_->deleted_member_types_.erase(j);
4524 	      }
4525 	    else
4526 	      priv_->inserted_member_types_[name] = d;
4527 	  }
4528       }
4529   }
4530 
4531   {
4532     edit_script& e = priv_->data_members_changes_;
4533 
4534     for (vector<deletion>::const_iterator it = e.deletions().begin();
4535 	 it != e.deletions().end();
4536 	 ++it)
4537       {
4538 	unsigned i = it->index();
4539 	var_decl_sptr data_member =
4540 	  is_var_decl(first_class_or_union()->get_non_static_data_members()[i]);
4541 	string name = data_member->get_anon_dm_reliable_name();
4542 
4543 	ABG_ASSERT(priv_->deleted_data_members_.find(name)
4544 		   == priv_->deleted_data_members_.end());
4545 	priv_->deleted_data_members_[name] = data_member;
4546       }
4547 
4548     for (vector<insertion>::const_iterator it = e.insertions().begin();
4549 	 it != e.insertions().end();
4550 	 ++it)
4551       {
4552 	for (vector<unsigned>::const_iterator iit =
4553 	       it->inserted_indexes().begin();
4554 	     iit != it->inserted_indexes().end();
4555 	     ++iit)
4556 	  {
4557 	    unsigned i = *iit;
4558 	    decl_base_sptr d =
4559 	      second_class_or_union()->get_non_static_data_members()[i];
4560 	    var_decl_sptr added_dm = is_var_decl(d);
4561 	    string name = added_dm->get_anon_dm_reliable_name();
4562 	    ABG_ASSERT(priv_->inserted_data_members_.find(name)
4563 		       == priv_->inserted_data_members_.end());
4564 
4565 	    bool ignore_added_anonymous_data_member = false;
4566 	    if (is_anonymous_data_member(added_dm))
4567 	      {
4568 		//
4569 		// Handle insertion of anonymous data member to
4570 		// replace existing data members.
4571 		//
4572 		// For instance consider this:
4573 		//   struct S
4574 		//   {
4575 		//     int a;
4576 		//     int b;
4577 		//     int c;
4578 		//   };// end struct S
4579 		//
4580 		//   Where the data members 'a' and 'b' are replaced
4581 		//   by an anonymous data member without changing the
4582 		//   effective bit layout of the structure:
4583 		//
4584 		//   struct S
4585 		//   {
4586 		//     struct
4587 		//     {
4588 		//       union
4589 		//       {
4590 		//         int a;
4591 		//         char a_1;
4592 		//       };
4593 		//       union
4594 		//       {
4595 		//         int b;
4596 		//         char b_1;
4597 		//       };
4598 		//     };
4599 		//     int c;
4600 		//   }; // end struct S
4601 		//
4602 		var_decl_sptr replaced_dm, replacing_dm;
4603 		bool added_anon_dm_changes_dm = false;
4604 		// The vector of data members replaced by anonymous
4605 		// data members.
4606 		vector<var_decl_sptr> dms_replaced_by_anon_dm;
4607 
4608 		//
4609 		// Let's start collecting the set of data members
4610 		// which have been replaced by anonymous types in a
4611 		// harmless way.  These are going to be collected into
4612 		// dms_replaced_by_anon_dm and, ultimately, into
4613 		// priv_->dms_replaced_by_adms_
4614 		//
4615 		for (string_decl_base_sptr_map::const_iterator it =
4616 		       priv_->deleted_data_members_.begin();
4617 		     it != priv_->deleted_data_members_.end();
4618 		     ++it)
4619 		  {
4620 		    // We don't support this pattern for anonymous
4621 		    // data members themselves being replaced.  If
4622 		    // that occurs then we'll just report it verbatim.
4623 		    if (is_anonymous_data_member(it->second))
4624 		      continue;
4625 
4626 		    string deleted_dm_name = it->second->get_name();
4627 		    if ((replacing_dm =
4628 			 find_data_member_from_anonymous_data_member(added_dm,
4629 								     deleted_dm_name)))
4630 		      {
4631 			// So it looks like replacing_dm might have
4632 			// replaced the data member which name is
4633 			// 'deleted_dm_name'.  Let's look deeper to be
4634 			// sure.
4635 			//
4636 			// Note that replacing_dm is part (member) of
4637 			// an anonymous data member that might replace
4638 			// replaced_dm.
4639 
4640 			// So let's get that replaced data member.
4641 			replaced_dm = is_var_decl(it->second);
4642 			size_t replaced_dm_offset =
4643 			  get_data_member_offset(replaced_dm),
4644 			replacing_dm_offset =
4645 			  get_absolute_data_member_offset(replacing_dm);
4646 
4647 			if (replaced_dm_offset != replacing_dm_offset)
4648 			  {
4649 			    // So the replacing data member and the
4650 			    // replaced data member don't have the
4651 			    // same offset.  This is not the pattern we
4652 			    // are looking for.  Rather, it looks like
4653 			    // the anonymous data member has *changed*
4654 			    // the data member.
4655 			    added_anon_dm_changes_dm = true;
4656 			    break;
4657 			  }
4658 
4659 			if (replaced_dm->get_type()->get_size_in_bits()
4660 			    == replaced_dm->get_type()->get_size_in_bits())
4661 			  dms_replaced_by_anon_dm.push_back(replaced_dm);
4662 			else
4663 			  {
4664 			    added_anon_dm_changes_dm = true;
4665 			    break;
4666 			  }
4667 		      }
4668 		  }
4669 
4670 		// Now walk dms_replaced_by_anon_dm to fill up
4671 		// priv_->dms_replaced_by_adms_ with the set of data
4672 		// members replaced by anonymous data members.
4673 		if (!added_anon_dm_changes_dm
4674 		    && !dms_replaced_by_anon_dm.empty())
4675 		  {
4676 		    // See if the added data member isn't too big.
4677 		    type_base_sptr added_dm_type = added_dm->get_type();
4678 		    ABG_ASSERT(added_dm_type);
4679 		    var_decl_sptr new_next_dm =
4680 		      get_next_data_member(second_class_or_union(),
4681 					   added_dm);
4682 		    var_decl_sptr old_next_dm =
4683 		      first_class_or_union()->find_data_member(new_next_dm);
4684 
4685 		    if (!old_next_dm
4686 			|| (old_next_dm
4687 			    && (get_absolute_data_member_offset(old_next_dm)
4688 				== get_absolute_data_member_offset(new_next_dm))))
4689 		      {
4690 			// None of the data members that are replaced
4691 			// by the added union should be considered as
4692 			// having been deleted.
4693 			ignore_added_anonymous_data_member = true;
4694 			for (vector<var_decl_sptr>::const_iterator i =
4695 			       dms_replaced_by_anon_dm.begin();
4696 			     i != dms_replaced_by_anon_dm.end();
4697 			     ++i)
4698 			  {
4699 			    string n = (*i)->get_name();
4700 			    priv_->dms_replaced_by_adms_[n] =
4701 			      added_dm;
4702 			    priv_->deleted_data_members_.erase(n);
4703 			  }
4704 		      }
4705 		  }
4706 	      }
4707 
4708 	    if (!ignore_added_anonymous_data_member)
4709 	      {
4710 		// Detect changed data members.
4711 		//
4712 		// A changed data member (that we shall name D) is a data
4713 		// member that satisfies the conditions below:
4714 		//
4715 		// 1/ It must have been added.
4716 		//
4717 		// 2/ It must have been deleted as well.
4718 		//
4719 		// 3/ It there must be a non-empty difference between the
4720 		// deleted D and the added D.
4721 		string_decl_base_sptr_map::const_iterator j =
4722 		  priv_->deleted_data_members_.find(name);
4723 		if (j != priv_->deleted_data_members_.end())
4724 		  {
4725 		    if (*j->second != *d)
4726 		      {
4727 			var_decl_sptr old_dm = is_var_decl(j->second);
4728 			priv_->subtype_changed_dm_[name]=
4729 			  compute_diff(old_dm, added_dm, context());
4730 		      }
4731 		    priv_->deleted_data_members_.erase(j);
4732 		  }
4733 		else
4734 		  priv_->inserted_data_members_[name] = d;
4735 	      }
4736 	  }
4737       }
4738 
4739     // Now detect when a data member is deleted from offset N and
4740     // another one is added to offset N.  In that case, we want to be
4741     // able to say that the data member at offset N changed.
4742     for (string_decl_base_sptr_map::const_iterator i =
4743 	   priv_->deleted_data_members_.begin();
4744 	 i != priv_->deleted_data_members_.end();
4745 	 ++i)
4746       {
4747 	unsigned offset = get_data_member_offset(i->second);
4748 	priv_->deleted_dm_by_offset_[offset] = i->second;
4749       }
4750 
4751     for (string_decl_base_sptr_map::const_iterator i =
4752 	   priv_->inserted_data_members_.begin();
4753 	 i != priv_->inserted_data_members_.end();
4754 	 ++i)
4755       {
4756 	unsigned offset = get_data_member_offset(i->second);
4757 	priv_->inserted_dm_by_offset_[offset] = i->second;
4758       }
4759 
4760     for (unsigned_decl_base_sptr_map::const_iterator i =
4761 	   priv_->inserted_dm_by_offset_.begin();
4762 	 i != priv_->inserted_dm_by_offset_.end();
4763 	 ++i)
4764       {
4765 	unsigned_decl_base_sptr_map::const_iterator j =
4766 	  priv_->deleted_dm_by_offset_.find(i->first);
4767 	if (j != priv_->deleted_dm_by_offset_.end())
4768 	  {
4769 	    var_decl_sptr old_dm = is_var_decl(j->second);
4770 	    var_decl_sptr new_dm = is_var_decl(i->second);
4771 	    priv_->changed_dm_[i->first] =
4772 	      compute_diff(old_dm, new_dm, context());
4773 	  }
4774       }
4775 
4776     for (unsigned_var_diff_sptr_map::const_iterator i =
4777 	   priv_->changed_dm_.begin();
4778 	 i != priv_->changed_dm_.end();
4779 	 ++i)
4780       {
4781 	priv_->deleted_dm_by_offset_.erase(i->first);
4782 	priv_->inserted_dm_by_offset_.erase(i->first);
4783 	priv_->deleted_data_members_.erase
4784 	  (i->second->first_var()->get_anon_dm_reliable_name());
4785 	priv_->inserted_data_members_.erase
4786 	  (i->second->second_var()->get_anon_dm_reliable_name());
4787       }
4788   }
4789   sort_string_data_member_diff_sptr_map(priv_->subtype_changed_dm_,
4790 					priv_->sorted_subtype_changed_dm_);
4791   sort_unsigned_data_member_diff_sptr_map(priv_->changed_dm_,
4792 					  priv_->sorted_changed_dm_);
4793 
4794   {
4795     edit_script& e = priv_->member_class_tmpls_changes_;
4796 
4797     for (vector<deletion>::const_iterator it = e.deletions().begin();
4798 	 it != e.deletions().end();
4799 	 ++it)
4800       {
4801 	unsigned i = it->index();
4802 	decl_base_sptr d =
4803 	  first_class_or_union()->get_member_class_templates()[i]->
4804 	  as_class_tdecl();
4805 	string name = d->get_name();
4806 	ABG_ASSERT(priv_->deleted_member_class_tmpls_.find(name)
4807 	       == priv_->deleted_member_class_tmpls_.end());
4808 	priv_->deleted_member_class_tmpls_[name] = d;
4809       }
4810 
4811     for (vector<insertion>::const_iterator it = e.insertions().begin();
4812 	 it != e.insertions().end();
4813 	 ++it)
4814       {
4815 	for (vector<unsigned>::const_iterator iit =
4816 	       it->inserted_indexes().begin();
4817 	     iit != it->inserted_indexes().end();
4818 	     ++iit)
4819 	  {
4820 	    unsigned i = *iit;
4821 	    decl_base_sptr d =
4822 	      second_class_or_union()->get_member_class_templates()[i]->
4823 	      as_class_tdecl();
4824 	    string name = d->get_name();
4825 	    ABG_ASSERT(priv_->inserted_member_class_tmpls_.find(name)
4826 		   == priv_->inserted_member_class_tmpls_.end());
4827 	    string_decl_base_sptr_map::const_iterator j =
4828 	      priv_->deleted_member_class_tmpls_.find(name);
4829 	    if (j != priv_->deleted_member_class_tmpls_.end())
4830 	      {
4831 		if (*j->second != *d)
4832 		  priv_->changed_member_types_[name]=
4833 		    compute_diff(j->second, d, context());
4834 		priv_->deleted_member_class_tmpls_.erase(j);
4835 	      }
4836 	    else
4837 	      priv_->inserted_member_class_tmpls_[name] = d;
4838 	  }
4839       }
4840   }
4841   sort_string_diff_sptr_map(priv_->changed_member_types_,
4842 			    priv_->sorted_changed_member_types_);
4843 }
4844 
4845 /// Allocate the memory for the priv_ pimpl data member of the @ref
4846 /// class_or_union_diff class.
4847 void
allocate_priv_data()4848 class_or_union_diff::allocate_priv_data()
4849 {
4850   if (!priv_)
4851     priv_.reset(new priv);
4852 }
4853 
4854 /// Constructor for the @ref class_or_union_diff class.
4855 ///
4856 /// @param first_scope the first @ref class_or_union of the diff node.
4857 ///
4858 /// @param second_scope the second @ref class_or_union of the diff node.
4859 ///
4860 /// @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)4861 class_or_union_diff::class_or_union_diff(class_or_union_sptr first_scope,
4862 					 class_or_union_sptr second_scope,
4863 					 diff_context_sptr ctxt)
4864   : type_diff_base(first_scope, second_scope, ctxt)
4865     //priv_(new priv)
4866 {}
4867 
4868 /// Getter of the private data of the @ref class_or_union_diff type.
4869 ///
4870 /// Note that due to an optimization, the private data of @ref
4871 /// class_or_union_diff can be shared among several instances of
4872 /// class_or_union_diff, so you should never try to access
4873 /// class_or_union_diff::priv directly.
4874 ///
4875 /// When class_or_union_diff::priv is shared, this function returns
4876 /// the correct shared one.
4877 ///
4878 /// @return the (possibly) shared private data of the current instance
4879 /// of @ref class_or_union_diff.
4880 const class_or_union_diff::priv_ptr&
get_priv() const4881 class_or_union_diff::get_priv() const
4882 {
4883   if (priv_)
4884     return priv_;
4885 
4886   // If the current class_or_union_diff::priv member is empty, then look for
4887   // the shared one, from the canonical type.
4888   class_or_union_diff *canonical =
4889     dynamic_cast<class_or_union_diff*>(get_canonical_diff());
4890   ABG_ASSERT(canonical);
4891   ABG_ASSERT(canonical->priv_);
4892 
4893   return canonical->priv_;
4894 }
4895 
4896 /// Destructor of class_or_union_diff.
~class_or_union_diff()4897 class_or_union_diff::~class_or_union_diff()
4898 {
4899 }
4900 
4901 /// @return the first @ref class_or_union involved in the diff.
4902 class_or_union_sptr
first_class_or_union() const4903 class_or_union_diff::first_class_or_union() const
4904 {return is_class_or_union_type(first_subject());}
4905 
4906 /// @return the second @ref class_or_union involved in the diff.
4907 class_or_union_sptr
second_class_or_union() const4908 class_or_union_diff::second_class_or_union() const
4909 {return is_class_or_union_type(second_subject());}
4910 
4911 /// @return the edit script of the member types of the two @ref
4912 /// class_or_union.
4913 const edit_script&
member_types_changes() const4914 class_or_union_diff::member_types_changes() const
4915 {return get_priv()->member_types_changes_;}
4916 
4917 /// @return the edit script of the member types of the two @ref
4918 /// class_or_union.
4919 edit_script&
member_types_changes()4920 class_or_union_diff::member_types_changes()
4921 {return get_priv()->member_types_changes_;}
4922 
4923 /// @return the edit script of the data members of the two @ref
4924 /// class_or_union.
4925 const edit_script&
data_members_changes() const4926 class_or_union_diff::data_members_changes() const
4927 {return get_priv()->data_members_changes_;}
4928 
4929 /// @return the edit script of the data members of the two @ref
4930 /// class_or_union.
4931 edit_script&
data_members_changes()4932 class_or_union_diff::data_members_changes()
4933 {return get_priv()->data_members_changes_;}
4934 
4935 /// Getter for the data members that got inserted.
4936 ///
4937 /// @return a map of data members that got inserted.
4938 const string_decl_base_sptr_map&
inserted_data_members() const4939 class_or_union_diff::inserted_data_members() const
4940 {return get_priv()->inserted_data_members_;}
4941 
4942 /// Getter for the data members that got deleted.
4943 ///
4944 /// @return a map of data members that got deleted.
4945 const string_decl_base_sptr_map&
deleted_data_members() const4946 class_or_union_diff::deleted_data_members() const
4947 {return get_priv()->deleted_data_members_;}
4948 
4949 /// @return the edit script of the member functions of the two @ref
4950 /// class_or_union.
4951 const edit_script&
member_fns_changes() const4952 class_or_union_diff::member_fns_changes() const
4953 {return get_priv()->member_fns_changes_;}
4954 
4955 /// Getter for the virtual members functions that have had a change in
4956 /// a sub-type, without having a change in their symbol name.
4957 ///
4958 /// @return a sorted vector of virtual member functions that have a
4959 /// sub-type change.
4960 const function_decl_diff_sptrs_type&
changed_member_fns() const4961 class_or_union_diff::changed_member_fns() const
4962 {return get_priv()->sorted_changed_member_functions_;}
4963 
4964 /// @return the edit script of the member functions of the two
4965 /// classes.
4966 edit_script&
member_fns_changes()4967 class_or_union_diff::member_fns_changes()
4968 {return get_priv()->member_fns_changes_;}
4969 
4970 /// @return a map of member functions that got deleted.
4971 const string_member_function_sptr_map&
deleted_member_fns() const4972 class_or_union_diff::deleted_member_fns() const
4973 {return get_priv()->deleted_member_functions_;}
4974 
4975 /// @return a map of member functions that got inserted.
4976 const string_member_function_sptr_map&
inserted_member_fns() const4977 class_or_union_diff::inserted_member_fns() const
4978 {return get_priv()->inserted_member_functions_;}
4979 
4980 /// Getter of the sorted vector of data members that got replaced by
4981 /// another data member.
4982 ///
4983 /// @return sorted vector of changed data member.
4984 const var_diff_sptrs_type&
sorted_changed_data_members() const4985 class_or_union_diff::sorted_changed_data_members() const
4986 {return get_priv()->sorted_changed_dm_;}
4987 
4988 /// Count the number of /filtered/ data members that got replaced by
4989 /// another data member.
4990 ///
4991 /// @return the number of changed data member that got filtered out.
4992 size_t
count_filtered_changed_data_members(bool local) const4993 class_or_union_diff::count_filtered_changed_data_members(bool local) const
4994 {return get_priv()->count_filtered_changed_dm(local);}
4995 
4996 /// Getter of the sorted vector of data members with a (sub-)type change.
4997 ///
4998 /// @return sorted vector of changed data member.
4999 const var_diff_sptrs_type&
sorted_subtype_changed_data_members() const5000 class_or_union_diff::sorted_subtype_changed_data_members() const
5001 {return get_priv()->sorted_subtype_changed_dm_;}
5002 
5003 /// Count the number of /filtered/ data members with a sub-type change.
5004 ///
5005 /// @return the number of changed data member that got filtered out.
5006 size_t
count_filtered_subtype_changed_data_members(bool local) const5007 class_or_union_diff::count_filtered_subtype_changed_data_members(bool local) const
5008 {return get_priv()->count_filtered_subtype_changed_dm(local);}
5009 
5010 /// Get the map of data members that got replaced by anonymous data
5011 /// members.
5012 ///
5013 /// The key of a map entry is the name of the replaced data member and
5014 /// the value is the anonymous data member that replaces it.
5015 ///
5016 /// @return the map of data members replaced by anonymous data
5017 /// members.
5018 const string_decl_base_sptr_map&
data_members_replaced_by_adms() const5019 class_or_union_diff::data_members_replaced_by_adms() const
5020 {return get_priv()->dms_replaced_by_adms_;}
5021 
5022 /// Get an ordered vector of of data members that got replaced by
5023 /// anonymous data members.
5024 ///
5025 /// This returns a vector of pair of two data members: the one that
5026 /// was replaced, and the anonymous data member that replaced it.
5027 ///
5028 /// @return the sorted vector data members replaced by anonymous data members.
5029 const changed_var_sptrs_type&
ordered_data_members_replaced_by_adms() const5030 class_or_union_diff::ordered_data_members_replaced_by_adms() const
5031 {
5032   if (priv_->dms_replaced_by_adms_ordered_.empty())
5033     {
5034       for (string_decl_base_sptr_map::const_iterator it =
5035 	     priv_->dms_replaced_by_adms_.begin();
5036 	   it != priv_->dms_replaced_by_adms_.end();
5037 	   ++it)
5038 	{
5039 	  const var_decl_sptr dm =
5040 	    first_class_or_union()->find_data_member(it->first);
5041 	  ABG_ASSERT(dm);
5042 	  changed_var_sptr changed_dm(dm, is_data_member(it->second));
5043 	  priv_->dms_replaced_by_adms_ordered_.push_back(changed_dm);
5044 	}
5045       sort_changed_data_members(priv_->dms_replaced_by_adms_ordered_);
5046     }
5047 
5048   return priv_->dms_replaced_by_adms_ordered_;
5049 }
5050 
5051 /// @return the edit script of the member function templates of the two
5052 /// @ref class_or_union.
5053 const edit_script&
member_fn_tmpls_changes() const5054 class_or_union_diff::member_fn_tmpls_changes() const
5055 {return get_priv()->member_fn_tmpls_changes_;}
5056 
5057 /// @return the edit script of the member function templates of the
5058 /// two @ref class_or_union.
5059 edit_script&
member_fn_tmpls_changes()5060 class_or_union_diff::member_fn_tmpls_changes()
5061 {return get_priv()->member_fn_tmpls_changes_;}
5062 
5063 /// @return the edit script of the member class templates of the two
5064 /// @ref class_or_union.
5065 const edit_script&
member_class_tmpls_changes() const5066 class_or_union_diff::member_class_tmpls_changes() const
5067 {return get_priv()->member_class_tmpls_changes_;}
5068 
5069 /// @return the edit script of the member class templates of the two
5070 /// @ref class_or_union.
5071 edit_script&
member_class_tmpls_changes()5072 class_or_union_diff::member_class_tmpls_changes()
5073 {return get_priv()->member_class_tmpls_changes_;}
5074 
5075 /// Test if the current diff node carries a change.
5076 bool
has_changes() const5077 class_or_union_diff::has_changes() const
5078 {return first_class_or_union() != second_class_or_union();}
5079 
5080 /// @return the kind of local change carried by the current diff node.
5081 /// The value returned is zero if the current node carries no local
5082 /// change.
5083 enum change_kind
has_local_changes() const5084 class_or_union_diff::has_local_changes() const
5085 {
5086   ir::change_kind k = ir::NO_CHANGE_KIND;
5087   if (!equals(*first_class_or_union(), *second_class_or_union(), &k))
5088     return k & ir::ALL_LOCAL_CHANGES_MASK;
5089   return ir::NO_CHANGE_KIND;
5090 }
5091 
5092 
5093 /// Report the changes carried by the current @ref class_or_union_diff
5094 /// node in a textual format.
5095 ///
5096 /// @param out the output stream to write the textual report to.
5097 ///
5098 /// @param indent the number of white space to use as indentation.
5099 void
report(ostream & out,const string & indent) const5100 class_or_union_diff::report(ostream& out, const string& indent) const
5101 {
5102   context()->get_reporter()->report(*this, out, indent);
5103 }
5104 
5105 /// Populate the vector of children node of the @ref diff base type
5106 /// sub-object of this instance of @ref class_or_union_diff.
5107 ///
5108 /// The children node can then later be retrieved using
5109 /// diff::children_node().
5110 void
chain_into_hierarchy()5111 class_or_union_diff::chain_into_hierarchy()
5112 {
5113   // data member changes
5114   for (var_diff_sptrs_type::const_iterator i =
5115 	 get_priv()->sorted_subtype_changed_dm_.begin();
5116        i != get_priv()->sorted_subtype_changed_dm_.end();
5117        ++i)
5118     if (diff_sptr d = *i)
5119       append_child_node(d);
5120 
5121   for (var_diff_sptrs_type::const_iterator i =
5122 	 get_priv()->sorted_changed_dm_.begin();
5123        i != get_priv()->sorted_changed_dm_.end();
5124        ++i)
5125     if (diff_sptr d = *i)
5126       append_child_node(d);
5127 
5128   // member types changes
5129   for (diff_sptrs_type::const_iterator i =
5130 	 get_priv()->sorted_changed_member_types_.begin();
5131        i != get_priv()->sorted_changed_member_types_.end();
5132        ++i)
5133     if (diff_sptr d = *i)
5134       append_child_node(d);
5135 
5136   // member function changes
5137   for (function_decl_diff_sptrs_type::const_iterator i =
5138 	 get_priv()->sorted_changed_member_functions_.begin();
5139        i != get_priv()->sorted_changed_member_functions_.end();
5140        ++i)
5141     if (diff_sptr d = *i)
5142       append_child_node(d);
5143 }
5144 
5145 // </class_or_union_diff stuff>
5146 
5147 //<class_diff stuff>
5148 
5149 /// Clear the lookup tables useful for reporting.
5150 ///
5151 /// This function must be updated each time a lookup table is added or
5152 /// removed from the class_diff::priv.
5153 void
clear_lookup_tables(void)5154 class_diff::clear_lookup_tables(void)
5155 {
5156   priv_->deleted_bases_.clear();
5157   priv_->inserted_bases_.clear();
5158   priv_->changed_bases_.clear();
5159 }
5160 
5161 /// Tests if the lookup tables are empty.
5162 ///
5163 /// @return true if the lookup tables are empty, false otherwise.
5164 bool
lookup_tables_empty(void) const5165 class_diff::lookup_tables_empty(void) const
5166 {
5167   return (priv_->deleted_bases_.empty()
5168 	  && priv_->inserted_bases_.empty()
5169 	  && priv_->changed_bases_.empty());
5170 }
5171 
5172 /// If the lookup tables are not yet built, walk the differences and
5173 /// fill them.
5174 void
ensure_lookup_tables_populated(void) const5175 class_diff::ensure_lookup_tables_populated(void) const
5176 {
5177   class_or_union_diff::ensure_lookup_tables_populated();
5178 
5179   if (!lookup_tables_empty())
5180     return;
5181 
5182   {
5183     edit_script& e = get_priv()->base_changes_;
5184 
5185     for (vector<deletion>::const_iterator it = e.deletions().begin();
5186 	 it != e.deletions().end();
5187 	 ++it)
5188       {
5189 	unsigned i = it->index();
5190 	class_decl::base_spec_sptr b =
5191 	  first_class_decl()->get_base_specifiers()[i];
5192 	string name = b->get_base_class()->get_name();
5193 	ABG_ASSERT(get_priv()->deleted_bases_.find(name)
5194 	       == get_priv()->deleted_bases_.end());
5195 	get_priv()->deleted_bases_[name] = b;
5196       }
5197 
5198     for (vector<insertion>::const_iterator it = e.insertions().begin();
5199 	 it != e.insertions().end();
5200 	 ++it)
5201       {
5202 	for (vector<unsigned>::const_iterator iit =
5203 	       it->inserted_indexes().begin();
5204 	     iit != it->inserted_indexes().end();
5205 	     ++iit)
5206 	  {
5207 	    unsigned i = *iit;
5208 	    class_decl::base_spec_sptr b =
5209 	      second_class_decl()->get_base_specifiers()[i];
5210 	    string name = b->get_base_class()->get_name();
5211 	    ABG_ASSERT(get_priv()->inserted_bases_.find(name)
5212 		   == get_priv()->inserted_bases_.end());
5213 	    string_base_sptr_map::const_iterator j =
5214 	      get_priv()->deleted_bases_.find(name);
5215 	    if (j != get_priv()->deleted_bases_.end())
5216 	      {
5217 		if (j->second != b)
5218 		  get_priv()->changed_bases_[name] =
5219 		    compute_diff(j->second, b, context());
5220 		else
5221 		  // The base class changed place.  IOW, the base
5222 		  // classes got re-arranged.  Let's keep track of the
5223 		  // base classes that moved.
5224 		  get_priv()->moved_bases_.push_back(b);
5225 		get_priv()->deleted_bases_.erase(j);
5226 	      }
5227 	    else
5228 	      get_priv()->inserted_bases_[name] = b;
5229 	  }
5230       }
5231   }
5232 
5233   sort_string_base_sptr_map(get_priv()->deleted_bases_,
5234 			    get_priv()->sorted_deleted_bases_);
5235   sort_string_base_sptr_map(get_priv()->inserted_bases_,
5236 			    get_priv()->sorted_inserted_bases_);
5237   sort_string_base_diff_sptr_map(get_priv()->changed_bases_,
5238 				 get_priv()->sorted_changed_bases_);
5239 
5240   {
5241     const class_or_union_diff::priv_ptr &p = class_or_union_diff::get_priv();
5242 
5243     edit_script& e = p->member_fns_changes_;
5244 
5245     for (vector<deletion>::const_iterator it = e.deletions().begin();
5246 	 it != e.deletions().end();
5247 	 ++it)
5248       {
5249 	unsigned i = it->index();
5250 	method_decl_sptr mem_fn =
5251 	  first_class_decl()->get_virtual_mem_fns()[i];
5252 	string name = mem_fn->get_linkage_name();
5253 	if (name.empty())
5254 	  name = mem_fn->get_pretty_representation();
5255 	ABG_ASSERT(!name.empty());
5256 	if (p->deleted_member_functions_.find(name)
5257 	    != p->deleted_member_functions_.end())
5258 	  continue;
5259 	p->deleted_member_functions_[name] = mem_fn;
5260       }
5261 
5262     for (vector<insertion>::const_iterator it = e.insertions().begin();
5263 	 it != e.insertions().end();
5264 	 ++it)
5265       {
5266 	for (vector<unsigned>::const_iterator iit =
5267 	       it->inserted_indexes().begin();
5268 	     iit != it->inserted_indexes().end();
5269 	     ++iit)
5270 	  {
5271 	    unsigned i = *iit;
5272 
5273 	    method_decl_sptr mem_fn =
5274 	      second_class_decl()->get_virtual_mem_fns()[i];
5275 	    string name = mem_fn->get_linkage_name();
5276 	    if (name.empty())
5277 	      name = mem_fn->get_pretty_representation();
5278 	    ABG_ASSERT(!name.empty());
5279 	    if (p->inserted_member_functions_.find(name)
5280 		!= p->inserted_member_functions_.end())
5281 	      continue;
5282 	    string_member_function_sptr_map::const_iterator j =
5283 	      p->deleted_member_functions_.find(name);
5284 
5285 	    if (j != p->deleted_member_functions_.end())
5286 	      {
5287 		if (*j->second != *mem_fn)
5288 		  p->changed_member_functions_[name] =
5289 		    compute_diff(static_pointer_cast<function_decl>(j->second),
5290 				 static_pointer_cast<function_decl>(mem_fn),
5291 				 context());
5292 		p->deleted_member_functions_.erase(j);
5293 	      }
5294 	    else
5295 	      p->inserted_member_functions_[name] = mem_fn;
5296 	  }
5297       }
5298 
5299     // Now walk the allegedly deleted member functions; check if their
5300     // underlying symbols are deleted as well; otherwise, consider
5301     // that the member function in question hasn't been deleted.
5302 
5303     vector<string> to_delete;
5304     corpus_sptr f = context()->get_first_corpus(),
5305       s = context()->get_second_corpus();
5306     if (s)
5307       for (string_member_function_sptr_map::const_iterator i =
5308 	     deleted_member_fns().begin();
5309 	   i != deleted_member_fns().end();
5310 	   ++i)
5311 	{
5312 	  if (get_member_function_is_virtual(i->second))
5313 	    continue;
5314 	  // We assume that all non-virtual member functions functions
5315 	  // we look at here have ELF symbols.
5316 	  if (!i->second->get_symbol()
5317 	      || s->lookup_function_symbol(*i->second->get_symbol()))
5318 	    to_delete.push_back(i->first);
5319 	}
5320 
5321 
5322     for (vector<string>::const_iterator i = to_delete.begin();
5323 	 i != to_delete.end();
5324 	 ++i)
5325       p->deleted_member_functions_.erase(*i);
5326 
5327     // Do something similar for added functions.
5328     to_delete.clear();
5329     if (f)
5330       for (string_member_function_sptr_map::const_iterator i =
5331 	     inserted_member_fns().begin();
5332 	   i != inserted_member_fns().end();
5333 	   ++i)
5334 	{
5335 	  if (get_member_function_is_virtual(i->second))
5336 	    continue;
5337 	  // We assume that all non-virtual member functions functions
5338 	  // we look at here have ELF symbols.
5339 	  if (!i->second->get_symbol()
5340 	      || f->lookup_function_symbol(*i->second->get_symbol()))
5341 	    to_delete.push_back(i->first);
5342 	}
5343 
5344     for (vector<string>::const_iterator i = to_delete.begin();
5345 	 i != to_delete.end();
5346 	 ++i)
5347       p->inserted_member_functions_.erase(*i);
5348 
5349     sort_string_member_function_sptr_map(p->deleted_member_functions_,
5350 					 p->sorted_deleted_member_functions_);
5351 
5352     sort_string_member_function_sptr_map(p->inserted_member_functions_,
5353 					 p->sorted_inserted_member_functions_);
5354 
5355     sort_string_virtual_member_function_diff_sptr_map
5356       (p->changed_member_functions_,
5357        p->sorted_changed_member_functions_);
5358   }
5359 }
5360 
5361 /// Allocate the memory for the priv_ pimpl data member of the @ref
5362 /// class_diff class.
5363 void
allocate_priv_data()5364 class_diff::allocate_priv_data()
5365 {
5366   class_or_union_diff::allocate_priv_data();
5367   if (!priv_)
5368     priv_.reset(new priv);
5369 }
5370 
5371 /// Test whether a given base class has changed.  A base class has
5372 /// changed if it's in both in deleted *and* inserted bases.
5373 ///
5374 ///@param d the declaration for the base class to consider.
5375 ///
5376 /// @return the new base class if the given base class has changed, or
5377 /// NULL if it hasn't.
5378 class_decl::base_spec_sptr
base_has_changed(class_decl::base_spec_sptr d) const5379 class_diff::priv::base_has_changed(class_decl::base_spec_sptr d) const
5380 {
5381   string qname = d->get_base_class()->get_qualified_name();
5382   string_base_diff_sptr_map::const_iterator it =
5383     changed_bases_.find(qname);
5384 
5385   return (it == changed_bases_.end())
5386     ? class_decl::base_spec_sptr()
5387     : it->second->second_base();
5388 
5389 }
5390 
5391 /// Count the number of bases classes whose changes got filtered out.
5392 ///
5393 /// @return the number of bases classes whose changes got filtered
5394 /// out.
5395 size_t
count_filtered_bases()5396 class_diff::priv::count_filtered_bases()
5397 {
5398   size_t num_filtered = 0;
5399   for (base_diff_sptrs_type::const_iterator i = sorted_changed_bases_.begin();
5400        i != sorted_changed_bases_.end();
5401        ++i)
5402     {
5403       diff_sptr diff = *i;
5404       if (diff && diff->is_filtered_out())
5405 	++num_filtered;
5406     }
5407   return num_filtered;
5408 }
5409 
5410 /// Populate the vector of children node of the @ref diff base type
5411 /// sub-object of this instance of @ref class_diff.
5412 ///
5413 /// The children node can then later be retrieved using
5414 /// diff::children_node().
5415 void
chain_into_hierarchy()5416 class_diff::chain_into_hierarchy()
5417 {
5418   class_or_union_diff::chain_into_hierarchy();
5419 
5420   // base class changes.
5421   for (base_diff_sptrs_type::const_iterator i =
5422 	 get_priv()->sorted_changed_bases_.begin();
5423        i != get_priv()->sorted_changed_bases_.end();
5424        ++i)
5425     if (diff_sptr d = *i)
5426       append_child_node(d);
5427 }
5428 
5429 /// Constructor of class_diff
5430 ///
5431 /// @param first_scope the first class of the diff.
5432 ///
5433 /// @param second_scope the second class of the diff.
5434 ///
5435 /// @param ctxt the diff context to use.
class_diff(class_decl_sptr first_scope,class_decl_sptr second_scope,diff_context_sptr ctxt)5436 class_diff::class_diff(class_decl_sptr first_scope,
5437 		       class_decl_sptr second_scope,
5438 		       diff_context_sptr ctxt)
5439   : class_or_union_diff(first_scope, second_scope, ctxt)
5440     //  We don't initialize the priv_ data member here.  This is an
5441     //  optimization to reduce memory consumption (and also execution
5442     //  time) for cases where there are a lot of instances of
5443     //  class_diff in the same equivalence class.  In compute_diff(),
5444     //  the priv_ is set to the priv_ of the canonical diff node.
5445     //  See PR libabigail/17948.
5446 {}
5447 
~class_diff()5448 class_diff::~class_diff()
5449 {}
5450 
5451 /// Getter of the private data of the @ref class_diff type.
5452 ///
5453 /// Note that due to an optimization, the private data of @ref
5454 /// class_diff can be shared among several instances of class_diff, so
5455 /// you should never try to access class_diff::priv directly.
5456 ///
5457 /// When class_diff::priv is shared, this function returns the correct
5458 /// shared one.
5459 ///
5460 /// @return the (possibly) shared private data of the current instance
5461 /// of class_diff.
5462 const class_diff::priv_ptr&
get_priv() const5463 class_diff::get_priv() const
5464 {
5465   if (priv_)
5466     return priv_;
5467 
5468   // If the current class_diff::priv member is empty, then look for
5469   // the shared one, from the canonical type.
5470   class_diff *canonical =
5471     dynamic_cast<class_diff*>(get_canonical_diff());
5472   ABG_ASSERT(canonical);
5473   ABG_ASSERT(canonical->priv_);
5474 
5475   return canonical->priv_;
5476 }
5477 
5478 /// @return the pretty representation of the current instance of @ref
5479 /// class_diff.
5480 const string&
get_pretty_representation() const5481 class_diff::get_pretty_representation() const
5482 {
5483   if (diff::priv_->pretty_representation_.empty())
5484     {
5485       std::ostringstream o;
5486       o << "class_diff["
5487 	<< first_subject()->get_pretty_representation()
5488 	<< ", "
5489 	<< second_subject()->get_pretty_representation()
5490 	<< "]";
5491       diff::priv_->pretty_representation_ = o.str();
5492     }
5493   return diff::priv_->pretty_representation_;
5494 }
5495 
5496 /// Return true iff the current diff node carries a change.
5497 ///
5498 /// @return true iff the current diff node carries a change.
5499 bool
has_changes() const5500 class_diff::has_changes() const
5501 {return (first_class_decl() != second_class_decl());}
5502 
5503 /// @return the kind of local change carried by the current diff node.
5504 /// The value returned is zero if the current node carries no local
5505 /// change.
5506 enum change_kind
has_local_changes() const5507 class_diff::has_local_changes() const
5508 {
5509   ir::change_kind k = ir::NO_CHANGE_KIND;
5510   if (!equals(*first_class_decl(), *second_class_decl(), &k))
5511     return k & ir::ALL_LOCAL_CHANGES_MASK;
5512   return ir::NO_CHANGE_KIND;
5513 }
5514 
5515 /// @return the first class invoveld in the diff.
5516 shared_ptr<class_decl>
first_class_decl() const5517 class_diff::first_class_decl() const
5518 {return dynamic_pointer_cast<class_decl>(first_subject());}
5519 
5520 /// Getter of the second class involved in the diff.
5521 ///
5522 /// @return the second class invoveld in the diff
5523 shared_ptr<class_decl>
second_class_decl() const5524 class_diff::second_class_decl() const
5525 {return dynamic_pointer_cast<class_decl>(second_subject());}
5526 
5527 /// @return the edit script of the bases of the two classes.
5528 const edit_script&
base_changes() const5529 class_diff::base_changes() const
5530 {return get_priv()->base_changes_;}
5531 
5532 /// Getter for the deleted base classes of the diff.
5533 ///
5534 /// @return a map containing the deleted base classes, keyed with
5535 /// their pretty representation.
5536 const string_base_sptr_map&
deleted_bases() const5537 class_diff::deleted_bases() const
5538 {return get_priv()->deleted_bases_;}
5539 
5540 /// Getter for the inserted base classes of the diff.
5541 ///
5542 /// @return a map containing the inserted base classes, keyed with
5543 /// their pretty representation.
5544 const string_base_sptr_map&
inserted_bases() const5545 class_diff::inserted_bases() const
5546 {return get_priv()->inserted_bases_;}
5547 
5548 /// Getter for the changed base classes of the diff.
5549 ///
5550 /// @return a sorted vector containing the changed base classes
5551 const base_diff_sptrs_type&
changed_bases()5552 class_diff::changed_bases()
5553 {return get_priv()->sorted_changed_bases_;}
5554 
5555 /// Getter for the vector of bases that "moved".
5556 /// That is, the vector of base types which position changed.  If this
5557 /// vector is not empty, it means the bases of the underlying class
5558 /// type got re-ordered.
5559 ///
5560 /// @return the vector of bases that moved.
5561 const vector<class_decl::base_spec_sptr>&
moved_bases() const5562 class_diff::moved_bases() const
5563 {return get_priv()->moved_bases_;}
5564 
5565 /// @return the edit script of the bases of the two classes.
5566 edit_script&
base_changes()5567 class_diff::base_changes()
5568 {return get_priv()->base_changes_;}
5569 
5570 /// Produce a basic report about the changes between two class_decl.
5571 ///
5572 /// @param out the output stream to report the changes to.
5573 ///
5574 /// @param indent the string to use as an indentation prefix in the
5575 /// report.
5576 void
report(ostream & out,const string & indent) const5577 class_diff::report(ostream& out, const string& indent) const
5578 {
5579   context()->get_reporter()->report(*this, out, indent);
5580 }
5581 
5582 /// Compute the set of changes between two instances of class_decl.
5583 ///
5584 /// Note that the two types must have been created in the same @ref
5585 /// environment, otherwise, this function aborts.
5586 ///
5587 /// @param first the first class_decl to consider.
5588 ///
5589 /// @param second the second class_decl to consider.
5590 ///
5591 /// @return changes the resulting changes.
5592 ///
5593 /// @param ctxt the diff context to use.
5594 class_diff_sptr
compute_diff(const class_decl_sptr first,const class_decl_sptr second,diff_context_sptr ctxt)5595 compute_diff(const class_decl_sptr	first,
5596 	     const class_decl_sptr	second,
5597 	     diff_context_sptr		ctxt)
5598 {
5599   if (first && second)
5600     ABG_ASSERT(first->get_environment() == second->get_environment());
5601 
5602   class_decl_sptr f = is_class_type(look_through_decl_only_class(first)),
5603     s = is_class_type(look_through_decl_only_class(second));
5604 
5605   class_diff_sptr changes(new class_diff(f, s, ctxt));
5606 
5607   ctxt->initialize_canonical_diff(changes);
5608   ABG_ASSERT(changes->get_canonical_diff());
5609 
5610   if (!ctxt->get_canonical_diff_for(first, second))
5611     {
5612       // Either first or second is a decl-only class; let's set the
5613       // canonical diff here in that case.
5614       diff_sptr canonical_diff = ctxt->get_canonical_diff_for(changes);
5615       ABG_ASSERT(canonical_diff);
5616       ctxt->set_canonical_diff_for(first, second, canonical_diff);
5617     }
5618 
5619   // Ok, so this is an optimization.  Do not freak out if it looks
5620   // weird, because, well, it does look weird.  This speeds up
5621   // greatly, for instance, the test case given at PR
5622   // libabigail/17948.
5623   //
5624   // We are setting the private data of the new instance of class_diff
5625   // (which is 'changes') to the private data of its canonical
5626   // instance.  That is, we are sharing the private data of 'changes'
5627   // with the private data of its canonical instance to consume less
5628   // memory in cases where the equivalence class of 'changes' is huge.
5629   //
5630   // But if changes is its own canonical instance, then we initialize
5631   // its private data properly
5632   if (is_class_diff(changes->get_canonical_diff()) == changes.get())
5633     // changes is its own canonical instance, so it gets a brand new
5634     // private data.
5635     changes->allocate_priv_data();
5636   else
5637     {
5638       // changes has a non-empty equivalence class so it's going to
5639       // share its private data with its canonical instance.  Next
5640       // time class_diff::get_priv() is invoked, it's going to return
5641       // the shared private data of the canonical instance.
5642       return changes;
5643     }
5644 
5645   // Compare base specs
5646   compute_diff(f->get_base_specifiers().begin(),
5647 	       f->get_base_specifiers().end(),
5648 	       s->get_base_specifiers().begin(),
5649 	       s->get_base_specifiers().end(),
5650 	       changes->base_changes());
5651 
5652   // Do *not* compare member types because it generates lots of noise
5653   // and I doubt it's really useful.
5654 #if 0
5655   compute_diff(f->get_member_types().begin(),
5656 	       f->get_member_types().end(),
5657 	       s->get_member_types().begin(),
5658 	       s->get_member_types().end(),
5659 	       changes->member_types_changes());
5660 #endif
5661 
5662   // Compare data member
5663   compute_diff(f->get_non_static_data_members().begin(),
5664 	       f->get_non_static_data_members().end(),
5665 	       s->get_non_static_data_members().begin(),
5666 	       s->get_non_static_data_members().end(),
5667 	       changes->data_members_changes());
5668 
5669   // Compare virtual member functions
5670   compute_diff(f->get_virtual_mem_fns().begin(),
5671 	       f->get_virtual_mem_fns().end(),
5672 	       s->get_virtual_mem_fns().begin(),
5673 	       s->get_virtual_mem_fns().end(),
5674 	       changes->member_fns_changes());
5675 
5676   // Compare member function templates
5677   compute_diff(f->get_member_function_templates().begin(),
5678 	       f->get_member_function_templates().end(),
5679 	       s->get_member_function_templates().begin(),
5680 	       s->get_member_function_templates().end(),
5681 	       changes->member_fn_tmpls_changes());
5682 
5683   // Likewise, do not compare member class templates
5684 #if 0
5685   compute_diff(f->get_member_class_templates().begin(),
5686 	       f->get_member_class_templates().end(),
5687 	       s->get_member_class_templates().begin(),
5688 	       s->get_member_class_templates().end(),
5689 	       changes->member_class_tmpls_changes());
5690 #endif
5691 
5692   changes->ensure_lookup_tables_populated();
5693 
5694   return changes;
5695 }
5696 
5697 //</class_diff stuff>
5698 
5699 // <base_diff stuff>
5700 
5701 /// Populate the vector of children node of the @ref diff base type
5702 /// sub-object of this instance of @ref base_diff.
5703 ///
5704 /// The children node can then later be retrieved using
5705 /// diff::children_node().
5706 void
chain_into_hierarchy()5707 base_diff::chain_into_hierarchy()
5708 {append_child_node(get_underlying_class_diff());}
5709 
5710 /// @param first the first base spec to consider.
5711 ///
5712 /// @param second the second base spec to consider.
5713 ///
5714 /// @param ctxt the context of the diff.  Note that this context
5715 /// object must stay alive at least during the life time of the
5716 /// current instance of @ref base_diff.  Otherwise memory corruption
5717 /// issues occur.
base_diff(class_decl::base_spec_sptr first,class_decl::base_spec_sptr second,class_diff_sptr underlying,diff_context_sptr ctxt)5718 base_diff::base_diff(class_decl::base_spec_sptr first,
5719 		     class_decl::base_spec_sptr second,
5720 		     class_diff_sptr		underlying,
5721 		     diff_context_sptr		ctxt)
5722   : diff(first, second, ctxt),
5723     priv_(new priv(underlying))
5724 {}
5725 
5726 /// Getter for the first base spec of the diff object.
5727 ///
5728 /// @return the first base specifier for the diff object.
5729 class_decl::base_spec_sptr
first_base() const5730 base_diff::first_base() const
5731 {return dynamic_pointer_cast<class_decl::base_spec>(first_subject());}
5732 
5733 /// Getter for the second base spec of the diff object.
5734 ///
5735 /// @return the second base specifier for the diff object.
5736 class_decl::base_spec_sptr
second_base() const5737 base_diff::second_base() const
5738 {return dynamic_pointer_cast<class_decl::base_spec>(second_subject());}
5739 
5740 /// Getter for the diff object for the diff of the underlying base
5741 /// classes.
5742 ///
5743 /// @return the diff object for the diff of the underlying base
5744 /// classes.
5745 const class_diff_sptr
get_underlying_class_diff() const5746 base_diff::get_underlying_class_diff() const
5747 {return priv_->underlying_class_diff_;}
5748 
5749 /// Setter for the diff object for the diff of the underlyng base
5750 /// classes.
5751 ///
5752 /// @param d the new diff object for the diff of the underlying base
5753 /// classes.
5754 void
set_underlying_class_diff(class_diff_sptr d)5755 base_diff::set_underlying_class_diff(class_diff_sptr d)
5756 {priv_->underlying_class_diff_ = d;}
5757 
5758 /// @return the pretty representation for the current instance of @ref
5759 /// base_diff.
5760 const string&
get_pretty_representation() const5761 base_diff::get_pretty_representation() const
5762 {
5763   if (diff::priv_->pretty_representation_.empty())
5764     {
5765       std::ostringstream o;
5766       o << "base_diff["
5767 	<< first_subject()->get_pretty_representation()
5768 	<< ", "
5769 	<< second_subject()->get_pretty_representation()
5770 	<< "]";
5771       diff::priv_->pretty_representation_ = o.str();
5772     }
5773   return diff::priv_->pretty_representation_;
5774 }
5775 
5776 /// Return true iff the current diff node carries a change.
5777 ///
5778 /// Return true iff the current diff node carries a change.
5779 bool
has_changes() const5780 base_diff::has_changes() const
5781 {return first_base() != second_base();}
5782 
5783 /// @return the kind of local change carried by the current diff node.
5784 /// The value returned is zero if the current node carries no local
5785 /// change.
5786 enum change_kind
has_local_changes() const5787 base_diff::has_local_changes() const
5788 {
5789   ir::change_kind k = ir::NO_CHANGE_KIND;
5790   if (!equals(*first_base(), *second_base(), &k))
5791     return k & ir::ALL_LOCAL_CHANGES_MASK;
5792   return ir::NO_CHANGE_KIND;
5793 }
5794 
5795 /// Generates a report for the current instance of base_diff.
5796 ///
5797 /// @param out the output stream to send the report to.
5798 ///
5799 /// @param indent the string to use for indentation.
5800 void
report(ostream & out,const string & indent) const5801 base_diff::report(ostream& out, const string& indent) const
5802 {
5803   context()->get_reporter()->report(*this, out, indent);
5804 }
5805 
5806 /// Constructs the diff object representing a diff between two base
5807 /// class specifications.
5808 ///
5809 /// Note that the two artifacts must have been created in the same
5810 /// @ref environment, otherwise, this function aborts.
5811 ///
5812 /// @param first the first base class specification.
5813 ///
5814 /// @param second the second base class specification.
5815 ///
5816 /// @param ctxt the content of the diff.
5817 ///
5818 /// @return the resulting diff object.
5819 base_diff_sptr
compute_diff(const class_decl::base_spec_sptr first,const class_decl::base_spec_sptr second,diff_context_sptr ctxt)5820 compute_diff(const class_decl::base_spec_sptr	first,
5821 	     const class_decl::base_spec_sptr	second,
5822 	     diff_context_sptr			ctxt)
5823 {
5824   if (first && second)
5825     {
5826       ABG_ASSERT(first->get_environment() == second->get_environment());
5827       ABG_ASSERT(first->get_base_class()->get_environment()
5828 	     == second->get_base_class()->get_environment());
5829       ABG_ASSERT(first->get_environment()
5830 	     == first->get_base_class()->get_environment());
5831     }
5832 
5833   class_diff_sptr cl = compute_diff(first->get_base_class(),
5834 				    second->get_base_class(),
5835 				    ctxt);
5836   base_diff_sptr changes(new base_diff(first, second, cl, ctxt));
5837 
5838   ctxt->initialize_canonical_diff(changes);
5839 
5840   return changes;
5841 }
5842 
5843 // </base_diff stuff>
5844 
5845 
5846 // <union_diff stuff>
5847 
5848 /// Clear the lookup tables useful for reporting.
5849 ///
5850 /// This function must be updated each time a lookup table is added or
5851 /// removed from the union_diff::priv.
5852 void
clear_lookup_tables(void)5853 union_diff::clear_lookup_tables(void)
5854 {class_or_union_diff::clear_lookup_tables();}
5855 
5856 /// Tests if the lookup tables are empty.
5857 ///
5858 /// @return true if the lookup tables are empty, false otherwise.
5859 bool
lookup_tables_empty(void) const5860 union_diff::lookup_tables_empty(void) const
5861 {return class_or_union_diff::lookup_tables_empty();}
5862 
5863 /// If the lookup tables are not yet built, walk the differences and
5864 /// fill them.
5865 void
ensure_lookup_tables_populated(void) const5866 union_diff::ensure_lookup_tables_populated(void) const
5867 {class_or_union_diff::ensure_lookup_tables_populated();}
5868 
5869 /// Allocate the memory for the priv_ pimpl data member of the @ref
5870 /// union_diff class.
5871 void
allocate_priv_data()5872 union_diff::allocate_priv_data()
5873 {
5874   class_or_union_diff::allocate_priv_data();
5875 }
5876 
5877 /// Constructor for the @ref union_diff type.
5878 ///
5879 /// @param first_union the first object of the comparison.
5880 ///
5881 /// @param second_union the second object of the comparison.
5882 ///
5883 /// @param ctxt the context of the comparison.
union_diff(union_decl_sptr first_union,union_decl_sptr second_union,diff_context_sptr ctxt)5884 union_diff::union_diff(union_decl_sptr first_union,
5885 		       union_decl_sptr second_union,
5886 		       diff_context_sptr ctxt)
5887   : class_or_union_diff(first_union, second_union, ctxt)
5888 {}
5889 
5890 /// Destructor of the union_diff node.
~union_diff()5891 union_diff::~union_diff()
5892 {}
5893 
5894 /// @return the first object of the comparison.
5895 union_decl_sptr
first_union_decl() const5896 union_diff::first_union_decl() const
5897 {return is_union_type(first_subject());}
5898 
5899 /// @return the second object of the comparison.
5900 union_decl_sptr
second_union_decl() const5901 union_diff::second_union_decl() const
5902 {return is_union_type(second_subject());}
5903 
5904 /// @return the pretty representation of the current diff node.
5905 const string&
get_pretty_representation() const5906 union_diff::get_pretty_representation() const
5907 {
5908   if (diff::priv_->pretty_representation_.empty())
5909     {
5910       std::ostringstream o;
5911       o << "union_diff["
5912 	<< first_subject()->get_pretty_representation()
5913 	<< ", "
5914 	<< second_subject()->get_pretty_representation()
5915 	<< "]";
5916       diff::priv_->pretty_representation_ = o.str();
5917     }
5918   return diff::priv_->pretty_representation_;
5919 }
5920 
5921 /// Report the changes carried by the current @ref union_diff node in
5922 /// a textual format.
5923 ///
5924 /// @param out the output stream to write the textual report to.
5925 ///
5926 /// @param indent the number of white space to use as indentation.
5927 void
report(ostream & out,const string & indent) const5928 union_diff::report(ostream& out, const string& indent) const
5929 {
5930   context()->get_reporter()->report(*this, out, indent);
5931 }
5932 
5933 /// Compute the difference between two @ref union_decl types.
5934 ///
5935 /// Note that the two types must hav been created in the same
5936 /// environment, otherwise, this function aborts.
5937 ///
5938 /// @param first the first @ref union_decl to consider.
5939 ///
5940 /// @param second the second @ref union_decl to consider.
5941 ///
5942 /// @param ctxt the context of the diff to use.
5943 union_diff_sptr
compute_diff(const union_decl_sptr first,const union_decl_sptr second,diff_context_sptr ctxt)5944 compute_diff(const union_decl_sptr	first,
5945 	     const union_decl_sptr	second,
5946 	     diff_context_sptr	ctxt)
5947 {
5948   if (first && second)
5949     ABG_ASSERT(first->get_environment() == second->get_environment());
5950 
5951   union_diff_sptr changes(new union_diff(first, second, ctxt));
5952 
5953   ctxt->initialize_canonical_diff(changes);
5954   ABG_ASSERT(changes->get_canonical_diff());
5955 
5956   // Ok, so this is an optimization.  Do not freak out if it looks
5957   // weird, because, well, it does look weird.  This speeds up
5958   // greatly, for instance, the test case given at PR
5959   // libabigail/17948.
5960   //
5961   // We are setting the private data of the new instance of class_diff
5962   // (which is 'changes') to the private data of its canonical
5963   // instance.  That is, we are sharing the private data of 'changes'
5964   // with the private data of its canonical instance to consume less
5965   // memory in cases where the equivalence class of 'changes' is huge.
5966   //
5967   // But if changes is its own canonical instance, then we initialize
5968   // its private data properly.
5969   if (is_union_diff(changes->get_canonical_diff()) ==  changes.get())
5970     // changes is its own canonical instance, so it gets a brand new
5971     // private data.
5972     changes->allocate_priv_data();
5973   else
5974     {
5975       // changes has a non-empty equivalence class so it's going to
5976       // share its private data with its canonical instance.  Next
5977       // time class_diff::get_priv() is invoked, it's going to return
5978       // the shared private data of the canonical instance.
5979       return changes;
5980     }
5981 
5982   // Compare data member
5983   compute_diff(first->get_non_static_data_members().begin(),
5984 	       first->get_non_static_data_members().end(),
5985 	       second->get_non_static_data_members().begin(),
5986 	       second->get_non_static_data_members().end(),
5987 	       changes->data_members_changes());
5988 
5989 #if 0
5990   // Compare member functions
5991   compute_diff(first->get_mem_fns().begin(),
5992 	       first->get_mem_fns().end(),
5993 	       second->get_mem_fns().begin(),
5994 	       second->get_mem_fns().end(),
5995 	       changes->member_fns_changes());
5996 
5997   // Compare member function templates
5998   compute_diff(first->get_member_function_templates().begin(),
5999 	       first->get_member_function_templates().end(),
6000 	       second->get_member_function_templates().begin(),
6001 	       second->get_member_function_templates().end(),
6002 	       changes->member_fn_tmpls_changes());
6003 #endif
6004 
6005   changes->ensure_lookup_tables_populated();
6006 
6007   return changes;
6008 }
6009 
6010 // </union_diff stuff>
6011 
6012 //<scope_diff stuff>
6013 
6014 /// Clear the lookup tables that are useful for reporting.
6015 ///
6016 /// This function must be updated each time a lookup table is added or
6017 /// removed.
6018 void
clear_lookup_tables()6019 scope_diff::clear_lookup_tables()
6020 {
6021   priv_->deleted_types_.clear();
6022   priv_->deleted_decls_.clear();
6023   priv_->inserted_types_.clear();
6024   priv_->inserted_decls_.clear();
6025   priv_->changed_types_.clear();
6026   priv_->changed_decls_.clear();
6027   priv_->removed_types_.clear();
6028   priv_->removed_decls_.clear();
6029   priv_->added_types_.clear();
6030   priv_->added_decls_.clear();
6031 }
6032 
6033 /// Tests if the lookup tables are empty.
6034 ///
6035 /// This function must be updated each time a lookup table is added or
6036 /// removed.
6037 ///
6038 /// @return true iff all the lookup tables are empty.
6039 bool
lookup_tables_empty() const6040 scope_diff::lookup_tables_empty() const
6041 {
6042   return (priv_->deleted_types_.empty()
6043 	  && priv_->deleted_decls_.empty()
6044 	  && priv_->inserted_types_.empty()
6045 	  && priv_->inserted_decls_.empty()
6046 	  && priv_->changed_types_.empty()
6047 	  && priv_->changed_decls_.empty()
6048 	  && priv_->removed_types_.empty()
6049 	  && priv_->removed_decls_.empty()
6050 	  && priv_->added_types_.empty()
6051 	  && priv_->added_decls_.empty());
6052 }
6053 
6054 /// If the lookup tables are not yet built, walk the member_changes_
6055 /// member and fill the lookup tables.
6056 void
ensure_lookup_tables_populated()6057 scope_diff::ensure_lookup_tables_populated()
6058 {
6059   if (!lookup_tables_empty())
6060     return;
6061 
6062   edit_script& e = priv_->member_changes_;
6063 
6064   // Populate deleted types & decls lookup tables.
6065   for (vector<deletion>::const_iterator i = e.deletions().begin();
6066        i != e.deletions().end();
6067        ++i)
6068     {
6069       decl_base_sptr decl = deleted_member_at(i);
6070       string qname = decl->get_qualified_name();
6071       if (is_type(decl))
6072 	{
6073 	  class_decl_sptr klass_decl = dynamic_pointer_cast<class_decl>(decl);
6074 	  if (klass_decl && klass_decl->get_is_declaration_only())
6075 	    continue;
6076 
6077 	  ABG_ASSERT(priv_->deleted_types_.find(qname)
6078 		 == priv_->deleted_types_.end());
6079 	  priv_->deleted_types_[qname] = decl;
6080 	}
6081       else
6082 	{
6083 	  ABG_ASSERT(priv_->deleted_decls_.find(qname)
6084 		 == priv_->deleted_decls_.end());
6085 	  priv_->deleted_decls_[qname] = decl;
6086 	}
6087     }
6088 
6089   // Populate inserted types & decls as well as chagned types & decls
6090   // lookup tables.
6091   for (vector<insertion>::const_iterator it = e.insertions().begin();
6092        it != e.insertions().end();
6093        ++it)
6094     {
6095       for (vector<unsigned>::const_iterator i = it->inserted_indexes().begin();
6096 	   i != it->inserted_indexes().end();
6097 	   ++i)
6098 	{
6099 	  decl_base_sptr decl = inserted_member_at(i);
6100 	  string qname = decl->get_qualified_name();
6101 	  if (is_type(decl))
6102 	    {
6103 	      class_decl_sptr klass_decl =
6104 		dynamic_pointer_cast<class_decl>(decl);
6105 	      if (klass_decl && klass_decl->get_is_declaration_only())
6106 		continue;
6107 
6108 	      ABG_ASSERT(priv_->inserted_types_.find(qname)
6109 		     == priv_->inserted_types_.end());
6110 	      string_decl_base_sptr_map::const_iterator j =
6111 		priv_->deleted_types_.find(qname);
6112 	      if (j != priv_->deleted_types_.end())
6113 		{
6114 		  if (*j->second != *decl)
6115 		    priv_->changed_types_[qname] =
6116 		      compute_diff(j->second, decl, context());
6117 		  priv_->deleted_types_.erase(j);
6118 		}
6119 	      else
6120 		priv_->inserted_types_[qname] = decl;
6121 	    }
6122 	  else
6123 	    {
6124 	      ABG_ASSERT(priv_->inserted_decls_.find(qname)
6125 		     == priv_->inserted_decls_.end());
6126 	      string_decl_base_sptr_map::const_iterator j =
6127 		priv_->deleted_decls_.find(qname);
6128 	      if (j != priv_->deleted_decls_.end())
6129 		{
6130 		  if (*j->second != *decl)
6131 		    priv_->changed_decls_[qname] =
6132 		      compute_diff(j->second, decl, context());
6133 		  priv_->deleted_decls_.erase(j);
6134 		}
6135 	      else
6136 		priv_->inserted_decls_[qname] = decl;
6137 	    }
6138 	}
6139     }
6140 
6141   sort_string_diff_sptr_map(priv_->changed_decls_,
6142 			    priv_->sorted_changed_decls_);
6143   sort_string_diff_sptr_map(priv_->changed_types_,
6144 			    priv_->sorted_changed_types_);
6145 
6146   // Populate removed types/decls lookup tables
6147   for (string_decl_base_sptr_map::const_iterator i =
6148 	 priv_->deleted_types_.begin();
6149        i != priv_->deleted_types_.end();
6150        ++i)
6151     {
6152       string_decl_base_sptr_map::const_iterator r =
6153 	priv_->inserted_types_.find(i->first);
6154       if (r == priv_->inserted_types_.end())
6155 	priv_->removed_types_[i->first] = i->second;
6156     }
6157   for (string_decl_base_sptr_map::const_iterator i =
6158 	 priv_->deleted_decls_.begin();
6159        i != priv_->deleted_decls_.end();
6160        ++i)
6161     {
6162       string_decl_base_sptr_map::const_iterator r =
6163 	priv_->inserted_decls_.find(i->first);
6164       if (r == priv_->inserted_decls_.end())
6165 	priv_->removed_decls_[i->first] = i->second;
6166     }
6167 
6168   // Populate added types/decls.
6169   for (string_decl_base_sptr_map::const_iterator i =
6170 	 priv_->inserted_types_.begin();
6171        i != priv_->inserted_types_.end();
6172        ++i)
6173     {
6174       string_decl_base_sptr_map::const_iterator r =
6175 	priv_->deleted_types_.find(i->first);
6176       if (r == priv_->deleted_types_.end())
6177 	priv_->added_types_[i->first] = i->second;
6178     }
6179   for (string_decl_base_sptr_map::const_iterator i =
6180 	 priv_->inserted_decls_.begin();
6181        i != priv_->inserted_decls_.end();
6182        ++i)
6183     {
6184       string_decl_base_sptr_map::const_iterator r =
6185 	priv_->deleted_decls_.find(i->first);
6186       if (r == priv_->deleted_decls_.end())
6187 	priv_->added_decls_[i->first] = i->second;
6188     }
6189 }
6190 
6191 /// Populate the vector of children node of the @ref diff base type
6192 /// sub-object of this instance of @ref scope_diff.
6193 ///
6194 /// The children node can then later be retrieved using
6195 /// diff::children_node().
6196 void
chain_into_hierarchy()6197 scope_diff::chain_into_hierarchy()
6198 {
6199   for (diff_sptrs_type::const_iterator i = changed_types().begin();
6200        i != changed_types().end();
6201        ++i)
6202     if (*i)
6203       append_child_node(*i);
6204 
6205   for (diff_sptrs_type::const_iterator i = changed_decls().begin();
6206        i != changed_decls().end();
6207        ++i)
6208     if (*i)
6209       append_child_node(*i);
6210 }
6211 
6212 /// Constructor for scope_diff
6213 ///
6214 /// @param first_scope the first scope to consider for the diff.
6215 ///
6216 /// @param second_scope the second scope to consider for the diff.
6217 ///
6218 /// @param ctxt the diff context to use.  Note that this context
6219 /// object must stay alive at least during the life time of the
6220 /// current instance of @ref scope_diff.  Otherwise memory corruption
6221 /// issues occur.
scope_diff(scope_decl_sptr first_scope,scope_decl_sptr second_scope,diff_context_sptr ctxt)6222 scope_diff::scope_diff(scope_decl_sptr first_scope,
6223 		       scope_decl_sptr second_scope,
6224 		       diff_context_sptr ctxt)
6225   : diff(first_scope, second_scope, ctxt),
6226     priv_(new priv)
6227 {}
6228 
6229 /// Getter for the first scope of the diff.
6230 ///
6231 /// @return the first scope of the diff.
6232 const scope_decl_sptr
first_scope() const6233 scope_diff::first_scope() const
6234 {return dynamic_pointer_cast<scope_decl>(first_subject());}
6235 
6236 /// Getter for the second scope of the diff.
6237 ///
6238 /// @return the second scope of the diff.
6239 const scope_decl_sptr
second_scope() const6240 scope_diff::second_scope() const
6241 {return dynamic_pointer_cast<scope_decl>(second_subject());}
6242 
6243 /// Accessor of the edit script of the members of a scope.
6244 ///
6245 /// This edit script is computed using the equality operator that
6246 /// applies to shared_ptr<decl_base>.
6247 ///
6248 /// That has interesting consequences.  For instance, consider two
6249 /// scopes S0 and S1.  S0 contains a class C0 and S1 contains a class
6250 /// S0'.  C0 and C0' have the same qualified name, but have different
6251 /// members.  The edit script will consider that C0 has been deleted
6252 /// from S0 and that S0' has been inserted.  This is a low level
6253 /// canonical representation of the changes; a higher level
6254 /// representation would give us a simpler way to say "the class C0
6255 /// has been modified into C0'".  But worry not.  We do have such
6256 /// higher representation as well; that is what changed_types() and
6257 /// changed_decls() is for.
6258 ///
6259 /// @return the edit script of the changes encapsulatd in this
6260 /// instance of scope_diff.
6261 const edit_script&
member_changes() const6262 scope_diff::member_changes() const
6263 {return priv_->member_changes_;}
6264 
6265 /// Accessor of the edit script of the members of a scope.
6266 ///
6267 /// This edit script is computed using the equality operator that
6268 /// applies to shared_ptr<decl_base>.
6269 ///
6270 /// That has interesting consequences.  For instance, consider two
6271 /// scopes S0 and S1.  S0 contains a class C0 and S1 contains a class
6272 /// S0'.  C0 and C0' have the same qualified name, but have different
6273 /// members.  The edit script will consider that C0 has been deleted
6274 /// from S0 and that S0' has been inserted.  This is a low level
6275 /// canonical representation of the changes; a higher level
6276 /// representation would give us a simpler way to say "the class C0
6277 /// has been modified into C0'".  But worry not.  We do have such
6278 /// higher representation as well; that is what changed_types() and
6279 /// changed_decls() is for.
6280 ///
6281 /// @return the edit script of the changes encapsulatd in this
6282 /// instance of scope_diff.
6283 edit_script&
member_changes()6284 scope_diff::member_changes()
6285 {return priv_->member_changes_;}
6286 
6287 /// Accessor that eases the manipulation of the edit script associated
6288 /// to this instance.  It returns the scope member that is reported
6289 /// (in the edit script) as deleted at a given index.
6290 ///
6291 /// @param i the index (in the edit script) of an element of the first
6292 /// scope that has been reported as being delete.
6293 ///
6294 /// @return the scope member that has been reported by the edit script
6295 /// as being deleted at index i.
6296 const decl_base_sptr
deleted_member_at(unsigned i) const6297 scope_diff::deleted_member_at(unsigned i) const
6298 {
6299   scope_decl_sptr scope = dynamic_pointer_cast<scope_decl>(first_subject());
6300  return scope->get_member_decls()[i];
6301 }
6302 
6303 /// Accessor that eases the manipulation of the edit script associated
6304 /// to this instance.  It returns the scope member (of the first scope
6305 /// of this diff instance) that is reported (in the edit script) as
6306 /// deleted at a given iterator.
6307 ///
6308 /// @param i the iterator of an element of the first scope that has
6309 /// been reported as being delete.
6310 ///
6311 /// @return the scope member of the first scope of this diff that has
6312 /// been reported by the edit script as being deleted at iterator i.
6313 const decl_base_sptr
deleted_member_at(vector<deletion>::const_iterator i) const6314 scope_diff::deleted_member_at(vector<deletion>::const_iterator i) const
6315 {return deleted_member_at(i->index());}
6316 
6317 /// Accessor that eases the manipulation of the edit script associated
6318 /// to this instance.  It returns the scope member (of the second
6319 /// scope of this diff instance) that is reported as being inserted
6320 /// from a given index.
6321 ///
6322 /// @param i the index of an element of the second scope this diff
6323 /// that has been reported by the edit script as being inserted.
6324 ///
6325 /// @return the scope member of the second scope of this diff that has
6326 /// been reported as being inserted from index i.
6327 const decl_base_sptr
inserted_member_at(unsigned i)6328 scope_diff::inserted_member_at(unsigned i)
6329 {
6330   scope_decl_sptr scope = dynamic_pointer_cast<scope_decl>(second_subject());
6331   return scope->get_member_decls()[i];
6332 }
6333 
6334 /// Accessor that eases the manipulation of the edit script associated
6335 /// to this instance.  It returns the scope member (of the second
6336 /// scope of this diff instance) that is reported as being inserted
6337 /// from a given iterator.
6338 ///
6339 /// @param i the iterator of an element of the second scope this diff
6340 /// that has been reported by the edit script as being inserted.
6341 ///
6342 /// @return the scope member of the second scope of this diff that has
6343 /// been reported as being inserted from iterator i.
6344 const decl_base_sptr
inserted_member_at(vector<unsigned>::const_iterator i)6345 scope_diff::inserted_member_at(vector<unsigned>::const_iterator i)
6346 {return inserted_member_at(*i);}
6347 
6348 /// @return a sorted vector of the types which content has changed
6349 /// from the first scope to the other.
6350 const diff_sptrs_type&
changed_types() const6351 scope_diff::changed_types() const
6352 {return priv_->sorted_changed_types_;}
6353 
6354 /// @return a sorted vector of the decls which content has changed
6355 /// from the first scope to the other.
6356 const diff_sptrs_type&
changed_decls() const6357 scope_diff::changed_decls() const
6358 {return priv_->sorted_changed_decls_;}
6359 
6360 const string_decl_base_sptr_map&
removed_types() const6361 scope_diff::removed_types() const
6362 {return priv_->removed_types_;}
6363 
6364 const string_decl_base_sptr_map&
removed_decls() const6365 scope_diff::removed_decls() const
6366 {return priv_->removed_decls_;}
6367 
6368 const string_decl_base_sptr_map&
added_types() const6369 scope_diff::added_types() const
6370 {return priv_->added_types_;}
6371 
6372 const string_decl_base_sptr_map&
added_decls() const6373 scope_diff::added_decls() const
6374 {return priv_->added_decls_;}
6375 
6376 /// @return the pretty representation for the current instance of @ref
6377 /// scope_diff.
6378 const string&
get_pretty_representation() const6379 scope_diff::get_pretty_representation() const
6380 {
6381   if (diff::priv_->pretty_representation_.empty())
6382     {
6383       std::ostringstream o;
6384       o << "scope_diff["
6385 	<< first_subject()->get_pretty_representation()
6386 	<< ", "
6387 	<< second_subject()->get_pretty_representation()
6388 	<< "]";
6389       diff::priv_->pretty_representation_ = o.str();
6390     }
6391   return diff::priv_->pretty_representation_;
6392 }
6393 
6394 /// Return true iff the current diff node carries a change.
6395 ///
6396 /// Return true iff the current diff node carries a change.
6397 bool
has_changes() const6398 scope_diff::has_changes() const
6399 {
6400   // TODO: add the number of really removed/added stuff.
6401   return changed_types().size() + changed_decls().size();
6402 }
6403 
6404 /// @return the kind of local change carried by the current diff node.
6405 /// The value returned is zero if the current node carries no local
6406 /// change.
6407 enum change_kind
has_local_changes() const6408 scope_diff::has_local_changes() const
6409 {
6410   ir::change_kind k = ir::NO_CHANGE_KIND;
6411   if (!equals(*first_scope(), *second_scope(), &k))
6412     return k & ir::ALL_LOCAL_CHANGES_MASK;
6413   return ir::NO_CHANGE_KIND;
6414 }
6415 
6416 /// Report the changes of one scope against another.
6417 ///
6418 /// @param out the out stream to report the changes to.
6419 ///
6420 /// @param indent the string to use for indentation.
6421 void
report(ostream & out,const string & indent) const6422 scope_diff::report(ostream& out, const string& indent) const
6423 {
6424   context()->get_reporter()->report(*this, out, indent);
6425 }
6426 
6427 /// Compute the diff between two scopes.
6428 ///
6429 /// Note that the two decls must have been created in the same @ref
6430 /// environment, otherwise, this function aborts.
6431 ///
6432 /// @param first the first scope to consider in computing the diff.
6433 ///
6434 /// @param second the second scope to consider in the diff
6435 /// computation.  The second scope is diffed against the first scope.
6436 ///
6437 /// @param d a pointer to the diff object to populate with the
6438 /// computed diff.
6439 ///
6440 /// @return return the populated \a d parameter passed to this
6441 /// function.
6442 ///
6443 /// @param ctxt the diff context to use.
6444 scope_diff_sptr
compute_diff(const scope_decl_sptr first,const scope_decl_sptr second,scope_diff_sptr d,diff_context_sptr ctxt)6445 compute_diff(const scope_decl_sptr	first,
6446 	     const scope_decl_sptr	second,
6447 	     scope_diff_sptr		d,
6448 	     diff_context_sptr		ctxt)
6449 {
6450   ABG_ASSERT(d->first_scope() == first && d->second_scope() == second);
6451 
6452   if (first && second)
6453     ABG_ASSERT(first->get_environment() == second->get_environment());
6454 
6455   compute_diff(first->get_member_decls().begin(),
6456 	       first->get_member_decls().end(),
6457 	       second->get_member_decls().begin(),
6458 	       second->get_member_decls().end(),
6459 	       d->member_changes());
6460 
6461   d->ensure_lookup_tables_populated();
6462   d->context(ctxt);
6463 
6464   return d;
6465 }
6466 
6467 /// Compute the diff between two scopes.
6468 ///
6469 /// Note that the two decls must have been created in the same @ref
6470 /// environment, otherwise, this function aborts.
6471 ///
6472 /// @param first_scope the first scope to consider in computing the diff.
6473 ///
6474 /// @param second_scope the second scope to consider in the diff
6475 /// computation.  The second scope is diffed against the first scope.
6476 ///
6477 /// @param ctxt the diff context to use.
6478 ///
6479 /// @return return the resulting diff
6480 scope_diff_sptr
compute_diff(const scope_decl_sptr first_scope,const scope_decl_sptr second_scope,diff_context_sptr ctxt)6481 compute_diff(const scope_decl_sptr	first_scope,
6482 	     const scope_decl_sptr	second_scope,
6483 	     diff_context_sptr		ctxt)
6484 {
6485   if (first_scope && second_scope)
6486     ABG_ASSERT(first_scope->get_environment()
6487 	   == second_scope->get_environment());
6488 
6489   scope_diff_sptr d(new scope_diff(first_scope, second_scope, ctxt));
6490   d = compute_diff(first_scope, second_scope, d, ctxt);
6491   ctxt->initialize_canonical_diff(d);
6492   return d;
6493 }
6494 
6495 //</scope_diff stuff>
6496 
6497 // <fn_parm_diff stuff>
6498 
6499 /// Constructor for the fn_parm_diff type.
6500 ///
6501 /// @param first the first subject of the diff.
6502 ///
6503 /// @param second the second subject of the diff.
6504 ///
6505 /// @param ctxt the context of the diff.  Note that this context
6506 /// object must stay alive at least during the life time of the
6507 /// current instance of @ref fn_parm_diff.  Otherwise memory
6508 /// corruption issues occur.
fn_parm_diff(const function_decl::parameter_sptr first,const function_decl::parameter_sptr second,diff_context_sptr ctxt)6509 fn_parm_diff::fn_parm_diff(const function_decl::parameter_sptr	first,
6510 			   const function_decl::parameter_sptr	second,
6511 			   diff_context_sptr			ctxt)
6512   : decl_diff_base(first, second, ctxt),
6513     priv_(new priv)
6514 {
6515   ABG_ASSERT(first->get_index() == second->get_index());
6516   priv_->type_diff = compute_diff(first->get_type(),
6517 				  second->get_type(),
6518 				  ctxt);
6519   ABG_ASSERT(priv_->type_diff);
6520 }
6521 
6522 /// Getter for the first subject of this diff node.
6523 ///
6524 /// @return the first function_decl::parameter_sptr subject of this
6525 /// diff node.
6526 const function_decl::parameter_sptr
first_parameter() const6527 fn_parm_diff::first_parameter() const
6528 {return dynamic_pointer_cast<function_decl::parameter>(first_subject());}
6529 
6530 /// Getter for the second subject of this diff node.
6531 ///
6532 /// @return the second function_decl::parameter_sptr subject of this
6533 /// diff node.
6534 const function_decl::parameter_sptr
second_parameter() const6535 fn_parm_diff::second_parameter() const
6536 {return dynamic_pointer_cast<function_decl::parameter>(second_subject());}
6537 
6538 /// Getter for the diff representing the changes on the type of the
6539 /// function parameter involved in the current instance of @ref
6540 /// fn_parm_diff.
6541 ///
6542 /// @return a diff_sptr representing the changes on the type of the
6543 /// function parameter we are interested in.
6544 diff_sptr
type_diff() const6545 fn_parm_diff::type_diff() const
6546 {return priv_->type_diff;}
6547 
6548 /// Build and return a textual representation of the current instance
6549 /// of @ref fn_parm_diff.
6550 ///
6551 /// @return the string representing the current instance of
6552 /// fn_parm_diff.
6553 const string&
get_pretty_representation() const6554 fn_parm_diff::get_pretty_representation() const
6555 {
6556   if (diff::priv_->pretty_representation_.empty())
6557     {
6558       std::ostringstream o;
6559       o << "function_parameter_diff["
6560 	<< first_subject()->get_pretty_representation()
6561 	<< ", "
6562 	<< second_subject()->get_pretty_representation()
6563 	<< "]";
6564       diff::priv_->pretty_representation_ = o.str();
6565     }
6566   return diff::priv_->pretty_representation_;
6567 }
6568 
6569 /// Return true iff the current diff node carries a change.
6570 ///
6571 /// @return true iff the current diff node carries a change.
6572 bool
has_changes() const6573 fn_parm_diff::has_changes() const
6574 {return *first_parameter() != *second_parameter();}
6575 
6576 /// Check if the current diff node carries a local change.
6577 ///
6578 /// @return the kind of local change carried by the current diff node.
6579 /// The value returned is zero if the current node carries no local
6580 /// change.
6581 enum change_kind
has_local_changes() const6582 fn_parm_diff::has_local_changes() const
6583 {
6584   ir::change_kind k = ir::NO_CHANGE_KIND;
6585   if (!equals(*first_parameter(), *second_parameter(), &k))
6586     return k & ir::ALL_LOCAL_CHANGES_MASK;
6587   return ir::NO_CHANGE_KIND;
6588 }
6589 
6590 /// Emit a textual report about the current fn_parm_diff instance.
6591 ///
6592 /// @param out the output stream to emit the textual report to.
6593 ///
6594 /// @param indent the indentation string to use in the report.
6595 void
report(ostream & out,const string & indent) const6596 fn_parm_diff::report(ostream& out, const string& indent) const
6597 {
6598   context()->get_reporter()->report(*this, out, indent);
6599 }
6600 
6601 /// Populate the vector of children nodes of the @ref diff base type
6602 /// sub-object of this instance of @ref fn_parm_diff.
6603 ///
6604 /// The children nodes can then later be retrieved using
6605 /// diff::children_nodes()
6606 void
chain_into_hierarchy()6607 fn_parm_diff::chain_into_hierarchy()
6608 {
6609   if (type_diff())
6610     append_child_node(type_diff());
6611 }
6612 
6613 /// Compute the difference between two function_decl::parameter_sptr;
6614 /// that is, between two function parameters.  Return a resulting
6615 /// fn_parm_diff_sptr that represents the changes.
6616 ///
6617 /// Note that the two decls must have been created in the same @ref
6618 /// environment, otherwise, this function aborts.
6619 ///
6620 /// @param first the first subject of the diff.
6621 ///
6622 /// @param second the second subject of the diff.
6623 ///
6624 /// @param ctxt the context of the diff.
6625 ///
6626 /// @return fn_parm_diff_sptr the resulting diff node.
6627 fn_parm_diff_sptr
compute_diff(const function_decl::parameter_sptr first,const function_decl::parameter_sptr second,diff_context_sptr ctxt)6628 compute_diff(const function_decl::parameter_sptr	first,
6629 	     const function_decl::parameter_sptr	second,
6630 	     diff_context_sptr				ctxt)
6631 {
6632   if (!first || !second)
6633     return fn_parm_diff_sptr();
6634 
6635   ABG_ASSERT(first->get_environment() == second->get_environment());
6636 
6637   fn_parm_diff_sptr result(new fn_parm_diff(first, second, ctxt));
6638   ctxt->initialize_canonical_diff(result);
6639 
6640   return result;
6641 }
6642 // </fn_parm_diff stuff>
6643 
6644 // <function_type_diff stuff>
6645 
6646 void
ensure_lookup_tables_populated()6647 function_type_diff::ensure_lookup_tables_populated()
6648 {
6649   priv_->return_type_diff_ =
6650     compute_diff(first_function_type()->get_return_type(),
6651 		 second_function_type()->get_return_type(),
6652 		 context());
6653 
6654   string parm_name;
6655   function_decl::parameter_sptr parm;
6656   for (vector<deletion>::const_iterator i =
6657 	 priv_->parm_changes_.deletions().begin();
6658        i != priv_->parm_changes_.deletions().end();
6659        ++i)
6660     {
6661       parm = *(first_function_type()->get_first_parm()
6662 	       + i->index());
6663       parm_name = parm->get_name_id();
6664       // If for a reason the type name is empty we want to know and
6665       // fix that.
6666       ABG_ASSERT(!parm_name.empty());
6667       priv_->deleted_parms_[parm_name] = parm;
6668       priv_->deleted_parms_by_id_[parm->get_index()] = parm;
6669     }
6670 
6671   for (vector<insertion>::const_iterator i =
6672 	 priv_->parm_changes_.insertions().begin();
6673        i != priv_->parm_changes_.insertions().end();
6674        ++i)
6675     {
6676       for (vector<unsigned>::const_iterator j =
6677 	     i->inserted_indexes().begin();
6678 	   j != i->inserted_indexes().end();
6679 	   ++j)
6680 	{
6681 	  parm = *(second_function_type()->get_first_parm() + *j);
6682 	  parm_name = parm->get_name_id();
6683 	  // If for a reason the type name is empty we want to know and
6684 	  // fix that.
6685 	  ABG_ASSERT(!parm_name.empty());
6686 	  {
6687 	    string_parm_map::const_iterator k =
6688 	      priv_->deleted_parms_.find(parm_name);
6689 	    if (k != priv_->deleted_parms_.end())
6690 	      {
6691 		if (*k->second != *parm)
6692 		  priv_->subtype_changed_parms_[parm_name] =
6693 		    compute_diff(k->second, parm, context());
6694 		priv_->deleted_parms_.erase(parm_name);
6695 	      }
6696 	    else
6697 	      priv_->added_parms_[parm_name] = parm;
6698 	  }
6699 	  {
6700 	    unsigned_parm_map::const_iterator k =
6701 	      priv_->deleted_parms_by_id_.find(parm->get_index());
6702 	    if (k != priv_->deleted_parms_by_id_.end())
6703 	      {
6704 		if (*k->second != *parm
6705 		    && (k->second->get_name_id() != parm_name))
6706 		  priv_->changed_parms_by_id_[parm->get_index()] =
6707 		    compute_diff(k->second, parm, context());
6708 		priv_->added_parms_.erase(parm_name);
6709 		priv_->deleted_parms_.erase(k->second->get_name_id());
6710 		priv_->deleted_parms_by_id_.erase(parm->get_index());
6711 	      }
6712 	    else
6713 	      priv_->added_parms_by_id_[parm->get_index()] = parm;
6714 	  }
6715 	}
6716     }
6717 
6718   sort_string_fn_parm_diff_sptr_map(priv_->subtype_changed_parms_,
6719 				    priv_->sorted_subtype_changed_parms_);
6720   sort_string_fn_parm_diff_sptr_map(priv_->changed_parms_by_id_,
6721 				    priv_->sorted_changed_parms_by_id_);
6722   sort_string_parm_map(priv_->deleted_parms_,
6723 		       priv_->sorted_deleted_parms_);
6724 
6725   sort_string_parm_map(priv_->added_parms_,
6726 		       priv_->sorted_added_parms_);
6727 }
6728 
6729 /// In the vector of deleted parameters, get the one that is at a given
6730 /// index.
6731 ///
6732 /// @param i the index of the deleted parameter to get.
6733 ///
6734 /// @return the parameter returned.
6735 const function_decl::parameter_sptr
deleted_parameter_at(int i) const6736 function_type_diff::deleted_parameter_at(int i) const
6737 {return first_function_type()->get_parameters()[i];}
6738 
6739 /// Getter for the sorted vector of deleted parameters.
6740 ///
6741 /// @return the sorted vector of deleted parameters.
6742 const vector<function_decl::parameter_sptr>&
sorted_deleted_parms() const6743 function_type_diff::sorted_deleted_parms() const
6744 {return priv_->sorted_deleted_parms_;}
6745 
6746 /// Getter for the sorted vector of added parameters .
6747 ///
6748 /// @return the sorted vector of added parameters.
6749 const vector<function_decl::parameter_sptr>&
sorted_added_parms() const6750 function_type_diff::sorted_added_parms() const
6751 {return priv_->sorted_added_parms_;}
6752 
6753 /// In the vector of inserted parameters, get the one that is at a
6754 /// given index.
6755 ///
6756 /// @param i the index of the inserted parameter to get.
6757 ///
6758 /// @return the parameter returned.
6759 const function_decl::parameter_sptr
inserted_parameter_at(int i) const6760 function_type_diff::inserted_parameter_at(int i) const
6761 {return second_function_type()->get_parameters()[i];}
6762 
6763 /// Consutrctor of the @ref function_type type.
6764 ///
6765 /// @param first the first @ref function_type subject of the diff to
6766 /// create.
6767 ///
6768 /// @param second the second @ref function_type subject of the diff to
6769 /// create.
6770 ///
6771 /// @param ctxt the diff context to be used by the newly created
6772 /// instance of function_type_diff.  Note that this context object
6773 /// must stay alive at least during the life time of the current
6774 /// instance of @ref function_type_diff.  Otherwise memory corruption
6775 /// issues occur.
function_type_diff(const function_type_sptr first,const function_type_sptr second,diff_context_sptr ctxt)6776 function_type_diff::function_type_diff(const function_type_sptr first,
6777 				       const function_type_sptr second,
6778 				       diff_context_sptr	ctxt)
6779   : type_diff_base(first, second, ctxt),
6780     priv_(new priv)
6781 {}
6782 
6783 /// Getter for the first subject of the diff.
6784 ///
6785 /// @return the first function type involved in the diff.
6786 const function_type_sptr
first_function_type() const6787 function_type_diff::first_function_type() const
6788 {return dynamic_pointer_cast<function_type>(first_subject());}
6789 
6790 /// Getter for the second subject of the diff.
6791 ///
6792 /// @return the second function type involved in the diff.
6793 const function_type_sptr
second_function_type() const6794 function_type_diff::second_function_type() const
6795 {return dynamic_pointer_cast<function_type>(second_subject());}
6796 
6797 /// Getter for the diff of the return types of the two function types
6798 /// of the current diff.
6799 ///
6800 /// @return the diff of the return types of the two function types of
6801 /// the current diff.
6802 const diff_sptr
return_type_diff() const6803 function_type_diff::return_type_diff() const
6804 {return priv_->return_type_diff_;}
6805 
6806 /// Getter for the map of function parameter changes of the current diff.
6807 ///
6808 /// @return a map of function parameter changes of the current diff.
6809 const string_fn_parm_diff_sptr_map&
subtype_changed_parms() const6810 function_type_diff::subtype_changed_parms() const
6811 {return priv_->subtype_changed_parms_;}
6812 
6813 /// Getter for the map of parameters that got removed.
6814 ///
6815 /// @return the map of parameters that got removed.
6816 const string_parm_map&
removed_parms() const6817 function_type_diff::removed_parms() const
6818 {return priv_->deleted_parms_;}
6819 
6820 /// Getter for the map of parameters that got added.
6821 ///
6822 /// @return the map of parameters that got added.
6823 const string_parm_map&
added_parms() const6824 function_type_diff::added_parms() const
6825 {return priv_->added_parms_;}
6826 
6827 /// Build and return a copy of a pretty representation of the current
6828 /// instance of @ref function_type_diff.
6829 ///
6830 /// @return a copy of the pretty representation of the current
6831 /// instance of @ref function_type_diff.
6832 const string&
get_pretty_representation() const6833 function_type_diff::get_pretty_representation() const
6834 {
6835   if (diff::priv_->pretty_representation_.empty())
6836     {
6837       std::ostringstream o;
6838       o << "function_type_diff["
6839 	<< abigail::ir::get_pretty_representation(first_function_type())
6840 	<< ", "
6841 	<< abigail::ir::get_pretty_representation(second_function_type())
6842 	<< "]";
6843       diff::priv_->pretty_representation_ = o.str();
6844     }
6845   return diff::priv_->pretty_representation_;
6846 }
6847 
6848 /// Test if the current diff node carries changes.
6849 ///
6850 /// @return true iff the current diff node carries changes.
6851 bool
has_changes() const6852 function_type_diff::has_changes() const
6853 {return *first_function_type() != *second_function_type();}
6854 
6855 /// Test if the current diff node carries local changes.
6856 ///
6857 /// A local change is a change that is carried by this diff node, not
6858 /// by any of its children nodes.
6859 ///
6860 /// @return the kind of local change carried by the current diff node.
6861 /// The value returned is zero if the current node carries no local
6862 /// change.
6863 enum change_kind
has_local_changes() const6864 function_type_diff::has_local_changes() const
6865 {
6866   ir::change_kind k = ir::NO_CHANGE_KIND;
6867   if (!equals(*first_function_type(), *second_function_type(), &k))
6868     return k & ir::ALL_LOCAL_CHANGES_MASK;
6869   return ir::NO_CHANGE_KIND;
6870 }
6871 
6872 /// Build and emit a textual report about the current @ref
6873 /// function_type_diff instance.
6874 ///
6875 /// @param out the output stream.
6876 ///
6877 /// @param indent the indentation string to use.
6878 void
report(ostream & out,const string & indent) const6879 function_type_diff::report(ostream& out, const string& indent) const
6880 {
6881   context()->get_reporter()->report(*this, out, indent);
6882 }
6883 
6884 /// Populate the vector of children node of the @ref diff base type
6885 /// sub-object of this instance of @ref function_type_diff.
6886 ///
6887 /// The children node can then later be retrieved using
6888 /// diff::children_node().
6889 void
chain_into_hierarchy()6890 function_type_diff::chain_into_hierarchy()
6891 {
6892   if (diff_sptr d = return_type_diff())
6893     append_child_node(d);
6894 
6895   for (vector<fn_parm_diff_sptr>::const_iterator i =
6896 	 priv_->sorted_subtype_changed_parms_.begin();
6897        i != priv_->sorted_subtype_changed_parms_.end();
6898        ++i)
6899     if (diff_sptr d = *i)
6900       append_child_node(d);
6901 
6902   for (vector<fn_parm_diff_sptr>::const_iterator i =
6903 	 priv_->sorted_changed_parms_by_id_.begin();
6904        i != priv_->sorted_changed_parms_by_id_.end();
6905        ++i)
6906     if (diff_sptr d = *i)
6907       append_child_node(d);
6908 }
6909 
6910 /// Compute the diff between two instances of @ref function_type.
6911 ///
6912 /// Note that the two types must have been created in the same @ref
6913 /// environment, otherwise, this function aborts.
6914 ///
6915 /// @param first the first @ref function_type to consider for the diff.
6916 ///
6917 /// @param second the second @ref function_type to consider for the diff.
6918 ///
6919 /// @param ctxt the diff context to use.
6920 ///
6921 /// @return the resulting diff between the two @ref function_type.
6922 function_type_diff_sptr
compute_diff(const function_type_sptr first,const function_type_sptr second,diff_context_sptr ctxt)6923 compute_diff(const function_type_sptr	first,
6924 	     const function_type_sptr	second,
6925 	     diff_context_sptr		ctxt)
6926 {
6927   if (!first || !second)
6928     {
6929       // TODO: implement this for either first or second being NULL.
6930       return function_type_diff_sptr();
6931     }
6932 
6933   ABG_ASSERT(first->get_environment() == second->get_environment());
6934 
6935   function_type_diff_sptr result(new function_type_diff(first, second, ctxt));
6936 
6937   diff_utils::compute_diff(first->get_first_parm(),
6938 			   first->get_parameters().end(),
6939 			   second->get_first_parm(),
6940 			   second->get_parameters().end(),
6941 			   result->priv_->parm_changes_);
6942 
6943   result->ensure_lookup_tables_populated();
6944 
6945   ctxt->initialize_canonical_diff(result);
6946 
6947   return result;
6948 }
6949 // </function_type_diff stuff>
6950 
6951 // <function_decl_diff stuff>
6952 
6953 /// Build the lookup tables of the diff, if necessary.
6954 void
ensure_lookup_tables_populated()6955 function_decl_diff::ensure_lookup_tables_populated()
6956 {
6957 }
6958 
6959 /// Populate the vector of children node of the @ref diff base type
6960 /// sub-object of this instance of @ref function_decl_diff.
6961 ///
6962 /// The children node can then later be retrieved using
6963 /// diff::children_node().
6964 void
chain_into_hierarchy()6965 function_decl_diff::chain_into_hierarchy()
6966 {
6967   if (diff_sptr d = type_diff())
6968     append_child_node(d);
6969 }
6970 
6971 /// Constructor for function_decl_diff
6972 ///
6973 /// @param first the first function considered by the diff.
6974 ///
6975 /// @param second the second function considered by the diff.
6976 ///
6977 /// @param ctxt the context of the diff.  Note that this context
6978 /// object must stay alive at least during the life time of the
6979 /// current instance of @ref function_decl_diff.  Otherwise memory
6980 /// corruption issues occur.
function_decl_diff(const function_decl_sptr first,const function_decl_sptr second,diff_context_sptr ctxt)6981 function_decl_diff::function_decl_diff(const function_decl_sptr first,
6982 				       const function_decl_sptr second,
6983 				       diff_context_sptr	ctxt)
6984   : decl_diff_base(first, second, ctxt),
6985     priv_(new priv)
6986 {
6987 }
6988 
6989 /// @return the first function considered by the diff.
6990 const function_decl_sptr
first_function_decl() const6991 function_decl_diff::first_function_decl() const
6992 {return dynamic_pointer_cast<function_decl>(first_subject());}
6993 
6994 /// @return the second function considered by the diff.
6995 const function_decl_sptr
second_function_decl() const6996 function_decl_diff::second_function_decl() const
6997 {return dynamic_pointer_cast<function_decl>(second_subject());}
6998 
6999 const function_type_diff_sptr
type_diff() const7000 function_decl_diff::type_diff() const
7001 {return priv_->type_diff_;}
7002 
7003 /// @return the pretty representation for the current instance of @ref
7004 /// function_decl_diff.
7005 const string&
get_pretty_representation() const7006 function_decl_diff::get_pretty_representation() const
7007 {
7008   if (diff::priv_->pretty_representation_.empty())
7009     {
7010       std::ostringstream o;
7011       o << "function_diff["
7012 	<< first_subject()->get_pretty_representation()
7013 	<< ", "
7014 	<< second_subject()->get_pretty_representation()
7015 	<< "]";
7016       diff::priv_->pretty_representation_ = o.str();
7017     }
7018   return diff::priv_->pretty_representation_;
7019 }
7020 
7021 /// Return true iff the current diff node carries a change.
7022 ///
7023 /// @return true iff the current diff node carries a change.
7024 bool
has_changes() const7025 function_decl_diff::has_changes() const
7026 {return *first_function_decl() != *second_function_decl();}
7027 
7028 /// @return the kind of local change carried by the current diff node.
7029 /// The value returned is zero if the current node carries no local
7030 /// change.
7031 enum change_kind
has_local_changes() const7032 function_decl_diff::has_local_changes() const
7033 {
7034   ir::change_kind k = ir::NO_CHANGE_KIND;
7035   if (!equals(*first_function_decl(), *second_function_decl(), &k))
7036     return k & ir::ALL_LOCAL_CHANGES_MASK;
7037   return ir::NO_CHANGE_KIND;
7038 }
7039 
7040 /// Serialize a report of the changes encapsulated in the current
7041 /// instance of @ref function_decl_diff over to an output stream.
7042 ///
7043 /// @param out the output stream to serialize the report to.
7044 ///
7045 /// @param indent the string to use an an indentation prefix.
7046 void
report(ostream & out,const string & indent) const7047 function_decl_diff::report(ostream& out, const string& indent) const
7048 {
7049   context()->get_reporter()->report(*this, out, indent);
7050 }
7051 
7052 /// Compute the diff between two function_decl.
7053 ///
7054 /// Note that the two decls must have been created in the same @ref
7055 /// environment, otherwise, this function aborts.
7056 ///
7057 /// @param first the first function_decl to consider for the diff
7058 ///
7059 /// @param second the second function_decl to consider for the diff
7060 ///
7061 /// @param ctxt the diff context to use.
7062 ///
7063 /// @return the computed diff
7064 function_decl_diff_sptr
compute_diff(const function_decl_sptr first,const function_decl_sptr second,diff_context_sptr ctxt)7065 compute_diff(const function_decl_sptr first,
7066 	     const function_decl_sptr second,
7067 	     diff_context_sptr ctxt)
7068 {
7069   if (!first || !second)
7070     {
7071       // TODO: implement this for either first or second being NULL.
7072       return function_decl_diff_sptr();
7073     }
7074 
7075   ABG_ASSERT(first->get_environment() == second->get_environment());
7076 
7077   function_type_diff_sptr type_diff = compute_diff(first->get_type(),
7078 						   second->get_type(),
7079 						   ctxt);
7080 
7081   function_decl_diff_sptr result(new function_decl_diff(first, second,
7082 							ctxt));
7083   result->priv_->type_diff_ = type_diff;
7084 
7085   result->ensure_lookup_tables_populated();
7086 
7087   ctxt->initialize_canonical_diff(result);
7088 
7089   return result;
7090 }
7091 
7092 // </function_decl_diff stuff>
7093 
7094 // <type_decl_diff stuff>
7095 
7096 /// Constructor for type_decl_diff.
7097 ///
7098 /// @param first the first subject of the diff.
7099 ///
7100 /// @param second the second subject of the diff.
7101 ///
7102 /// @param ctxt the context of the diff.  Note that this context
7103 /// object must stay alive at least during the life time of the
7104 /// current instance of @ref type_decl_diff.  Otherwise memory
7105 /// corruption issues occur.
type_decl_diff(const type_decl_sptr first,const type_decl_sptr second,diff_context_sptr ctxt)7106 type_decl_diff::type_decl_diff(const type_decl_sptr first,
7107 			       const type_decl_sptr second,
7108 			       diff_context_sptr ctxt)
7109   : type_diff_base(first, second, ctxt)
7110 {}
7111 
7112 /// Getter for the first subject of the type_decl_diff.
7113 ///
7114 /// @return the first type_decl involved in the diff.
7115 const type_decl_sptr
first_type_decl() const7116 type_decl_diff::first_type_decl() const
7117 {return dynamic_pointer_cast<type_decl>(first_subject());}
7118 
7119 /// Getter for the second subject of the type_decl_diff.
7120 ///
7121 /// @return the second type_decl involved in the diff.
7122 const type_decl_sptr
second_type_decl() const7123 type_decl_diff::second_type_decl() const
7124 {return dynamic_pointer_cast<type_decl>(second_subject());}
7125 
7126 /// @return the pretty representation for the current instance of @ref
7127 /// type_decl_diff.
7128 const string&
get_pretty_representation() const7129 type_decl_diff::get_pretty_representation() const
7130 {
7131   if (diff::priv_->pretty_representation_.empty())
7132     {
7133       std::ostringstream o;
7134       o << "type_decl_diff["
7135 	<< first_subject()->get_pretty_representation()
7136 	<< ", "
7137 	<< second_subject()->get_pretty_representation()
7138 	<< "]";
7139       diff::priv_->pretty_representation_ = o.str();
7140     }
7141   return diff::priv_->pretty_representation_;
7142 }
7143 /// Return true iff the current diff node carries a change.
7144 ///
7145 /// @return true iff the current diff node carries a change.
7146 bool
has_changes() const7147 type_decl_diff::has_changes() const
7148 {return first_type_decl() != second_type_decl();}
7149 
7150 /// @return the kind of local change carried by the current diff node.
7151 /// The value returned is zero if the current node carries no local
7152 /// change.
7153 enum change_kind
has_local_changes() const7154 type_decl_diff::has_local_changes() const
7155 {
7156   ir::change_kind k = ir::NO_CHANGE_KIND;
7157   if (!equals(*first_type_decl(), *second_type_decl(), &k))
7158     return k & ir::ALL_LOCAL_CHANGES_MASK;
7159   return ir::NO_CHANGE_KIND;
7160 }
7161 /// Ouputs a report of the differences between of the two type_decl
7162 /// involved in the type_decl_diff.
7163 ///
7164 /// @param out the output stream to emit the report to.
7165 ///
7166 /// @param indent the string to use for indentatino indent.
7167 void
report(ostream & out,const string & indent) const7168 type_decl_diff::report(ostream& out, const string& indent) const
7169 {
7170   context()->get_reporter()->report(*this, out, indent);
7171 }
7172 
7173 /// Compute a diff between two type_decl.
7174 ///
7175 /// Note that the two types must have been created in the same @ref
7176 /// environment, otherwise, this function aborts.
7177 ///
7178 /// This function doesn't actually compute a diff.  As a type_decl is
7179 /// very simple (unlike compound constructs like function_decl or
7180 /// class_decl) it's easy to just compare the components of the
7181 /// type_decl to know what has changed.  Thus this function just
7182 /// builds and return a type_decl_diff object.  The
7183 /// type_decl_diff::report function will just compare the components
7184 /// of the the two type_decl and display where and how they differ.
7185 ///
7186 /// @param first a pointer to the first type_decl to
7187 /// consider.
7188 ///
7189 /// @param second a pointer to the second type_decl to consider.
7190 ///
7191 /// @param ctxt the diff context to use.
7192 ///
7193 /// @return a pointer to the resulting type_decl_diff.
7194 type_decl_diff_sptr
compute_diff(const type_decl_sptr first,const type_decl_sptr second,diff_context_sptr ctxt)7195 compute_diff(const type_decl_sptr	first,
7196 	     const type_decl_sptr	second,
7197 	     diff_context_sptr		ctxt)
7198 {
7199   if (first && second)
7200     ABG_ASSERT(first->get_environment() == second->get_environment());
7201 
7202   type_decl_diff_sptr result(new type_decl_diff(first, second, ctxt));
7203 
7204   // We don't need to actually compute a diff here as a type_decl
7205   // doesn't have complicated sub-components.  type_decl_diff::report
7206   // just walks the members of the type_decls and display information
7207   // about the ones that have changed.  On a similar note,
7208   // type_decl_diff::length returns 0 if the two type_decls are equal,
7209   // and 1 otherwise.
7210 
7211   ctxt->initialize_canonical_diff(result);
7212 
7213   return result;
7214 }
7215 
7216 // </type_decl_diff stuff>
7217 
7218 // <typedef_diff stuff>
7219 
7220 /// Populate the vector of children node of the @ref diff base type
7221 /// sub-object of this instance of @ref typedef_diff.
7222 ///
7223 /// The children node can then later be retrieved using
7224 /// diff::children_node().
7225 void
chain_into_hierarchy()7226 typedef_diff::chain_into_hierarchy()
7227 {append_child_node(underlying_type_diff());}
7228 
7229 /// Constructor for typedef_diff.
7230 ///
7231 /// @param first the first subject of the diff.
7232 ///
7233 /// @param second the second subject of the diff.
7234 ///
7235 /// @param underlying the underlying diff of the @ref typedef_diff.
7236 /// That is the diff between the underlying types of @p first and @p
7237 /// second.
7238 ///
7239 /// @param ctxt the context of the diff.  Note that this context
7240 /// object must stay alive at least during the life time of the
7241 /// current instance of @ref typedef_diff.  Otherwise memory
7242 /// corruption issues occur.
typedef_diff(const typedef_decl_sptr first,const typedef_decl_sptr second,const diff_sptr underlying,diff_context_sptr ctxt)7243 typedef_diff::typedef_diff(const typedef_decl_sptr	first,
7244 			   const typedef_decl_sptr	second,
7245 			   const diff_sptr		underlying,
7246 			   diff_context_sptr		ctxt)
7247   : type_diff_base(first, second, ctxt),
7248     priv_(new priv(underlying))
7249 {}
7250 
7251 /// Getter for the firt typedef_decl involved in the diff.
7252 ///
7253 /// @return the first subject of the diff.
7254 const typedef_decl_sptr
first_typedef_decl() const7255 typedef_diff::first_typedef_decl() const
7256 {return dynamic_pointer_cast<typedef_decl>(first_subject());}
7257 
7258 /// Getter for the second typedef_decl involved in the diff.
7259 ///
7260 /// @return the second subject of the diff.
7261 const typedef_decl_sptr
second_typedef_decl() const7262 typedef_diff::second_typedef_decl() const
7263 {return dynamic_pointer_cast<typedef_decl>(second_subject());}
7264 
7265 /// Getter for the diff between the two underlying types of the
7266 /// typedefs.
7267 ///
7268 /// @return the diff object reprensenting the difference between the
7269 /// two underlying types of the typedefs.
7270 const diff_sptr
underlying_type_diff() const7271 typedef_diff::underlying_type_diff() const
7272 {return priv_->underlying_type_diff_;}
7273 
7274 /// Setter for the diff between the two underlying types of the
7275 /// typedefs.
7276 ///
7277 /// @param d the new diff object reprensenting the difference between
7278 /// the two underlying types of the typedefs.
7279 void
underlying_type_diff(const diff_sptr d)7280 typedef_diff::underlying_type_diff(const diff_sptr d)
7281 {priv_->underlying_type_diff_ = d;}
7282 
7283 /// @return the pretty representation for the current instance of @ref
7284 /// typedef_diff.
7285 const string&
get_pretty_representation() const7286 typedef_diff::get_pretty_representation() const
7287 {
7288   if (diff::priv_->pretty_representation_.empty())
7289     {
7290       std::ostringstream o;
7291       o << "typedef_diff["
7292 	<< first_subject()->get_pretty_representation()
7293 	<< ", "
7294 	<< second_subject()->get_pretty_representation()
7295 	<< "]";
7296       diff::priv_->pretty_representation_ = o.str();
7297     }
7298   return diff::priv_->pretty_representation_;
7299 }
7300 
7301 /// Return true iff the current diff node carries a change.
7302 ///
7303 /// @return true iff the current diff node carries a change.
7304 bool
has_changes() const7305 typedef_diff::has_changes() const
7306 {
7307   decl_base_sptr second = second_typedef_decl();
7308   return !(*first_typedef_decl() == *second);
7309 }
7310 
7311 /// @return the kind of local change carried by the current diff node.
7312 /// The value returned is zero if the current node carries no local
7313 /// change.
7314 enum change_kind
has_local_changes() const7315 typedef_diff::has_local_changes() const
7316 {
7317   ir::change_kind k = ir::NO_CHANGE_KIND;
7318   if (!equals(*first_typedef_decl(), *second_typedef_decl(), &k))
7319     return k & ir::ALL_LOCAL_CHANGES_MASK;
7320   return ir::NO_CHANGE_KIND;
7321 }
7322 
7323 /// Reports the difference between the two subjects of the diff in a
7324 /// serialized form.
7325 ///
7326 /// @param out the output stream to emit the report to.
7327 ///
7328 /// @param indent the indentation string to use.
7329 void
report(ostream & out,const string & indent) const7330 typedef_diff::report(ostream& out, const string& indent) const
7331 {
7332   context()->get_reporter()->report(*this, out, indent);
7333 }
7334 
7335 /// Compute a diff between two typedef_decl.
7336 ///
7337 /// Note that the two types must have been created in the same @ref
7338 /// environment, otherwise, this function aborts.
7339 ///
7340 /// @param first a pointer to the first typedef_decl to consider.
7341 ///
7342 /// @param second a pointer to the second typedef_decl to consider.
7343 ///
7344 /// @param ctxt the diff context to use.
7345 ///
7346 /// @return a pointer to the the resulting typedef_diff.
7347 typedef_diff_sptr
compute_diff(const typedef_decl_sptr first,const typedef_decl_sptr second,diff_context_sptr ctxt)7348 compute_diff(const typedef_decl_sptr	first,
7349 	     const typedef_decl_sptr	second,
7350 	     diff_context_sptr		ctxt)
7351 {
7352   if (first && second)
7353     ABG_ASSERT(first->get_environment() == second->get_environment());
7354 
7355   diff_sptr d = compute_diff_for_types(first->get_underlying_type(),
7356 				       second->get_underlying_type(),
7357 				       ctxt);
7358   typedef_diff_sptr result(new typedef_diff(first, second, d, ctxt));
7359 
7360   ctxt->initialize_canonical_diff(result);
7361 
7362   return result;
7363 }
7364 
7365 /// Return the leaf underlying diff node of a @ref typedef_diff node.
7366 ///
7367 /// If the underlying diff node of a @ref typedef_diff node is itself
7368 /// a @ref typedef_diff node, then recursively look at the underlying
7369 /// diff nodes to get the first one that is not a a @ref typedef_diff
7370 /// node.  This is what a leaf underlying diff node means.
7371 ///
7372 /// Otherwise, if the underlying diff node of @ref typedef_diff is
7373 /// *NOT* a @ref typedef_diff node, then just return the underlying
7374 /// diff node.
7375 ///
7376 /// And if the diff node considered is not a @ref typedef_diff node,
7377 /// then just return it.
7378 ///
7379 /// @return the leaf underlying diff node of a @p diff.
7380 const diff*
get_typedef_diff_underlying_type_diff(const diff * diff)7381 get_typedef_diff_underlying_type_diff(const diff* diff)
7382 {
7383   const typedef_diff* d = dynamic_cast<const typedef_diff*>(diff);
7384   if (!d)
7385     return diff;
7386 
7387   if (const typedef_diff* deef =
7388       dynamic_cast<const typedef_diff*>(d->underlying_type_diff().get()))
7389     return get_typedef_diff_underlying_type_diff(deef);
7390 
7391   return d->underlying_type_diff().get();
7392 }
7393 
7394 // </typedef_diff stuff>
7395 
7396 // <translation_unit_diff stuff>
7397 
7398 /// Constructor for translation_unit_diff.
7399 ///
7400 /// @param first the first translation unit to consider for this diff.
7401 ///
7402 /// @param second the second translation unit to consider for this diff.
7403 ///
7404 /// @param ctxt the context of the diff.  Note that this context
7405 /// object must stay alive at least during the life time of the
7406 /// current instance of @ref translation_unit_diff.  Otherwise memory
7407 /// corruption issues occur.
translation_unit_diff(translation_unit_sptr first,translation_unit_sptr second,diff_context_sptr ctxt)7408 translation_unit_diff::translation_unit_diff(translation_unit_sptr first,
7409 					     translation_unit_sptr second,
7410 					     diff_context_sptr ctxt)
7411   : scope_diff(first->get_global_scope(), second->get_global_scope(), ctxt),
7412     priv_(new priv(first, second))
7413 {
7414 }
7415 
7416 /// Getter for the first translation unit of this diff.
7417 ///
7418 /// @return the first translation unit of this diff.
7419 const translation_unit_sptr
first_translation_unit() const7420 translation_unit_diff::first_translation_unit() const
7421 {return priv_->first_;}
7422 
7423 /// Getter for the second translation unit of this diff.
7424 ///
7425 /// @return the second translation unit of this diff.
7426 const translation_unit_sptr
second_translation_unit() const7427 translation_unit_diff::second_translation_unit() const
7428 {return priv_->second_;}
7429 
7430 /// Return true iff the current diff node carries a change.
7431 ///
7432 /// @return true iff the current diff node carries a change.
7433 bool
has_changes() const7434 translation_unit_diff::has_changes() const
7435 {return scope_diff::has_changes();}
7436 
7437 /// @return the kind of local change carried by the current diff node.
7438 /// The value returned is zero if the current node carries no local
7439 /// change.
7440 enum change_kind
has_local_changes() const7441 translation_unit_diff::has_local_changes() const
7442 {return ir::NO_CHANGE_KIND;}
7443 
7444 /// Report the diff in a serialized form.
7445 ///
7446 /// @param out the output stream to serialize the report to.
7447 ///
7448 /// @param indent the prefix to use as indentation for the report.
7449 void
report(ostream & out,const string & indent) const7450 translation_unit_diff::report(ostream& out, const string& indent) const
7451 {scope_diff::report(out, indent);}
7452 
7453 /// Compute the diff between two translation_units.
7454 ///
7455 /// Note that the two translation units must have been created in the
7456 /// same @ref environment, otherwise, this function aborts.
7457 ///
7458 /// @param first the first translation_unit to consider.
7459 ///
7460 /// @param second the second translation_unit to consider.
7461 ///
7462 /// @param ctxt the diff context to use.  If null, this function will
7463 /// create a new context and set to the diff object returned.
7464 ///
7465 /// @return the newly created diff object.
7466 translation_unit_diff_sptr
compute_diff(const translation_unit_sptr first,const translation_unit_sptr second,diff_context_sptr ctxt)7467 compute_diff(const translation_unit_sptr	first,
7468 	     const translation_unit_sptr	second,
7469 	     diff_context_sptr			ctxt)
7470 {
7471   ABG_ASSERT(first && second);
7472 
7473   ABG_ASSERT(first->get_environment() == second->get_environment());
7474 
7475   if (!ctxt)
7476     ctxt.reset(new diff_context);
7477 
7478   // TODO: handle first or second having empty contents.
7479   translation_unit_diff_sptr tu_diff(new translation_unit_diff(first, second,
7480 							       ctxt));
7481   scope_diff_sptr sc_diff = dynamic_pointer_cast<scope_diff>(tu_diff);
7482 
7483   compute_diff(static_pointer_cast<scope_decl>(first->get_global_scope()),
7484 	       static_pointer_cast<scope_decl>(second->get_global_scope()),
7485 	       sc_diff,
7486 	       ctxt);
7487 
7488   ctxt->initialize_canonical_diff(tu_diff);
7489 
7490   return tu_diff;
7491 }
7492 
7493 // </translation_unit_diff stuff>
7494 
7495 // <diff_maps stuff>
7496 
7497 /// The private data of the @ref diff_maps type.
7498 struct diff_maps::priv
7499 {
7500   string_diff_ptr_map type_decl_diff_map_;
7501   string_diff_ptr_map enum_diff_map_;
7502   string_diff_ptr_map class_diff_map_;
7503   string_diff_ptr_map union_diff_map_;
7504   string_diff_ptr_map typedef_diff_map_;
7505   string_diff_ptr_map array_diff_map_;
7506   string_diff_ptr_map reference_diff_map_;
7507   string_diff_ptr_map function_type_diff_map_;
7508   string_diff_ptr_map function_decl_diff_map_;
7509   string_diff_ptr_map var_decl_diff_map_;
7510   string_diff_ptr_map distinct_diff_map_;
7511   string_diff_ptr_map fn_parm_diff_map_;
7512   diff_artifact_set_map_type impacted_artifacts_map_;
7513 }; // end struct diff_maps::priv
7514 
7515 /// Default constructor of the @ref diff_maps type.
diff_maps()7516 diff_maps::diff_maps()
7517   : priv_(new diff_maps::priv())
7518 {}
7519 
7520 diff_maps::~diff_maps() = default;
7521 
7522 /// Getter of the map that contains basic type diffs.
7523 ///
7524 /// @return the map that contains basic type diffs.
7525 const string_diff_ptr_map&
get_type_decl_diff_map() const7526 diff_maps::get_type_decl_diff_map() const
7527 {return priv_->type_decl_diff_map_;}
7528 
7529 /// Getter of the map that contains basic type diffs.
7530 ///
7531 /// @return the map that contains basic type diffs.
7532 string_diff_ptr_map&
get_type_decl_diff_map()7533 diff_maps::get_type_decl_diff_map()
7534 {return priv_->type_decl_diff_map_;}
7535 
7536 /// Getter of the map that contains enum type diffs.
7537 ///
7538 /// @return the map that contains enum type diffs.
7539 const string_diff_ptr_map&
get_enum_diff_map() const7540 diff_maps::get_enum_diff_map() const
7541 {return priv_->enum_diff_map_;}
7542 
7543 /// Getter of the map that contains enum type diffs.
7544 ///
7545 /// @return the map that contains enum type diffs.
7546 string_diff_ptr_map&
get_enum_diff_map()7547 diff_maps::get_enum_diff_map()
7548 {return priv_->enum_diff_map_;}
7549 
7550 /// Getter of the map that contains class type diffs.
7551 ///
7552 /// @return the map that contains class type diffs.
7553 const string_diff_ptr_map&
get_class_diff_map() const7554 diff_maps::get_class_diff_map() const
7555 {return priv_->class_diff_map_;}
7556 
7557 /// Getter of the map that contains class type diffs.
7558 ///
7559 /// @return the map that contains class type diffs.
7560 string_diff_ptr_map&
get_class_diff_map()7561 diff_maps::get_class_diff_map()
7562 {return priv_->class_diff_map_;}
7563 
7564 /// Getter of the map that contains union type diffs.
7565 ///
7566 /// @return the map that contains union type diffs.
7567 const string_diff_ptr_map&
get_union_diff_map() const7568 diff_maps::get_union_diff_map() const
7569 {return priv_->union_diff_map_;}
7570 
7571 /// Getter of the map that contains union type diffs.
7572 ///
7573 /// @return the map that contains union type diffs.
7574 string_diff_ptr_map&
get_union_diff_map()7575 diff_maps::get_union_diff_map()
7576 {return priv_->union_diff_map_;}
7577 
7578 /// Getter of the map that contains typedef type diffs.
7579 ///
7580 /// @return the map that contains typedef type diffs.
7581 const string_diff_ptr_map&
get_typedef_diff_map() const7582 diff_maps::get_typedef_diff_map() const
7583 {return priv_->typedef_diff_map_;}
7584 
7585 /// Getter of the map that contains typedef type diffs.
7586 ///
7587 /// @return the map that contains typedef type diffs.
7588 string_diff_ptr_map&
get_typedef_diff_map()7589 diff_maps::get_typedef_diff_map()
7590 {return priv_->typedef_diff_map_;}
7591 
7592 /// Getter of the map that contains array type diffs.
7593 ///
7594 /// @return the map that contains array type diffs.
7595 const string_diff_ptr_map&
get_array_diff_map() const7596 diff_maps::get_array_diff_map() const
7597 {return priv_->array_diff_map_;}
7598 
7599 /// Getter of the map that contains array type diffs.
7600 ///
7601 /// @return the map that contains array type diffs.
7602 string_diff_ptr_map&
get_array_diff_map()7603 diff_maps::get_array_diff_map()
7604 {return priv_->array_diff_map_;}
7605 
7606 /// Getter of the map that contains reference type diffs.
7607 ///
7608 /// @return the map that contains reference type diffs.
7609 const string_diff_ptr_map&
get_reference_diff_map() const7610 diff_maps::get_reference_diff_map() const
7611 {return priv_->reference_diff_map_;}
7612 
7613 /// Getter of the map that contains reference type diffs.
7614 ///
7615 /// @return the map that contains reference type diffs.
7616 string_diff_ptr_map&
get_reference_diff_map()7617 diff_maps::get_reference_diff_map()
7618 {{return priv_->reference_diff_map_;}}
7619 
7620 /// Getter of the map that contains function parameter diffs.
7621 ///
7622 /// @return the map that contains function parameter diffs.
7623 const string_diff_ptr_map&
get_fn_parm_diff_map() const7624 diff_maps::get_fn_parm_diff_map() const
7625 {return priv_->fn_parm_diff_map_;}
7626 
7627 /// Getter of the map that contains function parameter diffs.
7628 ///
7629 /// @return the map that contains function parameter diffs.
7630 string_diff_ptr_map&
get_fn_parm_diff_map()7631 diff_maps::get_fn_parm_diff_map()
7632 {return priv_->fn_parm_diff_map_;}
7633 
7634 /// Getter of the map that contains function type diffs.
7635 ///
7636 /// @return the map that contains function type diffs.
7637 const string_diff_ptr_map&
get_function_type_diff_map() const7638 diff_maps::get_function_type_diff_map() const
7639 {return priv_->function_type_diff_map_;}
7640 
7641 /// Getter of the map that contains function type diffs.
7642 ///
7643 /// @return the map that contains function type diffs.
7644 string_diff_ptr_map&
get_function_type_diff_map()7645 diff_maps::get_function_type_diff_map()
7646 {return priv_->function_type_diff_map_;}
7647 
7648 /// Getter of the map that contains function decl diffs.
7649 ///
7650 /// @return the map that contains function decl diffs.
7651 const string_diff_ptr_map&
get_function_decl_diff_map() const7652 diff_maps::get_function_decl_diff_map() const
7653 {return priv_->function_decl_diff_map_;}
7654 
7655 /// Getter of the map that contains function decl diffs.
7656 ///
7657 /// @return the map that contains function decl diffs.
7658 string_diff_ptr_map&
get_function_decl_diff_map()7659 diff_maps::get_function_decl_diff_map()
7660 {return priv_->function_decl_diff_map_;}
7661 
7662 /// Getter of the map that contains var decl diffs.
7663 ///
7664 /// @return the map that contains var decl diffs.
7665 const string_diff_ptr_map&
get_var_decl_diff_map() const7666 diff_maps::get_var_decl_diff_map() const
7667 {return priv_->var_decl_diff_map_;}
7668 
7669 /// Getter of the map that contains var decl diffs.
7670 ///
7671 /// @return the map that contains var decl diffs.
7672 string_diff_ptr_map&
get_var_decl_diff_map()7673 diff_maps::get_var_decl_diff_map()
7674 {return priv_->var_decl_diff_map_;}
7675 
7676 /// Getter of the map that contains distinct diffs.
7677 ///
7678 /// @return the map that contains distinct diffs.
7679 const string_diff_ptr_map&
get_distinct_diff_map() const7680 diff_maps::get_distinct_diff_map() const
7681 {return priv_->distinct_diff_map_;}
7682 
7683 /// Getter of the map that contains distinct diffs.
7684 ///
7685 /// @return the map that contains distinct diffs.
7686 string_diff_ptr_map&
get_distinct_diff_map()7687 diff_maps::get_distinct_diff_map()
7688 {return priv_->distinct_diff_map_;}
7689 
7690 /// Insert a new diff node into the current instance of @ref diff_maps.
7691 ///
7692 /// @param dif the new diff node to insert into the @ref diff_maps.
7693 ///
7694 /// @param impacted_iface the interface (global function or variable)
7695 /// currently being analysed that led to analysing the diff node @p
7696 /// dif.  In other words, this is the interface impacted by the diff
7697 /// node @p dif.  Note that this can be nil in cases where we are
7698 /// directly analysing changes to a type that is not reachable from
7699 /// any global function or variable.
7700 ///
7701 /// @return true iff the diff node could be added to the current
7702 /// instance of @ref diff_maps.
7703 bool
insert_diff_node(const diff * dif,const type_or_decl_base_sptr & impacted_iface)7704 diff_maps::insert_diff_node(const diff *dif,
7705 			    const type_or_decl_base_sptr& impacted_iface)
7706 {
7707   string n = get_pretty_representation(dif->first_subject(),
7708 				       /*internal=*/true);
7709   if (const type_decl_diff *d = is_diff_of_basic_type(dif))
7710     get_type_decl_diff_map()[n] = const_cast<type_decl_diff*>(d);
7711   else if (const enum_diff *d = is_enum_diff(dif))
7712     get_enum_diff_map()[n] = const_cast<enum_diff*>(d);
7713   else if (const class_diff *d = is_class_diff(dif))
7714       get_class_diff_map()[n] = const_cast<class_diff*>(d);
7715   else if (const union_diff *d = is_union_diff(dif))
7716     get_union_diff_map()[n] = const_cast<union_diff*>(d);
7717   else if (const typedef_diff *d = is_typedef_diff(dif))
7718     get_typedef_diff_map()[n] = const_cast<typedef_diff*>(d);
7719   else if (const array_diff *d = is_array_diff(dif))
7720       get_array_diff_map()[n] = const_cast<array_diff*>(d);
7721   else if (const reference_diff *d = is_reference_diff(dif))
7722     get_reference_diff_map()[n] = const_cast<reference_diff*>(d);
7723   else if (const fn_parm_diff *d = is_fn_parm_diff(dif))
7724     get_fn_parm_diff_map()[n] = const_cast<fn_parm_diff*>(d);
7725   else if (const function_type_diff *d = is_function_type_diff(dif))
7726     get_function_type_diff_map()[n] = const_cast<function_type_diff*>(d);
7727   else if (const var_diff *d = is_var_diff(dif))
7728     get_var_decl_diff_map()[n] = const_cast<var_diff*>(d);
7729   else if (const function_decl_diff *d = is_function_decl_diff(dif))
7730     get_function_decl_diff_map()[n] = const_cast<function_decl_diff*>(d);
7731   else if (const distinct_diff *d = is_distinct_diff(dif))
7732     get_distinct_diff_map()[n] = const_cast<distinct_diff*>(d);
7733   else if (is_base_diff(dif))
7734     // we silently drop this case.
7735     return true;
7736   else
7737       ABG_ASSERT_NOT_REACHED;
7738 
7739   // Update the map that associates this diff node to the set of
7740   // interfaces it impacts.
7741 
7742   if (impacted_iface)
7743     {
7744       diff_artifact_set_map_type::iterator i =
7745 	priv_->impacted_artifacts_map_.find(dif);
7746 
7747       if (i == priv_->impacted_artifacts_map_.end())
7748 	{
7749 	  artifact_sptr_set_type set;
7750 	  set.insert(impacted_iface);
7751 	  priv_->impacted_artifacts_map_[dif] = set;
7752 	}
7753       else
7754 	i->second.insert(impacted_iface);
7755     }
7756 
7757   return true;
7758 }
7759 
7760 /// Lookup the interfaces that are impacted by a given leaf diff node.
7761 ///
7762 /// @param d the diff node to consider.
7763 ///
7764 /// @return the set of artifacts impacted by @p d.
7765 artifact_sptr_set_type*
lookup_impacted_interfaces(const diff * d) const7766 diff_maps::lookup_impacted_interfaces(const diff *d) const
7767 {
7768   diff_artifact_set_map_type::iterator i =
7769     priv_->impacted_artifacts_map_.find(d);
7770 
7771   if (i == priv_->impacted_artifacts_map_.end())
7772     return 0;
7773 
7774   return &i->second;
7775 }
7776 
7777 //
7778 // </diff_maps stuff>
7779 
7780 /// Constructor for the @ref diff_stat type.
7781 ///
7782 /// @param ctxt the context of the corpus diff.  Note that this
7783 /// context object must stay alive at least during the life time of
7784 /// the current instance of @ref corpus_diff::diff_stats.  Otherwise
7785 /// memory corruption issues occur.
diff_stats(diff_context_sptr ctxt)7786 corpus_diff::diff_stats::diff_stats(diff_context_sptr ctxt)
7787   : priv_(new priv(ctxt))
7788 {}
7789 
7790 /// Getter for the number of functions removed.
7791 ///
7792 /// @return the number of functions removed.
7793 size_t
num_func_removed() const7794 corpus_diff::diff_stats::num_func_removed() const
7795 {return priv_->num_func_removed;}
7796 
7797 /// Setter for the number of functions removed.
7798 ///
7799 /// @param n the new number of functions removed.
7800 void
num_func_removed(size_t n)7801 corpus_diff::diff_stats::num_func_removed(size_t n)
7802 {priv_->num_func_removed = n;}
7803 
7804 /// Getter for the number of removed functions that have been filtered
7805 /// out.
7806 ///
7807 /// @return the number of removed functions that have been filtered
7808 /// out.
7809 size_t
num_removed_func_filtered_out() const7810 corpus_diff::diff_stats::num_removed_func_filtered_out() const
7811 {
7812   if (priv_->ctxt() && !priv_->ctxt()->show_deleted_fns())
7813     return num_func_removed();
7814   return priv_->num_removed_func_filtered_out;
7815 }
7816 
7817 /// Setter for the number of removed functions that have been filtered
7818 /// out.
7819 ///
7820 /// @param t the new value.
7821 void
num_removed_func_filtered_out(size_t t)7822 corpus_diff::diff_stats::num_removed_func_filtered_out(size_t t)
7823 {priv_->num_removed_func_filtered_out = t;}
7824 
7825 /// Getter for the net number of function removed.
7826 ///
7827 /// This is the difference between the number of functions removed and
7828 /// the number of functons removed that have been filtered out.
7829 ///
7830 /// @return the net number of function removed.
7831 size_t
net_num_func_removed() const7832 corpus_diff::diff_stats::net_num_func_removed() const
7833 {
7834   ABG_ASSERT(num_func_removed() >= num_removed_func_filtered_out());
7835   return num_func_removed() - num_removed_func_filtered_out();
7836 }
7837 
7838 /// Getter for the number of functions added.
7839 ///
7840 /// @return the number of functions added.
7841 size_t
num_func_added() const7842 corpus_diff::diff_stats::num_func_added() const
7843 {return priv_->num_func_added;}
7844 
7845 /// Setter for the number of functions added.
7846 ///
7847 /// @param n the new number of functions added.
7848 void
num_func_added(size_t n)7849 corpus_diff::diff_stats::num_func_added(size_t n)
7850 {priv_->num_func_added = n;}
7851 
7852 /// Getter for the number of added function that have been filtered out.
7853 ///
7854 /// @return the number of added function that have been filtered out.
7855 size_t
num_added_func_filtered_out() const7856 corpus_diff::diff_stats::num_added_func_filtered_out() const
7857 {
7858   if (priv_->ctxt() && !priv_->ctxt()->show_added_fns())
7859     return num_func_added();
7860   return priv_->num_added_func_filtered_out;
7861 }
7862 
7863 /// Setter for the number of added function that have been filtered
7864 /// out.
7865 ///
7866 /// @param n the new value.
7867 void
num_added_func_filtered_out(size_t n)7868 corpus_diff::diff_stats::num_added_func_filtered_out(size_t n)
7869 {priv_->num_added_func_filtered_out = n;}
7870 
7871 /// Getter for the net number of added functions.
7872 ///
7873 /// The net number of added functions is the difference between the
7874 /// number of added functions and the number of added functions that
7875 /// have been filtered out.
7876 ///
7877 /// @return the net number of added functions.
7878 size_t
net_num_func_added() const7879 corpus_diff::diff_stats::net_num_func_added() const
7880 {
7881   ABG_ASSERT(num_func_added() >= num_added_func_filtered_out());
7882   return num_func_added() - num_added_func_filtered_out();
7883 }
7884 
7885 /// Getter for the number of functions that have a change in one of
7886 /// their sub-types.
7887 ///
7888 /// @return the number of functions that have a change in one of their
7889 /// sub-types.
7890 size_t
num_func_changed() const7891 corpus_diff::diff_stats::num_func_changed() const
7892 {return priv_->num_func_changed;}
7893 
7894 /// Setter for the number of functions that have a change in one of
7895 /// their sub-types.
7896 ///
7897 /// @@param n the new number of functions that have a change in one of
7898 /// their sub-types.
7899 void
num_func_changed(size_t n)7900 corpus_diff::diff_stats::num_func_changed(size_t n)
7901 {priv_->num_func_changed = n;}
7902 
7903 /// Getter for the number of functions that have a change in one of
7904 /// their sub-types, and that have been filtered out.
7905 ///
7906 /// @return the number of functions that have a change in one of their
7907 /// sub-types, and that have been filtered out.
7908 size_t
num_changed_func_filtered_out() const7909 corpus_diff::diff_stats::num_changed_func_filtered_out() const
7910 {return priv_->num_changed_func_filtered_out;}
7911 
7912 /// Setter for the number of functions that have a change in one of
7913 /// their sub-types, and that have been filtered out.
7914 ///
7915 /// @param n the new number of functions that have a change in one of their
7916 /// sub-types, and that have been filtered out.
7917 void
num_changed_func_filtered_out(size_t n)7918 corpus_diff::diff_stats::num_changed_func_filtered_out(size_t n)
7919 {priv_->num_changed_func_filtered_out = n;}
7920 
7921 /// Getter for the number of functions that carry virtual member
7922 /// offset changes.
7923 ///
7924 /// @return the number of functions that carry virtual member changes.
7925 size_t
num_func_with_virtual_offset_changes() const7926 corpus_diff::diff_stats::num_func_with_virtual_offset_changes() const
7927 {return priv_->num_func_with_virt_offset_changes;}
7928 
7929 /// Setter for the number of functions that carry virtual member
7930 /// offset changes.
7931 ///
7932 /// @param n the new number of functions that carry virtual member
7933 /// offset.  changes.
7934 void
num_func_with_virtual_offset_changes(size_t n)7935 corpus_diff::diff_stats::num_func_with_virtual_offset_changes(size_t n)
7936 {priv_->num_func_with_virt_offset_changes = n;}
7937 
7938 /// Getter for the number of functions that have a change in their
7939 /// sub-types, minus the number of these functions that got filtered
7940 /// out from the diff.
7941 ///
7942 /// @return for the the number of functions that have a change in
7943 /// their sub-types, minus the number of these functions that got
7944 /// filtered out from the diff.
7945 size_t
net_num_func_changed() const7946 corpus_diff::diff_stats::net_num_func_changed() const
7947 {return num_func_changed() - num_changed_func_filtered_out();}
7948 
7949 /// Getter for the number of variables removed.
7950 ///
7951 /// @return the number of variables removed.
7952 size_t
num_vars_removed() const7953 corpus_diff::diff_stats::num_vars_removed() const
7954 {return priv_->num_vars_removed;}
7955 
7956 /// Setter for the number of variables removed.
7957 ///
7958 /// @param n the new number of variables removed.
7959 void
num_vars_removed(size_t n)7960 corpus_diff::diff_stats::num_vars_removed(size_t n)
7961 {priv_->num_vars_removed = n;}
7962 
7963 /// Getter for the number removed variables that have been filtered
7964 /// out.
7965 ///
7966 /// @return the number removed variables that have been filtered out.
7967 size_t
num_removed_vars_filtered_out() const7968 corpus_diff::diff_stats::num_removed_vars_filtered_out() const
7969 {
7970   if (priv_->ctxt() && !priv_->ctxt()->show_deleted_vars())
7971     return num_vars_removed();
7972   return priv_->num_removed_vars_filtered_out;
7973 }
7974 
7975 /// Setter for the number of removed variables that have been filtered
7976 /// out.
7977 ///
7978 /// @param n the new value.
7979 void
num_removed_vars_filtered_out(size_t n) const7980 corpus_diff::diff_stats::num_removed_vars_filtered_out(size_t n) const
7981 {priv_->num_removed_vars_filtered_out = n;}
7982 
7983 /// Getter for the net number of removed variables.
7984 ///
7985 /// The net number of removed variables is the difference between the
7986 /// number of removed variables and the number of removed variables
7987 /// that have been filtered out.
7988 ///
7989 /// @return the net number of removed variables.
7990 size_t
net_num_vars_removed() const7991 corpus_diff::diff_stats::net_num_vars_removed() const
7992 {
7993   ABG_ASSERT(num_vars_removed() >= num_removed_vars_filtered_out());
7994   return num_vars_removed() - num_removed_vars_filtered_out();
7995 }
7996 
7997 /// Getter for the number of variables added.
7998 ///
7999 /// @return the number of variables added.
8000 size_t
num_vars_added() const8001 corpus_diff::diff_stats::num_vars_added() const
8002 {return priv_->num_vars_added;}
8003 
8004 /// Setter for the number of variables added.
8005 ///
8006 /// @param n the new number of variables added.
8007 void
num_vars_added(size_t n)8008 corpus_diff::diff_stats::num_vars_added(size_t n)
8009 {priv_->num_vars_added = n;}
8010 
8011 /// Getter for the number of added variables that have been filtered
8012 /// out.
8013 ///
8014 /// @return the number of added variables that have been filtered out.
8015 size_t
num_added_vars_filtered_out() const8016 corpus_diff::diff_stats::num_added_vars_filtered_out() const
8017 {
8018   if (priv_->ctxt() && !priv_->ctxt()->show_added_vars())
8019     return num_vars_added();
8020   return priv_->num_added_vars_filtered_out;
8021 }
8022 
8023 /// Setter for the number of added variables that have been filtered
8024 /// out.
8025 ///
8026 /// @param n the new value.
8027 void
num_added_vars_filtered_out(size_t n)8028 corpus_diff::diff_stats::num_added_vars_filtered_out(size_t n)
8029 {priv_->num_added_vars_filtered_out = n;}
8030 
8031 /// Getter for the net number of added variables.
8032 ///
8033 /// The net number of added variables is the difference between the
8034 /// number of added variables and the number of added variables that
8035 /// have been filetered out.
8036 ///
8037 /// @return the net number of added variables.
8038 size_t
net_num_vars_added() const8039 corpus_diff::diff_stats::net_num_vars_added() const
8040 {
8041   ABG_ASSERT(num_vars_added() >= num_added_vars_filtered_out());
8042   return num_vars_added() - num_added_vars_filtered_out();
8043 }
8044 
8045 /// Getter for the number of variables that have a change in one of
8046 /// their sub-types.
8047 ///
8048 /// @return the number of variables that have a change in one of their
8049 /// sub-types.
8050 size_t
num_vars_changed() const8051 corpus_diff::diff_stats::num_vars_changed() const
8052 {return priv_->num_vars_changed;}
8053 
8054 /// Setter for the number of variables that have a change in one of
8055 /// their sub-types.
8056 ///
8057 /// @param n the new number of variables that have a change in one of
8058 /// their sub-types.
8059 void
num_vars_changed(size_t n)8060 corpus_diff::diff_stats::num_vars_changed(size_t n)
8061 {priv_->num_vars_changed = n;}
8062 
8063 /// Getter for the number of variables that have a change in one of
8064 /// their sub-types, and that have been filtered out.
8065 ///
8066 /// @return the number of functions that have a change in one of their
8067 /// sub-types, and that have been filtered out.
8068 size_t
num_changed_vars_filtered_out() const8069 corpus_diff::diff_stats::num_changed_vars_filtered_out() const
8070 {return priv_->num_changed_vars_filtered_out;}
8071 
8072 /// Setter for the number of variables that have a change in one of
8073 /// their sub-types, and that have been filtered out.
8074 ///
8075 /// @param n the new number of variables that have a change in one of their
8076 /// sub-types, and that have been filtered out.
8077 void
num_changed_vars_filtered_out(size_t n)8078 corpus_diff::diff_stats::num_changed_vars_filtered_out(size_t n)
8079 {priv_->num_changed_vars_filtered_out = n;}
8080 
8081 /// Getter for the number of variables that have a change in their
8082 /// sub-types, minus the number of these variables that got filtered
8083 /// out from the diff.
8084 ///
8085 /// @return for the the number of variables that have a change in
8086 /// their sub-types, minus the number of these variables that got
8087 /// filtered out from the diff.
8088 size_t
net_num_vars_changed() const8089 corpus_diff::diff_stats::net_num_vars_changed() const
8090 {return num_vars_changed() - num_changed_vars_filtered_out();}
8091 
8092 /// Getter for the number of function symbols (not referenced by any
8093 /// debug info) that got removed.
8094 ///
8095 /// @return the number of function symbols (not referenced by any
8096 /// debug info) that got removed.
8097 size_t
num_func_syms_removed() const8098 corpus_diff::diff_stats::num_func_syms_removed() const
8099 {return priv_->num_func_syms_removed;}
8100 
8101 /// Setter for the number of function symbols (not referenced by any
8102 /// debug info) that got removed.
8103 ///
8104 /// @param n the number of function symbols (not referenced by any
8105 /// debug info) that got removed.
8106 void
num_func_syms_removed(size_t n)8107 corpus_diff::diff_stats::num_func_syms_removed(size_t n)
8108 {priv_->num_func_syms_removed = n;}
8109 
8110 /// Getter for the number of removed function symbols, not referenced
8111 /// by debug info, that have been filtered out.
8112 ///
8113 /// @return the number of removed function symbols, not referenced by
8114 /// debug info, that have been filtered out.
8115 size_t
num_removed_func_syms_filtered_out() const8116 corpus_diff::diff_stats::num_removed_func_syms_filtered_out() const
8117 {
8118   if (priv_->ctxt()
8119       && !priv_->ctxt()->show_symbols_unreferenced_by_debug_info())
8120     return num_func_syms_removed();
8121   return priv_->num_removed_func_syms_filtered_out;
8122 }
8123 
8124 /// Setter for the number of removed function symbols, not referenced
8125 /// by debug info, that have been filtered out.
8126 ///
8127 /// @param n the new the number of removed function symbols, not
8128 /// referenced by debug info, that have been filtered out.
8129 void
num_removed_func_syms_filtered_out(size_t n)8130 corpus_diff::diff_stats::num_removed_func_syms_filtered_out(size_t n)
8131 {priv_->num_removed_func_syms_filtered_out = n;}
8132 
8133 /// Getter of the net number of removed function symbols that are not
8134 /// referenced by any debug info.
8135 ///
8136 /// This is the difference between the total number of removed
8137 /// function symbols and the number of removed function symbols that
8138 /// have been filteted out.  Both numbers are for symbols not
8139 /// referenced by debug info.
8140 ///
8141 /// return the net number of removed function symbols that are not
8142 /// referenced by any debug info.
8143 size_t
net_num_removed_func_syms() const8144 corpus_diff::diff_stats::net_num_removed_func_syms() const
8145 {
8146   ABG_ASSERT(num_func_syms_removed() >= num_removed_func_syms_filtered_out());
8147   return num_func_syms_removed() - num_removed_func_syms_filtered_out();
8148 }
8149 
8150 /// Getter for the number of function symbols (not referenced by any
8151 /// debug info) that got added.
8152 ///
8153 /// @return the number of function symbols (not referenced by any
8154 /// debug info) that got added.
8155 size_t
num_func_syms_added() const8156 corpus_diff::diff_stats::num_func_syms_added() const
8157 {return priv_->num_func_syms_added;}
8158 
8159 /// Setter for the number of function symbols (not referenced by any
8160 /// debug info) that got added.
8161 ///
8162 /// @param n the new number of function symbols (not referenced by any
8163 /// debug info) that got added.
8164 void
num_func_syms_added(size_t n)8165 corpus_diff::diff_stats::num_func_syms_added(size_t n)
8166 {priv_->num_func_syms_added = n;}
8167 
8168 /// Getter for the number of added function symbols, not referenced by
8169 /// any debug info, that have been filtered out.
8170 ///
8171 /// @return the number of added function symbols, not referenced by
8172 /// any debug info, that have been filtered out.
8173 size_t
num_added_func_syms_filtered_out() const8174 corpus_diff::diff_stats::num_added_func_syms_filtered_out() const
8175 {
8176   if (priv_->ctxt()
8177       && !(priv_->ctxt()->show_added_symbols_unreferenced_by_debug_info()
8178 	   && priv_->ctxt()->show_symbols_unreferenced_by_debug_info()))
8179     return num_func_syms_added();
8180   return priv_->num_added_func_syms_filtered_out;
8181 }
8182 
8183 /// Setter for the number of added function symbols, not referenced by
8184 /// any debug info, that have been filtered out.
8185 ///
8186 /// @param n the new number of added function symbols, not referenced
8187 /// by any debug info, that have been filtered out.
8188 void
num_added_func_syms_filtered_out(size_t n)8189 corpus_diff::diff_stats::num_added_func_syms_filtered_out(size_t n)
8190 {priv_->num_added_func_syms_filtered_out = n;}
8191 
8192 /// Getter of the net number of added function symbols that are not
8193 /// referenced by any debug info.
8194 ///
8195 /// This is the difference between the total number of added
8196 /// function symbols and the number of added function symbols that
8197 /// have been filteted out.  Both numbers are for symbols not
8198 /// referenced by debug info.
8199 ///
8200 /// return the net number of added function symbols that are not
8201 /// referenced by any debug info.
8202 size_t
net_num_added_func_syms() const8203 corpus_diff::diff_stats::net_num_added_func_syms() const
8204 {
8205   ABG_ASSERT(num_func_syms_added() >= num_added_func_syms_filtered_out());
8206   return num_func_syms_added()- num_added_func_syms_filtered_out();
8207 }
8208 
8209 /// Getter for the number of variable symbols (not referenced by any
8210 /// debug info) that got removed.
8211 ///
8212 /// @return the number of variable symbols (not referenced by any
8213 /// debug info) that got removed.
8214 size_t
num_var_syms_removed() const8215 corpus_diff::diff_stats::num_var_syms_removed() const
8216 {return priv_->num_var_syms_removed;}
8217 
8218 /// Setter for the number of variable symbols (not referenced by any
8219 /// debug info) that got removed.
8220 ///
8221 /// @param n the number of variable symbols (not referenced by any
8222 /// debug info) that got removed.
8223 void
num_var_syms_removed(size_t n)8224 corpus_diff::diff_stats::num_var_syms_removed(size_t n)
8225 {priv_->num_var_syms_removed = n;}
8226 
8227 /// Getter for the number of removed variable symbols, not referenced
8228 /// by any debug info, that have been filtered out.
8229 ///
8230 /// @return the number of removed variable symbols, not referenced
8231 /// by any debug info, that have been filtered out.
8232 size_t
num_removed_var_syms_filtered_out() const8233 corpus_diff::diff_stats::num_removed_var_syms_filtered_out() const
8234 {
8235   if (priv_->ctxt()
8236       && !priv_->ctxt()->show_symbols_unreferenced_by_debug_info())
8237     return num_var_syms_removed();
8238   return priv_->num_removed_var_syms_filtered_out;
8239 }
8240 
8241 /// Setter for the number of removed variable symbols, not referenced
8242 /// by any debug info, that have been filtered out.
8243 ///
8244 /// @param n the number of removed variable symbols, not referenced by
8245 /// any debug info, that have been filtered out.
8246 void
num_removed_var_syms_filtered_out(size_t n)8247 corpus_diff::diff_stats::num_removed_var_syms_filtered_out(size_t n)
8248 {priv_->num_removed_var_syms_filtered_out = n;}
8249 
8250 /// Getter of the net number of removed variable symbols that are not
8251 /// referenced by any debug info.
8252 ///
8253 /// This is the difference between the total number of removed
8254 /// variable symbols and the number of removed variable symbols that
8255 /// have been filteted out.  Both numbers are for symbols not
8256 /// referenced by debug info.
8257 ///
8258 /// return the net number of removed variable symbols that are not
8259 /// referenced by any debug info.
8260 size_t
net_num_removed_var_syms() const8261 corpus_diff::diff_stats::net_num_removed_var_syms() const
8262 {
8263   ABG_ASSERT(num_var_syms_removed() >= num_removed_var_syms_filtered_out());
8264   return num_var_syms_removed() - num_removed_var_syms_filtered_out();
8265 }
8266 
8267 /// Getter for the number of variable symbols (not referenced by any
8268 /// debug info) that got added.
8269 ///
8270 /// @return the number of variable symbols (not referenced by any
8271 /// debug info) that got added.
8272 size_t
num_var_syms_added() const8273 corpus_diff::diff_stats::num_var_syms_added() const
8274 {return priv_->num_var_syms_added;}
8275 
8276 /// Setter for the number of variable symbols (not referenced by any
8277 /// debug info) that got added.
8278 ///
8279 /// @param n the new number of variable symbols (not referenced by any
8280 /// debug info) that got added.
8281 void
num_var_syms_added(size_t n)8282 corpus_diff::diff_stats::num_var_syms_added(size_t n)
8283 {priv_->num_var_syms_added = n;}
8284 
8285 /// Getter for the number of added variable symbols, not referenced by
8286 /// any debug info, that have been filtered out.
8287 ///
8288 /// @return the number of added variable symbols, not referenced by
8289 /// any debug info, that have been filtered out.
8290 size_t
num_added_var_syms_filtered_out() const8291 corpus_diff::diff_stats::num_added_var_syms_filtered_out() const
8292 {
8293   if (priv_->ctxt()
8294       && !(priv_->ctxt()->show_added_symbols_unreferenced_by_debug_info()
8295 	   && priv_->ctxt()->show_symbols_unreferenced_by_debug_info()))
8296     return num_var_syms_added();
8297   return priv_->num_added_var_syms_filtered_out;
8298 }
8299 
8300 /// Setter for the number of added variable symbols, not referenced by
8301 /// any debug info, that have been filtered out.
8302 ///
8303 /// @param n the new number of added variable symbols, not referenced
8304 /// by any debug info, that have been filtered out.
8305 void
num_added_var_syms_filtered_out(size_t n)8306 corpus_diff::diff_stats::num_added_var_syms_filtered_out(size_t n)
8307 {priv_->num_added_var_syms_filtered_out = n;}
8308 
8309 /// Getter of the net number of added variable symbols that are not
8310 /// referenced by any debug info.
8311 ///
8312 /// This is the difference between the total number of added
8313 /// variable symbols and the number of added variable symbols that
8314 /// have been filteted out.  Both numbers are for symbols not
8315 /// referenced by debug info.
8316 ///
8317 /// return the net number of added variable symbols that are not
8318 /// referenced by any debug info.
8319 size_t
net_num_added_var_syms() const8320 corpus_diff::diff_stats::net_num_added_var_syms() const
8321 {
8322   ABG_ASSERT(num_var_syms_added() >= num_added_var_syms_filtered_out());
8323   return num_var_syms_added() - num_added_var_syms_filtered_out();
8324 }
8325 
8326 /// Getter of the number of leaf type change diff nodes.
8327 ///
8328 /// @return the number of leaf type change diff nodes.
8329 size_t
num_leaf_changes() const8330 corpus_diff::diff_stats::num_leaf_changes() const
8331 {return priv_->num_leaf_changes;}
8332 
8333 /// Setter of the number of leaf type change diff nodes.
8334 ///
8335 /// @param n the new number of leaf type change diff nodes.
8336 void
num_leaf_changes(size_t n)8337 corpus_diff::diff_stats::num_leaf_changes(size_t n)
8338 {priv_->num_leaf_changes = n;}
8339 
8340 /// Getter of the number of leaf type change diff nodes that have been
8341 /// filtered out.
8342 ///
8343 /// @return the number of leaf type change diff nodes that have been
8344 size_t
num_leaf_changes_filtered_out() const8345 corpus_diff::diff_stats::num_leaf_changes_filtered_out() const
8346 {return priv_->num_leaf_changes_filtered_out;}
8347 
8348 /// Setter of the number of leaf type change diff nodes that have been
8349 /// filtered out.
8350 ///
8351 /// @param n the new number of leaf type change diff nodes that have
8352 /// been filtered out.
8353 void
num_leaf_changes_filtered_out(size_t n)8354 corpus_diff::diff_stats::num_leaf_changes_filtered_out(size_t n)
8355 {priv_->num_leaf_changes_filtered_out = n;}
8356 
8357 /// Getter of the net number of leaf change diff nodes.
8358 ///
8359 /// This is the difference between the total number of leaf change
8360 /// diff nodes, and the number of the leaf change diff nodes that have
8361 /// been filtered out.
8362 ///
8363 /// A leaf change is either a type change, a function change or a
8364 /// variable change.
8365 size_t
net_num_leaf_changes() const8366 corpus_diff::diff_stats::net_num_leaf_changes() const
8367 {
8368   ABG_ASSERT(num_leaf_changes() >= num_leaf_changes_filtered_out());
8369   return num_leaf_changes() - num_leaf_changes_filtered_out();
8370 }
8371 
8372 /// Getter for the number of leaf type change diff nodes.
8373 ///
8374 /// @return the number of leaf type changes diff nodes.
8375 size_t
num_leaf_type_changes() const8376 corpus_diff::diff_stats::num_leaf_type_changes() const
8377 {return priv_->num_leaf_type_changes;}
8378 
8379 /// Setter for the number of leaf type change diff nodes.
8380 ///
8381 /// @param n the new number of leaf type change diff nodes.
8382 void
num_leaf_type_changes(size_t n)8383 corpus_diff::diff_stats::num_leaf_type_changes(size_t n)
8384 {priv_->num_leaf_type_changes = n;}
8385 
8386 /// Getter for the number of filtered out leaf type change diff nodes.
8387 ///
8388 /// @return the number of filtered out leaf type change diff nodes.
8389 size_t
num_leaf_type_changes_filtered_out() const8390 corpus_diff::diff_stats::num_leaf_type_changes_filtered_out() const
8391 {return priv_->num_leaf_type_changes_filtered_out;}
8392 
8393 /// Setter for the number of filtered out leaf type change diff nodes.
8394 /// @param n the new number of filtered out leaf type change diff nodes.
8395 void
num_leaf_type_changes_filtered_out(size_t n)8396 corpus_diff::diff_stats::num_leaf_type_changes_filtered_out(size_t n)
8397 {priv_->num_leaf_type_changes_filtered_out = n;}
8398 
8399 /// Getter for the net number of leaf type change diff nodes.
8400 ///
8401 /// This is the difference between the number of leaf type changes and
8402 /// the number of filtered out leaf type changes.
8403 ///
8404 /// @return the net number of leaf type change diff nodes.
8405 size_t
net_num_leaf_type_changes() const8406 corpus_diff::diff_stats::net_num_leaf_type_changes() const
8407 {return num_leaf_type_changes() - num_leaf_type_changes_filtered_out();}
8408 
8409 /// Getter for the number of leaf function change diff nodes.
8410 ///
8411 /// @return the number of leaf function change diff nodes.
8412 size_t
num_leaf_func_changes() const8413 corpus_diff::diff_stats::num_leaf_func_changes() const
8414 {return priv_->num_leaf_func_changes;}
8415 
8416 /// Setter for the number of leaf function change diff nodes.
8417 ///
8418 /// @param n the new number of leaf function change diff nodes.
8419 void
num_leaf_func_changes(size_t n)8420 corpus_diff::diff_stats::num_leaf_func_changes(size_t n)
8421 {priv_->num_leaf_func_changes = n;}
8422 
8423 /// Getter for the number of leaf function change diff nodes that were
8424 /// filtered out.
8425 ///
8426 /// @return the number of leaf function change diff nodes that were
8427 /// filtered out.
8428 size_t
num_leaf_func_changes_filtered_out() const8429 corpus_diff::diff_stats::num_leaf_func_changes_filtered_out() const
8430 {return priv_->num_leaf_func_changes_filtered_out;}
8431 
8432 /// Setter for the number of leaf function change diff nodes that were
8433 /// filtered out.
8434 ///
8435 /// @param n the new number of leaf function change diff nodes that
8436 /// were filtered out.
8437 void
num_leaf_func_changes_filtered_out(size_t n)8438 corpus_diff::diff_stats::num_leaf_func_changes_filtered_out(size_t n)
8439 {priv_->num_leaf_func_changes_filtered_out = n;}
8440 
8441 /// Getter for the net number of leaf function change diff nodes.
8442 ///
8443 /// This is the difference between the number of leaf function change
8444 /// diff nodes and the number of filtered out leaf function change
8445 /// diff nodes.
8446 ///
8447 /// @return the net number of leaf function change diff nodes.
8448 size_t
net_num_leaf_func_changes() const8449 corpus_diff::diff_stats::net_num_leaf_func_changes() const
8450 {return num_leaf_func_changes() - num_leaf_func_changes_filtered_out();}
8451 
8452 /// Getter for the number of leaf variable change diff nodes.
8453 ///
8454 /// @return the number of leaf variable change diff nodes.
8455 size_t
num_leaf_var_changes() const8456 corpus_diff::diff_stats::num_leaf_var_changes() const
8457 {return priv_->num_leaf_var_changes;}
8458 
8459 /// Setter for the number of leaf variable change diff nodes.
8460 ///
8461 /// @param n the number of leaf variable change diff nodes.
8462 void
num_leaf_var_changes(size_t n)8463 corpus_diff::diff_stats::num_leaf_var_changes(size_t n)
8464 {priv_->num_leaf_var_changes = n;}
8465 
8466 /// Getter of the number of added types that are unreachable from the
8467 /// public interface of the ABI corpus.
8468 ///
8469 /// Public interface means the set of defined and publicly exported
8470 /// functions and variables of the ABI corpus.
8471 ///
8472 /// @return the number of added types that are unreachable from the
8473 /// public interface of the ABI corpus.
8474 size_t
num_added_unreachable_types() const8475 corpus_diff::diff_stats::num_added_unreachable_types() const
8476 {return priv_->num_added_unreachable_types;}
8477 
8478 /// Setter of the number of added types that are unreachable from the
8479 /// public interface (global functions or variables) of the ABI
8480 /// corpus.
8481 ///
8482 /// Public interface means the set of defined and publicly exported
8483 /// functions and variables of the ABI corpus.
8484 ///
8485 /// @param n the new number of added types that are unreachable from
8486 /// the public interface of the ABI corpus.
8487 void
num_added_unreachable_types(size_t n)8488 corpus_diff::diff_stats::num_added_unreachable_types(size_t n)
8489 {priv_->num_added_unreachable_types = n;}
8490 
8491 /// Getter of the number of added types that are unreachable from
8492 /// public interfaces and that are filtered out by suppression
8493 /// specifications.
8494 ///
8495 /// @return the number of added types that are unreachable from public
8496 /// interfaces and that are filtered out by suppression
8497 /// specifications.
8498 size_t
num_added_unreachable_types_filtered_out() const8499 corpus_diff::diff_stats::num_added_unreachable_types_filtered_out() const
8500 {return priv_->num_added_unreachable_types_filtered_out;}
8501 
8502 /// Setter of the number of added types that are unreachable from
8503 /// public interfaces and that are filtered out by suppression
8504 /// specifications.
8505 ///
8506 /// @param n the new number of added types that are unreachable from
8507 /// public interfaces and that are filtered out by suppression
8508 /// specifications.
8509 void
num_added_unreachable_types_filtered_out(size_t n)8510 corpus_diff::diff_stats::num_added_unreachable_types_filtered_out(size_t n)
8511 {priv_->num_added_unreachable_types_filtered_out = n;}
8512 
8513 /// Getter of the number of added types that are unreachable from
8514 /// public interfaces and that are *NOT* filtered out by suppression
8515 /// specifications.
8516 ///
8517 /// @return the number of added types that are unreachable from public
8518 /// interfaces and that are *NOT* filtered out by suppression
8519 /// specifications.
8520 size_t
net_num_added_unreachable_types() const8521 corpus_diff::diff_stats::net_num_added_unreachable_types() const
8522 {
8523   ABG_ASSERT(num_added_unreachable_types()
8524 	     >=
8525 	     num_added_unreachable_types_filtered_out());
8526 
8527   return (num_added_unreachable_types()
8528 	  -
8529 	  num_added_unreachable_types_filtered_out());
8530 }
8531 
8532 /// Getter of the number of removed types that are unreachable from
8533 /// the public interface of the ABI corpus.
8534 ///
8535 /// Public interface means the set of defined and publicly exported
8536 /// functions and variables of the ABI corpus.
8537 ///
8538 /// @return the number of removed types that are unreachable from
8539 /// the public interface of the ABI corpus.
8540 size_t
num_removed_unreachable_types() const8541 corpus_diff::diff_stats::num_removed_unreachable_types() const
8542 {return priv_->num_removed_unreachable_types;}
8543 
8544 /// Setter of the number of removed types that are unreachable from
8545 /// the public interface of the ABI corpus.
8546 ///
8547 /// Public interface means the set of defined and publicly exported
8548 /// functions and variables of the ABI corpus.
8549 ///
8550 ///@param n the new number of removed types that are unreachable from
8551 /// the public interface of the ABI corpus.
8552 void
num_removed_unreachable_types(size_t n)8553 corpus_diff::diff_stats::num_removed_unreachable_types(size_t n)
8554 {priv_->num_removed_unreachable_types = n;}
8555 
8556 /// Getter of the number of removed types that are not reachable from
8557 /// public interfaces and that have been filtered out by suppression
8558 /// specifications.
8559 ///
8560 /// @return the number of removed types that are not reachable from
8561 /// public interfaces and that have been filtered out by suppression
8562 /// specifications.
8563 size_t
num_removed_unreachable_types_filtered_out() const8564 corpus_diff::diff_stats::num_removed_unreachable_types_filtered_out() const
8565 {return priv_->num_removed_unreachable_types_filtered_out;}
8566 
8567 /// Setter of the number of removed types that are not reachable from
8568 /// public interfaces and that have been filtered out by suppression
8569 /// specifications.
8570 ///
8571 /// @param n the new number of removed types that are not reachable
8572 /// from public interfaces and that have been filtered out by
8573 /// suppression specifications.
8574 void
num_removed_unreachable_types_filtered_out(size_t n)8575 corpus_diff::diff_stats::num_removed_unreachable_types_filtered_out(size_t n)
8576 {priv_->num_removed_unreachable_types_filtered_out = n;}
8577 
8578 /// Getter of the number of removed types that are not reachable from
8579 /// public interfaces and that have *NOT* been filtered out by
8580 /// suppression specifications.
8581 ///
8582 /// @return the number of removed types that are not reachable from
8583 /// public interfaces and that have *NOT* been filtered out by
8584 /// suppression specifications.
8585 size_t
net_num_removed_unreachable_types() const8586 corpus_diff::diff_stats::net_num_removed_unreachable_types() const
8587 {
8588   ABG_ASSERT(num_removed_unreachable_types()
8589 	     >=
8590 	     num_removed_unreachable_types_filtered_out());
8591 
8592   return (num_removed_unreachable_types()
8593 	  -
8594 	  num_removed_unreachable_types_filtered_out());
8595 }
8596 
8597 /// Getter of the number of changed types that are unreachable from
8598 /// the public interface of the ABI corpus.
8599 ///
8600 /// Public interface means the set of defined and publicly exported
8601 /// functions and variables of the ABI corpus.
8602 ///
8603 /// @return the number of changed types that are unreachable from the
8604 /// public interface of the ABI corpus.
8605 size_t
num_changed_unreachable_types() const8606 corpus_diff::diff_stats::num_changed_unreachable_types() const
8607 {return priv_->num_changed_unreachable_types;}
8608 
8609 /// Setter of the number of changed types that are unreachable from
8610 /// the public interface of the ABI corpus.
8611 ///
8612 /// Public interface means the set of defined and publicly exported
8613 /// functions and variables of the ABI corpus.
8614 ///
8615 ///@param n the new number of changed types that are unreachable from
8616 /// the public interface of the ABI corpus.
8617 void
num_changed_unreachable_types(size_t n)8618 corpus_diff::diff_stats::num_changed_unreachable_types(size_t n)
8619 {priv_->num_changed_unreachable_types = n;}
8620 
8621 /// Getter of the number of changed types that are unreachable from
8622 /// public interfaces and that have been filtered out by suppression
8623 /// specifications.
8624 ///
8625 /// @return the number of changed types that are unreachable from
8626 /// public interfaces and that have been filtered out by suppression
8627 /// specifications.
8628 size_t
num_changed_unreachable_types_filtered_out() const8629 corpus_diff::diff_stats::num_changed_unreachable_types_filtered_out() const
8630 {return priv_->num_changed_unreachable_types_filtered_out;}
8631 
8632 /// Setter of the number of changed types that are unreachable from
8633 /// public interfaces and that have been filtered out by suppression
8634 /// specifications.
8635 ///
8636 /// @param n the new number of changed types that are unreachable from
8637 /// public interfaces and that have been filtered out by suppression
8638 /// specifications.
8639 void
num_changed_unreachable_types_filtered_out(size_t n)8640 corpus_diff::diff_stats::num_changed_unreachable_types_filtered_out(size_t n)
8641 {priv_->num_changed_unreachable_types_filtered_out = n;}
8642 
8643 /// Getter of the number of changed types that are unreachable from
8644 /// public interfaces and that have *NOT* been filtered out by
8645 /// suppression specifications.
8646 ///
8647 /// @return the number of changed types that are unreachable from
8648 /// public interfaces and that have *NOT* been filtered out by
8649 /// suppression specifications.
8650 size_t
net_num_changed_unreachable_types() const8651 corpus_diff::diff_stats::net_num_changed_unreachable_types() const
8652 {
8653   ABG_ASSERT(num_changed_unreachable_types()
8654 	     >=
8655 	     num_changed_unreachable_types_filtered_out());
8656 
8657   return (num_changed_unreachable_types()
8658 	  -
8659 	  num_changed_unreachable_types_filtered_out());
8660 }
8661 
8662 /// Getter for the number of leaf variable changes diff nodes that
8663 /// have been filtered out.
8664 ///
8665 /// @return the number of leaf variable changes diff nodes that have
8666 /// been filtered out.
8667 size_t
num_leaf_var_changes_filtered_out() const8668 corpus_diff::diff_stats::num_leaf_var_changes_filtered_out() const
8669 {return priv_->num_leaf_var_changes_filtered_out;}
8670 
8671 /// Setter for the number of leaf variable changes diff nodes that
8672 /// have been filtered out.
8673 ///
8674 /// @param n the number of leaf variable changes diff nodes that have
8675 /// been filtered out.
8676 void
num_leaf_var_changes_filtered_out(size_t n)8677 corpus_diff::diff_stats::num_leaf_var_changes_filtered_out(size_t n)
8678 {priv_->num_leaf_var_changes_filtered_out = n;}
8679 
8680 /// Getter for the net number of leaf variable change diff nodes.
8681 ///
8682 /// This the difference between the number of leaf variable change
8683 /// diff nodes and the number of filtered out leaf variable change
8684 /// diff nodes.
8685 ///
8686 /// @return the net number of leaf variable change diff nodes.
8687 size_t
net_num_leaf_var_changes() const8688 corpus_diff::diff_stats::net_num_leaf_var_changes() const
8689 {return num_leaf_var_changes() - num_leaf_var_changes_filtered_out();}
8690 
8691 
8692 // <corpus_diff stuff>
8693 
8694 /// Getter of the context associated with this corpus.
8695 ///
8696 /// @return a smart pointer to the context associate with the corpus.
8697 diff_context_sptr
get_context()8698 corpus_diff::priv::get_context()
8699 {return ctxt_.lock();}
8700 
8701 /// Tests if the lookup tables are empty.
8702 ///
8703 /// @return true if the lookup tables are empty, false otherwise.
8704 bool
lookup_tables_empty() const8705 corpus_diff::priv::lookup_tables_empty() const
8706 {
8707   return (deleted_fns_.empty()
8708 	  && added_fns_.empty()
8709 	  && changed_fns_map_.empty()
8710 	  && deleted_vars_.empty()
8711 	  && added_vars_.empty()
8712 	  && changed_vars_map_.empty());
8713 }
8714 
8715 /// Clear the lookup tables useful for reporting an enum_diff.
8716 void
clear_lookup_tables()8717 corpus_diff::priv::clear_lookup_tables()
8718 {
8719   deleted_fns_.clear();
8720   added_fns_.clear();
8721   changed_fns_map_.clear();
8722   deleted_vars_.clear();
8723   added_vars_.clear();
8724   changed_vars_map_.clear();
8725 }
8726 
8727 /// If the lookup tables are not yet built, walk the differences and
8728 /// fill the lookup tables.
8729 void
ensure_lookup_tables_populated()8730 corpus_diff::priv::ensure_lookup_tables_populated()
8731 {
8732   if (!lookup_tables_empty())
8733     return;
8734 
8735   diff_context_sptr ctxt = get_context();
8736 
8737   {
8738     edit_script& e = fns_edit_script_;
8739 
8740     for (vector<deletion>::const_iterator it = e.deletions().begin();
8741 	 it != e.deletions().end();
8742 	 ++it)
8743       {
8744 	unsigned i = it->index();
8745 	ABG_ASSERT(i < first_->get_functions().size());
8746 
8747 	function_decl* deleted_fn = first_->get_functions()[i];
8748 	string n = deleted_fn->get_id();
8749 	ABG_ASSERT(!n.empty());
8750 	// The below is commented out because there can be several
8751 	// functions with the same ID in the corpus.  So several
8752 	// functions with the same ID can be deleted.
8753 	// ABG_ASSERT(deleted_fns_.find(n) == deleted_fns_.end());
8754 	deleted_fns_[n] = deleted_fn;
8755       }
8756 
8757     for (vector<insertion>::const_iterator it = e.insertions().begin();
8758 	 it != e.insertions().end();
8759 	 ++it)
8760       {
8761 	for (vector<unsigned>::const_iterator iit =
8762 	       it->inserted_indexes().begin();
8763 	     iit != it->inserted_indexes().end();
8764 	     ++iit)
8765 	  {
8766 	    unsigned i = *iit;
8767 	    function_decl* added_fn = second_->get_functions()[i];
8768 	    string n = added_fn->get_id();
8769 	    ABG_ASSERT(!n.empty());
8770 	    // The below is commented out because there can be several
8771 	    // functions with the same ID in the corpus.  So several
8772 	    // functions with the same ID can be added.
8773 	    // ABG_ASSERT(added_fns_.find(n) == added_fns_.end());
8774 	    string_function_ptr_map::const_iterator j =
8775 	      deleted_fns_.find(n);
8776 	    if (j != deleted_fns_.end())
8777 	      {
8778 		function_decl_sptr f(j->second, noop_deleter());
8779 		function_decl_sptr s(added_fn, noop_deleter());
8780 		function_decl_diff_sptr d = compute_diff(f, s, ctxt);
8781 		if (*j->second != *added_fn)
8782 		  changed_fns_map_[j->first] = d;
8783 		deleted_fns_.erase(j);
8784 	      }
8785 	    else
8786 	      added_fns_[n] = added_fn;
8787 	  }
8788       }
8789     sort_string_function_decl_diff_sptr_map(changed_fns_map_, changed_fns_);
8790 
8791     // Now walk the allegedly deleted functions; check if their
8792     // underlying symbols are deleted as well; otherwise, consider
8793     // that the function in question hasn't been deleted.
8794 
8795     vector<string> to_delete;
8796     for (string_function_ptr_map::const_iterator i = deleted_fns_.begin();
8797 	 i != deleted_fns_.end();
8798 	 ++i)
8799       if (second_->lookup_function_symbol(*i->second->get_symbol()))
8800 	to_delete.push_back(i->first);
8801 
8802     for (vector<string>::const_iterator i = to_delete.begin();
8803 	 i != to_delete.end();
8804 	 ++i)
8805       deleted_fns_.erase(*i);
8806 
8807     // Do something similar for added functions.
8808 
8809     to_delete.clear();
8810     for (string_function_ptr_map::const_iterator i = added_fns_.begin();
8811 	 i != added_fns_.end();
8812 	 ++i)
8813       {
8814 	if (first_->lookup_function_symbol(*i->second->get_symbol()))
8815 	  to_delete.push_back(i->first);
8816 	else if (! i->second->get_symbol()->get_version().is_empty()
8817 		 && i->second->get_symbol()->get_version().is_default())
8818 	  // We are looking for a symbol that has a default version,
8819 	  // and which seems to be newly added.  Let's see if the same
8820 	  // symbol with *no* version was already present in the
8821 	  // former corpus.  If yes, then the symbol shouldn't be
8822 	  // considered as 'added'.
8823 	  {
8824 	    elf_symbol::version empty_version;
8825 	    if (first_->lookup_function_symbol(i->second->get_symbol()->get_name(),
8826 					       empty_version))
8827 	      to_delete.push_back(i->first);
8828 	  }
8829       }
8830 
8831     for (vector<string>::const_iterator i = to_delete.begin();
8832 	 i != to_delete.end();
8833 	 ++i)
8834       added_fns_.erase(*i);
8835   }
8836 
8837   {
8838     edit_script& e = vars_edit_script_;
8839 
8840     for (vector<deletion>::const_iterator it = e.deletions().begin();
8841 	 it != e.deletions().end();
8842 	 ++it)
8843       {
8844 	unsigned i = it->index();
8845 	ABG_ASSERT(i < first_->get_variables().size());
8846 
8847 	var_decl* deleted_var = first_->get_variables()[i];
8848 	string n = deleted_var->get_id();
8849 	ABG_ASSERT(!n.empty());
8850 	ABG_ASSERT(deleted_vars_.find(n) == deleted_vars_.end());
8851 	deleted_vars_[n] = deleted_var;
8852       }
8853 
8854     for (vector<insertion>::const_iterator it = e.insertions().begin();
8855 	 it != e.insertions().end();
8856 	 ++it)
8857       {
8858 	for (vector<unsigned>::const_iterator iit =
8859 	       it->inserted_indexes().begin();
8860 	     iit != it->inserted_indexes().end();
8861 	     ++iit)
8862 	  {
8863 	    unsigned i = *iit;
8864 	    var_decl* added_var = second_->get_variables()[i];
8865 	    string n = added_var->get_id();
8866 	    ABG_ASSERT(!n.empty());
8867 	    {
8868 	      string_var_ptr_map::const_iterator k = added_vars_.find(n);
8869 	      if ( k != added_vars_.end())
8870 		{
8871 		  ABG_ASSERT(is_member_decl(k->second)
8872 			 && get_member_is_static(k->second));
8873 		  continue;
8874 		}
8875 	    }
8876 	    string_var_ptr_map::const_iterator j =
8877 	      deleted_vars_.find(n);
8878 	    if (j != deleted_vars_.end())
8879 	      {
8880 		if (*j->second != *added_var)
8881 		  {
8882 		    var_decl_sptr f(j->second, noop_deleter());
8883 		    var_decl_sptr s(added_var, noop_deleter());
8884 		    changed_vars_map_[n] = compute_diff(f, s, ctxt);
8885 		  }
8886 		deleted_vars_.erase(j);
8887 	      }
8888 	    else
8889 	      added_vars_[n] = added_var;
8890 	  }
8891       }
8892     sort_string_var_diff_sptr_map(changed_vars_map_,
8893 				  sorted_changed_vars_);
8894 
8895     // Now walk the allegedly deleted variables; check if their
8896     // underlying symbols are deleted as well; otherwise consider
8897     // that the variable in question hasn't been deleted.
8898 
8899     vector<string> to_delete;
8900     for (string_var_ptr_map::const_iterator i = deleted_vars_.begin();
8901 	 i != deleted_vars_.end();
8902 	 ++i)
8903       if (second_->lookup_variable_symbol(*i->second->get_symbol()))
8904 	to_delete.push_back(i->first);
8905 
8906     for (vector<string>::const_iterator i = to_delete.begin();
8907 	 i != to_delete.end();
8908 	 ++i)
8909       deleted_vars_.erase(*i);
8910 
8911     // Do something similar for added variables.
8912 
8913     to_delete.clear();
8914     for (string_var_ptr_map::const_iterator i = added_vars_.begin();
8915 	 i != added_vars_.end();
8916 	 ++i)
8917       if (first_->lookup_variable_symbol(*i->second->get_symbol()))
8918 	to_delete.push_back(i->first);
8919       else if (! i->second->get_symbol()->get_version().is_empty()
8920 		 && i->second->get_symbol()->get_version().is_default())
8921 	// We are looking for a symbol that has a default version,
8922 	// and which seems to be newly added.  Let's see if the same
8923 	// symbol with *no* version was already present in the
8924 	// former corpus.  If yes, then the symbol shouldn't be
8925 	// considered as 'added'.
8926 	{
8927 	  elf_symbol::version empty_version;
8928 	  if (first_->lookup_variable_symbol(i->second->get_symbol()->get_name(),
8929 					     empty_version))
8930 	    to_delete.push_back(i->first);
8931 	}
8932 
8933     for (vector<string>::const_iterator i = to_delete.begin();
8934 	 i != to_delete.end();
8935 	 ++i)
8936       added_vars_.erase(*i);
8937   }
8938 
8939   // Massage the edit script for added/removed function symbols that
8940   // were not referenced by any debug info and turn them into maps of
8941   // {symbol_name, symbol}.
8942   {
8943     edit_script& e = unrefed_fn_syms_edit_script_;
8944     for (vector<deletion>::const_iterator it = e.deletions().begin();
8945 	 it != e.deletions().end();
8946 	 ++it)
8947       {
8948 	unsigned i = it->index();
8949 	ABG_ASSERT(i < first_->get_unreferenced_function_symbols().size());
8950 	elf_symbol_sptr deleted_sym =
8951 	  first_->get_unreferenced_function_symbols()[i];
8952 	if (!second_->lookup_function_symbol(*deleted_sym))
8953 	  deleted_unrefed_fn_syms_[deleted_sym->get_id_string()] = deleted_sym;
8954       }
8955 
8956     for (vector<insertion>::const_iterator it = e.insertions().begin();
8957 	 it != e.insertions().end();
8958 	 ++it)
8959       {
8960 	for (vector<unsigned>::const_iterator iit =
8961 	       it->inserted_indexes().begin();
8962 	     iit != it->inserted_indexes().end();
8963 	     ++iit)
8964 	  {
8965 	    unsigned i = *iit;
8966 	    ABG_ASSERT(i < second_->get_unreferenced_function_symbols().size());
8967 	    elf_symbol_sptr added_sym =
8968 	      second_->get_unreferenced_function_symbols()[i];
8969 	    if ((deleted_unrefed_fn_syms_.find(added_sym->get_id_string())
8970 		 == deleted_unrefed_fn_syms_.end()))
8971 	      {
8972 		if (!first_->lookup_function_symbol(*added_sym))
8973 		  {
8974 		    bool do_add = true;
8975 		    if (! added_sym->get_version().is_empty()
8976 			&& added_sym->get_version().is_default())
8977 		      {
8978 			// So added_seem has a default version.  If
8979 			// the former corpus had a symbol with the
8980 			// same name as added_sym but with *no*
8981 			// version, then added_sym shouldn't be
8982 			// considered as a newly added symbol.
8983 			elf_symbol::version empty_version;
8984 			if (first_->lookup_function_symbol(added_sym->get_name(),
8985 							   empty_version))
8986 			  do_add = false;
8987 		      }
8988 
8989 		    if (do_add)
8990 		      added_unrefed_fn_syms_[added_sym->get_id_string()] =
8991 			added_sym;
8992 		  }
8993 	      }
8994 	    else
8995 	      deleted_unrefed_fn_syms_.erase(added_sym->get_id_string());
8996 	  }
8997       }
8998   }
8999 
9000   // Massage the edit script for added/removed variable symbols that
9001   // were not referenced by any debug info and turn them into maps of
9002   // {symbol_name, symbol}.
9003   {
9004     edit_script& e = unrefed_var_syms_edit_script_;
9005     for (vector<deletion>::const_iterator it = e.deletions().begin();
9006 	 it != e.deletions().end();
9007 	 ++it)
9008       {
9009 	unsigned i = it->index();
9010 	ABG_ASSERT(i < first_->get_unreferenced_variable_symbols().size());
9011 	elf_symbol_sptr deleted_sym =
9012 	  first_->get_unreferenced_variable_symbols()[i];
9013 	if (!second_->lookup_variable_symbol(*deleted_sym))
9014 	  deleted_unrefed_var_syms_[deleted_sym->get_id_string()] = deleted_sym;
9015       }
9016 
9017     for (vector<insertion>::const_iterator it = e.insertions().begin();
9018 	 it != e.insertions().end();
9019 	 ++it)
9020       {
9021 	for (vector<unsigned>::const_iterator iit =
9022 	       it->inserted_indexes().begin();
9023 	     iit != it->inserted_indexes().end();
9024 	     ++iit)
9025 	  {
9026 	    unsigned i = *iit;
9027 	    ABG_ASSERT(i < second_->get_unreferenced_variable_symbols().size());
9028 	    elf_symbol_sptr added_sym =
9029 	      second_->get_unreferenced_variable_symbols()[i];
9030 	    if (deleted_unrefed_var_syms_.find(added_sym->get_id_string())
9031 		== deleted_unrefed_var_syms_.end())
9032 	      {
9033 		if (!first_->lookup_variable_symbol(*added_sym))
9034 		  {
9035 		    bool do_add = true;
9036 		    if (! added_sym->get_version().is_empty()
9037 			&& added_sym->get_version().is_default())
9038 		      {
9039 			// So added_seem has a default version.  If
9040 			// the former corpus had a symbol with the
9041 			// same name as added_sym but with *no*
9042 			// version, then added_sym shouldn't be
9043 			// considered as a newly added symbol.
9044 			elf_symbol::version empty_version;
9045 			if (first_->lookup_variable_symbol(added_sym->get_name(),
9046 							   empty_version))
9047 			  do_add = false;
9048 		      }
9049 
9050 		    if (do_add)
9051 		      added_unrefed_var_syms_[added_sym->get_id_string()] =
9052 			added_sym;
9053 		  }
9054 	      }
9055 	    else
9056 	      deleted_unrefed_var_syms_.erase(added_sym->get_id_string());
9057 	  }
9058       }
9059   }
9060 
9061   // Handle the unreachable_types_edit_script_
9062   {
9063     edit_script& e = unreachable_types_edit_script_;
9064 
9065     // Populate the map of deleted unreachable types from the
9066     // deletions of the edit script.
9067     for (vector<deletion>::const_iterator it = e.deletions().begin();
9068 	 it != e.deletions().end();
9069 	 ++it)
9070       {
9071 	unsigned i = it->index();
9072 	type_base_sptr t
9073 	  (first_->get_types_not_reachable_from_public_interfaces()[i]);
9074 
9075 	if (!is_user_defined_type(t))
9076 	  continue;
9077 
9078 	string repr = abigail::ir::get_pretty_representation(t, true);
9079 	deleted_unreachable_types_[repr] = t;
9080       }
9081 
9082     // Populate the map of added and change unreachable types from the
9083     // insertions of the edit script.
9084     for (vector<insertion>::const_iterator it = e.insertions().begin();
9085 	 it != e.insertions().end();
9086 	 ++it)
9087       {
9088 	for (vector<unsigned>::const_iterator iit =
9089 	       it->inserted_indexes().begin();
9090 	     iit != it->inserted_indexes().end();
9091 	     ++iit)
9092 	  {
9093 	    unsigned i = *iit;
9094 	    type_base_sptr t
9095 	      (second_->get_types_not_reachable_from_public_interfaces()[i]);
9096 
9097 	    if (!is_user_defined_type(t))
9098 	      continue;
9099 
9100 	    string repr = abigail::ir::get_pretty_representation(t, true);
9101 
9102 	    // Let's see if the inserted type we are looking at was
9103 	    // reported as deleted as well.
9104 	    //
9105 	    // If it's been deleted and a different version of it has
9106 	    // now been added, it means it's been *changed*.  In that
9107 	    // case we'll compute the diff of that change and store it
9108 	    // in the map of changed unreachable types.
9109 	    //
9110 	    // Otherwise, it means the type's been added so we'll add
9111 	    // it to the set of added unreachable types.
9112 
9113 	    string_type_base_sptr_map::const_iterator j =
9114 	      deleted_unreachable_types_.find(repr);
9115 	    if (j != deleted_unreachable_types_.end())
9116 	      {
9117 		// So there was another type of the same pretty
9118 		// representation which was reported as deleted.
9119 		// Let's see if they are different or not ...
9120 		decl_base_sptr old_type = is_decl(j->second);
9121 		decl_base_sptr new_type = is_decl(t);
9122 		if (old_type != new_type)
9123 		  {
9124 		    // The previously added type is different from this
9125 		    // one that is added.  That means the initial type
9126 		    // was changed.  Let's compute its diff and store it
9127 		    // as a changed type.
9128 		    diff_sptr d = compute_diff(old_type, new_type, ctxt);
9129 		    ABG_ASSERT(d->has_changes());
9130 		    changed_unreachable_types_[repr]= d;
9131 		  }
9132 
9133 		// In any case, the type was both deleted and added,
9134 		// so we cannot have it marked as being deleted.  So
9135 		// let's remove it from the deleted types.
9136 		deleted_unreachable_types_.erase(j);
9137 	      }
9138 	    else
9139 	      // The type wasn't previously reported as deleted, so
9140 	      // it's really added.
9141 	      added_unreachable_types_[repr] = t;
9142 	  }
9143       }
9144   }
9145 }
9146 
9147 /// Test if a change reports about a given @ref function_decl that is
9148 /// changed in a certain way is suppressed by a given suppression
9149 /// specifiation
9150 ///
9151 /// @param fn the @ref function_decl to consider.
9152 ///
9153 /// @param suppr the suppression specification to consider.
9154 ///
9155 /// @param k the kind of change that happened to @p fn.
9156 ///
9157 /// @param ctxt the context of the current diff.
9158 ///
9159 /// @return true iff the suppression specification @p suppr suppresses
9160 /// change reports about function @p fn, if that function changes in
9161 /// the way expressed by @p k.
9162 static bool
function_is_suppressed(const function_decl * fn,const suppression_sptr suppr,function_suppression::change_kind k,const diff_context_sptr ctxt)9163 function_is_suppressed(const function_decl* fn,
9164 		       const suppression_sptr suppr,
9165 		       function_suppression::change_kind k,
9166 		       const diff_context_sptr ctxt)
9167 {
9168   function_suppression_sptr fn_suppr = is_function_suppression(suppr);
9169   if (!fn_suppr)
9170     return false;
9171   return fn_suppr->suppresses_function(fn, k, ctxt);
9172 }
9173 
9174 /// Test if a change reports about a given @ref var_decl that is
9175 /// changed in a certain way is suppressed by a given suppression
9176 /// specifiation
9177 ///
9178 /// @param fn the @ref var_decl to consider.
9179 ///
9180 /// @param suppr the suppression specification to consider.
9181 ///
9182 /// @param k the kind of change that happened to @p fn.
9183 ///
9184 /// @param ctxt the context of the current diff.
9185 ///
9186 /// @return true iff the suppression specification @p suppr suppresses
9187 /// change reports about variable @p fn, if that variable changes in
9188 /// the way expressed by @p k.
9189 static bool
variable_is_suppressed(const var_decl * var,const suppression_sptr suppr,variable_suppression::change_kind k,const diff_context_sptr ctxt)9190 variable_is_suppressed(const var_decl* var,
9191 		       const suppression_sptr suppr,
9192 		       variable_suppression::change_kind k,
9193 		       const diff_context_sptr ctxt)
9194 {
9195   variable_suppression_sptr var_suppr = is_variable_suppression(suppr);
9196   if (!var_suppr)
9197     return false;
9198   return var_suppr->suppresses_variable(var, k, ctxt);
9199 }
9200 
9201 /// Apply suppression specifications for this corpus diff to the set
9202 /// of added/removed functions/variables, as well as to types not
9203 /// reachable from global functions/variables.
9204 void
apply_supprs_to_added_removed_fns_vars_unreachable_types()9205 corpus_diff::priv::apply_supprs_to_added_removed_fns_vars_unreachable_types()
9206 {
9207   diff_context_sptr ctxt = get_context();
9208 
9209   const suppressions_type& suppressions = ctxt->suppressions();
9210   for (suppressions_type::const_iterator i = suppressions.begin();
9211        i != suppressions.end();
9212        ++i)
9213     {
9214       // Added/Deleted functions.
9215       if (function_suppression_sptr fn_suppr = is_function_suppression(*i))
9216 	{
9217 	  // Added functions
9218 	  for (string_function_ptr_map::const_iterator e = added_fns_.begin();
9219 	       e != added_fns_.end();
9220 	       ++e)
9221 	    if (function_is_suppressed(e->second, fn_suppr,
9222 				       function_suppression::ADDED_FUNCTION_CHANGE_KIND,
9223 				       ctxt))
9224 	      suppressed_added_fns_[e->first] = e->second;
9225 
9226 	  // Deleted functions.
9227 	  for (string_function_ptr_map::const_iterator e = deleted_fns_.begin();
9228 	       e != deleted_fns_.end();
9229 	       ++e)
9230 	    if (function_is_suppressed(e->second, fn_suppr,
9231 				       function_suppression::DELETED_FUNCTION_CHANGE_KIND,
9232 				       ctxt))
9233 	      suppressed_deleted_fns_[e->first] = e->second;
9234 
9235 	  // Added function symbols not referenced by any debug info
9236 	  for (string_elf_symbol_map::const_iterator e =
9237 		 added_unrefed_fn_syms_.begin();
9238 	       e != added_unrefed_fn_syms_.end();
9239 	       ++e)
9240 	    if (fn_suppr->suppresses_function_symbol(e->second,
9241 						     function_suppression::ADDED_FUNCTION_CHANGE_KIND,
9242 						     ctxt))
9243 	      suppressed_added_unrefed_fn_syms_[e->first] = e->second;
9244 
9245 	  // Removed function symbols not referenced by any debug info
9246 	  for (string_elf_symbol_map::const_iterator e =
9247 		 deleted_unrefed_fn_syms_.begin();
9248 	       e != deleted_unrefed_fn_syms_.end();
9249 	       ++e)
9250 	    if (fn_suppr->suppresses_function_symbol(e->second,
9251 						     function_suppression::DELETED_FUNCTION_CHANGE_KIND,
9252 						     ctxt))
9253 	      suppressed_deleted_unrefed_fn_syms_[e->first] = e->second;
9254 	}
9255       // Added/Delete virtual member functions changes that might be
9256       // suppressed by a type_suppression that matches the enclosing
9257       // class of the virtual member function.
9258       else if (type_suppression_sptr type_suppr = is_type_suppression(*i))
9259 	{
9260 	  // Added virtual functions
9261 	  for (string_function_ptr_map::const_iterator e = added_fns_.begin();
9262 	       e != added_fns_.end();
9263 	       ++e)
9264 	    if (is_member_function(e->second)
9265 		&& get_member_function_is_virtual(e->second))
9266 	      {
9267 		function_decl *f = e->second;
9268 		class_decl_sptr c =
9269 		  is_class_type(is_method_type(f->get_type())->get_class_type());
9270 		ABG_ASSERT(c);
9271 		if (type_suppr->suppresses_type(c, ctxt))
9272 		  suppressed_added_fns_[e->first] = e->second;
9273 	      }
9274 	  // Deleted virtual functions
9275 	  for (string_function_ptr_map::const_iterator e = deleted_fns_.begin();
9276 	       e != deleted_fns_.end();
9277 	       ++e)
9278 	    if (is_member_function(e->second)
9279 		&& get_member_function_is_virtual(e->second))
9280 	      {
9281 		function_decl *f = e->second;
9282 		class_decl_sptr c =
9283 		  is_class_type(is_method_type(f->get_type())->get_class_type());
9284 		ABG_ASSERT(c);
9285 		if (type_suppr->suppresses_type(c, ctxt))
9286 		  suppressed_deleted_fns_[e->first] = e->second;
9287 	      }
9288 
9289 	  // Apply this type suppression to deleted types
9290 	  // non-reachable from a public interface.
9291 	  for (string_type_base_sptr_map::const_iterator e =
9292 		 deleted_unreachable_types_.begin();
9293 	       e != deleted_unreachable_types_.end();
9294 	       ++e)
9295 	    if (type_suppr->suppresses_type(e->second, ctxt))
9296 	      suppressed_deleted_unreachable_types_[e->first] = e->second;
9297 
9298 	  // Apply this type suppression to added types
9299 	  // non-reachable from a public interface.
9300 	  for (string_type_base_sptr_map::const_iterator e =
9301 		 added_unreachable_types_.begin();
9302 	       e != added_unreachable_types_.end();
9303 	       ++e)
9304 	    if (type_suppr->suppresses_type(e->second, ctxt))
9305 	      suppressed_added_unreachable_types_[e->first] = e->second;
9306 	}
9307       // Added/Deleted variables
9308       else if (variable_suppression_sptr var_suppr =
9309 	       is_variable_suppression(*i))
9310 	{
9311 	  // Added variables
9312 	  for (string_var_ptr_map::const_iterator e = added_vars_.begin();
9313 	       e != added_vars_.end();
9314 	       ++e)
9315 	    if (variable_is_suppressed(e->second, var_suppr,
9316 				       variable_suppression::ADDED_VARIABLE_CHANGE_KIND,
9317 				       ctxt))
9318 	      suppressed_added_vars_[e->first] = e->second;
9319 
9320 	  //Deleted variables
9321 	  for (string_var_ptr_map::const_iterator e = deleted_vars_.begin();
9322 	       e != deleted_vars_.end();
9323 	       ++e)
9324 	    if (variable_is_suppressed(e->second, var_suppr,
9325 				       variable_suppression::DELETED_VARIABLE_CHANGE_KIND,
9326 				       ctxt))
9327 	      suppressed_deleted_vars_[e->first] = e->second;
9328 
9329 	  // Added variable symbols not referenced by any debug info
9330 	  for (string_elf_symbol_map::const_iterator e =
9331 		 added_unrefed_var_syms_.begin();
9332 	       e != added_unrefed_var_syms_.end();
9333 	       ++e)
9334 	    if (var_suppr->suppresses_variable_symbol(e->second,
9335 						      variable_suppression::ADDED_VARIABLE_CHANGE_KIND,
9336 						      ctxt))
9337 	      suppressed_added_unrefed_var_syms_[e->first] = e->second;
9338 
9339 	  // Removed variable symbols not referenced by any debug info
9340 	  for (string_elf_symbol_map::const_iterator e =
9341 		 deleted_unrefed_var_syms_.begin();
9342 	       e != deleted_unrefed_var_syms_.end();
9343 	       ++e)
9344 	    if (var_suppr->suppresses_variable_symbol(e->second,
9345 						      variable_suppression::DELETED_VARIABLE_CHANGE_KIND,
9346 						      ctxt))
9347 	      suppressed_deleted_unrefed_var_syms_[e->first] = e->second;
9348 	}
9349     }
9350 }
9351 
9352 /// Test if the change reports for a given deleted function have
9353 /// been deleted.
9354 ///
9355 /// @param fn the function to consider.
9356 ///
9357 /// @return true iff the change reports for a give given deleted
9358 /// function have been deleted.
9359 bool
deleted_function_is_suppressed(const function_decl * fn) const9360 corpus_diff::priv::deleted_function_is_suppressed(const function_decl* fn) const
9361 {
9362   if (!fn)
9363     return false;
9364 
9365   string_function_ptr_map::const_iterator i =
9366     suppressed_deleted_fns_.find(fn->get_id());
9367 
9368   return (i != suppressed_deleted_fns_.end());
9369 }
9370 
9371 /// Test if an added type that is unreachable from public interface
9372 /// has been suppressed by a suppression specification.
9373 ///
9374 /// @param t the added unreachable type to be considered.
9375 ///
9376 /// @return true iff @p t has been suppressed by a suppression
9377 /// specification.
9378 bool
added_unreachable_type_is_suppressed(const type_base * t) const9379 corpus_diff::priv::added_unreachable_type_is_suppressed(const type_base *t)const
9380 {
9381   if (!t)
9382     return false;
9383 
9384   string repr = abigail::ir::get_pretty_representation(t, /*internal=*/true);
9385   string_type_base_sptr_map::const_iterator i =
9386     suppressed_added_unreachable_types_.find(repr);
9387   if (i == suppressed_added_unreachable_types_.end())
9388     return false;
9389 
9390   return true;
9391 }
9392 
9393 /// Test if a deleted type that is unreachable from public interface
9394 /// has been suppressed by a suppression specification.
9395 ///
9396 /// @param t the deleted unreachable type to be considered.
9397 ///
9398 /// @return true iff @p t has been suppressed by a suppression
9399 /// specification.
9400 bool
deleted_unreachable_type_is_suppressed(const type_base * t) const9401 corpus_diff::priv::deleted_unreachable_type_is_suppressed(const type_base *t) const
9402 {
9403   if (!t)
9404     return false;
9405 
9406   string repr = abigail::ir::get_pretty_representation(t, /*internal=*/true);
9407   string_type_base_sptr_map::const_iterator i =
9408     suppressed_deleted_unreachable_types_.find(repr);
9409   if (i == suppressed_deleted_unreachable_types_.end())
9410     return false;
9411 
9412   return true;
9413 }
9414 
9415 /// Test if the change reports for a give given added function has
9416 /// been deleted.
9417 ///
9418 /// @param fn the function to consider.
9419 ///
9420 /// @return true iff the change reports for a give given added
9421 /// function has been deleted.
9422 bool
added_function_is_suppressed(const function_decl * fn) const9423 corpus_diff::priv::added_function_is_suppressed(const function_decl* fn) const
9424 {
9425   if (!fn)
9426     return false;
9427 
9428   string_function_ptr_map::const_iterator i =
9429     suppressed_added_fns_.find(fn->get_id());
9430 
9431   return (i != suppressed_added_fns_.end());
9432 }
9433 
9434 /// Test if the change reports for a give given deleted variable has
9435 /// been deleted.
9436 ///
9437 /// @param var the variable to consider.
9438 ///
9439 /// @return true iff the change reports for a give given deleted
9440 /// variable has been deleted.
9441 bool
deleted_variable_is_suppressed(const var_decl * var) const9442 corpus_diff::priv::deleted_variable_is_suppressed(const var_decl* var) const
9443 {
9444   if (!var)
9445     return false;
9446 
9447   string_var_ptr_map::const_iterator i =
9448     suppressed_deleted_vars_.find(var->get_id());
9449 
9450   return (i != suppressed_deleted_vars_.end());
9451 }
9452 
9453 /// Test if the change reports for a given added variable have been
9454 /// suppressed.
9455 ///
9456 /// @param var the variable to consider.
9457 ///
9458 /// @return true iff the change reports for a given deleted
9459 /// variable has been deleted.
9460 bool
added_variable_is_suppressed(const var_decl * var) const9461 corpus_diff::priv::added_variable_is_suppressed(const var_decl* var) const
9462 {
9463   if (!var)
9464     return false;
9465 
9466   string_var_ptr_map::const_iterator i =
9467     suppressed_added_vars_.find(var->get_id());
9468 
9469   return (i != suppressed_added_vars_.end());
9470 }
9471 
9472 /// Test if the change reports for a given deleted function symbol
9473 /// (that is not referenced by any debug info) has been suppressed.
9474 ///
9475 /// @param var the function to consider.
9476 ///
9477 /// @return true iff the change reports for a given deleted function
9478 /// symbol has been suppressed.
9479 bool
deleted_unrefed_fn_sym_is_suppressed(const elf_symbol * s) const9480 corpus_diff::priv::deleted_unrefed_fn_sym_is_suppressed(const elf_symbol* s) const
9481 {
9482   if (!s)
9483     return false;
9484 
9485   string_elf_symbol_map::const_iterator i =
9486     suppressed_deleted_unrefed_fn_syms_.find(s->get_id_string());
9487 
9488   return (i != suppressed_deleted_unrefed_fn_syms_.end());
9489 }
9490 
9491 /// Test if the change reports for a given added function symbol
9492 /// (that is not referenced by any debug info) has been suppressed.
9493 ///
9494 /// @param var the function to consider.
9495 ///
9496 /// @return true iff the change reports for a given added function
9497 /// symbol has been suppressed.
9498 bool
added_unrefed_fn_sym_is_suppressed(const elf_symbol * s) const9499 corpus_diff::priv::added_unrefed_fn_sym_is_suppressed(const elf_symbol* s) const
9500 {
9501   if (!s)
9502     return false;
9503 
9504   string_elf_symbol_map::const_iterator i =
9505     suppressed_added_unrefed_fn_syms_.find(s->get_id_string());
9506 
9507   return (i != suppressed_added_unrefed_fn_syms_.end());
9508 }
9509 
9510 /// Test if the change reports for a given deleted variable symbol
9511 /// (that is not referenced by any debug info) has been suppressed.
9512 ///
9513 /// @param var the variable to consider.
9514 ///
9515 /// @return true iff the change reports for a given deleted variable
9516 /// symbol has been suppressed.
9517 bool
deleted_unrefed_var_sym_is_suppressed(const elf_symbol * s) const9518 corpus_diff::priv::deleted_unrefed_var_sym_is_suppressed(const elf_symbol* s) const
9519 {
9520   if (!s)
9521     return false;
9522 
9523   string_elf_symbol_map::const_iterator i =
9524     suppressed_deleted_unrefed_var_syms_.find(s->get_id_string());
9525 
9526   return (i != suppressed_deleted_unrefed_var_syms_.end());
9527 }
9528 
9529 /// Test if the change reports for a given added variable symbol
9530 /// (that is not referenced by any debug info) has been suppressed.
9531 ///
9532 /// @param var the variable to consider.
9533 ///
9534 /// @return true iff the change reports for a given added variable
9535 /// symbol has been suppressed.
9536 bool
added_unrefed_var_sym_is_suppressed(const elf_symbol * s) const9537 corpus_diff::priv::added_unrefed_var_sym_is_suppressed(const elf_symbol* s) const
9538 {
9539   if (!s)
9540     return false;
9541 
9542   string_elf_symbol_map::const_iterator i =
9543     suppressed_added_unrefed_var_syms_.find(s->get_id_string());
9544 
9545   return (i != suppressed_added_unrefed_var_syms_.end());
9546 }
9547 
9548 #ifdef do_count_diff_map_changes
9549 #undef do_count_diff_map_changes
9550 #endif
9551 #define do_count_diff_map_changes(diff_map, n_changes, n_filtered)	\
9552   {									\
9553     string_diff_ptr_map::const_iterator i;				\
9554     for (i = diff_map.begin();						\
9555 	 i != diff_map.end();						\
9556 	 ++i)								\
9557       { \
9558 	if (const var_diff* d = is_var_diff(i->second))		\
9559 	  if (is_data_member(d->first_var()))				\
9560 	    continue;							\
9561 									\
9562 	if (i->second->has_local_changes())				\
9563 	  ++n_changes;							\
9564 	if (!i->second->get_canonical_diff()->to_be_reported())		\
9565 	  ++n_filtered;						\
9566       }								\
9567   }
9568 
9569 /// Count the number of leaf changes as well as the number of the
9570 /// changes that have been filtered out.
9571 ///
9572 /// @param num_changes out parameter.  This is set to the total number
9573 /// of leaf changes.
9574 ///
9575 /// @param num_filtered out parameter.  This is set to the number of
9576 /// leaf changes that have been filtered out.
9577 void
count_leaf_changes(size_t & num_changes,size_t & num_filtered)9578 corpus_diff::priv::count_leaf_changes(size_t &num_changes, size_t &num_filtered)
9579 {
9580   count_leaf_type_changes(num_changes, num_filtered);
9581 
9582   // Now count the non-type changes.
9583   do_count_diff_map_changes(leaf_diffs_.get_function_decl_diff_map(),
9584     num_changes, num_filtered);
9585   do_count_diff_map_changes(leaf_diffs_.get_var_decl_diff_map(),
9586     num_changes, num_filtered);
9587 }
9588 
9589 /// Count the number of leaf *type* changes as well as the number of
9590 /// the leaf type changes that have been filtered out.
9591 ///
9592 /// @param num_changes out parameter.  This is set to the total number
9593 /// of leaf type changes.
9594 ///
9595 /// @param num_filtered out parameter.  This is set to the number of
9596 /// leaf type changes that have been filtered out.
9597 void
count_leaf_type_changes(size_t & num_changes,size_t & num_filtered)9598 corpus_diff::priv::count_leaf_type_changes(size_t &num_changes,
9599 					   size_t &num_filtered)
9600 {
9601   do_count_diff_map_changes(leaf_diffs_.get_type_decl_diff_map(),
9602     num_changes, num_filtered);
9603   do_count_diff_map_changes(leaf_diffs_.get_enum_diff_map(),
9604     num_changes, num_filtered);
9605   do_count_diff_map_changes(leaf_diffs_.get_class_diff_map(),
9606     num_changes, num_filtered);
9607   do_count_diff_map_changes(leaf_diffs_.get_union_diff_map(),
9608     num_changes, num_filtered);
9609   do_count_diff_map_changes(leaf_diffs_.get_typedef_diff_map(),
9610     num_changes, num_filtered);
9611   do_count_diff_map_changes(leaf_diffs_.get_array_diff_map(),
9612     num_changes, num_filtered);
9613   do_count_diff_map_changes(leaf_diffs_.get_distinct_diff_map(),
9614     num_changes, num_filtered);
9615   do_count_diff_map_changes(leaf_diffs_.get_fn_parm_diff_map(),
9616 			    num_changes, num_filtered);
9617 }
9618 
9619 /// Count the number of types not reachable from the interface (i.e,
9620 /// not reachable from global functions or variables).
9621 ///
9622 /// @param num_added this is set to the number of added types not
9623 /// reachable from the interface.
9624 ///
9625 /// @param num_deleted this is set to the number of deleted types not
9626 /// reachable from the interface.
9627 ///
9628 /// @param num_changed this is set to the number of changed types not
9629 /// reachable from the interface.
9630 ///
9631 /// @param num_filtered_added this is set to the number of added types
9632 /// not reachable from the interface and that have been filtered out
9633 /// by suppression specifications.
9634 ///
9635 /// @param num_filtered_deleted this is set to the number of deleted
9636 /// types not reachable from the interface and that have been filtered
9637 /// out by suppression specifications.
9638 ///
9639 /// @param num_filtered_changed this is set to the number of changed
9640 /// types not reachable from the interface and that have been filtered
9641 /// out by suppression specifications.
9642 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)9643 corpus_diff::priv::count_unreachable_types(size_t &num_added,
9644 					   size_t &num_deleted,
9645 					   size_t &num_changed,
9646 					   size_t &num_filtered_added,
9647 					   size_t &num_filtered_deleted,
9648 					   size_t &num_filtered_changed)
9649 {
9650   num_added = added_unreachable_types_.size();
9651   num_deleted = deleted_unreachable_types_.size();
9652   num_changed = changed_unreachable_types_.size();
9653   num_filtered_added = suppressed_added_unreachable_types_.size();
9654   num_filtered_deleted = suppressed_deleted_unreachable_types_.size();
9655 
9656   for (vector<diff_sptr>::const_iterator i =
9657 	 changed_unreachable_types_sorted().begin();
9658        i != changed_unreachable_types_sorted().end();
9659        ++i)
9660     if (!(*i)->to_be_reported())
9661       ++num_filtered_changed;
9662 }
9663 
9664 /// Get the sorted vector of diff nodes representing changed
9665 /// unreachable types.
9666 ///
9667 /// Upon the first invocation of this method, if the vector is empty,
9668 /// this function gets the diff nodes representing changed
9669 /// unreachable, sort them, and return the sorted vector.
9670 ///
9671 /// @return the sorted vector of diff nodes representing changed
9672 /// unreachable types.
9673 const vector<diff_sptr>&
changed_unreachable_types_sorted() const9674 corpus_diff::priv::changed_unreachable_types_sorted() const
9675 {
9676 if (changed_unreachable_types_sorted_.empty())
9677   if (!changed_unreachable_types_.empty())
9678     sort_string_diff_sptr_map(changed_unreachable_types_,
9679 			      changed_unreachable_types_sorted_);
9680 
9681  return changed_unreachable_types_sorted_;
9682 }
9683 
9684 /// Compute the diff stats.
9685 ///
9686 /// To know the number of functions that got filtered out, this
9687 /// function applies the categorizing filters to the diff sub-trees of
9688 /// each function changes diff, prior to calculating the stats.
9689 ///
9690 /// @param num_removed the number of removed functions.
9691 ///
9692 /// @param num_added the number of added functions.
9693 ///
9694 /// @param num_changed the number of changed functions.
9695 ///
9696 /// @param num_filtered_out the number of changed functions that are
9697 /// got filtered out from the report
9698 void
apply_filters_and_compute_diff_stats(diff_stats & stat)9699 corpus_diff::priv::apply_filters_and_compute_diff_stats(diff_stats& stat)
9700 {
9701   stat.num_func_removed(deleted_fns_.size());
9702   stat.num_removed_func_filtered_out(suppressed_deleted_fns_.size());
9703   stat.num_func_added(added_fns_.size());
9704   stat.num_added_func_filtered_out(suppressed_added_fns_.size());
9705   stat.num_func_changed(changed_fns_map_.size());
9706 
9707   stat.num_vars_removed(deleted_vars_.size());
9708   stat.num_removed_vars_filtered_out(suppressed_deleted_vars_.size());
9709   stat.num_vars_added(added_vars_.size());
9710   stat.num_added_vars_filtered_out(suppressed_added_vars_.size());
9711   stat.num_vars_changed(changed_vars_map_.size());
9712 
9713   diff_context_sptr ctxt = get_context();
9714 
9715   // Walk the changed function diff nodes to apply the categorization
9716   // filters.
9717   diff_sptr diff;
9718   for (function_decl_diff_sptrs_type::const_iterator i =
9719 	 changed_fns_.begin();
9720        i != changed_fns_.end();
9721        ++i)
9722     {
9723       diff_sptr diff = *i;
9724       ctxt->maybe_apply_filters(diff);
9725     }
9726 
9727   // Walk the changed variable diff nodes to apply the categorization
9728   // filters.
9729   for (var_diff_sptrs_type::const_iterator i = sorted_changed_vars_.begin();
9730        i != sorted_changed_vars_.end();
9731        ++i)
9732     {
9733       diff_sptr diff = *i;
9734       ctxt->maybe_apply_filters(diff);
9735     }
9736 
9737   // walk the changed unreachable types to apply categorization
9738   // filters
9739   for (diff_sptrs_type::const_iterator i =
9740 	  changed_unreachable_types_sorted().begin();
9741 	i != changed_unreachable_types_sorted().end();
9742        ++i)
9743     {
9744       diff_sptr diff = *i;
9745       ctxt->maybe_apply_filters(diff);
9746     }
9747 
9748   categorize_redundant_changed_sub_nodes();
9749 
9750   // Walk the changed function diff nodes to count the number of
9751   // filtered-out functions and the number of functions with virtual
9752   // offset changes.
9753   for (function_decl_diff_sptrs_type::const_iterator i =
9754 	 changed_fns_.begin();
9755        i != changed_fns_.end();
9756        ++i)
9757     {
9758       if ((*i)->is_filtered_out())
9759 	{
9760 	  stat.num_changed_func_filtered_out
9761 	    (stat.num_changed_func_filtered_out() + 1);
9762 
9763 	  if ((*i)->has_local_changes())
9764 	    stat.num_leaf_func_changes_filtered_out
9765 	      (stat.num_leaf_func_changes_filtered_out() + 1);
9766 	}
9767       else
9768 	{
9769 	  if ((*i)->get_category() & VIRTUAL_MEMBER_CHANGE_CATEGORY)
9770 	    stat.num_func_with_virtual_offset_changes
9771 	      (stat.num_func_with_virtual_offset_changes() + 1);
9772 	}
9773 
9774       if ((*i)->has_local_changes())
9775 	stat.num_leaf_func_changes
9776 	  (stat.num_leaf_func_changes() + 1);
9777     }
9778 
9779   // Walk the changed variables diff nodes to count the number of
9780   // filtered-out variables.
9781   for (var_diff_sptrs_type ::const_iterator i = sorted_changed_vars_.begin();
9782        i != sorted_changed_vars_.end();
9783        ++i)
9784     {
9785       if ((*i)->is_filtered_out())
9786 	{
9787 	  stat.num_changed_vars_filtered_out
9788 	    (stat.num_changed_vars_filtered_out() + 1);
9789 
9790 	  if ((*i)->has_local_changes())
9791 	    stat.num_leaf_var_changes_filtered_out
9792 	      (stat.num_leaf_var_changes_filtered_out() + 1);
9793 	}
9794       if ((*i)->has_local_changes())
9795 	stat.num_leaf_var_changes
9796 	  (stat.num_leaf_var_changes() + 1);
9797     }
9798 
9799   stat.num_func_syms_added(added_unrefed_fn_syms_.size());
9800   stat.num_added_func_syms_filtered_out(suppressed_added_unrefed_fn_syms_.size());
9801   stat.num_func_syms_removed(deleted_unrefed_fn_syms_.size());
9802   stat.num_removed_func_syms_filtered_out(suppressed_deleted_unrefed_fn_syms_.size());
9803   stat.num_var_syms_added(added_unrefed_var_syms_.size());
9804   stat.num_added_var_syms_filtered_out(suppressed_added_unrefed_var_syms_.size());
9805   stat.num_var_syms_removed(deleted_unrefed_var_syms_.size());
9806   stat.num_removed_var_syms_filtered_out(suppressed_deleted_unrefed_var_syms_.size());
9807 
9808   // Walk the general leaf type diff nodes to count them
9809   {
9810     size_t num_type_changes = 0, num_type_filtered = 0;
9811     count_leaf_type_changes(num_type_changes, num_type_filtered);
9812 
9813     stat.num_leaf_type_changes(num_type_changes);
9814     stat.num_leaf_type_changes_filtered_out(num_type_filtered);
9815   }
9816 
9817   // Walk the general leaf artefacts diff nodes to count them
9818   {
9819     size_t num_changes = 0, num_filtered = 0;
9820     count_leaf_changes(num_changes, num_filtered);
9821 
9822     stat.num_leaf_changes(num_changes);
9823     stat.num_leaf_changes_filtered_out(num_filtered);
9824   }
9825 
9826   // Walk the unreachable types to count them
9827   {
9828     size_t num_added_unreachable_types = 0,
9829       num_changed_unreachable_types = 0,
9830       num_deleted_unreachable_types = 0,
9831       num_added_unreachable_types_filtered = 0,
9832       num_changed_unreachable_types_filtered = 0,
9833       num_deleted_unreachable_types_filtered = 0;
9834 
9835     count_unreachable_types(num_added_unreachable_types,
9836 			    num_deleted_unreachable_types,
9837 			    num_changed_unreachable_types,
9838 			    num_added_unreachable_types_filtered,
9839 			    num_deleted_unreachable_types_filtered,
9840 			    num_changed_unreachable_types_filtered);
9841 
9842     stat.num_added_unreachable_types(num_added_unreachable_types);
9843     stat.num_removed_unreachable_types(num_deleted_unreachable_types);
9844     stat.num_changed_unreachable_types(num_changed_unreachable_types);
9845     stat.num_added_unreachable_types_filtered_out
9846       (num_added_unreachable_types_filtered);
9847     stat.num_removed_unreachable_types_filtered_out
9848       (num_deleted_unreachable_types_filtered);
9849     stat.num_changed_unreachable_types_filtered_out
9850       (num_changed_unreachable_types_filtered);
9851   }
9852 }
9853 
9854 /// Emit the summary of the functions & variables that got
9855 /// removed/changed/added.
9856 ///
9857 /// TODO: This should be handled by the reporters, just like what is
9858 /// done for reporter_base::diff_to_be_reported.
9859 ///
9860 /// @param out the output stream to emit the stats to.
9861 ///
9862 /// @param indent the indentation string to use in the summary.
9863 void
emit_diff_stats(const diff_stats & s,ostream & out,const string & indent)9864 corpus_diff::priv::emit_diff_stats(const diff_stats&	s,
9865 				   ostream&		out,
9866 				   const string&	indent)
9867 {
9868   /// Report added/removed/changed functions.
9869   size_t net_num_leaf_changes =
9870     s.net_num_func_removed() +
9871     s.net_num_func_added() +
9872     s.net_num_leaf_func_changes() +
9873     s.net_num_vars_removed() +
9874     s.net_num_vars_added() +
9875     s.net_num_leaf_var_changes() +
9876     s.net_num_leaf_type_changes() +
9877     s.net_num_removed_func_syms() +
9878     s.net_num_added_func_syms() +
9879     s.net_num_removed_var_syms() +
9880     s.net_num_added_var_syms();
9881 
9882   if (!sonames_equal_)
9883     out << indent << "ELF SONAME changed\n";
9884 
9885   if (!architectures_equal_)
9886     out << indent << "ELF architecture changed\n";
9887 
9888   diff_context_sptr ctxt = get_context();
9889 
9890   if (ctxt->show_leaf_changes_only())
9891     {
9892       out << "Leaf changes summary: ";
9893       out << net_num_leaf_changes << " artifact";
9894       if (net_num_leaf_changes > 1)
9895 	out << "s";
9896       out << " changed";
9897 
9898       if (size_t num_filtered = s.num_leaf_changes_filtered_out())
9899 	out << " (" << num_filtered << " filtered out)";
9900       out << "\n";
9901 
9902       out << indent << "Changed leaf types summary: "
9903 	  << s.net_num_leaf_type_changes();
9904       if (s.num_leaf_type_changes_filtered_out())
9905 	out << " (" << s.num_leaf_type_changes_filtered_out()
9906 	    << " filtered out)";
9907       out << " leaf type";
9908       if (s.num_leaf_type_changes() > 1)
9909 	out << "s";
9910       out << " changed\n";
9911 
9912       // function changes summary
9913       out << indent << "Removed/Changed/Added functions summary: ";
9914       out << s.net_num_func_removed() << " Removed";
9915      if (s.num_removed_func_filtered_out())
9916 	out << " ("
9917 	    << s.num_removed_func_filtered_out()
9918 	    << " filtered out)";
9919       out << ", ";
9920 
9921       out << s.net_num_leaf_func_changes() << " Changed";
9922       if (s.num_leaf_func_changes_filtered_out())
9923 	    out << " ("
9924 		<< s.num_leaf_func_changes_filtered_out()
9925 		<< " filtered out)";
9926       out << ", ";
9927 
9928       out << s.net_num_func_added()<< " Added ";
9929       if (s.net_num_func_added() <= 1)
9930 	out << "function";
9931       else
9932 	out << "functions";
9933       if (s.num_added_func_filtered_out())
9934 	out << " (" << s.num_added_func_filtered_out() << " filtered out)";
9935       out << "\n";
9936 
9937       // variables changes summary
9938       out << indent << "Removed/Changed/Added variables summary: ";
9939       out << s.net_num_vars_removed() << " Removed";
9940       if (s.num_removed_vars_filtered_out())
9941 	out << " (" << s.num_removed_vars_filtered_out()
9942 	    << " filtered out)";
9943       out << ", ";
9944 
9945       out << s.net_num_leaf_var_changes() << " Changed";
9946       if (s.num_leaf_var_changes_filtered_out())
9947 	out << " ("
9948 	    << s.num_leaf_var_changes_filtered_out()
9949 	    << " filtered out)";
9950       out << ", ";
9951 
9952       out << s.net_num_vars_added() << " Added ";
9953       if (s.net_num_vars_added() <= 1)
9954 	out << "variable";
9955       else
9956 	out << "variables";
9957       if (s.num_added_vars_filtered_out())
9958 	out << " (" << s.num_added_vars_filtered_out()
9959 	    << " filtered out)";
9960       out << "\n";
9961     }
9962   else // if (ctxt->show_leaf_changes_only())
9963     {
9964       size_t total_nb_function_changes = s.num_func_removed()
9965 	+ s.num_func_changed() +  s.num_func_added();
9966 
9967       // function changes summary
9968       out << indent << "Functions changes summary: ";
9969       out << s.net_num_func_removed() << " Removed";
9970       if (s.num_removed_func_filtered_out())
9971 	out << " ("
9972 	    << s.num_removed_func_filtered_out()
9973 	    << " filtered out)";
9974       out << ", ";
9975 
9976       out << s.net_num_func_changed() << " Changed";
9977       if (s.num_changed_func_filtered_out())
9978 	out << " (" << s.num_changed_func_filtered_out() << " filtered out)";
9979       out << ", ";
9980 
9981       out << s.net_num_func_added() << " Added";
9982       if (s.num_added_func_filtered_out())
9983 	out << " (" << s.num_added_func_filtered_out() << " filtered out)";
9984       if (total_nb_function_changes <= 1)
9985 	out << " function";
9986       else
9987 	out << " functions";
9988       out << "\n";
9989 
9990       // variables changes summary
9991       size_t total_nb_variable_changes = s.num_vars_removed()
9992 	+ s.num_vars_changed() + s.num_vars_added();
9993 
9994       out << indent << "Variables changes summary: ";
9995       out << s.net_num_vars_removed() << " Removed";
9996       if (s.num_removed_vars_filtered_out())
9997 	out << " (" << s.num_removed_vars_filtered_out()
9998 	    << " filtered out)";
9999       out << ", ";
10000 
10001       out << s.num_vars_changed() - s.num_changed_vars_filtered_out() << " Changed";
10002       if (s.num_changed_vars_filtered_out())
10003 	out << " (" << s.num_changed_vars_filtered_out() << " filtered out)";
10004       out << ", ";
10005 
10006       out << s.net_num_vars_added() << " Added";
10007       if (s.num_added_vars_filtered_out())
10008 	out << " (" << s.num_added_vars_filtered_out()
10009 	    << " filtered out)";
10010       if (total_nb_variable_changes <= 1)
10011 	out << " variable";
10012       else
10013 	out << " variables";
10014       out << "\n";
10015     }
10016 
10017   // Show statistics about types not reachable from global
10018   // functions/variables.
10019   if (ctxt->show_unreachable_types())
10020     {
10021       size_t total_nb_unreachable_type_changes =
10022 	s.num_removed_unreachable_types()
10023 	+ s.num_changed_unreachable_types()
10024 	+ s.num_added_unreachable_types();
10025 
10026       // Show summary of unreachable types
10027       out << indent << "Unreachable types summary: "
10028 	  << s.net_num_removed_unreachable_types()
10029 	  << " removed";
10030       if (s.num_removed_unreachable_types_filtered_out())
10031 	out << " (" << s.num_removed_unreachable_types_filtered_out()
10032 	    << " filtered out)";
10033       out << ", ";
10034 
10035       out << s.net_num_changed_unreachable_types()
10036 	  << " changed";
10037       if (s.num_changed_unreachable_types_filtered_out())
10038 	out << " (" << s.num_changed_unreachable_types_filtered_out()
10039 	    << " filtered out)";
10040       out << ", ";
10041 
10042       out << s.net_num_added_unreachable_types()
10043 	  << " added";
10044       if (s.num_added_unreachable_types_filtered_out())
10045 	out << " (" << s.num_added_unreachable_types_filtered_out()
10046 	    << " filtered out)";
10047       if (total_nb_unreachable_type_changes <= 1)
10048 	out << " type";
10049       else
10050 	out << " types";
10051       out << "\n";
10052     }
10053 
10054   if (ctxt->show_symbols_unreferenced_by_debug_info()
10055       && (s.num_func_syms_removed()
10056 	  || s.num_func_syms_added()
10057 	  || s.num_var_syms_removed()
10058 	  || s.num_var_syms_added()))
10059     {
10060       // function symbols changes summary.
10061 
10062       if (!ctxt->show_added_symbols_unreferenced_by_debug_info()
10063 	  && s.num_func_syms_removed() == 0
10064 	  && s.num_func_syms_added() != 0)
10065 	// If the only unreferenced function symbol change is function
10066 	// syms that got added, but we were forbidden to show function
10067 	// syms being added, do nothing.
10068 	;
10069       else
10070 	{
10071 	  out << indent
10072 	      << "Function symbols changes summary: "
10073 	      << s.net_num_removed_func_syms() << " Removed";
10074 	  if (s.num_removed_func_syms_filtered_out())
10075 	    out << " (" << s.num_removed_func_syms_filtered_out()
10076 		<< " filtered out)";
10077 	  out << ", ";
10078 	  out << s.net_num_added_func_syms() << " Added";
10079 	  if (s.num_added_func_syms_filtered_out())
10080 	    out << " (" << s.num_added_func_syms_filtered_out()
10081 		<< " filtered out)";
10082 	  out << " function symbol";
10083 	  if (s.num_func_syms_added() + s.num_func_syms_removed() > 1)
10084 	    out << "s";
10085 	  out << " not referenced by debug info\n";
10086 	}
10087 
10088       // variable symbol changes summary.
10089 
10090       if (!ctxt->show_added_symbols_unreferenced_by_debug_info()
10091 	  && s.num_var_syms_removed() == 0
10092 	  && s.num_var_syms_added() != 0)
10093 	// If the only unreferenced variable symbol change is variable
10094 	// syms that got added, but we were forbidden to show variable
10095 	// syms being added, do nothing.
10096 	;
10097       else
10098 	{
10099 	  out << indent
10100 	      << "Variable symbols changes summary: "
10101 	      << s.net_num_removed_var_syms() << " Removed";
10102 	  if (s.num_removed_var_syms_filtered_out())
10103 	    out << " (" << s.num_removed_var_syms_filtered_out()
10104 		<< " filtered out)";
10105 	  out << ", ";
10106 	  out << s.net_num_added_var_syms() << " Added";
10107 	  if (s.num_added_var_syms_filtered_out())
10108 	    out << " (" << s.num_added_var_syms_filtered_out()
10109 		<< " filtered out)";
10110 	  out << " variable symbol";
10111 	  if (s.num_var_syms_added() + s.num_var_syms_removed() > 1)
10112 	    out << "s";
10113 	  out << " not referenced by debug info\n";
10114 	}
10115     }
10116 }
10117 
10118 /// Walk the changed functions and variables diff nodes to categorize
10119 /// redundant nodes.
10120 void
categorize_redundant_changed_sub_nodes()10121 corpus_diff::priv::categorize_redundant_changed_sub_nodes()
10122 {
10123   diff_sptr diff;
10124 
10125   diff_context_sptr ctxt = get_context();
10126 
10127   ctxt->forget_visited_diffs();
10128   for (function_decl_diff_sptrs_type::const_iterator i =
10129 	 changed_fns_.begin();
10130        i!= changed_fns_.end();
10131        ++i)
10132     {
10133       diff = *i;
10134       categorize_redundancy(diff);
10135     }
10136 
10137   for (var_diff_sptrs_type::const_iterator i = sorted_changed_vars_.begin();
10138        i!= sorted_changed_vars_.end();
10139        ++i)
10140     {
10141       diff_sptr diff = *i;
10142       categorize_redundancy(diff);
10143     }
10144 
10145   for (diff_sptrs_type::const_iterator i =
10146 	 changed_unreachable_types_sorted().begin();
10147        i!= changed_unreachable_types_sorted().end();
10148        ++i)
10149     {
10150       diff_sptr diff = *i;
10151       categorize_redundancy(diff);
10152     }
10153 }
10154 
10155 /// Walk the changed functions and variables diff nodes and clear the
10156 /// redundancy categorization they might carry.
10157 void
clear_redundancy_categorization()10158 corpus_diff::priv::clear_redundancy_categorization()
10159 {
10160   diff_sptr diff;
10161   for (function_decl_diff_sptrs_type::const_iterator i = changed_fns_.begin();
10162        i!= changed_fns_.end();
10163        ++i)
10164     {
10165       diff = *i;
10166       abigail::comparison::clear_redundancy_categorization(diff);
10167     }
10168 
10169   for (var_diff_sptrs_type::const_iterator i = sorted_changed_vars_.begin();
10170        i!= sorted_changed_vars_.end();
10171        ++i)
10172     {
10173       diff = *i;
10174       abigail::comparison::clear_redundancy_categorization(diff);
10175     }
10176 }
10177 
10178 /// If the user asked to dump the diff tree node (for changed
10179 /// variables and functions) on the error output stream, then just do
10180 /// that.
10181 ///
10182 /// This function is used for debugging purposes.
10183 void
maybe_dump_diff_tree()10184 corpus_diff::priv::maybe_dump_diff_tree()
10185 {
10186   diff_context_sptr ctxt = get_context();
10187 
10188   if (!ctxt->dump_diff_tree()
10189       || ctxt->error_output_stream() == 0)
10190     return;
10191 
10192   if (!changed_fns_.empty())
10193     {
10194       *ctxt->error_output_stream() << "changed functions diff tree: \n\n";
10195       for (function_decl_diff_sptrs_type::const_iterator i =
10196 	     changed_fns_.begin();
10197 	   i != changed_fns_.end();
10198 	   ++i)
10199 	{
10200 	  diff_sptr d = *i;
10201 	  print_diff_tree(d, *ctxt->error_output_stream());
10202 	}
10203     }
10204 
10205   if (!sorted_changed_vars_.empty())
10206     {
10207       *ctxt->error_output_stream() << "\nchanged variables diff tree: \n\n";
10208       for (var_diff_sptrs_type::const_iterator i =
10209 	     sorted_changed_vars_.begin();
10210 	   i != sorted_changed_vars_.end();
10211 	   ++i)
10212 	{
10213 	  diff_sptr d = *i;
10214 	  print_diff_tree(d, *ctxt->error_output_stream());
10215 	}
10216     }
10217 
10218   if (!changed_unreachable_types_sorted().empty())
10219     {
10220       *ctxt->error_output_stream() << "\nchanged unreachable "
10221 	"types diff tree: \n\n";
10222       for (vector<diff_sptr>::const_iterator i =
10223 	     changed_unreachable_types_sorted().begin();
10224 	   i != changed_unreachable_types_sorted().end();
10225 	   ++i)
10226 	{
10227 	  diff_sptr d = *i;
10228 	  print_diff_tree(d, *ctxt->error_output_stream());
10229 	}
10230     }
10231 }
10232 
10233 /// Populate the vector of children node of the @ref corpus_diff type.
10234 ///
10235 /// The children node can then later be retrieved using
10236 /// corpus_diff::children_node().
10237 void
chain_into_hierarchy()10238 corpus_diff::chain_into_hierarchy()
10239 {
10240   for (function_decl_diff_sptrs_type::const_iterator i =
10241 	 changed_functions_sorted().begin();
10242        i != changed_functions_sorted().end();
10243        ++i)
10244     if (diff_sptr d = *i)
10245       append_child_node(d);
10246 }
10247 
10248 /// Constructor for @ref corpus_diff.
10249 ///
10250 /// @param first the first corpus of the diff.
10251 ///
10252 /// @param second the second corpus of the diff.
10253 ///
10254 /// @param ctxt the diff context to use.  Note that this context
10255 /// object must stay alive at least during the life time of the
10256 /// current instance of @ref corpus_diff.  Otherwise memory corruption
10257 /// issues occur.
corpus_diff(corpus_sptr first,corpus_sptr second,diff_context_sptr ctxt)10258 corpus_diff::corpus_diff(corpus_sptr first,
10259 			 corpus_sptr second,
10260 			 diff_context_sptr ctxt)
10261   : priv_(new priv(first, second, ctxt))
10262 {}
10263 
10264 corpus_diff::~corpus_diff() = default;
10265 
10266 /// Finish building the current instance of @ref corpus_diff.
10267 void
finish_diff_type()10268 corpus_diff::finish_diff_type()
10269 {
10270   if (priv_->finished_)
10271     return;
10272   chain_into_hierarchy();
10273   priv_->finished_ = true;
10274 }
10275 
10276 /// @return the first corpus of the diff.
10277 corpus_sptr
first_corpus() const10278 corpus_diff::first_corpus() const
10279 {return priv_->first_;}
10280 
10281 /// @return the second corpus of the diff.
10282 corpus_sptr
second_corpus() const10283 corpus_diff::second_corpus() const
10284 {return priv_->second_;}
10285 
10286 /// @return the children nodes of the current instance of corpus_diff.
10287 const vector<diff*>&
children_nodes() const10288 corpus_diff::children_nodes() const
10289 {return priv_->children_;}
10290 
10291 /// Append a new child node to the vector of children nodes for the
10292 /// current instance of @ref corpus_diff node.
10293 ///
10294 /// Note that the vector of children nodes for the current instance of
10295 /// @ref corpus_diff node must remain sorted, using
10296 /// diff_less_than_functor.
10297 ///
10298 /// @param d the new child node.  Note that the life time of the
10299 /// object held by @p d will thus equal the life time of the current
10300 /// instance of @ref corpus_diff.
10301 void
append_child_node(diff_sptr d)10302 corpus_diff::append_child_node(diff_sptr d)
10303 {
10304   ABG_ASSERT(d);
10305 
10306   diff_less_than_functor is_less_than;
10307   bool inserted = false;
10308   for (vector<diff*>::iterator i = priv_->children_.begin();
10309        i != priv_->children_.end();
10310        ++i)
10311     // Look for the point where to insert the diff child node.
10312     if (!is_less_than(d.get(), *i))
10313       {
10314 	context()->keep_diff_alive(d);
10315 	priv_->children_.insert(i, d.get());
10316 	// As we have just inserted 'd' into the vector, the iterator
10317 	// 'i' is invalidated.  We must *NOT* use it anymore.
10318 	inserted = true;
10319 	break;
10320       }
10321 
10322   if (!inserted)
10323     {
10324       context()->keep_diff_alive(d);
10325       // We didn't insert anything to the vector, presumably b/c it was
10326       // empty or had one element that was "less than" 'd'.  We can thus
10327       // just append 'd' to the end of the vector.
10328       priv_->children_.push_back(d.get());
10329     }
10330 }
10331 
10332 /// @return the bare edit script of the functions changed as recorded
10333 /// by the diff.
10334 edit_script&
function_changes() const10335 corpus_diff::function_changes() const
10336 {return priv_->fns_edit_script_;}
10337 
10338 /// @return the bare edit script of the variables changed as recorded
10339 /// by the diff.
10340 edit_script&
variable_changes() const10341 corpus_diff::variable_changes() const
10342 {return priv_->vars_edit_script_;}
10343 
10344 /// Test if the soname of the underlying corpus has changed.
10345 ///
10346 /// @return true iff the soname has changed.
10347 bool
soname_changed() const10348 corpus_diff::soname_changed() const
10349 {return !priv_->sonames_equal_;}
10350 
10351 /// Test if the architecture of the underlying corpus has changed.
10352 ///
10353 /// @return true iff the architecture has changed.
10354 bool
architecture_changed() const10355 corpus_diff::architecture_changed() const
10356 {return !priv_->architectures_equal_;}
10357 
10358 /// Getter for the deleted functions of the diff.
10359 ///
10360 /// @return the the deleted functions of the diff.
10361 const string_function_ptr_map&
deleted_functions() const10362 corpus_diff::deleted_functions() const
10363 {return priv_->deleted_fns_;}
10364 
10365 /// Getter for the added functions of the diff.
10366 ///
10367 /// @return the added functions of the diff.
10368 const string_function_ptr_map&
added_functions()10369 corpus_diff::added_functions()
10370 {return priv_->added_fns_;}
10371 
10372 /// Getter for the functions which signature didn't change, but which
10373 /// do have some indirect changes in their parms.
10374 ///
10375 /// @return a non-sorted map of functions which signature didn't
10376 /// change, but which do have some indirect changes in their parms.
10377 /// The key of the map is a unique identifier for the function; it's
10378 /// usually made of the name and version of the underlying ELF symbol
10379 /// of the function for corpora that were built from ELF files.
10380 const string_function_decl_diff_sptr_map&
changed_functions()10381 corpus_diff::changed_functions()
10382 {return priv_->changed_fns_map_;}
10383 
10384 /// Getter for a sorted vector of functions which signature didn't
10385 /// change, but which do have some indirect changes in their parms.
10386 ///
10387 /// @return a sorted vector of functions which signature didn't
10388 /// change, but which do have some indirect changes in their parms.
10389 const function_decl_diff_sptrs_type&
changed_functions_sorted()10390 corpus_diff::changed_functions_sorted()
10391 {return priv_->changed_fns_;}
10392 
10393 /// Getter for the variables that got deleted from the first subject
10394 /// of the diff.
10395 ///
10396 /// @return the map of deleted variable.
10397 const string_var_ptr_map&
deleted_variables() const10398 corpus_diff::deleted_variables() const
10399 {return priv_->deleted_vars_;}
10400 
10401 /// Getter for the added variables of the diff.
10402 ///
10403 /// @return the map of added variable.
10404 const string_var_ptr_map&
added_variables() const10405 corpus_diff::added_variables() const
10406 {return priv_->added_vars_;}
10407 
10408 /// Getter for the non-sorted map of variables which signature didn't
10409 /// change but which do have some indirect changes in some sub-types.
10410 ///
10411 /// @return the non-sorted map of changed variables.
10412 const string_var_diff_sptr_map&
changed_variables()10413 corpus_diff::changed_variables()
10414 {return priv_->changed_vars_map_;}
10415 
10416 /// Getter for the sorted vector of variables which signature didn't
10417 /// change but which do have some indirect changes in some sub-types.
10418 ///
10419 /// @return a sorted vector of changed variables.
10420 const var_diff_sptrs_type&
changed_variables_sorted()10421 corpus_diff::changed_variables_sorted()
10422 {return priv_->sorted_changed_vars_;}
10423 
10424 /// Getter for function symbols not referenced by any debug info and
10425 /// that got deleted.
10426 ///
10427 /// @return a map of elf function symbols not referenced by any debug
10428 /// info and that got deleted.
10429 const string_elf_symbol_map&
deleted_unrefed_function_symbols() const10430 corpus_diff::deleted_unrefed_function_symbols() const
10431 {return priv_->deleted_unrefed_fn_syms_;}
10432 
10433 /// Getter for function symbols not referenced by any debug info and
10434 /// that got added.
10435 ///
10436 /// @return a map of elf function symbols not referenced by any debug
10437 /// info and that got added.
10438 const string_elf_symbol_map&
added_unrefed_function_symbols() const10439 corpus_diff::added_unrefed_function_symbols() const
10440 {return priv_->added_unrefed_fn_syms_;}
10441 
10442 /// Getter for variable symbols not referenced by any debug info and
10443 /// that got deleted.
10444 ///
10445 /// @return a map of elf variable symbols not referenced by any debug
10446 /// info and that got deleted.
10447 const string_elf_symbol_map&
deleted_unrefed_variable_symbols() const10448 corpus_diff::deleted_unrefed_variable_symbols() const
10449 {return priv_->deleted_unrefed_var_syms_;}
10450 
10451 /// Getter for variable symbols not referenced by any debug info and
10452 /// that got added.
10453 ///
10454 /// @return a map of elf variable symbols not referenced by any debug
10455 /// info and that got added.
10456 const string_elf_symbol_map&
added_unrefed_variable_symbols() const10457 corpus_diff::added_unrefed_variable_symbols() const
10458 {return priv_->added_unrefed_var_syms_;}
10459 
10460 /// Getter for a map of deleted types that are not reachable from
10461 /// global functions/variables.
10462 ///
10463 /// @return a map that associates pretty representation of deleted
10464 /// unreachable types and said types.
10465 const string_type_base_sptr_map&
deleted_unreachable_types() const10466 corpus_diff::deleted_unreachable_types() const
10467 {return priv_->deleted_unreachable_types_;}
10468 
10469 /// Getter of a sorted vector of deleted types that are not reachable
10470 /// from global functions/variables.
10471 ///
10472 /// @return a sorted vector of deleted types that are not reachable
10473 /// from global functions/variables.  The types are lexicographically
10474 /// sorted by considering their pretty representation.
10475 const vector<type_base_sptr>&
deleted_unreachable_types_sorted() const10476 corpus_diff::deleted_unreachable_types_sorted() const
10477 {
10478   if (priv_->deleted_unreachable_types_sorted_.empty())
10479     if (!priv_->deleted_unreachable_types_.empty())
10480       sort_string_type_base_sptr_map(priv_->deleted_unreachable_types_,
10481 				     priv_->deleted_unreachable_types_sorted_);
10482 
10483   return priv_->deleted_unreachable_types_sorted_;
10484 }
10485 
10486 /// Getter for a map of added types that are not reachable from global
10487 /// functions/variables.
10488 ///
10489 /// @return a map that associates pretty representation of added
10490 /// unreachable types and said types.
10491 const string_type_base_sptr_map&
added_unreachable_types() const10492 corpus_diff::added_unreachable_types() const
10493 {return priv_->added_unreachable_types_;}
10494 
10495 /// Getter of a sorted vector of added types that are not reachable
10496 /// from global functions/variables.
10497 ///
10498 /// @return a sorted vector of added types that are not reachable from
10499 /// global functions/variables.  The types are lexicographically
10500 /// sorted by considering their pretty representation.
10501 const vector<type_base_sptr>&
added_unreachable_types_sorted() const10502 corpus_diff::added_unreachable_types_sorted() const
10503 {
10504   if (priv_->added_unreachable_types_sorted_.empty())
10505     if (!priv_->added_unreachable_types_.empty())
10506       sort_string_type_base_sptr_map(priv_->added_unreachable_types_,
10507 				     priv_->added_unreachable_types_sorted_);
10508 
10509   return priv_->added_unreachable_types_sorted_;
10510 }
10511 
10512 /// Getter for a map of changed types that are not reachable from
10513 /// global functions/variables.
10514 ///
10515 /// @return a map that associates pretty representation of changed
10516 /// unreachable types and said types.
10517 const string_diff_sptr_map&
changed_unreachable_types() const10518 corpus_diff::changed_unreachable_types() const
10519 {return priv_->changed_unreachable_types_;}
10520 
10521 /// Getter of a sorted vector of changed types that are not reachable
10522 /// from global functions/variables.
10523 ///
10524 /// @return a sorted vector of changed types that are not reachable
10525 /// from global functions/variables.  The diffs are lexicographically
10526 /// sorted by considering their pretty representation.
10527 const vector<diff_sptr>&
changed_unreachable_types_sorted() const10528 corpus_diff::changed_unreachable_types_sorted() const
10529 {return priv_->changed_unreachable_types_sorted();}
10530 
10531 /// Getter of the diff context of this diff
10532 ///
10533 /// @return the diff context for this diff.
10534 const diff_context_sptr
context() const10535 corpus_diff::context() const
10536 {return priv_->get_context();}
10537 
10538 /// @return the pretty representation for the current instance of @ref
10539 /// corpus_diff
10540 const string&
get_pretty_representation() const10541 corpus_diff::get_pretty_representation() const
10542 {
10543   if (priv_->pretty_representation_.empty())
10544     {
10545       std::ostringstream o;
10546       o << "corpus_diff["
10547 	<< first_corpus()->get_path()
10548 	<< ", "
10549 	<< second_corpus()->get_path()
10550 	<< "]";
10551       priv_->pretty_representation_ = o.str();
10552     }
10553   return priv_->pretty_representation_;
10554 }
10555 /// Return true iff the current @ref corpus_diff node carries a
10556 /// change.
10557 ///
10558 /// @return true iff the current diff node carries a change.
10559 bool
has_changes() const10560 corpus_diff::has_changes() const
10561 {
10562   return (soname_changed()
10563 	  || architecture_changed()
10564 	  || !(priv_->deleted_fns_.empty()
10565 	       && priv_->added_fns_.empty()
10566 	       && priv_->changed_fns_map_.empty()
10567 	       && priv_->deleted_vars_.empty()
10568 	       && priv_->added_vars_.empty()
10569 	       && priv_->changed_vars_map_.empty()
10570 	       && priv_->added_unrefed_fn_syms_.empty()
10571 	       && priv_->deleted_unrefed_fn_syms_.empty()
10572 	       && priv_->added_unrefed_var_syms_.empty()
10573 	       && priv_->deleted_unrefed_var_syms_.empty()
10574 	       && priv_->deleted_unreachable_types_.empty()
10575 	       && priv_->added_unreachable_types_.empty()
10576 	       && priv_->changed_unreachable_types_.empty()));
10577 }
10578 
10579 /// Test if the current instance of @ref corpus_diff carries changes
10580 /// that we are sure are incompatible.  By incompatible change we mean
10581 /// a change that "breaks" the ABI of the corpus we are looking at.
10582 ///
10583 /// In concrete terms, this function considers the following changes
10584 /// as being ABI incompatible for sure:
10585 ///
10586 ///   - a soname change
10587 ///   - if exported functions or variables got removed
10588 ///
10589 /// Note that subtype changes *can* represent changes that break ABI
10590 /// too.  But they also can be changes that are OK, ABI-wise.
10591 ///
10592 /// It's up to the user to provide suppression specifications to say
10593 /// explicitely which subtype change is OK.  The remaining sub-type
10594 /// changes are then considered to be ABI incompatible.  But to test
10595 /// if such ABI incompatible subtype changes are present you need to
10596 /// use the function @ref corpus_diff::has_net_subtype_changes()
10597 ///
10598 /// @return true iff the current instance of @ref corpus_diff carries
10599 /// changes that we are sure are ABI incompatible.
10600 bool
has_incompatible_changes() const10601 corpus_diff::has_incompatible_changes() const
10602 {
10603   const diff_stats& stats = const_cast<corpus_diff*>(this)->
10604     apply_filters_and_suppressions_before_reporting();
10605 
10606   return (soname_changed() || architecture_changed()
10607 	  || stats.net_num_func_removed() != 0
10608 	  || (stats.num_func_with_virtual_offset_changes() != 0
10609 	      // If all reports about functions with sub-type changes
10610 	      // have been suppressed, then even those about functions
10611 	      // that are virtual don't matter anymore because the
10612 	      // user willingly requested to shut them down
10613 	      && stats.net_num_func_changed() != 0)
10614 	  || stats.net_num_vars_removed() != 0
10615 	  || stats.net_num_removed_func_syms() != 0
10616 	  || stats.net_num_removed_var_syms() != 0
10617 	  || stats.net_num_removed_unreachable_types() != 0
10618 	  || stats.net_num_changed_unreachable_types() != 0);
10619 }
10620 
10621 /// Test if the current instance of @ref corpus_diff carries subtype
10622 /// changes whose reports are not suppressed by any suppression
10623 /// specification.  In effect, these are deemed incompatible ABI
10624 /// changes.
10625 ///
10626 /// @return true iff the the current instance of @ref corpus_diff
10627 /// carries subtype changes that are deemed incompatible ABI changes.
10628 bool
has_net_subtype_changes() const10629 corpus_diff::has_net_subtype_changes() const
10630 {
10631   const diff_stats& stats = const_cast<corpus_diff*>(this)->
10632       apply_filters_and_suppressions_before_reporting();
10633 
10634   return (stats.net_num_func_changed() != 0
10635 	  || stats.net_num_vars_changed() != 0
10636 	  || stats.net_num_removed_unreachable_types() != 0
10637 	  || stats.net_num_changed_unreachable_types() != 0);
10638 }
10639 
10640 /// Test if the current instance of @ref corpus_diff carries changes
10641 /// whose reports are not suppressed by any suppression specification.
10642 /// In effect, these are deemed incompatible ABI changes.
10643 ///
10644 /// @return true iff the the current instance of @ref corpus_diff
10645 /// carries subtype changes that are deemed incompatible ABI changes.
10646 bool
has_net_changes() const10647 corpus_diff::has_net_changes() const
10648 {return  context()->get_reporter()->diff_has_net_changes(this);}
10649 
10650 /// Apply the different filters that are registered to be applied to
10651 /// the diff tree; that includes the categorization filters.  Also,
10652 /// apply the suppression interpretation filters.
10653 ///
10654 /// After the filters are applied, this function calculates some
10655 /// statistics about the changes carried by the current instance of
10656 /// @ref corpus_diff.  These statistics are represented by an instance
10657 /// of @ref corpus_diff::diff_stats.
10658 ///
10659 /// This member function is called by the reporting function
10660 /// corpus_diff::report().
10661 ///
10662 /// Note that for a given instance of corpus_diff, this function
10663 /// applies the filters and suppressions only the first time it is
10664 /// invoked.  Subsequent invocations just return the instance of
10665 /// corpus_diff::diff_stats that was cached after the first
10666 /// invocation.
10667 ///
10668 /// @return a reference to the statistics about the changes carried by
10669 /// the current instance of @ref corpus_diff.
10670 const corpus_diff::diff_stats&
apply_filters_and_suppressions_before_reporting()10671 corpus_diff::apply_filters_and_suppressions_before_reporting()
10672 {
10673   if (priv_->diff_stats_)
10674     return *priv_->diff_stats_;
10675 
10676   apply_suppressions(this);
10677   priv_->diff_stats_.reset(new diff_stats(context()));
10678   mark_leaf_diff_nodes();
10679   priv_->apply_filters_and_compute_diff_stats(*priv_->diff_stats_);
10680   return *priv_->diff_stats_;
10681 }
10682 
10683 /// A visitor that marks leaf diff nodes by storing them in the
10684 /// instance of @ref diff_maps returned by
10685 /// corpus_diff::get_leaf_diffs() invoked on the current instance of
10686 /// corpus_diff.
10687 struct leaf_diff_node_marker_visitor : public diff_node_visitor
10688 {
10689   /// This is called when the visitor visits a diff node.
10690   ///
10691   /// It basically tests if the diff node being visited is a leaf diff
10692   /// node - that is, it contains local changes.  If it does, then the
10693   /// node is added to the set of maps that hold leaf diffs in the
10694   /// current corpus_diff.
10695   ///
10696   /// Note that only leaf nodes that are reachable from public
10697   /// interfaces (global functions or variables) are collected by this
10698   /// visitor.
10699   ///
10700   /// @param d the diff node being visited.
10701   virtual void
visit_beginabigail::comparison::leaf_diff_node_marker_visitor10702   visit_begin(diff *d)
10703   {
10704     if (d->has_local_changes()
10705 	// A leaf basic (or class/union) type name change makes no
10706 	// sense when showing just leaf changes.  It only makes sense
10707 	// when it can explain the details about a non-leaf change.
10708 	// In other words, it doesn't make sense to say that an "int"
10709 	// became "unsigned int".  But it does make sense to say that
10710 	// a typedef changed because its underlying type was 'int' and
10711 	// is now an "unsigned int".
10712 	&& !filtering::has_basic_or_class_type_name_change(d)
10713 	// Similarly, a *local* change describing a type that changed
10714 	// its nature doesn't make sense.
10715 	&& !is_distinct_diff(d)
10716 	// Similarly, a pointer (or reference or array), a typedef or
10717 	// qualified type change in itself doesn't make sense.  It
10718 	// would rather make sense to show that pointer change as part
10719 	// of the variable change whose pointer type changed, for
10720 	// instance.
10721 	&& !is_pointer_diff(d)
10722 	&& !is_reference_diff(d)
10723 	&& !is_qualified_type_diff(d)
10724 	&& !is_typedef_diff(d)
10725 	&& !is_array_diff(d)
10726 	// Similarly a parameter change in itself doesn't make sense.
10727 	// It should have already been reported as part of the change
10728 	// of the function it belongs to.
10729 	&& !is_fn_parm_diff(d)
10730 	// An anonymous class or union diff doesn't make sense on its
10731 	// own.  It must have been described already by the diff of
10732 	// the enclosing struct or union if 'd' is from an anonymous
10733 	// data member, or from a typedef change if 'd' is from a
10734 	// typedef change which underlying type is an anonymous
10735 	// struct/union.
10736 	&& !is_anonymous_class_or_union_diff(d)
10737 	// Don't show decl-only-ness changes either.
10738 	&& !filtering::has_decl_only_def_change(d)
10739 	// Sometime, we can encounter artifacts of bogus DWARF that
10740 	// yield a diff node for a decl-only class (and empty class
10741 	// with the is_declaration flag set) that carries a non-zero
10742 	// size!  And of course at some point that non-zero size
10743 	// changes.  We need to be able to detect that.
10744 	&& !filtering::is_decl_only_class_with_size_change(d))
10745       {
10746 	diff_context_sptr ctxt = d->context();
10747 	const corpus_diff *corpus_diff_node = ctxt->get_corpus_diff().get();
10748 	ABG_ASSERT(corpus_diff_node);
10749 
10750 	if (diff *iface_diff = get_current_topmost_iface_diff())
10751 	  {
10752 	    type_or_decl_base_sptr iface = iface_diff->first_subject();
10753 	    // So, this diff node that is reachable from a global
10754 	    // function or variable carries a leaf change.  Let's add
10755 	    // it to the set of of leaf diffs of corpus_diff_node.
10756 	    const_cast<corpus_diff*>(corpus_diff_node)->
10757 	      get_leaf_diffs().insert_diff_node(d, iface);
10758 	  }
10759       }
10760   }
10761 }; // end struct leaf_diff_node_marker_visitor
10762 
10763 /// Walks the diff nodes associated to the current corpus diff and
10764 /// mark those that carry local changes.  They are said to be leaf
10765 /// diff nodes.
10766 ///
10767 /// The marked nodes are available from the
10768 /// corpus_diff::get_leaf_diffs() function.
10769 void
mark_leaf_diff_nodes()10770 corpus_diff::mark_leaf_diff_nodes()
10771 {
10772   if (!has_changes())
10773     return;
10774 
10775   if (!context()->show_leaf_changes_only())
10776     return;
10777 
10778   leaf_diff_node_marker_visitor v;
10779   context()->forget_visited_diffs();
10780   bool s = context()->visiting_a_node_twice_is_forbidden();
10781   context()->forbid_visiting_a_node_twice(true);
10782   context()->forbid_visiting_a_node_twice_per_interface(true);
10783   traverse(v);
10784   context()->forbid_visiting_a_node_twice(s);
10785   context()->forbid_visiting_a_node_twice_per_interface(false);
10786 }
10787 
10788 /// Get the set of maps that contain leaf nodes.  A leaf node being a
10789 /// node with a local change.
10790 ///
10791 /// @return the set of maps that contain leaf nodes.  A leaf node
10792 /// being a node with a local change.
10793 diff_maps&
get_leaf_diffs()10794 corpus_diff::get_leaf_diffs()
10795 {return priv_->leaf_diffs_;}
10796 
10797 /// Get the set of maps that contain leaf nodes.  A leaf node being a
10798 /// node with a local change.
10799 ///
10800 /// @return the set of maps that contain leaf nodes.  A leaf node
10801 /// being a node with a local change.
10802 const diff_maps&
get_leaf_diffs() const10803 corpus_diff::get_leaf_diffs() const
10804 {return priv_->leaf_diffs_;}
10805 
10806 /// Report the diff in a serialized form.
10807 ///
10808 /// @param out the stream to serialize the diff to.
10809 ///
10810 /// @param indent the prefix to use for the indentation of this
10811 /// serialization.
10812 void
report(ostream & out,const string & indent) const10813 corpus_diff::report(ostream& out, const string& indent) const
10814 {
10815   context()->get_reporter()->report(*this, out, indent);
10816 }
10817 
10818 /// Traverse the diff sub-tree under the current instance corpus_diff.
10819 ///
10820 /// @param v the visitor to invoke on each diff node of the sub-tree.
10821 ///
10822 /// @return true if the traversing has to keep going on, false otherwise.
10823 bool
traverse(diff_node_visitor & v)10824 corpus_diff::traverse(diff_node_visitor& v)
10825 {
10826   finish_diff_type();
10827 
10828   v.visit_begin(this);
10829 
10830   if (!v.visit(this, true))
10831     {
10832       v.visit_end(this);
10833       return false;
10834     }
10835 
10836   for (function_decl_diff_sptrs_type::const_iterator i =
10837 	 changed_functions_sorted().begin();
10838        i != changed_functions_sorted().end();
10839        ++i)
10840     {
10841       if (diff_sptr d = *i)
10842 	{
10843 	  const diff_context_sptr &ctxt = context();
10844 	  if (ctxt->visiting_a_node_twice_is_forbidden_per_interface())
10845 	    ctxt->forget_visited_diffs();
10846 
10847 	  v.set_current_topmost_iface_diff(d.get());
10848 
10849 	  if (!d->traverse(v))
10850 	    {
10851 	      v.visit_end(this);
10852 	      v.set_current_topmost_iface_diff(0);
10853 	      return false;
10854 	    }
10855 	}
10856     }
10857 
10858   for (var_diff_sptrs_type::const_iterator i =
10859 	 changed_variables_sorted().begin();
10860        i != changed_variables_sorted().end();
10861        ++i)
10862     {
10863       if (diff_sptr d = *i)
10864 	{
10865 	  const diff_context_sptr &ctxt = context();
10866 	  if (ctxt->visiting_a_node_twice_is_forbidden_per_interface())
10867 	    ctxt->forget_visited_diffs();
10868 
10869 	  v.set_current_topmost_iface_diff(d.get());
10870 
10871 	  if (!d->traverse(v))
10872 	    {
10873 	      v.visit_end(this);
10874 	      v.set_current_topmost_iface_diff(0);
10875 	      return false;
10876 	    }
10877 	}
10878     }
10879 
10880   v.set_current_topmost_iface_diff(0);
10881 
10882   // Traverse the changed unreachable type diffs.  These diffs are on
10883   // types that are not reachable from global functions or variables.
10884   for (vector<diff_sptr>::const_iterator i =
10885 	 changed_unreachable_types_sorted().begin();
10886        i != changed_unreachable_types_sorted().end();
10887        ++i)
10888     {
10889       if (diff_sptr d = *i)
10890 	{
10891 	  const diff_context_sptr &ctxt = context();
10892 	  if (ctxt->visiting_a_node_twice_is_forbidden_per_interface())
10893 	    ctxt->forget_visited_diffs();
10894 
10895 	  if (!d->traverse(v))
10896 	    {
10897 	      v.visit_end(this);
10898 	      return false;
10899 	    }
10900 	}
10901     }
10902 
10903   v.visit_end(this);
10904   return true;
10905 }
10906 
10907 /// Compute the diff between two instances of @ref corpus.
10908 ///
10909 /// Note that the two corpora must have been created in the same @ref
10910 /// environment, otherwise, this function aborts.
10911 ///
10912 /// @param f the first @ref corpus to consider for the diff.
10913 ///
10914 /// @param s the second @ref corpus to consider for the diff.
10915 ///
10916 /// @param ctxt the diff context to use.
10917 ///
10918 /// @return the resulting diff between the two @ref corpus.
10919 corpus_diff_sptr
compute_diff(const corpus_sptr f,const corpus_sptr s,diff_context_sptr ctxt)10920 compute_diff(const corpus_sptr	f,
10921 	     const corpus_sptr	s,
10922 	     diff_context_sptr	ctxt)
10923 {
10924   typedef corpus::functions::const_iterator fns_it_type;
10925   typedef corpus::variables::const_iterator vars_it_type;
10926   typedef elf_symbols::const_iterator symbols_it_type;
10927   typedef diff_utils::deep_ptr_eq_functor eq_type;
10928   typedef vector<type_base_wptr>::const_iterator type_base_wptr_it_type;
10929 
10930   ABG_ASSERT(f && s);
10931 
10932   // We can only compare two corpora that were built out of the same
10933   // environment.
10934   ABG_ASSERT(f->get_environment() == s->get_environment());
10935 
10936   if (!ctxt)
10937     ctxt.reset(new diff_context);
10938 
10939   corpus_diff_sptr r(new corpus_diff(f, s, ctxt));
10940 
10941   ctxt->set_corpus_diff(r);
10942 
10943   if(ctxt->show_soname_change())
10944     r->priv_->sonames_equal_ = f->get_soname() == s->get_soname();
10945   else
10946     r->priv_->sonames_equal_ = true;
10947 
10948   r->priv_->architectures_equal_ =
10949     f->get_architecture_name() == s->get_architecture_name();
10950 
10951   // Compute the diff of publicly defined and exported functions
10952   diff_utils::compute_diff<fns_it_type, eq_type>(f->get_functions().begin(),
10953 						 f->get_functions().end(),
10954 						 s->get_functions().begin(),
10955 						 s->get_functions().end(),
10956 						 r->priv_->fns_edit_script_);
10957 
10958   // Compute the diff of publicly defined and exported variables.
10959   diff_utils::compute_diff<vars_it_type, eq_type>
10960     (f->get_variables().begin(), f->get_variables().end(),
10961      s->get_variables().begin(), s->get_variables().end(),
10962      r->priv_->vars_edit_script_);
10963 
10964   // Compute the diff of function elf symbols not referenced by debug
10965   // info.
10966   diff_utils::compute_diff<symbols_it_type, eq_type>
10967     (f->get_unreferenced_function_symbols().begin(),
10968      f->get_unreferenced_function_symbols().end(),
10969      s->get_unreferenced_function_symbols().begin(),
10970      s->get_unreferenced_function_symbols().end(),
10971      r->priv_->unrefed_fn_syms_edit_script_);
10972 
10973   // Compute the diff of variable elf symbols not referenced by debug
10974   // info.
10975     diff_utils::compute_diff<symbols_it_type, eq_type>
10976     (f->get_unreferenced_variable_symbols().begin(),
10977      f->get_unreferenced_variable_symbols().end(),
10978      s->get_unreferenced_variable_symbols().begin(),
10979      s->get_unreferenced_variable_symbols().end(),
10980      r->priv_->unrefed_var_syms_edit_script_);
10981 
10982     if (ctxt->show_unreachable_types())
10983       // Compute the diff of types not reachable from public functions
10984       // or global variables that are exported.
10985       diff_utils::compute_diff<type_base_wptr_it_type, eq_type>
10986 	(f->get_types_not_reachable_from_public_interfaces().begin(),
10987 	 f->get_types_not_reachable_from_public_interfaces().end(),
10988 	 s->get_types_not_reachable_from_public_interfaces().begin(),
10989 	 s->get_types_not_reachable_from_public_interfaces().end(),
10990 	 r->priv_->unreachable_types_edit_script_);
10991 
10992   r->priv_->ensure_lookup_tables_populated();
10993 
10994   return r;
10995 }
10996 
10997 // </corpus stuff>
10998 
10999 /// Compute the diff between two instances of @ref corpus_group.
11000 ///
11001 /// Note that the two corpus_diff must have been created in the same
11002 /// @ref environment, otherwise, this function aborts.
11003 ///
11004 /// @param f the first @ref corpus_group to consider for the diff.
11005 ///
11006 /// @param s the second @ref corpus_group to consider for the diff.
11007 ///
11008 /// @param ctxt the diff context to use.
11009 ///
11010 /// @return the resulting diff between the two @ref corpus_group.
11011 corpus_diff_sptr
compute_diff(const corpus_group_sptr & f,const corpus_group_sptr & s,diff_context_sptr ctxt)11012 compute_diff(const corpus_group_sptr&	f,
11013 	     const corpus_group_sptr&	s,
11014 	     diff_context_sptr	ctxt)
11015 {
11016 
11017   corpus_sptr c1 = f;
11018   corpus_sptr c2 = s;
11019 
11020   return compute_diff(c1, c2, ctxt);
11021 }
11022 
11023 // <corpus_group stuff>
11024 
11025 // </corpus_group stuff>
11026 // <diff_node_visitor stuff>
11027 
11028 /// The private data of the @diff_node_visitor type.
11029 struct diff_node_visitor::priv
11030 {
11031   diff*	topmost_interface_diff;
11032   visiting_kind kind;
11033 
privabigail::comparison::diff_node_visitor::priv11034   priv()
11035     : topmost_interface_diff(),
11036       kind()
11037   {}
11038 
privabigail::comparison::diff_node_visitor::priv11039   priv(visiting_kind k)
11040     : topmost_interface_diff(),
11041       kind(k)
11042   {}
11043 }; // end struct diff_node_visitor
11044 
11045 /// Default constructor of the @ref diff_node_visitor type.
diff_node_visitor()11046 diff_node_visitor::diff_node_visitor()
11047   : priv_(new priv)
11048 {}
11049 
11050 diff_node_visitor::~diff_node_visitor() = default;
11051 
11052 /// Constructor of the @ref diff_node_visitor type.
11053 ///
11054 /// @param k how the visiting has to be performed.
diff_node_visitor(visiting_kind k)11055 diff_node_visitor::diff_node_visitor(visiting_kind k)
11056   : priv_(new priv(k))
11057 {}
11058 
11059 /// Getter for the visiting policy of the traversing code while
11060 /// invoking this visitor.
11061 ///
11062 /// @return the visiting policy used by the traversing code when
11063 /// invoking this visitor.
11064 visiting_kind
get_visiting_kind() const11065 diff_node_visitor::get_visiting_kind() const
11066 {return priv_->kind;}
11067 
11068 /// Setter for the visiting policy of the traversing code while
11069 /// invoking this visitor.
11070 ///
11071 /// @param v a bit map representing the new visiting policy used by
11072 /// the traversing code when invoking this visitor.
11073 void
set_visiting_kind(visiting_kind v)11074 diff_node_visitor::set_visiting_kind(visiting_kind v)
11075 {priv_->kind = v;}
11076 
11077 /// Setter for the visiting policy of the traversing code while
11078 /// invoking this visitor.  This one makes a logical or between the
11079 /// current policy and the bitmap given in argument and assigns the
11080 /// current policy to the result.
11081 ///
11082 /// @param v a bitmap representing the visiting policy to or with
11083 /// the current policy.
11084 void
or_visiting_kind(visiting_kind v)11085 diff_node_visitor::or_visiting_kind(visiting_kind v)
11086 {priv_->kind = priv_->kind | v;}
11087 
11088 /// Setter of the diff current topmost interface which is impacted by
11089 /// the current diff node being visited.
11090 ///
11091 /// @param d the current topmost interface diff impacted.
11092 void
set_current_topmost_iface_diff(diff * d)11093 diff_node_visitor::set_current_topmost_iface_diff(diff* d)
11094 {priv_->topmost_interface_diff = d;}
11095 
11096 /// Getter of the diff current topmost interface which is impacted by
11097 /// the current diff node being visited.
11098 ///
11099 /// @return the current topmost interface diff impacted.
11100 diff*
get_current_topmost_iface_diff() const11101 diff_node_visitor::get_current_topmost_iface_diff() const
11102 {return priv_->topmost_interface_diff;}
11103 
11104 /// This is called by the traversing code on a @ref diff node just
11105 /// before visiting it.  That is, before visiting it and its children
11106 /// node.
11107 ///
11108 /// @param d the diff node to visit.
11109 void
visit_begin(diff *)11110 diff_node_visitor::visit_begin(diff* /*p*/)
11111 {}
11112 
11113 /// This is called by the traversing code on a @ref diff node just
11114 /// after visiting it.  That is after visiting it and its children
11115 /// nodes.
11116 ///
11117 /// @param d the diff node that got visited.
11118 void
visit_end(diff *)11119 diff_node_visitor::visit_end(diff* /*p*/)
11120 {}
11121 
11122 /// This is called by the traversing code on a @ref corpus_diff node
11123 /// just before visiting it.  That is, before visiting it and its
11124 /// children node.
11125 ///
11126 /// @param p the corpus_diff node to visit.
11127 ///
11128 void
visit_begin(corpus_diff *)11129 diff_node_visitor::visit_begin(corpus_diff* /*p*/)
11130 {}
11131 
11132 /// This is called by the traversing code on a @ref corpus_diff node
11133 /// just after visiting it.  That is after visiting it and its children
11134 /// nodes.
11135 ///
11136 /// @param d the diff node that got visited.
11137 void
visit_end(corpus_diff *)11138 diff_node_visitor::visit_end(corpus_diff* /*d*/)
11139 {}
11140 
11141 /// Default visitor implementation
11142 ///
11143 /// @return true
11144 bool
visit(diff *,bool)11145 diff_node_visitor::visit(diff*, bool)
11146 {return true;}
11147 
11148 /// Default visitor implementation.
11149 ///
11150 /// @return true
11151 bool
visit(distinct_diff * dif,bool pre)11152 diff_node_visitor::visit(distinct_diff* dif, bool pre)
11153 {
11154   diff* d = dif;
11155   visit(d, pre);
11156 
11157   return true;
11158 }
11159 
11160 /// Default visitor implementation.
11161 ///
11162 /// @return true
11163 bool
visit(var_diff * dif,bool pre)11164 diff_node_visitor::visit(var_diff* dif, bool pre)
11165 {
11166   diff* d = dif;
11167   visit(d, pre);
11168 
11169   return true;
11170 }
11171 
11172 /// Default visitor implementation.
11173 ///
11174 /// @return true
11175 bool
visit(pointer_diff * dif,bool pre)11176 diff_node_visitor::visit(pointer_diff* dif, bool pre)
11177 {
11178   diff* d = dif;
11179   visit(d, pre);
11180 
11181   return true;
11182 }
11183 
11184 /// Default visitor implementation.
11185 ///
11186 /// @return true
11187 bool
visit(reference_diff * dif,bool pre)11188 diff_node_visitor::visit(reference_diff* dif, bool pre)
11189 {
11190   diff* d = dif;
11191   visit(d, pre);
11192 
11193   return true;
11194 }
11195 
11196 /// Default visitor implementation.
11197 ///
11198 /// @return true
11199 bool
visit(qualified_type_diff * dif,bool pre)11200 diff_node_visitor::visit(qualified_type_diff* dif, bool pre)
11201 {
11202   diff* d = dif;
11203   visit(d, pre);
11204 
11205   return true;
11206 }
11207 
11208 /// Default visitor implementation.
11209 ///
11210 /// @return true
11211 bool
visit(enum_diff * dif,bool pre)11212 diff_node_visitor::visit(enum_diff* dif, bool pre)
11213 {
11214   diff* d = dif;
11215   visit(d, pre);
11216 
11217   return true;
11218 }
11219 
11220 /// Default visitor implementation.
11221 ///
11222 /// @return true
11223 bool
visit(class_diff * dif,bool pre)11224 diff_node_visitor::visit(class_diff* dif, bool pre)
11225 {
11226   diff* d = dif;
11227   visit(d, pre);
11228 
11229   return true;
11230 }
11231 
11232 /// Default visitor implementation.
11233 ///
11234 /// @return true
11235 bool
visit(base_diff * dif,bool pre)11236 diff_node_visitor::visit(base_diff* dif, bool pre)
11237 {
11238   diff* d = dif;
11239   visit(d, pre);
11240 
11241   return true;
11242 }
11243 
11244 /// Default visitor implementation.
11245 ///
11246 /// @return true
11247 bool
visit(scope_diff * dif,bool pre)11248 diff_node_visitor::visit(scope_diff* dif, bool pre)
11249 {
11250   diff* d = dif;
11251   visit(d, pre);
11252 
11253   return true;
11254 }
11255 
11256 /// Default visitor implementation.
11257 ///
11258 /// @return true
11259 bool
visit(function_decl_diff * dif,bool pre)11260 diff_node_visitor::visit(function_decl_diff* dif, bool pre)
11261 {
11262   diff* d = dif;
11263   visit(d, pre);
11264 
11265   return true;
11266 }
11267 
11268 /// Default visitor implementation.
11269 ///
11270 /// @return true
11271 bool
visit(type_decl_diff * dif,bool pre)11272 diff_node_visitor::visit(type_decl_diff* dif, bool pre)
11273 {
11274   diff* d = dif;
11275   visit(d, pre);
11276 
11277   return true;
11278 }
11279 
11280 /// Default visitor implementation.
11281 ///
11282 /// @return true
11283 bool
visit(typedef_diff * dif,bool pre)11284 diff_node_visitor::visit(typedef_diff* dif, bool pre)
11285 {
11286   diff* d = dif;
11287   visit(d, pre);
11288 
11289   return true;
11290 }
11291 
11292 /// Default visitor implementation.
11293 ///
11294 /// @return true
11295 bool
visit(translation_unit_diff * dif,bool pre)11296 diff_node_visitor::visit(translation_unit_diff* dif, bool pre)
11297 {
11298   diff* d = dif;
11299   visit(d, pre);
11300 
11301   return true;
11302 }
11303 
11304 /// Default visitor implementation.
11305 ///
11306 /// @return true
11307 bool
visit(corpus_diff *,bool)11308 diff_node_visitor::visit(corpus_diff*, bool)
11309 {return true;}
11310 
11311 // </diff_node_visitor stuff>
11312 
11313 // <redundant diff node marking>
11314 
11315 // </redundant diff node marking>
11316 
11317 // <diff tree category propagation>
11318 
11319 /// A visitor to propagate the category of a node up to its parent
11320 /// nodes.  This visitor doesn't touch the REDUNDANT_CATEGORY or the
11321 /// SUPPRESSED_CATEGORY because those are propagated using other
11322 /// specific visitors.
11323 struct category_propagation_visitor : public diff_node_visitor
11324 {
11325   virtual void
visit_endabigail::comparison::category_propagation_visitor11326   visit_end(diff* d)
11327   {
11328     // Has this diff node 'd' been already visited ?
11329     bool already_visited = d->context()->diff_has_been_visited(d);
11330 
11331     // The canonical diff node of the class of equivalence of the diff
11332     // node 'd'.
11333     diff* canonical = d->get_canonical_diff();
11334 
11335     // If this class of equivalence of diff node is being visited for
11336     // the first time, then update its canonical node's category too.
11337     bool update_canonical = !already_visited && canonical;
11338 
11339     for (vector<diff*>::const_iterator i = d->children_nodes().begin();
11340 	 i != d->children_nodes().end();
11341 	 ++i)
11342       {
11343 	// If we are visiting the class of equivalence of 'd' for the
11344 	// first time, then let's look at the children of 'd' and
11345 	// propagate their categories to 'd'.
11346 	//
11347 	// If the class of equivalence of 'd' has already been
11348 	// visited, then let's look at the canonical diff nodes of the
11349 	// children of 'd' and propagate their categories to 'd'.
11350 	diff* diff = already_visited
11351 	  ? (*i)->get_canonical_diff()
11352 	  : *i;
11353 
11354 	ABG_ASSERT(diff);
11355 
11356 	diff_category c = diff->get_category();
11357 	// Do not propagate redundant and suppressed categories. Those
11358 	// are propagated in a specific pass elsewhere.
11359 	c &= ~(REDUNDANT_CATEGORY
11360 	       | SUPPRESSED_CATEGORY
11361 	       | PRIVATE_TYPE_CATEGORY);
11362 	// Also, if a (class) type has got a harmful name change, do not
11363 	// propagate harmless name changes coming from its sub-types
11364 	// (i.e, data members) to the class itself.
11365 	if (filtering::has_harmful_name_change(d))
11366 	  c &= ~HARMLESS_DECL_NAME_CHANGE_CATEGORY;
11367 
11368 	d->add_to_category(c);
11369 	if (!already_visited && canonical)
11370 	  if (update_canonical)
11371 	    canonical->add_to_category(c);
11372       }
11373   }
11374 };// end struct category_propagation_visitor
11375 
11376 /// Visit all the nodes of a given sub-tree.  For each node that has a
11377 /// particular category set, propagate that category set up to its
11378 /// parent nodes.
11379 ///
11380 /// @param diff_tree the diff sub-tree to walk for categorization
11381 /// purpose;
11382 void
propagate_categories(diff * diff_tree)11383 propagate_categories(diff* diff_tree)
11384 {
11385   category_propagation_visitor v;
11386   bool s = diff_tree->context()->visiting_a_node_twice_is_forbidden();
11387   diff_tree->context()->forbid_visiting_a_node_twice(true);
11388   diff_tree->context()->forget_visited_diffs();
11389   diff_tree->traverse(v);
11390   diff_tree->context()->forbid_visiting_a_node_twice(s);
11391 }
11392 
11393 /// Visit all the nodes of a given sub-tree.  For each node that has a
11394 /// particular category set, propagate that category set up to its
11395 /// parent nodes.
11396 ///
11397 /// @param diff_tree the diff sub-tree to walk for categorization
11398 /// purpose;
11399 void
propagate_categories(diff_sptr diff_tree)11400 propagate_categories(diff_sptr diff_tree)
11401 {propagate_categories(diff_tree.get());}
11402 
11403 /// Visit all the nodes of a given corpus tree.  For each node that
11404 /// has a particular category set, propagate that category set up to
11405 /// its parent nodes.
11406 ///
11407 /// @param diff_tree the corpus_diff tree to walk for categorization
11408 /// purpose;
11409 void
propagate_categories(corpus_diff * diff_tree)11410 propagate_categories(corpus_diff* diff_tree)
11411 {
11412   category_propagation_visitor v;
11413   bool s = diff_tree->context()->visiting_a_node_twice_is_forbidden();
11414   diff_tree->context()->forbid_visiting_a_node_twice(false);
11415   diff_tree->traverse(v);
11416   diff_tree->context()->forbid_visiting_a_node_twice(s);
11417 }
11418 
11419 /// Visit all the nodes of a given corpus tree.  For each node that
11420 /// has a particular category set, propagate that category set up to
11421 /// its parent nodes.
11422 ///
11423 /// @param diff_tree the corpus_diff tree to walk for categorization
11424 /// purpose;
11425 void
propagate_categories(corpus_diff_sptr diff_tree)11426 propagate_categories(corpus_diff_sptr diff_tree)
11427 {propagate_categories(diff_tree.get());}
11428 
11429 /// A tree node visitor that knows how to categorizes a given diff
11430 /// node in the SUPPRESSED_CATEGORY category and how to propagate that
11431 /// categorization.
11432 struct suppression_categorization_visitor : public diff_node_visitor
11433 {
11434 
11435   /// Before visiting the children of the diff node, check if the node
11436   /// is suppressed by a suppression specification.  If it is, mark
11437   /// the node as belonging to the SUPPRESSED_CATEGORY category.
11438   ///
11439   /// @param p the diff node to visit.
11440   virtual void
visit_beginabigail::comparison::suppression_categorization_visitor11441   visit_begin(diff* d)
11442   {
11443     bool is_private_type = false;
11444     if (d->is_suppressed(is_private_type))
11445       {
11446 	diff_category c = is_private_type
11447 	  ? PRIVATE_TYPE_CATEGORY
11448 	  : SUPPRESSED_CATEGORY;
11449 	d->add_to_local_and_inherited_categories(c);
11450 
11451 	// If a node was suppressed, all the other nodes of its class
11452 	// of equivalence are suppressed too.
11453 	diff *canonical_diff = d->get_canonical_diff();
11454 	if (canonical_diff != d)
11455 	  canonical_diff->add_to_category(c);
11456       }
11457   }
11458 
11459   /// After visiting the children nodes of a given diff node,
11460   /// propagate the SUPPRESSED_CATEGORY from the children nodes to the
11461   /// diff node, if need be.
11462   ///
11463   /// That is, if all children nodes carry a suppressed change the
11464   /// current node should be marked as suppressed as well.
11465   ///
11466   /// In practice, this might be too strong of a condition.  If the
11467   /// current node carries a local change (i.e, a change not carried
11468   /// by any of its children node) and if that change is not
11469   /// suppressed, then the current node should *NOT* be suppressed.
11470   ///
11471   /// But right now, the IR doesn't let us know about local vs
11472   /// children-carried changes.  So we cannot be that precise yet.
11473   virtual void
visit_endabigail::comparison::suppression_categorization_visitor11474   visit_end(diff* d)
11475   {
11476     bool has_non_suppressed_child = false;
11477     bool has_non_empty_child = false;
11478     bool has_suppressed_child = false;
11479     bool has_non_private_child = false;
11480     bool has_private_child = false;
11481 
11482     if (// A node to which we can propagate the "SUPPRESSED_CATEGORY"
11483 	// (or the PRIVATE_TYPE_CATEGORY for the same matter)
11484 	// category from its children is a node which:
11485 	//
11486 	//  1/ hasn't been suppressed already
11487 	//
11488 	//  2/ and has no local change (unless it's a pointer,
11489 	//  reference or qualified diff node).
11490 	//
11491 	//  Note that qualified type and typedef diff nodes are a bit
11492 	//  special.  The local changes of the underlying type are
11493 	//  considered local for the qualified/typedef type, just like
11494 	//  for pointer/reference types.  But then the qualified or
11495 	//  typedef type itself can have local changes of its own, and
11496 	//  those changes are of the kind LOCAL_NON_TYPE_CHANGE_KIND.
11497 	//  So a qualified type which have local changes that are
11498 	//  *NOT* of LOCAL_NON_TYPE_CHANGE_KIND (or that has no local
11499 	//  changes at all) and which is in the PRIVATE_TYPE_CATEGORY
11500 	//  or SUPPRESSED_CATEGORY can see these categories be
11501 	//  propagated.
11502 	//
11503 	// Note that all pointer/reference diff node changes are
11504 	// potentially considered local, i.e, local changes of the
11505 	// pointed-to-type are considered local to the pointer itself.
11506 	//
11507 	// Similarly, changes local to the type of function parameters,
11508 	// variables (and data members) and classes (that are not of
11509 	// LOCAL_NON_TYPE_CHANGE_KIND kind) and that have been
11510 	// suppressed can propagate their SUPPRESSED_CATEGORY-ness to
11511 	// those kinds of diff node.
11512 	!(d->get_category() & SUPPRESSED_CATEGORY)
11513 	&& (!d->has_local_changes()
11514 	    || is_pointer_diff(d)
11515 	    || is_reference_diff(d)
11516 	    || (is_qualified_type_diff(d)
11517 		&& (!(d->has_local_changes() & LOCAL_NON_TYPE_CHANGE_KIND)))
11518 	    || (is_typedef_diff(d)
11519 		&& (!(d->has_local_changes() & LOCAL_NON_TYPE_CHANGE_KIND)))
11520 	    || (is_function_decl_diff(d)
11521 		&& (!(d->has_local_changes() & LOCAL_NON_TYPE_CHANGE_KIND)))
11522 	    || (is_fn_parm_diff(d)
11523 		&& (!(d->has_local_changes() & LOCAL_NON_TYPE_CHANGE_KIND)))
11524 	    || (is_function_type_diff(d)
11525 		&& (!(d->has_local_changes() & LOCAL_NON_TYPE_CHANGE_KIND)))
11526 	    || (is_var_diff(d)
11527 		&& (!(d->has_local_changes() & LOCAL_NON_TYPE_CHANGE_KIND)))
11528 	    ||  (is_class_diff(d)
11529 		&& (!(d->has_local_changes() & LOCAL_NON_TYPE_CHANGE_KIND)))))
11530       {
11531 	// Note that we handle private diff nodes differently from
11532 	// generally suppressed diff nodes.  E.g, it's not because a
11533 	// type is private (and suppressed because of that; i.e, in
11534 	// the category PRIVATE_TYPE_CATEGORY) that a typedef to that
11535 	// type should also be private and so suppressed.  Private
11536 	// diff nodes thus have different propagation rules than
11537 	// generally suppressed rules.
11538 	for (vector<diff*>::const_iterator i = d->children_nodes().begin();
11539 	     i != d->children_nodes().end();
11540 	     ++i)
11541 	  {
11542 	    diff* child = *i;
11543 	    if (child->has_changes())
11544 	      {
11545 		has_non_empty_child = true;
11546 		if (child->get_class_of_equiv_category() & SUPPRESSED_CATEGORY)
11547 		  has_suppressed_child = true;
11548 		else if (child->get_class_of_equiv_category()
11549 			 & PRIVATE_TYPE_CATEGORY)
11550 		  // Propagation of the PRIVATE_TYPE_CATEGORY is going
11551 		  // to be handled later below.
11552 		  ;
11553 		else
11554 		  has_non_suppressed_child = true;
11555 
11556 		if (child->get_class_of_equiv_category()
11557 		    & PRIVATE_TYPE_CATEGORY)
11558 		  has_private_child = true;
11559 		else if (child->get_class_of_equiv_category()
11560 			 & SUPPRESSED_CATEGORY)
11561 		  // Propagation of the SUPPRESSED_CATEGORY has been
11562 		  // handled above already.
11563 		  ;
11564 		else
11565 		  has_non_private_child = true;
11566 	      }
11567 	  }
11568 
11569 	if (has_non_empty_child
11570 	    && has_suppressed_child
11571 	    && !has_non_suppressed_child)
11572 	  {
11573 	    d->add_to_category(SUPPRESSED_CATEGORY);
11574 	    // If a node was suppressed, all the other nodes of its class
11575 	    // of equivalence are suppressed too.
11576 	    diff *canonical_diff = d->get_canonical_diff();
11577 	    if (canonical_diff != d)
11578 	      canonical_diff->add_to_category(SUPPRESSED_CATEGORY);
11579 	  }
11580 
11581 	// Note that the private-ness of a an underlying type won't be
11582 	// propagated to its parent typedef, by virtue of the big "if"
11583 	// clause at the beginning of this function.  So we don't have
11584 	// to handle that case here.  So the idiom of defining
11585 	// typedefs of private (opaque) types will be respected;
11586 	// meaning that changes to opaque underlying type will be
11587 	// flagged as private and the typedef will be flagged private
11588 	// as well, unless the typedef itself has local non-type
11589 	// changes.  In the later case, changes to the typedef will be
11590 	// emitted because the typedef won't inherit the privateness
11591 	// of its underlying type.  So in practise, the typedef
11592 	// remains public for the purpose of change reporting.
11593 	if (has_non_empty_child
11594 	    && has_private_child
11595 	    && !has_non_private_child)
11596 	  {
11597 	    d->add_to_category(PRIVATE_TYPE_CATEGORY);
11598 	    // If a node was suppressed, all the other nodes of its class
11599 	    // of equivalence are suppressed too.
11600 	    diff *canonical_diff = d->get_canonical_diff();
11601 	    if (canonical_diff != d)
11602 	      canonical_diff->add_to_category(PRIVATE_TYPE_CATEGORY);
11603 	  }
11604 
11605 	// If the underlying type of a typedef is private and carries
11606 	// changes (that are implicitely suppressed because it's
11607 	// private) then the typedef must be suppressed too, so that
11608 	// those changes to the underlying type are not seen.
11609 	if (is_typedef_diff(d)
11610 	    && !d->has_local_changes()
11611 	    && has_private_child
11612 	    && has_non_empty_child)
11613 	  {
11614 	    d->add_to_category(SUPPRESSED_CATEGORY|PRIVATE_TYPE_CATEGORY);
11615 	    // If a node was suppressed, all the other nodes of its class
11616 	    // of equivalence are suppressed too.
11617 	    diff *canonical_diff = d->get_canonical_diff();
11618 	    if (canonical_diff != d)
11619 	      canonical_diff->add_to_category
11620 		(SUPPRESSED_CATEGORY|PRIVATE_TYPE_CATEGORY);
11621 	  }
11622 
11623 	if (const function_decl_diff *fn_diff = is_function_decl_diff(d))
11624 	  if (!(d->has_local_changes() & LOCAL_NON_TYPE_CHANGE_KIND))
11625 	    {
11626 	      // d is a function diff that carries a local *type*
11627 	      // change (that means it's a change to the function
11628 	      // type).  Let's see if the child function type diff
11629 	      // node is suppressed.  That would mean that we are
11630 	      // instructed to show details of a diff that is deemed
11631 	      // suppressed; this means the suppression conflicts with
11632 	      // a local type change.  In that case, let's follow what
11633 	      // the user asked and suppress the function altogether,
11634 	      if (function_type_diff_sptr fn_type_diff = fn_diff->type_diff())
11635 		if (fn_type_diff->is_suppressed())
11636 		  {
11637 		    d->add_to_category(SUPPRESSED_CATEGORY);
11638 		    // If a node was suppressed, all the other nodes
11639 		    // of its class of equivalence are suppressed too.
11640 		    diff *canonical_diff = d->get_canonical_diff();
11641 		    if (canonical_diff != d)
11642 		      canonical_diff->add_to_category(SUPPRESSED_CATEGORY);
11643 		  }
11644 	  }
11645       }
11646   }
11647 }; //end struct suppression_categorization_visitor
11648 
11649 /// Walk a given diff-sub tree and appply the suppressions carried by
11650 /// the context.  If the suppression applies to a given node than
11651 /// categorize the node into the SUPPRESSED_CATEGORY category and
11652 /// propagate that categorization.
11653 ///
11654 /// @param diff_tree the diff-sub tree to apply the suppressions to.
11655 void
apply_suppressions(diff * diff_tree)11656 apply_suppressions(diff* diff_tree)
11657 {
11658   if (diff_tree && !diff_tree->context()->suppressions().empty())
11659     {
11660       // Apply suppressions to functions and variables that have
11661       // changed sub-types.
11662       suppression_categorization_visitor v;
11663       diff_tree->context()->forget_visited_diffs();
11664       bool s = diff_tree->context()->visiting_a_node_twice_is_forbidden();
11665       diff_tree->context()->forbid_visiting_a_node_twice(true);
11666       diff_tree->traverse(v);
11667       diff_tree->context()->forbid_visiting_a_node_twice(s);
11668     }
11669 }
11670 
11671 /// Walk a given diff-sub tree and appply the suppressions carried by
11672 /// the context.  If the suppression applies to a given node than
11673 /// categorize the node into the SUPPRESSED_CATEGORY category and
11674 /// propagate that categorization.
11675 ///
11676 /// @param diff_tree the diff-sub tree to apply the suppressions to.
11677 void
apply_suppressions(diff_sptr diff_tree)11678 apply_suppressions(diff_sptr diff_tree)
11679 {apply_suppressions(diff_tree.get());}
11680 
11681 /// Walk a @ref corpus_diff tree and appply the suppressions carried
11682 /// by the context.  If the suppression applies to a given node then
11683 /// categorize the node into the SUPPRESSED_CATEGORY category and
11684 /// propagate that categorization.
11685 ///
11686 /// @param diff_tree the diff tree to apply the suppressions to.
11687 void
apply_suppressions(const corpus_diff * diff_tree)11688 apply_suppressions(const corpus_diff* diff_tree)
11689 {
11690   if (diff_tree && !diff_tree->context()->suppressions().empty())
11691     {
11692       // First, visit the children trees of changed constructs:
11693       // changed functions, variables, as well as sub-types of these,
11694       // and apply suppression specifications to these ...
11695       suppression_categorization_visitor v;
11696       diff_tree->context()->forget_visited_diffs();
11697       bool s = diff_tree->context()->visiting_a_node_twice_is_forbidden();
11698       diff_tree->context()->forbid_visiting_a_node_twice(true);
11699       const_cast<corpus_diff*>(diff_tree)->traverse(v);
11700       diff_tree->context()->forbid_visiting_a_node_twice(s);
11701 
11702       // ... then also visit the set of added and removed functions,
11703       // variables, symbols, and types not reachable from global
11704       // functions and variables.
11705       diff_tree->priv_->
11706 	apply_supprs_to_added_removed_fns_vars_unreachable_types();
11707     }
11708 }
11709 
11710 /// Walk a diff tree and appply the suppressions carried by the
11711 /// context.  If the suppression applies to a given node than
11712 /// categorize the node into the SUPPRESSED_CATEGORY category and
11713 /// propagate that categorization.
11714 ///
11715 /// @param diff_tree the diff tree to apply the suppressions to.
11716 void
apply_suppressions(corpus_diff_sptr diff_tree)11717 apply_suppressions(corpus_diff_sptr  diff_tree)
11718 {apply_suppressions(diff_tree.get());}
11719 
11720 // </diff tree category propagation>
11721 
11722 // <diff tree printing stuff>
11723 
11724 /// A visitor to print (to an output stream) a pretty representation
11725 /// of a @ref diff sub-tree or of a complete @ref corpus_diff tree.
11726 struct diff_node_printer : public diff_node_visitor
11727 {
11728   ostream& out_;
11729   unsigned level_;
11730 
11731   /// Emit a certain number of spaces to the output stream associated
11732   /// to this diff_node_printer.
11733   ///
11734   /// @param level half of the numver of spaces to emit.
11735   void
do_indentabigail::comparison::diff_node_printer11736   do_indent(unsigned level)
11737   {
11738     for (unsigned i = 0; i < level; ++i)
11739       out_ << "  ";
11740   }
11741 
diff_node_printerabigail::comparison::diff_node_printer11742   diff_node_printer(ostream& out)
11743     : diff_node_visitor(DO_NOT_MARK_VISITED_NODES_AS_VISITED),
11744       out_(out),
11745       level_(0)
11746   {}
11747 
11748   virtual void
visit_beginabigail::comparison::diff_node_printer11749   visit_begin(diff*)
11750   {
11751     ++level_;
11752   }
11753 
11754   virtual void
visit_endabigail::comparison::diff_node_printer11755   visit_end(diff*)
11756   {
11757     --level_;
11758   }
11759 
11760   virtual void
visit_beginabigail::comparison::diff_node_printer11761   visit_begin(corpus_diff*)
11762   {
11763     ++level_;
11764   }
11765 
11766   virtual void
visit_endabigail::comparison::diff_node_printer11767   visit_end(corpus_diff*)
11768   {
11769     --level_;
11770   }
11771 
11772   virtual bool
visitabigail::comparison::diff_node_printer11773   visit(diff* d, bool pre)
11774   {
11775     if (!pre)
11776       // We are post-visiting the diff node D.  Which means, we have
11777       // printed a pretty representation for it already.  So do
11778       // nothing now.
11779       return true;
11780 
11781     do_indent(level_);
11782     out_ << d->get_pretty_representation();
11783     out_ << "\n";
11784     do_indent(level_);
11785     out_ << "{\n";
11786     do_indent(level_ + 1);
11787     out_ << "category: "<< d->get_category() << "\n";
11788     do_indent(level_ + 1);
11789     out_ << "@: " << std::hex << d << std::dec << "\n";
11790     do_indent(level_ + 1);
11791     out_ << "@-canonical: " << std::hex
11792 	 << d->get_canonical_diff()
11793 	 << std::dec << "\n";
11794     do_indent(level_);
11795     out_ << "}\n";
11796 
11797     return true;
11798   }
11799 
11800   virtual bool
visitabigail::comparison::diff_node_printer11801   visit(corpus_diff* d, bool pre)
11802   {
11803     if (!pre)
11804       // We are post-visiting the diff node D.  Which means, we have
11805       // printed a pretty representation for it already.  So do
11806       // nothing now.
11807       return true;
11808 
11809     // indent
11810     for (unsigned i = 0; i < level_; ++i)
11811       out_ << ' ';
11812     out_ << d->get_pretty_representation();
11813     out_ << '\n';
11814     return true;
11815   }
11816 }; // end struct diff_printer_visitor
11817 
11818 // </ diff tree printing stuff>
11819 
11820 /// Emit a textual representation of a @ref diff sub-tree to an
11821 /// output stream.
11822 ///
11823 /// @param diff_tree the sub-tree to emit the textual representation
11824 /// for.
11825 ///
11826 /// @param out the output stream to emit the textual representation
11827 /// for @p diff_tree to.
11828 void
print_diff_tree(diff * diff_tree,ostream & out)11829 print_diff_tree(diff* diff_tree, ostream& out)
11830 {
11831   diff_node_printer p(out);
11832   bool s = diff_tree->context()->visiting_a_node_twice_is_forbidden();
11833   diff_tree->context()->forbid_visiting_a_node_twice(false);
11834   diff_tree->traverse(p);
11835   diff_tree->context()->forbid_visiting_a_node_twice(s);
11836 }
11837 
11838 /// Emit a textual representation of a @ref corpus_diff tree to an
11839 /// output stream.
11840 ///
11841 /// @param diff_tree the @ref corpus_diff tree to emit the textual
11842 /// representation for.
11843 ///
11844 /// @param out the output stream to emit the textual representation
11845 /// for @p diff_tree to.
11846 void
print_diff_tree(corpus_diff * diff_tree,std::ostream & out)11847 print_diff_tree(corpus_diff* diff_tree, std::ostream& out)
11848 {
11849   diff_node_printer p(out);
11850   bool s = diff_tree->context()->visiting_a_node_twice_is_forbidden();
11851   diff_tree->context()->forbid_visiting_a_node_twice(false);
11852   diff_tree->traverse(p);
11853   diff_tree->context()->forbid_visiting_a_node_twice(s);
11854 }
11855 
11856 /// Emit a textual representation of a @ref diff sub-tree to an
11857 /// output stream.
11858 ///
11859 /// @param diff_tree the sub-tree to emit the textual representation
11860 /// for.
11861 ///
11862 /// @param out the output stream to emit the textual representation
11863 /// for @p diff_tree to.
11864 void
print_diff_tree(diff_sptr diff_tree,std::ostream & o)11865 print_diff_tree(diff_sptr diff_tree,
11866 		std::ostream& o)
11867 {print_diff_tree(diff_tree.get(), o);}
11868 
11869 /// Emit a textual representation of a @ref corpus_diff tree to an
11870 /// output stream.
11871 ///
11872 /// @param diff_tree the @ref corpus_diff tree to emit the textual
11873 /// representation for.
11874 ///
11875 /// @param out the output stream to emit the textual representation
11876 /// for @p diff_tree to.
11877 void
print_diff_tree(corpus_diff_sptr diff_tree,std::ostream & o)11878 print_diff_tree(corpus_diff_sptr diff_tree,
11879 		std::ostream& o)
11880 {print_diff_tree(diff_tree.get(), o);}
11881 
11882 // <redundancy_marking_visitor>
11883 
11884 /// A tree visitor to categorize nodes with respect to the
11885 /// REDUNDANT_CATEGORY.  That is, detect if a node is redundant (is
11886 /// present on several spots of the tree) and mark such nodes
11887 /// appropriatly.  This visitor also takes care of propagating the
11888 /// REDUNDANT_CATEGORY of a given node to its parent nodes as
11889 /// appropriate.
11890 struct redundancy_marking_visitor : public diff_node_visitor
11891 {
11892   bool skip_children_nodes_;
11893 
redundancy_marking_visitorabigail::comparison::redundancy_marking_visitor11894   redundancy_marking_visitor()
11895     : skip_children_nodes_()
11896   {}
11897 
11898   virtual void
visit_beginabigail::comparison::redundancy_marking_visitor11899   visit_begin(diff* d)
11900   {
11901     if (d->to_be_reported())
11902       {
11903 	// A diff node that carries a change and that has been already
11904 	// traversed elsewhere is considered redundant.  So let's mark
11905 	// it as such and let's not traverse it; that is, let's not
11906 	// visit its children.
11907 	if ((d->context()->diff_has_been_visited(d)
11908 	     || d->get_canonical_diff()->is_traversing())
11909 	    && d->has_changes())
11910 	  {
11911 	    // But if two diff nodes are redundant sibbling that carry
11912 	    // changes of base types, do not mark them as being
11913 	    // redundant.  This is to avoid marking nodes as redundant
11914 	    // in this case:
11915 	    //
11916 	    //     int foo(int a, int b);
11917 	    // compared with:
11918 	    //     float foo(float a, float b); (in C).
11919 	    //
11920 	    // In this case, we want to report all the occurences of
11921 	    // the int->float change because logically, they are at
11922 	    // the same level in the diff tree.
11923 
11924 	    bool redundant_with_sibling_node = false;
11925 	    const diff* p = d->parent_node();
11926 
11927 	    // If this is a child node of a fn_parm_diff, look through
11928 	    // the fn_parm_diff node to get the function diff node.
11929 	    if (p && dynamic_cast<const fn_parm_diff*>(p))
11930 	      p = p->parent_node();
11931 
11932 	    if (p)
11933 	      for (vector<diff*>::const_iterator s =
11934 		     p->children_nodes().begin();
11935 		   s != p->children_nodes().end();
11936 		   ++s)
11937 		{
11938 		  if (*s == d)
11939 		    continue;
11940 		  diff* sib = *s;
11941 		  // If this is a fn_parm_diff, look through the
11942 		  // fn_parm_diff node to get at the real type node.
11943 		  if (fn_parm_diff* f = dynamic_cast<fn_parm_diff*>(*s))
11944 		    sib = f->type_diff().get();
11945 		  if (sib == d)
11946 		    continue;
11947 		  if (sib->get_canonical_diff() == d->get_canonical_diff()
11948 		      // Sibbling diff nodes that carry base type
11949 		      // changes ar to be marked as redundant.
11950 		      && (is_base_diff(sib) || is_distinct_diff(sib)))
11951 		    {
11952 		      redundant_with_sibling_node = true;
11953 		      break;
11954 		    }
11955 		}
11956 	    if (!redundant_with_sibling_node
11957 		// Changes to basic types should never be considered
11958 		// redundant.  For instance, if a member of integer
11959 		// type is changed into a char type in both a struct A
11960 		// and a struct B, we want to see both changes.
11961 		&& !has_basic_type_change_only(d)
11962 		// The same goes for distinct type changes
11963 		&& !filtering::is_mostly_distinct_diff(d)
11964 		// Functions with similar *local* changes are never marked
11965 		// redundant because otherwise one could miss important
11966 		// similar local changes that are applied to different
11967 		// functions.
11968 		&& !is_function_type_diff_with_local_changes(d)
11969 		// Changes involving variadic parameters of functions
11970 		// should never be marked redundant because we want to see
11971 		// them all.
11972 		&& !is_diff_of_variadic_parameter(d)
11973 		&& !is_diff_of_variadic_parameter_type(d)
11974 		// If the canonical diff itself has been filtered out,
11975 		// then this one is not marked redundant, unless the
11976 		// canonical diff was already redundant.
11977 		&& (!d->get_canonical_diff()->is_filtered_out()
11978 		    || (d->get_canonical_diff()->get_category()
11979 			& REDUNDANT_CATEGORY))
11980 		// If the *same* diff node (not one that is merely
11981 		// equivalent to this one) has already been visited
11982 		// the do not mark it as beind redundant.  It's only
11983 		// the other nodes that are equivalent to this one
11984 		// that must be marked redundant.
11985 		&& d->context()->diff_has_been_visited(d) != d
11986 		// If the diff node is a function parameter and is not
11987 		// a reference/pointer (to a non basic or a non
11988 		// distinct type diff) then do not mark it as
11989 		// redundant.
11990 		//
11991 		// Children nodes of base class diff nodes are never
11992 		// redundant either, we want to see them all.
11993 		&& (is_reference_or_ptr_diff_to_non_basic_nor_distinct_types(d)
11994 		    || (!is_child_node_of_function_parm_diff(d)
11995 			&& !is_child_node_of_base_diff(d))))
11996 	      {
11997 		d->add_to_category(REDUNDANT_CATEGORY);
11998 		// As we said in preamble, as this node is marked as
11999 		// being redundant, let's not visit its children.
12000 		// This is not an optimization; it's needed for
12001 		// correctness.  In the case of a diff node involving
12002 		// a class type that refers to himself, visiting the
12003 		// children nodes might cause them to be wrongly
12004 		// marked as redundant.
12005 		set_visiting_kind(get_visiting_kind()
12006 				  | SKIP_CHILDREN_VISITING_KIND);
12007 		skip_children_nodes_ = true;
12008 	      }
12009 	  }
12010       }
12011     else
12012       {
12013 	// If the node is not to be reported, do not look at it children.
12014 	set_visiting_kind(get_visiting_kind() | SKIP_CHILDREN_VISITING_KIND);
12015 	skip_children_nodes_ = true;
12016       }
12017   }
12018 
12019   virtual void
visit_beginabigail::comparison::redundancy_marking_visitor12020   visit_begin(corpus_diff*)
12021   {
12022   }
12023 
12024   virtual void
visit_endabigail::comparison::redundancy_marking_visitor12025   visit_end(diff* d)
12026   {
12027     if (skip_children_nodes_)
12028       // When visiting this node, we decided to skip its children
12029       // node.  Now that we are done visiting the node, lets stop
12030       // avoiding the children nodes visiting for the other tree
12031       // nodes.
12032       {
12033 	set_visiting_kind(get_visiting_kind() & (~SKIP_CHILDREN_VISITING_KIND));
12034 	skip_children_nodes_ = false;
12035       }
12036     else
12037       {
12038 	// Propagate the redundancy categorization of the children nodes
12039 	// to this node.  But if this node has local changes, then it
12040 	// doesn't inherit redundancy from its children nodes.
12041 	if (!(d->get_category() & REDUNDANT_CATEGORY)
12042 	    && (!d->has_local_changes_to_be_reported()
12043 		// By default, pointer, reference and qualified types
12044 		// consider that a local changes to their underlying
12045 		// type is always a local change for themselves.
12046 		//
12047 		// This is as if those types don't have local changes
12048 		// in the same sense as other types.  So we always
12049 		// propagate redundancy to them, regardless of if they
12050 		// have local changes or not.
12051 		//
12052 		// We also propagate redundancy to typedef types if
12053 		// these /only/ carry changes to their underlying
12054 		// type.
12055 		//
12056 		// Note that changes to the underlying type of a
12057 		// typedef is considered local of
12058 		// LOCAL_TYPE_CHANGE_KIND kind.  The other changes to the
12059 		// typedef itself are considered local of
12060 		// LOCAL_NON_TYPE_CHANGE_KIND kind.
12061 		|| is_pointer_diff(d)
12062 		|| is_qualified_type_diff(d)
12063 		// A typedef with local non-type changes should not
12064 		// see redundancy propagation from its underlying
12065 		// type, otherwise, the non-type change might be
12066 		// "suppressed" away.
12067 		|| (is_typedef_diff(d)
12068 		    && (!(d->has_local_changes()
12069 			  & LOCAL_NON_TYPE_CHANGE_KIND)))
12070 		// A (member) variable with non-type local changes
12071 		// should not see redundacy propagation from its type.
12072 		// If redundant local-type changes are carried by its
12073 		// type however, then that redundancy is propagated to
12074 		// the variable.  This is key to keep the redundancy
12075 		// consistency in the system; otherwise, a type change
12076 		// would be rightfully considered redundant at some
12077 		// places but not at others.
12078 		|| (is_var_diff(d)
12079 		    && (!(d->has_local_changes()
12080 			  & LOCAL_NON_TYPE_CHANGE_KIND)))
12081 		))
12082 	  {
12083 	    bool has_non_redundant_child = false;
12084 	    bool has_non_empty_child = false;
12085 	    for (vector<diff*>::const_iterator i =
12086 		   d->children_nodes().begin();
12087 		 i != d->children_nodes().end();
12088 		 ++i)
12089 	      {
12090 		if ((*i)->has_changes())
12091 		  {
12092 		    has_non_empty_child = true;
12093 		    // Let's see if the current child node '*i' is
12094 		    // "non-redundant".
12095 		    //
12096 		    // A non-redundant node would be a node that
12097 		    // carries a change to be reported and has not
12098 		    // been marked as being redundant.
12099 		    if ((*i)->to_be_reported()
12100 			&& ((*i)->get_category() & REDUNDANT_CATEGORY) == 0)
12101 		      has_non_redundant_child = true;
12102 		  }
12103 		if (has_non_redundant_child)
12104 		  break;
12105 	      }
12106 
12107 	    // A diff node for which at least a child node carries a
12108 	    // change, and for which all the children are redundant is
12109 	    // deemed redundant too, unless it has local changes.
12110 	    if (has_non_empty_child
12111 		&& !has_non_redundant_child)
12112 	      d->add_to_category(REDUNDANT_CATEGORY);
12113 	  }
12114       }
12115   }
12116 
12117   virtual void
visit_endabigail::comparison::redundancy_marking_visitor12118   visit_end(corpus_diff*)
12119   {
12120   }
12121 
12122   virtual bool
visitabigail::comparison::redundancy_marking_visitor12123   visit(diff*, bool)
12124   {return true;}
12125 
12126   virtual bool
visitabigail::comparison::redundancy_marking_visitor12127   visit(corpus_diff*, bool)
12128   {
12129     return true;
12130   }
12131 };// end struct redundancy_marking_visitor
12132 
12133 /// A visitor of @ref diff nodes that clears the REDUNDANT_CATEGORY
12134 /// category out of the nodes.
12135 struct redundancy_clearing_visitor : public diff_node_visitor
12136 {
12137   bool
visitabigail::comparison::redundancy_clearing_visitor12138   visit(corpus_diff*, bool)
12139   {return true;}
12140 
12141   bool
visitabigail::comparison::redundancy_clearing_visitor12142   visit(diff* d, bool)
12143   {
12144     // clear the REDUNDANT_CATEGORY out of the current node.
12145     diff_category c = d->get_category();
12146     c &= ~REDUNDANT_CATEGORY;
12147     d->set_category(c);
12148     return true;
12149   }
12150 }; // end struct redundancy_clearing_visitor
12151 
12152 /// Walk a given @ref diff sub-tree to categorize each of the nodes
12153 /// with respect to the REDUNDANT_CATEGORY.
12154 ///
12155 /// @param diff_tree the @ref diff sub-tree to walk.
12156 void
categorize_redundancy(diff * diff_tree)12157 categorize_redundancy(diff* diff_tree)
12158 {
12159   if (diff_tree->context()->show_redundant_changes())
12160     return;
12161   redundancy_marking_visitor v;
12162   bool s = diff_tree->context()->visiting_a_node_twice_is_forbidden();
12163   diff_tree->context()->forbid_visiting_a_node_twice(false);
12164   diff_tree->traverse(v);
12165   diff_tree->context()->forbid_visiting_a_node_twice(s);
12166 }
12167 
12168 /// Walk a given @ref diff sub-tree to categorize each of the nodes
12169 /// with respect to the REDUNDANT_CATEGORY.
12170 ///
12171 /// @param diff_tree the @ref diff sub-tree to walk.
12172 void
categorize_redundancy(diff_sptr diff_tree)12173 categorize_redundancy(diff_sptr diff_tree)
12174 {categorize_redundancy(diff_tree.get());}
12175 
12176 /// Walk a given @ref corpus_diff tree to categorize each of the nodes
12177 /// with respect to the REDUNDANT_CATEGORY.
12178 ///
12179 /// @param diff_tree the @ref corpus_diff tree to walk.
12180 void
categorize_redundancy(corpus_diff * diff_tree)12181 categorize_redundancy(corpus_diff* diff_tree)
12182 {
12183   redundancy_marking_visitor v;
12184   diff_tree->context()->forget_visited_diffs();
12185   bool s = diff_tree->context()->visiting_a_node_twice_is_forbidden();
12186   diff_tree->context()->forbid_visiting_a_node_twice(false);
12187   diff_tree->traverse(v);
12188   diff_tree->context()->forbid_visiting_a_node_twice(s);
12189 }
12190 
12191 /// Walk a given @ref corpus_diff tree to categorize each of the nodes
12192 /// with respect to the REDUNDANT_CATEGORY.
12193 ///
12194 /// @param diff_tree the @ref corpus_diff tree to walk.
12195 void
categorize_redundancy(corpus_diff_sptr diff_tree)12196 categorize_redundancy(corpus_diff_sptr diff_tree)
12197 {categorize_redundancy(diff_tree.get());}
12198 
12199 // </redundancy_marking_visitor>
12200 
12201 /// Walk a given @ref diff sub-tree to clear the REDUNDANT_CATEGORY
12202 /// out of the category of the nodes.
12203 ///
12204 /// @param diff_tree the @ref diff sub-tree to walk.
12205 void
clear_redundancy_categorization(diff * diff_tree)12206 clear_redundancy_categorization(diff* diff_tree)
12207 {
12208   redundancy_clearing_visitor v;
12209   bool s = diff_tree->context()->visiting_a_node_twice_is_forbidden();
12210   diff_tree->context()->forbid_visiting_a_node_twice(false);
12211   diff_tree->traverse(v);
12212   diff_tree->context()->forbid_visiting_a_node_twice(s);
12213   diff_tree->context()->forget_visited_diffs();
12214 }
12215 
12216 /// Walk a given @ref diff sub-tree to clear the REDUNDANT_CATEGORY
12217 /// out of the category of the nodes.
12218 ///
12219 /// @param diff_tree the @ref diff sub-tree to walk.
12220 void
clear_redundancy_categorization(diff_sptr diff_tree)12221 clear_redundancy_categorization(diff_sptr diff_tree)
12222 {clear_redundancy_categorization(diff_tree.get());}
12223 
12224 /// Walk a given @ref corpus_diff tree to clear the REDUNDANT_CATEGORY
12225 /// out of the category of the nodes.
12226 ///
12227 /// @param diff_tree the @ref corpus_diff tree to walk.
12228 void
clear_redundancy_categorization(corpus_diff * diff_tree)12229 clear_redundancy_categorization(corpus_diff* diff_tree)
12230 {
12231   redundancy_clearing_visitor v;
12232   bool s = diff_tree->context()->visiting_a_node_twice_is_forbidden();
12233   diff_tree->context()->forbid_visiting_a_node_twice(false);
12234   diff_tree->traverse(v);
12235   diff_tree->context()->forbid_visiting_a_node_twice(s);
12236   diff_tree->context()->forget_visited_diffs();
12237 }
12238 
12239 /// Walk a given @ref corpus_diff tree to clear the REDUNDANT_CATEGORY
12240 /// out of the category of the nodes.
12241 ///
12242 /// @param diff_tree the @ref corpus_diff tree to walk.
12243 void
clear_redundancy_categorization(corpus_diff_sptr diff_tree)12244 clear_redundancy_categorization(corpus_diff_sptr diff_tree)
12245 {clear_redundancy_categorization(diff_tree.get());}
12246 
12247 /// Apply the @ref diff tree filters that have been associated to the
12248 /// context of the a given @ref corpus_diff tree.  As a result, the
12249 /// nodes of the @diff tree are going to be categorized into one of
12250 /// several of the categories of @ref diff_category.
12251 ///
12252 /// @param diff_tree the @ref corpus_diff instance which @ref diff are
12253 /// to be categorized.
12254 void
apply_filters(corpus_diff_sptr diff_tree)12255 apply_filters(corpus_diff_sptr diff_tree)
12256 {
12257   diff_tree->context()->maybe_apply_filters(diff_tree);
12258   propagate_categories(diff_tree);
12259 }
12260 
12261 /// Test if a diff node represents the difference between a variadic
12262 /// parameter type and something else.
12263 ///
12264 /// @param d the diff node to consider.
12265 ///
12266 /// @return true iff @p d is a diff node that represents the
12267 /// difference between a variadic parameter type and something else.
12268 bool
is_diff_of_variadic_parameter_type(const diff * d)12269 is_diff_of_variadic_parameter_type(const diff* d)
12270 {
12271   if (!d)
12272     return false;
12273 
12274   type_base_sptr t = is_type(d->first_subject());
12275   if (t && t->get_environment()->is_variadic_parameter_type(t))
12276     return true;
12277 
12278   t = is_type(d->second_subject());
12279   if (t && t->get_environment()->is_variadic_parameter_type(t))
12280     return true;
12281 
12282   return false;
12283 }
12284 
12285 /// Test if a diff node represents the difference between a variadic
12286 /// parameter type and something else.
12287 ///
12288 /// @param d the diff node to consider.
12289 ///
12290 /// @return true iff @p d is a diff node that represents the
12291 /// difference between a variadic parameter type and something else.
12292 bool
is_diff_of_variadic_parameter_type(const diff_sptr & d)12293 is_diff_of_variadic_parameter_type(const diff_sptr& d)
12294 {return is_diff_of_variadic_parameter_type(d.get());}
12295 
12296 /// Test if a diff node represents the difference between a variadic
12297 /// parameter and something else.
12298 ///
12299 /// @param d the diff node to consider.
12300 ///
12301 /// @return true iff @p d is a diff node that represents the
12302 /// difference between a variadic parameter and something else.
12303 bool
is_diff_of_variadic_parameter(const diff * d)12304 is_diff_of_variadic_parameter(const diff* d)
12305 {
12306   fn_parm_diff* diff =
12307     dynamic_cast<fn_parm_diff*>(const_cast<abigail::comparison::diff*>(d));
12308   return (diff && is_diff_of_variadic_parameter_type(diff->type_diff()));
12309 }
12310 
12311 /// Test if a diff node represents the difference between a variadic
12312 /// parameter and something else.
12313 ///
12314 /// @param d the diff node to consider.
12315 ///
12316 /// @return true iff @p d is a diff node that represents the
12317 /// difference between a variadic parameter and something else.
12318 bool
is_diff_of_variadic_parameter(const diff_sptr & d)12319 is_diff_of_variadic_parameter(const diff_sptr& d)
12320 {return is_diff_of_variadic_parameter(d.get());}
12321 
12322 /// Test if a diff node represents a diff between two basic types.
12323 ///
12324 /// @param d the diff node to consider.
12325 ///
12326 /// @return true iff @p d is a diff between two basic types.
12327 const type_decl_diff*
is_diff_of_basic_type(const diff * d)12328 is_diff_of_basic_type(const diff *d)
12329 {return dynamic_cast<const type_decl_diff*>(d);}
12330 
12331 /// Test if a diff node represents a diff between two basic types, or
12332 /// between pointers, references or qualified type to basic types.
12333 ///
12334 /// @param diff the diff node to consider.
12335 ///
12336 /// @param allow_indirect_type if true, then this function looks into
12337 /// pointer, reference or qualified diff types to see if they "point
12338 /// to" basic types.
12339 ///
12340 /// @return true iff @p d is a diff between two basic types.
12341 const type_decl_diff*
is_diff_of_basic_type(const diff * diff,bool allow_indirect_type)12342 is_diff_of_basic_type(const diff* diff, bool allow_indirect_type)
12343 {
12344   if (allow_indirect_type)
12345       diff = peel_pointer_or_qualified_type_diff(diff);
12346   return is_diff_of_basic_type(diff);
12347 }
12348 
12349 /// If a diff node is about changes between two typedef types, get the
12350 /// diff node about changes between the underlying types.
12351 ///
12352 /// Note that this function walks the tree of underlying diff nodes
12353 /// returns the first diff node about types that are not typedefs.
12354 ///
12355 /// @param dif the dif node to consider.
12356 ///
12357 /// @return the underlying diff node of @p dif, or just return @p dif
12358 /// if it's not a typedef diff node.
12359 const diff*
peel_typedef_diff(const diff * dif)12360 peel_typedef_diff(const diff* dif)
12361 {
12362   const typedef_diff *d = 0;
12363   while ((d = is_typedef_diff(dif)))
12364     dif = d->underlying_type_diff().get();
12365   return dif;
12366 }
12367 
12368 /// If a diff node is about changes between two pointer types, get the
12369 /// diff node about changes between the underlying (pointed-to) types.
12370 ///
12371 /// Note that this function walks the tree of underlying diff nodes
12372 /// returns the first diff node about types that are not pointers.
12373 ///
12374 /// @param dif the dif node to consider.
12375 ///
12376 /// @return the underlying diff node of @p dif, or just return @p dif
12377 /// if it's not a pointer diff node.
12378 const diff*
peel_pointer_diff(const diff * dif)12379 peel_pointer_diff(const diff* dif)
12380 {
12381   const pointer_diff *d = 0;
12382   while ((d = is_pointer_diff(dif)))
12383     dif = d->underlying_type_diff().get();
12384   return dif;
12385 }
12386 
12387 /// If a diff node is about changes between two reference types, get
12388 /// the diff node about changes between the underlying (pointed-to)
12389 /// types.
12390 ///
12391 /// Note that this function walks the tree of underlying diff nodes
12392 /// returns the first diff node about types that are not references.
12393 ///
12394 /// @param dif the dif node to consider.
12395 ///
12396 /// @return the underlying diff node of @p dif, or just return @p dif
12397 /// if it's not a reference diff node.
12398 const diff*
peel_reference_diff(const diff * dif)12399 peel_reference_diff(const diff* dif)
12400 {
12401   const reference_diff *d = 0;
12402   while ((d = is_reference_diff(dif)))
12403     dif = d->underlying_type_diff().get();
12404   return dif;
12405 }
12406 
12407 /// If a diff node is about changes between two qualified types, get
12408 /// the diff node about changes between the underlying (non-qualified)
12409 /// types.
12410 ///
12411 /// Note that this function walks the tree of underlying diff nodes
12412 /// returns the first diff node about types that are not qualified.
12413 ///
12414 /// @param dif the dif node to consider.
12415 ///
12416 /// @return the underlying diff node of @p dif, or just return @p dif
12417 /// if it's not a qualified diff node.
12418 const diff*
peel_qualified_diff(const diff * dif)12419 peel_qualified_diff(const diff* dif)
12420 {
12421   const qualified_type_diff *d = 0;
12422   while ((d = is_qualified_type_diff(dif)))
12423     dif = d->underlying_type_diff().get();
12424   return dif;
12425 }
12426 
12427 /// If a diff node is about changes between two pointer, reference or
12428 /// qualified types, get the diff node about changes between the
12429 /// underlying types.
12430 ///
12431 /// Note that this function walks the tree of underlying diff nodes
12432 /// returns the first diff node about types that are not pointer,
12433 /// reference or qualified.
12434 ///
12435 /// @param dif the dif node to consider.
12436 ///
12437 /// @return the underlying diff node of @p dif, or just return @p dif
12438 /// if it's not a pointer, reference or qualified diff node.
12439 const diff*
peel_pointer_or_qualified_type_diff(const diff * dif)12440 peel_pointer_or_qualified_type_diff(const diff*dif)
12441 {
12442   while (true)
12443     {
12444       if (const pointer_diff *d = is_pointer_diff(dif))
12445 	dif = peel_pointer_diff(d);
12446       else if (const reference_diff *d = is_reference_diff(dif))
12447 	dif = peel_reference_diff(d);
12448       else if (const qualified_type_diff *d = is_qualified_type_diff(dif))
12449 	dif = peel_qualified_diff(d);
12450       else
12451 	break;
12452     }
12453   return dif;
12454 }
12455 
12456 /// If a diff node is about changes between two typedefs or qualified
12457 /// types, get the diff node about changes between the underlying
12458 /// types.
12459 ///
12460 /// Note that this function walks the tree of underlying diff nodes
12461 /// returns the first diff node about types that are not typedef or
12462 /// qualified types.
12463 ///
12464 /// @param dif the dif node to consider.
12465 ///
12466 /// @return the underlying diff node of @p dif, or just return @p dif
12467 /// if it's not typedef or qualified diff node.
12468 const diff*
peel_typedef_or_qualified_type_diff(const diff * dif)12469 peel_typedef_or_qualified_type_diff(const diff *dif)
12470 {
12471   while (true)
12472     {
12473       if (const typedef_diff *d = is_typedef_diff(dif))
12474 	dif = peel_typedef_diff(d);
12475       else if (const qualified_type_diff *d = is_qualified_type_diff(dif))
12476 	dif = peel_qualified_diff(d);
12477       else
12478 	break;
12479     }
12480   return dif;
12481 }
12482 
12483 /// Test if a diff node represents a diff between two class or union
12484 /// types.
12485 ///
12486 /// @param d the diff node to consider.
12487 ///
12488 /// @return iff @p is a diff between two class or union types then
12489 /// return the instance of @ref class_or_union_diff that @p derives
12490 /// from.  Otherwise, return nil.
12491 const class_or_union_diff*
is_diff_of_class_or_union_type(const diff * d)12492 is_diff_of_class_or_union_type(const diff *d)
12493 {return dynamic_cast<const class_or_union_diff*>(d);}
12494 
12495 /// Test if a given diff node carries *only* a local type change.
12496 ///
12497 /// @param d the diff node to consider.
12498 ///
12499 /// @return true iff @p has a change and that change is a local type
12500 /// change.
12501 static bool
has_local_type_change_only(const diff * d)12502 has_local_type_change_only(const diff *d)
12503 {
12504   if (enum change_kind k = d->has_local_changes())
12505     if ((k & LOCAL_NON_TYPE_CHANGE_KIND) == 0
12506 	&& (k & LOCAL_TYPE_CHANGE_KIND) != 0)
12507       return true;
12508 
12509   return false;
12510 }
12511 
12512 /// Test if a diff node is a decl diff that only carries a basic type
12513 /// change on its type diff sub-node.
12514 ///
12515 ///Note that that pointers/references/qualified types diffs to basic
12516 /// type diffs are considered as having basic type change only.
12517 ///
12518 /// @param d the diff node to consider.
12519 ///
12520 /// @return true iff @p d is a decl diff that only carries a basic
12521 /// type change on its type diff sub-node.
12522 bool
has_basic_type_change_only(const diff * d)12523 has_basic_type_change_only(const diff *d)
12524 {
12525   if (is_diff_of_basic_type(d, true) && d->has_changes())
12526     return true;
12527   else if (const var_diff * v = dynamic_cast<const var_diff*>(d))
12528     return (has_local_type_change_only(v)
12529 	    && is_diff_of_basic_type(v->type_diff().get(), true));
12530   else if (const fn_parm_diff * p = dynamic_cast<const fn_parm_diff*>(d))
12531     return (has_local_type_change_only(p)
12532 	    && is_diff_of_basic_type(p->type_diff().get(), true));
12533   else if (const function_decl_diff* f =
12534 	   dynamic_cast<const function_decl_diff*>(d))
12535     return (has_local_type_change_only(f)
12536 	    && f->type_diff()
12537 	    && is_diff_of_basic_type(f->type_diff()->return_type_diff().get(),
12538 				     true));
12539   return false;
12540 }
12541 }// end namespace comparison
12542 } // end namespace abigail
12543