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