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