• 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 /// A getter for the flag that says if we should flag indirect class
1671 /// and union changes in leaf-changes-only mode.
1672 ///
1673 /// @return the flag.
1674 bool
flag_indirect_changes() const1675 diff_context::flag_indirect_changes() const
1676 {return priv_->flag_indirect_changes_;}
1677 
1678 /// A setter for the flag that says if we should flag indirect class
1679 /// and union changes in leaf-changes-only mode.
1680 ///
1681 /// @param f the flag to set.
1682 void
flag_indirect_changes(bool f)1683 diff_context::flag_indirect_changes(bool f)
1684 {priv_->flag_indirect_changes_ = f;}
1685 
1686 /// Getter for the flag that indicates if symbols not referenced by
1687 /// any debug info are to be compared and reported about.
1688 ///
1689 /// @return the boolean flag.
1690 bool
show_symbols_unreferenced_by_debug_info() const1691 diff_context::show_symbols_unreferenced_by_debug_info() const
1692 {return priv_->show_syms_unreferenced_by_di_;}
1693 
1694 /// Setter for the flag that indicates if symbols not referenced by
1695 /// any debug info are to be compared and reported about.
1696 ///
1697 /// @param f the new flag to set.
1698 void
show_symbols_unreferenced_by_debug_info(bool f)1699 diff_context::show_symbols_unreferenced_by_debug_info(bool f)
1700 {priv_->show_syms_unreferenced_by_di_ = f;}
1701 
1702 /// Getter for the flag that indicates if symbols not referenced by
1703 /// any debug info and that got added are to be reported about.
1704 ///
1705 /// @return true iff symbols not referenced by any debug info and that
1706 /// got added are to be reported about.
1707 bool
show_added_symbols_unreferenced_by_debug_info() const1708 diff_context::show_added_symbols_unreferenced_by_debug_info() const
1709 {return priv_->show_added_syms_unreferenced_by_di_;}
1710 
1711 /// Setter for the flag that indicates if symbols not referenced by
1712 /// any debug info and that got added are to be reported about.
1713 ///
1714 /// @param f the new flag that says if symbols not referenced by any
1715 /// debug info and that got added are to be reported about.
1716 void
show_added_symbols_unreferenced_by_debug_info(bool f)1717 diff_context::show_added_symbols_unreferenced_by_debug_info(bool f)
1718 {priv_->show_added_syms_unreferenced_by_di_ = f;}
1719 
1720 /// Setter for the flag that indicates if changes on types unreachable
1721 /// from global functions and variables are to be reported.
1722 ///
1723 /// @param f if true, then changes on types unreachable from global
1724 /// functions and variables are to be reported.
1725 void
show_unreachable_types(bool f)1726 diff_context::show_unreachable_types(bool f)
1727 {priv_->show_unreachable_types_ = f;}
1728 
1729 /// Getter for the flag that indicates if changes on types unreachable
1730 /// from global functions and variables are to be reported.
1731 ///
1732 /// @return true iff changes on types unreachable from global
1733 /// functions and variables are to be reported.
1734 bool
show_unreachable_types()1735 diff_context::show_unreachable_types()
1736 {return priv_->show_unreachable_types_;}
1737 
1738 /// Getter of the flag that indicates if the leaf reporter should
1739 /// display a summary of the interfaces impacted by a given leaf
1740 /// change or not.
1741 ///
1742 /// @return the flag that indicates if the leaf reporter should
1743 /// display a summary of the interfaces impacted by a given leaf
1744 /// change or not.
1745 bool
show_impacted_interfaces() const1746 diff_context::show_impacted_interfaces() const
1747 {return priv_->show_impacted_interfaces_;}
1748 
1749 /// Setter of the flag that indicates if the leaf reporter should
1750 /// display a summary of the interfaces impacted by a given leaf
1751 /// change or not.
1752 ///
1753 /// @param f the new value of the flag that indicates if the leaf
1754 /// reporter should display a summary of the interfaces impacted by a
1755 /// given leaf change or not.
1756 void
show_impacted_interfaces(bool f)1757 diff_context::show_impacted_interfaces(bool f)
1758 {priv_->show_impacted_interfaces_ = f;}
1759 
1760 /// Setter for the default output stream used by code of the
1761 /// comparison engine.  By default the default output stream is a NULL
1762 /// pointer.
1763 ///
1764 /// @param o a pointer to the default output stream.
1765 void
default_output_stream(ostream * o)1766 diff_context::default_output_stream(ostream* o)
1767 {priv_->default_output_stream_ = o;}
1768 
1769 /// Getter for the default output stream used by code of the
1770 /// comparison engine.  By default the default output stream is a NULL
1771 /// pointer.
1772 ///
1773 /// @return a pointer to the default output stream.
1774 ostream*
default_output_stream()1775 diff_context::default_output_stream()
1776 {return priv_->default_output_stream_;}
1777 
1778 /// Setter for the errror output stream used by code of the comparison
1779 /// engine.  By default the error output stream is a NULL pointer.
1780 ///
1781 /// @param o a pointer to the error output stream.
1782 void
error_output_stream(ostream * o)1783 diff_context::error_output_stream(ostream* o)
1784 {priv_->error_output_stream_ = o;}
1785 
1786 /// Getter for the errror output stream used by code of the comparison
1787 /// engine.  By default the error output stream is a NULL pointer.
1788 ///
1789 /// @return a pointer to the error output stream.
1790 ostream*
error_output_stream() const1791 diff_context::error_output_stream() const
1792 {return priv_->error_output_stream_;}
1793 
1794 /// Test if the comparison engine should dump the diff tree for the
1795 /// changed functions and variables it has.
1796 ///
1797 /// @return true if after the comparison, the engine should dump the
1798 /// diff tree for the changed functions and variables it has.
1799 bool
dump_diff_tree() const1800 diff_context::dump_diff_tree() const
1801 {return priv_->dump_diff_tree_;}
1802 
1803 /// Set if the comparison engine should dump the diff tree for the
1804 /// changed functions and variables it has.
1805 ///
1806 /// @param f true if after the comparison, the engine should dump the
1807 /// diff tree for the changed functions and variables it has.
1808 void
dump_diff_tree(bool f)1809 diff_context::dump_diff_tree(bool f)
1810 {priv_->dump_diff_tree_ = f;}
1811 
1812 /// Emit a textual representation of a diff tree to the error output
1813 /// stream of the current context, for debugging purposes.
1814 ///
1815 /// @param d the diff tree to serialize to the error output associated
1816 /// to the current instance of @ref diff_context.
1817 void
do_dump_diff_tree(const diff_sptr d) const1818 diff_context::do_dump_diff_tree(const diff_sptr d) const
1819 {
1820   if (error_output_stream())
1821     print_diff_tree(d, *error_output_stream());
1822 }
1823 
1824 /// Emit a textual representation of a @ref corpus_diff tree to the error
1825 /// output stream of the current context, for debugging purposes.
1826 ///
1827 /// @param d the @ref corpus_diff tree to serialize to the error
1828 /// output associated to the current instance of @ref diff_context.
1829 void
do_dump_diff_tree(const corpus_diff_sptr d) const1830 diff_context::do_dump_diff_tree(const corpus_diff_sptr d) const
1831 {
1832   if (error_output_stream())
1833     print_diff_tree(d, *error_output_stream());
1834 }
1835 // </diff_context stuff>
1836 
1837 // <diff stuff>
1838 
1839 /// Constructor for the @ref diff type.
1840 ///
1841 /// This constructs a diff between two subjects that are actually
1842 /// declarations; the first and the second one.
1843 ///
1844 /// @param first_subject the first decl (subject) of the diff.
1845 ///
1846 /// @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)1847 diff::diff(type_or_decl_base_sptr first_subject,
1848 	   type_or_decl_base_sptr second_subject)
1849   : priv_(new priv(first_subject, second_subject,
1850 		   diff_context_sptr(),
1851 		   NO_CHANGE_CATEGORY,
1852 		   /*reported_once=*/false,
1853 		   /*currently_reporting=*/false))
1854 {}
1855 
1856 /// Constructor for the @ref diff type.
1857 ///
1858 /// This constructs a diff between two subjects that are actually
1859 /// declarations; the first and the second one.
1860 ///
1861 /// @param first_subject the first decl (subject) of the diff.
1862 ///
1863 /// @param second_subject the second decl (subject) of the diff.
1864 ///
1865 /// @param ctxt the context of the diff.  Note that this context
1866 /// object must stay alive during the entire life time of the current
1867 /// 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)1868 diff::diff(type_or_decl_base_sptr	first_subject,
1869 	   type_or_decl_base_sptr	second_subject,
1870 	   diff_context_sptr	ctxt)
1871   : priv_(new priv(first_subject, second_subject,
1872 		   ctxt, NO_CHANGE_CATEGORY,
1873 		   /*reported_once=*/false,
1874 		   /*currently_reporting=*/false))
1875 {}
1876 
1877 /// Flag a given diff node as being traversed.
1878 ///
1879 /// For certain diff nodes like @ref class_diff, it's important to
1880 /// avoid traversing the node again while it's already being
1881 /// traversed; otherwise this leads to infinite loops.  So the
1882 /// diff::begin_traversing() and diff::end_traversing() methods flag a
1883 /// given node as being traversed (or not), so that
1884 /// diff::is_traversing() can tell if the node is being traversed.
1885 ///
1886 /// Note that traversing a node means visiting it *and* visiting its
1887 /// children nodes.
1888 ///
1889 /// The canonical node is marked as being traversed too.
1890 ///
1891 /// These functions are called by the traversing code.
1892 void
begin_traversing()1893 diff::begin_traversing()
1894 {
1895   ABG_ASSERT(!is_traversing());
1896   if (priv_->canonical_diff_)
1897     priv_->canonical_diff_->priv_->traversing_ = true;
1898   priv_->traversing_ = true;
1899 }
1900 
1901 /// Tell if a given node is being traversed or not.
1902 ///
1903 /// Note that traversing a node means visiting it *and* visiting its
1904 /// children nodes.
1905 ///
1906 /// It's the canonical node which is looked at, actually.
1907 ///
1908 /// Please read the comments for the diff::begin_traversing() for mode
1909 /// context.
1910 ///
1911 /// @return true if the current instance of @diff is being traversed.
1912 bool
is_traversing() const1913 diff::is_traversing() const
1914 {
1915   if (priv_->canonical_diff_)
1916     return priv_->canonical_diff_->priv_->traversing_;
1917   return priv_->traversing_;
1918 }
1919 
1920 /// Flag a given diff node as not being traversed anymore.
1921 ///
1922 /// Note that traversing a node means visiting it *and* visiting its
1923 /// children nodes.
1924 ///
1925 /// Please read the comments of the function diff::begin_traversing()
1926 /// for mode context.
1927 void
end_traversing()1928 diff::end_traversing()
1929 {
1930   ABG_ASSERT(is_traversing());
1931   if (priv_->canonical_diff_)
1932     priv_->canonical_diff_->priv_->traversing_ = false;
1933   priv_->traversing_ = false;
1934 }
1935 
1936 /// Finish the building of a given kind of a diff tree node.
1937 ///
1938 /// For instance, certain kinds of diff tree node have specific
1939 /// children nodes that are populated after the constructor of the
1940 /// diff tree node has been called.  In that case, calling overloads
1941 /// of this method ensures that these children nodes are properly
1942 /// gathered and setup.
1943 void
finish_diff_type()1944 diff::finish_diff_type()
1945 {
1946 }
1947 
1948 /// Getter of the first subject of the diff.
1949 ///
1950 /// @return the first subject of the diff.
1951 type_or_decl_base_sptr
first_subject() const1952 diff::first_subject() const
1953 {return dynamic_pointer_cast<type_or_decl_base>(priv_->first_subject_);}
1954 
1955 /// Getter of the second subject of the diff.
1956 ///
1957 /// @return the second subject of the diff.
1958 type_or_decl_base_sptr
second_subject() const1959 diff::second_subject() const
1960 {return dynamic_pointer_cast<type_or_decl_base>(priv_->second_subject_);}
1961 
1962 /// Getter for the children nodes of the current @ref diff node.
1963 ///
1964 /// @return a vector of the children nodes.
1965 const vector<diff*>&
children_nodes() const1966 diff::children_nodes() const
1967 {return priv_->children_;}
1968 
1969 /// Getter for the parent node of the current @ref diff node.
1970 ///
1971 /// @return the parent node of the current @ref diff node.
1972 const diff*
parent_node() const1973 diff::parent_node() const
1974 {return priv_->parent_;}
1975 
1976 /// Getter for the canonical diff of the current instance of @ref
1977 /// diff.
1978 ///
1979 /// Note that the canonical diff node for the current instanc eof diff
1980 /// node must have been set by invoking
1981 /// class_diff::initialize_canonical_diff() on the current instance of
1982 /// diff node.
1983 ///
1984 /// @return the canonical diff node or null if none was set.
1985 diff*
get_canonical_diff() const1986 diff::get_canonical_diff() const
1987 {return priv_->canonical_diff_;}
1988 
1989 /// Setter for the canonical diff of the current instance of @ref
1990 /// diff.
1991 ///
1992 /// @param d the new canonical node to set.
1993 void
set_canonical_diff(diff * d)1994 diff::set_canonical_diff(diff * d)
1995 {priv_->canonical_diff_ = d;}
1996 
1997 /// Add a new child node to the vector of children nodes for the
1998 /// current @ref diff node.
1999 ///
2000 /// @param d the new child node to add to the children nodes.
2001 void
append_child_node(diff_sptr d)2002 diff::append_child_node(diff_sptr d)
2003 {
2004   ABG_ASSERT(d);
2005 
2006   // Ensure 'd' is kept alive for the life time of the context of this
2007   // diff.
2008   context()->keep_diff_alive(d);
2009 
2010   // Add the underlying pointer of 'd' to the vector of children.
2011   // Note that this vector holds no reference to 'd'. This is to avoid
2012   // reference cycles.  The reference to 'd' is held by the context of
2013   // this diff, thanks to the call to context()->keep_diff_alive(d)
2014   // above.
2015   priv_->children_.push_back(d.get());
2016 
2017   diff_less_than_functor comp;
2018   std::sort(priv_->children_.begin(),
2019 	    priv_->children_.end(),
2020 	    comp);
2021 
2022   d->priv_->parent_ = this;
2023 }
2024 
2025 /// Getter of the context of the current diff.
2026 ///
2027 /// @return the context of the current diff.
2028 const diff_context_sptr
context() const2029 diff::context() const
2030 {return priv_->get_context();}
2031 
2032 /// Setter of the context of the current diff.
2033 ///
2034 /// @param c the new context to set.
2035 void
context(diff_context_sptr c)2036 diff::context(diff_context_sptr c)
2037 {priv_->ctxt_ = c;}
2038 
2039 /// Tests if we are currently in the middle of emitting a report for
2040 /// this diff.
2041 ///
2042 /// @return true if we are currently emitting a report for the
2043 /// current diff, false otherwise.
2044 bool
currently_reporting() const2045 diff::currently_reporting() const
2046 {
2047   if (priv_->canonical_diff_)
2048     return priv_->canonical_diff_->priv_->currently_reporting_;
2049   return priv_->currently_reporting_;
2050 }
2051 
2052 /// Sets a flag saying if we are currently in the middle of emitting
2053 /// a report for this diff.
2054 ///
2055 /// @param f true if we are currently emitting a report for the
2056 /// current diff, false otherwise.
2057 void
currently_reporting(bool f) const2058 diff::currently_reporting(bool f) const
2059 {
2060   if (priv_->canonical_diff_)
2061     priv_->canonical_diff_->priv_->currently_reporting_ = f;
2062   priv_->currently_reporting_ = f;
2063 }
2064 
2065 /// Tests if a report has already been emitted for the current diff.
2066 ///
2067 /// @return true if a report has already been emitted for the
2068 /// current diff, false otherwise.
2069 bool
reported_once() const2070 diff::reported_once() const
2071 {
2072   ABG_ASSERT(priv_->canonical_diff_);
2073   return priv_->canonical_diff_->priv_->reported_once_;
2074 }
2075 
2076 /// The generic traversing code that walks a given diff sub-tree.
2077 ///
2078 /// Note that there is a difference between traversing a diff node and
2079 /// visiting it.  Basically, traversing a diff node means visiting it
2080 /// and visiting its children nodes too.  So one can visit a node
2081 /// without traversing it.  But traversing a node without visiting it
2082 /// is not possible.
2083 ///
2084 /// Note that by default this traversing code visits a given class of
2085 /// equivalence of a diff node only once.  This behaviour can been
2086 /// changed by calling
2087 /// diff_context::visiting_a_node_twice_is_forbidden(), but this is
2088 /// very risky as it might create endless loops while visiting a diff
2089 /// tree graph that has changes that refer to themselves; that is,
2090 /// diff tree graphs with cycles.
2091 ///
2092 /// When a diff node is encountered, the
2093 /// diff_node_visitor::visit_begin() method is invoked on the diff
2094 /// node first.
2095 ///
2096 /// If the diff node has already been visited, then
2097 /// node_visitor::visit_end() is called on it and the node traversing
2098 /// is done; the children of the diff node are not visited in this
2099 /// case.
2100 ///
2101 /// If the diff node has *NOT* been visited yet, then the
2102 /// diff_node_visitor::visit() method is invoked with it's 'pre'
2103 /// argument set to true.  Then if the diff_node_visitor::visit()
2104 /// returns true, then the children nodes of the diff node are
2105 /// visited.  Otherwise, no children nodes of the diff node is
2106 /// visited and the diff_node_visitor::visit_end() is called.
2107 
2108 /// After the children nodes are visited (and only if they are
2109 /// visited) the diff_node_visitor::visit() method is invoked with
2110 /// it's 'pre' argument set to false.  And then the
2111 /// diff_node_visitor::visit_end() is called.
2112 ///
2113 /// @param v the entity that visits each node of the diff sub-tree.
2114 ///
2115 /// @return true to tell the caller that all of the sub-tree could be
2116 /// walked.  This instructs the caller to keep walking the rest of the
2117 /// tree.  Return false otherwise.
2118 bool
traverse(diff_node_visitor & v)2119 diff::traverse(diff_node_visitor& v)
2120 {
2121   finish_diff_type();
2122 
2123   v.visit_begin(this);
2124 
2125   bool already_visited = false;
2126   if (context()->visiting_a_node_twice_is_forbidden()
2127       && context()->diff_has_been_visited(this))
2128     already_visited = true;
2129 
2130   bool mark_visited_nodes_as_traversed =
2131     !(v.get_visiting_kind() & DO_NOT_MARK_VISITED_NODES_AS_VISITED);
2132 
2133   if (!already_visited && !v.visit(this, /*pre=*/true))
2134     {
2135       v.visit_end(this);
2136       if (mark_visited_nodes_as_traversed)
2137 	context()->mark_diff_as_visited(this);
2138       return false;
2139     }
2140 
2141   if (!(v.get_visiting_kind() & SKIP_CHILDREN_VISITING_KIND)
2142       && !is_traversing()
2143       && !already_visited)
2144     {
2145       begin_traversing();
2146       for (vector<diff*>::const_iterator i = children_nodes().begin();
2147 	   i != children_nodes().end();
2148 	   ++i)
2149 	{
2150 	  if (!(*i)->traverse(v))
2151 	    {
2152 	      v.visit_end(this);
2153 	      if (mark_visited_nodes_as_traversed)
2154 		context()->mark_diff_as_visited(this);
2155 	      end_traversing();
2156 	      return false;
2157 	    }
2158 	}
2159       end_traversing();
2160     }
2161 
2162   if (!v.visit(this, /*pref=*/false))
2163     {
2164       v.visit_end(this);
2165       if (mark_visited_nodes_as_traversed)
2166 	context()->mark_diff_as_visited(this);
2167       return false;
2168     }
2169 
2170   v.visit_end(this);
2171   if (!already_visited && mark_visited_nodes_as_traversed)
2172     context()->mark_diff_as_visited(this);
2173 
2174   return true;
2175 }
2176 
2177 /// Sets a flag saying if a report has already been emitted for the
2178 /// current diff.
2179 ///
2180 /// @param f true if a report has already been emitted for the
2181 /// current diff, false otherwise.
2182 void
reported_once(bool f) const2183 diff::reported_once(bool f) const
2184 {
2185   ABG_ASSERT(priv_->canonical_diff_);
2186   priv_->canonical_diff_->priv_->reported_once_ = f;
2187   priv_->reported_once_ = f;
2188 }
2189 
2190 /// Getter for the local category of the current diff tree node.
2191 ///
2192 /// The local category represents the set of categories of a diff
2193 /// node, not taking in account the categories inherited from its
2194 /// children nodes.
2195 ///
2196 /// @return the local category of the current diff tree node.
2197 diff_category
get_local_category() const2198 diff::get_local_category() const
2199 {return priv_->local_category_;}
2200 
2201 /// Getter of the category of the class of equivalence of the current
2202 /// diff tree node.
2203 ///
2204 /// That is, if the current diff tree node has a canonical node,
2205 /// return the category of that canonical node.  Otherwise, return the
2206 /// category of the current node.
2207 ///
2208 /// @return the category of the class of equivalence of the current
2209 /// tree node.
2210 diff_category
get_class_of_equiv_category() const2211 diff::get_class_of_equiv_category() const
2212 {
2213   diff* canonical = get_canonical_diff();
2214   return canonical ? canonical->get_category() : get_category();
2215 }
2216 
2217 /// Getter for the category of the current diff tree node.
2218 ///
2219 /// This category represents the union of the local category and the
2220 /// categories inherited from the children diff nodes.
2221 ///
2222 /// @return the category of the current diff tree node.
2223 diff_category
get_category() const2224 diff::get_category() const
2225 {return priv_->category_;}
2226 
2227 /// Adds the current diff tree node to an additional set of
2228 /// categories.  Note that the categories include thoses inherited
2229 /// from the children nodes of this diff node.
2230 ///
2231 /// @param c a bit-map representing the set of categories to add the
2232 /// current diff tree node to.
2233 ///
2234 /// @return the resulting bit-map representing the categories this
2235 /// current diff tree node belongs to, including those inherited from
2236 /// its children nodes.
2237 diff_category
add_to_category(diff_category c)2238 diff::add_to_category(diff_category c)
2239 {
2240   priv_->category_ = priv_->category_ | c;
2241   return priv_->category_;
2242 }
2243 
2244 /// Adds the current diff tree node to the categories resulting from
2245 /// the local changes of the current diff node.
2246 ///
2247 /// @param c a bit-map representing the set of categories to add the
2248 /// current diff tree node to.
2249 ///
2250 /// @return the resulting bit-map representing the categories this
2251 /// current diff tree node belongs to.
2252 diff_category
add_to_local_category(diff_category c)2253 diff::add_to_local_category(diff_category c)
2254 {
2255   priv_->local_category_ = priv_->local_category_ | c;
2256   return priv_->local_category_;
2257 }
2258 
2259 /// Adds the current diff tree node to the categories resulting from
2260 /// the local and inherited changes of the current diff node.
2261 ///
2262 /// @param c a bit-map representing the set of categories to add the
2263 /// current diff tree node to.
2264 void
add_to_local_and_inherited_categories(diff_category c)2265 diff::add_to_local_and_inherited_categories(diff_category c)
2266 {
2267   add_to_local_category(c);
2268   add_to_category(c);
2269 }
2270 
2271 /// Remove the current diff tree node from an a existing sef of
2272 /// categories.  The categories include those inherited from the
2273 /// children nodes of the current diff node.
2274 ///
2275 /// @param c a bit-map representing the set of categories to add the
2276 /// current diff tree node to.
2277 ///
2278 /// @return the resulting bit-map representing the categories this
2279 /// current diff tree onde belongs to, including the categories
2280 /// inherited from the children nodes of the current diff node.
2281 diff_category
remove_from_category(diff_category c)2282 diff::remove_from_category(diff_category c)
2283 {
2284   priv_->category_ = priv_->category_ & ~c;
2285   return priv_->category_;
2286 }
2287 
2288 /// Remove the current diff tree node from the categories resulting
2289 /// from the local changes.
2290 ///
2291 /// @param c a bit-map representing the set of categories to add the
2292 /// current diff tree node to.
2293 ///
2294 /// @return the resulting bit-map representing the categories this
2295 /// current diff tree onde belongs to.
2296 diff_category
remove_from_local_category(diff_category c)2297 diff::remove_from_local_category(diff_category c)
2298 {
2299   priv_->local_category_ = priv_->local_category_ & ~c;
2300   return priv_->local_category_;
2301 }
2302 
2303 /// Set the category of the current @ref diff node.  This category
2304 /// includes the categories inherited from the children nodes of the
2305 /// current diff node.
2306 ///
2307 /// @param c the new category for the current diff node.
2308 void
set_category(diff_category c)2309 diff::set_category(diff_category c)
2310 {priv_->category_ = c;}
2311 
2312 /// Set the local category of the current @ref diff node.
2313 ///
2314 /// @param c the new category for the current diff node.
2315 void
set_local_category(diff_category c)2316 diff::set_local_category(diff_category c)
2317 {priv_->local_category_ = c;}
2318 
2319 /// Test if this diff tree node is to be filtered out for reporting
2320 /// purposes.
2321 ///
2322 /// The function tests if the categories of the diff tree node are
2323 /// "forbidden" by the context or not.
2324 ///
2325 /// @return true iff the current diff node should NOT be reported.
2326 bool
is_filtered_out() const2327 diff::is_filtered_out() const
2328 {
2329   if (diff * canonical = get_canonical_diff())
2330     if (canonical->get_category() & SUPPRESSED_CATEGORY
2331 	|| canonical->get_category() & PRIVATE_TYPE_CATEGORY)
2332       // The canonical type was suppressed either by a user-provided
2333       // suppression specification or by a "private-type" suppression
2334       // specification..  This means all the class of equivalence of
2335       // that canonical type was suppressed.  So this node should be
2336       // suppressed too.
2337       return true;
2338   return priv_->is_filtered_out(get_category());
2339 }
2340 
2341 /// Test if this diff tree node is to be filtered out for reporting
2342 /// purposes, but by considering only the categories that were *NOT*
2343 /// inherited from its children nodes.
2344 ///
2345 /// The function tests if the local categories of the diff tree node
2346 /// are "forbidden" by the context or not.
2347 ///
2348 /// @return true iff the current diff node should NOT be reported,
2349 /// with respect to its local categories.
2350 bool
is_filtered_out_wrt_non_inherited_categories() const2351 diff::is_filtered_out_wrt_non_inherited_categories() const
2352 {return priv_->is_filtered_out(get_local_category());}
2353 
2354 /// Test if the current diff node has been suppressed by a
2355 /// user-provided suppression specification.
2356 ///
2357 /// @return true if the current diff node has been suppressed by a
2358 /// user-provided suppression list.
2359 bool
is_suppressed() const2360 diff::is_suppressed() const
2361 {
2362   bool is_private = false;
2363   return is_suppressed(is_private);
2364 }
2365 
2366 /// Test if the current diff node has been suppressed by a
2367 /// user-provided suppression specification or by an auto-generated
2368 /// "private type" suppression specification.
2369 ///
2370 /// Note that private type suppressions are auto-generated from the
2371 /// path to where public headers are, as given by the user.
2372 ///
2373 /// @param is_private_type out parameter if the current diff node was
2374 /// suppressed because it's a private type then this parameter is set
2375 /// to true.
2376 ///
2377 /// @return true if the current diff node has been suppressed by a
2378 /// user-provided suppression list.
2379 bool
is_suppressed(bool & is_private_type) const2380 diff::is_suppressed(bool &is_private_type) const
2381 {
2382   const suppressions_type& suppressions = context()->suppressions();
2383   for (suppressions_type::const_iterator i = suppressions.begin();
2384        i != suppressions.end();
2385        ++i)
2386     {
2387       if ((*i)->suppresses_diff(this))
2388 	{
2389 	  if (is_private_type_suppr_spec(*i))
2390 	    is_private_type = true;
2391 	  return true;
2392 	}
2393     }
2394   return false;
2395 }
2396 
2397 /// Test if this diff tree node should be reported.
2398 ///
2399 /// @return true iff the current node should be reported.
2400 bool
to_be_reported() const2401 diff::to_be_reported() const
2402 {
2403   if (has_changes() && !is_filtered_out())
2404     return true;
2405   return false;
2406 }
2407 
2408 /// Test if this diff tree node should be reported when considering
2409 /// the categories that were *NOT* inherited from its children nodes.
2410 ///
2411 /// @return true iff the current node should be reported.
2412 bool
has_local_changes_to_be_reported() const2413 diff::has_local_changes_to_be_reported() const
2414 {
2415   if (has_local_changes()
2416       && !is_filtered_out_wrt_non_inherited_categories())
2417     return true;
2418   return false;
2419 }
2420 
2421 /// Get a pretty representation of the current @ref diff node.
2422 ///
2423 /// This is suitable for e.g. emitting debugging traces for the diff
2424 /// tree nodes.
2425 ///
2426 /// @return the pretty representation of the diff node.
2427 const string&
get_pretty_representation() const2428 diff::get_pretty_representation() const
2429 {
2430   if (priv_->pretty_representation_.empty())
2431     priv_->pretty_representation_ = "empty_diff";
2432   return priv_->pretty_representation_;
2433 }
2434 
2435 /// Default implementation of the hierachy chaining virtual function.
2436 ///
2437 /// There are several types of diff nodes that have logical children
2438 /// nodes; for instance, a typedef_diff has the diff of the underlying
2439 /// type as a child node.  A var_diff has the diff of the types of the
2440 /// variables as a child node, etc.
2441 ///
2442 /// But because the @ref diff base has a generic representation for
2443 /// children nodes of the all the types of @ref diff nodes (regardless
2444 /// of the specific most-derived type of diff node) that one can get
2445 /// using the method diff::children_nodes(), one need to populate that
2446 /// vector of children node.
2447 ///
2448 /// Populating that vector of children node is done by this function;
2449 /// it must be overloaded by each most-derived type of diff node that
2450 /// extends the @ref diff type.
2451 void
chain_into_hierarchy()2452 diff::chain_into_hierarchy()
2453 {}
2454 
2455 // </diff stuff>
2456 
2457 // <type_diff_base stuff>
2458 
type_diff_base(type_base_sptr first_subject,type_base_sptr second_subject,diff_context_sptr ctxt)2459 type_diff_base::type_diff_base(type_base_sptr	first_subject,
2460 			       type_base_sptr	second_subject,
2461 			       diff_context_sptr	ctxt)
2462   : diff(first_subject, second_subject, ctxt),
2463     priv_(new priv)
2464 {}
2465 
~type_diff_base()2466 type_diff_base::~type_diff_base()
2467 {}
2468 // </type_diff_base stuff>
2469 
2470 // <decl_diff_base stuff>
2471 
2472 /// Constructor of @ref decl_diff_base.
2473 ///
2474 /// @param first_subject the first subject of the diff.
2475 ///
2476 /// @param second_subject the second subject of the diff.
2477 ///
2478 /// @param ctxt the context of the diff.  This object must stay alive
2479 /// at least during the life time of the current instance of @ref
2480 /// 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)2481 decl_diff_base::decl_diff_base(decl_base_sptr	first_subject,
2482 			       decl_base_sptr	second_subject,
2483 			       diff_context_sptr	ctxt)
2484   : diff(first_subject, second_subject, ctxt),
2485     priv_(new priv)
2486 {}
2487 
~decl_diff_base()2488 decl_diff_base::~decl_diff_base()
2489 {}
2490 
2491 // </decl_diff_base stuff>
2492 
2493 // <distinct_diff stuff>
2494 
2495 /// @return a pretty representation for the @ref distinct_diff node.
2496 const string&
get_pretty_representation() const2497 distinct_diff::get_pretty_representation() const
2498 {
2499   if (diff::priv_->pretty_representation_.empty())
2500     {
2501       std::ostringstream o;
2502       o << "distinct_diff[";
2503       if (first_subject())
2504 	o << first_subject()->get_pretty_representation();
2505       else
2506 	o << "null";
2507       o << ", ";
2508       if (second_subject())
2509 	o << second_subject()->get_pretty_representation() ;
2510       else
2511 	o << "null";
2512       o << "]" ;
2513       diff::priv_->pretty_representation_ = o.str();
2514     }
2515   return diff::priv_->pretty_representation_;
2516 }
2517 
2518 /// Populate the vector of children node of the @ref diff base type
2519 /// sub-object of this instance of @distinct_diff.
2520 ///
2521 /// The children nodes can then later be retrieved using
2522 /// diff::children_nodes().
2523 void
chain_into_hierarchy()2524 distinct_diff::chain_into_hierarchy()
2525 {
2526   ABG_ASSERT(entities_are_of_distinct_kinds(first(), second()));
2527 
2528   if (diff_sptr d = compatible_child_diff())
2529     append_child_node(d);
2530 }
2531 
2532 /// Constructor for @ref distinct_diff.
2533 ///
2534 /// Note that the two entities considered for the diff (and passed in
2535 /// parameter) must be of different kinds.
2536 ///
2537 /// @param first the first entity to consider for the diff.
2538 ///
2539 /// @param second the second entity to consider for the diff.
2540 ///
2541 /// @param ctxt the context of the diff.  Note that this context
2542 /// object must stay alive at least during the life time of the
2543 /// current instance of @ref distinct_diff.  Otherwise memory
2544 /// corruption issues occur.
distinct_diff(type_or_decl_base_sptr first,type_or_decl_base_sptr second,diff_context_sptr ctxt)2545 distinct_diff::distinct_diff(type_or_decl_base_sptr first,
2546 			     type_or_decl_base_sptr second,
2547 			     diff_context_sptr ctxt)
2548   : diff(first, second, ctxt),
2549     priv_(new priv)
2550 {ABG_ASSERT(entities_are_of_distinct_kinds(first, second));}
2551 
2552 /// Finish building the current instance of @ref distinct_diff.
2553 void
finish_diff_type()2554 distinct_diff::finish_diff_type()
2555 {
2556   if (diff::priv_->finished_)
2557     return;
2558 
2559   chain_into_hierarchy();
2560   diff::priv_->finished_ = true;
2561 }
2562 
2563 /// Getter for the first subject of the diff.
2564 ///
2565 /// @return the first subject of the diff.
2566 const type_or_decl_base_sptr
first() const2567 distinct_diff::first() const
2568 {return first_subject();}
2569 
2570 /// Getter for the second subject of the diff.
2571 ///
2572 /// @return the second subject of the diff.
2573 const type_or_decl_base_sptr
second() const2574 distinct_diff::second() const
2575 {return second_subject();}
2576 
2577 /// Getter for the child diff of this distinct_diff instance.
2578 ///
2579 /// When a distinct_diff has two subjects that are different but
2580 /// compatible, then the distinct_diff instance has a child diff node
2581 /// (named the compatible child diff) that is the diff between the two
2582 /// subjects stripped from their typedefs.  Otherwise, the compatible
2583 /// child diff is nul.
2584 ///
2585 /// Note that two diff subjects (that compare different) are
2586 /// considered compatible if stripping typedefs out of them makes them
2587 /// comparing equal.
2588 ///
2589 /// @return the compatible child diff node, if any.  Otherwise, null.
2590 const diff_sptr
compatible_child_diff() const2591 distinct_diff::compatible_child_diff() const
2592 {
2593   if (!priv_->compatible_child_diff)
2594     {
2595       type_base_sptr fs = strip_typedef(is_type(first())),
2596 	ss = strip_typedef(is_type(second()));
2597 
2598       if (fs && ss
2599 	  && !entities_are_of_distinct_kinds(get_type_declaration(fs),
2600 					     get_type_declaration(ss)))
2601 	priv_->compatible_child_diff = compute_diff(get_type_declaration(fs),
2602 						    get_type_declaration(ss),
2603 						    context());
2604     }
2605   return priv_->compatible_child_diff;
2606 }
2607 
2608 /// Test if the two arguments are of different kind, or that are both
2609 /// NULL.
2610 ///
2611 /// @param first the first argument to test for similarity in kind.
2612 ///
2613 /// @param second the second argument to test for similarity in kind.
2614 ///
2615 /// @return true iff the two arguments are of different kind.
2616 bool
entities_are_of_distinct_kinds(type_or_decl_base_sptr first,type_or_decl_base_sptr second)2617 distinct_diff::entities_are_of_distinct_kinds(type_or_decl_base_sptr first,
2618 					      type_or_decl_base_sptr second)
2619 {
2620   if (!!first != !!second)
2621     return true;
2622   if (!first && !second)
2623     // We do consider diffs of two empty decls as a diff of distinct
2624     // kinds, for now.
2625     return true;
2626   if (first == second)
2627     return false;
2628 
2629   const type_or_decl_base &f = *first, &s = *second;
2630   return typeid(f) != typeid(s);
2631 }
2632 
2633 /// @return true if the two subjects of the diff are different, false
2634 /// otherwise.
2635 bool
has_changes() const2636 distinct_diff::has_changes() const
2637 {return first() != second();}
2638 
2639 /// @return the kind of local change carried by the current diff node.
2640 /// The value returned is zero if the current node carries no local
2641 /// change.
2642 enum change_kind
has_local_changes() const2643 distinct_diff::has_local_changes() const
2644 {
2645   // Changes on a distinct_diff are all local.
2646   if (has_changes())
2647     return LOCAL_TYPE_CHANGE_KIND;
2648   return NO_CHANGE_KIND;
2649 }
2650 
2651 /// Emit a report about the current diff instance.
2652 ///
2653 /// @param out the output stream to send the diff report to.
2654 ///
2655 /// @param indent the indentation string to use in the report.
2656 void
report(ostream & out,const string & indent) const2657 distinct_diff::report(ostream& out, const string& indent) const
2658 {
2659   context()->get_reporter()->report(*this, out, indent);
2660 }
2661 
2662 /// Try to diff entities that are of distinct kinds.
2663 ///
2664 /// @param first the first entity to consider for the diff.
2665 ///
2666 /// @param second the second entity to consider for the diff.
2667 ///
2668 /// @param ctxt the context of the diff.
2669 ///
2670 /// @return a non-null diff if a diff object could be built, null
2671 /// otherwise.
2672 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)2673 compute_diff_for_distinct_kinds(const type_or_decl_base_sptr first,
2674 				const type_or_decl_base_sptr second,
2675 				diff_context_sptr ctxt)
2676 {
2677   if (!distinct_diff::entities_are_of_distinct_kinds(first, second))
2678     return distinct_diff_sptr();
2679 
2680   distinct_diff_sptr result(new distinct_diff(first, second, ctxt));
2681 
2682   ctxt->initialize_canonical_diff(result);
2683 
2684   return result;
2685 }
2686 
2687 /// </distinct_diff stuff>
2688 
2689 /// Try to compute a diff on two instances of DiffType representation.
2690 ///
2691 /// The function template performs the diff if and only if the decl
2692 /// representations are of a DiffType.
2693 ///
2694 /// @tparm DiffType the type of instances to diff.
2695 ///
2696 /// @param first the first representation of decl to consider in the
2697 /// diff computation.
2698 ///
2699 /// @param second the second representation of decl to consider in the
2700 /// diff computation.
2701 ///
2702 /// @param ctxt the diff context to use.
2703 ///
2704 ///@return the diff of the two types @p first and @p second if and
2705 ///only if they represent the parametrized type DiffType.  Otherwise,
2706 ///returns a NULL pointer value.
2707 template<typename DiffType>
2708 diff_sptr
try_to_diff(const type_or_decl_base_sptr first,const type_or_decl_base_sptr second,diff_context_sptr ctxt)2709 try_to_diff(const type_or_decl_base_sptr first,
2710 	    const type_or_decl_base_sptr second,
2711 	    diff_context_sptr ctxt)
2712 {
2713   if (shared_ptr<DiffType> f =
2714       dynamic_pointer_cast<DiffType>(first))
2715     {
2716       shared_ptr<DiffType> s =
2717 	dynamic_pointer_cast<DiffType>(second);
2718       if (!s)
2719 	return diff_sptr();
2720       return compute_diff(f, s, ctxt);
2721     }
2722   return diff_sptr();
2723 }
2724 
2725 
2726 /// This is a specialization of @ref try_to_diff() template to diff
2727 /// instances of @ref class_decl.
2728 ///
2729 /// @param first the first representation of decl to consider in the
2730 /// diff computation.
2731 ///
2732 /// @param second the second representation of decl to consider in the
2733 /// diff computation.
2734 ///
2735 /// @param ctxt the diff context to use.
2736 template<>
2737 diff_sptr
try_to_diff(const type_or_decl_base_sptr first,const type_or_decl_base_sptr second,diff_context_sptr ctxt)2738 try_to_diff<class_decl>(const type_or_decl_base_sptr first,
2739 			const type_or_decl_base_sptr second,
2740 			diff_context_sptr ctxt)
2741 {
2742   if (class_decl_sptr f =
2743       dynamic_pointer_cast<class_decl>(first))
2744     {
2745       class_decl_sptr s = dynamic_pointer_cast<class_decl>(second);
2746       if (!s)
2747 	return diff_sptr();
2748 
2749       if (f->get_is_declaration_only())
2750 	{
2751 	  class_decl_sptr f2 =
2752 	    is_class_type (f->get_definition_of_declaration());
2753 	  if (f2)
2754 	    f = f2;
2755 	}
2756       if (s->get_is_declaration_only())
2757 	{
2758 	  class_decl_sptr s2 =
2759 	    is_class_type(s->get_definition_of_declaration());
2760 	  if (s2)
2761 	    s = s2;
2762 	}
2763       return compute_diff(f, s, ctxt);
2764     }
2765   return diff_sptr();
2766 }
2767 
2768 /// Try to diff entities that are of distinct kinds.
2769 ///
2770 /// @param first the first entity to consider for the diff.
2771 ///
2772 /// @param second the second entity to consider for the diff.
2773 ///
2774 /// @param ctxt the context of the diff.
2775 ///
2776 /// @return a non-null diff if a diff object could be built, null
2777 /// otherwise.
2778 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)2779 try_to_diff_distinct_kinds(const type_or_decl_base_sptr first,
2780 			   const type_or_decl_base_sptr second,
2781 			   diff_context_sptr ctxt)
2782 {return compute_diff_for_distinct_kinds(first, second, ctxt);}
2783 
2784 /// Compute the difference between two types.
2785 ///
2786 /// The function considers every possible types known to libabigail
2787 /// and runs the appropriate diff function on them.
2788 ///
2789 /// Whenever a new kind of type decl is supported by abigail, if we
2790 /// want to be able to diff two instances of it, we need to update
2791 /// this function to support it.
2792 ///
2793 /// @param first the first type decl to consider for the diff
2794 ///
2795 /// @param second the second type decl to consider for the diff.
2796 ///
2797 /// @param ctxt the diff context to use.
2798 ///
2799 /// @return the resulting diff.  It's a pointer to a descendent of
2800 /// abigail::comparison::diff.
2801 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)2802 compute_diff_for_types(const type_or_decl_base_sptr& first,
2803 		       const type_or_decl_base_sptr& second,
2804 		       const diff_context_sptr& ctxt)
2805 {
2806   type_or_decl_base_sptr f = first;
2807   type_or_decl_base_sptr s = second;
2808 
2809   diff_sptr d;
2810 
2811   ((d = try_to_diff<type_decl>(f, s, ctxt))
2812    ||(d = try_to_diff<enum_type_decl>(f, s, ctxt))
2813    ||(d = try_to_diff<union_decl>(f, s,ctxt))
2814    ||(d = try_to_diff<class_decl>(f, s,ctxt))
2815    ||(d = try_to_diff<pointer_type_def>(f, s, ctxt))
2816    ||(d = try_to_diff<reference_type_def>(f, s, ctxt))
2817    ||(d = try_to_diff<array_type_def>(f, s, ctxt))
2818    ||(d = try_to_diff<qualified_type_def>(f, s, ctxt))
2819    ||(d = try_to_diff<typedef_decl>(f, s, ctxt))
2820    ||(d = try_to_diff<function_type>(f, s, ctxt))
2821    ||(d = try_to_diff_distinct_kinds(f, s, ctxt)));
2822 
2823   ABG_ASSERT(d);
2824 
2825   return d;
2826 }
2827 
2828 diff_category
operator |(diff_category c1,diff_category c2)2829 operator|(diff_category c1, diff_category c2)
2830 {return static_cast<diff_category>(static_cast<unsigned>(c1)
2831 				   | static_cast<unsigned>(c2));}
2832 
2833 diff_category&
operator |=(diff_category & c1,diff_category c2)2834 operator|=(diff_category& c1, diff_category c2)
2835 {
2836   c1 = c1 | c2;
2837   return c1;
2838 }
2839 
2840 diff_category&
operator &=(diff_category & c1,diff_category c2)2841 operator&=(diff_category& c1, diff_category c2)
2842 {
2843   c1 = c1 & c2;
2844   return c1;
2845 }
2846 
2847 diff_category
operator ^(diff_category c1,diff_category c2)2848 operator^(diff_category c1, diff_category c2)
2849 {return static_cast<diff_category>(static_cast<unsigned>(c1)
2850 				   ^ static_cast<unsigned>(c2));}
2851 
2852 diff_category
operator &(diff_category c1,diff_category c2)2853 operator&(diff_category c1, diff_category c2)
2854 {return static_cast<diff_category>(static_cast<unsigned>(c1)
2855 				   & static_cast<unsigned>(c2));}
2856 
2857 diff_category
operator ~(diff_category c)2858 operator~(diff_category c)
2859 {return static_cast<diff_category>(~static_cast<unsigned>(c));}
2860 
2861 
2862 /// Getter of a bitmap made of the set of change categories that are
2863 /// considered harmless.
2864 ///
2865 /// @return the bitmap made of the set of change categories that are
2866 /// considered harmless.
2867 diff_category
get_default_harmless_categories_bitmap()2868 get_default_harmless_categories_bitmap()
2869 {
2870   return (abigail::comparison::ACCESS_CHANGE_CATEGORY
2871 	  | abigail::comparison::COMPATIBLE_TYPE_CHANGE_CATEGORY
2872 	  | abigail::comparison::HARMLESS_DECL_NAME_CHANGE_CATEGORY
2873 	  | abigail::comparison::NON_VIRT_MEM_FUN_CHANGE_CATEGORY
2874 	  | abigail::comparison::STATIC_DATA_MEMBER_CHANGE_CATEGORY
2875 	  | abigail::comparison::HARMLESS_ENUM_CHANGE_CATEGORY
2876 	  | abigail::comparison::HARMLESS_SYMBOL_ALIAS_CHANGE_CATEGORY
2877 	  | abigail::comparison::HARMLESS_UNION_CHANGE_CATEGORY
2878 	  | abigail::comparison::HARMLESS_DATA_MEMBER_CHANGE_CATEGORY
2879 	  | abigail::comparison::TYPE_DECL_ONLY_DEF_CHANGE_CATEGORY
2880 	  | abigail::comparison::FN_PARM_TYPE_TOP_CV_CHANGE_CATEGORY
2881 	  | abigail::comparison::FN_PARM_TYPE_CV_CHANGE_CATEGORY
2882 	  | abigail::comparison::FN_RETURN_TYPE_CV_CHANGE_CATEGORY
2883 	  | abigail::comparison::VAR_TYPE_CV_CHANGE_CATEGORY
2884 	  | abigail::comparison::VOID_PTR_TO_PTR_CHANGE_CATEGORY
2885 	  | abigail::comparison::BENIGN_INFINITE_ARRAY_CHANGE_CATEGORY);
2886 }
2887 
2888 /// Getter of a bitmap made of the set of change categories that are
2889 /// considered harmful.
2890 ///
2891 /// @return the bitmap made of the set of change categories that are
2892 /// considered harmful.
2893 diff_category
get_default_harmful_categories_bitmap()2894 get_default_harmful_categories_bitmap()
2895 {
2896   return (abigail::comparison::SIZE_OR_OFFSET_CHANGE_CATEGORY
2897 	  | abigail::comparison::VIRTUAL_MEMBER_CHANGE_CATEGORY
2898 	  | abigail::comparison::FN_PARM_ADD_REMOVE_CHANGE_CATEGORY);
2899 }
2900 
2901 /// Serialize an instance of @ref diff_category to an output stream.
2902 ///
2903 /// @param o the output stream to serialize @p c to.
2904 ///
2905 /// @param c the instance of diff_category to serialize.
2906 ///
2907 /// @return the output stream to serialize @p c to.
2908 ostream&
operator <<(ostream & o,diff_category c)2909 operator<<(ostream& o, diff_category c)
2910 {
2911   bool emitted_a_category = false;
2912 
2913   if (c == NO_CHANGE_CATEGORY)
2914     {
2915       o << "NO_CHANGE_CATEGORY";
2916       emitted_a_category = true;
2917     }
2918 
2919   if (c & ACCESS_CHANGE_CATEGORY)
2920     {
2921       if (emitted_a_category)
2922 	o << "|";
2923       o << "ACCESS_CHANGE_CATEGORY";
2924       emitted_a_category |= true;
2925     }
2926 
2927   if (c & COMPATIBLE_TYPE_CHANGE_CATEGORY)
2928     {
2929       if (emitted_a_category)
2930 	o << "|";
2931       o << "COMPATIBLE_TYPE_CHANGE_CATEGORY";
2932       emitted_a_category |= true;
2933     }
2934 
2935   if (c & HARMLESS_DECL_NAME_CHANGE_CATEGORY)
2936     {
2937       if (emitted_a_category)
2938 	o << "|";
2939       o << "HARMLESS_DECL_NAME_CHANGE_CATEGORY";
2940       emitted_a_category |= true;
2941     }
2942 
2943   if (c & NON_VIRT_MEM_FUN_CHANGE_CATEGORY)
2944     {
2945       if (emitted_a_category)
2946 	o << "|";
2947       o << "NON_VIRT_MEM_FUN_CHANGE_CATEGORY";
2948       emitted_a_category |= true;
2949     }
2950 
2951   if (c & STATIC_DATA_MEMBER_CHANGE_CATEGORY)
2952     {
2953       if (emitted_a_category)
2954 	o << "|";
2955       o << "STATIC_DATA_MEMBER_CHANGE_CATEGORY";
2956       emitted_a_category |= true;
2957     }
2958 
2959   if (c & HARMLESS_ENUM_CHANGE_CATEGORY)
2960     {
2961       if (emitted_a_category)
2962 	o << "|";
2963       o << "HARMLESS_ENUM_CHANGE_CATEGORY";
2964       emitted_a_category |= true;
2965     }
2966 
2967     if (c & HARMLESS_DATA_MEMBER_CHANGE_CATEGORY)
2968     {
2969       if (emitted_a_category)
2970 	o << "|";
2971       o << "HARMLESS_DATA_MEMBER_CHANGE_CATEGORY";
2972       emitted_a_category |= true;
2973     }
2974 
2975   if (c & HARMLESS_SYMBOL_ALIAS_CHANGE_CATEGORY)
2976     {
2977       if (emitted_a_category)
2978 	o << "|";
2979       o << "HARMLESS_SYMBOL_ALIAS_CHANGE_CATEGORY";
2980       emitted_a_category |= true;
2981     }
2982 
2983   if (c & HARMLESS_UNION_CHANGE_CATEGORY)
2984     {
2985       if (emitted_a_category)
2986 	o << "|";
2987       o << "HARMLESS_UNION_CHANGE_CATEGORY";
2988       emitted_a_category |= true;
2989     }
2990 
2991   if (c & SUPPRESSED_CATEGORY)
2992     {
2993       if (emitted_a_category)
2994 	o << "|";
2995       o << "SUPPRESSED_CATEGORY";
2996       emitted_a_category |= true;
2997     }
2998 
2999   if (c & PRIVATE_TYPE_CATEGORY)
3000     {
3001       if (emitted_a_category)
3002 	o << "|";
3003       o << "PRIVATE_TYPE_CATEGORY";
3004       emitted_a_category |= true;
3005     }
3006 
3007   if (c & SIZE_OR_OFFSET_CHANGE_CATEGORY)
3008     {
3009       if (emitted_a_category)
3010 	o << "|";
3011       o << "SIZE_OR_OFFSET_CHANGE_CATEGORY";
3012       emitted_a_category |= true;
3013     }
3014 
3015   if (c & VIRTUAL_MEMBER_CHANGE_CATEGORY)
3016     {
3017       if (emitted_a_category)
3018 	o << "|";
3019       o << "VIRTUAL_MEMBER_CHANGE_CATEGORY";
3020       emitted_a_category |= true;
3021     }
3022 
3023   if (c & REDUNDANT_CATEGORY)
3024     {
3025       if (emitted_a_category)
3026 	o << "|";
3027       o << "REDUNDANT_CATEGORY";
3028       emitted_a_category |= true;
3029     }
3030 
3031   if (c & TYPE_DECL_ONLY_DEF_CHANGE_CATEGORY)
3032     {
3033       if (emitted_a_category)
3034 	o << "|";
3035       o << "TYPE_DECL_ONLY_DEF_CHANGE_CATEGORY";
3036       emitted_a_category |= true;
3037     }
3038 
3039   if (c & FN_PARM_TYPE_TOP_CV_CHANGE_CATEGORY)
3040     {
3041       if (emitted_a_category)
3042 	o << "|";
3043       o << "FN_PARM_TYPE_TOP_CV_CHANGE_CATEGORY";
3044       emitted_a_category |= true;
3045     }
3046 
3047   if (c & FN_PARM_TYPE_CV_CHANGE_CATEGORY)
3048     {
3049       if (emitted_a_category)
3050 	o << "|";
3051       o << "FN_PARM_TYPE_CV_CHANGE_CATEGORY";
3052       emitted_a_category |= true;
3053     }
3054 
3055   if (c & FN_RETURN_TYPE_CV_CHANGE_CATEGORY)
3056     {
3057       if (emitted_a_category)
3058 	o << "|";
3059       o << "FN_RETURN_TYPE_CV_CHANGE_CATEGORY";
3060       emitted_a_category |= true;
3061     }
3062 
3063     if (c & FN_PARM_ADD_REMOVE_CHANGE_CATEGORY)
3064     {
3065       if (emitted_a_category)
3066 	o << "|";
3067       o << "FN_PARM_ADD_REMOVE_CHANGE_CATEGORY";
3068       emitted_a_category |= true;
3069     }
3070 
3071   if (c & VAR_TYPE_CV_CHANGE_CATEGORY)
3072     {
3073       if (emitted_a_category)
3074 	o << "|";
3075       o << "VAR_TYPE_CV_CHANGE_CATEGORY";
3076       emitted_a_category |= true;
3077     }
3078 
3079   if (c & VOID_PTR_TO_PTR_CHANGE_CATEGORY)
3080     {
3081       if (emitted_a_category)
3082 	o << "|";
3083       o << "VOID_PTR_TO_PTR_CHANGE_CATEGORY";
3084       emitted_a_category |= true;
3085     }
3086 
3087   if (c & BENIGN_INFINITE_ARRAY_CHANGE_CATEGORY)
3088     {
3089       if (emitted_a_category)
3090 	o << "|";
3091       o << "BENIGN_INFINITE_ARRAY_CHANGE_CATEGORY";
3092       emitted_a_category |= true;
3093     }
3094 
3095   return o;
3096 }
3097 
3098 /// Compute the difference between two decls.
3099 ///
3100 /// The function consider every possible decls known to libabigail and
3101 /// runs the appropriate diff function on them.
3102 ///
3103 /// Whenever a new kind of non-type decl is supported by abigail, if
3104 /// we want to be able to diff two instances of it, we need to update
3105 /// this function to support it.
3106 ///
3107 /// @param first the first decl to consider for the diff
3108 ///
3109 /// @param second the second decl to consider for the diff.
3110 ///
3111 /// @param ctxt the diff context to use.
3112 ///
3113 /// @return the resulting diff.
3114 static diff_sptr
compute_diff_for_decls(const decl_base_sptr first,const decl_base_sptr second,diff_context_sptr ctxt)3115 compute_diff_for_decls(const decl_base_sptr first,
3116 		       const decl_base_sptr second,
3117 		       diff_context_sptr ctxt)
3118 {
3119 
3120   diff_sptr d;
3121 
3122   ((d = try_to_diff<function_decl>(first, second, ctxt))
3123    || (d = try_to_diff<var_decl>(first, second, ctxt))
3124    || (d = try_to_diff_distinct_kinds(first, second, ctxt)));
3125 
3126    ABG_ASSERT(d);
3127 
3128   return d;
3129 }
3130 
3131 /// Compute the difference between two decls.  The decls can represent
3132 /// either type declarations, or non-type declaration.
3133 ///
3134 /// Note that the two decls must have been created in the same @ref
3135 /// environment, otherwise, this function aborts.
3136 ///
3137 /// @param first the first decl to consider.
3138 ///
3139 /// @param second the second decl to consider.
3140 ///
3141 /// @param ctxt the diff context to use.
3142 ///
3143 /// @return the resulting diff, or NULL if the diff could not be
3144 /// computed.
3145 diff_sptr
compute_diff(const decl_base_sptr first,const decl_base_sptr second,diff_context_sptr ctxt)3146 compute_diff(const decl_base_sptr	first,
3147 	     const decl_base_sptr	second,
3148 	     diff_context_sptr		ctxt)
3149 {
3150   if (!first || !second)
3151     return diff_sptr();
3152 
3153   ABG_ASSERT(first->get_environment() == second->get_environment());
3154 
3155   diff_sptr d;
3156   if (is_type(first) && is_type(second))
3157     d = compute_diff_for_types(first, second, ctxt);
3158   else
3159     d = compute_diff_for_decls(first, second, ctxt);
3160   ABG_ASSERT(d);
3161   return d;
3162 }
3163 
3164 /// Compute the difference between two types.
3165 ///
3166 /// Note that the two types must have been created in the same @ref
3167 /// environment, otherwise, this function aborts.
3168 ///
3169 /// @param first the first type to consider.
3170 ///
3171 /// @param second the second type to consider.
3172 ///
3173 /// @param ctxt the diff context to use.
3174 ///
3175 /// @return the resulting diff, or NULL if the diff couldn't be
3176 /// computed.
3177 diff_sptr
compute_diff(const type_base_sptr first,const type_base_sptr second,diff_context_sptr ctxt)3178 compute_diff(const type_base_sptr	first,
3179 	     const type_base_sptr	second,
3180 	     diff_context_sptr		ctxt)
3181 {
3182   decl_base_sptr f = get_type_declaration(first),
3183     s = get_type_declaration(second);
3184 
3185   if (first && second)
3186     ABG_ASSERT(first->get_environment() == second->get_environment());
3187 
3188   diff_sptr d = compute_diff_for_types(f,s, ctxt);
3189   ABG_ASSERT(d);
3190   return d;
3191 }
3192 
3193 /// Get a copy of the pretty representation of a diff node.
3194 ///
3195 /// @param d the diff node to consider.
3196 ///
3197 /// @return the pretty representation string.
3198 string
get_pretty_representation(diff * d)3199 get_pretty_representation(diff* d)
3200 {
3201   if (!d)
3202     return "";
3203   string prefix= "diff of ";
3204   return prefix + get_pretty_representation(d->first_subject());
3205 }
3206 
3207 // <var_diff stuff>
3208 
3209 /// Populate the vector of children node of the @ref diff base type
3210 /// sub-object of this instance of @ref var_diff.
3211 ///
3212 /// The children node can then later be retrieved using
3213 /// diff::children_node().
3214 void
chain_into_hierarchy()3215 var_diff::chain_into_hierarchy()
3216 {append_child_node(type_diff());}
3217 
3218 /// @return the pretty representation for this current instance of
3219 /// @ref var_diff.
3220 const string&
get_pretty_representation() const3221 var_diff::get_pretty_representation() const
3222 {
3223   if (diff::priv_->pretty_representation_.empty())
3224     {
3225       std::ostringstream o;
3226       o << "var_diff["
3227 	<< first_subject()->get_pretty_representation()
3228 	<< ", "
3229 	<< second_subject()->get_pretty_representation()
3230 	<< "]";
3231       diff::priv_->pretty_representation_ = o.str();
3232     }
3233   return diff::priv_->pretty_representation_;
3234 }
3235 /// Constructor for @ref var_diff.
3236 ///
3237 /// @param first the first instance of @ref var_decl to consider in
3238 /// the diff.
3239 ///
3240 /// @param second the second instance of @ref var_decl to consider in
3241 /// the diff.
3242 ///
3243 /// @param type_diff the diff between types of the instances of
3244 /// var_decl.
3245 ///
3246 /// @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)3247 var_diff::var_diff(var_decl_sptr	first,
3248 		   var_decl_sptr	second,
3249 		   diff_sptr		type_diff,
3250 		   diff_context_sptr	ctxt)
3251   : decl_diff_base(first, second, ctxt),
3252     priv_(new priv)
3253 {priv_->type_diff_ = type_diff;}
3254 
3255 /// Finish building the current instance of @ref var_diff.
3256 void
finish_diff_type()3257 var_diff::finish_diff_type()
3258 {
3259   if (diff::priv_->finished_)
3260     return;
3261   chain_into_hierarchy();
3262   diff::priv_->finished_ = true;
3263 }
3264 
3265 /// Getter for the first @ref var_decl of the diff.
3266 ///
3267 /// @return the first @ref var_decl of the diff.
3268 var_decl_sptr
first_var() const3269 var_diff::first_var() const
3270 {return dynamic_pointer_cast<var_decl>(first_subject());}
3271 
3272 /// Getter for the second @ref var_decl of the diff.
3273 ///
3274 /// @return the second @ref var_decl of the diff.
3275 var_decl_sptr
second_var() const3276 var_diff::second_var() const
3277 {return dynamic_pointer_cast<var_decl>(second_subject());}
3278 
3279 /// Getter for the diff of the types of the instances of @ref
3280 /// var_decl.
3281 ///
3282 /// @return the diff of the types of the instances of @ref var_decl.
3283 diff_sptr
type_diff() const3284 var_diff::type_diff() const
3285 {
3286   if (diff_sptr result = priv_->type_diff_.lock())
3287     return result;
3288   else
3289     {
3290       result = compute_diff(first_var()->get_type(),
3291 			    second_var()->get_type(),
3292 			    context());
3293       context()->keep_diff_alive(result);
3294       priv_->type_diff_ = result;
3295       return result;
3296     }
3297 }
3298 
3299 /// Return true iff the diff node has a change.
3300 ///
3301 /// @return true iff the diff node has a change.
3302 bool
has_changes() const3303 var_diff::has_changes() const
3304 {return *first_var() != *second_var();}
3305 
3306 /// @return the kind of local change carried by the current diff node.
3307 /// The value returned is zero if the current node carries no local
3308 /// change.
3309 enum change_kind
has_local_changes() const3310 var_diff::has_local_changes() const
3311 {
3312   ir::change_kind k = ir::NO_CHANGE_KIND;
3313   if (!equals(*first_var(), *second_var(), &k))
3314     return k & ir::ALL_LOCAL_CHANGES_MASK;
3315   return ir::NO_CHANGE_KIND;
3316 }
3317 
3318 /// Report the diff in a serialized form.
3319 ///
3320 /// @param out the stream to serialize the diff to.
3321 ///
3322 /// @param indent the prefix to use for the indentation of this
3323 /// serialization.
3324 void
report(ostream & out,const string & indent) const3325 var_diff::report(ostream& out, const string& indent) const
3326 {
3327   context()->get_reporter()->report(*this, out, indent);
3328 }
3329 
3330 /// Compute the diff between two instances of @ref var_decl.
3331 ///
3332 /// Note that the two decls must have been created in the same @ref
3333 /// environment, otherwise, this function aborts.
3334 ///
3335 /// @param first the first @ref var_decl to consider for the diff.
3336 ///
3337 /// @param second the second @ref var_decl to consider for the diff.
3338 ///
3339 /// @param ctxt the diff context to use.
3340 ///
3341 /// @return the resulting diff between the two @ref var_decl.
3342 var_diff_sptr
compute_diff(const var_decl_sptr first,const var_decl_sptr second,diff_context_sptr ctxt)3343 compute_diff(const var_decl_sptr	first,
3344 	     const var_decl_sptr	second,
3345 	     diff_context_sptr		ctxt)
3346 {
3347   if (first && second)
3348     ABG_ASSERT(first->get_environment() == second->get_environment());
3349 
3350   var_diff_sptr d(new var_diff(first, second, diff_sptr(), ctxt));
3351   ctxt->initialize_canonical_diff(d);
3352 
3353   return d;
3354 }
3355 
3356 // </var_diff stuff>
3357 
3358 // <pointer_type_def stuff>
3359 
3360 /// Populate the vector of children node of the @ref diff base type
3361 /// sub-object of this instance of @ref pointer_diff.
3362 ///
3363 /// The children node can then later be retrieved using
3364 /// diff::children_node().
3365 void
chain_into_hierarchy()3366 pointer_diff::chain_into_hierarchy()
3367 {append_child_node(underlying_type_diff());}
3368 
3369 /// Constructor for a pointer_diff.
3370 ///
3371 /// @param first the first pointer to consider for the diff.
3372 ///
3373 /// @param second the secon pointer to consider for the diff.
3374 ///
3375 /// @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)3376 pointer_diff::pointer_diff(pointer_type_def_sptr	first,
3377 			   pointer_type_def_sptr	second,
3378 			   diff_sptr			underlying,
3379 			   diff_context_sptr		ctxt)
3380   : type_diff_base(first, second, ctxt),
3381     priv_(new priv(underlying))
3382 {}
3383 
3384 /// Finish building the current instance of @ref pointer_diff.
3385 void
finish_diff_type()3386 pointer_diff::finish_diff_type()
3387 {
3388   if (diff::priv_->finished_)
3389     return;
3390   chain_into_hierarchy();
3391   diff::priv_->finished_ = true;
3392 }
3393 
3394 /// Getter for the first subject of a pointer diff
3395 ///
3396 /// @return the first pointer considered in this pointer diff.
3397 const pointer_type_def_sptr
first_pointer() const3398 pointer_diff::first_pointer() const
3399 {return dynamic_pointer_cast<pointer_type_def>(first_subject());}
3400 
3401 /// Getter for the second subject of a pointer diff
3402 ///
3403 /// @return the second pointer considered in this pointer diff.
3404 const pointer_type_def_sptr
second_pointer() const3405 pointer_diff::second_pointer() const
3406 {return dynamic_pointer_cast<pointer_type_def>(second_subject());}
3407 
3408 /// @return the pretty represenation for the current instance of @ref
3409 /// pointer_diff.
3410 const string&
get_pretty_representation() const3411 pointer_diff::get_pretty_representation() const
3412 {
3413   if (diff::priv_->pretty_representation_.empty())
3414     {
3415       std::ostringstream o;
3416       o << "pointer_diff["
3417 	<< first_subject()->get_pretty_representation()
3418 	<< ", "
3419 	<< second_subject()->get_pretty_representation()
3420 	<< "]";
3421       diff::priv_->pretty_representation_ = o.str();
3422     }
3423   return diff::priv_->pretty_representation_;
3424 }
3425 
3426 /// Return true iff the current diff node carries a change.
3427 ///
3428 /// @return true iff the current diff node carries a change.
3429 bool
has_changes() const3430 pointer_diff::has_changes() const
3431 {return first_pointer() != second_pointer();}
3432 
3433 /// @return the kind of local change carried by the current diff node.
3434 /// The value returned is zero if the current node carries no local
3435 /// change.
3436 enum change_kind
has_local_changes() const3437 pointer_diff::has_local_changes() const
3438 {
3439   ir::change_kind k = ir::NO_CHANGE_KIND;
3440   if (!equals(*first_pointer(), *second_pointer(), &k))
3441     return k & ir::ALL_LOCAL_CHANGES_MASK;
3442   return ir::NO_CHANGE_KIND;
3443 }
3444 
3445 /// Getter for the diff between the pointed-to types of the pointers
3446 /// of this diff.
3447 ///
3448 /// @return the diff between the pointed-to types.
3449 diff_sptr
underlying_type_diff() const3450 pointer_diff::underlying_type_diff() const
3451 {return priv_->underlying_type_diff_;}
3452 
3453 /// Setter for the diff between the pointed-to types of the pointers
3454 /// of this diff.
3455 ///
3456 /// @param d the new diff between the pointed-to types of the pointers
3457 /// of this diff.
3458 void
underlying_type_diff(const diff_sptr d)3459 pointer_diff::underlying_type_diff(const diff_sptr d)
3460 {priv_->underlying_type_diff_ = d;}
3461 
3462 /// Report the diff in a serialized form.
3463 ///
3464 /// @param out the stream to serialize the diff to.
3465 ///
3466 /// @param indent the prefix to use for the indentation of this
3467 /// serialization.
3468 void
report(ostream & out,const string & indent) const3469 pointer_diff::report(ostream& out, const string& indent) const
3470 {
3471   context()->get_reporter()->report(*this, out, indent);
3472 }
3473 
3474 /// Compute the diff between between two pointers.
3475 ///
3476 /// Note that the two types must have been created in the same @ref
3477 /// environment, otherwise, this function aborts.
3478 ///
3479 /// @param first the pointer to consider for the diff.
3480 ///
3481 /// @param second the pointer to consider for the diff.
3482 ///
3483 /// @return the resulting diff between the two pointers.
3484 ///
3485 /// @param ctxt the diff context to use.
3486 pointer_diff_sptr
compute_diff(pointer_type_def_sptr first,pointer_type_def_sptr second,diff_context_sptr ctxt)3487 compute_diff(pointer_type_def_sptr	first,
3488 	     pointer_type_def_sptr	second,
3489 	     diff_context_sptr		ctxt)
3490 {
3491   if (first && second)
3492     ABG_ASSERT(first->get_environment() == second->get_environment());
3493 
3494   diff_sptr d = compute_diff_for_types(first->get_pointed_to_type(),
3495 				       second->get_pointed_to_type(),
3496 				       ctxt);
3497   pointer_diff_sptr result(new pointer_diff(first, second, d, ctxt));
3498   ctxt->initialize_canonical_diff(result);
3499 
3500   return result;
3501 }
3502 
3503 // </pointer_type_def>
3504 
3505 // <array_type_def>
3506 
3507 /// Populate the vector of children node of the @ref diff base type
3508 /// sub-object of this instance of @ref array_diff.
3509 ///
3510 /// The children node can then later be retrieved using
3511 /// diff::children_node().
3512 void
chain_into_hierarchy()3513 array_diff::chain_into_hierarchy()
3514 {append_child_node(element_type_diff());}
3515 
3516 /// Constructor for array_diff
3517 ///
3518 /// @param first the first array_type of the diff.
3519 ///
3520 /// @param second the second array_type of the diff.
3521 ///
3522 /// @param element_type_diff the diff between the two array element
3523 /// types.
3524 ///
3525 /// @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)3526 array_diff::array_diff(const array_type_def_sptr	first,
3527 		       const array_type_def_sptr	second,
3528 		       diff_sptr			element_type_diff,
3529 		       diff_context_sptr		ctxt)
3530   : type_diff_base(first, second, ctxt),
3531     priv_(new priv(element_type_diff))
3532 {}
3533 
3534 /// Finish building the current instance of @ref array_diff.
3535 void
finish_diff_type()3536 array_diff::finish_diff_type()
3537 {
3538   if (diff::priv_->finished_)
3539     return;
3540   chain_into_hierarchy();
3541   diff::priv_->finished_ = true;
3542 }
3543 
3544 /// Getter for the first array of the diff.
3545 ///
3546 /// @return the first array of the diff.
3547 const array_type_def_sptr
first_array() const3548 array_diff::first_array() const
3549 {return dynamic_pointer_cast<array_type_def>(first_subject());}
3550 
3551 /// Getter for the second array of the diff.
3552 ///
3553 /// @return for the second array of the diff.
3554 const array_type_def_sptr
second_array() const3555 array_diff::second_array() const
3556 {return dynamic_pointer_cast<array_type_def>(second_subject());}
3557 
3558 /// Getter for the diff between the two types of array elements.
3559 ///
3560 /// @return the diff between the two types of array elements.
3561 const diff_sptr&
element_type_diff() const3562 array_diff::element_type_diff() const
3563 {return priv_->element_type_diff_;}
3564 
3565 /// Setter for the diff between the two array element types.
3566 ///
3567 /// @param d the new diff betweend the two array element types.
3568 void
element_type_diff(diff_sptr d)3569 array_diff::element_type_diff(diff_sptr d)
3570 {priv_->element_type_diff_ = d;}
3571 
3572 /// @return the pretty representation for the current instance of @ref
3573 /// array_diff.
3574 const string&
get_pretty_representation() const3575 array_diff::get_pretty_representation() const
3576 {
3577   if (diff::priv_->pretty_representation_.empty())
3578     {
3579       std::ostringstream o;
3580       o << "array_diff["
3581 	<< first_subject()->get_pretty_representation()
3582 	<< ", "
3583 	<< second_subject()->get_pretty_representation()
3584 	<< "]";
3585       diff::priv_->pretty_representation_ = o.str();
3586     }
3587   return diff::priv_->pretty_representation_;
3588 }
3589 
3590 /// Return true iff the current diff node carries a change.
3591 ///
3592 /// @return true iff the current diff node carries a change.
3593 bool
has_changes() const3594 array_diff::has_changes() const
3595 {
3596   bool l = false;
3597 
3598   //  the array element types match check for differing dimensions
3599   //  etc...
3600   array_type_def_sptr
3601     f = dynamic_pointer_cast<array_type_def>(first_subject()),
3602     s = dynamic_pointer_cast<array_type_def>(second_subject());
3603 
3604   if (f->get_name() != s->get_name())
3605     l |= true;
3606   if (f->get_size_in_bits() != s->get_size_in_bits())
3607     l |= true;
3608   if (f->get_alignment_in_bits() != s->get_alignment_in_bits())
3609     l |= true;
3610 
3611   l |=  element_type_diff()
3612     ? element_type_diff()->has_changes()
3613     : false;
3614 
3615   return l;
3616 }
3617 
3618 
3619 /// @return the kind of local change carried by the current diff node.
3620 /// The value returned is zero if the current node carries no local
3621 /// change.
3622 enum change_kind
has_local_changes() const3623 array_diff::has_local_changes() const
3624 {
3625   ir::change_kind k = ir::NO_CHANGE_KIND;
3626   if (!equals(*first_array(), *second_array(), &k))
3627     return k & ir::ALL_LOCAL_CHANGES_MASK;
3628   return ir::NO_CHANGE_KIND;
3629 }
3630 
3631 /// Report the diff in a serialized form.
3632 ///
3633 /// @param out the output stream to serialize the dif to.
3634 ///
3635 /// @param indent the string to use for indenting the report.
3636 void
report(ostream & out,const string & indent) const3637 array_diff::report(ostream& out, const string& indent) const
3638 {
3639   context()->get_reporter()->report(*this, out, indent);
3640 }
3641 
3642 /// Compute the diff between two arrays.
3643 ///
3644 /// Note that the two types must have been created in the same @ref
3645 /// environment, otherwise, this function aborts.
3646 ///
3647 /// @param first the first array to consider for the diff.
3648 ///
3649 /// @param second the second array to consider for the diff.
3650 ///
3651 /// @param ctxt the diff context to use.
3652 array_diff_sptr
compute_diff(array_type_def_sptr first,array_type_def_sptr second,diff_context_sptr ctxt)3653 compute_diff(array_type_def_sptr	first,
3654 	     array_type_def_sptr	second,
3655 	     diff_context_sptr		ctxt)
3656 {
3657   if (first && second)
3658     ABG_ASSERT(first->get_environment() == second->get_environment());
3659 
3660   diff_sptr d = compute_diff_for_types(first->get_element_type(),
3661 				       second->get_element_type(),
3662 				       ctxt);
3663   array_diff_sptr result(new array_diff(first, second, d, ctxt));
3664   ctxt->initialize_canonical_diff(result);
3665   return result;
3666 }
3667 // </array_type_def>
3668 
3669 // <reference_type_def>
3670 
3671 /// Populate the vector of children node of the @ref diff base type
3672 /// sub-object of this instance of @ref reference_diff.
3673 ///
3674 /// The children node can then later be retrieved using
3675 /// diff::children_node().
3676 void
chain_into_hierarchy()3677 reference_diff::chain_into_hierarchy()
3678 {append_child_node(underlying_type_diff());}
3679 
3680 /// Constructor for reference_diff
3681 ///
3682 /// @param first the first reference_type of the diff.
3683 ///
3684 /// @param second the second reference_type of the diff.
3685 ///
3686 /// @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)3687 reference_diff::reference_diff(const reference_type_def_sptr	first,
3688 			       const reference_type_def_sptr	second,
3689 			       diff_sptr			underlying,
3690 			       diff_context_sptr		ctxt)
3691   : type_diff_base(first, second, ctxt),
3692 	priv_(new priv(underlying))
3693 {}
3694 
3695 /// Finish building the current instance of @ref reference_diff.
3696 void
finish_diff_type()3697 reference_diff::finish_diff_type()
3698 {
3699   if (diff::priv_->finished_)
3700     return;
3701   chain_into_hierarchy();
3702   diff::priv_->finished_ = true;
3703 }
3704 
3705 /// Getter for the first reference of the diff.
3706 ///
3707 /// @return the first reference of the diff.
3708 reference_type_def_sptr
first_reference() const3709 reference_diff::first_reference() const
3710 {return dynamic_pointer_cast<reference_type_def>(first_subject());}
3711 
3712 /// Getter for the second reference of the diff.
3713 ///
3714 /// @return for the second reference of the diff.
3715 reference_type_def_sptr
second_reference() const3716 reference_diff::second_reference() const
3717 {return dynamic_pointer_cast<reference_type_def>(second_subject());}
3718 
3719 
3720 /// Getter for the diff between the two referred-to types.
3721 ///
3722 /// @return the diff between the two referred-to types.
3723 const diff_sptr&
underlying_type_diff() const3724 reference_diff::underlying_type_diff() const
3725 {return priv_->underlying_type_diff_;}
3726 
3727 /// Setter for the diff between the two referred-to types.
3728 ///
3729 /// @param d the new diff betweend the two referred-to types.
3730 diff_sptr&
underlying_type_diff(diff_sptr d)3731 reference_diff::underlying_type_diff(diff_sptr d)
3732 {
3733   priv_->underlying_type_diff_ = d;
3734   return priv_->underlying_type_diff_;
3735 }
3736 
3737 /// @return the pretty representation for the current instance of @ref
3738 /// reference_diff.
3739 const string&
get_pretty_representation() const3740 reference_diff::get_pretty_representation() const
3741 {
3742   if (diff::priv_->pretty_representation_.empty())
3743     {
3744       std::ostringstream o;
3745       o << "reference_diff["
3746 	<< first_subject()->get_pretty_representation()
3747 	<< ", "
3748 	<< second_subject()->get_pretty_representation()
3749 	<< "]";
3750       diff::priv_->pretty_representation_ = o.str();
3751     }
3752   return diff::priv_->pretty_representation_;
3753 }
3754 
3755 /// Return true iff the current diff node carries a change.
3756 ///
3757 /// @return true iff the current diff node carries a change.
3758 bool
has_changes() const3759 reference_diff::has_changes() const
3760 {
3761   return first_reference() != second_reference();
3762 }
3763 
3764 /// @return the kind of local change carried by the current diff node.
3765 /// The value returned is zero if the current node carries no local
3766 /// change.
3767 enum change_kind
has_local_changes() const3768 reference_diff::has_local_changes() const
3769 {
3770   ir::change_kind k = ir::NO_CHANGE_KIND;
3771   if (!equals(*first_reference(), *second_reference(), &k))
3772     return k & ir::ALL_LOCAL_CHANGES_MASK;
3773   return ir::NO_CHANGE_KIND;
3774 }
3775 
3776 /// Report the diff in a serialized form.
3777 ///
3778 /// @param out the output stream to serialize the dif to.
3779 ///
3780 /// @param indent the string to use for indenting the report.
3781 void
report(ostream & out,const string & indent) const3782 reference_diff::report(ostream& out, const string& indent) const
3783 {
3784   context()->get_reporter()->report(*this, out, indent);
3785 }
3786 
3787 /// Compute the diff between two references.
3788 ///
3789 /// Note that the two types must have been created in the same @ref
3790 /// environment, otherwise, this function aborts.
3791 ///
3792 /// @param first the first reference to consider for the diff.
3793 ///
3794 /// @param second the second reference to consider for the diff.
3795 ///
3796 /// @param ctxt the diff context to use.
3797 reference_diff_sptr
compute_diff(reference_type_def_sptr first,reference_type_def_sptr second,diff_context_sptr ctxt)3798 compute_diff(reference_type_def_sptr	first,
3799 	     reference_type_def_sptr	second,
3800 	     diff_context_sptr		ctxt)
3801 {
3802   if (first && second)
3803     ABG_ASSERT(first->get_environment() == second->get_environment());
3804 
3805   diff_sptr d = compute_diff_for_types(first->get_pointed_to_type(),
3806 				       second->get_pointed_to_type(),
3807 				       ctxt);
3808   reference_diff_sptr result(new reference_diff(first, second, d, ctxt));
3809   ctxt->initialize_canonical_diff(result);
3810   return result;
3811 }
3812 // </reference_type_def>
3813 
3814 // <qualified_type_diff stuff>
3815 
3816 /// Populate the vector of children node of the @ref diff base type
3817 /// sub-object of this instance of @ref qualified_type_diff.
3818 ///
3819 /// The children node can then later be retrieved using
3820 /// diff::children_node().
3821 void
chain_into_hierarchy()3822 qualified_type_diff::chain_into_hierarchy()
3823 {append_child_node(leaf_underlying_type_diff());}
3824 
3825 /// Constructor for qualified_type_diff.
3826 ///
3827 /// @param first the first qualified type of the diff.
3828 ///
3829 /// @param second the second qualified type of the diff.
3830 ///
3831 /// @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)3832 qualified_type_diff::qualified_type_diff(qualified_type_def_sptr	first,
3833 					 qualified_type_def_sptr	second,
3834 					 diff_sptr			under,
3835 					 diff_context_sptr		ctxt)
3836   : type_diff_base(first, second, ctxt),
3837     priv_(new priv(under))
3838 {}
3839 
3840 /// Finish building the current instance of @ref qualified_type_diff.
3841 void
finish_diff_type()3842 qualified_type_diff::finish_diff_type()
3843 {
3844   if (diff::priv_->finished_)
3845     return;
3846   chain_into_hierarchy();
3847   diff::priv_->finished_ = true;
3848 }
3849 
3850 /// Getter for the first qualified type of the diff.
3851 ///
3852 /// @return the first qualified type of the diff.
3853 const qualified_type_def_sptr
first_qualified_type() const3854 qualified_type_diff::first_qualified_type() const
3855 {return dynamic_pointer_cast<qualified_type_def>(first_subject());}
3856 
3857 /// Getter for the second qualified type of the diff.
3858 ///
3859 /// @return the second qualified type of the diff.
3860 const qualified_type_def_sptr
second_qualified_type() const3861 qualified_type_diff::second_qualified_type() const
3862 {return dynamic_pointer_cast<qualified_type_def>(second_subject());}
3863 
3864 /// Getter for the diff between the underlying types of the two
3865 /// qualified types.
3866 ///
3867 /// @return the diff between the underlying types of the two qualified
3868 /// types.
3869 diff_sptr
underlying_type_diff() const3870 qualified_type_diff::underlying_type_diff() const
3871 {return priv_->underlying_type_diff;}
3872 
3873 /// Getter for the diff between the most underlying non-qualified
3874 /// types of two qualified types.
3875 ///
3876 /// @return the diff between the most underlying non-qualified types
3877 /// of two qualified types.
3878 diff_sptr
leaf_underlying_type_diff() const3879 qualified_type_diff::leaf_underlying_type_diff() const
3880 {
3881   if (!priv_->leaf_underlying_type_diff)
3882     priv_->leaf_underlying_type_diff
3883       = compute_diff_for_types(get_leaf_type(first_qualified_type()),
3884 			       get_leaf_type(second_qualified_type()),
3885 			       context());
3886 
3887   return priv_->leaf_underlying_type_diff;
3888 }
3889 
3890 /// Setter for the diff between the underlying types of the two
3891 /// qualified types.
3892 ///
3893 /// @return the diff between the underlying types of the two qualified
3894 /// types.
3895 void
underlying_type_diff(const diff_sptr d)3896 qualified_type_diff::underlying_type_diff(const diff_sptr d)
3897 {priv_->underlying_type_diff = d;}
3898 
3899 /// @return the pretty representation of the current instance of @ref
3900 /// qualified_type_diff.
3901 const string&
get_pretty_representation() const3902 qualified_type_diff::get_pretty_representation() const
3903 {
3904   if (diff::priv_->pretty_representation_.empty())
3905     {
3906       std::ostringstream o;
3907       o << "qualified_type_diff["
3908 	<< first_subject()->get_pretty_representation()
3909 	<< ", "
3910 	<< second_subject()->get_pretty_representation()
3911 	<< "]";
3912       diff::priv_->pretty_representation_ = o.str();
3913     }
3914   return diff::priv_->pretty_representation_;
3915 }
3916 
3917 /// Return true iff the current diff node carries a change.
3918 ///
3919 /// @return true iff the current diff node carries a change.
3920 bool
has_changes() const3921 qualified_type_diff::has_changes() const
3922 {return first_qualified_type() != second_qualified_type();}
3923 
3924 /// @return the kind of local change carried by the current diff node.
3925 /// The value returned is zero if the current node carries no local
3926 /// change.
3927 enum change_kind
has_local_changes() const3928 qualified_type_diff::has_local_changes() const
3929 {
3930   ir::change_kind k = ir::NO_CHANGE_KIND;
3931   if (!equals(*first_qualified_type(), *second_qualified_type(), &k))
3932     return k & ir::ALL_LOCAL_CHANGES_MASK;
3933   return ir::NO_CHANGE_KIND;
3934 }
3935 
3936 /// Report the diff in a serialized form.
3937 ///
3938 /// @param out the output stream to serialize to.
3939 ///
3940 /// @param indent the string to use to indent the lines of the report.
3941 void
report(ostream & out,const string & indent) const3942 qualified_type_diff::report(ostream& out, const string& indent) const
3943 {
3944   context()->get_reporter()->report(*this, out, indent);
3945 }
3946 
3947 /// Compute the diff between two qualified types.
3948 ///
3949 /// Note that the two types must have been created in the same @ref
3950 /// environment, otherwise, this function aborts.
3951 ///
3952 /// @param first the first qualified type to consider for the diff.
3953 ///
3954 /// @param second the second qualified type to consider for the diff.
3955 ///
3956 /// @param ctxt the diff context to use.
3957 qualified_type_diff_sptr
compute_diff(const qualified_type_def_sptr first,const qualified_type_def_sptr second,diff_context_sptr ctxt)3958 compute_diff(const qualified_type_def_sptr	first,
3959 	     const qualified_type_def_sptr	second,
3960 	     diff_context_sptr			ctxt)
3961 {
3962   if (first && second)
3963     ABG_ASSERT(first->get_environment() == second->get_environment());
3964 
3965   diff_sptr d = compute_diff_for_types(first->get_underlying_type(),
3966 				       second->get_underlying_type(),
3967 				       ctxt);
3968   qualified_type_diff_sptr result(new qualified_type_diff(first, second,
3969 							  d, ctxt));
3970   ctxt->initialize_canonical_diff(result);
3971   return result;
3972 }
3973 
3974 // </qualified_type_diff stuff>
3975 
3976 // <enum_diff stuff>
3977 
3978 /// Clear the lookup tables useful for reporting an enum_diff.
3979 ///
3980 /// This function must be updated each time a lookup table is added or
3981 /// removed from the class_diff::priv.
3982 void
clear_lookup_tables()3983 enum_diff::clear_lookup_tables()
3984 {
3985   priv_->deleted_enumerators_.clear();
3986   priv_->inserted_enumerators_.clear();
3987   priv_->changed_enumerators_.clear();
3988 }
3989 
3990 /// Tests if the lookup tables are empty.
3991 ///
3992 /// @return true if the lookup tables are empty, false otherwise.
3993 bool
lookup_tables_empty() const3994 enum_diff::lookup_tables_empty() const
3995 {
3996   return (priv_->deleted_enumerators_.empty()
3997 	  && priv_->inserted_enumerators_.empty()
3998 	  && priv_->changed_enumerators_.empty());
3999 }
4000 
4001 /// If the lookup tables are not yet built, walk the differences and
4002 /// fill the lookup tables.
4003 void
ensure_lookup_tables_populated()4004 enum_diff::ensure_lookup_tables_populated()
4005 {
4006   if (!lookup_tables_empty())
4007     return;
4008 
4009   {
4010     edit_script e = priv_->enumerators_changes_;
4011 
4012     for (vector<deletion>::const_iterator it = e.deletions().begin();
4013 	 it != e.deletions().end();
4014 	 ++it)
4015       {
4016 	unsigned i = it->index();
4017 	const enum_type_decl::enumerator& n =
4018 	  first_enum()->get_enumerators()[i];
4019 	const string& name = n.get_name();
4020 	ABG_ASSERT(priv_->deleted_enumerators_.find(n.get_name())
4021 	       == priv_->deleted_enumerators_.end());
4022 	priv_->deleted_enumerators_[name] = n;
4023       }
4024 
4025     for (vector<insertion>::const_iterator it = e.insertions().begin();
4026 	 it != e.insertions().end();
4027 	 ++it)
4028       {
4029 	for (vector<unsigned>::const_iterator iit =
4030 	       it->inserted_indexes().begin();
4031 	     iit != it->inserted_indexes().end();
4032 	     ++iit)
4033 	  {
4034 	    unsigned i = *iit;
4035 	    const enum_type_decl::enumerator& n =
4036 	      second_enum()->get_enumerators()[i];
4037 	    const string& name = n.get_name();
4038 	    ABG_ASSERT(priv_->inserted_enumerators_.find(n.get_name())
4039 		   == priv_->inserted_enumerators_.end());
4040 	    string_enumerator_map::const_iterator j =
4041 	      priv_->deleted_enumerators_.find(name);
4042 	    if (j == priv_->deleted_enumerators_.end())
4043 	      priv_->inserted_enumerators_[name] = n;
4044 	    else
4045 	      {
4046 		if (j->second != n)
4047 		  priv_->changed_enumerators_[j->first] =
4048 		    std::make_pair(j->second, n);
4049 		priv_->deleted_enumerators_.erase(j);
4050 	      }
4051 	  }
4052       }
4053   }
4054 }
4055 
4056 /// Populate the vector of children node of the @ref diff base type
4057 /// sub-object of this instance of @ref enum_diff.
4058 ///
4059 /// The children node can then later be retrieved using
4060 /// diff::children_node().
4061 void
chain_into_hierarchy()4062 enum_diff::chain_into_hierarchy()
4063 {append_child_node(underlying_type_diff());}
4064 
4065 /// Constructor for enum_diff.
4066 ///
4067 /// @param first the first enum type of the diff.
4068 ///
4069 /// @param second the second enum type of the diff.
4070 ///
4071 /// @param underlying_type_diff the diff of the two underlying types
4072 /// of the two enum types.
4073 ///
4074 /// @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)4075 enum_diff::enum_diff(const enum_type_decl_sptr	first,
4076 		     const enum_type_decl_sptr	second,
4077 		     const diff_sptr		underlying_type_diff,
4078 		     const diff_context_sptr	ctxt)
4079   : type_diff_base(first, second, ctxt),
4080     priv_(new priv(underlying_type_diff))
4081 {}
4082 
4083 /// Finish building the current instance of @ref enum_diff.
4084 void
finish_diff_type()4085 enum_diff::finish_diff_type()
4086 {
4087   if (diff::priv_->finished_)
4088     return;
4089   chain_into_hierarchy();
4090   diff::priv_->finished_ = true;
4091 }
4092 
4093 /// @return the first enum of the diff.
4094 const enum_type_decl_sptr
first_enum() const4095 enum_diff::first_enum() const
4096 {return dynamic_pointer_cast<enum_type_decl>(first_subject());}
4097 
4098 /// @return the second enum of the diff.
4099 const enum_type_decl_sptr
second_enum() const4100 enum_diff::second_enum() const
4101 {return dynamic_pointer_cast<enum_type_decl>(second_subject());}
4102 
4103 /// @return the diff of the two underlying enum types.
4104 diff_sptr
underlying_type_diff() const4105 enum_diff::underlying_type_diff() const
4106 {return priv_->underlying_type_diff_;}
4107 
4108 /// @return a map of the enumerators that were deleted.
4109 const string_enumerator_map&
deleted_enumerators() const4110 enum_diff::deleted_enumerators() const
4111 {return priv_->deleted_enumerators_;}
4112 
4113 /// @return a map of the enumerators that were inserted
4114 const string_enumerator_map&
inserted_enumerators() const4115 enum_diff::inserted_enumerators() const
4116 {return priv_->inserted_enumerators_;}
4117 
4118 /// @return a map of the enumerators that were changed
4119 const string_changed_enumerator_map&
changed_enumerators() const4120 enum_diff::changed_enumerators() const
4121 {return priv_->changed_enumerators_;}
4122 
4123 /// @return the pretty representation of the current instance of @ref
4124 /// enum_diff.
4125 const string&
get_pretty_representation() const4126 enum_diff::get_pretty_representation() const
4127 {
4128   if (diff::priv_->pretty_representation_.empty())
4129     {
4130       std::ostringstream o;
4131       o << "enum_diff["
4132 	<< first_subject()->get_pretty_representation()
4133 	<< ", "
4134 	<< second_subject()->get_pretty_representation()
4135 	<< "]";
4136       diff::priv_->pretty_representation_ = o.str();
4137     }
4138   return diff::priv_->pretty_representation_;
4139 }
4140 
4141 /// Return true iff the current diff node carries a change.
4142 ///
4143 /// @return true iff the current diff node carries a change.
4144 bool
has_changes() const4145 enum_diff::has_changes() const
4146 {return first_enum() != second_enum();}
4147 
4148 /// @return the kind of local change carried by the current diff node.
4149 /// The value returned is zero if the current node carries no local
4150 /// change.
4151 enum change_kind
has_local_changes() const4152 enum_diff::has_local_changes() const
4153 {
4154   ir::change_kind k = ir::NO_CHANGE_KIND;
4155   if (!equals(*first_enum(), *second_enum(), &k))
4156     return k & ir::ALL_LOCAL_CHANGES_MASK;
4157   return ir::NO_CHANGE_KIND;
4158 }
4159 
4160 /// Report the differences between the two enums.
4161 ///
4162 /// @param out the output stream to send the report to.
4163 ///
4164 /// @param indent the string to use for indentation.
4165 void
report(ostream & out,const string & indent) const4166 enum_diff::report(ostream& out, const string& indent) const
4167 {
4168   context()->get_reporter()->report(*this, out, indent);
4169 }
4170 
4171 /// Compute the set of changes between two instances of @ref
4172 /// enum_type_decl.
4173 ///
4174 /// Note that the two types must have been created in the same @ref
4175 /// environment, otherwise, this function aborts.
4176 ///
4177 /// @param first a pointer to the first enum_type_decl to consider.
4178 ///
4179 /// @param second a pointer to the second enum_type_decl to consider.
4180 ///
4181 /// @return the resulting diff of the two enums @p first and @p
4182 /// second.
4183 ///
4184 /// @param ctxt the diff context to use.
4185 enum_diff_sptr
compute_diff(const enum_type_decl_sptr first,const enum_type_decl_sptr second,diff_context_sptr ctxt)4186 compute_diff(const enum_type_decl_sptr first,
4187 	     const enum_type_decl_sptr second,
4188 	     diff_context_sptr ctxt)
4189 {
4190   if (first && second)
4191     ABG_ASSERT(first->get_environment() == second->get_environment());
4192 
4193   diff_sptr ud = compute_diff_for_types(first->get_underlying_type(),
4194 					second->get_underlying_type(),
4195 					ctxt);
4196   enum_diff_sptr d(new enum_diff(first, second, ud, ctxt));
4197   bool s = first->get_environment()->use_enum_binary_only_equality();
4198   first->get_environment()->use_enum_binary_only_equality(true);
4199   if (first != second)
4200     {
4201       first->get_environment()->use_enum_binary_only_equality(false);
4202       compute_diff(first->get_enumerators().begin(),
4203 		   first->get_enumerators().end(),
4204 		   second->get_enumerators().begin(),
4205 		   second->get_enumerators().end(),
4206 		   d->priv_->enumerators_changes_);
4207       d->ensure_lookup_tables_populated();
4208     }
4209   first->get_environment()->use_enum_binary_only_equality(s);
4210   ctxt->initialize_canonical_diff(d);
4211 
4212   return d;
4213 }
4214 // </enum_diff stuff>
4215 
4216 // <class_or_union_diff stuff>
4217 
4218 /// Test if the current diff node carries a member type change for a
4219 /// member type which name is the same as the name of a given type
4220 /// declaration.
4221 ///
4222 /// @param d the type declaration which name should be equal to the
4223 /// name of the member type that might have changed.
4224 ///
4225 /// @return the member type that has changed, iff there were a member
4226 /// type (which name is the same as the name of @p d) that changed.
4227 /// Note that the member type that is returned is the new value of the
4228 /// member type that changed.
4229 type_or_decl_base_sptr
member_type_has_changed(decl_base_sptr d) const4230 class_or_union_diff::priv::member_type_has_changed(decl_base_sptr d) const
4231 {
4232   string qname = d->get_qualified_name();
4233   string_diff_sptr_map::const_iterator it =
4234     changed_member_types_.find(qname);
4235 
4236   return ((it == changed_member_types_.end())
4237 	  ? type_or_decl_base_sptr()
4238 	  : it->second->second_subject());
4239 }
4240 
4241 /// Test if the current diff node carries a data member change for a
4242 /// data member which name is the same as the name of a given type
4243 /// declaration.
4244 ///
4245 /// @param d the type declaration which name should be equal to the
4246 /// name of the data member that might have changed.
4247 ///
4248 /// @return the data member that has changed, iff there were a data
4249 /// member type (which name is the same as the name of @p d) that
4250 /// changed.  Note that the data member that is returned is the new
4251 /// value of the data member that changed.
4252 decl_base_sptr
subtype_changed_dm(decl_base_sptr d) const4253 class_or_union_diff::priv::subtype_changed_dm(decl_base_sptr d) const
4254 {
4255   string qname = d->get_qualified_name();
4256   string_var_diff_sptr_map::const_iterator it =
4257     subtype_changed_dm_.find(qname);
4258 
4259   if (it == subtype_changed_dm_.end())
4260     return decl_base_sptr();
4261   return it->second->second_var();
4262 }
4263 
4264 /// Test if the current diff node carries a member class template
4265 /// change for a member class template which name is the same as the
4266 /// name of a given type declaration.
4267 ///
4268 /// @param d the type declaration which name should be equal to the
4269 /// name of the member class template that might have changed.
4270 ///
4271 /// @return the member class template that has changed, iff there were
4272 /// a member class template (which name is the same as the name of @p
4273 /// d) that changed.  Note that the member class template that is
4274 /// returned is the new value of the member class template that
4275 /// changed.
4276 decl_base_sptr
member_class_tmpl_has_changed(decl_base_sptr d) const4277 class_or_union_diff::priv::member_class_tmpl_has_changed(decl_base_sptr d) const
4278 {
4279   string qname = d->get_qualified_name();
4280   string_diff_sptr_map::const_iterator it =
4281     changed_member_class_tmpls_.find(qname);
4282 
4283   return ((it == changed_member_class_tmpls_.end())
4284 	  ? decl_base_sptr()
4285 	  : dynamic_pointer_cast<decl_base>(it->second->second_subject()));
4286 }
4287 
4288 /// Get the number of non static data members that were deleted.
4289 ///
4290 /// @return the number of non static data members that were deleted.
4291 size_t
get_deleted_non_static_data_members_number() const4292 class_or_union_diff::priv::get_deleted_non_static_data_members_number() const
4293 {
4294   size_t result = 0;
4295 
4296   for (string_decl_base_sptr_map::const_iterator i =
4297 	 deleted_data_members_.begin();
4298        i != deleted_data_members_.end();
4299        ++i)
4300     if (is_member_decl(i->second)
4301 	&& !get_member_is_static(i->second))
4302       ++result;
4303 
4304   return result;
4305 }
4306 
4307 /// Get the number of non static data members that were inserted.
4308 ///
4309 /// @return the number of non static data members that were inserted.
4310 size_t
get_inserted_non_static_data_members_number() const4311 class_or_union_diff::priv::get_inserted_non_static_data_members_number() const
4312 {
4313   size_t result = 0;
4314 
4315   for (string_decl_base_sptr_map::const_iterator i =
4316 	 inserted_data_members_.begin();
4317        i != inserted_data_members_.end();
4318        ++i)
4319     if (is_member_decl(i->second)
4320 	&& !get_member_is_static(i->second))
4321       ++result;
4322 
4323   return result;
4324 }
4325 
4326 /// Get the number of data member sub-type changes carried by the
4327 /// current diff node that were filtered out.
4328 ///
4329 /// @param local_only if true, it means that only (filtered) local
4330 /// changes are considered.
4331 ///
4332 /// @return the number of data member sub-type changes carried by the
4333 /// current diff node that were filtered out.
4334 size_t
count_filtered_subtype_changed_dm(bool local_only)4335 class_or_union_diff::priv::count_filtered_subtype_changed_dm(bool local_only)
4336 {
4337   size_t num_filtered= 0;
4338   for (var_diff_sptrs_type::const_iterator i =
4339 	 sorted_subtype_changed_dm_.begin();
4340        i != sorted_subtype_changed_dm_.end();
4341        ++i)
4342     {
4343       if (local_only)
4344 	{
4345 	  if ((*i)->has_changes()
4346 	      && !(*i)->has_local_changes_to_be_reported())
4347 	    ++num_filtered;
4348 	}
4349       else
4350 	{
4351 	  if ((*i)->is_filtered_out())
4352 	    ++num_filtered;
4353 	}
4354     }
4355   return num_filtered;
4356 }
4357 
4358 /// Get the number of data member changes carried by the current diff
4359 /// node that were filtered out.
4360 ///
4361 /// @param local_only if true, it means that only (filtered) local
4362 /// changes are considered.
4363 ///
4364 /// @return the number of data member changes carried by the current
4365 /// diff node that were filtered out.
4366 size_t
count_filtered_changed_dm(bool local_only)4367 class_or_union_diff::priv::count_filtered_changed_dm(bool local_only)
4368 {
4369   size_t num_filtered= 0;
4370 
4371   for (unsigned_var_diff_sptr_map::const_iterator i = changed_dm_.begin();
4372        i != changed_dm_.end();
4373        ++i)
4374     {
4375       diff_sptr diff = i->second;
4376       if (local_only)
4377 	{
4378 	  if ((diff->has_changes() && !diff->has_local_changes_to_be_reported())
4379 	      || diff->is_filtered_out())
4380 	    ++num_filtered;
4381 	}
4382       else
4383 	{
4384 	  if (diff->is_filtered_out())
4385 	    ++num_filtered;
4386 	}
4387     }
4388   return num_filtered;
4389 }
4390 
4391 /// Skip the processing of the current member function if its
4392 /// virtual-ness is disallowed by the user.
4393 ///
4394 /// This is to be used in the member functions below that are used to
4395 /// count the number of filtered inserted, deleted and changed member
4396 /// functions.
4397 #define SKIP_MEM_FN_IF_VIRTUALITY_DISALLOWED				\
4398   do {									\
4399     if (get_member_function_is_virtual(f)					\
4400 	|| get_member_function_is_virtual(s))				\
4401       {								\
4402 	if (!(allowed_category | VIRTUAL_MEMBER_CHANGE_CATEGORY))	\
4403 	  continue;							\
4404       }								\
4405     else								\
4406       {								\
4407 	if (!(allowed_category | NON_VIRT_MEM_FUN_CHANGE_CATEGORY))	\
4408 	  continue;							\
4409       }								\
4410   } while (false)
4411 
4412 /// Get the number of member functions changes carried by the current
4413 /// diff node that were filtered out.
4414 ///
4415 /// @return the number of member functions changes carried by the
4416 /// current diff node that were filtered out.
4417 size_t
count_filtered_changed_mem_fns(const diff_context_sptr & ctxt)4418 class_or_union_diff::priv::count_filtered_changed_mem_fns
4419 (const diff_context_sptr& ctxt)
4420 {
4421   size_t count = 0;
4422   diff_category allowed_category = ctxt->get_allowed_category();
4423 
4424   for (function_decl_diff_sptrs_type::const_iterator i =
4425 	 sorted_changed_member_functions_.begin();
4426        i != sorted_changed_member_functions_.end();
4427        ++i)
4428     {
4429       method_decl_sptr f =
4430 	dynamic_pointer_cast<method_decl>
4431 	((*i)->first_function_decl());
4432       ABG_ASSERT(f);
4433 
4434       method_decl_sptr s =
4435 	dynamic_pointer_cast<method_decl>
4436 	((*i)->second_function_decl());
4437       ABG_ASSERT(s);
4438 
4439       SKIP_MEM_FN_IF_VIRTUALITY_DISALLOWED;
4440 
4441       diff_sptr diff = *i;
4442       ctxt->maybe_apply_filters(diff);
4443 
4444       if (diff->is_filtered_out())
4445 	++count;
4446     }
4447 
4448   return count;
4449 }
4450 
4451 /// Get the number of member functions insertions carried by the current
4452 /// diff node that were filtered out.
4453 ///
4454 /// @return the number of member functions insertions carried by the
4455 /// current diff node that were filtered out.
4456 size_t
count_filtered_inserted_mem_fns(const diff_context_sptr & ctxt)4457 class_or_union_diff::priv::count_filtered_inserted_mem_fns
4458 (const diff_context_sptr& ctxt)
4459 {
4460     size_t count = 0;
4461   diff_category allowed_category = ctxt->get_allowed_category();
4462 
4463   for (string_member_function_sptr_map::const_iterator i =
4464 	 inserted_member_functions_.begin();
4465        i != inserted_member_functions_.end();
4466        ++i)
4467     {
4468       method_decl_sptr f = i->second,
4469 	s = i->second;
4470 
4471       SKIP_MEM_FN_IF_VIRTUALITY_DISALLOWED;
4472 
4473       diff_sptr diff = compute_diff_for_decls(f, s, ctxt);
4474       ctxt->maybe_apply_filters(diff);
4475 
4476       if (diff->get_category() != NO_CHANGE_CATEGORY
4477 	  && diff->is_filtered_out())
4478 	++count;
4479     }
4480 
4481   return count;
4482 }
4483 
4484 /// Get the number of member functions deletions carried by the current
4485 /// diff node that were filtered out.
4486 ///
4487 /// @return the number of member functions deletions carried by the
4488 /// current diff node that were filtered out.
4489 size_t
count_filtered_deleted_mem_fns(const diff_context_sptr & ctxt)4490 class_or_union_diff::priv::count_filtered_deleted_mem_fns
4491 (const diff_context_sptr& ctxt)
4492 {
4493   size_t count = 0;
4494   diff_category allowed_category = ctxt->get_allowed_category();
4495 
4496   for (string_member_function_sptr_map::const_iterator i =
4497 	 deleted_member_functions_.begin();
4498        i != deleted_member_functions_.end();
4499        ++i)
4500     {
4501       method_decl_sptr f = i->second,
4502 	s = i->second;
4503 
4504       SKIP_MEM_FN_IF_VIRTUALITY_DISALLOWED;
4505 
4506       diff_sptr diff = compute_diff_for_decls(f, s, ctxt);
4507       ctxt->maybe_apply_filters(diff);
4508 
4509       if (diff->get_category() != NO_CHANGE_CATEGORY
4510 	  && diff->is_filtered_out())
4511 	++count;
4512     }
4513 
4514   return count;
4515 }
4516 
4517 /// Clear the lookup tables useful for reporting.
4518 ///
4519 /// This function must be updated each time a lookup table is added or
4520 /// removed from the class_or_union_diff::priv.
4521 void
clear_lookup_tables()4522 class_or_union_diff::clear_lookup_tables()
4523 {
4524   priv_->deleted_member_types_.clear();
4525   priv_->inserted_member_types_.clear();
4526   priv_->changed_member_types_.clear();
4527   priv_->deleted_data_members_.clear();
4528   priv_->inserted_data_members_.clear();
4529   priv_->subtype_changed_dm_.clear();
4530   priv_->deleted_member_functions_.clear();
4531   priv_->inserted_member_functions_.clear();
4532   priv_->changed_member_functions_.clear();
4533   priv_->deleted_member_class_tmpls_.clear();
4534   priv_->inserted_member_class_tmpls_.clear();
4535   priv_->changed_member_class_tmpls_.clear();
4536 }
4537 
4538 /// Tests if the lookup tables are empty.
4539 ///
4540 /// @return true if the lookup tables are empty, false otherwise.
4541 bool
lookup_tables_empty(void) const4542 class_or_union_diff::lookup_tables_empty(void) const
4543 {
4544   return (priv_->deleted_member_types_.empty()
4545 	  && priv_->inserted_member_types_.empty()
4546 	  && priv_->changed_member_types_.empty()
4547 	  && priv_->deleted_data_members_.empty()
4548 	  && priv_->inserted_data_members_.empty()
4549 	  && priv_->subtype_changed_dm_.empty()
4550 	  && priv_->inserted_member_functions_.empty()
4551 	  && priv_->deleted_member_functions_.empty()
4552 	  && priv_->changed_member_functions_.empty()
4553 	  && priv_->deleted_member_class_tmpls_.empty()
4554 	  && priv_->inserted_member_class_tmpls_.empty()
4555 	  && priv_->changed_member_class_tmpls_.empty());
4556 }
4557 
4558 /// If the lookup tables are not yet built, walk the differences and
4559 /// fill them.
4560 void
ensure_lookup_tables_populated(void) const4561 class_or_union_diff::ensure_lookup_tables_populated(void) const
4562 {
4563   {
4564     edit_script& e = priv_->member_types_changes_;
4565 
4566     for (vector<deletion>::const_iterator it = e.deletions().begin();
4567 	 it != e.deletions().end();
4568 	 ++it)
4569       {
4570 	unsigned i = it->index();
4571 	decl_base_sptr d =
4572 	  get_type_declaration(first_class_or_union()->get_member_types()[i]);
4573 	class_or_union_sptr record_type = is_class_or_union_type(d);
4574 	if (record_type && record_type->get_is_declaration_only())
4575 	  continue;
4576 	string name = d->get_name();
4577 	priv_->deleted_member_types_[name] = d;
4578       }
4579 
4580     for (vector<insertion>::const_iterator it = e.insertions().begin();
4581 	 it != e.insertions().end();
4582 	 ++it)
4583       {
4584 	for (vector<unsigned>::const_iterator iit =
4585 	       it->inserted_indexes().begin();
4586 	     iit != it->inserted_indexes().end();
4587 	     ++iit)
4588 	  {
4589 	    unsigned i = *iit;
4590 	    decl_base_sptr d =
4591 	      get_type_declaration(second_class_or_union()->get_member_types()[i]);
4592 	    class_or_union_sptr record_type = is_class_or_union_type(d);
4593 	    if (record_type && record_type->get_is_declaration_only())
4594 	      continue;
4595 	    string name = d->get_name();
4596 	    string_decl_base_sptr_map::const_iterator j =
4597 	      priv_->deleted_member_types_.find(name);
4598 	    if (j != priv_->deleted_member_types_.end())
4599 	      {
4600 		if (*j->second != *d)
4601 		  priv_->changed_member_types_[name] =
4602 		    compute_diff(j->second, d, context());
4603 
4604 		priv_->deleted_member_types_.erase(j);
4605 	      }
4606 	    else
4607 	      priv_->inserted_member_types_[name] = d;
4608 	  }
4609       }
4610   }
4611 
4612   {
4613     edit_script& e = priv_->data_members_changes_;
4614 
4615     for (vector<deletion>::const_iterator it = e.deletions().begin();
4616 	 it != e.deletions().end();
4617 	 ++it)
4618       {
4619 	unsigned i = it->index();
4620 	var_decl_sptr data_member =
4621 	  is_var_decl(first_class_or_union()->get_non_static_data_members()[i]);
4622 	string name = data_member->get_anon_dm_reliable_name();
4623 
4624 	ABG_ASSERT(priv_->deleted_data_members_.find(name)
4625 		   == priv_->deleted_data_members_.end());
4626 	priv_->deleted_data_members_[name] = data_member;
4627       }
4628 
4629     for (vector<insertion>::const_iterator it = e.insertions().begin();
4630 	 it != e.insertions().end();
4631 	 ++it)
4632       {
4633 	for (vector<unsigned>::const_iterator iit =
4634 	       it->inserted_indexes().begin();
4635 	     iit != it->inserted_indexes().end();
4636 	     ++iit)
4637 	  {
4638 	    unsigned i = *iit;
4639 	    decl_base_sptr d =
4640 	      second_class_or_union()->get_non_static_data_members()[i];
4641 	    var_decl_sptr added_dm = is_var_decl(d);
4642 	    string name = added_dm->get_anon_dm_reliable_name();
4643 	    ABG_ASSERT(priv_->inserted_data_members_.find(name)
4644 		       == priv_->inserted_data_members_.end());
4645 
4646 	    bool ignore_added_anonymous_data_member = false;
4647 	    if (is_anonymous_data_member(added_dm))
4648 	      {
4649 		//
4650 		// Handle insertion of anonymous data member to
4651 		// replace existing data members.
4652 		//
4653 		// For instance consider this:
4654 		//   struct S
4655 		//   {
4656 		//     int a;
4657 		//     int b;
4658 		//     int c;
4659 		//   };// end struct S
4660 		//
4661 		//   Where the data members 'a' and 'b' are replaced
4662 		//   by an anonymous data member without changing the
4663 		//   effective bit layout of the structure:
4664 		//
4665 		//   struct S
4666 		//   {
4667 		//     struct
4668 		//     {
4669 		//       union
4670 		//       {
4671 		//         int a;
4672 		//         char a_1;
4673 		//       };
4674 		//       union
4675 		//       {
4676 		//         int b;
4677 		//         char b_1;
4678 		//       };
4679 		//     };
4680 		//     int c;
4681 		//   }; // end struct S
4682 		//
4683 		var_decl_sptr replaced_dm, replacing_dm;
4684 		bool added_anon_dm_changes_dm = false;
4685 		// The vector of data members replaced by anonymous
4686 		// data members.
4687 		vector<var_decl_sptr> dms_replaced_by_anon_dm;
4688 
4689 		//
4690 		// Let's start collecting the set of data members
4691 		// which have been replaced by anonymous types in a
4692 		// harmless way.  These are going to be collected into
4693 		// dms_replaced_by_anon_dm and, ultimately, into
4694 		// priv_->dms_replaced_by_adms_
4695 		//
4696 		for (string_decl_base_sptr_map::const_iterator it =
4697 		       priv_->deleted_data_members_.begin();
4698 		     it != priv_->deleted_data_members_.end();
4699 		     ++it)
4700 		  {
4701 		    // We don't support this pattern for anonymous
4702 		    // data members themselves being replaced.  If
4703 		    // that occurs then we'll just report it verbatim.
4704 		    if (is_anonymous_data_member(it->second))
4705 		      continue;
4706 
4707 		    string deleted_dm_name = it->second->get_name();
4708 		    if ((replacing_dm =
4709 			 find_data_member_from_anonymous_data_member(added_dm,
4710 								     deleted_dm_name)))
4711 		      {
4712 			// So it looks like replacing_dm might have
4713 			// replaced the data member which name is
4714 			// 'deleted_dm_name'.  Let's look deeper to be
4715 			// sure.
4716 			//
4717 			// Note that replacing_dm is part (member) of
4718 			// an anonymous data member that might replace
4719 			// replaced_dm.
4720 
4721 			// So let's get that replaced data member.
4722 			replaced_dm = is_var_decl(it->second);
4723 			size_t replaced_dm_offset =
4724 			  get_data_member_offset(replaced_dm),
4725 			replacing_dm_offset =
4726 			  get_absolute_data_member_offset(replacing_dm);
4727 
4728 			if (replaced_dm_offset != replacing_dm_offset)
4729 			  {
4730 			    // So the replacing data member and the
4731 			    // replaced data member don't have the
4732 			    // same offset.  This is not the pattern we
4733 			    // are looking for.  Rather, it looks like
4734 			    // the anonymous data member has *changed*
4735 			    // the data member.
4736 			    added_anon_dm_changes_dm = true;
4737 			    break;
4738 			  }
4739 
4740 			if (replaced_dm->get_type()->get_size_in_bits()
4741 			    == replaced_dm->get_type()->get_size_in_bits())
4742 			  dms_replaced_by_anon_dm.push_back(replaced_dm);
4743 			else
4744 			  {
4745 			    added_anon_dm_changes_dm = true;
4746 			    break;
4747 			  }
4748 		      }
4749 		  }
4750 
4751 		// Now walk dms_replaced_by_anon_dm to fill up
4752 		// priv_->dms_replaced_by_adms_ with the set of data
4753 		// members replaced by anonymous data members.
4754 		if (!added_anon_dm_changes_dm
4755 		    && !dms_replaced_by_anon_dm.empty())
4756 		  {
4757 		    // See if the added data member isn't too big.
4758 		    type_base_sptr added_dm_type = added_dm->get_type();
4759 		    ABG_ASSERT(added_dm_type);
4760 		    var_decl_sptr new_next_dm =
4761 		      get_next_data_member(second_class_or_union(),
4762 					   added_dm);
4763 		    var_decl_sptr old_next_dm =
4764 		      first_class_or_union()->find_data_member(new_next_dm);
4765 
4766 		    if (!old_next_dm
4767 			|| (old_next_dm
4768 			    && (get_absolute_data_member_offset(old_next_dm)
4769 				== get_absolute_data_member_offset(new_next_dm))))
4770 		      {
4771 			// None of the data members that are replaced
4772 			// by the added union should be considered as
4773 			// having been deleted.
4774 			ignore_added_anonymous_data_member = true;
4775 			for (vector<var_decl_sptr>::const_iterator i =
4776 			       dms_replaced_by_anon_dm.begin();
4777 			     i != dms_replaced_by_anon_dm.end();
4778 			     ++i)
4779 			  {
4780 			    string n = (*i)->get_name();
4781 			    priv_->dms_replaced_by_adms_[n] =
4782 			      added_dm;
4783 			    priv_->deleted_data_members_.erase(n);
4784 			  }
4785 		      }
4786 		  }
4787 	      }
4788 
4789 	    if (!ignore_added_anonymous_data_member)
4790 	      {
4791 		// Detect changed data members.
4792 		//
4793 		// A changed data member (that we shall name D) is a data
4794 		// member that satisfies the conditions below:
4795 		//
4796 		// 1/ It must have been added.
4797 		//
4798 		// 2/ It must have been deleted as well.
4799 		//
4800 		// 3/ It there must be a non-empty difference between the
4801 		// deleted D and the added D.
4802 		string_decl_base_sptr_map::const_iterator j =
4803 		  priv_->deleted_data_members_.find(name);
4804 		if (j != priv_->deleted_data_members_.end())
4805 		  {
4806 		    if (*j->second != *d)
4807 		      {
4808 			var_decl_sptr old_dm = is_var_decl(j->second);
4809 			priv_->subtype_changed_dm_[name]=
4810 			  compute_diff(old_dm, added_dm, context());
4811 		      }
4812 		    priv_->deleted_data_members_.erase(j);
4813 		  }
4814 		else
4815 		  priv_->inserted_data_members_[name] = d;
4816 	      }
4817 	  }
4818       }
4819 
4820     // Now detect when a data member is deleted from offset N and
4821     // another one is added to offset N.  In that case, we want to be
4822     // able to say that the data member at offset N changed.
4823     for (string_decl_base_sptr_map::const_iterator i =
4824 	   priv_->deleted_data_members_.begin();
4825 	 i != priv_->deleted_data_members_.end();
4826 	 ++i)
4827       {
4828 	unsigned offset = get_data_member_offset(i->second);
4829 	priv_->deleted_dm_by_offset_[offset] = i->second;
4830       }
4831 
4832     for (string_decl_base_sptr_map::const_iterator i =
4833 	   priv_->inserted_data_members_.begin();
4834 	 i != priv_->inserted_data_members_.end();
4835 	 ++i)
4836       {
4837 	unsigned offset = get_data_member_offset(i->second);
4838 	priv_->inserted_dm_by_offset_[offset] = i->second;
4839       }
4840 
4841     for (unsigned_decl_base_sptr_map::const_iterator i =
4842 	   priv_->inserted_dm_by_offset_.begin();
4843 	 i != priv_->inserted_dm_by_offset_.end();
4844 	 ++i)
4845       {
4846 	unsigned_decl_base_sptr_map::const_iterator j =
4847 	  priv_->deleted_dm_by_offset_.find(i->first);
4848 	if (j != priv_->deleted_dm_by_offset_.end())
4849 	  {
4850 	    var_decl_sptr old_dm = is_var_decl(j->second);
4851 	    var_decl_sptr new_dm = is_var_decl(i->second);
4852 	    priv_->changed_dm_[i->first] =
4853 	      compute_diff(old_dm, new_dm, context());
4854 	  }
4855       }
4856 
4857     for (unsigned_var_diff_sptr_map::const_iterator i =
4858 	   priv_->changed_dm_.begin();
4859 	 i != priv_->changed_dm_.end();
4860 	 ++i)
4861       {
4862 	priv_->deleted_dm_by_offset_.erase(i->first);
4863 	priv_->inserted_dm_by_offset_.erase(i->first);
4864 	priv_->deleted_data_members_.erase
4865 	  (i->second->first_var()->get_anon_dm_reliable_name());
4866 	priv_->inserted_data_members_.erase
4867 	  (i->second->second_var()->get_anon_dm_reliable_name());
4868       }
4869   }
4870   sort_string_data_member_diff_sptr_map(priv_->subtype_changed_dm_,
4871 					priv_->sorted_subtype_changed_dm_);
4872   sort_unsigned_data_member_diff_sptr_map(priv_->changed_dm_,
4873 					  priv_->sorted_changed_dm_);
4874 
4875   {
4876     edit_script& e = priv_->member_class_tmpls_changes_;
4877 
4878     for (vector<deletion>::const_iterator it = e.deletions().begin();
4879 	 it != e.deletions().end();
4880 	 ++it)
4881       {
4882 	unsigned i = it->index();
4883 	decl_base_sptr d =
4884 	  first_class_or_union()->get_member_class_templates()[i]->
4885 	  as_class_tdecl();
4886 	string name = d->get_name();
4887 	ABG_ASSERT(priv_->deleted_member_class_tmpls_.find(name)
4888 	       == priv_->deleted_member_class_tmpls_.end());
4889 	priv_->deleted_member_class_tmpls_[name] = d;
4890       }
4891 
4892     for (vector<insertion>::const_iterator it = e.insertions().begin();
4893 	 it != e.insertions().end();
4894 	 ++it)
4895       {
4896 	for (vector<unsigned>::const_iterator iit =
4897 	       it->inserted_indexes().begin();
4898 	     iit != it->inserted_indexes().end();
4899 	     ++iit)
4900 	  {
4901 	    unsigned i = *iit;
4902 	    decl_base_sptr d =
4903 	      second_class_or_union()->get_member_class_templates()[i]->
4904 	      as_class_tdecl();
4905 	    string name = d->get_name();
4906 	    ABG_ASSERT(priv_->inserted_member_class_tmpls_.find(name)
4907 		   == priv_->inserted_member_class_tmpls_.end());
4908 	    string_decl_base_sptr_map::const_iterator j =
4909 	      priv_->deleted_member_class_tmpls_.find(name);
4910 	    if (j != priv_->deleted_member_class_tmpls_.end())
4911 	      {
4912 		if (*j->second != *d)
4913 		  priv_->changed_member_types_[name]=
4914 		    compute_diff(j->second, d, context());
4915 		priv_->deleted_member_class_tmpls_.erase(j);
4916 	      }
4917 	    else
4918 	      priv_->inserted_member_class_tmpls_[name] = d;
4919 	  }
4920       }
4921   }
4922   sort_string_diff_sptr_map(priv_->changed_member_types_,
4923 			    priv_->sorted_changed_member_types_);
4924 }
4925 
4926 /// Allocate the memory for the priv_ pimpl data member of the @ref
4927 /// class_or_union_diff class.
4928 void
allocate_priv_data()4929 class_or_union_diff::allocate_priv_data()
4930 {
4931   if (!priv_)
4932     priv_.reset(new priv);
4933 }
4934 
4935 /// Constructor for the @ref class_or_union_diff class.
4936 ///
4937 /// @param first_scope the first @ref class_or_union of the diff node.
4938 ///
4939 /// @param second_scope the second @ref class_or_union of the diff node.
4940 ///
4941 /// @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)4942 class_or_union_diff::class_or_union_diff(class_or_union_sptr first_scope,
4943 					 class_or_union_sptr second_scope,
4944 					 diff_context_sptr ctxt)
4945   : type_diff_base(first_scope, second_scope, ctxt)
4946     //priv_(new priv)
4947 {}
4948 
4949 /// Finish building the current instance of @ref class_or_union_diff.
4950 void
finish_diff_type()4951 class_or_union_diff::finish_diff_type()
4952 {
4953   if (diff::priv_->finished_)
4954     return;
4955   chain_into_hierarchy();
4956   diff::priv_->finished_ = true;
4957 }
4958 
4959 /// Getter of the private data of the @ref class_or_union_diff type.
4960 ///
4961 /// Note that due to an optimization, the private data of @ref
4962 /// class_or_union_diff can be shared among several instances of
4963 /// class_or_union_diff, so you should never try to access
4964 /// class_or_union_diff::priv directly.
4965 ///
4966 /// When class_or_union_diff::priv is shared, this function returns
4967 /// the correct shared one.
4968 ///
4969 /// @return the (possibly) shared private data of the current instance
4970 /// of @ref class_or_union_diff.
4971 const class_or_union_diff::priv_ptr&
get_priv() const4972 class_or_union_diff::get_priv() const
4973 {
4974   if (priv_)
4975     return priv_;
4976 
4977   // If the current class_or_union_diff::priv member is empty, then look for
4978   // the shared one, from the canonical type.
4979   class_or_union_diff *canonical =
4980     dynamic_cast<class_or_union_diff*>(get_canonical_diff());
4981   ABG_ASSERT(canonical);
4982   ABG_ASSERT(canonical->priv_);
4983 
4984   return canonical->priv_;
4985 }
4986 
4987 /// Destructor of class_or_union_diff.
~class_or_union_diff()4988 class_or_union_diff::~class_or_union_diff()
4989 {
4990 }
4991 
4992 /// @return the first @ref class_or_union involved in the diff.
4993 class_or_union_sptr
first_class_or_union() const4994 class_or_union_diff::first_class_or_union() const
4995 {return is_class_or_union_type(first_subject());}
4996 
4997 /// @return the second @ref class_or_union involved in the diff.
4998 class_or_union_sptr
second_class_or_union() const4999 class_or_union_diff::second_class_or_union() const
5000 {return is_class_or_union_type(second_subject());}
5001 
5002 /// @return the edit script of the member types of the two @ref
5003 /// class_or_union.
5004 const edit_script&
member_types_changes() const5005 class_or_union_diff::member_types_changes() const
5006 {return get_priv()->member_types_changes_;}
5007 
5008 /// @return the edit script of the member types of the two @ref
5009 /// class_or_union.
5010 edit_script&
member_types_changes()5011 class_or_union_diff::member_types_changes()
5012 {return get_priv()->member_types_changes_;}
5013 
5014 /// @return the edit script of the data members of the two @ref
5015 /// class_or_union.
5016 const edit_script&
data_members_changes() const5017 class_or_union_diff::data_members_changes() const
5018 {return get_priv()->data_members_changes_;}
5019 
5020 /// @return the edit script of the data members of the two @ref
5021 /// class_or_union.
5022 edit_script&
data_members_changes()5023 class_or_union_diff::data_members_changes()
5024 {return get_priv()->data_members_changes_;}
5025 
5026 /// Getter for the data members that got inserted.
5027 ///
5028 /// @return a map of data members that got inserted.
5029 const string_decl_base_sptr_map&
inserted_data_members() const5030 class_or_union_diff::inserted_data_members() const
5031 {return get_priv()->inserted_data_members_;}
5032 
5033 /// Getter for the data members that got deleted.
5034 ///
5035 /// @return a map of data members that got deleted.
5036 const string_decl_base_sptr_map&
deleted_data_members() const5037 class_or_union_diff::deleted_data_members() const
5038 {return get_priv()->deleted_data_members_;}
5039 
5040 /// @return the edit script of the member functions of the two @ref
5041 /// class_or_union.
5042 const edit_script&
member_fns_changes() const5043 class_or_union_diff::member_fns_changes() const
5044 {return get_priv()->member_fns_changes_;}
5045 
5046 /// Getter for the virtual members functions that have had a change in
5047 /// a sub-type, without having a change in their symbol name.
5048 ///
5049 /// @return a sorted vector of virtual member functions that have a
5050 /// sub-type change.
5051 const function_decl_diff_sptrs_type&
changed_member_fns() const5052 class_or_union_diff::changed_member_fns() const
5053 {return get_priv()->sorted_changed_member_functions_;}
5054 
5055 /// @return the edit script of the member functions of the two
5056 /// classes.
5057 edit_script&
member_fns_changes()5058 class_or_union_diff::member_fns_changes()
5059 {return get_priv()->member_fns_changes_;}
5060 
5061 /// @return a map of member functions that got deleted.
5062 const string_member_function_sptr_map&
deleted_member_fns() const5063 class_or_union_diff::deleted_member_fns() const
5064 {return get_priv()->deleted_member_functions_;}
5065 
5066 /// @return a map of member functions that got inserted.
5067 const string_member_function_sptr_map&
inserted_member_fns() const5068 class_or_union_diff::inserted_member_fns() const
5069 {return get_priv()->inserted_member_functions_;}
5070 
5071 /// Getter of the sorted vector of data members that got replaced by
5072 /// another data member.
5073 ///
5074 /// @return sorted vector of changed data member.
5075 const var_diff_sptrs_type&
sorted_changed_data_members() const5076 class_or_union_diff::sorted_changed_data_members() const
5077 {return get_priv()->sorted_changed_dm_;}
5078 
5079 /// Count the number of /filtered/ data members that got replaced by
5080 /// another data member.
5081 ///
5082 /// @return the number of changed data member that got filtered out.
5083 size_t
count_filtered_changed_data_members(bool local) const5084 class_or_union_diff::count_filtered_changed_data_members(bool local) const
5085 {return get_priv()->count_filtered_changed_dm(local);}
5086 
5087 /// Getter of the sorted vector of data members with a (sub-)type change.
5088 ///
5089 /// @return sorted vector of changed data member.
5090 const var_diff_sptrs_type&
sorted_subtype_changed_data_members() const5091 class_or_union_diff::sorted_subtype_changed_data_members() const
5092 {return get_priv()->sorted_subtype_changed_dm_;}
5093 
5094 /// Count the number of /filtered/ data members with a sub-type change.
5095 ///
5096 /// @return the number of changed data member that got filtered out.
5097 size_t
count_filtered_subtype_changed_data_members(bool local) const5098 class_or_union_diff::count_filtered_subtype_changed_data_members(bool local) const
5099 {return get_priv()->count_filtered_subtype_changed_dm(local);}
5100 
5101 /// Get the map of data members that got replaced by anonymous data
5102 /// members.
5103 ///
5104 /// The key of a map entry is the name of the replaced data member and
5105 /// the value is the anonymous data member that replaces it.
5106 ///
5107 /// @return the map of data members replaced by anonymous data
5108 /// members.
5109 const string_decl_base_sptr_map&
data_members_replaced_by_adms() const5110 class_or_union_diff::data_members_replaced_by_adms() const
5111 {return get_priv()->dms_replaced_by_adms_;}
5112 
5113 /// Get an ordered vector of of data members that got replaced by
5114 /// anonymous data members.
5115 ///
5116 /// This returns a vector of pair of two data members: the one that
5117 /// was replaced, and the anonymous data member that replaced it.
5118 ///
5119 /// @return the sorted vector data members replaced by anonymous data members.
5120 const changed_var_sptrs_type&
ordered_data_members_replaced_by_adms() const5121 class_or_union_diff::ordered_data_members_replaced_by_adms() const
5122 {
5123   if (priv_->dms_replaced_by_adms_ordered_.empty())
5124     {
5125       for (string_decl_base_sptr_map::const_iterator it =
5126 	     priv_->dms_replaced_by_adms_.begin();
5127 	   it != priv_->dms_replaced_by_adms_.end();
5128 	   ++it)
5129 	{
5130 	  const var_decl_sptr dm =
5131 	    first_class_or_union()->find_data_member(it->first);
5132 	  ABG_ASSERT(dm);
5133 	  changed_var_sptr changed_dm(dm, is_data_member(it->second));
5134 	  priv_->dms_replaced_by_adms_ordered_.push_back(changed_dm);
5135 	}
5136       sort_changed_data_members(priv_->dms_replaced_by_adms_ordered_);
5137     }
5138 
5139   return priv_->dms_replaced_by_adms_ordered_;
5140 }
5141 
5142 /// @return the edit script of the member function templates of the two
5143 /// @ref class_or_union.
5144 const edit_script&
member_fn_tmpls_changes() const5145 class_or_union_diff::member_fn_tmpls_changes() const
5146 {return get_priv()->member_fn_tmpls_changes_;}
5147 
5148 /// @return the edit script of the member function templates of the
5149 /// two @ref class_or_union.
5150 edit_script&
member_fn_tmpls_changes()5151 class_or_union_diff::member_fn_tmpls_changes()
5152 {return get_priv()->member_fn_tmpls_changes_;}
5153 
5154 /// @return the edit script of the member class templates of the two
5155 /// @ref class_or_union.
5156 const edit_script&
member_class_tmpls_changes() const5157 class_or_union_diff::member_class_tmpls_changes() const
5158 {return get_priv()->member_class_tmpls_changes_;}
5159 
5160 /// @return the edit script of the member class templates of the two
5161 /// @ref class_or_union.
5162 edit_script&
member_class_tmpls_changes()5163 class_or_union_diff::member_class_tmpls_changes()
5164 {return get_priv()->member_class_tmpls_changes_;}
5165 
5166 /// Test if the current diff node carries a change.
5167 bool
has_changes() const5168 class_or_union_diff::has_changes() const
5169 {return first_class_or_union() != second_class_or_union();}
5170 
5171 /// @return the kind of local change carried by the current diff node.
5172 /// The value returned is zero if the current node carries no local
5173 /// change.
5174 enum change_kind
has_local_changes() const5175 class_or_union_diff::has_local_changes() const
5176 {
5177   ir::change_kind k = ir::NO_CHANGE_KIND;
5178   if (!equals(*first_class_or_union(), *second_class_or_union(), &k))
5179     return k & ir::ALL_LOCAL_CHANGES_MASK;
5180   return ir::NO_CHANGE_KIND;
5181 }
5182 
5183 
5184 /// Report the changes carried by the current @ref class_or_union_diff
5185 /// node in a textual format.
5186 ///
5187 /// @param out the output stream to write the textual report to.
5188 ///
5189 /// @param indent the number of white space to use as indentation.
5190 void
report(ostream & out,const string & indent) const5191 class_or_union_diff::report(ostream& out, const string& indent) const
5192 {
5193   context()->get_reporter()->report(*this, out, indent);
5194 }
5195 
5196 /// Populate the vector of children node of the @ref diff base type
5197 /// sub-object of this instance of @ref class_or_union_diff.
5198 ///
5199 /// The children node can then later be retrieved using
5200 /// diff::children_node().
5201 void
chain_into_hierarchy()5202 class_or_union_diff::chain_into_hierarchy()
5203 {
5204   // data member changes
5205   for (var_diff_sptrs_type::const_iterator i =
5206 	 get_priv()->sorted_subtype_changed_dm_.begin();
5207        i != get_priv()->sorted_subtype_changed_dm_.end();
5208        ++i)
5209     if (diff_sptr d = *i)
5210       append_child_node(d);
5211 
5212   for (var_diff_sptrs_type::const_iterator i =
5213 	 get_priv()->sorted_changed_dm_.begin();
5214        i != get_priv()->sorted_changed_dm_.end();
5215        ++i)
5216     if (diff_sptr d = *i)
5217       append_child_node(d);
5218 
5219   // member types changes
5220   for (diff_sptrs_type::const_iterator i =
5221 	 get_priv()->sorted_changed_member_types_.begin();
5222        i != get_priv()->sorted_changed_member_types_.end();
5223        ++i)
5224     if (diff_sptr d = *i)
5225       append_child_node(d);
5226 
5227   // member function changes
5228   for (function_decl_diff_sptrs_type::const_iterator i =
5229 	 get_priv()->sorted_changed_member_functions_.begin();
5230        i != get_priv()->sorted_changed_member_functions_.end();
5231        ++i)
5232     if (diff_sptr d = *i)
5233       append_child_node(d);
5234 }
5235 
5236 // </class_or_union_diff stuff>
5237 
5238 //<class_diff stuff>
5239 
5240 /// Clear the lookup tables useful for reporting.
5241 ///
5242 /// This function must be updated each time a lookup table is added or
5243 /// removed from the class_diff::priv.
5244 void
clear_lookup_tables(void)5245 class_diff::clear_lookup_tables(void)
5246 {
5247   priv_->deleted_bases_.clear();
5248   priv_->inserted_bases_.clear();
5249   priv_->changed_bases_.clear();
5250 }
5251 
5252 /// Tests if the lookup tables are empty.
5253 ///
5254 /// @return true if the lookup tables are empty, false otherwise.
5255 bool
lookup_tables_empty(void) const5256 class_diff::lookup_tables_empty(void) const
5257 {
5258   return (priv_->deleted_bases_.empty()
5259 	  && priv_->inserted_bases_.empty()
5260 	  && priv_->changed_bases_.empty());
5261 }
5262 
5263 /// If the lookup tables are not yet built, walk the differences and
5264 /// fill them.
5265 void
ensure_lookup_tables_populated(void) const5266 class_diff::ensure_lookup_tables_populated(void) const
5267 {
5268   class_or_union_diff::ensure_lookup_tables_populated();
5269 
5270   if (!lookup_tables_empty())
5271     return;
5272 
5273   {
5274     edit_script& e = get_priv()->base_changes_;
5275 
5276     for (vector<deletion>::const_iterator it = e.deletions().begin();
5277 	 it != e.deletions().end();
5278 	 ++it)
5279       {
5280 	unsigned i = it->index();
5281 	class_decl::base_spec_sptr b =
5282 	  first_class_decl()->get_base_specifiers()[i];
5283 	string name = b->get_base_class()->get_name();
5284 	ABG_ASSERT(get_priv()->deleted_bases_.find(name)
5285 	       == get_priv()->deleted_bases_.end());
5286 	get_priv()->deleted_bases_[name] = b;
5287       }
5288 
5289     for (vector<insertion>::const_iterator it = e.insertions().begin();
5290 	 it != e.insertions().end();
5291 	 ++it)
5292       {
5293 	for (vector<unsigned>::const_iterator iit =
5294 	       it->inserted_indexes().begin();
5295 	     iit != it->inserted_indexes().end();
5296 	     ++iit)
5297 	  {
5298 	    unsigned i = *iit;
5299 	    class_decl::base_spec_sptr b =
5300 	      second_class_decl()->get_base_specifiers()[i];
5301 	    string name = b->get_base_class()->get_name();
5302 	    ABG_ASSERT(get_priv()->inserted_bases_.find(name)
5303 		   == get_priv()->inserted_bases_.end());
5304 	    string_base_sptr_map::const_iterator j =
5305 	      get_priv()->deleted_bases_.find(name);
5306 	    if (j != get_priv()->deleted_bases_.end())
5307 	      {
5308 		if (j->second != b)
5309 		  get_priv()->changed_bases_[name] =
5310 		    compute_diff(j->second, b, context());
5311 		get_priv()->deleted_bases_.erase(j);
5312 	      }
5313 	    else
5314 	      get_priv()->inserted_bases_[name] = b;
5315 	  }
5316       }
5317   }
5318 
5319   sort_string_base_sptr_map(get_priv()->deleted_bases_,
5320 			    get_priv()->sorted_deleted_bases_);
5321   sort_string_base_sptr_map(get_priv()->inserted_bases_,
5322 			    get_priv()->sorted_inserted_bases_);
5323   sort_string_base_diff_sptr_map(get_priv()->changed_bases_,
5324 				 get_priv()->sorted_changed_bases_);
5325 
5326   {
5327     const class_or_union_diff::priv_ptr &p = class_or_union_diff::get_priv();
5328 
5329     edit_script& e = p->member_fns_changes_;
5330 
5331     for (vector<deletion>::const_iterator it = e.deletions().begin();
5332 	 it != e.deletions().end();
5333 	 ++it)
5334       {
5335 	unsigned i = it->index();
5336 	method_decl_sptr mem_fn =
5337 	  first_class_decl()->get_virtual_mem_fns()[i];
5338 	string name = mem_fn->get_linkage_name();
5339 	if (name.empty())
5340 	  name = mem_fn->get_pretty_representation();
5341 	ABG_ASSERT(!name.empty());
5342 	if (p->deleted_member_functions_.find(name)
5343 	    != p->deleted_member_functions_.end())
5344 	  continue;
5345 	p->deleted_member_functions_[name] = mem_fn;
5346       }
5347 
5348     for (vector<insertion>::const_iterator it = e.insertions().begin();
5349 	 it != e.insertions().end();
5350 	 ++it)
5351       {
5352 	for (vector<unsigned>::const_iterator iit =
5353 	       it->inserted_indexes().begin();
5354 	     iit != it->inserted_indexes().end();
5355 	     ++iit)
5356 	  {
5357 	    unsigned i = *iit;
5358 
5359 	    method_decl_sptr mem_fn =
5360 	      second_class_decl()->get_virtual_mem_fns()[i];
5361 	    string name = mem_fn->get_linkage_name();
5362 	    if (name.empty())
5363 	      name = mem_fn->get_pretty_representation();
5364 	    ABG_ASSERT(!name.empty());
5365 	    if (p->inserted_member_functions_.find(name)
5366 		!= p->inserted_member_functions_.end())
5367 	      continue;
5368 	    string_member_function_sptr_map::const_iterator j =
5369 	      p->deleted_member_functions_.find(name);
5370 
5371 	    if (j != p->deleted_member_functions_.end())
5372 	      {
5373 		if (*j->second != *mem_fn)
5374 		  p->changed_member_functions_[name] =
5375 		    compute_diff(static_pointer_cast<function_decl>(j->second),
5376 				 static_pointer_cast<function_decl>(mem_fn),
5377 				 context());
5378 		p->deleted_member_functions_.erase(j);
5379 	      }
5380 	    else
5381 	      p->inserted_member_functions_[name] = mem_fn;
5382 	  }
5383       }
5384 
5385     // Now walk the allegedly deleted member functions; check if their
5386     // underlying symbols are deleted as well; otherwise, consider
5387     // that the member function in question hasn't been deleted.
5388 
5389     vector<string> to_delete;
5390     corpus_sptr f = context()->get_first_corpus(),
5391       s = context()->get_second_corpus();
5392     if (s)
5393       for (string_member_function_sptr_map::const_iterator i =
5394 	     deleted_member_fns().begin();
5395 	   i != deleted_member_fns().end();
5396 	   ++i)
5397 	{
5398 	  if (get_member_function_is_virtual(i->second))
5399 	    continue;
5400 	  // We assume that all non-virtual member functions functions
5401 	  // we look at here have ELF symbols.
5402 	  if (!i->second->get_symbol()
5403 	      || s->lookup_function_symbol(*i->second->get_symbol()))
5404 	    to_delete.push_back(i->first);
5405 	}
5406 
5407 
5408     for (vector<string>::const_iterator i = to_delete.begin();
5409 	 i != to_delete.end();
5410 	 ++i)
5411       p->deleted_member_functions_.erase(*i);
5412 
5413     // Do something similar for added functions.
5414     to_delete.clear();
5415     if (f)
5416       for (string_member_function_sptr_map::const_iterator i =
5417 	     inserted_member_fns().begin();
5418 	   i != inserted_member_fns().end();
5419 	   ++i)
5420 	{
5421 	  if (get_member_function_is_virtual(i->second))
5422 	    continue;
5423 	  // We assume that all non-virtual member functions functions
5424 	  // we look at here have ELF symbols.
5425 	  if (!i->second->get_symbol()
5426 	      || f->lookup_function_symbol(*i->second->get_symbol()))
5427 	    to_delete.push_back(i->first);
5428 	}
5429 
5430     for (vector<string>::const_iterator i = to_delete.begin();
5431 	 i != to_delete.end();
5432 	 ++i)
5433       p->inserted_member_functions_.erase(*i);
5434 
5435     sort_string_member_function_sptr_map(p->deleted_member_functions_,
5436 					 p->sorted_deleted_member_functions_);
5437 
5438     sort_string_member_function_sptr_map(p->inserted_member_functions_,
5439 					 p->sorted_inserted_member_functions_);
5440 
5441     sort_string_virtual_member_function_diff_sptr_map
5442       (p->changed_member_functions_,
5443        p->sorted_changed_member_functions_);
5444   }
5445 }
5446 
5447 /// Allocate the memory for the priv_ pimpl data member of the @ref
5448 /// class_diff class.
5449 void
allocate_priv_data()5450 class_diff::allocate_priv_data()
5451 {
5452   class_or_union_diff::allocate_priv_data();
5453   if (!priv_)
5454     priv_.reset(new priv);
5455 }
5456 
5457 /// Test whether a given base class has changed.  A base class has
5458 /// changed if it's in both in deleted *and* inserted bases.
5459 ///
5460 ///@param d the declaration for the base class to consider.
5461 ///
5462 /// @return the new base class if the given base class has changed, or
5463 /// NULL if it hasn't.
5464 class_decl::base_spec_sptr
base_has_changed(class_decl::base_spec_sptr d) const5465 class_diff::priv::base_has_changed(class_decl::base_spec_sptr d) const
5466 {
5467   string qname = d->get_base_class()->get_qualified_name();
5468   string_base_diff_sptr_map::const_iterator it =
5469     changed_bases_.find(qname);
5470 
5471   return (it == changed_bases_.end())
5472     ? class_decl::base_spec_sptr()
5473     : it->second->second_base();
5474 
5475 }
5476 
5477 /// Count the number of bases classes whose changes got filtered out.
5478 ///
5479 /// @return the number of bases classes whose changes got filtered
5480 /// out.
5481 size_t
count_filtered_bases()5482 class_diff::priv::count_filtered_bases()
5483 {
5484   size_t num_filtered = 0;
5485   for (base_diff_sptrs_type::const_iterator i = sorted_changed_bases_.begin();
5486        i != sorted_changed_bases_.end();
5487        ++i)
5488     {
5489       diff_sptr diff = *i;
5490       if (diff && diff->is_filtered_out())
5491 	++num_filtered;
5492     }
5493   return num_filtered;
5494 }
5495 
5496 /// Populate the vector of children node of the @ref diff base type
5497 /// sub-object of this instance of @ref class_diff.
5498 ///
5499 /// The children node can then later be retrieved using
5500 /// diff::children_node().
5501 void
chain_into_hierarchy()5502 class_diff::chain_into_hierarchy()
5503 {
5504   class_or_union_diff::chain_into_hierarchy();
5505 
5506   // base class changes.
5507   for (base_diff_sptrs_type::const_iterator i =
5508 	 get_priv()->sorted_changed_bases_.begin();
5509        i != get_priv()->sorted_changed_bases_.end();
5510        ++i)
5511     if (diff_sptr d = *i)
5512       append_child_node(d);
5513 }
5514 
5515 /// Constructor of class_diff
5516 ///
5517 /// @param first_scope the first class of the diff.
5518 ///
5519 /// @param second_scope the second class of the diff.
5520 ///
5521 /// @param ctxt the diff context to use.
class_diff(class_decl_sptr first_scope,class_decl_sptr second_scope,diff_context_sptr ctxt)5522 class_diff::class_diff(class_decl_sptr first_scope,
5523 		       class_decl_sptr second_scope,
5524 		       diff_context_sptr ctxt)
5525   : class_or_union_diff(first_scope, second_scope, ctxt)
5526     //  We don't initialize the priv_ data member here.  This is an
5527     //  optimization to reduce memory consumption (and also execution
5528     //  time) for cases where there are a lot of instances of
5529     //  class_diff in the same equivalence class.  In compute_diff(),
5530     //  the priv_ is set to the priv_ of the canonical diff node.
5531     //  See PR libabigail/17948.
5532 {}
5533 
~class_diff()5534 class_diff::~class_diff()
5535 {}
5536 
5537 /// Getter of the private data of the @ref class_diff type.
5538 ///
5539 /// Note that due to an optimization, the private data of @ref
5540 /// class_diff can be shared among several instances of class_diff, so
5541 /// you should never try to access class_diff::priv directly.
5542 ///
5543 /// When class_diff::priv is shared, this function returns the correct
5544 /// shared one.
5545 ///
5546 /// @return the (possibly) shared private data of the current instance
5547 /// of class_diff.
5548 const class_diff::priv_ptr&
get_priv() const5549 class_diff::get_priv() const
5550 {
5551   if (priv_)
5552     return priv_;
5553 
5554   // If the current class_diff::priv member is empty, then look for
5555   // the shared one, from the canonical type.
5556   class_diff *canonical =
5557     dynamic_cast<class_diff*>(get_canonical_diff());
5558   ABG_ASSERT(canonical);
5559   ABG_ASSERT(canonical->priv_);
5560 
5561   return canonical->priv_;
5562 }
5563 
5564 /// Finish building the current instance of @ref class_diff.
5565 void
finish_diff_type()5566 class_diff::finish_diff_type()
5567 {
5568   if (diff::priv_->finished_)
5569     return;
5570   chain_into_hierarchy();
5571   diff::priv_->finished_ = true;
5572 }
5573 
5574 /// @return the pretty representation of the current instance of @ref
5575 /// class_diff.
5576 const string&
get_pretty_representation() const5577 class_diff::get_pretty_representation() const
5578 {
5579   if (diff::priv_->pretty_representation_.empty())
5580     {
5581       std::ostringstream o;
5582       o << "class_diff["
5583 	<< first_subject()->get_pretty_representation()
5584 	<< ", "
5585 	<< second_subject()->get_pretty_representation()
5586 	<< "]";
5587       diff::priv_->pretty_representation_ = o.str();
5588     }
5589   return diff::priv_->pretty_representation_;
5590 }
5591 
5592 /// Return true iff the current diff node carries a change.
5593 ///
5594 /// @return true iff the current diff node carries a change.
5595 bool
has_changes() const5596 class_diff::has_changes() const
5597 {return (first_class_decl() != second_class_decl());}
5598 
5599 /// @return the kind of local change carried by the current diff node.
5600 /// The value returned is zero if the current node carries no local
5601 /// change.
5602 enum change_kind
has_local_changes() const5603 class_diff::has_local_changes() const
5604 {
5605   ir::change_kind k = ir::NO_CHANGE_KIND;
5606   if (!equals(*first_class_decl(), *second_class_decl(), &k))
5607     return k & ir::ALL_LOCAL_CHANGES_MASK;
5608   return ir::NO_CHANGE_KIND;
5609 }
5610 
5611 /// @return the first class invoveld in the diff.
5612 shared_ptr<class_decl>
first_class_decl() const5613 class_diff::first_class_decl() const
5614 {return dynamic_pointer_cast<class_decl>(first_subject());}
5615 
5616 /// Getter of the second class involved in the diff.
5617 ///
5618 /// @return the second class invoveld in the diff
5619 shared_ptr<class_decl>
second_class_decl() const5620 class_diff::second_class_decl() const
5621 {return dynamic_pointer_cast<class_decl>(second_subject());}
5622 
5623 /// @return the edit script of the bases of the two classes.
5624 const edit_script&
base_changes() const5625 class_diff::base_changes() const
5626 {return get_priv()->base_changes_;}
5627 
5628 /// Getter for the deleted base classes of the diff.
5629 ///
5630 /// @return a map containing the deleted base classes, keyed with
5631 /// their pretty representation.
5632 const string_base_sptr_map&
deleted_bases() const5633 class_diff::deleted_bases() const
5634 {return get_priv()->deleted_bases_;}
5635 
5636 /// Getter for the inserted base classes of the diff.
5637 ///
5638 /// @return a map containing the inserted base classes, keyed with
5639 /// their pretty representation.
5640 const string_base_sptr_map&
inserted_bases() const5641 class_diff::inserted_bases() const
5642 {return get_priv()->inserted_bases_;}
5643 
5644 /// Getter for the changed base classes of the diff.
5645 ///
5646 /// @return a sorted vector containing the changed base classes
5647 const base_diff_sptrs_type&
changed_bases()5648 class_diff::changed_bases()
5649 {return get_priv()->sorted_changed_bases_;}
5650 
5651 /// @return the edit script of the bases of the two classes.
5652 edit_script&
base_changes()5653 class_diff::base_changes()
5654 {return get_priv()->base_changes_;}
5655 
5656 /// Produce a basic report about the changes between two class_decl.
5657 ///
5658 /// @param out the output stream to report the changes to.
5659 ///
5660 /// @param indent the string to use as an indentation prefix in the
5661 /// report.
5662 void
report(ostream & out,const string & indent) const5663 class_diff::report(ostream& out, const string& indent) const
5664 {
5665   context()->get_reporter()->report(*this, out, indent);
5666 }
5667 
5668 /// Compute the set of changes between two instances of class_decl.
5669 ///
5670 /// Note that the two types must have been created in the same @ref
5671 /// environment, otherwise, this function aborts.
5672 ///
5673 /// @param first the first class_decl to consider.
5674 ///
5675 /// @param second the second class_decl to consider.
5676 ///
5677 /// @return changes the resulting changes.
5678 ///
5679 /// @param ctxt the diff context to use.
5680 class_diff_sptr
compute_diff(const class_decl_sptr first,const class_decl_sptr second,diff_context_sptr ctxt)5681 compute_diff(const class_decl_sptr	first,
5682 	     const class_decl_sptr	second,
5683 	     diff_context_sptr		ctxt)
5684 {
5685   if (first && second)
5686     ABG_ASSERT(first->get_environment() == second->get_environment());
5687 
5688   class_decl_sptr f = is_class_type(look_through_decl_only_class(first)),
5689     s = is_class_type(look_through_decl_only_class(second));
5690 
5691   class_diff_sptr changes(new class_diff(f, s, ctxt));
5692 
5693   ctxt->initialize_canonical_diff(changes);
5694   ABG_ASSERT(changes->get_canonical_diff());
5695 
5696   if (!ctxt->get_canonical_diff_for(first, second))
5697     {
5698       // Either first or second is a decl-only class; let's set the
5699       // canonical diff here in that case.
5700       diff_sptr canonical_diff = ctxt->get_canonical_diff_for(changes);
5701       ABG_ASSERT(canonical_diff);
5702       ctxt->set_canonical_diff_for(first, second, canonical_diff);
5703     }
5704 
5705   // Ok, so this is an optimization.  Do not freak out if it looks
5706   // weird, because, well, it does look weird.  This speeds up
5707   // greatly, for instance, the test case given at PR
5708   // libabigail/17948.
5709   //
5710   // We are setting the private data of the new instance of class_diff
5711   // (which is 'changes') to the private data of its canonical
5712   // instance.  That is, we are sharing the private data of 'changes'
5713   // with the private data of its canonical instance to consume less
5714   // memory in cases where the equivalence class of 'changes' is huge.
5715   //
5716   // But if changes is its own canonical instance, then we initialize
5717   // its private data properly
5718   if (is_class_diff(changes->get_canonical_diff()) == changes.get())
5719     // changes is its own canonical instance, so it gets a brand new
5720     // private data.
5721     changes->allocate_priv_data();
5722   else
5723     {
5724       // changes has a non-empty equivalence class so it's going to
5725       // share its private data with its canonical instance.  Next
5726       // time class_diff::get_priv() is invoked, it's going to return
5727       // the shared private data of the canonical instance.
5728       return changes;
5729     }
5730 
5731   // Compare base specs
5732   compute_diff(f->get_base_specifiers().begin(),
5733 	       f->get_base_specifiers().end(),
5734 	       s->get_base_specifiers().begin(),
5735 	       s->get_base_specifiers().end(),
5736 	       changes->base_changes());
5737 
5738   // Do *not* compare member types because it generates lots of noise
5739   // and I doubt it's really useful.
5740 #if 0
5741   compute_diff(f->get_member_types().begin(),
5742 	       f->get_member_types().end(),
5743 	       s->get_member_types().begin(),
5744 	       s->get_member_types().end(),
5745 	       changes->member_types_changes());
5746 #endif
5747 
5748   // Compare data member
5749   compute_diff(f->get_non_static_data_members().begin(),
5750 	       f->get_non_static_data_members().end(),
5751 	       s->get_non_static_data_members().begin(),
5752 	       s->get_non_static_data_members().end(),
5753 	       changes->data_members_changes());
5754 
5755   // Compare virtual member functions
5756   compute_diff(f->get_virtual_mem_fns().begin(),
5757 	       f->get_virtual_mem_fns().end(),
5758 	       s->get_virtual_mem_fns().begin(),
5759 	       s->get_virtual_mem_fns().end(),
5760 	       changes->member_fns_changes());
5761 
5762   // Compare member function templates
5763   compute_diff(f->get_member_function_templates().begin(),
5764 	       f->get_member_function_templates().end(),
5765 	       s->get_member_function_templates().begin(),
5766 	       s->get_member_function_templates().end(),
5767 	       changes->member_fn_tmpls_changes());
5768 
5769   // Likewise, do not compare member class templates
5770 #if 0
5771   compute_diff(f->get_member_class_templates().begin(),
5772 	       f->get_member_class_templates().end(),
5773 	       s->get_member_class_templates().begin(),
5774 	       s->get_member_class_templates().end(),
5775 	       changes->member_class_tmpls_changes());
5776 #endif
5777 
5778   changes->ensure_lookup_tables_populated();
5779 
5780   return changes;
5781 }
5782 
5783 //</class_diff stuff>
5784 
5785 // <base_diff stuff>
5786 
5787 /// Populate the vector of children node of the @ref diff base type
5788 /// sub-object of this instance of @ref base_diff.
5789 ///
5790 /// The children node can then later be retrieved using
5791 /// diff::children_node().
5792 void
chain_into_hierarchy()5793 base_diff::chain_into_hierarchy()
5794 {append_child_node(get_underlying_class_diff());}
5795 
5796 /// @param first the first base spec to consider.
5797 ///
5798 /// @param second the second base spec to consider.
5799 ///
5800 /// @param ctxt the context of the diff.  Note that this context
5801 /// object must stay alive at least during the life time of the
5802 /// current instance of @ref base_diff.  Otherwise memory corruption
5803 /// issues occur.
base_diff(class_decl::base_spec_sptr first,class_decl::base_spec_sptr second,class_diff_sptr underlying,diff_context_sptr ctxt)5804 base_diff::base_diff(class_decl::base_spec_sptr first,
5805 		     class_decl::base_spec_sptr second,
5806 		     class_diff_sptr		underlying,
5807 		     diff_context_sptr		ctxt)
5808   : diff(first, second, ctxt),
5809     priv_(new priv(underlying))
5810 {}
5811 
5812 /// Finish building the current instance of @ref base_diff.
5813 void
finish_diff_type()5814 base_diff::finish_diff_type()
5815 {
5816   if (diff::priv_->finished_)
5817     return;
5818 
5819   chain_into_hierarchy();
5820   diff::priv_->finished_ = true;
5821 }
5822 
5823 /// Getter for the first base spec of the diff object.
5824 ///
5825 /// @return the first base specifier for the diff object.
5826 class_decl::base_spec_sptr
first_base() const5827 base_diff::first_base() const
5828 {return dynamic_pointer_cast<class_decl::base_spec>(first_subject());}
5829 
5830 /// Getter for the second base spec of the diff object.
5831 ///
5832 /// @return the second base specifier for the diff object.
5833 class_decl::base_spec_sptr
second_base() const5834 base_diff::second_base() const
5835 {return dynamic_pointer_cast<class_decl::base_spec>(second_subject());}
5836 
5837 /// Getter for the diff object for the diff of the underlying base
5838 /// classes.
5839 ///
5840 /// @return the diff object for the diff of the underlying base
5841 /// classes.
5842 const class_diff_sptr
get_underlying_class_diff() const5843 base_diff::get_underlying_class_diff() const
5844 {return priv_->underlying_class_diff_;}
5845 
5846 /// Setter for the diff object for the diff of the underlyng base
5847 /// classes.
5848 ///
5849 /// @param d the new diff object for the diff of the underlying base
5850 /// classes.
5851 void
set_underlying_class_diff(class_diff_sptr d)5852 base_diff::set_underlying_class_diff(class_diff_sptr d)
5853 {priv_->underlying_class_diff_ = d;}
5854 
5855 /// @return the pretty representation for the current instance of @ref
5856 /// base_diff.
5857 const string&
get_pretty_representation() const5858 base_diff::get_pretty_representation() const
5859 {
5860   if (diff::priv_->pretty_representation_.empty())
5861     {
5862       std::ostringstream o;
5863       o << "base_diff["
5864 	<< first_subject()->get_pretty_representation()
5865 	<< ", "
5866 	<< second_subject()->get_pretty_representation()
5867 	<< "]";
5868       diff::priv_->pretty_representation_ = o.str();
5869     }
5870   return diff::priv_->pretty_representation_;
5871 }
5872 
5873 /// Return true iff the current diff node carries a change.
5874 ///
5875 /// Return true iff the current diff node carries a change.
5876 bool
has_changes() const5877 base_diff::has_changes() const
5878 {return first_base() != second_base();}
5879 
5880 /// @return the kind of local change carried by the current diff node.
5881 /// The value returned is zero if the current node carries no local
5882 /// change.
5883 enum change_kind
has_local_changes() const5884 base_diff::has_local_changes() const
5885 {
5886   ir::change_kind k = ir::NO_CHANGE_KIND;
5887   if (!equals(*first_base(), *second_base(), &k))
5888     return k & ir::ALL_LOCAL_CHANGES_MASK;
5889   return ir::NO_CHANGE_KIND;
5890 }
5891 
5892 /// Generates a report for the current instance of base_diff.
5893 ///
5894 /// @param out the output stream to send the report to.
5895 ///
5896 /// @param indent the string to use for indentation.
5897 void
report(ostream & out,const string & indent) const5898 base_diff::report(ostream& out, const string& indent) const
5899 {
5900   context()->get_reporter()->report(*this, out, indent);
5901 }
5902 
5903 /// Constructs the diff object representing a diff between two base
5904 /// class specifications.
5905 ///
5906 /// Note that the two artifacts must have been created in the same
5907 /// @ref environment, otherwise, this function aborts.
5908 ///
5909 /// @param first the first base class specification.
5910 ///
5911 /// @param second the second base class specification.
5912 ///
5913 /// @param ctxt the content of the diff.
5914 ///
5915 /// @return the resulting diff object.
5916 base_diff_sptr
compute_diff(const class_decl::base_spec_sptr first,const class_decl::base_spec_sptr second,diff_context_sptr ctxt)5917 compute_diff(const class_decl::base_spec_sptr	first,
5918 	     const class_decl::base_spec_sptr	second,
5919 	     diff_context_sptr			ctxt)
5920 {
5921   if (first && second)
5922     {
5923       ABG_ASSERT(first->get_environment() == second->get_environment());
5924       ABG_ASSERT(first->get_base_class()->get_environment()
5925 	     == second->get_base_class()->get_environment());
5926       ABG_ASSERT(first->get_environment()
5927 	     == first->get_base_class()->get_environment());
5928     }
5929 
5930   class_diff_sptr cl = compute_diff(first->get_base_class(),
5931 				    second->get_base_class(),
5932 				    ctxt);
5933   base_diff_sptr changes(new base_diff(first, second, cl, ctxt));
5934 
5935   ctxt->initialize_canonical_diff(changes);
5936 
5937   return changes;
5938 }
5939 
5940 // </base_diff stuff>
5941 
5942 
5943 // <union_diff stuff>
5944 
5945 /// Clear the lookup tables useful for reporting.
5946 ///
5947 /// This function must be updated each time a lookup table is added or
5948 /// removed from the union_diff::priv.
5949 void
clear_lookup_tables(void)5950 union_diff::clear_lookup_tables(void)
5951 {class_or_union_diff::clear_lookup_tables();}
5952 
5953 /// Tests if the lookup tables are empty.
5954 ///
5955 /// @return true if the lookup tables are empty, false otherwise.
5956 bool
lookup_tables_empty(void) const5957 union_diff::lookup_tables_empty(void) const
5958 {return class_or_union_diff::lookup_tables_empty();}
5959 
5960 /// If the lookup tables are not yet built, walk the differences and
5961 /// fill them.
5962 void
ensure_lookup_tables_populated(void) const5963 union_diff::ensure_lookup_tables_populated(void) const
5964 {class_or_union_diff::ensure_lookup_tables_populated();}
5965 
5966 /// Allocate the memory for the priv_ pimpl data member of the @ref
5967 /// union_diff class.
5968 void
allocate_priv_data()5969 union_diff::allocate_priv_data()
5970 {
5971   class_or_union_diff::allocate_priv_data();
5972 }
5973 
5974 /// Constructor for the @ref union_diff type.
5975 ///
5976 /// @param first_union the first object of the comparison.
5977 ///
5978 /// @param second_union the second object of the comparison.
5979 ///
5980 /// @param ctxt the context of the comparison.
union_diff(union_decl_sptr first_union,union_decl_sptr second_union,diff_context_sptr ctxt)5981 union_diff::union_diff(union_decl_sptr first_union,
5982 		       union_decl_sptr second_union,
5983 		       diff_context_sptr ctxt)
5984   : class_or_union_diff(first_union, second_union, ctxt)
5985 {}
5986 
5987 /// Finish building the current instance of @ref union_diff.
5988 void
finish_diff_type()5989 union_diff::finish_diff_type()
5990 {class_or_union_diff::finish_diff_type();}
5991 
5992 /// Destructor of the union_diff node.
~union_diff()5993 union_diff::~union_diff()
5994 {}
5995 
5996 /// @return the first object of the comparison.
5997 union_decl_sptr
first_union_decl() const5998 union_diff::first_union_decl() const
5999 {return is_union_type(first_subject());}
6000 
6001 /// @return the second object of the comparison.
6002 union_decl_sptr
second_union_decl() const6003 union_diff::second_union_decl() const
6004 {return is_union_type(second_subject());}
6005 
6006 /// @return the pretty representation of the current diff node.
6007 const string&
get_pretty_representation() const6008 union_diff::get_pretty_representation() const
6009 {
6010   if (diff::priv_->pretty_representation_.empty())
6011     {
6012       std::ostringstream o;
6013       o << "union_diff["
6014 	<< first_subject()->get_pretty_representation()
6015 	<< ", "
6016 	<< second_subject()->get_pretty_representation()
6017 	<< "]";
6018       diff::priv_->pretty_representation_ = o.str();
6019     }
6020   return diff::priv_->pretty_representation_;
6021 }
6022 
6023 /// Report the changes carried by the current @ref union_diff node in
6024 /// a textual format.
6025 ///
6026 /// @param out the output stream to write the textual report to.
6027 ///
6028 /// @param indent the number of white space to use as indentation.
6029 void
report(ostream & out,const string & indent) const6030 union_diff::report(ostream& out, const string& indent) const
6031 {
6032   context()->get_reporter()->report(*this, out, indent);
6033 }
6034 
6035 /// Compute the difference between two @ref union_decl types.
6036 ///
6037 /// Note that the two types must hav been created in the same
6038 /// environment, otherwise, this function aborts.
6039 ///
6040 /// @param first the first @ref union_decl to consider.
6041 ///
6042 /// @param second the second @ref union_decl to consider.
6043 ///
6044 /// @param ctxt the context of the diff to use.
6045 union_diff_sptr
compute_diff(const union_decl_sptr first,const union_decl_sptr second,diff_context_sptr ctxt)6046 compute_diff(const union_decl_sptr	first,
6047 	     const union_decl_sptr	second,
6048 	     diff_context_sptr	ctxt)
6049 {
6050   if (first && second)
6051     ABG_ASSERT(first->get_environment() == second->get_environment());
6052 
6053   union_diff_sptr changes(new union_diff(first, second, ctxt));
6054 
6055   ctxt->initialize_canonical_diff(changes);
6056   ABG_ASSERT(changes->get_canonical_diff());
6057 
6058   // Ok, so this is an optimization.  Do not freak out if it looks
6059   // weird, because, well, it does look weird.  This speeds up
6060   // greatly, for instance, the test case given at PR
6061   // libabigail/17948.
6062   //
6063   // We are setting the private data of the new instance of class_diff
6064   // (which is 'changes') to the private data of its canonical
6065   // instance.  That is, we are sharing the private data of 'changes'
6066   // with the private data of its canonical instance to consume less
6067   // memory in cases where the equivalence class of 'changes' is huge.
6068   //
6069   // But if changes is its own canonical instance, then we initialize
6070   // its private data properly.
6071   if (is_union_diff(changes->get_canonical_diff()) ==  changes.get())
6072     // changes is its own canonical instance, so it gets a brand new
6073     // private data.
6074     changes->allocate_priv_data();
6075   else
6076     {
6077       // changes has a non-empty equivalence class so it's going to
6078       // share its private data with its canonical instance.  Next
6079       // time class_diff::get_priv() is invoked, it's going to return
6080       // the shared private data of the canonical instance.
6081       return changes;
6082     }
6083 
6084   // Compare data member
6085   compute_diff(first->get_non_static_data_members().begin(),
6086 	       first->get_non_static_data_members().end(),
6087 	       second->get_non_static_data_members().begin(),
6088 	       second->get_non_static_data_members().end(),
6089 	       changes->data_members_changes());
6090 
6091 #if 0
6092   // Compare member functions
6093   compute_diff(first->get_mem_fns().begin(),
6094 	       first->get_mem_fns().end(),
6095 	       second->get_mem_fns().begin(),
6096 	       second->get_mem_fns().end(),
6097 	       changes->member_fns_changes());
6098 
6099   // Compare member function templates
6100   compute_diff(first->get_member_function_templates().begin(),
6101 	       first->get_member_function_templates().end(),
6102 	       second->get_member_function_templates().begin(),
6103 	       second->get_member_function_templates().end(),
6104 	       changes->member_fn_tmpls_changes());
6105 #endif
6106 
6107   changes->ensure_lookup_tables_populated();
6108 
6109   return changes;
6110 }
6111 
6112 // </union_diff stuff>
6113 
6114 //<scope_diff stuff>
6115 
6116 /// Clear the lookup tables that are useful for reporting.
6117 ///
6118 /// This function must be updated each time a lookup table is added or
6119 /// removed.
6120 void
clear_lookup_tables()6121 scope_diff::clear_lookup_tables()
6122 {
6123   priv_->deleted_types_.clear();
6124   priv_->deleted_decls_.clear();
6125   priv_->inserted_types_.clear();
6126   priv_->inserted_decls_.clear();
6127   priv_->changed_types_.clear();
6128   priv_->changed_decls_.clear();
6129   priv_->removed_types_.clear();
6130   priv_->removed_decls_.clear();
6131   priv_->added_types_.clear();
6132   priv_->added_decls_.clear();
6133 }
6134 
6135 /// Tests if the lookup tables are empty.
6136 ///
6137 /// This function must be updated each time a lookup table is added or
6138 /// removed.
6139 ///
6140 /// @return true iff all the lookup tables are empty.
6141 bool
lookup_tables_empty() const6142 scope_diff::lookup_tables_empty() const
6143 {
6144   return (priv_->deleted_types_.empty()
6145 	  && priv_->deleted_decls_.empty()
6146 	  && priv_->inserted_types_.empty()
6147 	  && priv_->inserted_decls_.empty()
6148 	  && priv_->changed_types_.empty()
6149 	  && priv_->changed_decls_.empty()
6150 	  && priv_->removed_types_.empty()
6151 	  && priv_->removed_decls_.empty()
6152 	  && priv_->added_types_.empty()
6153 	  && priv_->added_decls_.empty());
6154 }
6155 
6156 /// If the lookup tables are not yet built, walk the member_changes_
6157 /// member and fill the lookup tables.
6158 void
ensure_lookup_tables_populated()6159 scope_diff::ensure_lookup_tables_populated()
6160 {
6161   if (!lookup_tables_empty())
6162     return;
6163 
6164   edit_script& e = priv_->member_changes_;
6165 
6166   // Populate deleted types & decls lookup tables.
6167   for (vector<deletion>::const_iterator i = e.deletions().begin();
6168        i != e.deletions().end();
6169        ++i)
6170     {
6171       decl_base_sptr decl = deleted_member_at(i);
6172       string qname = decl->get_qualified_name();
6173       if (is_type(decl))
6174 	{
6175 	  class_decl_sptr klass_decl = dynamic_pointer_cast<class_decl>(decl);
6176 	  if (klass_decl && klass_decl->get_is_declaration_only())
6177 	    continue;
6178 
6179 	  ABG_ASSERT(priv_->deleted_types_.find(qname)
6180 		 == priv_->deleted_types_.end());
6181 	  priv_->deleted_types_[qname] = decl;
6182 	}
6183       else
6184 	{
6185 	  ABG_ASSERT(priv_->deleted_decls_.find(qname)
6186 		 == priv_->deleted_decls_.end());
6187 	  priv_->deleted_decls_[qname] = decl;
6188 	}
6189     }
6190 
6191   // Populate inserted types & decls as well as chagned types & decls
6192   // lookup tables.
6193   for (vector<insertion>::const_iterator it = e.insertions().begin();
6194        it != e.insertions().end();
6195        ++it)
6196     {
6197       for (vector<unsigned>::const_iterator i = it->inserted_indexes().begin();
6198 	   i != it->inserted_indexes().end();
6199 	   ++i)
6200 	{
6201 	  decl_base_sptr decl = inserted_member_at(i);
6202 	  string qname = decl->get_qualified_name();
6203 	  if (is_type(decl))
6204 	    {
6205 	      class_decl_sptr klass_decl =
6206 		dynamic_pointer_cast<class_decl>(decl);
6207 	      if (klass_decl && klass_decl->get_is_declaration_only())
6208 		continue;
6209 
6210 	      ABG_ASSERT(priv_->inserted_types_.find(qname)
6211 		     == priv_->inserted_types_.end());
6212 	      string_decl_base_sptr_map::const_iterator j =
6213 		priv_->deleted_types_.find(qname);
6214 	      if (j != priv_->deleted_types_.end())
6215 		{
6216 		  if (*j->second != *decl)
6217 		    priv_->changed_types_[qname] =
6218 		      compute_diff(j->second, decl, context());
6219 		  priv_->deleted_types_.erase(j);
6220 		}
6221 	      else
6222 		priv_->inserted_types_[qname] = decl;
6223 	    }
6224 	  else
6225 	    {
6226 	      ABG_ASSERT(priv_->inserted_decls_.find(qname)
6227 		     == priv_->inserted_decls_.end());
6228 	      string_decl_base_sptr_map::const_iterator j =
6229 		priv_->deleted_decls_.find(qname);
6230 	      if (j != priv_->deleted_decls_.end())
6231 		{
6232 		  if (*j->second != *decl)
6233 		    priv_->changed_decls_[qname] =
6234 		      compute_diff(j->second, decl, context());
6235 		  priv_->deleted_decls_.erase(j);
6236 		}
6237 	      else
6238 		priv_->inserted_decls_[qname] = decl;
6239 	    }
6240 	}
6241     }
6242 
6243   sort_string_diff_sptr_map(priv_->changed_decls_,
6244 			    priv_->sorted_changed_decls_);
6245   sort_string_diff_sptr_map(priv_->changed_types_,
6246 			    priv_->sorted_changed_types_);
6247 
6248   // Populate removed types/decls lookup tables
6249   for (string_decl_base_sptr_map::const_iterator i =
6250 	 priv_->deleted_types_.begin();
6251        i != priv_->deleted_types_.end();
6252        ++i)
6253     {
6254       string_decl_base_sptr_map::const_iterator r =
6255 	priv_->inserted_types_.find(i->first);
6256       if (r == priv_->inserted_types_.end())
6257 	priv_->removed_types_[i->first] = i->second;
6258     }
6259   for (string_decl_base_sptr_map::const_iterator i =
6260 	 priv_->deleted_decls_.begin();
6261        i != priv_->deleted_decls_.end();
6262        ++i)
6263     {
6264       string_decl_base_sptr_map::const_iterator r =
6265 	priv_->inserted_decls_.find(i->first);
6266       if (r == priv_->inserted_decls_.end())
6267 	priv_->removed_decls_[i->first] = i->second;
6268     }
6269 
6270   // Populate added types/decls.
6271   for (string_decl_base_sptr_map::const_iterator i =
6272 	 priv_->inserted_types_.begin();
6273        i != priv_->inserted_types_.end();
6274        ++i)
6275     {
6276       string_decl_base_sptr_map::const_iterator r =
6277 	priv_->deleted_types_.find(i->first);
6278       if (r == priv_->deleted_types_.end())
6279 	priv_->added_types_[i->first] = i->second;
6280     }
6281   for (string_decl_base_sptr_map::const_iterator i =
6282 	 priv_->inserted_decls_.begin();
6283        i != priv_->inserted_decls_.end();
6284        ++i)
6285     {
6286       string_decl_base_sptr_map::const_iterator r =
6287 	priv_->deleted_decls_.find(i->first);
6288       if (r == priv_->deleted_decls_.end())
6289 	priv_->added_decls_[i->first] = i->second;
6290     }
6291 }
6292 
6293 /// Populate the vector of children node of the @ref diff base type
6294 /// sub-object of this instance of @ref scope_diff.
6295 ///
6296 /// The children node can then later be retrieved using
6297 /// diff::children_node().
6298 void
chain_into_hierarchy()6299 scope_diff::chain_into_hierarchy()
6300 {
6301   for (diff_sptrs_type::const_iterator i = changed_types().begin();
6302        i != changed_types().end();
6303        ++i)
6304     if (*i)
6305       append_child_node(*i);
6306 
6307   for (diff_sptrs_type::const_iterator i = changed_decls().begin();
6308        i != changed_decls().end();
6309        ++i)
6310     if (*i)
6311       append_child_node(*i);
6312 }
6313 
6314 /// Constructor for scope_diff
6315 ///
6316 /// @param first_scope the first scope to consider for the diff.
6317 ///
6318 /// @param second_scope the second scope to consider for the diff.
6319 ///
6320 /// @param ctxt the diff context to use.  Note that this context
6321 /// object must stay alive at least during the life time of the
6322 /// current instance of @ref scope_diff.  Otherwise memory corruption
6323 /// issues occur.
scope_diff(scope_decl_sptr first_scope,scope_decl_sptr second_scope,diff_context_sptr ctxt)6324 scope_diff::scope_diff(scope_decl_sptr first_scope,
6325 		       scope_decl_sptr second_scope,
6326 		       diff_context_sptr ctxt)
6327   : diff(first_scope, second_scope, ctxt),
6328     priv_(new priv)
6329 {}
6330 
6331 /// Finish building the current instance of @ref scope_diff.
6332 void
finish_diff_type()6333 scope_diff::finish_diff_type()
6334 {
6335   if (diff::priv_->finished_)
6336     return;
6337   chain_into_hierarchy();
6338   diff::priv_->finished_ = true;
6339 }
6340 
6341 /// Getter for the first scope of the diff.
6342 ///
6343 /// @return the first scope of the diff.
6344 const scope_decl_sptr
first_scope() const6345 scope_diff::first_scope() const
6346 {return dynamic_pointer_cast<scope_decl>(first_subject());}
6347 
6348 /// Getter for the second scope of the diff.
6349 ///
6350 /// @return the second scope of the diff.
6351 const scope_decl_sptr
second_scope() const6352 scope_diff::second_scope() const
6353 {return dynamic_pointer_cast<scope_decl>(second_subject());}
6354 
6355 /// Accessor of the edit script of the members of a scope.
6356 ///
6357 /// This edit script is computed using the equality operator that
6358 /// applies to shared_ptr<decl_base>.
6359 ///
6360 /// That has interesting consequences.  For instance, consider two
6361 /// scopes S0 and S1.  S0 contains a class C0 and S1 contains a class
6362 /// S0'.  C0 and C0' have the same qualified name, but have different
6363 /// members.  The edit script will consider that C0 has been deleted
6364 /// from S0 and that S0' has been inserted.  This is a low level
6365 /// canonical representation of the changes; a higher level
6366 /// representation would give us a simpler way to say "the class C0
6367 /// has been modified into C0'".  But worry not.  We do have such
6368 /// higher representation as well; that is what changed_types() and
6369 /// changed_decls() is for.
6370 ///
6371 /// @return the edit script of the changes encapsulatd in this
6372 /// instance of scope_diff.
6373 const edit_script&
member_changes() const6374 scope_diff::member_changes() const
6375 {return priv_->member_changes_;}
6376 
6377 /// Accessor of the edit script of the members of a scope.
6378 ///
6379 /// This edit script is computed using the equality operator that
6380 /// applies to shared_ptr<decl_base>.
6381 ///
6382 /// That has interesting consequences.  For instance, consider two
6383 /// scopes S0 and S1.  S0 contains a class C0 and S1 contains a class
6384 /// S0'.  C0 and C0' have the same qualified name, but have different
6385 /// members.  The edit script will consider that C0 has been deleted
6386 /// from S0 and that S0' has been inserted.  This is a low level
6387 /// canonical representation of the changes; a higher level
6388 /// representation would give us a simpler way to say "the class C0
6389 /// has been modified into C0'".  But worry not.  We do have such
6390 /// higher representation as well; that is what changed_types() and
6391 /// changed_decls() is for.
6392 ///
6393 /// @return the edit script of the changes encapsulatd in this
6394 /// instance of scope_diff.
6395 edit_script&
member_changes()6396 scope_diff::member_changes()
6397 {return priv_->member_changes_;}
6398 
6399 /// Accessor that eases the manipulation of the edit script associated
6400 /// to this instance.  It returns the scope member that is reported
6401 /// (in the edit script) as deleted at a given index.
6402 ///
6403 /// @param i the index (in the edit script) of an element of the first
6404 /// scope that has been reported as being delete.
6405 ///
6406 /// @return the scope member that has been reported by the edit script
6407 /// as being deleted at index i.
6408 const decl_base_sptr
deleted_member_at(unsigned i) const6409 scope_diff::deleted_member_at(unsigned i) const
6410 {
6411   scope_decl_sptr scope = dynamic_pointer_cast<scope_decl>(first_subject());
6412  return scope->get_member_decls()[i];
6413 }
6414 
6415 /// Accessor that eases the manipulation of the edit script associated
6416 /// to this instance.  It returns the scope member (of the first scope
6417 /// of this diff instance) that is reported (in the edit script) as
6418 /// deleted at a given iterator.
6419 ///
6420 /// @param i the iterator of an element of the first scope that has
6421 /// been reported as being delete.
6422 ///
6423 /// @return the scope member of the first scope of this diff that has
6424 /// been reported by the edit script as being deleted at iterator i.
6425 const decl_base_sptr
deleted_member_at(vector<deletion>::const_iterator i) const6426 scope_diff::deleted_member_at(vector<deletion>::const_iterator i) const
6427 {return deleted_member_at(i->index());}
6428 
6429 /// Accessor that eases the manipulation of the edit script associated
6430 /// to this instance.  It returns the scope member (of the second
6431 /// scope of this diff instance) that is reported as being inserted
6432 /// from a given index.
6433 ///
6434 /// @param i the index of an element of the second scope this diff
6435 /// that has been reported by the edit script as being inserted.
6436 ///
6437 /// @return the scope member of the second scope of this diff that has
6438 /// been reported as being inserted from index i.
6439 const decl_base_sptr
inserted_member_at(unsigned i)6440 scope_diff::inserted_member_at(unsigned i)
6441 {
6442   scope_decl_sptr scope = dynamic_pointer_cast<scope_decl>(second_subject());
6443   return scope->get_member_decls()[i];
6444 }
6445 
6446 /// Accessor that eases the manipulation of the edit script associated
6447 /// to this instance.  It returns the scope member (of the second
6448 /// scope of this diff instance) that is reported as being inserted
6449 /// from a given iterator.
6450 ///
6451 /// @param i the iterator of an element of the second scope this diff
6452 /// that has been reported by the edit script as being inserted.
6453 ///
6454 /// @return the scope member of the second scope of this diff that has
6455 /// been reported as being inserted from iterator i.
6456 const decl_base_sptr
inserted_member_at(vector<unsigned>::const_iterator i)6457 scope_diff::inserted_member_at(vector<unsigned>::const_iterator i)
6458 {return inserted_member_at(*i);}
6459 
6460 /// @return a sorted vector of the types which content has changed
6461 /// from the first scope to the other.
6462 const diff_sptrs_type&
changed_types() const6463 scope_diff::changed_types() const
6464 {return priv_->sorted_changed_types_;}
6465 
6466 /// @return a sorted vector of the decls which content has changed
6467 /// from the first scope to the other.
6468 const diff_sptrs_type&
changed_decls() const6469 scope_diff::changed_decls() const
6470 {return priv_->sorted_changed_decls_;}
6471 
6472 const string_decl_base_sptr_map&
removed_types() const6473 scope_diff::removed_types() const
6474 {return priv_->removed_types_;}
6475 
6476 const string_decl_base_sptr_map&
removed_decls() const6477 scope_diff::removed_decls() const
6478 {return priv_->removed_decls_;}
6479 
6480 const string_decl_base_sptr_map&
added_types() const6481 scope_diff::added_types() const
6482 {return priv_->added_types_;}
6483 
6484 const string_decl_base_sptr_map&
added_decls() const6485 scope_diff::added_decls() const
6486 {return priv_->added_decls_;}
6487 
6488 /// @return the pretty representation for the current instance of @ref
6489 /// scope_diff.
6490 const string&
get_pretty_representation() const6491 scope_diff::get_pretty_representation() const
6492 {
6493   if (diff::priv_->pretty_representation_.empty())
6494     {
6495       std::ostringstream o;
6496       o << "scope_diff["
6497 	<< first_subject()->get_pretty_representation()
6498 	<< ", "
6499 	<< second_subject()->get_pretty_representation()
6500 	<< "]";
6501       diff::priv_->pretty_representation_ = o.str();
6502     }
6503   return diff::priv_->pretty_representation_;
6504 }
6505 
6506 /// Return true iff the current diff node carries a change.
6507 ///
6508 /// Return true iff the current diff node carries a change.
6509 bool
has_changes() const6510 scope_diff::has_changes() const
6511 {
6512   // TODO: add the number of really removed/added stuff.
6513   return changed_types().size() + changed_decls().size();
6514 }
6515 
6516 /// @return the kind of local change carried by the current diff node.
6517 /// The value returned is zero if the current node carries no local
6518 /// change.
6519 enum change_kind
has_local_changes() const6520 scope_diff::has_local_changes() const
6521 {
6522   ir::change_kind k = ir::NO_CHANGE_KIND;
6523   if (!equals(*first_scope(), *second_scope(), &k))
6524     return k & ir::ALL_LOCAL_CHANGES_MASK;
6525   return ir::NO_CHANGE_KIND;
6526 }
6527 
6528 /// Report the changes of one scope against another.
6529 ///
6530 /// @param out the out stream to report the changes to.
6531 ///
6532 /// @param indent the string to use for indentation.
6533 void
report(ostream & out,const string & indent) const6534 scope_diff::report(ostream& out, const string& indent) const
6535 {
6536   context()->get_reporter()->report(*this, out, indent);
6537 }
6538 
6539 /// Compute the diff between two scopes.
6540 ///
6541 /// Note that the two decls must have been created in the same @ref
6542 /// environment, otherwise, this function aborts.
6543 ///
6544 /// @param first the first scope to consider in computing the diff.
6545 ///
6546 /// @param second the second scope to consider in the diff
6547 /// computation.  The second scope is diffed against the first scope.
6548 ///
6549 /// @param d a pointer to the diff object to populate with the
6550 /// computed diff.
6551 ///
6552 /// @return return the populated \a d parameter passed to this
6553 /// function.
6554 ///
6555 /// @param ctxt the diff context to use.
6556 scope_diff_sptr
compute_diff(const scope_decl_sptr first,const scope_decl_sptr second,scope_diff_sptr d,diff_context_sptr ctxt)6557 compute_diff(const scope_decl_sptr	first,
6558 	     const scope_decl_sptr	second,
6559 	     scope_diff_sptr		d,
6560 	     diff_context_sptr		ctxt)
6561 {
6562   ABG_ASSERT(d->first_scope() == first && d->second_scope() == second);
6563 
6564   if (first && second)
6565     ABG_ASSERT(first->get_environment() == second->get_environment());
6566 
6567   compute_diff(first->get_member_decls().begin(),
6568 	       first->get_member_decls().end(),
6569 	       second->get_member_decls().begin(),
6570 	       second->get_member_decls().end(),
6571 	       d->member_changes());
6572 
6573   d->ensure_lookup_tables_populated();
6574   d->context(ctxt);
6575 
6576   return d;
6577 }
6578 
6579 /// Compute the diff between two scopes.
6580 ///
6581 /// Note that the two decls must have been created in the same @ref
6582 /// environment, otherwise, this function aborts.
6583 ///
6584 /// @param first_scope the first scope to consider in computing the diff.
6585 ///
6586 /// @param second_scope the second scope to consider in the diff
6587 /// computation.  The second scope is diffed against the first scope.
6588 ///
6589 /// @param ctxt the diff context to use.
6590 ///
6591 /// @return return the resulting diff
6592 scope_diff_sptr
compute_diff(const scope_decl_sptr first_scope,const scope_decl_sptr second_scope,diff_context_sptr ctxt)6593 compute_diff(const scope_decl_sptr	first_scope,
6594 	     const scope_decl_sptr	second_scope,
6595 	     diff_context_sptr		ctxt)
6596 {
6597   if (first_scope && second_scope)
6598     ABG_ASSERT(first_scope->get_environment()
6599 	   == second_scope->get_environment());
6600 
6601   scope_diff_sptr d(new scope_diff(first_scope, second_scope, ctxt));
6602   d = compute_diff(first_scope, second_scope, d, ctxt);
6603   ctxt->initialize_canonical_diff(d);
6604   return d;
6605 }
6606 
6607 //</scope_diff stuff>
6608 
6609 // <fn_parm_diff stuff>
6610 
6611 /// Constructor for the fn_parm_diff type.
6612 ///
6613 /// @param first the first subject of the diff.
6614 ///
6615 /// @param second the second subject of the diff.
6616 ///
6617 /// @param ctxt the context of the diff.  Note that this context
6618 /// object must stay alive at least during the life time of the
6619 /// current instance of @ref fn_parm_diff.  Otherwise memory
6620 /// corruption issues occur.
fn_parm_diff(const function_decl::parameter_sptr first,const function_decl::parameter_sptr second,diff_context_sptr ctxt)6621 fn_parm_diff::fn_parm_diff(const function_decl::parameter_sptr	first,
6622 			   const function_decl::parameter_sptr	second,
6623 			   diff_context_sptr			ctxt)
6624   : decl_diff_base(first, second, ctxt),
6625     priv_(new priv)
6626 {
6627   ABG_ASSERT(first->get_index() == second->get_index());
6628   priv_->type_diff = compute_diff(first->get_type(),
6629 				  second->get_type(),
6630 				  ctxt);
6631   ABG_ASSERT(priv_->type_diff);
6632 }
6633 
6634 /// Finish the building of the current instance of @ref fn_parm_diff.
6635 void
finish_diff_type()6636 fn_parm_diff::finish_diff_type()
6637 {
6638   if (diff::priv_->finished_)
6639     return;
6640   chain_into_hierarchy();
6641   diff::priv_->finished_ = true;
6642 }
6643 
6644 /// Getter for the first subject of this diff node.
6645 ///
6646 /// @return the first function_decl::parameter_sptr subject of this
6647 /// diff node.
6648 const function_decl::parameter_sptr
first_parameter() const6649 fn_parm_diff::first_parameter() const
6650 {return dynamic_pointer_cast<function_decl::parameter>(first_subject());}
6651 
6652 /// Getter for the second subject of this diff node.
6653 ///
6654 /// @return the second function_decl::parameter_sptr subject of this
6655 /// diff node.
6656 const function_decl::parameter_sptr
second_parameter() const6657 fn_parm_diff::second_parameter() const
6658 {return dynamic_pointer_cast<function_decl::parameter>(second_subject());}
6659 
6660 /// Getter for the diff representing the changes on the type of the
6661 /// function parameter involved in the current instance of @ref
6662 /// fn_parm_diff.
6663 ///
6664 /// @return a diff_sptr representing the changes on the type of the
6665 /// function parameter we are interested in.
6666 diff_sptr
type_diff() const6667 fn_parm_diff::type_diff() const
6668 {return priv_->type_diff;}
6669 
6670 /// Build and return a textual representation of the current instance
6671 /// of @ref fn_parm_diff.
6672 ///
6673 /// @return the string representing the current instance of
6674 /// fn_parm_diff.
6675 const string&
get_pretty_representation() const6676 fn_parm_diff::get_pretty_representation() const
6677 {
6678   if (diff::priv_->pretty_representation_.empty())
6679     {
6680       std::ostringstream o;
6681       o << "function_parameter_diff["
6682 	<< first_subject()->get_pretty_representation()
6683 	<< ", "
6684 	<< second_subject()->get_pretty_representation()
6685 	<< "]";
6686       diff::priv_->pretty_representation_ = o.str();
6687     }
6688   return diff::priv_->pretty_representation_;
6689 }
6690 
6691 /// Return true iff the current diff node carries a change.
6692 ///
6693 /// @return true iff the current diff node carries a change.
6694 bool
has_changes() const6695 fn_parm_diff::has_changes() const
6696 {return *first_parameter() != *second_parameter();}
6697 
6698 /// Check if the current diff node carries a local change.
6699 ///
6700 /// @return the kind of local change carried by the current diff node.
6701 /// The value returned is zero if the current node carries no local
6702 /// change.
6703 enum change_kind
has_local_changes() const6704 fn_parm_diff::has_local_changes() const
6705 {
6706   ir::change_kind k = ir::NO_CHANGE_KIND;
6707   if (!equals(*first_parameter(), *second_parameter(), &k))
6708     return k & ir::ALL_LOCAL_CHANGES_MASK;
6709   return ir::NO_CHANGE_KIND;
6710 }
6711 
6712 /// Emit a textual report about the current fn_parm_diff instance.
6713 ///
6714 /// @param out the output stream to emit the textual report to.
6715 ///
6716 /// @param indent the indentation string to use in the report.
6717 void
report(ostream & out,const string & indent) const6718 fn_parm_diff::report(ostream& out, const string& indent) const
6719 {
6720   context()->get_reporter()->report(*this, out, indent);
6721 }
6722 
6723 /// Populate the vector of children nodes of the @ref diff base type
6724 /// sub-object of this instance of @ref fn_parm_diff.
6725 ///
6726 /// The children nodes can then later be retrieved using
6727 /// diff::children_nodes()
6728 void
chain_into_hierarchy()6729 fn_parm_diff::chain_into_hierarchy()
6730 {
6731   if (type_diff())
6732     append_child_node(type_diff());
6733 }
6734 
6735 /// Compute the difference between two function_decl::parameter_sptr;
6736 /// that is, between two function parameters.  Return a resulting
6737 /// fn_parm_diff_sptr that represents the changes.
6738 ///
6739 /// Note that the two decls must have been created in the same @ref
6740 /// environment, otherwise, this function aborts.
6741 ///
6742 /// @param first the first subject of the diff.
6743 ///
6744 /// @param second the second subject of the diff.
6745 ///
6746 /// @param ctxt the context of the diff.
6747 ///
6748 /// @return fn_parm_diff_sptr the resulting diff node.
6749 fn_parm_diff_sptr
compute_diff(const function_decl::parameter_sptr first,const function_decl::parameter_sptr second,diff_context_sptr ctxt)6750 compute_diff(const function_decl::parameter_sptr	first,
6751 	     const function_decl::parameter_sptr	second,
6752 	     diff_context_sptr				ctxt)
6753 {
6754   if (!first || !second)
6755     return fn_parm_diff_sptr();
6756 
6757   ABG_ASSERT(first->get_environment() == second->get_environment());
6758 
6759   fn_parm_diff_sptr result(new fn_parm_diff(first, second, ctxt));
6760   ctxt->initialize_canonical_diff(result);
6761 
6762   return result;
6763 }
6764 // </fn_parm_diff stuff>
6765 
6766 // <function_type_diff stuff>
6767 
6768 void
ensure_lookup_tables_populated()6769 function_type_diff::ensure_lookup_tables_populated()
6770 {
6771   priv_->return_type_diff_ =
6772     compute_diff(first_function_type()->get_return_type(),
6773 		 second_function_type()->get_return_type(),
6774 		 context());
6775 
6776   string parm_name;
6777   function_decl::parameter_sptr parm;
6778   for (vector<deletion>::const_iterator i =
6779 	 priv_->parm_changes_.deletions().begin();
6780        i != priv_->parm_changes_.deletions().end();
6781        ++i)
6782     {
6783       parm = *(first_function_type()->get_first_parm()
6784 	       + i->index());
6785       parm_name = parm->get_name_id();
6786       // If for a reason the type name is empty we want to know and
6787       // fix that.
6788       ABG_ASSERT(!parm_name.empty());
6789       priv_->deleted_parms_[parm_name] = parm;
6790       priv_->deleted_parms_by_id_[parm->get_index()] = parm;
6791     }
6792 
6793   for (vector<insertion>::const_iterator i =
6794 	 priv_->parm_changes_.insertions().begin();
6795        i != priv_->parm_changes_.insertions().end();
6796        ++i)
6797     {
6798       for (vector<unsigned>::const_iterator j =
6799 	     i->inserted_indexes().begin();
6800 	   j != i->inserted_indexes().end();
6801 	   ++j)
6802 	{
6803 	  parm = *(second_function_type()->get_first_parm() + *j);
6804 	  parm_name = parm->get_name_id();
6805 	  // If for a reason the type name is empty we want to know and
6806 	  // fix that.
6807 	  ABG_ASSERT(!parm_name.empty());
6808 	  {
6809 	    string_parm_map::const_iterator k =
6810 	      priv_->deleted_parms_.find(parm_name);
6811 	    if (k != priv_->deleted_parms_.end())
6812 	      {
6813 		if (*k->second != *parm)
6814 		  priv_->subtype_changed_parms_[parm_name] =
6815 		    compute_diff(k->second, parm, context());
6816 		priv_->deleted_parms_.erase(parm_name);
6817 	      }
6818 	    else
6819 	      priv_->added_parms_[parm_name] = parm;
6820 	  }
6821 	  {
6822 	    unsigned_parm_map::const_iterator k =
6823 	      priv_->deleted_parms_by_id_.find(parm->get_index());
6824 	    if (k != priv_->deleted_parms_by_id_.end())
6825 	      {
6826 		if (*k->second != *parm
6827 		    && (k->second->get_name_id() != parm_name))
6828 		  priv_->changed_parms_by_id_[parm->get_index()] =
6829 		    compute_diff(k->second, parm, context());
6830 		priv_->added_parms_.erase(parm_name);
6831 		priv_->deleted_parms_.erase(k->second->get_name_id());
6832 		priv_->deleted_parms_by_id_.erase(parm->get_index());
6833 	      }
6834 	    else
6835 	      priv_->added_parms_by_id_[parm->get_index()] = parm;
6836 	  }
6837 	}
6838     }
6839 
6840   sort_string_fn_parm_diff_sptr_map(priv_->subtype_changed_parms_,
6841 				    priv_->sorted_subtype_changed_parms_);
6842   sort_string_fn_parm_diff_sptr_map(priv_->changed_parms_by_id_,
6843 				    priv_->sorted_changed_parms_by_id_);
6844   sort_string_parm_map(priv_->deleted_parms_,
6845 		       priv_->sorted_deleted_parms_);
6846 
6847   sort_string_parm_map(priv_->added_parms_,
6848 		       priv_->sorted_added_parms_);
6849 }
6850 
6851 /// In the vector of deleted parameters, get the one that is at a given
6852 /// index.
6853 ///
6854 /// @param i the index of the deleted parameter to get.
6855 ///
6856 /// @return the parameter returned.
6857 const function_decl::parameter_sptr
deleted_parameter_at(int i) const6858 function_type_diff::deleted_parameter_at(int i) const
6859 {return first_function_type()->get_parameters()[i];}
6860 
6861 /// Getter for the sorted vector of deleted parameters.
6862 ///
6863 /// @return the sorted vector of deleted parameters.
6864 const vector<function_decl::parameter_sptr>&
sorted_deleted_parms() const6865 function_type_diff::sorted_deleted_parms() const
6866 {return priv_->sorted_deleted_parms_;}
6867 
6868 /// Getter for the sorted vector of added parameters .
6869 ///
6870 /// @return the sorted vector of added parameters.
6871 const vector<function_decl::parameter_sptr>&
sorted_added_parms() const6872 function_type_diff::sorted_added_parms() const
6873 {return priv_->sorted_added_parms_;}
6874 
6875 /// In the vector of inserted parameters, get the one that is at a
6876 /// given index.
6877 ///
6878 /// @param i the index of the inserted parameter to get.
6879 ///
6880 /// @return the parameter returned.
6881 const function_decl::parameter_sptr
inserted_parameter_at(int i) const6882 function_type_diff::inserted_parameter_at(int i) const
6883 {return second_function_type()->get_parameters()[i];}
6884 
6885 /// Consutrctor of the @ref function_type type.
6886 ///
6887 /// @param first the first @ref function_type subject of the diff to
6888 /// create.
6889 ///
6890 /// @param second the second @ref function_type subject of the diff to
6891 /// create.
6892 ///
6893 /// @param ctxt the diff context to be used by the newly created
6894 /// instance of function_type_diff.  Note that this context object
6895 /// must stay alive at least during the life time of the current
6896 /// instance of @ref function_type_diff.  Otherwise memory corruption
6897 /// issues occur.
function_type_diff(const function_type_sptr first,const function_type_sptr second,diff_context_sptr ctxt)6898 function_type_diff::function_type_diff(const function_type_sptr first,
6899 				       const function_type_sptr second,
6900 				       diff_context_sptr	ctxt)
6901   : type_diff_base(first, second, ctxt),
6902     priv_(new priv)
6903 {}
6904 
6905 /// Finish building the current instance of @ref function_type_diff
6906 void
finish_diff_type()6907 function_type_diff::finish_diff_type()
6908 {
6909   if (diff::priv_->finished_)
6910     return;
6911   chain_into_hierarchy();
6912   diff::priv_->finished_ = true;
6913 }
6914 
6915 /// Getter for the first subject of the diff.
6916 ///
6917 /// @return the first function type involved in the diff.
6918 const function_type_sptr
first_function_type() const6919 function_type_diff::first_function_type() const
6920 {return dynamic_pointer_cast<function_type>(first_subject());}
6921 
6922 /// Getter for the second subject of the diff.
6923 ///
6924 /// @return the second function type involved in the diff.
6925 const function_type_sptr
second_function_type() const6926 function_type_diff::second_function_type() const
6927 {return dynamic_pointer_cast<function_type>(second_subject());}
6928 
6929 /// Getter for the diff of the return types of the two function types
6930 /// of the current diff.
6931 ///
6932 /// @return the diff of the return types of the two function types of
6933 /// the current diff.
6934 const diff_sptr
return_type_diff() const6935 function_type_diff::return_type_diff() const
6936 {return priv_->return_type_diff_;}
6937 
6938 /// Getter for the map of function parameter changes of the current diff.
6939 ///
6940 /// @return a map of function parameter changes of the current diff.
6941 const string_fn_parm_diff_sptr_map&
subtype_changed_parms() const6942 function_type_diff::subtype_changed_parms() const
6943 {return priv_->subtype_changed_parms_;}
6944 
6945 /// Getter for the map of parameters that got removed.
6946 ///
6947 /// @return the map of parameters that got removed.
6948 const string_parm_map&
removed_parms() const6949 function_type_diff::removed_parms() const
6950 {return priv_->deleted_parms_;}
6951 
6952 /// Getter for the map of parameters that got added.
6953 ///
6954 /// @return the map of parameters that got added.
6955 const string_parm_map&
added_parms() const6956 function_type_diff::added_parms() const
6957 {return priv_->added_parms_;}
6958 
6959 /// Build and return a copy of a pretty representation of the current
6960 /// instance of @ref function_type_diff.
6961 ///
6962 /// @return a copy of the pretty representation of the current
6963 /// instance of @ref function_type_diff.
6964 const string&
get_pretty_representation() const6965 function_type_diff::get_pretty_representation() const
6966 {
6967   if (diff::priv_->pretty_representation_.empty())
6968     {
6969       std::ostringstream o;
6970       o << "function_type_diff["
6971 	<< abigail::ir::get_pretty_representation(first_function_type())
6972 	<< ", "
6973 	<< abigail::ir::get_pretty_representation(second_function_type())
6974 	<< "]";
6975       diff::priv_->pretty_representation_ = o.str();
6976     }
6977   return diff::priv_->pretty_representation_;
6978 }
6979 
6980 /// Test if the current diff node carries changes.
6981 ///
6982 /// @return true iff the current diff node carries changes.
6983 bool
has_changes() const6984 function_type_diff::has_changes() const
6985 {return *first_function_type() != *second_function_type();}
6986 
6987 /// Test if the current diff node carries local changes.
6988 ///
6989 /// A local change is a change that is carried by this diff node, not
6990 /// by any of its children nodes.
6991 ///
6992 /// @return the kind of local change carried by the current diff node.
6993 /// The value returned is zero if the current node carries no local
6994 /// change.
6995 enum change_kind
has_local_changes() const6996 function_type_diff::has_local_changes() const
6997 {
6998   ir::change_kind k = ir::NO_CHANGE_KIND;
6999   if (!equals(*first_function_type(), *second_function_type(), &k))
7000     return k & ir::ALL_LOCAL_CHANGES_MASK;
7001   return ir::NO_CHANGE_KIND;
7002 }
7003 
7004 /// Build and emit a textual report about the current @ref
7005 /// function_type_diff instance.
7006 ///
7007 /// @param out the output stream.
7008 ///
7009 /// @param indent the indentation string to use.
7010 void
report(ostream & out,const string & indent) const7011 function_type_diff::report(ostream& out, const string& indent) const
7012 {
7013   context()->get_reporter()->report(*this, out, indent);
7014 }
7015 
7016 /// Populate the vector of children node of the @ref diff base type
7017 /// sub-object of this instance of @ref function_type_diff.
7018 ///
7019 /// The children node can then later be retrieved using
7020 /// diff::children_node().
7021 void
chain_into_hierarchy()7022 function_type_diff::chain_into_hierarchy()
7023 {
7024   if (diff_sptr d = return_type_diff())
7025     append_child_node(d);
7026 
7027   for (vector<fn_parm_diff_sptr>::const_iterator i =
7028 	 priv_->sorted_subtype_changed_parms_.begin();
7029        i != priv_->sorted_subtype_changed_parms_.end();
7030        ++i)
7031     if (diff_sptr d = *i)
7032       append_child_node(d);
7033 
7034   for (vector<fn_parm_diff_sptr>::const_iterator i =
7035 	 priv_->sorted_changed_parms_by_id_.begin();
7036        i != priv_->sorted_changed_parms_by_id_.end();
7037        ++i)
7038     if (diff_sptr d = *i)
7039       append_child_node(d);
7040 }
7041 
7042 /// Compute the diff between two instances of @ref function_type.
7043 ///
7044 /// Note that the two types must have been created in the same @ref
7045 /// environment, otherwise, this function aborts.
7046 ///
7047 /// @param first the first @ref function_type to consider for the diff.
7048 ///
7049 /// @param second the second @ref function_type to consider for the diff.
7050 ///
7051 /// @param ctxt the diff context to use.
7052 ///
7053 /// @return the resulting diff between the two @ref function_type.
7054 function_type_diff_sptr
compute_diff(const function_type_sptr first,const function_type_sptr second,diff_context_sptr ctxt)7055 compute_diff(const function_type_sptr	first,
7056 	     const function_type_sptr	second,
7057 	     diff_context_sptr		ctxt)
7058 {
7059   if (!first || !second)
7060     {
7061       // TODO: implement this for either first or second being NULL.
7062       return function_type_diff_sptr();
7063     }
7064 
7065   ABG_ASSERT(first->get_environment() == second->get_environment());
7066 
7067   function_type_diff_sptr result(new function_type_diff(first, second, ctxt));
7068 
7069   diff_utils::compute_diff(first->get_first_parm(),
7070 			   first->get_parameters().end(),
7071 			   second->get_first_parm(),
7072 			   second->get_parameters().end(),
7073 			   result->priv_->parm_changes_);
7074 
7075   result->ensure_lookup_tables_populated();
7076 
7077   ctxt->initialize_canonical_diff(result);
7078 
7079   return result;
7080 }
7081 // </function_type_diff stuff>
7082 
7083 // <function_decl_diff stuff>
7084 
7085 /// Build the lookup tables of the diff, if necessary.
7086 void
ensure_lookup_tables_populated()7087 function_decl_diff::ensure_lookup_tables_populated()
7088 {
7089 }
7090 
7091 /// Populate the vector of children node of the @ref diff base type
7092 /// sub-object of this instance of @ref function_decl_diff.
7093 ///
7094 /// The children node can then later be retrieved using
7095 /// diff::children_node().
7096 void
chain_into_hierarchy()7097 function_decl_diff::chain_into_hierarchy()
7098 {
7099   if (diff_sptr d = type_diff())
7100     append_child_node(d);
7101 }
7102 
7103 /// Constructor for function_decl_diff
7104 ///
7105 /// @param first the first function considered by the diff.
7106 ///
7107 /// @param second the second function considered by the diff.
7108 ///
7109 /// @param ctxt the context of the diff.  Note that this context
7110 /// object must stay alive at least during the life time of the
7111 /// current instance of @ref function_decl_diff.  Otherwise memory
7112 /// corruption issues occur.
function_decl_diff(const function_decl_sptr first,const function_decl_sptr second,diff_context_sptr ctxt)7113 function_decl_diff::function_decl_diff(const function_decl_sptr first,
7114 				       const function_decl_sptr second,
7115 				       diff_context_sptr	ctxt)
7116   : decl_diff_base(first, second, ctxt),
7117     priv_(new priv)
7118 {
7119 }
7120 
7121 /// Finish building the current instance of @ref function_decl_diff.
7122 void
finish_diff_type()7123 function_decl_diff::finish_diff_type()
7124 {
7125   if (diff::priv_->finished_)
7126     return;
7127   chain_into_hierarchy();
7128   diff::priv_->finished_ = true;
7129 }
7130 
7131 /// @return the first function considered by the diff.
7132 const function_decl_sptr
first_function_decl() const7133 function_decl_diff::first_function_decl() const
7134 {return dynamic_pointer_cast<function_decl>(first_subject());}
7135 
7136 /// @return the second function considered by the diff.
7137 const function_decl_sptr
second_function_decl() const7138 function_decl_diff::second_function_decl() const
7139 {return dynamic_pointer_cast<function_decl>(second_subject());}
7140 
7141 const function_type_diff_sptr
type_diff() const7142 function_decl_diff::type_diff() const
7143 {return priv_->type_diff_;}
7144 
7145 /// @return the pretty representation for the current instance of @ref
7146 /// function_decl_diff.
7147 const string&
get_pretty_representation() const7148 function_decl_diff::get_pretty_representation() const
7149 {
7150   if (diff::priv_->pretty_representation_.empty())
7151     {
7152       std::ostringstream o;
7153       o << "function_diff["
7154 	<< first_subject()->get_pretty_representation()
7155 	<< ", "
7156 	<< second_subject()->get_pretty_representation()
7157 	<< "]";
7158       diff::priv_->pretty_representation_ = o.str();
7159     }
7160   return diff::priv_->pretty_representation_;
7161 }
7162 
7163 /// Return true iff the current diff node carries a change.
7164 ///
7165 /// @return true iff the current diff node carries a change.
7166 bool
has_changes() const7167 function_decl_diff::has_changes() const
7168 {return *first_function_decl() != *second_function_decl();}
7169 
7170 /// @return the kind of local change carried by the current diff node.
7171 /// The value returned is zero if the current node carries no local
7172 /// change.
7173 enum change_kind
has_local_changes() const7174 function_decl_diff::has_local_changes() const
7175 {
7176   ir::change_kind k = ir::NO_CHANGE_KIND;
7177   if (!equals(*first_function_decl(), *second_function_decl(), &k))
7178     return k & ir::ALL_LOCAL_CHANGES_MASK;
7179   return ir::NO_CHANGE_KIND;
7180 }
7181 
7182 /// Serialize a report of the changes encapsulated in the current
7183 /// instance of @ref function_decl_diff over to an output stream.
7184 ///
7185 /// @param out the output stream to serialize the report to.
7186 ///
7187 /// @param indent the string to use an an indentation prefix.
7188 void
report(ostream & out,const string & indent) const7189 function_decl_diff::report(ostream& out, const string& indent) const
7190 {
7191   context()->get_reporter()->report(*this, out, indent);
7192 }
7193 
7194 /// Compute the diff between two function_decl.
7195 ///
7196 /// Note that the two decls must have been created in the same @ref
7197 /// environment, otherwise, this function aborts.
7198 ///
7199 /// @param first the first function_decl to consider for the diff
7200 ///
7201 /// @param second the second function_decl to consider for the diff
7202 ///
7203 /// @param ctxt the diff context to use.
7204 ///
7205 /// @return the computed diff
7206 function_decl_diff_sptr
compute_diff(const function_decl_sptr first,const function_decl_sptr second,diff_context_sptr ctxt)7207 compute_diff(const function_decl_sptr first,
7208 	     const function_decl_sptr second,
7209 	     diff_context_sptr ctxt)
7210 {
7211   if (!first || !second)
7212     {
7213       // TODO: implement this for either first or second being NULL.
7214       return function_decl_diff_sptr();
7215     }
7216 
7217   ABG_ASSERT(first->get_environment() == second->get_environment());
7218 
7219   function_type_diff_sptr type_diff = compute_diff(first->get_type(),
7220 						   second->get_type(),
7221 						   ctxt);
7222 
7223   function_decl_diff_sptr result(new function_decl_diff(first, second,
7224 							ctxt));
7225   result->priv_->type_diff_ = type_diff;
7226 
7227   result->ensure_lookup_tables_populated();
7228 
7229   ctxt->initialize_canonical_diff(result);
7230 
7231   return result;
7232 }
7233 
7234 // </function_decl_diff stuff>
7235 
7236 // <type_decl_diff stuff>
7237 
7238 /// Constructor for type_decl_diff.
7239 ///
7240 /// @param first the first subject of the diff.
7241 ///
7242 /// @param second the second subject of the diff.
7243 ///
7244 /// @param ctxt the context of the diff.  Note that this context
7245 /// object must stay alive at least during the life time of the
7246 /// current instance of @ref type_decl_diff.  Otherwise memory
7247 /// corruption issues occur.
type_decl_diff(const type_decl_sptr first,const type_decl_sptr second,diff_context_sptr ctxt)7248 type_decl_diff::type_decl_diff(const type_decl_sptr first,
7249 			       const type_decl_sptr second,
7250 			       diff_context_sptr ctxt)
7251   : type_diff_base(first, second, ctxt)
7252 {}
7253 
7254 /// Finish building the current instance of @ref type_decl_diff.
7255 void
finish_diff_type()7256 type_decl_diff::finish_diff_type()
7257 {
7258   if (diff::priv_->finished_)
7259     return;
7260   diff::priv_->finished_ = true;
7261 }
7262 
7263 /// Getter for the first subject of the type_decl_diff.
7264 ///
7265 /// @return the first type_decl involved in the diff.
7266 const type_decl_sptr
first_type_decl() const7267 type_decl_diff::first_type_decl() const
7268 {return dynamic_pointer_cast<type_decl>(first_subject());}
7269 
7270 /// Getter for the second subject of the type_decl_diff.
7271 ///
7272 /// @return the second type_decl involved in the diff.
7273 const type_decl_sptr
second_type_decl() const7274 type_decl_diff::second_type_decl() const
7275 {return dynamic_pointer_cast<type_decl>(second_subject());}
7276 
7277 /// @return the pretty representation for the current instance of @ref
7278 /// type_decl_diff.
7279 const string&
get_pretty_representation() const7280 type_decl_diff::get_pretty_representation() const
7281 {
7282   if (diff::priv_->pretty_representation_.empty())
7283     {
7284       std::ostringstream o;
7285       o << "type_decl_diff["
7286 	<< first_subject()->get_pretty_representation()
7287 	<< ", "
7288 	<< second_subject()->get_pretty_representation()
7289 	<< "]";
7290       diff::priv_->pretty_representation_ = o.str();
7291     }
7292   return diff::priv_->pretty_representation_;
7293 }
7294 /// Return true iff the current diff node carries a change.
7295 ///
7296 /// @return true iff the current diff node carries a change.
7297 bool
has_changes() const7298 type_decl_diff::has_changes() const
7299 {return first_type_decl() != second_type_decl();}
7300 
7301 /// @return the kind of local change carried by the current diff node.
7302 /// The value returned is zero if the current node carries no local
7303 /// change.
7304 enum change_kind
has_local_changes() const7305 type_decl_diff::has_local_changes() const
7306 {
7307   ir::change_kind k = ir::NO_CHANGE_KIND;
7308   if (!equals(*first_type_decl(), *second_type_decl(), &k))
7309     return k & ir::ALL_LOCAL_CHANGES_MASK;
7310   return ir::NO_CHANGE_KIND;
7311 }
7312 /// Ouputs a report of the differences between of the two type_decl
7313 /// involved in the type_decl_diff.
7314 ///
7315 /// @param out the output stream to emit the report to.
7316 ///
7317 /// @param indent the string to use for indentatino indent.
7318 void
report(ostream & out,const string & indent) const7319 type_decl_diff::report(ostream& out, const string& indent) const
7320 {
7321   context()->get_reporter()->report(*this, out, indent);
7322 }
7323 
7324 /// Compute a diff between two type_decl.
7325 ///
7326 /// Note that the two types must have been created in the same @ref
7327 /// environment, otherwise, this function aborts.
7328 ///
7329 /// This function doesn't actually compute a diff.  As a type_decl is
7330 /// very simple (unlike compound constructs like function_decl or
7331 /// class_decl) it's easy to just compare the components of the
7332 /// type_decl to know what has changed.  Thus this function just
7333 /// builds and return a type_decl_diff object.  The
7334 /// type_decl_diff::report function will just compare the components
7335 /// of the the two type_decl and display where and how they differ.
7336 ///
7337 /// @param first a pointer to the first type_decl to
7338 /// consider.
7339 ///
7340 /// @param second a pointer to the second type_decl to consider.
7341 ///
7342 /// @param ctxt the diff context to use.
7343 ///
7344 /// @return a pointer to the resulting type_decl_diff.
7345 type_decl_diff_sptr
compute_diff(const type_decl_sptr first,const type_decl_sptr second,diff_context_sptr ctxt)7346 compute_diff(const type_decl_sptr	first,
7347 	     const type_decl_sptr	second,
7348 	     diff_context_sptr		ctxt)
7349 {
7350   if (first && second)
7351     ABG_ASSERT(first->get_environment() == second->get_environment());
7352 
7353   type_decl_diff_sptr result(new type_decl_diff(first, second, ctxt));
7354 
7355   // We don't need to actually compute a diff here as a type_decl
7356   // doesn't have complicated sub-components.  type_decl_diff::report
7357   // just walks the members of the type_decls and display information
7358   // about the ones that have changed.  On a similar note,
7359   // type_decl_diff::length returns 0 if the two type_decls are equal,
7360   // and 1 otherwise.
7361 
7362   ctxt->initialize_canonical_diff(result);
7363 
7364   return result;
7365 }
7366 
7367 // </type_decl_diff stuff>
7368 
7369 // <typedef_diff stuff>
7370 
7371 /// Populate the vector of children node of the @ref diff base type
7372 /// sub-object of this instance of @ref typedef_diff.
7373 ///
7374 /// The children node can then later be retrieved using
7375 /// diff::children_node().
7376 void
chain_into_hierarchy()7377 typedef_diff::chain_into_hierarchy()
7378 {append_child_node(underlying_type_diff());}
7379 
7380 /// Constructor for typedef_diff.
7381 ///
7382 /// @param first the first subject of the diff.
7383 ///
7384 /// @param second the second subject of the diff.
7385 ///
7386 /// @param underlying the underlying diff of the @ref typedef_diff.
7387 /// That is the diff between the underlying types of @p first and @p
7388 /// second.
7389 ///
7390 /// @param ctxt the context of the diff.  Note that this context
7391 /// object must stay alive at least during the life time of the
7392 /// current instance of @ref typedef_diff.  Otherwise memory
7393 /// corruption issues occur.
typedef_diff(const typedef_decl_sptr first,const typedef_decl_sptr second,const diff_sptr underlying,diff_context_sptr ctxt)7394 typedef_diff::typedef_diff(const typedef_decl_sptr	first,
7395 			   const typedef_decl_sptr	second,
7396 			   const diff_sptr		underlying,
7397 			   diff_context_sptr		ctxt)
7398   : type_diff_base(first, second, ctxt),
7399     priv_(new priv(underlying))
7400 {}
7401 
7402 /// Finish building the current instance of @ref typedef_diff.
7403 void
finish_diff_type()7404 typedef_diff::finish_diff_type()
7405 {
7406   if (diff::priv_->finished_)
7407     return;
7408   chain_into_hierarchy();
7409   diff::priv_->finished_ = true;
7410 }
7411 
7412 /// Getter for the firt typedef_decl involved in the diff.
7413 ///
7414 /// @return the first subject of the diff.
7415 const typedef_decl_sptr
first_typedef_decl() const7416 typedef_diff::first_typedef_decl() const
7417 {return dynamic_pointer_cast<typedef_decl>(first_subject());}
7418 
7419 /// Getter for the second typedef_decl involved in the diff.
7420 ///
7421 /// @return the second subject of the diff.
7422 const typedef_decl_sptr
second_typedef_decl() const7423 typedef_diff::second_typedef_decl() const
7424 {return dynamic_pointer_cast<typedef_decl>(second_subject());}
7425 
7426 /// Getter for the diff between the two underlying types of the
7427 /// typedefs.
7428 ///
7429 /// @return the diff object reprensenting the difference between the
7430 /// two underlying types of the typedefs.
7431 const diff_sptr
underlying_type_diff() const7432 typedef_diff::underlying_type_diff() const
7433 {return priv_->underlying_type_diff_;}
7434 
7435 /// Setter for the diff between the two underlying types of the
7436 /// typedefs.
7437 ///
7438 /// @param d the new diff object reprensenting the difference between
7439 /// the two underlying types of the typedefs.
7440 void
underlying_type_diff(const diff_sptr d)7441 typedef_diff::underlying_type_diff(const diff_sptr d)
7442 {priv_->underlying_type_diff_ = d;}
7443 
7444 /// @return the pretty representation for the current instance of @ref
7445 /// typedef_diff.
7446 const string&
get_pretty_representation() const7447 typedef_diff::get_pretty_representation() const
7448 {
7449   if (diff::priv_->pretty_representation_.empty())
7450     {
7451       std::ostringstream o;
7452       o << "typedef_diff["
7453 	<< first_subject()->get_pretty_representation()
7454 	<< ", "
7455 	<< second_subject()->get_pretty_representation()
7456 	<< "]";
7457       diff::priv_->pretty_representation_ = o.str();
7458     }
7459   return diff::priv_->pretty_representation_;
7460 }
7461 
7462 /// Return true iff the current diff node carries a change.
7463 ///
7464 /// @return true iff the current diff node carries a change.
7465 bool
has_changes() const7466 typedef_diff::has_changes() const
7467 {
7468   decl_base_sptr second = second_typedef_decl();
7469   return !(*first_typedef_decl() == *second);
7470 }
7471 
7472 /// @return the kind of local change carried by the current diff node.
7473 /// The value returned is zero if the current node carries no local
7474 /// change.
7475 enum change_kind
has_local_changes() const7476 typedef_diff::has_local_changes() const
7477 {
7478   ir::change_kind k = ir::NO_CHANGE_KIND;
7479   if (!equals(*first_typedef_decl(), *second_typedef_decl(), &k))
7480     return k & ir::ALL_LOCAL_CHANGES_MASK;
7481   return ir::NO_CHANGE_KIND;
7482 }
7483 
7484 /// Reports the difference between the two subjects of the diff in a
7485 /// serialized form.
7486 ///
7487 /// @param out the output stream to emit the report to.
7488 ///
7489 /// @param indent the indentation string to use.
7490 void
report(ostream & out,const string & indent) const7491 typedef_diff::report(ostream& out, const string& indent) const
7492 {
7493   context()->get_reporter()->report(*this, out, indent);
7494 }
7495 
7496 /// Compute a diff between two typedef_decl.
7497 ///
7498 /// Note that the two types must have been created in the same @ref
7499 /// environment, otherwise, this function aborts.
7500 ///
7501 /// @param first a pointer to the first typedef_decl to consider.
7502 ///
7503 /// @param second a pointer to the second typedef_decl to consider.
7504 ///
7505 /// @param ctxt the diff context to use.
7506 ///
7507 /// @return a pointer to the the resulting typedef_diff.
7508 typedef_diff_sptr
compute_diff(const typedef_decl_sptr first,const typedef_decl_sptr second,diff_context_sptr ctxt)7509 compute_diff(const typedef_decl_sptr	first,
7510 	     const typedef_decl_sptr	second,
7511 	     diff_context_sptr		ctxt)
7512 {
7513   if (first && second)
7514     ABG_ASSERT(first->get_environment() == second->get_environment());
7515 
7516   diff_sptr d = compute_diff_for_types(first->get_underlying_type(),
7517 				       second->get_underlying_type(),
7518 				       ctxt);
7519   typedef_diff_sptr result(new typedef_diff(first, second, d, ctxt));
7520 
7521   ctxt->initialize_canonical_diff(result);
7522 
7523   return result;
7524 }
7525 
7526 /// Return the leaf underlying diff node of a @ref typedef_diff node.
7527 ///
7528 /// If the underlying diff node of a @ref typedef_diff node is itself
7529 /// a @ref typedef_diff node, then recursively look at the underlying
7530 /// diff nodes to get the first one that is not a a @ref typedef_diff
7531 /// node.  This is what a leaf underlying diff node means.
7532 ///
7533 /// Otherwise, if the underlying diff node of @ref typedef_diff is
7534 /// *NOT* a @ref typedef_diff node, then just return the underlying
7535 /// diff node.
7536 ///
7537 /// And if the diff node considered is not a @ref typedef_diff node,
7538 /// then just return it.
7539 ///
7540 /// @return the leaf underlying diff node of a @p diff.
7541 const diff*
get_typedef_diff_underlying_type_diff(const diff * diff)7542 get_typedef_diff_underlying_type_diff(const diff* diff)
7543 {
7544   const typedef_diff* d = dynamic_cast<const typedef_diff*>(diff);
7545   if (!d)
7546     return diff;
7547 
7548   if (const typedef_diff* deef =
7549       dynamic_cast<const typedef_diff*>(d->underlying_type_diff().get()))
7550     return get_typedef_diff_underlying_type_diff(deef);
7551 
7552   return d->underlying_type_diff().get();
7553 }
7554 
7555 // </typedef_diff stuff>
7556 
7557 // <translation_unit_diff stuff>
7558 
7559 /// Constructor for translation_unit_diff.
7560 ///
7561 /// @param first the first translation unit to consider for this diff.
7562 ///
7563 /// @param second the second translation unit to consider for this diff.
7564 ///
7565 /// @param ctxt the context of the diff.  Note that this context
7566 /// object must stay alive at least during the life time of the
7567 /// current instance of @ref translation_unit_diff.  Otherwise memory
7568 /// corruption issues occur.
translation_unit_diff(translation_unit_sptr first,translation_unit_sptr second,diff_context_sptr ctxt)7569 translation_unit_diff::translation_unit_diff(translation_unit_sptr first,
7570 					     translation_unit_sptr second,
7571 					     diff_context_sptr ctxt)
7572   : scope_diff(first->get_global_scope(), second->get_global_scope(), ctxt),
7573     priv_(new priv(first, second))
7574 {
7575 }
7576 
7577 /// Getter for the first translation unit of this diff.
7578 ///
7579 /// @return the first translation unit of this diff.
7580 const translation_unit_sptr
first_translation_unit() const7581 translation_unit_diff::first_translation_unit() const
7582 {return priv_->first_;}
7583 
7584 /// Getter for the second translation unit of this diff.
7585 ///
7586 /// @return the second translation unit of this diff.
7587 const translation_unit_sptr
second_translation_unit() const7588 translation_unit_diff::second_translation_unit() const
7589 {return priv_->second_;}
7590 
7591 /// Return true iff the current diff node carries a change.
7592 ///
7593 /// @return true iff the current diff node carries a change.
7594 bool
has_changes() const7595 translation_unit_diff::has_changes() const
7596 {return scope_diff::has_changes();}
7597 
7598 /// @return the kind of local change carried by the current diff node.
7599 /// The value returned is zero if the current node carries no local
7600 /// change.
7601 enum change_kind
has_local_changes() const7602 translation_unit_diff::has_local_changes() const
7603 {return ir::NO_CHANGE_KIND;}
7604 
7605 /// Report the diff in a serialized form.
7606 ///
7607 /// @param out the output stream to serialize the report to.
7608 ///
7609 /// @param indent the prefix to use as indentation for the report.
7610 void
report(ostream & out,const string & indent) const7611 translation_unit_diff::report(ostream& out, const string& indent) const
7612 {scope_diff::report(out, indent);}
7613 
7614 /// Compute the diff between two translation_units.
7615 ///
7616 /// Note that the two translation units must have been created in the
7617 /// same @ref environment, otherwise, this function aborts.
7618 ///
7619 /// @param first the first translation_unit to consider.
7620 ///
7621 /// @param second the second translation_unit to consider.
7622 ///
7623 /// @param ctxt the diff context to use.  If null, this function will
7624 /// create a new context and set to the diff object returned.
7625 ///
7626 /// @return the newly created diff object.
7627 translation_unit_diff_sptr
compute_diff(const translation_unit_sptr first,const translation_unit_sptr second,diff_context_sptr ctxt)7628 compute_diff(const translation_unit_sptr	first,
7629 	     const translation_unit_sptr	second,
7630 	     diff_context_sptr			ctxt)
7631 {
7632   ABG_ASSERT(first && second);
7633 
7634   ABG_ASSERT(first->get_environment() == second->get_environment());
7635 
7636   if (!ctxt)
7637     ctxt.reset(new diff_context);
7638 
7639   // TODO: handle first or second having empty contents.
7640   translation_unit_diff_sptr tu_diff(new translation_unit_diff(first, second,
7641 							       ctxt));
7642   scope_diff_sptr sc_diff = dynamic_pointer_cast<scope_diff>(tu_diff);
7643 
7644   compute_diff(static_pointer_cast<scope_decl>(first->get_global_scope()),
7645 	       static_pointer_cast<scope_decl>(second->get_global_scope()),
7646 	       sc_diff,
7647 	       ctxt);
7648 
7649   ctxt->initialize_canonical_diff(tu_diff);
7650 
7651   return tu_diff;
7652 }
7653 
7654 // </translation_unit_diff stuff>
7655 
7656 // <diff_maps stuff>
7657 
7658 /// The private data of the @ref diff_maps type.
7659 struct diff_maps::priv
7660 {
7661   string_diff_ptr_map type_decl_diff_map_;
7662   string_diff_ptr_map enum_diff_map_;
7663   string_diff_ptr_map class_diff_map_;
7664   string_diff_ptr_map union_diff_map_;
7665   string_diff_ptr_map typedef_diff_map_;
7666   string_diff_ptr_map array_diff_map_;
7667   string_diff_ptr_map reference_diff_map_;
7668   string_diff_ptr_map function_type_diff_map_;
7669   string_diff_ptr_map function_decl_diff_map_;
7670   string_diff_ptr_map var_decl_diff_map_;
7671   string_diff_ptr_map distinct_diff_map_;
7672   string_diff_ptr_map fn_parm_diff_map_;
7673   diff_artifact_set_map_type impacted_artifacts_map_;
7674 }; // end struct diff_maps::priv
7675 
7676 /// Default constructor of the @ref diff_maps type.
diff_maps()7677 diff_maps::diff_maps()
7678   : priv_(new diff_maps::priv())
7679 {}
7680 
7681 diff_maps::~diff_maps() = default;
7682 
7683 /// Getter of the map that contains basic type diffs.
7684 ///
7685 /// @return the map that contains basic type diffs.
7686 const string_diff_ptr_map&
get_type_decl_diff_map() const7687 diff_maps::get_type_decl_diff_map() const
7688 {return priv_->type_decl_diff_map_;}
7689 
7690 /// Getter of the map that contains basic type diffs.
7691 ///
7692 /// @return the map that contains basic type diffs.
7693 string_diff_ptr_map&
get_type_decl_diff_map()7694 diff_maps::get_type_decl_diff_map()
7695 {return priv_->type_decl_diff_map_;}
7696 
7697 /// Getter of the map that contains enum type diffs.
7698 ///
7699 /// @return the map that contains enum type diffs.
7700 const string_diff_ptr_map&
get_enum_diff_map() const7701 diff_maps::get_enum_diff_map() const
7702 {return priv_->enum_diff_map_;}
7703 
7704 /// Getter of the map that contains enum type diffs.
7705 ///
7706 /// @return the map that contains enum type diffs.
7707 string_diff_ptr_map&
get_enum_diff_map()7708 diff_maps::get_enum_diff_map()
7709 {return priv_->enum_diff_map_;}
7710 
7711 /// Getter of the map that contains class type diffs.
7712 ///
7713 /// @return the map that contains class type diffs.
7714 const string_diff_ptr_map&
get_class_diff_map() const7715 diff_maps::get_class_diff_map() const
7716 {return priv_->class_diff_map_;}
7717 
7718 /// Getter of the map that contains class type diffs.
7719 ///
7720 /// @return the map that contains class type diffs.
7721 string_diff_ptr_map&
get_class_diff_map()7722 diff_maps::get_class_diff_map()
7723 {return priv_->class_diff_map_;}
7724 
7725 /// Getter of the map that contains union type diffs.
7726 ///
7727 /// @return the map that contains union type diffs.
7728 const string_diff_ptr_map&
get_union_diff_map() const7729 diff_maps::get_union_diff_map() const
7730 {return priv_->union_diff_map_;}
7731 
7732 /// Getter of the map that contains union type diffs.
7733 ///
7734 /// @return the map that contains union type diffs.
7735 string_diff_ptr_map&
get_union_diff_map()7736 diff_maps::get_union_diff_map()
7737 {return priv_->union_diff_map_;}
7738 
7739 /// Getter of the map that contains typedef type diffs.
7740 ///
7741 /// @return the map that contains typedef type diffs.
7742 const string_diff_ptr_map&
get_typedef_diff_map() const7743 diff_maps::get_typedef_diff_map() const
7744 {return priv_->typedef_diff_map_;}
7745 
7746 /// Getter of the map that contains typedef type diffs.
7747 ///
7748 /// @return the map that contains typedef type diffs.
7749 string_diff_ptr_map&
get_typedef_diff_map()7750 diff_maps::get_typedef_diff_map()
7751 {return priv_->typedef_diff_map_;}
7752 
7753 /// Getter of the map that contains array type diffs.
7754 ///
7755 /// @return the map that contains array type diffs.
7756 const string_diff_ptr_map&
get_array_diff_map() const7757 diff_maps::get_array_diff_map() const
7758 {return priv_->array_diff_map_;}
7759 
7760 /// Getter of the map that contains array type diffs.
7761 ///
7762 /// @return the map that contains array type diffs.
7763 string_diff_ptr_map&
get_array_diff_map()7764 diff_maps::get_array_diff_map()
7765 {return priv_->array_diff_map_;}
7766 
7767 /// Getter of the map that contains reference type diffs.
7768 ///
7769 /// @return the map that contains reference type diffs.
7770 const string_diff_ptr_map&
get_reference_diff_map() const7771 diff_maps::get_reference_diff_map() const
7772 {return priv_->reference_diff_map_;}
7773 
7774 /// Getter of the map that contains reference type diffs.
7775 ///
7776 /// @return the map that contains reference type diffs.
7777 string_diff_ptr_map&
get_reference_diff_map()7778 diff_maps::get_reference_diff_map()
7779 {{return priv_->reference_diff_map_;}}
7780 
7781 /// Getter of the map that contains function parameter diffs.
7782 ///
7783 /// @return the map that contains function parameter diffs.
7784 const string_diff_ptr_map&
get_fn_parm_diff_map() const7785 diff_maps::get_fn_parm_diff_map() const
7786 {return priv_->fn_parm_diff_map_;}
7787 
7788 /// Getter of the map that contains function parameter diffs.
7789 ///
7790 /// @return the map that contains function parameter diffs.
7791 string_diff_ptr_map&
get_fn_parm_diff_map()7792 diff_maps::get_fn_parm_diff_map()
7793 {return priv_->fn_parm_diff_map_;}
7794 
7795 /// Getter of the map that contains function type diffs.
7796 ///
7797 /// @return the map that contains function type diffs.
7798 const string_diff_ptr_map&
get_function_type_diff_map() const7799 diff_maps::get_function_type_diff_map() const
7800 {return priv_->function_type_diff_map_;}
7801 
7802 /// Getter of the map that contains function type diffs.
7803 ///
7804 /// @return the map that contains function type diffs.
7805 string_diff_ptr_map&
get_function_type_diff_map()7806 diff_maps::get_function_type_diff_map()
7807 {return priv_->function_type_diff_map_;}
7808 
7809 /// Getter of the map that contains function decl diffs.
7810 ///
7811 /// @return the map that contains function decl diffs.
7812 const string_diff_ptr_map&
get_function_decl_diff_map() const7813 diff_maps::get_function_decl_diff_map() const
7814 {return priv_->function_decl_diff_map_;}
7815 
7816 /// Getter of the map that contains function decl diffs.
7817 ///
7818 /// @return the map that contains function decl diffs.
7819 string_diff_ptr_map&
get_function_decl_diff_map()7820 diff_maps::get_function_decl_diff_map()
7821 {return priv_->function_decl_diff_map_;}
7822 
7823 /// Getter of the map that contains var decl diffs.
7824 ///
7825 /// @return the map that contains var decl diffs.
7826 const string_diff_ptr_map&
get_var_decl_diff_map() const7827 diff_maps::get_var_decl_diff_map() const
7828 {return priv_->var_decl_diff_map_;}
7829 
7830 /// Getter of the map that contains var decl diffs.
7831 ///
7832 /// @return the map that contains var decl diffs.
7833 string_diff_ptr_map&
get_var_decl_diff_map()7834 diff_maps::get_var_decl_diff_map()
7835 {return priv_->var_decl_diff_map_;}
7836 
7837 /// Getter of the map that contains distinct diffs.
7838 ///
7839 /// @return the map that contains distinct diffs.
7840 const string_diff_ptr_map&
get_distinct_diff_map() const7841 diff_maps::get_distinct_diff_map() const
7842 {return priv_->distinct_diff_map_;}
7843 
7844 /// Getter of the map that contains distinct diffs.
7845 ///
7846 /// @return the map that contains distinct diffs.
7847 string_diff_ptr_map&
get_distinct_diff_map()7848 diff_maps::get_distinct_diff_map()
7849 {return priv_->distinct_diff_map_;}
7850 
7851 /// Insert a new diff node into the current instance of @ref diff_maps.
7852 ///
7853 /// @param dif the new diff node to insert into the @ref diff_maps.
7854 ///
7855 /// @param impacted_iface the interface (global function or variable)
7856 /// currently being analysed that led to analysing the diff node @p
7857 /// dif.  In other words, this is the interface impacted by the diff
7858 /// node @p dif.  Note that this can be nil in cases where we are
7859 /// directly analysing changes to a type that is not reachable from
7860 /// any global function or variable.
7861 ///
7862 /// @return true iff the diff node could be added to the current
7863 /// instance of @ref diff_maps.
7864 bool
insert_diff_node(const diff * dif,const type_or_decl_base_sptr & impacted_iface)7865 diff_maps::insert_diff_node(const diff *dif,
7866 			    const type_or_decl_base_sptr& impacted_iface)
7867 {
7868   string n = get_pretty_representation(dif->first_subject(),
7869 				       /*internal=*/true);
7870   if (const type_decl_diff *d = is_diff_of_basic_type(dif))
7871     get_type_decl_diff_map()[n] = const_cast<type_decl_diff*>(d);
7872   else if (const enum_diff *d = is_enum_diff(dif))
7873     get_enum_diff_map()[n] = const_cast<enum_diff*>(d);
7874   else if (const class_diff *d = is_class_diff(dif))
7875       get_class_diff_map()[n] = const_cast<class_diff*>(d);
7876   else if (const union_diff *d = is_union_diff(dif))
7877     get_union_diff_map()[n] = const_cast<union_diff*>(d);
7878   else if (const typedef_diff *d = is_typedef_diff(dif))
7879     get_typedef_diff_map()[n] = const_cast<typedef_diff*>(d);
7880   else if (const array_diff *d = is_array_diff(dif))
7881       get_array_diff_map()[n] = const_cast<array_diff*>(d);
7882   else if (const reference_diff *d = is_reference_diff(dif))
7883     get_reference_diff_map()[n] = const_cast<reference_diff*>(d);
7884   else if (const fn_parm_diff *d = is_fn_parm_diff(dif))
7885     get_fn_parm_diff_map()[n] = const_cast<fn_parm_diff*>(d);
7886   else if (const function_type_diff *d = is_function_type_diff(dif))
7887     get_function_type_diff_map()[n] = const_cast<function_type_diff*>(d);
7888   else if (const var_diff *d = is_var_diff(dif))
7889     get_var_decl_diff_map()[n] = const_cast<var_diff*>(d);
7890   else if (const function_decl_diff *d = is_function_decl_diff(dif))
7891     get_function_decl_diff_map()[n] = const_cast<function_decl_diff*>(d);
7892   else if (const distinct_diff *d = is_distinct_diff(dif))
7893     get_distinct_diff_map()[n] = const_cast<distinct_diff*>(d);
7894   else if (is_base_diff(dif))
7895     // we silently drop this case.
7896     return true;
7897   else
7898       ABG_ASSERT_NOT_REACHED;
7899 
7900   // Update the map that associates this diff node to the set of
7901   // interfaces it impacts.
7902 
7903   if (impacted_iface)
7904     {
7905       diff_artifact_set_map_type::iterator i =
7906 	priv_->impacted_artifacts_map_.find(dif);
7907 
7908       if (i == priv_->impacted_artifacts_map_.end())
7909 	{
7910 	  artifact_sptr_set_type set;
7911 	  set.insert(impacted_iface);
7912 	  priv_->impacted_artifacts_map_[dif] = set;
7913 	}
7914       else
7915 	i->second.insert(impacted_iface);
7916     }
7917 
7918   return true;
7919 }
7920 
7921 /// Lookup the interfaces that are impacted by a given leaf diff node.
7922 ///
7923 /// @param d the diff node to consider.
7924 ///
7925 /// @return the set of artifacts impacted by @p d.
7926 artifact_sptr_set_type*
lookup_impacted_interfaces(const diff * d) const7927 diff_maps::lookup_impacted_interfaces(const diff *d) const
7928 {
7929   diff_artifact_set_map_type::iterator i =
7930     priv_->impacted_artifacts_map_.find(d);
7931 
7932   if (i == priv_->impacted_artifacts_map_.end())
7933     return 0;
7934 
7935   return &i->second;
7936 }
7937 
7938 //
7939 // </diff_maps stuff>
7940 
7941 /// Constructor for the @ref diff_stat type.
7942 ///
7943 /// @param ctxt the context of the corpus diff.  Note that this
7944 /// context object must stay alive at least during the life time of
7945 /// the current instance of @ref corpus_diff::diff_stats.  Otherwise
7946 /// memory corruption issues occur.
diff_stats(diff_context_sptr ctxt)7947 corpus_diff::diff_stats::diff_stats(diff_context_sptr ctxt)
7948   : priv_(new priv(ctxt))
7949 {}
7950 
7951 /// Getter for the number of functions removed.
7952 ///
7953 /// @return the number of functions removed.
7954 size_t
num_func_removed() const7955 corpus_diff::diff_stats::num_func_removed() const
7956 {return priv_->num_func_removed;}
7957 
7958 /// Setter for the number of functions removed.
7959 ///
7960 /// @param n the new number of functions removed.
7961 void
num_func_removed(size_t n)7962 corpus_diff::diff_stats::num_func_removed(size_t n)
7963 {priv_->num_func_removed = n;}
7964 
7965 /// Getter for the number of removed functions that have been filtered
7966 /// out.
7967 ///
7968 /// @return the number of removed functions that have been filtered
7969 /// out.
7970 size_t
num_removed_func_filtered_out() const7971 corpus_diff::diff_stats::num_removed_func_filtered_out() const
7972 {
7973   if (priv_->ctxt() && !priv_->ctxt()->show_deleted_fns())
7974     return num_func_removed();
7975   return priv_->num_removed_func_filtered_out;
7976 }
7977 
7978 /// Setter for the number of removed functions that have been filtered
7979 /// out.
7980 ///
7981 /// @param t the new value.
7982 void
num_removed_func_filtered_out(size_t t)7983 corpus_diff::diff_stats::num_removed_func_filtered_out(size_t t)
7984 {priv_->num_removed_func_filtered_out = t;}
7985 
7986 /// Getter for the net number of function removed.
7987 ///
7988 /// This is the difference between the number of functions removed and
7989 /// the number of functons removed that have been filtered out.
7990 ///
7991 /// @return the net number of function removed.
7992 size_t
net_num_func_removed() const7993 corpus_diff::diff_stats::net_num_func_removed() const
7994 {
7995   ABG_ASSERT(num_func_removed() >= num_removed_func_filtered_out());
7996   return num_func_removed() - num_removed_func_filtered_out();
7997 }
7998 
7999 /// Getter for the number of functions added.
8000 ///
8001 /// @return the number of functions added.
8002 size_t
num_func_added() const8003 corpus_diff::diff_stats::num_func_added() const
8004 {return priv_->num_func_added;}
8005 
8006 /// Setter for the number of functions added.
8007 ///
8008 /// @param n the new number of functions added.
8009 void
num_func_added(size_t n)8010 corpus_diff::diff_stats::num_func_added(size_t n)
8011 {priv_->num_func_added = n;}
8012 
8013 /// Getter for the number of added function that have been filtered out.
8014 ///
8015 /// @return the number of added function that have been filtered out.
8016 size_t
num_added_func_filtered_out() const8017 corpus_diff::diff_stats::num_added_func_filtered_out() const
8018 {
8019   if (priv_->ctxt() && !priv_->ctxt()->show_added_fns())
8020     return num_func_added();
8021   return priv_->num_added_func_filtered_out;
8022 }
8023 
8024 /// Setter for the number of added function that have been filtered
8025 /// out.
8026 ///
8027 /// @param n the new value.
8028 void
num_added_func_filtered_out(size_t n)8029 corpus_diff::diff_stats::num_added_func_filtered_out(size_t n)
8030 {priv_->num_added_func_filtered_out = n;}
8031 
8032 /// Getter for the net number of added functions.
8033 ///
8034 /// The net number of added functions is the difference between the
8035 /// number of added functions and the number of added functions that
8036 /// have been filtered out.
8037 ///
8038 /// @return the net number of added functions.
8039 size_t
net_num_func_added() const8040 corpus_diff::diff_stats::net_num_func_added() const
8041 {
8042   ABG_ASSERT(num_func_added() >= num_added_func_filtered_out());
8043   return num_func_added() - num_added_func_filtered_out();
8044 }
8045 
8046 /// Getter for the number of functions that have a change in one of
8047 /// their sub-types.
8048 ///
8049 /// @return the number of functions that have a change in one of their
8050 /// sub-types.
8051 size_t
num_func_changed() const8052 corpus_diff::diff_stats::num_func_changed() const
8053 {return priv_->num_func_changed;}
8054 
8055 /// Setter for the number of functions that have a change in one of
8056 /// their sub-types.
8057 ///
8058 /// @@param n the new number of functions that have a change in one of
8059 /// their sub-types.
8060 void
num_func_changed(size_t n)8061 corpus_diff::diff_stats::num_func_changed(size_t n)
8062 {priv_->num_func_changed = n;}
8063 
8064 /// Getter for the number of functions that have a change in one of
8065 /// their sub-types, and that have been filtered out.
8066 ///
8067 /// @return the number of functions that have a change in one of their
8068 /// sub-types, and that have been filtered out.
8069 size_t
num_changed_func_filtered_out() const8070 corpus_diff::diff_stats::num_changed_func_filtered_out() const
8071 {return priv_->num_changed_func_filtered_out;}
8072 
8073 /// Setter for the number of functions that have a change in one of
8074 /// their sub-types, and that have been filtered out.
8075 ///
8076 /// @param n the new number of functions that have a change in one of their
8077 /// sub-types, and that have been filtered out.
8078 void
num_changed_func_filtered_out(size_t n)8079 corpus_diff::diff_stats::num_changed_func_filtered_out(size_t n)
8080 {priv_->num_changed_func_filtered_out = n;}
8081 
8082 /// Getter for the number of functions that carry virtual member
8083 /// offset changes.
8084 ///
8085 /// @return the number of functions that carry virtual member changes.
8086 size_t
num_func_with_virtual_offset_changes() const8087 corpus_diff::diff_stats::num_func_with_virtual_offset_changes() const
8088 {return priv_->num_func_with_virt_offset_changes;}
8089 
8090 /// Setter for the number of functions that carry virtual member
8091 /// offset changes.
8092 ///
8093 /// @param n the new number of functions that carry virtual member
8094 /// offset.  changes.
8095 void
num_func_with_virtual_offset_changes(size_t n)8096 corpus_diff::diff_stats::num_func_with_virtual_offset_changes(size_t n)
8097 {priv_->num_func_with_virt_offset_changes = n;}
8098 
8099 /// Getter for the number of functions that have a change in their
8100 /// sub-types, minus the number of these functions that got filtered
8101 /// out from the diff.
8102 ///
8103 /// @return for the the number of functions that have a change in
8104 /// their sub-types, minus the number of these functions that got
8105 /// filtered out from the diff.
8106 size_t
net_num_func_changed() const8107 corpus_diff::diff_stats::net_num_func_changed() const
8108 {return num_func_changed() - num_changed_func_filtered_out();}
8109 
8110 /// Getter for the number of variables removed.
8111 ///
8112 /// @return the number of variables removed.
8113 size_t
num_vars_removed() const8114 corpus_diff::diff_stats::num_vars_removed() const
8115 {return priv_->num_vars_removed;}
8116 
8117 /// Setter for the number of variables removed.
8118 ///
8119 /// @param n the new number of variables removed.
8120 void
num_vars_removed(size_t n)8121 corpus_diff::diff_stats::num_vars_removed(size_t n)
8122 {priv_->num_vars_removed = n;}
8123 
8124 /// Getter for the number removed variables that have been filtered
8125 /// out.
8126 ///
8127 /// @return the number removed variables that have been filtered out.
8128 size_t
num_removed_vars_filtered_out() const8129 corpus_diff::diff_stats::num_removed_vars_filtered_out() const
8130 {
8131   if (priv_->ctxt() && !priv_->ctxt()->show_deleted_vars())
8132     return num_vars_removed();
8133   return priv_->num_removed_vars_filtered_out;
8134 }
8135 
8136 /// Setter for the number of removed variables that have been filtered
8137 /// out.
8138 ///
8139 /// @param n the new value.
8140 void
num_removed_vars_filtered_out(size_t n) const8141 corpus_diff::diff_stats::num_removed_vars_filtered_out(size_t n) const
8142 {priv_->num_removed_vars_filtered_out = n;}
8143 
8144 /// Getter for the net number of removed variables.
8145 ///
8146 /// The net number of removed variables is the difference between the
8147 /// number of removed variables and the number of removed variables
8148 /// that have been filtered out.
8149 ///
8150 /// @return the net number of removed variables.
8151 size_t
net_num_vars_removed() const8152 corpus_diff::diff_stats::net_num_vars_removed() const
8153 {
8154   ABG_ASSERT(num_vars_removed() >= num_removed_vars_filtered_out());
8155   return num_vars_removed() - num_removed_vars_filtered_out();
8156 }
8157 
8158 /// Getter for the number of variables added.
8159 ///
8160 /// @return the number of variables added.
8161 size_t
num_vars_added() const8162 corpus_diff::diff_stats::num_vars_added() const
8163 {return priv_->num_vars_added;}
8164 
8165 /// Setter for the number of variables added.
8166 ///
8167 /// @param n the new number of variables added.
8168 void
num_vars_added(size_t n)8169 corpus_diff::diff_stats::num_vars_added(size_t n)
8170 {priv_->num_vars_added = n;}
8171 
8172 /// Getter for the number of added variables that have been filtered
8173 /// out.
8174 ///
8175 /// @return the number of added variables that have been filtered out.
8176 size_t
num_added_vars_filtered_out() const8177 corpus_diff::diff_stats::num_added_vars_filtered_out() const
8178 {
8179   if (priv_->ctxt() && !priv_->ctxt()->show_added_vars())
8180     return num_vars_added();
8181   return priv_->num_added_vars_filtered_out;
8182 }
8183 
8184 /// Setter for the number of added variables that have been filtered
8185 /// out.
8186 ///
8187 /// @param n the new value.
8188 void
num_added_vars_filtered_out(size_t n)8189 corpus_diff::diff_stats::num_added_vars_filtered_out(size_t n)
8190 {priv_->num_added_vars_filtered_out = n;}
8191 
8192 /// Getter for the net number of added variables.
8193 ///
8194 /// The net number of added variables is the difference between the
8195 /// number of added variables and the number of added variables that
8196 /// have been filetered out.
8197 ///
8198 /// @return the net number of added variables.
8199 size_t
net_num_vars_added() const8200 corpus_diff::diff_stats::net_num_vars_added() const
8201 {
8202   ABG_ASSERT(num_vars_added() >= num_added_vars_filtered_out());
8203   return num_vars_added() - num_added_vars_filtered_out();
8204 }
8205 
8206 /// Getter for the number of variables that have a change in one of
8207 /// their sub-types.
8208 ///
8209 /// @return the number of variables that have a change in one of their
8210 /// sub-types.
8211 size_t
num_vars_changed() const8212 corpus_diff::diff_stats::num_vars_changed() const
8213 {return priv_->num_vars_changed;}
8214 
8215 /// Setter for the number of variables that have a change in one of
8216 /// their sub-types.
8217 ///
8218 /// @param n the new number of variables that have a change in one of
8219 /// their sub-types.
8220 void
num_vars_changed(size_t n)8221 corpus_diff::diff_stats::num_vars_changed(size_t n)
8222 {priv_->num_vars_changed = n;}
8223 
8224 /// Getter for the number of variables that have a change in one of
8225 /// their sub-types, and that have been filtered out.
8226 ///
8227 /// @return the number of functions that have a change in one of their
8228 /// sub-types, and that have been filtered out.
8229 size_t
num_changed_vars_filtered_out() const8230 corpus_diff::diff_stats::num_changed_vars_filtered_out() const
8231 {return priv_->num_changed_vars_filtered_out;}
8232 
8233 /// Setter for the number of variables that have a change in one of
8234 /// their sub-types, and that have been filtered out.
8235 ///
8236 /// @param n the new number of variables that have a change in one of their
8237 /// sub-types, and that have been filtered out.
8238 void
num_changed_vars_filtered_out(size_t n)8239 corpus_diff::diff_stats::num_changed_vars_filtered_out(size_t n)
8240 {priv_->num_changed_vars_filtered_out = n;}
8241 
8242 /// Getter for the number of variables that have a change in their
8243 /// sub-types, minus the number of these variables that got filtered
8244 /// out from the diff.
8245 ///
8246 /// @return for the the number of variables that have a change in
8247 /// their sub-types, minus the number of these variables that got
8248 /// filtered out from the diff.
8249 size_t
net_num_vars_changed() const8250 corpus_diff::diff_stats::net_num_vars_changed() const
8251 {return num_vars_changed() - num_changed_vars_filtered_out();}
8252 
8253 /// Getter for the number of function symbols (not referenced by any
8254 /// debug info) that got removed.
8255 ///
8256 /// @return the number of function symbols (not referenced by any
8257 /// debug info) that got removed.
8258 size_t
num_func_syms_removed() const8259 corpus_diff::diff_stats::num_func_syms_removed() const
8260 {return priv_->num_func_syms_removed;}
8261 
8262 /// Setter for the number of function symbols (not referenced by any
8263 /// debug info) that got removed.
8264 ///
8265 /// @param n the number of function symbols (not referenced by any
8266 /// debug info) that got removed.
8267 void
num_func_syms_removed(size_t n)8268 corpus_diff::diff_stats::num_func_syms_removed(size_t n)
8269 {priv_->num_func_syms_removed = n;}
8270 
8271 /// Getter for the number of removed function symbols, not referenced
8272 /// by debug info, that have been filtered out.
8273 ///
8274 /// @return the number of removed function symbols, not referenced by
8275 /// debug info, that have been filtered out.
8276 size_t
num_removed_func_syms_filtered_out() const8277 corpus_diff::diff_stats::num_removed_func_syms_filtered_out() const
8278 {
8279   if (priv_->ctxt()
8280       && !priv_->ctxt()->show_symbols_unreferenced_by_debug_info())
8281     return num_func_syms_removed();
8282   return priv_->num_removed_func_syms_filtered_out;
8283 }
8284 
8285 /// Setter for the number of removed function symbols, not referenced
8286 /// by debug info, that have been filtered out.
8287 ///
8288 /// @param n the new the number of removed function symbols, not
8289 /// referenced by debug info, that have been filtered out.
8290 void
num_removed_func_syms_filtered_out(size_t n)8291 corpus_diff::diff_stats::num_removed_func_syms_filtered_out(size_t n)
8292 {priv_->num_removed_func_syms_filtered_out = n;}
8293 
8294 /// Getter of the net number of removed function symbols that are not
8295 /// referenced by any debug info.
8296 ///
8297 /// This is the difference between the total number of removed
8298 /// function symbols and the number of removed function symbols that
8299 /// have been filteted out.  Both numbers are for symbols not
8300 /// referenced by debug info.
8301 ///
8302 /// return the net number of removed function symbols that are not
8303 /// referenced by any debug info.
8304 size_t
net_num_removed_func_syms() const8305 corpus_diff::diff_stats::net_num_removed_func_syms() const
8306 {
8307   ABG_ASSERT(num_func_syms_removed() >= num_removed_func_syms_filtered_out());
8308   return num_func_syms_removed() - num_removed_func_syms_filtered_out();
8309 }
8310 
8311 /// Getter for the number of function symbols (not referenced by any
8312 /// debug info) that got added.
8313 ///
8314 /// @return the number of function symbols (not referenced by any
8315 /// debug info) that got added.
8316 size_t
num_func_syms_added() const8317 corpus_diff::diff_stats::num_func_syms_added() const
8318 {return priv_->num_func_syms_added;}
8319 
8320 /// Setter for the number of function symbols (not referenced by any
8321 /// debug info) that got added.
8322 ///
8323 /// @param n the new number of function symbols (not referenced by any
8324 /// debug info) that got added.
8325 void
num_func_syms_added(size_t n)8326 corpus_diff::diff_stats::num_func_syms_added(size_t n)
8327 {priv_->num_func_syms_added = n;}
8328 
8329 /// Getter for the number of added function symbols, not referenced by
8330 /// any debug info, that have been filtered out.
8331 ///
8332 /// @return the number of added function symbols, not referenced by
8333 /// any debug info, that have been filtered out.
8334 size_t
num_added_func_syms_filtered_out() const8335 corpus_diff::diff_stats::num_added_func_syms_filtered_out() const
8336 {
8337   if (priv_->ctxt()
8338       && !(priv_->ctxt()->show_added_symbols_unreferenced_by_debug_info()
8339 	   && priv_->ctxt()->show_symbols_unreferenced_by_debug_info()))
8340     return num_func_syms_added();
8341   return priv_->num_added_func_syms_filtered_out;
8342 }
8343 
8344 /// Setter for the number of added function symbols, not referenced by
8345 /// any debug info, that have been filtered out.
8346 ///
8347 /// @param n the new number of added function symbols, not referenced
8348 /// by any debug info, that have been filtered out.
8349 void
num_added_func_syms_filtered_out(size_t n)8350 corpus_diff::diff_stats::num_added_func_syms_filtered_out(size_t n)
8351 {priv_->num_added_func_syms_filtered_out = n;}
8352 
8353 /// Getter of the net number of added function symbols that are not
8354 /// referenced by any debug info.
8355 ///
8356 /// This is the difference between the total number of added
8357 /// function symbols and the number of added function symbols that
8358 /// have been filteted out.  Both numbers are for symbols not
8359 /// referenced by debug info.
8360 ///
8361 /// return the net number of added function symbols that are not
8362 /// referenced by any debug info.
8363 size_t
net_num_added_func_syms() const8364 corpus_diff::diff_stats::net_num_added_func_syms() const
8365 {
8366   ABG_ASSERT(num_func_syms_added() >= num_added_func_syms_filtered_out());
8367   return num_func_syms_added()- num_added_func_syms_filtered_out();
8368 }
8369 
8370 /// Getter for the number of variable symbols (not referenced by any
8371 /// debug info) that got removed.
8372 ///
8373 /// @return the number of variable symbols (not referenced by any
8374 /// debug info) that got removed.
8375 size_t
num_var_syms_removed() const8376 corpus_diff::diff_stats::num_var_syms_removed() const
8377 {return priv_->num_var_syms_removed;}
8378 
8379 /// Setter for the number of variable symbols (not referenced by any
8380 /// debug info) that got removed.
8381 ///
8382 /// @param n the number of variable symbols (not referenced by any
8383 /// debug info) that got removed.
8384 void
num_var_syms_removed(size_t n)8385 corpus_diff::diff_stats::num_var_syms_removed(size_t n)
8386 {priv_->num_var_syms_removed = n;}
8387 
8388 /// Getter for the number of removed variable symbols, not referenced
8389 /// by any debug info, that have been filtered out.
8390 ///
8391 /// @return the number of removed variable symbols, not referenced
8392 /// by any debug info, that have been filtered out.
8393 size_t
num_removed_var_syms_filtered_out() const8394 corpus_diff::diff_stats::num_removed_var_syms_filtered_out() const
8395 {
8396   if (priv_->ctxt()
8397       && !priv_->ctxt()->show_symbols_unreferenced_by_debug_info())
8398     return num_var_syms_removed();
8399   return priv_->num_removed_var_syms_filtered_out;
8400 }
8401 
8402 /// Setter for the number of removed variable symbols, not referenced
8403 /// by any debug info, that have been filtered out.
8404 ///
8405 /// @param n the number of removed variable symbols, not referenced by
8406 /// any debug info, that have been filtered out.
8407 void
num_removed_var_syms_filtered_out(size_t n)8408 corpus_diff::diff_stats::num_removed_var_syms_filtered_out(size_t n)
8409 {priv_->num_removed_var_syms_filtered_out = n;}
8410 
8411 /// Getter of the net number of removed variable symbols that are not
8412 /// referenced by any debug info.
8413 ///
8414 /// This is the difference between the total number of removed
8415 /// variable symbols and the number of removed variable symbols that
8416 /// have been filteted out.  Both numbers are for symbols not
8417 /// referenced by debug info.
8418 ///
8419 /// return the net number of removed variable symbols that are not
8420 /// referenced by any debug info.
8421 size_t
net_num_removed_var_syms() const8422 corpus_diff::diff_stats::net_num_removed_var_syms() const
8423 {
8424   ABG_ASSERT(num_var_syms_removed() >= num_removed_var_syms_filtered_out());
8425   return num_var_syms_removed() - num_removed_var_syms_filtered_out();
8426 }
8427 
8428 /// Getter for the number of variable symbols (not referenced by any
8429 /// debug info) that got added.
8430 ///
8431 /// @return the number of variable symbols (not referenced by any
8432 /// debug info) that got added.
8433 size_t
num_var_syms_added() const8434 corpus_diff::diff_stats::num_var_syms_added() const
8435 {return priv_->num_var_syms_added;}
8436 
8437 /// Setter for the number of variable symbols (not referenced by any
8438 /// debug info) that got added.
8439 ///
8440 /// @param n the new number of variable symbols (not referenced by any
8441 /// debug info) that got added.
8442 void
num_var_syms_added(size_t n)8443 corpus_diff::diff_stats::num_var_syms_added(size_t n)
8444 {priv_->num_var_syms_added = n;}
8445 
8446 /// Getter for the number of added variable symbols, not referenced by
8447 /// any debug info, that have been filtered out.
8448 ///
8449 /// @return the number of added variable symbols, not referenced by
8450 /// any debug info, that have been filtered out.
8451 size_t
num_added_var_syms_filtered_out() const8452 corpus_diff::diff_stats::num_added_var_syms_filtered_out() const
8453 {
8454   if (priv_->ctxt()
8455       && !(priv_->ctxt()->show_added_symbols_unreferenced_by_debug_info()
8456 	   && priv_->ctxt()->show_symbols_unreferenced_by_debug_info()))
8457     return num_var_syms_added();
8458   return priv_->num_added_var_syms_filtered_out;
8459 }
8460 
8461 /// Setter for the number of added variable symbols, not referenced by
8462 /// any debug info, that have been filtered out.
8463 ///
8464 /// @param n the new number of added variable symbols, not referenced
8465 /// by any debug info, that have been filtered out.
8466 void
num_added_var_syms_filtered_out(size_t n)8467 corpus_diff::diff_stats::num_added_var_syms_filtered_out(size_t n)
8468 {priv_->num_added_var_syms_filtered_out = n;}
8469 
8470 /// Getter of the net number of added variable symbols that are not
8471 /// referenced by any debug info.
8472 ///
8473 /// This is the difference between the total number of added
8474 /// variable symbols and the number of added variable symbols that
8475 /// have been filteted out.  Both numbers are for symbols not
8476 /// referenced by debug info.
8477 ///
8478 /// return the net number of added variable symbols that are not
8479 /// referenced by any debug info.
8480 size_t
net_num_added_var_syms() const8481 corpus_diff::diff_stats::net_num_added_var_syms() const
8482 {
8483   ABG_ASSERT(num_var_syms_added() >= num_added_var_syms_filtered_out());
8484   return num_var_syms_added() - num_added_var_syms_filtered_out();
8485 }
8486 
8487 /// Getter of the number of leaf type change diff nodes.
8488 ///
8489 /// @return the number of leaf type change diff nodes.
8490 size_t
num_leaf_changes() const8491 corpus_diff::diff_stats::num_leaf_changes() const
8492 {return priv_->num_leaf_changes;}
8493 
8494 /// Setter of the number of leaf type change diff nodes.
8495 ///
8496 /// @param n the new number of leaf type change diff nodes.
8497 void
num_leaf_changes(size_t n)8498 corpus_diff::diff_stats::num_leaf_changes(size_t n)
8499 {priv_->num_leaf_changes = n;}
8500 
8501 /// Getter of the number of leaf type change diff nodes that have been
8502 /// filtered out.
8503 ///
8504 /// @return the number of leaf type change diff nodes that have been
8505 size_t
num_leaf_changes_filtered_out() const8506 corpus_diff::diff_stats::num_leaf_changes_filtered_out() const
8507 {return priv_->num_leaf_changes_filtered_out;}
8508 
8509 /// Setter of the number of leaf type change diff nodes that have been
8510 /// filtered out.
8511 ///
8512 /// @param n the new number of leaf type change diff nodes that have
8513 /// been filtered out.
8514 void
num_leaf_changes_filtered_out(size_t n)8515 corpus_diff::diff_stats::num_leaf_changes_filtered_out(size_t n)
8516 {priv_->num_leaf_changes_filtered_out = n;}
8517 
8518 /// Getter of the net number of leaf change diff nodes.
8519 ///
8520 /// This is the difference between the total number of leaf change
8521 /// diff nodes, and the number of the leaf change diff nodes that have
8522 /// been filtered out.
8523 ///
8524 /// A leaf change is either a type change, a function change or a
8525 /// variable change.
8526 size_t
net_num_leaf_changes() const8527 corpus_diff::diff_stats::net_num_leaf_changes() const
8528 {
8529   ABG_ASSERT(num_leaf_changes() >= num_leaf_changes_filtered_out());
8530   return num_leaf_changes() - num_leaf_changes_filtered_out();
8531 }
8532 
8533 /// Getter for the number of leaf type change diff nodes.
8534 ///
8535 /// @return the number of leaf type changes diff nodes.
8536 size_t
num_leaf_type_changes() const8537 corpus_diff::diff_stats::num_leaf_type_changes() const
8538 {return priv_->num_leaf_type_changes;}
8539 
8540 /// Setter for the number of leaf type change diff nodes.
8541 ///
8542 /// @param n the new number of leaf type change diff nodes.
8543 void
num_leaf_type_changes(size_t n)8544 corpus_diff::diff_stats::num_leaf_type_changes(size_t n)
8545 {priv_->num_leaf_type_changes = n;}
8546 
8547 /// Getter for the number of filtered out leaf type change diff nodes.
8548 ///
8549 /// @return the number of filtered out leaf type change diff nodes.
8550 size_t
num_leaf_type_changes_filtered_out() const8551 corpus_diff::diff_stats::num_leaf_type_changes_filtered_out() const
8552 {return priv_->num_leaf_type_changes_filtered_out;}
8553 
8554 /// Setter for the number of filtered out leaf type change diff nodes.
8555 /// @param n the new number of filtered out leaf type change diff nodes.
8556 void
num_leaf_type_changes_filtered_out(size_t n)8557 corpus_diff::diff_stats::num_leaf_type_changes_filtered_out(size_t n)
8558 {priv_->num_leaf_type_changes_filtered_out = n;}
8559 
8560 /// Getter for the net number of leaf type change diff nodes.
8561 ///
8562 /// This is the difference between the number of leaf type changes and
8563 /// the number of filtered out leaf type changes.
8564 ///
8565 /// @return the net number of leaf type change diff nodes.
8566 size_t
net_num_leaf_type_changes() const8567 corpus_diff::diff_stats::net_num_leaf_type_changes() const
8568 {return num_leaf_type_changes() - num_leaf_type_changes_filtered_out();}
8569 
8570 /// Getter for the number of leaf function change diff nodes.
8571 ///
8572 /// @return the number of leaf function change diff nodes.
8573 size_t
num_leaf_func_changes() const8574 corpus_diff::diff_stats::num_leaf_func_changes() const
8575 {return priv_->num_leaf_func_changes;}
8576 
8577 /// Setter for the number of leaf function change diff nodes.
8578 ///
8579 /// @param n the new number of leaf function change diff nodes.
8580 void
num_leaf_func_changes(size_t n)8581 corpus_diff::diff_stats::num_leaf_func_changes(size_t n)
8582 {priv_->num_leaf_func_changes = n;}
8583 
8584 /// Getter for the number of leaf function change diff nodes that were
8585 /// filtered out.
8586 ///
8587 /// @return the number of leaf function change diff nodes that were
8588 /// filtered out.
8589 size_t
num_leaf_func_changes_filtered_out() const8590 corpus_diff::diff_stats::num_leaf_func_changes_filtered_out() const
8591 {return priv_->num_leaf_func_changes_filtered_out;}
8592 
8593 /// Setter for the number of leaf function change diff nodes that were
8594 /// filtered out.
8595 ///
8596 /// @param n the new number of leaf function change diff nodes that
8597 /// were filtered out.
8598 void
num_leaf_func_changes_filtered_out(size_t n)8599 corpus_diff::diff_stats::num_leaf_func_changes_filtered_out(size_t n)
8600 {priv_->num_leaf_func_changes_filtered_out = n;}
8601 
8602 /// Getter for the net number of leaf function change diff nodes.
8603 ///
8604 /// This is the difference between the number of leaf function change
8605 /// diff nodes and the number of filtered out leaf function change
8606 /// diff nodes.
8607 ///
8608 /// @return the net number of leaf function change diff nodes.
8609 size_t
net_num_leaf_func_changes() const8610 corpus_diff::diff_stats::net_num_leaf_func_changes() const
8611 {return num_leaf_func_changes() - num_leaf_func_changes_filtered_out();}
8612 
8613 /// Getter for the number of leaf variable change diff nodes.
8614 ///
8615 /// @return the number of leaf variable change diff nodes.
8616 size_t
num_leaf_var_changes() const8617 corpus_diff::diff_stats::num_leaf_var_changes() const
8618 {return priv_->num_leaf_var_changes;}
8619 
8620 /// Setter for the number of leaf variable change diff nodes.
8621 ///
8622 /// @param n the number of leaf variable change diff nodes.
8623 void
num_leaf_var_changes(size_t n)8624 corpus_diff::diff_stats::num_leaf_var_changes(size_t n)
8625 {priv_->num_leaf_var_changes = n;}
8626 
8627 /// Getter of the number of added types that are unreachable from the
8628 /// public interface of the ABI corpus.
8629 ///
8630 /// Public interface means the set of defined and publicly exported
8631 /// functions and variables of the ABI corpus.
8632 ///
8633 /// @return the number of added types that are unreachable from the
8634 /// public interface of the ABI corpus.
8635 size_t
num_added_unreachable_types() const8636 corpus_diff::diff_stats::num_added_unreachable_types() const
8637 {return priv_->num_added_unreachable_types;}
8638 
8639 /// Setter of the number of added types that are unreachable from the
8640 /// public interface (global functions or variables) of the ABI
8641 /// corpus.
8642 ///
8643 /// Public interface means the set of defined and publicly exported
8644 /// functions and variables of the ABI corpus.
8645 ///
8646 /// @param n the new number of added types that are unreachable from
8647 /// the public interface of the ABI corpus.
8648 void
num_added_unreachable_types(size_t n)8649 corpus_diff::diff_stats::num_added_unreachable_types(size_t n)
8650 {priv_->num_added_unreachable_types = n;}
8651 
8652 /// Getter of the number of added types that are unreachable from
8653 /// public interfaces and that are filtered out by suppression
8654 /// specifications.
8655 ///
8656 /// @return the number of added types that are unreachable from public
8657 /// interfaces and that are filtered out by suppression
8658 /// specifications.
8659 size_t
num_added_unreachable_types_filtered_out() const8660 corpus_diff::diff_stats::num_added_unreachable_types_filtered_out() const
8661 {return priv_->num_added_unreachable_types_filtered_out;}
8662 
8663 /// Setter of the number of added types that are unreachable from
8664 /// public interfaces and that are filtered out by suppression
8665 /// specifications.
8666 ///
8667 /// @param n the new number of added types that are unreachable from
8668 /// public interfaces and that are filtered out by suppression
8669 /// specifications.
8670 void
num_added_unreachable_types_filtered_out(size_t n)8671 corpus_diff::diff_stats::num_added_unreachable_types_filtered_out(size_t n)
8672 {priv_->num_added_unreachable_types_filtered_out = n;}
8673 
8674 /// Getter of the number of added types that are unreachable from
8675 /// public interfaces and that are *NOT* filtered out by suppression
8676 /// specifications.
8677 ///
8678 /// @return the number of added types that are unreachable from public
8679 /// interfaces and that are *NOT* filtered out by suppression
8680 /// specifications.
8681 size_t
net_num_added_unreachable_types() const8682 corpus_diff::diff_stats::net_num_added_unreachable_types() const
8683 {
8684   ABG_ASSERT(num_added_unreachable_types()
8685 	     >=
8686 	     num_added_unreachable_types_filtered_out());
8687 
8688   return (num_added_unreachable_types()
8689 	  -
8690 	  num_added_unreachable_types_filtered_out());
8691 }
8692 
8693 /// Getter of the number of removed types that are unreachable from
8694 /// the public interface of the ABI corpus.
8695 ///
8696 /// Public interface means the set of defined and publicly exported
8697 /// functions and variables of the ABI corpus.
8698 ///
8699 /// @return the number of removed types that are unreachable from
8700 /// the public interface of the ABI corpus.
8701 size_t
num_removed_unreachable_types() const8702 corpus_diff::diff_stats::num_removed_unreachable_types() const
8703 {return priv_->num_removed_unreachable_types;}
8704 
8705 /// Setter of the number of removed types that are unreachable from
8706 /// the public interface of the ABI corpus.
8707 ///
8708 /// Public interface means the set of defined and publicly exported
8709 /// functions and variables of the ABI corpus.
8710 ///
8711 ///@param n the new number of removed types that are unreachable from
8712 /// the public interface of the ABI corpus.
8713 void
num_removed_unreachable_types(size_t n)8714 corpus_diff::diff_stats::num_removed_unreachable_types(size_t n)
8715 {priv_->num_removed_unreachable_types = n;}
8716 
8717 /// Getter of the number of removed types that are not reachable from
8718 /// public interfaces and that have been filtered out by suppression
8719 /// specifications.
8720 ///
8721 /// @return the number of removed types that are not reachable from
8722 /// public interfaces and that have been filtered out by suppression
8723 /// specifications.
8724 size_t
num_removed_unreachable_types_filtered_out() const8725 corpus_diff::diff_stats::num_removed_unreachable_types_filtered_out() const
8726 {return priv_->num_removed_unreachable_types_filtered_out;}
8727 
8728 /// Setter of the number of removed types that are not reachable from
8729 /// public interfaces and that have been filtered out by suppression
8730 /// specifications.
8731 ///
8732 /// @param n the new number of removed types that are not reachable
8733 /// from public interfaces and that have been filtered out by
8734 /// suppression specifications.
8735 void
num_removed_unreachable_types_filtered_out(size_t n)8736 corpus_diff::diff_stats::num_removed_unreachable_types_filtered_out(size_t n)
8737 {priv_->num_removed_unreachable_types_filtered_out = n;}
8738 
8739 /// Getter of the number of removed types that are not reachable from
8740 /// public interfaces and that have *NOT* been filtered out by
8741 /// suppression specifications.
8742 ///
8743 /// @return the number of removed types that are not reachable from
8744 /// public interfaces and that have *NOT* been filtered out by
8745 /// suppression specifications.
8746 size_t
net_num_removed_unreachable_types() const8747 corpus_diff::diff_stats::net_num_removed_unreachable_types() const
8748 {
8749   ABG_ASSERT(num_removed_unreachable_types()
8750 	     >=
8751 	     num_removed_unreachable_types_filtered_out());
8752 
8753   return (num_removed_unreachable_types()
8754 	  -
8755 	  num_removed_unreachable_types_filtered_out());
8756 }
8757 
8758 /// Getter of the number of changed types that are unreachable from
8759 /// the public interface of the ABI corpus.
8760 ///
8761 /// Public interface means the set of defined and publicly exported
8762 /// functions and variables of the ABI corpus.
8763 ///
8764 /// @return the number of changed types that are unreachable from the
8765 /// public interface of the ABI corpus.
8766 size_t
num_changed_unreachable_types() const8767 corpus_diff::diff_stats::num_changed_unreachable_types() const
8768 {return priv_->num_changed_unreachable_types;}
8769 
8770 /// Setter of the number of changed types that are unreachable from
8771 /// the public interface of the ABI corpus.
8772 ///
8773 /// Public interface means the set of defined and publicly exported
8774 /// functions and variables of the ABI corpus.
8775 ///
8776 ///@param n the new number of changed types that are unreachable from
8777 /// the public interface of the ABI corpus.
8778 void
num_changed_unreachable_types(size_t n)8779 corpus_diff::diff_stats::num_changed_unreachable_types(size_t n)
8780 {priv_->num_changed_unreachable_types = n;}
8781 
8782 /// Getter of the number of changed types that are unreachable from
8783 /// public interfaces and that have been filtered out by suppression
8784 /// specifications.
8785 ///
8786 /// @return the number of changed types that are unreachable from
8787 /// public interfaces and that have been filtered out by suppression
8788 /// specifications.
8789 size_t
num_changed_unreachable_types_filtered_out() const8790 corpus_diff::diff_stats::num_changed_unreachable_types_filtered_out() const
8791 {return priv_->num_changed_unreachable_types_filtered_out;}
8792 
8793 /// Setter of the number of changed types that are unreachable from
8794 /// public interfaces and that have been filtered out by suppression
8795 /// specifications.
8796 ///
8797 /// @param n the new number of changed types that are unreachable from
8798 /// public interfaces and that have been filtered out by suppression
8799 /// specifications.
8800 void
num_changed_unreachable_types_filtered_out(size_t n)8801 corpus_diff::diff_stats::num_changed_unreachable_types_filtered_out(size_t n)
8802 {priv_->num_changed_unreachable_types_filtered_out = n;}
8803 
8804 /// Getter of the number of changed types that are unreachable from
8805 /// public interfaces and that have *NOT* been filtered out by
8806 /// suppression specifications.
8807 ///
8808 /// @return the number of changed types that are unreachable from
8809 /// public interfaces and that have *NOT* been filtered out by
8810 /// suppression specifications.
8811 size_t
net_num_changed_unreachable_types() const8812 corpus_diff::diff_stats::net_num_changed_unreachable_types() const
8813 {
8814   ABG_ASSERT(num_changed_unreachable_types()
8815 	     >=
8816 	     num_changed_unreachable_types_filtered_out());
8817 
8818   return (num_changed_unreachable_types()
8819 	  -
8820 	  num_changed_unreachable_types_filtered_out());
8821 }
8822 
8823 /// Getter for the number of leaf variable changes diff nodes that
8824 /// have been filtered out.
8825 ///
8826 /// @return the number of leaf variable changes diff nodes that have
8827 /// been filtered out.
8828 size_t
num_leaf_var_changes_filtered_out() const8829 corpus_diff::diff_stats::num_leaf_var_changes_filtered_out() const
8830 {return priv_->num_leaf_var_changes_filtered_out;}
8831 
8832 /// Setter for the number of leaf variable changes diff nodes that
8833 /// have been filtered out.
8834 ///
8835 /// @param n the number of leaf variable changes diff nodes that have
8836 /// been filtered out.
8837 void
num_leaf_var_changes_filtered_out(size_t n)8838 corpus_diff::diff_stats::num_leaf_var_changes_filtered_out(size_t n)
8839 {priv_->num_leaf_var_changes_filtered_out = n;}
8840 
8841 /// Getter for the net number of leaf variable change diff nodes.
8842 ///
8843 /// This the difference between the number of leaf variable change
8844 /// diff nodes and the number of filtered out leaf variable change
8845 /// diff nodes.
8846 ///
8847 /// @return the net number of leaf variable change diff nodes.
8848 size_t
net_num_leaf_var_changes() const8849 corpus_diff::diff_stats::net_num_leaf_var_changes() const
8850 {return num_leaf_var_changes() - num_leaf_var_changes_filtered_out();}
8851 
8852 
8853 // <corpus_diff stuff>
8854 
8855 /// Getter of the context associated with this corpus.
8856 ///
8857 /// @return a smart pointer to the context associate with the corpus.
8858 diff_context_sptr
get_context()8859 corpus_diff::priv::get_context()
8860 {return ctxt_.lock();}
8861 
8862 /// Tests if the lookup tables are empty.
8863 ///
8864 /// @return true if the lookup tables are empty, false otherwise.
8865 bool
lookup_tables_empty() const8866 corpus_diff::priv::lookup_tables_empty() const
8867 {
8868   return (deleted_fns_.empty()
8869 	  && added_fns_.empty()
8870 	  && changed_fns_map_.empty()
8871 	  && deleted_vars_.empty()
8872 	  && added_vars_.empty()
8873 	  && changed_vars_map_.empty());
8874 }
8875 
8876 /// Clear the lookup tables useful for reporting an enum_diff.
8877 void
clear_lookup_tables()8878 corpus_diff::priv::clear_lookup_tables()
8879 {
8880   deleted_fns_.clear();
8881   added_fns_.clear();
8882   changed_fns_map_.clear();
8883   deleted_vars_.clear();
8884   added_vars_.clear();
8885   changed_vars_map_.clear();
8886 }
8887 
8888 /// If the lookup tables are not yet built, walk the differences and
8889 /// fill the lookup tables.
8890 void
ensure_lookup_tables_populated()8891 corpus_diff::priv::ensure_lookup_tables_populated()
8892 {
8893   if (!lookup_tables_empty())
8894     return;
8895 
8896   diff_context_sptr ctxt = get_context();
8897 
8898   {
8899     edit_script& e = fns_edit_script_;
8900 
8901     for (vector<deletion>::const_iterator it = e.deletions().begin();
8902 	 it != e.deletions().end();
8903 	 ++it)
8904       {
8905 	unsigned i = it->index();
8906 	ABG_ASSERT(i < first_->get_functions().size());
8907 
8908 	function_decl* deleted_fn = first_->get_functions()[i];
8909 	string n = deleted_fn->get_id();
8910 	ABG_ASSERT(!n.empty());
8911 	// The below is commented out because there can be several
8912 	// functions with the same ID in the corpus.  So several
8913 	// functions with the same ID can be deleted.
8914 	// ABG_ASSERT(deleted_fns_.find(n) == deleted_fns_.end());
8915 	deleted_fns_[n] = deleted_fn;
8916       }
8917 
8918     for (vector<insertion>::const_iterator it = e.insertions().begin();
8919 	 it != e.insertions().end();
8920 	 ++it)
8921       {
8922 	for (vector<unsigned>::const_iterator iit =
8923 	       it->inserted_indexes().begin();
8924 	     iit != it->inserted_indexes().end();
8925 	     ++iit)
8926 	  {
8927 	    unsigned i = *iit;
8928 	    function_decl* added_fn = second_->get_functions()[i];
8929 	    string n = added_fn->get_id();
8930 	    ABG_ASSERT(!n.empty());
8931 	    // The below is commented out because there can be several
8932 	    // functions with the same ID in the corpus.  So several
8933 	    // functions with the same ID can be added.
8934 	    // ABG_ASSERT(added_fns_.find(n) == added_fns_.end());
8935 	    string_function_ptr_map::const_iterator j =
8936 	      deleted_fns_.find(n);
8937 	    if (j != deleted_fns_.end())
8938 	      {
8939 		function_decl_sptr f(j->second, noop_deleter());
8940 		function_decl_sptr s(added_fn, noop_deleter());
8941 		function_decl_diff_sptr d = compute_diff(f, s, ctxt);
8942 		if (*j->second != *added_fn)
8943 		  changed_fns_map_[j->first] = d;
8944 		deleted_fns_.erase(j);
8945 	      }
8946 	    else
8947 	      added_fns_[n] = added_fn;
8948 	  }
8949       }
8950     sort_string_function_decl_diff_sptr_map(changed_fns_map_, changed_fns_);
8951 
8952     // Now walk the allegedly deleted functions; check if their
8953     // underlying symbols are deleted as well; otherwise, consider
8954     // that the function in question hasn't been deleted.
8955 
8956     vector<string> to_delete;
8957     for (string_function_ptr_map::const_iterator i = deleted_fns_.begin();
8958 	 i != deleted_fns_.end();
8959 	 ++i)
8960       if (second_->lookup_function_symbol(*i->second->get_symbol()))
8961 	to_delete.push_back(i->first);
8962 
8963     for (vector<string>::const_iterator i = to_delete.begin();
8964 	 i != to_delete.end();
8965 	 ++i)
8966       deleted_fns_.erase(*i);
8967 
8968     // Do something similar for added functions.
8969 
8970     to_delete.clear();
8971     for (string_function_ptr_map::const_iterator i = added_fns_.begin();
8972 	 i != added_fns_.end();
8973 	 ++i)
8974       {
8975 	if (first_->lookup_function_symbol(*i->second->get_symbol()))
8976 	  to_delete.push_back(i->first);
8977 	else if (! i->second->get_symbol()->get_version().is_empty()
8978 		 && i->second->get_symbol()->get_version().is_default())
8979 	  // We are looking for a symbol that has a default version,
8980 	  // and which seems to be newly added.  Let's see if the same
8981 	  // symbol with *no* version was already present in the
8982 	  // former corpus.  If yes, then the symbol shouldn't be
8983 	  // considered as 'added'.
8984 	  {
8985 	    elf_symbol::version empty_version;
8986 	    if (first_->lookup_function_symbol(i->second->get_symbol()->get_name(),
8987 					       empty_version))
8988 	      to_delete.push_back(i->first);
8989 	  }
8990       }
8991 
8992     for (vector<string>::const_iterator i = to_delete.begin();
8993 	 i != to_delete.end();
8994 	 ++i)
8995       added_fns_.erase(*i);
8996   }
8997 
8998   {
8999     edit_script& e = vars_edit_script_;
9000 
9001     for (vector<deletion>::const_iterator it = e.deletions().begin();
9002 	 it != e.deletions().end();
9003 	 ++it)
9004       {
9005 	unsigned i = it->index();
9006 	ABG_ASSERT(i < first_->get_variables().size());
9007 
9008 	var_decl* deleted_var = first_->get_variables()[i];
9009 	string n = deleted_var->get_id();
9010 	ABG_ASSERT(!n.empty());
9011 	ABG_ASSERT(deleted_vars_.find(n) == deleted_vars_.end());
9012 	deleted_vars_[n] = deleted_var;
9013       }
9014 
9015     for (vector<insertion>::const_iterator it = e.insertions().begin();
9016 	 it != e.insertions().end();
9017 	 ++it)
9018       {
9019 	for (vector<unsigned>::const_iterator iit =
9020 	       it->inserted_indexes().begin();
9021 	     iit != it->inserted_indexes().end();
9022 	     ++iit)
9023 	  {
9024 	    unsigned i = *iit;
9025 	    var_decl* added_var = second_->get_variables()[i];
9026 	    string n = added_var->get_id();
9027 	    ABG_ASSERT(!n.empty());
9028 	    {
9029 	      string_var_ptr_map::const_iterator k = added_vars_.find(n);
9030 	      if ( k != added_vars_.end())
9031 		{
9032 		  ABG_ASSERT(is_member_decl(k->second)
9033 			 && get_member_is_static(k->second));
9034 		  continue;
9035 		}
9036 	    }
9037 	    string_var_ptr_map::const_iterator j =
9038 	      deleted_vars_.find(n);
9039 	    if (j != deleted_vars_.end())
9040 	      {
9041 		if (*j->second != *added_var)
9042 		  {
9043 		    var_decl_sptr f(j->second, noop_deleter());
9044 		    var_decl_sptr s(added_var, noop_deleter());
9045 		    changed_vars_map_[n] = compute_diff(f, s, ctxt);
9046 		  }
9047 		deleted_vars_.erase(j);
9048 	      }
9049 	    else
9050 	      added_vars_[n] = added_var;
9051 	  }
9052       }
9053     sort_string_var_diff_sptr_map(changed_vars_map_,
9054 				  sorted_changed_vars_);
9055 
9056     // Now walk the allegedly deleted variables; check if their
9057     // underlying symbols are deleted as well; otherwise consider
9058     // that the variable in question hasn't been deleted.
9059 
9060     vector<string> to_delete;
9061     for (string_var_ptr_map::const_iterator i = deleted_vars_.begin();
9062 	 i != deleted_vars_.end();
9063 	 ++i)
9064       if (second_->lookup_variable_symbol(*i->second->get_symbol()))
9065 	to_delete.push_back(i->first);
9066 
9067     for (vector<string>::const_iterator i = to_delete.begin();
9068 	 i != to_delete.end();
9069 	 ++i)
9070       deleted_vars_.erase(*i);
9071 
9072     // Do something similar for added variables.
9073 
9074     to_delete.clear();
9075     for (string_var_ptr_map::const_iterator i = added_vars_.begin();
9076 	 i != added_vars_.end();
9077 	 ++i)
9078       if (first_->lookup_variable_symbol(*i->second->get_symbol()))
9079 	to_delete.push_back(i->first);
9080       else if (! i->second->get_symbol()->get_version().is_empty()
9081 		 && i->second->get_symbol()->get_version().is_default())
9082 	// We are looking for a symbol that has a default version,
9083 	// and which seems to be newly added.  Let's see if the same
9084 	// symbol with *no* version was already present in the
9085 	// former corpus.  If yes, then the symbol shouldn't be
9086 	// considered as 'added'.
9087 	{
9088 	  elf_symbol::version empty_version;
9089 	  if (first_->lookup_variable_symbol(i->second->get_symbol()->get_name(),
9090 					     empty_version))
9091 	    to_delete.push_back(i->first);
9092 	}
9093 
9094     for (vector<string>::const_iterator i = to_delete.begin();
9095 	 i != to_delete.end();
9096 	 ++i)
9097       added_vars_.erase(*i);
9098   }
9099 
9100   // Massage the edit script for added/removed function symbols that
9101   // were not referenced by any debug info and turn them into maps of
9102   // {symbol_name, symbol}.
9103   {
9104     edit_script& e = unrefed_fn_syms_edit_script_;
9105     for (vector<deletion>::const_iterator it = e.deletions().begin();
9106 	 it != e.deletions().end();
9107 	 ++it)
9108       {
9109 	unsigned i = it->index();
9110 	ABG_ASSERT(i < first_->get_unreferenced_function_symbols().size());
9111 	elf_symbol_sptr deleted_sym =
9112 	  first_->get_unreferenced_function_symbols()[i];
9113 	if (!second_->lookup_function_symbol(*deleted_sym))
9114 	  deleted_unrefed_fn_syms_[deleted_sym->get_id_string()] = deleted_sym;
9115       }
9116 
9117     for (vector<insertion>::const_iterator it = e.insertions().begin();
9118 	 it != e.insertions().end();
9119 	 ++it)
9120       {
9121 	for (vector<unsigned>::const_iterator iit =
9122 	       it->inserted_indexes().begin();
9123 	     iit != it->inserted_indexes().end();
9124 	     ++iit)
9125 	  {
9126 	    unsigned i = *iit;
9127 	    ABG_ASSERT(i < second_->get_unreferenced_function_symbols().size());
9128 	    elf_symbol_sptr added_sym =
9129 	      second_->get_unreferenced_function_symbols()[i];
9130 	    if ((deleted_unrefed_fn_syms_.find(added_sym->get_id_string())
9131 		 == deleted_unrefed_fn_syms_.end()))
9132 	      {
9133 		if (!first_->lookup_function_symbol(*added_sym))
9134 		  {
9135 		    bool do_add = true;
9136 		    if (! added_sym->get_version().is_empty()
9137 			&& added_sym->get_version().is_default())
9138 		      {
9139 			// So added_seem has a default version.  If
9140 			// the former corpus had a symbol with the
9141 			// same name as added_sym but with *no*
9142 			// version, then added_sym shouldn't be
9143 			// considered as a newly added symbol.
9144 			elf_symbol::version empty_version;
9145 			if (first_->lookup_function_symbol(added_sym->get_name(),
9146 							   empty_version))
9147 			  do_add = false;
9148 		      }
9149 
9150 		    if (do_add)
9151 		      added_unrefed_fn_syms_[added_sym->get_id_string()] =
9152 			added_sym;
9153 		  }
9154 	      }
9155 	    else
9156 	      deleted_unrefed_fn_syms_.erase(added_sym->get_id_string());
9157 	  }
9158       }
9159   }
9160 
9161   // Massage the edit script for added/removed variable symbols that
9162   // were not referenced by any debug info and turn them into maps of
9163   // {symbol_name, symbol}.
9164   {
9165     edit_script& e = unrefed_var_syms_edit_script_;
9166     for (vector<deletion>::const_iterator it = e.deletions().begin();
9167 	 it != e.deletions().end();
9168 	 ++it)
9169       {
9170 	unsigned i = it->index();
9171 	ABG_ASSERT(i < first_->get_unreferenced_variable_symbols().size());
9172 	elf_symbol_sptr deleted_sym =
9173 	  first_->get_unreferenced_variable_symbols()[i];
9174 	if (!second_->lookup_variable_symbol(*deleted_sym))
9175 	  deleted_unrefed_var_syms_[deleted_sym->get_id_string()] = deleted_sym;
9176       }
9177 
9178     for (vector<insertion>::const_iterator it = e.insertions().begin();
9179 	 it != e.insertions().end();
9180 	 ++it)
9181       {
9182 	for (vector<unsigned>::const_iterator iit =
9183 	       it->inserted_indexes().begin();
9184 	     iit != it->inserted_indexes().end();
9185 	     ++iit)
9186 	  {
9187 	    unsigned i = *iit;
9188 	    ABG_ASSERT(i < second_->get_unreferenced_variable_symbols().size());
9189 	    elf_symbol_sptr added_sym =
9190 	      second_->get_unreferenced_variable_symbols()[i];
9191 	    if (deleted_unrefed_var_syms_.find(added_sym->get_id_string())
9192 		== deleted_unrefed_var_syms_.end())
9193 	      {
9194 		if (!first_->lookup_variable_symbol(*added_sym))
9195 		  {
9196 		    bool do_add = true;
9197 		    if (! added_sym->get_version().is_empty()
9198 			&& added_sym->get_version().is_default())
9199 		      {
9200 			// So added_seem has a default version.  If
9201 			// the former corpus had a symbol with the
9202 			// same name as added_sym but with *no*
9203 			// version, then added_sym shouldn't be
9204 			// considered as a newly added symbol.
9205 			elf_symbol::version empty_version;
9206 			if (first_->lookup_variable_symbol(added_sym->get_name(),
9207 							   empty_version))
9208 			  do_add = false;
9209 		      }
9210 
9211 		    if (do_add)
9212 		      added_unrefed_var_syms_[added_sym->get_id_string()] =
9213 			added_sym;
9214 		  }
9215 	      }
9216 	    else
9217 	      deleted_unrefed_var_syms_.erase(added_sym->get_id_string());
9218 	  }
9219       }
9220   }
9221 
9222   // Handle the unreachable_types_edit_script_
9223   {
9224     edit_script& e = unreachable_types_edit_script_;
9225 
9226     // Populate the map of deleted unreachable types from the
9227     // deletions of the edit script.
9228     for (vector<deletion>::const_iterator it = e.deletions().begin();
9229 	 it != e.deletions().end();
9230 	 ++it)
9231       {
9232 	unsigned i = it->index();
9233 	type_base_sptr t
9234 	  (first_->get_types_not_reachable_from_public_interfaces()[i]);
9235 
9236 	if (!is_user_defined_type(t))
9237 	  continue;
9238 
9239 	string repr = abigail::ir::get_pretty_representation(t, true);
9240 	deleted_unreachable_types_[repr] = t;
9241       }
9242 
9243     // Populate the map of added and change unreachable types from the
9244     // insertions of the edit script.
9245     for (vector<insertion>::const_iterator it = e.insertions().begin();
9246 	 it != e.insertions().end();
9247 	 ++it)
9248       {
9249 	for (vector<unsigned>::const_iterator iit =
9250 	       it->inserted_indexes().begin();
9251 	     iit != it->inserted_indexes().end();
9252 	     ++iit)
9253 	  {
9254 	    unsigned i = *iit;
9255 	    type_base_sptr t
9256 	      (second_->get_types_not_reachable_from_public_interfaces()[i]);
9257 
9258 	    if (!is_user_defined_type(t))
9259 	      continue;
9260 
9261 	    string repr = abigail::ir::get_pretty_representation(t, true);
9262 
9263 	    // Let's see if the inserted type we are looking at was
9264 	    // reported as deleted as well.
9265 	    //
9266 	    // If it's been deleted and a different version of it has
9267 	    // now been added, it means it's been *changed*.  In that
9268 	    // case we'll compute the diff of that change and store it
9269 	    // in the map of changed unreachable types.
9270 	    //
9271 	    // Otherwise, it means the type's been added so we'll add
9272 	    // it to the set of added unreachable types.
9273 
9274 	    string_type_base_sptr_map::const_iterator j =
9275 	      deleted_unreachable_types_.find(repr);
9276 	    if (j != deleted_unreachable_types_.end())
9277 	      {
9278 		// So there was another type of the same pretty
9279 		// representation which was reported as deleted.
9280 		// Let's see if they are different or not ...
9281 		decl_base_sptr old_type = is_decl(j->second);
9282 		decl_base_sptr new_type = is_decl(t);
9283 		if (old_type != new_type)
9284 		  {
9285 		    // The previously added type is different from this
9286 		    // one that is added.  That means the initial type
9287 		    // was changed.  Let's compute its diff and store it
9288 		    // as a changed type.
9289 		    diff_sptr d = compute_diff(old_type, new_type, ctxt);
9290 		    ABG_ASSERT(d->has_changes());
9291 		    changed_unreachable_types_[repr]= d;
9292 		  }
9293 
9294 		// In any case, the type was both deleted and added,
9295 		// so we cannot have it marked as being deleted.  So
9296 		// let's remove it from the deleted types.
9297 		deleted_unreachable_types_.erase(j);
9298 	      }
9299 	    else
9300 	      // The type wasn't previously reported as deleted, so
9301 	      // it's really added.
9302 	      added_unreachable_types_[repr] = t;
9303 	  }
9304       }
9305   }
9306 }
9307 
9308 /// Test if a change reports about a given @ref function_decl that is
9309 /// changed in a certain way is suppressed by a given suppression
9310 /// specifiation
9311 ///
9312 /// @param fn the @ref function_decl to consider.
9313 ///
9314 /// @param suppr the suppression specification to consider.
9315 ///
9316 /// @param k the kind of change that happened to @p fn.
9317 ///
9318 /// @param ctxt the context of the current diff.
9319 ///
9320 /// @return true iff the suppression specification @p suppr suppresses
9321 /// change reports about function @p fn, if that function changes in
9322 /// the way expressed by @p k.
9323 static bool
function_is_suppressed(const function_decl * fn,const suppression_sptr suppr,function_suppression::change_kind k,const diff_context_sptr ctxt)9324 function_is_suppressed(const function_decl* fn,
9325 		       const suppression_sptr suppr,
9326 		       function_suppression::change_kind k,
9327 		       const diff_context_sptr ctxt)
9328 {
9329   function_suppression_sptr fn_suppr = is_function_suppression(suppr);
9330   if (!fn_suppr)
9331     return false;
9332   return fn_suppr->suppresses_function(fn, k, ctxt);
9333 }
9334 
9335 /// Test if a change reports about a given @ref var_decl that is
9336 /// changed in a certain way is suppressed by a given suppression
9337 /// specifiation
9338 ///
9339 /// @param fn the @ref var_decl to consider.
9340 ///
9341 /// @param suppr the suppression specification to consider.
9342 ///
9343 /// @param k the kind of change that happened to @p fn.
9344 ///
9345 /// @param ctxt the context of the current diff.
9346 ///
9347 /// @return true iff the suppression specification @p suppr suppresses
9348 /// change reports about variable @p fn, if that variable changes in
9349 /// the way expressed by @p k.
9350 static bool
variable_is_suppressed(const var_decl * var,const suppression_sptr suppr,variable_suppression::change_kind k,const diff_context_sptr ctxt)9351 variable_is_suppressed(const var_decl* var,
9352 		       const suppression_sptr suppr,
9353 		       variable_suppression::change_kind k,
9354 		       const diff_context_sptr ctxt)
9355 {
9356   variable_suppression_sptr var_suppr = is_variable_suppression(suppr);
9357   if (!var_suppr)
9358     return false;
9359   return var_suppr->suppresses_variable(var, k, ctxt);
9360 }
9361 
9362 /// Apply suppression specifications for this corpus diff to the set
9363 /// of added/removed functions/variables, as well as to types not
9364 /// reachable from global functions/variables.
9365 void
apply_supprs_to_added_removed_fns_vars_unreachable_types()9366 corpus_diff::priv::apply_supprs_to_added_removed_fns_vars_unreachable_types()
9367 {
9368   diff_context_sptr ctxt = get_context();
9369 
9370   const suppressions_type& suppressions = ctxt->suppressions();
9371   for (suppressions_type::const_iterator i = suppressions.begin();
9372        i != suppressions.end();
9373        ++i)
9374     {
9375       // Added/Deleted functions.
9376       if (function_suppression_sptr fn_suppr = is_function_suppression(*i))
9377 	{
9378 	  // Added functions
9379 	  for (string_function_ptr_map::const_iterator e = added_fns_.begin();
9380 	       e != added_fns_.end();
9381 	       ++e)
9382 	    if (function_is_suppressed(e->second, fn_suppr,
9383 				       function_suppression::ADDED_FUNCTION_CHANGE_KIND,
9384 				       ctxt))
9385 	      suppressed_added_fns_[e->first] = e->second;
9386 
9387 	  // Deleted functions.
9388 	  for (string_function_ptr_map::const_iterator e = deleted_fns_.begin();
9389 	       e != deleted_fns_.end();
9390 	       ++e)
9391 	    if (function_is_suppressed(e->second, fn_suppr,
9392 				       function_suppression::DELETED_FUNCTION_CHANGE_KIND,
9393 				       ctxt))
9394 	      suppressed_deleted_fns_[e->first] = e->second;
9395 
9396 	  // Added function symbols not referenced by any debug info
9397 	  for (string_elf_symbol_map::const_iterator e =
9398 		 added_unrefed_fn_syms_.begin();
9399 	       e != added_unrefed_fn_syms_.end();
9400 	       ++e)
9401 	    if (fn_suppr->suppresses_function_symbol(e->second,
9402 						     function_suppression::ADDED_FUNCTION_CHANGE_KIND,
9403 						     ctxt))
9404 	      suppressed_added_unrefed_fn_syms_[e->first] = e->second;
9405 
9406 	  // Removed function symbols not referenced by any debug info
9407 	  for (string_elf_symbol_map::const_iterator e =
9408 		 deleted_unrefed_fn_syms_.begin();
9409 	       e != deleted_unrefed_fn_syms_.end();
9410 	       ++e)
9411 	    if (fn_suppr->suppresses_function_symbol(e->second,
9412 						     function_suppression::DELETED_FUNCTION_CHANGE_KIND,
9413 						     ctxt))
9414 	      suppressed_deleted_unrefed_fn_syms_[e->first] = e->second;
9415 	}
9416       // Added/Delete virtual member functions changes that might be
9417       // suppressed by a type_suppression that matches the enclosing
9418       // class of the virtual member function.
9419       else if (type_suppression_sptr type_suppr = is_type_suppression(*i))
9420 	{
9421 	  // Added virtual functions
9422 	  for (string_function_ptr_map::const_iterator e = added_fns_.begin();
9423 	       e != added_fns_.end();
9424 	       ++e)
9425 	    if (is_member_function(e->second)
9426 		&& get_member_function_is_virtual(e->second))
9427 	      {
9428 		function_decl *f = e->second;
9429 		class_decl_sptr c =
9430 		  is_class_type(is_method_type(f->get_type())->get_class_type());
9431 		ABG_ASSERT(c);
9432 		if (type_suppr->suppresses_type(c, ctxt))
9433 		  suppressed_added_fns_[e->first] = e->second;
9434 	      }
9435 	  // Deleted virtual functions
9436 	  for (string_function_ptr_map::const_iterator e = deleted_fns_.begin();
9437 	       e != deleted_fns_.end();
9438 	       ++e)
9439 	    if (is_member_function(e->second)
9440 		&& get_member_function_is_virtual(e->second))
9441 	      {
9442 		function_decl *f = e->second;
9443 		class_decl_sptr c =
9444 		  is_class_type(is_method_type(f->get_type())->get_class_type());
9445 		ABG_ASSERT(c);
9446 		if (type_suppr->suppresses_type(c, ctxt))
9447 		  suppressed_deleted_fns_[e->first] = e->second;
9448 	      }
9449 
9450 	  // Apply this type suppression to deleted types
9451 	  // non-reachable from a public interface.
9452 	  for (string_type_base_sptr_map::const_iterator e =
9453 		 deleted_unreachable_types_.begin();
9454 	       e != deleted_unreachable_types_.end();
9455 	       ++e)
9456 	    if (type_suppr->suppresses_type(e->second, ctxt))
9457 	      suppressed_deleted_unreachable_types_[e->first] = e->second;
9458 
9459 	  // Apply this type suppression to added types
9460 	  // non-reachable from a public interface.
9461 	  for (string_type_base_sptr_map::const_iterator e =
9462 		 added_unreachable_types_.begin();
9463 	       e != added_unreachable_types_.end();
9464 	       ++e)
9465 	    if (type_suppr->suppresses_type(e->second, ctxt))
9466 	      suppressed_added_unreachable_types_[e->first] = e->second;
9467 	}
9468       // Added/Deleted variables
9469       else if (variable_suppression_sptr var_suppr =
9470 	       is_variable_suppression(*i))
9471 	{
9472 	  // Added variables
9473 	  for (string_var_ptr_map::const_iterator e = added_vars_.begin();
9474 	       e != added_vars_.end();
9475 	       ++e)
9476 	    if (variable_is_suppressed(e->second, var_suppr,
9477 				       variable_suppression::ADDED_VARIABLE_CHANGE_KIND,
9478 				       ctxt))
9479 	      suppressed_added_vars_[e->first] = e->second;
9480 
9481 	  //Deleted variables
9482 	  for (string_var_ptr_map::const_iterator e = deleted_vars_.begin();
9483 	       e != deleted_vars_.end();
9484 	       ++e)
9485 	    if (variable_is_suppressed(e->second, var_suppr,
9486 				       variable_suppression::DELETED_VARIABLE_CHANGE_KIND,
9487 				       ctxt))
9488 	      suppressed_deleted_vars_[e->first] = e->second;
9489 
9490 	  // Added variable symbols not referenced by any debug info
9491 	  for (string_elf_symbol_map::const_iterator e =
9492 		 added_unrefed_var_syms_.begin();
9493 	       e != added_unrefed_var_syms_.end();
9494 	       ++e)
9495 	    if (var_suppr->suppresses_variable_symbol(e->second,
9496 						      variable_suppression::ADDED_VARIABLE_CHANGE_KIND,
9497 						      ctxt))
9498 	      suppressed_added_unrefed_var_syms_[e->first] = e->second;
9499 
9500 	  // Removed variable symbols not referenced by any debug info
9501 	  for (string_elf_symbol_map::const_iterator e =
9502 		 deleted_unrefed_var_syms_.begin();
9503 	       e != deleted_unrefed_var_syms_.end();
9504 	       ++e)
9505 	    if (var_suppr->suppresses_variable_symbol(e->second,
9506 						      variable_suppression::DELETED_VARIABLE_CHANGE_KIND,
9507 						      ctxt))
9508 	      suppressed_deleted_unrefed_var_syms_[e->first] = e->second;
9509 	}
9510     }
9511 }
9512 
9513 /// Test if the change reports for a given deleted function have
9514 /// been deleted.
9515 ///
9516 /// @param fn the function to consider.
9517 ///
9518 /// @return true iff the change reports for a give given deleted
9519 /// function have been deleted.
9520 bool
deleted_function_is_suppressed(const function_decl * fn) const9521 corpus_diff::priv::deleted_function_is_suppressed(const function_decl* fn) const
9522 {
9523   if (!fn)
9524     return false;
9525 
9526   string_function_ptr_map::const_iterator i =
9527     suppressed_deleted_fns_.find(fn->get_id());
9528 
9529   return (i != suppressed_deleted_fns_.end());
9530 }
9531 
9532 /// Test if an added type that is unreachable from public interface
9533 /// has been suppressed by a suppression specification.
9534 ///
9535 /// @param t the added unreachable type to be considered.
9536 ///
9537 /// @return true iff @p t has been suppressed by a suppression
9538 /// specification.
9539 bool
added_unreachable_type_is_suppressed(const type_base * t) const9540 corpus_diff::priv::added_unreachable_type_is_suppressed(const type_base *t)const
9541 {
9542   if (!t)
9543     return false;
9544 
9545   string repr = abigail::ir::get_pretty_representation(t, /*internal=*/true);
9546   string_type_base_sptr_map::const_iterator i =
9547     suppressed_added_unreachable_types_.find(repr);
9548   if (i == suppressed_added_unreachable_types_.end())
9549     return false;
9550 
9551   return true;
9552 }
9553 
9554 /// Test if a deleted type that is unreachable from public interface
9555 /// has been suppressed by a suppression specification.
9556 ///
9557 /// @param t the deleted unreachable type to be considered.
9558 ///
9559 /// @return true iff @p t has been suppressed by a suppression
9560 /// specification.
9561 bool
deleted_unreachable_type_is_suppressed(const type_base * t) const9562 corpus_diff::priv::deleted_unreachable_type_is_suppressed(const type_base *t) const
9563 {
9564   if (!t)
9565     return false;
9566 
9567   string repr = abigail::ir::get_pretty_representation(t, /*internal=*/true);
9568   string_type_base_sptr_map::const_iterator i =
9569     suppressed_deleted_unreachable_types_.find(repr);
9570   if (i == suppressed_deleted_unreachable_types_.end())
9571     return false;
9572 
9573   return true;
9574 }
9575 
9576 /// Test if the change reports for a give given added function has
9577 /// been deleted.
9578 ///
9579 /// @param fn the function to consider.
9580 ///
9581 /// @return true iff the change reports for a give given added
9582 /// function has been deleted.
9583 bool
added_function_is_suppressed(const function_decl * fn) const9584 corpus_diff::priv::added_function_is_suppressed(const function_decl* fn) const
9585 {
9586   if (!fn)
9587     return false;
9588 
9589   string_function_ptr_map::const_iterator i =
9590     suppressed_added_fns_.find(fn->get_id());
9591 
9592   return (i != suppressed_added_fns_.end());
9593 }
9594 
9595 /// Test if the change reports for a give given deleted variable has
9596 /// been deleted.
9597 ///
9598 /// @param var the variable to consider.
9599 ///
9600 /// @return true iff the change reports for a give given deleted
9601 /// variable has been deleted.
9602 bool
deleted_variable_is_suppressed(const var_decl * var) const9603 corpus_diff::priv::deleted_variable_is_suppressed(const var_decl* var) const
9604 {
9605   if (!var)
9606     return false;
9607 
9608   string_var_ptr_map::const_iterator i =
9609     suppressed_deleted_vars_.find(var->get_id());
9610 
9611   return (i != suppressed_deleted_vars_.end());
9612 }
9613 
9614 /// Test if the change reports for a given added variable have been
9615 /// suppressed.
9616 ///
9617 /// @param var the variable to consider.
9618 ///
9619 /// @return true iff the change reports for a given deleted
9620 /// variable has been deleted.
9621 bool
added_variable_is_suppressed(const var_decl * var) const9622 corpus_diff::priv::added_variable_is_suppressed(const var_decl* var) const
9623 {
9624   if (!var)
9625     return false;
9626 
9627   string_var_ptr_map::const_iterator i =
9628     suppressed_added_vars_.find(var->get_id());
9629 
9630   return (i != suppressed_added_vars_.end());
9631 }
9632 
9633 /// Test if the change reports for a given deleted function symbol
9634 /// (that is not referenced by any debug info) has been suppressed.
9635 ///
9636 /// @param var the function to consider.
9637 ///
9638 /// @return true iff the change reports for a given deleted function
9639 /// symbol has been suppressed.
9640 bool
deleted_unrefed_fn_sym_is_suppressed(const elf_symbol * s) const9641 corpus_diff::priv::deleted_unrefed_fn_sym_is_suppressed(const elf_symbol* s) const
9642 {
9643   if (!s)
9644     return false;
9645 
9646   string_elf_symbol_map::const_iterator i =
9647     suppressed_deleted_unrefed_fn_syms_.find(s->get_id_string());
9648 
9649   return (i != suppressed_deleted_unrefed_fn_syms_.end());
9650 }
9651 
9652 /// Test if the change reports for a given added function symbol
9653 /// (that is not referenced by any debug info) has been suppressed.
9654 ///
9655 /// @param var the function to consider.
9656 ///
9657 /// @return true iff the change reports for a given added function
9658 /// symbol has been suppressed.
9659 bool
added_unrefed_fn_sym_is_suppressed(const elf_symbol * s) const9660 corpus_diff::priv::added_unrefed_fn_sym_is_suppressed(const elf_symbol* s) const
9661 {
9662   if (!s)
9663     return false;
9664 
9665   string_elf_symbol_map::const_iterator i =
9666     suppressed_added_unrefed_fn_syms_.find(s->get_id_string());
9667 
9668   return (i != suppressed_added_unrefed_fn_syms_.end());
9669 }
9670 
9671 /// Test if the change reports for a given deleted variable symbol
9672 /// (that is not referenced by any debug info) has been suppressed.
9673 ///
9674 /// @param var the variable to consider.
9675 ///
9676 /// @return true iff the change reports for a given deleted variable
9677 /// symbol has been suppressed.
9678 bool
deleted_unrefed_var_sym_is_suppressed(const elf_symbol * s) const9679 corpus_diff::priv::deleted_unrefed_var_sym_is_suppressed(const elf_symbol* s) const
9680 {
9681   if (!s)
9682     return false;
9683 
9684   string_elf_symbol_map::const_iterator i =
9685     suppressed_deleted_unrefed_var_syms_.find(s->get_id_string());
9686 
9687   return (i != suppressed_deleted_unrefed_var_syms_.end());
9688 }
9689 
9690 /// Test if the change reports for a given added variable symbol
9691 /// (that is not referenced by any debug info) has been suppressed.
9692 ///
9693 /// @param var the variable to consider.
9694 ///
9695 /// @return true iff the change reports for a given added variable
9696 /// symbol has been suppressed.
9697 bool
added_unrefed_var_sym_is_suppressed(const elf_symbol * s) const9698 corpus_diff::priv::added_unrefed_var_sym_is_suppressed(const elf_symbol* s) const
9699 {
9700   if (!s)
9701     return false;
9702 
9703   string_elf_symbol_map::const_iterator i =
9704     suppressed_added_unrefed_var_syms_.find(s->get_id_string());
9705 
9706   return (i != suppressed_added_unrefed_var_syms_.end());
9707 }
9708 
9709 #ifdef do_count_diff_map_changes
9710 #undef do_count_diff_map_changes
9711 #endif
9712 #define do_count_diff_map_changes(diff_map, n_changes, n_filtered)	\
9713   {									\
9714     string_diff_ptr_map::const_iterator i;				\
9715     for (i = diff_map.begin();						\
9716 	 i != diff_map.end();						\
9717 	 ++i)								\
9718       { \
9719 	if (const var_diff* d = is_var_diff(i->second))		\
9720 	  if (is_data_member(d->first_var()))				\
9721 	    continue;							\
9722 									\
9723 	if (i->second->has_local_changes())				\
9724 	  ++n_changes;							\
9725 	if (!i->second->get_canonical_diff()->to_be_reported())		\
9726 	  ++n_filtered;						\
9727       }								\
9728   }
9729 
9730 /// Count the number of leaf changes as well as the number of the
9731 /// changes that have been filtered out.
9732 ///
9733 /// @param num_changes out parameter.  This is set to the total number
9734 /// of leaf changes.
9735 ///
9736 /// @param num_filtered out parameter.  This is set to the number of
9737 /// leaf changes that have been filtered out.
9738 void
count_leaf_changes(size_t & num_changes,size_t & num_filtered)9739 corpus_diff::priv::count_leaf_changes(size_t &num_changes, size_t &num_filtered)
9740 {
9741   count_leaf_type_changes(num_changes, num_filtered);
9742 
9743   // Now count the non-type changes.
9744   do_count_diff_map_changes(leaf_diffs_.get_function_decl_diff_map(),
9745     num_changes, num_filtered);
9746   do_count_diff_map_changes(leaf_diffs_.get_var_decl_diff_map(),
9747     num_changes, num_filtered);
9748 }
9749 
9750 /// Count the number of leaf *type* changes as well as the number of
9751 /// the leaf type changes that have been filtered out.
9752 ///
9753 /// @param num_changes out parameter.  This is set to the total number
9754 /// of leaf type changes.
9755 ///
9756 /// @param num_filtered out parameter.  This is set to the number of
9757 /// leaf type changes that have been filtered out.
9758 void
count_leaf_type_changes(size_t & num_changes,size_t & num_filtered)9759 corpus_diff::priv::count_leaf_type_changes(size_t &num_changes,
9760 					   size_t &num_filtered)
9761 {
9762   do_count_diff_map_changes(leaf_diffs_.get_type_decl_diff_map(),
9763     num_changes, num_filtered);
9764   do_count_diff_map_changes(leaf_diffs_.get_enum_diff_map(),
9765     num_changes, num_filtered);
9766   do_count_diff_map_changes(leaf_diffs_.get_class_diff_map(),
9767     num_changes, num_filtered);
9768   do_count_diff_map_changes(leaf_diffs_.get_union_diff_map(),
9769     num_changes, num_filtered);
9770   do_count_diff_map_changes(leaf_diffs_.get_typedef_diff_map(),
9771     num_changes, num_filtered);
9772   do_count_diff_map_changes(leaf_diffs_.get_array_diff_map(),
9773     num_changes, num_filtered);
9774   do_count_diff_map_changes(leaf_diffs_.get_distinct_diff_map(),
9775     num_changes, num_filtered);
9776   do_count_diff_map_changes(leaf_diffs_.get_fn_parm_diff_map(),
9777 			    num_changes, num_filtered);
9778 }
9779 
9780 /// Count the number of types not reachable from the interface (i.e,
9781 /// not reachable from global functions or variables).
9782 ///
9783 /// @param num_added this is set to the number of added types not
9784 /// reachable from the interface.
9785 ///
9786 /// @param num_deleted this is set to the number of deleted types not
9787 /// reachable from the interface.
9788 ///
9789 /// @param num_changed this is set to the number of changed types not
9790 /// reachable from the interface.
9791 ///
9792 /// @param num_filtered_added this is set to the number of added types
9793 /// not reachable from the interface and that have been filtered out
9794 /// by suppression specifications.
9795 ///
9796 /// @param num_filtered_deleted this is set to the number of deleted
9797 /// types not reachable from the interface and that have been filtered
9798 /// out by suppression specifications.
9799 ///
9800 /// @param num_filtered_changed this is set to the number of changed
9801 /// types not reachable from the interface and that have been filtered
9802 /// out by suppression specifications.
9803 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)9804 corpus_diff::priv::count_unreachable_types(size_t &num_added,
9805 					   size_t &num_deleted,
9806 					   size_t &num_changed,
9807 					   size_t &num_filtered_added,
9808 					   size_t &num_filtered_deleted,
9809 					   size_t &num_filtered_changed)
9810 {
9811   num_added = added_unreachable_types_.size();
9812   num_deleted = deleted_unreachable_types_.size();
9813   num_changed = changed_unreachable_types_.size();
9814   num_filtered_added = suppressed_added_unreachable_types_.size();
9815   num_filtered_deleted = suppressed_deleted_unreachable_types_.size();
9816 
9817   for (vector<diff_sptr>::const_iterator i =
9818 	 changed_unreachable_types_sorted().begin();
9819        i != changed_unreachable_types_sorted().end();
9820        ++i)
9821     if (!(*i)->to_be_reported())
9822       ++num_filtered_changed;
9823 }
9824 
9825 /// Get the sorted vector of diff nodes representing changed
9826 /// unreachable types.
9827 ///
9828 /// Upon the first invocation of this method, if the vector is empty,
9829 /// this function gets the diff nodes representing changed
9830 /// unreachable, sort them, and return the sorted vector.
9831 ///
9832 /// @return the sorted vector of diff nodes representing changed
9833 /// unreachable types.
9834 const vector<diff_sptr>&
changed_unreachable_types_sorted() const9835 corpus_diff::priv::changed_unreachable_types_sorted() const
9836 {
9837 if (changed_unreachable_types_sorted_.empty())
9838   if (!changed_unreachable_types_.empty())
9839     sort_string_diff_sptr_map(changed_unreachable_types_,
9840 			      changed_unreachable_types_sorted_);
9841 
9842  return changed_unreachable_types_sorted_;
9843 }
9844 
9845 /// Compute the diff stats.
9846 ///
9847 /// To know the number of functions that got filtered out, this
9848 /// function applies the categorizing filters to the diff sub-trees of
9849 /// each function changes diff, prior to calculating the stats.
9850 ///
9851 /// @param num_removed the number of removed functions.
9852 ///
9853 /// @param num_added the number of added functions.
9854 ///
9855 /// @param num_changed the number of changed functions.
9856 ///
9857 /// @param num_filtered_out the number of changed functions that are
9858 /// got filtered out from the report
9859 void
apply_filters_and_compute_diff_stats(diff_stats & stat)9860 corpus_diff::priv::apply_filters_and_compute_diff_stats(diff_stats& stat)
9861 {
9862   stat.num_func_removed(deleted_fns_.size());
9863   stat.num_removed_func_filtered_out(suppressed_deleted_fns_.size());
9864   stat.num_func_added(added_fns_.size());
9865   stat.num_added_func_filtered_out(suppressed_added_fns_.size());
9866   stat.num_func_changed(changed_fns_map_.size());
9867 
9868   stat.num_vars_removed(deleted_vars_.size());
9869   stat.num_removed_vars_filtered_out(suppressed_deleted_vars_.size());
9870   stat.num_vars_added(added_vars_.size());
9871   stat.num_added_vars_filtered_out(suppressed_added_vars_.size());
9872   stat.num_vars_changed(changed_vars_map_.size());
9873 
9874   diff_context_sptr ctxt = get_context();
9875 
9876   // Walk the changed function diff nodes to apply the categorization
9877   // filters.
9878   diff_sptr diff;
9879   for (function_decl_diff_sptrs_type::const_iterator i =
9880 	 changed_fns_.begin();
9881        i != changed_fns_.end();
9882        ++i)
9883     {
9884       diff_sptr diff = *i;
9885       ctxt->maybe_apply_filters(diff);
9886     }
9887 
9888   // Walk the changed variable diff nodes to apply the categorization
9889   // filters.
9890   for (var_diff_sptrs_type::const_iterator i = sorted_changed_vars_.begin();
9891        i != sorted_changed_vars_.end();
9892        ++i)
9893     {
9894       diff_sptr diff = *i;
9895       ctxt->maybe_apply_filters(diff);
9896     }
9897 
9898   // walk the changed unreachable types to apply categorization
9899   // filters
9900   for (diff_sptrs_type::const_iterator i =
9901 	  changed_unreachable_types_sorted().begin();
9902 	i != changed_unreachable_types_sorted().end();
9903        ++i)
9904     {
9905       diff_sptr diff = *i;
9906       ctxt->maybe_apply_filters(diff);
9907     }
9908 
9909   categorize_redundant_changed_sub_nodes();
9910 
9911   // Walk the changed function diff nodes to count the number of
9912   // filtered-out functions and the number of functions with virtual
9913   // offset changes.
9914   for (function_decl_diff_sptrs_type::const_iterator i =
9915 	 changed_fns_.begin();
9916        i != changed_fns_.end();
9917        ++i)
9918     {
9919       if ((*i)->is_filtered_out())
9920 	{
9921 	  stat.num_changed_func_filtered_out
9922 	    (stat.num_changed_func_filtered_out() + 1);
9923 
9924 	  if ((*i)->has_local_changes())
9925 	    stat.num_leaf_func_changes_filtered_out
9926 	      (stat.num_leaf_func_changes_filtered_out() + 1);
9927 	}
9928       else
9929 	{
9930 	  if ((*i)->get_category() & VIRTUAL_MEMBER_CHANGE_CATEGORY)
9931 	    stat.num_func_with_virtual_offset_changes
9932 	      (stat.num_func_with_virtual_offset_changes() + 1);
9933 	}
9934 
9935       if ((*i)->has_local_changes())
9936 	stat.num_leaf_func_changes
9937 	  (stat.num_leaf_func_changes() + 1);
9938     }
9939 
9940   // Walk the changed variables diff nodes to count the number of
9941   // filtered-out variables.
9942   for (var_diff_sptrs_type ::const_iterator i = sorted_changed_vars_.begin();
9943        i != sorted_changed_vars_.end();
9944        ++i)
9945     {
9946       if ((*i)->is_filtered_out())
9947 	{
9948 	  stat.num_changed_vars_filtered_out
9949 	    (stat.num_changed_vars_filtered_out() + 1);
9950 
9951 	  if ((*i)->has_local_changes())
9952 	    stat.num_leaf_var_changes_filtered_out
9953 	      (stat.num_leaf_var_changes_filtered_out() + 1);
9954 	}
9955       if ((*i)->has_local_changes())
9956 	stat.num_leaf_var_changes
9957 	  (stat.num_leaf_var_changes() + 1);
9958     }
9959 
9960   stat.num_func_syms_added(added_unrefed_fn_syms_.size());
9961   stat.num_added_func_syms_filtered_out(suppressed_added_unrefed_fn_syms_.size());
9962   stat.num_func_syms_removed(deleted_unrefed_fn_syms_.size());
9963   stat.num_removed_func_syms_filtered_out(suppressed_deleted_unrefed_fn_syms_.size());
9964   stat.num_var_syms_added(added_unrefed_var_syms_.size());
9965   stat.num_added_var_syms_filtered_out(suppressed_added_unrefed_var_syms_.size());
9966   stat.num_var_syms_removed(deleted_unrefed_var_syms_.size());
9967   stat.num_removed_var_syms_filtered_out(suppressed_deleted_unrefed_var_syms_.size());
9968 
9969   // Walk the general leaf type diff nodes to count them
9970   {
9971     size_t num_type_changes = 0, num_type_filtered = 0;
9972     count_leaf_type_changes(num_type_changes, num_type_filtered);
9973 
9974     stat.num_leaf_type_changes(num_type_changes);
9975     stat.num_leaf_type_changes_filtered_out(num_type_filtered);
9976   }
9977 
9978   // Walk the general leaf artefacts diff nodes to count them
9979   {
9980     size_t num_changes = 0, num_filtered = 0;
9981     count_leaf_changes(num_changes, num_filtered);
9982 
9983     stat.num_leaf_changes(num_changes);
9984     stat.num_leaf_changes_filtered_out(num_filtered);
9985   }
9986 
9987   // Walk the unreachable types to count them
9988   {
9989     size_t num_added_unreachable_types = 0,
9990       num_changed_unreachable_types = 0,
9991       num_deleted_unreachable_types = 0,
9992       num_added_unreachable_types_filtered = 0,
9993       num_changed_unreachable_types_filtered = 0,
9994       num_deleted_unreachable_types_filtered = 0;
9995 
9996     count_unreachable_types(num_added_unreachable_types,
9997 			    num_deleted_unreachable_types,
9998 			    num_changed_unreachable_types,
9999 			    num_added_unreachable_types_filtered,
10000 			    num_deleted_unreachable_types_filtered,
10001 			    num_changed_unreachable_types_filtered);
10002 
10003     stat.num_added_unreachable_types(num_added_unreachable_types);
10004     stat.num_removed_unreachable_types(num_deleted_unreachable_types);
10005     stat.num_changed_unreachable_types(num_changed_unreachable_types);
10006     stat.num_added_unreachable_types_filtered_out
10007       (num_added_unreachable_types_filtered);
10008     stat.num_removed_unreachable_types_filtered_out
10009       (num_deleted_unreachable_types_filtered);
10010     stat.num_changed_unreachable_types_filtered_out
10011       (num_changed_unreachable_types_filtered);
10012   }
10013 }
10014 
10015 /// Emit the summary of the functions & variables that got
10016 /// removed/changed/added.
10017 ///
10018 /// TODO: This should be handled by the reporters, just like what is
10019 /// done for reporter_base::diff_to_be_reported.
10020 ///
10021 /// @param out the output stream to emit the stats to.
10022 ///
10023 /// @param indent the indentation string to use in the summary.
10024 void
emit_diff_stats(const diff_stats & s,ostream & out,const string & indent)10025 corpus_diff::priv::emit_diff_stats(const diff_stats&	s,
10026 				   ostream&		out,
10027 				   const string&	indent)
10028 {
10029   /// Report added/removed/changed functions.
10030   size_t net_num_leaf_changes =
10031     s.net_num_func_removed() +
10032     s.net_num_func_added() +
10033     s.net_num_leaf_func_changes() +
10034     s.net_num_vars_removed() +
10035     s.net_num_vars_added() +
10036     s.net_num_leaf_var_changes() +
10037     s.net_num_leaf_type_changes();
10038 
10039   if (!sonames_equal_)
10040     out << indent << "ELF SONAME changed\n";
10041 
10042   if (!architectures_equal_)
10043     out << indent << "ELF architecture changed\n";
10044 
10045   diff_context_sptr ctxt = get_context();
10046 
10047   if (ctxt->show_leaf_changes_only())
10048     {
10049       out << "Leaf changes summary: ";
10050       out << net_num_leaf_changes << " artifact";
10051       if (net_num_leaf_changes > 1)
10052 	out << "s";
10053       out << " changed";
10054 
10055       if (size_t num_filtered = s.num_leaf_changes_filtered_out())
10056 	out << " (" << num_filtered << " filtered out)";
10057       out << "\n";
10058 
10059       out << indent << "Changed leaf types summary: "
10060 	  << s.net_num_leaf_type_changes();
10061       if (s.num_leaf_type_changes_filtered_out())
10062 	out << " (" << s.num_leaf_type_changes_filtered_out()
10063 	    << " filtered out)";
10064       out << " leaf type";
10065       if (s.num_leaf_type_changes() > 1)
10066 	out << "s";
10067       out << " changed\n";
10068 
10069       // function changes summary
10070       out << indent << "Removed/Changed/Added functions summary: ";
10071       out << s.net_num_func_removed() << " Removed";
10072      if (s.num_removed_func_filtered_out())
10073 	out << " ("
10074 	    << s.num_removed_func_filtered_out()
10075 	    << " filtered out)";
10076       out << ", ";
10077 
10078       out << s.net_num_leaf_func_changes() << " Changed";
10079       if (s.num_leaf_func_changes_filtered_out())
10080 	    out << " ("
10081 		<< s.num_leaf_func_changes_filtered_out()
10082 		<< " filtered out)";
10083       out << ", ";
10084 
10085       out << s.net_num_func_added()<< " Added ";
10086       if (s.net_num_func_added() <= 1)
10087 	out << "function";
10088       else
10089 	out << "functions";
10090       if (s.num_added_func_filtered_out())
10091 	out << " (" << s.num_added_func_filtered_out() << " filtered out)";
10092       out << "\n";
10093 
10094       // variables changes summary
10095       out << indent << "Removed/Changed/Added variables summary: ";
10096       out << s.net_num_vars_removed() << " Removed";
10097       if (s.num_removed_vars_filtered_out())
10098 	out << " (" << s.num_removed_vars_filtered_out()
10099 	    << " filtered out)";
10100       out << ", ";
10101 
10102       out << s.net_num_leaf_var_changes() << " Changed";
10103       if (s.num_leaf_var_changes_filtered_out())
10104 	out << " ("
10105 	    << s.num_leaf_var_changes_filtered_out()
10106 	    << " filtered out)";
10107       out << ", ";
10108 
10109       out << s.net_num_vars_added() << " Added ";
10110       if (s.net_num_vars_added() <= 1)
10111 	out << "variable";
10112       else
10113 	out << "variables";
10114       if (s.num_added_vars_filtered_out())
10115 	out << " (" << s.num_added_vars_filtered_out()
10116 	    << " filtered out)";
10117       out << "\n";
10118     }
10119   else // if (ctxt->show_leaf_changes_only())
10120     {
10121       size_t total_nb_function_changes = s.num_func_removed()
10122 	+ s.num_func_changed() +  s.num_func_added();
10123 
10124       // function changes summary
10125       out << indent << "Functions changes summary: ";
10126       out << s.net_num_func_removed() << " Removed";
10127       if (s.num_removed_func_filtered_out())
10128 	out << " ("
10129 	    << s.num_removed_func_filtered_out()
10130 	    << " filtered out)";
10131       out << ", ";
10132 
10133       out << s.net_num_func_changed() << " Changed";
10134       if (s.num_changed_func_filtered_out())
10135 	out << " (" << s.num_changed_func_filtered_out() << " filtered out)";
10136       out << ", ";
10137 
10138       out << s.net_num_func_added() << " Added";
10139       if (s.num_added_func_filtered_out())
10140 	out << " (" << s.num_added_func_filtered_out() << " filtered out)";
10141       if (total_nb_function_changes <= 1)
10142 	out << " function";
10143       else
10144 	out << " functions";
10145       out << "\n";
10146 
10147       // variables changes summary
10148       size_t total_nb_variable_changes = s.num_vars_removed()
10149 	+ s.num_vars_changed() + s.num_vars_added();
10150 
10151       out << indent << "Variables changes summary: ";
10152       out << s.net_num_vars_removed() << " Removed";
10153       if (s.num_removed_vars_filtered_out())
10154 	out << " (" << s.num_removed_vars_filtered_out()
10155 	    << " filtered out)";
10156       out << ", ";
10157 
10158       out << s.num_vars_changed() - s.num_changed_vars_filtered_out() << " Changed";
10159       if (s.num_changed_vars_filtered_out())
10160 	out << " (" << s.num_changed_vars_filtered_out() << " filtered out)";
10161       out << ", ";
10162 
10163       out << s.net_num_vars_added() << " Added";
10164       if (s.num_added_vars_filtered_out())
10165 	out << " (" << s.num_added_vars_filtered_out()
10166 	    << " filtered out)";
10167       if (total_nb_variable_changes <= 1)
10168 	out << " variable";
10169       else
10170 	out << " variables";
10171       out << "\n";
10172     }
10173 
10174   // Show statistics about types not reachable from global
10175   // functions/variables.
10176   if (ctxt->show_unreachable_types())
10177     {
10178       size_t total_nb_unreachable_type_changes =
10179 	s.num_removed_unreachable_types()
10180 	+ s.num_changed_unreachable_types()
10181 	+ s.num_added_unreachable_types();
10182 
10183       // Show summary of unreachable types
10184       out << indent << "Unreachable types summary: "
10185 	  << s.net_num_removed_unreachable_types()
10186 	  << " removed";
10187       if (s.num_removed_unreachable_types_filtered_out())
10188 	out << " (" << s.num_removed_unreachable_types_filtered_out()
10189 	    << " filtered out)";
10190       out << ", ";
10191 
10192       out << s.net_num_changed_unreachable_types()
10193 	  << " changed";
10194       if (s.num_changed_unreachable_types_filtered_out())
10195 	out << " (" << s.num_changed_unreachable_types_filtered_out()
10196 	    << " filtered out)";
10197       out << ", ";
10198 
10199       out << s.net_num_added_unreachable_types()
10200 	  << " added";
10201       if (s.num_added_unreachable_types_filtered_out())
10202 	out << " (" << s.num_added_unreachable_types_filtered_out()
10203 	    << " filtered out)";
10204       if (total_nb_unreachable_type_changes <= 1)
10205 	out << " type";
10206       else
10207 	out << " types";
10208       out << "\n";
10209     }
10210 
10211   if (ctxt->show_symbols_unreferenced_by_debug_info()
10212       && (s.num_func_syms_removed()
10213 	  || s.num_func_syms_added()
10214 	  || s.num_var_syms_removed()
10215 	  || s.num_var_syms_added()))
10216     {
10217       // function symbols changes summary.
10218 
10219       if (!ctxt->show_added_symbols_unreferenced_by_debug_info()
10220 	  && s.num_func_syms_removed() == 0
10221 	  && s.num_func_syms_added() != 0)
10222 	// If the only unreferenced function symbol change is function
10223 	// syms that got added, but we were forbidden to show function
10224 	// syms being added, do nothing.
10225 	;
10226       else
10227 	{
10228 	  out << indent
10229 	      << "Function symbols changes summary: "
10230 	      << s.net_num_removed_func_syms() << " Removed";
10231 	  if (s.num_removed_func_syms_filtered_out())
10232 	    out << " (" << s.num_removed_func_syms_filtered_out()
10233 		<< " filtered out)";
10234 	  out << ", ";
10235 	  out << s.net_num_added_func_syms() << " Added";
10236 	  if (s.num_added_func_syms_filtered_out())
10237 	    out << " (" << s.num_added_func_syms_filtered_out()
10238 		<< " filtered out)";
10239 	  out << " function symbol";
10240 	  if (s.num_func_syms_added() + s.num_func_syms_removed() > 1)
10241 	    out << "s";
10242 	  out << " not referenced by debug info\n";
10243 	}
10244 
10245       // variable symbol changes summary.
10246 
10247       if (!ctxt->show_added_symbols_unreferenced_by_debug_info()
10248 	  && s.num_var_syms_removed() == 0
10249 	  && s.num_var_syms_added() != 0)
10250 	// If the only unreferenced variable symbol change is variable
10251 	// syms that got added, but we were forbidden to show variable
10252 	// syms being added, do nothing.
10253 	;
10254       else
10255 	{
10256 	  out << indent
10257 	      << "Variable symbols changes summary: "
10258 	      << s.net_num_removed_var_syms() << " Removed";
10259 	  if (s.num_removed_var_syms_filtered_out())
10260 	    out << " (" << s.num_removed_var_syms_filtered_out()
10261 		<< " filtered out)";
10262 	  out << ", ";
10263 	  out << s.net_num_added_var_syms() << " Added";
10264 	  if (s.num_added_var_syms_filtered_out())
10265 	    out << " (" << s.num_added_var_syms_filtered_out()
10266 		<< " filtered out)";
10267 	  out << " variable symbol";
10268 	  if (s.num_var_syms_added() + s.num_var_syms_removed() > 1)
10269 	    out << "s";
10270 	  out << " not referenced by debug info\n";
10271 	}
10272     }
10273 }
10274 
10275 /// Walk the changed functions and variables diff nodes to categorize
10276 /// redundant nodes.
10277 void
categorize_redundant_changed_sub_nodes()10278 corpus_diff::priv::categorize_redundant_changed_sub_nodes()
10279 {
10280   diff_sptr diff;
10281 
10282   diff_context_sptr ctxt = get_context();
10283 
10284   ctxt->forget_visited_diffs();
10285   for (function_decl_diff_sptrs_type::const_iterator i =
10286 	 changed_fns_.begin();
10287        i!= changed_fns_.end();
10288        ++i)
10289     {
10290       diff = *i;
10291       categorize_redundancy(diff);
10292     }
10293 
10294   for (var_diff_sptrs_type::const_iterator i = sorted_changed_vars_.begin();
10295        i!= sorted_changed_vars_.end();
10296        ++i)
10297     {
10298       diff_sptr diff = *i;
10299       categorize_redundancy(diff);
10300     }
10301 
10302   for (diff_sptrs_type::const_iterator i =
10303 	 changed_unreachable_types_sorted().begin();
10304        i!= changed_unreachable_types_sorted().end();
10305        ++i)
10306     {
10307       diff_sptr diff = *i;
10308       categorize_redundancy(diff);
10309     }
10310 }
10311 
10312 /// Walk the changed functions and variables diff nodes and clear the
10313 /// redundancy categorization they might carry.
10314 void
clear_redundancy_categorization()10315 corpus_diff::priv::clear_redundancy_categorization()
10316 {
10317   diff_sptr diff;
10318   for (function_decl_diff_sptrs_type::const_iterator i = changed_fns_.begin();
10319        i!= changed_fns_.end();
10320        ++i)
10321     {
10322       diff = *i;
10323       abigail::comparison::clear_redundancy_categorization(diff);
10324     }
10325 
10326   for (var_diff_sptrs_type::const_iterator i = sorted_changed_vars_.begin();
10327        i!= sorted_changed_vars_.end();
10328        ++i)
10329     {
10330       diff = *i;
10331       abigail::comparison::clear_redundancy_categorization(diff);
10332     }
10333 }
10334 
10335 /// If the user asked to dump the diff tree node (for changed
10336 /// variables and functions) on the error output stream, then just do
10337 /// that.
10338 ///
10339 /// This function is used for debugging purposes.
10340 void
maybe_dump_diff_tree()10341 corpus_diff::priv::maybe_dump_diff_tree()
10342 {
10343   diff_context_sptr ctxt = get_context();
10344 
10345   if (!ctxt->dump_diff_tree()
10346       || ctxt->error_output_stream() == 0)
10347     return;
10348 
10349   if (!changed_fns_.empty())
10350     {
10351       *ctxt->error_output_stream() << "changed functions diff tree: \n\n";
10352       for (function_decl_diff_sptrs_type::const_iterator i =
10353 	     changed_fns_.begin();
10354 	   i != changed_fns_.end();
10355 	   ++i)
10356 	{
10357 	  diff_sptr d = *i;
10358 	  print_diff_tree(d, *ctxt->error_output_stream());
10359 	}
10360     }
10361 
10362   if (!sorted_changed_vars_.empty())
10363     {
10364       *ctxt->error_output_stream() << "\nchanged variables diff tree: \n\n";
10365       for (var_diff_sptrs_type::const_iterator i =
10366 	     sorted_changed_vars_.begin();
10367 	   i != sorted_changed_vars_.end();
10368 	   ++i)
10369 	{
10370 	  diff_sptr d = *i;
10371 	  print_diff_tree(d, *ctxt->error_output_stream());
10372 	}
10373     }
10374 
10375   if (!changed_unreachable_types_sorted().empty())
10376     {
10377       *ctxt->error_output_stream() << "\nchanged unreachable "
10378 	"types diff tree: \n\n";
10379       for (vector<diff_sptr>::const_iterator i =
10380 	     changed_unreachable_types_sorted().begin();
10381 	   i != changed_unreachable_types_sorted().end();
10382 	   ++i)
10383 	{
10384 	  diff_sptr d = *i;
10385 	  print_diff_tree(d, *ctxt->error_output_stream());
10386 	}
10387     }
10388 }
10389 
10390 /// Populate the vector of children node of the @ref corpus_diff type.
10391 ///
10392 /// The children node can then later be retrieved using
10393 /// corpus_diff::children_node().
10394 void
chain_into_hierarchy()10395 corpus_diff::chain_into_hierarchy()
10396 {
10397   for (function_decl_diff_sptrs_type::const_iterator i =
10398 	 changed_functions_sorted().begin();
10399        i != changed_functions_sorted().end();
10400        ++i)
10401     if (diff_sptr d = *i)
10402       append_child_node(d);
10403 }
10404 
10405 /// Constructor for @ref corpus_diff.
10406 ///
10407 /// @param first the first corpus of the diff.
10408 ///
10409 /// @param second the second corpus of the diff.
10410 ///
10411 /// @param ctxt the diff context to use.  Note that this context
10412 /// object must stay alive at least during the life time of the
10413 /// current instance of @ref corpus_diff.  Otherwise memory corruption
10414 /// issues occur.
corpus_diff(corpus_sptr first,corpus_sptr second,diff_context_sptr ctxt)10415 corpus_diff::corpus_diff(corpus_sptr first,
10416 			 corpus_sptr second,
10417 			 diff_context_sptr ctxt)
10418   : priv_(new priv(first, second, ctxt))
10419 {}
10420 
10421 corpus_diff::~corpus_diff() = default;
10422 
10423 /// Finish building the current instance of @ref corpus_diff.
10424 void
finish_diff_type()10425 corpus_diff::finish_diff_type()
10426 {
10427   if (priv_->finished_)
10428     return;
10429   chain_into_hierarchy();
10430   priv_->finished_ = true;
10431 }
10432 
10433 /// @return the first corpus of the diff.
10434 corpus_sptr
first_corpus() const10435 corpus_diff::first_corpus() const
10436 {return priv_->first_;}
10437 
10438 /// @return the second corpus of the diff.
10439 corpus_sptr
second_corpus() const10440 corpus_diff::second_corpus() const
10441 {return priv_->second_;}
10442 
10443 /// @return the children nodes of the current instance of corpus_diff.
10444 const vector<diff*>&
children_nodes() const10445 corpus_diff::children_nodes() const
10446 {return priv_->children_;}
10447 
10448 /// Append a new child node to the vector of children nodes for the
10449 /// current instance of @ref corpus_diff node.
10450 ///
10451 /// Note that the vector of children nodes for the current instance of
10452 /// @ref corpus_diff node must remain sorted, using
10453 /// diff_less_than_functor.
10454 ///
10455 /// @param d the new child node.  Note that the life time of the
10456 /// object held by @p d will thus equal the life time of the current
10457 /// instance of @ref corpus_diff.
10458 void
append_child_node(diff_sptr d)10459 corpus_diff::append_child_node(diff_sptr d)
10460 {
10461   ABG_ASSERT(d);
10462 
10463   diff_less_than_functor is_less_than;
10464   bool inserted = false;
10465   for (vector<diff*>::iterator i = priv_->children_.begin();
10466        i != priv_->children_.end();
10467        ++i)
10468     // Look for the point where to insert the diff child node.
10469     if (!is_less_than(d.get(), *i))
10470       {
10471 	context()->keep_diff_alive(d);
10472 	priv_->children_.insert(i, d.get());
10473 	// As we have just inserted 'd' into the vector, the iterator
10474 	// 'i' is invalidated.  We must *NOT* use it anymore.
10475 	inserted = true;
10476 	break;
10477       }
10478 
10479   if (!inserted)
10480     {
10481       context()->keep_diff_alive(d);
10482       // We didn't insert anything to the vector, presumably b/c it was
10483       // empty or had one element that was "less than" 'd'.  We can thus
10484       // just append 'd' to the end of the vector.
10485       priv_->children_.push_back(d.get());
10486     }
10487 }
10488 
10489 /// @return the bare edit script of the functions changed as recorded
10490 /// by the diff.
10491 edit_script&
function_changes() const10492 corpus_diff::function_changes() const
10493 {return priv_->fns_edit_script_;}
10494 
10495 /// @return the bare edit script of the variables changed as recorded
10496 /// by the diff.
10497 edit_script&
variable_changes() const10498 corpus_diff::variable_changes() const
10499 {return priv_->vars_edit_script_;}
10500 
10501 /// Test if the soname of the underlying corpus has changed.
10502 ///
10503 /// @return true iff the soname has changed.
10504 bool
soname_changed() const10505 corpus_diff::soname_changed() const
10506 {return !priv_->sonames_equal_;}
10507 
10508 /// Test if the architecture of the underlying corpus has changed.
10509 ///
10510 /// @return true iff the architecture has changed.
10511 bool
architecture_changed() const10512 corpus_diff::architecture_changed() const
10513 {return !priv_->architectures_equal_;}
10514 
10515 /// Getter for the deleted functions of the diff.
10516 ///
10517 /// @return the the deleted functions of the diff.
10518 const string_function_ptr_map&
deleted_functions() const10519 corpus_diff::deleted_functions() const
10520 {return priv_->deleted_fns_;}
10521 
10522 /// Getter for the added functions of the diff.
10523 ///
10524 /// @return the added functions of the diff.
10525 const string_function_ptr_map&
added_functions()10526 corpus_diff::added_functions()
10527 {return priv_->added_fns_;}
10528 
10529 /// Getter for the functions which signature didn't change, but which
10530 /// do have some indirect changes in their parms.
10531 ///
10532 /// @return a non-sorted map of functions which signature didn't
10533 /// change, but which do have some indirect changes in their parms.
10534 /// The key of the map is a unique identifier for the function; it's
10535 /// usually made of the name and version of the underlying ELF symbol
10536 /// of the function for corpora that were built from ELF files.
10537 const string_function_decl_diff_sptr_map&
changed_functions()10538 corpus_diff::changed_functions()
10539 {return priv_->changed_fns_map_;}
10540 
10541 /// Getter for a sorted vector of functions which signature didn't
10542 /// change, but which do have some indirect changes in their parms.
10543 ///
10544 /// @return a sorted vector of functions which signature didn't
10545 /// change, but which do have some indirect changes in their parms.
10546 const function_decl_diff_sptrs_type&
changed_functions_sorted()10547 corpus_diff::changed_functions_sorted()
10548 {return priv_->changed_fns_;}
10549 
10550 /// Getter for the variables that got deleted from the first subject
10551 /// of the diff.
10552 ///
10553 /// @return the map of deleted variable.
10554 const string_var_ptr_map&
deleted_variables() const10555 corpus_diff::deleted_variables() const
10556 {return priv_->deleted_vars_;}
10557 
10558 /// Getter for the added variables of the diff.
10559 ///
10560 /// @return the map of added variable.
10561 const string_var_ptr_map&
added_variables() const10562 corpus_diff::added_variables() const
10563 {return priv_->added_vars_;}
10564 
10565 /// Getter for the non-sorted map of variables which signature didn't
10566 /// change but which do have some indirect changes in some sub-types.
10567 ///
10568 /// @return the non-sorted map of changed variables.
10569 const string_var_diff_sptr_map&
changed_variables()10570 corpus_diff::changed_variables()
10571 {return priv_->changed_vars_map_;}
10572 
10573 /// Getter for the sorted vector of variables which signature didn't
10574 /// change but which do have some indirect changes in some sub-types.
10575 ///
10576 /// @return a sorted vector of changed variables.
10577 const var_diff_sptrs_type&
changed_variables_sorted()10578 corpus_diff::changed_variables_sorted()
10579 {return priv_->sorted_changed_vars_;}
10580 
10581 /// Getter for function symbols not referenced by any debug info and
10582 /// that got deleted.
10583 ///
10584 /// @return a map of elf function symbols not referenced by any debug
10585 /// info and that got deleted.
10586 const string_elf_symbol_map&
deleted_unrefed_function_symbols() const10587 corpus_diff::deleted_unrefed_function_symbols() const
10588 {return priv_->deleted_unrefed_fn_syms_;}
10589 
10590 /// Getter for function symbols not referenced by any debug info and
10591 /// that got added.
10592 ///
10593 /// @return a map of elf function symbols not referenced by any debug
10594 /// info and that got added.
10595 const string_elf_symbol_map&
added_unrefed_function_symbols() const10596 corpus_diff::added_unrefed_function_symbols() const
10597 {return priv_->added_unrefed_fn_syms_;}
10598 
10599 /// Getter for variable symbols not referenced by any debug info and
10600 /// that got deleted.
10601 ///
10602 /// @return a map of elf variable symbols not referenced by any debug
10603 /// info and that got deleted.
10604 const string_elf_symbol_map&
deleted_unrefed_variable_symbols() const10605 corpus_diff::deleted_unrefed_variable_symbols() const
10606 {return priv_->deleted_unrefed_var_syms_;}
10607 
10608 /// Getter for variable symbols not referenced by any debug info and
10609 /// that got added.
10610 ///
10611 /// @return a map of elf variable symbols not referenced by any debug
10612 /// info and that got added.
10613 const string_elf_symbol_map&
added_unrefed_variable_symbols() const10614 corpus_diff::added_unrefed_variable_symbols() const
10615 {return priv_->added_unrefed_var_syms_;}
10616 
10617 /// Getter for a map of deleted types that are not reachable from
10618 /// global functions/variables.
10619 ///
10620 /// @return a map that associates pretty representation of deleted
10621 /// unreachable types and said types.
10622 const string_type_base_sptr_map&
deleted_unreachable_types() const10623 corpus_diff::deleted_unreachable_types() const
10624 {return priv_->deleted_unreachable_types_;}
10625 
10626 /// Getter of a sorted vector of deleted types that are not reachable
10627 /// from global functions/variables.
10628 ///
10629 /// @return a sorted vector of deleted types that are not reachable
10630 /// from global functions/variables.  The types are lexicographically
10631 /// sorted by considering their pretty representation.
10632 const vector<type_base_sptr>&
deleted_unreachable_types_sorted() const10633 corpus_diff::deleted_unreachable_types_sorted() const
10634 {
10635   if (priv_->deleted_unreachable_types_sorted_.empty())
10636     if (!priv_->deleted_unreachable_types_.empty())
10637       sort_string_type_base_sptr_map(priv_->deleted_unreachable_types_,
10638 				     priv_->deleted_unreachable_types_sorted_);
10639 
10640   return priv_->deleted_unreachable_types_sorted_;
10641 }
10642 
10643 /// Getter for a map of added types that are not reachable from global
10644 /// functions/variables.
10645 ///
10646 /// @return a map that associates pretty representation of added
10647 /// unreachable types and said types.
10648 const string_type_base_sptr_map&
added_unreachable_types() const10649 corpus_diff::added_unreachable_types() const
10650 {return priv_->added_unreachable_types_;}
10651 
10652 /// Getter of a sorted vector of added types that are not reachable
10653 /// from global functions/variables.
10654 ///
10655 /// @return a sorted vector of added types that are not reachable from
10656 /// global functions/variables.  The types are lexicographically
10657 /// sorted by considering their pretty representation.
10658 const vector<type_base_sptr>&
added_unreachable_types_sorted() const10659 corpus_diff::added_unreachable_types_sorted() const
10660 {
10661   if (priv_->added_unreachable_types_sorted_.empty())
10662     if (!priv_->added_unreachable_types_.empty())
10663       sort_string_type_base_sptr_map(priv_->added_unreachable_types_,
10664 				     priv_->added_unreachable_types_sorted_);
10665 
10666   return priv_->added_unreachable_types_sorted_;
10667 }
10668 
10669 /// Getter for a map of changed types that are not reachable from
10670 /// global functions/variables.
10671 ///
10672 /// @return a map that associates pretty representation of changed
10673 /// unreachable types and said types.
10674 const string_diff_sptr_map&
changed_unreachable_types() const10675 corpus_diff::changed_unreachable_types() const
10676 {return priv_->changed_unreachable_types_;}
10677 
10678 /// Getter of a sorted vector of changed types that are not reachable
10679 /// from global functions/variables.
10680 ///
10681 /// @return a sorted vector of changed types that are not reachable
10682 /// from global functions/variables.  The diffs are lexicographically
10683 /// sorted by considering their pretty representation.
10684 const vector<diff_sptr>&
changed_unreachable_types_sorted() const10685 corpus_diff::changed_unreachable_types_sorted() const
10686 {return priv_->changed_unreachable_types_sorted();}
10687 
10688 /// Getter of the diff context of this diff
10689 ///
10690 /// @return the diff context for this diff.
10691 const diff_context_sptr
context() const10692 corpus_diff::context() const
10693 {return priv_->get_context();}
10694 
10695 /// @return the pretty representation for the current instance of @ref
10696 /// corpus_diff
10697 const string&
get_pretty_representation() const10698 corpus_diff::get_pretty_representation() const
10699 {
10700   if (priv_->pretty_representation_.empty())
10701     {
10702       std::ostringstream o;
10703       o << "corpus_diff["
10704 	<< first_corpus()->get_path()
10705 	<< ", "
10706 	<< second_corpus()->get_path()
10707 	<< "]";
10708       priv_->pretty_representation_ = o.str();
10709     }
10710   return priv_->pretty_representation_;
10711 }
10712 /// Return true iff the current @ref corpus_diff node carries a
10713 /// change.
10714 ///
10715 /// @return true iff the current diff node carries a change.
10716 bool
has_changes() const10717 corpus_diff::has_changes() const
10718 {
10719   return (soname_changed()
10720 	  || architecture_changed()
10721 	  || !(priv_->deleted_fns_.empty()
10722 	       && priv_->added_fns_.empty()
10723 	       && priv_->changed_fns_map_.empty()
10724 	       && priv_->deleted_vars_.empty()
10725 	       && priv_->added_vars_.empty()
10726 	       && priv_->changed_vars_map_.empty()
10727 	       && priv_->added_unrefed_fn_syms_.empty()
10728 	       && priv_->deleted_unrefed_fn_syms_.empty()
10729 	       && priv_->added_unrefed_var_syms_.empty()
10730 	       && priv_->deleted_unrefed_var_syms_.empty()
10731 	       && priv_->deleted_unreachable_types_.empty()
10732 	       && priv_->added_unreachable_types_.empty()
10733 	       && priv_->changed_unreachable_types_.empty()));
10734 }
10735 
10736 /// Test if the current instance of @ref corpus_diff carries changes
10737 /// that we are sure are incompatible.  By incompatible change we mean
10738 /// a change that "breaks" the ABI of the corpus we are looking at.
10739 ///
10740 /// In concrete terms, this function considers the following changes
10741 /// as being ABI incompatible for sure:
10742 ///
10743 ///   - a soname change
10744 ///   - if exported functions or variables got removed
10745 ///
10746 /// Note that subtype changes *can* represent changes that break ABI
10747 /// too.  But they also can be changes that are OK, ABI-wise.
10748 ///
10749 /// It's up to the user to provide suppression specifications to say
10750 /// explicitely which subtype change is OK.  The remaining sub-type
10751 /// changes are then considered to be ABI incompatible.  But to test
10752 /// if such ABI incompatible subtype changes are present you need to
10753 /// use the function @ref corpus_diff::has_net_subtype_changes()
10754 ///
10755 /// @return true iff the current instance of @ref corpus_diff carries
10756 /// changes that we are sure are ABI incompatible.
10757 bool
has_incompatible_changes() const10758 corpus_diff::has_incompatible_changes() const
10759 {
10760   const diff_stats& stats = const_cast<corpus_diff*>(this)->
10761     apply_filters_and_suppressions_before_reporting();
10762 
10763   return (soname_changed() || architecture_changed()
10764 	  || stats.net_num_func_removed() != 0
10765 	  || (stats.num_func_with_virtual_offset_changes() != 0
10766 	      // If all reports about functions with sub-type changes
10767 	      // have been suppressed, then even those about functions
10768 	      // that are virtual don't matter anymore because the
10769 	      // user willingly requested to shut them down
10770 	      && stats.net_num_func_changed() != 0)
10771 	  || stats.net_num_vars_removed() != 0
10772 	  || stats.net_num_removed_func_syms() != 0
10773 	  || stats.net_num_removed_var_syms() != 0
10774 	  || stats.net_num_removed_unreachable_types() != 0
10775 	  || stats.net_num_changed_unreachable_types() != 0);
10776 }
10777 
10778 /// Test if the current instance of @ref corpus_diff carries subtype
10779 /// changes whose reports are not suppressed by any suppression
10780 /// specification.  In effect, these are deemed incompatible ABI
10781 /// changes.
10782 ///
10783 /// @return true iff the the current instance of @ref corpus_diff
10784 /// carries subtype changes that are deemed incompatible ABI changes.
10785 bool
has_net_subtype_changes() const10786 corpus_diff::has_net_subtype_changes() const
10787 {
10788   const diff_stats& stats = const_cast<corpus_diff*>(this)->
10789       apply_filters_and_suppressions_before_reporting();
10790 
10791   return (stats.net_num_func_changed() != 0
10792 	  || stats.net_num_vars_changed() != 0
10793 	  || stats.net_num_removed_unreachable_types() != 0
10794 	  || stats.net_num_changed_unreachable_types() != 0);
10795 }
10796 
10797 /// Test if the current instance of @ref corpus_diff carries changes
10798 /// whose reports are not suppressed by any suppression specification.
10799 /// In effect, these are deemed incompatible ABI changes.
10800 ///
10801 /// @return true iff the the current instance of @ref corpus_diff
10802 /// carries subtype changes that are deemed incompatible ABI changes.
10803 bool
has_net_changes() const10804 corpus_diff::has_net_changes() const
10805 {return  context()->get_reporter()->diff_has_net_changes(this);}
10806 
10807 /// Apply the different filters that are registered to be applied to
10808 /// the diff tree; that includes the categorization filters.  Also,
10809 /// apply the suppression interpretation filters.
10810 ///
10811 /// After the filters are applied, this function calculates some
10812 /// statistics about the changes carried by the current instance of
10813 /// @ref corpus_diff.  These statistics are represented by an instance
10814 /// of @ref corpus_diff::diff_stats.
10815 ///
10816 /// This member function is called by the reporting function
10817 /// corpus_diff::report().
10818 ///
10819 /// Note that for a given instance of corpus_diff, this function
10820 /// applies the filters and suppressions only the first time it is
10821 /// invoked.  Subsequent invocations just return the instance of
10822 /// corpus_diff::diff_stats that was cached after the first
10823 /// invocation.
10824 ///
10825 /// @return a reference to the statistics about the changes carried by
10826 /// the current instance of @ref corpus_diff.
10827 const corpus_diff::diff_stats&
apply_filters_and_suppressions_before_reporting()10828 corpus_diff::apply_filters_and_suppressions_before_reporting()
10829 {
10830   if (priv_->diff_stats_)
10831     return *priv_->diff_stats_;
10832 
10833   apply_suppressions(this);
10834   priv_->diff_stats_.reset(new diff_stats(context()));
10835   mark_leaf_diff_nodes();
10836   priv_->apply_filters_and_compute_diff_stats(*priv_->diff_stats_);
10837   return *priv_->diff_stats_;
10838 }
10839 
10840 /// A visitor that marks leaf diff nodes by storing them in the
10841 /// instance of @ref diff_maps returned by
10842 /// corpus_diff::get_leaf_diffs() invoked on the current instance of
10843 /// corpus_diff.
10844 struct leaf_diff_node_marker_visitor : public diff_node_visitor
10845 {
10846   /// This is called when the visitor visits a diff node.
10847   ///
10848   /// It basically tests if the diff node being visited is a leaf diff
10849   /// node - that is, it contains local changes.  If it does, then the
10850   /// node is added to the set of maps that hold leaf diffs in the
10851   /// current corpus_diff.
10852   ///
10853   /// Note that only leaf nodes that are reachable from public
10854   /// interfaces (global functions or variables) are collected by this
10855   /// visitor.
10856   ///
10857   /// @param d the diff node being visited.
10858   virtual void
visit_beginabigail::comparison::leaf_diff_node_marker_visitor10859   visit_begin(diff *d)
10860   {
10861     if (d->has_local_changes()
10862 	// A leaf basic (or class/union) type name change makes no
10863 	// sense when showing just leaf changes.  It only makes sense
10864 	// when it can explain the details about a non-leaf change.
10865 	// In other words, it doesn't make sense to say that an "int"
10866 	// became "unsigned int".  But it does make sense to say that
10867 	// a typedef changed because its underlying type was 'int' and
10868 	// is now an "unsigned int".
10869 	&& !filtering::has_basic_or_class_type_name_change(d)
10870 	// Similarly, a *local* change describing a type that changed
10871 	// its nature doesn't make sense.
10872 	&& !is_distinct_diff(d)
10873 	// Similarly, a pointer (or reference or array), a typedef or
10874 	// qualified type change in itself doesn't make sense.  It
10875 	// would rather make sense to show that pointer change as part
10876 	// of the variable change whose pointer type changed, for
10877 	// instance.
10878 	&& !is_pointer_diff(d)
10879 	&& !is_reference_diff(d)
10880 	&& !is_qualified_type_diff(d)
10881 	&& !is_typedef_diff(d)
10882 	&& !is_array_diff(d)
10883 	// Similarly a parameter change in itself doesn't make sense.
10884 	// It should have already been reported as part of the change
10885 	// of the function it belongs to.
10886 	&& !is_fn_parm_diff(d)
10887 	// An anonymous class or union diff doesn't make sense on its
10888 	// own.  It must have been described already by the diff of
10889 	// the enclosing struct or union if 'd' is from an anonymous
10890 	// data member, or from a typedef change if 'd' is from a
10891 	// typedef change which underlying type is an anonymous
10892 	// struct/union.
10893 	&& !is_anonymous_class_or_union_diff(d)
10894 	// Don't show decl-only-ness changes either.
10895 	&& !filtering::has_decl_only_def_change(d)
10896 	// Sometime, we can encounter artifacts of bogus DWARF that
10897 	// yield a diff node for a decl-only class (and empty class
10898 	// with the is_declaration flag set) that carries a non-zero
10899 	// size!  And of course at some point that non-zero size
10900 	// changes.  We need to be able to detect that.
10901 	&& !filtering::is_decl_only_class_with_size_change(d))
10902       {
10903 	diff_context_sptr ctxt = d->context();
10904 	const corpus_diff *corpus_diff_node = ctxt->get_corpus_diff().get();
10905 	ABG_ASSERT(corpus_diff_node);
10906 
10907 	if (diff *iface_diff = get_current_topmost_iface_diff())
10908 	  {
10909 	    type_or_decl_base_sptr iface = iface_diff->first_subject();
10910 	    // So, this diff node that is reachable from a global
10911 	    // function or variable carries a leaf change.  Let's add
10912 	    // it to the set of of leaf diffs of corpus_diff_node.
10913 	    const_cast<corpus_diff*>(corpus_diff_node)->
10914 	      get_leaf_diffs().insert_diff_node(d, iface);
10915 	  }
10916       }
10917   }
10918 }; // end struct leaf_diff_node_marker_visitor
10919 
10920 /// Walks the diff nodes associated to the current corpus diff and
10921 /// mark those that carry local changes.  They are said to be leaf
10922 /// diff nodes.
10923 ///
10924 /// The marked nodes are available from the
10925 /// corpus_diff::get_leaf_diffs() function.
10926 void
mark_leaf_diff_nodes()10927 corpus_diff::mark_leaf_diff_nodes()
10928 {
10929   if (!has_changes())
10930     return;
10931 
10932   if (!context()->show_leaf_changes_only())
10933     return;
10934 
10935   leaf_diff_node_marker_visitor v;
10936   context()->forget_visited_diffs();
10937   bool s = context()->visiting_a_node_twice_is_forbidden();
10938   context()->forbid_visiting_a_node_twice(true);
10939   context()->forbid_visiting_a_node_twice_per_interface(true);
10940   traverse(v);
10941   context()->forbid_visiting_a_node_twice(s);
10942   context()->forbid_visiting_a_node_twice_per_interface(false);
10943 }
10944 
10945 /// Get the set of maps that contain leaf nodes.  A leaf node being a
10946 /// node with a local change.
10947 ///
10948 /// @return the set of maps that contain leaf nodes.  A leaf node
10949 /// being a node with a local change.
10950 diff_maps&
get_leaf_diffs()10951 corpus_diff::get_leaf_diffs()
10952 {return priv_->leaf_diffs_;}
10953 
10954 /// Get the set of maps that contain leaf nodes.  A leaf node being a
10955 /// node with a local change.
10956 ///
10957 /// @return the set of maps that contain leaf nodes.  A leaf node
10958 /// being a node with a local change.
10959 const diff_maps&
get_leaf_diffs() const10960 corpus_diff::get_leaf_diffs() const
10961 {return priv_->leaf_diffs_;}
10962 
10963 /// Report the diff in a serialized form.
10964 ///
10965 /// @param out the stream to serialize the diff to.
10966 ///
10967 /// @param indent the prefix to use for the indentation of this
10968 /// serialization.
10969 void
report(ostream & out,const string & indent) const10970 corpus_diff::report(ostream& out, const string& indent) const
10971 {
10972   context()->get_reporter()->report(*this, out, indent);
10973 }
10974 
10975 /// Traverse the diff sub-tree under the current instance corpus_diff.
10976 ///
10977 /// @param v the visitor to invoke on each diff node of the sub-tree.
10978 ///
10979 /// @return true if the traversing has to keep going on, false otherwise.
10980 bool
traverse(diff_node_visitor & v)10981 corpus_diff::traverse(diff_node_visitor& v)
10982 {
10983   finish_diff_type();
10984 
10985   v.visit_begin(this);
10986 
10987   if (!v.visit(this, true))
10988     {
10989       v.visit_end(this);
10990       return false;
10991     }
10992 
10993   for (function_decl_diff_sptrs_type::const_iterator i =
10994 	 changed_functions_sorted().begin();
10995        i != changed_functions_sorted().end();
10996        ++i)
10997     {
10998       if (diff_sptr d = *i)
10999 	{
11000 	  const diff_context_sptr &ctxt = context();
11001 	  if (ctxt->visiting_a_node_twice_is_forbidden_per_interface())
11002 	    ctxt->forget_visited_diffs();
11003 
11004 	  v.set_current_topmost_iface_diff(d.get());
11005 
11006 	  if (!d->traverse(v))
11007 	    {
11008 	      v.visit_end(this);
11009 	      v.set_current_topmost_iface_diff(0);
11010 	      return false;
11011 	    }
11012 	}
11013     }
11014 
11015   for (var_diff_sptrs_type::const_iterator i =
11016 	 changed_variables_sorted().begin();
11017        i != changed_variables_sorted().end();
11018        ++i)
11019     {
11020       if (diff_sptr d = *i)
11021 	{
11022 	  const diff_context_sptr &ctxt = context();
11023 	  if (ctxt->visiting_a_node_twice_is_forbidden_per_interface())
11024 	    ctxt->forget_visited_diffs();
11025 
11026 	  v.set_current_topmost_iface_diff(d.get());
11027 
11028 	  if (!d->traverse(v))
11029 	    {
11030 	      v.visit_end(this);
11031 	      v.set_current_topmost_iface_diff(0);
11032 	      return false;
11033 	    }
11034 	}
11035     }
11036 
11037   v.set_current_topmost_iface_diff(0);
11038 
11039   // Traverse the changed unreachable type diffs.  These diffs are on
11040   // types that are not reachable from global functions or variables.
11041   for (vector<diff_sptr>::const_iterator i =
11042 	 changed_unreachable_types_sorted().begin();
11043        i != changed_unreachable_types_sorted().end();
11044        ++i)
11045     {
11046       if (diff_sptr d = *i)
11047 	{
11048 	  const diff_context_sptr &ctxt = context();
11049 	  if (ctxt->visiting_a_node_twice_is_forbidden_per_interface())
11050 	    ctxt->forget_visited_diffs();
11051 
11052 	  if (!d->traverse(v))
11053 	    {
11054 	      v.visit_end(this);
11055 	      return false;
11056 	    }
11057 	}
11058     }
11059 
11060   v.visit_end(this);
11061   return true;
11062 }
11063 
11064 /// Compute the diff between two instances of @ref corpus.
11065 ///
11066 /// Note that the two corpora must have been created in the same @ref
11067 /// environment, otherwise, this function aborts.
11068 ///
11069 /// @param f the first @ref corpus to consider for the diff.
11070 ///
11071 /// @param s the second @ref corpus to consider for the diff.
11072 ///
11073 /// @param ctxt the diff context to use.
11074 ///
11075 /// @return the resulting diff between the two @ref corpus.
11076 corpus_diff_sptr
compute_diff(const corpus_sptr f,const corpus_sptr s,diff_context_sptr ctxt)11077 compute_diff(const corpus_sptr	f,
11078 	     const corpus_sptr	s,
11079 	     diff_context_sptr	ctxt)
11080 {
11081   typedef corpus::functions::const_iterator fns_it_type;
11082   typedef corpus::variables::const_iterator vars_it_type;
11083   typedef elf_symbols::const_iterator symbols_it_type;
11084   typedef diff_utils::deep_ptr_eq_functor eq_type;
11085   typedef vector<type_base_wptr>::const_iterator type_base_wptr_it_type;
11086 
11087   ABG_ASSERT(f && s);
11088 
11089   // We can only compare two corpora that were built out of the same
11090   // environment.
11091   ABG_ASSERT(f->get_environment() == s->get_environment());
11092 
11093   if (!ctxt)
11094     ctxt.reset(new diff_context);
11095 
11096   corpus_diff_sptr r(new corpus_diff(f, s, ctxt));
11097 
11098   ctxt->set_corpus_diff(r);
11099 
11100   r->priv_->sonames_equal_ = f->get_soname() == s->get_soname();
11101 
11102   r->priv_->architectures_equal_ =
11103     f->get_architecture_name() == s->get_architecture_name();
11104 
11105   // Compute the diff of publicly defined and exported functions
11106   diff_utils::compute_diff<fns_it_type, eq_type>(f->get_functions().begin(),
11107 						 f->get_functions().end(),
11108 						 s->get_functions().begin(),
11109 						 s->get_functions().end(),
11110 						 r->priv_->fns_edit_script_);
11111 
11112   // Compute the diff of publicly defined and exported variables.
11113   diff_utils::compute_diff<vars_it_type, eq_type>
11114     (f->get_variables().begin(), f->get_variables().end(),
11115      s->get_variables().begin(), s->get_variables().end(),
11116      r->priv_->vars_edit_script_);
11117 
11118   // Compute the diff of function elf symbols not referenced by debug
11119   // info.
11120   diff_utils::compute_diff<symbols_it_type, eq_type>
11121     (f->get_unreferenced_function_symbols().begin(),
11122      f->get_unreferenced_function_symbols().end(),
11123      s->get_unreferenced_function_symbols().begin(),
11124      s->get_unreferenced_function_symbols().end(),
11125      r->priv_->unrefed_fn_syms_edit_script_);
11126 
11127   // Compute the diff of variable elf symbols not referenced by debug
11128   // info.
11129     diff_utils::compute_diff<symbols_it_type, eq_type>
11130     (f->get_unreferenced_variable_symbols().begin(),
11131      f->get_unreferenced_variable_symbols().end(),
11132      s->get_unreferenced_variable_symbols().begin(),
11133      s->get_unreferenced_variable_symbols().end(),
11134      r->priv_->unrefed_var_syms_edit_script_);
11135 
11136     if (ctxt->show_unreachable_types())
11137       // Compute the diff of types not reachable from public functions
11138       // or global variables that are exported.
11139       diff_utils::compute_diff<type_base_wptr_it_type, eq_type>
11140 	(f->get_types_not_reachable_from_public_interfaces().begin(),
11141 	 f->get_types_not_reachable_from_public_interfaces().end(),
11142 	 s->get_types_not_reachable_from_public_interfaces().begin(),
11143 	 s->get_types_not_reachable_from_public_interfaces().end(),
11144 	 r->priv_->unreachable_types_edit_script_);
11145 
11146   r->priv_->ensure_lookup_tables_populated();
11147 
11148   return r;
11149 }
11150 
11151 // </corpus stuff>
11152 
11153 /// Compute the diff between two instances of @ref corpus_group.
11154 ///
11155 /// Note that the two corpus_diff must have been created in the same
11156 /// @ref environment, otherwise, this function aborts.
11157 ///
11158 /// @param f the first @ref corpus_group to consider for the diff.
11159 ///
11160 /// @param s the second @ref corpus_group to consider for the diff.
11161 ///
11162 /// @param ctxt the diff context to use.
11163 ///
11164 /// @return the resulting diff between the two @ref corpus_group.
11165 corpus_diff_sptr
compute_diff(const corpus_group_sptr & f,const corpus_group_sptr & s,diff_context_sptr ctxt)11166 compute_diff(const corpus_group_sptr&	f,
11167 	     const corpus_group_sptr&	s,
11168 	     diff_context_sptr	ctxt)
11169 {
11170 
11171   corpus_sptr c1 = f;
11172   corpus_sptr c2 = s;
11173 
11174   return compute_diff(c1, c2, ctxt);
11175 }
11176 
11177 // <corpus_group stuff>
11178 
11179 // </corpus_group stuff>
11180 // <diff_node_visitor stuff>
11181 
11182 /// The private data of the @diff_node_visitor type.
11183 struct diff_node_visitor::priv
11184 {
11185   diff*	topmost_interface_diff;
11186   visiting_kind kind;
11187 
privabigail::comparison::diff_node_visitor::priv11188   priv()
11189     : topmost_interface_diff(),
11190       kind()
11191   {}
11192 
privabigail::comparison::diff_node_visitor::priv11193   priv(visiting_kind k)
11194     : topmost_interface_diff(),
11195       kind(k)
11196   {}
11197 }; // end struct diff_node_visitor
11198 
11199 /// Default constructor of the @ref diff_node_visitor type.
diff_node_visitor()11200 diff_node_visitor::diff_node_visitor()
11201   : priv_(new priv)
11202 {}
11203 
11204 diff_node_visitor::~diff_node_visitor() = default;
11205 
11206 /// Constructor of the @ref diff_node_visitor type.
11207 ///
11208 /// @param k how the visiting has to be performed.
diff_node_visitor(visiting_kind k)11209 diff_node_visitor::diff_node_visitor(visiting_kind k)
11210   : priv_(new priv(k))
11211 {}
11212 
11213 /// Getter for the visiting policy of the traversing code while
11214 /// invoking this visitor.
11215 ///
11216 /// @return the visiting policy used by the traversing code when
11217 /// invoking this visitor.
11218 visiting_kind
get_visiting_kind() const11219 diff_node_visitor::get_visiting_kind() const
11220 {return priv_->kind;}
11221 
11222 /// Setter for the visiting policy of the traversing code while
11223 /// invoking this visitor.
11224 ///
11225 /// @param v a bit map representing the new visiting policy used by
11226 /// the traversing code when invoking this visitor.
11227 void
set_visiting_kind(visiting_kind v)11228 diff_node_visitor::set_visiting_kind(visiting_kind v)
11229 {priv_->kind = v;}
11230 
11231 /// Setter for the visiting policy of the traversing code while
11232 /// invoking this visitor.  This one makes a logical or between the
11233 /// current policy and the bitmap given in argument and assigns the
11234 /// current policy to the result.
11235 ///
11236 /// @param v a bitmap representing the visiting policy to or with
11237 /// the current policy.
11238 void
or_visiting_kind(visiting_kind v)11239 diff_node_visitor::or_visiting_kind(visiting_kind v)
11240 {priv_->kind = priv_->kind | v;}
11241 
11242 /// Setter of the diff current topmost interface which is impacted by
11243 /// the current diff node being visited.
11244 ///
11245 /// @param d the current topmost interface diff impacted.
11246 void
set_current_topmost_iface_diff(diff * d)11247 diff_node_visitor::set_current_topmost_iface_diff(diff* d)
11248 {priv_->topmost_interface_diff = d;}
11249 
11250 /// Getter of the diff current topmost interface which is impacted by
11251 /// the current diff node being visited.
11252 ///
11253 /// @return the current topmost interface diff impacted.
11254 diff*
get_current_topmost_iface_diff() const11255 diff_node_visitor::get_current_topmost_iface_diff() const
11256 {return priv_->topmost_interface_diff;}
11257 
11258 /// This is called by the traversing code on a @ref diff node just
11259 /// before visiting it.  That is, before visiting it and its children
11260 /// node.
11261 ///
11262 /// @param d the diff node to visit.
11263 void
visit_begin(diff *)11264 diff_node_visitor::visit_begin(diff* /*p*/)
11265 {}
11266 
11267 /// This is called by the traversing code on a @ref diff node just
11268 /// after visiting it.  That is after visiting it and its children
11269 /// nodes.
11270 ///
11271 /// @param d the diff node that got visited.
11272 void
visit_end(diff *)11273 diff_node_visitor::visit_end(diff* /*p*/)
11274 {}
11275 
11276 /// This is called by the traversing code on a @ref corpus_diff node
11277 /// just before visiting it.  That is, before visiting it and its
11278 /// children node.
11279 ///
11280 /// @param p the corpus_diff node to visit.
11281 ///
11282 void
visit_begin(corpus_diff *)11283 diff_node_visitor::visit_begin(corpus_diff* /*p*/)
11284 {}
11285 
11286 /// This is called by the traversing code on a @ref corpus_diff node
11287 /// just after visiting it.  That is after visiting it and its children
11288 /// nodes.
11289 ///
11290 /// @param d the diff node that got visited.
11291 void
visit_end(corpus_diff *)11292 diff_node_visitor::visit_end(corpus_diff* /*d*/)
11293 {}
11294 
11295 /// Default visitor implementation
11296 ///
11297 /// @return true
11298 bool
visit(diff *,bool)11299 diff_node_visitor::visit(diff*, bool)
11300 {return true;}
11301 
11302 /// Default visitor implementation.
11303 ///
11304 /// @return true
11305 bool
visit(distinct_diff * dif,bool pre)11306 diff_node_visitor::visit(distinct_diff* dif, bool pre)
11307 {
11308   diff* d = dif;
11309   visit(d, pre);
11310 
11311   return true;
11312 }
11313 
11314 /// Default visitor implementation.
11315 ///
11316 /// @return true
11317 bool
visit(var_diff * dif,bool pre)11318 diff_node_visitor::visit(var_diff* dif, bool pre)
11319 {
11320   diff* d = dif;
11321   visit(d, pre);
11322 
11323   return true;
11324 }
11325 
11326 /// Default visitor implementation.
11327 ///
11328 /// @return true
11329 bool
visit(pointer_diff * dif,bool pre)11330 diff_node_visitor::visit(pointer_diff* dif, bool pre)
11331 {
11332   diff* d = dif;
11333   visit(d, pre);
11334 
11335   return true;
11336 }
11337 
11338 /// Default visitor implementation.
11339 ///
11340 /// @return true
11341 bool
visit(reference_diff * dif,bool pre)11342 diff_node_visitor::visit(reference_diff* dif, bool pre)
11343 {
11344   diff* d = dif;
11345   visit(d, pre);
11346 
11347   return true;
11348 }
11349 
11350 /// Default visitor implementation.
11351 ///
11352 /// @return true
11353 bool
visit(qualified_type_diff * dif,bool pre)11354 diff_node_visitor::visit(qualified_type_diff* dif, bool pre)
11355 {
11356   diff* d = dif;
11357   visit(d, pre);
11358 
11359   return true;
11360 }
11361 
11362 /// Default visitor implementation.
11363 ///
11364 /// @return true
11365 bool
visit(enum_diff * dif,bool pre)11366 diff_node_visitor::visit(enum_diff* dif, bool pre)
11367 {
11368   diff* d = dif;
11369   visit(d, pre);
11370 
11371   return true;
11372 }
11373 
11374 /// Default visitor implementation.
11375 ///
11376 /// @return true
11377 bool
visit(class_diff * dif,bool pre)11378 diff_node_visitor::visit(class_diff* dif, bool pre)
11379 {
11380   diff* d = dif;
11381   visit(d, pre);
11382 
11383   return true;
11384 }
11385 
11386 /// Default visitor implementation.
11387 ///
11388 /// @return true
11389 bool
visit(base_diff * dif,bool pre)11390 diff_node_visitor::visit(base_diff* dif, bool pre)
11391 {
11392   diff* d = dif;
11393   visit(d, pre);
11394 
11395   return true;
11396 }
11397 
11398 /// Default visitor implementation.
11399 ///
11400 /// @return true
11401 bool
visit(scope_diff * dif,bool pre)11402 diff_node_visitor::visit(scope_diff* dif, bool pre)
11403 {
11404   diff* d = dif;
11405   visit(d, pre);
11406 
11407   return true;
11408 }
11409 
11410 /// Default visitor implementation.
11411 ///
11412 /// @return true
11413 bool
visit(function_decl_diff * dif,bool pre)11414 diff_node_visitor::visit(function_decl_diff* dif, bool pre)
11415 {
11416   diff* d = dif;
11417   visit(d, pre);
11418 
11419   return true;
11420 }
11421 
11422 /// Default visitor implementation.
11423 ///
11424 /// @return true
11425 bool
visit(type_decl_diff * dif,bool pre)11426 diff_node_visitor::visit(type_decl_diff* dif, bool pre)
11427 {
11428   diff* d = dif;
11429   visit(d, pre);
11430 
11431   return true;
11432 }
11433 
11434 /// Default visitor implementation.
11435 ///
11436 /// @return true
11437 bool
visit(typedef_diff * dif,bool pre)11438 diff_node_visitor::visit(typedef_diff* dif, bool pre)
11439 {
11440   diff* d = dif;
11441   visit(d, pre);
11442 
11443   return true;
11444 }
11445 
11446 /// Default visitor implementation.
11447 ///
11448 /// @return true
11449 bool
visit(translation_unit_diff * dif,bool pre)11450 diff_node_visitor::visit(translation_unit_diff* dif, bool pre)
11451 {
11452   diff* d = dif;
11453   visit(d, pre);
11454 
11455   return true;
11456 }
11457 
11458 /// Default visitor implementation.
11459 ///
11460 /// @return true
11461 bool
visit(corpus_diff *,bool)11462 diff_node_visitor::visit(corpus_diff*, bool)
11463 {return true;}
11464 
11465 // </diff_node_visitor stuff>
11466 
11467 // <redundant diff node marking>
11468 
11469 // </redundant diff node marking>
11470 
11471 // <diff tree category propagation>
11472 
11473 /// A visitor to propagate the category of a node up to its parent
11474 /// nodes.  This visitor doesn't touch the REDUNDANT_CATEGORY or the
11475 /// SUPPRESSED_CATEGORY because those are propagated using other
11476 /// specific visitors.
11477 struct category_propagation_visitor : public diff_node_visitor
11478 {
11479   virtual void
visit_endabigail::comparison::category_propagation_visitor11480   visit_end(diff* d)
11481   {
11482     // Has this diff node 'd' been already visited ?
11483     bool already_visited = d->context()->diff_has_been_visited(d);
11484 
11485     // The canonical diff node of the class of equivalence of the diff
11486     // node 'd'.
11487     diff* canonical = d->get_canonical_diff();
11488 
11489     // If this class of equivalence of diff node is being visited for
11490     // the first time, then update its canonical node's category too.
11491     bool update_canonical = !already_visited && canonical;
11492 
11493     for (vector<diff*>::const_iterator i = d->children_nodes().begin();
11494 	 i != d->children_nodes().end();
11495 	 ++i)
11496       {
11497 	// If we are visiting the class of equivalence of 'd' for the
11498 	// first time, then let's look at the children of 'd' and
11499 	// propagate their categories to 'd'.
11500 	//
11501 	// If the class of equivalence of 'd' has already been
11502 	// visited, then let's look at the canonical diff nodes of the
11503 	// children of 'd' and propagate their categories to 'd'.
11504 	diff* diff = already_visited
11505 	  ? (*i)->get_canonical_diff()
11506 	  : *i;
11507 
11508 	ABG_ASSERT(diff);
11509 
11510 	diff_category c = diff->get_category();
11511 	// Do not propagate redundant and suppressed categories. Those
11512 	// are propagated in a specific pass elsewhere.
11513 	c &= ~(REDUNDANT_CATEGORY
11514 	       | SUPPRESSED_CATEGORY
11515 	       | PRIVATE_TYPE_CATEGORY);
11516 	// Also, if a (class) type has got a harmful name change, do not
11517 	// propagate harmless name changes coming from its sub-types
11518 	// (i.e, data members) to the class itself.
11519 	if (filtering::has_harmful_name_change(d))
11520 	  c &= ~HARMLESS_DECL_NAME_CHANGE_CATEGORY;
11521 
11522 	d->add_to_category(c);
11523 	if (!already_visited && canonical)
11524 	  if (update_canonical)
11525 	    canonical->add_to_category(c);
11526       }
11527   }
11528 };// end struct category_propagation_visitor
11529 
11530 /// Visit all the nodes of a given sub-tree.  For each node that has a
11531 /// particular category set, propagate that category set up to its
11532 /// parent nodes.
11533 ///
11534 /// @param diff_tree the diff sub-tree to walk for categorization
11535 /// purpose;
11536 void
propagate_categories(diff * diff_tree)11537 propagate_categories(diff* diff_tree)
11538 {
11539   category_propagation_visitor v;
11540   bool s = diff_tree->context()->visiting_a_node_twice_is_forbidden();
11541   diff_tree->context()->forbid_visiting_a_node_twice(true);
11542   diff_tree->context()->forget_visited_diffs();
11543   diff_tree->traverse(v);
11544   diff_tree->context()->forbid_visiting_a_node_twice(s);
11545 }
11546 
11547 /// Visit all the nodes of a given sub-tree.  For each node that has a
11548 /// particular category set, propagate that category set up to its
11549 /// parent nodes.
11550 ///
11551 /// @param diff_tree the diff sub-tree to walk for categorization
11552 /// purpose;
11553 void
propagate_categories(diff_sptr diff_tree)11554 propagate_categories(diff_sptr diff_tree)
11555 {propagate_categories(diff_tree.get());}
11556 
11557 /// Visit all the nodes of a given corpus tree.  For each node that
11558 /// has a particular category set, propagate that category set up to
11559 /// its parent nodes.
11560 ///
11561 /// @param diff_tree the corpus_diff tree to walk for categorization
11562 /// purpose;
11563 void
propagate_categories(corpus_diff * diff_tree)11564 propagate_categories(corpus_diff* diff_tree)
11565 {
11566   category_propagation_visitor v;
11567   bool s = diff_tree->context()->visiting_a_node_twice_is_forbidden();
11568   diff_tree->context()->forbid_visiting_a_node_twice(false);
11569   diff_tree->traverse(v);
11570   diff_tree->context()->forbid_visiting_a_node_twice(s);
11571 }
11572 
11573 /// Visit all the nodes of a given corpus tree.  For each node that
11574 /// has a particular category set, propagate that category set up to
11575 /// its parent nodes.
11576 ///
11577 /// @param diff_tree the corpus_diff tree to walk for categorization
11578 /// purpose;
11579 void
propagate_categories(corpus_diff_sptr diff_tree)11580 propagate_categories(corpus_diff_sptr diff_tree)
11581 {propagate_categories(diff_tree.get());}
11582 
11583 /// A tree node visitor that knows how to categorizes a given diff
11584 /// node in the SUPPRESSED_CATEGORY category and how to propagate that
11585 /// categorization.
11586 struct suppression_categorization_visitor : public diff_node_visitor
11587 {
11588 
11589   /// Before visiting the children of the diff node, check if the node
11590   /// is suppressed by a suppression specification.  If it is, mark
11591   /// the node as belonging to the SUPPRESSED_CATEGORY category.
11592   ///
11593   /// @param p the diff node to visit.
11594   virtual void
visit_beginabigail::comparison::suppression_categorization_visitor11595   visit_begin(diff* d)
11596   {
11597     bool is_private_type = false;
11598     if (d->is_suppressed(is_private_type))
11599       {
11600 	diff_category c = is_private_type
11601 	  ? PRIVATE_TYPE_CATEGORY
11602 	  : SUPPRESSED_CATEGORY;
11603 	d->add_to_local_and_inherited_categories(c);
11604 
11605 	// If a node was suppressed, all the other nodes of its class
11606 	// of equivalence are suppressed too.
11607 	diff *canonical_diff = d->get_canonical_diff();
11608 	if (canonical_diff != d)
11609 	  canonical_diff->add_to_category(c);
11610       }
11611   }
11612 
11613   /// After visiting the children nodes of a given diff node,
11614   /// propagate the SUPPRESSED_CATEGORY from the children nodes to the
11615   /// diff node, if need be.
11616   ///
11617   /// That is, if all children nodes carry a suppressed change the
11618   /// current node should be marked as suppressed as well.
11619   ///
11620   /// In practice, this might be too strong of a condition.  If the
11621   /// current node carries a local change (i.e, a change not carried
11622   /// by any of its children node) and if that change is not
11623   /// suppressed, then the current node should *NOT* be suppressed.
11624   ///
11625   /// But right now, the IR doesn't let us know about local vs
11626   /// children-carried changes.  So we cannot be that precise yet.
11627   virtual void
visit_endabigail::comparison::suppression_categorization_visitor11628   visit_end(diff* d)
11629   {
11630     bool has_non_suppressed_child = false;
11631     bool has_non_empty_child = false;
11632     bool has_suppressed_child = false;
11633     bool has_non_private_child = false;
11634     bool has_private_child = false;
11635 
11636     if (// A node to which we can propagate the "SUPPRESSED_CATEGORY"
11637 	// (or the PRIVATE_TYPE_CATEGORY for the same matter)
11638 	// category from its children is a node which:
11639 	//
11640 	//  1/ hasn't been suppressed already
11641 	//
11642 	//  2/ and has no local change (unless it's a pointer,
11643 	//  reference or qualified diff node).
11644 	//
11645 	//  Note that qualified type and typedef diff nodes are a bit
11646 	//  special.  The local changes of the underlying type are
11647 	//  considered local for the qualified/typedef type, just like
11648 	//  for pointer/reference types.  But then the qualified or
11649 	//  typedef type itself can have local changes of its own, and
11650 	//  those changes are of the kind LOCAL_NON_TYPE_CHANGE_KIND.
11651 	//  So a qualified type which have local changes that are
11652 	//  *NOT* of LOCAL_NON_TYPE_CHANGE_KIND (or that has no local
11653 	//  changes at all) and which is in the PRIVATE_TYPE_CATEGORY
11654 	//  or SUPPRESSED_CATEGORY can see these categories be
11655 	//  propagated.
11656 	//
11657 	// Note that all pointer/reference diff node changes are
11658 	// potentially considered local, i.e, local changes of the
11659 	// pointed-to-type are considered local to the pointer itself.
11660 	//
11661 	// Similarly, changes local to the type of function parameters,
11662 	// variables (and data members) and classes (that are not of
11663 	// LOCAL_NON_TYPE_CHANGE_KIND kind) and that have been
11664 	// suppressed can propagate their SUPPRESSED_CATEGORY-ness to
11665 	// those kinds of diff node.
11666 	!(d->get_category() & SUPPRESSED_CATEGORY)
11667 	&& (!d->has_local_changes()
11668 	    || is_pointer_diff(d)
11669 	    || is_reference_diff(d)
11670 	    || (is_qualified_type_diff(d)
11671 		&& (!(d->has_local_changes() & LOCAL_NON_TYPE_CHANGE_KIND)))
11672 	    || (is_typedef_diff(d)
11673 		&& (!(d->has_local_changes() & LOCAL_NON_TYPE_CHANGE_KIND)))
11674 	    || (is_function_decl_diff(d)
11675 		&& (!(d->has_local_changes() & LOCAL_NON_TYPE_CHANGE_KIND)))
11676 	    || (is_fn_parm_diff(d)
11677 		&& (!(d->has_local_changes() & LOCAL_NON_TYPE_CHANGE_KIND)))
11678 	    || (is_function_type_diff(d)
11679 		&& (!(d->has_local_changes() & LOCAL_NON_TYPE_CHANGE_KIND)))
11680 	    || (is_var_diff(d)
11681 		&& (!(d->has_local_changes() & LOCAL_NON_TYPE_CHANGE_KIND)))
11682 	    ||  (is_class_diff(d)
11683 		&& (!(d->has_local_changes() & LOCAL_NON_TYPE_CHANGE_KIND)))))
11684       {
11685 	// Note that we handle private diff nodes differently from
11686 	// generally suppressed diff nodes.  E.g, it's not because a
11687 	// type is private (and suppressed because of that; i.e, in
11688 	// the category PRIVATE_TYPE_CATEGORY) that a typedef to that
11689 	// type should also be private and so suppressed.  Private
11690 	// diff nodes thus have different propagation rules than
11691 	// generally suppressed rules.
11692 	for (vector<diff*>::const_iterator i = d->children_nodes().begin();
11693 	     i != d->children_nodes().end();
11694 	     ++i)
11695 	  {
11696 	    diff* child = *i;
11697 	    if (child->has_changes())
11698 	      {
11699 		has_non_empty_child = true;
11700 		if (child->get_class_of_equiv_category() & SUPPRESSED_CATEGORY)
11701 		  has_suppressed_child = true;
11702 		else if (child->get_class_of_equiv_category()
11703 			 & PRIVATE_TYPE_CATEGORY)
11704 		  // Propagation of the PRIVATE_TYPE_CATEGORY is going
11705 		  // to be handled later below.
11706 		  ;
11707 		else
11708 		  has_non_suppressed_child = true;
11709 
11710 		if (child->get_class_of_equiv_category()
11711 		    & PRIVATE_TYPE_CATEGORY)
11712 		  has_private_child = true;
11713 		else if (child->get_class_of_equiv_category()
11714 			 & SUPPRESSED_CATEGORY)
11715 		  // Propagation of the SUPPRESSED_CATEGORY has been
11716 		  // handled above already.
11717 		  ;
11718 		else
11719 		  has_non_private_child = true;
11720 	      }
11721 	  }
11722 
11723 	if (has_non_empty_child
11724 	    && has_suppressed_child
11725 	    && !has_non_suppressed_child)
11726 	  {
11727 	    d->add_to_category(SUPPRESSED_CATEGORY);
11728 	    // If a node was suppressed, all the other nodes of its class
11729 	    // of equivalence are suppressed too.
11730 	    diff *canonical_diff = d->get_canonical_diff();
11731 	    if (canonical_diff != d)
11732 	      canonical_diff->add_to_category(SUPPRESSED_CATEGORY);
11733 	  }
11734 
11735 	// Note that the private-ness of a an underlying type won't be
11736 	// propagated to its parent typedef, by virtue of the big "if"
11737 	// clause at the beginning of this function.  So we don't have
11738 	// to handle that case here.  So the idiom of defining
11739 	// typedefs of private (opaque) types will be respected;
11740 	// meaning that changes to opaque underlying type will be
11741 	// flagged as private and the typedef will be flagged private
11742 	// as well, unless the typedef itself has local non-type
11743 	// changes.  In the later case, changes to the typedef will be
11744 	// emitted because the typedef won't inherit the privateness
11745 	// of its underlying type.  So in practise, the typedef
11746 	// remains public for the purpose of change reporting.
11747 	if (has_non_empty_child
11748 	    && has_private_child
11749 	    && !has_non_private_child)
11750 	  {
11751 	    d->add_to_category(PRIVATE_TYPE_CATEGORY);
11752 	    // If a node was suppressed, all the other nodes of its class
11753 	    // of equivalence are suppressed too.
11754 	    diff *canonical_diff = d->get_canonical_diff();
11755 	    if (canonical_diff != d)
11756 	      canonical_diff->add_to_category(PRIVATE_TYPE_CATEGORY);
11757 	  }
11758 
11759 	// If the underlying type of a typedef is private and carries
11760 	// changes (that are implicitely suppressed because it's
11761 	// private) then the typedef must be suppressed too, so that
11762 	// those changes to the underlying type are not seen.
11763 	if (is_typedef_diff(d)
11764 	    && !d->has_local_changes()
11765 	    && has_private_child
11766 	    && has_non_empty_child)
11767 	  {
11768 	    d->add_to_category(SUPPRESSED_CATEGORY|PRIVATE_TYPE_CATEGORY);
11769 	    // If a node was suppressed, all the other nodes of its class
11770 	    // of equivalence are suppressed too.
11771 	    diff *canonical_diff = d->get_canonical_diff();
11772 	    if (canonical_diff != d)
11773 	      canonical_diff->add_to_category
11774 		(SUPPRESSED_CATEGORY|PRIVATE_TYPE_CATEGORY);
11775 	  }
11776 
11777 	if (const function_decl_diff *fn_diff = is_function_decl_diff(d))
11778 	  if (!(d->has_local_changes() & LOCAL_NON_TYPE_CHANGE_KIND))
11779 	    {
11780 	      // d is a function diff that carries a local *type*
11781 	      // change (that means it's a change to the function
11782 	      // type).  Let's see if the child function type diff
11783 	      // node is suppressed.  That would mean that we are
11784 	      // instructed to show details of a diff that is deemed
11785 	      // suppressed; this means the suppression conflicts with
11786 	      // a local type change.  In that case, let's follow what
11787 	      // the user asked and suppress the function altogether,
11788 	      if (function_type_diff_sptr fn_type_diff = fn_diff->type_diff())
11789 		if (fn_type_diff->is_suppressed())
11790 		  {
11791 		    d->add_to_category(SUPPRESSED_CATEGORY);
11792 		    // If a node was suppressed, all the other nodes
11793 		    // of its class of equivalence are suppressed too.
11794 		    diff *canonical_diff = d->get_canonical_diff();
11795 		    if (canonical_diff != d)
11796 		      canonical_diff->add_to_category(SUPPRESSED_CATEGORY);
11797 		  }
11798 	  }
11799       }
11800   }
11801 }; //end struct suppression_categorization_visitor
11802 
11803 /// Walk a given diff-sub tree and appply the suppressions carried by
11804 /// the context.  If the suppression applies to a given node than
11805 /// categorize the node into the SUPPRESSED_CATEGORY category and
11806 /// propagate that categorization.
11807 ///
11808 /// @param diff_tree the diff-sub tree to apply the suppressions to.
11809 void
apply_suppressions(diff * diff_tree)11810 apply_suppressions(diff* diff_tree)
11811 {
11812   if (diff_tree && !diff_tree->context()->suppressions().empty())
11813     {
11814       // Apply suppressions to functions and variables that have
11815       // changed sub-types.
11816       suppression_categorization_visitor v;
11817       diff_tree->context()->forget_visited_diffs();
11818       bool s = diff_tree->context()->visiting_a_node_twice_is_forbidden();
11819       diff_tree->context()->forbid_visiting_a_node_twice(true);
11820       diff_tree->traverse(v);
11821       diff_tree->context()->forbid_visiting_a_node_twice(s);
11822     }
11823 }
11824 
11825 /// Walk a given diff-sub tree and appply the suppressions carried by
11826 /// the context.  If the suppression applies to a given node than
11827 /// categorize the node into the SUPPRESSED_CATEGORY category and
11828 /// propagate that categorization.
11829 ///
11830 /// @param diff_tree the diff-sub tree to apply the suppressions to.
11831 void
apply_suppressions(diff_sptr diff_tree)11832 apply_suppressions(diff_sptr diff_tree)
11833 {apply_suppressions(diff_tree.get());}
11834 
11835 /// Walk a @ref corpus_diff tree and appply the suppressions carried
11836 /// by the context.  If the suppression applies to a given node then
11837 /// categorize the node into the SUPPRESSED_CATEGORY category and
11838 /// propagate that categorization.
11839 ///
11840 /// @param diff_tree the diff tree to apply the suppressions to.
11841 void
apply_suppressions(const corpus_diff * diff_tree)11842 apply_suppressions(const corpus_diff* diff_tree)
11843 {
11844   if (diff_tree && !diff_tree->context()->suppressions().empty())
11845     {
11846       // First, visit the children trees of changed constructs:
11847       // changed functions, variables, as well as sub-types of these,
11848       // and apply suppression specifications to these ...
11849       suppression_categorization_visitor v;
11850       diff_tree->context()->forget_visited_diffs();
11851       bool s = diff_tree->context()->visiting_a_node_twice_is_forbidden();
11852       diff_tree->context()->forbid_visiting_a_node_twice(true);
11853       const_cast<corpus_diff*>(diff_tree)->traverse(v);
11854       diff_tree->context()->forbid_visiting_a_node_twice(s);
11855 
11856       // ... then also visit the set of added and removed functions,
11857       // variables, symbols, and types not reachable from global
11858       // functions and variables.
11859       diff_tree->priv_->
11860 	apply_supprs_to_added_removed_fns_vars_unreachable_types();
11861     }
11862 }
11863 
11864 /// Walk a diff tree and appply the suppressions carried by the
11865 /// context.  If the suppression applies to a given node than
11866 /// categorize the node into the SUPPRESSED_CATEGORY category and
11867 /// propagate that categorization.
11868 ///
11869 /// @param diff_tree the diff tree to apply the suppressions to.
11870 void
apply_suppressions(corpus_diff_sptr diff_tree)11871 apply_suppressions(corpus_diff_sptr  diff_tree)
11872 {apply_suppressions(diff_tree.get());}
11873 
11874 // </diff tree category propagation>
11875 
11876 // <diff tree printing stuff>
11877 
11878 /// A visitor to print (to an output stream) a pretty representation
11879 /// of a @ref diff sub-tree or of a complete @ref corpus_diff tree.
11880 struct diff_node_printer : public diff_node_visitor
11881 {
11882   ostream& out_;
11883   unsigned level_;
11884 
11885   /// Emit a certain number of spaces to the output stream associated
11886   /// to this diff_node_printer.
11887   ///
11888   /// @param level half of the numver of spaces to emit.
11889   void
do_indentabigail::comparison::diff_node_printer11890   do_indent(unsigned level)
11891   {
11892     for (unsigned i = 0; i < level; ++i)
11893       out_ << "  ";
11894   }
11895 
diff_node_printerabigail::comparison::diff_node_printer11896   diff_node_printer(ostream& out)
11897     : diff_node_visitor(DO_NOT_MARK_VISITED_NODES_AS_VISITED),
11898       out_(out),
11899       level_(0)
11900   {}
11901 
11902   virtual void
visit_beginabigail::comparison::diff_node_printer11903   visit_begin(diff*)
11904   {
11905     ++level_;
11906   }
11907 
11908   virtual void
visit_endabigail::comparison::diff_node_printer11909   visit_end(diff*)
11910   {
11911     --level_;
11912   }
11913 
11914   virtual void
visit_beginabigail::comparison::diff_node_printer11915   visit_begin(corpus_diff*)
11916   {
11917     ++level_;
11918   }
11919 
11920   virtual void
visit_endabigail::comparison::diff_node_printer11921   visit_end(corpus_diff*)
11922   {
11923     --level_;
11924   }
11925 
11926   virtual bool
visitabigail::comparison::diff_node_printer11927   visit(diff* d, bool pre)
11928   {
11929     if (!pre)
11930       // We are post-visiting the diff node D.  Which means, we have
11931       // printed a pretty representation for it already.  So do
11932       // nothing now.
11933       return true;
11934 
11935     do_indent(level_);
11936     out_ << d->get_pretty_representation();
11937     out_ << "\n";
11938     do_indent(level_);
11939     out_ << "{\n";
11940     do_indent(level_ + 1);
11941     out_ << "category: "<< d->get_category() << "\n";
11942     do_indent(level_ + 1);
11943     out_ << "@: " << std::hex << d << std::dec << "\n";
11944     do_indent(level_ + 1);
11945     out_ << "@-canonical: " << std::hex
11946 	 << d->get_canonical_diff()
11947 	 << std::dec << "\n";
11948     do_indent(level_);
11949     out_ << "}\n";
11950 
11951     return true;
11952   }
11953 
11954   virtual bool
visitabigail::comparison::diff_node_printer11955   visit(corpus_diff* d, bool pre)
11956   {
11957     if (!pre)
11958       // We are post-visiting the diff node D.  Which means, we have
11959       // printed a pretty representation for it already.  So do
11960       // nothing now.
11961       return true;
11962 
11963     // indent
11964     for (unsigned i = 0; i < level_; ++i)
11965       out_ << ' ';
11966     out_ << d->get_pretty_representation();
11967     out_ << '\n';
11968     return true;
11969   }
11970 }; // end struct diff_printer_visitor
11971 
11972 // </ diff tree printing stuff>
11973 
11974 /// Emit a textual representation of a @ref diff sub-tree to an
11975 /// output stream.
11976 ///
11977 /// @param diff_tree the sub-tree to emit the textual representation
11978 /// for.
11979 ///
11980 /// @param out the output stream to emit the textual representation
11981 /// for @p diff_tree to.
11982 void
print_diff_tree(diff * diff_tree,ostream & out)11983 print_diff_tree(diff* diff_tree, ostream& out)
11984 {
11985   diff_node_printer p(out);
11986   bool s = diff_tree->context()->visiting_a_node_twice_is_forbidden();
11987   diff_tree->context()->forbid_visiting_a_node_twice(false);
11988   diff_tree->traverse(p);
11989   diff_tree->context()->forbid_visiting_a_node_twice(s);
11990 }
11991 
11992 /// Emit a textual representation of a @ref corpus_diff tree to an
11993 /// output stream.
11994 ///
11995 /// @param diff_tree the @ref corpus_diff tree to emit the textual
11996 /// representation for.
11997 ///
11998 /// @param out the output stream to emit the textual representation
11999 /// for @p diff_tree to.
12000 void
print_diff_tree(corpus_diff * diff_tree,std::ostream & out)12001 print_diff_tree(corpus_diff* diff_tree, std::ostream& out)
12002 {
12003   diff_node_printer p(out);
12004   bool s = diff_tree->context()->visiting_a_node_twice_is_forbidden();
12005   diff_tree->context()->forbid_visiting_a_node_twice(false);
12006   diff_tree->traverse(p);
12007   diff_tree->context()->forbid_visiting_a_node_twice(s);
12008 }
12009 
12010 /// Emit a textual representation of a @ref diff sub-tree to an
12011 /// output stream.
12012 ///
12013 /// @param diff_tree the sub-tree to emit the textual representation
12014 /// for.
12015 ///
12016 /// @param out the output stream to emit the textual representation
12017 /// for @p diff_tree to.
12018 void
print_diff_tree(diff_sptr diff_tree,std::ostream & o)12019 print_diff_tree(diff_sptr diff_tree,
12020 		std::ostream& o)
12021 {print_diff_tree(diff_tree.get(), o);}
12022 
12023 /// Emit a textual representation of a @ref corpus_diff tree to an
12024 /// output stream.
12025 ///
12026 /// @param diff_tree the @ref corpus_diff tree to emit the textual
12027 /// representation for.
12028 ///
12029 /// @param out the output stream to emit the textual representation
12030 /// for @p diff_tree to.
12031 void
print_diff_tree(corpus_diff_sptr diff_tree,std::ostream & o)12032 print_diff_tree(corpus_diff_sptr diff_tree,
12033 		std::ostream& o)
12034 {print_diff_tree(diff_tree.get(), o);}
12035 
12036 // <redundancy_marking_visitor>
12037 
12038 /// A tree visitor to categorize nodes with respect to the
12039 /// REDUNDANT_CATEGORY.  That is, detect if a node is redundant (is
12040 /// present on several spots of the tree) and mark such nodes
12041 /// appropriatly.  This visitor also takes care of propagating the
12042 /// REDUNDANT_CATEGORY of a given node to its parent nodes as
12043 /// appropriate.
12044 struct redundancy_marking_visitor : public diff_node_visitor
12045 {
12046   bool skip_children_nodes_;
12047 
redundancy_marking_visitorabigail::comparison::redundancy_marking_visitor12048   redundancy_marking_visitor()
12049     : skip_children_nodes_()
12050   {}
12051 
12052   virtual void
visit_beginabigail::comparison::redundancy_marking_visitor12053   visit_begin(diff* d)
12054   {
12055     if (d->to_be_reported())
12056       {
12057 	// A diff node that carries a change and that has been already
12058 	// traversed elsewhere is considered redundant.  So let's mark
12059 	// it as such and let's not traverse it; that is, let's not
12060 	// visit its children.
12061 	if ((d->context()->diff_has_been_visited(d)
12062 	     || d->get_canonical_diff()->is_traversing())
12063 	    && d->has_changes())
12064 	  {
12065 	    // But if two diff nodes are redundant sibbling that carry
12066 	    // changes of base types, do not mark them as being
12067 	    // redundant.  This is to avoid marking nodes as redundant
12068 	    // in this case:
12069 	    //
12070 	    //     int foo(int a, int b);
12071 	    // compared with:
12072 	    //     float foo(float a, float b); (in C).
12073 	    //
12074 	    // In this case, we want to report all the occurences of
12075 	    // the int->float change because logically, they are at
12076 	    // the same level in the diff tree.
12077 
12078 	    bool redundant_with_sibling_node = false;
12079 	    const diff* p = d->parent_node();
12080 
12081 	    // If this is a child node of a fn_parm_diff, look through
12082 	    // the fn_parm_diff node to get the function diff node.
12083 	    if (p && dynamic_cast<const fn_parm_diff*>(p))
12084 	      p = p->parent_node();
12085 
12086 	    if (p)
12087 	      for (vector<diff*>::const_iterator s =
12088 		     p->children_nodes().begin();
12089 		   s != p->children_nodes().end();
12090 		   ++s)
12091 		{
12092 		  if (*s == d)
12093 		    continue;
12094 		  diff* sib = *s;
12095 		  // If this is a fn_parm_diff, look through the
12096 		  // fn_parm_diff node to get at the real type node.
12097 		  if (fn_parm_diff* f = dynamic_cast<fn_parm_diff*>(*s))
12098 		    sib = f->type_diff().get();
12099 		  if (sib == d)
12100 		    continue;
12101 		  if (sib->get_canonical_diff() == d->get_canonical_diff()
12102 		      // Sibbling diff nodes that carry base type
12103 		      // changes ar to be marked as redundant.
12104 		      && (is_base_diff(sib) || is_distinct_diff(sib)))
12105 		    {
12106 		      redundant_with_sibling_node = true;
12107 		      break;
12108 		    }
12109 		}
12110 	    if (!redundant_with_sibling_node
12111 		// Changes to basic types should never be considered
12112 		// redundant.  For instance, if a member of integer
12113 		// type is changed into a char type in both a struct A
12114 		// and a struct B, we want to see both changes.
12115 		&& !has_basic_type_change_only(d)
12116 		// The same goes for distinct type changes
12117 		&& !filtering::is_mostly_distinct_diff(d)
12118 		// Functions with similar *local* changes are never marked
12119 		// redundant because otherwise one could miss important
12120 		// similar local changes that are applied to different
12121 		// functions.
12122 		&& !is_function_type_diff_with_local_changes(d)
12123 		// Changes involving variadic parameters of functions
12124 		// should never be marked redundant because we want to see
12125 		// them all.
12126 		&& !is_diff_of_variadic_parameter(d)
12127 		&& !is_diff_of_variadic_parameter_type(d)
12128 		// If the canonical diff itself has been filtered out,
12129 		// then this one is not marked redundant, unless the
12130 		// canonical diff was already redundant.
12131 		&& (!d->get_canonical_diff()->is_filtered_out()
12132 		    || (d->get_canonical_diff()->get_category()
12133 			& REDUNDANT_CATEGORY))
12134 		// If the *same* diff node (not one that is merely
12135 		// equivalent to this one) has already been visited
12136 		// the do not mark it as beind redundant.  It's only
12137 		// the other nodes that are equivalent to this one
12138 		// that must be marked redundant.
12139 		&& d->context()->diff_has_been_visited(d) != d
12140 		// If the diff node is a function parameter and is not
12141 		// a reference/pointer (to a non basic or a non
12142 		// distinct type diff) then do not mark it as
12143 		// redundant.
12144 		//
12145 		// Children nodes of base class diff nodes are never
12146 		// redundant either, we want to see them all.
12147 		&& (is_reference_or_ptr_diff_to_non_basic_nor_distinct_types(d)
12148 		    || (!is_child_node_of_function_parm_diff(d)
12149 			&& !is_child_node_of_base_diff(d))))
12150 	      {
12151 		d->add_to_category(REDUNDANT_CATEGORY);
12152 		// As we said in preamble, as this node is marked as
12153 		// being redundant, let's not visit its children.
12154 		// This is not an optimization; it's needed for
12155 		// correctness.  In the case of a diff node involving
12156 		// a class type that refers to himself, visiting the
12157 		// children nodes might cause them to be wrongly
12158 		// marked as redundant.
12159 		set_visiting_kind(get_visiting_kind()
12160 				  | SKIP_CHILDREN_VISITING_KIND);
12161 		skip_children_nodes_ = true;
12162 	      }
12163 	  }
12164       }
12165     else
12166       {
12167 	// If the node is not to be reported, do not look at it children.
12168 	set_visiting_kind(get_visiting_kind() | SKIP_CHILDREN_VISITING_KIND);
12169 	skip_children_nodes_ = true;
12170       }
12171   }
12172 
12173   virtual void
visit_beginabigail::comparison::redundancy_marking_visitor12174   visit_begin(corpus_diff*)
12175   {
12176   }
12177 
12178   virtual void
visit_endabigail::comparison::redundancy_marking_visitor12179   visit_end(diff* d)
12180   {
12181     if (skip_children_nodes_)
12182       // When visiting this node, we decided to skip its children
12183       // node.  Now that we are done visiting the node, lets stop
12184       // avoiding the children nodes visiting for the other tree
12185       // nodes.
12186       {
12187 	set_visiting_kind(get_visiting_kind() & (~SKIP_CHILDREN_VISITING_KIND));
12188 	skip_children_nodes_ = false;
12189       }
12190     else
12191       {
12192 	// Propagate the redundancy categorization of the children nodes
12193 	// to this node.  But if this node has local changes, then it
12194 	// doesn't inherit redundancy from its children nodes.
12195 	if (!(d->get_category() & REDUNDANT_CATEGORY)
12196 	    && (!d->has_local_changes_to_be_reported()
12197 		// By default, pointer, reference and qualified types
12198 		// consider that a local changes to their underlying
12199 		// type is always a local change for themselves.
12200 		//
12201 		// This is as if those types don't have local changes
12202 		// in the same sense as other types.  So we always
12203 		// propagate redundancy to them, regardless of if they
12204 		// have local changes or not.
12205 		//
12206 		// We also propagate redundancy to typedef types if
12207 		// these /only/ carry changes to their underlying
12208 		// type.
12209 		//
12210 		// Note that changes to the underlying type of a
12211 		// typedef is considered local of
12212 		// LOCAL_TYPE_CHANGE_KIND kind.  The other changes to the
12213 		// typedef itself are considered local of
12214 		// LOCAL_NON_TYPE_CHANGE_KIND kind.
12215 		|| is_pointer_diff(d)
12216 		|| is_qualified_type_diff(d)
12217 		// A typedef with local non-type changes should not
12218 		// see redundancy propagation from its underlying
12219 		// type, otherwise, the non-type change might be
12220 		// "suppressed" away.
12221 		|| (is_typedef_diff(d)
12222 		    && (!(d->has_local_changes()
12223 			  & LOCAL_NON_TYPE_CHANGE_KIND)))
12224 		// A (member) variable with non-type local changes
12225 		// should not see redundacy propagation from its type.
12226 		// If redundant local-type changes are carried by its
12227 		// type however, then that redundancy is propagated to
12228 		// the variable.  This is key to keep the redundancy
12229 		// consistency in the system; otherwise, a type change
12230 		// would be rightfully considered redundant at some
12231 		// places but not at others.
12232 		|| (is_var_diff(d)
12233 		    && (!(d->has_local_changes()
12234 			  & LOCAL_NON_TYPE_CHANGE_KIND)))
12235 		))
12236 	  {
12237 	    bool has_non_redundant_child = false;
12238 	    bool has_non_empty_child = false;
12239 	    for (vector<diff*>::const_iterator i =
12240 		   d->children_nodes().begin();
12241 		 i != d->children_nodes().end();
12242 		 ++i)
12243 	      {
12244 		if ((*i)->has_changes())
12245 		  {
12246 		    has_non_empty_child = true;
12247 		    // Let's see if the current child node '*i' is
12248 		    // "non-redundant".
12249 		    //
12250 		    // A non-redundant node would be a node that
12251 		    // carries a change to be reported and has not
12252 		    // been marked as being redundant.
12253 		    if ((*i)->to_be_reported()
12254 			&& ((*i)->get_category() & REDUNDANT_CATEGORY) == 0)
12255 		      has_non_redundant_child = true;
12256 		  }
12257 		if (has_non_redundant_child)
12258 		  break;
12259 	      }
12260 
12261 	    // A diff node for which at least a child node carries a
12262 	    // change, and for which all the children are redundant is
12263 	    // deemed redundant too, unless it has local changes.
12264 	    if (has_non_empty_child
12265 		&& !has_non_redundant_child)
12266 	      d->add_to_category(REDUNDANT_CATEGORY);
12267 	  }
12268       }
12269   }
12270 
12271   virtual void
visit_endabigail::comparison::redundancy_marking_visitor12272   visit_end(corpus_diff*)
12273   {
12274   }
12275 
12276   virtual bool
visitabigail::comparison::redundancy_marking_visitor12277   visit(diff*, bool)
12278   {return true;}
12279 
12280   virtual bool
visitabigail::comparison::redundancy_marking_visitor12281   visit(corpus_diff*, bool)
12282   {
12283     return true;
12284   }
12285 };// end struct redundancy_marking_visitor
12286 
12287 /// A visitor of @ref diff nodes that clears the REDUNDANT_CATEGORY
12288 /// category out of the nodes.
12289 struct redundancy_clearing_visitor : public diff_node_visitor
12290 {
12291   bool
visitabigail::comparison::redundancy_clearing_visitor12292   visit(corpus_diff*, bool)
12293   {return true;}
12294 
12295   bool
visitabigail::comparison::redundancy_clearing_visitor12296   visit(diff* d, bool)
12297   {
12298     // clear the REDUNDANT_CATEGORY out of the current node.
12299     diff_category c = d->get_category();
12300     c &= ~REDUNDANT_CATEGORY;
12301     d->set_category(c);
12302     return true;
12303   }
12304 }; // end struct redundancy_clearing_visitor
12305 
12306 /// Walk a given @ref diff sub-tree to categorize each of the nodes
12307 /// with respect to the REDUNDANT_CATEGORY.
12308 ///
12309 /// @param diff_tree the @ref diff sub-tree to walk.
12310 void
categorize_redundancy(diff * diff_tree)12311 categorize_redundancy(diff* diff_tree)
12312 {
12313   if (diff_tree->context()->show_redundant_changes())
12314     return;
12315   redundancy_marking_visitor v;
12316   bool s = diff_tree->context()->visiting_a_node_twice_is_forbidden();
12317   diff_tree->context()->forbid_visiting_a_node_twice(false);
12318   diff_tree->traverse(v);
12319   diff_tree->context()->forbid_visiting_a_node_twice(s);
12320 }
12321 
12322 /// Walk a given @ref diff sub-tree to categorize each of the nodes
12323 /// with respect to the REDUNDANT_CATEGORY.
12324 ///
12325 /// @param diff_tree the @ref diff sub-tree to walk.
12326 void
categorize_redundancy(diff_sptr diff_tree)12327 categorize_redundancy(diff_sptr diff_tree)
12328 {categorize_redundancy(diff_tree.get());}
12329 
12330 /// Walk a given @ref corpus_diff tree to categorize each of the nodes
12331 /// with respect to the REDUNDANT_CATEGORY.
12332 ///
12333 /// @param diff_tree the @ref corpus_diff tree to walk.
12334 void
categorize_redundancy(corpus_diff * diff_tree)12335 categorize_redundancy(corpus_diff* diff_tree)
12336 {
12337   redundancy_marking_visitor v;
12338   diff_tree->context()->forget_visited_diffs();
12339   bool s = diff_tree->context()->visiting_a_node_twice_is_forbidden();
12340   diff_tree->context()->forbid_visiting_a_node_twice(false);
12341   diff_tree->traverse(v);
12342   diff_tree->context()->forbid_visiting_a_node_twice(s);
12343 }
12344 
12345 /// Walk a given @ref corpus_diff tree to categorize each of the nodes
12346 /// with respect to the REDUNDANT_CATEGORY.
12347 ///
12348 /// @param diff_tree the @ref corpus_diff tree to walk.
12349 void
categorize_redundancy(corpus_diff_sptr diff_tree)12350 categorize_redundancy(corpus_diff_sptr diff_tree)
12351 {categorize_redundancy(diff_tree.get());}
12352 
12353 // </redundancy_marking_visitor>
12354 
12355 /// Walk a given @ref diff sub-tree to clear the REDUNDANT_CATEGORY
12356 /// out of the category of the nodes.
12357 ///
12358 /// @param diff_tree the @ref diff sub-tree to walk.
12359 void
clear_redundancy_categorization(diff * diff_tree)12360 clear_redundancy_categorization(diff* diff_tree)
12361 {
12362   redundancy_clearing_visitor v;
12363   bool s = diff_tree->context()->visiting_a_node_twice_is_forbidden();
12364   diff_tree->context()->forbid_visiting_a_node_twice(false);
12365   diff_tree->traverse(v);
12366   diff_tree->context()->forbid_visiting_a_node_twice(s);
12367   diff_tree->context()->forget_visited_diffs();
12368 }
12369 
12370 /// Walk a given @ref diff sub-tree to clear the REDUNDANT_CATEGORY
12371 /// out of the category of the nodes.
12372 ///
12373 /// @param diff_tree the @ref diff sub-tree to walk.
12374 void
clear_redundancy_categorization(diff_sptr diff_tree)12375 clear_redundancy_categorization(diff_sptr diff_tree)
12376 {clear_redundancy_categorization(diff_tree.get());}
12377 
12378 /// Walk a given @ref corpus_diff tree to clear the REDUNDANT_CATEGORY
12379 /// out of the category of the nodes.
12380 ///
12381 /// @param diff_tree the @ref corpus_diff tree to walk.
12382 void
clear_redundancy_categorization(corpus_diff * diff_tree)12383 clear_redundancy_categorization(corpus_diff* diff_tree)
12384 {
12385   redundancy_clearing_visitor v;
12386   bool s = diff_tree->context()->visiting_a_node_twice_is_forbidden();
12387   diff_tree->context()->forbid_visiting_a_node_twice(false);
12388   diff_tree->traverse(v);
12389   diff_tree->context()->forbid_visiting_a_node_twice(s);
12390   diff_tree->context()->forget_visited_diffs();
12391 }
12392 
12393 /// Walk a given @ref corpus_diff tree to clear the REDUNDANT_CATEGORY
12394 /// out of the category of the nodes.
12395 ///
12396 /// @param diff_tree the @ref corpus_diff tree to walk.
12397 void
clear_redundancy_categorization(corpus_diff_sptr diff_tree)12398 clear_redundancy_categorization(corpus_diff_sptr diff_tree)
12399 {clear_redundancy_categorization(diff_tree.get());}
12400 
12401 /// Apply the @ref diff tree filters that have been associated to the
12402 /// context of the a given @ref corpus_diff tree.  As a result, the
12403 /// nodes of the @diff tree are going to be categorized into one of
12404 /// several of the categories of @ref diff_category.
12405 ///
12406 /// @param diff_tree the @ref corpus_diff instance which @ref diff are
12407 /// to be categorized.
12408 void
apply_filters(corpus_diff_sptr diff_tree)12409 apply_filters(corpus_diff_sptr diff_tree)
12410 {
12411   diff_tree->context()->maybe_apply_filters(diff_tree);
12412   propagate_categories(diff_tree);
12413 }
12414 
12415 /// Test if a diff node represents the difference between a variadic
12416 /// parameter type and something else.
12417 ///
12418 /// @param d the diff node to consider.
12419 ///
12420 /// @return true iff @p d is a diff node that represents the
12421 /// difference between a variadic parameter type and something else.
12422 bool
is_diff_of_variadic_parameter_type(const diff * d)12423 is_diff_of_variadic_parameter_type(const diff* d)
12424 {
12425   if (!d)
12426     return false;
12427 
12428   type_base_sptr t = is_type(d->first_subject());
12429   if (t && t->get_environment()->is_variadic_parameter_type(t))
12430     return true;
12431 
12432   t = is_type(d->second_subject());
12433   if (t && t->get_environment()->is_variadic_parameter_type(t))
12434     return true;
12435 
12436   return false;
12437 }
12438 
12439 /// Test if a diff node represents the difference between a variadic
12440 /// parameter type and something else.
12441 ///
12442 /// @param d the diff node to consider.
12443 ///
12444 /// @return true iff @p d is a diff node that represents the
12445 /// difference between a variadic parameter type and something else.
12446 bool
is_diff_of_variadic_parameter_type(const diff_sptr & d)12447 is_diff_of_variadic_parameter_type(const diff_sptr& d)
12448 {return is_diff_of_variadic_parameter_type(d.get());}
12449 
12450 /// Test if a diff node represents the difference between a variadic
12451 /// parameter and something else.
12452 ///
12453 /// @param d the diff node to consider.
12454 ///
12455 /// @return true iff @p d is a diff node that represents the
12456 /// difference between a variadic parameter and something else.
12457 bool
is_diff_of_variadic_parameter(const diff * d)12458 is_diff_of_variadic_parameter(const diff* d)
12459 {
12460   fn_parm_diff* diff =
12461     dynamic_cast<fn_parm_diff*>(const_cast<abigail::comparison::diff*>(d));
12462   return (diff && is_diff_of_variadic_parameter_type(diff->type_diff()));
12463 }
12464 
12465 /// Test if a diff node represents the difference between a variadic
12466 /// parameter and something else.
12467 ///
12468 /// @param d the diff node to consider.
12469 ///
12470 /// @return true iff @p d is a diff node that represents the
12471 /// difference between a variadic parameter and something else.
12472 bool
is_diff_of_variadic_parameter(const diff_sptr & d)12473 is_diff_of_variadic_parameter(const diff_sptr& d)
12474 {return is_diff_of_variadic_parameter(d.get());}
12475 
12476 /// Test if a diff node represents a diff between two basic types.
12477 ///
12478 /// @param d the diff node to consider.
12479 ///
12480 /// @return true iff @p d is a diff between two basic types.
12481 const type_decl_diff*
is_diff_of_basic_type(const diff * d)12482 is_diff_of_basic_type(const diff *d)
12483 {return dynamic_cast<const type_decl_diff*>(d);}
12484 
12485 /// Test if a diff node represents a diff between two basic types, or
12486 /// between pointers, references or qualified type to basic types.
12487 ///
12488 /// @param diff the diff node to consider.
12489 ///
12490 /// @param allow_indirect_type if true, then this function looks into
12491 /// pointer, reference or qualified diff types to see if they "point
12492 /// to" basic types.
12493 ///
12494 /// @return true iff @p d is a diff between two basic types.
12495 const type_decl_diff*
is_diff_of_basic_type(const diff * diff,bool allow_indirect_type)12496 is_diff_of_basic_type(const diff* diff, bool allow_indirect_type)
12497 {
12498   if (allow_indirect_type)
12499       diff = peel_pointer_or_qualified_type_diff(diff);
12500   return is_diff_of_basic_type(diff);
12501 }
12502 
12503 /// If a diff node is about changes between two typedef types, get the
12504 /// diff node about changes between the underlying types.
12505 ///
12506 /// Note that this function walks the tree of underlying diff nodes
12507 /// returns the first diff node about types that are not typedefs.
12508 ///
12509 /// @param dif the dif node to consider.
12510 ///
12511 /// @return the underlying diff node of @p dif, or just return @p dif
12512 /// if it's not a typedef diff node.
12513 const diff*
peel_typedef_diff(const diff * dif)12514 peel_typedef_diff(const diff* dif)
12515 {
12516   const typedef_diff *d = 0;
12517   while ((d = is_typedef_diff(dif)))
12518     dif = d->underlying_type_diff().get();
12519   return dif;
12520 }
12521 
12522 /// If a diff node is about changes between two pointer types, get the
12523 /// diff node about changes between the underlying (pointed-to) types.
12524 ///
12525 /// Note that this function walks the tree of underlying diff nodes
12526 /// returns the first diff node about types that are not pointers.
12527 ///
12528 /// @param dif the dif node to consider.
12529 ///
12530 /// @return the underlying diff node of @p dif, or just return @p dif
12531 /// if it's not a pointer diff node.
12532 const diff*
peel_pointer_diff(const diff * dif)12533 peel_pointer_diff(const diff* dif)
12534 {
12535   const pointer_diff *d = 0;
12536   while ((d = is_pointer_diff(dif)))
12537     dif = d->underlying_type_diff().get();
12538   return dif;
12539 }
12540 
12541 /// If a diff node is about changes between two reference types, get
12542 /// the diff node about changes between the underlying (pointed-to)
12543 /// types.
12544 ///
12545 /// Note that this function walks the tree of underlying diff nodes
12546 /// returns the first diff node about types that are not references.
12547 ///
12548 /// @param dif the dif node to consider.
12549 ///
12550 /// @return the underlying diff node of @p dif, or just return @p dif
12551 /// if it's not a reference diff node.
12552 const diff*
peel_reference_diff(const diff * dif)12553 peel_reference_diff(const diff* dif)
12554 {
12555   const reference_diff *d = 0;
12556   while ((d = is_reference_diff(dif)))
12557     dif = d->underlying_type_diff().get();
12558   return dif;
12559 }
12560 
12561 /// If a diff node is about changes between two qualified types, get
12562 /// the diff node about changes between the underlying (non-qualified)
12563 /// types.
12564 ///
12565 /// Note that this function walks the tree of underlying diff nodes
12566 /// returns the first diff node about types that are not qualified.
12567 ///
12568 /// @param dif the dif node to consider.
12569 ///
12570 /// @return the underlying diff node of @p dif, or just return @p dif
12571 /// if it's not a qualified diff node.
12572 const diff*
peel_qualified_diff(const diff * dif)12573 peel_qualified_diff(const diff* dif)
12574 {
12575   const qualified_type_diff *d = 0;
12576   while ((d = is_qualified_type_diff(dif)))
12577     dif = d->underlying_type_diff().get();
12578   return dif;
12579 }
12580 
12581 /// If a diff node is about changes between two pointer, reference or
12582 /// qualified types, get the diff node about changes between the
12583 /// underlying types.
12584 ///
12585 /// Note that this function walks the tree of underlying diff nodes
12586 /// returns the first diff node about types that are not pointer,
12587 /// reference or qualified.
12588 ///
12589 /// @param dif the dif node to consider.
12590 ///
12591 /// @return the underlying diff node of @p dif, or just return @p dif
12592 /// if it's not a pointer, reference or qualified diff node.
12593 const diff*
peel_pointer_or_qualified_type_diff(const diff * dif)12594 peel_pointer_or_qualified_type_diff(const diff*dif)
12595 {
12596   while (true)
12597     {
12598       if (const pointer_diff *d = is_pointer_diff(dif))
12599 	dif = peel_pointer_diff(d);
12600       else if (const reference_diff *d = is_reference_diff(dif))
12601 	dif = peel_reference_diff(d);
12602       else if (const qualified_type_diff *d = is_qualified_type_diff(dif))
12603 	dif = peel_qualified_diff(d);
12604       else
12605 	break;
12606     }
12607   return dif;
12608 }
12609 
12610 /// If a diff node is about changes between two typedefs or qualified
12611 /// types, get the diff node about changes between the underlying
12612 /// types.
12613 ///
12614 /// Note that this function walks the tree of underlying diff nodes
12615 /// returns the first diff node about types that are not typedef or
12616 /// qualified types.
12617 ///
12618 /// @param dif the dif node to consider.
12619 ///
12620 /// @return the underlying diff node of @p dif, or just return @p dif
12621 /// if it's not typedef or qualified diff node.
12622 const diff*
peel_typedef_or_qualified_type_diff(const diff * dif)12623 peel_typedef_or_qualified_type_diff(const diff *dif)
12624 {
12625   while (true)
12626     {
12627       if (const typedef_diff *d = is_typedef_diff(dif))
12628 	dif = peel_typedef_diff(d);
12629       else if (const qualified_type_diff *d = is_qualified_type_diff(dif))
12630 	dif = peel_qualified_diff(d);
12631       else
12632 	break;
12633     }
12634   return dif;
12635 }
12636 
12637 /// Test if a diff node represents a diff between two class or union
12638 /// types.
12639 ///
12640 /// @param d the diff node to consider.
12641 ///
12642 /// @return iff @p is a diff between two class or union types then
12643 /// return the instance of @ref class_or_union_diff that @p derives
12644 /// from.  Otherwise, return nil.
12645 const class_or_union_diff*
is_diff_of_class_or_union_type(const diff * d)12646 is_diff_of_class_or_union_type(const diff *d)
12647 {return dynamic_cast<const class_or_union_diff*>(d);}
12648 
12649 /// Test if a given diff node carries *only* a local type change.
12650 ///
12651 /// @param d the diff node to consider.
12652 ///
12653 /// @return true iff @p has a change and that change is a local type
12654 /// change.
12655 static bool
has_local_type_change_only(const diff * d)12656 has_local_type_change_only(const diff *d)
12657 {
12658   if (enum change_kind k = d->has_local_changes())
12659     if ((k & LOCAL_NON_TYPE_CHANGE_KIND) == 0
12660 	&& (k & LOCAL_TYPE_CHANGE_KIND) != 0)
12661       return true;
12662 
12663   return false;
12664 }
12665 
12666 /// Test if a diff node is a decl diff that only carries a basic type
12667 /// change on its type diff sub-node.
12668 ///
12669 ///Note that that pointers/references/qualified types diffs to basic
12670 /// type diffs are considered as having basic type change only.
12671 ///
12672 /// @param d the diff node to consider.
12673 ///
12674 /// @return true iff @p d is a decl diff that only carries a basic
12675 /// type change on its type diff sub-node.
12676 bool
has_basic_type_change_only(const diff * d)12677 has_basic_type_change_only(const diff *d)
12678 {
12679   if (is_diff_of_basic_type(d, true) && d->has_changes())
12680     return true;
12681   else if (const var_diff * v = dynamic_cast<const var_diff*>(d))
12682     return (has_local_type_change_only(v)
12683 	    && is_diff_of_basic_type(v->type_diff().get(), true));
12684   else if (const fn_parm_diff * p = dynamic_cast<const fn_parm_diff*>(d))
12685     return (has_local_type_change_only(p)
12686 	    && is_diff_of_basic_type(p->type_diff().get(), true));
12687   else if (const function_decl_diff* f =
12688 	   dynamic_cast<const function_decl_diff*>(d))
12689     return (has_local_type_change_only(f)
12690 	    && f->type_diff()
12691 	    && is_diff_of_basic_type(f->type_diff()->return_type_diff().get(),
12692 				     true));
12693   return false;
12694 }
12695 }// end namespace comparison
12696 } // end namespace abigail
12697